diff options
author | Russell King <rmk@dyn-67.arm.linux.org.uk> | 2009-05-29 05:19:22 -0400 |
---|---|---|
committer | Russell King <rmk+kernel@arm.linux.org.uk> | 2009-05-29 05:19:22 -0400 |
commit | a35197a8be891072b3654dc7a2285573150dedee (patch) | |
tree | f3829335b8a0cd40e2cdb94d7fefb54bf67977df | |
parent | 6daad5c6c586bf07528ae5b39e801b204468f907 (diff) | |
parent | 67a433ce278b98f47272726a22537fab7fd99de9 (diff) |
Merge branch 'for-rmk' of git://gitorious.org/linux-gemini/mainline
136 files changed, 10581 insertions, 698 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index e87bdbfbcc75..fd5cac013037 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -1535,6 +1535,10 @@ and is between 256 and 4096 characters. It is defined in the file | |||
1535 | register save and restore. The kernel will only save | 1535 | register save and restore. The kernel will only save |
1536 | legacy floating-point registers on task switch. | 1536 | legacy floating-point registers on task switch. |
1537 | 1537 | ||
1538 | noxsave [BUGS=X86] Disables x86 extended register state save | ||
1539 | and restore using xsave. The kernel will fallback to | ||
1540 | enabling legacy floating-point and sse state. | ||
1541 | |||
1538 | nohlt [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or | 1542 | nohlt [BUGS=ARM,SH] Tells the kernel that the sleep(SH) or |
1539 | wfi(ARM) instruction doesn't work correctly and not to | 1543 | wfi(ARM) instruction doesn't work correctly and not to |
1540 | use it. This is also useful when using JTAG debugger. | 1544 | use it. This is also useful when using JTAG debugger. |
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt index 8eec05bc079e..322869fc8a9e 100644 --- a/Documentation/sound/alsa/HD-Audio-Models.txt +++ b/Documentation/sound/alsa/HD-Audio-Models.txt | |||
@@ -334,6 +334,7 @@ STAC9227/9228/9229/927x | |||
334 | ref-no-jd Reference board without HP/Mic jack detection | 334 | ref-no-jd Reference board without HP/Mic jack detection |
335 | 3stack D965 3stack | 335 | 3stack D965 3stack |
336 | 5stack D965 5stack + SPDIF | 336 | 5stack D965 5stack + SPDIF |
337 | 5stack-no-fp D965 5stack without front panel | ||
337 | dell-3stack Dell Dimension E520 | 338 | dell-3stack Dell Dimension E520 |
338 | dell-bios Fixes with Dell BIOS setup | 339 | dell-bios Fixes with Dell BIOS setup |
339 | auto BIOS setup (default) | 340 | auto BIOS setup (default) |
diff --git a/MAINTAINERS b/MAINTAINERS index 64ea80e45e3b..42c53ab6b9fa 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -624,6 +624,7 @@ M: paulius.zaleckas@teltonika.lt | |||
624 | L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) | 624 | L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) |
625 | T: git git://gitorious.org/linux-gemini/mainline.git | 625 | T: git git://gitorious.org/linux-gemini/mainline.git |
626 | S: Maintained | 626 | S: Maintained |
627 | F: arch/arm/mach-gemini/ | ||
627 | 628 | ||
628 | ARM/EBSA110 MACHINE SUPPORT | 629 | ARM/EBSA110 MACHINE SUPPORT |
629 | P: Russell King | 630 | P: Russell King |
@@ -650,6 +651,7 @@ P: Paulius Zaleckas | |||
650 | M: paulius.zaleckas@teltonika.lt | 651 | M: paulius.zaleckas@teltonika.lt |
651 | L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) | 652 | L: linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only) |
652 | S: Maintained | 653 | S: Maintained |
654 | F: arch/arm/mm/*-fa* | ||
653 | 655 | ||
654 | ARM/FOOTBRIDGE ARCHITECTURE | 656 | ARM/FOOTBRIDGE ARCHITECTURE |
655 | P: Russell King | 657 | P: Russell King |
@@ -1132,17 +1134,17 @@ F: fs/bfs/ | |||
1132 | F: include/linux/bfs_fs.h | 1134 | F: include/linux/bfs_fs.h |
1133 | 1135 | ||
1134 | BLACKFIN ARCHITECTURE | 1136 | BLACKFIN ARCHITECTURE |
1135 | P: Bryan Wu | 1137 | P: Mike Frysinger |
1136 | M: cooloney@kernel.org | 1138 | M: vapier@gentoo.org |
1137 | L: uclinux-dist-devel@blackfin.uclinux.org | 1139 | L: uclinux-dist-devel@blackfin.uclinux.org |
1138 | W: http://blackfin.uclinux.org | 1140 | W: http://blackfin.uclinux.org |
1139 | S: Supported | 1141 | S: Supported |
1140 | F: arch/blackfin/ | 1142 | F: arch/blackfin/ |
1141 | 1143 | ||
1142 | BLACKFIN EMAC DRIVER | 1144 | BLACKFIN EMAC DRIVER |
1143 | P: Bryan Wu | 1145 | P: Michael Hennerich |
1144 | M: cooloney@kernel.org | 1146 | M: michael.hennerich@analog.com |
1145 | L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) | 1147 | L: uclinux-dist-devel@blackfin.uclinux.org |
1146 | W: http://blackfin.uclinux.org | 1148 | W: http://blackfin.uclinux.org |
1147 | S: Supported | 1149 | S: Supported |
1148 | F: drivers/net/bfin_mac.* | 1150 | F: drivers/net/bfin_mac.* |
@@ -1150,7 +1152,7 @@ F: drivers/net/bfin_mac.* | |||
1150 | BLACKFIN RTC DRIVER | 1152 | BLACKFIN RTC DRIVER |
1151 | P: Mike Frysinger | 1153 | P: Mike Frysinger |
1152 | M: vapier.adi@gmail.com | 1154 | M: vapier.adi@gmail.com |
1153 | L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) | 1155 | L: uclinux-dist-devel@blackfin.uclinux.org |
1154 | W: http://blackfin.uclinux.org | 1156 | W: http://blackfin.uclinux.org |
1155 | S: Supported | 1157 | S: Supported |
1156 | F: drivers/rtc/rtc-bfin.c | 1158 | F: drivers/rtc/rtc-bfin.c |
@@ -1158,7 +1160,7 @@ F: drivers/rtc/rtc-bfin.c | |||
1158 | BLACKFIN SERIAL DRIVER | 1160 | BLACKFIN SERIAL DRIVER |
1159 | P: Sonic Zhang | 1161 | P: Sonic Zhang |
1160 | M: sonic.zhang@analog.com | 1162 | M: sonic.zhang@analog.com |
1161 | L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) | 1163 | L: uclinux-dist-devel@blackfin.uclinux.org |
1162 | W: http://blackfin.uclinux.org | 1164 | W: http://blackfin.uclinux.org |
1163 | S: Supported | 1165 | S: Supported |
1164 | F: drivers/serial/bfin_5xx.c | 1166 | F: drivers/serial/bfin_5xx.c |
@@ -1166,7 +1168,7 @@ F: drivers/serial/bfin_5xx.c | |||
1166 | BLACKFIN WATCHDOG DRIVER | 1168 | BLACKFIN WATCHDOG DRIVER |
1167 | P: Mike Frysinger | 1169 | P: Mike Frysinger |
1168 | M: vapier.adi@gmail.com | 1170 | M: vapier.adi@gmail.com |
1169 | L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) | 1171 | L: uclinux-dist-devel@blackfin.uclinux.org |
1170 | W: http://blackfin.uclinux.org | 1172 | W: http://blackfin.uclinux.org |
1171 | S: Supported | 1173 | S: Supported |
1172 | F: drivers/watchdog/bfin_wdt.c | 1174 | F: drivers/watchdog/bfin_wdt.c |
@@ -1174,7 +1176,7 @@ F: drivers/watchdog/bfin_wdt.c | |||
1174 | BLACKFIN I2C TWI DRIVER | 1176 | BLACKFIN I2C TWI DRIVER |
1175 | P: Sonic Zhang | 1177 | P: Sonic Zhang |
1176 | M: sonic.zhang@analog.com | 1178 | M: sonic.zhang@analog.com |
1177 | L: uclinux-dist-devel@blackfin.uclinux.org (subscribers-only) | 1179 | L: uclinux-dist-devel@blackfin.uclinux.org |
1178 | W: http://blackfin.uclinux.org/ | 1180 | W: http://blackfin.uclinux.org/ |
1179 | S: Supported | 1181 | S: Supported |
1180 | F: drivers/i2c/busses/i2c-bfin-twi.c | 1182 | F: drivers/i2c/busses/i2c-bfin-twi.c |
@@ -1431,6 +1433,14 @@ P: Russell King | |||
1431 | M: linux@arm.linux.org.uk | 1433 | M: linux@arm.linux.org.uk |
1432 | F: include/linux/clk.h | 1434 | F: include/linux/clk.h |
1433 | 1435 | ||
1436 | CISCO FCOE HBA DRIVER | ||
1437 | P: Abhijeet Joglekar | ||
1438 | M: abjoglek@cisco.com | ||
1439 | P: Joe Eykholt | ||
1440 | M: jeykholt@cisco.com | ||
1441 | L: linux-scsi@vger.kernel.org | ||
1442 | S: Supported | ||
1443 | |||
1434 | CODA FILE SYSTEM | 1444 | CODA FILE SYSTEM |
1435 | P: Jan Harkes | 1445 | P: Jan Harkes |
1436 | M: jaharkes@cs.cmu.edu | 1446 | M: jaharkes@cs.cmu.edu |
@@ -1,8 +1,8 @@ | |||
1 | VERSION = 2 | 1 | VERSION = 2 |
2 | PATCHLEVEL = 6 | 2 | PATCHLEVEL = 6 |
3 | SUBLEVEL = 30 | 3 | SUBLEVEL = 30 |
4 | EXTRAVERSION = -rc6 | 4 | EXTRAVERSION = -rc7 |
5 | NAME = Vindictive Armadillo | 5 | NAME = Man-Eating Seals of Antiquity |
6 | 6 | ||
7 | # *DOCUMENTATION* | 7 | # *DOCUMENTATION* |
8 | # To see a list of typical targets execute "make help" | 8 | # To see a list of typical targets execute "make help" |
diff --git a/arch/arm/mach-gemini/include/mach/hardware.h b/arch/arm/mach-gemini/include/mach/hardware.h index de6752674c05..213a4fcfeb1c 100644 --- a/arch/arm/mach-gemini/include/mach/hardware.h +++ b/arch/arm/mach-gemini/include/mach/hardware.h | |||
@@ -15,10 +15,9 @@ | |||
15 | /* | 15 | /* |
16 | * Memory Map definitions | 16 | * Memory Map definitions |
17 | */ | 17 | */ |
18 | /* FIXME: Does it really swap SRAM like this? */ | ||
19 | #ifdef CONFIG_GEMINI_MEM_SWAP | 18 | #ifdef CONFIG_GEMINI_MEM_SWAP |
20 | # define GEMINI_DRAM_BASE 0x00000000 | 19 | # define GEMINI_DRAM_BASE 0x00000000 |
21 | # define GEMINI_SRAM_BASE 0x20000000 | 20 | # define GEMINI_SRAM_BASE 0x70000000 |
22 | #else | 21 | #else |
23 | # define GEMINI_SRAM_BASE 0x00000000 | 22 | # define GEMINI_SRAM_BASE 0x00000000 |
24 | # define GEMINI_DRAM_BASE 0x10000000 | 23 | # define GEMINI_DRAM_BASE 0x10000000 |
diff --git a/arch/blackfin/include/asm/.gitignore b/arch/blackfin/include/asm/.gitignore deleted file mode 100644 index 7858564a4466..000000000000 --- a/arch/blackfin/include/asm/.gitignore +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | +mach | ||
diff --git a/arch/blackfin/include/asm/unistd.h b/arch/blackfin/include/asm/unistd.h index 1e57b636e0bc..cf5066d3efd2 100644 --- a/arch/blackfin/include/asm/unistd.h +++ b/arch/blackfin/include/asm/unistd.h | |||
@@ -378,8 +378,10 @@ | |||
378 | #define __NR_dup3 363 | 378 | #define __NR_dup3 363 |
379 | #define __NR_pipe2 364 | 379 | #define __NR_pipe2 364 |
380 | #define __NR_inotify_init1 365 | 380 | #define __NR_inotify_init1 365 |
381 | #define __NR_preadv 366 | ||
382 | #define __NR_pwritev 367 | ||
381 | 383 | ||
382 | #define __NR_syscall 366 | 384 | #define __NR_syscall 368 |
383 | #define NR_syscalls __NR_syscall | 385 | #define NR_syscalls __NR_syscall |
384 | 386 | ||
385 | /* Old optional stuff no one actually uses */ | 387 | /* Old optional stuff no one actually uses */ |
diff --git a/arch/blackfin/kernel/.gitignore b/arch/blackfin/kernel/.gitignore new file mode 100644 index 000000000000..c5f676c3c224 --- /dev/null +++ b/arch/blackfin/kernel/.gitignore | |||
@@ -0,0 +1 @@ | |||
vmlinux.lds | |||
diff --git a/arch/blackfin/lib/strncmp.c b/arch/blackfin/lib/strncmp.c index 2aaae78a68e0..46518b1d2983 100644 --- a/arch/blackfin/lib/strncmp.c +++ b/arch/blackfin/lib/strncmp.c | |||
@@ -8,9 +8,8 @@ | |||
8 | 8 | ||
9 | #define strncmp __inline_strncmp | 9 | #define strncmp __inline_strncmp |
10 | #include <asm/string.h> | 10 | #include <asm/string.h> |
11 | #undef strncmp | ||
12 | |||
13 | #include <linux/module.h> | 11 | #include <linux/module.h> |
12 | #undef strncmp | ||
14 | 13 | ||
15 | int strncmp(const char *cs, const char *ct, size_t count) | 14 | int strncmp(const char *cs, const char *ct, size_t count) |
16 | { | 15 | { |
diff --git a/arch/blackfin/mach-common/entry.S b/arch/blackfin/mach-common/entry.S index 21e65a339a22..a063a434f7e3 100644 --- a/arch/blackfin/mach-common/entry.S +++ b/arch/blackfin/mach-common/entry.S | |||
@@ -1581,6 +1581,8 @@ ENTRY(_sys_call_table) | |||
1581 | .long _sys_dup3 | 1581 | .long _sys_dup3 |
1582 | .long _sys_pipe2 | 1582 | .long _sys_pipe2 |
1583 | .long _sys_inotify_init1 /* 365 */ | 1583 | .long _sys_inotify_init1 /* 365 */ |
1584 | .long _sys_preadv | ||
1585 | .long _sys_pwritev | ||
1584 | 1586 | ||
1585 | .rept NR_syscalls-(.-_sys_call_table)/4 | 1587 | .rept NR_syscalls-(.-_sys_call_table)/4 |
1586 | .long _sys_ni_syscall | 1588 | .long _sys_ni_syscall |
diff --git a/arch/powerpc/Kconfig b/arch/powerpc/Kconfig index a0d1146a0578..cdc9a6ff4be8 100644 --- a/arch/powerpc/Kconfig +++ b/arch/powerpc/Kconfig | |||
@@ -868,6 +868,18 @@ config TASK_SIZE | |||
868 | default "0x80000000" if PPC_PREP || PPC_8xx | 868 | default "0x80000000" if PPC_PREP || PPC_8xx |
869 | default "0xc0000000" | 869 | default "0xc0000000" |
870 | 870 | ||
871 | config CONSISTENT_SIZE_BOOL | ||
872 | bool "Set custom consistent memory pool size" | ||
873 | depends on ADVANCED_OPTIONS && NOT_COHERENT_CACHE | ||
874 | help | ||
875 | This option allows you to set the size of the | ||
876 | consistent memory pool. This pool of virtual memory | ||
877 | is used to make consistent memory allocations. | ||
878 | |||
879 | config CONSISTENT_SIZE | ||
880 | hex "Size of consistent memory pool" if CONSISTENT_SIZE_BOOL | ||
881 | default "0x00200000" if NOT_COHERENT_CACHE | ||
882 | |||
871 | config PIN_TLB | 883 | config PIN_TLB |
872 | bool "Pinned Kernel TLBs (860 ONLY)" | 884 | bool "Pinned Kernel TLBs (860 ONLY)" |
873 | depends on ADVANCED_OPTIONS && 8xx | 885 | depends on ADVANCED_OPTIONS && 8xx |
diff --git a/arch/powerpc/include/asm/dma-mapping.h b/arch/powerpc/include/asm/dma-mapping.h index c69f2b5f0cc4..cb448d68452c 100644 --- a/arch/powerpc/include/asm/dma-mapping.h +++ b/arch/powerpc/include/asm/dma-mapping.h | |||
@@ -26,7 +26,9 @@ | |||
26 | * allocate the space "normally" and use the cache management functions | 26 | * allocate the space "normally" and use the cache management functions |
27 | * to ensure it is consistent. | 27 | * to ensure it is consistent. |
28 | */ | 28 | */ |
29 | extern void *__dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp); | 29 | struct device; |
30 | extern void *__dma_alloc_coherent(struct device *dev, size_t size, | ||
31 | dma_addr_t *handle, gfp_t gfp); | ||
30 | extern void __dma_free_coherent(size_t size, void *vaddr); | 32 | extern void __dma_free_coherent(size_t size, void *vaddr); |
31 | extern void __dma_sync(void *vaddr, size_t size, int direction); | 33 | extern void __dma_sync(void *vaddr, size_t size, int direction); |
32 | extern void __dma_sync_page(struct page *page, unsigned long offset, | 34 | extern void __dma_sync_page(struct page *page, unsigned long offset, |
@@ -37,7 +39,7 @@ extern void __dma_sync_page(struct page *page, unsigned long offset, | |||
37 | * Cache coherent cores. | 39 | * Cache coherent cores. |
38 | */ | 40 | */ |
39 | 41 | ||
40 | #define __dma_alloc_coherent(gfp, size, handle) NULL | 42 | #define __dma_alloc_coherent(dev, gfp, size, handle) NULL |
41 | #define __dma_free_coherent(size, addr) ((void)0) | 43 | #define __dma_free_coherent(size, addr) ((void)0) |
42 | #define __dma_sync(addr, size, rw) ((void)0) | 44 | #define __dma_sync(addr, size, rw) ((void)0) |
43 | #define __dma_sync_page(pg, off, sz, rw) ((void)0) | 45 | #define __dma_sync_page(pg, off, sz, rw) ((void)0) |
diff --git a/arch/powerpc/include/asm/fixmap.h b/arch/powerpc/include/asm/fixmap.h index d60fd18f428c..f1f4e23a84e9 100644 --- a/arch/powerpc/include/asm/fixmap.h +++ b/arch/powerpc/include/asm/fixmap.h | |||
@@ -14,8 +14,6 @@ | |||
14 | #ifndef _ASM_FIXMAP_H | 14 | #ifndef _ASM_FIXMAP_H |
15 | #define _ASM_FIXMAP_H | 15 | #define _ASM_FIXMAP_H |
16 | 16 | ||
17 | extern unsigned long FIXADDR_TOP; | ||
18 | |||
19 | #ifndef __ASSEMBLY__ | 17 | #ifndef __ASSEMBLY__ |
20 | #include <linux/kernel.h> | 18 | #include <linux/kernel.h> |
21 | #include <asm/page.h> | 19 | #include <asm/page.h> |
@@ -24,6 +22,8 @@ extern unsigned long FIXADDR_TOP; | |||
24 | #include <asm/kmap_types.h> | 22 | #include <asm/kmap_types.h> |
25 | #endif | 23 | #endif |
26 | 24 | ||
25 | #define FIXADDR_TOP ((unsigned long)(-PAGE_SIZE)) | ||
26 | |||
27 | /* | 27 | /* |
28 | * Here we define all the compile-time 'special' virtual | 28 | * Here we define all the compile-time 'special' virtual |
29 | * addresses. The point is to have a constant address at | 29 | * addresses. The point is to have a constant address at |
diff --git a/arch/powerpc/include/asm/pgtable-ppc32.h b/arch/powerpc/include/asm/pgtable-ppc32.h index ba45c997830f..c9ff9d75990e 100644 --- a/arch/powerpc/include/asm/pgtable-ppc32.h +++ b/arch/powerpc/include/asm/pgtable-ppc32.h | |||
@@ -10,7 +10,7 @@ | |||
10 | 10 | ||
11 | extern unsigned long va_to_phys(unsigned long address); | 11 | extern unsigned long va_to_phys(unsigned long address); |
12 | extern pte_t *va_to_pte(unsigned long address); | 12 | extern pte_t *va_to_pte(unsigned long address); |
13 | extern unsigned long ioremap_bot, ioremap_base; | 13 | extern unsigned long ioremap_bot; |
14 | 14 | ||
15 | #ifdef CONFIG_44x | 15 | #ifdef CONFIG_44x |
16 | extern int icache_44x_need_flush; | 16 | extern int icache_44x_need_flush; |
@@ -56,8 +56,30 @@ extern int icache_44x_need_flush; | |||
56 | printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) | 56 | printk("%s:%d: bad pgd %08lx.\n", __FILE__, __LINE__, pgd_val(e)) |
57 | 57 | ||
58 | /* | 58 | /* |
59 | * This is the bottom of the PKMAP area with HIGHMEM or an arbitrary | ||
60 | * value (for now) on others, from where we can start layout kernel | ||
61 | * virtual space that goes below PKMAP and FIXMAP | ||
62 | */ | ||
63 | #ifdef CONFIG_HIGHMEM | ||
64 | #define KVIRT_TOP PKMAP_BASE | ||
65 | #else | ||
66 | #define KVIRT_TOP (0xfe000000UL) /* for now, could be FIXMAP_BASE ? */ | ||
67 | #endif | ||
68 | |||
69 | /* | ||
70 | * ioremap_bot starts at that address. Early ioremaps move down from there, | ||
71 | * until mem_init() at which point this becomes the top of the vmalloc | ||
72 | * and ioremap space | ||
73 | */ | ||
74 | #ifdef CONFIG_NOT_COHERENT_CACHE | ||
75 | #define IOREMAP_TOP ((KVIRT_TOP - CONFIG_CONSISTENT_SIZE) & PAGE_MASK) | ||
76 | #else | ||
77 | #define IOREMAP_TOP KVIRT_TOP | ||
78 | #endif | ||
79 | |||
80 | /* | ||
59 | * Just any arbitrary offset to the start of the vmalloc VM area: the | 81 | * Just any arbitrary offset to the start of the vmalloc VM area: the |
60 | * current 64MB value just means that there will be a 64MB "hole" after the | 82 | * current 16MB value just means that there will be a 64MB "hole" after the |
61 | * physical memory until the kernel virtual memory starts. That means that | 83 | * physical memory until the kernel virtual memory starts. That means that |
62 | * any out-of-bounds memory accesses will hopefully be caught. | 84 | * any out-of-bounds memory accesses will hopefully be caught. |
63 | * The vmalloc() routines leaves a hole of 4kB between each vmalloced | 85 | * The vmalloc() routines leaves a hole of 4kB between each vmalloced |
diff --git a/arch/powerpc/kernel/dma.c b/arch/powerpc/kernel/dma.c index 53c7788cba78..6b02793dc75b 100644 --- a/arch/powerpc/kernel/dma.c +++ b/arch/powerpc/kernel/dma.c | |||
@@ -32,7 +32,7 @@ void *dma_direct_alloc_coherent(struct device *dev, size_t size, | |||
32 | { | 32 | { |
33 | void *ret; | 33 | void *ret; |
34 | #ifdef CONFIG_NOT_COHERENT_CACHE | 34 | #ifdef CONFIG_NOT_COHERENT_CACHE |
35 | ret = __dma_alloc_coherent(size, dma_handle, flag); | 35 | ret = __dma_alloc_coherent(dev, size, dma_handle, flag); |
36 | if (ret == NULL) | 36 | if (ret == NULL) |
37 | return NULL; | 37 | return NULL; |
38 | *dma_handle += get_dma_direct_offset(dev); | 38 | *dma_handle += get_dma_direct_offset(dev); |
diff --git a/arch/powerpc/lib/Makefile b/arch/powerpc/lib/Makefile index 8db35278a4b4..29b742b90f1f 100644 --- a/arch/powerpc/lib/Makefile +++ b/arch/powerpc/lib/Makefile | |||
@@ -18,7 +18,6 @@ obj-$(CONFIG_PPC64) += copypage_64.o copyuser_64.o \ | |||
18 | memcpy_64.o usercopy_64.o mem_64.o string.o | 18 | memcpy_64.o usercopy_64.o mem_64.o string.o |
19 | obj-$(CONFIG_XMON) += sstep.o | 19 | obj-$(CONFIG_XMON) += sstep.o |
20 | obj-$(CONFIG_KPROBES) += sstep.o | 20 | obj-$(CONFIG_KPROBES) += sstep.o |
21 | obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o | ||
22 | 21 | ||
23 | ifeq ($(CONFIG_PPC64),y) | 22 | ifeq ($(CONFIG_PPC64),y) |
24 | obj-$(CONFIG_SMP) += locks.o | 23 | obj-$(CONFIG_SMP) += locks.o |
diff --git a/arch/powerpc/lib/dma-noncoherent.c b/arch/powerpc/lib/dma-noncoherent.c deleted file mode 100644 index 005a28d380af..000000000000 --- a/arch/powerpc/lib/dma-noncoherent.c +++ /dev/null | |||
@@ -1,237 +0,0 @@ | |||
1 | /* | ||
2 | * PowerPC version derived from arch/arm/mm/consistent.c | ||
3 | * Copyright (C) 2001 Dan Malek (dmalek@jlc.net) | ||
4 | * | ||
5 | * Copyright (C) 2000 Russell King | ||
6 | * | ||
7 | * Consistent memory allocators. Used for DMA devices that want to | ||
8 | * share uncached memory with the processor core. The function return | ||
9 | * is the virtual address and 'dma_handle' is the physical address. | ||
10 | * Mostly stolen from the ARM port, with some changes for PowerPC. | ||
11 | * -- Dan | ||
12 | * | ||
13 | * Reorganized to get rid of the arch-specific consistent_* functions | ||
14 | * and provide non-coherent implementations for the DMA API. -Matt | ||
15 | * | ||
16 | * Added in_interrupt() safe dma_alloc_coherent()/dma_free_coherent() | ||
17 | * implementation. This is pulled straight from ARM and barely | ||
18 | * modified. -Matt | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or modify | ||
21 | * it under the terms of the GNU General Public License version 2 as | ||
22 | * published by the Free Software Foundation. | ||
23 | */ | ||
24 | |||
25 | #include <linux/sched.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/string.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/highmem.h> | ||
31 | #include <linux/dma-mapping.h> | ||
32 | #include <linux/vmalloc.h> | ||
33 | |||
34 | #include <asm/tlbflush.h> | ||
35 | |||
36 | /* | ||
37 | * Allocate DMA-coherent memory space and return both the kernel remapped | ||
38 | * virtual and bus address for that space. | ||
39 | */ | ||
40 | void * | ||
41 | __dma_alloc_coherent(size_t size, dma_addr_t *handle, gfp_t gfp) | ||
42 | { | ||
43 | struct page *page; | ||
44 | unsigned long order; | ||
45 | int i; | ||
46 | unsigned int nr_pages = PAGE_ALIGN(size)>>PAGE_SHIFT; | ||
47 | unsigned int array_size = nr_pages * sizeof(struct page *); | ||
48 | struct page **pages; | ||
49 | struct page *end; | ||
50 | u64 mask = 0x00ffffff, limit; /* ISA default */ | ||
51 | struct vm_struct *area; | ||
52 | |||
53 | BUG_ON(!mem_init_done); | ||
54 | size = PAGE_ALIGN(size); | ||
55 | limit = (mask + 1) & ~mask; | ||
56 | if (limit && size >= limit) { | ||
57 | printk(KERN_WARNING "coherent allocation too big (requested " | ||
58 | "%#x mask %#Lx)\n", size, mask); | ||
59 | return NULL; | ||
60 | } | ||
61 | |||
62 | order = get_order(size); | ||
63 | |||
64 | if (mask != 0xffffffff) | ||
65 | gfp |= GFP_DMA; | ||
66 | |||
67 | page = alloc_pages(gfp, order); | ||
68 | if (!page) | ||
69 | goto no_page; | ||
70 | |||
71 | end = page + (1 << order); | ||
72 | |||
73 | /* | ||
74 | * Invalidate any data that might be lurking in the | ||
75 | * kernel direct-mapped region for device DMA. | ||
76 | */ | ||
77 | { | ||
78 | unsigned long kaddr = (unsigned long)page_address(page); | ||
79 | memset(page_address(page), 0, size); | ||
80 | flush_dcache_range(kaddr, kaddr + size); | ||
81 | } | ||
82 | |||
83 | split_page(page, order); | ||
84 | |||
85 | /* | ||
86 | * Set the "dma handle" | ||
87 | */ | ||
88 | *handle = page_to_phys(page); | ||
89 | |||
90 | area = get_vm_area_caller(size, VM_IOREMAP, | ||
91 | __builtin_return_address(1)); | ||
92 | if (!area) | ||
93 | goto out_free_pages; | ||
94 | |||
95 | if (array_size > PAGE_SIZE) { | ||
96 | pages = vmalloc(array_size); | ||
97 | area->flags |= VM_VPAGES; | ||
98 | } else { | ||
99 | pages = kmalloc(array_size, GFP_KERNEL); | ||
100 | } | ||
101 | if (!pages) | ||
102 | goto out_free_area; | ||
103 | |||
104 | area->pages = pages; | ||
105 | area->nr_pages = nr_pages; | ||
106 | |||
107 | for (i = 0; i < nr_pages; i++) | ||
108 | pages[i] = page + i; | ||
109 | |||
110 | if (map_vm_area(area, pgprot_noncached(PAGE_KERNEL), &pages)) | ||
111 | goto out_unmap; | ||
112 | |||
113 | /* | ||
114 | * Free the otherwise unused pages. | ||
115 | */ | ||
116 | page += nr_pages; | ||
117 | while (page < end) { | ||
118 | __free_page(page); | ||
119 | page++; | ||
120 | } | ||
121 | |||
122 | return area->addr; | ||
123 | out_unmap: | ||
124 | vunmap(area->addr); | ||
125 | if (array_size > PAGE_SIZE) | ||
126 | vfree(pages); | ||
127 | else | ||
128 | kfree(pages); | ||
129 | goto out_free_pages; | ||
130 | out_free_area: | ||
131 | free_vm_area(area); | ||
132 | out_free_pages: | ||
133 | if (page) | ||
134 | __free_pages(page, order); | ||
135 | no_page: | ||
136 | return NULL; | ||
137 | } | ||
138 | EXPORT_SYMBOL(__dma_alloc_coherent); | ||
139 | |||
140 | /* | ||
141 | * free a page as defined by the above mapping. | ||
142 | */ | ||
143 | void __dma_free_coherent(size_t size, void *vaddr) | ||
144 | { | ||
145 | vfree(vaddr); | ||
146 | |||
147 | } | ||
148 | EXPORT_SYMBOL(__dma_free_coherent); | ||
149 | |||
150 | /* | ||
151 | * make an area consistent. | ||
152 | */ | ||
153 | void __dma_sync(void *vaddr, size_t size, int direction) | ||
154 | { | ||
155 | unsigned long start = (unsigned long)vaddr; | ||
156 | unsigned long end = start + size; | ||
157 | |||
158 | switch (direction) { | ||
159 | case DMA_NONE: | ||
160 | BUG(); | ||
161 | case DMA_FROM_DEVICE: | ||
162 | /* | ||
163 | * invalidate only when cache-line aligned otherwise there is | ||
164 | * the potential for discarding uncommitted data from the cache | ||
165 | */ | ||
166 | if ((start & (L1_CACHE_BYTES - 1)) || (size & (L1_CACHE_BYTES - 1))) | ||
167 | flush_dcache_range(start, end); | ||
168 | else | ||
169 | invalidate_dcache_range(start, end); | ||
170 | break; | ||
171 | case DMA_TO_DEVICE: /* writeback only */ | ||
172 | clean_dcache_range(start, end); | ||
173 | break; | ||
174 | case DMA_BIDIRECTIONAL: /* writeback and invalidate */ | ||
175 | flush_dcache_range(start, end); | ||
176 | break; | ||
177 | } | ||
178 | } | ||
179 | EXPORT_SYMBOL(__dma_sync); | ||
180 | |||
181 | #ifdef CONFIG_HIGHMEM | ||
182 | /* | ||
183 | * __dma_sync_page() implementation for systems using highmem. | ||
184 | * In this case, each page of a buffer must be kmapped/kunmapped | ||
185 | * in order to have a virtual address for __dma_sync(). This must | ||
186 | * not sleep so kmap_atomic()/kunmap_atomic() are used. | ||
187 | * | ||
188 | * Note: yes, it is possible and correct to have a buffer extend | ||
189 | * beyond the first page. | ||
190 | */ | ||
191 | static inline void __dma_sync_page_highmem(struct page *page, | ||
192 | unsigned long offset, size_t size, int direction) | ||
193 | { | ||
194 | size_t seg_size = min((size_t)(PAGE_SIZE - offset), size); | ||
195 | size_t cur_size = seg_size; | ||
196 | unsigned long flags, start, seg_offset = offset; | ||
197 | int nr_segs = 1 + ((size - seg_size) + PAGE_SIZE - 1)/PAGE_SIZE; | ||
198 | int seg_nr = 0; | ||
199 | |||
200 | local_irq_save(flags); | ||
201 | |||
202 | do { | ||
203 | start = (unsigned long)kmap_atomic(page + seg_nr, | ||
204 | KM_PPC_SYNC_PAGE) + seg_offset; | ||
205 | |||
206 | /* Sync this buffer segment */ | ||
207 | __dma_sync((void *)start, seg_size, direction); | ||
208 | kunmap_atomic((void *)start, KM_PPC_SYNC_PAGE); | ||
209 | seg_nr++; | ||
210 | |||
211 | /* Calculate next buffer segment size */ | ||
212 | seg_size = min((size_t)PAGE_SIZE, size - cur_size); | ||
213 | |||
214 | /* Add the segment size to our running total */ | ||
215 | cur_size += seg_size; | ||
216 | seg_offset = 0; | ||
217 | } while (seg_nr < nr_segs); | ||
218 | |||
219 | local_irq_restore(flags); | ||
220 | } | ||
221 | #endif /* CONFIG_HIGHMEM */ | ||
222 | |||
223 | /* | ||
224 | * __dma_sync_page makes memory consistent. identical to __dma_sync, but | ||
225 | * takes a struct page instead of a virtual address | ||
226 | */ | ||
227 | void __dma_sync_page(struct page *page, unsigned long offset, | ||
228 | size_t size, int direction) | ||
229 | { | ||
230 | #ifdef CONFIG_HIGHMEM | ||
231 | __dma_sync_page_highmem(page, offset, size, direction); | ||
232 | #else | ||
233 | unsigned long start = (unsigned long)page_address(page) + offset; | ||
234 | __dma_sync((void *)start, size, direction); | ||
235 | #endif | ||
236 | } | ||
237 | EXPORT_SYMBOL(__dma_sync_page); | ||
diff --git a/arch/powerpc/mm/Makefile b/arch/powerpc/mm/Makefile index 17290bcedc5e..b746f4ca4209 100644 --- a/arch/powerpc/mm/Makefile +++ b/arch/powerpc/mm/Makefile | |||
@@ -26,3 +26,4 @@ obj-$(CONFIG_NEED_MULTIPLE_NODES) += numa.o | |||
26 | obj-$(CONFIG_PPC_MM_SLICES) += slice.o | 26 | obj-$(CONFIG_PPC_MM_SLICES) += slice.o |
27 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o | 27 | obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o |
28 | obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o | 28 | obj-$(CONFIG_PPC_SUBPAGE_PROT) += subpage-prot.o |
29 | obj-$(CONFIG_NOT_COHERENT_CACHE) += dma-noncoherent.o | ||
diff --git a/arch/powerpc/mm/dma-noncoherent.c b/arch/powerpc/mm/dma-noncoherent.c new file mode 100644 index 000000000000..36692f5c9a76 --- /dev/null +++ b/arch/powerpc/mm/dma-noncoherent.c | |||
@@ -0,0 +1,400 @@ | |||
1 | /* | ||
2 | * PowerPC version derived from arch/arm/mm/consistent.c | ||
3 | * Copyright (C) 2001 Dan Malek (dmalek@jlc.net) | ||
4 | * | ||
5 | * Copyright (C) 2000 Russell King | ||
6 | * | ||
7 | * Consistent memory allocators. Used for DMA devices that want to | ||
8 | * share uncached memory with the processor core. The function return | ||
9 | * is the virtual address and 'dma_handle' is the physical address. | ||
10 | * Mostly stolen from the ARM port, with some changes for PowerPC. | ||
11 | * -- Dan | ||
12 | * | ||
13 | * Reorganized to get rid of the arch-specific consistent_* functions | ||
14 | * and provide non-coherent implementations for the DMA API. -Matt | ||
15 | * | ||
16 | * Added in_interrupt() safe dma_alloc_coherent()/dma_free_coherent() | ||
17 | * implementation. This is pulled straight from ARM and barely | ||
18 | * modified. -Matt | ||
19 | * | ||
20 | * This program is free software; you can redistribute it and/or modify | ||
21 | * it under the terms of the GNU General Public License version 2 as | ||
22 | * published by the Free Software Foundation. | ||
23 | */ | ||
24 | |||
25 | #include <linux/sched.h> | ||
26 | #include <linux/kernel.h> | ||
27 | #include <linux/errno.h> | ||
28 | #include <linux/string.h> | ||
29 | #include <linux/types.h> | ||
30 | #include <linux/highmem.h> | ||
31 | #include <linux/dma-mapping.h> | ||
32 | |||
33 | #include <asm/tlbflush.h> | ||
34 | |||
35 | #include "mmu_decl.h" | ||
36 | |||
37 | /* | ||
38 | * This address range defaults to a value that is safe for all | ||
39 | * platforms which currently set CONFIG_NOT_COHERENT_CACHE. It | ||
40 | * can be further configured for specific applications under | ||
41 | * the "Advanced Setup" menu. -Matt | ||
42 | */ | ||
43 | #define CONSISTENT_BASE (IOREMAP_TOP) | ||
44 | #define CONSISTENT_END (CONSISTENT_BASE + CONFIG_CONSISTENT_SIZE) | ||
45 | #define CONSISTENT_OFFSET(x) (((unsigned long)(x) - CONSISTENT_BASE) >> PAGE_SHIFT) | ||
46 | |||
47 | /* | ||
48 | * This is the page table (2MB) covering uncached, DMA consistent allocations | ||
49 | */ | ||
50 | static DEFINE_SPINLOCK(consistent_lock); | ||
51 | |||
52 | /* | ||
53 | * VM region handling support. | ||
54 | * | ||
55 | * This should become something generic, handling VM region allocations for | ||
56 | * vmalloc and similar (ioremap, module space, etc). | ||
57 | * | ||
58 | * I envisage vmalloc()'s supporting vm_struct becoming: | ||
59 | * | ||
60 | * struct vm_struct { | ||
61 | * struct vm_region region; | ||
62 | * unsigned long flags; | ||
63 | * struct page **pages; | ||
64 | * unsigned int nr_pages; | ||
65 | * unsigned long phys_addr; | ||
66 | * }; | ||
67 | * | ||
68 | * get_vm_area() would then call vm_region_alloc with an appropriate | ||
69 | * struct vm_region head (eg): | ||
70 | * | ||
71 | * struct vm_region vmalloc_head = { | ||
72 | * .vm_list = LIST_HEAD_INIT(vmalloc_head.vm_list), | ||
73 | * .vm_start = VMALLOC_START, | ||
74 | * .vm_end = VMALLOC_END, | ||
75 | * }; | ||
76 | * | ||
77 | * However, vmalloc_head.vm_start is variable (typically, it is dependent on | ||
78 | * the amount of RAM found at boot time.) I would imagine that get_vm_area() | ||
79 | * would have to initialise this each time prior to calling vm_region_alloc(). | ||
80 | */ | ||
81 | struct ppc_vm_region { | ||
82 | struct list_head vm_list; | ||
83 | unsigned long vm_start; | ||
84 | unsigned long vm_end; | ||
85 | }; | ||
86 | |||
87 | static struct ppc_vm_region consistent_head = { | ||
88 | .vm_list = LIST_HEAD_INIT(consistent_head.vm_list), | ||
89 | .vm_start = CONSISTENT_BASE, | ||
90 | .vm_end = CONSISTENT_END, | ||
91 | }; | ||
92 | |||
93 | static struct ppc_vm_region * | ||
94 | ppc_vm_region_alloc(struct ppc_vm_region *head, size_t size, gfp_t gfp) | ||
95 | { | ||
96 | unsigned long addr = head->vm_start, end = head->vm_end - size; | ||
97 | unsigned long flags; | ||
98 | struct ppc_vm_region *c, *new; | ||
99 | |||
100 | new = kmalloc(sizeof(struct ppc_vm_region), gfp); | ||
101 | if (!new) | ||
102 | goto out; | ||
103 | |||
104 | spin_lock_irqsave(&consistent_lock, flags); | ||
105 | |||
106 | list_for_each_entry(c, &head->vm_list, vm_list) { | ||
107 | if ((addr + size) < addr) | ||
108 | goto nospc; | ||
109 | if ((addr + size) <= c->vm_start) | ||
110 | goto found; | ||
111 | addr = c->vm_end; | ||
112 | if (addr > end) | ||
113 | goto nospc; | ||
114 | } | ||
115 | |||
116 | found: | ||
117 | /* | ||
118 | * Insert this entry _before_ the one we found. | ||
119 | */ | ||
120 | list_add_tail(&new->vm_list, &c->vm_list); | ||
121 | new->vm_start = addr; | ||
122 | new->vm_end = addr + size; | ||
123 | |||
124 | spin_unlock_irqrestore(&consistent_lock, flags); | ||
125 | return new; | ||
126 | |||
127 | nospc: | ||
128 | spin_unlock_irqrestore(&consistent_lock, flags); | ||
129 | kfree(new); | ||
130 | out: | ||
131 | return NULL; | ||
132 | } | ||
133 | |||
134 | static struct ppc_vm_region *ppc_vm_region_find(struct ppc_vm_region *head, unsigned long addr) | ||
135 | { | ||
136 | struct ppc_vm_region *c; | ||
137 | |||
138 | list_for_each_entry(c, &head->vm_list, vm_list) { | ||
139 | if (c->vm_start == addr) | ||
140 | goto out; | ||
141 | } | ||
142 | c = NULL; | ||
143 | out: | ||
144 | return c; | ||
145 | } | ||
146 | |||
147 | /* | ||
148 | * Allocate DMA-coherent memory space and return both the kernel remapped | ||
149 | * virtual and bus address for that space. | ||
150 | */ | ||
151 | void * | ||
152 | __dma_alloc_coherent(struct device *dev, size_t size, dma_addr_t *handle, gfp_t gfp) | ||
153 | { | ||
154 | struct page *page; | ||
155 | struct ppc_vm_region *c; | ||
156 | unsigned long order; | ||
157 | u64 mask = ISA_DMA_THRESHOLD, limit; | ||
158 | |||
159 | if (dev) { | ||
160 | mask = dev->coherent_dma_mask; | ||
161 | |||
162 | /* | ||
163 | * Sanity check the DMA mask - it must be non-zero, and | ||
164 | * must be able to be satisfied by a DMA allocation. | ||
165 | */ | ||
166 | if (mask == 0) { | ||
167 | dev_warn(dev, "coherent DMA mask is unset\n"); | ||
168 | goto no_page; | ||
169 | } | ||
170 | |||
171 | if ((~mask) & ISA_DMA_THRESHOLD) { | ||
172 | dev_warn(dev, "coherent DMA mask %#llx is smaller " | ||
173 | "than system GFP_DMA mask %#llx\n", | ||
174 | mask, (unsigned long long)ISA_DMA_THRESHOLD); | ||
175 | goto no_page; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | |||
180 | size = PAGE_ALIGN(size); | ||
181 | limit = (mask + 1) & ~mask; | ||
182 | if ((limit && size >= limit) || | ||
183 | size >= (CONSISTENT_END - CONSISTENT_BASE)) { | ||
184 | printk(KERN_WARNING "coherent allocation too big (requested %#x mask %#Lx)\n", | ||
185 | size, mask); | ||
186 | return NULL; | ||
187 | } | ||
188 | |||
189 | order = get_order(size); | ||
190 | |||
191 | /* Might be useful if we ever have a real legacy DMA zone... */ | ||
192 | if (mask != 0xffffffff) | ||
193 | gfp |= GFP_DMA; | ||
194 | |||
195 | page = alloc_pages(gfp, order); | ||
196 | if (!page) | ||
197 | goto no_page; | ||
198 | |||
199 | /* | ||
200 | * Invalidate any data that might be lurking in the | ||
201 | * kernel direct-mapped region for device DMA. | ||
202 | */ | ||
203 | { | ||
204 | unsigned long kaddr = (unsigned long)page_address(page); | ||
205 | memset(page_address(page), 0, size); | ||
206 | flush_dcache_range(kaddr, kaddr + size); | ||
207 | } | ||
208 | |||
209 | /* | ||
210 | * Allocate a virtual address in the consistent mapping region. | ||
211 | */ | ||
212 | c = ppc_vm_region_alloc(&consistent_head, size, | ||
213 | gfp & ~(__GFP_DMA | __GFP_HIGHMEM)); | ||
214 | if (c) { | ||
215 | unsigned long vaddr = c->vm_start; | ||
216 | struct page *end = page + (1 << order); | ||
217 | |||
218 | split_page(page, order); | ||
219 | |||
220 | /* | ||
221 | * Set the "dma handle" | ||
222 | */ | ||
223 | *handle = page_to_phys(page); | ||
224 | |||
225 | do { | ||
226 | SetPageReserved(page); | ||
227 | map_page(vaddr, page_to_phys(page), | ||
228 | pgprot_noncached(PAGE_KERNEL)); | ||
229 | page++; | ||
230 | vaddr += PAGE_SIZE; | ||
231 | } while (size -= PAGE_SIZE); | ||
232 | |||
233 | /* | ||
234 | * Free the otherwise unused pages. | ||
235 | */ | ||
236 | while (page < end) { | ||
237 | __free_page(page); | ||
238 | page++; | ||
239 | } | ||
240 | |||
241 | return (void *)c->vm_start; | ||
242 | } | ||
243 | |||
244 | if (page) | ||
245 | __free_pages(page, order); | ||
246 | no_page: | ||
247 | return NULL; | ||
248 | } | ||
249 | EXPORT_SYMBOL(__dma_alloc_coherent); | ||
250 | |||
251 | /* | ||
252 | * free a page as defined by the above mapping. | ||
253 | */ | ||
254 | void __dma_free_coherent(size_t size, void *vaddr) | ||
255 | { | ||
256 | struct ppc_vm_region *c; | ||
257 | unsigned long flags, addr; | ||
258 | |||
259 | size = PAGE_ALIGN(size); | ||
260 | |||
261 | spin_lock_irqsave(&consistent_lock, flags); | ||
262 | |||
263 | c = ppc_vm_region_find(&consistent_head, (unsigned long)vaddr); | ||
264 | if (!c) | ||
265 | goto no_area; | ||
266 | |||
267 | if ((c->vm_end - c->vm_start) != size) { | ||
268 | printk(KERN_ERR "%s: freeing wrong coherent size (%ld != %d)\n", | ||
269 | __func__, c->vm_end - c->vm_start, size); | ||
270 | dump_stack(); | ||
271 | size = c->vm_end - c->vm_start; | ||
272 | } | ||
273 | |||
274 | addr = c->vm_start; | ||
275 | do { | ||
276 | pte_t *ptep; | ||
277 | unsigned long pfn; | ||
278 | |||
279 | ptep = pte_offset_kernel(pmd_offset(pud_offset(pgd_offset_k(addr), | ||
280 | addr), | ||
281 | addr), | ||
282 | addr); | ||
283 | if (!pte_none(*ptep) && pte_present(*ptep)) { | ||
284 | pfn = pte_pfn(*ptep); | ||
285 | pte_clear(&init_mm, addr, ptep); | ||
286 | if (pfn_valid(pfn)) { | ||
287 | struct page *page = pfn_to_page(pfn); | ||
288 | |||
289 | ClearPageReserved(page); | ||
290 | __free_page(page); | ||
291 | } | ||
292 | } | ||
293 | addr += PAGE_SIZE; | ||
294 | } while (size -= PAGE_SIZE); | ||
295 | |||
296 | flush_tlb_kernel_range(c->vm_start, c->vm_end); | ||
297 | |||
298 | list_del(&c->vm_list); | ||
299 | |||
300 | spin_unlock_irqrestore(&consistent_lock, flags); | ||
301 | |||
302 | kfree(c); | ||
303 | return; | ||
304 | |||
305 | no_area: | ||
306 | spin_unlock_irqrestore(&consistent_lock, flags); | ||
307 | printk(KERN_ERR "%s: trying to free invalid coherent area: %p\n", | ||
308 | __func__, vaddr); | ||
309 | dump_stack(); | ||
310 | } | ||
311 | EXPORT_SYMBOL(__dma_free_coherent); | ||
312 | |||
313 | /* | ||
314 | * make an area consistent. | ||
315 | */ | ||
316 | void __dma_sync(void *vaddr, size_t size, int direction) | ||
317 | { | ||
318 | unsigned long start = (unsigned long)vaddr; | ||
319 | unsigned long end = start + size; | ||
320 | |||
321 | switch (direction) { | ||
322 | case DMA_NONE: | ||
323 | BUG(); | ||
324 | case DMA_FROM_DEVICE: | ||
325 | /* | ||
326 | * invalidate only when cache-line aligned otherwise there is | ||
327 | * the potential for discarding uncommitted data from the cache | ||
328 | */ | ||
329 | if ((start & (L1_CACHE_BYTES - 1)) || (size & (L1_CACHE_BYTES - 1))) | ||
330 | flush_dcache_range(start, end); | ||
331 | else | ||
332 | invalidate_dcache_range(start, end); | ||
333 | break; | ||
334 | case DMA_TO_DEVICE: /* writeback only */ | ||
335 | clean_dcache_range(start, end); | ||
336 | break; | ||
337 | case DMA_BIDIRECTIONAL: /* writeback and invalidate */ | ||
338 | flush_dcache_range(start, end); | ||
339 | break; | ||
340 | } | ||
341 | } | ||
342 | EXPORT_SYMBOL(__dma_sync); | ||
343 | |||
344 | #ifdef CONFIG_HIGHMEM | ||
345 | /* | ||
346 | * __dma_sync_page() implementation for systems using highmem. | ||
347 | * In this case, each page of a buffer must be kmapped/kunmapped | ||
348 | * in order to have a virtual address for __dma_sync(). This must | ||
349 | * not sleep so kmap_atomic()/kunmap_atomic() are used. | ||
350 | * | ||
351 | * Note: yes, it is possible and correct to have a buffer extend | ||
352 | * beyond the first page. | ||
353 | */ | ||
354 | static inline void __dma_sync_page_highmem(struct page *page, | ||
355 | unsigned long offset, size_t size, int direction) | ||
356 | { | ||
357 | size_t seg_size = min((size_t)(PAGE_SIZE - offset), size); | ||
358 | size_t cur_size = seg_size; | ||
359 | unsigned long flags, start, seg_offset = offset; | ||
360 | int nr_segs = 1 + ((size - seg_size) + PAGE_SIZE - 1)/PAGE_SIZE; | ||
361 | int seg_nr = 0; | ||
362 | |||
363 | local_irq_save(flags); | ||
364 | |||
365 | do { | ||
366 | start = (unsigned long)kmap_atomic(page + seg_nr, | ||
367 | KM_PPC_SYNC_PAGE) + seg_offset; | ||
368 | |||
369 | /* Sync this buffer segment */ | ||
370 | __dma_sync((void *)start, seg_size, direction); | ||
371 | kunmap_atomic((void *)start, KM_PPC_SYNC_PAGE); | ||
372 | seg_nr++; | ||
373 | |||
374 | /* Calculate next buffer segment size */ | ||
375 | seg_size = min((size_t)PAGE_SIZE, size - cur_size); | ||
376 | |||
377 | /* Add the segment size to our running total */ | ||
378 | cur_size += seg_size; | ||
379 | seg_offset = 0; | ||
380 | } while (seg_nr < nr_segs); | ||
381 | |||
382 | local_irq_restore(flags); | ||
383 | } | ||
384 | #endif /* CONFIG_HIGHMEM */ | ||
385 | |||
386 | /* | ||
387 | * __dma_sync_page makes memory consistent. identical to __dma_sync, but | ||
388 | * takes a struct page instead of a virtual address | ||
389 | */ | ||
390 | void __dma_sync_page(struct page *page, unsigned long offset, | ||
391 | size_t size, int direction) | ||
392 | { | ||
393 | #ifdef CONFIG_HIGHMEM | ||
394 | __dma_sync_page_highmem(page, offset, size, direction); | ||
395 | #else | ||
396 | unsigned long start = (unsigned long)page_address(page) + offset; | ||
397 | __dma_sync((void *)start, size, direction); | ||
398 | #endif | ||
399 | } | ||
400 | EXPORT_SYMBOL(__dma_sync_page); | ||
diff --git a/arch/powerpc/mm/init_32.c b/arch/powerpc/mm/init_32.c index 666a5e8a5be1..3de6a0d93824 100644 --- a/arch/powerpc/mm/init_32.c +++ b/arch/powerpc/mm/init_32.c | |||
@@ -168,12 +168,8 @@ void __init MMU_init(void) | |||
168 | ppc_md.progress("MMU:mapin", 0x301); | 168 | ppc_md.progress("MMU:mapin", 0x301); |
169 | mapin_ram(); | 169 | mapin_ram(); |
170 | 170 | ||
171 | #ifdef CONFIG_HIGHMEM | 171 | /* Initialize early top-down ioremap allocator */ |
172 | ioremap_base = PKMAP_BASE; | 172 | ioremap_bot = IOREMAP_TOP; |
173 | #else | ||
174 | ioremap_base = 0xfe000000UL; /* for now, could be 0xfffff000 */ | ||
175 | #endif /* CONFIG_HIGHMEM */ | ||
176 | ioremap_bot = ioremap_base; | ||
177 | 173 | ||
178 | /* Map in I/O resources */ | 174 | /* Map in I/O resources */ |
179 | if (ppc_md.progress) | 175 | if (ppc_md.progress) |
diff --git a/arch/powerpc/mm/mem.c b/arch/powerpc/mm/mem.c index d0602a76bf7f..579382c163a9 100644 --- a/arch/powerpc/mm/mem.c +++ b/arch/powerpc/mm/mem.c | |||
@@ -380,6 +380,23 @@ void __init mem_init(void) | |||
380 | bsssize >> 10, | 380 | bsssize >> 10, |
381 | initsize >> 10); | 381 | initsize >> 10); |
382 | 382 | ||
383 | #ifdef CONFIG_PPC32 | ||
384 | pr_info("Kernel virtual memory layout:\n"); | ||
385 | pr_info(" * 0x%08lx..0x%08lx : fixmap\n", FIXADDR_START, FIXADDR_TOP); | ||
386 | #ifdef CONFIG_HIGHMEM | ||
387 | pr_info(" * 0x%08lx..0x%08lx : highmem PTEs\n", | ||
388 | PKMAP_BASE, PKMAP_ADDR(LAST_PKMAP)); | ||
389 | #endif /* CONFIG_HIGHMEM */ | ||
390 | #ifdef CONFIG_NOT_COHERENT_CACHE | ||
391 | pr_info(" * 0x%08lx..0x%08lx : consistent mem\n", | ||
392 | IOREMAP_TOP, IOREMAP_TOP + CONFIG_CONSISTENT_SIZE); | ||
393 | #endif /* CONFIG_NOT_COHERENT_CACHE */ | ||
394 | pr_info(" * 0x%08lx..0x%08lx : early ioremap\n", | ||
395 | ioremap_bot, IOREMAP_TOP); | ||
396 | pr_info(" * 0x%08lx..0x%08lx : vmalloc & ioremap\n", | ||
397 | VMALLOC_START, VMALLOC_END); | ||
398 | #endif /* CONFIG_PPC32 */ | ||
399 | |||
383 | mem_init_done = 1; | 400 | mem_init_done = 1; |
384 | } | 401 | } |
385 | 402 | ||
diff --git a/arch/powerpc/mm/mmu_context_nohash.c b/arch/powerpc/mm/mmu_context_nohash.c index a70e311bd457..030d0005b4d2 100644 --- a/arch/powerpc/mm/mmu_context_nohash.c +++ b/arch/powerpc/mm/mmu_context_nohash.c | |||
@@ -127,12 +127,12 @@ static unsigned int steal_context_up(unsigned int id) | |||
127 | 127 | ||
128 | pr_debug("[%d] steal context %d from mm @%p\n", cpu, id, mm); | 128 | pr_debug("[%d] steal context %d from mm @%p\n", cpu, id, mm); |
129 | 129 | ||
130 | /* Mark this mm has having no context anymore */ | ||
131 | mm->context.id = MMU_NO_CONTEXT; | ||
132 | |||
133 | /* Flush the TLB for that context */ | 130 | /* Flush the TLB for that context */ |
134 | local_flush_tlb_mm(mm); | 131 | local_flush_tlb_mm(mm); |
135 | 132 | ||
133 | /* Mark this mm has having no context anymore */ | ||
134 | mm->context.id = MMU_NO_CONTEXT; | ||
135 | |||
136 | /* XXX This clear should ultimately be part of local_flush_tlb_mm */ | 136 | /* XXX This clear should ultimately be part of local_flush_tlb_mm */ |
137 | __clear_bit(id, stale_map[cpu]); | 137 | __clear_bit(id, stale_map[cpu]); |
138 | 138 | ||
diff --git a/arch/powerpc/mm/pgtable_32.c b/arch/powerpc/mm/pgtable_32.c index 430d0908fa50..5422169626ba 100644 --- a/arch/powerpc/mm/pgtable_32.c +++ b/arch/powerpc/mm/pgtable_32.c | |||
@@ -399,8 +399,6 @@ void kernel_map_pages(struct page *page, int numpages, int enable) | |||
399 | #endif /* CONFIG_DEBUG_PAGEALLOC */ | 399 | #endif /* CONFIG_DEBUG_PAGEALLOC */ |
400 | 400 | ||
401 | static int fixmaps; | 401 | static int fixmaps; |
402 | unsigned long FIXADDR_TOP = (-PAGE_SIZE); | ||
403 | EXPORT_SYMBOL(FIXADDR_TOP); | ||
404 | 402 | ||
405 | void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags) | 403 | void __set_fixmap (enum fixed_addresses idx, phys_addr_t phys, pgprot_t flags) |
406 | { | 404 | { |
diff --git a/arch/x86/boot/compressed/relocs.c b/arch/x86/boot/compressed/relocs.c index 857e492c571e..bbeb0c3fbd90 100644 --- a/arch/x86/boot/compressed/relocs.c +++ b/arch/x86/boot/compressed/relocs.c | |||
@@ -504,8 +504,11 @@ static void walk_relocs(void (*visit)(Elf32_Rel *rel, Elf32_Sym *sym)) | |||
504 | if (sym->st_shndx == SHN_ABS) { | 504 | if (sym->st_shndx == SHN_ABS) { |
505 | continue; | 505 | continue; |
506 | } | 506 | } |
507 | if (r_type == R_386_PC32) { | 507 | if (r_type == R_386_NONE || r_type == R_386_PC32) { |
508 | /* PC relative relocations don't need to be adjusted */ | 508 | /* |
509 | * NONE can be ignored and and PC relative | ||
510 | * relocations don't need to be adjusted. | ||
511 | */ | ||
509 | } | 512 | } |
510 | else if (r_type == R_386_32) { | 513 | else if (r_type == R_386_32) { |
511 | /* Visit relocations that need to be adjusted */ | 514 | /* Visit relocations that need to be adjusted */ |
diff --git a/arch/x86/boot/memory.c b/arch/x86/boot/memory.c index 5054c2ddd1a0..74b3d2ba84e9 100644 --- a/arch/x86/boot/memory.c +++ b/arch/x86/boot/memory.c | |||
@@ -17,11 +17,6 @@ | |||
17 | 17 | ||
18 | #define SMAP 0x534d4150 /* ASCII "SMAP" */ | 18 | #define SMAP 0x534d4150 /* ASCII "SMAP" */ |
19 | 19 | ||
20 | struct e820_ext_entry { | ||
21 | struct e820entry std; | ||
22 | u32 ext_flags; | ||
23 | } __attribute__((packed)); | ||
24 | |||
25 | static int detect_memory_e820(void) | 20 | static int detect_memory_e820(void) |
26 | { | 21 | { |
27 | int count = 0; | 22 | int count = 0; |
@@ -29,13 +24,21 @@ static int detect_memory_e820(void) | |||
29 | u32 size, id, edi; | 24 | u32 size, id, edi; |
30 | u8 err; | 25 | u8 err; |
31 | struct e820entry *desc = boot_params.e820_map; | 26 | struct e820entry *desc = boot_params.e820_map; |
32 | static struct e820_ext_entry buf; /* static so it is zeroed */ | 27 | static struct e820entry buf; /* static so it is zeroed */ |
33 | 28 | ||
34 | /* | 29 | /* |
35 | * Set this here so that if the BIOS doesn't change this field | 30 | * Note: at least one BIOS is known which assumes that the |
36 | * but still doesn't change %ecx, we're still okay... | 31 | * buffer pointed to by one e820 call is the same one as |
32 | * the previous call, and only changes modified fields. Therefore, | ||
33 | * we use a temporary buffer and copy the results entry by entry. | ||
34 | * | ||
35 | * This routine deliberately does not try to account for | ||
36 | * ACPI 3+ extended attributes. This is because there are | ||
37 | * BIOSes in the field which report zero for the valid bit for | ||
38 | * all ranges, and we don't currently make any use of the | ||
39 | * other attribute bits. Revisit this if we see the extended | ||
40 | * attribute bits deployed in a meaningful way in the future. | ||
37 | */ | 41 | */ |
38 | buf.ext_flags = 1; | ||
39 | 42 | ||
40 | do { | 43 | do { |
41 | size = sizeof buf; | 44 | size = sizeof buf; |
@@ -66,13 +69,7 @@ static int detect_memory_e820(void) | |||
66 | break; | 69 | break; |
67 | } | 70 | } |
68 | 71 | ||
69 | /* ACPI 3.0 added the extended flags support. If bit 0 | 72 | *desc++ = buf; |
70 | in the extended flags is zero, we're supposed to simply | ||
71 | ignore the entry -- a backwards incompatible change! */ | ||
72 | if (size > 20 && !(buf.ext_flags & 1)) | ||
73 | continue; | ||
74 | |||
75 | *desc++ = buf.std; | ||
76 | count++; | 73 | count++; |
77 | } while (next && count < ARRAY_SIZE(boot_params.e820_map)); | 74 | } while (next && count < ARRAY_SIZE(boot_params.e820_map)); |
78 | 75 | ||
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c index c1caefc82e62..77848d9fca68 100644 --- a/arch/x86/kernel/cpu/common.c +++ b/arch/x86/kernel/cpu/common.c | |||
@@ -114,6 +114,13 @@ DEFINE_PER_CPU_PAGE_ALIGNED(struct gdt_page, gdt_page) = { .gdt = { | |||
114 | } }; | 114 | } }; |
115 | EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); | 115 | EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); |
116 | 116 | ||
117 | static int __init x86_xsave_setup(char *s) | ||
118 | { | ||
119 | setup_clear_cpu_cap(X86_FEATURE_XSAVE); | ||
120 | return 1; | ||
121 | } | ||
122 | __setup("noxsave", x86_xsave_setup); | ||
123 | |||
117 | #ifdef CONFIG_X86_32 | 124 | #ifdef CONFIG_X86_32 |
118 | static int cachesize_override __cpuinitdata = -1; | 125 | static int cachesize_override __cpuinitdata = -1; |
119 | static int disable_x86_serial_nr __cpuinitdata = 1; | 126 | static int disable_x86_serial_nr __cpuinitdata = 1; |
diff --git a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c index 6ac55bd341ae..869615193720 100644 --- a/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c +++ b/arch/x86/kernel/cpu/cpufreq/p4-clockmod.c | |||
@@ -168,6 +168,7 @@ static unsigned int cpufreq_p4_get_frequency(struct cpuinfo_x86 *c) | |||
168 | case 0x0E: /* Core */ | 168 | case 0x0E: /* Core */ |
169 | case 0x0F: /* Core Duo */ | 169 | case 0x0F: /* Core Duo */ |
170 | case 0x16: /* Celeron Core */ | 170 | case 0x16: /* Celeron Core */ |
171 | case 0x1C: /* Atom */ | ||
171 | p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; | 172 | p4clockmod_driver.flags |= CPUFREQ_CONST_LOOPS; |
172 | return speedstep_get_frequency(SPEEDSTEP_CPU_PCORE); | 173 | return speedstep_get_frequency(SPEEDSTEP_CPU_PCORE); |
173 | case 0x0D: /* Pentium M (Dothan) */ | 174 | case 0x0D: /* Pentium M (Dothan) */ |
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c index 3c28ccd49742..a8363e5be4ef 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k7.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k7.c | |||
@@ -168,10 +168,12 @@ static int check_powernow(void) | |||
168 | return 1; | 168 | return 1; |
169 | } | 169 | } |
170 | 170 | ||
171 | #ifdef CONFIG_X86_POWERNOW_K7_ACPI | ||
171 | static void invalidate_entry(unsigned int entry) | 172 | static void invalidate_entry(unsigned int entry) |
172 | { | 173 | { |
173 | powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID; | 174 | powernow_table[entry].frequency = CPUFREQ_ENTRY_INVALID; |
174 | } | 175 | } |
176 | #endif | ||
175 | 177 | ||
176 | static int get_ranges(unsigned char *pst) | 178 | static int get_ranges(unsigned char *pst) |
177 | { | 179 | { |
diff --git a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c index 4709ead2db52..f6b32d112357 100644 --- a/arch/x86/kernel/cpu/cpufreq/powernow-k8.c +++ b/arch/x86/kernel/cpu/cpufreq/powernow-k8.c | |||
@@ -649,6 +649,20 @@ static void print_basics(struct powernow_k8_data *data) | |||
649 | data->batps); | 649 | data->batps); |
650 | } | 650 | } |
651 | 651 | ||
652 | static u32 freq_from_fid_did(u32 fid, u32 did) | ||
653 | { | ||
654 | u32 mhz = 0; | ||
655 | |||
656 | if (boot_cpu_data.x86 == 0x10) | ||
657 | mhz = (100 * (fid + 0x10)) >> did; | ||
658 | else if (boot_cpu_data.x86 == 0x11) | ||
659 | mhz = (100 * (fid + 8)) >> did; | ||
660 | else | ||
661 | BUG(); | ||
662 | |||
663 | return mhz * 1000; | ||
664 | } | ||
665 | |||
652 | static int fill_powernow_table(struct powernow_k8_data *data, | 666 | static int fill_powernow_table(struct powernow_k8_data *data, |
653 | struct pst_s *pst, u8 maxvid) | 667 | struct pst_s *pst, u8 maxvid) |
654 | { | 668 | { |
@@ -923,8 +937,13 @@ static int fill_powernow_table_pstate(struct powernow_k8_data *data, | |||
923 | 937 | ||
924 | powernow_table[i].index = index; | 938 | powernow_table[i].index = index; |
925 | 939 | ||
926 | powernow_table[i].frequency = | 940 | /* Frequency may be rounded for these */ |
927 | data->acpi_data.states[i].core_frequency * 1000; | 941 | if (boot_cpu_data.x86 == 0x10 || boot_cpu_data.x86 == 0x11) { |
942 | powernow_table[i].frequency = | ||
943 | freq_from_fid_did(lo & 0x3f, (lo >> 6) & 7); | ||
944 | } else | ||
945 | powernow_table[i].frequency = | ||
946 | data->acpi_data.states[i].core_frequency * 1000; | ||
928 | } | 947 | } |
929 | return 0; | 948 | return 0; |
930 | } | 949 | } |
@@ -1215,13 +1234,16 @@ static int powernowk8_verify(struct cpufreq_policy *pol) | |||
1215 | return cpufreq_frequency_table_verify(pol, data->powernow_table); | 1234 | return cpufreq_frequency_table_verify(pol, data->powernow_table); |
1216 | } | 1235 | } |
1217 | 1236 | ||
1237 | static const char ACPI_PSS_BIOS_BUG_MSG[] = | ||
1238 | KERN_ERR FW_BUG PFX "No compatible ACPI _PSS objects found.\n" | ||
1239 | KERN_ERR FW_BUG PFX "Try again with latest BIOS.\n"; | ||
1240 | |||
1218 | /* per CPU init entry point to the driver */ | 1241 | /* per CPU init entry point to the driver */ |
1219 | static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) | 1242 | static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) |
1220 | { | 1243 | { |
1221 | struct powernow_k8_data *data; | 1244 | struct powernow_k8_data *data; |
1222 | cpumask_t oldmask; | 1245 | cpumask_t oldmask; |
1223 | int rc; | 1246 | int rc; |
1224 | static int print_once; | ||
1225 | 1247 | ||
1226 | if (!cpu_online(pol->cpu)) | 1248 | if (!cpu_online(pol->cpu)) |
1227 | return -ENODEV; | 1249 | return -ENODEV; |
@@ -1244,19 +1266,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol) | |||
1244 | * an UP version, and is deprecated by AMD. | 1266 | * an UP version, and is deprecated by AMD. |
1245 | */ | 1267 | */ |
1246 | if (num_online_cpus() != 1) { | 1268 | if (num_online_cpus() != 1) { |
1247 | /* | 1269 | printk_once(ACPI_PSS_BIOS_BUG_MSG); |
1248 | * Replace this one with print_once as soon as such a | ||
1249 | * thing gets introduced | ||
1250 | */ | ||
1251 | if (!print_once) { | ||
1252 | WARN_ONCE(1, KERN_ERR FW_BUG PFX "Your BIOS " | ||
1253 | "does not provide ACPI _PSS objects " | ||
1254 | "in a way that Linux understands. " | ||
1255 | "Please report this to the Linux ACPI" | ||
1256 | " maintainers and complain to your " | ||
1257 | "BIOS vendor.\n"); | ||
1258 | print_once++; | ||
1259 | } | ||
1260 | goto err_out; | 1270 | goto err_out; |
1261 | } | 1271 | } |
1262 | if (pol->cpu != 0) { | 1272 | if (pol->cpu != 0) { |
diff --git a/arch/x86/kernel/reboot.c b/arch/x86/kernel/reboot.c index 1340dad417f4..667188e0b5a0 100644 --- a/arch/x86/kernel/reboot.c +++ b/arch/x86/kernel/reboot.c | |||
@@ -232,6 +232,14 @@ static struct dmi_system_id __initdata reboot_dmi_table[] = { | |||
232 | DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), | 232 | DMI_MATCH(DMI_PRODUCT_NAME, "Dell DXP061"), |
233 | }, | 233 | }, |
234 | }, | 234 | }, |
235 | { /* Handle problems with rebooting on Sony VGN-Z540N */ | ||
236 | .callback = set_bios_reboot, | ||
237 | .ident = "Sony VGN-Z540N", | ||
238 | .matches = { | ||
239 | DMI_MATCH(DMI_SYS_VENDOR, "Sony Corporation"), | ||
240 | DMI_MATCH(DMI_PRODUCT_NAME, "VGN-Z540N"), | ||
241 | }, | ||
242 | }, | ||
235 | { } | 243 | { } |
236 | }; | 244 | }; |
237 | 245 | ||
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c index 3a97a4cf1872..8f0e13be36b3 100644 --- a/arch/x86/kernel/setup_percpu.c +++ b/arch/x86/kernel/setup_percpu.c | |||
@@ -160,8 +160,10 @@ static ssize_t __init setup_pcpu_remap(size_t static_size) | |||
160 | /* | 160 | /* |
161 | * If large page isn't supported, there's no benefit in doing | 161 | * If large page isn't supported, there's no benefit in doing |
162 | * this. Also, on non-NUMA, embedding is better. | 162 | * this. Also, on non-NUMA, embedding is better. |
163 | * | ||
164 | * NOTE: disabled for now. | ||
163 | */ | 165 | */ |
164 | if (!cpu_has_pse || !pcpu_need_numa()) | 166 | if (true || !cpu_has_pse || !pcpu_need_numa()) |
165 | return -EINVAL; | 167 | return -EINVAL; |
166 | 168 | ||
167 | /* | 169 | /* |
diff --git a/arch/x86/kvm/mmu.c b/arch/x86/kvm/mmu.c index b6caf1329b1b..32cf11e5728a 100644 --- a/arch/x86/kvm/mmu.c +++ b/arch/x86/kvm/mmu.c | |||
@@ -2897,8 +2897,7 @@ static int kvm_pv_mmu_write(struct kvm_vcpu *vcpu, | |||
2897 | 2897 | ||
2898 | static int kvm_pv_mmu_flush_tlb(struct kvm_vcpu *vcpu) | 2898 | static int kvm_pv_mmu_flush_tlb(struct kvm_vcpu *vcpu) |
2899 | { | 2899 | { |
2900 | kvm_x86_ops->tlb_flush(vcpu); | 2900 | kvm_set_cr3(vcpu, vcpu->arch.cr3); |
2901 | set_bit(KVM_REQ_MMU_SYNC, &vcpu->requests); | ||
2902 | return 1; | 2901 | return 1; |
2903 | } | 2902 | } |
2904 | 2903 | ||
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 49079a46687b..3944e917e794 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c | |||
@@ -338,6 +338,9 @@ EXPORT_SYMBOL_GPL(kvm_lmsw); | |||
338 | 338 | ||
339 | void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) | 339 | void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) |
340 | { | 340 | { |
341 | unsigned long old_cr4 = vcpu->arch.cr4; | ||
342 | unsigned long pdptr_bits = X86_CR4_PGE | X86_CR4_PSE | X86_CR4_PAE; | ||
343 | |||
341 | if (cr4 & CR4_RESERVED_BITS) { | 344 | if (cr4 & CR4_RESERVED_BITS) { |
342 | printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n"); | 345 | printk(KERN_DEBUG "set_cr4: #GP, reserved bits\n"); |
343 | kvm_inject_gp(vcpu, 0); | 346 | kvm_inject_gp(vcpu, 0); |
@@ -351,7 +354,8 @@ void kvm_set_cr4(struct kvm_vcpu *vcpu, unsigned long cr4) | |||
351 | kvm_inject_gp(vcpu, 0); | 354 | kvm_inject_gp(vcpu, 0); |
352 | return; | 355 | return; |
353 | } | 356 | } |
354 | } else if (is_paging(vcpu) && !is_pae(vcpu) && (cr4 & X86_CR4_PAE) | 357 | } else if (is_paging(vcpu) && (cr4 & X86_CR4_PAE) |
358 | && ((cr4 ^ old_cr4) & pdptr_bits) | ||
355 | && !load_pdptrs(vcpu, vcpu->arch.cr3)) { | 359 | && !load_pdptrs(vcpu, vcpu->arch.cr3)) { |
356 | printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n"); | 360 | printk(KERN_DEBUG "set_cr4: #GP, pdptrs reserved bits\n"); |
357 | kvm_inject_gp(vcpu, 0); | 361 | kvm_inject_gp(vcpu, 0); |
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c index 797f9f107cb6..e17efed088c5 100644 --- a/arch/x86/mm/pageattr.c +++ b/arch/x86/mm/pageattr.c | |||
@@ -153,7 +153,7 @@ static void __cpa_flush_all(void *arg) | |||
153 | */ | 153 | */ |
154 | __flush_tlb_all(); | 154 | __flush_tlb_all(); |
155 | 155 | ||
156 | if (cache && boot_cpu_data.x86_model >= 4) | 156 | if (cache && boot_cpu_data.x86 >= 4) |
157 | wbinvd(); | 157 | wbinvd(); |
158 | } | 158 | } |
159 | 159 | ||
@@ -208,20 +208,15 @@ static void cpa_flush_array(unsigned long *start, int numpages, int cache, | |||
208 | int in_flags, struct page **pages) | 208 | int in_flags, struct page **pages) |
209 | { | 209 | { |
210 | unsigned int i, level; | 210 | unsigned int i, level; |
211 | unsigned long do_wbinvd = cache && numpages >= 1024; /* 4M threshold */ | ||
211 | 212 | ||
212 | BUG_ON(irqs_disabled()); | 213 | BUG_ON(irqs_disabled()); |
213 | 214 | ||
214 | on_each_cpu(__cpa_flush_range, NULL, 1); | 215 | on_each_cpu(__cpa_flush_all, (void *) do_wbinvd, 1); |
215 | 216 | ||
216 | if (!cache) | 217 | if (!cache || do_wbinvd) |
217 | return; | 218 | return; |
218 | 219 | ||
219 | /* 4M threshold */ | ||
220 | if (numpages >= 1024) { | ||
221 | if (boot_cpu_data.x86_model >= 4) | ||
222 | wbinvd(); | ||
223 | return; | ||
224 | } | ||
225 | /* | 220 | /* |
226 | * We only need to flush on one CPU, | 221 | * We only need to flush on one CPU, |
227 | * clflush is a MESI-coherent instruction that | 222 | * clflush is a MESI-coherent instruction that |
diff --git a/drivers/base/power/main.c b/drivers/base/power/main.c index 69b4ddb7de3b..3e4bc699bc0f 100644 --- a/drivers/base/power/main.c +++ b/drivers/base/power/main.c | |||
@@ -357,6 +357,7 @@ static void dpm_power_up(pm_message_t state) | |||
357 | { | 357 | { |
358 | struct device *dev; | 358 | struct device *dev; |
359 | 359 | ||
360 | mutex_lock(&dpm_list_mtx); | ||
360 | list_for_each_entry(dev, &dpm_list, power.entry) | 361 | list_for_each_entry(dev, &dpm_list, power.entry) |
361 | if (dev->power.status > DPM_OFF) { | 362 | if (dev->power.status > DPM_OFF) { |
362 | int error; | 363 | int error; |
@@ -366,6 +367,7 @@ static void dpm_power_up(pm_message_t state) | |||
366 | if (error) | 367 | if (error) |
367 | pm_dev_err(dev, state, " early", error); | 368 | pm_dev_err(dev, state, " early", error); |
368 | } | 369 | } |
370 | mutex_unlock(&dpm_list_mtx); | ||
369 | } | 371 | } |
370 | 372 | ||
371 | /** | 373 | /** |
@@ -614,6 +616,7 @@ int device_power_down(pm_message_t state) | |||
614 | int error = 0; | 616 | int error = 0; |
615 | 617 | ||
616 | suspend_device_irqs(); | 618 | suspend_device_irqs(); |
619 | mutex_lock(&dpm_list_mtx); | ||
617 | list_for_each_entry_reverse(dev, &dpm_list, power.entry) { | 620 | list_for_each_entry_reverse(dev, &dpm_list, power.entry) { |
618 | error = suspend_device_noirq(dev, state); | 621 | error = suspend_device_noirq(dev, state); |
619 | if (error) { | 622 | if (error) { |
@@ -622,6 +625,7 @@ int device_power_down(pm_message_t state) | |||
622 | } | 625 | } |
623 | dev->power.status = DPM_OFF_IRQ; | 626 | dev->power.status = DPM_OFF_IRQ; |
624 | } | 627 | } |
628 | mutex_unlock(&dpm_list_mtx); | ||
625 | if (error) | 629 | if (error) |
626 | device_power_up(resume_event(state)); | 630 | device_power_up(resume_event(state)); |
627 | return error; | 631 | return error; |
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c index d270e8eb3e67..47d2ad0ae079 100644 --- a/drivers/cpufreq/cpufreq.c +++ b/drivers/cpufreq/cpufreq.c | |||
@@ -1070,11 +1070,11 @@ static int __cpufreq_remove_dev(struct sys_device *sys_dev) | |||
1070 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); | 1070 | spin_unlock_irqrestore(&cpufreq_driver_lock, flags); |
1071 | #endif | 1071 | #endif |
1072 | 1072 | ||
1073 | unlock_policy_rwsem_write(cpu); | ||
1074 | |||
1073 | if (cpufreq_driver->target) | 1075 | if (cpufreq_driver->target) |
1074 | __cpufreq_governor(data, CPUFREQ_GOV_STOP); | 1076 | __cpufreq_governor(data, CPUFREQ_GOV_STOP); |
1075 | 1077 | ||
1076 | unlock_policy_rwsem_write(cpu); | ||
1077 | |||
1078 | kobject_put(&data->kobj); | 1078 | kobject_put(&data->kobj); |
1079 | 1079 | ||
1080 | /* we need to make sure that the underlying kobj is actually | 1080 | /* we need to make sure that the underlying kobj is actually |
diff --git a/drivers/cpufreq/cpufreq_conservative.c b/drivers/cpufreq/cpufreq_conservative.c index 2ecd95e4ab1a..7a74d175287b 100644 --- a/drivers/cpufreq/cpufreq_conservative.c +++ b/drivers/cpufreq/cpufreq_conservative.c | |||
@@ -91,6 +91,9 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */ | |||
91 | * (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then | 91 | * (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then |
92 | * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock | 92 | * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock |
93 | * is recursive for the same process. -Venki | 93 | * is recursive for the same process. -Venki |
94 | * DEADLOCK ALERT! (2) : do_dbs_timer() must not take the dbs_mutex, because it | ||
95 | * would deadlock with cancel_delayed_work_sync(), which is needed for proper | ||
96 | * raceless workqueue teardown. | ||
94 | */ | 97 | */ |
95 | static DEFINE_MUTEX(dbs_mutex); | 98 | static DEFINE_MUTEX(dbs_mutex); |
96 | 99 | ||
@@ -542,7 +545,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) | |||
542 | static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) | 545 | static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) |
543 | { | 546 | { |
544 | dbs_info->enable = 0; | 547 | dbs_info->enable = 0; |
545 | cancel_delayed_work(&dbs_info->work); | 548 | cancel_delayed_work_sync(&dbs_info->work); |
546 | } | 549 | } |
547 | 550 | ||
548 | static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | 551 | static int cpufreq_governor_dbs(struct cpufreq_policy *policy, |
diff --git a/drivers/cpufreq/cpufreq_ondemand.c b/drivers/cpufreq/cpufreq_ondemand.c index 338f428a15b7..e741c339df76 100644 --- a/drivers/cpufreq/cpufreq_ondemand.c +++ b/drivers/cpufreq/cpufreq_ondemand.c | |||
@@ -98,6 +98,9 @@ static unsigned int dbs_enable; /* number of CPUs using this policy */ | |||
98 | * (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then | 98 | * (like __cpufreq_driver_target()) is being called with dbs_mutex taken, then |
99 | * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock | 99 | * cpu_hotplug lock should be taken before that. Note that cpu_hotplug lock |
100 | * is recursive for the same process. -Venki | 100 | * is recursive for the same process. -Venki |
101 | * DEADLOCK ALERT! (2) : do_dbs_timer() must not take the dbs_mutex, because it | ||
102 | * would deadlock with cancel_delayed_work_sync(), which is needed for proper | ||
103 | * raceless workqueue teardown. | ||
101 | */ | 104 | */ |
102 | static DEFINE_MUTEX(dbs_mutex); | 105 | static DEFINE_MUTEX(dbs_mutex); |
103 | 106 | ||
@@ -562,7 +565,7 @@ static inline void dbs_timer_init(struct cpu_dbs_info_s *dbs_info) | |||
562 | static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) | 565 | static inline void dbs_timer_exit(struct cpu_dbs_info_s *dbs_info) |
563 | { | 566 | { |
564 | dbs_info->enable = 0; | 567 | dbs_info->enable = 0; |
565 | cancel_delayed_work(&dbs_info->work); | 568 | cancel_delayed_work_sync(&dbs_info->work); |
566 | } | 569 | } |
567 | 570 | ||
568 | static int cpufreq_governor_dbs(struct cpufreq_policy *policy, | 571 | static int cpufreq_governor_dbs(struct cpufreq_policy *policy, |
diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 9b149fe824c3..c431fa54bbb5 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h | |||
@@ -180,7 +180,8 @@ typedef struct drm_i915_private { | |||
180 | int backlight_duty_cycle; /* restore backlight to this value */ | 180 | int backlight_duty_cycle; /* restore backlight to this value */ |
181 | bool panel_wants_dither; | 181 | bool panel_wants_dither; |
182 | struct drm_display_mode *panel_fixed_mode; | 182 | struct drm_display_mode *panel_fixed_mode; |
183 | struct drm_display_mode *vbt_mode; /* if any */ | 183 | struct drm_display_mode *lfp_lvds_vbt_mode; /* if any */ |
184 | struct drm_display_mode *sdvo_lvds_vbt_mode; /* if any */ | ||
184 | 185 | ||
185 | /* Feature bits from the VBIOS */ | 186 | /* Feature bits from the VBIOS */ |
186 | unsigned int int_tv_support:1; | 187 | unsigned int int_tv_support:1; |
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c index b189b49c7602..717b6a854bcd 100644 --- a/drivers/gpu/drm/i915/i915_gem.c +++ b/drivers/gpu/drm/i915/i915_gem.c | |||
@@ -349,7 +349,7 @@ i915_gem_shmem_pread_slow(struct drm_device *dev, struct drm_gem_object *obj, | |||
349 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; | 349 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; |
350 | num_pages = last_data_page - first_data_page + 1; | 350 | num_pages = last_data_page - first_data_page + 1; |
351 | 351 | ||
352 | user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); | 352 | user_pages = drm_calloc_large(num_pages, sizeof(struct page *)); |
353 | if (user_pages == NULL) | 353 | if (user_pages == NULL) |
354 | return -ENOMEM; | 354 | return -ENOMEM; |
355 | 355 | ||
@@ -429,7 +429,7 @@ fail_put_user_pages: | |||
429 | SetPageDirty(user_pages[i]); | 429 | SetPageDirty(user_pages[i]); |
430 | page_cache_release(user_pages[i]); | 430 | page_cache_release(user_pages[i]); |
431 | } | 431 | } |
432 | kfree(user_pages); | 432 | drm_free_large(user_pages); |
433 | 433 | ||
434 | return ret; | 434 | return ret; |
435 | } | 435 | } |
@@ -649,7 +649,7 @@ i915_gem_gtt_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, | |||
649 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; | 649 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; |
650 | num_pages = last_data_page - first_data_page + 1; | 650 | num_pages = last_data_page - first_data_page + 1; |
651 | 651 | ||
652 | user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); | 652 | user_pages = drm_calloc_large(num_pages, sizeof(struct page *)); |
653 | if (user_pages == NULL) | 653 | if (user_pages == NULL) |
654 | return -ENOMEM; | 654 | return -ENOMEM; |
655 | 655 | ||
@@ -719,7 +719,7 @@ out_unlock: | |||
719 | out_unpin_pages: | 719 | out_unpin_pages: |
720 | for (i = 0; i < pinned_pages; i++) | 720 | for (i = 0; i < pinned_pages; i++) |
721 | page_cache_release(user_pages[i]); | 721 | page_cache_release(user_pages[i]); |
722 | kfree(user_pages); | 722 | drm_free_large(user_pages); |
723 | 723 | ||
724 | return ret; | 724 | return ret; |
725 | } | 725 | } |
@@ -824,7 +824,7 @@ i915_gem_shmem_pwrite_slow(struct drm_device *dev, struct drm_gem_object *obj, | |||
824 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; | 824 | last_data_page = (data_ptr + args->size - 1) / PAGE_SIZE; |
825 | num_pages = last_data_page - first_data_page + 1; | 825 | num_pages = last_data_page - first_data_page + 1; |
826 | 826 | ||
827 | user_pages = kcalloc(num_pages, sizeof(struct page *), GFP_KERNEL); | 827 | user_pages = drm_calloc_large(num_pages, sizeof(struct page *)); |
828 | if (user_pages == NULL) | 828 | if (user_pages == NULL) |
829 | return -ENOMEM; | 829 | return -ENOMEM; |
830 | 830 | ||
@@ -902,7 +902,7 @@ fail_unlock: | |||
902 | fail_put_user_pages: | 902 | fail_put_user_pages: |
903 | for (i = 0; i < pinned_pages; i++) | 903 | for (i = 0; i < pinned_pages; i++) |
904 | page_cache_release(user_pages[i]); | 904 | page_cache_release(user_pages[i]); |
905 | kfree(user_pages); | 905 | drm_free_large(user_pages); |
906 | 906 | ||
907 | return ret; | 907 | return ret; |
908 | } | 908 | } |
@@ -1145,7 +1145,7 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf) | |||
1145 | mutex_unlock(&dev->struct_mutex); | 1145 | mutex_unlock(&dev->struct_mutex); |
1146 | return VM_FAULT_SIGBUS; | 1146 | return VM_FAULT_SIGBUS; |
1147 | } | 1147 | } |
1148 | list_add(&obj_priv->list, &dev_priv->mm.inactive_list); | 1148 | list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); |
1149 | } | 1149 | } |
1150 | 1150 | ||
1151 | /* Need a new fence register? */ | 1151 | /* Need a new fence register? */ |
@@ -1375,7 +1375,7 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data, | |||
1375 | mutex_unlock(&dev->struct_mutex); | 1375 | mutex_unlock(&dev->struct_mutex); |
1376 | return ret; | 1376 | return ret; |
1377 | } | 1377 | } |
1378 | list_add(&obj_priv->list, &dev_priv->mm.inactive_list); | 1378 | list_add_tail(&obj_priv->list, &dev_priv->mm.inactive_list); |
1379 | } | 1379 | } |
1380 | 1380 | ||
1381 | drm_gem_object_unreference(obj); | 1381 | drm_gem_object_unreference(obj); |
@@ -1408,9 +1408,7 @@ i915_gem_object_put_pages(struct drm_gem_object *obj) | |||
1408 | } | 1408 | } |
1409 | obj_priv->dirty = 0; | 1409 | obj_priv->dirty = 0; |
1410 | 1410 | ||
1411 | drm_free(obj_priv->pages, | 1411 | drm_free_large(obj_priv->pages); |
1412 | page_count * sizeof(struct page *), | ||
1413 | DRM_MEM_DRIVER); | ||
1414 | obj_priv->pages = NULL; | 1412 | obj_priv->pages = NULL; |
1415 | } | 1413 | } |
1416 | 1414 | ||
@@ -2024,8 +2022,7 @@ i915_gem_object_get_pages(struct drm_gem_object *obj) | |||
2024 | */ | 2022 | */ |
2025 | page_count = obj->size / PAGE_SIZE; | 2023 | page_count = obj->size / PAGE_SIZE; |
2026 | BUG_ON(obj_priv->pages != NULL); | 2024 | BUG_ON(obj_priv->pages != NULL); |
2027 | obj_priv->pages = drm_calloc(page_count, sizeof(struct page *), | 2025 | obj_priv->pages = drm_calloc_large(page_count, sizeof(struct page *)); |
2028 | DRM_MEM_DRIVER); | ||
2029 | if (obj_priv->pages == NULL) { | 2026 | if (obj_priv->pages == NULL) { |
2030 | DRM_ERROR("Faled to allocate page list\n"); | 2027 | DRM_ERROR("Faled to allocate page list\n"); |
2031 | obj_priv->pages_refcount--; | 2028 | obj_priv->pages_refcount--; |
@@ -3111,7 +3108,7 @@ i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list, | |||
3111 | reloc_count += exec_list[i].relocation_count; | 3108 | reloc_count += exec_list[i].relocation_count; |
3112 | } | 3109 | } |
3113 | 3110 | ||
3114 | *relocs = drm_calloc(reloc_count, sizeof(**relocs), DRM_MEM_DRIVER); | 3111 | *relocs = drm_calloc_large(reloc_count, sizeof(**relocs)); |
3115 | if (*relocs == NULL) | 3112 | if (*relocs == NULL) |
3116 | return -ENOMEM; | 3113 | return -ENOMEM; |
3117 | 3114 | ||
@@ -3125,8 +3122,7 @@ i915_gem_get_relocs_from_user(struct drm_i915_gem_exec_object *exec_list, | |||
3125 | exec_list[i].relocation_count * | 3122 | exec_list[i].relocation_count * |
3126 | sizeof(**relocs)); | 3123 | sizeof(**relocs)); |
3127 | if (ret != 0) { | 3124 | if (ret != 0) { |
3128 | drm_free(*relocs, reloc_count * sizeof(**relocs), | 3125 | drm_free_large(*relocs); |
3129 | DRM_MEM_DRIVER); | ||
3130 | *relocs = NULL; | 3126 | *relocs = NULL; |
3131 | return -EFAULT; | 3127 | return -EFAULT; |
3132 | } | 3128 | } |
@@ -3165,7 +3161,7 @@ i915_gem_put_relocs_to_user(struct drm_i915_gem_exec_object *exec_list, | |||
3165 | } | 3161 | } |
3166 | 3162 | ||
3167 | err: | 3163 | err: |
3168 | drm_free(relocs, reloc_count * sizeof(*relocs), DRM_MEM_DRIVER); | 3164 | drm_free_large(relocs); |
3169 | 3165 | ||
3170 | return ret; | 3166 | return ret; |
3171 | } | 3167 | } |
@@ -3198,10 +3194,8 @@ i915_gem_execbuffer(struct drm_device *dev, void *data, | |||
3198 | return -EINVAL; | 3194 | return -EINVAL; |
3199 | } | 3195 | } |
3200 | /* Copy in the exec list from userland */ | 3196 | /* Copy in the exec list from userland */ |
3201 | exec_list = drm_calloc(sizeof(*exec_list), args->buffer_count, | 3197 | exec_list = drm_calloc_large(sizeof(*exec_list), args->buffer_count); |
3202 | DRM_MEM_DRIVER); | 3198 | object_list = drm_calloc_large(sizeof(*object_list), args->buffer_count); |
3203 | object_list = drm_calloc(sizeof(*object_list), args->buffer_count, | ||
3204 | DRM_MEM_DRIVER); | ||
3205 | if (exec_list == NULL || object_list == NULL) { | 3199 | if (exec_list == NULL || object_list == NULL) { |
3206 | DRM_ERROR("Failed to allocate exec or object list " | 3200 | DRM_ERROR("Failed to allocate exec or object list " |
3207 | "for %d buffers\n", | 3201 | "for %d buffers\n", |
@@ -3462,10 +3456,8 @@ err: | |||
3462 | } | 3456 | } |
3463 | 3457 | ||
3464 | pre_mutex_err: | 3458 | pre_mutex_err: |
3465 | drm_free(object_list, sizeof(*object_list) * args->buffer_count, | 3459 | drm_free_large(object_list); |
3466 | DRM_MEM_DRIVER); | 3460 | drm_free_large(exec_list); |
3467 | drm_free(exec_list, sizeof(*exec_list) * args->buffer_count, | ||
3468 | DRM_MEM_DRIVER); | ||
3469 | drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects, | 3461 | drm_free(cliprects, sizeof(*cliprects) * args->num_cliprects, |
3470 | DRM_MEM_DRIVER); | 3462 | DRM_MEM_DRIVER); |
3471 | 3463 | ||
diff --git a/drivers/gpu/drm/i915/i915_reg.h b/drivers/gpu/drm/i915/i915_reg.h index 15da44cf21b1..9668cc0d7f4e 100644 --- a/drivers/gpu/drm/i915/i915_reg.h +++ b/drivers/gpu/drm/i915/i915_reg.h | |||
@@ -1410,9 +1410,25 @@ | |||
1410 | 1410 | ||
1411 | /* Cursor A & B regs */ | 1411 | /* Cursor A & B regs */ |
1412 | #define CURACNTR 0x70080 | 1412 | #define CURACNTR 0x70080 |
1413 | /* Old style CUR*CNTR flags (desktop 8xx) */ | ||
1414 | #define CURSOR_ENABLE 0x80000000 | ||
1415 | #define CURSOR_GAMMA_ENABLE 0x40000000 | ||
1416 | #define CURSOR_STRIDE_MASK 0x30000000 | ||
1417 | #define CURSOR_FORMAT_SHIFT 24 | ||
1418 | #define CURSOR_FORMAT_MASK (0x07 << CURSOR_FORMAT_SHIFT) | ||
1419 | #define CURSOR_FORMAT_2C (0x00 << CURSOR_FORMAT_SHIFT) | ||
1420 | #define CURSOR_FORMAT_3C (0x01 << CURSOR_FORMAT_SHIFT) | ||
1421 | #define CURSOR_FORMAT_4C (0x02 << CURSOR_FORMAT_SHIFT) | ||
1422 | #define CURSOR_FORMAT_ARGB (0x04 << CURSOR_FORMAT_SHIFT) | ||
1423 | #define CURSOR_FORMAT_XRGB (0x05 << CURSOR_FORMAT_SHIFT) | ||
1424 | /* New style CUR*CNTR flags */ | ||
1425 | #define CURSOR_MODE 0x27 | ||
1413 | #define CURSOR_MODE_DISABLE 0x00 | 1426 | #define CURSOR_MODE_DISABLE 0x00 |
1414 | #define CURSOR_MODE_64_32B_AX 0x07 | 1427 | #define CURSOR_MODE_64_32B_AX 0x07 |
1415 | #define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) | 1428 | #define CURSOR_MODE_64_ARGB_AX ((1 << 5) | CURSOR_MODE_64_32B_AX) |
1429 | #define MCURSOR_PIPE_SELECT (1 << 28) | ||
1430 | #define MCURSOR_PIPE_A 0x00 | ||
1431 | #define MCURSOR_PIPE_B (1 << 28) | ||
1416 | #define MCURSOR_GAMMA_ENABLE (1 << 26) | 1432 | #define MCURSOR_GAMMA_ENABLE (1 << 26) |
1417 | #define CURABASE 0x70084 | 1433 | #define CURABASE 0x70084 |
1418 | #define CURAPOS 0x70088 | 1434 | #define CURAPOS 0x70088 |
@@ -1420,6 +1436,7 @@ | |||
1420 | #define CURSOR_POS_SIGN 0x8000 | 1436 | #define CURSOR_POS_SIGN 0x8000 |
1421 | #define CURSOR_X_SHIFT 0 | 1437 | #define CURSOR_X_SHIFT 0 |
1422 | #define CURSOR_Y_SHIFT 16 | 1438 | #define CURSOR_Y_SHIFT 16 |
1439 | #define CURSIZE 0x700a0 | ||
1423 | #define CURBCNTR 0x700c0 | 1440 | #define CURBCNTR 0x700c0 |
1424 | #define CURBBASE 0x700c4 | 1441 | #define CURBBASE 0x700c4 |
1425 | #define CURBPOS 0x700c8 | 1442 | #define CURBPOS 0x700c8 |
diff --git a/drivers/gpu/drm/i915/intel_bios.c b/drivers/gpu/drm/i915/intel_bios.c index fc28e2bbd542..9d78cff33b24 100644 --- a/drivers/gpu/drm/i915/intel_bios.c +++ b/drivers/gpu/drm/i915/intel_bios.c | |||
@@ -57,9 +57,43 @@ find_section(struct bdb_header *bdb, int section_id) | |||
57 | return NULL; | 57 | return NULL; |
58 | } | 58 | } |
59 | 59 | ||
60 | /* Try to find panel data */ | ||
61 | static void | 60 | static void |
62 | parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) | 61 | fill_detail_timing_data(struct drm_display_mode *panel_fixed_mode, |
62 | struct lvds_dvo_timing *dvo_timing) | ||
63 | { | ||
64 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | | ||
65 | dvo_timing->hactive_lo; | ||
66 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + | ||
67 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); | ||
68 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + | ||
69 | dvo_timing->hsync_pulse_width; | ||
70 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + | ||
71 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); | ||
72 | |||
73 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | | ||
74 | dvo_timing->vactive_lo; | ||
75 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + | ||
76 | dvo_timing->vsync_off; | ||
77 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + | ||
78 | dvo_timing->vsync_pulse_width; | ||
79 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + | ||
80 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); | ||
81 | panel_fixed_mode->clock = dvo_timing->clock * 10; | ||
82 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; | ||
83 | |||
84 | /* Some VBTs have bogus h/vtotal values */ | ||
85 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) | ||
86 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; | ||
87 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) | ||
88 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; | ||
89 | |||
90 | drm_mode_set_name(panel_fixed_mode); | ||
91 | } | ||
92 | |||
93 | /* Try to find integrated panel data */ | ||
94 | static void | ||
95 | parse_lfp_panel_data(struct drm_i915_private *dev_priv, | ||
96 | struct bdb_header *bdb) | ||
63 | { | 97 | { |
64 | struct bdb_lvds_options *lvds_options; | 98 | struct bdb_lvds_options *lvds_options; |
65 | struct bdb_lvds_lfp_data *lvds_lfp_data; | 99 | struct bdb_lvds_lfp_data *lvds_lfp_data; |
@@ -91,38 +125,45 @@ parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb) | |||
91 | panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), | 125 | panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), |
92 | DRM_MEM_DRIVER); | 126 | DRM_MEM_DRIVER); |
93 | 127 | ||
94 | panel_fixed_mode->hdisplay = (dvo_timing->hactive_hi << 8) | | 128 | fill_detail_timing_data(panel_fixed_mode, dvo_timing); |
95 | dvo_timing->hactive_lo; | ||
96 | panel_fixed_mode->hsync_start = panel_fixed_mode->hdisplay + | ||
97 | ((dvo_timing->hsync_off_hi << 8) | dvo_timing->hsync_off_lo); | ||
98 | panel_fixed_mode->hsync_end = panel_fixed_mode->hsync_start + | ||
99 | dvo_timing->hsync_pulse_width; | ||
100 | panel_fixed_mode->htotal = panel_fixed_mode->hdisplay + | ||
101 | ((dvo_timing->hblank_hi << 8) | dvo_timing->hblank_lo); | ||
102 | 129 | ||
103 | panel_fixed_mode->vdisplay = (dvo_timing->vactive_hi << 8) | | 130 | dev_priv->lfp_lvds_vbt_mode = panel_fixed_mode; |
104 | dvo_timing->vactive_lo; | ||
105 | panel_fixed_mode->vsync_start = panel_fixed_mode->vdisplay + | ||
106 | dvo_timing->vsync_off; | ||
107 | panel_fixed_mode->vsync_end = panel_fixed_mode->vsync_start + | ||
108 | dvo_timing->vsync_pulse_width; | ||
109 | panel_fixed_mode->vtotal = panel_fixed_mode->vdisplay + | ||
110 | ((dvo_timing->vblank_hi << 8) | dvo_timing->vblank_lo); | ||
111 | panel_fixed_mode->clock = dvo_timing->clock * 10; | ||
112 | panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED; | ||
113 | 131 | ||
114 | /* Some VBTs have bogus h/vtotal values */ | 132 | DRM_DEBUG("Found panel mode in BIOS VBT tables:\n"); |
115 | if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal) | 133 | drm_mode_debug_printmodeline(panel_fixed_mode); |
116 | panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1; | ||
117 | if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal) | ||
118 | panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1; | ||
119 | 134 | ||
120 | drm_mode_set_name(panel_fixed_mode); | 135 | return; |
136 | } | ||
137 | |||
138 | /* Try to find sdvo panel data */ | ||
139 | static void | ||
140 | parse_sdvo_panel_data(struct drm_i915_private *dev_priv, | ||
141 | struct bdb_header *bdb) | ||
142 | { | ||
143 | struct bdb_sdvo_lvds_options *sdvo_lvds_options; | ||
144 | struct lvds_dvo_timing *dvo_timing; | ||
145 | struct drm_display_mode *panel_fixed_mode; | ||
121 | 146 | ||
122 | dev_priv->vbt_mode = panel_fixed_mode; | 147 | dev_priv->sdvo_lvds_vbt_mode = NULL; |
123 | 148 | ||
124 | DRM_DEBUG("Found panel mode in BIOS VBT tables:\n"); | 149 | sdvo_lvds_options = find_section(bdb, BDB_SDVO_LVDS_OPTIONS); |
125 | drm_mode_debug_printmodeline(panel_fixed_mode); | 150 | if (!sdvo_lvds_options) |
151 | return; | ||
152 | |||
153 | dvo_timing = find_section(bdb, BDB_SDVO_PANEL_DTDS); | ||
154 | if (!dvo_timing) | ||
155 | return; | ||
156 | |||
157 | panel_fixed_mode = drm_calloc(1, sizeof(*panel_fixed_mode), | ||
158 | DRM_MEM_DRIVER); | ||
159 | |||
160 | if (!panel_fixed_mode) | ||
161 | return; | ||
162 | |||
163 | fill_detail_timing_data(panel_fixed_mode, | ||
164 | dvo_timing + sdvo_lvds_options->panel_type); | ||
165 | |||
166 | dev_priv->sdvo_lvds_vbt_mode = panel_fixed_mode; | ||
126 | 167 | ||
127 | return; | 168 | return; |
128 | } | 169 | } |
@@ -199,7 +240,8 @@ intel_init_bios(struct drm_device *dev) | |||
199 | 240 | ||
200 | /* Grab useful general definitions */ | 241 | /* Grab useful general definitions */ |
201 | parse_general_features(dev_priv, bdb); | 242 | parse_general_features(dev_priv, bdb); |
202 | parse_panel_data(dev_priv, bdb); | 243 | parse_lfp_panel_data(dev_priv, bdb); |
244 | parse_sdvo_panel_data(dev_priv, bdb); | ||
203 | 245 | ||
204 | pci_unmap_rom(pdev, bios); | 246 | pci_unmap_rom(pdev, bios); |
205 | 247 | ||
diff --git a/drivers/gpu/drm/i915/intel_bios.h b/drivers/gpu/drm/i915/intel_bios.h index de621aad85b5..8ca2cde15804 100644 --- a/drivers/gpu/drm/i915/intel_bios.h +++ b/drivers/gpu/drm/i915/intel_bios.h | |||
@@ -279,6 +279,23 @@ struct vch_bdb_22 { | |||
279 | struct vch_panel_data panels[16]; | 279 | struct vch_panel_data panels[16]; |
280 | } __attribute__((packed)); | 280 | } __attribute__((packed)); |
281 | 281 | ||
282 | struct bdb_sdvo_lvds_options { | ||
283 | u8 panel_backlight; | ||
284 | u8 h40_set_panel_type; | ||
285 | u8 panel_type; | ||
286 | u8 ssc_clk_freq; | ||
287 | u16 als_low_trip; | ||
288 | u16 als_high_trip; | ||
289 | u8 sclalarcoeff_tab_row_num; | ||
290 | u8 sclalarcoeff_tab_row_size; | ||
291 | u8 coefficient[8]; | ||
292 | u8 panel_misc_bits_1; | ||
293 | u8 panel_misc_bits_2; | ||
294 | u8 panel_misc_bits_3; | ||
295 | u8 panel_misc_bits_4; | ||
296 | } __attribute__((packed)); | ||
297 | |||
298 | |||
282 | bool intel_init_bios(struct drm_device *dev); | 299 | bool intel_init_bios(struct drm_device *dev); |
283 | 300 | ||
284 | /* | 301 | /* |
diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c index 19148c3df637..640f5158effc 100644 --- a/drivers/gpu/drm/i915/intel_crt.c +++ b/drivers/gpu/drm/i915/intel_crt.c | |||
@@ -198,9 +198,142 @@ static bool intel_crt_detect_ddc(struct drm_connector *connector) | |||
198 | return intel_ddc_probe(intel_output); | 198 | return intel_ddc_probe(intel_output); |
199 | } | 199 | } |
200 | 200 | ||
201 | static enum drm_connector_status | ||
202 | intel_crt_load_detect(struct drm_crtc *crtc, struct intel_output *intel_output) | ||
203 | { | ||
204 | struct drm_encoder *encoder = &intel_output->enc; | ||
205 | struct drm_device *dev = encoder->dev; | ||
206 | struct drm_i915_private *dev_priv = dev->dev_private; | ||
207 | struct intel_crtc *intel_crtc = to_intel_crtc(crtc); | ||
208 | uint32_t pipe = intel_crtc->pipe; | ||
209 | uint32_t save_bclrpat; | ||
210 | uint32_t save_vtotal; | ||
211 | uint32_t vtotal, vactive; | ||
212 | uint32_t vsample; | ||
213 | uint32_t vblank, vblank_start, vblank_end; | ||
214 | uint32_t dsl; | ||
215 | uint32_t bclrpat_reg; | ||
216 | uint32_t vtotal_reg; | ||
217 | uint32_t vblank_reg; | ||
218 | uint32_t vsync_reg; | ||
219 | uint32_t pipeconf_reg; | ||
220 | uint32_t pipe_dsl_reg; | ||
221 | uint8_t st00; | ||
222 | enum drm_connector_status status; | ||
223 | |||
224 | if (pipe == 0) { | ||
225 | bclrpat_reg = BCLRPAT_A; | ||
226 | vtotal_reg = VTOTAL_A; | ||
227 | vblank_reg = VBLANK_A; | ||
228 | vsync_reg = VSYNC_A; | ||
229 | pipeconf_reg = PIPEACONF; | ||
230 | pipe_dsl_reg = PIPEADSL; | ||
231 | } else { | ||
232 | bclrpat_reg = BCLRPAT_B; | ||
233 | vtotal_reg = VTOTAL_B; | ||
234 | vblank_reg = VBLANK_B; | ||
235 | vsync_reg = VSYNC_B; | ||
236 | pipeconf_reg = PIPEBCONF; | ||
237 | pipe_dsl_reg = PIPEBDSL; | ||
238 | } | ||
239 | |||
240 | save_bclrpat = I915_READ(bclrpat_reg); | ||
241 | save_vtotal = I915_READ(vtotal_reg); | ||
242 | vblank = I915_READ(vblank_reg); | ||
243 | |||
244 | vtotal = ((save_vtotal >> 16) & 0xfff) + 1; | ||
245 | vactive = (save_vtotal & 0x7ff) + 1; | ||
246 | |||
247 | vblank_start = (vblank & 0xfff) + 1; | ||
248 | vblank_end = ((vblank >> 16) & 0xfff) + 1; | ||
249 | |||
250 | /* Set the border color to purple. */ | ||
251 | I915_WRITE(bclrpat_reg, 0x500050); | ||
252 | |||
253 | if (IS_I9XX(dev)) { | ||
254 | uint32_t pipeconf = I915_READ(pipeconf_reg); | ||
255 | I915_WRITE(pipeconf_reg, pipeconf | PIPECONF_FORCE_BORDER); | ||
256 | /* Wait for next Vblank to substitue | ||
257 | * border color for Color info */ | ||
258 | intel_wait_for_vblank(dev); | ||
259 | st00 = I915_READ8(VGA_MSR_WRITE); | ||
260 | status = ((st00 & (1 << 4)) != 0) ? | ||
261 | connector_status_connected : | ||
262 | connector_status_disconnected; | ||
263 | |||
264 | I915_WRITE(pipeconf_reg, pipeconf); | ||
265 | } else { | ||
266 | bool restore_vblank = false; | ||
267 | int count, detect; | ||
268 | |||
269 | /* | ||
270 | * If there isn't any border, add some. | ||
271 | * Yes, this will flicker | ||
272 | */ | ||
273 | if (vblank_start <= vactive && vblank_end >= vtotal) { | ||
274 | uint32_t vsync = I915_READ(vsync_reg); | ||
275 | uint32_t vsync_start = (vsync & 0xffff) + 1; | ||
276 | |||
277 | vblank_start = vsync_start; | ||
278 | I915_WRITE(vblank_reg, | ||
279 | (vblank_start - 1) | | ||
280 | ((vblank_end - 1) << 16)); | ||
281 | restore_vblank = true; | ||
282 | } | ||
283 | /* sample in the vertical border, selecting the larger one */ | ||
284 | if (vblank_start - vactive >= vtotal - vblank_end) | ||
285 | vsample = (vblank_start + vactive) >> 1; | ||
286 | else | ||
287 | vsample = (vtotal + vblank_end) >> 1; | ||
288 | |||
289 | /* | ||
290 | * Wait for the border to be displayed | ||
291 | */ | ||
292 | while (I915_READ(pipe_dsl_reg) >= vactive) | ||
293 | ; | ||
294 | while ((dsl = I915_READ(pipe_dsl_reg)) <= vsample) | ||
295 | ; | ||
296 | /* | ||
297 | * Watch ST00 for an entire scanline | ||
298 | */ | ||
299 | detect = 0; | ||
300 | count = 0; | ||
301 | do { | ||
302 | count++; | ||
303 | /* Read the ST00 VGA status register */ | ||
304 | st00 = I915_READ8(VGA_MSR_WRITE); | ||
305 | if (st00 & (1 << 4)) | ||
306 | detect++; | ||
307 | } while ((I915_READ(pipe_dsl_reg) == dsl)); | ||
308 | |||
309 | /* restore vblank if necessary */ | ||
310 | if (restore_vblank) | ||
311 | I915_WRITE(vblank_reg, vblank); | ||
312 | /* | ||
313 | * If more than 3/4 of the scanline detected a monitor, | ||
314 | * then it is assumed to be present. This works even on i830, | ||
315 | * where there isn't any way to force the border color across | ||
316 | * the screen | ||
317 | */ | ||
318 | status = detect * 4 > count * 3 ? | ||
319 | connector_status_connected : | ||
320 | connector_status_disconnected; | ||
321 | } | ||
322 | |||
323 | /* Restore previous settings */ | ||
324 | I915_WRITE(bclrpat_reg, save_bclrpat); | ||
325 | |||
326 | return status; | ||
327 | } | ||
328 | |||
201 | static enum drm_connector_status intel_crt_detect(struct drm_connector *connector) | 329 | static enum drm_connector_status intel_crt_detect(struct drm_connector *connector) |
202 | { | 330 | { |
203 | struct drm_device *dev = connector->dev; | 331 | struct drm_device *dev = connector->dev; |
332 | struct intel_output *intel_output = to_intel_output(connector); | ||
333 | struct drm_encoder *encoder = &intel_output->enc; | ||
334 | struct drm_crtc *crtc; | ||
335 | int dpms_mode; | ||
336 | enum drm_connector_status status; | ||
204 | 337 | ||
205 | if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { | 338 | if (IS_I9XX(dev) && !IS_I915G(dev) && !IS_I915GM(dev)) { |
206 | if (intel_crt_detect_hotplug(connector)) | 339 | if (intel_crt_detect_hotplug(connector)) |
@@ -212,8 +345,20 @@ static enum drm_connector_status intel_crt_detect(struct drm_connector *connecto | |||
212 | if (intel_crt_detect_ddc(connector)) | 345 | if (intel_crt_detect_ddc(connector)) |
213 | return connector_status_connected; | 346 | return connector_status_connected; |
214 | 347 | ||
215 | /* TODO use load detect */ | 348 | /* for pre-945g platforms use load detect */ |
216 | return connector_status_unknown; | 349 | if (encoder->crtc && encoder->crtc->enabled) { |
350 | status = intel_crt_load_detect(encoder->crtc, intel_output); | ||
351 | } else { | ||
352 | crtc = intel_get_load_detect_pipe(intel_output, | ||
353 | NULL, &dpms_mode); | ||
354 | if (crtc) { | ||
355 | status = intel_crt_load_detect(crtc, intel_output); | ||
356 | intel_release_load_detect_pipe(intel_output, dpms_mode); | ||
357 | } else | ||
358 | status = connector_status_unknown; | ||
359 | } | ||
360 | |||
361 | return status; | ||
217 | } | 362 | } |
218 | 363 | ||
219 | static void intel_crt_destroy(struct drm_connector *connector) | 364 | static void intel_crt_destroy(struct drm_connector *connector) |
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c index 3387cf32f385..c9d6f10ba92e 100644 --- a/drivers/gpu/drm/i915/intel_display.c +++ b/drivers/gpu/drm/i915/intel_display.c | |||
@@ -1357,7 +1357,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, | |||
1357 | int pipe = intel_crtc->pipe; | 1357 | int pipe = intel_crtc->pipe; |
1358 | uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; | 1358 | uint32_t control = (pipe == 0) ? CURACNTR : CURBCNTR; |
1359 | uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; | 1359 | uint32_t base = (pipe == 0) ? CURABASE : CURBBASE; |
1360 | uint32_t temp; | 1360 | uint32_t temp = I915_READ(control); |
1361 | size_t addr; | 1361 | size_t addr; |
1362 | int ret; | 1362 | int ret; |
1363 | 1363 | ||
@@ -1366,7 +1366,12 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, | |||
1366 | /* if we want to turn off the cursor ignore width and height */ | 1366 | /* if we want to turn off the cursor ignore width and height */ |
1367 | if (!handle) { | 1367 | if (!handle) { |
1368 | DRM_DEBUG("cursor off\n"); | 1368 | DRM_DEBUG("cursor off\n"); |
1369 | temp = CURSOR_MODE_DISABLE; | 1369 | if (IS_MOBILE(dev) || IS_I9XX(dev)) { |
1370 | temp &= ~(CURSOR_MODE | MCURSOR_GAMMA_ENABLE); | ||
1371 | temp |= CURSOR_MODE_DISABLE; | ||
1372 | } else { | ||
1373 | temp &= ~(CURSOR_ENABLE | CURSOR_GAMMA_ENABLE); | ||
1374 | } | ||
1370 | addr = 0; | 1375 | addr = 0; |
1371 | bo = NULL; | 1376 | bo = NULL; |
1372 | mutex_lock(&dev->struct_mutex); | 1377 | mutex_lock(&dev->struct_mutex); |
@@ -1409,10 +1414,19 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc, | |||
1409 | addr = obj_priv->phys_obj->handle->busaddr; | 1414 | addr = obj_priv->phys_obj->handle->busaddr; |
1410 | } | 1415 | } |
1411 | 1416 | ||
1412 | temp = 0; | 1417 | if (!IS_I9XX(dev)) |
1413 | /* set the pipe for the cursor */ | 1418 | I915_WRITE(CURSIZE, (height << 12) | width); |
1414 | temp |= (pipe << 28); | 1419 | |
1415 | temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; | 1420 | /* Hooray for CUR*CNTR differences */ |
1421 | if (IS_MOBILE(dev) || IS_I9XX(dev)) { | ||
1422 | temp &= ~(CURSOR_MODE | MCURSOR_PIPE_SELECT); | ||
1423 | temp |= CURSOR_MODE_64_ARGB_AX | MCURSOR_GAMMA_ENABLE; | ||
1424 | temp |= (pipe << 28); /* Connect to correct pipe */ | ||
1425 | } else { | ||
1426 | temp &= ~(CURSOR_FORMAT_MASK); | ||
1427 | temp |= CURSOR_ENABLE; | ||
1428 | temp |= CURSOR_FORMAT_ARGB | CURSOR_GAMMA_ENABLE; | ||
1429 | } | ||
1416 | 1430 | ||
1417 | finish: | 1431 | finish: |
1418 | I915_WRITE(control, temp); | 1432 | I915_WRITE(control, temp); |
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c index 439a86514993..53731f0ffcb5 100644 --- a/drivers/gpu/drm/i915/intel_lvds.c +++ b/drivers/gpu/drm/i915/intel_lvds.c | |||
@@ -511,10 +511,10 @@ void intel_lvds_init(struct drm_device *dev) | |||
511 | } | 511 | } |
512 | 512 | ||
513 | /* Failed to get EDID, what about VBT? */ | 513 | /* Failed to get EDID, what about VBT? */ |
514 | if (dev_priv->vbt_mode) { | 514 | if (dev_priv->lfp_lvds_vbt_mode) { |
515 | mutex_lock(&dev->mode_config.mutex); | 515 | mutex_lock(&dev->mode_config.mutex); |
516 | dev_priv->panel_fixed_mode = | 516 | dev_priv->panel_fixed_mode = |
517 | drm_mode_duplicate(dev, dev_priv->vbt_mode); | 517 | drm_mode_duplicate(dev, dev_priv->lfp_lvds_vbt_mode); |
518 | mutex_unlock(&dev->mode_config.mutex); | 518 | mutex_unlock(&dev->mode_config.mutex); |
519 | if (dev_priv->panel_fixed_mode) { | 519 | if (dev_priv->panel_fixed_mode) { |
520 | dev_priv->panel_fixed_mode->type |= | 520 | dev_priv->panel_fixed_mode->type |= |
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c index 9913651c1e17..f3ef6bfd8ffc 100644 --- a/drivers/gpu/drm/i915/intel_sdvo.c +++ b/drivers/gpu/drm/i915/intel_sdvo.c | |||
@@ -69,6 +69,10 @@ struct intel_sdvo_priv { | |||
69 | * This is set if we treat the device as HDMI, instead of DVI. | 69 | * This is set if we treat the device as HDMI, instead of DVI. |
70 | */ | 70 | */ |
71 | bool is_hdmi; | 71 | bool is_hdmi; |
72 | /** | ||
73 | * This is set if we detect output of sdvo device as LVDS. | ||
74 | */ | ||
75 | bool is_lvds; | ||
72 | 76 | ||
73 | /** | 77 | /** |
74 | * Returned SDTV resolutions allowed for the current format, if the | 78 | * Returned SDTV resolutions allowed for the current format, if the |
@@ -1398,10 +1402,8 @@ static enum drm_connector_status intel_sdvo_detect(struct drm_connector *connect | |||
1398 | static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) | 1402 | static void intel_sdvo_get_ddc_modes(struct drm_connector *connector) |
1399 | { | 1403 | { |
1400 | struct intel_output *intel_output = to_intel_output(connector); | 1404 | struct intel_output *intel_output = to_intel_output(connector); |
1401 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
1402 | 1405 | ||
1403 | /* set the bus switch and get the modes */ | 1406 | /* set the bus switch and get the modes */ |
1404 | intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus); | ||
1405 | intel_ddc_get_modes(intel_output); | 1407 | intel_ddc_get_modes(intel_output); |
1406 | 1408 | ||
1407 | #if 0 | 1409 | #if 0 |
@@ -1543,6 +1545,37 @@ static void intel_sdvo_get_tv_modes(struct drm_connector *connector) | |||
1543 | } | 1545 | } |
1544 | } | 1546 | } |
1545 | 1547 | ||
1548 | static void intel_sdvo_get_lvds_modes(struct drm_connector *connector) | ||
1549 | { | ||
1550 | struct intel_output *intel_output = to_intel_output(connector); | ||
1551 | struct intel_sdvo_priv *sdvo_priv = intel_output->dev_priv; | ||
1552 | struct drm_i915_private *dev_priv = connector->dev->dev_private; | ||
1553 | |||
1554 | /* | ||
1555 | * Attempt to get the mode list from DDC. | ||
1556 | * Assume that the preferred modes are | ||
1557 | * arranged in priority order. | ||
1558 | */ | ||
1559 | /* set the bus switch and get the modes */ | ||
1560 | intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus); | ||
1561 | intel_ddc_get_modes(intel_output); | ||
1562 | if (list_empty(&connector->probed_modes) == false) | ||
1563 | return; | ||
1564 | |||
1565 | /* Fetch modes from VBT */ | ||
1566 | if (dev_priv->sdvo_lvds_vbt_mode != NULL) { | ||
1567 | struct drm_display_mode *newmode; | ||
1568 | newmode = drm_mode_duplicate(connector->dev, | ||
1569 | dev_priv->sdvo_lvds_vbt_mode); | ||
1570 | if (newmode != NULL) { | ||
1571 | /* Guarantee the mode is preferred */ | ||
1572 | newmode->type = (DRM_MODE_TYPE_PREFERRED | | ||
1573 | DRM_MODE_TYPE_DRIVER); | ||
1574 | drm_mode_probed_add(connector, newmode); | ||
1575 | } | ||
1576 | } | ||
1577 | } | ||
1578 | |||
1546 | static int intel_sdvo_get_modes(struct drm_connector *connector) | 1579 | static int intel_sdvo_get_modes(struct drm_connector *connector) |
1547 | { | 1580 | { |
1548 | struct intel_output *output = to_intel_output(connector); | 1581 | struct intel_output *output = to_intel_output(connector); |
@@ -1550,6 +1583,8 @@ static int intel_sdvo_get_modes(struct drm_connector *connector) | |||
1550 | 1583 | ||
1551 | if (sdvo_priv->is_tv) | 1584 | if (sdvo_priv->is_tv) |
1552 | intel_sdvo_get_tv_modes(connector); | 1585 | intel_sdvo_get_tv_modes(connector); |
1586 | else if (sdvo_priv->is_lvds == true) | ||
1587 | intel_sdvo_get_lvds_modes(connector); | ||
1553 | else | 1588 | else |
1554 | intel_sdvo_get_ddc_modes(connector); | 1589 | intel_sdvo_get_ddc_modes(connector); |
1555 | 1590 | ||
@@ -1564,6 +1599,9 @@ static void intel_sdvo_destroy(struct drm_connector *connector) | |||
1564 | 1599 | ||
1565 | if (intel_output->i2c_bus) | 1600 | if (intel_output->i2c_bus) |
1566 | intel_i2c_destroy(intel_output->i2c_bus); | 1601 | intel_i2c_destroy(intel_output->i2c_bus); |
1602 | if (intel_output->ddc_bus) | ||
1603 | intel_i2c_destroy(intel_output->ddc_bus); | ||
1604 | |||
1567 | drm_sysfs_connector_remove(connector); | 1605 | drm_sysfs_connector_remove(connector); |
1568 | drm_connector_cleanup(connector); | 1606 | drm_connector_cleanup(connector); |
1569 | kfree(intel_output); | 1607 | kfree(intel_output); |
@@ -1660,12 +1698,56 @@ intel_sdvo_get_digital_encoding_mode(struct intel_output *output) | |||
1660 | return true; | 1698 | return true; |
1661 | } | 1699 | } |
1662 | 1700 | ||
1701 | static struct intel_output * | ||
1702 | intel_sdvo_chan_to_intel_output(struct intel_i2c_chan *chan) | ||
1703 | { | ||
1704 | struct drm_device *dev = chan->drm_dev; | ||
1705 | struct drm_connector *connector; | ||
1706 | struct intel_output *intel_output = NULL; | ||
1707 | |||
1708 | list_for_each_entry(connector, | ||
1709 | &dev->mode_config.connector_list, head) { | ||
1710 | if (to_intel_output(connector)->ddc_bus == chan) { | ||
1711 | intel_output = to_intel_output(connector); | ||
1712 | break; | ||
1713 | } | ||
1714 | } | ||
1715 | return intel_output; | ||
1716 | } | ||
1717 | |||
1718 | static int intel_sdvo_master_xfer(struct i2c_adapter *i2c_adap, | ||
1719 | struct i2c_msg msgs[], int num) | ||
1720 | { | ||
1721 | struct intel_output *intel_output; | ||
1722 | struct intel_sdvo_priv *sdvo_priv; | ||
1723 | struct i2c_algo_bit_data *algo_data; | ||
1724 | struct i2c_algorithm *algo; | ||
1725 | |||
1726 | algo_data = (struct i2c_algo_bit_data *)i2c_adap->algo_data; | ||
1727 | intel_output = | ||
1728 | intel_sdvo_chan_to_intel_output( | ||
1729 | (struct intel_i2c_chan *)(algo_data->data)); | ||
1730 | if (intel_output == NULL) | ||
1731 | return -EINVAL; | ||
1732 | |||
1733 | sdvo_priv = intel_output->dev_priv; | ||
1734 | algo = (struct i2c_algorithm *)intel_output->i2c_bus->adapter.algo; | ||
1735 | |||
1736 | intel_sdvo_set_control_bus_switch(intel_output, sdvo_priv->ddc_bus); | ||
1737 | return algo->master_xfer(i2c_adap, msgs, num); | ||
1738 | } | ||
1739 | |||
1740 | static struct i2c_algorithm intel_sdvo_i2c_bit_algo = { | ||
1741 | .master_xfer = intel_sdvo_master_xfer, | ||
1742 | }; | ||
1743 | |||
1663 | bool intel_sdvo_init(struct drm_device *dev, int output_device) | 1744 | bool intel_sdvo_init(struct drm_device *dev, int output_device) |
1664 | { | 1745 | { |
1665 | struct drm_connector *connector; | 1746 | struct drm_connector *connector; |
1666 | struct intel_output *intel_output; | 1747 | struct intel_output *intel_output; |
1667 | struct intel_sdvo_priv *sdvo_priv; | 1748 | struct intel_sdvo_priv *sdvo_priv; |
1668 | struct intel_i2c_chan *i2cbus = NULL; | 1749 | struct intel_i2c_chan *i2cbus = NULL; |
1750 | struct intel_i2c_chan *ddcbus = NULL; | ||
1669 | int connector_type; | 1751 | int connector_type; |
1670 | u8 ch[0x40]; | 1752 | u8 ch[0x40]; |
1671 | int i; | 1753 | int i; |
@@ -1676,17 +1758,9 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
1676 | return false; | 1758 | return false; |
1677 | } | 1759 | } |
1678 | 1760 | ||
1679 | connector = &intel_output->base; | ||
1680 | |||
1681 | drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, | ||
1682 | DRM_MODE_CONNECTOR_Unknown); | ||
1683 | drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); | ||
1684 | sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); | 1761 | sdvo_priv = (struct intel_sdvo_priv *)(intel_output + 1); |
1685 | intel_output->type = INTEL_OUTPUT_SDVO; | 1762 | intel_output->type = INTEL_OUTPUT_SDVO; |
1686 | 1763 | ||
1687 | connector->interlace_allowed = 0; | ||
1688 | connector->doublescan_allowed = 0; | ||
1689 | |||
1690 | /* setup the DDC bus. */ | 1764 | /* setup the DDC bus. */ |
1691 | if (output_device == SDVOB) | 1765 | if (output_device == SDVOB) |
1692 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); | 1766 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOB"); |
@@ -1694,7 +1768,7 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
1694 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); | 1768 | i2cbus = intel_i2c_create(dev, GPIOE, "SDVOCTRL_E for SDVOC"); |
1695 | 1769 | ||
1696 | if (!i2cbus) | 1770 | if (!i2cbus) |
1697 | goto err_connector; | 1771 | goto err_inteloutput; |
1698 | 1772 | ||
1699 | sdvo_priv->i2c_bus = i2cbus; | 1773 | sdvo_priv->i2c_bus = i2cbus; |
1700 | 1774 | ||
@@ -1710,7 +1784,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
1710 | intel_output->i2c_bus = i2cbus; | 1784 | intel_output->i2c_bus = i2cbus; |
1711 | intel_output->dev_priv = sdvo_priv; | 1785 | intel_output->dev_priv = sdvo_priv; |
1712 | 1786 | ||
1713 | |||
1714 | /* Read the regs to test if we can talk to the device */ | 1787 | /* Read the regs to test if we can talk to the device */ |
1715 | for (i = 0; i < 0x40; i++) { | 1788 | for (i = 0; i < 0x40; i++) { |
1716 | if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { | 1789 | if (!intel_sdvo_read_byte(intel_output, i, &ch[i])) { |
@@ -1720,6 +1793,22 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
1720 | } | 1793 | } |
1721 | } | 1794 | } |
1722 | 1795 | ||
1796 | /* setup the DDC bus. */ | ||
1797 | if (output_device == SDVOB) | ||
1798 | ddcbus = intel_i2c_create(dev, GPIOE, "SDVOB DDC BUS"); | ||
1799 | else | ||
1800 | ddcbus = intel_i2c_create(dev, GPIOE, "SDVOC DDC BUS"); | ||
1801 | |||
1802 | if (ddcbus == NULL) | ||
1803 | goto err_i2c; | ||
1804 | |||
1805 | intel_sdvo_i2c_bit_algo.functionality = | ||
1806 | intel_output->i2c_bus->adapter.algo->functionality; | ||
1807 | ddcbus->adapter.algo = &intel_sdvo_i2c_bit_algo; | ||
1808 | intel_output->ddc_bus = ddcbus; | ||
1809 | |||
1810 | /* In defaut case sdvo lvds is false */ | ||
1811 | sdvo_priv->is_lvds = false; | ||
1723 | intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); | 1812 | intel_sdvo_get_capabilities(intel_output, &sdvo_priv->caps); |
1724 | 1813 | ||
1725 | if (sdvo_priv->caps.output_flags & | 1814 | if (sdvo_priv->caps.output_flags & |
@@ -1729,7 +1818,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
1729 | else | 1818 | else |
1730 | sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1; | 1819 | sdvo_priv->controlled_output = SDVO_OUTPUT_TMDS1; |
1731 | 1820 | ||
1732 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1733 | encoder_type = DRM_MODE_ENCODER_TMDS; | 1821 | encoder_type = DRM_MODE_ENCODER_TMDS; |
1734 | connector_type = DRM_MODE_CONNECTOR_DVID; | 1822 | connector_type = DRM_MODE_CONNECTOR_DVID; |
1735 | 1823 | ||
@@ -1747,7 +1835,6 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
1747 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0) | 1835 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_SVID0) |
1748 | { | 1836 | { |
1749 | sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0; | 1837 | sdvo_priv->controlled_output = SDVO_OUTPUT_SVID0; |
1750 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1751 | encoder_type = DRM_MODE_ENCODER_TVDAC; | 1838 | encoder_type = DRM_MODE_ENCODER_TVDAC; |
1752 | connector_type = DRM_MODE_CONNECTOR_SVIDEO; | 1839 | connector_type = DRM_MODE_CONNECTOR_SVIDEO; |
1753 | sdvo_priv->is_tv = true; | 1840 | sdvo_priv->is_tv = true; |
@@ -1756,30 +1843,28 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
1756 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) | 1843 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB0) |
1757 | { | 1844 | { |
1758 | sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0; | 1845 | sdvo_priv->controlled_output = SDVO_OUTPUT_RGB0; |
1759 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1760 | encoder_type = DRM_MODE_ENCODER_DAC; | 1846 | encoder_type = DRM_MODE_ENCODER_DAC; |
1761 | connector_type = DRM_MODE_CONNECTOR_VGA; | 1847 | connector_type = DRM_MODE_CONNECTOR_VGA; |
1762 | } | 1848 | } |
1763 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) | 1849 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_RGB1) |
1764 | { | 1850 | { |
1765 | sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1; | 1851 | sdvo_priv->controlled_output = SDVO_OUTPUT_RGB1; |
1766 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1767 | encoder_type = DRM_MODE_ENCODER_DAC; | 1852 | encoder_type = DRM_MODE_ENCODER_DAC; |
1768 | connector_type = DRM_MODE_CONNECTOR_VGA; | 1853 | connector_type = DRM_MODE_CONNECTOR_VGA; |
1769 | } | 1854 | } |
1770 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0) | 1855 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS0) |
1771 | { | 1856 | { |
1772 | sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; | 1857 | sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS0; |
1773 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1774 | encoder_type = DRM_MODE_ENCODER_LVDS; | 1858 | encoder_type = DRM_MODE_ENCODER_LVDS; |
1775 | connector_type = DRM_MODE_CONNECTOR_LVDS; | 1859 | connector_type = DRM_MODE_CONNECTOR_LVDS; |
1860 | sdvo_priv->is_lvds = true; | ||
1776 | } | 1861 | } |
1777 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1) | 1862 | else if (sdvo_priv->caps.output_flags & SDVO_OUTPUT_LVDS1) |
1778 | { | 1863 | { |
1779 | sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1; | 1864 | sdvo_priv->controlled_output = SDVO_OUTPUT_LVDS1; |
1780 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1781 | encoder_type = DRM_MODE_ENCODER_LVDS; | 1865 | encoder_type = DRM_MODE_ENCODER_LVDS; |
1782 | connector_type = DRM_MODE_CONNECTOR_LVDS; | 1866 | connector_type = DRM_MODE_CONNECTOR_LVDS; |
1867 | sdvo_priv->is_lvds = true; | ||
1783 | } | 1868 | } |
1784 | else | 1869 | else |
1785 | { | 1870 | { |
@@ -1795,9 +1880,16 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
1795 | goto err_i2c; | 1880 | goto err_i2c; |
1796 | } | 1881 | } |
1797 | 1882 | ||
1883 | connector = &intel_output->base; | ||
1884 | drm_connector_init(dev, connector, &intel_sdvo_connector_funcs, | ||
1885 | connector_type); | ||
1886 | drm_connector_helper_add(connector, &intel_sdvo_connector_helper_funcs); | ||
1887 | connector->interlace_allowed = 0; | ||
1888 | connector->doublescan_allowed = 0; | ||
1889 | connector->display_info.subpixel_order = SubPixelHorizontalRGB; | ||
1890 | |||
1798 | drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); | 1891 | drm_encoder_init(dev, &intel_output->enc, &intel_sdvo_enc_funcs, encoder_type); |
1799 | drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); | 1892 | drm_encoder_helper_add(&intel_output->enc, &intel_sdvo_helper_funcs); |
1800 | connector->connector_type = connector_type; | ||
1801 | 1893 | ||
1802 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); | 1894 | drm_mode_connector_attach_encoder(&intel_output->base, &intel_output->enc); |
1803 | drm_sysfs_connector_add(connector); | 1895 | drm_sysfs_connector_add(connector); |
@@ -1829,14 +1921,13 @@ bool intel_sdvo_init(struct drm_device *dev, int output_device) | |||
1829 | sdvo_priv->caps.output_flags & | 1921 | sdvo_priv->caps.output_flags & |
1830 | (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); | 1922 | (SDVO_OUTPUT_TMDS1 | SDVO_OUTPUT_RGB1) ? 'Y' : 'N'); |
1831 | 1923 | ||
1832 | intel_output->ddc_bus = i2cbus; | ||
1833 | |||
1834 | return true; | 1924 | return true; |
1835 | 1925 | ||
1836 | err_i2c: | 1926 | err_i2c: |
1927 | if (ddcbus != NULL) | ||
1928 | intel_i2c_destroy(intel_output->ddc_bus); | ||
1837 | intel_i2c_destroy(intel_output->i2c_bus); | 1929 | intel_i2c_destroy(intel_output->i2c_bus); |
1838 | err_connector: | 1930 | err_inteloutput: |
1839 | drm_connector_cleanup(connector); | ||
1840 | kfree(intel_output); | 1931 | kfree(intel_output); |
1841 | 1932 | ||
1842 | return false; | 1933 | return false; |
diff --git a/drivers/isdn/gigaset/isocdata.c b/drivers/isdn/gigaset/isocdata.c index b171e75cb52e..29808c4fb1cb 100644 --- a/drivers/isdn/gigaset/isocdata.c +++ b/drivers/isdn/gigaset/isocdata.c | |||
@@ -175,7 +175,7 @@ int gigaset_isowbuf_getbytes(struct isowbuf_t *iwb, int size) | |||
175 | return -EINVAL; | 175 | return -EINVAL; |
176 | } | 176 | } |
177 | src = iwb->read; | 177 | src = iwb->read; |
178 | if (unlikely(limit > BAS_OUTBUFSIZE + BAS_OUTBUFPAD || | 178 | if (unlikely(limit >= BAS_OUTBUFSIZE + BAS_OUTBUFPAD || |
179 | (read < src && limit >= src))) { | 179 | (read < src && limit >= src))) { |
180 | pr_err("isoc write buffer frame reservation violated\n"); | 180 | pr_err("isoc write buffer frame reservation violated\n"); |
181 | return -EFAULT; | 181 | return -EFAULT; |
diff --git a/drivers/lguest/x86/core.c b/drivers/lguest/x86/core.c index 1a83910f674f..eaf722fe309a 100644 --- a/drivers/lguest/x86/core.c +++ b/drivers/lguest/x86/core.c | |||
@@ -358,6 +358,16 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu) | |||
358 | if (emulate_insn(cpu)) | 358 | if (emulate_insn(cpu)) |
359 | return; | 359 | return; |
360 | } | 360 | } |
361 | /* If KVM is active, the vmcall instruction triggers a | ||
362 | * General Protection Fault. Normally it triggers an | ||
363 | * invalid opcode fault (6): */ | ||
364 | case 6: | ||
365 | /* We need to check if ring == GUEST_PL and | ||
366 | * faulting instruction == vmcall. */ | ||
367 | if (is_hypercall(cpu)) { | ||
368 | rewrite_hypercall(cpu); | ||
369 | return; | ||
370 | } | ||
361 | break; | 371 | break; |
362 | case 14: /* We've intercepted a Page Fault. */ | 372 | case 14: /* We've intercepted a Page Fault. */ |
363 | /* The Guest accessed a virtual address that wasn't mapped. | 373 | /* The Guest accessed a virtual address that wasn't mapped. |
@@ -403,15 +413,6 @@ void lguest_arch_handle_trap(struct lg_cpu *cpu) | |||
403 | * up the pointer now to indicate a hypercall is pending. */ | 413 | * up the pointer now to indicate a hypercall is pending. */ |
404 | cpu->hcall = (struct hcall_args *)cpu->regs; | 414 | cpu->hcall = (struct hcall_args *)cpu->regs; |
405 | return; | 415 | return; |
406 | case 6: | ||
407 | /* kvm hypercalls trigger an invalid opcode fault (6). | ||
408 | * We need to check if ring == GUEST_PL and | ||
409 | * faulting instruction == vmcall. */ | ||
410 | if (is_hypercall(cpu)) { | ||
411 | rewrite_hypercall(cpu); | ||
412 | return; | ||
413 | } | ||
414 | break; | ||
415 | } | 416 | } |
416 | 417 | ||
417 | /* We didn't handle the trap, so it needs to go to the Guest. */ | 418 | /* We didn't handle the trap, so it needs to go to the Guest. */ |
diff --git a/drivers/md/bitmap.c b/drivers/md/bitmap.c index 47c68bc75a17..56df1cee8fb3 100644 --- a/drivers/md/bitmap.c +++ b/drivers/md/bitmap.c | |||
@@ -1097,14 +1097,12 @@ void bitmap_daemon_work(struct bitmap *bitmap) | |||
1097 | } | 1097 | } |
1098 | bitmap->allclean = 1; | 1098 | bitmap->allclean = 1; |
1099 | 1099 | ||
1100 | spin_lock_irqsave(&bitmap->lock, flags); | ||
1100 | for (j = 0; j < bitmap->chunks; j++) { | 1101 | for (j = 0; j < bitmap->chunks; j++) { |
1101 | bitmap_counter_t *bmc; | 1102 | bitmap_counter_t *bmc; |
1102 | spin_lock_irqsave(&bitmap->lock, flags); | 1103 | if (!bitmap->filemap) |
1103 | if (!bitmap->filemap) { | ||
1104 | /* error or shutdown */ | 1104 | /* error or shutdown */ |
1105 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
1106 | break; | 1105 | break; |
1107 | } | ||
1108 | 1106 | ||
1109 | page = filemap_get_page(bitmap, j); | 1107 | page = filemap_get_page(bitmap, j); |
1110 | 1108 | ||
@@ -1121,6 +1119,8 @@ void bitmap_daemon_work(struct bitmap *bitmap) | |||
1121 | write_page(bitmap, page, 0); | 1119 | write_page(bitmap, page, 0); |
1122 | bitmap->allclean = 0; | 1120 | bitmap->allclean = 0; |
1123 | } | 1121 | } |
1122 | spin_lock_irqsave(&bitmap->lock, flags); | ||
1123 | j |= (PAGE_BITS - 1); | ||
1124 | continue; | 1124 | continue; |
1125 | } | 1125 | } |
1126 | 1126 | ||
@@ -1181,9 +1181,10 @@ void bitmap_daemon_work(struct bitmap *bitmap) | |||
1181 | ext2_clear_bit(file_page_offset(j), paddr); | 1181 | ext2_clear_bit(file_page_offset(j), paddr); |
1182 | kunmap_atomic(paddr, KM_USER0); | 1182 | kunmap_atomic(paddr, KM_USER0); |
1183 | } | 1183 | } |
1184 | } | 1184 | } else |
1185 | spin_unlock_irqrestore(&bitmap->lock, flags); | 1185 | j |= PAGE_COUNTER_MASK; |
1186 | } | 1186 | } |
1187 | spin_unlock_irqrestore(&bitmap->lock, flags); | ||
1187 | 1188 | ||
1188 | /* now sync the final page */ | 1189 | /* now sync the final page */ |
1189 | if (lastpage != NULL) { | 1190 | if (lastpage != NULL) { |
diff --git a/drivers/md/md.c b/drivers/md/md.c index fccc8343a250..641b211fe3fe 100644 --- a/drivers/md/md.c +++ b/drivers/md/md.c | |||
@@ -1375,6 +1375,9 @@ static void super_1_sync(mddev_t *mddev, mdk_rdev_t *rdev) | |||
1375 | 1375 | ||
1376 | sb->raid_disks = cpu_to_le32(mddev->raid_disks); | 1376 | sb->raid_disks = cpu_to_le32(mddev->raid_disks); |
1377 | sb->size = cpu_to_le64(mddev->dev_sectors); | 1377 | sb->size = cpu_to_le64(mddev->dev_sectors); |
1378 | sb->chunksize = cpu_to_le32(mddev->chunk_size >> 9); | ||
1379 | sb->level = cpu_to_le32(mddev->level); | ||
1380 | sb->layout = cpu_to_le32(mddev->layout); | ||
1378 | 1381 | ||
1379 | if (mddev->bitmap && mddev->bitmap_file == NULL) { | 1382 | if (mddev->bitmap && mddev->bitmap_file == NULL) { |
1380 | sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); | 1383 | sb->bitmap_offset = cpu_to_le32((__u32)mddev->bitmap_offset); |
@@ -3303,7 +3306,9 @@ static ssize_t | |||
3303 | action_show(mddev_t *mddev, char *page) | 3306 | action_show(mddev_t *mddev, char *page) |
3304 | { | 3307 | { |
3305 | char *type = "idle"; | 3308 | char *type = "idle"; |
3306 | if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || | 3309 | if (test_bit(MD_RECOVERY_FROZEN, &mddev->recovery)) |
3310 | type = "frozen"; | ||
3311 | else if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery) || | ||
3307 | (!mddev->ro && test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))) { | 3312 | (!mddev->ro && test_bit(MD_RECOVERY_NEEDED, &mddev->recovery))) { |
3308 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) | 3313 | if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery)) |
3309 | type = "reshape"; | 3314 | type = "reshape"; |
@@ -3326,7 +3331,12 @@ action_store(mddev_t *mddev, const char *page, size_t len) | |||
3326 | if (!mddev->pers || !mddev->pers->sync_request) | 3331 | if (!mddev->pers || !mddev->pers->sync_request) |
3327 | return -EINVAL; | 3332 | return -EINVAL; |
3328 | 3333 | ||
3329 | if (cmd_match(page, "idle")) { | 3334 | if (cmd_match(page, "frozen")) |
3335 | set_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
3336 | else | ||
3337 | clear_bit(MD_RECOVERY_FROZEN, &mddev->recovery); | ||
3338 | |||
3339 | if (cmd_match(page, "idle") || cmd_match(page, "frozen")) { | ||
3330 | if (mddev->sync_thread) { | 3340 | if (mddev->sync_thread) { |
3331 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); | 3341 | set_bit(MD_RECOVERY_INTR, &mddev->recovery); |
3332 | md_unregister_thread(mddev->sync_thread); | 3342 | md_unregister_thread(mddev->sync_thread); |
@@ -3680,7 +3690,7 @@ array_size_store(mddev_t *mddev, const char *buf, size_t len) | |||
3680 | if (strict_blocks_to_sectors(buf, §ors) < 0) | 3690 | if (strict_blocks_to_sectors(buf, §ors) < 0) |
3681 | return -EINVAL; | 3691 | return -EINVAL; |
3682 | if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors) | 3692 | if (mddev->pers && mddev->pers->size(mddev, 0, 0) < sectors) |
3683 | return -EINVAL; | 3693 | return -E2BIG; |
3684 | 3694 | ||
3685 | mddev->external_size = 1; | 3695 | mddev->external_size = 1; |
3686 | } | 3696 | } |
@@ -5557,7 +5567,7 @@ static struct block_device_operations md_fops = | |||
5557 | .owner = THIS_MODULE, | 5567 | .owner = THIS_MODULE, |
5558 | .open = md_open, | 5568 | .open = md_open, |
5559 | .release = md_release, | 5569 | .release = md_release, |
5560 | .locked_ioctl = md_ioctl, | 5570 | .ioctl = md_ioctl, |
5561 | .getgeo = md_getgeo, | 5571 | .getgeo = md_getgeo, |
5562 | .media_changed = md_media_changed, | 5572 | .media_changed = md_media_changed, |
5563 | .revalidate_disk= md_revalidate, | 5573 | .revalidate_disk= md_revalidate, |
@@ -6352,12 +6362,13 @@ void md_do_sync(mddev_t *mddev) | |||
6352 | 6362 | ||
6353 | skipped = 0; | 6363 | skipped = 0; |
6354 | 6364 | ||
6355 | if ((mddev->curr_resync > mddev->curr_resync_completed && | 6365 | if (!test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) && |
6356 | (mddev->curr_resync - mddev->curr_resync_completed) | 6366 | ((mddev->curr_resync > mddev->curr_resync_completed && |
6357 | > (max_sectors >> 4)) || | 6367 | (mddev->curr_resync - mddev->curr_resync_completed) |
6358 | (j - mddev->curr_resync_completed)*2 | 6368 | > (max_sectors >> 4)) || |
6359 | >= mddev->resync_max - mddev->curr_resync_completed | 6369 | (j - mddev->curr_resync_completed)*2 |
6360 | ) { | 6370 | >= mddev->resync_max - mddev->curr_resync_completed |
6371 | )) { | ||
6361 | /* time to update curr_resync_completed */ | 6372 | /* time to update curr_resync_completed */ |
6362 | blk_unplug(mddev->queue); | 6373 | blk_unplug(mddev->queue); |
6363 | wait_event(mddev->recovery_wait, | 6374 | wait_event(mddev->recovery_wait, |
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c index 4616bc3a6e71..5d400aef8d9b 100644 --- a/drivers/md/raid5.c +++ b/drivers/md/raid5.c | |||
@@ -3811,13 +3811,13 @@ static sector_t reshape_request(mddev_t *mddev, sector_t sector_nr, int *skipped | |||
3811 | safepos = conf->reshape_safe; | 3811 | safepos = conf->reshape_safe; |
3812 | sector_div(safepos, data_disks); | 3812 | sector_div(safepos, data_disks); |
3813 | if (mddev->delta_disks < 0) { | 3813 | if (mddev->delta_disks < 0) { |
3814 | writepos -= reshape_sectors; | 3814 | writepos -= min_t(sector_t, reshape_sectors, writepos); |
3815 | readpos += reshape_sectors; | 3815 | readpos += reshape_sectors; |
3816 | safepos += reshape_sectors; | 3816 | safepos += reshape_sectors; |
3817 | } else { | 3817 | } else { |
3818 | writepos += reshape_sectors; | 3818 | writepos += reshape_sectors; |
3819 | readpos -= reshape_sectors; | 3819 | readpos -= min_t(sector_t, reshape_sectors, readpos); |
3820 | safepos -= reshape_sectors; | 3820 | safepos -= min_t(sector_t, reshape_sectors, safepos); |
3821 | } | 3821 | } |
3822 | 3822 | ||
3823 | /* 'writepos' is the most advanced device address we might write. | 3823 | /* 'writepos' is the most advanced device address we might write. |
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c index 3cf61ece71d7..348443bdb23b 100644 --- a/drivers/misc/enclosure.c +++ b/drivers/misc/enclosure.c | |||
@@ -119,7 +119,7 @@ enclosure_register(struct device *dev, const char *name, int components, | |||
119 | edev->edev.class = &enclosure_class; | 119 | edev->edev.class = &enclosure_class; |
120 | edev->edev.parent = get_device(dev); | 120 | edev->edev.parent = get_device(dev); |
121 | edev->cb = cb; | 121 | edev->cb = cb; |
122 | dev_set_name(&edev->edev, name); | 122 | dev_set_name(&edev->edev, "%s", name); |
123 | err = device_register(&edev->edev); | 123 | err = device_register(&edev->edev); |
124 | if (err) | 124 | if (err) |
125 | goto err; | 125 | goto err; |
@@ -255,8 +255,8 @@ enclosure_component_register(struct enclosure_device *edev, | |||
255 | ecomp->number = number; | 255 | ecomp->number = number; |
256 | cdev = &ecomp->cdev; | 256 | cdev = &ecomp->cdev; |
257 | cdev->parent = get_device(&edev->edev); | 257 | cdev->parent = get_device(&edev->edev); |
258 | if (name) | 258 | if (name && name[0]) |
259 | dev_set_name(cdev, name); | 259 | dev_set_name(cdev, "%s", name); |
260 | else | 260 | else |
261 | dev_set_name(cdev, "%u", number); | 261 | dev_set_name(cdev, "%u", number); |
262 | 262 | ||
diff --git a/drivers/net/Makefile b/drivers/net/Makefile index 1fc4602a6ff2..a1c25cb4669f 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile | |||
@@ -102,7 +102,7 @@ obj-$(CONFIG_HAMACHI) += hamachi.o | |||
102 | obj-$(CONFIG_NET) += Space.o loopback.o | 102 | obj-$(CONFIG_NET) += Space.o loopback.o |
103 | obj-$(CONFIG_SEEQ8005) += seeq8005.o | 103 | obj-$(CONFIG_SEEQ8005) += seeq8005.o |
104 | obj-$(CONFIG_NET_SB1000) += sb1000.o | 104 | obj-$(CONFIG_NET_SB1000) += sb1000.o |
105 | obj-$(CONFIG_MAC8390) += mac8390.o 8390.o | 105 | obj-$(CONFIG_MAC8390) += mac8390.o |
106 | obj-$(CONFIG_APNE) += apne.o 8390.o | 106 | obj-$(CONFIG_APNE) += apne.o 8390.o |
107 | obj-$(CONFIG_PCMCIA_PCNET) += 8390.o | 107 | obj-$(CONFIG_PCMCIA_PCNET) += 8390.o |
108 | obj-$(CONFIG_HP100) += hp100.o | 108 | obj-$(CONFIG_HP100) += hp100.o |
diff --git a/drivers/net/gianfar.c b/drivers/net/gianfar.c index b2c49679bba7..a0519184e54e 100644 --- a/drivers/net/gianfar.c +++ b/drivers/net/gianfar.c | |||
@@ -1885,8 +1885,17 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit) | |||
1885 | 1885 | ||
1886 | if (unlikely(!newskb)) | 1886 | if (unlikely(!newskb)) |
1887 | newskb = skb; | 1887 | newskb = skb; |
1888 | else if (skb) | 1888 | else if (skb) { |
1889 | /* | ||
1890 | * We need to reset ->data to what it | ||
1891 | * was before gfar_new_skb() re-aligned | ||
1892 | * it to an RXBUF_ALIGNMENT boundary | ||
1893 | * before we put the skb back on the | ||
1894 | * recycle list. | ||
1895 | */ | ||
1896 | skb->data = skb->head + NET_SKB_PAD; | ||
1889 | __skb_queue_head(&priv->rx_recycle, skb); | 1897 | __skb_queue_head(&priv->rx_recycle, skb); |
1898 | } | ||
1890 | } else { | 1899 | } else { |
1891 | /* Increment the number of packets */ | 1900 | /* Increment the number of packets */ |
1892 | dev->stats.rx_packets++; | 1901 | dev->stats.rx_packets++; |
diff --git a/drivers/net/mac8390.c b/drivers/net/mac8390.c index 8e884869a05b..f26667d5eaae 100644 --- a/drivers/net/mac8390.c +++ b/drivers/net/mac8390.c | |||
@@ -304,7 +304,7 @@ struct net_device * __init mac8390_probe(int unit) | |||
304 | if (!MACH_IS_MAC) | 304 | if (!MACH_IS_MAC) |
305 | return ERR_PTR(-ENODEV); | 305 | return ERR_PTR(-ENODEV); |
306 | 306 | ||
307 | dev = alloc_ei_netdev(); | 307 | dev = ____alloc_ei_netdev(0); |
308 | if (!dev) | 308 | if (!dev) |
309 | return ERR_PTR(-ENOMEM); | 309 | return ERR_PTR(-ENOMEM); |
310 | 310 | ||
@@ -481,10 +481,10 @@ void cleanup_module(void) | |||
481 | static const struct net_device_ops mac8390_netdev_ops = { | 481 | static const struct net_device_ops mac8390_netdev_ops = { |
482 | .ndo_open = mac8390_open, | 482 | .ndo_open = mac8390_open, |
483 | .ndo_stop = mac8390_close, | 483 | .ndo_stop = mac8390_close, |
484 | .ndo_start_xmit = ei_start_xmit, | 484 | .ndo_start_xmit = __ei_start_xmit, |
485 | .ndo_tx_timeout = ei_tx_timeout, | 485 | .ndo_tx_timeout = __ei_tx_timeout, |
486 | .ndo_get_stats = ei_get_stats, | 486 | .ndo_get_stats = __ei_get_stats, |
487 | .ndo_set_multicast_list = ei_set_multicast_list, | 487 | .ndo_set_multicast_list = __ei_set_multicast_list, |
488 | .ndo_validate_addr = eth_validate_addr, | 488 | .ndo_validate_addr = eth_validate_addr, |
489 | .ndo_set_mac_address = eth_mac_addr, | 489 | .ndo_set_mac_address = eth_mac_addr, |
490 | .ndo_change_mtu = eth_change_mtu, | 490 | .ndo_change_mtu = eth_change_mtu, |
diff --git a/drivers/net/r8169.c b/drivers/net/r8169.c index 0b6e8c896835..8247a945a1d9 100644 --- a/drivers/net/r8169.c +++ b/drivers/net/r8169.c | |||
@@ -3554,54 +3554,64 @@ static irqreturn_t rtl8169_interrupt(int irq, void *dev_instance) | |||
3554 | int handled = 0; | 3554 | int handled = 0; |
3555 | int status; | 3555 | int status; |
3556 | 3556 | ||
3557 | /* loop handling interrupts until we have no new ones or | ||
3558 | * we hit a invalid/hotplug case. | ||
3559 | */ | ||
3557 | status = RTL_R16(IntrStatus); | 3560 | status = RTL_R16(IntrStatus); |
3561 | while (status && status != 0xffff) { | ||
3562 | handled = 1; | ||
3558 | 3563 | ||
3559 | /* hotplug/major error/no more work/shared irq */ | 3564 | /* Handle all of the error cases first. These will reset |
3560 | if ((status == 0xffff) || !status) | 3565 | * the chip, so just exit the loop. |
3561 | goto out; | 3566 | */ |
3562 | 3567 | if (unlikely(!netif_running(dev))) { | |
3563 | handled = 1; | 3568 | rtl8169_asic_down(ioaddr); |
3569 | break; | ||
3570 | } | ||
3564 | 3571 | ||
3565 | if (unlikely(!netif_running(dev))) { | 3572 | /* Work around for rx fifo overflow */ |
3566 | rtl8169_asic_down(ioaddr); | 3573 | if (unlikely(status & RxFIFOOver) && |
3567 | goto out; | 3574 | (tp->mac_version == RTL_GIGA_MAC_VER_11)) { |
3568 | } | 3575 | netif_stop_queue(dev); |
3576 | rtl8169_tx_timeout(dev); | ||
3577 | break; | ||
3578 | } | ||
3569 | 3579 | ||
3570 | status &= tp->intr_mask; | 3580 | if (unlikely(status & SYSErr)) { |
3571 | RTL_W16(IntrStatus, | 3581 | rtl8169_pcierr_interrupt(dev); |
3572 | (status & RxFIFOOver) ? (status | RxOverflow) : status); | 3582 | break; |
3583 | } | ||
3573 | 3584 | ||
3574 | if (!(status & tp->intr_event)) | 3585 | if (status & LinkChg) |
3575 | goto out; | 3586 | rtl8169_check_link_status(dev, tp, ioaddr); |
3576 | 3587 | ||
3577 | /* Work around for rx fifo overflow */ | 3588 | /* We need to see the lastest version of tp->intr_mask to |
3578 | if (unlikely(status & RxFIFOOver) && | 3589 | * avoid ignoring an MSI interrupt and having to wait for |
3579 | (tp->mac_version == RTL_GIGA_MAC_VER_11)) { | 3590 | * another event which may never come. |
3580 | netif_stop_queue(dev); | 3591 | */ |
3581 | rtl8169_tx_timeout(dev); | 3592 | smp_rmb(); |
3582 | goto out; | 3593 | if (status & tp->intr_mask & tp->napi_event) { |
3583 | } | 3594 | RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); |
3595 | tp->intr_mask = ~tp->napi_event; | ||
3596 | |||
3597 | if (likely(napi_schedule_prep(&tp->napi))) | ||
3598 | __napi_schedule(&tp->napi); | ||
3599 | else if (netif_msg_intr(tp)) { | ||
3600 | printk(KERN_INFO "%s: interrupt %04x in poll\n", | ||
3601 | dev->name, status); | ||
3602 | } | ||
3603 | } | ||
3584 | 3604 | ||
3585 | if (unlikely(status & SYSErr)) { | 3605 | /* We only get a new MSI interrupt when all active irq |
3586 | rtl8169_pcierr_interrupt(dev); | 3606 | * sources on the chip have been acknowledged. So, ack |
3587 | goto out; | 3607 | * everything we've seen and check if new sources have become |
3608 | * active to avoid blocking all interrupts from the chip. | ||
3609 | */ | ||
3610 | RTL_W16(IntrStatus, | ||
3611 | (status & RxFIFOOver) ? (status | RxOverflow) : status); | ||
3612 | status = RTL_R16(IntrStatus); | ||
3588 | } | 3613 | } |
3589 | 3614 | ||
3590 | if (status & LinkChg) | ||
3591 | rtl8169_check_link_status(dev, tp, ioaddr); | ||
3592 | |||
3593 | if (status & tp->napi_event) { | ||
3594 | RTL_W16(IntrMask, tp->intr_event & ~tp->napi_event); | ||
3595 | tp->intr_mask = ~tp->napi_event; | ||
3596 | |||
3597 | if (likely(napi_schedule_prep(&tp->napi))) | ||
3598 | __napi_schedule(&tp->napi); | ||
3599 | else if (netif_msg_intr(tp)) { | ||
3600 | printk(KERN_INFO "%s: interrupt %04x in poll\n", | ||
3601 | dev->name, status); | ||
3602 | } | ||
3603 | } | ||
3604 | out: | ||
3605 | return IRQ_RETVAL(handled); | 3615 | return IRQ_RETVAL(handled); |
3606 | } | 3616 | } |
3607 | 3617 | ||
@@ -3617,13 +3627,15 @@ static int rtl8169_poll(struct napi_struct *napi, int budget) | |||
3617 | 3627 | ||
3618 | if (work_done < budget) { | 3628 | if (work_done < budget) { |
3619 | napi_complete(napi); | 3629 | napi_complete(napi); |
3620 | tp->intr_mask = 0xffff; | 3630 | |
3621 | /* | 3631 | /* We need for force the visibility of tp->intr_mask |
3622 | * 20040426: the barrier is not strictly required but the | 3632 | * for other CPUs, as we can loose an MSI interrupt |
3623 | * behavior of the irq handler could be less predictable | 3633 | * and potentially wait for a retransmit timeout if we don't. |
3624 | * without it. Btw, the lack of flush for the posted pci | 3634 | * The posted write to IntrMask is safe, as it will |
3625 | * write is safe - FR | 3635 | * eventually make it to the chip and we won't loose anything |
3636 | * until it does. | ||
3626 | */ | 3637 | */ |
3638 | tp->intr_mask = 0xffff; | ||
3627 | smp_wmb(); | 3639 | smp_wmb(); |
3628 | RTL_W16(IntrMask, tp->intr_event); | 3640 | RTL_W16(IntrMask, tp->intr_event); |
3629 | } | 3641 | } |
diff --git a/drivers/net/wimax/i2400m/usb.c b/drivers/net/wimax/i2400m/usb.c index ca4151a9e222..17851321b7fd 100644 --- a/drivers/net/wimax/i2400m/usb.c +++ b/drivers/net/wimax/i2400m/usb.c | |||
@@ -505,27 +505,52 @@ int i2400mu_suspend(struct usb_interface *iface, pm_message_t pm_msg) | |||
505 | #ifdef CONFIG_PM | 505 | #ifdef CONFIG_PM |
506 | struct usb_device *usb_dev = i2400mu->usb_dev; | 506 | struct usb_device *usb_dev = i2400mu->usb_dev; |
507 | #endif | 507 | #endif |
508 | unsigned is_autosuspend = 0; | ||
508 | struct i2400m *i2400m = &i2400mu->i2400m; | 509 | struct i2400m *i2400m = &i2400mu->i2400m; |
509 | 510 | ||
511 | #ifdef CONFIG_PM | ||
512 | if (usb_dev->auto_pm > 0) | ||
513 | is_autosuspend = 1; | ||
514 | #endif | ||
515 | |||
510 | d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); | 516 | d_fnstart(3, dev, "(iface %p pm_msg %u)\n", iface, pm_msg.event); |
511 | if (i2400m->updown == 0) | 517 | if (i2400m->updown == 0) |
512 | goto no_firmware; | 518 | goto no_firmware; |
513 | d_printf(1, dev, "fw up, requesting standby\n"); | 519 | if (i2400m->state == I2400M_SS_DATA_PATH_CONNECTED && is_autosuspend) { |
520 | /* ugh -- the device is connected and this suspend | ||
521 | * request is an autosuspend one (not a system standby | ||
522 | * / hibernate). | ||
523 | * | ||
524 | * The only way the device can go to standby is if the | ||
525 | * link with the base station is in IDLE mode; that | ||
526 | * were the case, we'd be in status | ||
527 | * I2400M_SS_CONNECTED_IDLE. But we are not. | ||
528 | * | ||
529 | * If we *tell* him to go power save now, it'll reset | ||
530 | * as a precautionary measure, so if this is an | ||
531 | * autosuspend thing, say no and it'll come back | ||
532 | * later, when the link is IDLE | ||
533 | */ | ||
534 | result = -EBADF; | ||
535 | d_printf(1, dev, "fw up, link up, not-idle, autosuspend: " | ||
536 | "not entering powersave\n"); | ||
537 | goto error_not_now; | ||
538 | } | ||
539 | d_printf(1, dev, "fw up: entering powersave\n"); | ||
514 | atomic_dec(&i2400mu->do_autopm); | 540 | atomic_dec(&i2400mu->do_autopm); |
515 | result = i2400m_cmd_enter_powersave(i2400m); | 541 | result = i2400m_cmd_enter_powersave(i2400m); |
516 | atomic_inc(&i2400mu->do_autopm); | 542 | atomic_inc(&i2400mu->do_autopm); |
517 | #ifdef CONFIG_PM | 543 | if (result < 0 && !is_autosuspend) { |
518 | if (result < 0 && usb_dev->auto_pm == 0) { | ||
519 | /* System suspend, can't fail */ | 544 | /* System suspend, can't fail */ |
520 | dev_err(dev, "failed to suspend, will reset on resume\n"); | 545 | dev_err(dev, "failed to suspend, will reset on resume\n"); |
521 | result = 0; | 546 | result = 0; |
522 | } | 547 | } |
523 | #endif | ||
524 | if (result < 0) | 548 | if (result < 0) |
525 | goto error_enter_powersave; | 549 | goto error_enter_powersave; |
526 | i2400mu_notification_release(i2400mu); | 550 | i2400mu_notification_release(i2400mu); |
527 | d_printf(1, dev, "fw up, got standby\n"); | 551 | d_printf(1, dev, "powersave requested\n"); |
528 | error_enter_powersave: | 552 | error_enter_powersave: |
553 | error_not_now: | ||
529 | no_firmware: | 554 | no_firmware: |
530 | d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", | 555 | d_fnend(3, dev, "(iface %p pm_msg %u) = %d\n", |
531 | iface, pm_msg.event, result); | 556 | iface, pm_msg.event, result); |
diff --git a/drivers/net/wireless/airo.c b/drivers/net/wireless/airo.c index d73475739127..9eabf4d1f2e7 100644 --- a/drivers/net/wireless/airo.c +++ b/drivers/net/wireless/airo.c | |||
@@ -6467,6 +6467,7 @@ static int airo_get_encode(struct net_device *dev, | |||
6467 | { | 6467 | { |
6468 | struct airo_info *local = dev->ml_priv; | 6468 | struct airo_info *local = dev->ml_priv; |
6469 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; | 6469 | int index = (dwrq->flags & IW_ENCODE_INDEX) - 1; |
6470 | int wep_key_len; | ||
6470 | u8 buf[16]; | 6471 | u8 buf[16]; |
6471 | 6472 | ||
6472 | if (!local->wep_capable) | 6473 | if (!local->wep_capable) |
@@ -6500,11 +6501,13 @@ static int airo_get_encode(struct net_device *dev, | |||
6500 | dwrq->flags |= index + 1; | 6501 | dwrq->flags |= index + 1; |
6501 | 6502 | ||
6502 | /* Copy the key to the user buffer */ | 6503 | /* Copy the key to the user buffer */ |
6503 | dwrq->length = get_wep_key(local, index, &buf[0], sizeof(buf)); | 6504 | wep_key_len = get_wep_key(local, index, &buf[0], sizeof(buf)); |
6504 | if (dwrq->length != -1) | 6505 | if (wep_key_len < 0) { |
6505 | memcpy(extra, buf, dwrq->length); | ||
6506 | else | ||
6507 | dwrq->length = 0; | 6506 | dwrq->length = 0; |
6507 | } else { | ||
6508 | dwrq->length = wep_key_len; | ||
6509 | memcpy(extra, buf, dwrq->length); | ||
6510 | } | ||
6508 | 6511 | ||
6509 | return 0; | 6512 | return 0; |
6510 | } | 6513 | } |
@@ -6617,7 +6620,7 @@ static int airo_get_encodeext(struct net_device *dev, | |||
6617 | struct airo_info *local = dev->ml_priv; | 6620 | struct airo_info *local = dev->ml_priv; |
6618 | struct iw_point *encoding = &wrqu->encoding; | 6621 | struct iw_point *encoding = &wrqu->encoding; |
6619 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; | 6622 | struct iw_encode_ext *ext = (struct iw_encode_ext *)extra; |
6620 | int idx, max_key_len; | 6623 | int idx, max_key_len, wep_key_len; |
6621 | u8 buf[16]; | 6624 | u8 buf[16]; |
6622 | 6625 | ||
6623 | if (!local->wep_capable) | 6626 | if (!local->wep_capable) |
@@ -6661,11 +6664,13 @@ static int airo_get_encodeext(struct net_device *dev, | |||
6661 | memset(extra, 0, 16); | 6664 | memset(extra, 0, 16); |
6662 | 6665 | ||
6663 | /* Copy the key to the user buffer */ | 6666 | /* Copy the key to the user buffer */ |
6664 | ext->key_len = get_wep_key(local, idx, &buf[0], sizeof(buf)); | 6667 | wep_key_len = get_wep_key(local, idx, &buf[0], sizeof(buf)); |
6665 | if (ext->key_len != -1) | 6668 | if (wep_key_len < 0) { |
6666 | memcpy(extra, buf, ext->key_len); | ||
6667 | else | ||
6668 | ext->key_len = 0; | 6669 | ext->key_len = 0; |
6670 | } else { | ||
6671 | ext->key_len = wep_key_len; | ||
6672 | memcpy(extra, buf, ext->key_len); | ||
6673 | } | ||
6669 | 6674 | ||
6670 | return 0; | 6675 | return 0; |
6671 | } | 6676 | } |
diff --git a/drivers/net/wireless/ath5k/phy.c b/drivers/net/wireless/ath5k/phy.c index 9e2faae5ae94..b48b29dca3d2 100644 --- a/drivers/net/wireless/ath5k/phy.c +++ b/drivers/net/wireless/ath5k/phy.c | |||
@@ -1487,28 +1487,35 @@ ath5k_get_linear_pcdac_min(const u8 *stepL, const u8 *stepR, | |||
1487 | { | 1487 | { |
1488 | s8 tmp; | 1488 | s8 tmp; |
1489 | s16 min_pwrL, min_pwrR; | 1489 | s16 min_pwrL, min_pwrR; |
1490 | s16 pwr_i = pwrL[0]; | 1490 | s16 pwr_i; |
1491 | 1491 | ||
1492 | do { | 1492 | if (pwrL[0] == pwrL[1]) |
1493 | pwr_i--; | 1493 | min_pwrL = pwrL[0]; |
1494 | tmp = (s8) ath5k_get_interpolated_value(pwr_i, | 1494 | else { |
1495 | pwrL[0], pwrL[1], | 1495 | pwr_i = pwrL[0]; |
1496 | stepL[0], stepL[1]); | 1496 | do { |
1497 | 1497 | pwr_i--; | |
1498 | } while (tmp > 1); | 1498 | tmp = (s8) ath5k_get_interpolated_value(pwr_i, |
1499 | 1499 | pwrL[0], pwrL[1], | |
1500 | min_pwrL = pwr_i; | 1500 | stepL[0], stepL[1]); |
1501 | 1501 | } while (tmp > 1); | |
1502 | pwr_i = pwrR[0]; | 1502 | |
1503 | do { | 1503 | min_pwrL = pwr_i; |
1504 | pwr_i--; | 1504 | } |
1505 | tmp = (s8) ath5k_get_interpolated_value(pwr_i, | ||
1506 | pwrR[0], pwrR[1], | ||
1507 | stepR[0], stepR[1]); | ||
1508 | |||
1509 | } while (tmp > 1); | ||
1510 | 1505 | ||
1511 | min_pwrR = pwr_i; | 1506 | if (pwrR[0] == pwrR[1]) |
1507 | min_pwrR = pwrR[0]; | ||
1508 | else { | ||
1509 | pwr_i = pwrR[0]; | ||
1510 | do { | ||
1511 | pwr_i--; | ||
1512 | tmp = (s8) ath5k_get_interpolated_value(pwr_i, | ||
1513 | pwrR[0], pwrR[1], | ||
1514 | stepR[0], stepR[1]); | ||
1515 | } while (tmp > 1); | ||
1516 | |||
1517 | min_pwrR = pwr_i; | ||
1518 | } | ||
1512 | 1519 | ||
1513 | /* Keep the right boundary so that it works for both curves */ | 1520 | /* Keep the right boundary so that it works for both curves */ |
1514 | return max(min_pwrL, min_pwrR); | 1521 | return max(min_pwrL, min_pwrR); |
diff --git a/drivers/net/wireless/ath5k/reset.c b/drivers/net/wireless/ath5k/reset.c index 7a17d31b2fd9..5f72c111c2e8 100644 --- a/drivers/net/wireless/ath5k/reset.c +++ b/drivers/net/wireless/ath5k/reset.c | |||
@@ -26,7 +26,7 @@ | |||
26 | \*****************************/ | 26 | \*****************************/ |
27 | 27 | ||
28 | #include <linux/pci.h> /* To determine if a card is pci-e */ | 28 | #include <linux/pci.h> /* To determine if a card is pci-e */ |
29 | #include <linux/bitops.h> /* For get_bitmask_order */ | 29 | #include <linux/log2.h> |
30 | #include "ath5k.h" | 30 | #include "ath5k.h" |
31 | #include "reg.h" | 31 | #include "reg.h" |
32 | #include "base.h" | 32 | #include "base.h" |
@@ -69,10 +69,10 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah, | |||
69 | 69 | ||
70 | /* Get exponent | 70 | /* Get exponent |
71 | * ALGO: coef_exp = 14 - highest set bit position */ | 71 | * ALGO: coef_exp = 14 - highest set bit position */ |
72 | coef_exp = get_bitmask_order(coef_scaled); | 72 | coef_exp = ilog2(coef_scaled); |
73 | 73 | ||
74 | /* Doesn't make sense if it's zero*/ | 74 | /* Doesn't make sense if it's zero*/ |
75 | if (!coef_exp) | 75 | if (!coef_scaled || !coef_exp) |
76 | return -EINVAL; | 76 | return -EINVAL; |
77 | 77 | ||
78 | /* Note: we've shifted coef_scaled by 24 */ | 78 | /* Note: we've shifted coef_scaled by 24 */ |
@@ -359,7 +359,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial) | |||
359 | mode |= AR5K_PHY_MODE_FREQ_5GHZ; | 359 | mode |= AR5K_PHY_MODE_FREQ_5GHZ; |
360 | 360 | ||
361 | if (ah->ah_radio == AR5K_RF5413) | 361 | if (ah->ah_radio == AR5K_RF5413) |
362 | clock |= AR5K_PHY_PLL_40MHZ_5413; | 362 | clock = AR5K_PHY_PLL_40MHZ_5413; |
363 | else | 363 | else |
364 | clock |= AR5K_PHY_PLL_40MHZ; | 364 | clock |= AR5K_PHY_PLL_40MHZ; |
365 | 365 | ||
diff --git a/drivers/net/wireless/iwlwifi/iwl-5000.c b/drivers/net/wireless/iwlwifi/iwl-5000.c index e5ca2511a81a..9452461ce864 100644 --- a/drivers/net/wireless/iwlwifi/iwl-5000.c +++ b/drivers/net/wireless/iwlwifi/iwl-5000.c | |||
@@ -46,7 +46,7 @@ | |||
46 | #include "iwl-6000-hw.h" | 46 | #include "iwl-6000-hw.h" |
47 | 47 | ||
48 | /* Highest firmware API version supported */ | 48 | /* Highest firmware API version supported */ |
49 | #define IWL5000_UCODE_API_MAX 1 | 49 | #define IWL5000_UCODE_API_MAX 2 |
50 | #define IWL5150_UCODE_API_MAX 2 | 50 | #define IWL5150_UCODE_API_MAX 2 |
51 | 51 | ||
52 | /* Lowest firmware API version supported */ | 52 | /* Lowest firmware API version supported */ |
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c index 3bb28db4a40f..f46ba2475776 100644 --- a/drivers/net/wireless/iwlwifi/iwl-agn.c +++ b/drivers/net/wireless/iwlwifi/iwl-agn.c | |||
@@ -669,13 +669,6 @@ static int iwl_set_mode(struct iwl_priv *priv, int mode) | |||
669 | if (!iwl_is_ready_rf(priv)) | 669 | if (!iwl_is_ready_rf(priv)) |
670 | return -EAGAIN; | 670 | return -EAGAIN; |
671 | 671 | ||
672 | cancel_delayed_work(&priv->scan_check); | ||
673 | if (iwl_scan_cancel_timeout(priv, 100)) { | ||
674 | IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); | ||
675 | IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); | ||
676 | return -EAGAIN; | ||
677 | } | ||
678 | |||
679 | iwl_commit_rxon(priv); | 672 | iwl_commit_rxon(priv); |
680 | 673 | ||
681 | return 0; | 674 | return 0; |
diff --git a/drivers/net/wireless/iwlwifi/iwl-scan.c b/drivers/net/wireless/iwlwifi/iwl-scan.c index e7c65c4f741b..6330b91e37ce 100644 --- a/drivers/net/wireless/iwlwifi/iwl-scan.c +++ b/drivers/net/wireless/iwlwifi/iwl-scan.c | |||
@@ -227,9 +227,6 @@ static void iwl_rx_scan_complete_notif(struct iwl_priv *priv, | |||
227 | /* The HW is no longer scanning */ | 227 | /* The HW is no longer scanning */ |
228 | clear_bit(STATUS_SCAN_HW, &priv->status); | 228 | clear_bit(STATUS_SCAN_HW, &priv->status); |
229 | 229 | ||
230 | /* The scan completion notification came in, so kill that timer... */ | ||
231 | cancel_delayed_work(&priv->scan_check); | ||
232 | |||
233 | IWL_DEBUG_INFO(priv, "Scan pass on %sGHz took %dms\n", | 230 | IWL_DEBUG_INFO(priv, "Scan pass on %sGHz took %dms\n", |
234 | (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ? | 231 | (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ? |
235 | "2.4" : "5.2", | 232 | "2.4" : "5.2", |
@@ -712,6 +709,8 @@ static void iwl_bg_request_scan(struct work_struct *data) | |||
712 | 709 | ||
713 | mutex_lock(&priv->mutex); | 710 | mutex_lock(&priv->mutex); |
714 | 711 | ||
712 | cancel_delayed_work(&priv->scan_check); | ||
713 | |||
715 | if (!iwl_is_ready(priv)) { | 714 | if (!iwl_is_ready(priv)) { |
716 | IWL_WARN(priv, "request scan called when driver not ready.\n"); | 715 | IWL_WARN(priv, "request scan called when driver not ready.\n"); |
717 | goto done; | 716 | goto done; |
@@ -925,6 +924,8 @@ void iwl_bg_scan_completed(struct work_struct *work) | |||
925 | 924 | ||
926 | IWL_DEBUG_SCAN(priv, "SCAN complete scan\n"); | 925 | IWL_DEBUG_SCAN(priv, "SCAN complete scan\n"); |
927 | 926 | ||
927 | cancel_delayed_work(&priv->scan_check); | ||
928 | |||
928 | ieee80211_scan_completed(priv->hw, false); | 929 | ieee80211_scan_completed(priv->hw, false); |
929 | 930 | ||
930 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) | 931 | if (test_bit(STATUS_EXIT_PENDING, &priv->status)) |
diff --git a/drivers/net/wireless/iwlwifi/iwl3945-base.c b/drivers/net/wireless/iwlwifi/iwl3945-base.c index 4cce66133500..ff4d0e41d7c4 100644 --- a/drivers/net/wireless/iwlwifi/iwl3945-base.c +++ b/drivers/net/wireless/iwlwifi/iwl3945-base.c | |||
@@ -782,13 +782,6 @@ static int iwl3945_set_mode(struct iwl_priv *priv, int mode) | |||
782 | if (!iwl_is_ready_rf(priv)) | 782 | if (!iwl_is_ready_rf(priv)) |
783 | return -EAGAIN; | 783 | return -EAGAIN; |
784 | 784 | ||
785 | cancel_delayed_work(&priv->scan_check); | ||
786 | if (iwl_scan_cancel_timeout(priv, 100)) { | ||
787 | IWL_WARN(priv, "Aborted scan still in progress after 100ms\n"); | ||
788 | IWL_DEBUG_MAC80211(priv, "leaving - scan abort failed.\n"); | ||
789 | return -EAGAIN; | ||
790 | } | ||
791 | |||
792 | iwl3945_commit_rxon(priv); | 785 | iwl3945_commit_rxon(priv); |
793 | 786 | ||
794 | return 0; | 787 | return 0; |
@@ -3298,6 +3291,8 @@ static void iwl3945_bg_request_scan(struct work_struct *data) | |||
3298 | 3291 | ||
3299 | mutex_lock(&priv->mutex); | 3292 | mutex_lock(&priv->mutex); |
3300 | 3293 | ||
3294 | cancel_delayed_work(&priv->scan_check); | ||
3295 | |||
3301 | if (!iwl_is_ready(priv)) { | 3296 | if (!iwl_is_ready(priv)) { |
3302 | IWL_WARN(priv, "request scan called when driver not ready.\n"); | 3297 | IWL_WARN(priv, "request scan called when driver not ready.\n"); |
3303 | goto done; | 3298 | goto done; |
diff --git a/drivers/net/wireless/rt2x00/rt2x00debug.c b/drivers/net/wireless/rt2x00/rt2x00debug.c index 07d378ef0b46..7b3ee8c2eaef 100644 --- a/drivers/net/wireless/rt2x00/rt2x00debug.c +++ b/drivers/net/wireless/rt2x00/rt2x00debug.c | |||
@@ -138,7 +138,7 @@ void rt2x00debug_update_crypto(struct rt2x00_dev *rt2x00dev, | |||
138 | 138 | ||
139 | if (cipher == CIPHER_TKIP_NO_MIC) | 139 | if (cipher == CIPHER_TKIP_NO_MIC) |
140 | cipher = CIPHER_TKIP; | 140 | cipher = CIPHER_TKIP; |
141 | if (cipher == CIPHER_NONE || cipher > CIPHER_MAX) | 141 | if (cipher == CIPHER_NONE || cipher >= CIPHER_MAX) |
142 | return; | 142 | return; |
143 | 143 | ||
144 | /* Remove CIPHER_NONE index */ | 144 | /* Remove CIPHER_NONE index */ |
diff --git a/drivers/oprofile/cpu_buffer.c b/drivers/oprofile/cpu_buffer.c index f0e99d4c066b..242257b19441 100644 --- a/drivers/oprofile/cpu_buffer.c +++ b/drivers/oprofile/cpu_buffer.c | |||
@@ -78,16 +78,20 @@ void free_cpu_buffers(void) | |||
78 | op_ring_buffer_write = NULL; | 78 | op_ring_buffer_write = NULL; |
79 | } | 79 | } |
80 | 80 | ||
81 | #define RB_EVENT_HDR_SIZE 4 | ||
82 | |||
81 | int alloc_cpu_buffers(void) | 83 | int alloc_cpu_buffers(void) |
82 | { | 84 | { |
83 | int i; | 85 | int i; |
84 | 86 | ||
85 | unsigned long buffer_size = oprofile_cpu_buffer_size; | 87 | unsigned long buffer_size = oprofile_cpu_buffer_size; |
88 | unsigned long byte_size = buffer_size * (sizeof(struct op_sample) + | ||
89 | RB_EVENT_HDR_SIZE); | ||
86 | 90 | ||
87 | op_ring_buffer_read = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS); | 91 | op_ring_buffer_read = ring_buffer_alloc(byte_size, OP_BUFFER_FLAGS); |
88 | if (!op_ring_buffer_read) | 92 | if (!op_ring_buffer_read) |
89 | goto fail; | 93 | goto fail; |
90 | op_ring_buffer_write = ring_buffer_alloc(buffer_size, OP_BUFFER_FLAGS); | 94 | op_ring_buffer_write = ring_buffer_alloc(byte_size, OP_BUFFER_FLAGS); |
91 | if (!op_ring_buffer_write) | 95 | if (!op_ring_buffer_write) |
92 | goto fail; | 96 | goto fail; |
93 | 97 | ||
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c index 8b7983aba8f7..36c21b19e5d7 100644 --- a/drivers/scsi/3w-9xxx.c +++ b/drivers/scsi/3w-9xxx.c | |||
@@ -1978,7 +1978,8 @@ static void twa_unmap_scsi_data(TW_Device_Extension *tw_dev, int request_id) | |||
1978 | { | 1978 | { |
1979 | struct scsi_cmnd *cmd = tw_dev->srb[request_id]; | 1979 | struct scsi_cmnd *cmd = tw_dev->srb[request_id]; |
1980 | 1980 | ||
1981 | scsi_dma_unmap(cmd); | 1981 | if (cmd->SCp.phase == TW_PHASE_SGLIST) |
1982 | scsi_dma_unmap(cmd); | ||
1982 | } /* End twa_unmap_scsi_data() */ | 1983 | } /* End twa_unmap_scsi_data() */ |
1983 | 1984 | ||
1984 | /* scsi_host_template initializer */ | 1985 | /* scsi_host_template initializer */ |
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index c03f1d2c9e2e..faa0fcfed71e 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c | |||
@@ -6,7 +6,7 @@ | |||
6 | Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 6 | Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
7 | Brad Strand <linux@3ware.com> | 7 | Brad Strand <linux@3ware.com> |
8 | 8 | ||
9 | Copyright (C) 1999-2007 3ware Inc. | 9 | Copyright (C) 1999-2009 3ware Inc. |
10 | 10 | ||
11 | Kernel compatiblity By: Andre Hedrick <andre@suse.com> | 11 | Kernel compatiblity By: Andre Hedrick <andre@suse.com> |
12 | Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> | 12 | Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> |
@@ -1294,7 +1294,8 @@ static void tw_unmap_scsi_data(struct pci_dev *pdev, struct scsi_cmnd *cmd) | |||
1294 | { | 1294 | { |
1295 | dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n"); | 1295 | dprintk(KERN_WARNING "3w-xxxx: tw_unmap_scsi_data()\n"); |
1296 | 1296 | ||
1297 | scsi_dma_unmap(cmd); | 1297 | if (cmd->SCp.phase == TW_PHASE_SGLIST) |
1298 | scsi_dma_unmap(cmd); | ||
1298 | } /* End tw_unmap_scsi_data() */ | 1299 | } /* End tw_unmap_scsi_data() */ |
1299 | 1300 | ||
1300 | /* This function will reset a device extension */ | 1301 | /* This function will reset a device extension */ |
diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 8e71e5e122b3..a5a2ba2561d9 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h | |||
@@ -6,7 +6,7 @@ | |||
6 | Arnaldo Carvalho de Melo <acme@conectiva.com.br> | 6 | Arnaldo Carvalho de Melo <acme@conectiva.com.br> |
7 | Brad Strand <linux@3ware.com> | 7 | Brad Strand <linux@3ware.com> |
8 | 8 | ||
9 | Copyright (C) 1999-2007 3ware Inc. | 9 | Copyright (C) 1999-2009 3ware Inc. |
10 | 10 | ||
11 | Kernel compatiblity By: Andre Hedrick <andre@suse.com> | 11 | Kernel compatiblity By: Andre Hedrick <andre@suse.com> |
12 | Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> | 12 | Non-Copyright (C) 2000 Andre Hedrick <andre@suse.com> |
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig index 8ed2990c826e..fb2740789b68 100644 --- a/drivers/scsi/Kconfig +++ b/drivers/scsi/Kconfig | |||
@@ -628,6 +628,17 @@ config FCOE | |||
628 | ---help--- | 628 | ---help--- |
629 | Fibre Channel over Ethernet module | 629 | Fibre Channel over Ethernet module |
630 | 630 | ||
631 | config FCOE_FNIC | ||
632 | tristate "Cisco FNIC Driver" | ||
633 | depends on PCI && X86 | ||
634 | select LIBFC | ||
635 | help | ||
636 | This is support for the Cisco PCI-Express FCoE HBA. | ||
637 | |||
638 | To compile this driver as a module, choose M here and read | ||
639 | <file:Documentation/scsi/scsi.txt>. | ||
640 | The module will be called fnic. | ||
641 | |||
631 | config SCSI_DMX3191D | 642 | config SCSI_DMX3191D |
632 | tristate "DMX3191D SCSI support" | 643 | tristate "DMX3191D SCSI support" |
633 | depends on PCI && SCSI | 644 | depends on PCI && SCSI |
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index e7c861ac417d..a5049cfb40ed 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile | |||
@@ -39,6 +39,7 @@ obj-$(CONFIG_SCSI_DH) += device_handler/ | |||
39 | obj-$(CONFIG_LIBFC) += libfc/ | 39 | obj-$(CONFIG_LIBFC) += libfc/ |
40 | obj-$(CONFIG_LIBFCOE) += fcoe/ | 40 | obj-$(CONFIG_LIBFCOE) += fcoe/ |
41 | obj-$(CONFIG_FCOE) += fcoe/ | 41 | obj-$(CONFIG_FCOE) += fcoe/ |
42 | obj-$(CONFIG_FCOE_FNIC) += fnic/ | ||
42 | obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o | 43 | obj-$(CONFIG_ISCSI_TCP) += libiscsi.o libiscsi_tcp.o iscsi_tcp.o |
43 | obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o | 44 | obj-$(CONFIG_INFINIBAND_ISER) += libiscsi.o |
44 | obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o | 45 | obj-$(CONFIG_SCSI_A4000T) += 53c700.o a4000t.o |
diff --git a/drivers/scsi/fnic/Makefile b/drivers/scsi/fnic/Makefile new file mode 100644 index 000000000000..37c3440bc17c --- /dev/null +++ b/drivers/scsi/fnic/Makefile | |||
@@ -0,0 +1,15 @@ | |||
1 | obj-$(CONFIG_FCOE_FNIC) += fnic.o | ||
2 | |||
3 | fnic-y := \ | ||
4 | fnic_attrs.o \ | ||
5 | fnic_isr.o \ | ||
6 | fnic_main.o \ | ||
7 | fnic_res.o \ | ||
8 | fnic_fcs.o \ | ||
9 | fnic_scsi.o \ | ||
10 | vnic_cq.o \ | ||
11 | vnic_dev.o \ | ||
12 | vnic_intr.o \ | ||
13 | vnic_rq.o \ | ||
14 | vnic_wq_copy.o \ | ||
15 | vnic_wq.o | ||
diff --git a/drivers/scsi/fnic/cq_desc.h b/drivers/scsi/fnic/cq_desc.h new file mode 100644 index 000000000000..d1225cf6320e --- /dev/null +++ b/drivers/scsi/fnic/cq_desc.h | |||
@@ -0,0 +1,78 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _CQ_DESC_H_ | ||
19 | #define _CQ_DESC_H_ | ||
20 | |||
21 | /* | ||
22 | * Completion queue descriptor types | ||
23 | */ | ||
24 | enum cq_desc_types { | ||
25 | CQ_DESC_TYPE_WQ_ENET = 0, | ||
26 | CQ_DESC_TYPE_DESC_COPY = 1, | ||
27 | CQ_DESC_TYPE_WQ_EXCH = 2, | ||
28 | CQ_DESC_TYPE_RQ_ENET = 3, | ||
29 | CQ_DESC_TYPE_RQ_FCP = 4, | ||
30 | }; | ||
31 | |||
32 | /* Completion queue descriptor: 16B | ||
33 | * | ||
34 | * All completion queues have this basic layout. The | ||
35 | * type_specfic area is unique for each completion | ||
36 | * queue type. | ||
37 | */ | ||
38 | struct cq_desc { | ||
39 | __le16 completed_index; | ||
40 | __le16 q_number; | ||
41 | u8 type_specfic[11]; | ||
42 | u8 type_color; | ||
43 | }; | ||
44 | |||
45 | #define CQ_DESC_TYPE_BITS 4 | ||
46 | #define CQ_DESC_TYPE_MASK ((1 << CQ_DESC_TYPE_BITS) - 1) | ||
47 | #define CQ_DESC_COLOR_MASK 1 | ||
48 | #define CQ_DESC_COLOR_SHIFT 7 | ||
49 | #define CQ_DESC_Q_NUM_BITS 10 | ||
50 | #define CQ_DESC_Q_NUM_MASK ((1 << CQ_DESC_Q_NUM_BITS) - 1) | ||
51 | #define CQ_DESC_COMP_NDX_BITS 12 | ||
52 | #define CQ_DESC_COMP_NDX_MASK ((1 << CQ_DESC_COMP_NDX_BITS) - 1) | ||
53 | |||
54 | static inline void cq_desc_dec(const struct cq_desc *desc_arg, | ||
55 | u8 *type, u8 *color, u16 *q_number, u16 *completed_index) | ||
56 | { | ||
57 | const struct cq_desc *desc = desc_arg; | ||
58 | const u8 type_color = desc->type_color; | ||
59 | |||
60 | *color = (type_color >> CQ_DESC_COLOR_SHIFT) & CQ_DESC_COLOR_MASK; | ||
61 | |||
62 | /* | ||
63 | * Make sure color bit is read from desc *before* other fields | ||
64 | * are read from desc. Hardware guarantees color bit is last | ||
65 | * bit (byte) written. Adding the rmb() prevents the compiler | ||
66 | * and/or CPU from reordering the reads which would potentially | ||
67 | * result in reading stale values. | ||
68 | */ | ||
69 | |||
70 | rmb(); | ||
71 | |||
72 | *type = type_color & CQ_DESC_TYPE_MASK; | ||
73 | *q_number = le16_to_cpu(desc->q_number) & CQ_DESC_Q_NUM_MASK; | ||
74 | *completed_index = le16_to_cpu(desc->completed_index) & | ||
75 | CQ_DESC_COMP_NDX_MASK; | ||
76 | } | ||
77 | |||
78 | #endif /* _CQ_DESC_H_ */ | ||
diff --git a/drivers/scsi/fnic/cq_enet_desc.h b/drivers/scsi/fnic/cq_enet_desc.h new file mode 100644 index 000000000000..a9fa26f82ddd --- /dev/null +++ b/drivers/scsi/fnic/cq_enet_desc.h | |||
@@ -0,0 +1,167 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _CQ_ENET_DESC_H_ | ||
19 | #define _CQ_ENET_DESC_H_ | ||
20 | |||
21 | #include "cq_desc.h" | ||
22 | |||
23 | /* Ethernet completion queue descriptor: 16B */ | ||
24 | struct cq_enet_wq_desc { | ||
25 | __le16 completed_index; | ||
26 | __le16 q_number; | ||
27 | u8 reserved[11]; | ||
28 | u8 type_color; | ||
29 | }; | ||
30 | |||
31 | static inline void cq_enet_wq_desc_dec(struct cq_enet_wq_desc *desc, | ||
32 | u8 *type, u8 *color, u16 *q_number, u16 *completed_index) | ||
33 | { | ||
34 | cq_desc_dec((struct cq_desc *)desc, type, | ||
35 | color, q_number, completed_index); | ||
36 | } | ||
37 | |||
38 | /* Completion queue descriptor: Ethernet receive queue, 16B */ | ||
39 | struct cq_enet_rq_desc { | ||
40 | __le16 completed_index_flags; | ||
41 | __le16 q_number_rss_type_flags; | ||
42 | __le32 rss_hash; | ||
43 | __le16 bytes_written_flags; | ||
44 | __le16 vlan; | ||
45 | __le16 checksum_fcoe; | ||
46 | u8 flags; | ||
47 | u8 type_color; | ||
48 | }; | ||
49 | |||
50 | #define CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT (0x1 << 12) | ||
51 | #define CQ_ENET_RQ_DESC_FLAGS_FCOE (0x1 << 13) | ||
52 | #define CQ_ENET_RQ_DESC_FLAGS_EOP (0x1 << 14) | ||
53 | #define CQ_ENET_RQ_DESC_FLAGS_SOP (0x1 << 15) | ||
54 | |||
55 | #define CQ_ENET_RQ_DESC_RSS_TYPE_BITS 4 | ||
56 | #define CQ_ENET_RQ_DESC_RSS_TYPE_MASK \ | ||
57 | ((1 << CQ_ENET_RQ_DESC_RSS_TYPE_BITS) - 1) | ||
58 | #define CQ_ENET_RQ_DESC_RSS_TYPE_NONE 0 | ||
59 | #define CQ_ENET_RQ_DESC_RSS_TYPE_IPv4 1 | ||
60 | #define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv4 2 | ||
61 | #define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6 3 | ||
62 | #define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6 4 | ||
63 | #define CQ_ENET_RQ_DESC_RSS_TYPE_IPv6_EX 5 | ||
64 | #define CQ_ENET_RQ_DESC_RSS_TYPE_TCP_IPv6_EX 6 | ||
65 | |||
66 | #define CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC (0x1 << 14) | ||
67 | |||
68 | #define CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS 14 | ||
69 | #define CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK \ | ||
70 | ((1 << CQ_ENET_RQ_DESC_BYTES_WRITTEN_BITS) - 1) | ||
71 | #define CQ_ENET_RQ_DESC_FLAGS_TRUNCATED (0x1 << 14) | ||
72 | #define CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED (0x1 << 15) | ||
73 | |||
74 | #define CQ_ENET_RQ_DESC_FCOE_SOF_BITS 4 | ||
75 | #define CQ_ENET_RQ_DESC_FCOE_SOF_MASK \ | ||
76 | ((1 << CQ_ENET_RQ_DESC_FCOE_SOF_BITS) - 1) | ||
77 | #define CQ_ENET_RQ_DESC_FCOE_EOF_BITS 8 | ||
78 | #define CQ_ENET_RQ_DESC_FCOE_EOF_MASK \ | ||
79 | ((1 << CQ_ENET_RQ_DESC_FCOE_EOF_BITS) - 1) | ||
80 | #define CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT 8 | ||
81 | |||
82 | #define CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK (0x1 << 0) | ||
83 | #define CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK (0x1 << 0) | ||
84 | #define CQ_ENET_RQ_DESC_FLAGS_UDP (0x1 << 1) | ||
85 | #define CQ_ENET_RQ_DESC_FCOE_ENC_ERROR (0x1 << 1) | ||
86 | #define CQ_ENET_RQ_DESC_FLAGS_TCP (0x1 << 2) | ||
87 | #define CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK (0x1 << 3) | ||
88 | #define CQ_ENET_RQ_DESC_FLAGS_IPV6 (0x1 << 4) | ||
89 | #define CQ_ENET_RQ_DESC_FLAGS_IPV4 (0x1 << 5) | ||
90 | #define CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT (0x1 << 6) | ||
91 | #define CQ_ENET_RQ_DESC_FLAGS_FCS_OK (0x1 << 7) | ||
92 | |||
93 | static inline void cq_enet_rq_desc_dec(struct cq_enet_rq_desc *desc, | ||
94 | u8 *type, u8 *color, u16 *q_number, u16 *completed_index, | ||
95 | u8 *ingress_port, u8 *fcoe, u8 *eop, u8 *sop, u8 *rss_type, | ||
96 | u8 *csum_not_calc, u32 *rss_hash, u16 *bytes_written, u8 *packet_error, | ||
97 | u8 *vlan_stripped, u16 *vlan, u16 *checksum, u8 *fcoe_sof, | ||
98 | u8 *fcoe_fc_crc_ok, u8 *fcoe_enc_error, u8 *fcoe_eof, | ||
99 | u8 *tcp_udp_csum_ok, u8 *udp, u8 *tcp, u8 *ipv4_csum_ok, | ||
100 | u8 *ipv6, u8 *ipv4, u8 *ipv4_fragment, u8 *fcs_ok) | ||
101 | { | ||
102 | u16 completed_index_flags = le16_to_cpu(desc->completed_index_flags); | ||
103 | u16 q_number_rss_type_flags = | ||
104 | le16_to_cpu(desc->q_number_rss_type_flags); | ||
105 | u16 bytes_written_flags = le16_to_cpu(desc->bytes_written_flags); | ||
106 | |||
107 | cq_desc_dec((struct cq_desc *)desc, type, | ||
108 | color, q_number, completed_index); | ||
109 | |||
110 | *ingress_port = (completed_index_flags & | ||
111 | CQ_ENET_RQ_DESC_FLAGS_INGRESS_PORT) ? 1 : 0; | ||
112 | *fcoe = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_FCOE) ? | ||
113 | 1 : 0; | ||
114 | *eop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_EOP) ? | ||
115 | 1 : 0; | ||
116 | *sop = (completed_index_flags & CQ_ENET_RQ_DESC_FLAGS_SOP) ? | ||
117 | 1 : 0; | ||
118 | |||
119 | *rss_type = (u8)((q_number_rss_type_flags >> CQ_DESC_Q_NUM_BITS) & | ||
120 | CQ_ENET_RQ_DESC_RSS_TYPE_MASK); | ||
121 | *csum_not_calc = (q_number_rss_type_flags & | ||
122 | CQ_ENET_RQ_DESC_FLAGS_CSUM_NOT_CALC) ? 1 : 0; | ||
123 | |||
124 | *rss_hash = le32_to_cpu(desc->rss_hash); | ||
125 | |||
126 | *bytes_written = bytes_written_flags & | ||
127 | CQ_ENET_RQ_DESC_BYTES_WRITTEN_MASK; | ||
128 | *packet_error = (bytes_written_flags & | ||
129 | CQ_ENET_RQ_DESC_FLAGS_TRUNCATED) ? 1 : 0; | ||
130 | *vlan_stripped = (bytes_written_flags & | ||
131 | CQ_ENET_RQ_DESC_FLAGS_VLAN_STRIPPED) ? 1 : 0; | ||
132 | |||
133 | *vlan = le16_to_cpu(desc->vlan); | ||
134 | |||
135 | if (*fcoe) { | ||
136 | *fcoe_sof = (u8)(le16_to_cpu(desc->checksum_fcoe) & | ||
137 | CQ_ENET_RQ_DESC_FCOE_SOF_MASK); | ||
138 | *fcoe_fc_crc_ok = (desc->flags & | ||
139 | CQ_ENET_RQ_DESC_FCOE_FC_CRC_OK) ? 1 : 0; | ||
140 | *fcoe_enc_error = (desc->flags & | ||
141 | CQ_ENET_RQ_DESC_FCOE_ENC_ERROR) ? 1 : 0; | ||
142 | *fcoe_eof = (u8)((desc->checksum_fcoe >> | ||
143 | CQ_ENET_RQ_DESC_FCOE_EOF_SHIFT) & | ||
144 | CQ_ENET_RQ_DESC_FCOE_EOF_MASK); | ||
145 | *checksum = 0; | ||
146 | } else { | ||
147 | *fcoe_sof = 0; | ||
148 | *fcoe_fc_crc_ok = 0; | ||
149 | *fcoe_enc_error = 0; | ||
150 | *fcoe_eof = 0; | ||
151 | *checksum = le16_to_cpu(desc->checksum_fcoe); | ||
152 | } | ||
153 | |||
154 | *tcp_udp_csum_ok = | ||
155 | (desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP_UDP_CSUM_OK) ? 1 : 0; | ||
156 | *udp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_UDP) ? 1 : 0; | ||
157 | *tcp = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_TCP) ? 1 : 0; | ||
158 | *ipv4_csum_ok = | ||
159 | (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_CSUM_OK) ? 1 : 0; | ||
160 | *ipv6 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV6) ? 1 : 0; | ||
161 | *ipv4 = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4) ? 1 : 0; | ||
162 | *ipv4_fragment = | ||
163 | (desc->flags & CQ_ENET_RQ_DESC_FLAGS_IPV4_FRAGMENT) ? 1 : 0; | ||
164 | *fcs_ok = (desc->flags & CQ_ENET_RQ_DESC_FLAGS_FCS_OK) ? 1 : 0; | ||
165 | } | ||
166 | |||
167 | #endif /* _CQ_ENET_DESC_H_ */ | ||
diff --git a/drivers/scsi/fnic/cq_exch_desc.h b/drivers/scsi/fnic/cq_exch_desc.h new file mode 100644 index 000000000000..501660cfe228 --- /dev/null +++ b/drivers/scsi/fnic/cq_exch_desc.h | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _CQ_EXCH_DESC_H_ | ||
19 | #define _CQ_EXCH_DESC_H_ | ||
20 | |||
21 | #include "cq_desc.h" | ||
22 | |||
23 | /* Exchange completion queue descriptor: 16B */ | ||
24 | struct cq_exch_wq_desc { | ||
25 | u16 completed_index; | ||
26 | u16 q_number; | ||
27 | u16 exchange_id; | ||
28 | u8 tmpl; | ||
29 | u8 reserved0; | ||
30 | u32 reserved1; | ||
31 | u8 exch_status; | ||
32 | u8 reserved2[2]; | ||
33 | u8 type_color; | ||
34 | }; | ||
35 | |||
36 | #define CQ_EXCH_WQ_STATUS_BITS 2 | ||
37 | #define CQ_EXCH_WQ_STATUS_MASK ((1 << CQ_EXCH_WQ_STATUS_BITS) - 1) | ||
38 | |||
39 | enum cq_exch_status_types { | ||
40 | CQ_EXCH_WQ_STATUS_TYPE_COMPLETE = 0, | ||
41 | CQ_EXCH_WQ_STATUS_TYPE_ABORT = 1, | ||
42 | CQ_EXCH_WQ_STATUS_TYPE_SGL_EOF = 2, | ||
43 | CQ_EXCH_WQ_STATUS_TYPE_TMPL_ERR = 3, | ||
44 | }; | ||
45 | |||
46 | static inline void cq_exch_wq_desc_dec(struct cq_exch_wq_desc *desc_ptr, | ||
47 | u8 *type, | ||
48 | u8 *color, | ||
49 | u16 *q_number, | ||
50 | u16 *completed_index, | ||
51 | u8 *exch_status) | ||
52 | { | ||
53 | cq_desc_dec((struct cq_desc *)desc_ptr, type, | ||
54 | color, q_number, completed_index); | ||
55 | *exch_status = desc_ptr->exch_status & CQ_EXCH_WQ_STATUS_MASK; | ||
56 | } | ||
57 | |||
58 | struct cq_fcp_rq_desc { | ||
59 | u16 completed_index_eop_sop_prt; | ||
60 | u16 q_number; | ||
61 | u16 exchange_id; | ||
62 | u16 tmpl; | ||
63 | u16 bytes_written; | ||
64 | u16 vlan; | ||
65 | u8 sof; | ||
66 | u8 eof; | ||
67 | u8 fcs_fer_fck; | ||
68 | u8 type_color; | ||
69 | }; | ||
70 | |||
71 | #define CQ_FCP_RQ_DESC_FLAGS_SOP (1 << 15) | ||
72 | #define CQ_FCP_RQ_DESC_FLAGS_EOP (1 << 14) | ||
73 | #define CQ_FCP_RQ_DESC_FLAGS_PRT (1 << 12) | ||
74 | #define CQ_FCP_RQ_DESC_TMPL_MASK 0x1f | ||
75 | #define CQ_FCP_RQ_DESC_BYTES_WRITTEN_MASK 0x3fff | ||
76 | #define CQ_FCP_RQ_DESC_PACKET_ERR_SHIFT 14 | ||
77 | #define CQ_FCP_RQ_DESC_PACKET_ERR_MASK (1 << CQ_FCP_RQ_DESC_PACKET_ERR_SHIFT) | ||
78 | #define CQ_FCP_RQ_DESC_VS_STRIPPED_SHIFT 15 | ||
79 | #define CQ_FCP_RQ_DESC_VS_STRIPPED_MASK (1 << CQ_FCP_RQ_DESC_VS_STRIPPED_SHIFT) | ||
80 | #define CQ_FCP_RQ_DESC_FC_CRC_OK_MASK 0x1 | ||
81 | #define CQ_FCP_RQ_DESC_FCOE_ERR_SHIFT 1 | ||
82 | #define CQ_FCP_RQ_DESC_FCOE_ERR_MASK (1 << CQ_FCP_RQ_DESC_FCOE_ERR_SHIFT) | ||
83 | #define CQ_FCP_RQ_DESC_FCS_OK_SHIFT 7 | ||
84 | #define CQ_FCP_RQ_DESC_FCS_OK_MASK (1 << CQ_FCP_RQ_DESC_FCS_OK_SHIFT) | ||
85 | |||
86 | static inline void cq_fcp_rq_desc_dec(struct cq_fcp_rq_desc *desc_ptr, | ||
87 | u8 *type, | ||
88 | u8 *color, | ||
89 | u16 *q_number, | ||
90 | u16 *completed_index, | ||
91 | u8 *eop, | ||
92 | u8 *sop, | ||
93 | u8 *fck, | ||
94 | u16 *exchange_id, | ||
95 | u16 *tmpl, | ||
96 | u32 *bytes_written, | ||
97 | u8 *sof, | ||
98 | u8 *eof, | ||
99 | u8 *ingress_port, | ||
100 | u8 *packet_err, | ||
101 | u8 *fcoe_err, | ||
102 | u8 *fcs_ok, | ||
103 | u8 *vlan_stripped, | ||
104 | u16 *vlan) | ||
105 | { | ||
106 | cq_desc_dec((struct cq_desc *)desc_ptr, type, | ||
107 | color, q_number, completed_index); | ||
108 | *eop = (desc_ptr->completed_index_eop_sop_prt & | ||
109 | CQ_FCP_RQ_DESC_FLAGS_EOP) ? 1 : 0; | ||
110 | *sop = (desc_ptr->completed_index_eop_sop_prt & | ||
111 | CQ_FCP_RQ_DESC_FLAGS_SOP) ? 1 : 0; | ||
112 | *ingress_port = | ||
113 | (desc_ptr->completed_index_eop_sop_prt & | ||
114 | CQ_FCP_RQ_DESC_FLAGS_PRT) ? 1 : 0; | ||
115 | *exchange_id = desc_ptr->exchange_id; | ||
116 | *tmpl = desc_ptr->tmpl & CQ_FCP_RQ_DESC_TMPL_MASK; | ||
117 | *bytes_written = | ||
118 | desc_ptr->bytes_written & CQ_FCP_RQ_DESC_BYTES_WRITTEN_MASK; | ||
119 | *packet_err = | ||
120 | (desc_ptr->bytes_written & CQ_FCP_RQ_DESC_PACKET_ERR_MASK) >> | ||
121 | CQ_FCP_RQ_DESC_PACKET_ERR_SHIFT; | ||
122 | *vlan_stripped = | ||
123 | (desc_ptr->bytes_written & CQ_FCP_RQ_DESC_VS_STRIPPED_MASK) >> | ||
124 | CQ_FCP_RQ_DESC_VS_STRIPPED_SHIFT; | ||
125 | *vlan = desc_ptr->vlan; | ||
126 | *sof = desc_ptr->sof; | ||
127 | *fck = desc_ptr->fcs_fer_fck & CQ_FCP_RQ_DESC_FC_CRC_OK_MASK; | ||
128 | *fcoe_err = (desc_ptr->fcs_fer_fck & CQ_FCP_RQ_DESC_FCOE_ERR_MASK) >> | ||
129 | CQ_FCP_RQ_DESC_FCOE_ERR_SHIFT; | ||
130 | *eof = desc_ptr->eof; | ||
131 | *fcs_ok = | ||
132 | (desc_ptr->fcs_fer_fck & CQ_FCP_RQ_DESC_FCS_OK_MASK) >> | ||
133 | CQ_FCP_RQ_DESC_FCS_OK_SHIFT; | ||
134 | } | ||
135 | |||
136 | struct cq_sgl_desc { | ||
137 | u16 exchange_id; | ||
138 | u16 q_number; | ||
139 | u32 active_burst_offset; | ||
140 | u32 tot_data_bytes; | ||
141 | u16 tmpl; | ||
142 | u8 sgl_err; | ||
143 | u8 type_color; | ||
144 | }; | ||
145 | |||
146 | enum cq_sgl_err_types { | ||
147 | CQ_SGL_ERR_NO_ERROR = 0, | ||
148 | CQ_SGL_ERR_OVERFLOW, /* data ran beyond end of SGL */ | ||
149 | CQ_SGL_ERR_SGL_LCL_ADDR_ERR, /* sgl access to local vnic addr illegal*/ | ||
150 | CQ_SGL_ERR_ADDR_RSP_ERR, /* sgl address error */ | ||
151 | CQ_SGL_ERR_DATA_RSP_ERR, /* sgl data rsp error */ | ||
152 | CQ_SGL_ERR_CNT_ZERO_ERR, /* SGL count is 0 */ | ||
153 | CQ_SGL_ERR_CNT_MAX_ERR, /* SGL count is larger than supported */ | ||
154 | CQ_SGL_ERR_ORDER_ERR, /* frames recv on both ports, order err */ | ||
155 | CQ_SGL_ERR_DATA_LCL_ADDR_ERR,/* sgl data buf to local vnic addr ill */ | ||
156 | CQ_SGL_ERR_HOST_CQ_ERR, /* host cq entry to local vnic addr ill */ | ||
157 | }; | ||
158 | |||
159 | #define CQ_SGL_SGL_ERR_MASK 0x1f | ||
160 | #define CQ_SGL_TMPL_MASK 0x1f | ||
161 | |||
162 | static inline void cq_sgl_desc_dec(struct cq_sgl_desc *desc_ptr, | ||
163 | u8 *type, | ||
164 | u8 *color, | ||
165 | u16 *q_number, | ||
166 | u16 *exchange_id, | ||
167 | u32 *active_burst_offset, | ||
168 | u32 *tot_data_bytes, | ||
169 | u16 *tmpl, | ||
170 | u8 *sgl_err) | ||
171 | { | ||
172 | /* Cheat a little by assuming exchange_id is the same as completed | ||
173 | index */ | ||
174 | cq_desc_dec((struct cq_desc *)desc_ptr, type, color, q_number, | ||
175 | exchange_id); | ||
176 | *active_burst_offset = desc_ptr->active_burst_offset; | ||
177 | *tot_data_bytes = desc_ptr->tot_data_bytes; | ||
178 | *tmpl = desc_ptr->tmpl & CQ_SGL_TMPL_MASK; | ||
179 | *sgl_err = desc_ptr->sgl_err & CQ_SGL_SGL_ERR_MASK; | ||
180 | } | ||
181 | |||
182 | #endif /* _CQ_EXCH_DESC_H_ */ | ||
diff --git a/drivers/scsi/fnic/fcpio.h b/drivers/scsi/fnic/fcpio.h new file mode 100644 index 000000000000..12d770d885c5 --- /dev/null +++ b/drivers/scsi/fnic/fcpio.h | |||
@@ -0,0 +1,780 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _FCPIO_H_ | ||
19 | #define _FCPIO_H_ | ||
20 | |||
21 | #include <linux/if_ether.h> | ||
22 | |||
23 | /* | ||
24 | * This header file includes all of the data structures used for | ||
25 | * communication by the host driver to the fcp firmware. | ||
26 | */ | ||
27 | |||
28 | /* | ||
29 | * Exchange and sequence id space allocated to the host driver | ||
30 | */ | ||
31 | #define FCPIO_HOST_EXCH_RANGE_START 0x1000 | ||
32 | #define FCPIO_HOST_EXCH_RANGE_END 0x1fff | ||
33 | #define FCPIO_HOST_SEQ_ID_RANGE_START 0x80 | ||
34 | #define FCPIO_HOST_SEQ_ID_RANGE_END 0xff | ||
35 | |||
36 | /* | ||
37 | * Command entry type | ||
38 | */ | ||
39 | enum fcpio_type { | ||
40 | /* | ||
41 | * Initiator request types | ||
42 | */ | ||
43 | FCPIO_ICMND_16 = 0x1, | ||
44 | FCPIO_ICMND_32, | ||
45 | FCPIO_ICMND_CMPL, | ||
46 | FCPIO_ITMF, | ||
47 | FCPIO_ITMF_CMPL, | ||
48 | |||
49 | /* | ||
50 | * Target request types | ||
51 | */ | ||
52 | FCPIO_TCMND_16 = 0x11, | ||
53 | FCPIO_TCMND_32, | ||
54 | FCPIO_TDATA, | ||
55 | FCPIO_TXRDY, | ||
56 | FCPIO_TRSP, | ||
57 | FCPIO_TDRSP_CMPL, | ||
58 | FCPIO_TTMF, | ||
59 | FCPIO_TTMF_ACK, | ||
60 | FCPIO_TABORT, | ||
61 | FCPIO_TABORT_CMPL, | ||
62 | |||
63 | /* | ||
64 | * Misc request types | ||
65 | */ | ||
66 | FCPIO_ACK = 0x20, | ||
67 | FCPIO_RESET, | ||
68 | FCPIO_RESET_CMPL, | ||
69 | FCPIO_FLOGI_REG, | ||
70 | FCPIO_FLOGI_REG_CMPL, | ||
71 | FCPIO_ECHO, | ||
72 | FCPIO_ECHO_CMPL, | ||
73 | FCPIO_LUNMAP_CHNG, | ||
74 | FCPIO_LUNMAP_REQ, | ||
75 | FCPIO_LUNMAP_REQ_CMPL, | ||
76 | FCPIO_FLOGI_FIP_REG, | ||
77 | FCPIO_FLOGI_FIP_REG_CMPL, | ||
78 | }; | ||
79 | |||
80 | /* | ||
81 | * Header status codes from the firmware | ||
82 | */ | ||
83 | enum fcpio_status { | ||
84 | FCPIO_SUCCESS = 0, /* request was successful */ | ||
85 | |||
86 | /* | ||
87 | * If a request to the firmware is rejected, the original request | ||
88 | * header will be returned with the status set to one of the following: | ||
89 | */ | ||
90 | FCPIO_INVALID_HEADER, /* header contains invalid data */ | ||
91 | FCPIO_OUT_OF_RESOURCE, /* out of resources to complete request */ | ||
92 | FCPIO_INVALID_PARAM, /* some parameter in request is invalid */ | ||
93 | FCPIO_REQ_NOT_SUPPORTED, /* request type is not supported */ | ||
94 | FCPIO_IO_NOT_FOUND, /* requested I/O was not found */ | ||
95 | |||
96 | /* | ||
97 | * Once a request is processed, the firmware will usually return | ||
98 | * a cmpl message type. In cases where errors occurred, | ||
99 | * the header status field would be filled in with one of the following: | ||
100 | */ | ||
101 | FCPIO_ABORTED = 0x41, /* request was aborted */ | ||
102 | FCPIO_TIMEOUT, /* request was timed out */ | ||
103 | FCPIO_SGL_INVALID, /* request was aborted due to sgl error */ | ||
104 | FCPIO_MSS_INVALID, /* request was aborted due to mss error */ | ||
105 | FCPIO_DATA_CNT_MISMATCH, /* recv/sent more/less data than exp. */ | ||
106 | FCPIO_FW_ERR, /* request was terminated due to fw error */ | ||
107 | FCPIO_ITMF_REJECTED, /* itmf req was rejected by remote node */ | ||
108 | FCPIO_ITMF_FAILED, /* itmf req was failed by remote node */ | ||
109 | FCPIO_ITMF_INCORRECT_LUN, /* itmf req targeted incorrect LUN */ | ||
110 | FCPIO_CMND_REJECTED, /* request was invalid and rejected */ | ||
111 | FCPIO_NO_PATH_AVAIL, /* no paths to the lun was available */ | ||
112 | FCPIO_PATH_FAILED, /* i/o sent to current path failed */ | ||
113 | FCPIO_LUNMAP_CHNG_PEND, /* i/o rejected due to lunmap change */ | ||
114 | }; | ||
115 | |||
116 | /* | ||
117 | * The header command tag. All host requests will use the "tag" field | ||
118 | * to mark commands with a unique tag. When the firmware responds to | ||
119 | * a host request, it will copy the tag field into the response. | ||
120 | * | ||
121 | * The only firmware requests that will use the rx_id/ox_id fields instead | ||
122 | * of the tag field will be the target command and target task management | ||
123 | * requests. These two requests do not have corresponding host requests | ||
124 | * since they come directly from the FC initiator on the network. | ||
125 | */ | ||
126 | struct fcpio_tag { | ||
127 | union { | ||
128 | u32 req_id; | ||
129 | struct { | ||
130 | u16 rx_id; | ||
131 | u16 ox_id; | ||
132 | } ex_id; | ||
133 | } u; | ||
134 | }; | ||
135 | |||
136 | static inline void | ||
137 | fcpio_tag_id_enc(struct fcpio_tag *tag, u32 id) | ||
138 | { | ||
139 | tag->u.req_id = id; | ||
140 | } | ||
141 | |||
142 | static inline void | ||
143 | fcpio_tag_id_dec(struct fcpio_tag *tag, u32 *id) | ||
144 | { | ||
145 | *id = tag->u.req_id; | ||
146 | } | ||
147 | |||
148 | static inline void | ||
149 | fcpio_tag_exid_enc(struct fcpio_tag *tag, u16 ox_id, u16 rx_id) | ||
150 | { | ||
151 | tag->u.ex_id.rx_id = rx_id; | ||
152 | tag->u.ex_id.ox_id = ox_id; | ||
153 | } | ||
154 | |||
155 | static inline void | ||
156 | fcpio_tag_exid_dec(struct fcpio_tag *tag, u16 *ox_id, u16 *rx_id) | ||
157 | { | ||
158 | *rx_id = tag->u.ex_id.rx_id; | ||
159 | *ox_id = tag->u.ex_id.ox_id; | ||
160 | } | ||
161 | |||
162 | /* | ||
163 | * The header for an fcpio request, whether from the firmware or from the | ||
164 | * host driver | ||
165 | */ | ||
166 | struct fcpio_header { | ||
167 | u8 type; /* enum fcpio_type */ | ||
168 | u8 status; /* header status entry */ | ||
169 | u16 _resvd; /* reserved */ | ||
170 | struct fcpio_tag tag; /* header tag */ | ||
171 | }; | ||
172 | |||
173 | static inline void | ||
174 | fcpio_header_enc(struct fcpio_header *hdr, | ||
175 | u8 type, u8 status, | ||
176 | struct fcpio_tag tag) | ||
177 | { | ||
178 | hdr->type = type; | ||
179 | hdr->status = status; | ||
180 | hdr->_resvd = 0; | ||
181 | hdr->tag = tag; | ||
182 | } | ||
183 | |||
184 | static inline void | ||
185 | fcpio_header_dec(struct fcpio_header *hdr, | ||
186 | u8 *type, u8 *status, | ||
187 | struct fcpio_tag *tag) | ||
188 | { | ||
189 | *type = hdr->type; | ||
190 | *status = hdr->status; | ||
191 | *tag = hdr->tag; | ||
192 | } | ||
193 | |||
194 | #define CDB_16 16 | ||
195 | #define CDB_32 32 | ||
196 | #define LUN_ADDRESS 8 | ||
197 | |||
198 | /* | ||
199 | * fcpio_icmnd_16: host -> firmware request | ||
200 | * | ||
201 | * used for sending out an initiator SCSI 16-byte command | ||
202 | */ | ||
203 | struct fcpio_icmnd_16 { | ||
204 | u32 lunmap_id; /* index into lunmap table */ | ||
205 | u8 special_req_flags; /* special exchange request flags */ | ||
206 | u8 _resvd0[3]; /* reserved */ | ||
207 | u32 sgl_cnt; /* scatter-gather list count */ | ||
208 | u32 sense_len; /* sense buffer length */ | ||
209 | u64 sgl_addr; /* scatter-gather list addr */ | ||
210 | u64 sense_addr; /* sense buffer address */ | ||
211 | u8 crn; /* SCSI Command Reference No. */ | ||
212 | u8 pri_ta; /* SCSI Priority and Task attribute */ | ||
213 | u8 _resvd1; /* reserved: should be 0 */ | ||
214 | u8 flags; /* command flags */ | ||
215 | u8 scsi_cdb[CDB_16]; /* SCSI Cmnd Descriptor Block */ | ||
216 | u32 data_len; /* length of data expected */ | ||
217 | u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ | ||
218 | u8 _resvd2; /* reserved */ | ||
219 | u8 d_id[3]; /* FC vNIC only: Target D_ID */ | ||
220 | u16 mss; /* FC vNIC only: max burst */ | ||
221 | u16 _resvd3; /* reserved */ | ||
222 | u32 r_a_tov; /* FC vNIC only: Res. Alloc Timeout */ | ||
223 | u32 e_d_tov; /* FC vNIC only: Err Detect Timeout */ | ||
224 | }; | ||
225 | |||
226 | /* | ||
227 | * Special request flags | ||
228 | */ | ||
229 | #define FCPIO_ICMND_SRFLAG_RETRY 0x01 /* Enable Retry handling on exchange */ | ||
230 | |||
231 | /* | ||
232 | * Priority/Task Attribute settings | ||
233 | */ | ||
234 | #define FCPIO_ICMND_PTA_SIMPLE 0 /* simple task attribute */ | ||
235 | #define FCPIO_ICMND_PTA_HEADQ 1 /* head of queue task attribute */ | ||
236 | #define FCPIO_ICMND_PTA_ORDERED 2 /* ordered task attribute */ | ||
237 | #define FCPIO_ICMND_PTA_ACA 4 /* auto contingent allegiance */ | ||
238 | #define FCPIO_ICMND_PRI_SHIFT 3 /* priority field starts in bit 3 */ | ||
239 | |||
240 | /* | ||
241 | * Command flags | ||
242 | */ | ||
243 | #define FCPIO_ICMND_RDDATA 0x02 /* read data */ | ||
244 | #define FCPIO_ICMND_WRDATA 0x01 /* write data */ | ||
245 | |||
246 | /* | ||
247 | * fcpio_icmnd_32: host -> firmware request | ||
248 | * | ||
249 | * used for sending out an initiator SCSI 32-byte command | ||
250 | */ | ||
251 | struct fcpio_icmnd_32 { | ||
252 | u32 lunmap_id; /* index into lunmap table */ | ||
253 | u8 special_req_flags; /* special exchange request flags */ | ||
254 | u8 _resvd0[3]; /* reserved */ | ||
255 | u32 sgl_cnt; /* scatter-gather list count */ | ||
256 | u32 sense_len; /* sense buffer length */ | ||
257 | u64 sgl_addr; /* scatter-gather list addr */ | ||
258 | u64 sense_addr; /* sense buffer address */ | ||
259 | u8 crn; /* SCSI Command Reference No. */ | ||
260 | u8 pri_ta; /* SCSI Priority and Task attribute */ | ||
261 | u8 _resvd1; /* reserved: should be 0 */ | ||
262 | u8 flags; /* command flags */ | ||
263 | u8 scsi_cdb[CDB_32]; /* SCSI Cmnd Descriptor Block */ | ||
264 | u32 data_len; /* length of data expected */ | ||
265 | u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ | ||
266 | u8 _resvd2; /* reserved */ | ||
267 | u8 d_id[3]; /* FC vNIC only: Target D_ID */ | ||
268 | u16 mss; /* FC vNIC only: max burst */ | ||
269 | u16 _resvd3; /* reserved */ | ||
270 | u32 r_a_tov; /* FC vNIC only: Res. Alloc Timeout */ | ||
271 | u32 e_d_tov; /* FC vNIC only: Error Detect Timeout */ | ||
272 | }; | ||
273 | |||
274 | /* | ||
275 | * fcpio_itmf: host -> firmware request | ||
276 | * | ||
277 | * used for requesting the firmware to abort a request and/or send out | ||
278 | * a task management function | ||
279 | * | ||
280 | * The t_tag field is only needed when the request type is ABT_TASK. | ||
281 | */ | ||
282 | struct fcpio_itmf { | ||
283 | u32 lunmap_id; /* index into lunmap table */ | ||
284 | u32 tm_req; /* SCSI Task Management request */ | ||
285 | u32 t_tag; /* header tag of fcpio to be aborted */ | ||
286 | u32 _resvd; /* _reserved */ | ||
287 | u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ | ||
288 | u8 _resvd1; /* reserved */ | ||
289 | u8 d_id[3]; /* FC vNIC only: Target D_ID */ | ||
290 | u32 r_a_tov; /* FC vNIC only: R_A_TOV in msec */ | ||
291 | u32 e_d_tov; /* FC vNIC only: E_D_TOV in msec */ | ||
292 | }; | ||
293 | |||
294 | /* | ||
295 | * Task Management request | ||
296 | */ | ||
297 | enum fcpio_itmf_tm_req_type { | ||
298 | FCPIO_ITMF_ABT_TASK_TERM = 0x01, /* abort task and terminate */ | ||
299 | FCPIO_ITMF_ABT_TASK, /* abort task and issue abts */ | ||
300 | FCPIO_ITMF_ABT_TASK_SET, /* abort task set */ | ||
301 | FCPIO_ITMF_CLR_TASK_SET, /* clear task set */ | ||
302 | FCPIO_ITMF_LUN_RESET, /* logical unit reset task mgmt */ | ||
303 | FCPIO_ITMF_CLR_ACA, /* Clear ACA condition */ | ||
304 | }; | ||
305 | |||
306 | /* | ||
307 | * fcpio_tdata: host -> firmware request | ||
308 | * | ||
309 | * used for requesting the firmware to send out a read data transfer for a | ||
310 | * target command | ||
311 | */ | ||
312 | struct fcpio_tdata { | ||
313 | u16 rx_id; /* FC rx_id of target command */ | ||
314 | u16 flags; /* command flags */ | ||
315 | u32 rel_offset; /* data sequence relative offset */ | ||
316 | u32 sgl_cnt; /* scatter-gather list count */ | ||
317 | u32 data_len; /* length of data expected to send */ | ||
318 | u64 sgl_addr; /* scatter-gather list address */ | ||
319 | }; | ||
320 | |||
321 | /* | ||
322 | * Command flags | ||
323 | */ | ||
324 | #define FCPIO_TDATA_SCSI_RSP 0x01 /* send a scsi resp. after last frame */ | ||
325 | |||
326 | /* | ||
327 | * fcpio_txrdy: host -> firmware request | ||
328 | * | ||
329 | * used for requesting the firmware to send out a write data transfer for a | ||
330 | * target command | ||
331 | */ | ||
332 | struct fcpio_txrdy { | ||
333 | u16 rx_id; /* FC rx_id of target command */ | ||
334 | u16 _resvd0; /* reserved */ | ||
335 | u32 rel_offset; /* data sequence relative offset */ | ||
336 | u32 sgl_cnt; /* scatter-gather list count */ | ||
337 | u32 data_len; /* length of data expected to send */ | ||
338 | u64 sgl_addr; /* scatter-gather list address */ | ||
339 | }; | ||
340 | |||
341 | /* | ||
342 | * fcpio_trsp: host -> firmware request | ||
343 | * | ||
344 | * used for requesting the firmware to send out a response for a target | ||
345 | * command | ||
346 | */ | ||
347 | struct fcpio_trsp { | ||
348 | u16 rx_id; /* FC rx_id of target command */ | ||
349 | u16 _resvd0; /* reserved */ | ||
350 | u32 sense_len; /* sense data buffer length */ | ||
351 | u64 sense_addr; /* sense data buffer address */ | ||
352 | u16 _resvd1; /* reserved */ | ||
353 | u8 flags; /* response request flags */ | ||
354 | u8 scsi_status; /* SCSI status */ | ||
355 | u32 residual; /* SCSI data residual value of I/O */ | ||
356 | }; | ||
357 | |||
358 | /* | ||
359 | * resposnse request flags | ||
360 | */ | ||
361 | #define FCPIO_TRSP_RESID_UNDER 0x08 /* residual is valid and is underflow */ | ||
362 | #define FCPIO_TRSP_RESID_OVER 0x04 /* residual is valid and is overflow */ | ||
363 | |||
364 | /* | ||
365 | * fcpio_ttmf_ack: host -> firmware response | ||
366 | * | ||
367 | * used by the host to indicate to the firmware it has received and processed | ||
368 | * the target tmf request | ||
369 | */ | ||
370 | struct fcpio_ttmf_ack { | ||
371 | u16 rx_id; /* FC rx_id of target command */ | ||
372 | u16 _resvd0; /* reserved */ | ||
373 | u32 tmf_status; /* SCSI task management status */ | ||
374 | }; | ||
375 | |||
376 | /* | ||
377 | * fcpio_tabort: host -> firmware request | ||
378 | * | ||
379 | * used by the host to request the firmware to abort a target request that was | ||
380 | * received by the firmware | ||
381 | */ | ||
382 | struct fcpio_tabort { | ||
383 | u16 rx_id; /* rx_id of the target request */ | ||
384 | }; | ||
385 | |||
386 | /* | ||
387 | * fcpio_reset: host -> firmware request | ||
388 | * | ||
389 | * used by the host to signal a reset of the driver to the firmware | ||
390 | * and to request firmware to clean up all outstanding I/O | ||
391 | */ | ||
392 | struct fcpio_reset { | ||
393 | u32 _resvd; | ||
394 | }; | ||
395 | |||
396 | enum fcpio_flogi_reg_format_type { | ||
397 | FCPIO_FLOGI_REG_DEF_DEST = 0, /* Use the oui | s_id mac format */ | ||
398 | FCPIO_FLOGI_REG_GW_DEST, /* Use the fixed gateway mac */ | ||
399 | }; | ||
400 | |||
401 | /* | ||
402 | * fcpio_flogi_reg: host -> firmware request | ||
403 | * | ||
404 | * fc vnic only | ||
405 | * used by the host to notify the firmware of the lif's s_id | ||
406 | * and destination mac address format | ||
407 | */ | ||
408 | struct fcpio_flogi_reg { | ||
409 | u8 format; | ||
410 | u8 s_id[3]; /* FC vNIC only: Source S_ID */ | ||
411 | u8 gateway_mac[ETH_ALEN]; /* Destination gateway mac */ | ||
412 | u16 _resvd; | ||
413 | u32 r_a_tov; /* R_A_TOV in msec */ | ||
414 | u32 e_d_tov; /* E_D_TOV in msec */ | ||
415 | }; | ||
416 | |||
417 | /* | ||
418 | * fcpio_echo: host -> firmware request | ||
419 | * | ||
420 | * sends a heartbeat echo request to the firmware | ||
421 | */ | ||
422 | struct fcpio_echo { | ||
423 | u32 _resvd; | ||
424 | }; | ||
425 | |||
426 | /* | ||
427 | * fcpio_lunmap_req: host -> firmware request | ||
428 | * | ||
429 | * scsi vnic only | ||
430 | * sends a request to retrieve the lunmap table for scsi vnics | ||
431 | */ | ||
432 | struct fcpio_lunmap_req { | ||
433 | u64 addr; /* address of the buffer */ | ||
434 | u32 len; /* len of the buffer */ | ||
435 | }; | ||
436 | |||
437 | /* | ||
438 | * fcpio_flogi_fip_reg: host -> firmware request | ||
439 | * | ||
440 | * fc vnic only | ||
441 | * used by the host to notify the firmware of the lif's s_id | ||
442 | * and destination mac address format | ||
443 | */ | ||
444 | struct fcpio_flogi_fip_reg { | ||
445 | u8 _resvd0; | ||
446 | u8 s_id[3]; /* FC vNIC only: Source S_ID */ | ||
447 | u8 fcf_mac[ETH_ALEN]; /* FCF Target destination mac */ | ||
448 | u16 _resvd1; | ||
449 | u32 r_a_tov; /* R_A_TOV in msec */ | ||
450 | u32 e_d_tov; /* E_D_TOV in msec */ | ||
451 | u8 ha_mac[ETH_ALEN]; /* Host adapter source mac */ | ||
452 | u16 _resvd2; | ||
453 | }; | ||
454 | |||
455 | /* | ||
456 | * Basic structure for all fcpio structures that are sent from the host to the | ||
457 | * firmware. They are 128 bytes per structure. | ||
458 | */ | ||
459 | #define FCPIO_HOST_REQ_LEN 128 /* expected length of host requests */ | ||
460 | |||
461 | struct fcpio_host_req { | ||
462 | struct fcpio_header hdr; | ||
463 | |||
464 | union { | ||
465 | /* | ||
466 | * Defines space needed for request | ||
467 | */ | ||
468 | u8 buf[FCPIO_HOST_REQ_LEN - sizeof(struct fcpio_header)]; | ||
469 | |||
470 | /* | ||
471 | * Initiator host requests | ||
472 | */ | ||
473 | struct fcpio_icmnd_16 icmnd_16; | ||
474 | struct fcpio_icmnd_32 icmnd_32; | ||
475 | struct fcpio_itmf itmf; | ||
476 | |||
477 | /* | ||
478 | * Target host requests | ||
479 | */ | ||
480 | struct fcpio_tdata tdata; | ||
481 | struct fcpio_txrdy txrdy; | ||
482 | struct fcpio_trsp trsp; | ||
483 | struct fcpio_ttmf_ack ttmf_ack; | ||
484 | struct fcpio_tabort tabort; | ||
485 | |||
486 | /* | ||
487 | * Misc requests | ||
488 | */ | ||
489 | struct fcpio_reset reset; | ||
490 | struct fcpio_flogi_reg flogi_reg; | ||
491 | struct fcpio_echo echo; | ||
492 | struct fcpio_lunmap_req lunmap_req; | ||
493 | struct fcpio_flogi_fip_reg flogi_fip_reg; | ||
494 | } u; | ||
495 | }; | ||
496 | |||
497 | /* | ||
498 | * fcpio_icmnd_cmpl: firmware -> host response | ||
499 | * | ||
500 | * used for sending the host a response to an initiator command | ||
501 | */ | ||
502 | struct fcpio_icmnd_cmpl { | ||
503 | u8 _resvd0[6]; /* reserved */ | ||
504 | u8 flags; /* response flags */ | ||
505 | u8 scsi_status; /* SCSI status */ | ||
506 | u32 residual; /* SCSI data residual length */ | ||
507 | u32 sense_len; /* SCSI sense length */ | ||
508 | }; | ||
509 | |||
510 | /* | ||
511 | * response flags | ||
512 | */ | ||
513 | #define FCPIO_ICMND_CMPL_RESID_UNDER 0x08 /* resid under and valid */ | ||
514 | #define FCPIO_ICMND_CMPL_RESID_OVER 0x04 /* resid over and valid */ | ||
515 | |||
516 | /* | ||
517 | * fcpio_itmf_cmpl: firmware -> host response | ||
518 | * | ||
519 | * used for sending the host a response for a itmf request | ||
520 | */ | ||
521 | struct fcpio_itmf_cmpl { | ||
522 | u32 _resvd; /* reserved */ | ||
523 | }; | ||
524 | |||
525 | /* | ||
526 | * fcpio_tcmnd_16: firmware -> host request | ||
527 | * | ||
528 | * used by the firmware to notify the host of an incoming target SCSI 16-Byte | ||
529 | * request | ||
530 | */ | ||
531 | struct fcpio_tcmnd_16 { | ||
532 | u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ | ||
533 | u8 crn; /* SCSI Command Reference No. */ | ||
534 | u8 pri_ta; /* SCSI Priority and Task attribute */ | ||
535 | u8 _resvd2; /* reserved: should be 0 */ | ||
536 | u8 flags; /* command flags */ | ||
537 | u8 scsi_cdb[CDB_16]; /* SCSI Cmnd Descriptor Block */ | ||
538 | u32 data_len; /* length of data expected */ | ||
539 | u8 _resvd1; /* reserved */ | ||
540 | u8 s_id[3]; /* FC vNIC only: Source S_ID */ | ||
541 | }; | ||
542 | |||
543 | /* | ||
544 | * Priority/Task Attribute settings | ||
545 | */ | ||
546 | #define FCPIO_TCMND_PTA_SIMPLE 0 /* simple task attribute */ | ||
547 | #define FCPIO_TCMND_PTA_HEADQ 1 /* head of queue task attribute */ | ||
548 | #define FCPIO_TCMND_PTA_ORDERED 2 /* ordered task attribute */ | ||
549 | #define FCPIO_TCMND_PTA_ACA 4 /* auto contingent allegiance */ | ||
550 | #define FCPIO_TCMND_PRI_SHIFT 3 /* priority field starts in bit 3 */ | ||
551 | |||
552 | /* | ||
553 | * Command flags | ||
554 | */ | ||
555 | #define FCPIO_TCMND_RDDATA 0x02 /* read data */ | ||
556 | #define FCPIO_TCMND_WRDATA 0x01 /* write data */ | ||
557 | |||
558 | /* | ||
559 | * fcpio_tcmnd_32: firmware -> host request | ||
560 | * | ||
561 | * used by the firmware to notify the host of an incoming target SCSI 32-Byte | ||
562 | * request | ||
563 | */ | ||
564 | struct fcpio_tcmnd_32 { | ||
565 | u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ | ||
566 | u8 crn; /* SCSI Command Reference No. */ | ||
567 | u8 pri_ta; /* SCSI Priority and Task attribute */ | ||
568 | u8 _resvd2; /* reserved: should be 0 */ | ||
569 | u8 flags; /* command flags */ | ||
570 | u8 scsi_cdb[CDB_32]; /* SCSI Cmnd Descriptor Block */ | ||
571 | u32 data_len; /* length of data expected */ | ||
572 | u8 _resvd0; /* reserved */ | ||
573 | u8 s_id[3]; /* FC vNIC only: Source S_ID */ | ||
574 | }; | ||
575 | |||
576 | /* | ||
577 | * fcpio_tdrsp_cmpl: firmware -> host response | ||
578 | * | ||
579 | * used by the firmware to notify the host of a response to a host target | ||
580 | * command | ||
581 | */ | ||
582 | struct fcpio_tdrsp_cmpl { | ||
583 | u16 rx_id; /* rx_id of the target request */ | ||
584 | u16 _resvd0; /* reserved */ | ||
585 | }; | ||
586 | |||
587 | /* | ||
588 | * fcpio_ttmf: firmware -> host request | ||
589 | * | ||
590 | * used by the firmware to notify the host of an incoming task management | ||
591 | * function request | ||
592 | */ | ||
593 | struct fcpio_ttmf { | ||
594 | u8 _resvd0; /* reserved */ | ||
595 | u8 s_id[3]; /* FC vNIC only: Source S_ID */ | ||
596 | u8 lun[LUN_ADDRESS]; /* FC vNIC only: LUN address */ | ||
597 | u8 crn; /* SCSI Command Reference No. */ | ||
598 | u8 _resvd2[3]; /* reserved */ | ||
599 | u32 tmf_type; /* task management request type */ | ||
600 | }; | ||
601 | |||
602 | /* | ||
603 | * Task Management request | ||
604 | */ | ||
605 | #define FCPIO_TTMF_CLR_ACA 0x40 /* Clear ACA condition */ | ||
606 | #define FCPIO_TTMF_LUN_RESET 0x10 /* logical unit reset task mgmt */ | ||
607 | #define FCPIO_TTMF_CLR_TASK_SET 0x04 /* clear task set */ | ||
608 | #define FCPIO_TTMF_ABT_TASK_SET 0x02 /* abort task set */ | ||
609 | #define FCPIO_TTMF_ABT_TASK 0x01 /* abort task */ | ||
610 | |||
611 | /* | ||
612 | * fcpio_tabort_cmpl: firmware -> host response | ||
613 | * | ||
614 | * used by the firmware to respond to a host's tabort request | ||
615 | */ | ||
616 | struct fcpio_tabort_cmpl { | ||
617 | u16 rx_id; /* rx_id of the target request */ | ||
618 | u16 _resvd0; /* reserved */ | ||
619 | }; | ||
620 | |||
621 | /* | ||
622 | * fcpio_ack: firmware -> host response | ||
623 | * | ||
624 | * used by firmware to notify the host of the last work request received | ||
625 | */ | ||
626 | struct fcpio_ack { | ||
627 | u16 request_out; /* last host entry received */ | ||
628 | u16 _resvd; | ||
629 | }; | ||
630 | |||
631 | /* | ||
632 | * fcpio_reset_cmpl: firmware -> host response | ||
633 | * | ||
634 | * use by firmware to respond to the host's reset request | ||
635 | */ | ||
636 | struct fcpio_reset_cmpl { | ||
637 | u16 vnic_id; | ||
638 | }; | ||
639 | |||
640 | /* | ||
641 | * fcpio_flogi_reg_cmpl: firmware -> host response | ||
642 | * | ||
643 | * fc vnic only | ||
644 | * response to the fcpio_flogi_reg request | ||
645 | */ | ||
646 | struct fcpio_flogi_reg_cmpl { | ||
647 | u32 _resvd; | ||
648 | }; | ||
649 | |||
650 | /* | ||
651 | * fcpio_echo_cmpl: firmware -> host response | ||
652 | * | ||
653 | * response to the fcpio_echo request | ||
654 | */ | ||
655 | struct fcpio_echo_cmpl { | ||
656 | u32 _resvd; | ||
657 | }; | ||
658 | |||
659 | /* | ||
660 | * fcpio_lunmap_chng: firmware -> host notification | ||
661 | * | ||
662 | * scsi vnic only | ||
663 | * notifies the host that the lunmap tables have changed | ||
664 | */ | ||
665 | struct fcpio_lunmap_chng { | ||
666 | u32 _resvd; | ||
667 | }; | ||
668 | |||
669 | /* | ||
670 | * fcpio_lunmap_req_cmpl: firmware -> host response | ||
671 | * | ||
672 | * scsi vnic only | ||
673 | * response for lunmap table request from the host | ||
674 | */ | ||
675 | struct fcpio_lunmap_req_cmpl { | ||
676 | u32 _resvd; | ||
677 | }; | ||
678 | |||
679 | /* | ||
680 | * Basic structure for all fcpio structures that are sent from the firmware to | ||
681 | * the host. They are 64 bytes per structure. | ||
682 | */ | ||
683 | #define FCPIO_FW_REQ_LEN 64 /* expected length of fw requests */ | ||
684 | struct fcpio_fw_req { | ||
685 | struct fcpio_header hdr; | ||
686 | |||
687 | union { | ||
688 | /* | ||
689 | * Defines space needed for request | ||
690 | */ | ||
691 | u8 buf[FCPIO_FW_REQ_LEN - sizeof(struct fcpio_header)]; | ||
692 | |||
693 | /* | ||
694 | * Initiator firmware responses | ||
695 | */ | ||
696 | struct fcpio_icmnd_cmpl icmnd_cmpl; | ||
697 | struct fcpio_itmf_cmpl itmf_cmpl; | ||
698 | |||
699 | /* | ||
700 | * Target firmware new requests | ||
701 | */ | ||
702 | struct fcpio_tcmnd_16 tcmnd_16; | ||
703 | struct fcpio_tcmnd_32 tcmnd_32; | ||
704 | |||
705 | /* | ||
706 | * Target firmware responses | ||
707 | */ | ||
708 | struct fcpio_tdrsp_cmpl tdrsp_cmpl; | ||
709 | struct fcpio_ttmf ttmf; | ||
710 | struct fcpio_tabort_cmpl tabort_cmpl; | ||
711 | |||
712 | /* | ||
713 | * Firmware response to work received | ||
714 | */ | ||
715 | struct fcpio_ack ack; | ||
716 | |||
717 | /* | ||
718 | * Misc requests | ||
719 | */ | ||
720 | struct fcpio_reset_cmpl reset_cmpl; | ||
721 | struct fcpio_flogi_reg_cmpl flogi_reg_cmpl; | ||
722 | struct fcpio_echo_cmpl echo_cmpl; | ||
723 | struct fcpio_lunmap_chng lunmap_chng; | ||
724 | struct fcpio_lunmap_req_cmpl lunmap_req_cmpl; | ||
725 | } u; | ||
726 | }; | ||
727 | |||
728 | /* | ||
729 | * Access routines to encode and decode the color bit, which is the most | ||
730 | * significant bit of the MSB of the structure | ||
731 | */ | ||
732 | static inline void fcpio_color_enc(struct fcpio_fw_req *fw_req, u8 color) | ||
733 | { | ||
734 | u8 *c = ((u8 *) fw_req) + sizeof(struct fcpio_fw_req) - 1; | ||
735 | |||
736 | if (color) | ||
737 | *c |= 0x80; | ||
738 | else | ||
739 | *c &= ~0x80; | ||
740 | } | ||
741 | |||
742 | static inline void fcpio_color_dec(struct fcpio_fw_req *fw_req, u8 *color) | ||
743 | { | ||
744 | u8 *c = ((u8 *) fw_req) + sizeof(struct fcpio_fw_req) - 1; | ||
745 | |||
746 | *color = *c >> 7; | ||
747 | |||
748 | /* | ||
749 | * Make sure color bit is read from desc *before* other fields | ||
750 | * are read from desc. Hardware guarantees color bit is last | ||
751 | * bit (byte) written. Adding the rmb() prevents the compiler | ||
752 | * and/or CPU from reordering the reads which would potentially | ||
753 | * result in reading stale values. | ||
754 | */ | ||
755 | |||
756 | rmb(); | ||
757 | |||
758 | } | ||
759 | |||
760 | /* | ||
761 | * Lunmap table entry for scsi vnics | ||
762 | */ | ||
763 | #define FCPIO_LUNMAP_TABLE_SIZE 256 | ||
764 | #define FCPIO_FLAGS_LUNMAP_VALID 0x80 | ||
765 | #define FCPIO_FLAGS_BOOT 0x01 | ||
766 | struct fcpio_lunmap_entry { | ||
767 | u8 bus; | ||
768 | u8 target; | ||
769 | u8 lun; | ||
770 | u8 path_cnt; | ||
771 | u16 flags; | ||
772 | u16 update_cnt; | ||
773 | }; | ||
774 | |||
775 | struct fcpio_lunmap_tbl { | ||
776 | u32 update_cnt; | ||
777 | struct fcpio_lunmap_entry lunmaps[FCPIO_LUNMAP_TABLE_SIZE]; | ||
778 | }; | ||
779 | |||
780 | #endif /* _FCPIO_H_ */ | ||
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h new file mode 100644 index 000000000000..e4c0a3d7d87b --- /dev/null +++ b/drivers/scsi/fnic/fnic.h | |||
@@ -0,0 +1,265 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _FNIC_H_ | ||
19 | #define _FNIC_H_ | ||
20 | |||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/netdevice.h> | ||
23 | #include <linux/workqueue.h> | ||
24 | #include <scsi/libfc.h> | ||
25 | #include "fnic_io.h" | ||
26 | #include "fnic_res.h" | ||
27 | #include "vnic_dev.h" | ||
28 | #include "vnic_wq.h" | ||
29 | #include "vnic_rq.h" | ||
30 | #include "vnic_cq.h" | ||
31 | #include "vnic_wq_copy.h" | ||
32 | #include "vnic_intr.h" | ||
33 | #include "vnic_stats.h" | ||
34 | #include "vnic_scsi.h" | ||
35 | |||
36 | #define DRV_NAME "fnic" | ||
37 | #define DRV_DESCRIPTION "Cisco FCoE HBA Driver" | ||
38 | #define DRV_VERSION "1.0.0.1121" | ||
39 | #define PFX DRV_NAME ": " | ||
40 | #define DFX DRV_NAME "%d: " | ||
41 | |||
42 | #define DESC_CLEAN_LOW_WATERMARK 8 | ||
43 | #define FNIC_MAX_IO_REQ 2048 /* scsi_cmnd tag map entries */ | ||
44 | #define FNIC_IO_LOCKS 64 /* IO locks: power of 2 */ | ||
45 | #define FNIC_DFLT_QUEUE_DEPTH 32 | ||
46 | #define FNIC_STATS_RATE_LIMIT 4 /* limit rate at which stats are pulled up */ | ||
47 | |||
48 | /* | ||
49 | * Tag bits used for special requests. | ||
50 | */ | ||
51 | #define BIT(nr) (1UL << (nr)) | ||
52 | #define FNIC_TAG_ABORT BIT(30) /* tag bit indicating abort */ | ||
53 | #define FNIC_TAG_DEV_RST BIT(29) /* indicates device reset */ | ||
54 | #define FNIC_TAG_MASK (BIT(24) - 1) /* mask for lookup */ | ||
55 | #define FNIC_NO_TAG -1 | ||
56 | |||
57 | /* | ||
58 | * Usage of the scsi_cmnd scratchpad. | ||
59 | * These fields are locked by the hashed io_req_lock. | ||
60 | */ | ||
61 | #define CMD_SP(Cmnd) ((Cmnd)->SCp.ptr) | ||
62 | #define CMD_STATE(Cmnd) ((Cmnd)->SCp.phase) | ||
63 | #define CMD_ABTS_STATUS(Cmnd) ((Cmnd)->SCp.Message) | ||
64 | #define CMD_LR_STATUS(Cmnd) ((Cmnd)->SCp.have_data_in) | ||
65 | #define CMD_TAG(Cmnd) ((Cmnd)->SCp.sent_command) | ||
66 | |||
67 | #define FCPIO_INVALID_CODE 0x100 /* hdr_status value unused by firmware */ | ||
68 | |||
69 | #define FNIC_LUN_RESET_TIMEOUT 10000 /* mSec */ | ||
70 | #define FNIC_HOST_RESET_TIMEOUT 10000 /* mSec */ | ||
71 | #define FNIC_RMDEVICE_TIMEOUT 1000 /* mSec */ | ||
72 | #define FNIC_HOST_RESET_SETTLE_TIME 30 /* Sec */ | ||
73 | |||
74 | #define FNIC_MAX_FCP_TARGET 256 | ||
75 | |||
76 | extern unsigned int fnic_log_level; | ||
77 | |||
78 | #define FNIC_MAIN_LOGGING 0x01 | ||
79 | #define FNIC_FCS_LOGGING 0x02 | ||
80 | #define FNIC_SCSI_LOGGING 0x04 | ||
81 | #define FNIC_ISR_LOGGING 0x08 | ||
82 | |||
83 | #define FNIC_CHECK_LOGGING(LEVEL, CMD) \ | ||
84 | do { \ | ||
85 | if (unlikely(fnic_log_level & LEVEL)) \ | ||
86 | do { \ | ||
87 | CMD; \ | ||
88 | } while (0); \ | ||
89 | } while (0) | ||
90 | |||
91 | #define FNIC_MAIN_DBG(kern_level, host, fmt, args...) \ | ||
92 | FNIC_CHECK_LOGGING(FNIC_MAIN_LOGGING, \ | ||
93 | shost_printk(kern_level, host, fmt, ##args);) | ||
94 | |||
95 | #define FNIC_FCS_DBG(kern_level, host, fmt, args...) \ | ||
96 | FNIC_CHECK_LOGGING(FNIC_FCS_LOGGING, \ | ||
97 | shost_printk(kern_level, host, fmt, ##args);) | ||
98 | |||
99 | #define FNIC_SCSI_DBG(kern_level, host, fmt, args...) \ | ||
100 | FNIC_CHECK_LOGGING(FNIC_SCSI_LOGGING, \ | ||
101 | shost_printk(kern_level, host, fmt, ##args);) | ||
102 | |||
103 | #define FNIC_ISR_DBG(kern_level, host, fmt, args...) \ | ||
104 | FNIC_CHECK_LOGGING(FNIC_ISR_LOGGING, \ | ||
105 | shost_printk(kern_level, host, fmt, ##args);) | ||
106 | |||
107 | extern const char *fnic_state_str[]; | ||
108 | |||
109 | enum fnic_intx_intr_index { | ||
110 | FNIC_INTX_WQ_RQ_COPYWQ, | ||
111 | FNIC_INTX_ERR, | ||
112 | FNIC_INTX_NOTIFY, | ||
113 | FNIC_INTX_INTR_MAX, | ||
114 | }; | ||
115 | |||
116 | enum fnic_msix_intr_index { | ||
117 | FNIC_MSIX_RQ, | ||
118 | FNIC_MSIX_WQ, | ||
119 | FNIC_MSIX_WQ_COPY, | ||
120 | FNIC_MSIX_ERR_NOTIFY, | ||
121 | FNIC_MSIX_INTR_MAX, | ||
122 | }; | ||
123 | |||
124 | struct fnic_msix_entry { | ||
125 | int requested; | ||
126 | char devname[IFNAMSIZ]; | ||
127 | irqreturn_t (*isr)(int, void *); | ||
128 | void *devid; | ||
129 | }; | ||
130 | |||
131 | enum fnic_state { | ||
132 | FNIC_IN_FC_MODE = 0, | ||
133 | FNIC_IN_FC_TRANS_ETH_MODE, | ||
134 | FNIC_IN_ETH_MODE, | ||
135 | FNIC_IN_ETH_TRANS_FC_MODE, | ||
136 | }; | ||
137 | |||
138 | #define FNIC_WQ_COPY_MAX 1 | ||
139 | #define FNIC_WQ_MAX 1 | ||
140 | #define FNIC_RQ_MAX 1 | ||
141 | #define FNIC_CQ_MAX (FNIC_WQ_COPY_MAX + FNIC_WQ_MAX + FNIC_RQ_MAX) | ||
142 | |||
143 | struct mempool; | ||
144 | |||
145 | /* Per-instance private data structure */ | ||
146 | struct fnic { | ||
147 | struct fc_lport *lport; | ||
148 | struct vnic_dev_bar bar0; | ||
149 | |||
150 | struct msix_entry msix_entry[FNIC_MSIX_INTR_MAX]; | ||
151 | struct fnic_msix_entry msix[FNIC_MSIX_INTR_MAX]; | ||
152 | |||
153 | struct vnic_stats *stats; | ||
154 | unsigned long stats_time; /* time of stats update */ | ||
155 | struct vnic_nic_cfg *nic_cfg; | ||
156 | char name[IFNAMSIZ]; | ||
157 | struct timer_list notify_timer; /* used for MSI interrupts */ | ||
158 | |||
159 | unsigned int err_intr_offset; | ||
160 | unsigned int link_intr_offset; | ||
161 | |||
162 | unsigned int wq_count; | ||
163 | unsigned int cq_count; | ||
164 | |||
165 | u32 fcoui_mode:1; /* use fcoui address*/ | ||
166 | u32 vlan_hw_insert:1; /* let hw insert the tag */ | ||
167 | u32 in_remove:1; /* fnic device in removal */ | ||
168 | u32 stop_rx_link_events:1; /* stop proc. rx frames, link events */ | ||
169 | |||
170 | struct completion *remove_wait; /* device remove thread blocks */ | ||
171 | |||
172 | struct fc_frame *flogi; | ||
173 | struct fc_frame *flogi_resp; | ||
174 | u16 flogi_oxid; | ||
175 | unsigned long s_id; | ||
176 | enum fnic_state state; | ||
177 | spinlock_t fnic_lock; | ||
178 | |||
179 | u16 vlan_id; /* VLAN tag including priority */ | ||
180 | u8 mac_addr[ETH_ALEN]; | ||
181 | u8 dest_addr[ETH_ALEN]; | ||
182 | u8 data_src_addr[ETH_ALEN]; | ||
183 | u64 fcp_input_bytes; /* internal statistic */ | ||
184 | u64 fcp_output_bytes; /* internal statistic */ | ||
185 | u32 link_down_cnt; | ||
186 | int link_status; | ||
187 | |||
188 | struct list_head list; | ||
189 | struct pci_dev *pdev; | ||
190 | struct vnic_fc_config config; | ||
191 | struct vnic_dev *vdev; | ||
192 | unsigned int raw_wq_count; | ||
193 | unsigned int wq_copy_count; | ||
194 | unsigned int rq_count; | ||
195 | int fw_ack_index[FNIC_WQ_COPY_MAX]; | ||
196 | unsigned short fw_ack_recd[FNIC_WQ_COPY_MAX]; | ||
197 | unsigned short wq_copy_desc_low[FNIC_WQ_COPY_MAX]; | ||
198 | unsigned int intr_count; | ||
199 | u32 __iomem *legacy_pba; | ||
200 | struct fnic_host_tag *tags; | ||
201 | mempool_t *io_req_pool; | ||
202 | mempool_t *io_sgl_pool[FNIC_SGL_NUM_CACHES]; | ||
203 | spinlock_t io_req_lock[FNIC_IO_LOCKS]; /* locks for scsi cmnds */ | ||
204 | |||
205 | struct work_struct link_work; | ||
206 | struct work_struct frame_work; | ||
207 | struct sk_buff_head frame_queue; | ||
208 | |||
209 | /* copy work queue cache line section */ | ||
210 | ____cacheline_aligned struct vnic_wq_copy wq_copy[FNIC_WQ_COPY_MAX]; | ||
211 | /* completion queue cache line section */ | ||
212 | ____cacheline_aligned struct vnic_cq cq[FNIC_CQ_MAX]; | ||
213 | |||
214 | spinlock_t wq_copy_lock[FNIC_WQ_COPY_MAX]; | ||
215 | |||
216 | /* work queue cache line section */ | ||
217 | ____cacheline_aligned struct vnic_wq wq[FNIC_WQ_MAX]; | ||
218 | spinlock_t wq_lock[FNIC_WQ_MAX]; | ||
219 | |||
220 | /* receive queue cache line section */ | ||
221 | ____cacheline_aligned struct vnic_rq rq[FNIC_RQ_MAX]; | ||
222 | |||
223 | /* interrupt resource cache line section */ | ||
224 | ____cacheline_aligned struct vnic_intr intr[FNIC_MSIX_INTR_MAX]; | ||
225 | }; | ||
226 | |||
227 | extern struct workqueue_struct *fnic_event_queue; | ||
228 | extern struct device_attribute *fnic_attrs[]; | ||
229 | |||
230 | void fnic_clear_intr_mode(struct fnic *fnic); | ||
231 | int fnic_set_intr_mode(struct fnic *fnic); | ||
232 | void fnic_free_intr(struct fnic *fnic); | ||
233 | int fnic_request_intr(struct fnic *fnic); | ||
234 | |||
235 | int fnic_send(struct fc_lport *, struct fc_frame *); | ||
236 | void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf); | ||
237 | void fnic_handle_frame(struct work_struct *work); | ||
238 | void fnic_handle_link(struct work_struct *work); | ||
239 | int fnic_rq_cmpl_handler(struct fnic *fnic, int); | ||
240 | int fnic_alloc_rq_frame(struct vnic_rq *rq); | ||
241 | void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf); | ||
242 | int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp); | ||
243 | |||
244 | int fnic_queuecommand(struct scsi_cmnd *, void (*done)(struct scsi_cmnd *)); | ||
245 | int fnic_abort_cmd(struct scsi_cmnd *); | ||
246 | int fnic_device_reset(struct scsi_cmnd *); | ||
247 | int fnic_host_reset(struct scsi_cmnd *); | ||
248 | int fnic_reset(struct Scsi_Host *); | ||
249 | void fnic_scsi_cleanup(struct fc_lport *); | ||
250 | void fnic_scsi_abort_io(struct fc_lport *); | ||
251 | void fnic_empty_scsi_cleanup(struct fc_lport *); | ||
252 | void fnic_exch_mgr_reset(struct fc_lport *, u32, u32); | ||
253 | int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int); | ||
254 | int fnic_wq_cmpl_handler(struct fnic *fnic, int); | ||
255 | int fnic_flogi_reg_handler(struct fnic *fnic); | ||
256 | void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, | ||
257 | struct fcpio_host_req *desc); | ||
258 | int fnic_fw_reset_handler(struct fnic *fnic); | ||
259 | void fnic_terminate_rport_io(struct fc_rport *); | ||
260 | const char *fnic_state_to_str(unsigned int state); | ||
261 | |||
262 | void fnic_log_q_error(struct fnic *fnic); | ||
263 | void fnic_handle_link_event(struct fnic *fnic); | ||
264 | |||
265 | #endif /* _FNIC_H_ */ | ||
diff --git a/drivers/scsi/fnic/fnic_attrs.c b/drivers/scsi/fnic/fnic_attrs.c new file mode 100644 index 000000000000..aea0c3becfd4 --- /dev/null +++ b/drivers/scsi/fnic/fnic_attrs.c | |||
@@ -0,0 +1,56 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/device.h> | ||
20 | #include <scsi/scsi_host.h> | ||
21 | #include "fnic.h" | ||
22 | |||
23 | static ssize_t fnic_show_state(struct device *dev, | ||
24 | struct device_attribute *attr, char *buf) | ||
25 | { | ||
26 | struct fc_lport *lp = shost_priv(class_to_shost(dev)); | ||
27 | struct fnic *fnic = lport_priv(lp); | ||
28 | |||
29 | return snprintf(buf, PAGE_SIZE, "%s\n", fnic_state_str[fnic->state]); | ||
30 | } | ||
31 | |||
32 | static ssize_t fnic_show_drv_version(struct device *dev, | ||
33 | struct device_attribute *attr, char *buf) | ||
34 | { | ||
35 | return snprintf(buf, PAGE_SIZE, "%s\n", DRV_VERSION); | ||
36 | } | ||
37 | |||
38 | static ssize_t fnic_show_link_state(struct device *dev, | ||
39 | struct device_attribute *attr, char *buf) | ||
40 | { | ||
41 | struct fc_lport *lp = shost_priv(class_to_shost(dev)); | ||
42 | |||
43 | return snprintf(buf, PAGE_SIZE, "%s\n", (lp->link_up) | ||
44 | ? "Link Up" : "Link Down"); | ||
45 | } | ||
46 | |||
47 | static DEVICE_ATTR(fnic_state, S_IRUGO, fnic_show_state, NULL); | ||
48 | static DEVICE_ATTR(drv_version, S_IRUGO, fnic_show_drv_version, NULL); | ||
49 | static DEVICE_ATTR(link_state, S_IRUGO, fnic_show_link_state, NULL); | ||
50 | |||
51 | struct device_attribute *fnic_attrs[] = { | ||
52 | &dev_attr_fnic_state, | ||
53 | &dev_attr_drv_version, | ||
54 | &dev_attr_link_state, | ||
55 | NULL, | ||
56 | }; | ||
diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c new file mode 100644 index 000000000000..07e6eedb83ce --- /dev/null +++ b/drivers/scsi/fnic/fnic_fcs.c | |||
@@ -0,0 +1,742 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/pci.h> | ||
20 | #include <linux/skbuff.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <linux/spinlock.h> | ||
23 | #include <linux/if_ether.h> | ||
24 | #include <linux/if_vlan.h> | ||
25 | #include <linux/workqueue.h> | ||
26 | #include <scsi/fc/fc_els.h> | ||
27 | #include <scsi/fc/fc_fcoe.h> | ||
28 | #include <scsi/fc_frame.h> | ||
29 | #include <scsi/libfc.h> | ||
30 | #include "fnic_io.h" | ||
31 | #include "fnic.h" | ||
32 | #include "cq_enet_desc.h" | ||
33 | #include "cq_exch_desc.h" | ||
34 | |||
35 | struct workqueue_struct *fnic_event_queue; | ||
36 | |||
37 | void fnic_handle_link(struct work_struct *work) | ||
38 | { | ||
39 | struct fnic *fnic = container_of(work, struct fnic, link_work); | ||
40 | unsigned long flags; | ||
41 | int old_link_status; | ||
42 | u32 old_link_down_cnt; | ||
43 | |||
44 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
45 | |||
46 | if (fnic->stop_rx_link_events) { | ||
47 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
48 | return; | ||
49 | } | ||
50 | |||
51 | old_link_down_cnt = fnic->link_down_cnt; | ||
52 | old_link_status = fnic->link_status; | ||
53 | fnic->link_status = vnic_dev_link_status(fnic->vdev); | ||
54 | fnic->link_down_cnt = vnic_dev_link_down_cnt(fnic->vdev); | ||
55 | |||
56 | if (old_link_status == fnic->link_status) { | ||
57 | if (!fnic->link_status) | ||
58 | /* DOWN -> DOWN */ | ||
59 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
60 | else { | ||
61 | if (old_link_down_cnt != fnic->link_down_cnt) { | ||
62 | /* UP -> DOWN -> UP */ | ||
63 | fnic->lport->host_stats.link_failure_count++; | ||
64 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
65 | FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, | ||
66 | "link down\n"); | ||
67 | fc_linkdown(fnic->lport); | ||
68 | FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, | ||
69 | "link up\n"); | ||
70 | fc_linkup(fnic->lport); | ||
71 | } else | ||
72 | /* UP -> UP */ | ||
73 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
74 | } | ||
75 | } else if (fnic->link_status) { | ||
76 | /* DOWN -> UP */ | ||
77 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
78 | FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "link up\n"); | ||
79 | fc_linkup(fnic->lport); | ||
80 | } else { | ||
81 | /* UP -> DOWN */ | ||
82 | fnic->lport->host_stats.link_failure_count++; | ||
83 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
84 | FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, "link down\n"); | ||
85 | fc_linkdown(fnic->lport); | ||
86 | } | ||
87 | |||
88 | } | ||
89 | |||
90 | /* | ||
91 | * This function passes incoming fabric frames to libFC | ||
92 | */ | ||
93 | void fnic_handle_frame(struct work_struct *work) | ||
94 | { | ||
95 | struct fnic *fnic = container_of(work, struct fnic, frame_work); | ||
96 | struct fc_lport *lp = fnic->lport; | ||
97 | unsigned long flags; | ||
98 | struct sk_buff *skb; | ||
99 | struct fc_frame *fp; | ||
100 | |||
101 | while ((skb = skb_dequeue(&fnic->frame_queue))) { | ||
102 | |||
103 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
104 | if (fnic->stop_rx_link_events) { | ||
105 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
106 | dev_kfree_skb(skb); | ||
107 | return; | ||
108 | } | ||
109 | fp = (struct fc_frame *)skb; | ||
110 | /* if Flogi resp frame, register the address */ | ||
111 | if (fr_flags(fp)) { | ||
112 | vnic_dev_add_addr(fnic->vdev, | ||
113 | fnic->data_src_addr); | ||
114 | fr_flags(fp) = 0; | ||
115 | } | ||
116 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
117 | |||
118 | fc_exch_recv(lp, lp->emp, fp); | ||
119 | } | ||
120 | |||
121 | } | ||
122 | |||
123 | static inline void fnic_import_rq_fc_frame(struct sk_buff *skb, | ||
124 | u32 len, u8 sof, u8 eof) | ||
125 | { | ||
126 | struct fc_frame *fp = (struct fc_frame *)skb; | ||
127 | |||
128 | skb_trim(skb, len); | ||
129 | fr_eof(fp) = eof; | ||
130 | fr_sof(fp) = sof; | ||
131 | } | ||
132 | |||
133 | |||
134 | static inline int fnic_import_rq_eth_pkt(struct sk_buff *skb, u32 len) | ||
135 | { | ||
136 | struct fc_frame *fp; | ||
137 | struct ethhdr *eh; | ||
138 | struct vlan_ethhdr *vh; | ||
139 | struct fcoe_hdr *fcoe_hdr; | ||
140 | struct fcoe_crc_eof *ft; | ||
141 | u32 transport_len = 0; | ||
142 | |||
143 | eh = (struct ethhdr *)skb->data; | ||
144 | vh = (struct vlan_ethhdr *)skb->data; | ||
145 | if (vh->h_vlan_proto == htons(ETH_P_8021Q) && | ||
146 | vh->h_vlan_encapsulated_proto == htons(ETH_P_FCOE)) { | ||
147 | skb_pull(skb, sizeof(struct vlan_ethhdr)); | ||
148 | transport_len += sizeof(struct vlan_ethhdr); | ||
149 | } else if (eh->h_proto == htons(ETH_P_FCOE)) { | ||
150 | transport_len += sizeof(struct ethhdr); | ||
151 | skb_pull(skb, sizeof(struct ethhdr)); | ||
152 | } else | ||
153 | return -1; | ||
154 | |||
155 | fcoe_hdr = (struct fcoe_hdr *)skb->data; | ||
156 | if (FC_FCOE_DECAPS_VER(fcoe_hdr) != FC_FCOE_VER) | ||
157 | return -1; | ||
158 | |||
159 | fp = (struct fc_frame *)skb; | ||
160 | fc_frame_init(fp); | ||
161 | fr_sof(fp) = fcoe_hdr->fcoe_sof; | ||
162 | skb_pull(skb, sizeof(struct fcoe_hdr)); | ||
163 | transport_len += sizeof(struct fcoe_hdr); | ||
164 | |||
165 | ft = (struct fcoe_crc_eof *)(skb->data + len - | ||
166 | transport_len - sizeof(*ft)); | ||
167 | fr_eof(fp) = ft->fcoe_eof; | ||
168 | skb_trim(skb, len - transport_len - sizeof(*ft)); | ||
169 | return 0; | ||
170 | } | ||
171 | |||
172 | static inline int fnic_handle_flogi_resp(struct fnic *fnic, | ||
173 | struct fc_frame *fp) | ||
174 | { | ||
175 | u8 mac[ETH_ALEN] = FC_FCOE_FLOGI_MAC; | ||
176 | struct ethhdr *eth_hdr; | ||
177 | struct fc_frame_header *fh; | ||
178 | int ret = 0; | ||
179 | unsigned long flags; | ||
180 | struct fc_frame *old_flogi_resp = NULL; | ||
181 | |||
182 | fh = (struct fc_frame_header *)fr_hdr(fp); | ||
183 | |||
184 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
185 | |||
186 | if (fnic->state == FNIC_IN_ETH_MODE) { | ||
187 | |||
188 | /* | ||
189 | * Check if oxid matches on taking the lock. A new Flogi | ||
190 | * issued by libFC might have changed the fnic cached oxid | ||
191 | */ | ||
192 | if (fnic->flogi_oxid != ntohs(fh->fh_ox_id)) { | ||
193 | FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, | ||
194 | "Flogi response oxid not" | ||
195 | " matching cached oxid, dropping frame" | ||
196 | "\n"); | ||
197 | ret = -1; | ||
198 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
199 | dev_kfree_skb_irq(fp_skb(fp)); | ||
200 | goto handle_flogi_resp_end; | ||
201 | } | ||
202 | |||
203 | /* Drop older cached flogi response frame, cache this frame */ | ||
204 | old_flogi_resp = fnic->flogi_resp; | ||
205 | fnic->flogi_resp = fp; | ||
206 | fnic->flogi_oxid = FC_XID_UNKNOWN; | ||
207 | |||
208 | /* | ||
209 | * this frame is part of flogi get the src mac addr from this | ||
210 | * frame if the src mac is fcoui based then we mark the | ||
211 | * address mode flag to use fcoui base for dst mac addr | ||
212 | * otherwise we have to store the fcoe gateway addr | ||
213 | */ | ||
214 | eth_hdr = (struct ethhdr *)skb_mac_header(fp_skb(fp)); | ||
215 | memcpy(mac, eth_hdr->h_source, ETH_ALEN); | ||
216 | |||
217 | if (ntoh24(mac) == FC_FCOE_OUI) | ||
218 | fnic->fcoui_mode = 1; | ||
219 | else { | ||
220 | fnic->fcoui_mode = 0; | ||
221 | memcpy(fnic->dest_addr, mac, ETH_ALEN); | ||
222 | } | ||
223 | |||
224 | /* | ||
225 | * Except for Flogi frame, all outbound frames from us have the | ||
226 | * Eth Src address as FC_FCOE_OUI"our_sid". Flogi frame uses | ||
227 | * the vnic MAC address as the Eth Src address | ||
228 | */ | ||
229 | fc_fcoe_set_mac(fnic->data_src_addr, fh->fh_d_id); | ||
230 | |||
231 | /* We get our s_id from the d_id of the flogi resp frame */ | ||
232 | fnic->s_id = ntoh24(fh->fh_d_id); | ||
233 | |||
234 | /* Change state to reflect transition from Eth to FC mode */ | ||
235 | fnic->state = FNIC_IN_ETH_TRANS_FC_MODE; | ||
236 | |||
237 | } else { | ||
238 | FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, | ||
239 | "Unexpected fnic state %s while" | ||
240 | " processing flogi resp\n", | ||
241 | fnic_state_to_str(fnic->state)); | ||
242 | ret = -1; | ||
243 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
244 | dev_kfree_skb_irq(fp_skb(fp)); | ||
245 | goto handle_flogi_resp_end; | ||
246 | } | ||
247 | |||
248 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
249 | |||
250 | /* Drop older cached frame */ | ||
251 | if (old_flogi_resp) | ||
252 | dev_kfree_skb_irq(fp_skb(old_flogi_resp)); | ||
253 | |||
254 | /* | ||
255 | * send flogi reg request to firmware, this will put the fnic in | ||
256 | * in FC mode | ||
257 | */ | ||
258 | ret = fnic_flogi_reg_handler(fnic); | ||
259 | |||
260 | if (ret < 0) { | ||
261 | int free_fp = 1; | ||
262 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
263 | /* | ||
264 | * free the frame is some other thread is not | ||
265 | * pointing to it | ||
266 | */ | ||
267 | if (fnic->flogi_resp != fp) | ||
268 | free_fp = 0; | ||
269 | else | ||
270 | fnic->flogi_resp = NULL; | ||
271 | |||
272 | if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE) | ||
273 | fnic->state = FNIC_IN_ETH_MODE; | ||
274 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
275 | if (free_fp) | ||
276 | dev_kfree_skb_irq(fp_skb(fp)); | ||
277 | } | ||
278 | |||
279 | handle_flogi_resp_end: | ||
280 | return ret; | ||
281 | } | ||
282 | |||
283 | /* Returns 1 for a response that matches cached flogi oxid */ | ||
284 | static inline int is_matching_flogi_resp_frame(struct fnic *fnic, | ||
285 | struct fc_frame *fp) | ||
286 | { | ||
287 | struct fc_frame_header *fh; | ||
288 | int ret = 0; | ||
289 | u32 f_ctl; | ||
290 | |||
291 | fh = fc_frame_header_get(fp); | ||
292 | f_ctl = ntoh24(fh->fh_f_ctl); | ||
293 | |||
294 | if (fnic->flogi_oxid == ntohs(fh->fh_ox_id) && | ||
295 | fh->fh_r_ctl == FC_RCTL_ELS_REP && | ||
296 | (f_ctl & (FC_FC_EX_CTX | FC_FC_SEQ_CTX)) == FC_FC_EX_CTX && | ||
297 | fh->fh_type == FC_TYPE_ELS) | ||
298 | ret = 1; | ||
299 | |||
300 | return ret; | ||
301 | } | ||
302 | |||
303 | static void fnic_rq_cmpl_frame_recv(struct vnic_rq *rq, struct cq_desc | ||
304 | *cq_desc, struct vnic_rq_buf *buf, | ||
305 | int skipped __attribute__((unused)), | ||
306 | void *opaque) | ||
307 | { | ||
308 | struct fnic *fnic = vnic_dev_priv(rq->vdev); | ||
309 | struct sk_buff *skb; | ||
310 | struct fc_frame *fp; | ||
311 | unsigned int eth_hdrs_stripped; | ||
312 | u8 type, color, eop, sop, ingress_port, vlan_stripped; | ||
313 | u8 fcoe = 0, fcoe_sof, fcoe_eof; | ||
314 | u8 fcoe_fc_crc_ok = 1, fcoe_enc_error = 0; | ||
315 | u8 tcp_udp_csum_ok, udp, tcp, ipv4_csum_ok; | ||
316 | u8 ipv6, ipv4, ipv4_fragment, rss_type, csum_not_calc; | ||
317 | u8 fcs_ok = 1, packet_error = 0; | ||
318 | u16 q_number, completed_index, bytes_written = 0, vlan, checksum; | ||
319 | u32 rss_hash; | ||
320 | u16 exchange_id, tmpl; | ||
321 | u8 sof = 0; | ||
322 | u8 eof = 0; | ||
323 | u32 fcp_bytes_written = 0; | ||
324 | unsigned long flags; | ||
325 | |||
326 | pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len, | ||
327 | PCI_DMA_FROMDEVICE); | ||
328 | skb = buf->os_buf; | ||
329 | buf->os_buf = NULL; | ||
330 | |||
331 | cq_desc_dec(cq_desc, &type, &color, &q_number, &completed_index); | ||
332 | if (type == CQ_DESC_TYPE_RQ_FCP) { | ||
333 | cq_fcp_rq_desc_dec((struct cq_fcp_rq_desc *)cq_desc, | ||
334 | &type, &color, &q_number, &completed_index, | ||
335 | &eop, &sop, &fcoe_fc_crc_ok, &exchange_id, | ||
336 | &tmpl, &fcp_bytes_written, &sof, &eof, | ||
337 | &ingress_port, &packet_error, | ||
338 | &fcoe_enc_error, &fcs_ok, &vlan_stripped, | ||
339 | &vlan); | ||
340 | eth_hdrs_stripped = 1; | ||
341 | |||
342 | } else if (type == CQ_DESC_TYPE_RQ_ENET) { | ||
343 | cq_enet_rq_desc_dec((struct cq_enet_rq_desc *)cq_desc, | ||
344 | &type, &color, &q_number, &completed_index, | ||
345 | &ingress_port, &fcoe, &eop, &sop, | ||
346 | &rss_type, &csum_not_calc, &rss_hash, | ||
347 | &bytes_written, &packet_error, | ||
348 | &vlan_stripped, &vlan, &checksum, | ||
349 | &fcoe_sof, &fcoe_fc_crc_ok, | ||
350 | &fcoe_enc_error, &fcoe_eof, | ||
351 | &tcp_udp_csum_ok, &udp, &tcp, | ||
352 | &ipv4_csum_ok, &ipv6, &ipv4, | ||
353 | &ipv4_fragment, &fcs_ok); | ||
354 | eth_hdrs_stripped = 0; | ||
355 | |||
356 | } else { | ||
357 | /* wrong CQ type*/ | ||
358 | shost_printk(KERN_ERR, fnic->lport->host, | ||
359 | "fnic rq_cmpl wrong cq type x%x\n", type); | ||
360 | goto drop; | ||
361 | } | ||
362 | |||
363 | if (!fcs_ok || packet_error || !fcoe_fc_crc_ok || fcoe_enc_error) { | ||
364 | FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, | ||
365 | "fnic rq_cmpl fcoe x%x fcsok x%x" | ||
366 | " pkterr x%x fcoe_fc_crc_ok x%x, fcoe_enc_err" | ||
367 | " x%x\n", | ||
368 | fcoe, fcs_ok, packet_error, | ||
369 | fcoe_fc_crc_ok, fcoe_enc_error); | ||
370 | goto drop; | ||
371 | } | ||
372 | |||
373 | if (eth_hdrs_stripped) | ||
374 | fnic_import_rq_fc_frame(skb, fcp_bytes_written, sof, eof); | ||
375 | else if (fnic_import_rq_eth_pkt(skb, bytes_written)) | ||
376 | goto drop; | ||
377 | |||
378 | fp = (struct fc_frame *)skb; | ||
379 | |||
380 | /* | ||
381 | * If frame is an ELS response that matches the cached FLOGI OX_ID, | ||
382 | * and is accept, issue flogi_reg_request copy wq request to firmware | ||
383 | * to register the S_ID and determine whether FC_OUI mode or GW mode. | ||
384 | */ | ||
385 | if (is_matching_flogi_resp_frame(fnic, fp)) { | ||
386 | if (!eth_hdrs_stripped) { | ||
387 | if (fc_frame_payload_op(fp) == ELS_LS_ACC) { | ||
388 | fnic_handle_flogi_resp(fnic, fp); | ||
389 | return; | ||
390 | } | ||
391 | /* | ||
392 | * Recd. Flogi reject. No point registering | ||
393 | * with fw, but forward to libFC | ||
394 | */ | ||
395 | goto forward; | ||
396 | } | ||
397 | goto drop; | ||
398 | } | ||
399 | if (!eth_hdrs_stripped) | ||
400 | goto drop; | ||
401 | |||
402 | forward: | ||
403 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
404 | if (fnic->stop_rx_link_events) { | ||
405 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
406 | goto drop; | ||
407 | } | ||
408 | /* Use fr_flags to indicate whether succ. flogi resp or not */ | ||
409 | fr_flags(fp) = 0; | ||
410 | fr_dev(fp) = fnic->lport; | ||
411 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
412 | |||
413 | skb_queue_tail(&fnic->frame_queue, skb); | ||
414 | queue_work(fnic_event_queue, &fnic->frame_work); | ||
415 | |||
416 | return; | ||
417 | drop: | ||
418 | dev_kfree_skb_irq(skb); | ||
419 | } | ||
420 | |||
421 | static int fnic_rq_cmpl_handler_cont(struct vnic_dev *vdev, | ||
422 | struct cq_desc *cq_desc, u8 type, | ||
423 | u16 q_number, u16 completed_index, | ||
424 | void *opaque) | ||
425 | { | ||
426 | struct fnic *fnic = vnic_dev_priv(vdev); | ||
427 | |||
428 | vnic_rq_service(&fnic->rq[q_number], cq_desc, completed_index, | ||
429 | VNIC_RQ_RETURN_DESC, fnic_rq_cmpl_frame_recv, | ||
430 | NULL); | ||
431 | return 0; | ||
432 | } | ||
433 | |||
434 | int fnic_rq_cmpl_handler(struct fnic *fnic, int rq_work_to_do) | ||
435 | { | ||
436 | unsigned int tot_rq_work_done = 0, cur_work_done; | ||
437 | unsigned int i; | ||
438 | int err; | ||
439 | |||
440 | for (i = 0; i < fnic->rq_count; i++) { | ||
441 | cur_work_done = vnic_cq_service(&fnic->cq[i], rq_work_to_do, | ||
442 | fnic_rq_cmpl_handler_cont, | ||
443 | NULL); | ||
444 | if (cur_work_done) { | ||
445 | err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame); | ||
446 | if (err) | ||
447 | shost_printk(KERN_ERR, fnic->lport->host, | ||
448 | "fnic_alloc_rq_frame cant alloc" | ||
449 | " frame\n"); | ||
450 | } | ||
451 | tot_rq_work_done += cur_work_done; | ||
452 | } | ||
453 | |||
454 | return tot_rq_work_done; | ||
455 | } | ||
456 | |||
457 | /* | ||
458 | * This function is called once at init time to allocate and fill RQ | ||
459 | * buffers. Subsequently, it is called in the interrupt context after RQ | ||
460 | * buffer processing to replenish the buffers in the RQ | ||
461 | */ | ||
462 | int fnic_alloc_rq_frame(struct vnic_rq *rq) | ||
463 | { | ||
464 | struct fnic *fnic = vnic_dev_priv(rq->vdev); | ||
465 | struct sk_buff *skb; | ||
466 | u16 len; | ||
467 | dma_addr_t pa; | ||
468 | |||
469 | len = FC_FRAME_HEADROOM + FC_MAX_FRAME + FC_FRAME_TAILROOM; | ||
470 | skb = dev_alloc_skb(len); | ||
471 | if (!skb) { | ||
472 | FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host, | ||
473 | "Unable to allocate RQ sk_buff\n"); | ||
474 | return -ENOMEM; | ||
475 | } | ||
476 | skb_reset_mac_header(skb); | ||
477 | skb_reset_transport_header(skb); | ||
478 | skb_reset_network_header(skb); | ||
479 | skb_put(skb, len); | ||
480 | pa = pci_map_single(fnic->pdev, skb->data, len, PCI_DMA_FROMDEVICE); | ||
481 | fnic_queue_rq_desc(rq, skb, pa, len); | ||
482 | return 0; | ||
483 | } | ||
484 | |||
485 | void fnic_free_rq_buf(struct vnic_rq *rq, struct vnic_rq_buf *buf) | ||
486 | { | ||
487 | struct fc_frame *fp = buf->os_buf; | ||
488 | struct fnic *fnic = vnic_dev_priv(rq->vdev); | ||
489 | |||
490 | pci_unmap_single(fnic->pdev, buf->dma_addr, buf->len, | ||
491 | PCI_DMA_FROMDEVICE); | ||
492 | |||
493 | dev_kfree_skb(fp_skb(fp)); | ||
494 | buf->os_buf = NULL; | ||
495 | } | ||
496 | |||
497 | static inline int is_flogi_frame(struct fc_frame_header *fh) | ||
498 | { | ||
499 | return fh->fh_r_ctl == FC_RCTL_ELS_REQ && *(u8 *)(fh + 1) == ELS_FLOGI; | ||
500 | } | ||
501 | |||
502 | int fnic_send_frame(struct fnic *fnic, struct fc_frame *fp) | ||
503 | { | ||
504 | struct vnic_wq *wq = &fnic->wq[0]; | ||
505 | struct sk_buff *skb; | ||
506 | dma_addr_t pa; | ||
507 | struct ethhdr *eth_hdr; | ||
508 | struct vlan_ethhdr *vlan_hdr; | ||
509 | struct fcoe_hdr *fcoe_hdr; | ||
510 | struct fc_frame_header *fh; | ||
511 | u32 tot_len, eth_hdr_len; | ||
512 | int ret = 0; | ||
513 | unsigned long flags; | ||
514 | |||
515 | fh = fc_frame_header_get(fp); | ||
516 | skb = fp_skb(fp); | ||
517 | |||
518 | if (!fnic->vlan_hw_insert) { | ||
519 | eth_hdr_len = sizeof(*vlan_hdr) + sizeof(*fcoe_hdr); | ||
520 | vlan_hdr = (struct vlan_ethhdr *)skb_push(skb, eth_hdr_len); | ||
521 | eth_hdr = (struct ethhdr *)vlan_hdr; | ||
522 | vlan_hdr->h_vlan_proto = htons(ETH_P_8021Q); | ||
523 | vlan_hdr->h_vlan_encapsulated_proto = htons(ETH_P_FCOE); | ||
524 | vlan_hdr->h_vlan_TCI = htons(fnic->vlan_id); | ||
525 | fcoe_hdr = (struct fcoe_hdr *)(vlan_hdr + 1); | ||
526 | } else { | ||
527 | eth_hdr_len = sizeof(*eth_hdr) + sizeof(*fcoe_hdr); | ||
528 | eth_hdr = (struct ethhdr *)skb_push(skb, eth_hdr_len); | ||
529 | eth_hdr->h_proto = htons(ETH_P_FCOE); | ||
530 | fcoe_hdr = (struct fcoe_hdr *)(eth_hdr + 1); | ||
531 | } | ||
532 | |||
533 | if (is_flogi_frame(fh)) { | ||
534 | fc_fcoe_set_mac(eth_hdr->h_dest, fh->fh_d_id); | ||
535 | memcpy(eth_hdr->h_source, fnic->mac_addr, ETH_ALEN); | ||
536 | } else { | ||
537 | if (fnic->fcoui_mode) | ||
538 | fc_fcoe_set_mac(eth_hdr->h_dest, fh->fh_d_id); | ||
539 | else | ||
540 | memcpy(eth_hdr->h_dest, fnic->dest_addr, ETH_ALEN); | ||
541 | memcpy(eth_hdr->h_source, fnic->data_src_addr, ETH_ALEN); | ||
542 | } | ||
543 | |||
544 | tot_len = skb->len; | ||
545 | BUG_ON(tot_len % 4); | ||
546 | |||
547 | memset(fcoe_hdr, 0, sizeof(*fcoe_hdr)); | ||
548 | fcoe_hdr->fcoe_sof = fr_sof(fp); | ||
549 | if (FC_FCOE_VER) | ||
550 | FC_FCOE_ENCAPS_VER(fcoe_hdr, FC_FCOE_VER); | ||
551 | |||
552 | pa = pci_map_single(fnic->pdev, eth_hdr, tot_len, PCI_DMA_TODEVICE); | ||
553 | |||
554 | spin_lock_irqsave(&fnic->wq_lock[0], flags); | ||
555 | |||
556 | if (!vnic_wq_desc_avail(wq)) { | ||
557 | pci_unmap_single(fnic->pdev, pa, | ||
558 | tot_len, PCI_DMA_TODEVICE); | ||
559 | ret = -1; | ||
560 | goto fnic_send_frame_end; | ||
561 | } | ||
562 | |||
563 | fnic_queue_wq_desc(wq, skb, pa, tot_len, fr_eof(fp), | ||
564 | fnic->vlan_hw_insert, fnic->vlan_id, 1, 1, 1); | ||
565 | fnic_send_frame_end: | ||
566 | spin_unlock_irqrestore(&fnic->wq_lock[0], flags); | ||
567 | |||
568 | if (ret) | ||
569 | dev_kfree_skb_any(fp_skb(fp)); | ||
570 | |||
571 | return ret; | ||
572 | } | ||
573 | |||
574 | /* | ||
575 | * fnic_send | ||
576 | * Routine to send a raw frame | ||
577 | */ | ||
578 | int fnic_send(struct fc_lport *lp, struct fc_frame *fp) | ||
579 | { | ||
580 | struct fnic *fnic = lport_priv(lp); | ||
581 | struct fc_frame_header *fh; | ||
582 | int ret = 0; | ||
583 | enum fnic_state old_state; | ||
584 | unsigned long flags; | ||
585 | struct fc_frame *old_flogi = NULL; | ||
586 | struct fc_frame *old_flogi_resp = NULL; | ||
587 | |||
588 | if (fnic->in_remove) { | ||
589 | dev_kfree_skb(fp_skb(fp)); | ||
590 | ret = -1; | ||
591 | goto fnic_send_end; | ||
592 | } | ||
593 | |||
594 | fh = fc_frame_header_get(fp); | ||
595 | /* if not an Flogi frame, send it out, this is the common case */ | ||
596 | if (!is_flogi_frame(fh)) | ||
597 | return fnic_send_frame(fnic, fp); | ||
598 | |||
599 | /* Flogi frame, now enter the state machine */ | ||
600 | |||
601 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
602 | again: | ||
603 | /* Get any old cached frames, free them after dropping lock */ | ||
604 | old_flogi = fnic->flogi; | ||
605 | fnic->flogi = NULL; | ||
606 | old_flogi_resp = fnic->flogi_resp; | ||
607 | fnic->flogi_resp = NULL; | ||
608 | |||
609 | fnic->flogi_oxid = FC_XID_UNKNOWN; | ||
610 | |||
611 | old_state = fnic->state; | ||
612 | switch (old_state) { | ||
613 | case FNIC_IN_FC_MODE: | ||
614 | case FNIC_IN_ETH_TRANS_FC_MODE: | ||
615 | default: | ||
616 | fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; | ||
617 | vnic_dev_del_addr(fnic->vdev, fnic->data_src_addr); | ||
618 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
619 | |||
620 | if (old_flogi) { | ||
621 | dev_kfree_skb(fp_skb(old_flogi)); | ||
622 | old_flogi = NULL; | ||
623 | } | ||
624 | if (old_flogi_resp) { | ||
625 | dev_kfree_skb(fp_skb(old_flogi_resp)); | ||
626 | old_flogi_resp = NULL; | ||
627 | } | ||
628 | |||
629 | ret = fnic_fw_reset_handler(fnic); | ||
630 | |||
631 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
632 | if (fnic->state != FNIC_IN_FC_TRANS_ETH_MODE) | ||
633 | goto again; | ||
634 | if (ret) { | ||
635 | fnic->state = old_state; | ||
636 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
637 | dev_kfree_skb(fp_skb(fp)); | ||
638 | goto fnic_send_end; | ||
639 | } | ||
640 | old_flogi = fnic->flogi; | ||
641 | fnic->flogi = fp; | ||
642 | fnic->flogi_oxid = ntohs(fh->fh_ox_id); | ||
643 | old_flogi_resp = fnic->flogi_resp; | ||
644 | fnic->flogi_resp = NULL; | ||
645 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
646 | break; | ||
647 | |||
648 | case FNIC_IN_FC_TRANS_ETH_MODE: | ||
649 | /* | ||
650 | * A reset is pending with the firmware. Store the flogi | ||
651 | * and its oxid. The transition out of this state happens | ||
652 | * only when Firmware completes the reset, either with | ||
653 | * success or failed. If success, transition to | ||
654 | * FNIC_IN_ETH_MODE, if fail, then transition to | ||
655 | * FNIC_IN_FC_MODE | ||
656 | */ | ||
657 | fnic->flogi = fp; | ||
658 | fnic->flogi_oxid = ntohs(fh->fh_ox_id); | ||
659 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
660 | break; | ||
661 | |||
662 | case FNIC_IN_ETH_MODE: | ||
663 | /* | ||
664 | * The fw/hw is already in eth mode. Store the oxid, | ||
665 | * and send the flogi frame out. The transition out of this | ||
666 | * state happens only we receive flogi response from the | ||
667 | * network, and the oxid matches the cached oxid when the | ||
668 | * flogi frame was sent out. If they match, then we issue | ||
669 | * a flogi_reg request and transition to state | ||
670 | * FNIC_IN_ETH_TRANS_FC_MODE | ||
671 | */ | ||
672 | fnic->flogi_oxid = ntohs(fh->fh_ox_id); | ||
673 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
674 | ret = fnic_send_frame(fnic, fp); | ||
675 | break; | ||
676 | } | ||
677 | |||
678 | fnic_send_end: | ||
679 | if (old_flogi) | ||
680 | dev_kfree_skb(fp_skb(old_flogi)); | ||
681 | if (old_flogi_resp) | ||
682 | dev_kfree_skb(fp_skb(old_flogi_resp)); | ||
683 | return ret; | ||
684 | } | ||
685 | |||
686 | static void fnic_wq_complete_frame_send(struct vnic_wq *wq, | ||
687 | struct cq_desc *cq_desc, | ||
688 | struct vnic_wq_buf *buf, void *opaque) | ||
689 | { | ||
690 | struct sk_buff *skb = buf->os_buf; | ||
691 | struct fc_frame *fp = (struct fc_frame *)skb; | ||
692 | struct fnic *fnic = vnic_dev_priv(wq->vdev); | ||
693 | |||
694 | pci_unmap_single(fnic->pdev, buf->dma_addr, | ||
695 | buf->len, PCI_DMA_TODEVICE); | ||
696 | dev_kfree_skb_irq(fp_skb(fp)); | ||
697 | buf->os_buf = NULL; | ||
698 | } | ||
699 | |||
700 | static int fnic_wq_cmpl_handler_cont(struct vnic_dev *vdev, | ||
701 | struct cq_desc *cq_desc, u8 type, | ||
702 | u16 q_number, u16 completed_index, | ||
703 | void *opaque) | ||
704 | { | ||
705 | struct fnic *fnic = vnic_dev_priv(vdev); | ||
706 | unsigned long flags; | ||
707 | |||
708 | spin_lock_irqsave(&fnic->wq_lock[q_number], flags); | ||
709 | vnic_wq_service(&fnic->wq[q_number], cq_desc, completed_index, | ||
710 | fnic_wq_complete_frame_send, NULL); | ||
711 | spin_unlock_irqrestore(&fnic->wq_lock[q_number], flags); | ||
712 | |||
713 | return 0; | ||
714 | } | ||
715 | |||
716 | int fnic_wq_cmpl_handler(struct fnic *fnic, int work_to_do) | ||
717 | { | ||
718 | unsigned int wq_work_done = 0; | ||
719 | unsigned int i; | ||
720 | |||
721 | for (i = 0; i < fnic->raw_wq_count; i++) { | ||
722 | wq_work_done += vnic_cq_service(&fnic->cq[fnic->rq_count+i], | ||
723 | work_to_do, | ||
724 | fnic_wq_cmpl_handler_cont, | ||
725 | NULL); | ||
726 | } | ||
727 | |||
728 | return wq_work_done; | ||
729 | } | ||
730 | |||
731 | |||
732 | void fnic_free_wq_buf(struct vnic_wq *wq, struct vnic_wq_buf *buf) | ||
733 | { | ||
734 | struct fc_frame *fp = buf->os_buf; | ||
735 | struct fnic *fnic = vnic_dev_priv(wq->vdev); | ||
736 | |||
737 | pci_unmap_single(fnic->pdev, buf->dma_addr, | ||
738 | buf->len, PCI_DMA_TODEVICE); | ||
739 | |||
740 | dev_kfree_skb(fp_skb(fp)); | ||
741 | buf->os_buf = NULL; | ||
742 | } | ||
diff --git a/drivers/scsi/fnic/fnic_io.h b/drivers/scsi/fnic/fnic_io.h new file mode 100644 index 000000000000..f0b896988cd5 --- /dev/null +++ b/drivers/scsi/fnic/fnic_io.h | |||
@@ -0,0 +1,67 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _FNIC_IO_H_ | ||
19 | #define _FNIC_IO_H_ | ||
20 | |||
21 | #include <scsi/fc/fc_fcp.h> | ||
22 | |||
23 | #define FNIC_DFLT_SG_DESC_CNT 32 | ||
24 | #define FNIC_MAX_SG_DESC_CNT 1024 /* Maximum descriptors per sgl */ | ||
25 | #define FNIC_SG_DESC_ALIGN 16 /* Descriptor address alignment */ | ||
26 | |||
27 | struct host_sg_desc { | ||
28 | __le64 addr; | ||
29 | __le32 len; | ||
30 | u32 _resvd; | ||
31 | }; | ||
32 | |||
33 | struct fnic_dflt_sgl_list { | ||
34 | struct host_sg_desc sg_desc[FNIC_DFLT_SG_DESC_CNT]; | ||
35 | }; | ||
36 | |||
37 | struct fnic_sgl_list { | ||
38 | struct host_sg_desc sg_desc[FNIC_MAX_SG_DESC_CNT]; | ||
39 | }; | ||
40 | |||
41 | enum fnic_sgl_list_type { | ||
42 | FNIC_SGL_CACHE_DFLT = 0, /* cache with default size sgl */ | ||
43 | FNIC_SGL_CACHE_MAX, /* cache with max size sgl */ | ||
44 | FNIC_SGL_NUM_CACHES /* number of sgl caches */ | ||
45 | }; | ||
46 | |||
47 | enum fnic_ioreq_state { | ||
48 | FNIC_IOREQ_CMD_PENDING = 0, | ||
49 | FNIC_IOREQ_ABTS_PENDING, | ||
50 | FNIC_IOREQ_ABTS_COMPLETE, | ||
51 | FNIC_IOREQ_CMD_COMPLETE, | ||
52 | }; | ||
53 | |||
54 | struct fnic_io_req { | ||
55 | struct host_sg_desc *sgl_list; /* sgl list */ | ||
56 | void *sgl_list_alloc; /* sgl list address used for free */ | ||
57 | dma_addr_t sense_buf_pa; /* dma address for sense buffer*/ | ||
58 | dma_addr_t sgl_list_pa; /* dma address for sgl list */ | ||
59 | u16 sgl_cnt; | ||
60 | u8 sgl_type; /* device DMA descriptor list type */ | ||
61 | u8 io_completed:1; /* set to 1 when fw completes IO */ | ||
62 | u32 port_id; /* remote port DID */ | ||
63 | struct completion *abts_done; /* completion for abts */ | ||
64 | struct completion *dr_done; /* completion for device reset */ | ||
65 | }; | ||
66 | |||
67 | #endif /* _FNIC_IO_H_ */ | ||
diff --git a/drivers/scsi/fnic/fnic_isr.c b/drivers/scsi/fnic/fnic_isr.c new file mode 100644 index 000000000000..2b3064828aea --- /dev/null +++ b/drivers/scsi/fnic/fnic_isr.c | |||
@@ -0,0 +1,332 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #include <linux/string.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include <linux/interrupt.h> | ||
22 | #include <scsi/libfc.h> | ||
23 | #include <scsi/fc_frame.h> | ||
24 | #include "vnic_dev.h" | ||
25 | #include "vnic_intr.h" | ||
26 | #include "vnic_stats.h" | ||
27 | #include "fnic_io.h" | ||
28 | #include "fnic.h" | ||
29 | |||
30 | static irqreturn_t fnic_isr_legacy(int irq, void *data) | ||
31 | { | ||
32 | struct fnic *fnic = data; | ||
33 | u32 pba; | ||
34 | unsigned long work_done = 0; | ||
35 | |||
36 | pba = vnic_intr_legacy_pba(fnic->legacy_pba); | ||
37 | if (!pba) | ||
38 | return IRQ_NONE; | ||
39 | |||
40 | if (pba & (1 << FNIC_INTX_NOTIFY)) { | ||
41 | vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_NOTIFY]); | ||
42 | fnic_handle_link_event(fnic); | ||
43 | } | ||
44 | |||
45 | if (pba & (1 << FNIC_INTX_ERR)) { | ||
46 | vnic_intr_return_all_credits(&fnic->intr[FNIC_INTX_ERR]); | ||
47 | fnic_log_q_error(fnic); | ||
48 | } | ||
49 | |||
50 | if (pba & (1 << FNIC_INTX_WQ_RQ_COPYWQ)) { | ||
51 | work_done += fnic_wq_copy_cmpl_handler(fnic, 8); | ||
52 | work_done += fnic_wq_cmpl_handler(fnic, 4); | ||
53 | work_done += fnic_rq_cmpl_handler(fnic, 4); | ||
54 | |||
55 | vnic_intr_return_credits(&fnic->intr[FNIC_INTX_WQ_RQ_COPYWQ], | ||
56 | work_done, | ||
57 | 1 /* unmask intr */, | ||
58 | 1 /* reset intr timer */); | ||
59 | } | ||
60 | |||
61 | return IRQ_HANDLED; | ||
62 | } | ||
63 | |||
64 | static irqreturn_t fnic_isr_msi(int irq, void *data) | ||
65 | { | ||
66 | struct fnic *fnic = data; | ||
67 | unsigned long work_done = 0; | ||
68 | |||
69 | work_done += fnic_wq_copy_cmpl_handler(fnic, 8); | ||
70 | work_done += fnic_wq_cmpl_handler(fnic, 4); | ||
71 | work_done += fnic_rq_cmpl_handler(fnic, 4); | ||
72 | |||
73 | vnic_intr_return_credits(&fnic->intr[0], | ||
74 | work_done, | ||
75 | 1 /* unmask intr */, | ||
76 | 1 /* reset intr timer */); | ||
77 | |||
78 | return IRQ_HANDLED; | ||
79 | } | ||
80 | |||
81 | static irqreturn_t fnic_isr_msix_rq(int irq, void *data) | ||
82 | { | ||
83 | struct fnic *fnic = data; | ||
84 | unsigned long rq_work_done = 0; | ||
85 | |||
86 | rq_work_done = fnic_rq_cmpl_handler(fnic, 4); | ||
87 | vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_RQ], | ||
88 | rq_work_done, | ||
89 | 1 /* unmask intr */, | ||
90 | 1 /* reset intr timer */); | ||
91 | |||
92 | return IRQ_HANDLED; | ||
93 | } | ||
94 | |||
95 | static irqreturn_t fnic_isr_msix_wq(int irq, void *data) | ||
96 | { | ||
97 | struct fnic *fnic = data; | ||
98 | unsigned long wq_work_done = 0; | ||
99 | |||
100 | wq_work_done = fnic_wq_cmpl_handler(fnic, 4); | ||
101 | vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ], | ||
102 | wq_work_done, | ||
103 | 1 /* unmask intr */, | ||
104 | 1 /* reset intr timer */); | ||
105 | return IRQ_HANDLED; | ||
106 | } | ||
107 | |||
108 | static irqreturn_t fnic_isr_msix_wq_copy(int irq, void *data) | ||
109 | { | ||
110 | struct fnic *fnic = data; | ||
111 | unsigned long wq_copy_work_done = 0; | ||
112 | |||
113 | wq_copy_work_done = fnic_wq_copy_cmpl_handler(fnic, 8); | ||
114 | vnic_intr_return_credits(&fnic->intr[FNIC_MSIX_WQ_COPY], | ||
115 | wq_copy_work_done, | ||
116 | 1 /* unmask intr */, | ||
117 | 1 /* reset intr timer */); | ||
118 | return IRQ_HANDLED; | ||
119 | } | ||
120 | |||
121 | static irqreturn_t fnic_isr_msix_err_notify(int irq, void *data) | ||
122 | { | ||
123 | struct fnic *fnic = data; | ||
124 | |||
125 | vnic_intr_return_all_credits(&fnic->intr[FNIC_MSIX_ERR_NOTIFY]); | ||
126 | fnic_log_q_error(fnic); | ||
127 | fnic_handle_link_event(fnic); | ||
128 | |||
129 | return IRQ_HANDLED; | ||
130 | } | ||
131 | |||
132 | void fnic_free_intr(struct fnic *fnic) | ||
133 | { | ||
134 | int i; | ||
135 | |||
136 | switch (vnic_dev_get_intr_mode(fnic->vdev)) { | ||
137 | case VNIC_DEV_INTR_MODE_INTX: | ||
138 | case VNIC_DEV_INTR_MODE_MSI: | ||
139 | free_irq(fnic->pdev->irq, fnic); | ||
140 | break; | ||
141 | |||
142 | case VNIC_DEV_INTR_MODE_MSIX: | ||
143 | for (i = 0; i < ARRAY_SIZE(fnic->msix); i++) | ||
144 | if (fnic->msix[i].requested) | ||
145 | free_irq(fnic->msix_entry[i].vector, | ||
146 | fnic->msix[i].devid); | ||
147 | break; | ||
148 | |||
149 | default: | ||
150 | break; | ||
151 | } | ||
152 | } | ||
153 | |||
154 | int fnic_request_intr(struct fnic *fnic) | ||
155 | { | ||
156 | int err = 0; | ||
157 | int i; | ||
158 | |||
159 | switch (vnic_dev_get_intr_mode(fnic->vdev)) { | ||
160 | |||
161 | case VNIC_DEV_INTR_MODE_INTX: | ||
162 | err = request_irq(fnic->pdev->irq, &fnic_isr_legacy, | ||
163 | IRQF_SHARED, DRV_NAME, fnic); | ||
164 | break; | ||
165 | |||
166 | case VNIC_DEV_INTR_MODE_MSI: | ||
167 | err = request_irq(fnic->pdev->irq, &fnic_isr_msi, | ||
168 | 0, fnic->name, fnic); | ||
169 | break; | ||
170 | |||
171 | case VNIC_DEV_INTR_MODE_MSIX: | ||
172 | |||
173 | sprintf(fnic->msix[FNIC_MSIX_RQ].devname, | ||
174 | "%.11s-fcs-rq", fnic->name); | ||
175 | fnic->msix[FNIC_MSIX_RQ].isr = fnic_isr_msix_rq; | ||
176 | fnic->msix[FNIC_MSIX_RQ].devid = fnic; | ||
177 | |||
178 | sprintf(fnic->msix[FNIC_MSIX_WQ].devname, | ||
179 | "%.11s-fcs-wq", fnic->name); | ||
180 | fnic->msix[FNIC_MSIX_WQ].isr = fnic_isr_msix_wq; | ||
181 | fnic->msix[FNIC_MSIX_WQ].devid = fnic; | ||
182 | |||
183 | sprintf(fnic->msix[FNIC_MSIX_WQ_COPY].devname, | ||
184 | "%.11s-scsi-wq", fnic->name); | ||
185 | fnic->msix[FNIC_MSIX_WQ_COPY].isr = fnic_isr_msix_wq_copy; | ||
186 | fnic->msix[FNIC_MSIX_WQ_COPY].devid = fnic; | ||
187 | |||
188 | sprintf(fnic->msix[FNIC_MSIX_ERR_NOTIFY].devname, | ||
189 | "%.11s-err-notify", fnic->name); | ||
190 | fnic->msix[FNIC_MSIX_ERR_NOTIFY].isr = | ||
191 | fnic_isr_msix_err_notify; | ||
192 | fnic->msix[FNIC_MSIX_ERR_NOTIFY].devid = fnic; | ||
193 | |||
194 | for (i = 0; i < ARRAY_SIZE(fnic->msix); i++) { | ||
195 | err = request_irq(fnic->msix_entry[i].vector, | ||
196 | fnic->msix[i].isr, 0, | ||
197 | fnic->msix[i].devname, | ||
198 | fnic->msix[i].devid); | ||
199 | if (err) { | ||
200 | shost_printk(KERN_ERR, fnic->lport->host, | ||
201 | "MSIX: request_irq" | ||
202 | " failed %d\n", err); | ||
203 | fnic_free_intr(fnic); | ||
204 | break; | ||
205 | } | ||
206 | fnic->msix[i].requested = 1; | ||
207 | } | ||
208 | break; | ||
209 | |||
210 | default: | ||
211 | break; | ||
212 | } | ||
213 | |||
214 | return err; | ||
215 | } | ||
216 | |||
217 | int fnic_set_intr_mode(struct fnic *fnic) | ||
218 | { | ||
219 | unsigned int n = ARRAY_SIZE(fnic->rq); | ||
220 | unsigned int m = ARRAY_SIZE(fnic->wq); | ||
221 | unsigned int o = ARRAY_SIZE(fnic->wq_copy); | ||
222 | unsigned int i; | ||
223 | |||
224 | /* | ||
225 | * Set interrupt mode (INTx, MSI, MSI-X) depending | ||
226 | * system capabilities. | ||
227 | * | ||
228 | * Try MSI-X first | ||
229 | * | ||
230 | * We need n RQs, m WQs, o Copy WQs, n+m+o CQs, and n+m+o+1 INTRs | ||
231 | * (last INTR is used for WQ/RQ errors and notification area) | ||
232 | */ | ||
233 | |||
234 | BUG_ON(ARRAY_SIZE(fnic->msix_entry) < n + m + o + 1); | ||
235 | for (i = 0; i < n + m + o + 1; i++) | ||
236 | fnic->msix_entry[i].entry = i; | ||
237 | |||
238 | if (fnic->rq_count >= n && | ||
239 | fnic->raw_wq_count >= m && | ||
240 | fnic->wq_copy_count >= o && | ||
241 | fnic->cq_count >= n + m + o) { | ||
242 | if (!pci_enable_msix(fnic->pdev, fnic->msix_entry, | ||
243 | n + m + o + 1)) { | ||
244 | fnic->rq_count = n; | ||
245 | fnic->raw_wq_count = m; | ||
246 | fnic->wq_copy_count = o; | ||
247 | fnic->wq_count = m + o; | ||
248 | fnic->cq_count = n + m + o; | ||
249 | fnic->intr_count = n + m + o + 1; | ||
250 | fnic->err_intr_offset = FNIC_MSIX_ERR_NOTIFY; | ||
251 | |||
252 | FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, | ||
253 | "Using MSI-X Interrupts\n"); | ||
254 | vnic_dev_set_intr_mode(fnic->vdev, | ||
255 | VNIC_DEV_INTR_MODE_MSIX); | ||
256 | return 0; | ||
257 | } | ||
258 | } | ||
259 | |||
260 | /* | ||
261 | * Next try MSI | ||
262 | * We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 1 INTR | ||
263 | */ | ||
264 | if (fnic->rq_count >= 1 && | ||
265 | fnic->raw_wq_count >= 1 && | ||
266 | fnic->wq_copy_count >= 1 && | ||
267 | fnic->cq_count >= 3 && | ||
268 | fnic->intr_count >= 1 && | ||
269 | !pci_enable_msi(fnic->pdev)) { | ||
270 | |||
271 | fnic->rq_count = 1; | ||
272 | fnic->raw_wq_count = 1; | ||
273 | fnic->wq_copy_count = 1; | ||
274 | fnic->wq_count = 2; | ||
275 | fnic->cq_count = 3; | ||
276 | fnic->intr_count = 1; | ||
277 | fnic->err_intr_offset = 0; | ||
278 | |||
279 | FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, | ||
280 | "Using MSI Interrupts\n"); | ||
281 | vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_MSI); | ||
282 | |||
283 | return 0; | ||
284 | } | ||
285 | |||
286 | /* | ||
287 | * Next try INTx | ||
288 | * We need 1 RQ, 1 WQ, 1 WQ_COPY, 3 CQs, and 3 INTRs | ||
289 | * 1 INTR is used for all 3 queues, 1 INTR for queue errors | ||
290 | * 1 INTR for notification area | ||
291 | */ | ||
292 | |||
293 | if (fnic->rq_count >= 1 && | ||
294 | fnic->raw_wq_count >= 1 && | ||
295 | fnic->wq_copy_count >= 1 && | ||
296 | fnic->cq_count >= 3 && | ||
297 | fnic->intr_count >= 3) { | ||
298 | |||
299 | fnic->rq_count = 1; | ||
300 | fnic->raw_wq_count = 1; | ||
301 | fnic->wq_copy_count = 1; | ||
302 | fnic->cq_count = 3; | ||
303 | fnic->intr_count = 3; | ||
304 | |||
305 | FNIC_ISR_DBG(KERN_DEBUG, fnic->lport->host, | ||
306 | "Using Legacy Interrupts\n"); | ||
307 | vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX); | ||
308 | |||
309 | return 0; | ||
310 | } | ||
311 | |||
312 | vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_UNKNOWN); | ||
313 | |||
314 | return -EINVAL; | ||
315 | } | ||
316 | |||
317 | void fnic_clear_intr_mode(struct fnic *fnic) | ||
318 | { | ||
319 | switch (vnic_dev_get_intr_mode(fnic->vdev)) { | ||
320 | case VNIC_DEV_INTR_MODE_MSIX: | ||
321 | pci_disable_msix(fnic->pdev); | ||
322 | break; | ||
323 | case VNIC_DEV_INTR_MODE_MSI: | ||
324 | pci_disable_msi(fnic->pdev); | ||
325 | break; | ||
326 | default: | ||
327 | break; | ||
328 | } | ||
329 | |||
330 | vnic_dev_set_intr_mode(fnic->vdev, VNIC_DEV_INTR_MODE_INTX); | ||
331 | } | ||
332 | |||
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c new file mode 100644 index 000000000000..32ef6b87d895 --- /dev/null +++ b/drivers/scsi/fnic/fnic_main.c | |||
@@ -0,0 +1,942 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #include <linux/module.h> | ||
19 | #include <linux/mempool.h> | ||
20 | #include <linux/string.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/init.h> | ||
23 | #include <linux/pci.h> | ||
24 | #include <linux/skbuff.h> | ||
25 | #include <linux/interrupt.h> | ||
26 | #include <linux/spinlock.h> | ||
27 | #include <linux/workqueue.h> | ||
28 | #include <scsi/scsi_host.h> | ||
29 | #include <scsi/scsi_transport.h> | ||
30 | #include <scsi/scsi_transport_fc.h> | ||
31 | #include <scsi/scsi_tcq.h> | ||
32 | #include <scsi/libfc.h> | ||
33 | #include <scsi/fc_frame.h> | ||
34 | |||
35 | #include "vnic_dev.h" | ||
36 | #include "vnic_intr.h" | ||
37 | #include "vnic_stats.h" | ||
38 | #include "fnic_io.h" | ||
39 | #include "fnic.h" | ||
40 | |||
41 | #define PCI_DEVICE_ID_CISCO_FNIC 0x0045 | ||
42 | |||
43 | /* Timer to poll notification area for events. Used for MSI interrupts */ | ||
44 | #define FNIC_NOTIFY_TIMER_PERIOD (2 * HZ) | ||
45 | |||
46 | static struct kmem_cache *fnic_sgl_cache[FNIC_SGL_NUM_CACHES]; | ||
47 | static struct kmem_cache *fnic_io_req_cache; | ||
48 | LIST_HEAD(fnic_list); | ||
49 | DEFINE_SPINLOCK(fnic_list_lock); | ||
50 | |||
51 | /* Supported devices by fnic module */ | ||
52 | static struct pci_device_id fnic_id_table[] = { | ||
53 | { PCI_DEVICE(PCI_VENDOR_ID_CISCO, PCI_DEVICE_ID_CISCO_FNIC) }, | ||
54 | { 0, } | ||
55 | }; | ||
56 | |||
57 | MODULE_DESCRIPTION(DRV_DESCRIPTION); | ||
58 | MODULE_AUTHOR("Abhijeet Joglekar <abjoglek@cisco.com>, " | ||
59 | "Joseph R. Eykholt <jeykholt@cisco.com>"); | ||
60 | MODULE_LICENSE("GPL v2"); | ||
61 | MODULE_VERSION(DRV_VERSION); | ||
62 | MODULE_DEVICE_TABLE(pci, fnic_id_table); | ||
63 | |||
64 | unsigned int fnic_log_level; | ||
65 | module_param(fnic_log_level, int, S_IRUGO|S_IWUSR); | ||
66 | MODULE_PARM_DESC(fnic_log_level, "bit mask of fnic logging levels"); | ||
67 | |||
68 | |||
69 | static struct libfc_function_template fnic_transport_template = { | ||
70 | .frame_send = fnic_send, | ||
71 | .fcp_abort_io = fnic_empty_scsi_cleanup, | ||
72 | .fcp_cleanup = fnic_empty_scsi_cleanup, | ||
73 | .exch_mgr_reset = fnic_exch_mgr_reset | ||
74 | }; | ||
75 | |||
76 | static int fnic_slave_alloc(struct scsi_device *sdev) | ||
77 | { | ||
78 | struct fc_rport *rport = starget_to_rport(scsi_target(sdev)); | ||
79 | struct fc_lport *lp = shost_priv(sdev->host); | ||
80 | struct fnic *fnic = lport_priv(lp); | ||
81 | |||
82 | sdev->tagged_supported = 1; | ||
83 | |||
84 | if (!rport || fc_remote_port_chkready(rport)) | ||
85 | return -ENXIO; | ||
86 | |||
87 | scsi_activate_tcq(sdev, FNIC_DFLT_QUEUE_DEPTH); | ||
88 | rport->dev_loss_tmo = fnic->config.port_down_timeout / 1000; | ||
89 | |||
90 | return 0; | ||
91 | } | ||
92 | |||
93 | static struct scsi_host_template fnic_host_template = { | ||
94 | .module = THIS_MODULE, | ||
95 | .name = DRV_NAME, | ||
96 | .queuecommand = fnic_queuecommand, | ||
97 | .eh_abort_handler = fnic_abort_cmd, | ||
98 | .eh_device_reset_handler = fnic_device_reset, | ||
99 | .eh_host_reset_handler = fnic_host_reset, | ||
100 | .slave_alloc = fnic_slave_alloc, | ||
101 | .change_queue_depth = fc_change_queue_depth, | ||
102 | .change_queue_type = fc_change_queue_type, | ||
103 | .this_id = -1, | ||
104 | .cmd_per_lun = 3, | ||
105 | .can_queue = FNIC_MAX_IO_REQ, | ||
106 | .use_clustering = ENABLE_CLUSTERING, | ||
107 | .sg_tablesize = FNIC_MAX_SG_DESC_CNT, | ||
108 | .max_sectors = 0xffff, | ||
109 | .shost_attrs = fnic_attrs, | ||
110 | }; | ||
111 | |||
112 | static void fnic_get_host_speed(struct Scsi_Host *shost); | ||
113 | static struct scsi_transport_template *fnic_fc_transport; | ||
114 | static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *); | ||
115 | |||
116 | static struct fc_function_template fnic_fc_functions = { | ||
117 | |||
118 | .show_host_node_name = 1, | ||
119 | .show_host_port_name = 1, | ||
120 | .show_host_supported_classes = 1, | ||
121 | .show_host_supported_fc4s = 1, | ||
122 | .show_host_active_fc4s = 1, | ||
123 | .show_host_maxframe_size = 1, | ||
124 | .show_host_port_id = 1, | ||
125 | .show_host_supported_speeds = 1, | ||
126 | .get_host_speed = fnic_get_host_speed, | ||
127 | .show_host_speed = 1, | ||
128 | .show_host_port_type = 1, | ||
129 | .get_host_port_state = fc_get_host_port_state, | ||
130 | .show_host_port_state = 1, | ||
131 | .show_host_symbolic_name = 1, | ||
132 | .show_rport_maxframe_size = 1, | ||
133 | .show_rport_supported_classes = 1, | ||
134 | .show_host_fabric_name = 1, | ||
135 | .show_starget_node_name = 1, | ||
136 | .show_starget_port_name = 1, | ||
137 | .show_starget_port_id = 1, | ||
138 | .show_rport_dev_loss_tmo = 1, | ||
139 | .issue_fc_host_lip = fnic_reset, | ||
140 | .get_fc_host_stats = fnic_get_stats, | ||
141 | .dd_fcrport_size = sizeof(struct fc_rport_libfc_priv), | ||
142 | .terminate_rport_io = fnic_terminate_rport_io, | ||
143 | }; | ||
144 | |||
145 | static void fnic_get_host_speed(struct Scsi_Host *shost) | ||
146 | { | ||
147 | struct fc_lport *lp = shost_priv(shost); | ||
148 | struct fnic *fnic = lport_priv(lp); | ||
149 | u32 port_speed = vnic_dev_port_speed(fnic->vdev); | ||
150 | |||
151 | /* Add in other values as they get defined in fw */ | ||
152 | switch (port_speed) { | ||
153 | case 10000: | ||
154 | fc_host_speed(shost) = FC_PORTSPEED_10GBIT; | ||
155 | break; | ||
156 | default: | ||
157 | fc_host_speed(shost) = FC_PORTSPEED_10GBIT; | ||
158 | break; | ||
159 | } | ||
160 | } | ||
161 | |||
162 | static struct fc_host_statistics *fnic_get_stats(struct Scsi_Host *host) | ||
163 | { | ||
164 | int ret; | ||
165 | struct fc_lport *lp = shost_priv(host); | ||
166 | struct fnic *fnic = lport_priv(lp); | ||
167 | struct fc_host_statistics *stats = &lp->host_stats; | ||
168 | struct vnic_stats *vs; | ||
169 | unsigned long flags; | ||
170 | |||
171 | if (time_before(jiffies, fnic->stats_time + HZ / FNIC_STATS_RATE_LIMIT)) | ||
172 | return stats; | ||
173 | fnic->stats_time = jiffies; | ||
174 | |||
175 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
176 | ret = vnic_dev_stats_dump(fnic->vdev, &fnic->stats); | ||
177 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
178 | |||
179 | if (ret) { | ||
180 | FNIC_MAIN_DBG(KERN_DEBUG, fnic->lport->host, | ||
181 | "fnic: Get vnic stats failed" | ||
182 | " 0x%x", ret); | ||
183 | return stats; | ||
184 | } | ||
185 | vs = fnic->stats; | ||
186 | stats->tx_frames = vs->tx.tx_unicast_frames_ok; | ||
187 | stats->tx_words = vs->tx.tx_unicast_bytes_ok / 4; | ||
188 | stats->rx_frames = vs->rx.rx_unicast_frames_ok; | ||
189 | stats->rx_words = vs->rx.rx_unicast_bytes_ok / 4; | ||
190 | stats->error_frames = vs->tx.tx_errors + vs->rx.rx_errors; | ||
191 | stats->dumped_frames = vs->tx.tx_drops + vs->rx.rx_drop; | ||
192 | stats->invalid_crc_count = vs->rx.rx_crc_errors; | ||
193 | stats->seconds_since_last_reset = (jiffies - lp->boot_time) / HZ; | ||
194 | stats->fcp_input_megabytes = div_u64(fnic->fcp_input_bytes, 1000000); | ||
195 | stats->fcp_output_megabytes = div_u64(fnic->fcp_output_bytes, 1000000); | ||
196 | |||
197 | return stats; | ||
198 | } | ||
199 | |||
200 | void fnic_log_q_error(struct fnic *fnic) | ||
201 | { | ||
202 | unsigned int i; | ||
203 | u32 error_status; | ||
204 | |||
205 | for (i = 0; i < fnic->raw_wq_count; i++) { | ||
206 | error_status = ioread32(&fnic->wq[i].ctrl->error_status); | ||
207 | if (error_status) | ||
208 | shost_printk(KERN_ERR, fnic->lport->host, | ||
209 | "WQ[%d] error_status" | ||
210 | " %d\n", i, error_status); | ||
211 | } | ||
212 | |||
213 | for (i = 0; i < fnic->rq_count; i++) { | ||
214 | error_status = ioread32(&fnic->rq[i].ctrl->error_status); | ||
215 | if (error_status) | ||
216 | shost_printk(KERN_ERR, fnic->lport->host, | ||
217 | "RQ[%d] error_status" | ||
218 | " %d\n", i, error_status); | ||
219 | } | ||
220 | |||
221 | for (i = 0; i < fnic->wq_copy_count; i++) { | ||
222 | error_status = ioread32(&fnic->wq_copy[i].ctrl->error_status); | ||
223 | if (error_status) | ||
224 | shost_printk(KERN_ERR, fnic->lport->host, | ||
225 | "CWQ[%d] error_status" | ||
226 | " %d\n", i, error_status); | ||
227 | } | ||
228 | } | ||
229 | |||
230 | void fnic_handle_link_event(struct fnic *fnic) | ||
231 | { | ||
232 | unsigned long flags; | ||
233 | |||
234 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
235 | if (fnic->stop_rx_link_events) { | ||
236 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
237 | return; | ||
238 | } | ||
239 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
240 | |||
241 | queue_work(fnic_event_queue, &fnic->link_work); | ||
242 | |||
243 | } | ||
244 | |||
245 | static int fnic_notify_set(struct fnic *fnic) | ||
246 | { | ||
247 | int err; | ||
248 | |||
249 | switch (vnic_dev_get_intr_mode(fnic->vdev)) { | ||
250 | case VNIC_DEV_INTR_MODE_INTX: | ||
251 | err = vnic_dev_notify_set(fnic->vdev, FNIC_INTX_NOTIFY); | ||
252 | break; | ||
253 | case VNIC_DEV_INTR_MODE_MSI: | ||
254 | err = vnic_dev_notify_set(fnic->vdev, -1); | ||
255 | break; | ||
256 | case VNIC_DEV_INTR_MODE_MSIX: | ||
257 | err = vnic_dev_notify_set(fnic->vdev, FNIC_MSIX_ERR_NOTIFY); | ||
258 | break; | ||
259 | default: | ||
260 | shost_printk(KERN_ERR, fnic->lport->host, | ||
261 | "Interrupt mode should be set up" | ||
262 | " before devcmd notify set %d\n", | ||
263 | vnic_dev_get_intr_mode(fnic->vdev)); | ||
264 | err = -1; | ||
265 | break; | ||
266 | } | ||
267 | |||
268 | return err; | ||
269 | } | ||
270 | |||
271 | static void fnic_notify_timer(unsigned long data) | ||
272 | { | ||
273 | struct fnic *fnic = (struct fnic *)data; | ||
274 | |||
275 | fnic_handle_link_event(fnic); | ||
276 | mod_timer(&fnic->notify_timer, | ||
277 | round_jiffies(jiffies + FNIC_NOTIFY_TIMER_PERIOD)); | ||
278 | } | ||
279 | |||
280 | static void fnic_notify_timer_start(struct fnic *fnic) | ||
281 | { | ||
282 | switch (vnic_dev_get_intr_mode(fnic->vdev)) { | ||
283 | case VNIC_DEV_INTR_MODE_MSI: | ||
284 | /* | ||
285 | * Schedule first timeout immediately. The driver is | ||
286 | * initiatialized and ready to look for link up notification | ||
287 | */ | ||
288 | mod_timer(&fnic->notify_timer, jiffies); | ||
289 | break; | ||
290 | default: | ||
291 | /* Using intr for notification for INTx/MSI-X */ | ||
292 | break; | ||
293 | }; | ||
294 | } | ||
295 | |||
296 | static int fnic_dev_wait(struct vnic_dev *vdev, | ||
297 | int (*start)(struct vnic_dev *, int), | ||
298 | int (*finished)(struct vnic_dev *, int *), | ||
299 | int arg) | ||
300 | { | ||
301 | unsigned long time; | ||
302 | int done; | ||
303 | int err; | ||
304 | |||
305 | err = start(vdev, arg); | ||
306 | if (err) | ||
307 | return err; | ||
308 | |||
309 | /* Wait for func to complete...2 seconds max */ | ||
310 | time = jiffies + (HZ * 2); | ||
311 | do { | ||
312 | err = finished(vdev, &done); | ||
313 | if (err) | ||
314 | return err; | ||
315 | if (done) | ||
316 | return 0; | ||
317 | schedule_timeout_uninterruptible(HZ / 10); | ||
318 | } while (time_after(time, jiffies)); | ||
319 | |||
320 | return -ETIMEDOUT; | ||
321 | } | ||
322 | |||
323 | static int fnic_cleanup(struct fnic *fnic) | ||
324 | { | ||
325 | unsigned int i; | ||
326 | int err; | ||
327 | unsigned long flags; | ||
328 | struct fc_frame *flogi = NULL; | ||
329 | struct fc_frame *flogi_resp = NULL; | ||
330 | |||
331 | vnic_dev_disable(fnic->vdev); | ||
332 | for (i = 0; i < fnic->intr_count; i++) | ||
333 | vnic_intr_mask(&fnic->intr[i]); | ||
334 | |||
335 | for (i = 0; i < fnic->rq_count; i++) { | ||
336 | err = vnic_rq_disable(&fnic->rq[i]); | ||
337 | if (err) | ||
338 | return err; | ||
339 | } | ||
340 | for (i = 0; i < fnic->raw_wq_count; i++) { | ||
341 | err = vnic_wq_disable(&fnic->wq[i]); | ||
342 | if (err) | ||
343 | return err; | ||
344 | } | ||
345 | for (i = 0; i < fnic->wq_copy_count; i++) { | ||
346 | err = vnic_wq_copy_disable(&fnic->wq_copy[i]); | ||
347 | if (err) | ||
348 | return err; | ||
349 | } | ||
350 | |||
351 | /* Clean up completed IOs and FCS frames */ | ||
352 | fnic_wq_copy_cmpl_handler(fnic, -1); | ||
353 | fnic_wq_cmpl_handler(fnic, -1); | ||
354 | fnic_rq_cmpl_handler(fnic, -1); | ||
355 | |||
356 | /* Clean up the IOs and FCS frames that have not completed */ | ||
357 | for (i = 0; i < fnic->raw_wq_count; i++) | ||
358 | vnic_wq_clean(&fnic->wq[i], fnic_free_wq_buf); | ||
359 | for (i = 0; i < fnic->rq_count; i++) | ||
360 | vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); | ||
361 | for (i = 0; i < fnic->wq_copy_count; i++) | ||
362 | vnic_wq_copy_clean(&fnic->wq_copy[i], | ||
363 | fnic_wq_copy_cleanup_handler); | ||
364 | |||
365 | for (i = 0; i < fnic->cq_count; i++) | ||
366 | vnic_cq_clean(&fnic->cq[i]); | ||
367 | for (i = 0; i < fnic->intr_count; i++) | ||
368 | vnic_intr_clean(&fnic->intr[i]); | ||
369 | |||
370 | /* | ||
371 | * Remove cached flogi and flogi resp frames if any | ||
372 | * These frames are not in any queue, and therefore queue | ||
373 | * cleanup does not clean them. So clean them explicitly | ||
374 | */ | ||
375 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
376 | flogi = fnic->flogi; | ||
377 | fnic->flogi = NULL; | ||
378 | flogi_resp = fnic->flogi_resp; | ||
379 | fnic->flogi_resp = NULL; | ||
380 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
381 | |||
382 | if (flogi) | ||
383 | dev_kfree_skb(fp_skb(flogi)); | ||
384 | |||
385 | if (flogi_resp) | ||
386 | dev_kfree_skb(fp_skb(flogi_resp)); | ||
387 | |||
388 | mempool_destroy(fnic->io_req_pool); | ||
389 | for (i = 0; i < FNIC_SGL_NUM_CACHES; i++) | ||
390 | mempool_destroy(fnic->io_sgl_pool[i]); | ||
391 | |||
392 | return 0; | ||
393 | } | ||
394 | |||
395 | static void fnic_iounmap(struct fnic *fnic) | ||
396 | { | ||
397 | if (fnic->bar0.vaddr) | ||
398 | iounmap(fnic->bar0.vaddr); | ||
399 | } | ||
400 | |||
401 | /* | ||
402 | * Allocate element for mempools requiring GFP_DMA flag. | ||
403 | * Otherwise, checks in kmem_flagcheck() hit BUG_ON(). | ||
404 | */ | ||
405 | static void *fnic_alloc_slab_dma(gfp_t gfp_mask, void *pool_data) | ||
406 | { | ||
407 | struct kmem_cache *mem = pool_data; | ||
408 | |||
409 | return kmem_cache_alloc(mem, gfp_mask | GFP_ATOMIC | GFP_DMA); | ||
410 | } | ||
411 | |||
412 | static int __devinit fnic_probe(struct pci_dev *pdev, | ||
413 | const struct pci_device_id *ent) | ||
414 | { | ||
415 | struct Scsi_Host *host; | ||
416 | struct fc_lport *lp; | ||
417 | struct fnic *fnic; | ||
418 | mempool_t *pool; | ||
419 | int err; | ||
420 | int i; | ||
421 | unsigned long flags; | ||
422 | |||
423 | /* | ||
424 | * Allocate SCSI Host and set up association between host, | ||
425 | * local port, and fnic | ||
426 | */ | ||
427 | host = scsi_host_alloc(&fnic_host_template, | ||
428 | sizeof(struct fc_lport) + sizeof(struct fnic)); | ||
429 | if (!host) { | ||
430 | printk(KERN_ERR PFX "Unable to alloc SCSI host\n"); | ||
431 | err = -ENOMEM; | ||
432 | goto err_out; | ||
433 | } | ||
434 | lp = shost_priv(host); | ||
435 | lp->host = host; | ||
436 | fnic = lport_priv(lp); | ||
437 | fnic->lport = lp; | ||
438 | |||
439 | snprintf(fnic->name, sizeof(fnic->name) - 1, "%s%d", DRV_NAME, | ||
440 | host->host_no); | ||
441 | |||
442 | host->transportt = fnic_fc_transport; | ||
443 | |||
444 | err = scsi_init_shared_tag_map(host, FNIC_MAX_IO_REQ); | ||
445 | if (err) { | ||
446 | shost_printk(KERN_ERR, fnic->lport->host, | ||
447 | "Unable to alloc shared tag map\n"); | ||
448 | goto err_out_free_hba; | ||
449 | } | ||
450 | |||
451 | /* Setup PCI resources */ | ||
452 | pci_set_drvdata(pdev, fnic); | ||
453 | |||
454 | fnic->pdev = pdev; | ||
455 | |||
456 | err = pci_enable_device(pdev); | ||
457 | if (err) { | ||
458 | shost_printk(KERN_ERR, fnic->lport->host, | ||
459 | "Cannot enable PCI device, aborting.\n"); | ||
460 | goto err_out_free_hba; | ||
461 | } | ||
462 | |||
463 | err = pci_request_regions(pdev, DRV_NAME); | ||
464 | if (err) { | ||
465 | shost_printk(KERN_ERR, fnic->lport->host, | ||
466 | "Cannot enable PCI resources, aborting\n"); | ||
467 | goto err_out_disable_device; | ||
468 | } | ||
469 | |||
470 | pci_set_master(pdev); | ||
471 | |||
472 | /* Query PCI controller on system for DMA addressing | ||
473 | * limitation for the device. Try 40-bit first, and | ||
474 | * fail to 32-bit. | ||
475 | */ | ||
476 | err = pci_set_dma_mask(pdev, DMA_40BIT_MASK); | ||
477 | if (err) { | ||
478 | err = pci_set_dma_mask(pdev, DMA_32BIT_MASK); | ||
479 | if (err) { | ||
480 | shost_printk(KERN_ERR, fnic->lport->host, | ||
481 | "No usable DMA configuration " | ||
482 | "aborting\n"); | ||
483 | goto err_out_release_regions; | ||
484 | } | ||
485 | err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); | ||
486 | if (err) { | ||
487 | shost_printk(KERN_ERR, fnic->lport->host, | ||
488 | "Unable to obtain 32-bit DMA " | ||
489 | "for consistent allocations, aborting.\n"); | ||
490 | goto err_out_release_regions; | ||
491 | } | ||
492 | } else { | ||
493 | err = pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK); | ||
494 | if (err) { | ||
495 | shost_printk(KERN_ERR, fnic->lport->host, | ||
496 | "Unable to obtain 40-bit DMA " | ||
497 | "for consistent allocations, aborting.\n"); | ||
498 | goto err_out_release_regions; | ||
499 | } | ||
500 | } | ||
501 | |||
502 | /* Map vNIC resources from BAR0 */ | ||
503 | if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) { | ||
504 | shost_printk(KERN_ERR, fnic->lport->host, | ||
505 | "BAR0 not memory-map'able, aborting.\n"); | ||
506 | err = -ENODEV; | ||
507 | goto err_out_release_regions; | ||
508 | } | ||
509 | |||
510 | fnic->bar0.vaddr = pci_iomap(pdev, 0, 0); | ||
511 | fnic->bar0.bus_addr = pci_resource_start(pdev, 0); | ||
512 | fnic->bar0.len = pci_resource_len(pdev, 0); | ||
513 | |||
514 | if (!fnic->bar0.vaddr) { | ||
515 | shost_printk(KERN_ERR, fnic->lport->host, | ||
516 | "Cannot memory-map BAR0 res hdr, " | ||
517 | "aborting.\n"); | ||
518 | err = -ENODEV; | ||
519 | goto err_out_release_regions; | ||
520 | } | ||
521 | |||
522 | fnic->vdev = vnic_dev_register(NULL, fnic, pdev, &fnic->bar0); | ||
523 | if (!fnic->vdev) { | ||
524 | shost_printk(KERN_ERR, fnic->lport->host, | ||
525 | "vNIC registration failed, " | ||
526 | "aborting.\n"); | ||
527 | err = -ENODEV; | ||
528 | goto err_out_iounmap; | ||
529 | } | ||
530 | |||
531 | err = fnic_dev_wait(fnic->vdev, vnic_dev_open, | ||
532 | vnic_dev_open_done, 0); | ||
533 | if (err) { | ||
534 | shost_printk(KERN_ERR, fnic->lport->host, | ||
535 | "vNIC dev open failed, aborting.\n"); | ||
536 | goto err_out_vnic_unregister; | ||
537 | } | ||
538 | |||
539 | err = vnic_dev_init(fnic->vdev, 0); | ||
540 | if (err) { | ||
541 | shost_printk(KERN_ERR, fnic->lport->host, | ||
542 | "vNIC dev init failed, aborting.\n"); | ||
543 | goto err_out_dev_close; | ||
544 | } | ||
545 | |||
546 | err = vnic_dev_mac_addr(fnic->vdev, fnic->mac_addr); | ||
547 | if (err) { | ||
548 | shost_printk(KERN_ERR, fnic->lport->host, | ||
549 | "vNIC get MAC addr failed \n"); | ||
550 | goto err_out_dev_close; | ||
551 | } | ||
552 | |||
553 | /* Get vNIC configuration */ | ||
554 | err = fnic_get_vnic_config(fnic); | ||
555 | if (err) { | ||
556 | shost_printk(KERN_ERR, fnic->lport->host, | ||
557 | "Get vNIC configuration failed, " | ||
558 | "aborting.\n"); | ||
559 | goto err_out_dev_close; | ||
560 | } | ||
561 | host->max_lun = fnic->config.luns_per_tgt; | ||
562 | host->max_id = FNIC_MAX_FCP_TARGET; | ||
563 | |||
564 | fnic_get_res_counts(fnic); | ||
565 | |||
566 | err = fnic_set_intr_mode(fnic); | ||
567 | if (err) { | ||
568 | shost_printk(KERN_ERR, fnic->lport->host, | ||
569 | "Failed to set intr mode, " | ||
570 | "aborting.\n"); | ||
571 | goto err_out_dev_close; | ||
572 | } | ||
573 | |||
574 | err = fnic_request_intr(fnic); | ||
575 | if (err) { | ||
576 | shost_printk(KERN_ERR, fnic->lport->host, | ||
577 | "Unable to request irq.\n"); | ||
578 | goto err_out_clear_intr; | ||
579 | } | ||
580 | |||
581 | err = fnic_alloc_vnic_resources(fnic); | ||
582 | if (err) { | ||
583 | shost_printk(KERN_ERR, fnic->lport->host, | ||
584 | "Failed to alloc vNIC resources, " | ||
585 | "aborting.\n"); | ||
586 | goto err_out_free_intr; | ||
587 | } | ||
588 | |||
589 | |||
590 | /* initialize all fnic locks */ | ||
591 | spin_lock_init(&fnic->fnic_lock); | ||
592 | |||
593 | for (i = 0; i < FNIC_WQ_MAX; i++) | ||
594 | spin_lock_init(&fnic->wq_lock[i]); | ||
595 | |||
596 | for (i = 0; i < FNIC_WQ_COPY_MAX; i++) { | ||
597 | spin_lock_init(&fnic->wq_copy_lock[i]); | ||
598 | fnic->wq_copy_desc_low[i] = DESC_CLEAN_LOW_WATERMARK; | ||
599 | fnic->fw_ack_recd[i] = 0; | ||
600 | fnic->fw_ack_index[i] = -1; | ||
601 | } | ||
602 | |||
603 | for (i = 0; i < FNIC_IO_LOCKS; i++) | ||
604 | spin_lock_init(&fnic->io_req_lock[i]); | ||
605 | |||
606 | fnic->io_req_pool = mempool_create_slab_pool(2, fnic_io_req_cache); | ||
607 | if (!fnic->io_req_pool) | ||
608 | goto err_out_free_resources; | ||
609 | |||
610 | pool = mempool_create(2, fnic_alloc_slab_dma, mempool_free_slab, | ||
611 | fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); | ||
612 | if (!pool) | ||
613 | goto err_out_free_ioreq_pool; | ||
614 | fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT] = pool; | ||
615 | |||
616 | pool = mempool_create(2, fnic_alloc_slab_dma, mempool_free_slab, | ||
617 | fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); | ||
618 | if (!pool) | ||
619 | goto err_out_free_dflt_pool; | ||
620 | fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX] = pool; | ||
621 | |||
622 | /* setup vlan config, hw inserts vlan header */ | ||
623 | fnic->vlan_hw_insert = 1; | ||
624 | fnic->vlan_id = 0; | ||
625 | |||
626 | fnic->flogi_oxid = FC_XID_UNKNOWN; | ||
627 | fnic->flogi = NULL; | ||
628 | fnic->flogi_resp = NULL; | ||
629 | fnic->state = FNIC_IN_FC_MODE; | ||
630 | |||
631 | /* Enable hardware stripping of vlan header on ingress */ | ||
632 | fnic_set_nic_config(fnic, 0, 0, 0, 0, 0, 0, 1); | ||
633 | |||
634 | /* Setup notification buffer area */ | ||
635 | err = fnic_notify_set(fnic); | ||
636 | if (err) { | ||
637 | shost_printk(KERN_ERR, fnic->lport->host, | ||
638 | "Failed to alloc notify buffer, aborting.\n"); | ||
639 | goto err_out_free_max_pool; | ||
640 | } | ||
641 | |||
642 | /* Setup notify timer when using MSI interrupts */ | ||
643 | if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) | ||
644 | setup_timer(&fnic->notify_timer, | ||
645 | fnic_notify_timer, (unsigned long)fnic); | ||
646 | |||
647 | /* allocate RQ buffers and post them to RQ*/ | ||
648 | for (i = 0; i < fnic->rq_count; i++) { | ||
649 | err = vnic_rq_fill(&fnic->rq[i], fnic_alloc_rq_frame); | ||
650 | if (err) { | ||
651 | shost_printk(KERN_ERR, fnic->lport->host, | ||
652 | "fnic_alloc_rq_frame can't alloc " | ||
653 | "frame\n"); | ||
654 | goto err_out_free_rq_buf; | ||
655 | } | ||
656 | } | ||
657 | |||
658 | /* | ||
659 | * Initialization done with PCI system, hardware, firmware. | ||
660 | * Add host to SCSI | ||
661 | */ | ||
662 | err = scsi_add_host(lp->host, &pdev->dev); | ||
663 | if (err) { | ||
664 | shost_printk(KERN_ERR, fnic->lport->host, | ||
665 | "fnic: scsi_add_host failed...exiting\n"); | ||
666 | goto err_out_free_rq_buf; | ||
667 | } | ||
668 | |||
669 | /* Start local port initiatialization */ | ||
670 | |||
671 | lp->link_up = 0; | ||
672 | lp->tt = fnic_transport_template; | ||
673 | |||
674 | lp->emp = fc_exch_mgr_alloc(lp, FC_CLASS_3, | ||
675 | FCPIO_HOST_EXCH_RANGE_START, | ||
676 | FCPIO_HOST_EXCH_RANGE_END); | ||
677 | if (!lp->emp) { | ||
678 | err = -ENOMEM; | ||
679 | goto err_out_remove_scsi_host; | ||
680 | } | ||
681 | |||
682 | lp->max_retry_count = fnic->config.flogi_retries; | ||
683 | lp->service_params = (FCP_SPPF_INIT_FCN | FCP_SPPF_RD_XRDY_DIS | | ||
684 | FCP_SPPF_CONF_COMPL); | ||
685 | if (fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR) | ||
686 | lp->service_params |= FCP_SPPF_RETRY; | ||
687 | |||
688 | lp->boot_time = jiffies; | ||
689 | lp->e_d_tov = fnic->config.ed_tov; | ||
690 | lp->r_a_tov = fnic->config.ra_tov; | ||
691 | lp->link_supported_speeds = FC_PORTSPEED_10GBIT; | ||
692 | fc_set_wwnn(lp, fnic->config.node_wwn); | ||
693 | fc_set_wwpn(lp, fnic->config.port_wwn); | ||
694 | |||
695 | fc_exch_init(lp); | ||
696 | fc_lport_init(lp); | ||
697 | fc_elsct_init(lp); | ||
698 | fc_rport_init(lp); | ||
699 | fc_disc_init(lp); | ||
700 | |||
701 | fc_lport_config(lp); | ||
702 | |||
703 | if (fc_set_mfs(lp, fnic->config.maxdatafieldsize + | ||
704 | sizeof(struct fc_frame_header))) { | ||
705 | err = -EINVAL; | ||
706 | goto err_out_free_exch_mgr; | ||
707 | } | ||
708 | fc_host_maxframe_size(lp->host) = lp->mfs; | ||
709 | |||
710 | sprintf(fc_host_symbolic_name(lp->host), | ||
711 | DRV_NAME " v" DRV_VERSION " over %s", fnic->name); | ||
712 | |||
713 | spin_lock_irqsave(&fnic_list_lock, flags); | ||
714 | list_add_tail(&fnic->list, &fnic_list); | ||
715 | spin_unlock_irqrestore(&fnic_list_lock, flags); | ||
716 | |||
717 | INIT_WORK(&fnic->link_work, fnic_handle_link); | ||
718 | INIT_WORK(&fnic->frame_work, fnic_handle_frame); | ||
719 | skb_queue_head_init(&fnic->frame_queue); | ||
720 | |||
721 | /* Enable all queues */ | ||
722 | for (i = 0; i < fnic->raw_wq_count; i++) | ||
723 | vnic_wq_enable(&fnic->wq[i]); | ||
724 | for (i = 0; i < fnic->rq_count; i++) | ||
725 | vnic_rq_enable(&fnic->rq[i]); | ||
726 | for (i = 0; i < fnic->wq_copy_count; i++) | ||
727 | vnic_wq_copy_enable(&fnic->wq_copy[i]); | ||
728 | |||
729 | fc_fabric_login(lp); | ||
730 | |||
731 | vnic_dev_enable(fnic->vdev); | ||
732 | for (i = 0; i < fnic->intr_count; i++) | ||
733 | vnic_intr_unmask(&fnic->intr[i]); | ||
734 | |||
735 | fnic_notify_timer_start(fnic); | ||
736 | |||
737 | return 0; | ||
738 | |||
739 | err_out_free_exch_mgr: | ||
740 | fc_exch_mgr_free(lp->emp); | ||
741 | err_out_remove_scsi_host: | ||
742 | fc_remove_host(fnic->lport->host); | ||
743 | scsi_remove_host(fnic->lport->host); | ||
744 | err_out_free_rq_buf: | ||
745 | for (i = 0; i < fnic->rq_count; i++) | ||
746 | vnic_rq_clean(&fnic->rq[i], fnic_free_rq_buf); | ||
747 | vnic_dev_notify_unset(fnic->vdev); | ||
748 | err_out_free_max_pool: | ||
749 | mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_MAX]); | ||
750 | err_out_free_dflt_pool: | ||
751 | mempool_destroy(fnic->io_sgl_pool[FNIC_SGL_CACHE_DFLT]); | ||
752 | err_out_free_ioreq_pool: | ||
753 | mempool_destroy(fnic->io_req_pool); | ||
754 | err_out_free_resources: | ||
755 | fnic_free_vnic_resources(fnic); | ||
756 | err_out_free_intr: | ||
757 | fnic_free_intr(fnic); | ||
758 | err_out_clear_intr: | ||
759 | fnic_clear_intr_mode(fnic); | ||
760 | err_out_dev_close: | ||
761 | vnic_dev_close(fnic->vdev); | ||
762 | err_out_vnic_unregister: | ||
763 | vnic_dev_unregister(fnic->vdev); | ||
764 | err_out_iounmap: | ||
765 | fnic_iounmap(fnic); | ||
766 | err_out_release_regions: | ||
767 | pci_release_regions(pdev); | ||
768 | err_out_disable_device: | ||
769 | pci_disable_device(pdev); | ||
770 | err_out_free_hba: | ||
771 | scsi_host_put(lp->host); | ||
772 | err_out: | ||
773 | return err; | ||
774 | } | ||
775 | |||
776 | static void __devexit fnic_remove(struct pci_dev *pdev) | ||
777 | { | ||
778 | struct fnic *fnic = pci_get_drvdata(pdev); | ||
779 | unsigned long flags; | ||
780 | |||
781 | /* | ||
782 | * Mark state so that the workqueue thread stops forwarding | ||
783 | * received frames and link events to the local port. ISR and | ||
784 | * other threads that can queue work items will also stop | ||
785 | * creating work items on the fnic workqueue | ||
786 | */ | ||
787 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
788 | fnic->stop_rx_link_events = 1; | ||
789 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
790 | |||
791 | if (vnic_dev_get_intr_mode(fnic->vdev) == VNIC_DEV_INTR_MODE_MSI) | ||
792 | del_timer_sync(&fnic->notify_timer); | ||
793 | |||
794 | /* | ||
795 | * Flush the fnic event queue. After this call, there should | ||
796 | * be no event queued for this fnic device in the workqueue | ||
797 | */ | ||
798 | flush_workqueue(fnic_event_queue); | ||
799 | skb_queue_purge(&fnic->frame_queue); | ||
800 | |||
801 | /* | ||
802 | * Log off the fabric. This stops all remote ports, dns port, | ||
803 | * logs off the fabric. This flushes all rport, disc, lport work | ||
804 | * before returning | ||
805 | */ | ||
806 | fc_fabric_logoff(fnic->lport); | ||
807 | |||
808 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
809 | fnic->in_remove = 1; | ||
810 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
811 | |||
812 | fc_lport_destroy(fnic->lport); | ||
813 | |||
814 | /* | ||
815 | * This stops the fnic device, masks all interrupts. Completed | ||
816 | * CQ entries are drained. Posted WQ/RQ/Copy-WQ entries are | ||
817 | * cleaned up | ||
818 | */ | ||
819 | fnic_cleanup(fnic); | ||
820 | |||
821 | BUG_ON(!skb_queue_empty(&fnic->frame_queue)); | ||
822 | |||
823 | spin_lock_irqsave(&fnic_list_lock, flags); | ||
824 | list_del(&fnic->list); | ||
825 | spin_unlock_irqrestore(&fnic_list_lock, flags); | ||
826 | |||
827 | fc_remove_host(fnic->lport->host); | ||
828 | scsi_remove_host(fnic->lport->host); | ||
829 | fc_exch_mgr_free(fnic->lport->emp); | ||
830 | vnic_dev_notify_unset(fnic->vdev); | ||
831 | fnic_free_vnic_resources(fnic); | ||
832 | fnic_free_intr(fnic); | ||
833 | fnic_clear_intr_mode(fnic); | ||
834 | vnic_dev_close(fnic->vdev); | ||
835 | vnic_dev_unregister(fnic->vdev); | ||
836 | fnic_iounmap(fnic); | ||
837 | pci_release_regions(pdev); | ||
838 | pci_disable_device(pdev); | ||
839 | pci_set_drvdata(pdev, NULL); | ||
840 | scsi_host_put(fnic->lport->host); | ||
841 | } | ||
842 | |||
843 | static struct pci_driver fnic_driver = { | ||
844 | .name = DRV_NAME, | ||
845 | .id_table = fnic_id_table, | ||
846 | .probe = fnic_probe, | ||
847 | .remove = __devexit_p(fnic_remove), | ||
848 | }; | ||
849 | |||
850 | static int __init fnic_init_module(void) | ||
851 | { | ||
852 | size_t len; | ||
853 | int err = 0; | ||
854 | |||
855 | printk(KERN_INFO PFX "%s, ver %s\n", DRV_DESCRIPTION, DRV_VERSION); | ||
856 | |||
857 | /* Create a cache for allocation of default size sgls */ | ||
858 | len = sizeof(struct fnic_dflt_sgl_list); | ||
859 | fnic_sgl_cache[FNIC_SGL_CACHE_DFLT] = kmem_cache_create | ||
860 | ("fnic_sgl_dflt", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN, | ||
861 | SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, | ||
862 | NULL); | ||
863 | if (!fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]) { | ||
864 | printk(KERN_ERR PFX "failed to create fnic dflt sgl slab\n"); | ||
865 | err = -ENOMEM; | ||
866 | goto err_create_fnic_sgl_slab_dflt; | ||
867 | } | ||
868 | |||
869 | /* Create a cache for allocation of max size sgls*/ | ||
870 | len = sizeof(struct fnic_sgl_list); | ||
871 | fnic_sgl_cache[FNIC_SGL_CACHE_MAX] = kmem_cache_create | ||
872 | ("fnic_sgl_max", len + FNIC_SG_DESC_ALIGN, FNIC_SG_DESC_ALIGN, | ||
873 | SLAB_HWCACHE_ALIGN | SLAB_CACHE_DMA, | ||
874 | NULL); | ||
875 | if (!fnic_sgl_cache[FNIC_SGL_CACHE_MAX]) { | ||
876 | printk(KERN_ERR PFX "failed to create fnic max sgl slab\n"); | ||
877 | err = -ENOMEM; | ||
878 | goto err_create_fnic_sgl_slab_max; | ||
879 | } | ||
880 | |||
881 | /* Create a cache of io_req structs for use via mempool */ | ||
882 | fnic_io_req_cache = kmem_cache_create("fnic_io_req", | ||
883 | sizeof(struct fnic_io_req), | ||
884 | 0, SLAB_HWCACHE_ALIGN, NULL); | ||
885 | if (!fnic_io_req_cache) { | ||
886 | printk(KERN_ERR PFX "failed to create fnic io_req slab\n"); | ||
887 | err = -ENOMEM; | ||
888 | goto err_create_fnic_ioreq_slab; | ||
889 | } | ||
890 | |||
891 | fnic_event_queue = create_singlethread_workqueue("fnic_event_wq"); | ||
892 | if (!fnic_event_queue) { | ||
893 | printk(KERN_ERR PFX "fnic work queue create failed\n"); | ||
894 | err = -ENOMEM; | ||
895 | goto err_create_fnic_workq; | ||
896 | } | ||
897 | |||
898 | spin_lock_init(&fnic_list_lock); | ||
899 | INIT_LIST_HEAD(&fnic_list); | ||
900 | |||
901 | fnic_fc_transport = fc_attach_transport(&fnic_fc_functions); | ||
902 | if (!fnic_fc_transport) { | ||
903 | printk(KERN_ERR PFX "fc_attach_transport error\n"); | ||
904 | err = -ENOMEM; | ||
905 | goto err_fc_transport; | ||
906 | } | ||
907 | |||
908 | /* register the driver with PCI system */ | ||
909 | err = pci_register_driver(&fnic_driver); | ||
910 | if (err < 0) { | ||
911 | printk(KERN_ERR PFX "pci register error\n"); | ||
912 | goto err_pci_register; | ||
913 | } | ||
914 | return err; | ||
915 | |||
916 | err_pci_register: | ||
917 | fc_release_transport(fnic_fc_transport); | ||
918 | err_fc_transport: | ||
919 | destroy_workqueue(fnic_event_queue); | ||
920 | err_create_fnic_workq: | ||
921 | kmem_cache_destroy(fnic_io_req_cache); | ||
922 | err_create_fnic_ioreq_slab: | ||
923 | kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); | ||
924 | err_create_fnic_sgl_slab_max: | ||
925 | kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); | ||
926 | err_create_fnic_sgl_slab_dflt: | ||
927 | return err; | ||
928 | } | ||
929 | |||
930 | static void __exit fnic_cleanup_module(void) | ||
931 | { | ||
932 | pci_unregister_driver(&fnic_driver); | ||
933 | destroy_workqueue(fnic_event_queue); | ||
934 | kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_MAX]); | ||
935 | kmem_cache_destroy(fnic_sgl_cache[FNIC_SGL_CACHE_DFLT]); | ||
936 | kmem_cache_destroy(fnic_io_req_cache); | ||
937 | fc_release_transport(fnic_fc_transport); | ||
938 | } | ||
939 | |||
940 | module_init(fnic_init_module); | ||
941 | module_exit(fnic_cleanup_module); | ||
942 | |||
diff --git a/drivers/scsi/fnic/fnic_res.c b/drivers/scsi/fnic/fnic_res.c new file mode 100644 index 000000000000..7ba61ec715d2 --- /dev/null +++ b/drivers/scsi/fnic/fnic_res.c | |||
@@ -0,0 +1,444 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include "wq_enet_desc.h" | ||
22 | #include "rq_enet_desc.h" | ||
23 | #include "cq_enet_desc.h" | ||
24 | #include "vnic_resource.h" | ||
25 | #include "vnic_dev.h" | ||
26 | #include "vnic_wq.h" | ||
27 | #include "vnic_rq.h" | ||
28 | #include "vnic_cq.h" | ||
29 | #include "vnic_intr.h" | ||
30 | #include "vnic_stats.h" | ||
31 | #include "vnic_nic.h" | ||
32 | #include "fnic.h" | ||
33 | |||
34 | int fnic_get_vnic_config(struct fnic *fnic) | ||
35 | { | ||
36 | struct vnic_fc_config *c = &fnic->config; | ||
37 | int err; | ||
38 | |||
39 | #define GET_CONFIG(m) \ | ||
40 | do { \ | ||
41 | err = vnic_dev_spec(fnic->vdev, \ | ||
42 | offsetof(struct vnic_fc_config, m), \ | ||
43 | sizeof(c->m), &c->m); \ | ||
44 | if (err) { \ | ||
45 | shost_printk(KERN_ERR, fnic->lport->host, \ | ||
46 | "Error getting %s, %d\n", #m, \ | ||
47 | err); \ | ||
48 | return err; \ | ||
49 | } \ | ||
50 | } while (0); | ||
51 | |||
52 | GET_CONFIG(node_wwn); | ||
53 | GET_CONFIG(port_wwn); | ||
54 | GET_CONFIG(wq_enet_desc_count); | ||
55 | GET_CONFIG(wq_copy_desc_count); | ||
56 | GET_CONFIG(rq_desc_count); | ||
57 | GET_CONFIG(maxdatafieldsize); | ||
58 | GET_CONFIG(ed_tov); | ||
59 | GET_CONFIG(ra_tov); | ||
60 | GET_CONFIG(intr_timer); | ||
61 | GET_CONFIG(intr_timer_type); | ||
62 | GET_CONFIG(flags); | ||
63 | GET_CONFIG(flogi_retries); | ||
64 | GET_CONFIG(flogi_timeout); | ||
65 | GET_CONFIG(plogi_retries); | ||
66 | GET_CONFIG(plogi_timeout); | ||
67 | GET_CONFIG(io_throttle_count); | ||
68 | GET_CONFIG(link_down_timeout); | ||
69 | GET_CONFIG(port_down_timeout); | ||
70 | GET_CONFIG(port_down_io_retries); | ||
71 | GET_CONFIG(luns_per_tgt); | ||
72 | |||
73 | c->wq_enet_desc_count = | ||
74 | min_t(u32, VNIC_FNIC_WQ_DESCS_MAX, | ||
75 | max_t(u32, VNIC_FNIC_WQ_DESCS_MIN, | ||
76 | c->wq_enet_desc_count)); | ||
77 | c->wq_enet_desc_count = ALIGN(c->wq_enet_desc_count, 16); | ||
78 | |||
79 | c->wq_copy_desc_count = | ||
80 | min_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MAX, | ||
81 | max_t(u32, VNIC_FNIC_WQ_COPY_DESCS_MIN, | ||
82 | c->wq_copy_desc_count)); | ||
83 | c->wq_copy_desc_count = ALIGN(c->wq_copy_desc_count, 16); | ||
84 | |||
85 | c->rq_desc_count = | ||
86 | min_t(u32, VNIC_FNIC_RQ_DESCS_MAX, | ||
87 | max_t(u32, VNIC_FNIC_RQ_DESCS_MIN, | ||
88 | c->rq_desc_count)); | ||
89 | c->rq_desc_count = ALIGN(c->rq_desc_count, 16); | ||
90 | |||
91 | c->maxdatafieldsize = | ||
92 | min_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MAX, | ||
93 | max_t(u16, VNIC_FNIC_MAXDATAFIELDSIZE_MIN, | ||
94 | c->maxdatafieldsize)); | ||
95 | c->ed_tov = | ||
96 | min_t(u32, VNIC_FNIC_EDTOV_MAX, | ||
97 | max_t(u32, VNIC_FNIC_EDTOV_MIN, | ||
98 | c->ed_tov)); | ||
99 | |||
100 | c->ra_tov = | ||
101 | min_t(u32, VNIC_FNIC_RATOV_MAX, | ||
102 | max_t(u32, VNIC_FNIC_RATOV_MIN, | ||
103 | c->ra_tov)); | ||
104 | |||
105 | c->flogi_retries = | ||
106 | min_t(u32, VNIC_FNIC_FLOGI_RETRIES_MAX, c->flogi_retries); | ||
107 | |||
108 | c->flogi_timeout = | ||
109 | min_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MAX, | ||
110 | max_t(u32, VNIC_FNIC_FLOGI_TIMEOUT_MIN, | ||
111 | c->flogi_timeout)); | ||
112 | |||
113 | c->plogi_retries = | ||
114 | min_t(u32, VNIC_FNIC_PLOGI_RETRIES_MAX, c->plogi_retries); | ||
115 | |||
116 | c->plogi_timeout = | ||
117 | min_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MAX, | ||
118 | max_t(u32, VNIC_FNIC_PLOGI_TIMEOUT_MIN, | ||
119 | c->plogi_timeout)); | ||
120 | |||
121 | c->io_throttle_count = | ||
122 | min_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MAX, | ||
123 | max_t(u32, VNIC_FNIC_IO_THROTTLE_COUNT_MIN, | ||
124 | c->io_throttle_count)); | ||
125 | |||
126 | c->link_down_timeout = | ||
127 | min_t(u32, VNIC_FNIC_LINK_DOWN_TIMEOUT_MAX, | ||
128 | c->link_down_timeout); | ||
129 | |||
130 | c->port_down_timeout = | ||
131 | min_t(u32, VNIC_FNIC_PORT_DOWN_TIMEOUT_MAX, | ||
132 | c->port_down_timeout); | ||
133 | |||
134 | c->port_down_io_retries = | ||
135 | min_t(u32, VNIC_FNIC_PORT_DOWN_IO_RETRIES_MAX, | ||
136 | c->port_down_io_retries); | ||
137 | |||
138 | c->luns_per_tgt = | ||
139 | min_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MAX, | ||
140 | max_t(u32, VNIC_FNIC_LUNS_PER_TARGET_MIN, | ||
141 | c->luns_per_tgt)); | ||
142 | |||
143 | c->intr_timer = min_t(u16, VNIC_INTR_TIMER_MAX, c->intr_timer); | ||
144 | c->intr_timer_type = c->intr_timer_type; | ||
145 | |||
146 | shost_printk(KERN_INFO, fnic->lport->host, | ||
147 | "vNIC MAC addr %02x:%02x:%02x:%02x:%02x:%02x " | ||
148 | "wq/wq_copy/rq %d/%d/%d\n", | ||
149 | fnic->mac_addr[0], fnic->mac_addr[1], fnic->mac_addr[2], | ||
150 | fnic->mac_addr[3], fnic->mac_addr[4], fnic->mac_addr[5], | ||
151 | c->wq_enet_desc_count, c->wq_copy_desc_count, | ||
152 | c->rq_desc_count); | ||
153 | shost_printk(KERN_INFO, fnic->lport->host, | ||
154 | "vNIC node wwn %llx port wwn %llx\n", | ||
155 | c->node_wwn, c->port_wwn); | ||
156 | shost_printk(KERN_INFO, fnic->lport->host, | ||
157 | "vNIC ed_tov %d ra_tov %d\n", | ||
158 | c->ed_tov, c->ra_tov); | ||
159 | shost_printk(KERN_INFO, fnic->lport->host, | ||
160 | "vNIC mtu %d intr timer %d\n", | ||
161 | c->maxdatafieldsize, c->intr_timer); | ||
162 | shost_printk(KERN_INFO, fnic->lport->host, | ||
163 | "vNIC flags 0x%x luns per tgt %d\n", | ||
164 | c->flags, c->luns_per_tgt); | ||
165 | shost_printk(KERN_INFO, fnic->lport->host, | ||
166 | "vNIC flogi_retries %d flogi timeout %d\n", | ||
167 | c->flogi_retries, c->flogi_timeout); | ||
168 | shost_printk(KERN_INFO, fnic->lport->host, | ||
169 | "vNIC plogi retries %d plogi timeout %d\n", | ||
170 | c->plogi_retries, c->plogi_timeout); | ||
171 | shost_printk(KERN_INFO, fnic->lport->host, | ||
172 | "vNIC io throttle count %d link dn timeout %d\n", | ||
173 | c->io_throttle_count, c->link_down_timeout); | ||
174 | shost_printk(KERN_INFO, fnic->lport->host, | ||
175 | "vNIC port dn io retries %d port dn timeout %d\n", | ||
176 | c->port_down_io_retries, c->port_down_timeout); | ||
177 | |||
178 | return 0; | ||
179 | } | ||
180 | |||
181 | int fnic_set_nic_config(struct fnic *fnic, u8 rss_default_cpu, | ||
182 | u8 rss_hash_type, | ||
183 | u8 rss_hash_bits, u8 rss_base_cpu, u8 rss_enable, | ||
184 | u8 tso_ipid_split_en, u8 ig_vlan_strip_en) | ||
185 | { | ||
186 | u64 a0, a1; | ||
187 | u32 nic_cfg; | ||
188 | int wait = 1000; | ||
189 | |||
190 | vnic_set_nic_cfg(&nic_cfg, rss_default_cpu, | ||
191 | rss_hash_type, rss_hash_bits, rss_base_cpu, | ||
192 | rss_enable, tso_ipid_split_en, ig_vlan_strip_en); | ||
193 | |||
194 | a0 = nic_cfg; | ||
195 | a1 = 0; | ||
196 | |||
197 | return vnic_dev_cmd(fnic->vdev, CMD_NIC_CFG, &a0, &a1, wait); | ||
198 | } | ||
199 | |||
200 | void fnic_get_res_counts(struct fnic *fnic) | ||
201 | { | ||
202 | fnic->wq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_WQ); | ||
203 | fnic->raw_wq_count = fnic->wq_count - 1; | ||
204 | fnic->wq_copy_count = fnic->wq_count - fnic->raw_wq_count; | ||
205 | fnic->rq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_RQ); | ||
206 | fnic->cq_count = vnic_dev_get_res_count(fnic->vdev, RES_TYPE_CQ); | ||
207 | fnic->intr_count = vnic_dev_get_res_count(fnic->vdev, | ||
208 | RES_TYPE_INTR_CTRL); | ||
209 | } | ||
210 | |||
211 | void fnic_free_vnic_resources(struct fnic *fnic) | ||
212 | { | ||
213 | unsigned int i; | ||
214 | |||
215 | for (i = 0; i < fnic->raw_wq_count; i++) | ||
216 | vnic_wq_free(&fnic->wq[i]); | ||
217 | |||
218 | for (i = 0; i < fnic->wq_copy_count; i++) | ||
219 | vnic_wq_copy_free(&fnic->wq_copy[i]); | ||
220 | |||
221 | for (i = 0; i < fnic->rq_count; i++) | ||
222 | vnic_rq_free(&fnic->rq[i]); | ||
223 | |||
224 | for (i = 0; i < fnic->cq_count; i++) | ||
225 | vnic_cq_free(&fnic->cq[i]); | ||
226 | |||
227 | for (i = 0; i < fnic->intr_count; i++) | ||
228 | vnic_intr_free(&fnic->intr[i]); | ||
229 | } | ||
230 | |||
231 | int fnic_alloc_vnic_resources(struct fnic *fnic) | ||
232 | { | ||
233 | enum vnic_dev_intr_mode intr_mode; | ||
234 | unsigned int mask_on_assertion; | ||
235 | unsigned int interrupt_offset; | ||
236 | unsigned int error_interrupt_enable; | ||
237 | unsigned int error_interrupt_offset; | ||
238 | unsigned int i, cq_index; | ||
239 | unsigned int wq_copy_cq_desc_count; | ||
240 | int err; | ||
241 | |||
242 | intr_mode = vnic_dev_get_intr_mode(fnic->vdev); | ||
243 | |||
244 | shost_printk(KERN_INFO, fnic->lport->host, "vNIC interrupt mode: %s\n", | ||
245 | intr_mode == VNIC_DEV_INTR_MODE_INTX ? "legacy PCI INTx" : | ||
246 | intr_mode == VNIC_DEV_INTR_MODE_MSI ? "MSI" : | ||
247 | intr_mode == VNIC_DEV_INTR_MODE_MSIX ? | ||
248 | "MSI-X" : "unknown"); | ||
249 | |||
250 | shost_printk(KERN_INFO, fnic->lport->host, "vNIC resources avail: " | ||
251 | "wq %d cp_wq %d raw_wq %d rq %d cq %d intr %d\n", | ||
252 | fnic->wq_count, fnic->wq_copy_count, fnic->raw_wq_count, | ||
253 | fnic->rq_count, fnic->cq_count, fnic->intr_count); | ||
254 | |||
255 | /* Allocate Raw WQ used for FCS frames */ | ||
256 | for (i = 0; i < fnic->raw_wq_count; i++) { | ||
257 | err = vnic_wq_alloc(fnic->vdev, &fnic->wq[i], i, | ||
258 | fnic->config.wq_enet_desc_count, | ||
259 | sizeof(struct wq_enet_desc)); | ||
260 | if (err) | ||
261 | goto err_out_cleanup; | ||
262 | } | ||
263 | |||
264 | /* Allocate Copy WQs used for SCSI IOs */ | ||
265 | for (i = 0; i < fnic->wq_copy_count; i++) { | ||
266 | err = vnic_wq_copy_alloc(fnic->vdev, &fnic->wq_copy[i], | ||
267 | (fnic->raw_wq_count + i), | ||
268 | fnic->config.wq_copy_desc_count, | ||
269 | sizeof(struct fcpio_host_req)); | ||
270 | if (err) | ||
271 | goto err_out_cleanup; | ||
272 | } | ||
273 | |||
274 | /* RQ for receiving FCS frames */ | ||
275 | for (i = 0; i < fnic->rq_count; i++) { | ||
276 | err = vnic_rq_alloc(fnic->vdev, &fnic->rq[i], i, | ||
277 | fnic->config.rq_desc_count, | ||
278 | sizeof(struct rq_enet_desc)); | ||
279 | if (err) | ||
280 | goto err_out_cleanup; | ||
281 | } | ||
282 | |||
283 | /* CQ for each RQ */ | ||
284 | for (i = 0; i < fnic->rq_count; i++) { | ||
285 | cq_index = i; | ||
286 | err = vnic_cq_alloc(fnic->vdev, | ||
287 | &fnic->cq[cq_index], cq_index, | ||
288 | fnic->config.rq_desc_count, | ||
289 | sizeof(struct cq_enet_rq_desc)); | ||
290 | if (err) | ||
291 | goto err_out_cleanup; | ||
292 | } | ||
293 | |||
294 | /* CQ for each WQ */ | ||
295 | for (i = 0; i < fnic->raw_wq_count; i++) { | ||
296 | cq_index = fnic->rq_count + i; | ||
297 | err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index], cq_index, | ||
298 | fnic->config.wq_enet_desc_count, | ||
299 | sizeof(struct cq_enet_wq_desc)); | ||
300 | if (err) | ||
301 | goto err_out_cleanup; | ||
302 | } | ||
303 | |||
304 | /* CQ for each COPY WQ */ | ||
305 | wq_copy_cq_desc_count = (fnic->config.wq_copy_desc_count * 3); | ||
306 | for (i = 0; i < fnic->wq_copy_count; i++) { | ||
307 | cq_index = fnic->raw_wq_count + fnic->rq_count + i; | ||
308 | err = vnic_cq_alloc(fnic->vdev, &fnic->cq[cq_index], | ||
309 | cq_index, | ||
310 | wq_copy_cq_desc_count, | ||
311 | sizeof(struct fcpio_fw_req)); | ||
312 | if (err) | ||
313 | goto err_out_cleanup; | ||
314 | } | ||
315 | |||
316 | for (i = 0; i < fnic->intr_count; i++) { | ||
317 | err = vnic_intr_alloc(fnic->vdev, &fnic->intr[i], i); | ||
318 | if (err) | ||
319 | goto err_out_cleanup; | ||
320 | } | ||
321 | |||
322 | fnic->legacy_pba = vnic_dev_get_res(fnic->vdev, | ||
323 | RES_TYPE_INTR_PBA_LEGACY, 0); | ||
324 | |||
325 | if (!fnic->legacy_pba && intr_mode == VNIC_DEV_INTR_MODE_INTX) { | ||
326 | shost_printk(KERN_ERR, fnic->lport->host, | ||
327 | "Failed to hook legacy pba resource\n"); | ||
328 | err = -ENODEV; | ||
329 | goto err_out_cleanup; | ||
330 | } | ||
331 | |||
332 | /* | ||
333 | * Init RQ/WQ resources. | ||
334 | * | ||
335 | * RQ[0 to n-1] point to CQ[0 to n-1] | ||
336 | * WQ[0 to m-1] point to CQ[n to n+m-1] | ||
337 | * WQ_COPY[0 to k-1] points to CQ[n+m to n+m+k-1] | ||
338 | * | ||
339 | * Note for copy wq we always initialize with cq_index = 0 | ||
340 | * | ||
341 | * Error interrupt is not enabled for MSI. | ||
342 | */ | ||
343 | |||
344 | switch (intr_mode) { | ||
345 | case VNIC_DEV_INTR_MODE_INTX: | ||
346 | case VNIC_DEV_INTR_MODE_MSIX: | ||
347 | error_interrupt_enable = 1; | ||
348 | error_interrupt_offset = fnic->err_intr_offset; | ||
349 | break; | ||
350 | default: | ||
351 | error_interrupt_enable = 0; | ||
352 | error_interrupt_offset = 0; | ||
353 | break; | ||
354 | } | ||
355 | |||
356 | for (i = 0; i < fnic->rq_count; i++) { | ||
357 | cq_index = i; | ||
358 | vnic_rq_init(&fnic->rq[i], | ||
359 | cq_index, | ||
360 | error_interrupt_enable, | ||
361 | error_interrupt_offset); | ||
362 | } | ||
363 | |||
364 | for (i = 0; i < fnic->raw_wq_count; i++) { | ||
365 | cq_index = i + fnic->rq_count; | ||
366 | vnic_wq_init(&fnic->wq[i], | ||
367 | cq_index, | ||
368 | error_interrupt_enable, | ||
369 | error_interrupt_offset); | ||
370 | } | ||
371 | |||
372 | for (i = 0; i < fnic->wq_copy_count; i++) { | ||
373 | vnic_wq_copy_init(&fnic->wq_copy[i], | ||
374 | 0 /* cq_index 0 - always */, | ||
375 | error_interrupt_enable, | ||
376 | error_interrupt_offset); | ||
377 | } | ||
378 | |||
379 | for (i = 0; i < fnic->cq_count; i++) { | ||
380 | |||
381 | switch (intr_mode) { | ||
382 | case VNIC_DEV_INTR_MODE_MSIX: | ||
383 | interrupt_offset = i; | ||
384 | break; | ||
385 | default: | ||
386 | interrupt_offset = 0; | ||
387 | break; | ||
388 | } | ||
389 | |||
390 | vnic_cq_init(&fnic->cq[i], | ||
391 | 0 /* flow_control_enable */, | ||
392 | 1 /* color_enable */, | ||
393 | 0 /* cq_head */, | ||
394 | 0 /* cq_tail */, | ||
395 | 1 /* cq_tail_color */, | ||
396 | 1 /* interrupt_enable */, | ||
397 | 1 /* cq_entry_enable */, | ||
398 | 0 /* cq_message_enable */, | ||
399 | interrupt_offset, | ||
400 | 0 /* cq_message_addr */); | ||
401 | } | ||
402 | |||
403 | /* | ||
404 | * Init INTR resources | ||
405 | * | ||
406 | * mask_on_assertion is not used for INTx due to the level- | ||
407 | * triggered nature of INTx | ||
408 | */ | ||
409 | |||
410 | switch (intr_mode) { | ||
411 | case VNIC_DEV_INTR_MODE_MSI: | ||
412 | case VNIC_DEV_INTR_MODE_MSIX: | ||
413 | mask_on_assertion = 1; | ||
414 | break; | ||
415 | default: | ||
416 | mask_on_assertion = 0; | ||
417 | break; | ||
418 | } | ||
419 | |||
420 | for (i = 0; i < fnic->intr_count; i++) { | ||
421 | vnic_intr_init(&fnic->intr[i], | ||
422 | fnic->config.intr_timer, | ||
423 | fnic->config.intr_timer_type, | ||
424 | mask_on_assertion); | ||
425 | } | ||
426 | |||
427 | /* init the stats memory by making the first call here */ | ||
428 | err = vnic_dev_stats_dump(fnic->vdev, &fnic->stats); | ||
429 | if (err) { | ||
430 | shost_printk(KERN_ERR, fnic->lport->host, | ||
431 | "vnic_dev_stats_dump failed - x%x\n", err); | ||
432 | goto err_out_cleanup; | ||
433 | } | ||
434 | |||
435 | /* Clear LIF stats */ | ||
436 | vnic_dev_stats_clear(fnic->vdev); | ||
437 | |||
438 | return 0; | ||
439 | |||
440 | err_out_cleanup: | ||
441 | fnic_free_vnic_resources(fnic); | ||
442 | |||
443 | return err; | ||
444 | } | ||
diff --git a/drivers/scsi/fnic/fnic_res.h b/drivers/scsi/fnic/fnic_res.h new file mode 100644 index 000000000000..b6f310262534 --- /dev/null +++ b/drivers/scsi/fnic/fnic_res.h | |||
@@ -0,0 +1,197 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _FNIC_RES_H_ | ||
19 | #define _FNIC_RES_H_ | ||
20 | |||
21 | #include "wq_enet_desc.h" | ||
22 | #include "rq_enet_desc.h" | ||
23 | #include "vnic_wq.h" | ||
24 | #include "vnic_rq.h" | ||
25 | #include "fnic_io.h" | ||
26 | #include "fcpio.h" | ||
27 | #include "vnic_wq_copy.h" | ||
28 | #include "vnic_cq_copy.h" | ||
29 | |||
30 | static inline void fnic_queue_wq_desc(struct vnic_wq *wq, | ||
31 | void *os_buf, dma_addr_t dma_addr, | ||
32 | unsigned int len, unsigned int fc_eof, | ||
33 | int vlan_tag_insert, | ||
34 | unsigned int vlan_tag, | ||
35 | int cq_entry, int sop, int eop) | ||
36 | { | ||
37 | struct wq_enet_desc *desc = vnic_wq_next_desc(wq); | ||
38 | |||
39 | wq_enet_desc_enc(desc, | ||
40 | (u64)dma_addr | VNIC_PADDR_TARGET, | ||
41 | (u16)len, | ||
42 | 0, /* mss_or_csum_offset */ | ||
43 | (u16)fc_eof, | ||
44 | 0, /* offload_mode */ | ||
45 | (u8)eop, (u8)cq_entry, | ||
46 | 1, /* fcoe_encap */ | ||
47 | (u8)vlan_tag_insert, | ||
48 | (u16)vlan_tag, | ||
49 | 0 /* loopback */); | ||
50 | |||
51 | vnic_wq_post(wq, os_buf, dma_addr, len, sop, eop); | ||
52 | } | ||
53 | |||
54 | static inline void fnic_queue_wq_copy_desc_icmnd_16(struct vnic_wq_copy *wq, | ||
55 | u32 req_id, | ||
56 | u32 lunmap_id, u8 spl_flags, | ||
57 | u32 sgl_cnt, u32 sense_len, | ||
58 | u64 sgl_addr, u64 sns_addr, | ||
59 | u8 crn, u8 pri_ta, | ||
60 | u8 flags, u8 *scsi_cdb, | ||
61 | u32 data_len, u8 *lun, | ||
62 | u32 d_id, u16 mss, | ||
63 | u32 ratov, u32 edtov) | ||
64 | { | ||
65 | struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); | ||
66 | |||
67 | desc->hdr.type = FCPIO_ICMND_16; /* enum fcpio_type */ | ||
68 | desc->hdr.status = 0; /* header status entry */ | ||
69 | desc->hdr._resvd = 0; /* reserved */ | ||
70 | desc->hdr.tag.u.req_id = req_id; /* id for this request */ | ||
71 | |||
72 | desc->u.icmnd_16.lunmap_id = lunmap_id; /* index into lunmap table */ | ||
73 | desc->u.icmnd_16.special_req_flags = spl_flags; /* exch req flags */ | ||
74 | desc->u.icmnd_16._resvd0[0] = 0; /* reserved */ | ||
75 | desc->u.icmnd_16._resvd0[1] = 0; /* reserved */ | ||
76 | desc->u.icmnd_16._resvd0[2] = 0; /* reserved */ | ||
77 | desc->u.icmnd_16.sgl_cnt = sgl_cnt; /* scatter-gather list count */ | ||
78 | desc->u.icmnd_16.sense_len = sense_len; /* sense buffer length */ | ||
79 | desc->u.icmnd_16.sgl_addr = sgl_addr; /* scatter-gather list addr */ | ||
80 | desc->u.icmnd_16.sense_addr = sns_addr; /* sense buffer address */ | ||
81 | desc->u.icmnd_16.crn = crn; /* SCSI Command Reference No.*/ | ||
82 | desc->u.icmnd_16.pri_ta = pri_ta; /* SCSI Pri & Task attribute */ | ||
83 | desc->u.icmnd_16._resvd1 = 0; /* reserved: should be 0 */ | ||
84 | desc->u.icmnd_16.flags = flags; /* command flags */ | ||
85 | memcpy(desc->u.icmnd_16.scsi_cdb, scsi_cdb, CDB_16); /* SCSI CDB */ | ||
86 | desc->u.icmnd_16.data_len = data_len; /* length of data expected */ | ||
87 | memcpy(desc->u.icmnd_16.lun, lun, LUN_ADDRESS); /* LUN address */ | ||
88 | desc->u.icmnd_16._resvd2 = 0; /* reserved */ | ||
89 | hton24(desc->u.icmnd_16.d_id, d_id); /* FC vNIC only: Target D_ID */ | ||
90 | desc->u.icmnd_16.mss = mss; /* FC vNIC only: max burst */ | ||
91 | desc->u.icmnd_16.r_a_tov = ratov; /*FC vNIC only: Res. Alloc Timeout */ | ||
92 | desc->u.icmnd_16.e_d_tov = edtov; /*FC vNIC only: Err Detect Timeout */ | ||
93 | |||
94 | vnic_wq_copy_post(wq); | ||
95 | } | ||
96 | |||
97 | static inline void fnic_queue_wq_copy_desc_itmf(struct vnic_wq_copy *wq, | ||
98 | u32 req_id, u32 lunmap_id, | ||
99 | u32 tm_req, u32 tm_id, u8 *lun, | ||
100 | u32 d_id, u32 r_a_tov, | ||
101 | u32 e_d_tov) | ||
102 | { | ||
103 | struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); | ||
104 | |||
105 | desc->hdr.type = FCPIO_ITMF; /* enum fcpio_type */ | ||
106 | desc->hdr.status = 0; /* header status entry */ | ||
107 | desc->hdr._resvd = 0; /* reserved */ | ||
108 | desc->hdr.tag.u.req_id = req_id; /* id for this request */ | ||
109 | |||
110 | desc->u.itmf.lunmap_id = lunmap_id; /* index into lunmap table */ | ||
111 | desc->u.itmf.tm_req = tm_req; /* SCSI Task Management request */ | ||
112 | desc->u.itmf.t_tag = tm_id; /* tag of fcpio to be aborted */ | ||
113 | desc->u.itmf._resvd = 0; | ||
114 | memcpy(desc->u.itmf.lun, lun, LUN_ADDRESS); /* LUN address */ | ||
115 | desc->u.itmf._resvd1 = 0; | ||
116 | hton24(desc->u.itmf.d_id, d_id); /* FC vNIC only: Target D_ID */ | ||
117 | desc->u.itmf.r_a_tov = r_a_tov; /* FC vNIC only: R_A_TOV in msec */ | ||
118 | desc->u.itmf.e_d_tov = e_d_tov; /* FC vNIC only: E_D_TOV in msec */ | ||
119 | |||
120 | vnic_wq_copy_post(wq); | ||
121 | } | ||
122 | |||
123 | static inline void fnic_queue_wq_copy_desc_flogi_reg(struct vnic_wq_copy *wq, | ||
124 | u32 req_id, u8 format, | ||
125 | u32 s_id, u8 *gw_mac) | ||
126 | { | ||
127 | struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); | ||
128 | |||
129 | desc->hdr.type = FCPIO_FLOGI_REG; /* enum fcpio_type */ | ||
130 | desc->hdr.status = 0; /* header status entry */ | ||
131 | desc->hdr._resvd = 0; /* reserved */ | ||
132 | desc->hdr.tag.u.req_id = req_id; /* id for this request */ | ||
133 | |||
134 | desc->u.flogi_reg.format = format; | ||
135 | hton24(desc->u.flogi_reg.s_id, s_id); | ||
136 | memcpy(desc->u.flogi_reg.gateway_mac, gw_mac, ETH_ALEN); | ||
137 | |||
138 | vnic_wq_copy_post(wq); | ||
139 | } | ||
140 | |||
141 | static inline void fnic_queue_wq_copy_desc_fw_reset(struct vnic_wq_copy *wq, | ||
142 | u32 req_id) | ||
143 | { | ||
144 | struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); | ||
145 | |||
146 | desc->hdr.type = FCPIO_RESET; /* enum fcpio_type */ | ||
147 | desc->hdr.status = 0; /* header status entry */ | ||
148 | desc->hdr._resvd = 0; /* reserved */ | ||
149 | desc->hdr.tag.u.req_id = req_id; /* id for this request */ | ||
150 | |||
151 | vnic_wq_copy_post(wq); | ||
152 | } | ||
153 | |||
154 | static inline void fnic_queue_wq_copy_desc_lunmap(struct vnic_wq_copy *wq, | ||
155 | u32 req_id, u64 lunmap_addr, | ||
156 | u32 lunmap_len) | ||
157 | { | ||
158 | struct fcpio_host_req *desc = vnic_wq_copy_next_desc(wq); | ||
159 | |||
160 | desc->hdr.type = FCPIO_LUNMAP_REQ; /* enum fcpio_type */ | ||
161 | desc->hdr.status = 0; /* header status entry */ | ||
162 | desc->hdr._resvd = 0; /* reserved */ | ||
163 | desc->hdr.tag.u.req_id = req_id; /* id for this request */ | ||
164 | |||
165 | desc->u.lunmap_req.addr = lunmap_addr; /* address of the buffer */ | ||
166 | desc->u.lunmap_req.len = lunmap_len; /* len of the buffer */ | ||
167 | |||
168 | vnic_wq_copy_post(wq); | ||
169 | } | ||
170 | |||
171 | static inline void fnic_queue_rq_desc(struct vnic_rq *rq, | ||
172 | void *os_buf, dma_addr_t dma_addr, | ||
173 | u16 len) | ||
174 | { | ||
175 | struct rq_enet_desc *desc = vnic_rq_next_desc(rq); | ||
176 | |||
177 | rq_enet_desc_enc(desc, | ||
178 | (u64)dma_addr | VNIC_PADDR_TARGET, | ||
179 | RQ_ENET_TYPE_ONLY_SOP, | ||
180 | (u16)len); | ||
181 | |||
182 | vnic_rq_post(rq, os_buf, 0, dma_addr, len); | ||
183 | } | ||
184 | |||
185 | |||
186 | struct fnic; | ||
187 | |||
188 | int fnic_get_vnic_config(struct fnic *); | ||
189 | int fnic_alloc_vnic_resources(struct fnic *); | ||
190 | void fnic_free_vnic_resources(struct fnic *); | ||
191 | void fnic_get_res_counts(struct fnic *); | ||
192 | int fnic_set_nic_config(struct fnic *fnic, u8 rss_default_cpu, | ||
193 | u8 rss_hash_type, u8 rss_hash_bits, u8 rss_base_cpu, | ||
194 | u8 rss_enable, u8 tso_ipid_split_en, | ||
195 | u8 ig_vlan_strip_en); | ||
196 | |||
197 | #endif /* _FNIC_RES_H_ */ | ||
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c new file mode 100644 index 000000000000..eabf36502856 --- /dev/null +++ b/drivers/scsi/fnic/fnic_scsi.c | |||
@@ -0,0 +1,1850 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #include <linux/mempool.h> | ||
19 | #include <linux/errno.h> | ||
20 | #include <linux/init.h> | ||
21 | #include <linux/workqueue.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/scatterlist.h> | ||
24 | #include <linux/skbuff.h> | ||
25 | #include <linux/spinlock.h> | ||
26 | #include <linux/if_ether.h> | ||
27 | #include <linux/if_vlan.h> | ||
28 | #include <linux/delay.h> | ||
29 | #include <scsi/scsi.h> | ||
30 | #include <scsi/scsi_host.h> | ||
31 | #include <scsi/scsi_device.h> | ||
32 | #include <scsi/scsi_cmnd.h> | ||
33 | #include <scsi/scsi_tcq.h> | ||
34 | #include <scsi/fc/fc_els.h> | ||
35 | #include <scsi/fc/fc_fcoe.h> | ||
36 | #include <scsi/libfc.h> | ||
37 | #include <scsi/fc_frame.h> | ||
38 | #include "fnic_io.h" | ||
39 | #include "fnic.h" | ||
40 | |||
41 | const char *fnic_state_str[] = { | ||
42 | [FNIC_IN_FC_MODE] = "FNIC_IN_FC_MODE", | ||
43 | [FNIC_IN_FC_TRANS_ETH_MODE] = "FNIC_IN_FC_TRANS_ETH_MODE", | ||
44 | [FNIC_IN_ETH_MODE] = "FNIC_IN_ETH_MODE", | ||
45 | [FNIC_IN_ETH_TRANS_FC_MODE] = "FNIC_IN_ETH_TRANS_FC_MODE", | ||
46 | }; | ||
47 | |||
48 | static const char *fnic_ioreq_state_str[] = { | ||
49 | [FNIC_IOREQ_CMD_PENDING] = "FNIC_IOREQ_CMD_PENDING", | ||
50 | [FNIC_IOREQ_ABTS_PENDING] = "FNIC_IOREQ_ABTS_PENDING", | ||
51 | [FNIC_IOREQ_ABTS_COMPLETE] = "FNIC_IOREQ_ABTS_COMPLETE", | ||
52 | [FNIC_IOREQ_CMD_COMPLETE] = "FNIC_IOREQ_CMD_COMPLETE", | ||
53 | }; | ||
54 | |||
55 | static const char *fcpio_status_str[] = { | ||
56 | [FCPIO_SUCCESS] = "FCPIO_SUCCESS", /*0x0*/ | ||
57 | [FCPIO_INVALID_HEADER] = "FCPIO_INVALID_HEADER", | ||
58 | [FCPIO_OUT_OF_RESOURCE] = "FCPIO_OUT_OF_RESOURCE", | ||
59 | [FCPIO_INVALID_PARAM] = "FCPIO_INVALID_PARAM]", | ||
60 | [FCPIO_REQ_NOT_SUPPORTED] = "FCPIO_REQ_NOT_SUPPORTED", | ||
61 | [FCPIO_IO_NOT_FOUND] = "FCPIO_IO_NOT_FOUND", | ||
62 | [FCPIO_ABORTED] = "FCPIO_ABORTED", /*0x41*/ | ||
63 | [FCPIO_TIMEOUT] = "FCPIO_TIMEOUT", | ||
64 | [FCPIO_SGL_INVALID] = "FCPIO_SGL_INVALID", | ||
65 | [FCPIO_MSS_INVALID] = "FCPIO_MSS_INVALID", | ||
66 | [FCPIO_DATA_CNT_MISMATCH] = "FCPIO_DATA_CNT_MISMATCH", | ||
67 | [FCPIO_FW_ERR] = "FCPIO_FW_ERR", | ||
68 | [FCPIO_ITMF_REJECTED] = "FCPIO_ITMF_REJECTED", | ||
69 | [FCPIO_ITMF_FAILED] = "FCPIO_ITMF_FAILED", | ||
70 | [FCPIO_ITMF_INCORRECT_LUN] = "FCPIO_ITMF_INCORRECT_LUN", | ||
71 | [FCPIO_CMND_REJECTED] = "FCPIO_CMND_REJECTED", | ||
72 | [FCPIO_NO_PATH_AVAIL] = "FCPIO_NO_PATH_AVAIL", | ||
73 | [FCPIO_PATH_FAILED] = "FCPIO_PATH_FAILED", | ||
74 | [FCPIO_LUNMAP_CHNG_PEND] = "FCPIO_LUNHMAP_CHNG_PEND", | ||
75 | }; | ||
76 | |||
77 | const char *fnic_state_to_str(unsigned int state) | ||
78 | { | ||
79 | if (state >= ARRAY_SIZE(fnic_state_str) || !fnic_state_str[state]) | ||
80 | return "unknown"; | ||
81 | |||
82 | return fnic_state_str[state]; | ||
83 | } | ||
84 | |||
85 | static const char *fnic_ioreq_state_to_str(unsigned int state) | ||
86 | { | ||
87 | if (state >= ARRAY_SIZE(fnic_ioreq_state_str) || | ||
88 | !fnic_ioreq_state_str[state]) | ||
89 | return "unknown"; | ||
90 | |||
91 | return fnic_ioreq_state_str[state]; | ||
92 | } | ||
93 | |||
94 | static const char *fnic_fcpio_status_to_str(unsigned int status) | ||
95 | { | ||
96 | if (status >= ARRAY_SIZE(fcpio_status_str) || !fcpio_status_str[status]) | ||
97 | return "unknown"; | ||
98 | |||
99 | return fcpio_status_str[status]; | ||
100 | } | ||
101 | |||
102 | static void fnic_cleanup_io(struct fnic *fnic, int exclude_id); | ||
103 | |||
104 | static inline spinlock_t *fnic_io_lock_hash(struct fnic *fnic, | ||
105 | struct scsi_cmnd *sc) | ||
106 | { | ||
107 | u32 hash = sc->request->tag & (FNIC_IO_LOCKS - 1); | ||
108 | |||
109 | return &fnic->io_req_lock[hash]; | ||
110 | } | ||
111 | |||
112 | /* | ||
113 | * Unmap the data buffer and sense buffer for an io_req, | ||
114 | * also unmap and free the device-private scatter/gather list. | ||
115 | */ | ||
116 | static void fnic_release_ioreq_buf(struct fnic *fnic, | ||
117 | struct fnic_io_req *io_req, | ||
118 | struct scsi_cmnd *sc) | ||
119 | { | ||
120 | if (io_req->sgl_list_pa) | ||
121 | pci_unmap_single(fnic->pdev, io_req->sgl_list_pa, | ||
122 | sizeof(io_req->sgl_list[0]) * io_req->sgl_cnt, | ||
123 | PCI_DMA_TODEVICE); | ||
124 | scsi_dma_unmap(sc); | ||
125 | |||
126 | if (io_req->sgl_cnt) | ||
127 | mempool_free(io_req->sgl_list_alloc, | ||
128 | fnic->io_sgl_pool[io_req->sgl_type]); | ||
129 | if (io_req->sense_buf_pa) | ||
130 | pci_unmap_single(fnic->pdev, io_req->sense_buf_pa, | ||
131 | SCSI_SENSE_BUFFERSIZE, PCI_DMA_FROMDEVICE); | ||
132 | } | ||
133 | |||
134 | /* Free up Copy Wq descriptors. Called with copy_wq lock held */ | ||
135 | static int free_wq_copy_descs(struct fnic *fnic, struct vnic_wq_copy *wq) | ||
136 | { | ||
137 | /* if no Ack received from firmware, then nothing to clean */ | ||
138 | if (!fnic->fw_ack_recd[0]) | ||
139 | return 1; | ||
140 | |||
141 | /* | ||
142 | * Update desc_available count based on number of freed descriptors | ||
143 | * Account for wraparound | ||
144 | */ | ||
145 | if (wq->to_clean_index <= fnic->fw_ack_index[0]) | ||
146 | wq->ring.desc_avail += (fnic->fw_ack_index[0] | ||
147 | - wq->to_clean_index + 1); | ||
148 | else | ||
149 | wq->ring.desc_avail += (wq->ring.desc_count | ||
150 | - wq->to_clean_index | ||
151 | + fnic->fw_ack_index[0] + 1); | ||
152 | |||
153 | /* | ||
154 | * just bump clean index to ack_index+1 accounting for wraparound | ||
155 | * this will essentially free up all descriptors between | ||
156 | * to_clean_index and fw_ack_index, both inclusive | ||
157 | */ | ||
158 | wq->to_clean_index = | ||
159 | (fnic->fw_ack_index[0] + 1) % wq->ring.desc_count; | ||
160 | |||
161 | /* we have processed the acks received so far */ | ||
162 | fnic->fw_ack_recd[0] = 0; | ||
163 | return 0; | ||
164 | } | ||
165 | |||
166 | |||
167 | /* | ||
168 | * fnic_fw_reset_handler | ||
169 | * Routine to send reset msg to fw | ||
170 | */ | ||
171 | int fnic_fw_reset_handler(struct fnic *fnic) | ||
172 | { | ||
173 | struct vnic_wq_copy *wq = &fnic->wq_copy[0]; | ||
174 | int ret = 0; | ||
175 | unsigned long flags; | ||
176 | |||
177 | spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); | ||
178 | |||
179 | if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) | ||
180 | free_wq_copy_descs(fnic, wq); | ||
181 | |||
182 | if (!vnic_wq_copy_desc_avail(wq)) | ||
183 | ret = -EAGAIN; | ||
184 | else | ||
185 | fnic_queue_wq_copy_desc_fw_reset(wq, SCSI_NO_TAG); | ||
186 | |||
187 | spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); | ||
188 | |||
189 | if (!ret) | ||
190 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
191 | "Issued fw reset\n"); | ||
192 | else | ||
193 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
194 | "Failed to issue fw reset\n"); | ||
195 | return ret; | ||
196 | } | ||
197 | |||
198 | |||
199 | /* | ||
200 | * fnic_flogi_reg_handler | ||
201 | * Routine to send flogi register msg to fw | ||
202 | */ | ||
203 | int fnic_flogi_reg_handler(struct fnic *fnic) | ||
204 | { | ||
205 | struct vnic_wq_copy *wq = &fnic->wq_copy[0]; | ||
206 | u8 gw_mac[ETH_ALEN]; | ||
207 | int ret = 0; | ||
208 | unsigned long flags; | ||
209 | |||
210 | spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); | ||
211 | |||
212 | if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) | ||
213 | free_wq_copy_descs(fnic, wq); | ||
214 | |||
215 | if (!vnic_wq_copy_desc_avail(wq)) { | ||
216 | ret = -EAGAIN; | ||
217 | goto flogi_reg_ioreq_end; | ||
218 | } | ||
219 | |||
220 | if (fnic->fcoui_mode) | ||
221 | memset(gw_mac, 0xff, ETH_ALEN); | ||
222 | else | ||
223 | memcpy(gw_mac, fnic->dest_addr, ETH_ALEN); | ||
224 | |||
225 | fnic_queue_wq_copy_desc_flogi_reg(wq, SCSI_NO_TAG, | ||
226 | FCPIO_FLOGI_REG_GW_DEST, | ||
227 | fnic->s_id, | ||
228 | gw_mac); | ||
229 | |||
230 | flogi_reg_ioreq_end: | ||
231 | spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); | ||
232 | |||
233 | if (!ret) | ||
234 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
235 | "flog reg issued\n"); | ||
236 | |||
237 | return ret; | ||
238 | } | ||
239 | |||
240 | /* | ||
241 | * fnic_queue_wq_copy_desc | ||
242 | * Routine to enqueue a wq copy desc | ||
243 | */ | ||
244 | static inline int fnic_queue_wq_copy_desc(struct fnic *fnic, | ||
245 | struct vnic_wq_copy *wq, | ||
246 | struct fnic_io_req *io_req, | ||
247 | struct scsi_cmnd *sc, | ||
248 | u32 sg_count) | ||
249 | { | ||
250 | struct scatterlist *sg; | ||
251 | struct fc_rport *rport = starget_to_rport(scsi_target(sc->device)); | ||
252 | struct fc_rport_libfc_priv *rp = rport->dd_data; | ||
253 | struct host_sg_desc *desc; | ||
254 | u8 pri_tag = 0; | ||
255 | unsigned int i; | ||
256 | unsigned long intr_flags; | ||
257 | int flags; | ||
258 | u8 exch_flags; | ||
259 | struct scsi_lun fc_lun; | ||
260 | char msg[2]; | ||
261 | |||
262 | if (sg_count) { | ||
263 | BUG_ON(sg_count < 0); | ||
264 | BUG_ON(sg_count > FNIC_MAX_SG_DESC_CNT); | ||
265 | |||
266 | /* For each SGE, create a device desc entry */ | ||
267 | desc = io_req->sgl_list; | ||
268 | for_each_sg(scsi_sglist(sc), sg, sg_count, i) { | ||
269 | desc->addr = cpu_to_le64(sg_dma_address(sg)); | ||
270 | desc->len = cpu_to_le32(sg_dma_len(sg)); | ||
271 | desc->_resvd = 0; | ||
272 | desc++; | ||
273 | } | ||
274 | |||
275 | io_req->sgl_list_pa = pci_map_single | ||
276 | (fnic->pdev, | ||
277 | io_req->sgl_list, | ||
278 | sizeof(io_req->sgl_list[0]) * sg_count, | ||
279 | PCI_DMA_TODEVICE); | ||
280 | } | ||
281 | |||
282 | io_req->sense_buf_pa = pci_map_single(fnic->pdev, | ||
283 | sc->sense_buffer, | ||
284 | SCSI_SENSE_BUFFERSIZE, | ||
285 | PCI_DMA_FROMDEVICE); | ||
286 | |||
287 | int_to_scsilun(sc->device->lun, &fc_lun); | ||
288 | |||
289 | pri_tag = FCPIO_ICMND_PTA_SIMPLE; | ||
290 | msg[0] = MSG_SIMPLE_TAG; | ||
291 | scsi_populate_tag_msg(sc, msg); | ||
292 | if (msg[0] == MSG_ORDERED_TAG) | ||
293 | pri_tag = FCPIO_ICMND_PTA_ORDERED; | ||
294 | |||
295 | /* Enqueue the descriptor in the Copy WQ */ | ||
296 | spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags); | ||
297 | |||
298 | if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) | ||
299 | free_wq_copy_descs(fnic, wq); | ||
300 | |||
301 | if (unlikely(!vnic_wq_copy_desc_avail(wq))) { | ||
302 | spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); | ||
303 | return SCSI_MLQUEUE_HOST_BUSY; | ||
304 | } | ||
305 | |||
306 | flags = 0; | ||
307 | if (sc->sc_data_direction == DMA_FROM_DEVICE) | ||
308 | flags = FCPIO_ICMND_RDDATA; | ||
309 | else if (sc->sc_data_direction == DMA_TO_DEVICE) | ||
310 | flags = FCPIO_ICMND_WRDATA; | ||
311 | |||
312 | exch_flags = 0; | ||
313 | if ((fnic->config.flags & VFCF_FCP_SEQ_LVL_ERR) && | ||
314 | (rp->flags & FC_RP_FLAGS_RETRY)) | ||
315 | exch_flags |= FCPIO_ICMND_SRFLAG_RETRY; | ||
316 | |||
317 | fnic_queue_wq_copy_desc_icmnd_16(wq, sc->request->tag, | ||
318 | 0, exch_flags, io_req->sgl_cnt, | ||
319 | SCSI_SENSE_BUFFERSIZE, | ||
320 | io_req->sgl_list_pa, | ||
321 | io_req->sense_buf_pa, | ||
322 | 0, /* scsi cmd ref, always 0 */ | ||
323 | pri_tag, /* scsi pri and tag */ | ||
324 | flags, /* command flags */ | ||
325 | sc->cmnd, scsi_bufflen(sc), | ||
326 | fc_lun.scsi_lun, io_req->port_id, | ||
327 | rport->maxframe_size, rp->r_a_tov, | ||
328 | rp->e_d_tov); | ||
329 | |||
330 | spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); | ||
331 | return 0; | ||
332 | } | ||
333 | |||
334 | /* | ||
335 | * fnic_queuecommand | ||
336 | * Routine to send a scsi cdb | ||
337 | * Called with host_lock held and interrupts disabled. | ||
338 | */ | ||
339 | int fnic_queuecommand(struct scsi_cmnd *sc, void (*done)(struct scsi_cmnd *)) | ||
340 | { | ||
341 | struct fc_lport *lp; | ||
342 | struct fc_rport *rport; | ||
343 | struct fnic_io_req *io_req; | ||
344 | struct fnic *fnic; | ||
345 | struct vnic_wq_copy *wq; | ||
346 | int ret; | ||
347 | u32 sg_count; | ||
348 | unsigned long flags; | ||
349 | unsigned long ptr; | ||
350 | |||
351 | rport = starget_to_rport(scsi_target(sc->device)); | ||
352 | ret = fc_remote_port_chkready(rport); | ||
353 | if (ret) { | ||
354 | sc->result = ret; | ||
355 | done(sc); | ||
356 | return 0; | ||
357 | } | ||
358 | |||
359 | lp = shost_priv(sc->device->host); | ||
360 | if (lp->state != LPORT_ST_READY || !(lp->link_up)) | ||
361 | return SCSI_MLQUEUE_HOST_BUSY; | ||
362 | |||
363 | /* | ||
364 | * Release host lock, use driver resource specific locks from here. | ||
365 | * Don't re-enable interrupts in case they were disabled prior to the | ||
366 | * caller disabling them. | ||
367 | */ | ||
368 | spin_unlock(lp->host->host_lock); | ||
369 | |||
370 | /* Get a new io_req for this SCSI IO */ | ||
371 | fnic = lport_priv(lp); | ||
372 | |||
373 | io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC); | ||
374 | if (!io_req) { | ||
375 | ret = SCSI_MLQUEUE_HOST_BUSY; | ||
376 | goto out; | ||
377 | } | ||
378 | memset(io_req, 0, sizeof(*io_req)); | ||
379 | |||
380 | /* Map the data buffer */ | ||
381 | sg_count = scsi_dma_map(sc); | ||
382 | if (sg_count < 0) { | ||
383 | mempool_free(io_req, fnic->io_req_pool); | ||
384 | goto out; | ||
385 | } | ||
386 | |||
387 | /* Determine the type of scatter/gather list we need */ | ||
388 | io_req->sgl_cnt = sg_count; | ||
389 | io_req->sgl_type = FNIC_SGL_CACHE_DFLT; | ||
390 | if (sg_count > FNIC_DFLT_SG_DESC_CNT) | ||
391 | io_req->sgl_type = FNIC_SGL_CACHE_MAX; | ||
392 | |||
393 | if (sg_count) { | ||
394 | io_req->sgl_list = | ||
395 | mempool_alloc(fnic->io_sgl_pool[io_req->sgl_type], | ||
396 | GFP_ATOMIC | GFP_DMA); | ||
397 | if (!io_req->sgl_list) { | ||
398 | ret = SCSI_MLQUEUE_HOST_BUSY; | ||
399 | scsi_dma_unmap(sc); | ||
400 | mempool_free(io_req, fnic->io_req_pool); | ||
401 | goto out; | ||
402 | } | ||
403 | |||
404 | /* Cache sgl list allocated address before alignment */ | ||
405 | io_req->sgl_list_alloc = io_req->sgl_list; | ||
406 | ptr = (unsigned long) io_req->sgl_list; | ||
407 | if (ptr % FNIC_SG_DESC_ALIGN) { | ||
408 | io_req->sgl_list = (struct host_sg_desc *) | ||
409 | (((unsigned long) ptr | ||
410 | + FNIC_SG_DESC_ALIGN - 1) | ||
411 | & ~(FNIC_SG_DESC_ALIGN - 1)); | ||
412 | } | ||
413 | } | ||
414 | |||
415 | /* initialize rest of io_req */ | ||
416 | io_req->port_id = rport->port_id; | ||
417 | CMD_STATE(sc) = FNIC_IOREQ_CMD_PENDING; | ||
418 | CMD_SP(sc) = (char *)io_req; | ||
419 | sc->scsi_done = done; | ||
420 | |||
421 | /* create copy wq desc and enqueue it */ | ||
422 | wq = &fnic->wq_copy[0]; | ||
423 | ret = fnic_queue_wq_copy_desc(fnic, wq, io_req, sc, sg_count); | ||
424 | if (ret) { | ||
425 | /* | ||
426 | * In case another thread cancelled the request, | ||
427 | * refetch the pointer under the lock. | ||
428 | */ | ||
429 | spinlock_t *io_lock = fnic_io_lock_hash(fnic, sc); | ||
430 | |||
431 | spin_lock_irqsave(io_lock, flags); | ||
432 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
433 | CMD_SP(sc) = NULL; | ||
434 | CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE; | ||
435 | spin_unlock_irqrestore(io_lock, flags); | ||
436 | if (io_req) { | ||
437 | fnic_release_ioreq_buf(fnic, io_req, sc); | ||
438 | mempool_free(io_req, fnic->io_req_pool); | ||
439 | } | ||
440 | } | ||
441 | out: | ||
442 | /* acquire host lock before returning to SCSI */ | ||
443 | spin_lock(lp->host->host_lock); | ||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | /* | ||
448 | * fnic_fcpio_fw_reset_cmpl_handler | ||
449 | * Routine to handle fw reset completion | ||
450 | */ | ||
451 | static int fnic_fcpio_fw_reset_cmpl_handler(struct fnic *fnic, | ||
452 | struct fcpio_fw_req *desc) | ||
453 | { | ||
454 | u8 type; | ||
455 | u8 hdr_status; | ||
456 | struct fcpio_tag tag; | ||
457 | int ret = 0; | ||
458 | struct fc_frame *flogi; | ||
459 | unsigned long flags; | ||
460 | |||
461 | fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); | ||
462 | |||
463 | /* Clean up all outstanding io requests */ | ||
464 | fnic_cleanup_io(fnic, SCSI_NO_TAG); | ||
465 | |||
466 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
467 | |||
468 | flogi = fnic->flogi; | ||
469 | fnic->flogi = NULL; | ||
470 | |||
471 | /* fnic should be in FC_TRANS_ETH_MODE */ | ||
472 | if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) { | ||
473 | /* Check status of reset completion */ | ||
474 | if (!hdr_status) { | ||
475 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
476 | "reset cmpl success\n"); | ||
477 | /* Ready to send flogi out */ | ||
478 | fnic->state = FNIC_IN_ETH_MODE; | ||
479 | } else { | ||
480 | FNIC_SCSI_DBG(KERN_DEBUG, | ||
481 | fnic->lport->host, | ||
482 | "fnic fw_reset : failed %s\n", | ||
483 | fnic_fcpio_status_to_str(hdr_status)); | ||
484 | |||
485 | /* | ||
486 | * Unable to change to eth mode, cannot send out flogi | ||
487 | * Change state to fc mode, so that subsequent Flogi | ||
488 | * requests from libFC will cause more attempts to | ||
489 | * reset the firmware. Free the cached flogi | ||
490 | */ | ||
491 | fnic->state = FNIC_IN_FC_MODE; | ||
492 | ret = -1; | ||
493 | } | ||
494 | } else { | ||
495 | FNIC_SCSI_DBG(KERN_DEBUG, | ||
496 | fnic->lport->host, | ||
497 | "Unexpected state %s while processing" | ||
498 | " reset cmpl\n", fnic_state_to_str(fnic->state)); | ||
499 | ret = -1; | ||
500 | } | ||
501 | |||
502 | /* Thread removing device blocks till firmware reset is complete */ | ||
503 | if (fnic->remove_wait) | ||
504 | complete(fnic->remove_wait); | ||
505 | |||
506 | /* | ||
507 | * If fnic is being removed, or fw reset failed | ||
508 | * free the flogi frame. Else, send it out | ||
509 | */ | ||
510 | if (fnic->remove_wait || ret) { | ||
511 | fnic->flogi_oxid = FC_XID_UNKNOWN; | ||
512 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
513 | if (flogi) | ||
514 | dev_kfree_skb_irq(fp_skb(flogi)); | ||
515 | goto reset_cmpl_handler_end; | ||
516 | } | ||
517 | |||
518 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
519 | |||
520 | if (flogi) | ||
521 | ret = fnic_send_frame(fnic, flogi); | ||
522 | |||
523 | reset_cmpl_handler_end: | ||
524 | return ret; | ||
525 | } | ||
526 | |||
527 | /* | ||
528 | * fnic_fcpio_flogi_reg_cmpl_handler | ||
529 | * Routine to handle flogi register completion | ||
530 | */ | ||
531 | static int fnic_fcpio_flogi_reg_cmpl_handler(struct fnic *fnic, | ||
532 | struct fcpio_fw_req *desc) | ||
533 | { | ||
534 | u8 type; | ||
535 | u8 hdr_status; | ||
536 | struct fcpio_tag tag; | ||
537 | int ret = 0; | ||
538 | struct fc_frame *flogi_resp = NULL; | ||
539 | unsigned long flags; | ||
540 | struct sk_buff *skb; | ||
541 | |||
542 | fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); | ||
543 | |||
544 | /* Update fnic state based on status of flogi reg completion */ | ||
545 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
546 | |||
547 | flogi_resp = fnic->flogi_resp; | ||
548 | fnic->flogi_resp = NULL; | ||
549 | |||
550 | if (fnic->state == FNIC_IN_ETH_TRANS_FC_MODE) { | ||
551 | |||
552 | /* Check flogi registration completion status */ | ||
553 | if (!hdr_status) { | ||
554 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
555 | "flog reg succeeded\n"); | ||
556 | fnic->state = FNIC_IN_FC_MODE; | ||
557 | } else { | ||
558 | FNIC_SCSI_DBG(KERN_DEBUG, | ||
559 | fnic->lport->host, | ||
560 | "fnic flogi reg :failed %s\n", | ||
561 | fnic_fcpio_status_to_str(hdr_status)); | ||
562 | fnic->state = FNIC_IN_ETH_MODE; | ||
563 | ret = -1; | ||
564 | } | ||
565 | } else { | ||
566 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
567 | "Unexpected fnic state %s while" | ||
568 | " processing flogi reg completion\n", | ||
569 | fnic_state_to_str(fnic->state)); | ||
570 | ret = -1; | ||
571 | } | ||
572 | |||
573 | /* Successful flogi reg cmpl, pass frame to LibFC */ | ||
574 | if (!ret && flogi_resp) { | ||
575 | if (fnic->stop_rx_link_events) { | ||
576 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
577 | goto reg_cmpl_handler_end; | ||
578 | } | ||
579 | skb = (struct sk_buff *)flogi_resp; | ||
580 | /* Use fr_flags to indicate whether flogi resp or not */ | ||
581 | fr_flags(flogi_resp) = 1; | ||
582 | fr_dev(flogi_resp) = fnic->lport; | ||
583 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
584 | |||
585 | skb_queue_tail(&fnic->frame_queue, skb); | ||
586 | queue_work(fnic_event_queue, &fnic->frame_work); | ||
587 | |||
588 | } else { | ||
589 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
590 | if (flogi_resp) | ||
591 | dev_kfree_skb_irq(fp_skb(flogi_resp)); | ||
592 | } | ||
593 | |||
594 | reg_cmpl_handler_end: | ||
595 | return ret; | ||
596 | } | ||
597 | |||
598 | static inline int is_ack_index_in_range(struct vnic_wq_copy *wq, | ||
599 | u16 request_out) | ||
600 | { | ||
601 | if (wq->to_clean_index <= wq->to_use_index) { | ||
602 | /* out of range, stale request_out index */ | ||
603 | if (request_out < wq->to_clean_index || | ||
604 | request_out >= wq->to_use_index) | ||
605 | return 0; | ||
606 | } else { | ||
607 | /* out of range, stale request_out index */ | ||
608 | if (request_out < wq->to_clean_index && | ||
609 | request_out >= wq->to_use_index) | ||
610 | return 0; | ||
611 | } | ||
612 | /* request_out index is in range */ | ||
613 | return 1; | ||
614 | } | ||
615 | |||
616 | |||
617 | /* | ||
618 | * Mark that ack received and store the Ack index. If there are multiple | ||
619 | * acks received before Tx thread cleans it up, the latest value will be | ||
620 | * used which is correct behavior. This state should be in the copy Wq | ||
621 | * instead of in the fnic | ||
622 | */ | ||
623 | static inline void fnic_fcpio_ack_handler(struct fnic *fnic, | ||
624 | unsigned int cq_index, | ||
625 | struct fcpio_fw_req *desc) | ||
626 | { | ||
627 | struct vnic_wq_copy *wq; | ||
628 | u16 request_out = desc->u.ack.request_out; | ||
629 | unsigned long flags; | ||
630 | |||
631 | /* mark the ack state */ | ||
632 | wq = &fnic->wq_copy[cq_index - fnic->raw_wq_count - fnic->rq_count]; | ||
633 | spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); | ||
634 | |||
635 | if (is_ack_index_in_range(wq, request_out)) { | ||
636 | fnic->fw_ack_index[0] = request_out; | ||
637 | fnic->fw_ack_recd[0] = 1; | ||
638 | } | ||
639 | spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); | ||
640 | } | ||
641 | |||
642 | /* | ||
643 | * fnic_fcpio_icmnd_cmpl_handler | ||
644 | * Routine to handle icmnd completions | ||
645 | */ | ||
646 | static void fnic_fcpio_icmnd_cmpl_handler(struct fnic *fnic, | ||
647 | struct fcpio_fw_req *desc) | ||
648 | { | ||
649 | u8 type; | ||
650 | u8 hdr_status; | ||
651 | struct fcpio_tag tag; | ||
652 | u32 id; | ||
653 | u64 xfer_len = 0; | ||
654 | struct fcpio_icmnd_cmpl *icmnd_cmpl; | ||
655 | struct fnic_io_req *io_req; | ||
656 | struct scsi_cmnd *sc; | ||
657 | unsigned long flags; | ||
658 | spinlock_t *io_lock; | ||
659 | |||
660 | /* Decode the cmpl description to get the io_req id */ | ||
661 | fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); | ||
662 | fcpio_tag_id_dec(&tag, &id); | ||
663 | |||
664 | if (id >= FNIC_MAX_IO_REQ) | ||
665 | return; | ||
666 | |||
667 | sc = scsi_host_find_tag(fnic->lport->host, id); | ||
668 | WARN_ON_ONCE(!sc); | ||
669 | if (!sc) | ||
670 | return; | ||
671 | |||
672 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
673 | spin_lock_irqsave(io_lock, flags); | ||
674 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
675 | WARN_ON_ONCE(!io_req); | ||
676 | if (!io_req) { | ||
677 | spin_unlock_irqrestore(io_lock, flags); | ||
678 | return; | ||
679 | } | ||
680 | |||
681 | /* firmware completed the io */ | ||
682 | io_req->io_completed = 1; | ||
683 | |||
684 | /* | ||
685 | * if SCSI-ML has already issued abort on this command, | ||
686 | * ignore completion of the IO. The abts path will clean it up | ||
687 | */ | ||
688 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { | ||
689 | spin_unlock_irqrestore(io_lock, flags); | ||
690 | return; | ||
691 | } | ||
692 | |||
693 | /* Mark the IO as complete */ | ||
694 | CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE; | ||
695 | |||
696 | icmnd_cmpl = &desc->u.icmnd_cmpl; | ||
697 | |||
698 | switch (hdr_status) { | ||
699 | case FCPIO_SUCCESS: | ||
700 | sc->result = (DID_OK << 16) | icmnd_cmpl->scsi_status; | ||
701 | xfer_len = scsi_bufflen(sc); | ||
702 | scsi_set_resid(sc, icmnd_cmpl->residual); | ||
703 | |||
704 | if (icmnd_cmpl->flags & FCPIO_ICMND_CMPL_RESID_UNDER) | ||
705 | xfer_len -= icmnd_cmpl->residual; | ||
706 | |||
707 | /* | ||
708 | * If queue_full, then try to reduce queue depth for all | ||
709 | * LUNS on the target. Todo: this should be accompanied | ||
710 | * by a periodic queue_depth rampup based on successful | ||
711 | * IO completion. | ||
712 | */ | ||
713 | if (icmnd_cmpl->scsi_status == QUEUE_FULL) { | ||
714 | struct scsi_device *t_sdev; | ||
715 | int qd = 0; | ||
716 | |||
717 | shost_for_each_device(t_sdev, sc->device->host) { | ||
718 | if (t_sdev->id != sc->device->id) | ||
719 | continue; | ||
720 | |||
721 | if (t_sdev->queue_depth > 1) { | ||
722 | qd = scsi_track_queue_full | ||
723 | (t_sdev, | ||
724 | t_sdev->queue_depth - 1); | ||
725 | if (qd == -1) | ||
726 | qd = t_sdev->host->cmd_per_lun; | ||
727 | shost_printk(KERN_INFO, | ||
728 | fnic->lport->host, | ||
729 | "scsi[%d:%d:%d:%d" | ||
730 | "] queue full detected," | ||
731 | "new depth = %d\n", | ||
732 | t_sdev->host->host_no, | ||
733 | t_sdev->channel, | ||
734 | t_sdev->id, t_sdev->lun, | ||
735 | t_sdev->queue_depth); | ||
736 | } | ||
737 | } | ||
738 | } | ||
739 | break; | ||
740 | |||
741 | case FCPIO_TIMEOUT: /* request was timed out */ | ||
742 | sc->result = (DID_TIME_OUT << 16) | icmnd_cmpl->scsi_status; | ||
743 | break; | ||
744 | |||
745 | case FCPIO_ABORTED: /* request was aborted */ | ||
746 | sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; | ||
747 | break; | ||
748 | |||
749 | case FCPIO_DATA_CNT_MISMATCH: /* recv/sent more/less data than exp. */ | ||
750 | scsi_set_resid(sc, icmnd_cmpl->residual); | ||
751 | sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; | ||
752 | break; | ||
753 | |||
754 | case FCPIO_OUT_OF_RESOURCE: /* out of resources to complete request */ | ||
755 | sc->result = (DID_REQUEUE << 16) | icmnd_cmpl->scsi_status; | ||
756 | break; | ||
757 | case FCPIO_INVALID_HEADER: /* header contains invalid data */ | ||
758 | case FCPIO_INVALID_PARAM: /* some parameter in request invalid */ | ||
759 | case FCPIO_REQ_NOT_SUPPORTED:/* request type is not supported */ | ||
760 | case FCPIO_IO_NOT_FOUND: /* requested I/O was not found */ | ||
761 | case FCPIO_SGL_INVALID: /* request was aborted due to sgl error */ | ||
762 | case FCPIO_MSS_INVALID: /* request was aborted due to mss error */ | ||
763 | case FCPIO_FW_ERR: /* request was terminated due fw error */ | ||
764 | default: | ||
765 | shost_printk(KERN_ERR, fnic->lport->host, "hdr status = %s\n", | ||
766 | fnic_fcpio_status_to_str(hdr_status)); | ||
767 | sc->result = (DID_ERROR << 16) | icmnd_cmpl->scsi_status; | ||
768 | break; | ||
769 | } | ||
770 | |||
771 | /* Break link with the SCSI command */ | ||
772 | CMD_SP(sc) = NULL; | ||
773 | |||
774 | spin_unlock_irqrestore(io_lock, flags); | ||
775 | |||
776 | fnic_release_ioreq_buf(fnic, io_req, sc); | ||
777 | |||
778 | mempool_free(io_req, fnic->io_req_pool); | ||
779 | |||
780 | if (sc->sc_data_direction == DMA_FROM_DEVICE) { | ||
781 | fnic->lport->host_stats.fcp_input_requests++; | ||
782 | fnic->fcp_input_bytes += xfer_len; | ||
783 | } else if (sc->sc_data_direction == DMA_TO_DEVICE) { | ||
784 | fnic->lport->host_stats.fcp_output_requests++; | ||
785 | fnic->fcp_output_bytes += xfer_len; | ||
786 | } else | ||
787 | fnic->lport->host_stats.fcp_control_requests++; | ||
788 | |||
789 | /* Call SCSI completion function to complete the IO */ | ||
790 | if (sc->scsi_done) | ||
791 | sc->scsi_done(sc); | ||
792 | |||
793 | } | ||
794 | |||
795 | /* fnic_fcpio_itmf_cmpl_handler | ||
796 | * Routine to handle itmf completions | ||
797 | */ | ||
798 | static void fnic_fcpio_itmf_cmpl_handler(struct fnic *fnic, | ||
799 | struct fcpio_fw_req *desc) | ||
800 | { | ||
801 | u8 type; | ||
802 | u8 hdr_status; | ||
803 | struct fcpio_tag tag; | ||
804 | u32 id; | ||
805 | struct scsi_cmnd *sc; | ||
806 | struct fnic_io_req *io_req; | ||
807 | unsigned long flags; | ||
808 | spinlock_t *io_lock; | ||
809 | |||
810 | fcpio_header_dec(&desc->hdr, &type, &hdr_status, &tag); | ||
811 | fcpio_tag_id_dec(&tag, &id); | ||
812 | |||
813 | if ((id & FNIC_TAG_MASK) >= FNIC_MAX_IO_REQ) | ||
814 | return; | ||
815 | |||
816 | sc = scsi_host_find_tag(fnic->lport->host, id & FNIC_TAG_MASK); | ||
817 | WARN_ON_ONCE(!sc); | ||
818 | if (!sc) | ||
819 | return; | ||
820 | |||
821 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
822 | spin_lock_irqsave(io_lock, flags); | ||
823 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
824 | WARN_ON_ONCE(!io_req); | ||
825 | if (!io_req) { | ||
826 | spin_unlock_irqrestore(io_lock, flags); | ||
827 | return; | ||
828 | } | ||
829 | |||
830 | if (id & FNIC_TAG_ABORT) { | ||
831 | /* Completion of abort cmd */ | ||
832 | if (CMD_STATE(sc) != FNIC_IOREQ_ABTS_PENDING) { | ||
833 | /* This is a late completion. Ignore it */ | ||
834 | spin_unlock_irqrestore(io_lock, flags); | ||
835 | return; | ||
836 | } | ||
837 | CMD_STATE(sc) = FNIC_IOREQ_ABTS_COMPLETE; | ||
838 | CMD_ABTS_STATUS(sc) = hdr_status; | ||
839 | |||
840 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
841 | "abts cmpl recd. id %d status %s\n", | ||
842 | (int)(id & FNIC_TAG_MASK), | ||
843 | fnic_fcpio_status_to_str(hdr_status)); | ||
844 | |||
845 | /* | ||
846 | * If scsi_eh thread is blocked waiting for abts to complete, | ||
847 | * signal completion to it. IO will be cleaned in the thread | ||
848 | * else clean it in this context | ||
849 | */ | ||
850 | if (io_req->abts_done) { | ||
851 | complete(io_req->abts_done); | ||
852 | spin_unlock_irqrestore(io_lock, flags); | ||
853 | } else { | ||
854 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
855 | "abts cmpl, completing IO\n"); | ||
856 | CMD_SP(sc) = NULL; | ||
857 | sc->result = (DID_ERROR << 16); | ||
858 | |||
859 | spin_unlock_irqrestore(io_lock, flags); | ||
860 | |||
861 | fnic_release_ioreq_buf(fnic, io_req, sc); | ||
862 | mempool_free(io_req, fnic->io_req_pool); | ||
863 | if (sc->scsi_done) | ||
864 | sc->scsi_done(sc); | ||
865 | } | ||
866 | |||
867 | } else if (id & FNIC_TAG_DEV_RST) { | ||
868 | /* Completion of device reset */ | ||
869 | CMD_LR_STATUS(sc) = hdr_status; | ||
870 | CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE; | ||
871 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
872 | "dev reset cmpl recd. id %d status %s\n", | ||
873 | (int)(id & FNIC_TAG_MASK), | ||
874 | fnic_fcpio_status_to_str(hdr_status)); | ||
875 | if (io_req->dr_done) | ||
876 | complete(io_req->dr_done); | ||
877 | spin_unlock_irqrestore(io_lock, flags); | ||
878 | |||
879 | } else { | ||
880 | shost_printk(KERN_ERR, fnic->lport->host, | ||
881 | "Unexpected itmf io state %s tag %x\n", | ||
882 | fnic_ioreq_state_to_str(CMD_STATE(sc)), id); | ||
883 | spin_unlock_irqrestore(io_lock, flags); | ||
884 | } | ||
885 | |||
886 | } | ||
887 | |||
888 | /* | ||
889 | * fnic_fcpio_cmpl_handler | ||
890 | * Routine to service the cq for wq_copy | ||
891 | */ | ||
892 | static int fnic_fcpio_cmpl_handler(struct vnic_dev *vdev, | ||
893 | unsigned int cq_index, | ||
894 | struct fcpio_fw_req *desc) | ||
895 | { | ||
896 | struct fnic *fnic = vnic_dev_priv(vdev); | ||
897 | int ret = 0; | ||
898 | |||
899 | switch (desc->hdr.type) { | ||
900 | case FCPIO_ACK: /* fw copied copy wq desc to its queue */ | ||
901 | fnic_fcpio_ack_handler(fnic, cq_index, desc); | ||
902 | break; | ||
903 | |||
904 | case FCPIO_ICMND_CMPL: /* fw completed a command */ | ||
905 | fnic_fcpio_icmnd_cmpl_handler(fnic, desc); | ||
906 | break; | ||
907 | |||
908 | case FCPIO_ITMF_CMPL: /* fw completed itmf (abort cmd, lun reset)*/ | ||
909 | fnic_fcpio_itmf_cmpl_handler(fnic, desc); | ||
910 | break; | ||
911 | |||
912 | case FCPIO_FLOGI_REG_CMPL: /* fw completed flogi_reg */ | ||
913 | ret = fnic_fcpio_flogi_reg_cmpl_handler(fnic, desc); | ||
914 | break; | ||
915 | |||
916 | case FCPIO_RESET_CMPL: /* fw completed reset */ | ||
917 | ret = fnic_fcpio_fw_reset_cmpl_handler(fnic, desc); | ||
918 | break; | ||
919 | |||
920 | default: | ||
921 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
922 | "firmware completion type %d\n", | ||
923 | desc->hdr.type); | ||
924 | break; | ||
925 | } | ||
926 | |||
927 | return ret; | ||
928 | } | ||
929 | |||
930 | /* | ||
931 | * fnic_wq_copy_cmpl_handler | ||
932 | * Routine to process wq copy | ||
933 | */ | ||
934 | int fnic_wq_copy_cmpl_handler(struct fnic *fnic, int copy_work_to_do) | ||
935 | { | ||
936 | unsigned int wq_work_done = 0; | ||
937 | unsigned int i, cq_index; | ||
938 | unsigned int cur_work_done; | ||
939 | |||
940 | for (i = 0; i < fnic->wq_copy_count; i++) { | ||
941 | cq_index = i + fnic->raw_wq_count + fnic->rq_count; | ||
942 | cur_work_done = vnic_cq_copy_service(&fnic->cq[cq_index], | ||
943 | fnic_fcpio_cmpl_handler, | ||
944 | copy_work_to_do); | ||
945 | wq_work_done += cur_work_done; | ||
946 | } | ||
947 | return wq_work_done; | ||
948 | } | ||
949 | |||
950 | static void fnic_cleanup_io(struct fnic *fnic, int exclude_id) | ||
951 | { | ||
952 | unsigned int i; | ||
953 | struct fnic_io_req *io_req; | ||
954 | unsigned long flags = 0; | ||
955 | struct scsi_cmnd *sc; | ||
956 | spinlock_t *io_lock; | ||
957 | |||
958 | for (i = 0; i < FNIC_MAX_IO_REQ; i++) { | ||
959 | if (i == exclude_id) | ||
960 | continue; | ||
961 | |||
962 | sc = scsi_host_find_tag(fnic->lport->host, i); | ||
963 | if (!sc) | ||
964 | continue; | ||
965 | |||
966 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
967 | spin_lock_irqsave(io_lock, flags); | ||
968 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
969 | if (!io_req) { | ||
970 | spin_unlock_irqrestore(io_lock, flags); | ||
971 | goto cleanup_scsi_cmd; | ||
972 | } | ||
973 | |||
974 | CMD_SP(sc) = NULL; | ||
975 | |||
976 | spin_unlock_irqrestore(io_lock, flags); | ||
977 | |||
978 | /* | ||
979 | * If there is a scsi_cmnd associated with this io_req, then | ||
980 | * free the corresponding state | ||
981 | */ | ||
982 | fnic_release_ioreq_buf(fnic, io_req, sc); | ||
983 | mempool_free(io_req, fnic->io_req_pool); | ||
984 | |||
985 | cleanup_scsi_cmd: | ||
986 | sc->result = DID_TRANSPORT_DISRUPTED << 16; | ||
987 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "fnic_cleanup_io:" | ||
988 | " DID_TRANSPORT_DISRUPTED\n"); | ||
989 | |||
990 | /* Complete the command to SCSI */ | ||
991 | if (sc->scsi_done) | ||
992 | sc->scsi_done(sc); | ||
993 | } | ||
994 | } | ||
995 | |||
996 | void fnic_wq_copy_cleanup_handler(struct vnic_wq_copy *wq, | ||
997 | struct fcpio_host_req *desc) | ||
998 | { | ||
999 | u32 id; | ||
1000 | struct fnic *fnic = vnic_dev_priv(wq->vdev); | ||
1001 | struct fnic_io_req *io_req; | ||
1002 | struct scsi_cmnd *sc; | ||
1003 | unsigned long flags; | ||
1004 | spinlock_t *io_lock; | ||
1005 | |||
1006 | /* get the tag reference */ | ||
1007 | fcpio_tag_id_dec(&desc->hdr.tag, &id); | ||
1008 | id &= FNIC_TAG_MASK; | ||
1009 | |||
1010 | if (id >= FNIC_MAX_IO_REQ) | ||
1011 | return; | ||
1012 | |||
1013 | sc = scsi_host_find_tag(fnic->lport->host, id); | ||
1014 | if (!sc) | ||
1015 | return; | ||
1016 | |||
1017 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
1018 | spin_lock_irqsave(io_lock, flags); | ||
1019 | |||
1020 | /* Get the IO context which this desc refers to */ | ||
1021 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1022 | |||
1023 | /* fnic interrupts are turned off by now */ | ||
1024 | |||
1025 | if (!io_req) { | ||
1026 | spin_unlock_irqrestore(io_lock, flags); | ||
1027 | goto wq_copy_cleanup_scsi_cmd; | ||
1028 | } | ||
1029 | |||
1030 | CMD_SP(sc) = NULL; | ||
1031 | |||
1032 | spin_unlock_irqrestore(io_lock, flags); | ||
1033 | |||
1034 | fnic_release_ioreq_buf(fnic, io_req, sc); | ||
1035 | mempool_free(io_req, fnic->io_req_pool); | ||
1036 | |||
1037 | wq_copy_cleanup_scsi_cmd: | ||
1038 | sc->result = DID_NO_CONNECT << 16; | ||
1039 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "wq_copy_cleanup_handler:" | ||
1040 | " DID_NO_CONNECT\n"); | ||
1041 | |||
1042 | if (sc->scsi_done) | ||
1043 | sc->scsi_done(sc); | ||
1044 | } | ||
1045 | |||
1046 | static inline int fnic_queue_abort_io_req(struct fnic *fnic, int tag, | ||
1047 | u32 task_req, u8 *fc_lun, | ||
1048 | struct fnic_io_req *io_req) | ||
1049 | { | ||
1050 | struct vnic_wq_copy *wq = &fnic->wq_copy[0]; | ||
1051 | unsigned long flags; | ||
1052 | |||
1053 | spin_lock_irqsave(&fnic->wq_copy_lock[0], flags); | ||
1054 | |||
1055 | if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) | ||
1056 | free_wq_copy_descs(fnic, wq); | ||
1057 | |||
1058 | if (!vnic_wq_copy_desc_avail(wq)) { | ||
1059 | spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); | ||
1060 | return 1; | ||
1061 | } | ||
1062 | fnic_queue_wq_copy_desc_itmf(wq, tag | FNIC_TAG_ABORT, | ||
1063 | 0, task_req, tag, fc_lun, io_req->port_id, | ||
1064 | fnic->config.ra_tov, fnic->config.ed_tov); | ||
1065 | |||
1066 | spin_unlock_irqrestore(&fnic->wq_copy_lock[0], flags); | ||
1067 | return 0; | ||
1068 | } | ||
1069 | |||
1070 | void fnic_rport_exch_reset(struct fnic *fnic, u32 port_id) | ||
1071 | { | ||
1072 | int tag; | ||
1073 | struct fnic_io_req *io_req; | ||
1074 | spinlock_t *io_lock; | ||
1075 | unsigned long flags; | ||
1076 | struct scsi_cmnd *sc; | ||
1077 | struct scsi_lun fc_lun; | ||
1078 | enum fnic_ioreq_state old_ioreq_state; | ||
1079 | |||
1080 | FNIC_SCSI_DBG(KERN_DEBUG, | ||
1081 | fnic->lport->host, | ||
1082 | "fnic_rport_reset_exch called portid 0x%06x\n", | ||
1083 | port_id); | ||
1084 | |||
1085 | if (fnic->in_remove) | ||
1086 | return; | ||
1087 | |||
1088 | for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) { | ||
1089 | sc = scsi_host_find_tag(fnic->lport->host, tag); | ||
1090 | if (!sc) | ||
1091 | continue; | ||
1092 | |||
1093 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
1094 | spin_lock_irqsave(io_lock, flags); | ||
1095 | |||
1096 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1097 | |||
1098 | if (!io_req || io_req->port_id != port_id) { | ||
1099 | spin_unlock_irqrestore(io_lock, flags); | ||
1100 | continue; | ||
1101 | } | ||
1102 | |||
1103 | /* | ||
1104 | * Found IO that is still pending with firmware and | ||
1105 | * belongs to rport that went away | ||
1106 | */ | ||
1107 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { | ||
1108 | spin_unlock_irqrestore(io_lock, flags); | ||
1109 | continue; | ||
1110 | } | ||
1111 | old_ioreq_state = CMD_STATE(sc); | ||
1112 | CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; | ||
1113 | CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; | ||
1114 | |||
1115 | BUG_ON(io_req->abts_done); | ||
1116 | |||
1117 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
1118 | "fnic_rport_reset_exch: Issuing abts\n"); | ||
1119 | |||
1120 | spin_unlock_irqrestore(io_lock, flags); | ||
1121 | |||
1122 | /* Now queue the abort command to firmware */ | ||
1123 | int_to_scsilun(sc->device->lun, &fc_lun); | ||
1124 | |||
1125 | if (fnic_queue_abort_io_req(fnic, tag, | ||
1126 | FCPIO_ITMF_ABT_TASK_TERM, | ||
1127 | fc_lun.scsi_lun, io_req)) { | ||
1128 | /* | ||
1129 | * Revert the cmd state back to old state, if | ||
1130 | * it hasnt changed in between. This cmd will get | ||
1131 | * aborted later by scsi_eh, or cleaned up during | ||
1132 | * lun reset | ||
1133 | */ | ||
1134 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
1135 | |||
1136 | spin_lock_irqsave(io_lock, flags); | ||
1137 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) | ||
1138 | CMD_STATE(sc) = old_ioreq_state; | ||
1139 | spin_unlock_irqrestore(io_lock, flags); | ||
1140 | } | ||
1141 | } | ||
1142 | |||
1143 | } | ||
1144 | |||
1145 | void fnic_terminate_rport_io(struct fc_rport *rport) | ||
1146 | { | ||
1147 | int tag; | ||
1148 | struct fnic_io_req *io_req; | ||
1149 | spinlock_t *io_lock; | ||
1150 | unsigned long flags; | ||
1151 | struct scsi_cmnd *sc; | ||
1152 | struct scsi_lun fc_lun; | ||
1153 | struct fc_rport_libfc_priv *rdata = rport->dd_data; | ||
1154 | struct fc_lport *lport = rdata->local_port; | ||
1155 | struct fnic *fnic = lport_priv(lport); | ||
1156 | struct fc_rport *cmd_rport; | ||
1157 | enum fnic_ioreq_state old_ioreq_state; | ||
1158 | |||
1159 | FNIC_SCSI_DBG(KERN_DEBUG, | ||
1160 | fnic->lport->host, "fnic_terminate_rport_io called" | ||
1161 | " wwpn 0x%llx, wwnn0x%llx, portid 0x%06x\n", | ||
1162 | rport->port_name, rport->node_name, | ||
1163 | rport->port_id); | ||
1164 | |||
1165 | if (fnic->in_remove) | ||
1166 | return; | ||
1167 | |||
1168 | for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) { | ||
1169 | sc = scsi_host_find_tag(fnic->lport->host, tag); | ||
1170 | if (!sc) | ||
1171 | continue; | ||
1172 | |||
1173 | cmd_rport = starget_to_rport(scsi_target(sc->device)); | ||
1174 | if (rport != cmd_rport) | ||
1175 | continue; | ||
1176 | |||
1177 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
1178 | spin_lock_irqsave(io_lock, flags); | ||
1179 | |||
1180 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1181 | |||
1182 | if (!io_req || rport != cmd_rport) { | ||
1183 | spin_unlock_irqrestore(io_lock, flags); | ||
1184 | continue; | ||
1185 | } | ||
1186 | |||
1187 | /* | ||
1188 | * Found IO that is still pending with firmware and | ||
1189 | * belongs to rport that went away | ||
1190 | */ | ||
1191 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { | ||
1192 | spin_unlock_irqrestore(io_lock, flags); | ||
1193 | continue; | ||
1194 | } | ||
1195 | old_ioreq_state = CMD_STATE(sc); | ||
1196 | CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; | ||
1197 | CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; | ||
1198 | |||
1199 | BUG_ON(io_req->abts_done); | ||
1200 | |||
1201 | FNIC_SCSI_DBG(KERN_DEBUG, | ||
1202 | fnic->lport->host, | ||
1203 | "fnic_terminate_rport_io: Issuing abts\n"); | ||
1204 | |||
1205 | spin_unlock_irqrestore(io_lock, flags); | ||
1206 | |||
1207 | /* Now queue the abort command to firmware */ | ||
1208 | int_to_scsilun(sc->device->lun, &fc_lun); | ||
1209 | |||
1210 | if (fnic_queue_abort_io_req(fnic, tag, | ||
1211 | FCPIO_ITMF_ABT_TASK_TERM, | ||
1212 | fc_lun.scsi_lun, io_req)) { | ||
1213 | /* | ||
1214 | * Revert the cmd state back to old state, if | ||
1215 | * it hasnt changed in between. This cmd will get | ||
1216 | * aborted later by scsi_eh, or cleaned up during | ||
1217 | * lun reset | ||
1218 | */ | ||
1219 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
1220 | |||
1221 | spin_lock_irqsave(io_lock, flags); | ||
1222 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) | ||
1223 | CMD_STATE(sc) = old_ioreq_state; | ||
1224 | spin_unlock_irqrestore(io_lock, flags); | ||
1225 | } | ||
1226 | } | ||
1227 | |||
1228 | } | ||
1229 | |||
1230 | static void fnic_block_error_handler(struct scsi_cmnd *sc) | ||
1231 | { | ||
1232 | struct Scsi_Host *shost = sc->device->host; | ||
1233 | struct fc_rport *rport = starget_to_rport(scsi_target(sc->device)); | ||
1234 | unsigned long flags; | ||
1235 | |||
1236 | spin_lock_irqsave(shost->host_lock, flags); | ||
1237 | while (rport->port_state == FC_PORTSTATE_BLOCKED) { | ||
1238 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1239 | msleep(1000); | ||
1240 | spin_lock_irqsave(shost->host_lock, flags); | ||
1241 | } | ||
1242 | spin_unlock_irqrestore(shost->host_lock, flags); | ||
1243 | |||
1244 | } | ||
1245 | |||
1246 | /* | ||
1247 | * This function is exported to SCSI for sending abort cmnds. | ||
1248 | * A SCSI IO is represented by a io_req in the driver. | ||
1249 | * The ioreq is linked to the SCSI Cmd, thus a link with the ULP's IO. | ||
1250 | */ | ||
1251 | int fnic_abort_cmd(struct scsi_cmnd *sc) | ||
1252 | { | ||
1253 | struct fc_lport *lp; | ||
1254 | struct fnic *fnic; | ||
1255 | struct fnic_io_req *io_req; | ||
1256 | struct fc_rport *rport; | ||
1257 | spinlock_t *io_lock; | ||
1258 | unsigned long flags; | ||
1259 | int ret = SUCCESS; | ||
1260 | u32 task_req; | ||
1261 | struct scsi_lun fc_lun; | ||
1262 | DECLARE_COMPLETION_ONSTACK(tm_done); | ||
1263 | |||
1264 | /* Wait for rport to unblock */ | ||
1265 | fnic_block_error_handler(sc); | ||
1266 | |||
1267 | /* Get local-port, check ready and link up */ | ||
1268 | lp = shost_priv(sc->device->host); | ||
1269 | |||
1270 | fnic = lport_priv(lp); | ||
1271 | FNIC_SCSI_DBG(KERN_DEBUG, | ||
1272 | fnic->lport->host, | ||
1273 | "Abort Cmd called FCID 0x%x, LUN 0x%x TAG %d\n", | ||
1274 | (starget_to_rport(scsi_target(sc->device)))->port_id, | ||
1275 | sc->device->lun, sc->request->tag); | ||
1276 | |||
1277 | if (lp->state != LPORT_ST_READY || !(lp->link_up)) { | ||
1278 | ret = FAILED; | ||
1279 | goto fnic_abort_cmd_end; | ||
1280 | } | ||
1281 | |||
1282 | /* | ||
1283 | * Avoid a race between SCSI issuing the abort and the device | ||
1284 | * completing the command. | ||
1285 | * | ||
1286 | * If the command is already completed by the fw cmpl code, | ||
1287 | * we just return SUCCESS from here. This means that the abort | ||
1288 | * succeeded. In the SCSI ML, since the timeout for command has | ||
1289 | * happened, the completion wont actually complete the command | ||
1290 | * and it will be considered as an aborted command | ||
1291 | * | ||
1292 | * The CMD_SP will not be cleared except while holding io_req_lock. | ||
1293 | */ | ||
1294 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
1295 | spin_lock_irqsave(io_lock, flags); | ||
1296 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1297 | if (!io_req) { | ||
1298 | spin_unlock_irqrestore(io_lock, flags); | ||
1299 | goto fnic_abort_cmd_end; | ||
1300 | } | ||
1301 | |||
1302 | io_req->abts_done = &tm_done; | ||
1303 | |||
1304 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { | ||
1305 | spin_unlock_irqrestore(io_lock, flags); | ||
1306 | goto wait_pending; | ||
1307 | } | ||
1308 | /* | ||
1309 | * Command is still pending, need to abort it | ||
1310 | * If the firmware completes the command after this point, | ||
1311 | * the completion wont be done till mid-layer, since abort | ||
1312 | * has already started. | ||
1313 | */ | ||
1314 | CMD_STATE(sc) = FNIC_IOREQ_ABTS_PENDING; | ||
1315 | CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; | ||
1316 | |||
1317 | spin_unlock_irqrestore(io_lock, flags); | ||
1318 | |||
1319 | /* | ||
1320 | * Check readiness of the remote port. If the path to remote | ||
1321 | * port is up, then send abts to the remote port to terminate | ||
1322 | * the IO. Else, just locally terminate the IO in the firmware | ||
1323 | */ | ||
1324 | rport = starget_to_rport(scsi_target(sc->device)); | ||
1325 | if (fc_remote_port_chkready(rport) == 0) | ||
1326 | task_req = FCPIO_ITMF_ABT_TASK; | ||
1327 | else | ||
1328 | task_req = FCPIO_ITMF_ABT_TASK_TERM; | ||
1329 | |||
1330 | /* Now queue the abort command to firmware */ | ||
1331 | int_to_scsilun(sc->device->lun, &fc_lun); | ||
1332 | |||
1333 | if (fnic_queue_abort_io_req(fnic, sc->request->tag, task_req, | ||
1334 | fc_lun.scsi_lun, io_req)) { | ||
1335 | spin_lock_irqsave(io_lock, flags); | ||
1336 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1337 | if (io_req) | ||
1338 | io_req->abts_done = NULL; | ||
1339 | spin_unlock_irqrestore(io_lock, flags); | ||
1340 | ret = FAILED; | ||
1341 | goto fnic_abort_cmd_end; | ||
1342 | } | ||
1343 | |||
1344 | /* | ||
1345 | * We queued an abort IO, wait for its completion. | ||
1346 | * Once the firmware completes the abort command, it will | ||
1347 | * wake up this thread. | ||
1348 | */ | ||
1349 | wait_pending: | ||
1350 | wait_for_completion_timeout(&tm_done, | ||
1351 | msecs_to_jiffies | ||
1352 | (2 * fnic->config.ra_tov + | ||
1353 | fnic->config.ed_tov)); | ||
1354 | |||
1355 | /* Check the abort status */ | ||
1356 | spin_lock_irqsave(io_lock, flags); | ||
1357 | |||
1358 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1359 | if (!io_req) { | ||
1360 | spin_unlock_irqrestore(io_lock, flags); | ||
1361 | ret = FAILED; | ||
1362 | goto fnic_abort_cmd_end; | ||
1363 | } | ||
1364 | io_req->abts_done = NULL; | ||
1365 | |||
1366 | /* fw did not complete abort, timed out */ | ||
1367 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { | ||
1368 | spin_unlock_irqrestore(io_lock, flags); | ||
1369 | ret = FAILED; | ||
1370 | goto fnic_abort_cmd_end; | ||
1371 | } | ||
1372 | |||
1373 | /* | ||
1374 | * firmware completed the abort, check the status, | ||
1375 | * free the io_req irrespective of failure or success | ||
1376 | */ | ||
1377 | if (CMD_ABTS_STATUS(sc) != FCPIO_SUCCESS) | ||
1378 | ret = FAILED; | ||
1379 | |||
1380 | CMD_SP(sc) = NULL; | ||
1381 | |||
1382 | spin_unlock_irqrestore(io_lock, flags); | ||
1383 | |||
1384 | fnic_release_ioreq_buf(fnic, io_req, sc); | ||
1385 | mempool_free(io_req, fnic->io_req_pool); | ||
1386 | |||
1387 | fnic_abort_cmd_end: | ||
1388 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
1389 | "Returning from abort cmd %s\n", | ||
1390 | (ret == SUCCESS) ? | ||
1391 | "SUCCESS" : "FAILED"); | ||
1392 | return ret; | ||
1393 | } | ||
1394 | |||
1395 | static inline int fnic_queue_dr_io_req(struct fnic *fnic, | ||
1396 | struct scsi_cmnd *sc, | ||
1397 | struct fnic_io_req *io_req) | ||
1398 | { | ||
1399 | struct vnic_wq_copy *wq = &fnic->wq_copy[0]; | ||
1400 | struct scsi_lun fc_lun; | ||
1401 | int ret = 0; | ||
1402 | unsigned long intr_flags; | ||
1403 | |||
1404 | spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags); | ||
1405 | |||
1406 | if (vnic_wq_copy_desc_avail(wq) <= fnic->wq_copy_desc_low[0]) | ||
1407 | free_wq_copy_descs(fnic, wq); | ||
1408 | |||
1409 | if (!vnic_wq_copy_desc_avail(wq)) { | ||
1410 | ret = -EAGAIN; | ||
1411 | goto lr_io_req_end; | ||
1412 | } | ||
1413 | |||
1414 | /* fill in the lun info */ | ||
1415 | int_to_scsilun(sc->device->lun, &fc_lun); | ||
1416 | |||
1417 | fnic_queue_wq_copy_desc_itmf(wq, sc->request->tag | FNIC_TAG_DEV_RST, | ||
1418 | 0, FCPIO_ITMF_LUN_RESET, SCSI_NO_TAG, | ||
1419 | fc_lun.scsi_lun, io_req->port_id, | ||
1420 | fnic->config.ra_tov, fnic->config.ed_tov); | ||
1421 | |||
1422 | lr_io_req_end: | ||
1423 | spin_unlock_irqrestore(&fnic->wq_copy_lock[0], intr_flags); | ||
1424 | |||
1425 | return ret; | ||
1426 | } | ||
1427 | |||
1428 | /* | ||
1429 | * Clean up any pending aborts on the lun | ||
1430 | * For each outstanding IO on this lun, whose abort is not completed by fw, | ||
1431 | * issue a local abort. Wait for abort to complete. Return 0 if all commands | ||
1432 | * successfully aborted, 1 otherwise | ||
1433 | */ | ||
1434 | static int fnic_clean_pending_aborts(struct fnic *fnic, | ||
1435 | struct scsi_cmnd *lr_sc) | ||
1436 | { | ||
1437 | int tag; | ||
1438 | struct fnic_io_req *io_req; | ||
1439 | spinlock_t *io_lock; | ||
1440 | unsigned long flags; | ||
1441 | int ret = 0; | ||
1442 | struct scsi_cmnd *sc; | ||
1443 | struct fc_rport *rport; | ||
1444 | struct scsi_lun fc_lun; | ||
1445 | struct scsi_device *lun_dev = lr_sc->device; | ||
1446 | DECLARE_COMPLETION_ONSTACK(tm_done); | ||
1447 | |||
1448 | for (tag = 0; tag < FNIC_MAX_IO_REQ; tag++) { | ||
1449 | sc = scsi_host_find_tag(fnic->lport->host, tag); | ||
1450 | /* | ||
1451 | * ignore this lun reset cmd or cmds that do not belong to | ||
1452 | * this lun | ||
1453 | */ | ||
1454 | if (!sc || sc == lr_sc || sc->device != lun_dev) | ||
1455 | continue; | ||
1456 | |||
1457 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
1458 | spin_lock_irqsave(io_lock, flags); | ||
1459 | |||
1460 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1461 | |||
1462 | if (!io_req || sc->device != lun_dev) { | ||
1463 | spin_unlock_irqrestore(io_lock, flags); | ||
1464 | continue; | ||
1465 | } | ||
1466 | |||
1467 | /* | ||
1468 | * Found IO that is still pending with firmware and | ||
1469 | * belongs to the LUN that we are resetting | ||
1470 | */ | ||
1471 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
1472 | "Found IO in %s on lun\n", | ||
1473 | fnic_ioreq_state_to_str(CMD_STATE(sc))); | ||
1474 | |||
1475 | BUG_ON(CMD_STATE(sc) != FNIC_IOREQ_ABTS_PENDING); | ||
1476 | |||
1477 | CMD_ABTS_STATUS(sc) = FCPIO_INVALID_CODE; | ||
1478 | io_req->abts_done = &tm_done; | ||
1479 | spin_unlock_irqrestore(io_lock, flags); | ||
1480 | |||
1481 | /* Now queue the abort command to firmware */ | ||
1482 | int_to_scsilun(sc->device->lun, &fc_lun); | ||
1483 | rport = starget_to_rport(scsi_target(sc->device)); | ||
1484 | |||
1485 | if (fnic_queue_abort_io_req(fnic, tag, | ||
1486 | FCPIO_ITMF_ABT_TASK_TERM, | ||
1487 | fc_lun.scsi_lun, io_req)) { | ||
1488 | spin_lock_irqsave(io_lock, flags); | ||
1489 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1490 | if (io_req) | ||
1491 | io_req->abts_done = NULL; | ||
1492 | spin_unlock_irqrestore(io_lock, flags); | ||
1493 | ret = 1; | ||
1494 | goto clean_pending_aborts_end; | ||
1495 | } | ||
1496 | |||
1497 | wait_for_completion_timeout(&tm_done, | ||
1498 | msecs_to_jiffies | ||
1499 | (fnic->config.ed_tov)); | ||
1500 | |||
1501 | /* Recheck cmd state to check if it is now aborted */ | ||
1502 | spin_lock_irqsave(io_lock, flags); | ||
1503 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1504 | if (!io_req) { | ||
1505 | spin_unlock_irqrestore(io_lock, flags); | ||
1506 | ret = 1; | ||
1507 | goto clean_pending_aborts_end; | ||
1508 | } | ||
1509 | |||
1510 | io_req->abts_done = NULL; | ||
1511 | |||
1512 | /* if abort is still pending with fw, fail */ | ||
1513 | if (CMD_STATE(sc) == FNIC_IOREQ_ABTS_PENDING) { | ||
1514 | spin_unlock_irqrestore(io_lock, flags); | ||
1515 | ret = 1; | ||
1516 | goto clean_pending_aborts_end; | ||
1517 | } | ||
1518 | CMD_SP(sc) = NULL; | ||
1519 | spin_unlock_irqrestore(io_lock, flags); | ||
1520 | |||
1521 | fnic_release_ioreq_buf(fnic, io_req, sc); | ||
1522 | mempool_free(io_req, fnic->io_req_pool); | ||
1523 | } | ||
1524 | |||
1525 | clean_pending_aborts_end: | ||
1526 | return ret; | ||
1527 | } | ||
1528 | |||
1529 | /* | ||
1530 | * SCSI Eh thread issues a Lun Reset when one or more commands on a LUN | ||
1531 | * fail to get aborted. It calls driver's eh_device_reset with a SCSI command | ||
1532 | * on the LUN. | ||
1533 | */ | ||
1534 | int fnic_device_reset(struct scsi_cmnd *sc) | ||
1535 | { | ||
1536 | struct fc_lport *lp; | ||
1537 | struct fnic *fnic; | ||
1538 | struct fnic_io_req *io_req; | ||
1539 | struct fc_rport *rport; | ||
1540 | int status; | ||
1541 | int ret = FAILED; | ||
1542 | spinlock_t *io_lock; | ||
1543 | unsigned long flags; | ||
1544 | DECLARE_COMPLETION_ONSTACK(tm_done); | ||
1545 | |||
1546 | /* Wait for rport to unblock */ | ||
1547 | fnic_block_error_handler(sc); | ||
1548 | |||
1549 | /* Get local-port, check ready and link up */ | ||
1550 | lp = shost_priv(sc->device->host); | ||
1551 | |||
1552 | fnic = lport_priv(lp); | ||
1553 | FNIC_SCSI_DBG(KERN_DEBUG, | ||
1554 | fnic->lport->host, | ||
1555 | "Device reset called FCID 0x%x, LUN 0x%x\n", | ||
1556 | (starget_to_rport(scsi_target(sc->device)))->port_id, | ||
1557 | sc->device->lun); | ||
1558 | |||
1559 | |||
1560 | if (lp->state != LPORT_ST_READY || !(lp->link_up)) | ||
1561 | goto fnic_device_reset_end; | ||
1562 | |||
1563 | /* Check if remote port up */ | ||
1564 | rport = starget_to_rport(scsi_target(sc->device)); | ||
1565 | if (fc_remote_port_chkready(rport)) | ||
1566 | goto fnic_device_reset_end; | ||
1567 | |||
1568 | io_lock = fnic_io_lock_hash(fnic, sc); | ||
1569 | spin_lock_irqsave(io_lock, flags); | ||
1570 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1571 | |||
1572 | /* | ||
1573 | * If there is a io_req attached to this command, then use it, | ||
1574 | * else allocate a new one. | ||
1575 | */ | ||
1576 | if (!io_req) { | ||
1577 | io_req = mempool_alloc(fnic->io_req_pool, GFP_ATOMIC); | ||
1578 | if (!io_req) { | ||
1579 | spin_unlock_irqrestore(io_lock, flags); | ||
1580 | goto fnic_device_reset_end; | ||
1581 | } | ||
1582 | memset(io_req, 0, sizeof(*io_req)); | ||
1583 | io_req->port_id = rport->port_id; | ||
1584 | CMD_SP(sc) = (char *)io_req; | ||
1585 | } | ||
1586 | io_req->dr_done = &tm_done; | ||
1587 | CMD_STATE(sc) = FNIC_IOREQ_CMD_PENDING; | ||
1588 | CMD_LR_STATUS(sc) = FCPIO_INVALID_CODE; | ||
1589 | spin_unlock_irqrestore(io_lock, flags); | ||
1590 | |||
1591 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, "TAG %d\n", | ||
1592 | sc->request->tag); | ||
1593 | |||
1594 | /* | ||
1595 | * issue the device reset, if enqueue failed, clean up the ioreq | ||
1596 | * and break assoc with scsi cmd | ||
1597 | */ | ||
1598 | if (fnic_queue_dr_io_req(fnic, sc, io_req)) { | ||
1599 | spin_lock_irqsave(io_lock, flags); | ||
1600 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1601 | if (io_req) | ||
1602 | io_req->dr_done = NULL; | ||
1603 | goto fnic_device_reset_clean; | ||
1604 | } | ||
1605 | |||
1606 | /* | ||
1607 | * Wait on the local completion for LUN reset. The io_req may be | ||
1608 | * freed while we wait since we hold no lock. | ||
1609 | */ | ||
1610 | wait_for_completion_timeout(&tm_done, | ||
1611 | msecs_to_jiffies(FNIC_LUN_RESET_TIMEOUT)); | ||
1612 | |||
1613 | spin_lock_irqsave(io_lock, flags); | ||
1614 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1615 | if (!io_req) { | ||
1616 | spin_unlock_irqrestore(io_lock, flags); | ||
1617 | goto fnic_device_reset_end; | ||
1618 | } | ||
1619 | io_req->dr_done = NULL; | ||
1620 | |||
1621 | status = CMD_LR_STATUS(sc); | ||
1622 | spin_unlock_irqrestore(io_lock, flags); | ||
1623 | |||
1624 | /* | ||
1625 | * If lun reset not completed, bail out with failed. io_req | ||
1626 | * gets cleaned up during higher levels of EH | ||
1627 | */ | ||
1628 | if (status == FCPIO_INVALID_CODE) { | ||
1629 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
1630 | "Device reset timed out\n"); | ||
1631 | goto fnic_device_reset_end; | ||
1632 | } | ||
1633 | |||
1634 | /* Completed, but not successful, clean up the io_req, return fail */ | ||
1635 | if (status != FCPIO_SUCCESS) { | ||
1636 | spin_lock_irqsave(io_lock, flags); | ||
1637 | FNIC_SCSI_DBG(KERN_DEBUG, | ||
1638 | fnic->lport->host, | ||
1639 | "Device reset completed - failed\n"); | ||
1640 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1641 | goto fnic_device_reset_clean; | ||
1642 | } | ||
1643 | |||
1644 | /* | ||
1645 | * Clean up any aborts on this lun that have still not | ||
1646 | * completed. If any of these fail, then LUN reset fails. | ||
1647 | * clean_pending_aborts cleans all cmds on this lun except | ||
1648 | * the lun reset cmd. If all cmds get cleaned, the lun reset | ||
1649 | * succeeds | ||
1650 | */ | ||
1651 | if (fnic_clean_pending_aborts(fnic, sc)) { | ||
1652 | spin_lock_irqsave(io_lock, flags); | ||
1653 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1654 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
1655 | "Device reset failed" | ||
1656 | " since could not abort all IOs\n"); | ||
1657 | goto fnic_device_reset_clean; | ||
1658 | } | ||
1659 | |||
1660 | /* Clean lun reset command */ | ||
1661 | spin_lock_irqsave(io_lock, flags); | ||
1662 | io_req = (struct fnic_io_req *)CMD_SP(sc); | ||
1663 | if (io_req) | ||
1664 | /* Completed, and successful */ | ||
1665 | ret = SUCCESS; | ||
1666 | |||
1667 | fnic_device_reset_clean: | ||
1668 | if (io_req) | ||
1669 | CMD_SP(sc) = NULL; | ||
1670 | |||
1671 | spin_unlock_irqrestore(io_lock, flags); | ||
1672 | |||
1673 | if (io_req) { | ||
1674 | fnic_release_ioreq_buf(fnic, io_req, sc); | ||
1675 | mempool_free(io_req, fnic->io_req_pool); | ||
1676 | } | ||
1677 | |||
1678 | fnic_device_reset_end: | ||
1679 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
1680 | "Returning from device reset %s\n", | ||
1681 | (ret == SUCCESS) ? | ||
1682 | "SUCCESS" : "FAILED"); | ||
1683 | return ret; | ||
1684 | } | ||
1685 | |||
1686 | /* Clean up all IOs, clean up libFC local port */ | ||
1687 | int fnic_reset(struct Scsi_Host *shost) | ||
1688 | { | ||
1689 | struct fc_lport *lp; | ||
1690 | struct fnic *fnic; | ||
1691 | int ret = SUCCESS; | ||
1692 | |||
1693 | lp = shost_priv(shost); | ||
1694 | fnic = lport_priv(lp); | ||
1695 | |||
1696 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
1697 | "fnic_reset called\n"); | ||
1698 | |||
1699 | /* | ||
1700 | * Reset local port, this will clean up libFC exchanges, | ||
1701 | * reset remote port sessions, and if link is up, begin flogi | ||
1702 | */ | ||
1703 | if (lp->tt.lport_reset(lp)) | ||
1704 | ret = FAILED; | ||
1705 | |||
1706 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
1707 | "Returning from fnic reset %s\n", | ||
1708 | (ret == SUCCESS) ? | ||
1709 | "SUCCESS" : "FAILED"); | ||
1710 | |||
1711 | return ret; | ||
1712 | } | ||
1713 | |||
1714 | /* | ||
1715 | * SCSI Error handling calls driver's eh_host_reset if all prior | ||
1716 | * error handling levels return FAILED. If host reset completes | ||
1717 | * successfully, and if link is up, then Fabric login begins. | ||
1718 | * | ||
1719 | * Host Reset is the highest level of error recovery. If this fails, then | ||
1720 | * host is offlined by SCSI. | ||
1721 | * | ||
1722 | */ | ||
1723 | int fnic_host_reset(struct scsi_cmnd *sc) | ||
1724 | { | ||
1725 | int ret; | ||
1726 | unsigned long wait_host_tmo; | ||
1727 | struct Scsi_Host *shost = sc->device->host; | ||
1728 | struct fc_lport *lp = shost_priv(shost); | ||
1729 | |||
1730 | /* | ||
1731 | * If fnic_reset is successful, wait for fabric login to complete | ||
1732 | * scsi-ml tries to send a TUR to every device if host reset is | ||
1733 | * successful, so before returning to scsi, fabric should be up | ||
1734 | */ | ||
1735 | ret = fnic_reset(shost); | ||
1736 | if (ret == SUCCESS) { | ||
1737 | wait_host_tmo = jiffies + FNIC_HOST_RESET_SETTLE_TIME * HZ; | ||
1738 | ret = FAILED; | ||
1739 | while (time_before(jiffies, wait_host_tmo)) { | ||
1740 | if ((lp->state == LPORT_ST_READY) && | ||
1741 | (lp->link_up)) { | ||
1742 | ret = SUCCESS; | ||
1743 | break; | ||
1744 | } | ||
1745 | ssleep(1); | ||
1746 | } | ||
1747 | } | ||
1748 | |||
1749 | return ret; | ||
1750 | } | ||
1751 | |||
1752 | /* | ||
1753 | * This fxn is called from libFC when host is removed | ||
1754 | */ | ||
1755 | void fnic_scsi_abort_io(struct fc_lport *lp) | ||
1756 | { | ||
1757 | int err = 0; | ||
1758 | unsigned long flags; | ||
1759 | enum fnic_state old_state; | ||
1760 | struct fnic *fnic = lport_priv(lp); | ||
1761 | DECLARE_COMPLETION_ONSTACK(remove_wait); | ||
1762 | |||
1763 | /* Issue firmware reset for fnic, wait for reset to complete */ | ||
1764 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
1765 | fnic->remove_wait = &remove_wait; | ||
1766 | old_state = fnic->state; | ||
1767 | fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; | ||
1768 | vnic_dev_del_addr(fnic->vdev, fnic->data_src_addr); | ||
1769 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
1770 | |||
1771 | err = fnic_fw_reset_handler(fnic); | ||
1772 | if (err) { | ||
1773 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
1774 | if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) | ||
1775 | fnic->state = old_state; | ||
1776 | fnic->remove_wait = NULL; | ||
1777 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
1778 | return; | ||
1779 | } | ||
1780 | |||
1781 | /* Wait for firmware reset to complete */ | ||
1782 | wait_for_completion_timeout(&remove_wait, | ||
1783 | msecs_to_jiffies(FNIC_RMDEVICE_TIMEOUT)); | ||
1784 | |||
1785 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
1786 | fnic->remove_wait = NULL; | ||
1787 | FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host, | ||
1788 | "fnic_scsi_abort_io %s\n", | ||
1789 | (fnic->state == FNIC_IN_ETH_MODE) ? | ||
1790 | "SUCCESS" : "FAILED"); | ||
1791 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
1792 | |||
1793 | } | ||
1794 | |||
1795 | /* | ||
1796 | * This fxn called from libFC to clean up driver IO state on link down | ||
1797 | */ | ||
1798 | void fnic_scsi_cleanup(struct fc_lport *lp) | ||
1799 | { | ||
1800 | unsigned long flags; | ||
1801 | enum fnic_state old_state; | ||
1802 | struct fnic *fnic = lport_priv(lp); | ||
1803 | |||
1804 | /* issue fw reset */ | ||
1805 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
1806 | old_state = fnic->state; | ||
1807 | fnic->state = FNIC_IN_FC_TRANS_ETH_MODE; | ||
1808 | vnic_dev_del_addr(fnic->vdev, fnic->data_src_addr); | ||
1809 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
1810 | |||
1811 | if (fnic_fw_reset_handler(fnic)) { | ||
1812 | spin_lock_irqsave(&fnic->fnic_lock, flags); | ||
1813 | if (fnic->state == FNIC_IN_FC_TRANS_ETH_MODE) | ||
1814 | fnic->state = old_state; | ||
1815 | spin_unlock_irqrestore(&fnic->fnic_lock, flags); | ||
1816 | } | ||
1817 | |||
1818 | } | ||
1819 | |||
1820 | void fnic_empty_scsi_cleanup(struct fc_lport *lp) | ||
1821 | { | ||
1822 | } | ||
1823 | |||
1824 | void fnic_exch_mgr_reset(struct fc_lport *lp, u32 sid, u32 did) | ||
1825 | { | ||
1826 | struct fnic *fnic = lport_priv(lp); | ||
1827 | |||
1828 | /* Non-zero sid, nothing to do */ | ||
1829 | if (sid) | ||
1830 | goto call_fc_exch_mgr_reset; | ||
1831 | |||
1832 | if (did) { | ||
1833 | fnic_rport_exch_reset(fnic, did); | ||
1834 | goto call_fc_exch_mgr_reset; | ||
1835 | } | ||
1836 | |||
1837 | /* | ||
1838 | * sid = 0, did = 0 | ||
1839 | * link down or device being removed | ||
1840 | */ | ||
1841 | if (!fnic->in_remove) | ||
1842 | fnic_scsi_cleanup(lp); | ||
1843 | else | ||
1844 | fnic_scsi_abort_io(lp); | ||
1845 | |||
1846 | /* call libFC exch mgr reset to reset its exchanges */ | ||
1847 | call_fc_exch_mgr_reset: | ||
1848 | fc_exch_mgr_reset(lp, sid, did); | ||
1849 | |||
1850 | } | ||
diff --git a/drivers/scsi/fnic/rq_enet_desc.h b/drivers/scsi/fnic/rq_enet_desc.h new file mode 100644 index 000000000000..92e80ae6b725 --- /dev/null +++ b/drivers/scsi/fnic/rq_enet_desc.h | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _RQ_ENET_DESC_H_ | ||
19 | #define _RQ_ENET_DESC_H_ | ||
20 | |||
21 | /* Ethernet receive queue descriptor: 16B */ | ||
22 | struct rq_enet_desc { | ||
23 | __le64 address; | ||
24 | __le16 length_type; | ||
25 | u8 reserved[6]; | ||
26 | }; | ||
27 | |||
28 | enum rq_enet_type_types { | ||
29 | RQ_ENET_TYPE_ONLY_SOP = 0, | ||
30 | RQ_ENET_TYPE_NOT_SOP = 1, | ||
31 | RQ_ENET_TYPE_RESV2 = 2, | ||
32 | RQ_ENET_TYPE_RESV3 = 3, | ||
33 | }; | ||
34 | |||
35 | #define RQ_ENET_ADDR_BITS 64 | ||
36 | #define RQ_ENET_LEN_BITS 14 | ||
37 | #define RQ_ENET_LEN_MASK ((1 << RQ_ENET_LEN_BITS) - 1) | ||
38 | #define RQ_ENET_TYPE_BITS 2 | ||
39 | #define RQ_ENET_TYPE_MASK ((1 << RQ_ENET_TYPE_BITS) - 1) | ||
40 | |||
41 | static inline void rq_enet_desc_enc(struct rq_enet_desc *desc, | ||
42 | u64 address, u8 type, u16 length) | ||
43 | { | ||
44 | desc->address = cpu_to_le64(address); | ||
45 | desc->length_type = cpu_to_le16((length & RQ_ENET_LEN_MASK) | | ||
46 | ((type & RQ_ENET_TYPE_MASK) << RQ_ENET_LEN_BITS)); | ||
47 | } | ||
48 | |||
49 | static inline void rq_enet_desc_dec(struct rq_enet_desc *desc, | ||
50 | u64 *address, u8 *type, u16 *length) | ||
51 | { | ||
52 | *address = le64_to_cpu(desc->address); | ||
53 | *length = le16_to_cpu(desc->length_type) & RQ_ENET_LEN_MASK; | ||
54 | *type = (u8)((le16_to_cpu(desc->length_type) >> RQ_ENET_LEN_BITS) & | ||
55 | RQ_ENET_TYPE_MASK); | ||
56 | } | ||
57 | |||
58 | #endif /* _RQ_ENET_DESC_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_cq.c b/drivers/scsi/fnic/vnic_cq.c new file mode 100644 index 000000000000..c5db32eda5ef --- /dev/null +++ b/drivers/scsi/fnic/vnic_cq.c | |||
@@ -0,0 +1,85 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #include <linux/errno.h> | ||
19 | #include <linux/types.h> | ||
20 | #include <linux/pci.h> | ||
21 | #include "vnic_dev.h" | ||
22 | #include "vnic_cq.h" | ||
23 | |||
24 | void vnic_cq_free(struct vnic_cq *cq) | ||
25 | { | ||
26 | vnic_dev_free_desc_ring(cq->vdev, &cq->ring); | ||
27 | |||
28 | cq->ctrl = NULL; | ||
29 | } | ||
30 | |||
31 | int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index, | ||
32 | unsigned int desc_count, unsigned int desc_size) | ||
33 | { | ||
34 | int err; | ||
35 | |||
36 | cq->index = index; | ||
37 | cq->vdev = vdev; | ||
38 | |||
39 | cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index); | ||
40 | if (!cq->ctrl) { | ||
41 | printk(KERN_ERR "Failed to hook CQ[%d] resource\n", index); | ||
42 | return -EINVAL; | ||
43 | } | ||
44 | |||
45 | err = vnic_dev_alloc_desc_ring(vdev, &cq->ring, desc_count, desc_size); | ||
46 | if (err) | ||
47 | return err; | ||
48 | |||
49 | return 0; | ||
50 | } | ||
51 | |||
52 | void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable, | ||
53 | unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail, | ||
54 | unsigned int cq_tail_color, unsigned int interrupt_enable, | ||
55 | unsigned int cq_entry_enable, unsigned int cq_message_enable, | ||
56 | unsigned int interrupt_offset, u64 cq_message_addr) | ||
57 | { | ||
58 | u64 paddr; | ||
59 | |||
60 | paddr = (u64)cq->ring.base_addr | VNIC_PADDR_TARGET; | ||
61 | writeq(paddr, &cq->ctrl->ring_base); | ||
62 | iowrite32(cq->ring.desc_count, &cq->ctrl->ring_size); | ||
63 | iowrite32(flow_control_enable, &cq->ctrl->flow_control_enable); | ||
64 | iowrite32(color_enable, &cq->ctrl->color_enable); | ||
65 | iowrite32(cq_head, &cq->ctrl->cq_head); | ||
66 | iowrite32(cq_tail, &cq->ctrl->cq_tail); | ||
67 | iowrite32(cq_tail_color, &cq->ctrl->cq_tail_color); | ||
68 | iowrite32(interrupt_enable, &cq->ctrl->interrupt_enable); | ||
69 | iowrite32(cq_entry_enable, &cq->ctrl->cq_entry_enable); | ||
70 | iowrite32(cq_message_enable, &cq->ctrl->cq_message_enable); | ||
71 | iowrite32(interrupt_offset, &cq->ctrl->interrupt_offset); | ||
72 | writeq(cq_message_addr, &cq->ctrl->cq_message_addr); | ||
73 | } | ||
74 | |||
75 | void vnic_cq_clean(struct vnic_cq *cq) | ||
76 | { | ||
77 | cq->to_clean = 0; | ||
78 | cq->last_color = 0; | ||
79 | |||
80 | iowrite32(0, &cq->ctrl->cq_head); | ||
81 | iowrite32(0, &cq->ctrl->cq_tail); | ||
82 | iowrite32(1, &cq->ctrl->cq_tail_color); | ||
83 | |||
84 | vnic_dev_clear_desc_ring(&cq->ring); | ||
85 | } | ||
diff --git a/drivers/scsi/fnic/vnic_cq.h b/drivers/scsi/fnic/vnic_cq.h new file mode 100644 index 000000000000..4ede6809fb1e --- /dev/null +++ b/drivers/scsi/fnic/vnic_cq.h | |||
@@ -0,0 +1,121 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_CQ_H_ | ||
19 | #define _VNIC_CQ_H_ | ||
20 | |||
21 | #include "cq_desc.h" | ||
22 | #include "vnic_dev.h" | ||
23 | |||
24 | /* | ||
25 | * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth | ||
26 | * Driver) when both are built with CONFIG options =y | ||
27 | */ | ||
28 | #define vnic_cq_service fnic_cq_service | ||
29 | #define vnic_cq_free fnic_cq_free | ||
30 | #define vnic_cq_alloc fnic_cq_alloc | ||
31 | #define vnic_cq_init fnic_cq_init | ||
32 | #define vnic_cq_clean fnic_cq_clean | ||
33 | |||
34 | /* Completion queue control */ | ||
35 | struct vnic_cq_ctrl { | ||
36 | u64 ring_base; /* 0x00 */ | ||
37 | u32 ring_size; /* 0x08 */ | ||
38 | u32 pad0; | ||
39 | u32 flow_control_enable; /* 0x10 */ | ||
40 | u32 pad1; | ||
41 | u32 color_enable; /* 0x18 */ | ||
42 | u32 pad2; | ||
43 | u32 cq_head; /* 0x20 */ | ||
44 | u32 pad3; | ||
45 | u32 cq_tail; /* 0x28 */ | ||
46 | u32 pad4; | ||
47 | u32 cq_tail_color; /* 0x30 */ | ||
48 | u32 pad5; | ||
49 | u32 interrupt_enable; /* 0x38 */ | ||
50 | u32 pad6; | ||
51 | u32 cq_entry_enable; /* 0x40 */ | ||
52 | u32 pad7; | ||
53 | u32 cq_message_enable; /* 0x48 */ | ||
54 | u32 pad8; | ||
55 | u32 interrupt_offset; /* 0x50 */ | ||
56 | u32 pad9; | ||
57 | u64 cq_message_addr; /* 0x58 */ | ||
58 | u32 pad10; | ||
59 | }; | ||
60 | |||
61 | struct vnic_cq { | ||
62 | unsigned int index; | ||
63 | struct vnic_dev *vdev; | ||
64 | struct vnic_cq_ctrl __iomem *ctrl; /* memory-mapped */ | ||
65 | struct vnic_dev_ring ring; | ||
66 | unsigned int to_clean; | ||
67 | unsigned int last_color; | ||
68 | }; | ||
69 | |||
70 | static inline unsigned int vnic_cq_service(struct vnic_cq *cq, | ||
71 | unsigned int work_to_do, | ||
72 | int (*q_service)(struct vnic_dev *vdev, struct cq_desc *cq_desc, | ||
73 | u8 type, u16 q_number, u16 completed_index, void *opaque), | ||
74 | void *opaque) | ||
75 | { | ||
76 | struct cq_desc *cq_desc; | ||
77 | unsigned int work_done = 0; | ||
78 | u16 q_number, completed_index; | ||
79 | u8 type, color; | ||
80 | |||
81 | cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + | ||
82 | cq->ring.desc_size * cq->to_clean); | ||
83 | cq_desc_dec(cq_desc, &type, &color, | ||
84 | &q_number, &completed_index); | ||
85 | |||
86 | while (color != cq->last_color) { | ||
87 | |||
88 | if ((*q_service)(cq->vdev, cq_desc, type, | ||
89 | q_number, completed_index, opaque)) | ||
90 | break; | ||
91 | |||
92 | cq->to_clean++; | ||
93 | if (cq->to_clean == cq->ring.desc_count) { | ||
94 | cq->to_clean = 0; | ||
95 | cq->last_color = cq->last_color ? 0 : 1; | ||
96 | } | ||
97 | |||
98 | cq_desc = (struct cq_desc *)((u8 *)cq->ring.descs + | ||
99 | cq->ring.desc_size * cq->to_clean); | ||
100 | cq_desc_dec(cq_desc, &type, &color, | ||
101 | &q_number, &completed_index); | ||
102 | |||
103 | work_done++; | ||
104 | if (work_done >= work_to_do) | ||
105 | break; | ||
106 | } | ||
107 | |||
108 | return work_done; | ||
109 | } | ||
110 | |||
111 | void vnic_cq_free(struct vnic_cq *cq); | ||
112 | int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index, | ||
113 | unsigned int desc_count, unsigned int desc_size); | ||
114 | void vnic_cq_init(struct vnic_cq *cq, unsigned int flow_control_enable, | ||
115 | unsigned int color_enable, unsigned int cq_head, unsigned int cq_tail, | ||
116 | unsigned int cq_tail_color, unsigned int interrupt_enable, | ||
117 | unsigned int cq_entry_enable, unsigned int message_enable, | ||
118 | unsigned int interrupt_offset, u64 message_addr); | ||
119 | void vnic_cq_clean(struct vnic_cq *cq); | ||
120 | |||
121 | #endif /* _VNIC_CQ_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_cq_copy.h b/drivers/scsi/fnic/vnic_cq_copy.h new file mode 100644 index 000000000000..7901ce255a81 --- /dev/null +++ b/drivers/scsi/fnic/vnic_cq_copy.h | |||
@@ -0,0 +1,62 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_CQ_COPY_H_ | ||
19 | #define _VNIC_CQ_COPY_H_ | ||
20 | |||
21 | #include "fcpio.h" | ||
22 | |||
23 | static inline unsigned int vnic_cq_copy_service( | ||
24 | struct vnic_cq *cq, | ||
25 | int (*q_service)(struct vnic_dev *vdev, | ||
26 | unsigned int index, | ||
27 | struct fcpio_fw_req *desc), | ||
28 | unsigned int work_to_do) | ||
29 | |||
30 | { | ||
31 | struct fcpio_fw_req *desc; | ||
32 | unsigned int work_done = 0; | ||
33 | u8 color; | ||
34 | |||
35 | desc = (struct fcpio_fw_req *)((u8 *)cq->ring.descs + | ||
36 | cq->ring.desc_size * cq->to_clean); | ||
37 | fcpio_color_dec(desc, &color); | ||
38 | |||
39 | while (color != cq->last_color) { | ||
40 | |||
41 | if ((*q_service)(cq->vdev, cq->index, desc)) | ||
42 | break; | ||
43 | |||
44 | cq->to_clean++; | ||
45 | if (cq->to_clean == cq->ring.desc_count) { | ||
46 | cq->to_clean = 0; | ||
47 | cq->last_color = cq->last_color ? 0 : 1; | ||
48 | } | ||
49 | |||
50 | desc = (struct fcpio_fw_req *)((u8 *)cq->ring.descs + | ||
51 | cq->ring.desc_size * cq->to_clean); | ||
52 | fcpio_color_dec(desc, &color); | ||
53 | |||
54 | work_done++; | ||
55 | if (work_done >= work_to_do) | ||
56 | break; | ||
57 | } | ||
58 | |||
59 | return work_done; | ||
60 | } | ||
61 | |||
62 | #endif /* _VNIC_CQ_COPY_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_dev.c b/drivers/scsi/fnic/vnic_dev.c new file mode 100644 index 000000000000..566770645086 --- /dev/null +++ b/drivers/scsi/fnic/vnic_dev.c | |||
@@ -0,0 +1,690 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include <linux/if_ether.h> | ||
25 | #include "vnic_resource.h" | ||
26 | #include "vnic_devcmd.h" | ||
27 | #include "vnic_dev.h" | ||
28 | #include "vnic_stats.h" | ||
29 | |||
30 | struct vnic_res { | ||
31 | void __iomem *vaddr; | ||
32 | unsigned int count; | ||
33 | }; | ||
34 | |||
35 | struct vnic_dev { | ||
36 | void *priv; | ||
37 | struct pci_dev *pdev; | ||
38 | struct vnic_res res[RES_TYPE_MAX]; | ||
39 | enum vnic_dev_intr_mode intr_mode; | ||
40 | struct vnic_devcmd __iomem *devcmd; | ||
41 | struct vnic_devcmd_notify *notify; | ||
42 | struct vnic_devcmd_notify notify_copy; | ||
43 | dma_addr_t notify_pa; | ||
44 | u32 *linkstatus; | ||
45 | dma_addr_t linkstatus_pa; | ||
46 | struct vnic_stats *stats; | ||
47 | dma_addr_t stats_pa; | ||
48 | struct vnic_devcmd_fw_info *fw_info; | ||
49 | dma_addr_t fw_info_pa; | ||
50 | }; | ||
51 | |||
52 | #define VNIC_MAX_RES_HDR_SIZE \ | ||
53 | (sizeof(struct vnic_resource_header) + \ | ||
54 | sizeof(struct vnic_resource) * RES_TYPE_MAX) | ||
55 | #define VNIC_RES_STRIDE 128 | ||
56 | |||
57 | void *vnic_dev_priv(struct vnic_dev *vdev) | ||
58 | { | ||
59 | return vdev->priv; | ||
60 | } | ||
61 | |||
62 | static int vnic_dev_discover_res(struct vnic_dev *vdev, | ||
63 | struct vnic_dev_bar *bar) | ||
64 | { | ||
65 | struct vnic_resource_header __iomem *rh; | ||
66 | struct vnic_resource __iomem *r; | ||
67 | u8 type; | ||
68 | |||
69 | if (bar->len < VNIC_MAX_RES_HDR_SIZE) { | ||
70 | printk(KERN_ERR "vNIC BAR0 res hdr length error\n"); | ||
71 | return -EINVAL; | ||
72 | } | ||
73 | |||
74 | rh = bar->vaddr; | ||
75 | if (!rh) { | ||
76 | printk(KERN_ERR "vNIC BAR0 res hdr not mem-mapped\n"); | ||
77 | return -EINVAL; | ||
78 | } | ||
79 | |||
80 | if (ioread32(&rh->magic) != VNIC_RES_MAGIC || | ||
81 | ioread32(&rh->version) != VNIC_RES_VERSION) { | ||
82 | printk(KERN_ERR "vNIC BAR0 res magic/version error " | ||
83 | "exp (%lx/%lx) curr (%x/%x)\n", | ||
84 | VNIC_RES_MAGIC, VNIC_RES_VERSION, | ||
85 | ioread32(&rh->magic), ioread32(&rh->version)); | ||
86 | return -EINVAL; | ||
87 | } | ||
88 | |||
89 | r = (struct vnic_resource __iomem *)(rh + 1); | ||
90 | |||
91 | while ((type = ioread8(&r->type)) != RES_TYPE_EOL) { | ||
92 | |||
93 | u8 bar_num = ioread8(&r->bar); | ||
94 | u32 bar_offset = ioread32(&r->bar_offset); | ||
95 | u32 count = ioread32(&r->count); | ||
96 | u32 len; | ||
97 | |||
98 | r++; | ||
99 | |||
100 | if (bar_num != 0) /* only mapping in BAR0 resources */ | ||
101 | continue; | ||
102 | |||
103 | switch (type) { | ||
104 | case RES_TYPE_WQ: | ||
105 | case RES_TYPE_RQ: | ||
106 | case RES_TYPE_CQ: | ||
107 | case RES_TYPE_INTR_CTRL: | ||
108 | /* each count is stride bytes long */ | ||
109 | len = count * VNIC_RES_STRIDE; | ||
110 | if (len + bar_offset > bar->len) { | ||
111 | printk(KERN_ERR "vNIC BAR0 resource %d " | ||
112 | "out-of-bounds, offset 0x%x + " | ||
113 | "size 0x%x > bar len 0x%lx\n", | ||
114 | type, bar_offset, | ||
115 | len, | ||
116 | bar->len); | ||
117 | return -EINVAL; | ||
118 | } | ||
119 | break; | ||
120 | case RES_TYPE_INTR_PBA_LEGACY: | ||
121 | case RES_TYPE_DEVCMD: | ||
122 | len = count; | ||
123 | break; | ||
124 | default: | ||
125 | continue; | ||
126 | } | ||
127 | |||
128 | vdev->res[type].count = count; | ||
129 | vdev->res[type].vaddr = (char __iomem *)bar->vaddr + bar_offset; | ||
130 | } | ||
131 | |||
132 | return 0; | ||
133 | } | ||
134 | |||
135 | unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, | ||
136 | enum vnic_res_type type) | ||
137 | { | ||
138 | return vdev->res[type].count; | ||
139 | } | ||
140 | |||
141 | void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, | ||
142 | unsigned int index) | ||
143 | { | ||
144 | if (!vdev->res[type].vaddr) | ||
145 | return NULL; | ||
146 | |||
147 | switch (type) { | ||
148 | case RES_TYPE_WQ: | ||
149 | case RES_TYPE_RQ: | ||
150 | case RES_TYPE_CQ: | ||
151 | case RES_TYPE_INTR_CTRL: | ||
152 | return (char __iomem *)vdev->res[type].vaddr + | ||
153 | index * VNIC_RES_STRIDE; | ||
154 | default: | ||
155 | return (char __iomem *)vdev->res[type].vaddr; | ||
156 | } | ||
157 | } | ||
158 | |||
159 | unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, | ||
160 | unsigned int desc_count, | ||
161 | unsigned int desc_size) | ||
162 | { | ||
163 | /* The base address of the desc rings must be 512 byte aligned. | ||
164 | * Descriptor count is aligned to groups of 32 descriptors. A | ||
165 | * count of 0 means the maximum 4096 descriptors. Descriptor | ||
166 | * size is aligned to 16 bytes. | ||
167 | */ | ||
168 | |||
169 | unsigned int count_align = 32; | ||
170 | unsigned int desc_align = 16; | ||
171 | |||
172 | ring->base_align = 512; | ||
173 | |||
174 | if (desc_count == 0) | ||
175 | desc_count = 4096; | ||
176 | |||
177 | ring->desc_count = ALIGN(desc_count, count_align); | ||
178 | |||
179 | ring->desc_size = ALIGN(desc_size, desc_align); | ||
180 | |||
181 | ring->size = ring->desc_count * ring->desc_size; | ||
182 | ring->size_unaligned = ring->size + ring->base_align; | ||
183 | |||
184 | return ring->size_unaligned; | ||
185 | } | ||
186 | |||
187 | void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring) | ||
188 | { | ||
189 | memset(ring->descs, 0, ring->size); | ||
190 | } | ||
191 | |||
192 | int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, | ||
193 | unsigned int desc_count, unsigned int desc_size) | ||
194 | { | ||
195 | vnic_dev_desc_ring_size(ring, desc_count, desc_size); | ||
196 | |||
197 | ring->descs_unaligned = pci_alloc_consistent(vdev->pdev, | ||
198 | ring->size_unaligned, | ||
199 | &ring->base_addr_unaligned); | ||
200 | |||
201 | if (!ring->descs_unaligned) { | ||
202 | printk(KERN_ERR | ||
203 | "Failed to allocate ring (size=%d), aborting\n", | ||
204 | (int)ring->size); | ||
205 | return -ENOMEM; | ||
206 | } | ||
207 | |||
208 | ring->base_addr = ALIGN(ring->base_addr_unaligned, | ||
209 | ring->base_align); | ||
210 | ring->descs = (u8 *)ring->descs_unaligned + | ||
211 | (ring->base_addr - ring->base_addr_unaligned); | ||
212 | |||
213 | vnic_dev_clear_desc_ring(ring); | ||
214 | |||
215 | ring->desc_avail = ring->desc_count - 1; | ||
216 | |||
217 | return 0; | ||
218 | } | ||
219 | |||
220 | void vnic_dev_free_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring) | ||
221 | { | ||
222 | if (ring->descs) { | ||
223 | pci_free_consistent(vdev->pdev, | ||
224 | ring->size_unaligned, | ||
225 | ring->descs_unaligned, | ||
226 | ring->base_addr_unaligned); | ||
227 | ring->descs = NULL; | ||
228 | } | ||
229 | } | ||
230 | |||
231 | int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, | ||
232 | u64 *a0, u64 *a1, int wait) | ||
233 | { | ||
234 | struct vnic_devcmd __iomem *devcmd = vdev->devcmd; | ||
235 | int delay; | ||
236 | u32 status; | ||
237 | int dev_cmd_err[] = { | ||
238 | /* convert from fw's version of error.h to host's version */ | ||
239 | 0, /* ERR_SUCCESS */ | ||
240 | EINVAL, /* ERR_EINVAL */ | ||
241 | EFAULT, /* ERR_EFAULT */ | ||
242 | EPERM, /* ERR_EPERM */ | ||
243 | EBUSY, /* ERR_EBUSY */ | ||
244 | }; | ||
245 | int err; | ||
246 | |||
247 | status = ioread32(&devcmd->status); | ||
248 | if (status & STAT_BUSY) { | ||
249 | printk(KERN_ERR "Busy devcmd %d\n", _CMD_N(cmd)); | ||
250 | return -EBUSY; | ||
251 | } | ||
252 | |||
253 | if (_CMD_DIR(cmd) & _CMD_DIR_WRITE) { | ||
254 | writeq(*a0, &devcmd->args[0]); | ||
255 | writeq(*a1, &devcmd->args[1]); | ||
256 | wmb(); | ||
257 | } | ||
258 | |||
259 | iowrite32(cmd, &devcmd->cmd); | ||
260 | |||
261 | if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT)) | ||
262 | return 0; | ||
263 | |||
264 | for (delay = 0; delay < wait; delay++) { | ||
265 | |||
266 | udelay(100); | ||
267 | |||
268 | status = ioread32(&devcmd->status); | ||
269 | if (!(status & STAT_BUSY)) { | ||
270 | |||
271 | if (status & STAT_ERROR) { | ||
272 | err = dev_cmd_err[(int)readq(&devcmd->args[0])]; | ||
273 | printk(KERN_ERR "Error %d devcmd %d\n", | ||
274 | err, _CMD_N(cmd)); | ||
275 | return -err; | ||
276 | } | ||
277 | |||
278 | if (_CMD_DIR(cmd) & _CMD_DIR_READ) { | ||
279 | rmb(); | ||
280 | *a0 = readq(&devcmd->args[0]); | ||
281 | *a1 = readq(&devcmd->args[1]); | ||
282 | } | ||
283 | |||
284 | return 0; | ||
285 | } | ||
286 | } | ||
287 | |||
288 | printk(KERN_ERR "Timedout devcmd %d\n", _CMD_N(cmd)); | ||
289 | return -ETIMEDOUT; | ||
290 | } | ||
291 | |||
292 | int vnic_dev_fw_info(struct vnic_dev *vdev, | ||
293 | struct vnic_devcmd_fw_info **fw_info) | ||
294 | { | ||
295 | u64 a0, a1 = 0; | ||
296 | int wait = 1000; | ||
297 | int err = 0; | ||
298 | |||
299 | if (!vdev->fw_info) { | ||
300 | vdev->fw_info = pci_alloc_consistent(vdev->pdev, | ||
301 | sizeof(struct vnic_devcmd_fw_info), | ||
302 | &vdev->fw_info_pa); | ||
303 | if (!vdev->fw_info) | ||
304 | return -ENOMEM; | ||
305 | |||
306 | a0 = vdev->fw_info_pa; | ||
307 | |||
308 | /* only get fw_info once and cache it */ | ||
309 | err = vnic_dev_cmd(vdev, CMD_MCPU_FW_INFO, &a0, &a1, wait); | ||
310 | } | ||
311 | |||
312 | *fw_info = vdev->fw_info; | ||
313 | |||
314 | return err; | ||
315 | } | ||
316 | |||
317 | int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, unsigned int size, | ||
318 | void *value) | ||
319 | { | ||
320 | u64 a0, a1; | ||
321 | int wait = 1000; | ||
322 | int err; | ||
323 | |||
324 | a0 = offset; | ||
325 | a1 = size; | ||
326 | |||
327 | err = vnic_dev_cmd(vdev, CMD_DEV_SPEC, &a0, &a1, wait); | ||
328 | |||
329 | switch (size) { | ||
330 | case 1: | ||
331 | *(u8 *)value = (u8)a0; | ||
332 | break; | ||
333 | case 2: | ||
334 | *(u16 *)value = (u16)a0; | ||
335 | break; | ||
336 | case 4: | ||
337 | *(u32 *)value = (u32)a0; | ||
338 | break; | ||
339 | case 8: | ||
340 | *(u64 *)value = a0; | ||
341 | break; | ||
342 | default: | ||
343 | BUG(); | ||
344 | break; | ||
345 | } | ||
346 | |||
347 | return err; | ||
348 | } | ||
349 | |||
350 | int vnic_dev_stats_clear(struct vnic_dev *vdev) | ||
351 | { | ||
352 | u64 a0 = 0, a1 = 0; | ||
353 | int wait = 1000; | ||
354 | return vnic_dev_cmd(vdev, CMD_STATS_CLEAR, &a0, &a1, wait); | ||
355 | } | ||
356 | |||
357 | int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats) | ||
358 | { | ||
359 | u64 a0, a1; | ||
360 | int wait = 1000; | ||
361 | |||
362 | if (!vdev->stats) { | ||
363 | vdev->stats = pci_alloc_consistent(vdev->pdev, | ||
364 | sizeof(struct vnic_stats), &vdev->stats_pa); | ||
365 | if (!vdev->stats) | ||
366 | return -ENOMEM; | ||
367 | } | ||
368 | |||
369 | *stats = vdev->stats; | ||
370 | a0 = vdev->stats_pa; | ||
371 | a1 = sizeof(struct vnic_stats); | ||
372 | |||
373 | return vnic_dev_cmd(vdev, CMD_STATS_DUMP, &a0, &a1, wait); | ||
374 | } | ||
375 | |||
376 | int vnic_dev_close(struct vnic_dev *vdev) | ||
377 | { | ||
378 | u64 a0 = 0, a1 = 0; | ||
379 | int wait = 1000; | ||
380 | return vnic_dev_cmd(vdev, CMD_CLOSE, &a0, &a1, wait); | ||
381 | } | ||
382 | |||
383 | int vnic_dev_enable(struct vnic_dev *vdev) | ||
384 | { | ||
385 | u64 a0 = 0, a1 = 0; | ||
386 | int wait = 1000; | ||
387 | return vnic_dev_cmd(vdev, CMD_ENABLE, &a0, &a1, wait); | ||
388 | } | ||
389 | |||
390 | int vnic_dev_disable(struct vnic_dev *vdev) | ||
391 | { | ||
392 | u64 a0 = 0, a1 = 0; | ||
393 | int wait = 1000; | ||
394 | return vnic_dev_cmd(vdev, CMD_DISABLE, &a0, &a1, wait); | ||
395 | } | ||
396 | |||
397 | int vnic_dev_open(struct vnic_dev *vdev, int arg) | ||
398 | { | ||
399 | u64 a0 = (u32)arg, a1 = 0; | ||
400 | int wait = 1000; | ||
401 | return vnic_dev_cmd(vdev, CMD_OPEN, &a0, &a1, wait); | ||
402 | } | ||
403 | |||
404 | int vnic_dev_open_done(struct vnic_dev *vdev, int *done) | ||
405 | { | ||
406 | u64 a0 = 0, a1 = 0; | ||
407 | int wait = 1000; | ||
408 | int err; | ||
409 | |||
410 | *done = 0; | ||
411 | |||
412 | err = vnic_dev_cmd(vdev, CMD_OPEN_STATUS, &a0, &a1, wait); | ||
413 | if (err) | ||
414 | return err; | ||
415 | |||
416 | *done = (a0 == 0); | ||
417 | |||
418 | return 0; | ||
419 | } | ||
420 | |||
421 | int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg) | ||
422 | { | ||
423 | u64 a0 = (u32)arg, a1 = 0; | ||
424 | int wait = 1000; | ||
425 | return vnic_dev_cmd(vdev, CMD_SOFT_RESET, &a0, &a1, wait); | ||
426 | } | ||
427 | |||
428 | int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done) | ||
429 | { | ||
430 | u64 a0 = 0, a1 = 0; | ||
431 | int wait = 1000; | ||
432 | int err; | ||
433 | |||
434 | *done = 0; | ||
435 | |||
436 | err = vnic_dev_cmd(vdev, CMD_SOFT_RESET_STATUS, &a0, &a1, wait); | ||
437 | if (err) | ||
438 | return err; | ||
439 | |||
440 | *done = (a0 == 0); | ||
441 | |||
442 | return 0; | ||
443 | } | ||
444 | |||
445 | int vnic_dev_hang_notify(struct vnic_dev *vdev) | ||
446 | { | ||
447 | u64 a0, a1; | ||
448 | int wait = 1000; | ||
449 | return vnic_dev_cmd(vdev, CMD_HANG_NOTIFY, &a0, &a1, wait); | ||
450 | } | ||
451 | |||
452 | int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr) | ||
453 | { | ||
454 | u64 a0, a1; | ||
455 | int wait = 1000; | ||
456 | int err, i; | ||
457 | |||
458 | for (i = 0; i < ETH_ALEN; i++) | ||
459 | mac_addr[i] = 0; | ||
460 | |||
461 | err = vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait); | ||
462 | if (err) | ||
463 | return err; | ||
464 | |||
465 | for (i = 0; i < ETH_ALEN; i++) | ||
466 | mac_addr[i] = ((u8 *)&a0)[i]; | ||
467 | |||
468 | return 0; | ||
469 | } | ||
470 | |||
471 | void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, | ||
472 | int broadcast, int promisc, int allmulti) | ||
473 | { | ||
474 | u64 a0, a1 = 0; | ||
475 | int wait = 1000; | ||
476 | int err; | ||
477 | |||
478 | a0 = (directed ? CMD_PFILTER_DIRECTED : 0) | | ||
479 | (multicast ? CMD_PFILTER_MULTICAST : 0) | | ||
480 | (broadcast ? CMD_PFILTER_BROADCAST : 0) | | ||
481 | (promisc ? CMD_PFILTER_PROMISCUOUS : 0) | | ||
482 | (allmulti ? CMD_PFILTER_ALL_MULTICAST : 0); | ||
483 | |||
484 | err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait); | ||
485 | if (err) | ||
486 | printk(KERN_ERR "Can't set packet filter\n"); | ||
487 | } | ||
488 | |||
489 | void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr) | ||
490 | { | ||
491 | u64 a0 = 0, a1 = 0; | ||
492 | int wait = 1000; | ||
493 | int err; | ||
494 | int i; | ||
495 | |||
496 | for (i = 0; i < ETH_ALEN; i++) | ||
497 | ((u8 *)&a0)[i] = addr[i]; | ||
498 | |||
499 | err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); | ||
500 | if (err) | ||
501 | printk(KERN_ERR | ||
502 | "Can't add addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", | ||
503 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], | ||
504 | err); | ||
505 | } | ||
506 | |||
507 | void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr) | ||
508 | { | ||
509 | u64 a0 = 0, a1 = 0; | ||
510 | int wait = 1000; | ||
511 | int err; | ||
512 | int i; | ||
513 | |||
514 | for (i = 0; i < ETH_ALEN; i++) | ||
515 | ((u8 *)&a0)[i] = addr[i]; | ||
516 | |||
517 | err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait); | ||
518 | if (err) | ||
519 | printk(KERN_ERR | ||
520 | "Can't del addr [%02x:%02x:%02x:%02x:%02x:%02x], %d\n", | ||
521 | addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], | ||
522 | err); | ||
523 | } | ||
524 | |||
525 | int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) | ||
526 | { | ||
527 | u64 a0, a1; | ||
528 | int wait = 1000; | ||
529 | |||
530 | if (!vdev->notify) { | ||
531 | vdev->notify = pci_alloc_consistent(vdev->pdev, | ||
532 | sizeof(struct vnic_devcmd_notify), | ||
533 | &vdev->notify_pa); | ||
534 | if (!vdev->notify) | ||
535 | return -ENOMEM; | ||
536 | } | ||
537 | |||
538 | a0 = vdev->notify_pa; | ||
539 | a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL; | ||
540 | a1 += sizeof(struct vnic_devcmd_notify); | ||
541 | |||
542 | return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); | ||
543 | } | ||
544 | |||
545 | void vnic_dev_notify_unset(struct vnic_dev *vdev) | ||
546 | { | ||
547 | u64 a0, a1; | ||
548 | int wait = 1000; | ||
549 | |||
550 | a0 = 0; /* paddr = 0 to unset notify buffer */ | ||
551 | a1 = 0x0000ffff00000000ULL; /* intr num = -1 to unreg for intr */ | ||
552 | a1 += sizeof(struct vnic_devcmd_notify); | ||
553 | |||
554 | vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); | ||
555 | } | ||
556 | |||
557 | static int vnic_dev_notify_ready(struct vnic_dev *vdev) | ||
558 | { | ||
559 | u32 *words; | ||
560 | unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4; | ||
561 | unsigned int i; | ||
562 | u32 csum; | ||
563 | |||
564 | if (!vdev->notify) | ||
565 | return 0; | ||
566 | |||
567 | do { | ||
568 | csum = 0; | ||
569 | memcpy(&vdev->notify_copy, vdev->notify, | ||
570 | sizeof(struct vnic_devcmd_notify)); | ||
571 | words = (u32 *)&vdev->notify_copy; | ||
572 | for (i = 1; i < nwords; i++) | ||
573 | csum += words[i]; | ||
574 | } while (csum != words[0]); | ||
575 | |||
576 | return 1; | ||
577 | } | ||
578 | |||
579 | int vnic_dev_init(struct vnic_dev *vdev, int arg) | ||
580 | { | ||
581 | u64 a0 = (u32)arg, a1 = 0; | ||
582 | int wait = 1000; | ||
583 | return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); | ||
584 | } | ||
585 | |||
586 | int vnic_dev_link_status(struct vnic_dev *vdev) | ||
587 | { | ||
588 | if (vdev->linkstatus) | ||
589 | return *vdev->linkstatus; | ||
590 | |||
591 | if (!vnic_dev_notify_ready(vdev)) | ||
592 | return 0; | ||
593 | |||
594 | return vdev->notify_copy.link_state; | ||
595 | } | ||
596 | |||
597 | u32 vnic_dev_port_speed(struct vnic_dev *vdev) | ||
598 | { | ||
599 | if (!vnic_dev_notify_ready(vdev)) | ||
600 | return 0; | ||
601 | |||
602 | return vdev->notify_copy.port_speed; | ||
603 | } | ||
604 | |||
605 | u32 vnic_dev_msg_lvl(struct vnic_dev *vdev) | ||
606 | { | ||
607 | if (!vnic_dev_notify_ready(vdev)) | ||
608 | return 0; | ||
609 | |||
610 | return vdev->notify_copy.msglvl; | ||
611 | } | ||
612 | |||
613 | u32 vnic_dev_mtu(struct vnic_dev *vdev) | ||
614 | { | ||
615 | if (!vnic_dev_notify_ready(vdev)) | ||
616 | return 0; | ||
617 | |||
618 | return vdev->notify_copy.mtu; | ||
619 | } | ||
620 | |||
621 | u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev) | ||
622 | { | ||
623 | if (!vnic_dev_notify_ready(vdev)) | ||
624 | return 0; | ||
625 | |||
626 | return vdev->notify_copy.link_down_cnt; | ||
627 | } | ||
628 | |||
629 | void vnic_dev_set_intr_mode(struct vnic_dev *vdev, | ||
630 | enum vnic_dev_intr_mode intr_mode) | ||
631 | { | ||
632 | vdev->intr_mode = intr_mode; | ||
633 | } | ||
634 | |||
635 | enum vnic_dev_intr_mode vnic_dev_get_intr_mode( | ||
636 | struct vnic_dev *vdev) | ||
637 | { | ||
638 | return vdev->intr_mode; | ||
639 | } | ||
640 | |||
641 | void vnic_dev_unregister(struct vnic_dev *vdev) | ||
642 | { | ||
643 | if (vdev) { | ||
644 | if (vdev->notify) | ||
645 | pci_free_consistent(vdev->pdev, | ||
646 | sizeof(struct vnic_devcmd_notify), | ||
647 | vdev->notify, | ||
648 | vdev->notify_pa); | ||
649 | if (vdev->linkstatus) | ||
650 | pci_free_consistent(vdev->pdev, | ||
651 | sizeof(u32), | ||
652 | vdev->linkstatus, | ||
653 | vdev->linkstatus_pa); | ||
654 | if (vdev->stats) | ||
655 | pci_free_consistent(vdev->pdev, | ||
656 | sizeof(struct vnic_dev), | ||
657 | vdev->stats, vdev->stats_pa); | ||
658 | if (vdev->fw_info) | ||
659 | pci_free_consistent(vdev->pdev, | ||
660 | sizeof(struct vnic_devcmd_fw_info), | ||
661 | vdev->fw_info, vdev->fw_info_pa); | ||
662 | kfree(vdev); | ||
663 | } | ||
664 | } | ||
665 | |||
666 | struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, | ||
667 | void *priv, struct pci_dev *pdev, struct vnic_dev_bar *bar) | ||
668 | { | ||
669 | if (!vdev) { | ||
670 | vdev = kzalloc(sizeof(struct vnic_dev), GFP_KERNEL); | ||
671 | if (!vdev) | ||
672 | return NULL; | ||
673 | } | ||
674 | |||
675 | vdev->priv = priv; | ||
676 | vdev->pdev = pdev; | ||
677 | |||
678 | if (vnic_dev_discover_res(vdev, bar)) | ||
679 | goto err_out; | ||
680 | |||
681 | vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0); | ||
682 | if (!vdev->devcmd) | ||
683 | goto err_out; | ||
684 | |||
685 | return vdev; | ||
686 | |||
687 | err_out: | ||
688 | vnic_dev_unregister(vdev); | ||
689 | return NULL; | ||
690 | } | ||
diff --git a/drivers/scsi/fnic/vnic_dev.h b/drivers/scsi/fnic/vnic_dev.h new file mode 100644 index 000000000000..f9935a8a5a09 --- /dev/null +++ b/drivers/scsi/fnic/vnic_dev.h | |||
@@ -0,0 +1,161 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_DEV_H_ | ||
19 | #define _VNIC_DEV_H_ | ||
20 | |||
21 | #include "vnic_resource.h" | ||
22 | #include "vnic_devcmd.h" | ||
23 | |||
24 | /* | ||
25 | * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth | ||
26 | * Driver) when both are built with CONFIG options =y | ||
27 | */ | ||
28 | #define vnic_dev_priv fnic_dev_priv | ||
29 | #define vnic_dev_get_res_count fnic_dev_get_res_count | ||
30 | #define vnic_dev_get_res fnic_dev_get_res | ||
31 | #define vnic_dev_desc_ring_size fnic_dev_desc_ring_siz | ||
32 | #define vnic_dev_clear_desc_ring fnic_dev_clear_desc_ring | ||
33 | #define vnic_dev_alloc_desc_ring fnic_dev_alloc_desc_ring | ||
34 | #define vnic_dev_free_desc_ring fnic_dev_free_desc_ring | ||
35 | #define vnic_dev_cmd fnic_dev_cmd | ||
36 | #define vnic_dev_fw_info fnic_dev_fw_info | ||
37 | #define vnic_dev_spec fnic_dev_spec | ||
38 | #define vnic_dev_stats_clear fnic_dev_stats_clear | ||
39 | #define vnic_dev_stats_dump fnic_dev_stats_dump | ||
40 | #define vnic_dev_hang_notify fnic_dev_hang_notify | ||
41 | #define vnic_dev_packet_filter fnic_dev_packet_filter | ||
42 | #define vnic_dev_add_addr fnic_dev_add_addr | ||
43 | #define vnic_dev_del_addr fnic_dev_del_addr | ||
44 | #define vnic_dev_mac_addr fnic_dev_mac_addr | ||
45 | #define vnic_dev_notify_set fnic_dev_notify_set | ||
46 | #define vnic_dev_notify_unset fnic_dev_notify_unset | ||
47 | #define vnic_dev_link_status fnic_dev_link_status | ||
48 | #define vnic_dev_port_speed fnic_dev_port_speed | ||
49 | #define vnic_dev_msg_lvl fnic_dev_msg_lvl | ||
50 | #define vnic_dev_mtu fnic_dev_mtu | ||
51 | #define vnic_dev_link_down_cnt fnic_dev_link_down_cnt | ||
52 | #define vnic_dev_close fnic_dev_close | ||
53 | #define vnic_dev_enable fnic_dev_enable | ||
54 | #define vnic_dev_disable fnic_dev_disable | ||
55 | #define vnic_dev_open fnic_dev_open | ||
56 | #define vnic_dev_open_done fnic_dev_open_done | ||
57 | #define vnic_dev_init fnic_dev_init | ||
58 | #define vnic_dev_soft_reset fnic_dev_soft_reset | ||
59 | #define vnic_dev_soft_reset_done fnic_dev_soft_reset_done | ||
60 | #define vnic_dev_set_intr_mode fnic_dev_set_intr_mode | ||
61 | #define vnic_dev_get_intr_mode fnic_dev_get_intr_mode | ||
62 | #define vnic_dev_unregister fnic_dev_unregister | ||
63 | #define vnic_dev_register fnic_dev_register | ||
64 | |||
65 | #ifndef VNIC_PADDR_TARGET | ||
66 | #define VNIC_PADDR_TARGET 0x0000000000000000ULL | ||
67 | #endif | ||
68 | |||
69 | #ifndef readq | ||
70 | static inline u64 readq(void __iomem *reg) | ||
71 | { | ||
72 | return ((u64)readl(reg + 0x4UL) << 32) | (u64)readl(reg); | ||
73 | } | ||
74 | |||
75 | static inline void writeq(u64 val, void __iomem *reg) | ||
76 | { | ||
77 | writel(val & 0xffffffff, reg); | ||
78 | writel(val >> 32, reg + 0x4UL); | ||
79 | } | ||
80 | #endif | ||
81 | |||
82 | enum vnic_dev_intr_mode { | ||
83 | VNIC_DEV_INTR_MODE_UNKNOWN, | ||
84 | VNIC_DEV_INTR_MODE_INTX, | ||
85 | VNIC_DEV_INTR_MODE_MSI, | ||
86 | VNIC_DEV_INTR_MODE_MSIX, | ||
87 | }; | ||
88 | |||
89 | struct vnic_dev_bar { | ||
90 | void __iomem *vaddr; | ||
91 | dma_addr_t bus_addr; | ||
92 | unsigned long len; | ||
93 | }; | ||
94 | |||
95 | struct vnic_dev_ring { | ||
96 | void *descs; | ||
97 | size_t size; | ||
98 | dma_addr_t base_addr; | ||
99 | size_t base_align; | ||
100 | void *descs_unaligned; | ||
101 | size_t size_unaligned; | ||
102 | dma_addr_t base_addr_unaligned; | ||
103 | unsigned int desc_size; | ||
104 | unsigned int desc_count; | ||
105 | unsigned int desc_avail; | ||
106 | }; | ||
107 | |||
108 | struct vnic_dev; | ||
109 | struct vnic_stats; | ||
110 | |||
111 | void *vnic_dev_priv(struct vnic_dev *vdev); | ||
112 | unsigned int vnic_dev_get_res_count(struct vnic_dev *vdev, | ||
113 | enum vnic_res_type type); | ||
114 | void __iomem *vnic_dev_get_res(struct vnic_dev *vdev, enum vnic_res_type type, | ||
115 | unsigned int index); | ||
116 | unsigned int vnic_dev_desc_ring_size(struct vnic_dev_ring *ring, | ||
117 | unsigned int desc_count, | ||
118 | unsigned int desc_size); | ||
119 | void vnic_dev_clear_desc_ring(struct vnic_dev_ring *ring); | ||
120 | int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, | ||
121 | unsigned int desc_count, unsigned int desc_size); | ||
122 | void vnic_dev_free_desc_ring(struct vnic_dev *vdev, | ||
123 | struct vnic_dev_ring *ring); | ||
124 | int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, | ||
125 | u64 *a0, u64 *a1, int wait); | ||
126 | int vnic_dev_fw_info(struct vnic_dev *vdev, | ||
127 | struct vnic_devcmd_fw_info **fw_info); | ||
128 | int vnic_dev_spec(struct vnic_dev *vdev, unsigned int offset, | ||
129 | unsigned int size, void *value); | ||
130 | int vnic_dev_stats_clear(struct vnic_dev *vdev); | ||
131 | int vnic_dev_stats_dump(struct vnic_dev *vdev, struct vnic_stats **stats); | ||
132 | int vnic_dev_hang_notify(struct vnic_dev *vdev); | ||
133 | void vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, | ||
134 | int broadcast, int promisc, int allmulti); | ||
135 | void vnic_dev_add_addr(struct vnic_dev *vdev, u8 *addr); | ||
136 | void vnic_dev_del_addr(struct vnic_dev *vdev, u8 *addr); | ||
137 | int vnic_dev_mac_addr(struct vnic_dev *vdev, u8 *mac_addr); | ||
138 | int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr); | ||
139 | void vnic_dev_notify_unset(struct vnic_dev *vdev); | ||
140 | int vnic_dev_link_status(struct vnic_dev *vdev); | ||
141 | u32 vnic_dev_port_speed(struct vnic_dev *vdev); | ||
142 | u32 vnic_dev_msg_lvl(struct vnic_dev *vdev); | ||
143 | u32 vnic_dev_mtu(struct vnic_dev *vdev); | ||
144 | u32 vnic_dev_link_down_cnt(struct vnic_dev *vdev); | ||
145 | int vnic_dev_close(struct vnic_dev *vdev); | ||
146 | int vnic_dev_enable(struct vnic_dev *vdev); | ||
147 | int vnic_dev_disable(struct vnic_dev *vdev); | ||
148 | int vnic_dev_open(struct vnic_dev *vdev, int arg); | ||
149 | int vnic_dev_open_done(struct vnic_dev *vdev, int *done); | ||
150 | int vnic_dev_init(struct vnic_dev *vdev, int arg); | ||
151 | int vnic_dev_soft_reset(struct vnic_dev *vdev, int arg); | ||
152 | int vnic_dev_soft_reset_done(struct vnic_dev *vdev, int *done); | ||
153 | void vnic_dev_set_intr_mode(struct vnic_dev *vdev, | ||
154 | enum vnic_dev_intr_mode intr_mode); | ||
155 | enum vnic_dev_intr_mode vnic_dev_get_intr_mode(struct vnic_dev *vdev); | ||
156 | void vnic_dev_unregister(struct vnic_dev *vdev); | ||
157 | struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, | ||
158 | void *priv, struct pci_dev *pdev, | ||
159 | struct vnic_dev_bar *bar); | ||
160 | |||
161 | #endif /* _VNIC_DEV_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_devcmd.h b/drivers/scsi/fnic/vnic_devcmd.h new file mode 100644 index 000000000000..d62b9061bf12 --- /dev/null +++ b/drivers/scsi/fnic/vnic_devcmd.h | |||
@@ -0,0 +1,281 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_DEVCMD_H_ | ||
19 | #define _VNIC_DEVCMD_H_ | ||
20 | |||
21 | #define _CMD_NBITS 14 | ||
22 | #define _CMD_VTYPEBITS 10 | ||
23 | #define _CMD_FLAGSBITS 6 | ||
24 | #define _CMD_DIRBITS 2 | ||
25 | |||
26 | #define _CMD_NMASK ((1 << _CMD_NBITS)-1) | ||
27 | #define _CMD_VTYPEMASK ((1 << _CMD_VTYPEBITS)-1) | ||
28 | #define _CMD_FLAGSMASK ((1 << _CMD_FLAGSBITS)-1) | ||
29 | #define _CMD_DIRMASK ((1 << _CMD_DIRBITS)-1) | ||
30 | |||
31 | #define _CMD_NSHIFT 0 | ||
32 | #define _CMD_VTYPESHIFT (_CMD_NSHIFT+_CMD_NBITS) | ||
33 | #define _CMD_FLAGSSHIFT (_CMD_VTYPESHIFT+_CMD_VTYPEBITS) | ||
34 | #define _CMD_DIRSHIFT (_CMD_FLAGSSHIFT+_CMD_FLAGSBITS) | ||
35 | |||
36 | /* | ||
37 | * Direction bits (from host perspective). | ||
38 | */ | ||
39 | #define _CMD_DIR_NONE 0U | ||
40 | #define _CMD_DIR_WRITE 1U | ||
41 | #define _CMD_DIR_READ 2U | ||
42 | #define _CMD_DIR_RW (_CMD_DIR_WRITE | _CMD_DIR_READ) | ||
43 | |||
44 | /* | ||
45 | * Flag bits. | ||
46 | */ | ||
47 | #define _CMD_FLAGS_NONE 0U | ||
48 | #define _CMD_FLAGS_NOWAIT 1U | ||
49 | |||
50 | /* | ||
51 | * vNIC type bits. | ||
52 | */ | ||
53 | #define _CMD_VTYPE_NONE 0U | ||
54 | #define _CMD_VTYPE_ENET 1U | ||
55 | #define _CMD_VTYPE_FC 2U | ||
56 | #define _CMD_VTYPE_SCSI 4U | ||
57 | #define _CMD_VTYPE_ALL (_CMD_VTYPE_ENET | _CMD_VTYPE_FC | _CMD_VTYPE_SCSI) | ||
58 | |||
59 | /* | ||
60 | * Used to create cmds.. | ||
61 | */ | ||
62 | #define _CMDCF(dir, flags, vtype, nr) \ | ||
63 | (((dir) << _CMD_DIRSHIFT) | \ | ||
64 | ((flags) << _CMD_FLAGSSHIFT) | \ | ||
65 | ((vtype) << _CMD_VTYPESHIFT) | \ | ||
66 | ((nr) << _CMD_NSHIFT)) | ||
67 | #define _CMDC(dir, vtype, nr) _CMDCF(dir, 0, vtype, nr) | ||
68 | #define _CMDCNW(dir, vtype, nr) _CMDCF(dir, _CMD_FLAGS_NOWAIT, vtype, nr) | ||
69 | |||
70 | /* | ||
71 | * Used to decode cmds.. | ||
72 | */ | ||
73 | #define _CMD_DIR(cmd) (((cmd) >> _CMD_DIRSHIFT) & _CMD_DIRMASK) | ||
74 | #define _CMD_FLAGS(cmd) (((cmd) >> _CMD_FLAGSSHIFT) & _CMD_FLAGSMASK) | ||
75 | #define _CMD_VTYPE(cmd) (((cmd) >> _CMD_VTYPESHIFT) & _CMD_VTYPEMASK) | ||
76 | #define _CMD_N(cmd) (((cmd) >> _CMD_NSHIFT) & _CMD_NMASK) | ||
77 | |||
78 | enum vnic_devcmd_cmd { | ||
79 | CMD_NONE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_NONE, 0), | ||
80 | |||
81 | /* mcpu fw info in mem: (u64)a0=paddr to struct vnic_devcmd_fw_info */ | ||
82 | CMD_MCPU_FW_INFO = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 1), | ||
83 | |||
84 | /* dev-specific block member: | ||
85 | * in: (u16)a0=offset,(u8)a1=size | ||
86 | * out: a0=value */ | ||
87 | CMD_DEV_SPEC = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 2), | ||
88 | |||
89 | /* stats clear */ | ||
90 | CMD_STATS_CLEAR = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 3), | ||
91 | |||
92 | /* stats dump in mem: (u64)a0=paddr to stats area, | ||
93 | * (u16)a1=sizeof stats area */ | ||
94 | CMD_STATS_DUMP = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 4), | ||
95 | |||
96 | /* set Rx packet filter: (u32)a0=filters (see CMD_PFILTER_*) */ | ||
97 | CMD_PACKET_FILTER = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 7), | ||
98 | |||
99 | /* hang detection notification */ | ||
100 | CMD_HANG_NOTIFY = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 8), | ||
101 | |||
102 | /* MAC address in (u48)a0 */ | ||
103 | CMD_MAC_ADDR = _CMDC(_CMD_DIR_READ, | ||
104 | _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 9), | ||
105 | |||
106 | /* disable/enable promisc mode: (u8)a0=0/1 */ | ||
107 | /***** XXX DEPRECATED *****/ | ||
108 | CMD_PROMISC_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 10), | ||
109 | |||
110 | /* disable/enable all-multi mode: (u8)a0=0/1 */ | ||
111 | /***** XXX DEPRECATED *****/ | ||
112 | CMD_ALLMULTI_MODE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 11), | ||
113 | |||
114 | /* add addr from (u48)a0 */ | ||
115 | CMD_ADDR_ADD = _CMDCNW(_CMD_DIR_WRITE, | ||
116 | _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 12), | ||
117 | |||
118 | /* del addr from (u48)a0 */ | ||
119 | CMD_ADDR_DEL = _CMDCNW(_CMD_DIR_WRITE, | ||
120 | _CMD_VTYPE_ENET | _CMD_VTYPE_FC, 13), | ||
121 | |||
122 | /* add VLAN id in (u16)a0 */ | ||
123 | CMD_VLAN_ADD = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 14), | ||
124 | |||
125 | /* del VLAN id in (u16)a0 */ | ||
126 | CMD_VLAN_DEL = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 15), | ||
127 | |||
128 | /* nic_cfg in (u32)a0 */ | ||
129 | CMD_NIC_CFG = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 16), | ||
130 | |||
131 | /* union vnic_rss_key in mem: (u64)a0=paddr, (u16)a1=len */ | ||
132 | CMD_RSS_KEY = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 17), | ||
133 | |||
134 | /* union vnic_rss_cpu in mem: (u64)a0=paddr, (u16)a1=len */ | ||
135 | CMD_RSS_CPU = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 18), | ||
136 | |||
137 | /* initiate softreset */ | ||
138 | CMD_SOFT_RESET = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 19), | ||
139 | |||
140 | /* softreset status: | ||
141 | * out: a0=0 reset complete, a0=1 reset in progress */ | ||
142 | CMD_SOFT_RESET_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 20), | ||
143 | |||
144 | /* set struct vnic_devcmd_notify buffer in mem: | ||
145 | * in: | ||
146 | * (u64)a0=paddr to notify (set paddr=0 to unset) | ||
147 | * (u32)a1 & 0x00000000ffffffff=sizeof(struct vnic_devcmd_notify) | ||
148 | * (u16)a1 & 0x0000ffff00000000=intr num (-1 for no intr) | ||
149 | * out: | ||
150 | * (u32)a1 = effective size | ||
151 | */ | ||
152 | CMD_NOTIFY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 21), | ||
153 | |||
154 | /* UNDI API: (u64)a0=paddr to s_PXENV_UNDI_ struct, | ||
155 | * (u8)a1=PXENV_UNDI_xxx */ | ||
156 | CMD_UNDI = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 22), | ||
157 | |||
158 | /* initiate open sequence (u32)a0=flags (see CMD_OPENF_*) */ | ||
159 | CMD_OPEN = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 23), | ||
160 | |||
161 | /* open status: | ||
162 | * out: a0=0 open complete, a0=1 open in progress */ | ||
163 | CMD_OPEN_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 24), | ||
164 | |||
165 | /* close vnic */ | ||
166 | CMD_CLOSE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25), | ||
167 | |||
168 | /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ | ||
169 | CMD_INIT = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), | ||
170 | |||
171 | /* variant of CMD_INIT, with provisioning info | ||
172 | * (u64)a0=paddr of vnic_devcmd_provinfo | ||
173 | * (u32)a1=sizeof provision info */ | ||
174 | CMD_INIT_PROV_INFO = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 27), | ||
175 | |||
176 | /* enable virtual link */ | ||
177 | CMD_ENABLE = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 28), | ||
178 | |||
179 | /* disable virtual link */ | ||
180 | CMD_DISABLE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 29), | ||
181 | |||
182 | /* stats dump all vnics on uplink in mem: (u64)a0=paddr (u32)a1=uif */ | ||
183 | CMD_STATS_DUMP_ALL = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 30), | ||
184 | |||
185 | /* init status: | ||
186 | * out: a0=0 init complete, a0=1 init in progress | ||
187 | * if a0=0, a1=errno */ | ||
188 | CMD_INIT_STATUS = _CMDC(_CMD_DIR_READ, _CMD_VTYPE_ALL, 31), | ||
189 | |||
190 | /* INT13 API: (u64)a0=paddr to vnic_int13_params struct | ||
191 | * (u8)a1=INT13_CMD_xxx */ | ||
192 | CMD_INT13 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_FC, 32), | ||
193 | |||
194 | /* logical uplink enable/disable: (u64)a0: 0/1=disable/enable */ | ||
195 | CMD_LOGICAL_UPLINK = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 33), | ||
196 | |||
197 | /* undo initialize of virtual link */ | ||
198 | CMD_DEINIT = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34), | ||
199 | }; | ||
200 | |||
201 | /* flags for CMD_OPEN */ | ||
202 | #define CMD_OPENF_OPROM 0x1 /* open coming from option rom */ | ||
203 | |||
204 | /* flags for CMD_INIT */ | ||
205 | #define CMD_INITF_DEFAULT_MAC 0x1 /* init with default mac addr */ | ||
206 | |||
207 | /* flags for CMD_PACKET_FILTER */ | ||
208 | #define CMD_PFILTER_DIRECTED 0x01 | ||
209 | #define CMD_PFILTER_MULTICAST 0x02 | ||
210 | #define CMD_PFILTER_BROADCAST 0x04 | ||
211 | #define CMD_PFILTER_PROMISCUOUS 0x08 | ||
212 | #define CMD_PFILTER_ALL_MULTICAST 0x10 | ||
213 | |||
214 | enum vnic_devcmd_status { | ||
215 | STAT_NONE = 0, | ||
216 | STAT_BUSY = 1 << 0, /* cmd in progress */ | ||
217 | STAT_ERROR = 1 << 1, /* last cmd caused error (code in a0) */ | ||
218 | }; | ||
219 | |||
220 | enum vnic_devcmd_error { | ||
221 | ERR_SUCCESS = 0, | ||
222 | ERR_EINVAL = 1, | ||
223 | ERR_EFAULT = 2, | ||
224 | ERR_EPERM = 3, | ||
225 | ERR_EBUSY = 4, | ||
226 | ERR_ECMDUNKNOWN = 5, | ||
227 | ERR_EBADSTATE = 6, | ||
228 | ERR_ENOMEM = 7, | ||
229 | ERR_ETIMEDOUT = 8, | ||
230 | ERR_ELINKDOWN = 9, | ||
231 | }; | ||
232 | |||
233 | struct vnic_devcmd_fw_info { | ||
234 | char fw_version[32]; | ||
235 | char fw_build[32]; | ||
236 | char hw_version[32]; | ||
237 | char hw_serial_number[32]; | ||
238 | }; | ||
239 | |||
240 | struct vnic_devcmd_notify { | ||
241 | u32 csum; /* checksum over following words */ | ||
242 | |||
243 | u32 link_state; /* link up == 1 */ | ||
244 | u32 port_speed; /* effective port speed (rate limit) */ | ||
245 | u32 mtu; /* MTU */ | ||
246 | u32 msglvl; /* requested driver msg lvl */ | ||
247 | u32 uif; /* uplink interface */ | ||
248 | u32 status; /* status bits (see VNIC_STF_*) */ | ||
249 | u32 error; /* error code (see ERR_*) for first ERR */ | ||
250 | u32 link_down_cnt; /* running count of link down transitions */ | ||
251 | }; | ||
252 | #define VNIC_STF_FATAL_ERR 0x0001 /* fatal fw error */ | ||
253 | |||
254 | struct vnic_devcmd_provinfo { | ||
255 | u8 oui[3]; | ||
256 | u8 type; | ||
257 | u8 data[0]; | ||
258 | }; | ||
259 | |||
260 | /* | ||
261 | * Writing cmd register causes STAT_BUSY to get set in status register. | ||
262 | * When cmd completes, STAT_BUSY will be cleared. | ||
263 | * | ||
264 | * If cmd completed successfully STAT_ERROR will be clear | ||
265 | * and args registers contain cmd-specific results. | ||
266 | * | ||
267 | * If cmd error, STAT_ERROR will be set and args[0] contains error code. | ||
268 | * | ||
269 | * status register is read-only. While STAT_BUSY is set, | ||
270 | * all other register contents are read-only. | ||
271 | */ | ||
272 | |||
273 | /* Make sizeof(vnic_devcmd) a power-of-2 for I/O BAR. */ | ||
274 | #define VNIC_DEVCMD_NARGS 15 | ||
275 | struct vnic_devcmd { | ||
276 | u32 status; /* RO */ | ||
277 | u32 cmd; /* RW */ | ||
278 | u64 args[VNIC_DEVCMD_NARGS]; /* RW cmd args (little-endian) */ | ||
279 | }; | ||
280 | |||
281 | #endif /* _VNIC_DEVCMD_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_intr.c b/drivers/scsi/fnic/vnic_intr.c new file mode 100644 index 000000000000..4f4dc8793d23 --- /dev/null +++ b/drivers/scsi/fnic/vnic_intr.c | |||
@@ -0,0 +1,60 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | #include <linux/kernel.h> | ||
20 | #include <linux/errno.h> | ||
21 | #include <linux/types.h> | ||
22 | #include <linux/pci.h> | ||
23 | #include <linux/delay.h> | ||
24 | #include "vnic_dev.h" | ||
25 | #include "vnic_intr.h" | ||
26 | |||
27 | void vnic_intr_free(struct vnic_intr *intr) | ||
28 | { | ||
29 | intr->ctrl = NULL; | ||
30 | } | ||
31 | |||
32 | int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, | ||
33 | unsigned int index) | ||
34 | { | ||
35 | intr->index = index; | ||
36 | intr->vdev = vdev; | ||
37 | |||
38 | intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index); | ||
39 | if (!intr->ctrl) { | ||
40 | printk(KERN_ERR "Failed to hook INTR[%d].ctrl resource\n", | ||
41 | index); | ||
42 | return -EINVAL; | ||
43 | } | ||
44 | |||
45 | return 0; | ||
46 | } | ||
47 | |||
48 | void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, | ||
49 | unsigned int coalescing_type, unsigned int mask_on_assertion) | ||
50 | { | ||
51 | iowrite32(coalescing_timer, &intr->ctrl->coalescing_timer); | ||
52 | iowrite32(coalescing_type, &intr->ctrl->coalescing_type); | ||
53 | iowrite32(mask_on_assertion, &intr->ctrl->mask_on_assertion); | ||
54 | iowrite32(0, &intr->ctrl->int_credits); | ||
55 | } | ||
56 | |||
57 | void vnic_intr_clean(struct vnic_intr *intr) | ||
58 | { | ||
59 | iowrite32(0, &intr->ctrl->int_credits); | ||
60 | } | ||
diff --git a/drivers/scsi/fnic/vnic_intr.h b/drivers/scsi/fnic/vnic_intr.h new file mode 100644 index 000000000000..d5fb40e7c98e --- /dev/null +++ b/drivers/scsi/fnic/vnic_intr.h | |||
@@ -0,0 +1,118 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_INTR_H_ | ||
19 | #define _VNIC_INTR_H_ | ||
20 | |||
21 | #include <linux/pci.h> | ||
22 | #include "vnic_dev.h" | ||
23 | |||
24 | /* | ||
25 | * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth | ||
26 | * Driver) when both are built with CONFIG options =y | ||
27 | */ | ||
28 | #define vnic_intr_unmask fnic_intr_unmask | ||
29 | #define vnic_intr_mask fnic_intr_mask | ||
30 | #define vnic_intr_return_credits fnic_intr_return_credits | ||
31 | #define vnic_intr_credits fnic_intr_credits | ||
32 | #define vnic_intr_return_all_credits fnic_intr_return_all_credits | ||
33 | #define vnic_intr_legacy_pba fnic_intr_legacy_pba | ||
34 | #define vnic_intr_free fnic_intr_free | ||
35 | #define vnic_intr_alloc fnic_intr_alloc | ||
36 | #define vnic_intr_init fnic_intr_init | ||
37 | #define vnic_intr_clean fnic_intr_clean | ||
38 | |||
39 | #define VNIC_INTR_TIMER_MAX 0xffff | ||
40 | |||
41 | #define VNIC_INTR_TIMER_TYPE_ABS 0 | ||
42 | #define VNIC_INTR_TIMER_TYPE_QUIET 1 | ||
43 | |||
44 | /* Interrupt control */ | ||
45 | struct vnic_intr_ctrl { | ||
46 | u32 coalescing_timer; /* 0x00 */ | ||
47 | u32 pad0; | ||
48 | u32 coalescing_value; /* 0x08 */ | ||
49 | u32 pad1; | ||
50 | u32 coalescing_type; /* 0x10 */ | ||
51 | u32 pad2; | ||
52 | u32 mask_on_assertion; /* 0x18 */ | ||
53 | u32 pad3; | ||
54 | u32 mask; /* 0x20 */ | ||
55 | u32 pad4; | ||
56 | u32 int_credits; /* 0x28 */ | ||
57 | u32 pad5; | ||
58 | u32 int_credit_return; /* 0x30 */ | ||
59 | u32 pad6; | ||
60 | }; | ||
61 | |||
62 | struct vnic_intr { | ||
63 | unsigned int index; | ||
64 | struct vnic_dev *vdev; | ||
65 | struct vnic_intr_ctrl __iomem *ctrl; /* memory-mapped */ | ||
66 | }; | ||
67 | |||
68 | static inline void vnic_intr_unmask(struct vnic_intr *intr) | ||
69 | { | ||
70 | iowrite32(0, &intr->ctrl->mask); | ||
71 | } | ||
72 | |||
73 | static inline void vnic_intr_mask(struct vnic_intr *intr) | ||
74 | { | ||
75 | iowrite32(1, &intr->ctrl->mask); | ||
76 | } | ||
77 | |||
78 | static inline void vnic_intr_return_credits(struct vnic_intr *intr, | ||
79 | unsigned int credits, int unmask, int reset_timer) | ||
80 | { | ||
81 | #define VNIC_INTR_UNMASK_SHIFT 16 | ||
82 | #define VNIC_INTR_RESET_TIMER_SHIFT 17 | ||
83 | |||
84 | u32 int_credit_return = (credits & 0xffff) | | ||
85 | (unmask ? (1 << VNIC_INTR_UNMASK_SHIFT) : 0) | | ||
86 | (reset_timer ? (1 << VNIC_INTR_RESET_TIMER_SHIFT) : 0); | ||
87 | |||
88 | iowrite32(int_credit_return, &intr->ctrl->int_credit_return); | ||
89 | } | ||
90 | |||
91 | static inline unsigned int vnic_intr_credits(struct vnic_intr *intr) | ||
92 | { | ||
93 | return ioread32(&intr->ctrl->int_credits); | ||
94 | } | ||
95 | |||
96 | static inline void vnic_intr_return_all_credits(struct vnic_intr *intr) | ||
97 | { | ||
98 | unsigned int credits = vnic_intr_credits(intr); | ||
99 | int unmask = 1; | ||
100 | int reset_timer = 1; | ||
101 | |||
102 | vnic_intr_return_credits(intr, credits, unmask, reset_timer); | ||
103 | } | ||
104 | |||
105 | static inline u32 vnic_intr_legacy_pba(u32 __iomem *legacy_pba) | ||
106 | { | ||
107 | /* read PBA without clearing */ | ||
108 | return ioread32(legacy_pba); | ||
109 | } | ||
110 | |||
111 | void vnic_intr_free(struct vnic_intr *intr); | ||
112 | int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr, | ||
113 | unsigned int index); | ||
114 | void vnic_intr_init(struct vnic_intr *intr, unsigned int coalescing_timer, | ||
115 | unsigned int coalescing_type, unsigned int mask_on_assertion); | ||
116 | void vnic_intr_clean(struct vnic_intr *intr); | ||
117 | |||
118 | #endif /* _VNIC_INTR_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_nic.h b/drivers/scsi/fnic/vnic_nic.h new file mode 100644 index 000000000000..f15b83eeaced --- /dev/null +++ b/drivers/scsi/fnic/vnic_nic.h | |||
@@ -0,0 +1,69 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_NIC_H_ | ||
19 | #define _VNIC_NIC_H_ | ||
20 | |||
21 | /* | ||
22 | * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth | ||
23 | * Driver) when both are built with CONFIG options =y | ||
24 | */ | ||
25 | #define vnic_set_nic_cfg fnic_set_nic_cfg | ||
26 | |||
27 | #define NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD 0xffUL | ||
28 | #define NIC_CFG_RSS_DEFAULT_CPU_SHIFT 0 | ||
29 | #define NIC_CFG_RSS_HASH_TYPE (0xffUL << 8) | ||
30 | #define NIC_CFG_RSS_HASH_TYPE_MASK_FIELD 0xffUL | ||
31 | #define NIC_CFG_RSS_HASH_TYPE_SHIFT 8 | ||
32 | #define NIC_CFG_RSS_HASH_BITS (7UL << 16) | ||
33 | #define NIC_CFG_RSS_HASH_BITS_MASK_FIELD 7UL | ||
34 | #define NIC_CFG_RSS_HASH_BITS_SHIFT 16 | ||
35 | #define NIC_CFG_RSS_BASE_CPU (7UL << 19) | ||
36 | #define NIC_CFG_RSS_BASE_CPU_MASK_FIELD 7UL | ||
37 | #define NIC_CFG_RSS_BASE_CPU_SHIFT 19 | ||
38 | #define NIC_CFG_RSS_ENABLE (1UL << 22) | ||
39 | #define NIC_CFG_RSS_ENABLE_MASK_FIELD 1UL | ||
40 | #define NIC_CFG_RSS_ENABLE_SHIFT 22 | ||
41 | #define NIC_CFG_TSO_IPID_SPLIT_EN (1UL << 23) | ||
42 | #define NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD 1UL | ||
43 | #define NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT 23 | ||
44 | #define NIC_CFG_IG_VLAN_STRIP_EN (1UL << 24) | ||
45 | #define NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD 1UL | ||
46 | #define NIC_CFG_IG_VLAN_STRIP_EN_SHIFT 24 | ||
47 | |||
48 | static inline void vnic_set_nic_cfg(u32 *nic_cfg, | ||
49 | u8 rss_default_cpu, u8 rss_hash_type, | ||
50 | u8 rss_hash_bits, u8 rss_base_cpu, | ||
51 | u8 rss_enable, u8 tso_ipid_split_en, | ||
52 | u8 ig_vlan_strip_en) | ||
53 | { | ||
54 | *nic_cfg = (rss_default_cpu & NIC_CFG_RSS_DEFAULT_CPU_MASK_FIELD) | | ||
55 | ((rss_hash_type & NIC_CFG_RSS_HASH_TYPE_MASK_FIELD) | ||
56 | << NIC_CFG_RSS_HASH_TYPE_SHIFT) | | ||
57 | ((rss_hash_bits & NIC_CFG_RSS_HASH_BITS_MASK_FIELD) | ||
58 | << NIC_CFG_RSS_HASH_BITS_SHIFT) | | ||
59 | ((rss_base_cpu & NIC_CFG_RSS_BASE_CPU_MASK_FIELD) | ||
60 | << NIC_CFG_RSS_BASE_CPU_SHIFT) | | ||
61 | ((rss_enable & NIC_CFG_RSS_ENABLE_MASK_FIELD) | ||
62 | << NIC_CFG_RSS_ENABLE_SHIFT) | | ||
63 | ((tso_ipid_split_en & NIC_CFG_TSO_IPID_SPLIT_EN_MASK_FIELD) | ||
64 | << NIC_CFG_TSO_IPID_SPLIT_EN_SHIFT) | | ||
65 | ((ig_vlan_strip_en & NIC_CFG_IG_VLAN_STRIP_EN_MASK_FIELD) | ||
66 | << NIC_CFG_IG_VLAN_STRIP_EN_SHIFT); | ||
67 | } | ||
68 | |||
69 | #endif /* _VNIC_NIC_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_resource.h b/drivers/scsi/fnic/vnic_resource.h new file mode 100644 index 000000000000..2d842f79d41a --- /dev/null +++ b/drivers/scsi/fnic/vnic_resource.h | |||
@@ -0,0 +1,61 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_RESOURCE_H_ | ||
19 | #define _VNIC_RESOURCE_H_ | ||
20 | |||
21 | #define VNIC_RES_MAGIC 0x766E6963L /* 'vnic' */ | ||
22 | #define VNIC_RES_VERSION 0x00000000L | ||
23 | |||
24 | /* vNIC resource types */ | ||
25 | enum vnic_res_type { | ||
26 | RES_TYPE_EOL, /* End-of-list */ | ||
27 | RES_TYPE_WQ, /* Work queues */ | ||
28 | RES_TYPE_RQ, /* Receive queues */ | ||
29 | RES_TYPE_CQ, /* Completion queues */ | ||
30 | RES_TYPE_RSVD1, | ||
31 | RES_TYPE_NIC_CFG, /* Enet NIC config registers */ | ||
32 | RES_TYPE_RSVD2, | ||
33 | RES_TYPE_RSVD3, | ||
34 | RES_TYPE_RSVD4, | ||
35 | RES_TYPE_RSVD5, | ||
36 | RES_TYPE_INTR_CTRL, /* Interrupt ctrl table */ | ||
37 | RES_TYPE_INTR_TABLE, /* MSI/MSI-X Interrupt table */ | ||
38 | RES_TYPE_INTR_PBA, /* MSI/MSI-X PBA table */ | ||
39 | RES_TYPE_INTR_PBA_LEGACY, /* Legacy intr status */ | ||
40 | RES_TYPE_RSVD6, | ||
41 | RES_TYPE_RSVD7, | ||
42 | RES_TYPE_DEVCMD, /* Device command region */ | ||
43 | RES_TYPE_PASS_THRU_PAGE, /* Pass-thru page */ | ||
44 | |||
45 | RES_TYPE_MAX, /* Count of resource types */ | ||
46 | }; | ||
47 | |||
48 | struct vnic_resource_header { | ||
49 | u32 magic; | ||
50 | u32 version; | ||
51 | }; | ||
52 | |||
53 | struct vnic_resource { | ||
54 | u8 type; | ||
55 | u8 bar; | ||
56 | u8 pad[2]; | ||
57 | u32 bar_offset; | ||
58 | u32 count; | ||
59 | }; | ||
60 | |||
61 | #endif /* _VNIC_RESOURCE_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_rq.c b/drivers/scsi/fnic/vnic_rq.c new file mode 100644 index 000000000000..bedd0d285630 --- /dev/null +++ b/drivers/scsi/fnic/vnic_rq.c | |||
@@ -0,0 +1,196 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | #include <linux/errno.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include "vnic_dev.h" | ||
24 | #include "vnic_rq.h" | ||
25 | |||
26 | static int vnic_rq_alloc_bufs(struct vnic_rq *rq) | ||
27 | { | ||
28 | struct vnic_rq_buf *buf; | ||
29 | struct vnic_dev *vdev; | ||
30 | unsigned int i, j, count = rq->ring.desc_count; | ||
31 | unsigned int blks = VNIC_RQ_BUF_BLKS_NEEDED(count); | ||
32 | |||
33 | vdev = rq->vdev; | ||
34 | |||
35 | for (i = 0; i < blks; i++) { | ||
36 | rq->bufs[i] = kzalloc(VNIC_RQ_BUF_BLK_SZ, GFP_ATOMIC); | ||
37 | if (!rq->bufs[i]) { | ||
38 | printk(KERN_ERR "Failed to alloc rq_bufs\n"); | ||
39 | return -ENOMEM; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | for (i = 0; i < blks; i++) { | ||
44 | buf = rq->bufs[i]; | ||
45 | for (j = 0; j < VNIC_RQ_BUF_BLK_ENTRIES; j++) { | ||
46 | buf->index = i * VNIC_RQ_BUF_BLK_ENTRIES + j; | ||
47 | buf->desc = (u8 *)rq->ring.descs + | ||
48 | rq->ring.desc_size * buf->index; | ||
49 | if (buf->index + 1 == count) { | ||
50 | buf->next = rq->bufs[0]; | ||
51 | break; | ||
52 | } else if (j + 1 == VNIC_RQ_BUF_BLK_ENTRIES) { | ||
53 | buf->next = rq->bufs[i + 1]; | ||
54 | } else { | ||
55 | buf->next = buf + 1; | ||
56 | buf++; | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | rq->to_use = rq->to_clean = rq->bufs[0]; | ||
62 | rq->buf_index = 0; | ||
63 | |||
64 | return 0; | ||
65 | } | ||
66 | |||
67 | void vnic_rq_free(struct vnic_rq *rq) | ||
68 | { | ||
69 | struct vnic_dev *vdev; | ||
70 | unsigned int i; | ||
71 | |||
72 | vdev = rq->vdev; | ||
73 | |||
74 | vnic_dev_free_desc_ring(vdev, &rq->ring); | ||
75 | |||
76 | for (i = 0; i < VNIC_RQ_BUF_BLKS_MAX; i++) { | ||
77 | kfree(rq->bufs[i]); | ||
78 | rq->bufs[i] = NULL; | ||
79 | } | ||
80 | |||
81 | rq->ctrl = NULL; | ||
82 | } | ||
83 | |||
84 | int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, | ||
85 | unsigned int desc_count, unsigned int desc_size) | ||
86 | { | ||
87 | int err; | ||
88 | |||
89 | rq->index = index; | ||
90 | rq->vdev = vdev; | ||
91 | |||
92 | rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index); | ||
93 | if (!rq->ctrl) { | ||
94 | printk(KERN_ERR "Failed to hook RQ[%d] resource\n", index); | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | |||
98 | vnic_rq_disable(rq); | ||
99 | |||
100 | err = vnic_dev_alloc_desc_ring(vdev, &rq->ring, desc_count, desc_size); | ||
101 | if (err) | ||
102 | return err; | ||
103 | |||
104 | err = vnic_rq_alloc_bufs(rq); | ||
105 | if (err) { | ||
106 | vnic_rq_free(rq); | ||
107 | return err; | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, | ||
114 | unsigned int error_interrupt_enable, | ||
115 | unsigned int error_interrupt_offset) | ||
116 | { | ||
117 | u64 paddr; | ||
118 | u32 fetch_index; | ||
119 | |||
120 | paddr = (u64)rq->ring.base_addr | VNIC_PADDR_TARGET; | ||
121 | writeq(paddr, &rq->ctrl->ring_base); | ||
122 | iowrite32(rq->ring.desc_count, &rq->ctrl->ring_size); | ||
123 | iowrite32(cq_index, &rq->ctrl->cq_index); | ||
124 | iowrite32(error_interrupt_enable, &rq->ctrl->error_interrupt_enable); | ||
125 | iowrite32(error_interrupt_offset, &rq->ctrl->error_interrupt_offset); | ||
126 | iowrite32(0, &rq->ctrl->dropped_packet_count); | ||
127 | iowrite32(0, &rq->ctrl->error_status); | ||
128 | |||
129 | /* Use current fetch_index as the ring starting point */ | ||
130 | fetch_index = ioread32(&rq->ctrl->fetch_index); | ||
131 | rq->to_use = rq->to_clean = | ||
132 | &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES] | ||
133 | [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES]; | ||
134 | iowrite32(fetch_index, &rq->ctrl->posted_index); | ||
135 | |||
136 | rq->buf_index = 0; | ||
137 | } | ||
138 | |||
139 | unsigned int vnic_rq_error_status(struct vnic_rq *rq) | ||
140 | { | ||
141 | return ioread32(&rq->ctrl->error_status); | ||
142 | } | ||
143 | |||
144 | void vnic_rq_enable(struct vnic_rq *rq) | ||
145 | { | ||
146 | iowrite32(1, &rq->ctrl->enable); | ||
147 | } | ||
148 | |||
149 | int vnic_rq_disable(struct vnic_rq *rq) | ||
150 | { | ||
151 | unsigned int wait; | ||
152 | |||
153 | iowrite32(0, &rq->ctrl->enable); | ||
154 | |||
155 | /* Wait for HW to ACK disable request */ | ||
156 | for (wait = 0; wait < 100; wait++) { | ||
157 | if (!(ioread32(&rq->ctrl->running))) | ||
158 | return 0; | ||
159 | udelay(1); | ||
160 | } | ||
161 | |||
162 | printk(KERN_ERR "Failed to disable RQ[%d]\n", rq->index); | ||
163 | |||
164 | return -ETIMEDOUT; | ||
165 | } | ||
166 | |||
167 | void vnic_rq_clean(struct vnic_rq *rq, | ||
168 | void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf)) | ||
169 | { | ||
170 | struct vnic_rq_buf *buf; | ||
171 | u32 fetch_index; | ||
172 | |||
173 | BUG_ON(ioread32(&rq->ctrl->enable)); | ||
174 | |||
175 | buf = rq->to_clean; | ||
176 | |||
177 | while (vnic_rq_desc_used(rq) > 0) { | ||
178 | |||
179 | (*buf_clean)(rq, buf); | ||
180 | |||
181 | buf = rq->to_clean = buf->next; | ||
182 | rq->ring.desc_avail++; | ||
183 | } | ||
184 | |||
185 | /* Use current fetch_index as the ring starting point */ | ||
186 | fetch_index = ioread32(&rq->ctrl->fetch_index); | ||
187 | rq->to_use = rq->to_clean = | ||
188 | &rq->bufs[fetch_index / VNIC_RQ_BUF_BLK_ENTRIES] | ||
189 | [fetch_index % VNIC_RQ_BUF_BLK_ENTRIES]; | ||
190 | iowrite32(fetch_index, &rq->ctrl->posted_index); | ||
191 | |||
192 | rq->buf_index = 0; | ||
193 | |||
194 | vnic_dev_clear_desc_ring(&rq->ring); | ||
195 | } | ||
196 | |||
diff --git a/drivers/scsi/fnic/vnic_rq.h b/drivers/scsi/fnic/vnic_rq.h new file mode 100644 index 000000000000..aebdfbd6ad3c --- /dev/null +++ b/drivers/scsi/fnic/vnic_rq.h | |||
@@ -0,0 +1,235 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_RQ_H_ | ||
19 | #define _VNIC_RQ_H_ | ||
20 | |||
21 | #include <linux/pci.h> | ||
22 | #include "vnic_dev.h" | ||
23 | #include "vnic_cq.h" | ||
24 | |||
25 | /* | ||
26 | * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth | ||
27 | * Driver) when both are built with CONFIG options =y | ||
28 | */ | ||
29 | #define vnic_rq_desc_avail fnic_rq_desc_avail | ||
30 | #define vnic_rq_desc_used fnic_rq_desc_used | ||
31 | #define vnic_rq_next_desc fnic_rq_next_desc | ||
32 | #define vnic_rq_next_index fnic_rq_next_index | ||
33 | #define vnic_rq_next_buf_index fnic_rq_next_buf_index | ||
34 | #define vnic_rq_post fnic_rq_post | ||
35 | #define vnic_rq_posting_soon fnic_rq_posting_soon | ||
36 | #define vnic_rq_return_descs fnic_rq_return_descs | ||
37 | #define vnic_rq_service fnic_rq_service | ||
38 | #define vnic_rq_fill fnic_rq_fill | ||
39 | #define vnic_rq_free fnic_rq_free | ||
40 | #define vnic_rq_alloc fnic_rq_alloc | ||
41 | #define vnic_rq_init fnic_rq_init | ||
42 | #define vnic_rq_error_status fnic_rq_error_status | ||
43 | #define vnic_rq_enable fnic_rq_enable | ||
44 | #define vnic_rq_disable fnic_rq_disable | ||
45 | #define vnic_rq_clean fnic_rq_clean | ||
46 | |||
47 | /* Receive queue control */ | ||
48 | struct vnic_rq_ctrl { | ||
49 | u64 ring_base; /* 0x00 */ | ||
50 | u32 ring_size; /* 0x08 */ | ||
51 | u32 pad0; | ||
52 | u32 posted_index; /* 0x10 */ | ||
53 | u32 pad1; | ||
54 | u32 cq_index; /* 0x18 */ | ||
55 | u32 pad2; | ||
56 | u32 enable; /* 0x20 */ | ||
57 | u32 pad3; | ||
58 | u32 running; /* 0x28 */ | ||
59 | u32 pad4; | ||
60 | u32 fetch_index; /* 0x30 */ | ||
61 | u32 pad5; | ||
62 | u32 error_interrupt_enable; /* 0x38 */ | ||
63 | u32 pad6; | ||
64 | u32 error_interrupt_offset; /* 0x40 */ | ||
65 | u32 pad7; | ||
66 | u32 error_status; /* 0x48 */ | ||
67 | u32 pad8; | ||
68 | u32 dropped_packet_count; /* 0x50 */ | ||
69 | u32 pad9; | ||
70 | u32 dropped_packet_count_rc; /* 0x58 */ | ||
71 | u32 pad10; | ||
72 | }; | ||
73 | |||
74 | /* Break the vnic_rq_buf allocations into blocks of 64 entries */ | ||
75 | #define VNIC_RQ_BUF_BLK_ENTRIES 64 | ||
76 | #define VNIC_RQ_BUF_BLK_SZ \ | ||
77 | (VNIC_RQ_BUF_BLK_ENTRIES * sizeof(struct vnic_rq_buf)) | ||
78 | #define VNIC_RQ_BUF_BLKS_NEEDED(entries) \ | ||
79 | DIV_ROUND_UP(entries, VNIC_RQ_BUF_BLK_ENTRIES) | ||
80 | #define VNIC_RQ_BUF_BLKS_MAX VNIC_RQ_BUF_BLKS_NEEDED(4096) | ||
81 | |||
82 | struct vnic_rq_buf { | ||
83 | struct vnic_rq_buf *next; | ||
84 | dma_addr_t dma_addr; | ||
85 | void *os_buf; | ||
86 | unsigned int os_buf_index; | ||
87 | unsigned int len; | ||
88 | unsigned int index; | ||
89 | void *desc; | ||
90 | }; | ||
91 | |||
92 | struct vnic_rq { | ||
93 | unsigned int index; | ||
94 | struct vnic_dev *vdev; | ||
95 | struct vnic_rq_ctrl __iomem *ctrl; /* memory-mapped */ | ||
96 | struct vnic_dev_ring ring; | ||
97 | struct vnic_rq_buf *bufs[VNIC_RQ_BUF_BLKS_MAX]; | ||
98 | struct vnic_rq_buf *to_use; | ||
99 | struct vnic_rq_buf *to_clean; | ||
100 | void *os_buf_head; | ||
101 | unsigned int buf_index; | ||
102 | unsigned int pkts_outstanding; | ||
103 | }; | ||
104 | |||
105 | static inline unsigned int vnic_rq_desc_avail(struct vnic_rq *rq) | ||
106 | { | ||
107 | /* how many does SW own? */ | ||
108 | return rq->ring.desc_avail; | ||
109 | } | ||
110 | |||
111 | static inline unsigned int vnic_rq_desc_used(struct vnic_rq *rq) | ||
112 | { | ||
113 | /* how many does HW own? */ | ||
114 | return rq->ring.desc_count - rq->ring.desc_avail - 1; | ||
115 | } | ||
116 | |||
117 | static inline void *vnic_rq_next_desc(struct vnic_rq *rq) | ||
118 | { | ||
119 | return rq->to_use->desc; | ||
120 | } | ||
121 | |||
122 | static inline unsigned int vnic_rq_next_index(struct vnic_rq *rq) | ||
123 | { | ||
124 | return rq->to_use->index; | ||
125 | } | ||
126 | |||
127 | static inline unsigned int vnic_rq_next_buf_index(struct vnic_rq *rq) | ||
128 | { | ||
129 | return rq->buf_index++; | ||
130 | } | ||
131 | |||
132 | static inline void vnic_rq_post(struct vnic_rq *rq, | ||
133 | void *os_buf, unsigned int os_buf_index, | ||
134 | dma_addr_t dma_addr, unsigned int len) | ||
135 | { | ||
136 | struct vnic_rq_buf *buf = rq->to_use; | ||
137 | |||
138 | buf->os_buf = os_buf; | ||
139 | buf->os_buf_index = os_buf_index; | ||
140 | buf->dma_addr = dma_addr; | ||
141 | buf->len = len; | ||
142 | |||
143 | buf = buf->next; | ||
144 | rq->to_use = buf; | ||
145 | rq->ring.desc_avail--; | ||
146 | |||
147 | /* Move the posted_index every nth descriptor | ||
148 | */ | ||
149 | |||
150 | #ifndef VNIC_RQ_RETURN_RATE | ||
151 | #define VNIC_RQ_RETURN_RATE 0xf /* keep 2^n - 1 */ | ||
152 | #endif | ||
153 | |||
154 | if ((buf->index & VNIC_RQ_RETURN_RATE) == 0) { | ||
155 | /* Adding write memory barrier prevents compiler and/or CPU | ||
156 | * reordering, thus avoiding descriptor posting before | ||
157 | * descriptor is initialized. Otherwise, hardware can read | ||
158 | * stale descriptor fields. | ||
159 | */ | ||
160 | wmb(); | ||
161 | iowrite32(buf->index, &rq->ctrl->posted_index); | ||
162 | } | ||
163 | } | ||
164 | |||
165 | static inline int vnic_rq_posting_soon(struct vnic_rq *rq) | ||
166 | { | ||
167 | return (rq->to_use->index & VNIC_RQ_RETURN_RATE) == 0; | ||
168 | } | ||
169 | |||
170 | static inline void vnic_rq_return_descs(struct vnic_rq *rq, unsigned int count) | ||
171 | { | ||
172 | rq->ring.desc_avail += count; | ||
173 | } | ||
174 | |||
175 | enum desc_return_options { | ||
176 | VNIC_RQ_RETURN_DESC, | ||
177 | VNIC_RQ_DEFER_RETURN_DESC, | ||
178 | }; | ||
179 | |||
180 | static inline void vnic_rq_service(struct vnic_rq *rq, | ||
181 | struct cq_desc *cq_desc, u16 completed_index, | ||
182 | int desc_return, void (*buf_service)(struct vnic_rq *rq, | ||
183 | struct cq_desc *cq_desc, struct vnic_rq_buf *buf, | ||
184 | int skipped, void *opaque), void *opaque) | ||
185 | { | ||
186 | struct vnic_rq_buf *buf; | ||
187 | int skipped; | ||
188 | |||
189 | buf = rq->to_clean; | ||
190 | while (1) { | ||
191 | |||
192 | skipped = (buf->index != completed_index); | ||
193 | |||
194 | (*buf_service)(rq, cq_desc, buf, skipped, opaque); | ||
195 | |||
196 | if (desc_return == VNIC_RQ_RETURN_DESC) | ||
197 | rq->ring.desc_avail++; | ||
198 | |||
199 | rq->to_clean = buf->next; | ||
200 | |||
201 | if (!skipped) | ||
202 | break; | ||
203 | |||
204 | buf = rq->to_clean; | ||
205 | } | ||
206 | } | ||
207 | |||
208 | static inline int vnic_rq_fill(struct vnic_rq *rq, | ||
209 | int (*buf_fill)(struct vnic_rq *rq)) | ||
210 | { | ||
211 | int err; | ||
212 | |||
213 | while (vnic_rq_desc_avail(rq) > 1) { | ||
214 | |||
215 | err = (*buf_fill)(rq); | ||
216 | if (err) | ||
217 | return err; | ||
218 | } | ||
219 | |||
220 | return 0; | ||
221 | } | ||
222 | |||
223 | void vnic_rq_free(struct vnic_rq *rq); | ||
224 | int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index, | ||
225 | unsigned int desc_count, unsigned int desc_size); | ||
226 | void vnic_rq_init(struct vnic_rq *rq, unsigned int cq_index, | ||
227 | unsigned int error_interrupt_enable, | ||
228 | unsigned int error_interrupt_offset); | ||
229 | unsigned int vnic_rq_error_status(struct vnic_rq *rq); | ||
230 | void vnic_rq_enable(struct vnic_rq *rq); | ||
231 | int vnic_rq_disable(struct vnic_rq *rq); | ||
232 | void vnic_rq_clean(struct vnic_rq *rq, | ||
233 | void (*buf_clean)(struct vnic_rq *rq, struct vnic_rq_buf *buf)); | ||
234 | |||
235 | #endif /* _VNIC_RQ_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_scsi.h b/drivers/scsi/fnic/vnic_scsi.h new file mode 100644 index 000000000000..46baa5254001 --- /dev/null +++ b/drivers/scsi/fnic/vnic_scsi.h | |||
@@ -0,0 +1,99 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_SCSI_H_ | ||
19 | #define _VNIC_SCSI_H_ | ||
20 | |||
21 | #define VNIC_FNIC_WQ_COPY_COUNT_MIN 1 | ||
22 | #define VNIC_FNIC_WQ_COPY_COUNT_MAX 1 | ||
23 | |||
24 | #define VNIC_FNIC_WQ_DESCS_MIN 64 | ||
25 | #define VNIC_FNIC_WQ_DESCS_MAX 128 | ||
26 | |||
27 | #define VNIC_FNIC_WQ_COPY_DESCS_MIN 64 | ||
28 | #define VNIC_FNIC_WQ_COPY_DESCS_MAX 512 | ||
29 | |||
30 | #define VNIC_FNIC_RQ_DESCS_MIN 64 | ||
31 | #define VNIC_FNIC_RQ_DESCS_MAX 128 | ||
32 | |||
33 | #define VNIC_FNIC_EDTOV_MIN 1000 | ||
34 | #define VNIC_FNIC_EDTOV_MAX 255000 | ||
35 | #define VNIC_FNIC_EDTOV_DEF 2000 | ||
36 | |||
37 | #define VNIC_FNIC_RATOV_MIN 1000 | ||
38 | #define VNIC_FNIC_RATOV_MAX 255000 | ||
39 | |||
40 | #define VNIC_FNIC_MAXDATAFIELDSIZE_MIN 256 | ||
41 | #define VNIC_FNIC_MAXDATAFIELDSIZE_MAX 2112 | ||
42 | |||
43 | #define VNIC_FNIC_FLOGI_RETRIES_MIN 0 | ||
44 | #define VNIC_FNIC_FLOGI_RETRIES_MAX 0xffffffff | ||
45 | #define VNIC_FNIC_FLOGI_RETRIES_DEF 0xffffffff | ||
46 | |||
47 | #define VNIC_FNIC_FLOGI_TIMEOUT_MIN 1000 | ||
48 | #define VNIC_FNIC_FLOGI_TIMEOUT_MAX 255000 | ||
49 | |||
50 | #define VNIC_FNIC_PLOGI_RETRIES_MIN 0 | ||
51 | #define VNIC_FNIC_PLOGI_RETRIES_MAX 255 | ||
52 | #define VNIC_FNIC_PLOGI_RETRIES_DEF 8 | ||
53 | |||
54 | #define VNIC_FNIC_PLOGI_TIMEOUT_MIN 1000 | ||
55 | #define VNIC_FNIC_PLOGI_TIMEOUT_MAX 255000 | ||
56 | |||
57 | #define VNIC_FNIC_IO_THROTTLE_COUNT_MIN 256 | ||
58 | #define VNIC_FNIC_IO_THROTTLE_COUNT_MAX 4096 | ||
59 | |||
60 | #define VNIC_FNIC_LINK_DOWN_TIMEOUT_MIN 0 | ||
61 | #define VNIC_FNIC_LINK_DOWN_TIMEOUT_MAX 240000 | ||
62 | |||
63 | #define VNIC_FNIC_PORT_DOWN_TIMEOUT_MIN 0 | ||
64 | #define VNIC_FNIC_PORT_DOWN_TIMEOUT_MAX 240000 | ||
65 | |||
66 | #define VNIC_FNIC_PORT_DOWN_IO_RETRIES_MIN 0 | ||
67 | #define VNIC_FNIC_PORT_DOWN_IO_RETRIES_MAX 255 | ||
68 | |||
69 | #define VNIC_FNIC_LUNS_PER_TARGET_MIN 1 | ||
70 | #define VNIC_FNIC_LUNS_PER_TARGET_MAX 1024 | ||
71 | |||
72 | /* Device-specific region: scsi configuration */ | ||
73 | struct vnic_fc_config { | ||
74 | u64 node_wwn; | ||
75 | u64 port_wwn; | ||
76 | u32 flags; | ||
77 | u32 wq_enet_desc_count; | ||
78 | u32 wq_copy_desc_count; | ||
79 | u32 rq_desc_count; | ||
80 | u32 flogi_retries; | ||
81 | u32 flogi_timeout; | ||
82 | u32 plogi_retries; | ||
83 | u32 plogi_timeout; | ||
84 | u32 io_throttle_count; | ||
85 | u32 link_down_timeout; | ||
86 | u32 port_down_timeout; | ||
87 | u32 port_down_io_retries; | ||
88 | u32 luns_per_tgt; | ||
89 | u16 maxdatafieldsize; | ||
90 | u16 ed_tov; | ||
91 | u16 ra_tov; | ||
92 | u16 intr_timer; | ||
93 | u8 intr_timer_type; | ||
94 | }; | ||
95 | |||
96 | #define VFCF_FCP_SEQ_LVL_ERR 0x1 /* Enable FCP-2 Error Recovery */ | ||
97 | #define VFCF_PERBI 0x2 /* persistent binding info available */ | ||
98 | |||
99 | #endif /* _VNIC_SCSI_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_stats.h b/drivers/scsi/fnic/vnic_stats.h new file mode 100644 index 000000000000..5372e23c1cb3 --- /dev/null +++ b/drivers/scsi/fnic/vnic_stats.h | |||
@@ -0,0 +1,68 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_STATS_H_ | ||
19 | #define _VNIC_STATS_H_ | ||
20 | |||
21 | /* Tx statistics */ | ||
22 | struct vnic_tx_stats { | ||
23 | u64 tx_frames_ok; | ||
24 | u64 tx_unicast_frames_ok; | ||
25 | u64 tx_multicast_frames_ok; | ||
26 | u64 tx_broadcast_frames_ok; | ||
27 | u64 tx_bytes_ok; | ||
28 | u64 tx_unicast_bytes_ok; | ||
29 | u64 tx_multicast_bytes_ok; | ||
30 | u64 tx_broadcast_bytes_ok; | ||
31 | u64 tx_drops; | ||
32 | u64 tx_errors; | ||
33 | u64 tx_tso; | ||
34 | u64 rsvd[16]; | ||
35 | }; | ||
36 | |||
37 | /* Rx statistics */ | ||
38 | struct vnic_rx_stats { | ||
39 | u64 rx_frames_ok; | ||
40 | u64 rx_frames_total; | ||
41 | u64 rx_unicast_frames_ok; | ||
42 | u64 rx_multicast_frames_ok; | ||
43 | u64 rx_broadcast_frames_ok; | ||
44 | u64 rx_bytes_ok; | ||
45 | u64 rx_unicast_bytes_ok; | ||
46 | u64 rx_multicast_bytes_ok; | ||
47 | u64 rx_broadcast_bytes_ok; | ||
48 | u64 rx_drop; | ||
49 | u64 rx_no_bufs; | ||
50 | u64 rx_errors; | ||
51 | u64 rx_rss; | ||
52 | u64 rx_crc_errors; | ||
53 | u64 rx_frames_64; | ||
54 | u64 rx_frames_127; | ||
55 | u64 rx_frames_255; | ||
56 | u64 rx_frames_511; | ||
57 | u64 rx_frames_1023; | ||
58 | u64 rx_frames_1518; | ||
59 | u64 rx_frames_to_max; | ||
60 | u64 rsvd[16]; | ||
61 | }; | ||
62 | |||
63 | struct vnic_stats { | ||
64 | struct vnic_tx_stats tx; | ||
65 | struct vnic_rx_stats rx; | ||
66 | }; | ||
67 | |||
68 | #endif /* _VNIC_STATS_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_wq.c b/drivers/scsi/fnic/vnic_wq.c new file mode 100644 index 000000000000..1f9ea790d130 --- /dev/null +++ b/drivers/scsi/fnic/vnic_wq.c | |||
@@ -0,0 +1,182 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | #include <linux/errno.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include "vnic_dev.h" | ||
24 | #include "vnic_wq.h" | ||
25 | |||
26 | static int vnic_wq_alloc_bufs(struct vnic_wq *wq) | ||
27 | { | ||
28 | struct vnic_wq_buf *buf; | ||
29 | struct vnic_dev *vdev; | ||
30 | unsigned int i, j, count = wq->ring.desc_count; | ||
31 | unsigned int blks = VNIC_WQ_BUF_BLKS_NEEDED(count); | ||
32 | |||
33 | vdev = wq->vdev; | ||
34 | |||
35 | for (i = 0; i < blks; i++) { | ||
36 | wq->bufs[i] = kzalloc(VNIC_WQ_BUF_BLK_SZ, GFP_ATOMIC); | ||
37 | if (!wq->bufs[i]) { | ||
38 | printk(KERN_ERR "Failed to alloc wq_bufs\n"); | ||
39 | return -ENOMEM; | ||
40 | } | ||
41 | } | ||
42 | |||
43 | for (i = 0; i < blks; i++) { | ||
44 | buf = wq->bufs[i]; | ||
45 | for (j = 0; j < VNIC_WQ_BUF_BLK_ENTRIES; j++) { | ||
46 | buf->index = i * VNIC_WQ_BUF_BLK_ENTRIES + j; | ||
47 | buf->desc = (u8 *)wq->ring.descs + | ||
48 | wq->ring.desc_size * buf->index; | ||
49 | if (buf->index + 1 == count) { | ||
50 | buf->next = wq->bufs[0]; | ||
51 | break; | ||
52 | } else if (j + 1 == VNIC_WQ_BUF_BLK_ENTRIES) { | ||
53 | buf->next = wq->bufs[i + 1]; | ||
54 | } else { | ||
55 | buf->next = buf + 1; | ||
56 | buf++; | ||
57 | } | ||
58 | } | ||
59 | } | ||
60 | |||
61 | wq->to_use = wq->to_clean = wq->bufs[0]; | ||
62 | |||
63 | return 0; | ||
64 | } | ||
65 | |||
66 | void vnic_wq_free(struct vnic_wq *wq) | ||
67 | { | ||
68 | struct vnic_dev *vdev; | ||
69 | unsigned int i; | ||
70 | |||
71 | vdev = wq->vdev; | ||
72 | |||
73 | vnic_dev_free_desc_ring(vdev, &wq->ring); | ||
74 | |||
75 | for (i = 0; i < VNIC_WQ_BUF_BLKS_MAX; i++) { | ||
76 | kfree(wq->bufs[i]); | ||
77 | wq->bufs[i] = NULL; | ||
78 | } | ||
79 | |||
80 | wq->ctrl = NULL; | ||
81 | |||
82 | } | ||
83 | |||
84 | int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, | ||
85 | unsigned int desc_count, unsigned int desc_size) | ||
86 | { | ||
87 | int err; | ||
88 | |||
89 | wq->index = index; | ||
90 | wq->vdev = vdev; | ||
91 | |||
92 | wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index); | ||
93 | if (!wq->ctrl) { | ||
94 | printk(KERN_ERR "Failed to hook WQ[%d] resource\n", index); | ||
95 | return -EINVAL; | ||
96 | } | ||
97 | |||
98 | vnic_wq_disable(wq); | ||
99 | |||
100 | err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size); | ||
101 | if (err) | ||
102 | return err; | ||
103 | |||
104 | err = vnic_wq_alloc_bufs(wq); | ||
105 | if (err) { | ||
106 | vnic_wq_free(wq); | ||
107 | return err; | ||
108 | } | ||
109 | |||
110 | return 0; | ||
111 | } | ||
112 | |||
113 | void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, | ||
114 | unsigned int error_interrupt_enable, | ||
115 | unsigned int error_interrupt_offset) | ||
116 | { | ||
117 | u64 paddr; | ||
118 | |||
119 | paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET; | ||
120 | writeq(paddr, &wq->ctrl->ring_base); | ||
121 | iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size); | ||
122 | iowrite32(0, &wq->ctrl->fetch_index); | ||
123 | iowrite32(0, &wq->ctrl->posted_index); | ||
124 | iowrite32(cq_index, &wq->ctrl->cq_index); | ||
125 | iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable); | ||
126 | iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset); | ||
127 | iowrite32(0, &wq->ctrl->error_status); | ||
128 | } | ||
129 | |||
130 | unsigned int vnic_wq_error_status(struct vnic_wq *wq) | ||
131 | { | ||
132 | return ioread32(&wq->ctrl->error_status); | ||
133 | } | ||
134 | |||
135 | void vnic_wq_enable(struct vnic_wq *wq) | ||
136 | { | ||
137 | iowrite32(1, &wq->ctrl->enable); | ||
138 | } | ||
139 | |||
140 | int vnic_wq_disable(struct vnic_wq *wq) | ||
141 | { | ||
142 | unsigned int wait; | ||
143 | |||
144 | iowrite32(0, &wq->ctrl->enable); | ||
145 | |||
146 | /* Wait for HW to ACK disable request */ | ||
147 | for (wait = 0; wait < 100; wait++) { | ||
148 | if (!(ioread32(&wq->ctrl->running))) | ||
149 | return 0; | ||
150 | udelay(1); | ||
151 | } | ||
152 | |||
153 | printk(KERN_ERR "Failed to disable WQ[%d]\n", wq->index); | ||
154 | |||
155 | return -ETIMEDOUT; | ||
156 | } | ||
157 | |||
158 | void vnic_wq_clean(struct vnic_wq *wq, | ||
159 | void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)) | ||
160 | { | ||
161 | struct vnic_wq_buf *buf; | ||
162 | |||
163 | BUG_ON(ioread32(&wq->ctrl->enable)); | ||
164 | |||
165 | buf = wq->to_clean; | ||
166 | |||
167 | while (vnic_wq_desc_used(wq) > 0) { | ||
168 | |||
169 | (*buf_clean)(wq, buf); | ||
170 | |||
171 | buf = wq->to_clean = buf->next; | ||
172 | wq->ring.desc_avail++; | ||
173 | } | ||
174 | |||
175 | wq->to_use = wq->to_clean = wq->bufs[0]; | ||
176 | |||
177 | iowrite32(0, &wq->ctrl->fetch_index); | ||
178 | iowrite32(0, &wq->ctrl->posted_index); | ||
179 | iowrite32(0, &wq->ctrl->error_status); | ||
180 | |||
181 | vnic_dev_clear_desc_ring(&wq->ring); | ||
182 | } | ||
diff --git a/drivers/scsi/fnic/vnic_wq.h b/drivers/scsi/fnic/vnic_wq.h new file mode 100644 index 000000000000..5cd094f79281 --- /dev/null +++ b/drivers/scsi/fnic/vnic_wq.h | |||
@@ -0,0 +1,175 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_WQ_H_ | ||
19 | #define _VNIC_WQ_H_ | ||
20 | |||
21 | #include <linux/pci.h> | ||
22 | #include "vnic_dev.h" | ||
23 | #include "vnic_cq.h" | ||
24 | |||
25 | /* | ||
26 | * These defines avoid symbol clash between fnic and enic (Cisco 10G Eth | ||
27 | * Driver) when both are built with CONFIG options =y | ||
28 | */ | ||
29 | #define vnic_wq_desc_avail fnic_wq_desc_avail | ||
30 | #define vnic_wq_desc_used fnic_wq_desc_used | ||
31 | #define vnic_wq_next_desc fni_cwq_next_desc | ||
32 | #define vnic_wq_post fnic_wq_post | ||
33 | #define vnic_wq_service fnic_wq_service | ||
34 | #define vnic_wq_free fnic_wq_free | ||
35 | #define vnic_wq_alloc fnic_wq_alloc | ||
36 | #define vnic_wq_init fnic_wq_init | ||
37 | #define vnic_wq_error_status fnic_wq_error_status | ||
38 | #define vnic_wq_enable fnic_wq_enable | ||
39 | #define vnic_wq_disable fnic_wq_disable | ||
40 | #define vnic_wq_clean fnic_wq_clean | ||
41 | |||
42 | /* Work queue control */ | ||
43 | struct vnic_wq_ctrl { | ||
44 | u64 ring_base; /* 0x00 */ | ||
45 | u32 ring_size; /* 0x08 */ | ||
46 | u32 pad0; | ||
47 | u32 posted_index; /* 0x10 */ | ||
48 | u32 pad1; | ||
49 | u32 cq_index; /* 0x18 */ | ||
50 | u32 pad2; | ||
51 | u32 enable; /* 0x20 */ | ||
52 | u32 pad3; | ||
53 | u32 running; /* 0x28 */ | ||
54 | u32 pad4; | ||
55 | u32 fetch_index; /* 0x30 */ | ||
56 | u32 pad5; | ||
57 | u32 dca_value; /* 0x38 */ | ||
58 | u32 pad6; | ||
59 | u32 error_interrupt_enable; /* 0x40 */ | ||
60 | u32 pad7; | ||
61 | u32 error_interrupt_offset; /* 0x48 */ | ||
62 | u32 pad8; | ||
63 | u32 error_status; /* 0x50 */ | ||
64 | u32 pad9; | ||
65 | }; | ||
66 | |||
67 | struct vnic_wq_buf { | ||
68 | struct vnic_wq_buf *next; | ||
69 | dma_addr_t dma_addr; | ||
70 | void *os_buf; | ||
71 | unsigned int len; | ||
72 | unsigned int index; | ||
73 | int sop; | ||
74 | void *desc; | ||
75 | }; | ||
76 | |||
77 | /* Break the vnic_wq_buf allocations into blocks of 64 entries */ | ||
78 | #define VNIC_WQ_BUF_BLK_ENTRIES 64 | ||
79 | #define VNIC_WQ_BUF_BLK_SZ \ | ||
80 | (VNIC_WQ_BUF_BLK_ENTRIES * sizeof(struct vnic_wq_buf)) | ||
81 | #define VNIC_WQ_BUF_BLKS_NEEDED(entries) \ | ||
82 | DIV_ROUND_UP(entries, VNIC_WQ_BUF_BLK_ENTRIES) | ||
83 | #define VNIC_WQ_BUF_BLKS_MAX VNIC_WQ_BUF_BLKS_NEEDED(4096) | ||
84 | |||
85 | struct vnic_wq { | ||
86 | unsigned int index; | ||
87 | struct vnic_dev *vdev; | ||
88 | struct vnic_wq_ctrl __iomem *ctrl; /* memory-mapped */ | ||
89 | struct vnic_dev_ring ring; | ||
90 | struct vnic_wq_buf *bufs[VNIC_WQ_BUF_BLKS_MAX]; | ||
91 | struct vnic_wq_buf *to_use; | ||
92 | struct vnic_wq_buf *to_clean; | ||
93 | unsigned int pkts_outstanding; | ||
94 | }; | ||
95 | |||
96 | static inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq) | ||
97 | { | ||
98 | /* how many does SW own? */ | ||
99 | return wq->ring.desc_avail; | ||
100 | } | ||
101 | |||
102 | static inline unsigned int vnic_wq_desc_used(struct vnic_wq *wq) | ||
103 | { | ||
104 | /* how many does HW own? */ | ||
105 | return wq->ring.desc_count - wq->ring.desc_avail - 1; | ||
106 | } | ||
107 | |||
108 | static inline void *vnic_wq_next_desc(struct vnic_wq *wq) | ||
109 | { | ||
110 | return wq->to_use->desc; | ||
111 | } | ||
112 | |||
113 | static inline void vnic_wq_post(struct vnic_wq *wq, | ||
114 | void *os_buf, dma_addr_t dma_addr, | ||
115 | unsigned int len, int sop, int eop) | ||
116 | { | ||
117 | struct vnic_wq_buf *buf = wq->to_use; | ||
118 | |||
119 | buf->sop = sop; | ||
120 | buf->os_buf = eop ? os_buf : NULL; | ||
121 | buf->dma_addr = dma_addr; | ||
122 | buf->len = len; | ||
123 | |||
124 | buf = buf->next; | ||
125 | if (eop) { | ||
126 | /* Adding write memory barrier prevents compiler and/or CPU | ||
127 | * reordering, thus avoiding descriptor posting before | ||
128 | * descriptor is initialized. Otherwise, hardware can read | ||
129 | * stale descriptor fields. | ||
130 | */ | ||
131 | wmb(); | ||
132 | iowrite32(buf->index, &wq->ctrl->posted_index); | ||
133 | } | ||
134 | wq->to_use = buf; | ||
135 | |||
136 | wq->ring.desc_avail--; | ||
137 | } | ||
138 | |||
139 | static inline void vnic_wq_service(struct vnic_wq *wq, | ||
140 | struct cq_desc *cq_desc, u16 completed_index, | ||
141 | void (*buf_service)(struct vnic_wq *wq, | ||
142 | struct cq_desc *cq_desc, struct vnic_wq_buf *buf, void *opaque), | ||
143 | void *opaque) | ||
144 | { | ||
145 | struct vnic_wq_buf *buf; | ||
146 | |||
147 | buf = wq->to_clean; | ||
148 | while (1) { | ||
149 | |||
150 | (*buf_service)(wq, cq_desc, buf, opaque); | ||
151 | |||
152 | wq->ring.desc_avail++; | ||
153 | |||
154 | wq->to_clean = buf->next; | ||
155 | |||
156 | if (buf->index == completed_index) | ||
157 | break; | ||
158 | |||
159 | buf = wq->to_clean; | ||
160 | } | ||
161 | } | ||
162 | |||
163 | void vnic_wq_free(struct vnic_wq *wq); | ||
164 | int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, | ||
165 | unsigned int desc_count, unsigned int desc_size); | ||
166 | void vnic_wq_init(struct vnic_wq *wq, unsigned int cq_index, | ||
167 | unsigned int error_interrupt_enable, | ||
168 | unsigned int error_interrupt_offset); | ||
169 | unsigned int vnic_wq_error_status(struct vnic_wq *wq); | ||
170 | void vnic_wq_enable(struct vnic_wq *wq); | ||
171 | int vnic_wq_disable(struct vnic_wq *wq); | ||
172 | void vnic_wq_clean(struct vnic_wq *wq, | ||
173 | void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)); | ||
174 | |||
175 | #endif /* _VNIC_WQ_H_ */ | ||
diff --git a/drivers/scsi/fnic/vnic_wq_copy.c b/drivers/scsi/fnic/vnic_wq_copy.c new file mode 100644 index 000000000000..9eab7e7caf38 --- /dev/null +++ b/drivers/scsi/fnic/vnic_wq_copy.c | |||
@@ -0,0 +1,117 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | |||
19 | #include <linux/errno.h> | ||
20 | #include <linux/types.h> | ||
21 | #include <linux/pci.h> | ||
22 | #include <linux/delay.h> | ||
23 | #include "vnic_wq_copy.h" | ||
24 | |||
25 | void vnic_wq_copy_enable(struct vnic_wq_copy *wq) | ||
26 | { | ||
27 | iowrite32(1, &wq->ctrl->enable); | ||
28 | } | ||
29 | |||
30 | int vnic_wq_copy_disable(struct vnic_wq_copy *wq) | ||
31 | { | ||
32 | unsigned int wait; | ||
33 | |||
34 | iowrite32(0, &wq->ctrl->enable); | ||
35 | |||
36 | /* Wait for HW to ACK disable request */ | ||
37 | for (wait = 0; wait < 100; wait++) { | ||
38 | if (!(ioread32(&wq->ctrl->running))) | ||
39 | return 0; | ||
40 | udelay(1); | ||
41 | } | ||
42 | |||
43 | printk(KERN_ERR "Failed to disable Copy WQ[%d]," | ||
44 | " fetch index=%d, posted_index=%d\n", | ||
45 | wq->index, ioread32(&wq->ctrl->fetch_index), | ||
46 | ioread32(&wq->ctrl->posted_index)); | ||
47 | |||
48 | return -ENODEV; | ||
49 | } | ||
50 | |||
51 | void vnic_wq_copy_clean(struct vnic_wq_copy *wq, | ||
52 | void (*q_clean)(struct vnic_wq_copy *wq, | ||
53 | struct fcpio_host_req *wq_desc)) | ||
54 | { | ||
55 | BUG_ON(ioread32(&wq->ctrl->enable)); | ||
56 | |||
57 | if (vnic_wq_copy_desc_in_use(wq)) | ||
58 | vnic_wq_copy_service(wq, -1, q_clean); | ||
59 | |||
60 | wq->to_use_index = wq->to_clean_index = 0; | ||
61 | |||
62 | iowrite32(0, &wq->ctrl->fetch_index); | ||
63 | iowrite32(0, &wq->ctrl->posted_index); | ||
64 | iowrite32(0, &wq->ctrl->error_status); | ||
65 | |||
66 | vnic_dev_clear_desc_ring(&wq->ring); | ||
67 | } | ||
68 | |||
69 | void vnic_wq_copy_free(struct vnic_wq_copy *wq) | ||
70 | { | ||
71 | struct vnic_dev *vdev; | ||
72 | |||
73 | vdev = wq->vdev; | ||
74 | vnic_dev_free_desc_ring(vdev, &wq->ring); | ||
75 | wq->ctrl = NULL; | ||
76 | } | ||
77 | |||
78 | int vnic_wq_copy_alloc(struct vnic_dev *vdev, struct vnic_wq_copy *wq, | ||
79 | unsigned int index, unsigned int desc_count, | ||
80 | unsigned int desc_size) | ||
81 | { | ||
82 | int err; | ||
83 | |||
84 | wq->index = index; | ||
85 | wq->vdev = vdev; | ||
86 | wq->to_use_index = wq->to_clean_index = 0; | ||
87 | wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index); | ||
88 | if (!wq->ctrl) { | ||
89 | printk(KERN_ERR "Failed to hook COPY WQ[%d] resource\n", index); | ||
90 | return -EINVAL; | ||
91 | } | ||
92 | |||
93 | vnic_wq_copy_disable(wq); | ||
94 | |||
95 | err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size); | ||
96 | if (err) | ||
97 | return err; | ||
98 | |||
99 | return 0; | ||
100 | } | ||
101 | |||
102 | void vnic_wq_copy_init(struct vnic_wq_copy *wq, unsigned int cq_index, | ||
103 | unsigned int error_interrupt_enable, | ||
104 | unsigned int error_interrupt_offset) | ||
105 | { | ||
106 | u64 paddr; | ||
107 | |||
108 | paddr = (u64)wq->ring.base_addr | VNIC_PADDR_TARGET; | ||
109 | writeq(paddr, &wq->ctrl->ring_base); | ||
110 | iowrite32(wq->ring.desc_count, &wq->ctrl->ring_size); | ||
111 | iowrite32(0, &wq->ctrl->fetch_index); | ||
112 | iowrite32(0, &wq->ctrl->posted_index); | ||
113 | iowrite32(cq_index, &wq->ctrl->cq_index); | ||
114 | iowrite32(error_interrupt_enable, &wq->ctrl->error_interrupt_enable); | ||
115 | iowrite32(error_interrupt_offset, &wq->ctrl->error_interrupt_offset); | ||
116 | } | ||
117 | |||
diff --git a/drivers/scsi/fnic/vnic_wq_copy.h b/drivers/scsi/fnic/vnic_wq_copy.h new file mode 100644 index 000000000000..6aff9740c3df --- /dev/null +++ b/drivers/scsi/fnic/vnic_wq_copy.h | |||
@@ -0,0 +1,128 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _VNIC_WQ_COPY_H_ | ||
19 | #define _VNIC_WQ_COPY_H_ | ||
20 | |||
21 | #include <linux/pci.h> | ||
22 | #include "vnic_wq.h" | ||
23 | #include "fcpio.h" | ||
24 | |||
25 | #define VNIC_WQ_COPY_MAX 1 | ||
26 | |||
27 | struct vnic_wq_copy { | ||
28 | unsigned int index; | ||
29 | struct vnic_dev *vdev; | ||
30 | struct vnic_wq_ctrl __iomem *ctrl; /* memory-mapped */ | ||
31 | struct vnic_dev_ring ring; | ||
32 | unsigned to_use_index; | ||
33 | unsigned to_clean_index; | ||
34 | }; | ||
35 | |||
36 | static inline unsigned int vnic_wq_copy_desc_avail(struct vnic_wq_copy *wq) | ||
37 | { | ||
38 | return wq->ring.desc_avail; | ||
39 | } | ||
40 | |||
41 | static inline unsigned int vnic_wq_copy_desc_in_use(struct vnic_wq_copy *wq) | ||
42 | { | ||
43 | return wq->ring.desc_count - 1 - wq->ring.desc_avail; | ||
44 | } | ||
45 | |||
46 | static inline void *vnic_wq_copy_next_desc(struct vnic_wq_copy *wq) | ||
47 | { | ||
48 | struct fcpio_host_req *desc = wq->ring.descs; | ||
49 | return &desc[wq->to_use_index]; | ||
50 | } | ||
51 | |||
52 | static inline void vnic_wq_copy_post(struct vnic_wq_copy *wq) | ||
53 | { | ||
54 | |||
55 | ((wq->to_use_index + 1) == wq->ring.desc_count) ? | ||
56 | (wq->to_use_index = 0) : (wq->to_use_index++); | ||
57 | wq->ring.desc_avail--; | ||
58 | |||
59 | /* Adding write memory barrier prevents compiler and/or CPU | ||
60 | * reordering, thus avoiding descriptor posting before | ||
61 | * descriptor is initialized. Otherwise, hardware can read | ||
62 | * stale descriptor fields. | ||
63 | */ | ||
64 | wmb(); | ||
65 | |||
66 | iowrite32(wq->to_use_index, &wq->ctrl->posted_index); | ||
67 | } | ||
68 | |||
69 | static inline void vnic_wq_copy_desc_process(struct vnic_wq_copy *wq, u16 index) | ||
70 | { | ||
71 | unsigned int cnt; | ||
72 | |||
73 | if (wq->to_clean_index <= index) | ||
74 | cnt = (index - wq->to_clean_index) + 1; | ||
75 | else | ||
76 | cnt = wq->ring.desc_count - wq->to_clean_index + index + 1; | ||
77 | |||
78 | wq->to_clean_index = ((index + 1) % wq->ring.desc_count); | ||
79 | wq->ring.desc_avail += cnt; | ||
80 | |||
81 | } | ||
82 | |||
83 | static inline void vnic_wq_copy_service(struct vnic_wq_copy *wq, | ||
84 | u16 completed_index, | ||
85 | void (*q_service)(struct vnic_wq_copy *wq, | ||
86 | struct fcpio_host_req *wq_desc)) | ||
87 | { | ||
88 | struct fcpio_host_req *wq_desc = wq->ring.descs; | ||
89 | unsigned int curr_index; | ||
90 | |||
91 | while (1) { | ||
92 | |||
93 | if (q_service) | ||
94 | (*q_service)(wq, &wq_desc[wq->to_clean_index]); | ||
95 | |||
96 | wq->ring.desc_avail++; | ||
97 | |||
98 | curr_index = wq->to_clean_index; | ||
99 | |||
100 | /* increment the to-clean index so that we start | ||
101 | * with an unprocessed index next time we enter the loop | ||
102 | */ | ||
103 | ((wq->to_clean_index + 1) == wq->ring.desc_count) ? | ||
104 | (wq->to_clean_index = 0) : (wq->to_clean_index++); | ||
105 | |||
106 | if (curr_index == completed_index) | ||
107 | break; | ||
108 | |||
109 | /* we have cleaned all the entries */ | ||
110 | if ((completed_index == (u16)-1) && | ||
111 | (wq->to_clean_index == wq->to_use_index)) | ||
112 | break; | ||
113 | } | ||
114 | } | ||
115 | |||
116 | void vnic_wq_copy_enable(struct vnic_wq_copy *wq); | ||
117 | int vnic_wq_copy_disable(struct vnic_wq_copy *wq); | ||
118 | void vnic_wq_copy_free(struct vnic_wq_copy *wq); | ||
119 | int vnic_wq_copy_alloc(struct vnic_dev *vdev, struct vnic_wq_copy *wq, | ||
120 | unsigned int index, unsigned int desc_count, unsigned int desc_size); | ||
121 | void vnic_wq_copy_init(struct vnic_wq_copy *wq, unsigned int cq_index, | ||
122 | unsigned int error_interrupt_enable, | ||
123 | unsigned int error_interrupt_offset); | ||
124 | void vnic_wq_copy_clean(struct vnic_wq_copy *wq, | ||
125 | void (*q_clean)(struct vnic_wq_copy *wq, | ||
126 | struct fcpio_host_req *wq_desc)); | ||
127 | |||
128 | #endif /* _VNIC_WQ_COPY_H_ */ | ||
diff --git a/drivers/scsi/fnic/wq_enet_desc.h b/drivers/scsi/fnic/wq_enet_desc.h new file mode 100644 index 000000000000..b121cbad18b8 --- /dev/null +++ b/drivers/scsi/fnic/wq_enet_desc.h | |||
@@ -0,0 +1,96 @@ | |||
1 | /* | ||
2 | * Copyright 2008 Cisco Systems, Inc. All rights reserved. | ||
3 | * Copyright 2007 Nuova Systems, Inc. All rights reserved. | ||
4 | * | ||
5 | * This program is free software; you may redistribute it and/or modify | ||
6 | * it under the terms of the GNU General Public License as published by | ||
7 | * the Free Software Foundation; version 2 of the License. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, | ||
10 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF | ||
11 | * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND | ||
12 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS | ||
13 | * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN | ||
15 | * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||
16 | * SOFTWARE. | ||
17 | */ | ||
18 | #ifndef _WQ_ENET_DESC_H_ | ||
19 | #define _WQ_ENET_DESC_H_ | ||
20 | |||
21 | /* Ethernet work queue descriptor: 16B */ | ||
22 | struct wq_enet_desc { | ||
23 | __le64 address; | ||
24 | __le16 length; | ||
25 | __le16 mss_loopback; | ||
26 | __le16 header_length_flags; | ||
27 | __le16 vlan_tag; | ||
28 | }; | ||
29 | |||
30 | #define WQ_ENET_ADDR_BITS 64 | ||
31 | #define WQ_ENET_LEN_BITS 14 | ||
32 | #define WQ_ENET_LEN_MASK ((1 << WQ_ENET_LEN_BITS) - 1) | ||
33 | #define WQ_ENET_MSS_BITS 14 | ||
34 | #define WQ_ENET_MSS_MASK ((1 << WQ_ENET_MSS_BITS) - 1) | ||
35 | #define WQ_ENET_MSS_SHIFT 2 | ||
36 | #define WQ_ENET_LOOPBACK_SHIFT 1 | ||
37 | #define WQ_ENET_HDRLEN_BITS 10 | ||
38 | #define WQ_ENET_HDRLEN_MASK ((1 << WQ_ENET_HDRLEN_BITS) - 1) | ||
39 | #define WQ_ENET_FLAGS_OM_BITS 2 | ||
40 | #define WQ_ENET_FLAGS_OM_MASK ((1 << WQ_ENET_FLAGS_OM_BITS) - 1) | ||
41 | #define WQ_ENET_FLAGS_EOP_SHIFT 12 | ||
42 | #define WQ_ENET_FLAGS_CQ_ENTRY_SHIFT 13 | ||
43 | #define WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT 14 | ||
44 | #define WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT 15 | ||
45 | |||
46 | #define WQ_ENET_OFFLOAD_MODE_CSUM 0 | ||
47 | #define WQ_ENET_OFFLOAD_MODE_RESERVED 1 | ||
48 | #define WQ_ENET_OFFLOAD_MODE_CSUM_L4 2 | ||
49 | #define WQ_ENET_OFFLOAD_MODE_TSO 3 | ||
50 | |||
51 | static inline void wq_enet_desc_enc(struct wq_enet_desc *desc, | ||
52 | u64 address, u16 length, u16 mss, u16 header_length, | ||
53 | u8 offload_mode, u8 eop, u8 cq_entry, u8 fcoe_encap, | ||
54 | u8 vlan_tag_insert, u16 vlan_tag, u8 loopback) | ||
55 | { | ||
56 | desc->address = cpu_to_le64(address); | ||
57 | desc->length = cpu_to_le16(length & WQ_ENET_LEN_MASK); | ||
58 | desc->mss_loopback = cpu_to_le16((mss & WQ_ENET_MSS_MASK) << | ||
59 | WQ_ENET_MSS_SHIFT | (loopback & 1) << WQ_ENET_LOOPBACK_SHIFT); | ||
60 | desc->header_length_flags = cpu_to_le16( | ||
61 | (header_length & WQ_ENET_HDRLEN_MASK) | | ||
62 | (offload_mode & WQ_ENET_FLAGS_OM_MASK) << WQ_ENET_HDRLEN_BITS | | ||
63 | (eop & 1) << WQ_ENET_FLAGS_EOP_SHIFT | | ||
64 | (cq_entry & 1) << WQ_ENET_FLAGS_CQ_ENTRY_SHIFT | | ||
65 | (fcoe_encap & 1) << WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT | | ||
66 | (vlan_tag_insert & 1) << WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT); | ||
67 | desc->vlan_tag = cpu_to_le16(vlan_tag); | ||
68 | } | ||
69 | |||
70 | static inline void wq_enet_desc_dec(struct wq_enet_desc *desc, | ||
71 | u64 *address, u16 *length, u16 *mss, u16 *header_length, | ||
72 | u8 *offload_mode, u8 *eop, u8 *cq_entry, u8 *fcoe_encap, | ||
73 | u8 *vlan_tag_insert, u16 *vlan_tag, u8 *loopback) | ||
74 | { | ||
75 | *address = le64_to_cpu(desc->address); | ||
76 | *length = le16_to_cpu(desc->length) & WQ_ENET_LEN_MASK; | ||
77 | *mss = (le16_to_cpu(desc->mss_loopback) >> WQ_ENET_MSS_SHIFT) & | ||
78 | WQ_ENET_MSS_MASK; | ||
79 | *loopback = (u8)((le16_to_cpu(desc->mss_loopback) >> | ||
80 | WQ_ENET_LOOPBACK_SHIFT) & 1); | ||
81 | *header_length = le16_to_cpu(desc->header_length_flags) & | ||
82 | WQ_ENET_HDRLEN_MASK; | ||
83 | *offload_mode = (u8)((le16_to_cpu(desc->header_length_flags) >> | ||
84 | WQ_ENET_HDRLEN_BITS) & WQ_ENET_FLAGS_OM_MASK); | ||
85 | *eop = (u8)((le16_to_cpu(desc->header_length_flags) >> | ||
86 | WQ_ENET_FLAGS_EOP_SHIFT) & 1); | ||
87 | *cq_entry = (u8)((le16_to_cpu(desc->header_length_flags) >> | ||
88 | WQ_ENET_FLAGS_CQ_ENTRY_SHIFT) & 1); | ||
89 | *fcoe_encap = (u8)((le16_to_cpu(desc->header_length_flags) >> | ||
90 | WQ_ENET_FLAGS_FCOE_ENCAP_SHIFT) & 1); | ||
91 | *vlan_tag_insert = (u8)((le16_to_cpu(desc->header_length_flags) >> | ||
92 | WQ_ENET_FLAGS_VLAN_TAG_INSERT_SHIFT) & 1); | ||
93 | *vlan_tag = le16_to_cpu(desc->vlan_tag); | ||
94 | } | ||
95 | |||
96 | #endif /* _WQ_ENET_DESC_H_ */ | ||
diff --git a/drivers/scsi/mpt2sas/mpt2sas_base.h b/drivers/scsi/mpt2sas/mpt2sas_base.h index babd4cc0cb25..36b1d1052ba1 100644 --- a/drivers/scsi/mpt2sas/mpt2sas_base.h +++ b/drivers/scsi/mpt2sas/mpt2sas_base.h | |||
@@ -69,7 +69,7 @@ | |||
69 | #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>" | 69 | #define MPT2SAS_AUTHOR "LSI Corporation <DL-MPTFusionLinux@lsi.com>" |
70 | #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" | 70 | #define MPT2SAS_DESCRIPTION "LSI MPT Fusion SAS 2.0 Device Driver" |
71 | #define MPT2SAS_DRIVER_VERSION "01.100.02.00" | 71 | #define MPT2SAS_DRIVER_VERSION "01.100.02.00" |
72 | #define MPT2SAS_MAJOR_VERSION 00 | 72 | #define MPT2SAS_MAJOR_VERSION 01 |
73 | #define MPT2SAS_MINOR_VERSION 100 | 73 | #define MPT2SAS_MINOR_VERSION 100 |
74 | #define MPT2SAS_BUILD_VERSION 02 | 74 | #define MPT2SAS_BUILD_VERSION 02 |
75 | #define MPT2SAS_RELEASE_VERSION 00 | 75 | #define MPT2SAS_RELEASE_VERSION 00 |
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c index 6f51ca485f35..e2b50d8f57a8 100644 --- a/drivers/scsi/scsi_scan.c +++ b/drivers/scsi/scsi_scan.c | |||
@@ -425,6 +425,7 @@ static struct scsi_target *scsi_alloc_target(struct device *parent, | |||
425 | INIT_LIST_HEAD(&starget->devices); | 425 | INIT_LIST_HEAD(&starget->devices); |
426 | starget->state = STARGET_CREATED; | 426 | starget->state = STARGET_CREATED; |
427 | starget->scsi_level = SCSI_2; | 427 | starget->scsi_level = SCSI_2; |
428 | starget->max_target_blocked = SCSI_DEFAULT_TARGET_BLOCKED; | ||
428 | retry: | 429 | retry: |
429 | spin_lock_irqsave(shost->host_lock, flags); | 430 | spin_lock_irqsave(shost->host_lock, flags); |
430 | 431 | ||
diff --git a/drivers/scsi/scsi_transport_iscsi.c b/drivers/scsi/scsi_transport_iscsi.c index 094795455293..0a2ce7b6325c 100644 --- a/drivers/scsi/scsi_transport_iscsi.c +++ b/drivers/scsi/scsi_transport_iscsi.c | |||
@@ -357,7 +357,7 @@ int iscsi_session_chkready(struct iscsi_cls_session *session) | |||
357 | err = 0; | 357 | err = 0; |
358 | break; | 358 | break; |
359 | case ISCSI_SESSION_FAILED: | 359 | case ISCSI_SESSION_FAILED: |
360 | err = DID_TRANSPORT_DISRUPTED << 16; | 360 | err = DID_IMM_RETRY << 16; |
361 | break; | 361 | break; |
362 | case ISCSI_SESSION_FREE: | 362 | case ISCSI_SESSION_FREE: |
363 | err = DID_TRANSPORT_FAILFAST << 16; | 363 | err = DID_TRANSPORT_FAILFAST << 16; |
diff --git a/drivers/serial/icom.c b/drivers/serial/icom.c index 6579e2be1dd1..a461b3b2c72d 100644 --- a/drivers/serial/icom.c +++ b/drivers/serial/icom.c | |||
@@ -1472,8 +1472,8 @@ static void icom_remove_adapter(struct icom_adapter *icom_adapter) | |||
1472 | 1472 | ||
1473 | free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); | 1473 | free_irq(icom_adapter->pci_dev->irq, (void *) icom_adapter); |
1474 | iounmap(icom_adapter->base_addr); | 1474 | iounmap(icom_adapter->base_addr); |
1475 | icom_free_adapter(icom_adapter); | ||
1476 | pci_release_regions(icom_adapter->pci_dev); | 1475 | pci_release_regions(icom_adapter->pci_dev); |
1476 | icom_free_adapter(icom_adapter); | ||
1477 | } | 1477 | } |
1478 | 1478 | ||
1479 | static void icom_kref_release(struct kref *kref) | 1479 | static void icom_kref_release(struct kref *kref) |
diff --git a/fs/cachefiles/internal.h b/fs/cachefiles/internal.h index 19218e1463d6..f7c255f9c624 100644 --- a/fs/cachefiles/internal.h +++ b/fs/cachefiles/internal.h | |||
@@ -122,13 +122,13 @@ static inline void cachefiles_state_changed(struct cachefiles_cache *cache) | |||
122 | } | 122 | } |
123 | 123 | ||
124 | /* | 124 | /* |
125 | * cf-bind.c | 125 | * bind.c |
126 | */ | 126 | */ |
127 | extern int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args); | 127 | extern int cachefiles_daemon_bind(struct cachefiles_cache *cache, char *args); |
128 | extern void cachefiles_daemon_unbind(struct cachefiles_cache *cache); | 128 | extern void cachefiles_daemon_unbind(struct cachefiles_cache *cache); |
129 | 129 | ||
130 | /* | 130 | /* |
131 | * cf-daemon.c | 131 | * daemon.c |
132 | */ | 132 | */ |
133 | extern const struct file_operations cachefiles_daemon_fops; | 133 | extern const struct file_operations cachefiles_daemon_fops; |
134 | 134 | ||
@@ -136,17 +136,17 @@ extern int cachefiles_has_space(struct cachefiles_cache *cache, | |||
136 | unsigned fnr, unsigned bnr); | 136 | unsigned fnr, unsigned bnr); |
137 | 137 | ||
138 | /* | 138 | /* |
139 | * cf-interface.c | 139 | * interface.c |
140 | */ | 140 | */ |
141 | extern const struct fscache_cache_ops cachefiles_cache_ops; | 141 | extern const struct fscache_cache_ops cachefiles_cache_ops; |
142 | 142 | ||
143 | /* | 143 | /* |
144 | * cf-key.c | 144 | * key.c |
145 | */ | 145 | */ |
146 | extern char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type); | 146 | extern char *cachefiles_cook_key(const u8 *raw, int keylen, uint8_t type); |
147 | 147 | ||
148 | /* | 148 | /* |
149 | * cf-namei.c | 149 | * namei.c |
150 | */ | 150 | */ |
151 | extern int cachefiles_delete_object(struct cachefiles_cache *cache, | 151 | extern int cachefiles_delete_object(struct cachefiles_cache *cache, |
152 | struct cachefiles_object *object); | 152 | struct cachefiles_object *object); |
@@ -165,7 +165,7 @@ extern int cachefiles_check_in_use(struct cachefiles_cache *cache, | |||
165 | struct dentry *dir, char *filename); | 165 | struct dentry *dir, char *filename); |
166 | 166 | ||
167 | /* | 167 | /* |
168 | * cf-proc.c | 168 | * proc.c |
169 | */ | 169 | */ |
170 | #ifdef CONFIG_CACHEFILES_HISTOGRAM | 170 | #ifdef CONFIG_CACHEFILES_HISTOGRAM |
171 | extern atomic_t cachefiles_lookup_histogram[HZ]; | 171 | extern atomic_t cachefiles_lookup_histogram[HZ]; |
@@ -190,7 +190,7 @@ void cachefiles_hist(atomic_t histogram[], unsigned long start_jif) | |||
190 | #endif | 190 | #endif |
191 | 191 | ||
192 | /* | 192 | /* |
193 | * cf-rdwr.c | 193 | * rdwr.c |
194 | */ | 194 | */ |
195 | extern int cachefiles_read_or_alloc_page(struct fscache_retrieval *, | 195 | extern int cachefiles_read_or_alloc_page(struct fscache_retrieval *, |
196 | struct page *, gfp_t); | 196 | struct page *, gfp_t); |
@@ -205,7 +205,7 @@ extern int cachefiles_write_page(struct fscache_storage *, struct page *); | |||
205 | extern void cachefiles_uncache_page(struct fscache_object *, struct page *); | 205 | extern void cachefiles_uncache_page(struct fscache_object *, struct page *); |
206 | 206 | ||
207 | /* | 207 | /* |
208 | * cf-security.c | 208 | * security.c |
209 | */ | 209 | */ |
210 | extern int cachefiles_get_security_ID(struct cachefiles_cache *cache); | 210 | extern int cachefiles_get_security_ID(struct cachefiles_cache *cache); |
211 | extern int cachefiles_determine_cache_security(struct cachefiles_cache *cache, | 211 | extern int cachefiles_determine_cache_security(struct cachefiles_cache *cache, |
@@ -225,7 +225,7 @@ static inline void cachefiles_end_secure(struct cachefiles_cache *cache, | |||
225 | } | 225 | } |
226 | 226 | ||
227 | /* | 227 | /* |
228 | * cf-xattr.c | 228 | * xattr.c |
229 | */ | 229 | */ |
230 | extern int cachefiles_check_object_type(struct cachefiles_object *object); | 230 | extern int cachefiles_check_object_type(struct cachefiles_object *object); |
231 | extern int cachefiles_set_object_xattr(struct cachefiles_object *object, | 231 | extern int cachefiles_set_object_xattr(struct cachefiles_object *object, |
diff --git a/fs/cifs/dir.c b/fs/cifs/dir.c index f49d684edd96..3758965d73d5 100644 --- a/fs/cifs/dir.c +++ b/fs/cifs/dir.c | |||
@@ -657,31 +657,36 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry, | |||
657 | } | 657 | } |
658 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); | 658 | cFYI(1, ("Full path: %s inode = 0x%p", full_path, direntry->d_inode)); |
659 | 659 | ||
660 | /* Posix open is only called (at lookup time) for file create now. | ||
661 | * For opens (rather than creates), because we do not know if it | ||
662 | * is a file or directory yet, and current Samba no longer allows | ||
663 | * us to do posix open on dirs, we could end up wasting an open call | ||
664 | * on what turns out to be a dir. For file opens, we wait to call posix | ||
665 | * open till cifs_open. It could be added here (lookup) in the future | ||
666 | * but the performance tradeoff of the extra network request when EISDIR | ||
667 | * or EACCES is returned would have to be weighed against the 50% | ||
668 | * reduction in network traffic in the other paths. | ||
669 | */ | ||
660 | if (pTcon->unix_ext) { | 670 | if (pTcon->unix_ext) { |
661 | if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && | 671 | if (!(nd->flags & (LOOKUP_PARENT | LOOKUP_DIRECTORY)) && |
662 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open) { | 672 | (nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open && |
663 | if (!((nd->intent.open.flags & O_CREAT) && | 673 | (nd->intent.open.flags & O_CREAT)) { |
664 | (nd->intent.open.flags & O_EXCL))) { | 674 | rc = cifs_posix_open(full_path, &newInode, |
665 | rc = cifs_posix_open(full_path, &newInode, | ||
666 | parent_dir_inode->i_sb, | 675 | parent_dir_inode->i_sb, |
667 | nd->intent.open.create_mode, | 676 | nd->intent.open.create_mode, |
668 | nd->intent.open.flags, &oplock, | 677 | nd->intent.open.flags, &oplock, |
669 | &fileHandle, xid); | 678 | &fileHandle, xid); |
670 | /* | 679 | /* |
671 | * This code works around a bug in | 680 | * The check below works around a bug in POSIX |
672 | * samba posix open in samba versions 3.3.1 | 681 | * open in samba versions 3.3.1 and earlier where |
673 | * and earlier where create works | 682 | * open could incorrectly fail with invalid parameter. |
674 | * but open fails with invalid parameter. | 683 | * If either that or op not supported returned, follow |
675 | * If either of these error codes are | 684 | * the normal lookup. |
676 | * returned, follow the normal lookup. | 685 | */ |
677 | * Otherwise, the error during posix open | 686 | if ((rc == 0) || (rc == -ENOENT)) |
678 | * is handled. | 687 | posix_open = true; |
679 | */ | 688 | else if ((rc == -EINVAL) || (rc != -EOPNOTSUPP)) |
680 | if ((rc != -EINVAL) && (rc != -EOPNOTSUPP)) | 689 | pTcon->broken_posix_open = true; |
681 | posix_open = true; | ||
682 | else | ||
683 | pTcon->broken_posix_open = true; | ||
684 | } | ||
685 | } | 690 | } |
686 | if (!posix_open) | 691 | if (!posix_open) |
687 | rc = cifs_get_inode_info_unix(&newInode, full_path, | 692 | rc = cifs_get_inode_info_unix(&newInode, full_path, |
diff --git a/fs/fscache/internal.h b/fs/fscache/internal.h index e0cbd16f6dc9..1c341304621f 100644 --- a/fs/fscache/internal.h +++ b/fs/fscache/internal.h | |||
@@ -28,7 +28,7 @@ | |||
28 | #define FSCACHE_MAX_THREADS 32 | 28 | #define FSCACHE_MAX_THREADS 32 |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * fsc-cache.c | 31 | * cache.c |
32 | */ | 32 | */ |
33 | extern struct list_head fscache_cache_list; | 33 | extern struct list_head fscache_cache_list; |
34 | extern struct rw_semaphore fscache_addremove_sem; | 34 | extern struct rw_semaphore fscache_addremove_sem; |
@@ -37,7 +37,7 @@ extern struct fscache_cache *fscache_select_cache_for_object( | |||
37 | struct fscache_cookie *); | 37 | struct fscache_cookie *); |
38 | 38 | ||
39 | /* | 39 | /* |
40 | * fsc-cookie.c | 40 | * cookie.c |
41 | */ | 41 | */ |
42 | extern struct kmem_cache *fscache_cookie_jar; | 42 | extern struct kmem_cache *fscache_cookie_jar; |
43 | 43 | ||
@@ -45,13 +45,13 @@ extern void fscache_cookie_init_once(void *); | |||
45 | extern void __fscache_cookie_put(struct fscache_cookie *); | 45 | extern void __fscache_cookie_put(struct fscache_cookie *); |
46 | 46 | ||
47 | /* | 47 | /* |
48 | * fsc-fsdef.c | 48 | * fsdef.c |
49 | */ | 49 | */ |
50 | extern struct fscache_cookie fscache_fsdef_index; | 50 | extern struct fscache_cookie fscache_fsdef_index; |
51 | extern struct fscache_cookie_def fscache_fsdef_netfs_def; | 51 | extern struct fscache_cookie_def fscache_fsdef_netfs_def; |
52 | 52 | ||
53 | /* | 53 | /* |
54 | * fsc-histogram.c | 54 | * histogram.c |
55 | */ | 55 | */ |
56 | #ifdef CONFIG_FSCACHE_HISTOGRAM | 56 | #ifdef CONFIG_FSCACHE_HISTOGRAM |
57 | extern atomic_t fscache_obj_instantiate_histogram[HZ]; | 57 | extern atomic_t fscache_obj_instantiate_histogram[HZ]; |
@@ -75,7 +75,7 @@ extern const struct file_operations fscache_histogram_fops; | |||
75 | #endif | 75 | #endif |
76 | 76 | ||
77 | /* | 77 | /* |
78 | * fsc-main.c | 78 | * main.c |
79 | */ | 79 | */ |
80 | extern unsigned fscache_defer_lookup; | 80 | extern unsigned fscache_defer_lookup; |
81 | extern unsigned fscache_defer_create; | 81 | extern unsigned fscache_defer_create; |
@@ -86,14 +86,14 @@ extern int fscache_wait_bit(void *); | |||
86 | extern int fscache_wait_bit_interruptible(void *); | 86 | extern int fscache_wait_bit_interruptible(void *); |
87 | 87 | ||
88 | /* | 88 | /* |
89 | * fsc-object.c | 89 | * object.c |
90 | */ | 90 | */ |
91 | extern void fscache_withdrawing_object(struct fscache_cache *, | 91 | extern void fscache_withdrawing_object(struct fscache_cache *, |
92 | struct fscache_object *); | 92 | struct fscache_object *); |
93 | extern void fscache_enqueue_object(struct fscache_object *); | 93 | extern void fscache_enqueue_object(struct fscache_object *); |
94 | 94 | ||
95 | /* | 95 | /* |
96 | * fsc-operation.c | 96 | * operation.c |
97 | */ | 97 | */ |
98 | extern int fscache_submit_exclusive_op(struct fscache_object *, | 98 | extern int fscache_submit_exclusive_op(struct fscache_object *, |
99 | struct fscache_operation *); | 99 | struct fscache_operation *); |
@@ -104,7 +104,7 @@ extern void fscache_start_operations(struct fscache_object *); | |||
104 | extern void fscache_operation_gc(struct work_struct *); | 104 | extern void fscache_operation_gc(struct work_struct *); |
105 | 105 | ||
106 | /* | 106 | /* |
107 | * fsc-proc.c | 107 | * proc.c |
108 | */ | 108 | */ |
109 | #ifdef CONFIG_PROC_FS | 109 | #ifdef CONFIG_PROC_FS |
110 | extern int __init fscache_proc_init(void); | 110 | extern int __init fscache_proc_init(void); |
@@ -115,7 +115,7 @@ extern void fscache_proc_cleanup(void); | |||
115 | #endif | 115 | #endif |
116 | 116 | ||
117 | /* | 117 | /* |
118 | * fsc-stats.c | 118 | * stats.c |
119 | */ | 119 | */ |
120 | #ifdef CONFIG_FSCACHE_STATS | 120 | #ifdef CONFIG_FSCACHE_STATS |
121 | extern atomic_t fscache_n_ops_processed[FSCACHE_MAX_THREADS]; | 121 | extern atomic_t fscache_n_ops_processed[FSCACHE_MAX_THREADS]; |
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c index a4d242680299..4674f8092da8 100644 --- a/fs/nfs/nfs4proc.c +++ b/fs/nfs/nfs4proc.c | |||
@@ -2594,12 +2594,9 @@ static void nfs4_renew_done(struct rpc_task *task, void *data) | |||
2594 | unsigned long timestamp = (unsigned long)data; | 2594 | unsigned long timestamp = (unsigned long)data; |
2595 | 2595 | ||
2596 | if (task->tk_status < 0) { | 2596 | if (task->tk_status < 0) { |
2597 | switch (task->tk_status) { | 2597 | /* Unless we're shutting down, schedule state recovery! */ |
2598 | case -NFS4ERR_STALE_CLIENTID: | 2598 | if (test_bit(NFS_CS_RENEWD, &clp->cl_res_state) != 0) |
2599 | case -NFS4ERR_EXPIRED: | 2599 | nfs4_schedule_state_recovery(clp); |
2600 | case -NFS4ERR_CB_PATH_DOWN: | ||
2601 | nfs4_schedule_state_recovery(clp); | ||
2602 | } | ||
2603 | return; | 2600 | return; |
2604 | } | 2601 | } |
2605 | spin_lock(&clp->cl_lock); | 2602 | spin_lock(&clp->cl_lock); |
diff --git a/fs/nfs/nfsroot.c b/fs/nfs/nfsroot.c index d9ef602fbc5a..e3ed5908820b 100644 --- a/fs/nfs/nfsroot.c +++ b/fs/nfs/nfsroot.c | |||
@@ -129,7 +129,7 @@ enum { | |||
129 | Opt_err | 129 | Opt_err |
130 | }; | 130 | }; |
131 | 131 | ||
132 | static match_table_t __initconst tokens = { | 132 | static const match_table_t tokens __initconst = { |
133 | {Opt_port, "port=%u"}, | 133 | {Opt_port, "port=%u"}, |
134 | {Opt_rsize, "rsize=%u"}, | 134 | {Opt_rsize, "rsize=%u"}, |
135 | {Opt_wsize, "wsize=%u"}, | 135 | {Opt_wsize, "wsize=%u"}, |
diff --git a/include/drm/drmP.h b/include/drm/drmP.h index c8c422151431..b84d8ae35e6f 100644 --- a/include/drm/drmP.h +++ b/include/drm/drmP.h | |||
@@ -1519,6 +1519,30 @@ static __inline__ void *drm_calloc(size_t nmemb, size_t size, int area) | |||
1519 | { | 1519 | { |
1520 | return kcalloc(nmemb, size, GFP_KERNEL); | 1520 | return kcalloc(nmemb, size, GFP_KERNEL); |
1521 | } | 1521 | } |
1522 | |||
1523 | static __inline__ void *drm_calloc_large(size_t nmemb, size_t size) | ||
1524 | { | ||
1525 | u8 *addr; | ||
1526 | |||
1527 | if (size <= PAGE_SIZE) | ||
1528 | return kcalloc(nmemb, size, GFP_KERNEL); | ||
1529 | |||
1530 | addr = vmalloc(nmemb * size); | ||
1531 | if (!addr) | ||
1532 | return NULL; | ||
1533 | |||
1534 | memset(addr, 0, nmemb * size); | ||
1535 | |||
1536 | return addr; | ||
1537 | } | ||
1538 | |||
1539 | static __inline void drm_free_large(void *ptr) | ||
1540 | { | ||
1541 | if (!is_vmalloc_addr(ptr)) | ||
1542 | return kfree(ptr); | ||
1543 | |||
1544 | vfree(ptr); | ||
1545 | } | ||
1522 | #else | 1546 | #else |
1523 | extern void *drm_alloc(size_t size, int area); | 1547 | extern void *drm_alloc(size_t size, int area); |
1524 | extern void drm_free(void *pt, size_t size, int area); | 1548 | extern void drm_free(void *pt, size_t size, int area); |
diff --git a/include/scsi/scsi_transport_fc.h b/include/scsi/scsi_transport_fc.h index c9184f756cad..68a8d873bbd9 100644 --- a/include/scsi/scsi_transport_fc.h +++ b/include/scsi/scsi_transport_fc.h | |||
@@ -680,7 +680,7 @@ fc_remote_port_chkready(struct fc_rport *rport) | |||
680 | if (rport->roles & FC_PORT_ROLE_FCP_TARGET) | 680 | if (rport->roles & FC_PORT_ROLE_FCP_TARGET) |
681 | result = 0; | 681 | result = 0; |
682 | else if (rport->flags & FC_RPORT_DEVLOSS_PENDING) | 682 | else if (rport->flags & FC_RPORT_DEVLOSS_PENDING) |
683 | result = DID_TRANSPORT_DISRUPTED << 16; | 683 | result = DID_IMM_RETRY << 16; |
684 | else | 684 | else |
685 | result = DID_NO_CONNECT << 16; | 685 | result = DID_NO_CONNECT << 16; |
686 | break; | 686 | break; |
@@ -688,7 +688,7 @@ fc_remote_port_chkready(struct fc_rport *rport) | |||
688 | if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT) | 688 | if (rport->flags & FC_RPORT_FAST_FAIL_TIMEDOUT) |
689 | result = DID_TRANSPORT_FAILFAST << 16; | 689 | result = DID_TRANSPORT_FAILFAST << 16; |
690 | else | 690 | else |
691 | result = DID_TRANSPORT_DISRUPTED << 16; | 691 | result = DID_IMM_RETRY << 16; |
692 | break; | 692 | break; |
693 | default: | 693 | default: |
694 | result = DID_NO_CONNECT << 16; | 694 | result = DID_NO_CONNECT << 16; |
diff --git a/init/main.c b/init/main.c index 3bbf93be744c..d721dad05dd7 100644 --- a/init/main.c +++ b/init/main.c | |||
@@ -566,8 +566,7 @@ asmlinkage void __init start_kernel(void) | |||
566 | tick_init(); | 566 | tick_init(); |
567 | boot_cpu_init(); | 567 | boot_cpu_init(); |
568 | page_address_init(); | 568 | page_address_init(); |
569 | printk(KERN_NOTICE); | 569 | printk(KERN_NOTICE "%s", linux_banner); |
570 | printk(linux_banner); | ||
571 | setup_arch(&command_line); | 570 | setup_arch(&command_line); |
572 | mm_init_owner(&init_mm, &init_task); | 571 | mm_init_owner(&init_mm, &init_task); |
573 | setup_command_line(command_line); | 572 | setup_command_line(command_line); |
diff --git a/kernel/async.c b/kernel/async.c index 968ef9457d4e..50540301ed0f 100644 --- a/kernel/async.c +++ b/kernel/async.c | |||
@@ -92,19 +92,23 @@ extern int initcall_debug; | |||
92 | static async_cookie_t __lowest_in_progress(struct list_head *running) | 92 | static async_cookie_t __lowest_in_progress(struct list_head *running) |
93 | { | 93 | { |
94 | struct async_entry *entry; | 94 | struct async_entry *entry; |
95 | async_cookie_t ret = next_cookie; /* begin with "infinity" value */ | ||
96 | |||
95 | if (!list_empty(running)) { | 97 | if (!list_empty(running)) { |
96 | entry = list_first_entry(running, | 98 | entry = list_first_entry(running, |
97 | struct async_entry, list); | 99 | struct async_entry, list); |
98 | return entry->cookie; | 100 | ret = entry->cookie; |
99 | } else if (!list_empty(&async_pending)) { | ||
100 | entry = list_first_entry(&async_pending, | ||
101 | struct async_entry, list); | ||
102 | return entry->cookie; | ||
103 | } else { | ||
104 | /* nothing in progress... next_cookie is "infinity" */ | ||
105 | return next_cookie; | ||
106 | } | 101 | } |
107 | 102 | ||
103 | if (!list_empty(&async_pending)) { | ||
104 | list_for_each_entry(entry, &async_pending, list) | ||
105 | if (entry->running == running) { | ||
106 | ret = entry->cookie; | ||
107 | break; | ||
108 | } | ||
109 | } | ||
110 | |||
111 | return ret; | ||
108 | } | 112 | } |
109 | 113 | ||
110 | static async_cookie_t lowest_in_progress(struct list_head *running) | 114 | static async_cookie_t lowest_in_progress(struct list_head *running) |
diff --git a/kernel/kexec.c b/kernel/kexec.c index 5a758c6e4950..e4983770913b 100644 --- a/kernel/kexec.c +++ b/kernel/kexec.c | |||
@@ -1451,7 +1451,6 @@ int kernel_kexec(void) | |||
1451 | error = device_suspend(PMSG_FREEZE); | 1451 | error = device_suspend(PMSG_FREEZE); |
1452 | if (error) | 1452 | if (error) |
1453 | goto Resume_console; | 1453 | goto Resume_console; |
1454 | device_pm_lock(); | ||
1455 | /* At this point, device_suspend() has been called, | 1454 | /* At this point, device_suspend() has been called, |
1456 | * but *not* device_power_down(). We *must* | 1455 | * but *not* device_power_down(). We *must* |
1457 | * device_power_down() now. Otherwise, drivers for | 1456 | * device_power_down() now. Otherwise, drivers for |
@@ -1489,7 +1488,6 @@ int kernel_kexec(void) | |||
1489 | enable_nonboot_cpus(); | 1488 | enable_nonboot_cpus(); |
1490 | device_power_up(PMSG_RESTORE); | 1489 | device_power_up(PMSG_RESTORE); |
1491 | Resume_devices: | 1490 | Resume_devices: |
1492 | device_pm_unlock(); | ||
1493 | device_resume(PMSG_RESTORE); | 1491 | device_resume(PMSG_RESTORE); |
1494 | Resume_console: | 1492 | Resume_console: |
1495 | resume_console(); | 1493 | resume_console(); |
diff --git a/kernel/kmod.c b/kernel/kmod.c index b750675251e5..7e95bedb2bfc 100644 --- a/kernel/kmod.c +++ b/kernel/kmod.c | |||
@@ -370,8 +370,10 @@ struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, | |||
370 | sub_info->argv = argv; | 370 | sub_info->argv = argv; |
371 | sub_info->envp = envp; | 371 | sub_info->envp = envp; |
372 | sub_info->cred = prepare_usermodehelper_creds(); | 372 | sub_info->cred = prepare_usermodehelper_creds(); |
373 | if (!sub_info->cred) | 373 | if (!sub_info->cred) { |
374 | kfree(sub_info); | ||
374 | return NULL; | 375 | return NULL; |
376 | } | ||
375 | 377 | ||
376 | out: | 378 | out: |
377 | return sub_info; | 379 | return sub_info; |
diff --git a/kernel/power/disk.c b/kernel/power/disk.c index b0dc9e7a0d17..5cb080e7eebd 100644 --- a/kernel/power/disk.c +++ b/kernel/power/disk.c | |||
@@ -215,8 +215,6 @@ static int create_image(int platform_mode) | |||
215 | if (error) | 215 | if (error) |
216 | return error; | 216 | return error; |
217 | 217 | ||
218 | device_pm_lock(); | ||
219 | |||
220 | /* At this point, device_suspend() has been called, but *not* | 218 | /* At this point, device_suspend() has been called, but *not* |
221 | * device_power_down(). We *must* call device_power_down() now. | 219 | * device_power_down(). We *must* call device_power_down() now. |
222 | * Otherwise, drivers for some devices (e.g. interrupt controllers) | 220 | * Otherwise, drivers for some devices (e.g. interrupt controllers) |
@@ -227,7 +225,7 @@ static int create_image(int platform_mode) | |||
227 | if (error) { | 225 | if (error) { |
228 | printk(KERN_ERR "PM: Some devices failed to power down, " | 226 | printk(KERN_ERR "PM: Some devices failed to power down, " |
229 | "aborting hibernation\n"); | 227 | "aborting hibernation\n"); |
230 | goto Unlock; | 228 | return error; |
231 | } | 229 | } |
232 | 230 | ||
233 | error = platform_pre_snapshot(platform_mode); | 231 | error = platform_pre_snapshot(platform_mode); |
@@ -280,9 +278,6 @@ static int create_image(int platform_mode) | |||
280 | device_power_up(in_suspend ? | 278 | device_power_up(in_suspend ? |
281 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); | 279 | (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE); |
282 | 280 | ||
283 | Unlock: | ||
284 | device_pm_unlock(); | ||
285 | |||
286 | return error; | 281 | return error; |
287 | } | 282 | } |
288 | 283 | ||
@@ -344,13 +339,11 @@ static int resume_target_kernel(bool platform_mode) | |||
344 | { | 339 | { |
345 | int error; | 340 | int error; |
346 | 341 | ||
347 | device_pm_lock(); | ||
348 | |||
349 | error = device_power_down(PMSG_QUIESCE); | 342 | error = device_power_down(PMSG_QUIESCE); |
350 | if (error) { | 343 | if (error) { |
351 | printk(KERN_ERR "PM: Some devices failed to power down, " | 344 | printk(KERN_ERR "PM: Some devices failed to power down, " |
352 | "aborting resume\n"); | 345 | "aborting resume\n"); |
353 | goto Unlock; | 346 | return error; |
354 | } | 347 | } |
355 | 348 | ||
356 | error = platform_pre_restore(platform_mode); | 349 | error = platform_pre_restore(platform_mode); |
@@ -403,9 +396,6 @@ static int resume_target_kernel(bool platform_mode) | |||
403 | 396 | ||
404 | device_power_up(PMSG_RECOVER); | 397 | device_power_up(PMSG_RECOVER); |
405 | 398 | ||
406 | Unlock: | ||
407 | device_pm_unlock(); | ||
408 | |||
409 | return error; | 399 | return error; |
410 | } | 400 | } |
411 | 401 | ||
@@ -464,11 +454,9 @@ int hibernation_platform_enter(void) | |||
464 | goto Resume_devices; | 454 | goto Resume_devices; |
465 | } | 455 | } |
466 | 456 | ||
467 | device_pm_lock(); | ||
468 | |||
469 | error = device_power_down(PMSG_HIBERNATE); | 457 | error = device_power_down(PMSG_HIBERNATE); |
470 | if (error) | 458 | if (error) |
471 | goto Unlock; | 459 | goto Resume_devices; |
472 | 460 | ||
473 | error = hibernation_ops->prepare(); | 461 | error = hibernation_ops->prepare(); |
474 | if (error) | 462 | if (error) |
@@ -493,9 +481,6 @@ int hibernation_platform_enter(void) | |||
493 | 481 | ||
494 | device_power_up(PMSG_RESTORE); | 482 | device_power_up(PMSG_RESTORE); |
495 | 483 | ||
496 | Unlock: | ||
497 | device_pm_unlock(); | ||
498 | |||
499 | Resume_devices: | 484 | Resume_devices: |
500 | entering_platform_hibernation = false; | 485 | entering_platform_hibernation = false; |
501 | device_resume(PMSG_RESTORE); | 486 | device_resume(PMSG_RESTORE); |
diff --git a/kernel/power/main.c b/kernel/power/main.c index f99ed6a75eac..868028280d13 100644 --- a/kernel/power/main.c +++ b/kernel/power/main.c | |||
@@ -289,12 +289,10 @@ static int suspend_enter(suspend_state_t state) | |||
289 | { | 289 | { |
290 | int error; | 290 | int error; |
291 | 291 | ||
292 | device_pm_lock(); | ||
293 | |||
294 | if (suspend_ops->prepare) { | 292 | if (suspend_ops->prepare) { |
295 | error = suspend_ops->prepare(); | 293 | error = suspend_ops->prepare(); |
296 | if (error) | 294 | if (error) |
297 | goto Done; | 295 | return error; |
298 | } | 296 | } |
299 | 297 | ||
300 | error = device_power_down(PMSG_SUSPEND); | 298 | error = device_power_down(PMSG_SUSPEND); |
@@ -343,9 +341,6 @@ static int suspend_enter(suspend_state_t state) | |||
343 | if (suspend_ops->finish) | 341 | if (suspend_ops->finish) |
344 | suspend_ops->finish(); | 342 | suspend_ops->finish(); |
345 | 343 | ||
346 | Done: | ||
347 | device_pm_unlock(); | ||
348 | |||
349 | return error; | 344 | return error; |
350 | } | 345 | } |
351 | 346 | ||
diff --git a/net/core/pktgen.c b/net/core/pktgen.c index 3779c1438c11..0666a827bc62 100644 --- a/net/core/pktgen.c +++ b/net/core/pktgen.c | |||
@@ -2447,7 +2447,7 @@ static inline void free_SAs(struct pktgen_dev *pkt_dev) | |||
2447 | if (pkt_dev->cflows) { | 2447 | if (pkt_dev->cflows) { |
2448 | /* let go of the SAs if we have them */ | 2448 | /* let go of the SAs if we have them */ |
2449 | int i = 0; | 2449 | int i = 0; |
2450 | for (; i < pkt_dev->nflows; i++){ | 2450 | for (; i < pkt_dev->cflows; i++) { |
2451 | struct xfrm_state *x = pkt_dev->flows[i].x; | 2451 | struct xfrm_state *x = pkt_dev->flows[i].x; |
2452 | if (x) { | 2452 | if (x) { |
2453 | xfrm_state_put(x); | 2453 | xfrm_state_put(x); |
diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c index ec0ae490f0b6..33c7c85dfe40 100644 --- a/net/ipv4/fib_trie.c +++ b/net/ipv4/fib_trie.c | |||
@@ -986,9 +986,12 @@ fib_find_node(struct trie *t, u32 key) | |||
986 | static struct node *trie_rebalance(struct trie *t, struct tnode *tn) | 986 | static struct node *trie_rebalance(struct trie *t, struct tnode *tn) |
987 | { | 987 | { |
988 | int wasfull; | 988 | int wasfull; |
989 | t_key cindex, key = tn->key; | 989 | t_key cindex, key; |
990 | struct tnode *tp; | 990 | struct tnode *tp; |
991 | 991 | ||
992 | preempt_disable(); | ||
993 | key = tn->key; | ||
994 | |||
992 | while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) { | 995 | while (tn != NULL && (tp = node_parent((struct node *)tn)) != NULL) { |
993 | cindex = tkey_extract_bits(key, tp->pos, tp->bits); | 996 | cindex = tkey_extract_bits(key, tp->pos, tp->bits); |
994 | wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); | 997 | wasfull = tnode_full(tp, tnode_get_child(tp, cindex)); |
@@ -1007,6 +1010,7 @@ static struct node *trie_rebalance(struct trie *t, struct tnode *tn) | |||
1007 | if (IS_TNODE(tn)) | 1010 | if (IS_TNODE(tn)) |
1008 | tn = (struct tnode *)resize(t, (struct tnode *)tn); | 1011 | tn = (struct tnode *)resize(t, (struct tnode *)tn); |
1009 | 1012 | ||
1013 | preempt_enable(); | ||
1010 | return (struct node *)tn; | 1014 | return (struct node *)tn; |
1011 | } | 1015 | } |
1012 | 1016 | ||
diff --git a/net/ipv4/route.c b/net/ipv4/route.c index c4c60e9f068a..28205e5bfa9b 100644 --- a/net/ipv4/route.c +++ b/net/ipv4/route.c | |||
@@ -784,8 +784,8 @@ static void rt_check_expire(void) | |||
784 | { | 784 | { |
785 | static unsigned int rover; | 785 | static unsigned int rover; |
786 | unsigned int i = rover, goal; | 786 | unsigned int i = rover, goal; |
787 | struct rtable *rth, **rthp; | 787 | struct rtable *rth, *aux, **rthp; |
788 | unsigned long length = 0, samples = 0; | 788 | unsigned long samples = 0; |
789 | unsigned long sum = 0, sum2 = 0; | 789 | unsigned long sum = 0, sum2 = 0; |
790 | u64 mult; | 790 | u64 mult; |
791 | 791 | ||
@@ -795,9 +795,9 @@ static void rt_check_expire(void) | |||
795 | goal = (unsigned int)mult; | 795 | goal = (unsigned int)mult; |
796 | if (goal > rt_hash_mask) | 796 | if (goal > rt_hash_mask) |
797 | goal = rt_hash_mask + 1; | 797 | goal = rt_hash_mask + 1; |
798 | length = 0; | ||
799 | for (; goal > 0; goal--) { | 798 | for (; goal > 0; goal--) { |
800 | unsigned long tmo = ip_rt_gc_timeout; | 799 | unsigned long tmo = ip_rt_gc_timeout; |
800 | unsigned long length; | ||
801 | 801 | ||
802 | i = (i + 1) & rt_hash_mask; | 802 | i = (i + 1) & rt_hash_mask; |
803 | rthp = &rt_hash_table[i].chain; | 803 | rthp = &rt_hash_table[i].chain; |
@@ -809,8 +809,10 @@ static void rt_check_expire(void) | |||
809 | 809 | ||
810 | if (*rthp == NULL) | 810 | if (*rthp == NULL) |
811 | continue; | 811 | continue; |
812 | length = 0; | ||
812 | spin_lock_bh(rt_hash_lock_addr(i)); | 813 | spin_lock_bh(rt_hash_lock_addr(i)); |
813 | while ((rth = *rthp) != NULL) { | 814 | while ((rth = *rthp) != NULL) { |
815 | prefetch(rth->u.dst.rt_next); | ||
814 | if (rt_is_expired(rth)) { | 816 | if (rt_is_expired(rth)) { |
815 | *rthp = rth->u.dst.rt_next; | 817 | *rthp = rth->u.dst.rt_next; |
816 | rt_free(rth); | 818 | rt_free(rth); |
@@ -819,33 +821,30 @@ static void rt_check_expire(void) | |||
819 | if (rth->u.dst.expires) { | 821 | if (rth->u.dst.expires) { |
820 | /* Entry is expired even if it is in use */ | 822 | /* Entry is expired even if it is in use */ |
821 | if (time_before_eq(jiffies, rth->u.dst.expires)) { | 823 | if (time_before_eq(jiffies, rth->u.dst.expires)) { |
824 | nofree: | ||
822 | tmo >>= 1; | 825 | tmo >>= 1; |
823 | rthp = &rth->u.dst.rt_next; | 826 | rthp = &rth->u.dst.rt_next; |
824 | /* | 827 | /* |
825 | * Only bump our length if the hash | 828 | * We only count entries on |
826 | * inputs on entries n and n+1 are not | ||
827 | * the same, we only count entries on | ||
828 | * a chain with equal hash inputs once | 829 | * a chain with equal hash inputs once |
829 | * so that entries for different QOS | 830 | * so that entries for different QOS |
830 | * levels, and other non-hash input | 831 | * levels, and other non-hash input |
831 | * attributes don't unfairly skew | 832 | * attributes don't unfairly skew |
832 | * the length computation | 833 | * the length computation |
833 | */ | 834 | */ |
834 | if ((*rthp == NULL) || | 835 | for (aux = rt_hash_table[i].chain;;) { |
835 | !compare_hash_inputs(&(*rthp)->fl, | 836 | if (aux == rth) { |
836 | &rth->fl)) | 837 | length += ONE; |
837 | length += ONE; | 838 | break; |
839 | } | ||
840 | if (compare_hash_inputs(&aux->fl, &rth->fl)) | ||
841 | break; | ||
842 | aux = aux->u.dst.rt_next; | ||
843 | } | ||
838 | continue; | 844 | continue; |
839 | } | 845 | } |
840 | } else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout)) { | 846 | } else if (!rt_may_expire(rth, tmo, ip_rt_gc_timeout)) |
841 | tmo >>= 1; | 847 | goto nofree; |
842 | rthp = &rth->u.dst.rt_next; | ||
843 | if ((*rthp == NULL) || | ||
844 | !compare_hash_inputs(&(*rthp)->fl, | ||
845 | &rth->fl)) | ||
846 | length += ONE; | ||
847 | continue; | ||
848 | } | ||
849 | 848 | ||
850 | /* Cleanup aged off entries. */ | 849 | /* Cleanup aged off entries. */ |
851 | *rthp = rth->u.dst.rt_next; | 850 | *rthp = rth->u.dst.rt_next; |
@@ -1068,7 +1067,6 @@ out: return 0; | |||
1068 | static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp) | 1067 | static int rt_intern_hash(unsigned hash, struct rtable *rt, struct rtable **rp) |
1069 | { | 1068 | { |
1070 | struct rtable *rth, **rthp; | 1069 | struct rtable *rth, **rthp; |
1071 | struct rtable *rthi; | ||
1072 | unsigned long now; | 1070 | unsigned long now; |
1073 | struct rtable *cand, **candp; | 1071 | struct rtable *cand, **candp; |
1074 | u32 min_score; | 1072 | u32 min_score; |
@@ -1088,7 +1086,6 @@ restart: | |||
1088 | } | 1086 | } |
1089 | 1087 | ||
1090 | rthp = &rt_hash_table[hash].chain; | 1088 | rthp = &rt_hash_table[hash].chain; |
1091 | rthi = NULL; | ||
1092 | 1089 | ||
1093 | spin_lock_bh(rt_hash_lock_addr(hash)); | 1090 | spin_lock_bh(rt_hash_lock_addr(hash)); |
1094 | while ((rth = *rthp) != NULL) { | 1091 | while ((rth = *rthp) != NULL) { |
@@ -1134,17 +1131,6 @@ restart: | |||
1134 | chain_length++; | 1131 | chain_length++; |
1135 | 1132 | ||
1136 | rthp = &rth->u.dst.rt_next; | 1133 | rthp = &rth->u.dst.rt_next; |
1137 | |||
1138 | /* | ||
1139 | * check to see if the next entry in the chain | ||
1140 | * contains the same hash input values as rt. If it does | ||
1141 | * This is where we will insert into the list, instead of | ||
1142 | * at the head. This groups entries that differ by aspects not | ||
1143 | * relvant to the hash function together, which we use to adjust | ||
1144 | * our chain length | ||
1145 | */ | ||
1146 | if (*rthp && compare_hash_inputs(&(*rthp)->fl, &rt->fl)) | ||
1147 | rthi = rth; | ||
1148 | } | 1134 | } |
1149 | 1135 | ||
1150 | if (cand) { | 1136 | if (cand) { |
@@ -1205,10 +1191,7 @@ restart: | |||
1205 | } | 1191 | } |
1206 | } | 1192 | } |
1207 | 1193 | ||
1208 | if (rthi) | 1194 | rt->u.dst.rt_next = rt_hash_table[hash].chain; |
1209 | rt->u.dst.rt_next = rthi->u.dst.rt_next; | ||
1210 | else | ||
1211 | rt->u.dst.rt_next = rt_hash_table[hash].chain; | ||
1212 | 1195 | ||
1213 | #if RT_CACHE_DEBUG >= 2 | 1196 | #if RT_CACHE_DEBUG >= 2 |
1214 | if (rt->u.dst.rt_next) { | 1197 | if (rt->u.dst.rt_next) { |
@@ -1224,10 +1207,7 @@ restart: | |||
1224 | * previous writes to rt are comitted to memory | 1207 | * previous writes to rt are comitted to memory |
1225 | * before making rt visible to other CPUS. | 1208 | * before making rt visible to other CPUS. |
1226 | */ | 1209 | */ |
1227 | if (rthi) | 1210 | rcu_assign_pointer(rt_hash_table[hash].chain, rt); |
1228 | rcu_assign_pointer(rthi->u.dst.rt_next, rt); | ||
1229 | else | ||
1230 | rcu_assign_pointer(rt_hash_table[hash].chain, rt); | ||
1231 | 1211 | ||
1232 | spin_unlock_bh(rt_hash_lock_addr(hash)); | 1212 | spin_unlock_bh(rt_hash_lock_addr(hash)); |
1233 | *rp = rt; | 1213 | *rp = rt; |
diff --git a/net/ipv4/tcp_vegas.c b/net/ipv4/tcp_vegas.c index a453aac91bd3..c6743eec9b7d 100644 --- a/net/ipv4/tcp_vegas.c +++ b/net/ipv4/tcp_vegas.c | |||
@@ -158,6 +158,11 @@ void tcp_vegas_cwnd_event(struct sock *sk, enum tcp_ca_event event) | |||
158 | } | 158 | } |
159 | EXPORT_SYMBOL_GPL(tcp_vegas_cwnd_event); | 159 | EXPORT_SYMBOL_GPL(tcp_vegas_cwnd_event); |
160 | 160 | ||
161 | static inline u32 tcp_vegas_ssthresh(struct tcp_sock *tp) | ||
162 | { | ||
163 | return min(tp->snd_ssthresh, tp->snd_cwnd-1); | ||
164 | } | ||
165 | |||
161 | static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) | 166 | static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) |
162 | { | 167 | { |
163 | struct tcp_sock *tp = tcp_sk(sk); | 168 | struct tcp_sock *tp = tcp_sk(sk); |
@@ -221,11 +226,10 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) | |||
221 | */ | 226 | */ |
222 | diff = tp->snd_cwnd * (rtt-vegas->baseRTT) / vegas->baseRTT; | 227 | diff = tp->snd_cwnd * (rtt-vegas->baseRTT) / vegas->baseRTT; |
223 | 228 | ||
224 | if (diff > gamma && tp->snd_ssthresh > 2 ) { | 229 | if (diff > gamma && tp->snd_cwnd <= tp->snd_ssthresh) { |
225 | /* Going too fast. Time to slow down | 230 | /* Going too fast. Time to slow down |
226 | * and switch to congestion avoidance. | 231 | * and switch to congestion avoidance. |
227 | */ | 232 | */ |
228 | tp->snd_ssthresh = 2; | ||
229 | 233 | ||
230 | /* Set cwnd to match the actual rate | 234 | /* Set cwnd to match the actual rate |
231 | * exactly: | 235 | * exactly: |
@@ -235,6 +239,7 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) | |||
235 | * utilization. | 239 | * utilization. |
236 | */ | 240 | */ |
237 | tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1); | 241 | tp->snd_cwnd = min(tp->snd_cwnd, (u32)target_cwnd+1); |
242 | tp->snd_ssthresh = tcp_vegas_ssthresh(tp); | ||
238 | 243 | ||
239 | } else if (tp->snd_cwnd <= tp->snd_ssthresh) { | 244 | } else if (tp->snd_cwnd <= tp->snd_ssthresh) { |
240 | /* Slow start. */ | 245 | /* Slow start. */ |
@@ -250,6 +255,8 @@ static void tcp_vegas_cong_avoid(struct sock *sk, u32 ack, u32 in_flight) | |||
250 | * we slow down. | 255 | * we slow down. |
251 | */ | 256 | */ |
252 | tp->snd_cwnd--; | 257 | tp->snd_cwnd--; |
258 | tp->snd_ssthresh | ||
259 | = tcp_vegas_ssthresh(tp); | ||
253 | } else if (diff < alpha) { | 260 | } else if (diff < alpha) { |
254 | /* We don't have enough extra packets | 261 | /* We don't have enough extra packets |
255 | * in the network, so speed up. | 262 | * in the network, so speed up. |
diff --git a/net/ipv6/route.c b/net/ipv6/route.c index 1394ddb6e35c..032a5ec391c5 100644 --- a/net/ipv6/route.c +++ b/net/ipv6/route.c | |||
@@ -137,6 +137,7 @@ static struct rt6_info ip6_null_entry_template = { | |||
137 | } | 137 | } |
138 | }, | 138 | }, |
139 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | 139 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), |
140 | .rt6i_protocol = RTPROT_KERNEL, | ||
140 | .rt6i_metric = ~(u32) 0, | 141 | .rt6i_metric = ~(u32) 0, |
141 | .rt6i_ref = ATOMIC_INIT(1), | 142 | .rt6i_ref = ATOMIC_INIT(1), |
142 | }; | 143 | }; |
@@ -159,6 +160,7 @@ static struct rt6_info ip6_prohibit_entry_template = { | |||
159 | } | 160 | } |
160 | }, | 161 | }, |
161 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | 162 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), |
163 | .rt6i_protocol = RTPROT_KERNEL, | ||
162 | .rt6i_metric = ~(u32) 0, | 164 | .rt6i_metric = ~(u32) 0, |
163 | .rt6i_ref = ATOMIC_INIT(1), | 165 | .rt6i_ref = ATOMIC_INIT(1), |
164 | }; | 166 | }; |
@@ -176,6 +178,7 @@ static struct rt6_info ip6_blk_hole_entry_template = { | |||
176 | } | 178 | } |
177 | }, | 179 | }, |
178 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), | 180 | .rt6i_flags = (RTF_REJECT | RTF_NONEXTHOP), |
181 | .rt6i_protocol = RTPROT_KERNEL, | ||
179 | .rt6i_metric = ~(u32) 0, | 182 | .rt6i_metric = ~(u32) 0, |
180 | .rt6i_ref = ATOMIC_INIT(1), | 183 | .rt6i_ref = ATOMIC_INIT(1), |
181 | }; | 184 | }; |
diff --git a/net/rxrpc/ar-connection.c b/net/rxrpc/ar-connection.c index 0f1218b8d289..67e38a056240 100644 --- a/net/rxrpc/ar-connection.c +++ b/net/rxrpc/ar-connection.c | |||
@@ -343,9 +343,9 @@ static int rxrpc_connect_exclusive(struct rxrpc_sock *rx, | |||
343 | /* not yet present - create a candidate for a new connection | 343 | /* not yet present - create a candidate for a new connection |
344 | * and then redo the check */ | 344 | * and then redo the check */ |
345 | conn = rxrpc_alloc_connection(gfp); | 345 | conn = rxrpc_alloc_connection(gfp); |
346 | if (IS_ERR(conn)) { | 346 | if (!conn) { |
347 | _leave(" = %ld", PTR_ERR(conn)); | 347 | _leave(" = -ENOMEM"); |
348 | return PTR_ERR(conn); | 348 | return -ENOMEM; |
349 | } | 349 | } |
350 | 350 | ||
351 | conn->trans = trans; | 351 | conn->trans = trans; |
@@ -508,9 +508,9 @@ int rxrpc_connect_call(struct rxrpc_sock *rx, | |||
508 | /* not yet present - create a candidate for a new connection and then | 508 | /* not yet present - create a candidate for a new connection and then |
509 | * redo the check */ | 509 | * redo the check */ |
510 | candidate = rxrpc_alloc_connection(gfp); | 510 | candidate = rxrpc_alloc_connection(gfp); |
511 | if (IS_ERR(candidate)) { | 511 | if (!candidate) { |
512 | _leave(" = %ld", PTR_ERR(candidate)); | 512 | _leave(" = -ENOMEM"); |
513 | return PTR_ERR(candidate); | 513 | return -ENOMEM; |
514 | } | 514 | } |
515 | 515 | ||
516 | candidate->trans = trans; | 516 | candidate->trans = trans; |
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c index 3b21e0cc5e69..465aafc2007f 100644 --- a/net/sunrpc/xprtrdma/verbs.c +++ b/net/sunrpc/xprtrdma/verbs.c | |||
@@ -1495,7 +1495,8 @@ rpcrdma_register_frmr_external(struct rpcrdma_mr_seg *seg, | |||
1495 | frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; | 1495 | frmr_wr.wr.fast_reg.page_shift = PAGE_SHIFT; |
1496 | frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT; | 1496 | frmr_wr.wr.fast_reg.length = i << PAGE_SHIFT; |
1497 | frmr_wr.wr.fast_reg.access_flags = (writing ? | 1497 | frmr_wr.wr.fast_reg.access_flags = (writing ? |
1498 | IB_ACCESS_REMOTE_WRITE : IB_ACCESS_REMOTE_READ); | 1498 | IB_ACCESS_REMOTE_WRITE | IB_ACCESS_LOCAL_WRITE : |
1499 | IB_ACCESS_REMOTE_READ); | ||
1499 | frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; | 1500 | frmr_wr.wr.fast_reg.rkey = seg1->mr_chunk.rl_mw->r.frmr.fr_mr->rkey; |
1500 | DECR_CQCOUNT(&r_xprt->rx_ep); | 1501 | DECR_CQCOUNT(&r_xprt->rx_ep); |
1501 | 1502 | ||
diff --git a/net/wireless/reg.c b/net/wireless/reg.c index 08265ca15785..487cb627ddba 100644 --- a/net/wireless/reg.c +++ b/net/wireless/reg.c | |||
@@ -1551,6 +1551,13 @@ static int regulatory_hint_core(const char *alpha2) | |||
1551 | 1551 | ||
1552 | queue_regulatory_request(request); | 1552 | queue_regulatory_request(request); |
1553 | 1553 | ||
1554 | /* | ||
1555 | * This ensures last_request is populated once modules | ||
1556 | * come swinging in and calling regulatory hints and | ||
1557 | * wiphy_apply_custom_regulatory(). | ||
1558 | */ | ||
1559 | flush_scheduled_work(); | ||
1560 | |||
1554 | return 0; | 1561 | return 0; |
1555 | } | 1562 | } |
1556 | 1563 | ||
diff --git a/net/wireless/wext.c b/net/wireless/wext.c index cb6a5bb85d80..0e59f9ae9b81 100644 --- a/net/wireless/wext.c +++ b/net/wireless/wext.c | |||
@@ -786,6 +786,13 @@ static int ioctl_standard_iw_point(struct iw_point *iwp, unsigned int cmd, | |||
786 | err = -EFAULT; | 786 | err = -EFAULT; |
787 | goto out; | 787 | goto out; |
788 | } | 788 | } |
789 | |||
790 | if (cmd == SIOCSIWENCODEEXT) { | ||
791 | struct iw_encode_ext *ee = (void *) extra; | ||
792 | |||
793 | if (iwp->length < sizeof(*ee) + ee->key_len) | ||
794 | return -EFAULT; | ||
795 | } | ||
789 | } | 796 | } |
790 | 797 | ||
791 | err = handler(dev, info, (union iwreq_data *) iwp, extra); | 798 | err = handler(dev, info, (union iwreq_data *) iwp, extra); |
diff --git a/security/tomoyo/tomoyo.c b/security/tomoyo/tomoyo.c index 5b481912752a..e42be5c4f055 100644 --- a/security/tomoyo/tomoyo.c +++ b/security/tomoyo/tomoyo.c | |||
@@ -27,6 +27,12 @@ static int tomoyo_cred_prepare(struct cred *new, const struct cred *old, | |||
27 | 27 | ||
28 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) | 28 | static int tomoyo_bprm_set_creds(struct linux_binprm *bprm) |
29 | { | 29 | { |
30 | int rc; | ||
31 | |||
32 | rc = cap_bprm_set_creds(bprm); | ||
33 | if (rc) | ||
34 | return rc; | ||
35 | |||
30 | /* | 36 | /* |
31 | * Do only if this function is called for the first time of an execve | 37 | * Do only if this function is called for the first time of an execve |
32 | * operation. | 38 | * operation. |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index 21e99cfa8c49..3128e1a6bc65 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -2141,6 +2141,7 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = { | |||
2141 | /* including bogus ALC268 in slot#2 that conflicts with ALC888 */ | 2141 | /* including bogus ALC268 in slot#2 that conflicts with ALC888 */ |
2142 | SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01), | 2142 | SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01), |
2143 | /* forced codec slots */ | 2143 | /* forced codec slots */ |
2144 | SND_PCI_QUIRK(0x1043, 0x1262, "ASUS W5Fm", 0x103), | ||
2144 | SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103), | 2145 | SND_PCI_QUIRK(0x1046, 0x1262, "ASUS W5F", 0x103), |
2145 | {} | 2146 | {} |
2146 | }; | 2147 | }; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index bcbb736f94f0..0fd258eba3a5 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -776,6 +776,12 @@ static void alc_set_input_pin(struct hda_codec *codec, hda_nid_t nid, | |||
776 | pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; | 776 | pincap = (pincap & AC_PINCAP_VREF) >> AC_PINCAP_VREF_SHIFT; |
777 | if (pincap & AC_PINCAP_VREF_80) | 777 | if (pincap & AC_PINCAP_VREF_80) |
778 | val = PIN_VREF80; | 778 | val = PIN_VREF80; |
779 | else if (pincap & AC_PINCAP_VREF_50) | ||
780 | val = PIN_VREF50; | ||
781 | else if (pincap & AC_PINCAP_VREF_100) | ||
782 | val = PIN_VREF100; | ||
783 | else if (pincap & AC_PINCAP_VREF_GRD) | ||
784 | val = PIN_VREFGRD; | ||
779 | } | 785 | } |
780 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); | 786 | snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, val); |
781 | } | 787 | } |
diff --git a/sound/pci/hda/patch_sigmatel.c b/sound/pci/hda/patch_sigmatel.c index 03b3646018a1..d2fd8ef6aef8 100644 --- a/sound/pci/hda/patch_sigmatel.c +++ b/sound/pci/hda/patch_sigmatel.c | |||
@@ -150,6 +150,7 @@ enum { | |||
150 | STAC_D965_REF, | 150 | STAC_D965_REF, |
151 | STAC_D965_3ST, | 151 | STAC_D965_3ST, |
152 | STAC_D965_5ST, | 152 | STAC_D965_5ST, |
153 | STAC_D965_5ST_NO_FP, | ||
153 | STAC_DELL_3ST, | 154 | STAC_DELL_3ST, |
154 | STAC_DELL_BIOS, | 155 | STAC_DELL_BIOS, |
155 | STAC_927X_MODELS | 156 | STAC_927X_MODELS |
@@ -2154,6 +2155,13 @@ static unsigned int d965_5st_pin_configs[14] = { | |||
2154 | 0x40000100, 0x40000100 | 2155 | 0x40000100, 0x40000100 |
2155 | }; | 2156 | }; |
2156 | 2157 | ||
2158 | static unsigned int d965_5st_no_fp_pin_configs[14] = { | ||
2159 | 0x40000100, 0x40000100, 0x0181304e, 0x01014010, | ||
2160 | 0x01a19040, 0x01011012, 0x01016011, 0x40000100, | ||
2161 | 0x40000100, 0x40000100, 0x40000100, 0x01442070, | ||
2162 | 0x40000100, 0x40000100 | ||
2163 | }; | ||
2164 | |||
2157 | static unsigned int dell_3st_pin_configs[14] = { | 2165 | static unsigned int dell_3st_pin_configs[14] = { |
2158 | 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, | 2166 | 0x02211230, 0x02a11220, 0x01a19040, 0x01114210, |
2159 | 0x01111212, 0x01116211, 0x01813050, 0x01112214, | 2167 | 0x01111212, 0x01116211, 0x01813050, 0x01112214, |
@@ -2166,6 +2174,7 @@ static unsigned int *stac927x_brd_tbl[STAC_927X_MODELS] = { | |||
2166 | [STAC_D965_REF] = ref927x_pin_configs, | 2174 | [STAC_D965_REF] = ref927x_pin_configs, |
2167 | [STAC_D965_3ST] = d965_3st_pin_configs, | 2175 | [STAC_D965_3ST] = d965_3st_pin_configs, |
2168 | [STAC_D965_5ST] = d965_5st_pin_configs, | 2176 | [STAC_D965_5ST] = d965_5st_pin_configs, |
2177 | [STAC_D965_5ST_NO_FP] = d965_5st_no_fp_pin_configs, | ||
2169 | [STAC_DELL_3ST] = dell_3st_pin_configs, | 2178 | [STAC_DELL_3ST] = dell_3st_pin_configs, |
2170 | [STAC_DELL_BIOS] = NULL, | 2179 | [STAC_DELL_BIOS] = NULL, |
2171 | }; | 2180 | }; |
@@ -2176,6 +2185,7 @@ static const char *stac927x_models[STAC_927X_MODELS] = { | |||
2176 | [STAC_D965_REF] = "ref", | 2185 | [STAC_D965_REF] = "ref", |
2177 | [STAC_D965_3ST] = "3stack", | 2186 | [STAC_D965_3ST] = "3stack", |
2178 | [STAC_D965_5ST] = "5stack", | 2187 | [STAC_D965_5ST] = "5stack", |
2188 | [STAC_D965_5ST_NO_FP] = "5stack-no-fp", | ||
2179 | [STAC_DELL_3ST] = "dell-3stack", | 2189 | [STAC_DELL_3ST] = "dell-3stack", |
2180 | [STAC_DELL_BIOS] = "dell-bios", | 2190 | [STAC_DELL_BIOS] = "dell-bios", |
2181 | }; | 2191 | }; |