diff --git a/[refs] b/[refs] index 998b1801c9b6..577b06591fff 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 28890d3598c352ae065b560e0fded3e79c800ba1 +refs/heads/master: 1c4f33296e8e79a6bbfffc8457d547ffc31d5dee diff --git a/trunk/Documentation/devicetree/bindings/gpio/gpio_keys.txt b/trunk/Documentation/devicetree/bindings/gpio/gpio_keys.txt deleted file mode 100644 index 7190c99d7611..000000000000 --- a/trunk/Documentation/devicetree/bindings/gpio/gpio_keys.txt +++ /dev/null @@ -1,36 +0,0 @@ -Device-Tree bindings for input/gpio_keys.c keyboard driver - -Required properties: - - compatible = "gpio-keys"; - -Optional properties: - - autorepeat: Boolean, Enable auto repeat feature of Linux input - subsystem. - -Each button (key) is represented as a sub-node of "gpio-keys": -Subnode properties: - - - gpios: OF devcie-tree gpio specificatin. - - label: Descriptive name of the key. - - linux,code: Keycode to emit. - -Optional subnode-properties: - - linux,input-type: Specify event type this button/key generates. - If not specified defaults to <1> == EV_KEY. - - debounce-interval: Debouncing interval time in milliseconds. - If not specified defaults to 5. - - gpio-key,wakeup: Boolean, button can wake-up the system. - -Example nodes: - - gpio_keys { - compatible = "gpio-keys"; - #address-cells = <1>; - #size-cells = <0>; - autorepeat; - button@21 { - label = "GPIO Key UP"; - linux,code = <103>; - gpios = <&gpio1 0 1>; - }; - ... diff --git a/trunk/Documentation/filesystems/nfs/Exporting b/trunk/Documentation/filesystems/nfs/Exporting index 09994c247289..87019d2b5981 100644 --- a/trunk/Documentation/filesystems/nfs/Exporting +++ b/trunk/Documentation/filesystems/nfs/Exporting @@ -92,14 +92,7 @@ For a filesystem to be exportable it must: 1/ provide the filehandle fragment routines described below. 2/ make sure that d_splice_alias is used rather than d_add when ->lookup finds an inode for a given parent and name. - - If inode is NULL, d_splice_alias(inode, dentry) is eqivalent to - - d_add(dentry, inode), NULL - - Similarly, d_splice_alias(ERR_PTR(err), dentry) = ERR_PTR(err) - - Typically the ->lookup routine will simply end with a: + Typically the ->lookup routine will end with a: return d_splice_alias(inode, dentry); } diff --git a/trunk/arch/microblaze/include/asm/cpuinfo.h b/trunk/arch/microblaze/include/asm/cpuinfo.h index 7d6831ac8a46..d8f013347a9e 100644 --- a/trunk/arch/microblaze/include/asm/cpuinfo.h +++ b/trunk/arch/microblaze/include/asm/cpuinfo.h @@ -38,7 +38,6 @@ struct cpuinfo { u32 use_exc; u32 ver_code; u32 mmu; - u32 mmu_privins; u32 endian; /* CPU caches */ diff --git a/trunk/arch/microblaze/include/asm/irqflags.h b/trunk/arch/microblaze/include/asm/irqflags.h index c9a6262832c4..c4532f032b3b 100644 --- a/trunk/arch/microblaze/include/asm/irqflags.h +++ b/trunk/arch/microblaze/include/asm/irqflags.h @@ -14,7 +14,7 @@ #if CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR -static inline notrace unsigned long arch_local_irq_save(void) +static inline unsigned long arch_local_irq_save(void) { unsigned long flags; asm volatile(" msrclr %0, %1 \n" @@ -25,7 +25,7 @@ static inline notrace unsigned long arch_local_irq_save(void) return flags; } -static inline notrace void arch_local_irq_disable(void) +static inline void arch_local_irq_disable(void) { /* this uses r0 without declaring it - is that correct? */ asm volatile(" msrclr r0, %0 \n" @@ -35,7 +35,7 @@ static inline notrace void arch_local_irq_disable(void) : "memory"); } -static inline notrace void arch_local_irq_enable(void) +static inline void arch_local_irq_enable(void) { /* this uses r0 without declaring it - is that correct? */ asm volatile(" msrset r0, %0 \n" @@ -47,7 +47,7 @@ static inline notrace void arch_local_irq_enable(void) #else /* !CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */ -static inline notrace unsigned long arch_local_irq_save(void) +static inline unsigned long arch_local_irq_save(void) { unsigned long flags, tmp; asm volatile (" mfs %0, rmsr \n" @@ -61,7 +61,7 @@ static inline notrace unsigned long arch_local_irq_save(void) return flags; } -static inline notrace void arch_local_irq_disable(void) +static inline void arch_local_irq_disable(void) { unsigned long tmp; asm volatile(" mfs %0, rmsr \n" @@ -74,7 +74,7 @@ static inline notrace void arch_local_irq_disable(void) : "memory"); } -static inline notrace void arch_local_irq_enable(void) +static inline void arch_local_irq_enable(void) { unsigned long tmp; asm volatile(" mfs %0, rmsr \n" @@ -89,7 +89,7 @@ static inline notrace void arch_local_irq_enable(void) #endif /* CONFIG_XILINX_MICROBLAZE0_USE_MSR_INSTR */ -static inline notrace unsigned long arch_local_save_flags(void) +static inline unsigned long arch_local_save_flags(void) { unsigned long flags; asm volatile(" mfs %0, rmsr \n" @@ -100,7 +100,7 @@ static inline notrace unsigned long arch_local_save_flags(void) return flags; } -static inline notrace void arch_local_irq_restore(unsigned long flags) +static inline void arch_local_irq_restore(unsigned long flags) { asm volatile(" mts rmsr, %0 \n" " nop \n" @@ -109,12 +109,12 @@ static inline notrace void arch_local_irq_restore(unsigned long flags) : "memory"); } -static inline notrace bool arch_irqs_disabled_flags(unsigned long flags) +static inline bool arch_irqs_disabled_flags(unsigned long flags) { return (flags & MSR_IE) == 0; } -static inline notrace bool arch_irqs_disabled(void) +static inline bool arch_irqs_disabled(void) { return arch_irqs_disabled_flags(arch_local_save_flags()); } diff --git a/trunk/arch/microblaze/include/asm/processor.h b/trunk/arch/microblaze/include/asm/processor.h index 7283bfb2f7e4..aed2a6be8e27 100644 --- a/trunk/arch/microblaze/include/asm/processor.h +++ b/trunk/arch/microblaze/include/asm/processor.h @@ -125,6 +125,9 @@ struct thread_struct { .pgdir = swapper_pg_dir, \ } +/* Do necessary setup to start up a newly executed thread. */ +void start_thread(struct pt_regs *regs, + unsigned long pc, unsigned long usp); /* Free all resources held by a thread. */ extern inline void release_thread(struct task_struct *dead_task) diff --git a/trunk/arch/microblaze/include/asm/prom.h b/trunk/arch/microblaze/include/asm/prom.h index 20c5e8e5121b..9ad567e2d425 100644 --- a/trunk/arch/microblaze/include/asm/prom.h +++ b/trunk/arch/microblaze/include/asm/prom.h @@ -26,12 +26,8 @@ #define HAVE_ARCH_DEVTREE_FIXUPS /* Other Prototypes */ -enum early_consoles { - UARTLITE = 1, - UART16550 = 2, -}; - -extern int of_early_console(void *version); +extern int early_uartlite_console(void); +extern int early_uart16550_console(void); /* * OF address retreival & translation diff --git a/trunk/arch/microblaze/include/asm/pvr.h b/trunk/arch/microblaze/include/asm/pvr.h index 4bbdb4c03b57..a10bec62e857 100644 --- a/trunk/arch/microblaze/include/asm/pvr.h +++ b/trunk/arch/microblaze/include/asm/pvr.h @@ -111,16 +111,16 @@ struct pvr_s { /* Target family PVR mask */ #define PVR10_TARGET_FAMILY_MASK 0xFF000000 -/* MMU description */ +/* MMU descrtiption */ #define PVR11_USE_MMU 0xC0000000 #define PVR11_MMU_ITLB_SIZE 0x38000000 #define PVR11_MMU_DTLB_SIZE 0x07000000 #define PVR11_MMU_TLB_ACCESS 0x00C00000 #define PVR11_MMU_ZONES 0x003C0000 -#define PVR11_MMU_PRIVINS 0x00010000 /* MSR Reset value PVR mask */ #define PVR11_MSR_RESET_VALUE_MASK 0x000007FF + /* PVR access macros */ #define PVR_IS_FULL(_pvr) (_pvr.pvr[0] & PVR0_PVR_FULL_MASK) #define PVR_USE_BARREL(_pvr) (_pvr.pvr[0] & PVR0_USE_BARREL_MASK) @@ -216,7 +216,6 @@ struct pvr_s { #define PVR_MMU_DTLB_SIZE(_pvr) (_pvr.pvr[11] & PVR11_MMU_DTLB_SIZE) #define PVR_MMU_TLB_ACCESS(_pvr) (_pvr.pvr[11] & PVR11_MMU_TLB_ACCESS) #define PVR_MMU_ZONES(_pvr) (_pvr.pvr[11] & PVR11_MMU_ZONES) -#define PVR_MMU_PRIVINS(pvr) (pvr.pvr[11] & PVR11_MMU_PRIVINS) /* endian */ #define PVR_ENDIAN(_pvr) (_pvr.pvr[0] & PVR0_ENDI) diff --git a/trunk/arch/microblaze/include/asm/setup.h b/trunk/arch/microblaze/include/asm/setup.h index 904e5ef6a11b..8f3968971e4e 100644 --- a/trunk/arch/microblaze/include/asm/setup.h +++ b/trunk/arch/microblaze/include/asm/setup.h @@ -23,7 +23,6 @@ extern char cmd_line[COMMAND_LINE_SIZE]; void early_printk(const char *fmt, ...); int setup_early_printk(char *opt); -void remap_early_printk(void); void disable_early_printk(void); #if defined(CONFIG_EARLY_PRINTK) diff --git a/trunk/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c b/trunk/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c index 916aaedf1945..f70a6047f08e 100644 --- a/trunk/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c +++ b/trunk/arch/microblaze/kernel/cpu/cpuinfo-pvr-full.c @@ -72,7 +72,6 @@ void set_cpuinfo_pvr_full(struct cpuinfo *ci, struct device_node *cpu) CI(pvr_user2, USER2); CI(mmu, USE_MMU); - CI(mmu_privins, MMU_PRIVINS); CI(endian, ENDIAN); CI(use_icache, USE_ICACHE); diff --git a/trunk/arch/microblaze/kernel/cpu/cpuinfo-static.c b/trunk/arch/microblaze/kernel/cpu/cpuinfo-static.c index 592bb2e838c4..b16b994ca3d2 100644 --- a/trunk/arch/microblaze/kernel/cpu/cpuinfo-static.c +++ b/trunk/arch/microblaze/kernel/cpu/cpuinfo-static.c @@ -119,7 +119,6 @@ void __init set_cpuinfo_static(struct cpuinfo *ci, struct device_node *cpu) ci->pvr_user2 = fcpu(cpu, "xlnx,pvr-user2"); ci->mmu = fcpu(cpu, "xlnx,use-mmu"); - ci->mmu_privins = fcpu(cpu, "xlnx,mmu-privileged-instr"); ci->endian = fcpu(cpu, "xlnx,endianness"); ci->ver_code = 0; diff --git a/trunk/arch/microblaze/kernel/cpu/cpuinfo.c b/trunk/arch/microblaze/kernel/cpu/cpuinfo.c index 44394d80a683..c1640c52711f 100644 --- a/trunk/arch/microblaze/kernel/cpu/cpuinfo.c +++ b/trunk/arch/microblaze/kernel/cpu/cpuinfo.c @@ -88,8 +88,4 @@ void __init setup_cpuinfo(void) printk(KERN_WARNING "%s: Unsupported PVR setting\n", __func__); set_cpuinfo_static(&cpuinfo, cpu); } - - if (cpuinfo.mmu_privins) - printk(KERN_WARNING "%s: Stream instructions enabled" - " - USERSPACE CAN LOCK THIS KERNEL!\n", __func__); } diff --git a/trunk/arch/microblaze/kernel/cpu/mb.c b/trunk/arch/microblaze/kernel/cpu/mb.c index 7b5dca7ed39d..b4048af02615 100644 --- a/trunk/arch/microblaze/kernel/cpu/mb.c +++ b/trunk/arch/microblaze/kernel/cpu/mb.c @@ -97,10 +97,6 @@ static int show_cpuinfo(struct seq_file *m, void *v) (cpuinfo.use_exc & PVR2_FPU_EXC_MASK) ? "fpu " : "", (cpuinfo.use_exc & PVR2_USE_FSL_EXC) ? "fsl " : ""); - count += seq_printf(m, - "Stream-insns:\t%sprivileged\n", - cpuinfo.mmu_privins ? "un" : ""); - if (cpuinfo.use_icache) count += seq_printf(m, "Icache:\t\t%ukB\tline length:\t%dB\n", @@ -114,11 +110,10 @@ static int show_cpuinfo(struct seq_file *m, void *v) "Dcache:\t\t%ukB\tline length:\t%dB\n", cpuinfo.dcache_size >> 10, cpuinfo.dcache_line_length); - seq_printf(m, "Dcache-Policy:\t"); if (cpuinfo.dcache_wb) - count += seq_printf(m, "write-back\n"); + count += seq_printf(m, "\t\twrite-back\n"); else - count += seq_printf(m, "write-through\n"); + count += seq_printf(m, "\t\twrite-through\n"); } else count += seq_printf(m, "Dcache:\t\tno\n"); diff --git a/trunk/arch/microblaze/kernel/early_printk.c b/trunk/arch/microblaze/kernel/early_printk.c index d26d92d47754..c3616a080ebf 100644 --- a/trunk/arch/microblaze/kernel/early_printk.c +++ b/trunk/arch/microblaze/kernel/early_printk.c @@ -35,7 +35,7 @@ static void early_printk_uartlite_putc(char c) * we'll never timeout on a working UART. */ - unsigned retries = 1000000; + unsigned retries = 10000; /* read status bit - 0x8 offset */ while (--retries && (in_be32(base_addr + 8) & (1 << 3))) ; @@ -60,7 +60,7 @@ static void early_printk_uartlite_write(struct console *unused, static struct console early_serial_uartlite_console = { .name = "earlyser", .write = early_printk_uartlite_write, - .flags = CON_PRINTBUFFER | CON_BOOT, + .flags = CON_PRINTBUFFER, .index = -1, }; #endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */ @@ -104,7 +104,7 @@ static void early_printk_uart16550_write(struct console *unused, static struct console early_serial_uart16550_console = { .name = "earlyser", .write = early_printk_uart16550_write, - .flags = CON_PRINTBUFFER | CON_BOOT, + .flags = CON_PRINTBUFFER, .index = -1, }; #endif /* CONFIG_SERIAL_8250_CONSOLE */ @@ -127,54 +127,46 @@ void early_printk(const char *fmt, ...) int __init setup_early_printk(char *opt) { - int version = 0; - if (early_console_initialized) return 1; - base_addr = of_early_console(&version); +#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE + base_addr = early_uartlite_console(); if (base_addr) { + early_console_initialized = 1; #ifdef CONFIG_MMU early_console_reg_tlb_alloc(base_addr); #endif - switch (version) { -#ifdef CONFIG_SERIAL_UARTLITE_CONSOLE - case UARTLITE: - printk(KERN_INFO "Early console on uartlite " - "at 0x%08x\n", base_addr); - early_console = &early_serial_uartlite_console; - break; -#endif + early_console = &early_serial_uartlite_console; + early_printk("early_printk_console is enabled at 0x%08x\n", + base_addr); + + /* register_console(early_console); */ + + return 0; + } +#endif /* CONFIG_SERIAL_UARTLITE_CONSOLE */ + #ifdef CONFIG_SERIAL_8250_CONSOLE - case UART16550: - printk(KERN_INFO "Early console on uart16650 " - "at 0x%08x\n", base_addr); - early_console = &early_serial_uart16550_console; - break; + base_addr = early_uart16550_console(); + base_addr &= ~3; /* clear register offset */ + if (base_addr) { + early_console_initialized = 1; +#ifdef CONFIG_MMU + early_console_reg_tlb_alloc(base_addr); #endif - default: - printk(KERN_INFO "Unsupported early console %d\n", - version); - return 1; - } + early_console = &early_serial_uart16550_console; + + early_printk("early_printk_console is enabled at 0x%08x\n", + base_addr); + + /* register_console(early_console); */ - register_console(early_console); - early_console_initialized = 1; return 0; } - return 1; -} +#endif /* CONFIG_SERIAL_8250_CONSOLE */ -/* Remap early console to virtual address and do not allocate one TLB - * only for early console because of performance degression */ -void __init remap_early_printk(void) -{ - if (!early_console_initialized || !early_console) - return; - printk(KERN_INFO "early_printk_console remaping from 0x%x to ", - base_addr); - base_addr = (u32) ioremap(base_addr, PAGE_SIZE); - printk(KERN_CONT "0x%x\n", base_addr); + return 1; } void __init disable_early_printk(void) diff --git a/trunk/arch/microblaze/kernel/hw_exception_handler.S b/trunk/arch/microblaze/kernel/hw_exception_handler.S index e62be8379604..56572e923a83 100644 --- a/trunk/arch/microblaze/kernel/hw_exception_handler.S +++ b/trunk/arch/microblaze/kernel/hw_exception_handler.S @@ -1113,23 +1113,23 @@ lw_r10_vm: R3_TO_LWREG_VM_V (10); lw_r11_vm: R3_TO_LWREG_VM_V (11); lw_r12_vm: R3_TO_LWREG_VM_V (12); lw_r13_vm: R3_TO_LWREG_VM_V (13); -lw_r14_vm: R3_TO_LWREG_VM_V (14); +lw_r14_vm: R3_TO_LWREG_VM (14); lw_r15_vm: R3_TO_LWREG_VM_V (15); -lw_r16_vm: R3_TO_LWREG_VM_V (16); +lw_r16_vm: R3_TO_LWREG_VM (16); lw_r17_vm: R3_TO_LWREG_VM_V (17); lw_r18_vm: R3_TO_LWREG_VM_V (18); -lw_r19_vm: R3_TO_LWREG_VM_V (19); -lw_r20_vm: R3_TO_LWREG_VM_V (20); -lw_r21_vm: R3_TO_LWREG_VM_V (21); -lw_r22_vm: R3_TO_LWREG_VM_V (22); -lw_r23_vm: R3_TO_LWREG_VM_V (23); -lw_r24_vm: R3_TO_LWREG_VM_V (24); -lw_r25_vm: R3_TO_LWREG_VM_V (25); -lw_r26_vm: R3_TO_LWREG_VM_V (26); -lw_r27_vm: R3_TO_LWREG_VM_V (27); -lw_r28_vm: R3_TO_LWREG_VM_V (28); -lw_r29_vm: R3_TO_LWREG_VM_V (29); -lw_r30_vm: R3_TO_LWREG_VM_V (30); +lw_r19_vm: R3_TO_LWREG_VM (19); +lw_r20_vm: R3_TO_LWREG_VM (20); +lw_r21_vm: R3_TO_LWREG_VM (21); +lw_r22_vm: R3_TO_LWREG_VM (22); +lw_r23_vm: R3_TO_LWREG_VM (23); +lw_r24_vm: R3_TO_LWREG_VM (24); +lw_r25_vm: R3_TO_LWREG_VM (25); +lw_r26_vm: R3_TO_LWREG_VM (26); +lw_r27_vm: R3_TO_LWREG_VM (27); +lw_r28_vm: R3_TO_LWREG_VM (28); +lw_r29_vm: R3_TO_LWREG_VM (29); +lw_r30_vm: R3_TO_LWREG_VM (30); lw_r31_vm: R3_TO_LWREG_VM_V (31); sw_table_vm: @@ -1147,23 +1147,23 @@ sw_r10_vm: SWREG_TO_R3_VM_V (10); sw_r11_vm: SWREG_TO_R3_VM_V (11); sw_r12_vm: SWREG_TO_R3_VM_V (12); sw_r13_vm: SWREG_TO_R3_VM_V (13); -sw_r14_vm: SWREG_TO_R3_VM_V (14); +sw_r14_vm: SWREG_TO_R3_VM (14); sw_r15_vm: SWREG_TO_R3_VM_V (15); -sw_r16_vm: SWREG_TO_R3_VM_V (16); +sw_r16_vm: SWREG_TO_R3_VM (16); sw_r17_vm: SWREG_TO_R3_VM_V (17); sw_r18_vm: SWREG_TO_R3_VM_V (18); -sw_r19_vm: SWREG_TO_R3_VM_V (19); -sw_r20_vm: SWREG_TO_R3_VM_V (20); -sw_r21_vm: SWREG_TO_R3_VM_V (21); -sw_r22_vm: SWREG_TO_R3_VM_V (22); -sw_r23_vm: SWREG_TO_R3_VM_V (23); -sw_r24_vm: SWREG_TO_R3_VM_V (24); -sw_r25_vm: SWREG_TO_R3_VM_V (25); -sw_r26_vm: SWREG_TO_R3_VM_V (26); -sw_r27_vm: SWREG_TO_R3_VM_V (27); -sw_r28_vm: SWREG_TO_R3_VM_V (28); -sw_r29_vm: SWREG_TO_R3_VM_V (29); -sw_r30_vm: SWREG_TO_R3_VM_V (30); +sw_r19_vm: SWREG_TO_R3_VM (19); +sw_r20_vm: SWREG_TO_R3_VM (20); +sw_r21_vm: SWREG_TO_R3_VM (21); +sw_r22_vm: SWREG_TO_R3_VM (22); +sw_r23_vm: SWREG_TO_R3_VM (23); +sw_r24_vm: SWREG_TO_R3_VM (24); +sw_r25_vm: SWREG_TO_R3_VM (25); +sw_r26_vm: SWREG_TO_R3_VM (26); +sw_r27_vm: SWREG_TO_R3_VM (27); +sw_r28_vm: SWREG_TO_R3_VM (28); +sw_r29_vm: SWREG_TO_R3_VM (29); +sw_r30_vm: SWREG_TO_R3_VM (30); sw_r31_vm: SWREG_TO_R3_VM_V (31); #endif /* CONFIG_MMU */ diff --git a/trunk/arch/microblaze/kernel/intc.c b/trunk/arch/microblaze/kernel/intc.c index eb41441c7fd0..c88f066f41bd 100644 --- a/trunk/arch/microblaze/kernel/intc.c +++ b/trunk/arch/microblaze/kernel/intc.c @@ -134,7 +134,7 @@ void __init init_IRQ(void) intr_type = be32_to_cpup(of_get_property(intc, "xlnx,kind-of-intr", NULL)); - if (intr_type > (u32)((1ULL << nr_irq) - 1)) + if (intr_type >= (1 << (nr_irq + 1))) printk(KERN_INFO " ERROR: Mismatch in kind-of-intr param\n"); #ifdef CONFIG_SELFMOD_INTC diff --git a/trunk/arch/microblaze/kernel/process.c b/trunk/arch/microblaze/kernel/process.c index dbb812421d8a..968648a81c1e 100644 --- a/trunk/arch/microblaze/kernel/process.c +++ b/trunk/arch/microblaze/kernel/process.c @@ -237,6 +237,7 @@ unsigned long get_wchan(struct task_struct *p) /* Set up a thread for executing a new program */ void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long usp) { + set_fs(USER_DS); regs->pc = pc; regs->r1 = usp; regs->pt_mode = 0; diff --git a/trunk/arch/microblaze/kernel/prom.c b/trunk/arch/microblaze/kernel/prom.c index 977484add216..b15cc219b1d9 100644 --- a/trunk/arch/microblaze/kernel/prom.c +++ b/trunk/arch/microblaze/kernel/prom.c @@ -53,58 +53,69 @@ void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align) } #ifdef CONFIG_EARLY_PRINTK -char *stdout; +/* MS this is Microblaze specifig function */ +static int __init early_init_dt_scan_serial(unsigned long node, + const char *uname, int depth, void *data) +{ + unsigned long l; + char *p; + const __be32 *addr; + + pr_debug("search \"serial\", depth: %d, uname: %s\n", depth, uname); + +/* find all serial nodes */ + if (strncmp(uname, "serial", 6) != 0) + return 0; + +/* find compatible node with uartlite */ + p = of_get_flat_dt_prop(node, "compatible", &l); + if ((strncmp(p, "xlnx,xps-uartlite", 17) != 0) && + (strncmp(p, "xlnx,opb-uartlite", 17) != 0) && + (strncmp(p, "xlnx,axi-uartlite", 17) != 0)) + return 0; + + addr = of_get_flat_dt_prop(node, "reg", &l); + return be32_to_cpup(addr); /* return address */ +} -int __init early_init_dt_scan_chosen_serial(unsigned long node, +/* this function is looking for early uartlite console - Microblaze specific */ +int __init early_uartlite_console(void) +{ + return of_scan_flat_dt(early_init_dt_scan_serial, NULL); +} + +/* MS this is Microblaze specifig function */ +static int __init early_init_dt_scan_serial_full(unsigned long node, const char *uname, int depth, void *data) { unsigned long l; char *p; + unsigned int addr; - pr_debug("%s: depth: %d, uname: %s\n", __func__, depth, uname); - - if (depth == 1 && (strcmp(uname, "chosen") == 0 || - strcmp(uname, "chosen@0") == 0)) { - p = of_get_flat_dt_prop(node, "linux,stdout-path", &l); - if (p != NULL && l > 0) - stdout = p; /* store pointer to stdout-path */ - } - - if (stdout && strstr(stdout, uname)) { - p = of_get_flat_dt_prop(node, "compatible", &l); - pr_debug("Compatible string: %s\n", p); - - if ((strncmp(p, "xlnx,xps-uart16550", 18) == 0) || - (strncmp(p, "xlnx,axi-uart16550", 18) == 0)) { - unsigned int addr; - - *(u32 *)data = UART16550; - - addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l); - addr += *(u32 *)of_get_flat_dt_prop(node, - "reg-offset", &l); - /* clear register offset */ - return be32_to_cpu(addr) & ~3; - } - if ((strncmp(p, "xlnx,xps-uartlite", 17) == 0) || - (strncmp(p, "xlnx,opb-uartlite", 17) == 0) || - (strncmp(p, "xlnx,axi-uartlite", 17) == 0) || - (strncmp(p, "xlnx,mdm", 8) == 0)) { - unsigned int *addrp; - - *(u32 *)data = UARTLITE; - - addrp = of_get_flat_dt_prop(node, "reg", &l); - return be32_to_cpup(addrp); /* return address */ - } - } - return 0; + pr_debug("search \"chosen\", depth: %d, uname: %s\n", depth, uname); + +/* find all serial nodes */ + if (strncmp(uname, "serial", 6) != 0) + return 0; + + early_init_dt_check_for_initrd(node); + +/* find compatible node with uartlite */ + p = of_get_flat_dt_prop(node, "compatible", &l); + + if ((strncmp(p, "xlnx,xps-uart16550", 18) != 0) && + (strncmp(p, "xlnx,axi-uart16550", 18) != 0)) + return 0; + + addr = *(u32 *)of_get_flat_dt_prop(node, "reg", &l); + addr += *(u32 *)of_get_flat_dt_prop(node, "reg-offset", &l); + return be32_to_cpu(addr); /* return address */ } -/* this function is looking for early console - Microblaze specific */ -int __init of_early_console(void *version) +/* this function is looking for early uartlite console - Microblaze specific */ +int __init early_uart16550_console(void) { - return of_scan_flat_dt(early_init_dt_scan_chosen_serial, version); + return of_scan_flat_dt(early_init_dt_scan_serial_full, NULL); } #endif diff --git a/trunk/arch/microblaze/kernel/setup.c b/trunk/arch/microblaze/kernel/setup.c index 0e654a12d37e..8e2c09b7ff26 100644 --- a/trunk/arch/microblaze/kernel/setup.c +++ b/trunk/arch/microblaze/kernel/setup.c @@ -59,11 +59,6 @@ void __init setup_arch(char **cmdline_p) setup_memory(); -#ifdef CONFIG_EARLY_PRINTK - /* remap early console to virtual address */ - remap_early_printk(); -#endif - xilinx_pci_init(); #if defined(CONFIG_SELFMOD_INTC) || defined(CONFIG_SELFMOD_TIMER) diff --git a/trunk/arch/sparc/lib/atomic32.c b/trunk/arch/sparc/lib/atomic32.c index 8600eb2461b5..1a371f8ae0b0 100644 --- a/trunk/arch/sparc/lib/atomic32.c +++ b/trunk/arch/sparc/lib/atomic32.c @@ -55,7 +55,7 @@ int atomic_cmpxchg(atomic_t *v, int old, int new) } EXPORT_SYMBOL(atomic_cmpxchg); -int __atomic_add_unless(atomic_t *v, int a, int u) +int atomic_add_unless(atomic_t *v, int a, int u) { int ret; unsigned long flags; @@ -67,7 +67,7 @@ int __atomic_add_unless(atomic_t *v, int a, int u) spin_unlock_irqrestore(ATOMIC_HASH(v), flags); return ret != u; } -EXPORT_SYMBOL(__atomic_add_unless); +EXPORT_SYMBOL(atomic_add_unless); /* Atomic operations are already serializing */ void atomic_set(atomic_t *v, int i) diff --git a/trunk/drivers/infiniband/ulp/iser/iser_initiator.c b/trunk/drivers/infiniband/ulp/iser/iser_initiator.c index 5745b7fe158c..95a08a8ca8aa 100644 --- a/trunk/drivers/infiniband/ulp/iser/iser_initiator.c +++ b/trunk/drivers/infiniband/ulp/iser/iser_initiator.c @@ -271,7 +271,7 @@ int iser_send_command(struct iscsi_conn *conn, unsigned long edtl; int err; struct iser_data_buf *data_buf; - struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr; + struct iscsi_cmd *hdr = (struct iscsi_cmd *)task->hdr; struct scsi_cmnd *sc = task->sc; struct iser_tx_desc *tx_desc = &iser_task->desc; diff --git a/trunk/drivers/input/joystick/xpad.c b/trunk/drivers/input/joystick/xpad.c index d72887585a14..56abf3d0e911 100644 --- a/trunk/drivers/input/joystick/xpad.c +++ b/trunk/drivers/input/joystick/xpad.c @@ -154,13 +154,10 @@ static const struct xpad_device { { 0x0f30, 0x8888, "BigBen XBMiniPad Controller", 0, XTYPE_XBOX }, { 0x102c, 0xff0c, "Joytech Wireless Advanced Controller", 0, XTYPE_XBOX }, { 0x12ab, 0x8809, "Xbox DDR dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, - { 0x12ab, 0x0004, "Honey Bee Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, - { 0x0e6f, 0x0105, "HSM3 Xbox360 dancepad", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x1430, 0x4748, "RedOctane Guitar Hero X-plorer", 0, XTYPE_XBOX360 }, { 0x1430, 0x8888, "TX6500+ Dance Pad (first generation)", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX }, { 0x146b, 0x0601, "BigBen Interactive XBOX 360 Controller", 0, XTYPE_XBOX360 }, { 0x045e, 0x028e, "Microsoft X-Box 360 pad", 0, XTYPE_XBOX360 }, - { 0x1bad, 0x0002, "Harmonix Rock Band Guitar", 0, XTYPE_XBOX360 }, { 0x1bad, 0x0003, "Harmonix Rock Band Drumkit", MAP_DPAD_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f0d, 0x0016, "Hori Real Arcade Pro.EX", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, { 0x0f0d, 0x000d, "Hori Fighting Stick EX2", MAP_TRIGGERS_TO_BUTTONS, XTYPE_XBOX360 }, @@ -239,10 +236,9 @@ static struct usb_device_id xpad_table [] = { XPAD_XBOX360_VENDOR(0x046d), /* Logitech X-Box 360 style controllers */ XPAD_XBOX360_VENDOR(0x0738), /* Mad Catz X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x0e6f), /* 0x0e6f X-Box 360 controllers */ - XPAD_XBOX360_VENDOR(0x12ab), /* X-Box 360 dance pads */ XPAD_XBOX360_VENDOR(0x1430), /* RedOctane X-Box 360 controllers */ XPAD_XBOX360_VENDOR(0x146b), /* BigBen Interactive Controllers */ - XPAD_XBOX360_VENDOR(0x1bad), /* Harminix Rock Band Guitar and Drums */ + XPAD_XBOX360_VENDOR(0x1bad), /* Rock Band Drums */ XPAD_XBOX360_VENDOR(0x0f0d), /* Hori Controllers */ { } }; @@ -549,7 +545,7 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) struct usb_endpoint_descriptor *ep_irq_out; int error; - if (xpad->xtype == XTYPE_UNKNOWN) + if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX) return 0; xpad->odata = usb_alloc_coherent(xpad->udev, XPAD_PKT_LEN, @@ -583,13 +579,13 @@ static int xpad_init_output(struct usb_interface *intf, struct usb_xpad *xpad) static void xpad_stop_output(struct usb_xpad *xpad) { - if (xpad->xtype != XTYPE_UNKNOWN) + if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) usb_kill_urb(xpad->irq_out); } static void xpad_deinit_output(struct usb_xpad *xpad) { - if (xpad->xtype != XTYPE_UNKNOWN) { + if (xpad->xtype == XTYPE_XBOX360 || xpad->xtype == XTYPE_XBOX) { usb_free_urb(xpad->irq_out); usb_free_coherent(xpad->udev, XPAD_PKT_LEN, xpad->odata, xpad->odata_dma); @@ -636,23 +632,6 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); - case XTYPE_XBOX360W: - xpad->odata[0] = 0x00; - xpad->odata[1] = 0x01; - xpad->odata[2] = 0x0F; - xpad->odata[3] = 0xC0; - xpad->odata[4] = 0x00; - xpad->odata[5] = strong / 256; - xpad->odata[6] = weak / 256; - xpad->odata[7] = 0x00; - xpad->odata[8] = 0x00; - xpad->odata[9] = 0x00; - xpad->odata[10] = 0x00; - xpad->odata[11] = 0x00; - xpad->irq_out->transfer_buffer_length = 12; - - return usb_submit_urb(xpad->irq_out, GFP_ATOMIC); - default: dbg("%s - rumble command sent to unsupported xpad type: %d", __func__, xpad->xtype); @@ -665,7 +644,7 @@ static int xpad_play_effect(struct input_dev *dev, void *data, struct ff_effect static int xpad_init_ff(struct usb_xpad *xpad) { - if (xpad->xtype == XTYPE_UNKNOWN) + if (xpad->xtype != XTYPE_XBOX360 && xpad->xtype != XTYPE_XBOX) return 0; input_set_capability(xpad->dev, EV_FF, FF_RUMBLE); diff --git a/trunk/drivers/input/keyboard/adp5588-keys.c b/trunk/drivers/input/keyboard/adp5588-keys.c index 7b404e5443ed..af45d275f686 100644 --- a/trunk/drivers/input/keyboard/adp5588-keys.c +++ b/trunk/drivers/input/keyboard/adp5588-keys.c @@ -9,6 +9,7 @@ */ #include +#include #include #include #include diff --git a/trunk/drivers/input/keyboard/adp5589-keys.c b/trunk/drivers/input/keyboard/adp5589-keys.c index c7708263051b..631598663aab 100644 --- a/trunk/drivers/input/keyboard/adp5589-keys.c +++ b/trunk/drivers/input/keyboard/adp5589-keys.c @@ -8,6 +8,7 @@ */ #include +#include #include #include #include diff --git a/trunk/drivers/input/keyboard/atkbd.c b/trunk/drivers/input/keyboard/atkbd.c index 19cfc0cf558c..11478eb2c27d 100644 --- a/trunk/drivers/input/keyboard/atkbd.c +++ b/trunk/drivers/input/keyboard/atkbd.c @@ -1578,14 +1578,14 @@ static int __init atkbd_setup_forced_release(const struct dmi_system_id *id) atkbd_platform_fixup = atkbd_apply_forced_release_keylist; atkbd_platform_fixup_data = id->driver_data; - return 1; + return 0; } static int __init atkbd_setup_scancode_fixup(const struct dmi_system_id *id) { atkbd_platform_scancode_fixup = id->driver_data; - return 1; + return 0; } static const struct dmi_system_id atkbd_dmi_quirk_table[] __initconst = { diff --git a/trunk/drivers/input/keyboard/gpio_keys.c b/trunk/drivers/input/keyboard/gpio_keys.c index ce281d152275..6e6145b9a4c1 100644 --- a/trunk/drivers/input/keyboard/gpio_keys.c +++ b/trunk/drivers/input/keyboard/gpio_keys.c @@ -2,7 +2,6 @@ * Driver for keys on GPIO lines capable of generating interrupts. * * Copyright 2005 Phil Blundell - * Copyright 2010, 2011 David Jander * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as @@ -26,8 +25,6 @@ #include #include #include -#include -#include struct gpio_button_data { struct gpio_keys_button *button; @@ -418,7 +415,7 @@ static int __devinit gpio_keys_setup_key(struct platform_device *pdev, if (!button->can_disable) irqflags |= IRQF_SHARED; - error = request_threaded_irq(irq, NULL, gpio_keys_isr, irqflags, desc, bdata); + error = request_any_context_irq(irq, gpio_keys_isr, irqflags, desc, bdata); if (error < 0) { dev_err(dev, "Unable to claim irq %d; error %d\n", irq, error); @@ -448,120 +445,15 @@ static void gpio_keys_close(struct input_dev *input) ddata->disable(input->dev.parent); } -/* - * Handlers for alternative sources of platform_data - */ -#ifdef CONFIG_OF -/* - * Translate OpenFirmware node properties into platform_data - */ -static int gpio_keys_get_devtree_pdata(struct device *dev, - struct gpio_keys_platform_data *pdata) -{ - struct device_node *node, *pp; - int i; - struct gpio_keys_button *buttons; - const u32 *reg; - int len; - - node = dev->of_node; - if (node == NULL) - return -ENODEV; - - memset(pdata, 0, sizeof *pdata); - - pdata->rep = !!of_get_property(node, "autorepeat", &len); - - /* First count the subnodes */ - pdata->nbuttons = 0; - pp = NULL; - while ((pp = of_get_next_child(node, pp))) - pdata->nbuttons++; - - if (pdata->nbuttons == 0) - return -ENODEV; - - buttons = kzalloc(pdata->nbuttons * (sizeof *buttons), GFP_KERNEL); - if (!buttons) - return -ENODEV; - - pp = NULL; - i = 0; - while ((pp = of_get_next_child(node, pp))) { - enum of_gpio_flags flags; - - if (!of_find_property(pp, "gpios", NULL)) { - pdata->nbuttons--; - dev_warn(dev, "Found button without gpios\n"); - continue; - } - buttons[i].gpio = of_get_gpio_flags(pp, 0, &flags); - buttons[i].active_low = flags & OF_GPIO_ACTIVE_LOW; - - reg = of_get_property(pp, "linux,code", &len); - if (!reg) { - dev_err(dev, "Button without keycode: 0x%x\n", buttons[i].gpio); - goto out_fail; - } - buttons[i].code = be32_to_cpup(reg); - - buttons[i].desc = of_get_property(pp, "label", &len); - - reg = of_get_property(pp, "linux,input-type", &len); - buttons[i].type = reg ? be32_to_cpup(reg) : EV_KEY; - - buttons[i].wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL); - - reg = of_get_property(pp, "debounce-interval", &len); - buttons[i].debounce_interval = reg ? be32_to_cpup(reg) : 5; - - i++; - } - - pdata->buttons = buttons; - - return 0; - -out_fail: - kfree(buttons); - return -ENODEV; -} - -static struct of_device_id gpio_keys_of_match[] = { - { .compatible = "gpio-keys", }, - { }, -}; -MODULE_DEVICE_TABLE(of, gpio_keys_of_match); - -#else - -static int gpio_keys_get_devtree_pdata(struct device *dev, - struct gpio_keys_platform_data *altp) -{ - return -ENODEV; -} - -#define gpio_keys_of_match NULL - -#endif - static int __devinit gpio_keys_probe(struct platform_device *pdev) { struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; struct gpio_keys_drvdata *ddata; struct device *dev = &pdev->dev; - struct gpio_keys_platform_data alt_pdata; struct input_dev *input; int i, error; int wakeup = 0; - if (!pdata) { - error = gpio_keys_get_devtree_pdata(dev, &alt_pdata); - if (error) - return error; - pdata = &alt_pdata; - } - ddata = kzalloc(sizeof(struct gpio_keys_drvdata) + pdata->nbuttons * sizeof(struct gpio_button_data), GFP_KERNEL); @@ -652,15 +544,13 @@ static int __devinit gpio_keys_probe(struct platform_device *pdev) fail1: input_free_device(input); kfree(ddata); - /* If we have no platform_data, we allocated buttons dynamically. */ - if (!pdev->dev.platform_data) - kfree(pdata->buttons); return error; } static int __devexit gpio_keys_remove(struct platform_device *pdev) { + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); struct input_dev *input = ddata->input; int i; @@ -669,39 +559,31 @@ static int __devexit gpio_keys_remove(struct platform_device *pdev) device_init_wakeup(&pdev->dev, 0); - for (i = 0; i < ddata->n_buttons; i++) { - int irq = gpio_to_irq(ddata->data[i].button->gpio); + for (i = 0; i < pdata->nbuttons; i++) { + int irq = gpio_to_irq(pdata->buttons[i].gpio); free_irq(irq, &ddata->data[i]); if (ddata->data[i].timer_debounce) del_timer_sync(&ddata->data[i].timer); cancel_work_sync(&ddata->data[i].work); - gpio_free(ddata->data[i].button->gpio); + gpio_free(pdata->buttons[i].gpio); } input_unregister_device(input); - /* - * If we had no platform_data, we allocated buttons dynamically, and - * must free them here. ddata->data[0].button is the pointer to the - * beginning of the allocated array. - */ - if (!pdev->dev.platform_data) - kfree(ddata->data[0].button); - - kfree(ddata); - return 0; } -#ifdef CONFIG_PM_SLEEP + +#ifdef CONFIG_PM static int gpio_keys_suspend(struct device *dev) { - struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; int i; - if (device_may_wakeup(dev)) { - for (i = 0; i < ddata->n_buttons; i++) { - struct gpio_keys_button *button = ddata->data[i].button; + if (device_may_wakeup(&pdev->dev)) { + for (i = 0; i < pdata->nbuttons; i++) { + struct gpio_keys_button *button = &pdata->buttons[i]; if (button->wakeup) { int irq = gpio_to_irq(button->gpio); enable_irq_wake(irq); @@ -714,13 +596,15 @@ static int gpio_keys_suspend(struct device *dev) static int gpio_keys_resume(struct device *dev) { - struct gpio_keys_drvdata *ddata = dev_get_drvdata(dev); + struct platform_device *pdev = to_platform_device(dev); + struct gpio_keys_drvdata *ddata = platform_get_drvdata(pdev); + struct gpio_keys_platform_data *pdata = pdev->dev.platform_data; int i; - for (i = 0; i < ddata->n_buttons; i++) { + for (i = 0; i < pdata->nbuttons; i++) { - struct gpio_keys_button *button = ddata->data[i].button; - if (button->wakeup && device_may_wakeup(dev)) { + struct gpio_keys_button *button = &pdata->buttons[i]; + if (button->wakeup && device_may_wakeup(&pdev->dev)) { int irq = gpio_to_irq(button->gpio); disable_irq_wake(irq); } @@ -731,9 +615,12 @@ static int gpio_keys_resume(struct device *dev) return 0; } -#endif -static SIMPLE_DEV_PM_OPS(gpio_keys_pm_ops, gpio_keys_suspend, gpio_keys_resume); +static const struct dev_pm_ops gpio_keys_pm_ops = { + .suspend = gpio_keys_suspend, + .resume = gpio_keys_resume, +}; +#endif static struct platform_driver gpio_keys_device_driver = { .probe = gpio_keys_probe, @@ -741,8 +628,9 @@ static struct platform_driver gpio_keys_device_driver = { .driver = { .name = "gpio-keys", .owner = THIS_MODULE, +#ifdef CONFIG_PM .pm = &gpio_keys_pm_ops, - .of_match_table = gpio_keys_of_match, +#endif } }; @@ -756,10 +644,10 @@ static void __exit gpio_keys_exit(void) platform_driver_unregister(&gpio_keys_device_driver); } -late_initcall(gpio_keys_init); +module_init(gpio_keys_init); module_exit(gpio_keys_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("Phil Blundell "); -MODULE_DESCRIPTION("Keyboard driver for GPIOs"); +MODULE_DESCRIPTION("Keyboard driver for CPU GPIOs"); MODULE_ALIAS("platform:gpio-keys"); diff --git a/trunk/drivers/input/keyboard/lm8323.c b/trunk/drivers/input/keyboard/lm8323.c index ab0acaf7fe8f..71f744a8e686 100644 --- a/trunk/drivers/input/keyboard/lm8323.c +++ b/trunk/drivers/input/keyboard/lm8323.c @@ -146,6 +146,7 @@ struct lm8323_chip { /* device lock */ struct mutex lock; struct i2c_client *client; + struct work_struct work; struct input_dev *idev; bool kp_enabled; bool pm_suspend; @@ -161,6 +162,7 @@ struct lm8323_chip { #define client_to_lm8323(c) container_of(c, struct lm8323_chip, client) #define dev_to_lm8323(d) container_of(d, struct lm8323_chip, client->dev) +#define work_to_lm8323(w) container_of(w, struct lm8323_chip, work) #define cdev_to_pwm(c) container_of(c, struct lm8323_pwm, cdev) #define work_to_pwm(w) container_of(w, struct lm8323_pwm, work) @@ -373,9 +375,9 @@ static void pwm_done(struct lm8323_pwm *pwm) * Bottom half: handle the interrupt by posting key events, or dealing with * errors appropriately. */ -static irqreturn_t lm8323_irq(int irq, void *_lm) +static void lm8323_work(struct work_struct *work) { - struct lm8323_chip *lm = _lm; + struct lm8323_chip *lm = work_to_lm8323(work); u8 ints; int i; @@ -407,6 +409,16 @@ static irqreturn_t lm8323_irq(int irq, void *_lm) } mutex_unlock(&lm->lock); +} + +/* + * We cannot use I2C in interrupt context, so we just schedule work. + */ +static irqreturn_t lm8323_irq(int irq, void *data) +{ + struct lm8323_chip *lm = data; + + schedule_work(&lm->work); return IRQ_HANDLED; } @@ -663,6 +675,7 @@ static int __devinit lm8323_probe(struct i2c_client *client, lm->client = client; lm->idev = idev; mutex_init(&lm->lock); + INIT_WORK(&lm->work, lm8323_work); lm->size_x = pdata->size_x; lm->size_y = pdata->size_y; @@ -733,8 +746,9 @@ static int __devinit lm8323_probe(struct i2c_client *client, goto fail3; } - err = request_threaded_irq(client->irq, NULL, lm8323_irq, - IRQF_TRIGGER_LOW|IRQF_ONESHOT, "lm8323", lm); + err = request_irq(client->irq, lm8323_irq, + IRQF_TRIGGER_FALLING | IRQF_DISABLED, + "lm8323", lm); if (err) { dev_err(&client->dev, "could not get IRQ %d\n", client->irq); goto fail4; @@ -769,6 +783,7 @@ static int __devexit lm8323_remove(struct i2c_client *client) disable_irq_wake(client->irq); free_irq(client->irq, lm); + cancel_work_sync(&lm->work); input_unregister_device(lm->idev); diff --git a/trunk/drivers/input/keyboard/mpr121_touchkey.c b/trunk/drivers/input/keyboard/mpr121_touchkey.c index 1c1615d9a7f9..0a9e81194888 100644 --- a/trunk/drivers/input/keyboard/mpr121_touchkey.c +++ b/trunk/drivers/input/keyboard/mpr121_touchkey.c @@ -43,15 +43,14 @@ * enabled capacitance sensing inputs and its run/suspend mode. */ #define ELECTRODE_CONF_ADDR 0x5e -#define ELECTRODE_CONF_QUICK_CHARGE 0x80 #define AUTO_CONFIG_CTRL_ADDR 0x7b #define AUTO_CONFIG_USL_ADDR 0x7d #define AUTO_CONFIG_LSL_ADDR 0x7e #define AUTO_CONFIG_TL_ADDR 0x7f /* Threshold of touch/release trigger */ -#define TOUCH_THRESHOLD 0x08 -#define RELEASE_THRESHOLD 0x05 +#define TOUCH_THRESHOLD 0x0f +#define RELEASE_THRESHOLD 0x0a /* Masks for touch and release triggers */ #define TOUCH_STATUS_MASK 0xfff /* MPR121 has 12 keys */ @@ -128,7 +127,7 @@ static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata, struct i2c_client *client) { const struct mpr121_init_register *reg; - unsigned char usl, lsl, tl, eleconf; + unsigned char usl, lsl, tl; int i, t, vdd, ret; /* Set up touch/release threshold for ele0-ele11 */ @@ -164,15 +163,8 @@ static int __devinit mpr121_phys_init(const struct mpr121_platform_data *pdata, ret = i2c_smbus_write_byte_data(client, AUTO_CONFIG_USL_ADDR, usl); ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_LSL_ADDR, lsl); ret |= i2c_smbus_write_byte_data(client, AUTO_CONFIG_TL_ADDR, tl); - - /* - * Quick charge bit will let the capacitive charge to ready - * state quickly, or the buttons may not function after system - * boot. - */ - eleconf = mpr121->keycount | ELECTRODE_CONF_QUICK_CHARGE; ret |= i2c_smbus_write_byte_data(client, ELECTRODE_CONF_ADDR, - eleconf); + mpr121->keycount); if (ret != 0) goto err_i2c_write; diff --git a/trunk/drivers/input/keyboard/pmic8xxx-keypad.c b/trunk/drivers/input/keyboard/pmic8xxx-keypad.c index e7cc51d0fb34..6229c3e8e78b 100644 --- a/trunk/drivers/input/keyboard/pmic8xxx-keypad.c +++ b/trunk/drivers/input/keyboard/pmic8xxx-keypad.c @@ -700,9 +700,9 @@ static int __devinit pmic8xxx_kp_probe(struct platform_device *pdev) return 0; err_pmic_reg_read: - free_irq(kp->key_stuck_irq, kp); + free_irq(kp->key_stuck_irq, NULL); err_req_stuck_irq: - free_irq(kp->key_sense_irq, kp); + free_irq(kp->key_sense_irq, NULL); err_gpio_config: err_get_irq: input_free_device(kp->input); @@ -717,8 +717,8 @@ static int __devexit pmic8xxx_kp_remove(struct platform_device *pdev) struct pmic8xxx_kp *kp = platform_get_drvdata(pdev); device_init_wakeup(&pdev->dev, 0); - free_irq(kp->key_stuck_irq, kp); - free_irq(kp->key_sense_irq, kp); + free_irq(kp->key_stuck_irq, NULL); + free_irq(kp->key_sense_irq, NULL); input_unregister_device(kp->input); kfree(kp); diff --git a/trunk/drivers/input/keyboard/qt1070.c b/trunk/drivers/input/keyboard/qt1070.c index b21bf5b876bb..ca7b89196ab7 100644 --- a/trunk/drivers/input/keyboard/qt1070.c +++ b/trunk/drivers/input/keyboard/qt1070.c @@ -239,6 +239,8 @@ static int __devexit qt1070_remove(struct i2c_client *client) input_unregister_device(data->input); kfree(data); + i2c_set_clientdata(client, NULL); + return 0; } diff --git a/trunk/drivers/input/keyboard/sh_keysc.c b/trunk/drivers/input/keyboard/sh_keysc.c index 934aeb583b30..6876700a4469 100644 --- a/trunk/drivers/input/keyboard/sh_keysc.c +++ b/trunk/drivers/input/keyboard/sh_keysc.c @@ -291,7 +291,7 @@ static int __devexit sh_keysc_remove(struct platform_device *pdev) return 0; } -#ifdef CONFIG_PM_SLEEP +#if CONFIG_PM_SLEEP static int sh_keysc_suspend(struct device *dev) { struct platform_device *pdev = to_platform_device(dev); diff --git a/trunk/drivers/input/keyboard/tegra-kbc.c b/trunk/drivers/input/keyboard/tegra-kbc.c index da3828fc2c09..2b3b73ec6689 100644 --- a/trunk/drivers/input/keyboard/tegra-kbc.c +++ b/trunk/drivers/input/keyboard/tegra-kbc.c @@ -657,7 +657,7 @@ static int __devinit tegra_kbc_probe(struct platform_device *pdev) input_set_drvdata(input_dev, kbc); - input_dev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP); + input_dev->evbit[0] = BIT_MASK(EV_KEY); input_set_capability(input_dev, EV_MSC, MSC_SCAN); input_dev->keycode = kbc->keycode; diff --git a/trunk/drivers/input/keyboard/tnetv107x-keypad.c b/trunk/drivers/input/keyboard/tnetv107x-keypad.c index 1c58681de81f..c8f097a15d89 100644 --- a/trunk/drivers/input/keyboard/tnetv107x-keypad.c +++ b/trunk/drivers/input/keyboard/tnetv107x-keypad.c @@ -337,5 +337,5 @@ module_exit(keypad_exit); MODULE_AUTHOR("Cyril Chemparathy"); MODULE_DESCRIPTION("TNETV107X Keypad Driver"); -MODULE_ALIAS("platform:tnetv107x-keypad"); +MODULE_ALIAS("platform: tnetv107x-keypad"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/misc/Kconfig b/trunk/drivers/input/misc/Kconfig index c9104bb4db06..d1bf8724b58f 100644 --- a/trunk/drivers/input/misc/Kconfig +++ b/trunk/drivers/input/misc/Kconfig @@ -100,27 +100,6 @@ config INPUT_MAX8925_ONKEY To compile this driver as a module, choose M here: the module will be called max8925_onkey. -config INPUT_MMA8450 - tristate "MMA8450 - Freescale's 3-Axis, 8/12-bit Digital Accelerometer" - depends on I2C - select INPUT_POLLDEV - help - Say Y here if you want to support Freescale's MMA8450 Accelerometer - through I2C interface. - - To compile this driver as a module, choose M here: the - module will be called mma8450. - -config INPUT_MPU3050 - tristate "MPU3050 Triaxial gyroscope sensor" - depends on I2C - help - Say Y here if you want to support InvenSense MPU3050 - connected via an I2C bus. - - To compile this driver as a module, choose M here: the - module will be called mpu3050. - config INPUT_APANEL tristate "Fujitsu Lifebook Application Panel buttons" depends on X86 && I2C && LEDS_CLASS @@ -230,23 +209,6 @@ config INPUT_KEYSPAN_REMOTE To compile this driver as a module, choose M here: the module will be called keyspan_remote. -config INPUT_KXTJ9 - tristate "Kionix KXTJ9 tri-axis digital accelerometer" - depends on I2C - help - Say Y here to enable support for the Kionix KXTJ9 digital tri-axis - accelerometer. - - To compile this driver as a module, choose M here: the module will - be called kxtj9. - -config INPUT_KXTJ9_POLLED_MODE - bool "Enable polling mode support" - depends on INPUT_KXTJ9 - select INPUT_POLLDEV - help - Say Y here if you need accelerometer to work in polling mode. - config INPUT_POWERMATE tristate "Griffin PowerMate and Contour Jog support" depends on USB_ARCH_HAS_HCD diff --git a/trunk/drivers/input/misc/Makefile b/trunk/drivers/input/misc/Makefile index 299ad5edba84..4da7c3a60e04 100644 --- a/trunk/drivers/input/misc/Makefile +++ b/trunk/drivers/input/misc/Makefile @@ -25,11 +25,8 @@ obj-$(CONFIG_INPUT_DM355EVM) += dm355evm_keys.o obj-$(CONFIG_HP_SDC_RTC) += hp_sdc_rtc.o obj-$(CONFIG_INPUT_IXP4XX_BEEPER) += ixp4xx-beeper.o obj-$(CONFIG_INPUT_KEYSPAN_REMOTE) += keyspan_remote.o -obj-$(CONFIG_INPUT_KXTJ9) += kxtj9.o obj-$(CONFIG_INPUT_M68K_BEEP) += m68kspkr.o obj-$(CONFIG_INPUT_MAX8925_ONKEY) += max8925_onkey.o -obj-$(CONFIG_INPUT_MMA8450) += mma8450.o -obj-$(CONFIG_INPUT_MPU3050) += mpu3050.o obj-$(CONFIG_INPUT_PCAP) += pcap_keys.o obj-$(CONFIG_INPUT_PCF50633_PMU) += pcf50633-input.o obj-$(CONFIG_INPUT_PCF8574) += pcf8574_keypad.o @@ -49,3 +46,4 @@ obj-$(CONFIG_INPUT_WISTRON_BTNS) += wistron_btns.o obj-$(CONFIG_INPUT_WM831X_ON) += wm831x-on.o obj-$(CONFIG_INPUT_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o obj-$(CONFIG_INPUT_YEALINK) += yealink.o + diff --git a/trunk/drivers/input/misc/bfin_rotary.c b/trunk/drivers/input/misc/bfin_rotary.c index d00edc9f39d1..4f72bdd69410 100644 --- a/trunk/drivers/input/misc/bfin_rotary.c +++ b/trunk/drivers/input/misc/bfin_rotary.c @@ -6,6 +6,7 @@ */ #include +#include #include #include #include diff --git a/trunk/drivers/input/misc/kxtj9.c b/trunk/drivers/input/misc/kxtj9.c deleted file mode 100644 index c456f63b6bae..000000000000 --- a/trunk/drivers/input/misc/kxtj9.c +++ /dev/null @@ -1,671 +0,0 @@ -/* - * Copyright (C) 2011 Kionix, Inc. - * Written by Chris Hudson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA - */ - -#include -#include -#include -#include -#include -#include -#include - -#define NAME "kxtj9" -#define G_MAX 8000 -/* OUTPUT REGISTERS */ -#define XOUT_L 0x06 -#define WHO_AM_I 0x0F -/* CONTROL REGISTERS */ -#define INT_REL 0x1A -#define CTRL_REG1 0x1B -#define INT_CTRL1 0x1E -#define DATA_CTRL 0x21 -/* CONTROL REGISTER 1 BITS */ -#define PC1_OFF 0x7F -#define PC1_ON (1 << 7) -/* Data ready funtion enable bit: set during probe if using irq mode */ -#define DRDYE (1 << 5) -/* INTERRUPT CONTROL REGISTER 1 BITS */ -/* Set these during probe if using irq mode */ -#define KXTJ9_IEL (1 << 3) -#define KXTJ9_IEA (1 << 4) -#define KXTJ9_IEN (1 << 5) -/* INPUT_ABS CONSTANTS */ -#define FUZZ 3 -#define FLAT 3 -/* RESUME STATE INDICES */ -#define RES_DATA_CTRL 0 -#define RES_CTRL_REG1 1 -#define RES_INT_CTRL1 2 -#define RESUME_ENTRIES 3 - -/* - * The following table lists the maximum appropriate poll interval for each - * available output data rate. - */ -static const struct { - unsigned int cutoff; - u8 mask; -} kxtj9_odr_table[] = { - { 3, ODR800F }, - { 5, ODR400F }, - { 10, ODR200F }, - { 20, ODR100F }, - { 40, ODR50F }, - { 80, ODR25F }, - { 0, ODR12_5F}, -}; - -struct kxtj9_data { - struct i2c_client *client; - struct kxtj9_platform_data pdata; - struct input_dev *input_dev; -#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE - struct input_polled_dev *poll_dev; -#endif - unsigned int last_poll_interval; - u8 shift; - u8 ctrl_reg1; - u8 data_ctrl; - u8 int_ctrl; -}; - -static int kxtj9_i2c_read(struct kxtj9_data *tj9, u8 addr, u8 *data, int len) -{ - struct i2c_msg msgs[] = { - { - .addr = tj9->client->addr, - .flags = tj9->client->flags, - .len = 1, - .buf = &addr, - }, - { - .addr = tj9->client->addr, - .flags = tj9->client->flags | I2C_M_RD, - .len = len, - .buf = data, - }, - }; - - return i2c_transfer(tj9->client->adapter, msgs, 2); -} - -static void kxtj9_report_acceleration_data(struct kxtj9_data *tj9) -{ - s16 acc_data[3]; /* Data bytes from hardware xL, xH, yL, yH, zL, zH */ - s16 x, y, z; - int err; - - err = kxtj9_i2c_read(tj9, XOUT_L, (u8 *)acc_data, 6); - if (err < 0) - dev_err(&tj9->client->dev, "accelerometer data read failed\n"); - - x = le16_to_cpu(acc_data[tj9->pdata.axis_map_x]) >> tj9->shift; - y = le16_to_cpu(acc_data[tj9->pdata.axis_map_y]) >> tj9->shift; - z = le16_to_cpu(acc_data[tj9->pdata.axis_map_z]) >> tj9->shift; - - input_report_abs(tj9->input_dev, ABS_X, tj9->pdata.negate_x ? -x : x); - input_report_abs(tj9->input_dev, ABS_Y, tj9->pdata.negate_y ? -y : y); - input_report_abs(tj9->input_dev, ABS_Z, tj9->pdata.negate_z ? -z : z); - input_sync(tj9->input_dev); -} - -static irqreturn_t kxtj9_isr(int irq, void *dev) -{ - struct kxtj9_data *tj9 = dev; - int err; - - /* data ready is the only possible interrupt type */ - kxtj9_report_acceleration_data(tj9); - - err = i2c_smbus_read_byte_data(tj9->client, INT_REL); - if (err < 0) - dev_err(&tj9->client->dev, - "error clearing interrupt status: %d\n", err); - - return IRQ_HANDLED; -} - -static int kxtj9_update_g_range(struct kxtj9_data *tj9, u8 new_g_range) -{ - switch (new_g_range) { - case KXTJ9_G_2G: - tj9->shift = 4; - break; - case KXTJ9_G_4G: - tj9->shift = 3; - break; - case KXTJ9_G_8G: - tj9->shift = 2; - break; - default: - return -EINVAL; - } - - tj9->ctrl_reg1 &= 0xe7; - tj9->ctrl_reg1 |= new_g_range; - - return 0; -} - -static int kxtj9_update_odr(struct kxtj9_data *tj9, unsigned int poll_interval) -{ - int err; - int i; - - /* Use the lowest ODR that can support the requested poll interval */ - for (i = 0; i < ARRAY_SIZE(kxtj9_odr_table); i++) { - tj9->data_ctrl = kxtj9_odr_table[i].mask; - if (poll_interval < kxtj9_odr_table[i].cutoff) - break; - } - - err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0); - if (err < 0) - return err; - - err = i2c_smbus_write_byte_data(tj9->client, DATA_CTRL, tj9->data_ctrl); - if (err < 0) - return err; - - err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1); - if (err < 0) - return err; - - return 0; -} - -static int kxtj9_device_power_on(struct kxtj9_data *tj9) -{ - if (tj9->pdata.power_on) - return tj9->pdata.power_on(); - - return 0; -} - -static void kxtj9_device_power_off(struct kxtj9_data *tj9) -{ - int err; - - tj9->ctrl_reg1 &= PC1_OFF; - err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1); - if (err < 0) - dev_err(&tj9->client->dev, "soft power off failed\n"); - - if (tj9->pdata.power_off) - tj9->pdata.power_off(); -} - -static int kxtj9_enable(struct kxtj9_data *tj9) -{ - int err; - - err = kxtj9_device_power_on(tj9); - if (err < 0) - return err; - - /* ensure that PC1 is cleared before updating control registers */ - err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, 0); - if (err < 0) - return err; - - /* only write INT_CTRL_REG1 if in irq mode */ - if (tj9->client->irq) { - err = i2c_smbus_write_byte_data(tj9->client, - INT_CTRL1, tj9->int_ctrl); - if (err < 0) - return err; - } - - err = kxtj9_update_g_range(tj9, tj9->pdata.g_range); - if (err < 0) - return err; - - /* turn on outputs */ - tj9->ctrl_reg1 |= PC1_ON; - err = i2c_smbus_write_byte_data(tj9->client, CTRL_REG1, tj9->ctrl_reg1); - if (err < 0) - return err; - - err = kxtj9_update_odr(tj9, tj9->last_poll_interval); - if (err < 0) - return err; - - /* clear initial interrupt if in irq mode */ - if (tj9->client->irq) { - err = i2c_smbus_read_byte_data(tj9->client, INT_REL); - if (err < 0) { - dev_err(&tj9->client->dev, - "error clearing interrupt: %d\n", err); - goto fail; - } - } - - return 0; - -fail: - kxtj9_device_power_off(tj9); - return err; -} - -static void kxtj9_disable(struct kxtj9_data *tj9) -{ - kxtj9_device_power_off(tj9); -} - -static int kxtj9_input_open(struct input_dev *input) -{ - struct kxtj9_data *tj9 = input_get_drvdata(input); - - return kxtj9_enable(tj9); -} - -static void kxtj9_input_close(struct input_dev *dev) -{ - struct kxtj9_data *tj9 = input_get_drvdata(dev); - - kxtj9_disable(tj9); -} - -static void __devinit kxtj9_init_input_device(struct kxtj9_data *tj9, - struct input_dev *input_dev) -{ - __set_bit(EV_ABS, input_dev->evbit); - input_set_abs_params(input_dev, ABS_X, -G_MAX, G_MAX, FUZZ, FLAT); - input_set_abs_params(input_dev, ABS_Y, -G_MAX, G_MAX, FUZZ, FLAT); - input_set_abs_params(input_dev, ABS_Z, -G_MAX, G_MAX, FUZZ, FLAT); - - input_dev->name = "kxtj9_accel"; - input_dev->id.bustype = BUS_I2C; - input_dev->dev.parent = &tj9->client->dev; -} - -static int __devinit kxtj9_setup_input_device(struct kxtj9_data *tj9) -{ - struct input_dev *input_dev; - int err; - - input_dev = input_allocate_device(); - if (!input_dev) { - dev_err(&tj9->client->dev, "input device allocate failed\n"); - return -ENOMEM; - } - - tj9->input_dev = input_dev; - - input_dev->open = kxtj9_input_open; - input_dev->close = kxtj9_input_close; - input_set_drvdata(input_dev, tj9); - - kxtj9_init_input_device(tj9, input_dev); - - err = input_register_device(tj9->input_dev); - if (err) { - dev_err(&tj9->client->dev, - "unable to register input polled device %s: %d\n", - tj9->input_dev->name, err); - input_free_device(tj9->input_dev); - return err; - } - - return 0; -} - -/* - * When IRQ mode is selected, we need to provide an interface to allow the user - * to change the output data rate of the part. For consistency, we are using - * the set_poll method, which accepts a poll interval in milliseconds, and then - * calls update_odr() while passing this value as an argument. In IRQ mode, the - * data outputs will not be read AT the requested poll interval, rather, the - * lowest ODR that can support the requested interval. The client application - * will be responsible for retrieving data from the input node at the desired - * interval. - */ - -/* Returns currently selected poll interval (in ms) */ -static ssize_t kxtj9_get_poll(struct device *dev, - struct device_attribute *attr, char *buf) -{ - struct i2c_client *client = to_i2c_client(dev); - struct kxtj9_data *tj9 = i2c_get_clientdata(client); - - return sprintf(buf, "%d\n", tj9->last_poll_interval); -} - -/* Allow users to select a new poll interval (in ms) */ -static ssize_t kxtj9_set_poll(struct device *dev, struct device_attribute *attr, - const char *buf, size_t count) -{ - struct i2c_client *client = to_i2c_client(dev); - struct kxtj9_data *tj9 = i2c_get_clientdata(client); - struct input_dev *input_dev = tj9->input_dev; - unsigned int interval; - int error; - - error = kstrtouint(buf, 10, &interval); - if (error < 0) - return error; - - /* Lock the device to prevent races with open/close (and itself) */ - mutex_lock(&input_dev->mutex); - - disable_irq(client->irq); - - /* - * Set current interval to the greater of the minimum interval or - * the requested interval - */ - tj9->last_poll_interval = max(interval, tj9->pdata.min_interval); - - kxtj9_update_odr(tj9, tj9->last_poll_interval); - - enable_irq(client->irq); - mutex_unlock(&input_dev->mutex); - - return count; -} - -static DEVICE_ATTR(poll, S_IRUGO|S_IWUSR, kxtj9_get_poll, kxtj9_set_poll); - -static struct attribute *kxtj9_attributes[] = { - &dev_attr_poll.attr, - NULL -}; - -static struct attribute_group kxtj9_attribute_group = { - .attrs = kxtj9_attributes -}; - - -#ifdef CONFIG_INPUT_KXTJ9_POLLED_MODE -static void kxtj9_poll(struct input_polled_dev *dev) -{ - struct kxtj9_data *tj9 = dev->private; - unsigned int poll_interval = dev->poll_interval; - - kxtj9_report_acceleration_data(tj9); - - if (poll_interval != tj9->last_poll_interval) { - kxtj9_update_odr(tj9, poll_interval); - tj9->last_poll_interval = poll_interval; - } -} - -static void kxtj9_polled_input_open(struct input_polled_dev *dev) -{ - struct kxtj9_data *tj9 = dev->private; - - kxtj9_enable(tj9); -} - -static void kxtj9_polled_input_close(struct input_polled_dev *dev) -{ - struct kxtj9_data *tj9 = dev->private; - - kxtj9_disable(tj9); -} - -static int __devinit kxtj9_setup_polled_device(struct kxtj9_data *tj9) -{ - int err; - struct input_polled_dev *poll_dev; - poll_dev = input_allocate_polled_device(); - - if (!poll_dev) { - dev_err(&tj9->client->dev, - "Failed to allocate polled device\n"); - return -ENOMEM; - } - - tj9->poll_dev = poll_dev; - tj9->input_dev = poll_dev->input; - - poll_dev->private = tj9; - poll_dev->poll = kxtj9_poll; - poll_dev->open = kxtj9_polled_input_open; - poll_dev->close = kxtj9_polled_input_close; - - kxtj9_init_input_device(tj9, poll_dev->input); - - err = input_register_polled_device(poll_dev); - if (err) { - dev_err(&tj9->client->dev, - "Unable to register polled device, err=%d\n", err); - input_free_polled_device(poll_dev); - return err; - } - - return 0; -} - -static void __devexit kxtj9_teardown_polled_device(struct kxtj9_data *tj9) -{ - input_unregister_polled_device(tj9->poll_dev); - input_free_polled_device(tj9->poll_dev); -} - -#else - -static inline int kxtj9_setup_polled_device(struct kxtj9_data *tj9) -{ - return -ENOSYS; -} - -static inline void kxtj9_teardown_polled_device(struct kxtj9_data *tj9) -{ -} - -#endif - -static int __devinit kxtj9_verify(struct kxtj9_data *tj9) -{ - int retval; - - retval = kxtj9_device_power_on(tj9); - if (retval < 0) - return retval; - - retval = i2c_smbus_read_byte_data(tj9->client, WHO_AM_I); - if (retval < 0) { - dev_err(&tj9->client->dev, "read err int source\n"); - goto out; - } - - retval = retval != 0x06 ? -EIO : 0; - -out: - kxtj9_device_power_off(tj9); - return retval; -} - -static int __devinit kxtj9_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - const struct kxtj9_platform_data *pdata = client->dev.platform_data; - struct kxtj9_data *tj9; - int err; - - if (!i2c_check_functionality(client->adapter, - I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE_DATA)) { - dev_err(&client->dev, "client is not i2c capable\n"); - return -ENXIO; - } - - if (!pdata) { - dev_err(&client->dev, "platform data is NULL; exiting\n"); - return -EINVAL; - } - - tj9 = kzalloc(sizeof(*tj9), GFP_KERNEL); - if (!tj9) { - dev_err(&client->dev, - "failed to allocate memory for module data\n"); - return -ENOMEM; - } - - tj9->client = client; - tj9->pdata = *pdata; - - if (pdata->init) { - err = pdata->init(); - if (err < 0) - goto err_free_mem; - } - - err = kxtj9_verify(tj9); - if (err < 0) { - dev_err(&client->dev, "device not recognized\n"); - goto err_pdata_exit; - } - - i2c_set_clientdata(client, tj9); - - tj9->ctrl_reg1 = tj9->pdata.res_12bit | tj9->pdata.g_range; - tj9->data_ctrl = tj9->pdata.data_odr_init; - - if (client->irq) { - /* If in irq mode, populate INT_CTRL_REG1 and enable DRDY. */ - tj9->int_ctrl |= KXTJ9_IEN | KXTJ9_IEA | KXTJ9_IEL; - tj9->ctrl_reg1 |= DRDYE; - - err = kxtj9_setup_input_device(tj9); - if (err) - goto err_pdata_exit; - - err = request_threaded_irq(client->irq, NULL, kxtj9_isr, - IRQF_TRIGGER_RISING | IRQF_ONESHOT, - "kxtj9-irq", tj9); - if (err) { - dev_err(&client->dev, "request irq failed: %d\n", err); - goto err_destroy_input; - } - - err = sysfs_create_group(&client->dev.kobj, &kxtj9_attribute_group); - if (err) { - dev_err(&client->dev, "sysfs create failed: %d\n", err); - goto err_free_irq; - } - - } else { - err = kxtj9_setup_polled_device(tj9); - if (err) - goto err_pdata_exit; - } - - return 0; - -err_free_irq: - free_irq(client->irq, tj9); -err_destroy_input: - input_unregister_device(tj9->input_dev); -err_pdata_exit: - if (tj9->pdata.exit) - tj9->pdata.exit(); -err_free_mem: - kfree(tj9); - return err; -} - -static int __devexit kxtj9_remove(struct i2c_client *client) -{ - struct kxtj9_data *tj9 = i2c_get_clientdata(client); - - if (client->irq) { - sysfs_remove_group(&client->dev.kobj, &kxtj9_attribute_group); - free_irq(client->irq, tj9); - input_unregister_device(tj9->input_dev); - } else { - kxtj9_teardown_polled_device(tj9); - } - - if (tj9->pdata.exit) - tj9->pdata.exit(); - - kfree(tj9); - - return 0; -} - -#ifdef CONFIG_PM_SLEEP -static int kxtj9_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct kxtj9_data *tj9 = i2c_get_clientdata(client); - struct input_dev *input_dev = tj9->input_dev; - - mutex_lock(&input_dev->mutex); - - if (input_dev->users) - kxtj9_disable(tj9); - - mutex_unlock(&input_dev->mutex); - return 0; -} - -static int kxtj9_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - struct kxtj9_data *tj9 = i2c_get_clientdata(client); - struct input_dev *input_dev = tj9->input_dev; - int retval = 0; - - mutex_lock(&input_dev->mutex); - - if (input_dev->users) - kxtj9_enable(tj9); - - mutex_unlock(&input_dev->mutex); - return retval; -} -#endif - -static SIMPLE_DEV_PM_OPS(kxtj9_pm_ops, kxtj9_suspend, kxtj9_resume); - -static const struct i2c_device_id kxtj9_id[] = { - { NAME, 0 }, - { }, -}; - -MODULE_DEVICE_TABLE(i2c, kxtj9_id); - -static struct i2c_driver kxtj9_driver = { - .driver = { - .name = NAME, - .owner = THIS_MODULE, - .pm = &kxtj9_pm_ops, - }, - .probe = kxtj9_probe, - .remove = __devexit_p(kxtj9_remove), - .id_table = kxtj9_id, -}; - -static int __init kxtj9_init(void) -{ - return i2c_add_driver(&kxtj9_driver); -} -module_init(kxtj9_init); - -static void __exit kxtj9_exit(void) -{ - i2c_del_driver(&kxtj9_driver); -} -module_exit(kxtj9_exit); - -MODULE_DESCRIPTION("KXTJ9 accelerometer driver"); -MODULE_AUTHOR("Chris Hudson "); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/misc/mma8450.c b/trunk/drivers/input/misc/mma8450.c deleted file mode 100644 index 20f8f9284f02..000000000000 --- a/trunk/drivers/input/misc/mma8450.c +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Driver for Freescale's 3-Axis Accelerometer MMA8450 - * - * Copyright (C) 2011 Freescale Semiconductor, Inc. All Rights Reserved. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. - */ - -#include -#include -#include -#include -#include -#include - -#define MMA8450_DRV_NAME "mma8450" - -#define MODE_CHANGE_DELAY_MS 100 -#define POLL_INTERVAL 100 -#define POLL_INTERVAL_MAX 500 - -/* register definitions */ -#define MMA8450_STATUS 0x00 -#define MMA8450_STATUS_ZXYDR 0x08 - -#define MMA8450_OUT_X8 0x01 -#define MMA8450_OUT_Y8 0x02 -#define MMA8450_OUT_Z8 0x03 - -#define MMA8450_OUT_X_LSB 0x05 -#define MMA8450_OUT_X_MSB 0x06 -#define MMA8450_OUT_Y_LSB 0x07 -#define MMA8450_OUT_Y_MSB 0x08 -#define MMA8450_OUT_Z_LSB 0x09 -#define MMA8450_OUT_Z_MSB 0x0a - -#define MMA8450_XYZ_DATA_CFG 0x16 - -#define MMA8450_CTRL_REG1 0x38 -#define MMA8450_CTRL_REG2 0x39 - -/* mma8450 status */ -struct mma8450 { - struct i2c_client *client; - struct input_polled_dev *idev; -}; - -static int mma8450_read(struct mma8450 *m, unsigned off) -{ - struct i2c_client *c = m->client; - int ret; - - ret = i2c_smbus_read_byte_data(c, off); - if (ret < 0) - dev_err(&c->dev, - "failed to read register 0x%02x, error %d\n", - off, ret); - - return ret; -} - -static int mma8450_write(struct mma8450 *m, unsigned off, u8 v) -{ - struct i2c_client *c = m->client; - int error; - - error = i2c_smbus_write_byte_data(c, off, v); - if (error < 0) { - dev_err(&c->dev, - "failed to write to register 0x%02x, error %d\n", - off, error); - return error; - } - - return 0; -} - -static int mma8450_read_xyz(struct mma8450 *m, int *x, int *y, int *z) -{ - struct i2c_client *c = m->client; - u8 buff[6]; - int err; - - err = i2c_smbus_read_i2c_block_data(c, MMA8450_OUT_X_LSB, 6, buff); - if (err < 0) { - dev_err(&c->dev, - "failed to read block data at 0x%02x, error %d\n", - MMA8450_OUT_X_LSB, err); - return err; - } - - *x = ((buff[1] << 4) & 0xff0) | (buff[0] & 0xf); - *y = ((buff[3] << 4) & 0xff0) | (buff[2] & 0xf); - *z = ((buff[5] << 4) & 0xff0) | (buff[4] & 0xf); - - return 0; -} - -static void mma8450_poll(struct input_polled_dev *dev) -{ - struct mma8450 *m = dev->private; - int x, y, z; - int ret; - int err; - - ret = mma8450_read(m, MMA8450_STATUS); - if (ret < 0) - return; - - if (!(ret & MMA8450_STATUS_ZXYDR)) - return; - - err = mma8450_read_xyz(m, &x, &y, &z); - if (err) - return; - - input_report_abs(dev->input, ABS_X, x); - input_report_abs(dev->input, ABS_Y, y); - input_report_abs(dev->input, ABS_Z, z); - input_sync(dev->input); -} - -/* Initialize the MMA8450 chip */ -static void mma8450_open(struct input_polled_dev *dev) -{ - struct mma8450 *m = dev->private; - int err; - - /* enable all events from X/Y/Z, no FIFO */ - err = mma8450_write(m, MMA8450_XYZ_DATA_CFG, 0x07); - if (err) - return; - - /* - * Sleep mode poll rate - 50Hz - * System output data rate - 400Hz - * Full scale selection - Active, +/- 2G - */ - err = mma8450_write(m, MMA8450_CTRL_REG1, 0x01); - if (err < 0) - return; - - msleep(MODE_CHANGE_DELAY_MS); -} - -static void mma8450_close(struct input_polled_dev *dev) -{ - struct mma8450 *m = dev->private; - - mma8450_write(m, MMA8450_CTRL_REG1, 0x00); - mma8450_write(m, MMA8450_CTRL_REG2, 0x01); -} - -/* - * I2C init/probing/exit functions - */ -static int __devinit mma8450_probe(struct i2c_client *c, - const struct i2c_device_id *id) -{ - struct input_polled_dev *idev; - struct mma8450 *m; - int err; - - m = kzalloc(sizeof(struct mma8450), GFP_KERNEL); - idev = input_allocate_polled_device(); - if (!m || !idev) { - err = -ENOMEM; - goto err_free_mem; - } - - m->client = c; - m->idev = idev; - - idev->private = m; - idev->input->name = MMA8450_DRV_NAME; - idev->input->id.bustype = BUS_I2C; - idev->poll = mma8450_poll; - idev->poll_interval = POLL_INTERVAL; - idev->poll_interval_max = POLL_INTERVAL_MAX; - idev->open = mma8450_open; - idev->close = mma8450_close; - - __set_bit(EV_ABS, idev->input->evbit); - input_set_abs_params(idev->input, ABS_X, -2048, 2047, 32, 32); - input_set_abs_params(idev->input, ABS_Y, -2048, 2047, 32, 32); - input_set_abs_params(idev->input, ABS_Z, -2048, 2047, 32, 32); - - err = input_register_polled_device(idev); - if (err) { - dev_err(&c->dev, "failed to register polled input device\n"); - goto err_free_mem; - } - - return 0; - -err_free_mem: - input_free_polled_device(idev); - kfree(m); - return err; -} - -static int __devexit mma8450_remove(struct i2c_client *c) -{ - struct mma8450 *m = i2c_get_clientdata(c); - struct input_polled_dev *idev = m->idev; - - input_unregister_polled_device(idev); - input_free_polled_device(idev); - kfree(m); - - return 0; -} - -static const struct i2c_device_id mma8450_id[] = { - { MMA8450_DRV_NAME, 0 }, - { }, -}; -MODULE_DEVICE_TABLE(i2c, mma8450_id); - -static struct i2c_driver mma8450_driver = { - .driver = { - .name = MMA8450_DRV_NAME, - .owner = THIS_MODULE, - }, - .probe = mma8450_probe, - .remove = __devexit_p(mma8450_remove), - .id_table = mma8450_id, -}; - -static int __init mma8450_init(void) -{ - return i2c_add_driver(&mma8450_driver); -} -module_init(mma8450_init); - -static void __exit mma8450_exit(void) -{ - i2c_del_driver(&mma8450_driver); -} -module_exit(mma8450_exit); - -MODULE_AUTHOR("Freescale Semiconductor, Inc."); -MODULE_DESCRIPTION("MMA8450 3-Axis Accelerometer Driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/misc/mpu3050.c b/trunk/drivers/input/misc/mpu3050.c deleted file mode 100644 index b95fac15b2ea..000000000000 --- a/trunk/drivers/input/misc/mpu3050.c +++ /dev/null @@ -1,376 +0,0 @@ -/* - * MPU3050 Tri-axis gyroscope driver - * - * Copyright (C) 2011 Wistron Co.Ltd - * Joseph Lai - * - * Trimmed down by Alan Cox to produce this version - * - * This is a 'lite' version of the driver, while we consider the right way - * to present the other features to user space. In particular it requires the - * device has an IRQ, and it only provides an input interface, so is not much - * use for device orientation. A fuller version is available from the Meego - * tree. - * - * This program is based on bma023.c. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; version 2 of the License. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. - * - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define MPU3050_CHIP_ID_REG 0x00 -#define MPU3050_CHIP_ID 0x69 -#define MPU3050_XOUT_H 0x1D -#define MPU3050_PWR_MGM 0x3E -#define MPU3050_PWR_MGM_POS 6 -#define MPU3050_PWR_MGM_MASK 0x40 - -#define MPU3050_AUTO_DELAY 1000 - -#define MPU3050_MIN_VALUE -32768 -#define MPU3050_MAX_VALUE 32767 - -struct axis_data { - s16 x; - s16 y; - s16 z; -}; - -struct mpu3050_sensor { - struct i2c_client *client; - struct device *dev; - struct input_dev *idev; -}; - -/** - * mpu3050_xyz_read_reg - read the axes values - * @buffer: provide register addr and get register - * @length: length of register - * - * Reads the register values in one transaction or returns a negative - * error code on failure. - */ -static int mpu3050_xyz_read_reg(struct i2c_client *client, - u8 *buffer, int length) -{ - /* - * Annoying we can't make this const because the i2c layer doesn't - * declare input buffers const. - */ - char cmd = MPU3050_XOUT_H; - struct i2c_msg msg[] = { - { - .addr = client->addr, - .flags = 0, - .len = 1, - .buf = &cmd, - }, - { - .addr = client->addr, - .flags = I2C_M_RD, - .len = length, - .buf = buffer, - }, - }; - - return i2c_transfer(client->adapter, msg, 2); -} - -/** - * mpu3050_read_xyz - get co-ordinates from device - * @client: i2c address of sensor - * @coords: co-ordinates to update - * - * Return the converted X Y and Z co-ordinates from the sensor device - */ -static void mpu3050_read_xyz(struct i2c_client *client, - struct axis_data *coords) -{ - u16 buffer[3]; - - mpu3050_xyz_read_reg(client, (u8 *)buffer, 6); - coords->x = be16_to_cpu(buffer[0]); - coords->y = be16_to_cpu(buffer[1]); - coords->z = be16_to_cpu(buffer[2]); - dev_dbg(&client->dev, "%s: x %d, y %d, z %d\n", __func__, - coords->x, coords->y, coords->z); -} - -/** - * mpu3050_set_power_mode - set the power mode - * @client: i2c client for the sensor - * @val: value to switch on/off of power, 1: normal power, 0: low power - * - * Put device to normal-power mode or low-power mode. - */ -static void mpu3050_set_power_mode(struct i2c_client *client, u8 val) -{ - u8 value; - - value = i2c_smbus_read_byte_data(client, MPU3050_PWR_MGM); - value = (value & ~MPU3050_PWR_MGM_MASK) | - (((val << MPU3050_PWR_MGM_POS) & MPU3050_PWR_MGM_MASK) ^ - MPU3050_PWR_MGM_MASK); - i2c_smbus_write_byte_data(client, MPU3050_PWR_MGM, value); -} - -/** - * mpu3050_input_open - called on input event open - * @input: input dev of opened device - * - * The input layer calls this function when input event is opened. The - * function will push the device to resume. Then, the device is ready - * to provide data. - */ -static int mpu3050_input_open(struct input_dev *input) -{ - struct mpu3050_sensor *sensor = input_get_drvdata(input); - - pm_runtime_get(sensor->dev); - - return 0; -} - -/** - * mpu3050_input_close - called on input event close - * @input: input dev of closed device - * - * The input layer calls this function when input event is closed. The - * function will push the device to suspend. - */ -static void mpu3050_input_close(struct input_dev *input) -{ - struct mpu3050_sensor *sensor = input_get_drvdata(input); - - pm_runtime_put(sensor->dev); -} - -/** - * mpu3050_interrupt_thread - handle an IRQ - * @irq: interrupt numner - * @data: the sensor - * - * Called by the kernel single threaded after an interrupt occurs. Read - * the sensor data and generate an input event for it. - */ -static irqreturn_t mpu3050_interrupt_thread(int irq, void *data) -{ - struct mpu3050_sensor *sensor = data; - struct axis_data axis; - - mpu3050_read_xyz(sensor->client, &axis); - - input_report_abs(sensor->idev, ABS_X, axis.x); - input_report_abs(sensor->idev, ABS_Y, axis.y); - input_report_abs(sensor->idev, ABS_Z, axis.z); - input_sync(sensor->idev); - - return IRQ_HANDLED; -} - -/** - * mpu3050_probe - device detection callback - * @client: i2c client of found device - * @id: id match information - * - * The I2C layer calls us when it believes a sensor is present at this - * address. Probe to see if this is correct and to validate the device. - * - * If present install the relevant sysfs interfaces and input device. - */ -static int __devinit mpu3050_probe(struct i2c_client *client, - const struct i2c_device_id *id) -{ - struct mpu3050_sensor *sensor; - struct input_dev *idev; - int ret; - int error; - - sensor = kzalloc(sizeof(struct mpu3050_sensor), GFP_KERNEL); - idev = input_allocate_device(); - if (!sensor || !idev) { - dev_err(&client->dev, "failed to allocate driver data\n"); - error = -ENOMEM; - goto err_free_mem; - } - - sensor->client = client; - sensor->dev = &client->dev; - sensor->idev = idev; - - mpu3050_set_power_mode(client, 1); - msleep(10); - - ret = i2c_smbus_read_byte_data(client, MPU3050_CHIP_ID_REG); - if (ret < 0) { - dev_err(&client->dev, "failed to detect device\n"); - error = -ENXIO; - goto err_free_mem; - } - - if (ret != MPU3050_CHIP_ID) { - dev_err(&client->dev, "unsupported chip id\n"); - error = -ENXIO; - goto err_free_mem; - } - - idev->name = "MPU3050"; - idev->id.bustype = BUS_I2C; - idev->dev.parent = &client->dev; - - idev->open = mpu3050_input_open; - idev->close = mpu3050_input_close; - - __set_bit(EV_ABS, idev->evbit); - input_set_abs_params(idev, ABS_X, - MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0); - input_set_abs_params(idev, ABS_Y, - MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0); - input_set_abs_params(idev, ABS_Z, - MPU3050_MIN_VALUE, MPU3050_MAX_VALUE, 0, 0); - - input_set_drvdata(idev, sensor); - - pm_runtime_set_active(&client->dev); - - error = request_threaded_irq(client->irq, - NULL, mpu3050_interrupt_thread, - IRQF_TRIGGER_RISING, - "mpu_int", sensor); - if (error) { - dev_err(&client->dev, - "can't get IRQ %d, error %d\n", client->irq, error); - goto err_pm_set_suspended; - } - - error = input_register_device(idev); - if (error) { - dev_err(&client->dev, "failed to register input device\n"); - goto err_free_irq; - } - - pm_runtime_enable(&client->dev); - pm_runtime_set_autosuspend_delay(&client->dev, MPU3050_AUTO_DELAY); - - return 0; - -err_free_irq: - free_irq(client->irq, sensor); -err_pm_set_suspended: - pm_runtime_set_suspended(&client->dev); -err_free_mem: - input_unregister_device(idev); - kfree(sensor); - return error; -} - -/** - * mpu3050_remove - remove a sensor - * @client: i2c client of sensor being removed - * - * Our sensor is going away, clean up the resources. - */ -static int __devexit mpu3050_remove(struct i2c_client *client) -{ - struct mpu3050_sensor *sensor = i2c_get_clientdata(client); - - pm_runtime_disable(&client->dev); - pm_runtime_set_suspended(&client->dev); - - free_irq(client->irq, sensor); - input_unregister_device(sensor->idev); - kfree(sensor); - - return 0; -} - -#ifdef CONFIG_PM -/** - * mpu3050_suspend - called on device suspend - * @dev: device being suspended - * - * Put the device into sleep mode before we suspend the machine. - */ -static int mpu3050_suspend(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - mpu3050_set_power_mode(client, 0); - - return 0; -} - -/** - * mpu3050_resume - called on device resume - * @dev: device being resumed - * - * Put the device into powered mode on resume. - */ -static int mpu3050_resume(struct device *dev) -{ - struct i2c_client *client = to_i2c_client(dev); - - mpu3050_set_power_mode(client, 1); - msleep(100); /* wait for gyro chip resume */ - - return 0; -} -#endif - -static UNIVERSAL_DEV_PM_OPS(mpu3050_pm, mpu3050_suspend, mpu3050_resume, NULL); - -static const struct i2c_device_id mpu3050_ids[] = { - { "mpu3050", 0 }, - { } -}; -MODULE_DEVICE_TABLE(i2c, mpu3050_ids); - -static struct i2c_driver mpu3050_i2c_driver = { - .driver = { - .name = "mpu3050", - .owner = THIS_MODULE, - .pm = &mpu3050_pm, - }, - .probe = mpu3050_probe, - .remove = __devexit_p(mpu3050_remove), - .id_table = mpu3050_ids, -}; - -static int __init mpu3050_init(void) -{ - return i2c_add_driver(&mpu3050_i2c_driver); -} -module_init(mpu3050_init); - -static void __exit mpu3050_exit(void) -{ - i2c_del_driver(&mpu3050_i2c_driver); -} -module_exit(mpu3050_exit); - -MODULE_AUTHOR("Wistron Corp."); -MODULE_DESCRIPTION("MPU3050 Tri-axis gyroscope driver"); -MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/misc/xen-kbdfront.c b/trunk/drivers/input/misc/xen-kbdfront.c index ad2e51c04db8..62bae99424e6 100644 --- a/trunk/drivers/input/misc/xen-kbdfront.c +++ b/trunk/drivers/input/misc/xen-kbdfront.c @@ -373,7 +373,7 @@ static struct xenbus_driver xenkbd_driver = { static int __init xenkbd_init(void) { - if (!xen_domain()) + if (!xen_pv_domain()) return -ENODEV; /* Nothing to do if running in dom0. */ diff --git a/trunk/drivers/input/mouse/gpio_mouse.c b/trunk/drivers/input/mouse/gpio_mouse.c index 58902fbb9896..7b6ce178f1b6 100644 --- a/trunk/drivers/input/mouse/gpio_mouse.c +++ b/trunk/drivers/input/mouse/gpio_mouse.c @@ -191,7 +191,7 @@ static void __exit gpio_mouse_exit(void) } module_exit(gpio_mouse_exit); -MODULE_AUTHOR("Hans-Christian Egtvedt "); +MODULE_AUTHOR("Hans-Christian Egtvedt "); MODULE_DESCRIPTION("GPIO mouse driver"); MODULE_LICENSE("GPL"); MODULE_ALIAS("platform:gpio_mouse"); /* work with hotplug and coldplug */ diff --git a/trunk/drivers/input/mouse/lifebook.c b/trunk/drivers/input/mouse/lifebook.c index 83bcaba96b89..c31ad11df6bb 100644 --- a/trunk/drivers/input/mouse/lifebook.c +++ b/trunk/drivers/input/mouse/lifebook.c @@ -33,7 +33,7 @@ static const char *desired_serio_phys; static int lifebook_limit_serio3(const struct dmi_system_id *d) { desired_serio_phys = "isa0060/serio3"; - return 1; + return 0; } static bool lifebook_use_6byte_proto; @@ -41,7 +41,7 @@ static bool lifebook_use_6byte_proto; static int lifebook_set_6byte_proto(const struct dmi_system_id *d) { lifebook_use_6byte_proto = true; - return 1; + return 0; } static const struct dmi_system_id __initconst lifebook_dmi_table[] = { diff --git a/trunk/drivers/input/mouse/pxa930_trkball.c b/trunk/drivers/input/mouse/pxa930_trkball.c index 6c5d84fcdea1..943cfec15665 100644 --- a/trunk/drivers/input/mouse/pxa930_trkball.c +++ b/trunk/drivers/input/mouse/pxa930_trkball.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/trunk/drivers/input/mouse/sentelic.c b/trunk/drivers/input/mouse/sentelic.c index 2fc887a51066..1242775fee19 100644 --- a/trunk/drivers/input/mouse/sentelic.c +++ b/trunk/drivers/input/mouse/sentelic.c @@ -20,6 +20,7 @@ */ #include +#include #include #include #include diff --git a/trunk/drivers/input/mouse/synaptics.c b/trunk/drivers/input/mouse/synaptics.c index 5538fc657af1..e06e045bf907 100644 --- a/trunk/drivers/input/mouse/synaptics.c +++ b/trunk/drivers/input/mouse/synaptics.c @@ -207,37 +207,27 @@ static int synaptics_identify(struct psmouse *psmouse) static int synaptics_resolution(struct psmouse *psmouse) { struct synaptics_data *priv = psmouse->private; - unsigned char resp[3]; + unsigned char res[3]; + unsigned char max[3]; if (SYN_ID_MAJOR(priv->identity) < 4) return 0; - if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, resp) == 0) { - if (resp[0] != 0 && (resp[1] & 0x80) && resp[2] != 0) { - priv->x_res = resp[0]; /* x resolution in units/mm */ - priv->y_res = resp[2]; /* y resolution in units/mm */ + if (synaptics_send_cmd(psmouse, SYN_QUE_RESOLUTION, res) == 0) { + if (res[0] != 0 && (res[1] & 0x80) && res[2] != 0) { + priv->x_res = res[0]; /* x resolution in units/mm */ + priv->y_res = res[2]; /* y resolution in units/mm */ } } if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 5 && SYN_CAP_MAX_DIMENSIONS(priv->ext_cap_0c)) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MAX_COORDS, resp)) { - printk(KERN_ERR "Synaptics claims to have max coordinates" - " query, but I'm not able to read it.\n"); - } else { - priv->x_max = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); - priv->y_max = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); - } - } - - if (SYN_EXT_CAP_REQUESTS(priv->capabilities) >= 7 && - SYN_CAP_MIN_DIMENSIONS(priv->ext_cap_0c)) { - if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_MIN_COORDS, resp)) { - printk(KERN_ERR "Synaptics claims to have min coordinates" - " query, but I'm not able to read it.\n"); + if (synaptics_send_cmd(psmouse, SYN_QUE_EXT_DIMENSIONS, max)) { + printk(KERN_ERR "Synaptics claims to have dimensions query," + " but I'm not able to read it.\n"); } else { - priv->x_min = (resp[0] << 5) | ((resp[1] & 0x0f) << 1); - priv->y_min = (resp[2] << 5) | ((resp[1] & 0xf0) >> 3); + priv->x_max = (max[0] << 5) | ((max[1] & 0x0f) << 1); + priv->y_max = (max[2] << 5) | ((max[1] & 0xf0) >> 3); } } @@ -416,10 +406,26 @@ static int synaptics_parse_hw_state(const unsigned char buf[], memset(hw, 0, sizeof(struct synaptics_hw_state)); if (SYN_MODEL_NEWABS(priv->model_id)) { + hw->x = (((buf[3] & 0x10) << 8) | + ((buf[1] & 0x0f) << 8) | + buf[4]); + hw->y = (((buf[3] & 0x20) << 7) | + ((buf[1] & 0xf0) << 4) | + buf[5]); + + hw->z = buf[2]; hw->w = (((buf[0] & 0x30) >> 2) | ((buf[0] & 0x04) >> 1) | ((buf[3] & 0x04) >> 2)); + if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) { + /* Gesture packet: (x, y, z) at half resolution */ + priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; + priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; + priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; + return 1; + } + hw->left = (buf[0] & 0x01) ? 1 : 0; hw->right = (buf[0] & 0x02) ? 1 : 0; @@ -442,22 +448,6 @@ static int synaptics_parse_hw_state(const unsigned char buf[], hw->down = ((buf[0] ^ buf[3]) & 0x02) ? 1 : 0; } - if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c) && hw->w == 2) { - /* Gesture packet: (x, y, z) at half resolution */ - priv->mt.x = (((buf[4] & 0x0f) << 8) | buf[1]) << 1; - priv->mt.y = (((buf[4] & 0xf0) << 4) | buf[2]) << 1; - priv->mt.z = ((buf[3] & 0x30) | (buf[5] & 0x0f)) << 1; - return 1; - } - - hw->x = (((buf[3] & 0x10) << 8) | - ((buf[1] & 0x0f) << 8) | - buf[4]); - hw->y = (((buf[3] & 0x20) << 7) | - ((buf[1] & 0xf0) << 4) | - buf[5]); - hw->z = buf[2]; - if (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) && ((buf[0] ^ buf[3]) & 0x02)) { switch (SYN_CAP_MULTI_BUTTON_NO(priv->ext_cap) & ~0x01) { @@ -495,8 +485,7 @@ static int synaptics_parse_hw_state(const unsigned char buf[], return 0; } -static void synaptics_report_semi_mt_slot(struct input_dev *dev, int slot, - bool active, int x, int y) +static void set_slot(struct input_dev *dev, int slot, bool active, int x, int y) { input_mt_slot(dev, slot); input_mt_report_slot_state(dev, MT_TOOL_FINGER, active); @@ -513,16 +502,14 @@ static void synaptics_report_semi_mt_data(struct input_dev *dev, int num_fingers) { if (num_fingers >= 2) { - synaptics_report_semi_mt_slot(dev, 0, true, min(a->x, b->x), - min(a->y, b->y)); - synaptics_report_semi_mt_slot(dev, 1, true, max(a->x, b->x), - max(a->y, b->y)); + set_slot(dev, 0, true, min(a->x, b->x), min(a->y, b->y)); + set_slot(dev, 1, true, max(a->x, b->x), max(a->y, b->y)); } else if (num_fingers == 1) { - synaptics_report_semi_mt_slot(dev, 0, true, a->x, a->y); - synaptics_report_semi_mt_slot(dev, 1, false, 0, 0); + set_slot(dev, 0, true, a->x, a->y); + set_slot(dev, 1, false, 0, 0); } else { - synaptics_report_semi_mt_slot(dev, 0, false, 0, 0); - synaptics_report_semi_mt_slot(dev, 1, false, 0, 0); + set_slot(dev, 0, false, 0, 0); + set_slot(dev, 1, false, 0, 0); } } @@ -697,36 +684,23 @@ static psmouse_ret_t synaptics_process_byte(struct psmouse *psmouse) static void set_input_params(struct input_dev *dev, struct synaptics_data *priv) { int i; - int fuzz = SYN_CAP_REDUCED_FILTERING(priv->ext_cap_0c) ? - SYN_REDUCED_FILTER_FUZZ : 0; __set_bit(INPUT_PROP_POINTER, dev->propbit); __set_bit(EV_ABS, dev->evbit); input_set_abs_params(dev, ABS_X, - priv->x_min ?: XMIN_NOMINAL, - priv->x_max ?: XMAX_NOMINAL, - fuzz, 0); + XMIN_NOMINAL, priv->x_max ?: XMAX_NOMINAL, 0, 0); input_set_abs_params(dev, ABS_Y, - priv->y_min ?: YMIN_NOMINAL, - priv->y_max ?: YMAX_NOMINAL, - fuzz, 0); + YMIN_NOMINAL, priv->y_max ?: YMAX_NOMINAL, 0, 0); input_set_abs_params(dev, ABS_PRESSURE, 0, 255, 0, 0); if (SYN_CAP_ADV_GESTURE(priv->ext_cap_0c)) { __set_bit(INPUT_PROP_SEMI_MT, dev->propbit); input_mt_init_slots(dev, 2); - input_set_abs_params(dev, ABS_MT_POSITION_X, - priv->x_min ?: XMIN_NOMINAL, - priv->x_max ?: XMAX_NOMINAL, - fuzz, 0); - input_set_abs_params(dev, ABS_MT_POSITION_Y, - priv->y_min ?: YMIN_NOMINAL, - priv->y_max ?: YMAX_NOMINAL, - fuzz, 0); - - input_abs_set_res(dev, ABS_MT_POSITION_X, priv->x_res); - input_abs_set_res(dev, ABS_MT_POSITION_Y, priv->y_res); + input_set_abs_params(dev, ABS_MT_POSITION_X, XMIN_NOMINAL, + priv->x_max ?: XMAX_NOMINAL, 0, 0); + input_set_abs_params(dev, ABS_MT_POSITION_Y, YMIN_NOMINAL, + priv->y_max ?: YMAX_NOMINAL, 0, 0); } if (SYN_CAP_PALMDETECT(priv->capabilities)) @@ -997,3 +971,4 @@ bool synaptics_supported(void) } #endif /* CONFIG_MOUSE_PS2_SYNAPTICS */ + diff --git a/trunk/drivers/input/mouse/synaptics.h b/trunk/drivers/input/mouse/synaptics.h index ca040aa80fa7..7453938bf5ef 100644 --- a/trunk/drivers/input/mouse/synaptics.h +++ b/trunk/drivers/input/mouse/synaptics.h @@ -19,8 +19,7 @@ #define SYN_QUE_RESOLUTION 0x08 #define SYN_QUE_EXT_CAPAB 0x09 #define SYN_QUE_EXT_CAPAB_0C 0x0c -#define SYN_QUE_EXT_MAX_COORDS 0x0d -#define SYN_QUE_EXT_MIN_COORDS 0x0f +#define SYN_QUE_EXT_DIMENSIONS 0x0d /* synatics modes */ #define SYN_BIT_ABSOLUTE_MODE (1 << 7) @@ -67,21 +66,18 @@ * 1 0x60 multifinger mode identifies firmware finger counting * (not reporting!) algorithm. * Not particularly meaningful - * 1 0x80 covered pad W clipped to 14, 15 == pad mostly covered - * 2 0x01 clickpad bit 1 2-button ClickPad - * 2 0x02 deluxe LED controls touchpad support LED commands + * 1 0x80 covered pad W clipped to 14, 15 == pad mostly covered + * 2 0x01 clickpad bit 1 2-button ClickPad + * 2 0x02 deluxe LED controls touchpad support LED commands * ala multimedia control bar * 2 0x04 reduced filtering firmware does less filtering on * position data, driver should watch * for noise. - * 2 0x20 report min query 0x0f gives min coord reported */ #define SYN_CAP_CLICKPAD(ex0c) ((ex0c) & 0x100000) /* 1-button ClickPad */ #define SYN_CAP_CLICKPAD2BTN(ex0c) ((ex0c) & 0x000100) /* 2-button ClickPad */ #define SYN_CAP_MAX_DIMENSIONS(ex0c) ((ex0c) & 0x020000) -#define SYN_CAP_MIN_DIMENSIONS(ex0c) ((ex0c) & 0x002000) #define SYN_CAP_ADV_GESTURE(ex0c) ((ex0c) & 0x080000) -#define SYN_CAP_REDUCED_FILTERING(ex0c) ((ex0c) & 0x000400) /* synaptics modes query bits */ #define SYN_MODE_ABSOLUTE(m) ((m) & (1 << 7)) @@ -108,9 +104,6 @@ #define SYN_NEWABS_RELAXED 2 #define SYN_OLDABS 3 -/* amount to fuzz position data when touchpad reports reduced filtering */ -#define SYN_REDUCED_FILTER_FUZZ 8 - /* * A structure to describe the state of the touchpad hardware (buttons and pad) */ @@ -137,8 +130,7 @@ struct synaptics_data { unsigned long int ext_cap_0c; /* Ext Caps from 0x0c query */ unsigned long int identity; /* Identification */ unsigned int x_res, y_res; /* X/Y resolution in units/mm */ - unsigned int x_max, y_max; /* Max coordinates (from FW) */ - unsigned int x_min, y_min; /* Min coordinates (from FW) */ + unsigned int x_max, y_max; /* Max dimensions (from FW) */ unsigned char pkt_type; /* packet type - old, new, etc */ unsigned char mode; /* current mode byte */ diff --git a/trunk/drivers/input/serio/at32psif.c b/trunk/drivers/input/serio/at32psif.c index 95280f9207e1..6ee8f0ddad51 100644 --- a/trunk/drivers/input/serio/at32psif.c +++ b/trunk/drivers/input/serio/at32psif.c @@ -372,6 +372,6 @@ static void __exit psif_exit(void) module_init(psif_init); module_exit(psif_exit); -MODULE_AUTHOR("Hans-Christian Egtvedt "); +MODULE_AUTHOR("Hans-Christian Egtvedt "); MODULE_DESCRIPTION("Atmel AVR32 PSIF PS/2 driver"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/serio/hp_sdc.c b/trunk/drivers/input/serio/hp_sdc.c index 979c443bf1ef..42206205e4f5 100644 --- a/trunk/drivers/input/serio/hp_sdc.c +++ b/trunk/drivers/input/serio/hp_sdc.c @@ -795,7 +795,7 @@ int hp_sdc_release_cooked_irq(hp_sdc_irqhook *callback) /************************* Keepalive timer task *********************/ -static void hp_sdc_kicker(unsigned long data) +void hp_sdc_kicker (unsigned long data) { tasklet_schedule(&hp_sdc.task); /* Re-insert the periodic task. */ diff --git a/trunk/drivers/input/tablet/aiptek.c b/trunk/drivers/input/tablet/aiptek.c index 6d89fd1842c3..0a619c558bfb 100644 --- a/trunk/drivers/input/tablet/aiptek.c +++ b/trunk/drivers/input/tablet/aiptek.c @@ -225,6 +225,7 @@ /* toolMode codes */ #define AIPTEK_TOOL_BUTTON_PEN_MODE BTN_TOOL_PEN +#define AIPTEK_TOOL_BUTTON_PEN_MODE BTN_TOOL_PEN #define AIPTEK_TOOL_BUTTON_PENCIL_MODE BTN_TOOL_PENCIL #define AIPTEK_TOOL_BUTTON_BRUSH_MODE BTN_TOOL_BRUSH #define AIPTEK_TOOL_BUTTON_AIRBRUSH_MODE BTN_TOOL_AIRBRUSH diff --git a/trunk/drivers/input/tablet/wacom_wac.c b/trunk/drivers/input/tablet/wacom_wac.c index 03ebcc8b24b5..08ba5ad9c9be 100644 --- a/trunk/drivers/input/tablet/wacom_wac.c +++ b/trunk/drivers/input/tablet/wacom_wac.c @@ -15,7 +15,6 @@ #include "wacom_wac.h" #include "wacom.h" #include -#include /* resolution for penabled devices */ #define WACOM_PL_RES 20 @@ -265,7 +264,6 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) wacom->id[0] = 0; input_report_abs(input, ABS_MISC, wacom->id[0]); /* report tool id */ input_report_key(input, wacom->tool[0], prox); - input_event(input, EV_MSC, MSC_SERIAL, 1); input_sync(input); /* sync last event */ } @@ -275,10 +273,11 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) prox = data[7] & 0xf8; if (prox || wacom->id[1]) { wacom->id[1] = PAD_DEVICE_ID; - input_report_key(input, BTN_BACK, (data[7] & 0x40)); - input_report_key(input, BTN_FORWARD, (data[7] & 0x80)); + input_report_key(input, BTN_0, (data[7] & 0x40)); + input_report_key(input, BTN_4, (data[7] & 0x80)); rw = ((data[7] & 0x18) >> 3) - ((data[7] & 0x20) >> 3); input_report_rel(input, REL_WHEEL, rw); + input_report_key(input, BTN_TOOL_FINGER, 0xf0); if (!prox) wacom->id[1] = 0; input_report_abs(input, ABS_MISC, wacom->id[1]); @@ -291,17 +290,18 @@ static int wacom_graphire_irq(struct wacom_wac *wacom) prox = (data[7] & 0xf8) || data[8]; if (prox || wacom->id[1]) { wacom->id[1] = PAD_DEVICE_ID; - input_report_key(input, BTN_BACK, (data[7] & 0x08)); - input_report_key(input, BTN_LEFT, (data[7] & 0x20)); - input_report_key(input, BTN_FORWARD, (data[7] & 0x10)); - input_report_key(input, BTN_RIGHT, (data[7] & 0x40)); + input_report_key(input, BTN_0, (data[7] & 0x08)); + input_report_key(input, BTN_1, (data[7] & 0x20)); + input_report_key(input, BTN_4, (data[7] & 0x10)); + input_report_key(input, BTN_5, (data[7] & 0x40)); input_report_abs(input, ABS_WHEEL, (data[8] & 0x7f)); + input_report_key(input, BTN_TOOL_FINGER, 0xf0); if (!prox) wacom->id[1] = 0; input_report_abs(input, ABS_MISC, wacom->id[1]); input_event(input, EV_MSC, MSC_SERIAL, 0xf0); - retval = 1; } + retval = 1; break; } exit: @@ -494,6 +494,10 @@ static int wacom_intuos_irq(struct wacom_wac *wacom) /* pad packets. Works as a second tool and is always in prox */ if (data[0] == WACOM_REPORT_INTUOSPAD) { + /* initiate the pad as a device */ + if (wacom->tool[1] != BTN_TOOL_FINGER) + wacom->tool[1] = BTN_TOOL_FINGER; + if (features->type >= INTUOS4S && features->type <= INTUOS4L) { input_report_key(input, BTN_0, (data[2] & 0x01)); input_report_key(input, BTN_1, (data[3] & 0x01)); @@ -1076,14 +1080,18 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, switch (wacom_wac->features.type) { case WACOM_MO: + __set_bit(BTN_1, input_dev->keybit); + __set_bit(BTN_5, input_dev->keybit); + input_set_abs_params(input_dev, ABS_WHEEL, 0, 71, 0, 0); /* fall through */ case WACOM_G4: input_set_capability(input_dev, EV_MSC, MSC_SERIAL); - __set_bit(BTN_BACK, input_dev->keybit); - __set_bit(BTN_FORWARD, input_dev->keybit); + __set_bit(BTN_TOOL_FINGER, input_dev->keybit); + __set_bit(BTN_0, input_dev->keybit); + __set_bit(BTN_4, input_dev->keybit); /* fall through */ case GRAPHIRE: @@ -1119,12 +1127,10 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, case CINTIQ: for (i = 0; i < 8; i++) __set_bit(BTN_0 + i, input_dev->keybit); + __set_bit(BTN_TOOL_FINGER, input_dev->keybit); - if (wacom_wac->features.type != WACOM_21UX2) { - input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); - input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); - } - + input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); + input_set_abs_params(input_dev, ABS_RY, 0, 4096, 0, 0); input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); wacom_setup_cintiq(wacom_wac); break; @@ -1145,6 +1151,8 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, __set_bit(BTN_2, input_dev->keybit); __set_bit(BTN_3, input_dev->keybit); + __set_bit(BTN_TOOL_FINGER, input_dev->keybit); + input_set_abs_params(input_dev, ABS_RX, 0, 4096, 0, 0); input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); /* fall through */ @@ -1162,6 +1170,7 @@ void wacom_setup_input_capabilities(struct input_dev *input_dev, case INTUOS4S: for (i = 0; i < 7; i++) __set_bit(BTN_0 + i, input_dev->keybit); + __set_bit(BTN_TOOL_FINGER, input_dev->keybit); input_set_abs_params(input_dev, ABS_Z, -900, 899, 0, 0); wacom_setup_intuos(wacom_wac); @@ -1286,12 +1295,6 @@ static const struct wacom_features wacom_features_0x65 = static const struct wacom_features wacom_features_0x69 = { "Wacom Bamboo1", WACOM_PKGLEN_GRAPHIRE, 5104, 3712, 511, 63, GRAPHIRE, WACOM_PENPRTN_RES, WACOM_PENPRTN_RES }; -static const struct wacom_features wacom_features_0x6A = - { "Wacom Bamboo1 4x6", WACOM_PKGLEN_GRAPHIRE, 14760, 9225, 1023, - 63, GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x6B = - { "Wacom Bamboo1 5x8", WACOM_PKGLEN_GRAPHIRE, 21648, 13530, 1023, - 63, GRAPHIRE, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x20 = { "Wacom Intuos 4x5", WACOM_PKGLEN_INTUOS, 12700, 10600, 1023, 31, INTUOS, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1424,9 +1427,6 @@ static const struct wacom_features wacom_features_0x90 = static const struct wacom_features wacom_features_0x93 = { "Wacom ISDv4 93", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; -static const struct wacom_features wacom_features_0x97 = - { "Wacom ISDv4 97", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 511, - 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0x9A = { "Wacom ISDv4 9A", WACOM_PKGLEN_GRAPHIRE, 26202, 16325, 255, 0, TABLETPC, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; @@ -1458,7 +1458,7 @@ static const struct wacom_features wacom_features_0xD3 = { "Wacom Bamboo 2FG 6x8", WACOM_PKGLEN_BBFUN, 21648, 13530, 1023, 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD4 = - { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, + { "Wacom Bamboo Pen", WACOM_PKGLEN_BBFUN, 14720, 9200, 255, 63, BAMBOO_PT, WACOM_INTUOS_RES, WACOM_INTUOS_RES }; static const struct wacom_features wacom_features_0xD6 = { "Wacom BambooPT 2FG 4x5", WACOM_PKGLEN_BBFUN, 14720, 9200, 1023, @@ -1483,11 +1483,6 @@ static const struct wacom_features wacom_features_0x6004 = USB_DEVICE(USB_VENDOR_ID_WACOM, prod), \ .driver_info = (kernel_ulong_t)&wacom_features_##prod -#define USB_DEVICE_DETAILED(prod, class, sub, proto) \ - USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_WACOM, prod, class, \ - sub, proto), \ - .driver_info = (kernel_ulong_t)&wacom_features_##prod - #define USB_DEVICE_LENOVO(prod) \ USB_DEVICE(USB_VENDOR_ID_LENOVO, prod), \ .driver_info = (kernel_ulong_t)&wacom_features_##prod @@ -1511,8 +1506,6 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0x64) }, { USB_DEVICE_WACOM(0x65) }, { USB_DEVICE_WACOM(0x69) }, - { USB_DEVICE_WACOM(0x6A) }, - { USB_DEVICE_WACOM(0x6B) }, { USB_DEVICE_WACOM(0x20) }, { USB_DEVICE_WACOM(0x21) }, { USB_DEVICE_WACOM(0x22) }, @@ -1552,13 +1545,7 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xC5) }, { USB_DEVICE_WACOM(0xC6) }, { USB_DEVICE_WACOM(0xC7) }, - /* - * DTU-2231 has two interfaces on the same configuration, - * only one is used. - */ - { USB_DEVICE_DETAILED(0xCE, USB_CLASS_HID, - USB_INTERFACE_SUBCLASS_BOOT, - USB_INTERFACE_PROTOCOL_MOUSE) }, + { USB_DEVICE_WACOM(0xCE) }, { USB_DEVICE_WACOM(0xD0) }, { USB_DEVICE_WACOM(0xD1) }, { USB_DEVICE_WACOM(0xD2) }, @@ -1573,7 +1560,6 @@ const struct usb_device_id wacom_ids[] = { { USB_DEVICE_WACOM(0xCC) }, { USB_DEVICE_WACOM(0x90) }, { USB_DEVICE_WACOM(0x93) }, - { USB_DEVICE_WACOM(0x97) }, { USB_DEVICE_WACOM(0x9A) }, { USB_DEVICE_WACOM(0x9F) }, { USB_DEVICE_WACOM(0xE2) }, diff --git a/trunk/drivers/input/touchscreen/ads7846.c b/trunk/drivers/input/touchscreen/ads7846.c index d507b9b67806..5196861b86ef 100644 --- a/trunk/drivers/input/touchscreen/ads7846.c +++ b/trunk/drivers/input/touchscreen/ads7846.c @@ -967,12 +967,17 @@ static int __devinit ads7846_setup_pendown(struct spi_device *spi, struct ads784 ts->get_pendown_state = pdata->get_pendown_state; } else if (gpio_is_valid(pdata->gpio_pendown)) { - err = gpio_request_one(pdata->gpio_pendown, GPIOF_IN, - "ads7846_pendown"); + err = gpio_request(pdata->gpio_pendown, "ads7846_pendown"); if (err) { - dev_err(&spi->dev, - "failed to request/setup pendown GPIO%d: %d\n", - pdata->gpio_pendown, err); + dev_err(&spi->dev, "failed to request pendown GPIO%d\n", + pdata->gpio_pendown); + return err; + } + err = gpio_direction_input(pdata->gpio_pendown); + if (err) { + dev_err(&spi->dev, "failed to setup pendown GPIO%d\n", + pdata->gpio_pendown); + gpio_free(pdata->gpio_pendown); return err; } diff --git a/trunk/drivers/input/touchscreen/atmel-wm97xx.c b/trunk/drivers/input/touchscreen/atmel-wm97xx.c index 8034cbb20f74..fa8e56bd9094 100644 --- a/trunk/drivers/input/touchscreen/atmel-wm97xx.c +++ b/trunk/drivers/input/touchscreen/atmel-wm97xx.c @@ -164,7 +164,7 @@ static irqreturn_t atmel_wm97xx_channel_b_interrupt(int irq, void *dev_id) data = ac97c_readl(atmel_wm97xx, CBRHR); value = data & 0x0fff; - source = data & WM97XX_ADCSEL_MASK; + source = data & WM97XX_ADCSRC_MASK; pen_down = (data & WM97XX_PEN_DOWN) >> 8; if (source == WM97XX_ADCSEL_X) @@ -442,6 +442,6 @@ static void __exit atmel_wm97xx_exit(void) } module_exit(atmel_wm97xx_exit); -MODULE_AUTHOR("Hans-Christian Egtvedt "); +MODULE_AUTHOR("Hans-Christian Egtvedt "); MODULE_DESCRIPTION("wm97xx continuous touch driver for Atmel AT91 and AVR32"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/touchscreen/atmel_mxt_ts.c b/trunk/drivers/input/touchscreen/atmel_mxt_ts.c index ae00604a6a81..1e61387c73ca 100644 --- a/trunk/drivers/input/touchscreen/atmel_mxt_ts.c +++ b/trunk/drivers/input/touchscreen/atmel_mxt_ts.c @@ -48,47 +48,41 @@ #define MXT_OBJECT_SIZE 6 /* Object types */ -#define MXT_DEBUG_DIAGNOSTIC_T37 37 -#define MXT_GEN_MESSAGE_T5 5 -#define MXT_GEN_COMMAND_T6 6 -#define MXT_GEN_POWER_T7 7 -#define MXT_GEN_ACQUIRE_T8 8 -#define MXT_GEN_DATASOURCE_T53 53 -#define MXT_TOUCH_MULTI_T9 9 -#define MXT_TOUCH_KEYARRAY_T15 15 -#define MXT_TOUCH_PROXIMITY_T23 23 -#define MXT_TOUCH_PROXKEY_T52 52 -#define MXT_PROCI_GRIPFACE_T20 20 -#define MXT_PROCG_NOISE_T22 22 -#define MXT_PROCI_ONETOUCH_T24 24 -#define MXT_PROCI_TWOTOUCH_T27 27 -#define MXT_PROCI_GRIP_T40 40 -#define MXT_PROCI_PALM_T41 41 -#define MXT_PROCI_TOUCHSUPPRESSION_T42 42 -#define MXT_PROCI_STYLUS_T47 47 -#define MXT_PROCG_NOISESUPPRESSION_T48 48 -#define MXT_SPT_COMMSCONFIG_T18 18 -#define MXT_SPT_GPIOPWM_T19 19 -#define MXT_SPT_SELFTEST_T25 25 -#define MXT_SPT_CTECONFIG_T28 28 -#define MXT_SPT_USERDATA_T38 38 -#define MXT_SPT_DIGITIZER_T43 43 -#define MXT_SPT_MESSAGECOUNT_T44 44 -#define MXT_SPT_CTECONFIG_T46 46 - -/* MXT_GEN_COMMAND_T6 field */ +#define MXT_DEBUG_DIAGNOSTIC 37 +#define MXT_GEN_MESSAGE 5 +#define MXT_GEN_COMMAND 6 +#define MXT_GEN_POWER 7 +#define MXT_GEN_ACQUIRE 8 +#define MXT_TOUCH_MULTI 9 +#define MXT_TOUCH_KEYARRAY 15 +#define MXT_TOUCH_PROXIMITY 23 +#define MXT_PROCI_GRIPFACE 20 +#define MXT_PROCG_NOISE 22 +#define MXT_PROCI_ONETOUCH 24 +#define MXT_PROCI_TWOTOUCH 27 +#define MXT_PROCI_GRIP 40 +#define MXT_PROCI_PALM 41 +#define MXT_SPT_COMMSCONFIG 18 +#define MXT_SPT_GPIOPWM 19 +#define MXT_SPT_SELFTEST 25 +#define MXT_SPT_CTECONFIG 28 +#define MXT_SPT_USERDATA 38 +#define MXT_SPT_DIGITIZER 43 +#define MXT_SPT_MESSAGECOUNT 44 + +/* MXT_GEN_COMMAND field */ #define MXT_COMMAND_RESET 0 #define MXT_COMMAND_BACKUPNV 1 #define MXT_COMMAND_CALIBRATE 2 #define MXT_COMMAND_REPORTALL 3 #define MXT_COMMAND_DIAGNOSTIC 5 -/* MXT_GEN_POWER_T7 field */ +/* MXT_GEN_POWER field */ #define MXT_POWER_IDLEACQINT 0 #define MXT_POWER_ACTVACQINT 1 #define MXT_POWER_ACTV2IDLETO 2 -/* MXT_GEN_ACQUIRE_T8 field */ +/* MXT_GEN_ACQUIRE field */ #define MXT_ACQUIRE_CHRGTIME 0 #define MXT_ACQUIRE_TCHDRIFT 2 #define MXT_ACQUIRE_DRIFTST 3 @@ -97,7 +91,7 @@ #define MXT_ACQUIRE_ATCHCALST 6 #define MXT_ACQUIRE_ATCHCALSTHR 7 -/* MXT_TOUCH_MULTI_T9 field */ +/* MXT_TOUCH_MULTI field */ #define MXT_TOUCH_CTRL 0 #define MXT_TOUCH_XORIGIN 1 #define MXT_TOUCH_YORIGIN 2 @@ -127,7 +121,7 @@ #define MXT_TOUCH_YEDGEDIST 29 #define MXT_TOUCH_JUMPLIMIT 30 -/* MXT_PROCI_GRIPFACE_T20 field */ +/* MXT_PROCI_GRIPFACE field */ #define MXT_GRIPFACE_CTRL 0 #define MXT_GRIPFACE_XLOGRIP 1 #define MXT_GRIPFACE_XHIGRIP 2 @@ -157,11 +151,11 @@ #define MXT_NOISE_FREQ4 15 #define MXT_NOISE_IDLEGCAFVALID 16 -/* MXT_SPT_COMMSCONFIG_T18 */ +/* MXT_SPT_COMMSCONFIG */ #define MXT_COMMS_CTRL 0 #define MXT_COMMS_CMD 1 -/* MXT_SPT_CTECONFIG_T28 field */ +/* MXT_SPT_CTECONFIG field */ #define MXT_CTE_CTRL 0 #define MXT_CTE_CMD 1 #define MXT_CTE_MODE 2 @@ -172,7 +166,7 @@ #define MXT_VOLTAGE_DEFAULT 2700000 #define MXT_VOLTAGE_STEP 10000 -/* Define for MXT_GEN_COMMAND_T6 */ +/* Define for MXT_GEN_COMMAND */ #define MXT_BOOT_VALUE 0xa5 #define MXT_BACKUP_VALUE 0x55 #define MXT_BACKUP_TIME 25 /* msec */ @@ -262,31 +256,24 @@ struct mxt_data { static bool mxt_object_readable(unsigned int type) { switch (type) { - case MXT_GEN_MESSAGE_T5: - case MXT_GEN_COMMAND_T6: - case MXT_GEN_POWER_T7: - case MXT_GEN_ACQUIRE_T8: - case MXT_GEN_DATASOURCE_T53: - case MXT_TOUCH_MULTI_T9: - case MXT_TOUCH_KEYARRAY_T15: - case MXT_TOUCH_PROXIMITY_T23: - case MXT_TOUCH_PROXKEY_T52: - case MXT_PROCI_GRIPFACE_T20: - case MXT_PROCG_NOISE_T22: - case MXT_PROCI_ONETOUCH_T24: - case MXT_PROCI_TWOTOUCH_T27: - case MXT_PROCI_GRIP_T40: - case MXT_PROCI_PALM_T41: - case MXT_PROCI_TOUCHSUPPRESSION_T42: - case MXT_PROCI_STYLUS_T47: - case MXT_PROCG_NOISESUPPRESSION_T48: - case MXT_SPT_COMMSCONFIG_T18: - case MXT_SPT_GPIOPWM_T19: - case MXT_SPT_SELFTEST_T25: - case MXT_SPT_CTECONFIG_T28: - case MXT_SPT_USERDATA_T38: - case MXT_SPT_DIGITIZER_T43: - case MXT_SPT_CTECONFIG_T46: + case MXT_GEN_MESSAGE: + case MXT_GEN_COMMAND: + case MXT_GEN_POWER: + case MXT_GEN_ACQUIRE: + case MXT_TOUCH_MULTI: + case MXT_TOUCH_KEYARRAY: + case MXT_TOUCH_PROXIMITY: + case MXT_PROCI_GRIPFACE: + case MXT_PROCG_NOISE: + case MXT_PROCI_ONETOUCH: + case MXT_PROCI_TWOTOUCH: + case MXT_PROCI_GRIP: + case MXT_PROCI_PALM: + case MXT_SPT_COMMSCONFIG: + case MXT_SPT_GPIOPWM: + case MXT_SPT_SELFTEST: + case MXT_SPT_CTECONFIG: + case MXT_SPT_USERDATA: return true; default: return false; @@ -296,28 +283,21 @@ static bool mxt_object_readable(unsigned int type) static bool mxt_object_writable(unsigned int type) { switch (type) { - case MXT_GEN_COMMAND_T6: - case MXT_GEN_POWER_T7: - case MXT_GEN_ACQUIRE_T8: - case MXT_TOUCH_MULTI_T9: - case MXT_TOUCH_KEYARRAY_T15: - case MXT_TOUCH_PROXIMITY_T23: - case MXT_TOUCH_PROXKEY_T52: - case MXT_PROCI_GRIPFACE_T20: - case MXT_PROCG_NOISE_T22: - case MXT_PROCI_ONETOUCH_T24: - case MXT_PROCI_TWOTOUCH_T27: - case MXT_PROCI_GRIP_T40: - case MXT_PROCI_PALM_T41: - case MXT_PROCI_TOUCHSUPPRESSION_T42: - case MXT_PROCI_STYLUS_T47: - case MXT_PROCG_NOISESUPPRESSION_T48: - case MXT_SPT_COMMSCONFIG_T18: - case MXT_SPT_GPIOPWM_T19: - case MXT_SPT_SELFTEST_T25: - case MXT_SPT_CTECONFIG_T28: - case MXT_SPT_DIGITIZER_T43: - case MXT_SPT_CTECONFIG_T46: + case MXT_GEN_COMMAND: + case MXT_GEN_POWER: + case MXT_GEN_ACQUIRE: + case MXT_TOUCH_MULTI: + case MXT_TOUCH_KEYARRAY: + case MXT_TOUCH_PROXIMITY: + case MXT_PROCI_GRIPFACE: + case MXT_PROCG_NOISE: + case MXT_PROCI_ONETOUCH: + case MXT_PROCI_TWOTOUCH: + case MXT_PROCI_GRIP: + case MXT_PROCI_PALM: + case MXT_SPT_GPIOPWM: + case MXT_SPT_SELFTEST: + case MXT_SPT_CTECONFIG: return true; default: return false; @@ -475,7 +455,7 @@ static int mxt_read_message(struct mxt_data *data, struct mxt_object *object; u16 reg; - object = mxt_get_object(data, MXT_GEN_MESSAGE_T5); + object = mxt_get_object(data, MXT_GEN_MESSAGE); if (!object) return -EINVAL; @@ -617,8 +597,8 @@ static irqreturn_t mxt_interrupt(int irq, void *dev_id) reportid = message.reportid; - /* whether reportid is thing of MXT_TOUCH_MULTI_T9 */ - object = mxt_get_object(data, MXT_TOUCH_MULTI_T9); + /* whether reportid is thing of MXT_TOUCH_MULTI */ + object = mxt_get_object(data, MXT_TOUCH_MULTI); if (!object) goto end; @@ -655,9 +635,7 @@ static int mxt_check_reg_init(struct mxt_data *data) if (!mxt_object_writable(object->type)) continue; - for (j = 0; - j < (object->size + 1) * (object->instances + 1); - j++) { + for (j = 0; j < object->size + 1; j++) { config_offset = index + j; if (config_offset > pdata->config_length) { dev_err(dev, "Not enough config data!\n"); @@ -666,7 +644,7 @@ static int mxt_check_reg_init(struct mxt_data *data) mxt_write_object(data, object->type, j, pdata->config[config_offset]); } - index += (object->size + 1) * (object->instances + 1); + index += object->size + 1; } return 0; @@ -700,31 +678,31 @@ static void mxt_handle_pdata(struct mxt_data *data) u8 voltage; /* Set touchscreen lines */ - mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_XSIZE, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_XSIZE, pdata->x_line); - mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_YSIZE, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_YSIZE, pdata->y_line); /* Set touchscreen orient */ - mxt_write_object(data, MXT_TOUCH_MULTI_T9, MXT_TOUCH_ORIENT, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_ORIENT, pdata->orient); /* Set touchscreen burst length */ - mxt_write_object(data, MXT_TOUCH_MULTI_T9, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_BLEN, pdata->blen); /* Set touchscreen threshold */ - mxt_write_object(data, MXT_TOUCH_MULTI_T9, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_TCHTHR, pdata->threshold); /* Set touchscreen resolution */ - mxt_write_object(data, MXT_TOUCH_MULTI_T9, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_XRANGE_LSB, (pdata->x_size - 1) & 0xff); - mxt_write_object(data, MXT_TOUCH_MULTI_T9, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_XRANGE_MSB, (pdata->x_size - 1) >> 8); - mxt_write_object(data, MXT_TOUCH_MULTI_T9, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_YRANGE_LSB, (pdata->y_size - 1) & 0xff); - mxt_write_object(data, MXT_TOUCH_MULTI_T9, + mxt_write_object(data, MXT_TOUCH_MULTI, MXT_TOUCH_YRANGE_MSB, (pdata->y_size - 1) >> 8); /* Set touchscreen voltage */ @@ -737,7 +715,7 @@ static void mxt_handle_pdata(struct mxt_data *data) voltage = (pdata->voltage - MXT_VOLTAGE_DEFAULT) / MXT_VOLTAGE_STEP; - mxt_write_object(data, MXT_SPT_CTECONFIG_T28, + mxt_write_object(data, MXT_SPT_CTECONFIG, MXT_CTE_VOLTAGE, voltage); } } @@ -841,13 +819,13 @@ static int mxt_initialize(struct mxt_data *data) mxt_handle_pdata(data); /* Backup to memory */ - mxt_write_object(data, MXT_GEN_COMMAND_T6, + mxt_write_object(data, MXT_GEN_COMMAND, MXT_COMMAND_BACKUPNV, MXT_BACKUP_VALUE); msleep(MXT_BACKUP_TIME); /* Soft reset */ - mxt_write_object(data, MXT_GEN_COMMAND_T6, + mxt_write_object(data, MXT_GEN_COMMAND, MXT_COMMAND_RESET, 1); msleep(MXT_RESET_TIME); @@ -943,7 +921,7 @@ static int mxt_load_fw(struct device *dev, const char *fn) } /* Change to the bootloader mode */ - mxt_write_object(data, MXT_GEN_COMMAND_T6, + mxt_write_object(data, MXT_GEN_COMMAND, MXT_COMMAND_RESET, MXT_BOOT_VALUE); msleep(MXT_RESET_TIME); @@ -1049,14 +1027,14 @@ static void mxt_start(struct mxt_data *data) { /* Touch enable */ mxt_write_object(data, - MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0x83); + MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0x83); } static void mxt_stop(struct mxt_data *data) { /* Touch disable */ mxt_write_object(data, - MXT_TOUCH_MULTI_T9, MXT_TOUCH_CTRL, 0); + MXT_TOUCH_MULTI, MXT_TOUCH_CTRL, 0); } static int mxt_input_open(struct input_dev *dev) @@ -1204,7 +1182,7 @@ static int mxt_resume(struct device *dev) struct input_dev *input_dev = data->input_dev; /* Soft reset */ - mxt_write_object(data, MXT_GEN_COMMAND_T6, + mxt_write_object(data, MXT_GEN_COMMAND, MXT_COMMAND_RESET, 1); msleep(MXT_RESET_TIME); diff --git a/trunk/drivers/input/touchscreen/cy8ctmg110_ts.c b/trunk/drivers/input/touchscreen/cy8ctmg110_ts.c index d8815c5d54ad..a93c5c26ab3f 100644 --- a/trunk/drivers/input/touchscreen/cy8ctmg110_ts.c +++ b/trunk/drivers/input/touchscreen/cy8ctmg110_ts.c @@ -84,9 +84,9 @@ static int cy8ctmg110_write_regs(struct cy8ctmg110 *tsc, unsigned char reg, memcpy(i2c_data + 1, value, len); ret = i2c_master_send(client, i2c_data, len + 1); - if (ret != len + 1) { + if (ret != 1) { dev_err(&client->dev, "i2c write data cmd failed\n"); - return ret < 0 ? ret : -EIO; + return ret ? ret : -EIO; } return 0; @@ -193,8 +193,6 @@ static int __devinit cy8ctmg110_probe(struct i2c_client *client, ts->client = client; ts->input = input_dev; - ts->reset_pin = pdata->reset_pin; - ts->irq_pin = pdata->irq_pin; snprintf(ts->phys, sizeof(ts->phys), "%s/input0", dev_name(&client->dev)); @@ -330,7 +328,7 @@ static int __devexit cy8ctmg110_remove(struct i2c_client *client) return 0; } -static const struct i2c_device_id cy8ctmg110_idtable[] = { +static struct i2c_device_id cy8ctmg110_idtable[] = { { CY8CTMG110_DRIVER_NAME, 1 }, { } }; diff --git a/trunk/drivers/input/touchscreen/intel-mid-touch.c b/trunk/drivers/input/touchscreen/intel-mid-touch.c index 327695268e06..66c96bfc5522 100644 --- a/trunk/drivers/input/touchscreen/intel-mid-touch.c +++ b/trunk/drivers/input/touchscreen/intel-mid-touch.c @@ -448,11 +448,15 @@ static int __devinit mrstouch_read_pmic_id(uint *vendor, uint *rev) */ static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev) { - int found = 0; - int err, i; + int err, i, found; u8 r8; + found = -1; + for (i = 0; i < MRSTOUCH_MAX_CHANNELS; i++) { + if (found >= 0) + break; + err = intel_scu_ipc_ioread8(PMICADDR0 + i, &r8); if (err) return err; @@ -462,15 +466,16 @@ static int __devinit mrstouch_chan_parse(struct mrstouch_dev *tsdev) break; } } + if (found < 0) + return 0; if (tsdev->vendor == PMIC_VENDOR_FS) { - if (found > MRSTOUCH_MAX_CHANNELS - 18) + if (found && found > (MRSTOUCH_MAX_CHANNELS - 18)) return -ENOSPC; } else { - if (found > MRSTOUCH_MAX_CHANNELS - 4) + if (found && found > (MRSTOUCH_MAX_CHANNELS - 4)) return -ENOSPC; } - return found; } diff --git a/trunk/drivers/input/touchscreen/mainstone-wm97xx.c b/trunk/drivers/input/touchscreen/mainstone-wm97xx.c index e966c29ff1bb..3242e7076258 100644 --- a/trunk/drivers/input/touchscreen/mainstone-wm97xx.c +++ b/trunk/drivers/input/touchscreen/mainstone-wm97xx.c @@ -157,9 +157,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm) x, y, p); /* are samples valid */ - if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X || - (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y || - (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES) + if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X || + (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y || + (p & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_PRES) goto up; /* coordinate is good */ diff --git a/trunk/drivers/input/touchscreen/tnetv107x-ts.c b/trunk/drivers/input/touchscreen/tnetv107x-ts.c index 089b0a0f3d8c..22a3411e93c5 100644 --- a/trunk/drivers/input/touchscreen/tnetv107x-ts.c +++ b/trunk/drivers/input/touchscreen/tnetv107x-ts.c @@ -393,5 +393,5 @@ module_exit(tsc_exit); MODULE_AUTHOR("Cyril Chemparathy"); MODULE_DESCRIPTION("TNETV107X Touchscreen Driver"); -MODULE_ALIAS("platform:tnetv107x-ts"); +MODULE_ALIAS("platform: tnetv107x-ts"); MODULE_LICENSE("GPL"); diff --git a/trunk/drivers/input/touchscreen/wm9705.c b/trunk/drivers/input/touchscreen/wm9705.c index adc13a523ab5..98e61175d3f5 100644 --- a/trunk/drivers/input/touchscreen/wm9705.c +++ b/trunk/drivers/input/touchscreen/wm9705.c @@ -215,9 +215,8 @@ static inline int is_pden(struct wm97xx *wm) static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample) { int timeout = 5 * delay; - bool wants_pen = adcsel & WM97XX_PEN_DOWN; - if (wants_pen && !wm->pen_probably_down) { + if (!wm->pen_probably_down) { u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); if (!(data & WM97XX_PEN_DOWN)) return RC_PENUP; @@ -225,10 +224,13 @@ static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample) } /* set up digitiser */ + if (adcsel & 0x8000) + adcsel = ((adcsel & 0x7fff) + 3) << 12; + if (wm->mach_ops && wm->mach_ops->pre_sample) wm->mach_ops->pre_sample(adcsel); - wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK) - | WM97XX_POLL | WM97XX_DELAY(delay)); + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, + adcsel | WM97XX_POLL | WM97XX_DELAY(delay)); /* wait 3 AC97 time slots + delay for conversion */ poll_delay(delay); @@ -254,14 +256,13 @@ static int wm9705_poll_sample(struct wm97xx *wm, int adcsel, int *sample) wm->mach_ops->post_sample(adcsel); /* check we have correct sample */ - if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) { - dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x", - adcsel & WM97XX_ADCSEL_MASK, - *sample & WM97XX_ADCSEL_MASK); + if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) { + dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel, + *sample & WM97XX_ADCSEL_MASK); return RC_PENUP; } - if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) { + if (!(*sample & WM97XX_PEN_DOWN)) { wm->pen_probably_down = 0; return RC_PENUP; } @@ -276,14 +277,14 @@ static int wm9705_poll_touch(struct wm97xx *wm, struct wm97xx_data *data) { int rc; - rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x); + rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_X, &data->x); if (rc != RC_VALID) return rc; - rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y); + rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y); if (rc != RC_VALID) return rc; if (pil) { - rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN, &data->p); + rc = wm9705_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p); if (rc != RC_VALID) return rc; } else diff --git a/trunk/drivers/input/touchscreen/wm9712.c b/trunk/drivers/input/touchscreen/wm9712.c index 6e743e3dfda4..2bc2fb801009 100644 --- a/trunk/drivers/input/touchscreen/wm9712.c +++ b/trunk/drivers/input/touchscreen/wm9712.c @@ -255,9 +255,8 @@ static inline int is_pden(struct wm97xx *wm) static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample) { int timeout = 5 * delay; - bool wants_pen = adcsel & WM97XX_PEN_DOWN; - if (wants_pen && !wm->pen_probably_down) { + if (!wm->pen_probably_down) { u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); if (!(data & WM97XX_PEN_DOWN)) return RC_PENUP; @@ -265,10 +264,13 @@ static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample) } /* set up digitiser */ + if (adcsel & 0x8000) + adcsel = ((adcsel & 0x7fff) + 3) << 12; + if (wm->mach_ops && wm->mach_ops->pre_sample) wm->mach_ops->pre_sample(adcsel); - wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, (adcsel & WM97XX_ADCSEL_MASK) - | WM97XX_POLL | WM97XX_DELAY(delay)); + wm97xx_reg_write(wm, AC97_WM97XX_DIGITISER1, + adcsel | WM97XX_POLL | WM97XX_DELAY(delay)); /* wait 3 AC97 time slots + delay for conversion */ poll_delay(delay); @@ -294,14 +296,13 @@ static int wm9712_poll_sample(struct wm97xx *wm, int adcsel, int *sample) wm->mach_ops->post_sample(adcsel); /* check we have correct sample */ - if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) { - dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x", - adcsel & WM97XX_ADCSEL_MASK, - *sample & WM97XX_ADCSEL_MASK); + if ((*sample & WM97XX_ADCSEL_MASK) != adcsel) { + dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel, + *sample & WM97XX_ADCSEL_MASK); return RC_PENUP; } - if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) { + if (!(*sample & WM97XX_PEN_DOWN)) { wm->pen_probably_down = 0; return RC_PENUP; } @@ -386,18 +387,16 @@ static int wm9712_poll_touch(struct wm97xx *wm, struct wm97xx_data *data) if (rc != RC_VALID) return rc; } else { - rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, - &data->x); + rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_X, &data->x); if (rc != RC_VALID) return rc; - rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, - &data->y); + rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_Y, &data->y); if (rc != RC_VALID) return rc; if (pil && !five_wire) { - rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN, + rc = wm9712_poll_sample(wm, WM97XX_ADCSEL_PRES, &data->p); if (rc != RC_VALID) return rc; diff --git a/trunk/drivers/input/touchscreen/wm9713.c b/trunk/drivers/input/touchscreen/wm9713.c index 7405353199d7..73ec99568f12 100644 --- a/trunk/drivers/input/touchscreen/wm9713.c +++ b/trunk/drivers/input/touchscreen/wm9713.c @@ -261,9 +261,8 @@ static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample) { u16 dig1; int timeout = 5 * delay; - bool wants_pen = adcsel & WM97XX_PEN_DOWN; - if (wants_pen && !wm->pen_probably_down) { + if (!wm->pen_probably_down) { u16 data = wm97xx_reg_read(wm, AC97_WM97XX_DIGITISER_RD); if (!(data & WM97XX_PEN_DOWN)) return RC_PENUP; @@ -271,14 +270,15 @@ static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample) } /* set up digitiser */ + if (adcsel & 0x8000) + adcsel = 1 << ((adcsel & 0x7fff) + 3); + dig1 = wm97xx_reg_read(wm, AC97_WM9713_DIG1); dig1 &= ~WM9713_ADCSEL_MASK; - /* WM97XX_ADCSEL_* channels need to be converted to WM9713 format */ - dig1 |= 1 << ((adcsel & WM97XX_ADCSEL_MASK) >> 12); if (wm->mach_ops && wm->mach_ops->pre_sample) wm->mach_ops->pre_sample(adcsel); - wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | WM9713_POLL); + wm97xx_reg_write(wm, AC97_WM9713_DIG1, dig1 | adcsel | WM9713_POLL); /* wait 3 AC97 time slots + delay for conversion */ poll_delay(delay); @@ -304,14 +304,13 @@ static int wm9713_poll_sample(struct wm97xx *wm, int adcsel, int *sample) wm->mach_ops->post_sample(adcsel); /* check we have correct sample */ - if ((*sample ^ adcsel) & WM97XX_ADCSEL_MASK) { - dev_dbg(wm->dev, "adc wrong sample, wanted %x got %x", - adcsel & WM97XX_ADCSEL_MASK, - *sample & WM97XX_ADCSEL_MASK); + if ((*sample & WM97XX_ADCSRC_MASK) != ffs(adcsel >> 1) << 12) { + dev_dbg(wm->dev, "adc wrong sample, read %x got %x", adcsel, + *sample & WM97XX_ADCSRC_MASK); return RC_PENUP; } - if (wants_pen && !(*sample & WM97XX_PEN_DOWN)) { + if (!(*sample & WM97XX_PEN_DOWN)) { wm->pen_probably_down = 0; return RC_PENUP; } @@ -401,14 +400,14 @@ static int wm9713_poll_touch(struct wm97xx *wm, struct wm97xx_data *data) if (rc != RC_VALID) return rc; } else { - rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_X | WM97XX_PEN_DOWN, &data->x); + rc = wm9713_poll_sample(wm, WM9713_ADCSEL_X, &data->x); if (rc != RC_VALID) return rc; - rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_Y | WM97XX_PEN_DOWN, &data->y); + rc = wm9713_poll_sample(wm, WM9713_ADCSEL_Y, &data->y); if (rc != RC_VALID) return rc; if (pil) { - rc = wm9713_poll_sample(wm, WM97XX_ADCSEL_PRES | WM97XX_PEN_DOWN, + rc = wm9713_poll_sample(wm, WM9713_ADCSEL_PRES, &data->p); if (rc != RC_VALID) return rc; diff --git a/trunk/drivers/input/touchscreen/zylonite-wm97xx.c b/trunk/drivers/input/touchscreen/zylonite-wm97xx.c index f6328c0cded6..5b0f15ec874a 100644 --- a/trunk/drivers/input/touchscreen/zylonite-wm97xx.c +++ b/trunk/drivers/input/touchscreen/zylonite-wm97xx.c @@ -122,9 +122,9 @@ static int wm97xx_acc_pen_down(struct wm97xx *wm) x, y, p); /* are samples valid */ - if ((x & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_X || - (y & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_Y || - (p & WM97XX_ADCSEL_MASK) != WM97XX_ADCSEL_PRES) + if ((x & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_X || + (y & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_Y || + (p & WM97XX_ADCSRC_MASK) != WM97XX_ADCSEL_PRES) goto up; /* coordinate is good */ diff --git a/trunk/drivers/pci/pci-label.c b/trunk/drivers/pci/pci-label.c index 81525ae5d869..77cb2a14c896 100644 --- a/trunk/drivers/pci/pci-label.c +++ b/trunk/drivers/pci/pci-label.c @@ -55,7 +55,7 @@ enum smbios_attr_enum { SMBIOS_ATTR_INSTANCE_SHOW, }; -static size_t +static mode_t find_smbios_instance_string(struct pci_dev *pdev, char *buf, enum smbios_attr_enum attribute) { diff --git a/trunk/drivers/scsi/be2iscsi/be_main.h b/trunk/drivers/scsi/be2iscsi/be_main.h index 5ce5170254ca..081c171a1ed6 100644 --- a/trunk/drivers/scsi/be2iscsi/be_main.h +++ b/trunk/drivers/scsi/be2iscsi/be_main.h @@ -397,7 +397,7 @@ struct amap_pdu_data_out { }; struct be_cmd_bhs { - struct iscsi_scsi_req iscsi_hdr; + struct iscsi_cmd iscsi_hdr; unsigned char pad1[16]; struct pdu_data_out iscsi_data_pdu; unsigned char pad2[BE_SENSE_INFO_SIZE - @@ -428,7 +428,7 @@ struct be_nonio_bhs { }; struct be_status_bhs { - struct iscsi_scsi_req iscsi_hdr; + struct iscsi_cmd iscsi_hdr; unsigned char pad1[16]; /** * The plus 2 below is to hold the sense info length that gets diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c b/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c index 9ae80cd5953b..030a96c646c3 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_hwi.c @@ -332,11 +332,11 @@ int bnx2i_send_iscsi_login(struct bnx2i_conn *bnx2i_conn, { struct bnx2i_cmd *bnx2i_cmd; struct bnx2i_login_request *login_wqe; - struct iscsi_login_req *login_hdr; + struct iscsi_login *login_hdr; u32 dword; bnx2i_cmd = (struct bnx2i_cmd *)task->dd_data; - login_hdr = (struct iscsi_login_req *)task->hdr; + login_hdr = (struct iscsi_login *)task->hdr; login_wqe = (struct bnx2i_login_request *) bnx2i_conn->ep->qp.sq_prod_qe; @@ -1349,7 +1349,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, struct bnx2i_cmd_response *resp_cqe; struct bnx2i_cmd *bnx2i_cmd; struct iscsi_task *task; - struct iscsi_scsi_rsp *hdr; + struct iscsi_cmd_rsp *hdr; u32 datalen = 0; resp_cqe = (struct bnx2i_cmd_response *)cqe; @@ -1376,7 +1376,7 @@ int bnx2i_process_scsi_cmd_resp(struct iscsi_session *session, } bnx2i_iscsi_unmap_sg_list(bnx2i_cmd); - hdr = (struct iscsi_scsi_rsp *)task->hdr; + hdr = (struct iscsi_cmd_rsp *)task->hdr; resp_cqe = (struct bnx2i_cmd_response *)cqe; hdr->opcode = resp_cqe->op_code; hdr->max_cmdsn = cpu_to_be32(resp_cqe->max_cmd_sn); diff --git a/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c b/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c index cffd4d75df56..5c55a75ae597 100644 --- a/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c +++ b/trunk/drivers/scsi/bnx2i/bnx2i_iscsi.c @@ -1213,7 +1213,7 @@ static int bnx2i_task_xmit(struct iscsi_task *task) struct bnx2i_conn *bnx2i_conn = conn->dd_data; struct scsi_cmnd *sc = task->sc; struct bnx2i_cmd *cmd = task->dd_data; - struct iscsi_scsi_req *hdr = (struct iscsi_scsi_req *)task->hdr; + struct iscsi_cmd *hdr = (struct iscsi_cmd *) task->hdr; if (atomic_read(&bnx2i_conn->ep->num_active_cmds) + 1 > hba->max_sqes) diff --git a/trunk/drivers/scsi/libiscsi.c b/trunk/drivers/scsi/libiscsi.c index 256a999d010b..d7a4120034a2 100644 --- a/trunk/drivers/scsi/libiscsi.c +++ b/trunk/drivers/scsi/libiscsi.c @@ -84,6 +84,22 @@ MODULE_PARM_DESC(debug_libiscsi_eh, __func__, ##arg); \ } while (0); +/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ +#define SNA32_CHECK 2147483648UL + +static int iscsi_sna_lt(u32 n1, u32 n2) +{ + return n1 != n2 && ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) || + (n1 > n2 && (n2 - n1 < SNA32_CHECK))); +} + +/* Serial Number Arithmetic, 32 bits, less than, RFC1982 */ +static int iscsi_sna_lte(u32 n1, u32 n2) +{ + return n1 == n2 || ((n1 < n2 && (n2 - n1 < SNA32_CHECK)) || + (n1 > n2 && (n2 - n1 < SNA32_CHECK))); +} + inline void iscsi_conn_queue_work(struct iscsi_conn *conn) { struct Scsi_Host *shost = conn->session->host; @@ -344,7 +360,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) struct iscsi_conn *conn = task->conn; struct iscsi_session *session = conn->session; struct scsi_cmnd *sc = task->sc; - struct iscsi_scsi_req *hdr; + struct iscsi_cmd *hdr; unsigned hdrlength, cmd_len; itt_t itt; int rc; @@ -358,7 +374,7 @@ static int iscsi_prep_scsi_cmd_pdu(struct iscsi_task *task) if (rc) return rc; } - hdr = (struct iscsi_scsi_req *)task->hdr; + hdr = (struct iscsi_cmd *) task->hdr; itt = hdr->itt; memset(hdr, 0, sizeof(*hdr)); @@ -814,7 +830,7 @@ static void iscsi_scsi_cmd_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr, struct iscsi_task *task, char *data, int datalen) { - struct iscsi_scsi_rsp *rhdr = (struct iscsi_scsi_rsp *)hdr; + struct iscsi_cmd_rsp *rhdr = (struct iscsi_cmd_rsp *)hdr; struct iscsi_session *session = conn->session; struct scsi_cmnd *sc = task->sc; diff --git a/trunk/drivers/staging/brcm80211/brcmsmac/mac80211_if.h b/trunk/drivers/staging/brcm80211/brcmsmac/mac80211_if.h index 40e3d375ea99..5711e7c16b50 100644 --- a/trunk/drivers/staging/brcm80211/brcmsmac/mac80211_if.h +++ b/trunk/drivers/staging/brcm80211/brcmsmac/mac80211_if.h @@ -24,6 +24,8 @@ #define BRCMS_SET_SHORTSLOT_OVERRIDE 146 +#include + /* BMAC Note: High-only driver is no longer working in softirq context as it needs to block and * sleep so perimeter lock has to be a semaphore instead of spinlock. This requires timers to be * submitted to workqueue instead of being on kernel timer diff --git a/trunk/drivers/target/Kconfig b/trunk/drivers/target/Kconfig index b28794b72125..5cb0f0ef6af0 100644 --- a/trunk/drivers/target/Kconfig +++ b/trunk/drivers/target/Kconfig @@ -31,6 +31,5 @@ config TCM_PSCSI source "drivers/target/loopback/Kconfig" source "drivers/target/tcm_fc/Kconfig" -source "drivers/target/iscsi/Kconfig" endif diff --git a/trunk/drivers/target/Makefile b/trunk/drivers/target/Makefile index 1060c7b7f803..21df808a992c 100644 --- a/trunk/drivers/target/Makefile +++ b/trunk/drivers/target/Makefile @@ -24,5 +24,5 @@ obj-$(CONFIG_TCM_PSCSI) += target_core_pscsi.o # Fabric modules obj-$(CONFIG_LOOPBACK_TARGET) += loopback/ + obj-$(CONFIG_TCM_FC) += tcm_fc/ -obj-$(CONFIG_ISCSI_TARGET) += iscsi/ diff --git a/trunk/drivers/target/iscsi/Kconfig b/trunk/drivers/target/iscsi/Kconfig deleted file mode 100644 index 564ff4e0dbc4..000000000000 --- a/trunk/drivers/target/iscsi/Kconfig +++ /dev/null @@ -1,8 +0,0 @@ -config ISCSI_TARGET - tristate "Linux-iSCSI.org iSCSI Target Mode Stack" - select CRYPTO - select CRYPTO_CRC32C - select CRYPTO_CRC32C_INTEL if X86 - help - Say M here to enable the ConfigFS enabled Linux-iSCSI.org iSCSI - Target Mode Stack. diff --git a/trunk/drivers/target/iscsi/Makefile b/trunk/drivers/target/iscsi/Makefile deleted file mode 100644 index 5b9a2cf7f0a9..000000000000 --- a/trunk/drivers/target/iscsi/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -iscsi_target_mod-y += iscsi_target_parameters.o \ - iscsi_target_seq_pdu_list.o \ - iscsi_target_tq.o \ - iscsi_target_auth.o \ - iscsi_target_datain_values.o \ - iscsi_target_device.o \ - iscsi_target_erl0.o \ - iscsi_target_erl1.o \ - iscsi_target_erl2.o \ - iscsi_target_login.o \ - iscsi_target_nego.o \ - iscsi_target_nodeattrib.o \ - iscsi_target_tmr.o \ - iscsi_target_tpg.o \ - iscsi_target_util.o \ - iscsi_target.o \ - iscsi_target_configfs.o \ - iscsi_target_stat.o - -obj-$(CONFIG_ISCSI_TARGET) += iscsi_target_mod.o diff --git a/trunk/drivers/target/iscsi/iscsi_target.c b/trunk/drivers/target/iscsi/iscsi_target.c deleted file mode 100644 index 14c81c4265bd..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target.c +++ /dev/null @@ -1,4559 +0,0 @@ -/******************************************************************************* - * This file contains main functions related to the iSCSI Target Core Driver. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_parameters.h" -#include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_tq.h" -#include "iscsi_target_configfs.h" -#include "iscsi_target_datain_values.h" -#include "iscsi_target_erl0.h" -#include "iscsi_target_erl1.h" -#include "iscsi_target_erl2.h" -#include "iscsi_target_login.h" -#include "iscsi_target_tmr.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_util.h" -#include "iscsi_target.h" -#include "iscsi_target_device.h" -#include "iscsi_target_stat.h" - -static LIST_HEAD(g_tiqn_list); -static LIST_HEAD(g_np_list); -static DEFINE_SPINLOCK(tiqn_lock); -static DEFINE_SPINLOCK(np_lock); - -static struct idr tiqn_idr; -struct idr sess_idr; -struct mutex auth_id_lock; -spinlock_t sess_idr_lock; - -struct iscsit_global *iscsit_global; - -struct kmem_cache *lio_cmd_cache; -struct kmem_cache *lio_qr_cache; -struct kmem_cache *lio_dr_cache; -struct kmem_cache *lio_ooo_cache; -struct kmem_cache *lio_r2t_cache; - -static int iscsit_handle_immediate_data(struct iscsi_cmd *, - unsigned char *buf, u32); -static int iscsit_logout_post_handler(struct iscsi_cmd *, struct iscsi_conn *); - -struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *buf) -{ - struct iscsi_tiqn *tiqn = NULL; - - spin_lock(&tiqn_lock); - list_for_each_entry(tiqn, &g_tiqn_list, tiqn_list) { - if (!strcmp(tiqn->tiqn, buf)) { - - spin_lock(&tiqn->tiqn_state_lock); - if (tiqn->tiqn_state == TIQN_STATE_ACTIVE) { - tiqn->tiqn_access_count++; - spin_unlock(&tiqn->tiqn_state_lock); - spin_unlock(&tiqn_lock); - return tiqn; - } - spin_unlock(&tiqn->tiqn_state_lock); - } - } - spin_unlock(&tiqn_lock); - - return NULL; -} - -static int iscsit_set_tiqn_shutdown(struct iscsi_tiqn *tiqn) -{ - spin_lock(&tiqn->tiqn_state_lock); - if (tiqn->tiqn_state == TIQN_STATE_ACTIVE) { - tiqn->tiqn_state = TIQN_STATE_SHUTDOWN; - spin_unlock(&tiqn->tiqn_state_lock); - return 0; - } - spin_unlock(&tiqn->tiqn_state_lock); - - return -1; -} - -void iscsit_put_tiqn_for_login(struct iscsi_tiqn *tiqn) -{ - spin_lock(&tiqn->tiqn_state_lock); - tiqn->tiqn_access_count--; - spin_unlock(&tiqn->tiqn_state_lock); -} - -/* - * Note that IQN formatting is expected to be done in userspace, and - * no explict IQN format checks are done here. - */ -struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *buf) -{ - struct iscsi_tiqn *tiqn = NULL; - int ret; - - if (strlen(buf) > ISCSI_IQN_LEN) { - pr_err("Target IQN exceeds %d bytes\n", - ISCSI_IQN_LEN); - return ERR_PTR(-EINVAL); - } - - tiqn = kzalloc(sizeof(struct iscsi_tiqn), GFP_KERNEL); - if (!tiqn) { - pr_err("Unable to allocate struct iscsi_tiqn\n"); - return ERR_PTR(-ENOMEM); - } - - sprintf(tiqn->tiqn, "%s", buf); - INIT_LIST_HEAD(&tiqn->tiqn_list); - INIT_LIST_HEAD(&tiqn->tiqn_tpg_list); - spin_lock_init(&tiqn->tiqn_state_lock); - spin_lock_init(&tiqn->tiqn_tpg_lock); - spin_lock_init(&tiqn->sess_err_stats.lock); - spin_lock_init(&tiqn->login_stats.lock); - spin_lock_init(&tiqn->logout_stats.lock); - - if (!idr_pre_get(&tiqn_idr, GFP_KERNEL)) { - pr_err("idr_pre_get() for tiqn_idr failed\n"); - kfree(tiqn); - return ERR_PTR(-ENOMEM); - } - tiqn->tiqn_state = TIQN_STATE_ACTIVE; - - spin_lock(&tiqn_lock); - ret = idr_get_new(&tiqn_idr, NULL, &tiqn->tiqn_index); - if (ret < 0) { - pr_err("idr_get_new() failed for tiqn->tiqn_index\n"); - spin_unlock(&tiqn_lock); - kfree(tiqn); - return ERR_PTR(ret); - } - list_add_tail(&tiqn->tiqn_list, &g_tiqn_list); - spin_unlock(&tiqn_lock); - - pr_debug("CORE[0] - Added iSCSI Target IQN: %s\n", tiqn->tiqn); - - return tiqn; - -} - -static void iscsit_wait_for_tiqn(struct iscsi_tiqn *tiqn) -{ - /* - * Wait for accesses to said struct iscsi_tiqn to end. - */ - spin_lock(&tiqn->tiqn_state_lock); - while (tiqn->tiqn_access_count != 0) { - spin_unlock(&tiqn->tiqn_state_lock); - msleep(10); - spin_lock(&tiqn->tiqn_state_lock); - } - spin_unlock(&tiqn->tiqn_state_lock); -} - -void iscsit_del_tiqn(struct iscsi_tiqn *tiqn) -{ - /* - * iscsit_set_tiqn_shutdown sets tiqn->tiqn_state = TIQN_STATE_SHUTDOWN - * while holding tiqn->tiqn_state_lock. This means that all subsequent - * attempts to access this struct iscsi_tiqn will fail from both transport - * fabric and control code paths. - */ - if (iscsit_set_tiqn_shutdown(tiqn) < 0) { - pr_err("iscsit_set_tiqn_shutdown() failed\n"); - return; - } - - iscsit_wait_for_tiqn(tiqn); - - spin_lock(&tiqn_lock); - list_del(&tiqn->tiqn_list); - idr_remove(&tiqn_idr, tiqn->tiqn_index); - spin_unlock(&tiqn_lock); - - pr_debug("CORE[0] - Deleted iSCSI Target IQN: %s\n", - tiqn->tiqn); - kfree(tiqn); -} - -int iscsit_access_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) -{ - int ret; - /* - * Determine if the network portal is accepting storage traffic. - */ - spin_lock_bh(&np->np_thread_lock); - if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { - spin_unlock_bh(&np->np_thread_lock); - return -1; - } - if (np->np_login_tpg) { - pr_err("np->np_login_tpg() is not NULL!\n"); - spin_unlock_bh(&np->np_thread_lock); - return -1; - } - spin_unlock_bh(&np->np_thread_lock); - /* - * Determine if the portal group is accepting storage traffic. - */ - spin_lock_bh(&tpg->tpg_state_lock); - if (tpg->tpg_state != TPG_STATE_ACTIVE) { - spin_unlock_bh(&tpg->tpg_state_lock); - return -1; - } - spin_unlock_bh(&tpg->tpg_state_lock); - - /* - * Here we serialize access across the TIQN+TPG Tuple. - */ - ret = mutex_lock_interruptible(&tpg->np_login_lock); - if ((ret != 0) || signal_pending(current)) - return -1; - - spin_lock_bh(&np->np_thread_lock); - np->np_login_tpg = tpg; - spin_unlock_bh(&np->np_thread_lock); - - return 0; -} - -int iscsit_deaccess_np(struct iscsi_np *np, struct iscsi_portal_group *tpg) -{ - struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; - - spin_lock_bh(&np->np_thread_lock); - np->np_login_tpg = NULL; - spin_unlock_bh(&np->np_thread_lock); - - mutex_unlock(&tpg->np_login_lock); - - if (tiqn) - iscsit_put_tiqn_for_login(tiqn); - - return 0; -} - -static struct iscsi_np *iscsit_get_np( - struct __kernel_sockaddr_storage *sockaddr, - int network_transport) -{ - struct sockaddr_in *sock_in, *sock_in_e; - struct sockaddr_in6 *sock_in6, *sock_in6_e; - struct iscsi_np *np; - int ip_match = 0; - u16 port; - - spin_lock_bh(&np_lock); - list_for_each_entry(np, &g_np_list, np_list) { - spin_lock(&np->np_thread_lock); - if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { - spin_unlock(&np->np_thread_lock); - continue; - } - - if (sockaddr->ss_family == AF_INET6) { - sock_in6 = (struct sockaddr_in6 *)sockaddr; - sock_in6_e = (struct sockaddr_in6 *)&np->np_sockaddr; - - if (!memcmp((void *)&sock_in6->sin6_addr.in6_u, - (void *)&sock_in6_e->sin6_addr.in6_u, - sizeof(struct in6_addr))) - ip_match = 1; - - port = ntohs(sock_in6->sin6_port); - } else { - sock_in = (struct sockaddr_in *)sockaddr; - sock_in_e = (struct sockaddr_in *)&np->np_sockaddr; - - if (sock_in->sin_addr.s_addr == - sock_in_e->sin_addr.s_addr) - ip_match = 1; - - port = ntohs(sock_in->sin_port); - } - - if ((ip_match == 1) && (np->np_port == port) && - (np->np_network_transport == network_transport)) { - /* - * Increment the np_exports reference count now to - * prevent iscsit_del_np() below from being called - * while iscsi_tpg_add_network_portal() is called. - */ - np->np_exports++; - spin_unlock(&np->np_thread_lock); - spin_unlock_bh(&np_lock); - return np; - } - spin_unlock(&np->np_thread_lock); - } - spin_unlock_bh(&np_lock); - - return NULL; -} - -struct iscsi_np *iscsit_add_np( - struct __kernel_sockaddr_storage *sockaddr, - char *ip_str, - int network_transport) -{ - struct sockaddr_in *sock_in; - struct sockaddr_in6 *sock_in6; - struct iscsi_np *np; - int ret; - /* - * Locate the existing struct iscsi_np if already active.. - */ - np = iscsit_get_np(sockaddr, network_transport); - if (np) - return np; - - np = kzalloc(sizeof(struct iscsi_np), GFP_KERNEL); - if (!np) { - pr_err("Unable to allocate memory for struct iscsi_np\n"); - return ERR_PTR(-ENOMEM); - } - - np->np_flags |= NPF_IP_NETWORK; - if (sockaddr->ss_family == AF_INET6) { - sock_in6 = (struct sockaddr_in6 *)sockaddr; - snprintf(np->np_ip, IPV6_ADDRESS_SPACE, "%s", ip_str); - np->np_port = ntohs(sock_in6->sin6_port); - } else { - sock_in = (struct sockaddr_in *)sockaddr; - sprintf(np->np_ip, "%s", ip_str); - np->np_port = ntohs(sock_in->sin_port); - } - - np->np_network_transport = network_transport; - spin_lock_init(&np->np_thread_lock); - init_completion(&np->np_restart_comp); - INIT_LIST_HEAD(&np->np_list); - - ret = iscsi_target_setup_login_socket(np, sockaddr); - if (ret != 0) { - kfree(np); - return ERR_PTR(ret); - } - - np->np_thread = kthread_run(iscsi_target_login_thread, np, "iscsi_np"); - if (IS_ERR(np->np_thread)) { - pr_err("Unable to create kthread: iscsi_np\n"); - ret = PTR_ERR(np->np_thread); - kfree(np); - return ERR_PTR(ret); - } - /* - * Increment the np_exports reference count now to prevent - * iscsit_del_np() below from being run while a new call to - * iscsi_tpg_add_network_portal() for a matching iscsi_np is - * active. We don't need to hold np->np_thread_lock at this - * point because iscsi_np has not been added to g_np_list yet. - */ - np->np_exports = 1; - - spin_lock_bh(&np_lock); - list_add_tail(&np->np_list, &g_np_list); - spin_unlock_bh(&np_lock); - - pr_debug("CORE[0] - Added Network Portal: %s:%hu on %s\n", - np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ? - "TCP" : "SCTP"); - - return np; -} - -int iscsit_reset_np_thread( - struct iscsi_np *np, - struct iscsi_tpg_np *tpg_np, - struct iscsi_portal_group *tpg) -{ - spin_lock_bh(&np->np_thread_lock); - if (tpg && tpg_np) { - /* - * The reset operation need only be performed when the - * passed struct iscsi_portal_group has a login in progress - * to one of the network portals. - */ - if (tpg_np->tpg_np->np_login_tpg != tpg) { - spin_unlock_bh(&np->np_thread_lock); - return 0; - } - } - if (np->np_thread_state == ISCSI_NP_THREAD_INACTIVE) { - spin_unlock_bh(&np->np_thread_lock); - return 0; - } - np->np_thread_state = ISCSI_NP_THREAD_RESET; - - if (np->np_thread) { - spin_unlock_bh(&np->np_thread_lock); - send_sig(SIGINT, np->np_thread, 1); - wait_for_completion(&np->np_restart_comp); - spin_lock_bh(&np->np_thread_lock); - } - spin_unlock_bh(&np->np_thread_lock); - - return 0; -} - -int iscsit_del_np_comm(struct iscsi_np *np) -{ - if (!np->np_socket) - return 0; - - /* - * Some network transports allocate their own struct sock->file, - * see if we need to free any additional allocated resources. - */ - if (np->np_flags & NPF_SCTP_STRUCT_FILE) { - kfree(np->np_socket->file); - np->np_socket->file = NULL; - } - - sock_release(np->np_socket); - return 0; -} - -int iscsit_del_np(struct iscsi_np *np) -{ - spin_lock_bh(&np->np_thread_lock); - np->np_exports--; - if (np->np_exports) { - spin_unlock_bh(&np->np_thread_lock); - return 0; - } - np->np_thread_state = ISCSI_NP_THREAD_SHUTDOWN; - spin_unlock_bh(&np->np_thread_lock); - - if (np->np_thread) { - /* - * We need to send the signal to wakeup Linux/Net - * which may be sleeping in sock_accept().. - */ - send_sig(SIGINT, np->np_thread, 1); - kthread_stop(np->np_thread); - } - iscsit_del_np_comm(np); - - spin_lock_bh(&np_lock); - list_del(&np->np_list); - spin_unlock_bh(&np_lock); - - pr_debug("CORE[0] - Removed Network Portal: %s:%hu on %s\n", - np->np_ip, np->np_port, (np->np_network_transport == ISCSI_TCP) ? - "TCP" : "SCTP"); - - kfree(np); - return 0; -} - -static int __init iscsi_target_init_module(void) -{ - int ret = 0; - - pr_debug("iSCSI-Target "ISCSIT_VERSION"\n"); - - iscsit_global = kzalloc(sizeof(struct iscsit_global), GFP_KERNEL); - if (!iscsit_global) { - pr_err("Unable to allocate memory for iscsit_global\n"); - return -1; - } - mutex_init(&auth_id_lock); - spin_lock_init(&sess_idr_lock); - idr_init(&tiqn_idr); - idr_init(&sess_idr); - - ret = iscsi_target_register_configfs(); - if (ret < 0) - goto out; - - ret = iscsi_thread_set_init(); - if (ret < 0) - goto configfs_out; - - if (iscsi_allocate_thread_sets(TARGET_THREAD_SET_COUNT) != - TARGET_THREAD_SET_COUNT) { - pr_err("iscsi_allocate_thread_sets() returned" - " unexpected value!\n"); - goto ts_out1; - } - - lio_cmd_cache = kmem_cache_create("lio_cmd_cache", - sizeof(struct iscsi_cmd), __alignof__(struct iscsi_cmd), - 0, NULL); - if (!lio_cmd_cache) { - pr_err("Unable to kmem_cache_create() for" - " lio_cmd_cache\n"); - goto ts_out2; - } - - lio_qr_cache = kmem_cache_create("lio_qr_cache", - sizeof(struct iscsi_queue_req), - __alignof__(struct iscsi_queue_req), 0, NULL); - if (!lio_qr_cache) { - pr_err("nable to kmem_cache_create() for" - " lio_qr_cache\n"); - goto cmd_out; - } - - lio_dr_cache = kmem_cache_create("lio_dr_cache", - sizeof(struct iscsi_datain_req), - __alignof__(struct iscsi_datain_req), 0, NULL); - if (!lio_dr_cache) { - pr_err("Unable to kmem_cache_create() for" - " lio_dr_cache\n"); - goto qr_out; - } - - lio_ooo_cache = kmem_cache_create("lio_ooo_cache", - sizeof(struct iscsi_ooo_cmdsn), - __alignof__(struct iscsi_ooo_cmdsn), 0, NULL); - if (!lio_ooo_cache) { - pr_err("Unable to kmem_cache_create() for" - " lio_ooo_cache\n"); - goto dr_out; - } - - lio_r2t_cache = kmem_cache_create("lio_r2t_cache", - sizeof(struct iscsi_r2t), __alignof__(struct iscsi_r2t), - 0, NULL); - if (!lio_r2t_cache) { - pr_err("Unable to kmem_cache_create() for" - " lio_r2t_cache\n"); - goto ooo_out; - } - - if (iscsit_load_discovery_tpg() < 0) - goto r2t_out; - - return ret; -r2t_out: - kmem_cache_destroy(lio_r2t_cache); -ooo_out: - kmem_cache_destroy(lio_ooo_cache); -dr_out: - kmem_cache_destroy(lio_dr_cache); -qr_out: - kmem_cache_destroy(lio_qr_cache); -cmd_out: - kmem_cache_destroy(lio_cmd_cache); -ts_out2: - iscsi_deallocate_thread_sets(); -ts_out1: - iscsi_thread_set_free(); -configfs_out: - iscsi_target_deregister_configfs(); -out: - kfree(iscsit_global); - return -ENOMEM; -} - -static void __exit iscsi_target_cleanup_module(void) -{ - iscsi_deallocate_thread_sets(); - iscsi_thread_set_free(); - iscsit_release_discovery_tpg(); - kmem_cache_destroy(lio_cmd_cache); - kmem_cache_destroy(lio_qr_cache); - kmem_cache_destroy(lio_dr_cache); - kmem_cache_destroy(lio_ooo_cache); - kmem_cache_destroy(lio_r2t_cache); - - iscsi_target_deregister_configfs(); - - kfree(iscsit_global); -} - -int iscsit_add_reject( - u8 reason, - int fail_conn, - unsigned char *buf, - struct iscsi_conn *conn) -{ - struct iscsi_cmd *cmd; - struct iscsi_reject *hdr; - int ret; - - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); - if (!cmd) - return -1; - - cmd->iscsi_opcode = ISCSI_OP_REJECT; - if (fail_conn) - cmd->cmd_flags |= ICF_REJECT_FAIL_CONN; - - hdr = (struct iscsi_reject *) cmd->pdu; - hdr->reason = reason; - - cmd->buf_ptr = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); - if (!cmd->buf_ptr) { - pr_err("Unable to allocate memory for cmd->buf_ptr\n"); - iscsit_release_cmd(cmd); - return -1; - } - memcpy(cmd->buf_ptr, buf, ISCSI_HDR_LEN); - - spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); - spin_unlock_bh(&conn->cmd_lock); - - cmd->i_state = ISTATE_SEND_REJECT; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - - ret = wait_for_completion_interruptible(&cmd->reject_comp); - if (ret != 0) - return -1; - - return (!fail_conn) ? 0 : -1; -} - -int iscsit_add_reject_from_cmd( - u8 reason, - int fail_conn, - int add_to_conn, - unsigned char *buf, - struct iscsi_cmd *cmd) -{ - struct iscsi_conn *conn; - struct iscsi_reject *hdr; - int ret; - - if (!cmd->conn) { - pr_err("cmd->conn is NULL for ITT: 0x%08x\n", - cmd->init_task_tag); - return -1; - } - conn = cmd->conn; - - cmd->iscsi_opcode = ISCSI_OP_REJECT; - if (fail_conn) - cmd->cmd_flags |= ICF_REJECT_FAIL_CONN; - - hdr = (struct iscsi_reject *) cmd->pdu; - hdr->reason = reason; - - cmd->buf_ptr = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); - if (!cmd->buf_ptr) { - pr_err("Unable to allocate memory for cmd->buf_ptr\n"); - iscsit_release_cmd(cmd); - return -1; - } - memcpy(cmd->buf_ptr, buf, ISCSI_HDR_LEN); - - if (add_to_conn) { - spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); - spin_unlock_bh(&conn->cmd_lock); - } - - cmd->i_state = ISTATE_SEND_REJECT; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - - ret = wait_for_completion_interruptible(&cmd->reject_comp); - if (ret != 0) - return -1; - - return (!fail_conn) ? 0 : -1; -} - -/* - * Map some portion of the allocated scatterlist to an iovec, suitable for - * kernel sockets to copy data in/out. This handles both pages and slab-allocated - * buffers, since we have been tricky and mapped t_mem_sg to the buffer in - * either case (see iscsit_alloc_buffs) - */ -static int iscsit_map_iovec( - struct iscsi_cmd *cmd, - struct kvec *iov, - u32 data_offset, - u32 data_length) -{ - u32 i = 0; - struct scatterlist *sg; - unsigned int page_off; - - /* - * We have a private mapping of the allocated pages in t_mem_sg. - * At this point, we also know each contains a page. - */ - sg = &cmd->t_mem_sg[data_offset / PAGE_SIZE]; - page_off = (data_offset % PAGE_SIZE); - - cmd->first_data_sg = sg; - cmd->first_data_sg_off = page_off; - - while (data_length) { - u32 cur_len = min_t(u32, data_length, sg->length - page_off); - - iov[i].iov_base = kmap(sg_page(sg)) + sg->offset + page_off; - iov[i].iov_len = cur_len; - - data_length -= cur_len; - page_off = 0; - sg = sg_next(sg); - i++; - } - - cmd->kmapped_nents = i; - - return i; -} - -static void iscsit_unmap_iovec(struct iscsi_cmd *cmd) -{ - u32 i; - struct scatterlist *sg; - - sg = cmd->first_data_sg; - - for (i = 0; i < cmd->kmapped_nents; i++) - kunmap(sg_page(&sg[i])); -} - -static void iscsit_ack_from_expstatsn(struct iscsi_conn *conn, u32 exp_statsn) -{ - struct iscsi_cmd *cmd; - - conn->exp_statsn = exp_statsn; - - spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { - spin_lock(&cmd->istate_lock); - if ((cmd->i_state == ISTATE_SENT_STATUS) && - (cmd->stat_sn < exp_statsn)) { - cmd->i_state = ISTATE_REMOVE; - spin_unlock(&cmd->istate_lock); - iscsit_add_cmd_to_immediate_queue(cmd, conn, - cmd->i_state); - continue; - } - spin_unlock(&cmd->istate_lock); - } - spin_unlock_bh(&conn->cmd_lock); -} - -static int iscsit_allocate_iovecs(struct iscsi_cmd *cmd) -{ - u32 iov_count = (cmd->se_cmd.t_data_nents == 0) ? 1 : - cmd->se_cmd.t_data_nents; - - iov_count += TRANSPORT_IOV_DATA_BUFFER; - - cmd->iov_data = kzalloc(iov_count * sizeof(struct kvec), GFP_KERNEL); - if (!cmd->iov_data) { - pr_err("Unable to allocate cmd->iov_data\n"); - return -ENOMEM; - } - - cmd->orig_iov_data_count = iov_count; - return 0; -} - -static int iscsit_alloc_buffs(struct iscsi_cmd *cmd) -{ - struct scatterlist *sgl; - u32 length = cmd->se_cmd.data_length; - int nents = DIV_ROUND_UP(length, PAGE_SIZE); - int i = 0, ret; - /* - * If no SCSI payload is present, allocate the default iovecs used for - * iSCSI PDU Header - */ - if (!length) - return iscsit_allocate_iovecs(cmd); - - sgl = kzalloc(sizeof(*sgl) * nents, GFP_KERNEL); - if (!sgl) - return -ENOMEM; - - sg_init_table(sgl, nents); - - while (length) { - int buf_size = min_t(int, length, PAGE_SIZE); - struct page *page; - - page = alloc_page(GFP_KERNEL | __GFP_ZERO); - if (!page) - goto page_alloc_failed; - - sg_set_page(&sgl[i], page, buf_size, 0); - - length -= buf_size; - i++; - } - - cmd->t_mem_sg = sgl; - cmd->t_mem_sg_nents = nents; - - /* BIDI ops not supported */ - - /* Tell the core about our preallocated memory */ - transport_generic_map_mem_to_cmd(&cmd->se_cmd, sgl, nents, NULL, 0); - /* - * Allocate iovecs for SCSI payload after transport_generic_map_mem_to_cmd - * so that cmd->se_cmd.t_tasks_se_num has been set. - */ - ret = iscsit_allocate_iovecs(cmd); - if (ret < 0) - goto page_alloc_failed; - - return 0; - -page_alloc_failed: - while (i >= 0) { - __free_page(sg_page(&sgl[i])); - i--; - } - kfree(cmd->t_mem_sg); - cmd->t_mem_sg = NULL; - return -ENOMEM; -} - -static int iscsit_handle_scsi_cmd( - struct iscsi_conn *conn, - unsigned char *buf) -{ - int data_direction, cmdsn_ret = 0, immed_ret, ret, transport_ret; - int dump_immediate_data = 0, send_check_condition = 0, payload_length; - struct iscsi_cmd *cmd = NULL; - struct iscsi_scsi_req *hdr; - - spin_lock_bh(&conn->sess->session_stats_lock); - conn->sess->cmd_pdus++; - if (conn->sess->se_sess->se_node_acl) { - spin_lock(&conn->sess->se_sess->se_node_acl->stats_lock); - conn->sess->se_sess->se_node_acl->num_cmds++; - spin_unlock(&conn->sess->se_sess->se_node_acl->stats_lock); - } - spin_unlock_bh(&conn->sess->session_stats_lock); - - hdr = (struct iscsi_scsi_req *) buf; - payload_length = ntoh24(hdr->dlength); - hdr->itt = be32_to_cpu(hdr->itt); - hdr->data_length = be32_to_cpu(hdr->data_length); - hdr->cmdsn = be32_to_cpu(hdr->cmdsn); - hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn); - - /* FIXME; Add checks for AdditionalHeaderSegment */ - - if (!(hdr->flags & ISCSI_FLAG_CMD_WRITE) && - !(hdr->flags & ISCSI_FLAG_CMD_FINAL)) { - pr_err("ISCSI_FLAG_CMD_WRITE & ISCSI_FLAG_CMD_FINAL" - " not set. Bad iSCSI Initiator.\n"); - return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, - buf, conn); - } - - if (((hdr->flags & ISCSI_FLAG_CMD_READ) || - (hdr->flags & ISCSI_FLAG_CMD_WRITE)) && !hdr->data_length) { - /* - * Vmware ESX v3.0 uses a modified Cisco Initiator (v3.4.2) - * that adds support for RESERVE/RELEASE. There is a bug - * add with this new functionality that sets R/W bits when - * neither CDB carries any READ or WRITE datapayloads. - */ - if ((hdr->cdb[0] == 0x16) || (hdr->cdb[0] == 0x17)) { - hdr->flags &= ~ISCSI_FLAG_CMD_READ; - hdr->flags &= ~ISCSI_FLAG_CMD_WRITE; - goto done; - } - - pr_err("ISCSI_FLAG_CMD_READ or ISCSI_FLAG_CMD_WRITE" - " set when Expected Data Transfer Length is 0 for" - " CDB: 0x%02x. Bad iSCSI Initiator.\n", hdr->cdb[0]); - return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, - buf, conn); - } -done: - - if (!(hdr->flags & ISCSI_FLAG_CMD_READ) && - !(hdr->flags & ISCSI_FLAG_CMD_WRITE) && (hdr->data_length != 0)) { - pr_err("ISCSI_FLAG_CMD_READ and/or ISCSI_FLAG_CMD_WRITE" - " MUST be set if Expected Data Transfer Length is not 0." - " Bad iSCSI Initiator\n"); - return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, - buf, conn); - } - - if ((hdr->flags & ISCSI_FLAG_CMD_READ) && - (hdr->flags & ISCSI_FLAG_CMD_WRITE)) { - pr_err("Bidirectional operations not supported!\n"); - return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, - buf, conn); - } - - if (hdr->opcode & ISCSI_OP_IMMEDIATE) { - pr_err("Illegally set Immediate Bit in iSCSI Initiator" - " Scsi Command PDU.\n"); - return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, - buf, conn); - } - - if (payload_length && !conn->sess->sess_ops->ImmediateData) { - pr_err("ImmediateData=No but DataSegmentLength=%u," - " protocol error.\n", payload_length); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - - if ((hdr->data_length == payload_length) && - (!(hdr->flags & ISCSI_FLAG_CMD_FINAL))) { - pr_err("Expected Data Transfer Length and Length of" - " Immediate Data are the same, but ISCSI_FLAG_CMD_FINAL" - " bit is not set protocol error\n"); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - - if (payload_length > hdr->data_length) { - pr_err("DataSegmentLength: %u is greater than" - " EDTL: %u, protocol error.\n", payload_length, - hdr->data_length); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - - if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) { - pr_err("DataSegmentLength: %u is greater than" - " MaxRecvDataSegmentLength: %u, protocol error.\n", - payload_length, conn->conn_ops->MaxRecvDataSegmentLength); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - - if (payload_length > conn->sess->sess_ops->FirstBurstLength) { - pr_err("DataSegmentLength: %u is greater than" - " FirstBurstLength: %u, protocol error.\n", - payload_length, conn->sess->sess_ops->FirstBurstLength); - return iscsit_add_reject(ISCSI_REASON_BOOKMARK_INVALID, 1, - buf, conn); - } - - data_direction = (hdr->flags & ISCSI_FLAG_CMD_WRITE) ? DMA_TO_DEVICE : - (hdr->flags & ISCSI_FLAG_CMD_READ) ? DMA_FROM_DEVICE : - DMA_NONE; - - cmd = iscsit_allocate_se_cmd(conn, hdr->data_length, data_direction, - (hdr->flags & ISCSI_FLAG_CMD_ATTR_MASK)); - if (!cmd) - return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1, - buf, conn); - - pr_debug("Got SCSI Command, ITT: 0x%08x, CmdSN: 0x%08x," - " ExpXferLen: %u, Length: %u, CID: %hu\n", hdr->itt, - hdr->cmdsn, hdr->data_length, payload_length, conn->cid); - - cmd->iscsi_opcode = ISCSI_OP_SCSI_CMD; - cmd->i_state = ISTATE_NEW_CMD; - cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0); - cmd->immediate_data = (payload_length) ? 1 : 0; - cmd->unsolicited_data = ((!(hdr->flags & ISCSI_FLAG_CMD_FINAL) && - (hdr->flags & ISCSI_FLAG_CMD_WRITE)) ? 1 : 0); - if (cmd->unsolicited_data) - cmd->cmd_flags |= ICF_NON_IMMEDIATE_UNSOLICITED_DATA; - - conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt; - if (hdr->flags & ISCSI_FLAG_CMD_READ) { - spin_lock_bh(&conn->sess->ttt_lock); - cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++; - if (cmd->targ_xfer_tag == 0xFFFFFFFF) - cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++; - spin_unlock_bh(&conn->sess->ttt_lock); - } else if (hdr->flags & ISCSI_FLAG_CMD_WRITE) - cmd->targ_xfer_tag = 0xFFFFFFFF; - cmd->cmd_sn = hdr->cmdsn; - cmd->exp_stat_sn = hdr->exp_statsn; - cmd->first_burst_len = payload_length; - - if (cmd->data_direction == DMA_FROM_DEVICE) { - struct iscsi_datain_req *dr; - - dr = iscsit_allocate_datain_req(); - if (!dr) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, 1, buf, cmd); - - iscsit_attach_datain_req(cmd, dr); - } - - /* - * The CDB is going to an se_device_t. - */ - ret = iscsit_get_lun_for_cmd(cmd, hdr->cdb, - get_unaligned_le64(&hdr->lun)); - if (ret < 0) { - if (cmd->se_cmd.scsi_sense_reason == TCM_NON_EXISTENT_LUN) { - pr_debug("Responding to non-acl'ed," - " non-existent or non-exported iSCSI LUN:" - " 0x%016Lx\n", get_unaligned_le64(&hdr->lun)); - } - if (ret == PYX_TRANSPORT_OUT_OF_MEMORY_RESOURCES) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, 1, buf, cmd); - - send_check_condition = 1; - goto attach_cmd; - } - /* - * The Initiator Node has access to the LUN (the addressing method - * is handled inside of iscsit_get_lun_for_cmd()). Now it's time to - * allocate 1->N transport tasks (depending on sector count and - * maximum request size the physical HBA(s) can handle. - */ - transport_ret = transport_generic_allocate_tasks(&cmd->se_cmd, hdr->cdb); - if (transport_ret == -ENOMEM) { - return iscsit_add_reject_from_cmd( - ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, 1, buf, cmd); - } else if (transport_ret == -EINVAL) { - /* - * Unsupported SAM Opcode. CHECK_CONDITION will be sent - * in iscsit_execute_cmd() during the CmdSN OOO Execution - * Mechinism. - */ - send_check_condition = 1; - } else { - if (iscsit_decide_list_to_build(cmd, payload_length) < 0) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, 1, buf, cmd); - } - -attach_cmd: - spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); - spin_unlock_bh(&conn->cmd_lock); - /* - * Check if we need to delay processing because of ALUA - * Active/NonOptimized primary access state.. - */ - core_alua_check_nonop_delay(&cmd->se_cmd); - /* - * Allocate and setup SGL used with transport_generic_map_mem_to_cmd(). - * also call iscsit_allocate_iovecs() - */ - ret = iscsit_alloc_buffs(cmd); - if (ret < 0) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, 1, buf, cmd); - /* - * Check the CmdSN against ExpCmdSN/MaxCmdSN here if - * the Immediate Bit is not set, and no Immediate - * Data is attached. - * - * A PDU/CmdSN carrying Immediate Data can only - * be processed after the DataCRC has passed. - * If the DataCRC fails, the CmdSN MUST NOT - * be acknowledged. (See below) - */ - if (!cmd->immediate_data) { - cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); - if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_PROTOCOL_ERROR, - 1, 0, buf, cmd); - } - - iscsit_ack_from_expstatsn(conn, hdr->exp_statsn); - - /* - * If no Immediate Data is attached, it's OK to return now. - */ - if (!cmd->immediate_data) { - if (send_check_condition) - return 0; - - if (cmd->unsolicited_data) { - iscsit_set_dataout_sequence_values(cmd); - - spin_lock_bh(&cmd->dataout_timeout_lock); - iscsit_start_dataout_timer(cmd, cmd->conn); - spin_unlock_bh(&cmd->dataout_timeout_lock); - } - - return 0; - } - - /* - * Early CHECK_CONDITIONs never make it to the transport processing - * thread. They are processed in CmdSN order by - * iscsit_check_received_cmdsn() below. - */ - if (send_check_condition) { - immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; - dump_immediate_data = 1; - goto after_immediate_data; - } - /* - * Call directly into transport_generic_new_cmd() to perform - * the backend memory allocation. - */ - ret = transport_generic_new_cmd(&cmd->se_cmd); - if ((ret < 0) || (cmd->se_cmd.se_cmd_flags & SCF_SE_CMD_FAILED)) { - immed_ret = IMMEDIATE_DATA_NORMAL_OPERATION; - dump_immediate_data = 1; - goto after_immediate_data; - } - - immed_ret = iscsit_handle_immediate_data(cmd, buf, payload_length); -after_immediate_data: - if (immed_ret == IMMEDIATE_DATA_NORMAL_OPERATION) { - /* - * A PDU/CmdSN carrying Immediate Data passed - * DataCRC, check against ExpCmdSN/MaxCmdSN if - * Immediate Bit is not set. - */ - cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); - /* - * Special case for Unsupported SAM WRITE Opcodes - * and ImmediateData=Yes. - */ - if (dump_immediate_data) { - if (iscsit_dump_data_payload(conn, payload_length, 1) < 0) - return -1; - } else if (cmd->unsolicited_data) { - iscsit_set_dataout_sequence_values(cmd); - - spin_lock_bh(&cmd->dataout_timeout_lock); - iscsit_start_dataout_timer(cmd, cmd->conn); - spin_unlock_bh(&cmd->dataout_timeout_lock); - } - - if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_PROTOCOL_ERROR, - 1, 0, buf, cmd); - - } else if (immed_ret == IMMEDIATE_DATA_ERL1_CRC_FAILURE) { - /* - * Immediate Data failed DataCRC and ERL>=1, - * silently drop this PDU and let the initiator - * plug the CmdSN gap. - * - * FIXME: Send Unsolicited NOPIN with reserved - * TTT here to help the initiator figure out - * the missing CmdSN, although they should be - * intelligent enough to determine the missing - * CmdSN and issue a retry to plug the sequence. - */ - cmd->i_state = ISTATE_REMOVE; - iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state); - } else /* immed_ret == IMMEDIATE_DATA_CANNOT_RECOVER */ - return -1; - - return 0; -} - -static u32 iscsit_do_crypto_hash_sg( - struct hash_desc *hash, - struct iscsi_cmd *cmd, - u32 data_offset, - u32 data_length, - u32 padding, - u8 *pad_bytes) -{ - u32 data_crc; - u32 i; - struct scatterlist *sg; - unsigned int page_off; - - crypto_hash_init(hash); - - sg = cmd->first_data_sg; - page_off = cmd->first_data_sg_off; - - i = 0; - while (data_length) { - u32 cur_len = min_t(u32, data_length, (sg[i].length - page_off)); - - crypto_hash_update(hash, &sg[i], cur_len); - - data_length -= cur_len; - page_off = 0; - i++; - } - - if (padding) { - struct scatterlist pad_sg; - - sg_init_one(&pad_sg, pad_bytes, padding); - crypto_hash_update(hash, &pad_sg, padding); - } - crypto_hash_final(hash, (u8 *) &data_crc); - - return data_crc; -} - -static void iscsit_do_crypto_hash_buf( - struct hash_desc *hash, - unsigned char *buf, - u32 payload_length, - u32 padding, - u8 *pad_bytes, - u8 *data_crc) -{ - struct scatterlist sg; - - crypto_hash_init(hash); - - sg_init_one(&sg, (u8 *)buf, payload_length); - crypto_hash_update(hash, &sg, payload_length); - - if (padding) { - sg_init_one(&sg, pad_bytes, padding); - crypto_hash_update(hash, &sg, padding); - } - crypto_hash_final(hash, data_crc); -} - -static int iscsit_handle_data_out(struct iscsi_conn *conn, unsigned char *buf) -{ - int iov_ret, ooo_cmdsn = 0, ret; - u8 data_crc_failed = 0; - u32 checksum, iov_count = 0, padding = 0, rx_got = 0; - u32 rx_size = 0, payload_length; - struct iscsi_cmd *cmd = NULL; - struct se_cmd *se_cmd; - struct iscsi_data *hdr; - struct kvec *iov; - unsigned long flags; - - hdr = (struct iscsi_data *) buf; - payload_length = ntoh24(hdr->dlength); - hdr->itt = be32_to_cpu(hdr->itt); - hdr->ttt = be32_to_cpu(hdr->ttt); - hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn); - hdr->datasn = be32_to_cpu(hdr->datasn); - hdr->offset = be32_to_cpu(hdr->offset); - - if (!payload_length) { - pr_err("DataOUT payload is ZERO, protocol error.\n"); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - - /* iSCSI write */ - spin_lock_bh(&conn->sess->session_stats_lock); - conn->sess->rx_data_octets += payload_length; - if (conn->sess->se_sess->se_node_acl) { - spin_lock(&conn->sess->se_sess->se_node_acl->stats_lock); - conn->sess->se_sess->se_node_acl->write_bytes += payload_length; - spin_unlock(&conn->sess->se_sess->se_node_acl->stats_lock); - } - spin_unlock_bh(&conn->sess->session_stats_lock); - - if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) { - pr_err("DataSegmentLength: %u is greater than" - " MaxRecvDataSegmentLength: %u\n", payload_length, - conn->conn_ops->MaxRecvDataSegmentLength); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - - cmd = iscsit_find_cmd_from_itt_or_dump(conn, hdr->itt, - payload_length); - if (!cmd) - return 0; - - pr_debug("Got DataOut ITT: 0x%08x, TTT: 0x%08x," - " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n", - hdr->itt, hdr->ttt, hdr->datasn, hdr->offset, - payload_length, conn->cid); - - if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) { - pr_err("Command ITT: 0x%08x received DataOUT after" - " last DataOUT received, dumping payload\n", - cmd->init_task_tag); - return iscsit_dump_data_payload(conn, payload_length, 1); - } - - if (cmd->data_direction != DMA_TO_DEVICE) { - pr_err("Command ITT: 0x%08x received DataOUT for a" - " NON-WRITE command.\n", cmd->init_task_tag); - return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, - 1, 0, buf, cmd); - } - se_cmd = &cmd->se_cmd; - iscsit_mod_dataout_timer(cmd); - - if ((hdr->offset + payload_length) > cmd->data_length) { - pr_err("DataOut Offset: %u, Length %u greater than" - " iSCSI Command EDTL %u, protocol error.\n", - hdr->offset, payload_length, cmd->data_length); - return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, - 1, 0, buf, cmd); - } - - if (cmd->unsolicited_data) { - int dump_unsolicited_data = 0; - - if (conn->sess->sess_ops->InitialR2T) { - pr_err("Received unexpected unsolicited data" - " while InitialR2T=Yes, protocol error.\n"); - transport_send_check_condition_and_sense(&cmd->se_cmd, - TCM_UNEXPECTED_UNSOLICITED_DATA, 0); - return -1; - } - /* - * Special case for dealing with Unsolicited DataOUT - * and Unsupported SAM WRITE Opcodes and SE resource allocation - * failures; - */ - - /* Something's amiss if we're not in WRITE_PENDING state... */ - spin_lock_irqsave(&se_cmd->t_state_lock, flags); - WARN_ON(se_cmd->t_state != TRANSPORT_WRITE_PENDING); - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - - spin_lock_irqsave(&se_cmd->t_state_lock, flags); - if (!(se_cmd->se_cmd_flags & SCF_SUPPORTED_SAM_OPCODE) || - (se_cmd->se_cmd_flags & SCF_SE_CMD_FAILED)) - dump_unsolicited_data = 1; - spin_unlock_irqrestore(&se_cmd->t_state_lock, flags); - - if (dump_unsolicited_data) { - /* - * Check if a delayed TASK_ABORTED status needs to - * be sent now if the ISCSI_FLAG_CMD_FINAL has been - * received with the unsolicitied data out. - */ - if (hdr->flags & ISCSI_FLAG_CMD_FINAL) - iscsit_stop_dataout_timer(cmd); - - transport_check_aborted_status(se_cmd, - (hdr->flags & ISCSI_FLAG_CMD_FINAL)); - return iscsit_dump_data_payload(conn, payload_length, 1); - } - } else { - /* - * For the normal solicited data path: - * - * Check for a delayed TASK_ABORTED status and dump any - * incoming data out payload if one exists. Also, when the - * ISCSI_FLAG_CMD_FINAL is set to denote the end of the current - * data out sequence, we decrement outstanding_r2ts. Once - * outstanding_r2ts reaches zero, go ahead and send the delayed - * TASK_ABORTED status. - */ - if (atomic_read(&se_cmd->t_transport_aborted) != 0) { - if (hdr->flags & ISCSI_FLAG_CMD_FINAL) - if (--cmd->outstanding_r2ts < 1) { - iscsit_stop_dataout_timer(cmd); - transport_check_aborted_status( - se_cmd, 1); - } - - return iscsit_dump_data_payload(conn, payload_length, 1); - } - } - /* - * Preform DataSN, DataSequenceInOrder, DataPDUInOrder, and - * within-command recovery checks before receiving the payload. - */ - ret = iscsit_check_pre_dataout(cmd, buf); - if (ret == DATAOUT_WITHIN_COMMAND_RECOVERY) - return 0; - else if (ret == DATAOUT_CANNOT_RECOVER) - return -1; - - rx_size += payload_length; - iov = &cmd->iov_data[0]; - - iov_ret = iscsit_map_iovec(cmd, iov, hdr->offset, payload_length); - if (iov_ret < 0) - return -1; - - iov_count += iov_ret; - - padding = ((-payload_length) & 3); - if (padding != 0) { - iov[iov_count].iov_base = cmd->pad_bytes; - iov[iov_count++].iov_len = padding; - rx_size += padding; - pr_debug("Receiving %u padding bytes.\n", padding); - } - - if (conn->conn_ops->DataDigest) { - iov[iov_count].iov_base = &checksum; - iov[iov_count++].iov_len = ISCSI_CRC_LEN; - rx_size += ISCSI_CRC_LEN; - } - - rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size); - - iscsit_unmap_iovec(cmd); - - if (rx_got != rx_size) - return -1; - - if (conn->conn_ops->DataDigest) { - u32 data_crc; - - data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd, - hdr->offset, payload_length, padding, - cmd->pad_bytes); - - if (checksum != data_crc) { - pr_err("ITT: 0x%08x, Offset: %u, Length: %u," - " DataSN: 0x%08x, CRC32C DataDigest 0x%08x" - " does not match computed 0x%08x\n", - hdr->itt, hdr->offset, payload_length, - hdr->datasn, checksum, data_crc); - data_crc_failed = 1; - } else { - pr_debug("Got CRC32C DataDigest 0x%08x for" - " %u bytes of Data Out\n", checksum, - payload_length); - } - } - /* - * Increment post receive data and CRC values or perform - * within-command recovery. - */ - ret = iscsit_check_post_dataout(cmd, buf, data_crc_failed); - if ((ret == DATAOUT_NORMAL) || (ret == DATAOUT_WITHIN_COMMAND_RECOVERY)) - return 0; - else if (ret == DATAOUT_SEND_R2T) { - iscsit_set_dataout_sequence_values(cmd); - iscsit_build_r2ts_for_cmd(cmd, conn, 0); - } else if (ret == DATAOUT_SEND_TO_TRANSPORT) { - /* - * Handle extra special case for out of order - * Unsolicited Data Out. - */ - spin_lock_bh(&cmd->istate_lock); - ooo_cmdsn = (cmd->cmd_flags & ICF_OOO_CMDSN); - cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT; - cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT; - spin_unlock_bh(&cmd->istate_lock); - - iscsit_stop_dataout_timer(cmd); - return (!ooo_cmdsn) ? transport_generic_handle_data( - &cmd->se_cmd) : 0; - } else /* DATAOUT_CANNOT_RECOVER */ - return -1; - - return 0; -} - -static int iscsit_handle_nop_out( - struct iscsi_conn *conn, - unsigned char *buf) -{ - unsigned char *ping_data = NULL; - int cmdsn_ret, niov = 0, ret = 0, rx_got, rx_size; - u32 checksum, data_crc, padding = 0, payload_length; - u64 lun; - struct iscsi_cmd *cmd = NULL; - struct kvec *iov = NULL; - struct iscsi_nopout *hdr; - - hdr = (struct iscsi_nopout *) buf; - payload_length = ntoh24(hdr->dlength); - lun = get_unaligned_le64(&hdr->lun); - hdr->itt = be32_to_cpu(hdr->itt); - hdr->ttt = be32_to_cpu(hdr->ttt); - hdr->cmdsn = be32_to_cpu(hdr->cmdsn); - hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn); - - if ((hdr->itt == 0xFFFFFFFF) && !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { - pr_err("NOPOUT ITT is reserved, but Immediate Bit is" - " not set, protocol error.\n"); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - - if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) { - pr_err("NOPOUT Ping Data DataSegmentLength: %u is" - " greater than MaxRecvDataSegmentLength: %u, protocol" - " error.\n", payload_length, - conn->conn_ops->MaxRecvDataSegmentLength); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - - pr_debug("Got NOPOUT Ping %s ITT: 0x%08x, TTT: 0x%09x," - " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n", - (hdr->itt == 0xFFFFFFFF) ? "Response" : "Request", - hdr->itt, hdr->ttt, hdr->cmdsn, hdr->exp_statsn, - payload_length); - /* - * This is not a response to a Unsolicited NopIN, which means - * it can either be a NOPOUT ping request (with a valid ITT), - * or a NOPOUT not requesting a NOPIN (with a reserved ITT). - * Either way, make sure we allocate an struct iscsi_cmd, as both - * can contain ping data. - */ - if (hdr->ttt == 0xFFFFFFFF) { - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); - if (!cmd) - return iscsit_add_reject( - ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, buf, conn); - - cmd->iscsi_opcode = ISCSI_OP_NOOP_OUT; - cmd->i_state = ISTATE_SEND_NOPIN; - cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? - 1 : 0); - conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt; - cmd->targ_xfer_tag = 0xFFFFFFFF; - cmd->cmd_sn = hdr->cmdsn; - cmd->exp_stat_sn = hdr->exp_statsn; - cmd->data_direction = DMA_NONE; - } - - if (payload_length && (hdr->ttt == 0xFFFFFFFF)) { - rx_size = payload_length; - ping_data = kzalloc(payload_length + 1, GFP_KERNEL); - if (!ping_data) { - pr_err("Unable to allocate memory for" - " NOPOUT ping data.\n"); - ret = -1; - goto out; - } - - iov = &cmd->iov_misc[0]; - iov[niov].iov_base = ping_data; - iov[niov++].iov_len = payload_length; - - padding = ((-payload_length) & 3); - if (padding != 0) { - pr_debug("Receiving %u additional bytes" - " for padding.\n", padding); - iov[niov].iov_base = &cmd->pad_bytes; - iov[niov++].iov_len = padding; - rx_size += padding; - } - if (conn->conn_ops->DataDigest) { - iov[niov].iov_base = &checksum; - iov[niov++].iov_len = ISCSI_CRC_LEN; - rx_size += ISCSI_CRC_LEN; - } - - rx_got = rx_data(conn, &cmd->iov_misc[0], niov, rx_size); - if (rx_got != rx_size) { - ret = -1; - goto out; - } - - if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, - ping_data, payload_length, - padding, cmd->pad_bytes, - (u8 *)&data_crc); - - if (checksum != data_crc) { - pr_err("Ping data CRC32C DataDigest" - " 0x%08x does not match computed 0x%08x\n", - checksum, data_crc); - if (!conn->sess->sess_ops->ErrorRecoveryLevel) { - pr_err("Unable to recover from" - " NOPOUT Ping DataCRC failure while in" - " ERL=0.\n"); - ret = -1; - goto out; - } else { - /* - * Silently drop this PDU and let the - * initiator plug the CmdSN gap. - */ - pr_debug("Dropping NOPOUT" - " Command CmdSN: 0x%08x due to" - " DataCRC error.\n", hdr->cmdsn); - ret = 0; - goto out; - } - } else { - pr_debug("Got CRC32C DataDigest" - " 0x%08x for %u bytes of ping data.\n", - checksum, payload_length); - } - } - - ping_data[payload_length] = '\0'; - /* - * Attach ping data to struct iscsi_cmd->buf_ptr. - */ - cmd->buf_ptr = (void *)ping_data; - cmd->buf_ptr_size = payload_length; - - pr_debug("Got %u bytes of NOPOUT ping" - " data.\n", payload_length); - pr_debug("Ping Data: \"%s\"\n", ping_data); - } - - if (hdr->itt != 0xFFFFFFFF) { - if (!cmd) { - pr_err("Checking CmdSN for NOPOUT," - " but cmd is NULL!\n"); - return -1; - } - /* - * Initiator is expecting a NopIN ping reply, - */ - spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); - spin_unlock_bh(&conn->cmd_lock); - - iscsit_ack_from_expstatsn(conn, hdr->exp_statsn); - - if (hdr->opcode & ISCSI_OP_IMMEDIATE) { - iscsit_add_cmd_to_response_queue(cmd, conn, - cmd->i_state); - return 0; - } - - cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); - if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { - ret = 0; - goto ping_out; - } - if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_PROTOCOL_ERROR, - 1, 0, buf, cmd); - - return 0; - } - - if (hdr->ttt != 0xFFFFFFFF) { - /* - * This was a response to a unsolicited NOPIN ping. - */ - cmd = iscsit_find_cmd_from_ttt(conn, hdr->ttt); - if (!cmd) - return -1; - - iscsit_stop_nopin_response_timer(conn); - - cmd->i_state = ISTATE_REMOVE; - iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state); - iscsit_start_nopin_timer(conn); - } else { - /* - * Initiator is not expecting a NOPIN is response. - * Just ignore for now. - * - * iSCSI v19-91 10.18 - * "A NOP-OUT may also be used to confirm a changed - * ExpStatSN if another PDU will not be available - * for a long time." - */ - ret = 0; - goto out; - } - - return 0; -out: - if (cmd) - iscsit_release_cmd(cmd); -ping_out: - kfree(ping_data); - return ret; -} - -static int iscsit_handle_task_mgt_cmd( - struct iscsi_conn *conn, - unsigned char *buf) -{ - struct iscsi_cmd *cmd; - struct se_tmr_req *se_tmr; - struct iscsi_tmr_req *tmr_req; - struct iscsi_tm *hdr; - u32 payload_length; - int out_of_order_cmdsn = 0; - int ret; - u8 function; - - hdr = (struct iscsi_tm *) buf; - payload_length = ntoh24(hdr->dlength); - hdr->itt = be32_to_cpu(hdr->itt); - hdr->rtt = be32_to_cpu(hdr->rtt); - hdr->cmdsn = be32_to_cpu(hdr->cmdsn); - hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn); - hdr->refcmdsn = be32_to_cpu(hdr->refcmdsn); - hdr->exp_datasn = be32_to_cpu(hdr->exp_datasn); - hdr->flags &= ~ISCSI_FLAG_CMD_FINAL; - function = hdr->flags; - - pr_debug("Got Task Management Request ITT: 0x%08x, CmdSN:" - " 0x%08x, Function: 0x%02x, RefTaskTag: 0x%08x, RefCmdSN:" - " 0x%08x, CID: %hu\n", hdr->itt, hdr->cmdsn, function, - hdr->rtt, hdr->refcmdsn, conn->cid); - - if ((function != ISCSI_TM_FUNC_ABORT_TASK) && - ((function != ISCSI_TM_FUNC_TASK_REASSIGN) && - (hdr->rtt != ISCSI_RESERVED_TAG))) { - pr_err("RefTaskTag should be set to 0xFFFFFFFF.\n"); - hdr->rtt = ISCSI_RESERVED_TAG; - } - - if ((function == ISCSI_TM_FUNC_TASK_REASSIGN) && - !(hdr->opcode & ISCSI_OP_IMMEDIATE)) { - pr_err("Task Management Request TASK_REASSIGN not" - " issued as immediate command, bad iSCSI Initiator" - "implementation\n"); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - if ((function != ISCSI_TM_FUNC_ABORT_TASK) && - (hdr->refcmdsn != ISCSI_RESERVED_TAG)) - hdr->refcmdsn = ISCSI_RESERVED_TAG; - - cmd = iscsit_allocate_se_cmd_for_tmr(conn, function); - if (!cmd) - return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, buf, conn); - - cmd->iscsi_opcode = ISCSI_OP_SCSI_TMFUNC; - cmd->i_state = ISTATE_SEND_TASKMGTRSP; - cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0); - cmd->init_task_tag = hdr->itt; - cmd->targ_xfer_tag = 0xFFFFFFFF; - cmd->cmd_sn = hdr->cmdsn; - cmd->exp_stat_sn = hdr->exp_statsn; - se_tmr = cmd->se_cmd.se_tmr_req; - tmr_req = cmd->tmr_req; - /* - * Locate the struct se_lun for all TMRs not related to ERL=2 TASK_REASSIGN - */ - if (function != ISCSI_TM_FUNC_TASK_REASSIGN) { - ret = iscsit_get_lun_for_tmr(cmd, - get_unaligned_le64(&hdr->lun)); - if (ret < 0) { - cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - se_tmr->response = ISCSI_TMF_RSP_NO_LUN; - goto attach; - } - } - - switch (function) { - case ISCSI_TM_FUNC_ABORT_TASK: - se_tmr->response = iscsit_tmr_abort_task(cmd, buf); - if (se_tmr->response != ISCSI_TMF_RSP_COMPLETE) { - cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - goto attach; - } - break; - case ISCSI_TM_FUNC_ABORT_TASK_SET: - case ISCSI_TM_FUNC_CLEAR_ACA: - case ISCSI_TM_FUNC_CLEAR_TASK_SET: - case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET: - break; - case ISCSI_TM_FUNC_TARGET_WARM_RESET: - if (iscsit_tmr_task_warm_reset(conn, tmr_req, buf) < 0) { - cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - se_tmr->response = ISCSI_TMF_RSP_AUTH_FAILED; - goto attach; - } - break; - case ISCSI_TM_FUNC_TARGET_COLD_RESET: - if (iscsit_tmr_task_cold_reset(conn, tmr_req, buf) < 0) { - cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - se_tmr->response = ISCSI_TMF_RSP_AUTH_FAILED; - goto attach; - } - break; - case ISCSI_TM_FUNC_TASK_REASSIGN: - se_tmr->response = iscsit_tmr_task_reassign(cmd, buf); - /* - * Perform sanity checks on the ExpDataSN only if the - * TASK_REASSIGN was successful. - */ - if (se_tmr->response != ISCSI_TMF_RSP_COMPLETE) - break; - - if (iscsit_check_task_reassign_expdatasn(tmr_req, conn) < 0) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_BOOKMARK_INVALID, 1, 1, - buf, cmd); - break; - default: - pr_err("Unknown TMR function: 0x%02x, protocol" - " error.\n", function); - cmd->se_cmd.se_cmd_flags |= SCF_SCSI_CDB_EXCEPTION; - se_tmr->response = ISCSI_TMF_RSP_NOT_SUPPORTED; - goto attach; - } - - if ((function != ISCSI_TM_FUNC_TASK_REASSIGN) && - (se_tmr->response == ISCSI_TMF_RSP_COMPLETE)) - se_tmr->call_transport = 1; -attach: - spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); - spin_unlock_bh(&conn->cmd_lock); - - if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { - int cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); - if (cmdsn_ret == CMDSN_HIGHER_THAN_EXP) - out_of_order_cmdsn = 1; - else if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { - return 0; - } else { /* (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) */ - return iscsit_add_reject_from_cmd( - ISCSI_REASON_PROTOCOL_ERROR, - 1, 0, buf, cmd); - } - } - iscsit_ack_from_expstatsn(conn, hdr->exp_statsn); - - if (out_of_order_cmdsn) - return 0; - /* - * Found the referenced task, send to transport for processing. - */ - if (se_tmr->call_transport) - return transport_generic_handle_tmr(&cmd->se_cmd); - - /* - * Could not find the referenced LUN, task, or Task Management - * command not authorized or supported. Change state and - * let the tx_thread send the response. - * - * For connection recovery, this is also the default action for - * TMR TASK_REASSIGN. - */ - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - return 0; -} - -/* #warning FIXME: Support Text Command parameters besides SendTargets */ -static int iscsit_handle_text_cmd( - struct iscsi_conn *conn, - unsigned char *buf) -{ - char *text_ptr, *text_in; - int cmdsn_ret, niov = 0, rx_got, rx_size; - u32 checksum = 0, data_crc = 0, payload_length; - u32 padding = 0, text_length = 0; - struct iscsi_cmd *cmd; - struct kvec iov[3]; - struct iscsi_text *hdr; - - hdr = (struct iscsi_text *) buf; - payload_length = ntoh24(hdr->dlength); - hdr->itt = be32_to_cpu(hdr->itt); - hdr->ttt = be32_to_cpu(hdr->ttt); - hdr->cmdsn = be32_to_cpu(hdr->cmdsn); - hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn); - - if (payload_length > conn->conn_ops->MaxRecvDataSegmentLength) { - pr_err("Unable to accept text parameter length: %u" - "greater than MaxRecvDataSegmentLength %u.\n", - payload_length, conn->conn_ops->MaxRecvDataSegmentLength); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - - pr_debug("Got Text Request: ITT: 0x%08x, CmdSN: 0x%08x," - " ExpStatSN: 0x%08x, Length: %u\n", hdr->itt, hdr->cmdsn, - hdr->exp_statsn, payload_length); - - rx_size = text_length = payload_length; - if (text_length) { - text_in = kzalloc(text_length, GFP_KERNEL); - if (!text_in) { - pr_err("Unable to allocate memory for" - " incoming text parameters\n"); - return -1; - } - - memset(iov, 0, 3 * sizeof(struct kvec)); - iov[niov].iov_base = text_in; - iov[niov++].iov_len = text_length; - - padding = ((-payload_length) & 3); - if (padding != 0) { - iov[niov].iov_base = cmd->pad_bytes; - iov[niov++].iov_len = padding; - rx_size += padding; - pr_debug("Receiving %u additional bytes" - " for padding.\n", padding); - } - if (conn->conn_ops->DataDigest) { - iov[niov].iov_base = &checksum; - iov[niov++].iov_len = ISCSI_CRC_LEN; - rx_size += ISCSI_CRC_LEN; - } - - rx_got = rx_data(conn, &iov[0], niov, rx_size); - if (rx_got != rx_size) { - kfree(text_in); - return -1; - } - - if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, - text_in, text_length, - padding, cmd->pad_bytes, - (u8 *)&data_crc); - - if (checksum != data_crc) { - pr_err("Text data CRC32C DataDigest" - " 0x%08x does not match computed" - " 0x%08x\n", checksum, data_crc); - if (!conn->sess->sess_ops->ErrorRecoveryLevel) { - pr_err("Unable to recover from" - " Text Data digest failure while in" - " ERL=0.\n"); - kfree(text_in); - return -1; - } else { - /* - * Silently drop this PDU and let the - * initiator plug the CmdSN gap. - */ - pr_debug("Dropping Text" - " Command CmdSN: 0x%08x due to" - " DataCRC error.\n", hdr->cmdsn); - kfree(text_in); - return 0; - } - } else { - pr_debug("Got CRC32C DataDigest" - " 0x%08x for %u bytes of text data.\n", - checksum, text_length); - } - } - text_in[text_length - 1] = '\0'; - pr_debug("Successfully read %d bytes of text" - " data.\n", text_length); - - if (strncmp("SendTargets", text_in, 11) != 0) { - pr_err("Received Text Data that is not" - " SendTargets, cannot continue.\n"); - kfree(text_in); - return -1; - } - text_ptr = strchr(text_in, '='); - if (!text_ptr) { - pr_err("No \"=\" separator found in Text Data," - " cannot continue.\n"); - kfree(text_in); - return -1; - } - if (strncmp("=All", text_ptr, 4) != 0) { - pr_err("Unable to locate All value for" - " SendTargets key, cannot continue.\n"); - kfree(text_in); - return -1; - } -/*#warning Support SendTargets=(iSCSI Target Name/Nothing) values. */ - kfree(text_in); - } - - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); - if (!cmd) - return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, buf, conn); - - cmd->iscsi_opcode = ISCSI_OP_TEXT; - cmd->i_state = ISTATE_SEND_TEXTRSP; - cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0); - conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt; - cmd->targ_xfer_tag = 0xFFFFFFFF; - cmd->cmd_sn = hdr->cmdsn; - cmd->exp_stat_sn = hdr->exp_statsn; - cmd->data_direction = DMA_NONE; - - spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); - spin_unlock_bh(&conn->cmd_lock); - - iscsit_ack_from_expstatsn(conn, hdr->exp_statsn); - - if (!(hdr->opcode & ISCSI_OP_IMMEDIATE)) { - cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); - if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) - return iscsit_add_reject_from_cmd( - ISCSI_REASON_PROTOCOL_ERROR, - 1, 0, buf, cmd); - - return 0; - } - - return iscsit_execute_cmd(cmd, 0); -} - -int iscsit_logout_closesession(struct iscsi_cmd *cmd, struct iscsi_conn *conn) -{ - struct iscsi_conn *conn_p; - struct iscsi_session *sess = conn->sess; - - pr_debug("Received logout request CLOSESESSION on CID: %hu" - " for SID: %u.\n", conn->cid, conn->sess->sid); - - atomic_set(&sess->session_logout, 1); - atomic_set(&conn->conn_logout_remove, 1); - conn->conn_logout_reason = ISCSI_LOGOUT_REASON_CLOSE_SESSION; - - iscsit_inc_conn_usage_count(conn); - iscsit_inc_session_usage_count(sess); - - spin_lock_bh(&sess->conn_lock); - list_for_each_entry(conn_p, &sess->sess_conn_list, conn_list) { - if (conn_p->conn_state != TARG_CONN_STATE_LOGGED_IN) - continue; - - pr_debug("Moving to TARG_CONN_STATE_IN_LOGOUT.\n"); - conn_p->conn_state = TARG_CONN_STATE_IN_LOGOUT; - } - spin_unlock_bh(&sess->conn_lock); - - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - - return 0; -} - -int iscsit_logout_closeconnection(struct iscsi_cmd *cmd, struct iscsi_conn *conn) -{ - struct iscsi_conn *l_conn; - struct iscsi_session *sess = conn->sess; - - pr_debug("Received logout request CLOSECONNECTION for CID:" - " %hu on CID: %hu.\n", cmd->logout_cid, conn->cid); - - /* - * A Logout Request with a CLOSECONNECTION reason code for a CID - * can arrive on a connection with a differing CID. - */ - if (conn->cid == cmd->logout_cid) { - spin_lock_bh(&conn->state_lock); - pr_debug("Moving to TARG_CONN_STATE_IN_LOGOUT.\n"); - conn->conn_state = TARG_CONN_STATE_IN_LOGOUT; - - atomic_set(&conn->conn_logout_remove, 1); - conn->conn_logout_reason = ISCSI_LOGOUT_REASON_CLOSE_CONNECTION; - iscsit_inc_conn_usage_count(conn); - - spin_unlock_bh(&conn->state_lock); - } else { - /* - * Handle all different cid CLOSECONNECTION requests in - * iscsit_logout_post_handler_diffcid() as to give enough - * time for any non immediate command's CmdSN to be - * acknowledged on the connection in question. - * - * Here we simply make sure the CID is still around. - */ - l_conn = iscsit_get_conn_from_cid(sess, - cmd->logout_cid); - if (!l_conn) { - cmd->logout_response = ISCSI_LOGOUT_CID_NOT_FOUND; - iscsit_add_cmd_to_response_queue(cmd, conn, - cmd->i_state); - return 0; - } - - iscsit_dec_conn_usage_count(l_conn); - } - - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - - return 0; -} - -int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *cmd, struct iscsi_conn *conn) -{ - struct iscsi_session *sess = conn->sess; - - pr_debug("Received explicit REMOVECONNFORRECOVERY logout for" - " CID: %hu on CID: %hu.\n", cmd->logout_cid, conn->cid); - - if (sess->sess_ops->ErrorRecoveryLevel != 2) { - pr_err("Received Logout Request REMOVECONNFORRECOVERY" - " while ERL!=2.\n"); - cmd->logout_response = ISCSI_LOGOUT_RECOVERY_UNSUPPORTED; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - return 0; - } - - if (conn->cid == cmd->logout_cid) { - pr_err("Received Logout Request REMOVECONNFORRECOVERY" - " with CID: %hu on CID: %hu, implementation error.\n", - cmd->logout_cid, conn->cid); - cmd->logout_response = ISCSI_LOGOUT_CLEANUP_FAILED; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - return 0; - } - - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - - return 0; -} - -static int iscsit_handle_logout_cmd( - struct iscsi_conn *conn, - unsigned char *buf) -{ - int cmdsn_ret, logout_remove = 0; - u8 reason_code = 0; - struct iscsi_cmd *cmd; - struct iscsi_logout *hdr; - struct iscsi_tiqn *tiqn = iscsit_snmp_get_tiqn(conn); - - hdr = (struct iscsi_logout *) buf; - reason_code = (hdr->flags & 0x7f); - hdr->itt = be32_to_cpu(hdr->itt); - hdr->cid = be16_to_cpu(hdr->cid); - hdr->cmdsn = be32_to_cpu(hdr->cmdsn); - hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn); - - if (tiqn) { - spin_lock(&tiqn->logout_stats.lock); - if (reason_code == ISCSI_LOGOUT_REASON_CLOSE_SESSION) - tiqn->logout_stats.normal_logouts++; - else - tiqn->logout_stats.abnormal_logouts++; - spin_unlock(&tiqn->logout_stats.lock); - } - - pr_debug("Got Logout Request ITT: 0x%08x CmdSN: 0x%08x" - " ExpStatSN: 0x%08x Reason: 0x%02x CID: %hu on CID: %hu\n", - hdr->itt, hdr->cmdsn, hdr->exp_statsn, reason_code, - hdr->cid, conn->cid); - - if (conn->conn_state != TARG_CONN_STATE_LOGGED_IN) { - pr_err("Received logout request on connection that" - " is not in logged in state, ignoring request.\n"); - return 0; - } - - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); - if (!cmd) - return iscsit_add_reject(ISCSI_REASON_BOOKMARK_NO_RESOURCES, 1, - buf, conn); - - cmd->iscsi_opcode = ISCSI_OP_LOGOUT; - cmd->i_state = ISTATE_SEND_LOGOUTRSP; - cmd->immediate_cmd = ((hdr->opcode & ISCSI_OP_IMMEDIATE) ? 1 : 0); - conn->sess->init_task_tag = cmd->init_task_tag = hdr->itt; - cmd->targ_xfer_tag = 0xFFFFFFFF; - cmd->cmd_sn = hdr->cmdsn; - cmd->exp_stat_sn = hdr->exp_statsn; - cmd->logout_cid = hdr->cid; - cmd->logout_reason = reason_code; - cmd->data_direction = DMA_NONE; - - /* - * We need to sleep in these cases (by returning 1) until the Logout - * Response gets sent in the tx thread. - */ - if ((reason_code == ISCSI_LOGOUT_REASON_CLOSE_SESSION) || - ((reason_code == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION) && - (hdr->cid == conn->cid))) - logout_remove = 1; - - spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); - spin_unlock_bh(&conn->cmd_lock); - - if (reason_code != ISCSI_LOGOUT_REASON_RECOVERY) - iscsit_ack_from_expstatsn(conn, hdr->exp_statsn); - - /* - * Immediate commands are executed, well, immediately. - * Non-Immediate Logout Commands are executed in CmdSN order. - */ - if (hdr->opcode & ISCSI_OP_IMMEDIATE) { - int ret = iscsit_execute_cmd(cmd, 0); - - if (ret < 0) - return ret; - } else { - cmdsn_ret = iscsit_sequence_cmd(conn, cmd, hdr->cmdsn); - if (cmdsn_ret == CMDSN_LOWER_THAN_EXP) { - logout_remove = 0; - } else if (cmdsn_ret == CMDSN_ERROR_CANNOT_RECOVER) { - return iscsit_add_reject_from_cmd( - ISCSI_REASON_PROTOCOL_ERROR, - 1, 0, buf, cmd); - } - } - - return logout_remove; -} - -static int iscsit_handle_snack( - struct iscsi_conn *conn, - unsigned char *buf) -{ - u32 unpacked_lun; - u64 lun; - struct iscsi_snack *hdr; - - hdr = (struct iscsi_snack *) buf; - hdr->flags &= ~ISCSI_FLAG_CMD_FINAL; - lun = get_unaligned_le64(&hdr->lun); - unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); - hdr->itt = be32_to_cpu(hdr->itt); - hdr->ttt = be32_to_cpu(hdr->ttt); - hdr->exp_statsn = be32_to_cpu(hdr->exp_statsn); - hdr->begrun = be32_to_cpu(hdr->begrun); - hdr->runlength = be32_to_cpu(hdr->runlength); - - pr_debug("Got ISCSI_INIT_SNACK, ITT: 0x%08x, ExpStatSN:" - " 0x%08x, Type: 0x%02x, BegRun: 0x%08x, RunLength: 0x%08x," - " CID: %hu\n", hdr->itt, hdr->exp_statsn, hdr->flags, - hdr->begrun, hdr->runlength, conn->cid); - - if (!conn->sess->sess_ops->ErrorRecoveryLevel) { - pr_err("Initiator sent SNACK request while in" - " ErrorRecoveryLevel=0.\n"); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - /* - * SNACK_DATA and SNACK_R2T are both 0, so check which function to - * call from inside iscsi_send_recovery_datain_or_r2t(). - */ - switch (hdr->flags & ISCSI_FLAG_SNACK_TYPE_MASK) { - case 0: - return iscsit_handle_recovery_datain_or_r2t(conn, buf, - hdr->itt, hdr->ttt, hdr->begrun, hdr->runlength); - return 0; - case ISCSI_FLAG_SNACK_TYPE_STATUS: - return iscsit_handle_status_snack(conn, hdr->itt, hdr->ttt, - hdr->begrun, hdr->runlength); - case ISCSI_FLAG_SNACK_TYPE_DATA_ACK: - return iscsit_handle_data_ack(conn, hdr->ttt, hdr->begrun, - hdr->runlength); - case ISCSI_FLAG_SNACK_TYPE_RDATA: - /* FIXME: Support R-Data SNACK */ - pr_err("R-Data SNACK Not Supported.\n"); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - default: - pr_err("Unknown SNACK type 0x%02x, protocol" - " error.\n", hdr->flags & 0x0f); - return iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buf, conn); - } - - return 0; -} - -static void iscsit_rx_thread_wait_for_tcp(struct iscsi_conn *conn) -{ - if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) || - (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) { - wait_for_completion_interruptible_timeout( - &conn->rx_half_close_comp, - ISCSI_RX_THREAD_TCP_TIMEOUT * HZ); - } -} - -static int iscsit_handle_immediate_data( - struct iscsi_cmd *cmd, - unsigned char *buf, - u32 length) -{ - int iov_ret, rx_got = 0, rx_size = 0; - u32 checksum, iov_count = 0, padding = 0; - struct iscsi_conn *conn = cmd->conn; - struct kvec *iov; - - iov_ret = iscsit_map_iovec(cmd, cmd->iov_data, cmd->write_data_done, length); - if (iov_ret < 0) - return IMMEDIATE_DATA_CANNOT_RECOVER; - - rx_size = length; - iov_count = iov_ret; - iov = &cmd->iov_data[0]; - - padding = ((-length) & 3); - if (padding != 0) { - iov[iov_count].iov_base = cmd->pad_bytes; - iov[iov_count++].iov_len = padding; - rx_size += padding; - } - - if (conn->conn_ops->DataDigest) { - iov[iov_count].iov_base = &checksum; - iov[iov_count++].iov_len = ISCSI_CRC_LEN; - rx_size += ISCSI_CRC_LEN; - } - - rx_got = rx_data(conn, &cmd->iov_data[0], iov_count, rx_size); - - iscsit_unmap_iovec(cmd); - - if (rx_got != rx_size) { - iscsit_rx_thread_wait_for_tcp(conn); - return IMMEDIATE_DATA_CANNOT_RECOVER; - } - - if (conn->conn_ops->DataDigest) { - u32 data_crc; - - data_crc = iscsit_do_crypto_hash_sg(&conn->conn_rx_hash, cmd, - cmd->write_data_done, length, padding, - cmd->pad_bytes); - - if (checksum != data_crc) { - pr_err("ImmediateData CRC32C DataDigest 0x%08x" - " does not match computed 0x%08x\n", checksum, - data_crc); - - if (!conn->sess->sess_ops->ErrorRecoveryLevel) { - pr_err("Unable to recover from" - " Immediate Data digest failure while" - " in ERL=0.\n"); - iscsit_add_reject_from_cmd( - ISCSI_REASON_DATA_DIGEST_ERROR, - 1, 0, buf, cmd); - return IMMEDIATE_DATA_CANNOT_RECOVER; - } else { - iscsit_add_reject_from_cmd( - ISCSI_REASON_DATA_DIGEST_ERROR, - 0, 0, buf, cmd); - return IMMEDIATE_DATA_ERL1_CRC_FAILURE; - } - } else { - pr_debug("Got CRC32C DataDigest 0x%08x for" - " %u bytes of Immediate Data\n", checksum, - length); - } - } - - cmd->write_data_done += length; - - if (cmd->write_data_done == cmd->data_length) { - spin_lock_bh(&cmd->istate_lock); - cmd->cmd_flags |= ICF_GOT_LAST_DATAOUT; - cmd->i_state = ISTATE_RECEIVED_LAST_DATAOUT; - spin_unlock_bh(&cmd->istate_lock); - } - - return IMMEDIATE_DATA_NORMAL_OPERATION; -} - -/* - * Called with sess->conn_lock held. - */ -/* #warning iscsi_build_conn_drop_async_message() only sends out on connections - with active network interface */ -static void iscsit_build_conn_drop_async_message(struct iscsi_conn *conn) -{ - struct iscsi_cmd *cmd; - struct iscsi_conn *conn_p; - - /* - * Only send a Asynchronous Message on connections whos network - * interface is still functional. - */ - list_for_each_entry(conn_p, &conn->sess->sess_conn_list, conn_list) { - if (conn_p->conn_state == TARG_CONN_STATE_LOGGED_IN) { - iscsit_inc_conn_usage_count(conn_p); - break; - } - } - - if (!conn_p) - return; - - cmd = iscsit_allocate_cmd(conn_p, GFP_KERNEL); - if (!cmd) { - iscsit_dec_conn_usage_count(conn_p); - return; - } - - cmd->logout_cid = conn->cid; - cmd->iscsi_opcode = ISCSI_OP_ASYNC_EVENT; - cmd->i_state = ISTATE_SEND_ASYNCMSG; - - spin_lock_bh(&conn_p->cmd_lock); - list_add_tail(&cmd->i_list, &conn_p->conn_cmd_list); - spin_unlock_bh(&conn_p->cmd_lock); - - iscsit_add_cmd_to_response_queue(cmd, conn_p, cmd->i_state); - iscsit_dec_conn_usage_count(conn_p); -} - -static int iscsit_send_conn_drop_async_message( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - struct iscsi_async *hdr; - - cmd->tx_size = ISCSI_HDR_LEN; - cmd->iscsi_opcode = ISCSI_OP_ASYNC_EVENT; - - hdr = (struct iscsi_async *) cmd->pdu; - hdr->opcode = ISCSI_OP_ASYNC_EVENT; - hdr->flags = ISCSI_FLAG_CMD_FINAL; - cmd->init_task_tag = 0xFFFFFFFF; - cmd->targ_xfer_tag = 0xFFFFFFFF; - put_unaligned_be64(0xFFFFFFFFFFFFFFFFULL, &hdr->rsvd4[0]); - cmd->stat_sn = conn->stat_sn++; - hdr->statsn = cpu_to_be32(cmd->stat_sn); - hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - hdr->async_event = ISCSI_ASYNC_MSG_DROPPING_CONNECTION; - hdr->param1 = cpu_to_be16(cmd->logout_cid); - hdr->param2 = cpu_to_be16(conn->sess->sess_ops->DefaultTime2Wait); - hdr->param3 = cpu_to_be16(conn->sess->sess_ops->DefaultTime2Retain); - - if (conn->conn_ops->HeaderDigest) { - u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)hdr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)header_digest); - - cmd->tx_size += ISCSI_CRC_LEN; - pr_debug("Attaching CRC32C HeaderDigest to" - " Async Message 0x%08x\n", *header_digest); - } - - cmd->iov_misc[0].iov_base = cmd->pdu; - cmd->iov_misc[0].iov_len = cmd->tx_size; - cmd->iov_misc_count = 1; - - pr_debug("Sending Connection Dropped Async Message StatSN:" - " 0x%08x, for CID: %hu on CID: %hu\n", cmd->stat_sn, - cmd->logout_cid, conn->cid); - return 0; -} - -static int iscsit_send_data_in( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn, - int *eodr) -{ - int iov_ret = 0, set_statsn = 0; - u32 iov_count = 0, tx_size = 0; - struct iscsi_datain datain; - struct iscsi_datain_req *dr; - struct iscsi_data_rsp *hdr; - struct kvec *iov; - - memset(&datain, 0, sizeof(struct iscsi_datain)); - dr = iscsit_get_datain_values(cmd, &datain); - if (!dr) { - pr_err("iscsit_get_datain_values failed for ITT: 0x%08x\n", - cmd->init_task_tag); - return -1; - } - - /* - * Be paranoid and double check the logic for now. - */ - if ((datain.offset + datain.length) > cmd->data_length) { - pr_err("Command ITT: 0x%08x, datain.offset: %u and" - " datain.length: %u exceeds cmd->data_length: %u\n", - cmd->init_task_tag, datain.offset, datain.length, - cmd->data_length); - return -1; - } - - spin_lock_bh(&conn->sess->session_stats_lock); - conn->sess->tx_data_octets += datain.length; - if (conn->sess->se_sess->se_node_acl) { - spin_lock(&conn->sess->se_sess->se_node_acl->stats_lock); - conn->sess->se_sess->se_node_acl->read_bytes += datain.length; - spin_unlock(&conn->sess->se_sess->se_node_acl->stats_lock); - } - spin_unlock_bh(&conn->sess->session_stats_lock); - /* - * Special case for successfully execution w/ both DATAIN - * and Sense Data. - */ - if ((datain.flags & ISCSI_FLAG_DATA_STATUS) && - (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE)) - datain.flags &= ~ISCSI_FLAG_DATA_STATUS; - else { - if ((dr->dr_complete == DATAIN_COMPLETE_NORMAL) || - (dr->dr_complete == DATAIN_COMPLETE_CONNECTION_RECOVERY)) { - iscsit_increment_maxcmdsn(cmd, conn->sess); - cmd->stat_sn = conn->stat_sn++; - set_statsn = 1; - } else if (dr->dr_complete == - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY) - set_statsn = 1; - } - - hdr = (struct iscsi_data_rsp *) cmd->pdu; - memset(hdr, 0, ISCSI_HDR_LEN); - hdr->opcode = ISCSI_OP_SCSI_DATA_IN; - hdr->flags = datain.flags; - if (hdr->flags & ISCSI_FLAG_DATA_STATUS) { - if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) { - hdr->flags |= ISCSI_FLAG_DATA_OVERFLOW; - hdr->residual_count = cpu_to_be32(cmd->residual_count); - } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) { - hdr->flags |= ISCSI_FLAG_DATA_UNDERFLOW; - hdr->residual_count = cpu_to_be32(cmd->residual_count); - } - } - hton24(hdr->dlength, datain.length); - if (hdr->flags & ISCSI_FLAG_DATA_ACK) - int_to_scsilun(cmd->se_cmd.orig_fe_lun, - (struct scsi_lun *)&hdr->lun); - else - put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun); - - hdr->itt = cpu_to_be32(cmd->init_task_tag); - hdr->ttt = (hdr->flags & ISCSI_FLAG_DATA_ACK) ? - cpu_to_be32(cmd->targ_xfer_tag) : - 0xFFFFFFFF; - hdr->statsn = (set_statsn) ? cpu_to_be32(cmd->stat_sn) : - 0xFFFFFFFF; - hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - hdr->datasn = cpu_to_be32(datain.data_sn); - hdr->offset = cpu_to_be32(datain.offset); - - iov = &cmd->iov_data[0]; - iov[iov_count].iov_base = cmd->pdu; - iov[iov_count++].iov_len = ISCSI_HDR_LEN; - tx_size += ISCSI_HDR_LEN; - - if (conn->conn_ops->HeaderDigest) { - u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)hdr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)header_digest); - - iov[0].iov_len += ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - - pr_debug("Attaching CRC32 HeaderDigest" - " for DataIN PDU 0x%08x\n", *header_digest); - } - - iov_ret = iscsit_map_iovec(cmd, &cmd->iov_data[1], datain.offset, datain.length); - if (iov_ret < 0) - return -1; - - iov_count += iov_ret; - tx_size += datain.length; - - cmd->padding = ((-datain.length) & 3); - if (cmd->padding) { - iov[iov_count].iov_base = cmd->pad_bytes; - iov[iov_count++].iov_len = cmd->padding; - tx_size += cmd->padding; - - pr_debug("Attaching %u padding bytes\n", - cmd->padding); - } - if (conn->conn_ops->DataDigest) { - cmd->data_crc = iscsit_do_crypto_hash_sg(&conn->conn_tx_hash, cmd, - datain.offset, datain.length, cmd->padding, cmd->pad_bytes); - - iov[iov_count].iov_base = &cmd->data_crc; - iov[iov_count++].iov_len = ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - - pr_debug("Attached CRC32C DataDigest %d bytes, crc" - " 0x%08x\n", datain.length+cmd->padding, cmd->data_crc); - } - - cmd->iov_data_count = iov_count; - cmd->tx_size = tx_size; - - pr_debug("Built DataIN ITT: 0x%08x, StatSN: 0x%08x," - " DataSN: 0x%08x, Offset: %u, Length: %u, CID: %hu\n", - cmd->init_task_tag, ntohl(hdr->statsn), ntohl(hdr->datasn), - ntohl(hdr->offset), datain.length, conn->cid); - - if (dr->dr_complete) { - *eodr = (cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) ? - 2 : 1; - iscsit_free_datain_req(cmd, dr); - } - - return 0; -} - -static int iscsit_send_logout_response( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - int niov = 0, tx_size; - struct iscsi_conn *logout_conn = NULL; - struct iscsi_conn_recovery *cr = NULL; - struct iscsi_session *sess = conn->sess; - struct kvec *iov; - struct iscsi_logout_rsp *hdr; - /* - * The actual shutting down of Sessions and/or Connections - * for CLOSESESSION and CLOSECONNECTION Logout Requests - * is done in scsi_logout_post_handler(). - */ - switch (cmd->logout_reason) { - case ISCSI_LOGOUT_REASON_CLOSE_SESSION: - pr_debug("iSCSI session logout successful, setting" - " logout response to ISCSI_LOGOUT_SUCCESS.\n"); - cmd->logout_response = ISCSI_LOGOUT_SUCCESS; - break; - case ISCSI_LOGOUT_REASON_CLOSE_CONNECTION: - if (cmd->logout_response == ISCSI_LOGOUT_CID_NOT_FOUND) - break; - /* - * For CLOSECONNECTION logout requests carrying - * a matching logout CID -> local CID, the reference - * for the local CID will have been incremented in - * iscsi_logout_closeconnection(). - * - * For CLOSECONNECTION logout requests carrying - * a different CID than the connection it arrived - * on, the connection responding to cmd->logout_cid - * is stopped in iscsit_logout_post_handler_diffcid(). - */ - - pr_debug("iSCSI CID: %hu logout on CID: %hu" - " successful.\n", cmd->logout_cid, conn->cid); - cmd->logout_response = ISCSI_LOGOUT_SUCCESS; - break; - case ISCSI_LOGOUT_REASON_RECOVERY: - if ((cmd->logout_response == ISCSI_LOGOUT_RECOVERY_UNSUPPORTED) || - (cmd->logout_response == ISCSI_LOGOUT_CLEANUP_FAILED)) - break; - /* - * If the connection is still active from our point of view - * force connection recovery to occur. - */ - logout_conn = iscsit_get_conn_from_cid_rcfr(sess, - cmd->logout_cid); - if ((logout_conn)) { - iscsit_connection_reinstatement_rcfr(logout_conn); - iscsit_dec_conn_usage_count(logout_conn); - } - - cr = iscsit_get_inactive_connection_recovery_entry( - conn->sess, cmd->logout_cid); - if (!cr) { - pr_err("Unable to locate CID: %hu for" - " REMOVECONNFORRECOVERY Logout Request.\n", - cmd->logout_cid); - cmd->logout_response = ISCSI_LOGOUT_CID_NOT_FOUND; - break; - } - - iscsit_discard_cr_cmds_by_expstatsn(cr, cmd->exp_stat_sn); - - pr_debug("iSCSI REMOVECONNFORRECOVERY logout" - " for recovery for CID: %hu on CID: %hu successful.\n", - cmd->logout_cid, conn->cid); - cmd->logout_response = ISCSI_LOGOUT_SUCCESS; - break; - default: - pr_err("Unknown cmd->logout_reason: 0x%02x\n", - cmd->logout_reason); - return -1; - } - - tx_size = ISCSI_HDR_LEN; - hdr = (struct iscsi_logout_rsp *)cmd->pdu; - memset(hdr, 0, ISCSI_HDR_LEN); - hdr->opcode = ISCSI_OP_LOGOUT_RSP; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - hdr->response = cmd->logout_response; - hdr->itt = cpu_to_be32(cmd->init_task_tag); - cmd->stat_sn = conn->stat_sn++; - hdr->statsn = cpu_to_be32(cmd->stat_sn); - - iscsit_increment_maxcmdsn(cmd, conn->sess); - hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - - iov = &cmd->iov_misc[0]; - iov[niov].iov_base = cmd->pdu; - iov[niov++].iov_len = ISCSI_HDR_LEN; - - if (conn->conn_ops->HeaderDigest) { - u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)hdr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)header_digest); - - iov[0].iov_len += ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - pr_debug("Attaching CRC32C HeaderDigest to" - " Logout Response 0x%08x\n", *header_digest); - } - cmd->iov_misc_count = niov; - cmd->tx_size = tx_size; - - pr_debug("Sending Logout Response ITT: 0x%08x StatSN:" - " 0x%08x Response: 0x%02x CID: %hu on CID: %hu\n", - cmd->init_task_tag, cmd->stat_sn, hdr->response, - cmd->logout_cid, conn->cid); - - return 0; -} - -/* - * Unsolicited NOPIN, either requesting a response or not. - */ -static int iscsit_send_unsolicited_nopin( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn, - int want_response) -{ - int tx_size = ISCSI_HDR_LEN; - struct iscsi_nopin *hdr; - - hdr = (struct iscsi_nopin *) cmd->pdu; - memset(hdr, 0, ISCSI_HDR_LEN); - hdr->opcode = ISCSI_OP_NOOP_IN; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - hdr->itt = cpu_to_be32(cmd->init_task_tag); - hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag); - cmd->stat_sn = conn->stat_sn; - hdr->statsn = cpu_to_be32(cmd->stat_sn); - hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - - if (conn->conn_ops->HeaderDigest) { - u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)hdr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)header_digest); - - tx_size += ISCSI_CRC_LEN; - pr_debug("Attaching CRC32C HeaderDigest to" - " NopIN 0x%08x\n", *header_digest); - } - - cmd->iov_misc[0].iov_base = cmd->pdu; - cmd->iov_misc[0].iov_len = tx_size; - cmd->iov_misc_count = 1; - cmd->tx_size = tx_size; - - pr_debug("Sending Unsolicited NOPIN TTT: 0x%08x StatSN:" - " 0x%08x CID: %hu\n", hdr->ttt, cmd->stat_sn, conn->cid); - - return 0; -} - -static int iscsit_send_nopin_response( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - int niov = 0, tx_size; - u32 padding = 0; - struct kvec *iov; - struct iscsi_nopin *hdr; - - tx_size = ISCSI_HDR_LEN; - hdr = (struct iscsi_nopin *) cmd->pdu; - memset(hdr, 0, ISCSI_HDR_LEN); - hdr->opcode = ISCSI_OP_NOOP_IN; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - hton24(hdr->dlength, cmd->buf_ptr_size); - put_unaligned_le64(0xFFFFFFFFFFFFFFFFULL, &hdr->lun); - hdr->itt = cpu_to_be32(cmd->init_task_tag); - hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag); - cmd->stat_sn = conn->stat_sn++; - hdr->statsn = cpu_to_be32(cmd->stat_sn); - - iscsit_increment_maxcmdsn(cmd, conn->sess); - hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - - iov = &cmd->iov_misc[0]; - iov[niov].iov_base = cmd->pdu; - iov[niov++].iov_len = ISCSI_HDR_LEN; - - if (conn->conn_ops->HeaderDigest) { - u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)hdr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)header_digest); - - iov[0].iov_len += ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - pr_debug("Attaching CRC32C HeaderDigest" - " to NopIn 0x%08x\n", *header_digest); - } - - /* - * NOPOUT Ping Data is attached to struct iscsi_cmd->buf_ptr. - * NOPOUT DataSegmentLength is at struct iscsi_cmd->buf_ptr_size. - */ - if (cmd->buf_ptr_size) { - iov[niov].iov_base = cmd->buf_ptr; - iov[niov++].iov_len = cmd->buf_ptr_size; - tx_size += cmd->buf_ptr_size; - - pr_debug("Echoing back %u bytes of ping" - " data.\n", cmd->buf_ptr_size); - - padding = ((-cmd->buf_ptr_size) & 3); - if (padding != 0) { - iov[niov].iov_base = &cmd->pad_bytes; - iov[niov++].iov_len = padding; - tx_size += padding; - pr_debug("Attaching %u additional" - " padding bytes.\n", padding); - } - if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - cmd->buf_ptr, cmd->buf_ptr_size, - padding, (u8 *)&cmd->pad_bytes, - (u8 *)&cmd->data_crc); - - iov[niov].iov_base = &cmd->data_crc; - iov[niov++].iov_len = ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - pr_debug("Attached DataDigest for %u" - " bytes of ping data, CRC 0x%08x\n", - cmd->buf_ptr_size, cmd->data_crc); - } - } - - cmd->iov_misc_count = niov; - cmd->tx_size = tx_size; - - pr_debug("Sending NOPIN Response ITT: 0x%08x, TTT:" - " 0x%08x, StatSN: 0x%08x, Length %u\n", cmd->init_task_tag, - cmd->targ_xfer_tag, cmd->stat_sn, cmd->buf_ptr_size); - - return 0; -} - -int iscsit_send_r2t( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - int tx_size = 0; - struct iscsi_r2t *r2t; - struct iscsi_r2t_rsp *hdr; - - r2t = iscsit_get_r2t_from_list(cmd); - if (!r2t) - return -1; - - hdr = (struct iscsi_r2t_rsp *) cmd->pdu; - memset(hdr, 0, ISCSI_HDR_LEN); - hdr->opcode = ISCSI_OP_R2T; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - int_to_scsilun(cmd->se_cmd.orig_fe_lun, - (struct scsi_lun *)&hdr->lun); - hdr->itt = cpu_to_be32(cmd->init_task_tag); - spin_lock_bh(&conn->sess->ttt_lock); - r2t->targ_xfer_tag = conn->sess->targ_xfer_tag++; - if (r2t->targ_xfer_tag == 0xFFFFFFFF) - r2t->targ_xfer_tag = conn->sess->targ_xfer_tag++; - spin_unlock_bh(&conn->sess->ttt_lock); - hdr->ttt = cpu_to_be32(r2t->targ_xfer_tag); - hdr->statsn = cpu_to_be32(conn->stat_sn); - hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - hdr->r2tsn = cpu_to_be32(r2t->r2t_sn); - hdr->data_offset = cpu_to_be32(r2t->offset); - hdr->data_length = cpu_to_be32(r2t->xfer_len); - - cmd->iov_misc[0].iov_base = cmd->pdu; - cmd->iov_misc[0].iov_len = ISCSI_HDR_LEN; - tx_size += ISCSI_HDR_LEN; - - if (conn->conn_ops->HeaderDigest) { - u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)hdr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)header_digest); - - cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - pr_debug("Attaching CRC32 HeaderDigest for R2T" - " PDU 0x%08x\n", *header_digest); - } - - pr_debug("Built %sR2T, ITT: 0x%08x, TTT: 0x%08x, StatSN:" - " 0x%08x, R2TSN: 0x%08x, Offset: %u, DDTL: %u, CID: %hu\n", - (!r2t->recovery_r2t) ? "" : "Recovery ", cmd->init_task_tag, - r2t->targ_xfer_tag, ntohl(hdr->statsn), r2t->r2t_sn, - r2t->offset, r2t->xfer_len, conn->cid); - - cmd->iov_misc_count = 1; - cmd->tx_size = tx_size; - - spin_lock_bh(&cmd->r2t_lock); - r2t->sent_r2t = 1; - spin_unlock_bh(&cmd->r2t_lock); - - return 0; -} - -/* - * type 0: Normal Operation. - * type 1: Called from Storage Transport. - * type 2: Called from iscsi_task_reassign_complete_write() for - * connection recovery. - */ -int iscsit_build_r2ts_for_cmd( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn, - int type) -{ - int first_r2t = 1; - u32 offset = 0, xfer_len = 0; - - spin_lock_bh(&cmd->r2t_lock); - if (cmd->cmd_flags & ICF_SENT_LAST_R2T) { - spin_unlock_bh(&cmd->r2t_lock); - return 0; - } - - if (conn->sess->sess_ops->DataSequenceInOrder && (type != 2)) - if (cmd->r2t_offset < cmd->write_data_done) - cmd->r2t_offset = cmd->write_data_done; - - while (cmd->outstanding_r2ts < conn->sess->sess_ops->MaxOutstandingR2T) { - if (conn->sess->sess_ops->DataSequenceInOrder) { - offset = cmd->r2t_offset; - - if (first_r2t && (type == 2)) { - xfer_len = ((offset + - (conn->sess->sess_ops->MaxBurstLength - - cmd->next_burst_len) > - cmd->data_length) ? - (cmd->data_length - offset) : - (conn->sess->sess_ops->MaxBurstLength - - cmd->next_burst_len)); - } else { - xfer_len = ((offset + - conn->sess->sess_ops->MaxBurstLength) > - cmd->data_length) ? - (cmd->data_length - offset) : - conn->sess->sess_ops->MaxBurstLength; - } - cmd->r2t_offset += xfer_len; - - if (cmd->r2t_offset == cmd->data_length) - cmd->cmd_flags |= ICF_SENT_LAST_R2T; - } else { - struct iscsi_seq *seq; - - seq = iscsit_get_seq_holder_for_r2t(cmd); - if (!seq) { - spin_unlock_bh(&cmd->r2t_lock); - return -1; - } - - offset = seq->offset; - xfer_len = seq->xfer_len; - - if (cmd->seq_send_order == cmd->seq_count) - cmd->cmd_flags |= ICF_SENT_LAST_R2T; - } - cmd->outstanding_r2ts++; - first_r2t = 0; - - if (iscsit_add_r2t_to_list(cmd, offset, xfer_len, 0, 0) < 0) { - spin_unlock_bh(&cmd->r2t_lock); - return -1; - } - - if (cmd->cmd_flags & ICF_SENT_LAST_R2T) - break; - } - spin_unlock_bh(&cmd->r2t_lock); - - return 0; -} - -static int iscsit_send_status( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - u8 iov_count = 0, recovery; - u32 padding = 0, tx_size = 0; - struct iscsi_scsi_rsp *hdr; - struct kvec *iov; - - recovery = (cmd->i_state != ISTATE_SEND_STATUS); - if (!recovery) - cmd->stat_sn = conn->stat_sn++; - - spin_lock_bh(&conn->sess->session_stats_lock); - conn->sess->rsp_pdus++; - spin_unlock_bh(&conn->sess->session_stats_lock); - - hdr = (struct iscsi_scsi_rsp *) cmd->pdu; - memset(hdr, 0, ISCSI_HDR_LEN); - hdr->opcode = ISCSI_OP_SCSI_CMD_RSP; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - if (cmd->se_cmd.se_cmd_flags & SCF_OVERFLOW_BIT) { - hdr->flags |= ISCSI_FLAG_CMD_OVERFLOW; - hdr->residual_count = cpu_to_be32(cmd->residual_count); - } else if (cmd->se_cmd.se_cmd_flags & SCF_UNDERFLOW_BIT) { - hdr->flags |= ISCSI_FLAG_CMD_UNDERFLOW; - hdr->residual_count = cpu_to_be32(cmd->residual_count); - } - hdr->response = cmd->iscsi_response; - hdr->cmd_status = cmd->se_cmd.scsi_status; - hdr->itt = cpu_to_be32(cmd->init_task_tag); - hdr->statsn = cpu_to_be32(cmd->stat_sn); - - iscsit_increment_maxcmdsn(cmd, conn->sess); - hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - - iov = &cmd->iov_misc[0]; - iov[iov_count].iov_base = cmd->pdu; - iov[iov_count++].iov_len = ISCSI_HDR_LEN; - tx_size += ISCSI_HDR_LEN; - - /* - * Attach SENSE DATA payload to iSCSI Response PDU - */ - if (cmd->se_cmd.sense_buffer && - ((cmd->se_cmd.se_cmd_flags & SCF_TRANSPORT_TASK_SENSE) || - (cmd->se_cmd.se_cmd_flags & SCF_EMULATED_TASK_SENSE))) { - padding = -(cmd->se_cmd.scsi_sense_length) & 3; - hton24(hdr->dlength, cmd->se_cmd.scsi_sense_length); - iov[iov_count].iov_base = cmd->se_cmd.sense_buffer; - iov[iov_count++].iov_len = - (cmd->se_cmd.scsi_sense_length + padding); - tx_size += cmd->se_cmd.scsi_sense_length; - - if (padding) { - memset(cmd->se_cmd.sense_buffer + - cmd->se_cmd.scsi_sense_length, 0, padding); - tx_size += padding; - pr_debug("Adding %u bytes of padding to" - " SENSE.\n", padding); - } - - if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - cmd->se_cmd.sense_buffer, - (cmd->se_cmd.scsi_sense_length + padding), - 0, NULL, (u8 *)&cmd->data_crc); - - iov[iov_count].iov_base = &cmd->data_crc; - iov[iov_count++].iov_len = ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - - pr_debug("Attaching CRC32 DataDigest for" - " SENSE, %u bytes CRC 0x%08x\n", - (cmd->se_cmd.scsi_sense_length + padding), - cmd->data_crc); - } - - pr_debug("Attaching SENSE DATA: %u bytes to iSCSI" - " Response PDU\n", - cmd->se_cmd.scsi_sense_length); - } - - if (conn->conn_ops->HeaderDigest) { - u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)hdr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)header_digest); - - iov[0].iov_len += ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - pr_debug("Attaching CRC32 HeaderDigest for Response" - " PDU 0x%08x\n", *header_digest); - } - - cmd->iov_misc_count = iov_count; - cmd->tx_size = tx_size; - - pr_debug("Built %sSCSI Response, ITT: 0x%08x, StatSN: 0x%08x," - " Response: 0x%02x, SAM Status: 0x%02x, CID: %hu\n", - (!recovery) ? "" : "Recovery ", cmd->init_task_tag, - cmd->stat_sn, 0x00, cmd->se_cmd.scsi_status, conn->cid); - - return 0; -} - -static u8 iscsit_convert_tcm_tmr_rsp(struct se_tmr_req *se_tmr) -{ - switch (se_tmr->response) { - case TMR_FUNCTION_COMPLETE: - return ISCSI_TMF_RSP_COMPLETE; - case TMR_TASK_DOES_NOT_EXIST: - return ISCSI_TMF_RSP_NO_TASK; - case TMR_LUN_DOES_NOT_EXIST: - return ISCSI_TMF_RSP_NO_LUN; - case TMR_TASK_MGMT_FUNCTION_NOT_SUPPORTED: - return ISCSI_TMF_RSP_NOT_SUPPORTED; - case TMR_FUNCTION_AUTHORIZATION_FAILED: - return ISCSI_TMF_RSP_AUTH_FAILED; - case TMR_FUNCTION_REJECTED: - default: - return ISCSI_TMF_RSP_REJECTED; - } -} - -static int iscsit_send_task_mgt_rsp( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req; - struct iscsi_tm_rsp *hdr; - u32 tx_size = 0; - - hdr = (struct iscsi_tm_rsp *) cmd->pdu; - memset(hdr, 0, ISCSI_HDR_LEN); - hdr->opcode = ISCSI_OP_SCSI_TMFUNC_RSP; - hdr->response = iscsit_convert_tcm_tmr_rsp(se_tmr); - hdr->itt = cpu_to_be32(cmd->init_task_tag); - cmd->stat_sn = conn->stat_sn++; - hdr->statsn = cpu_to_be32(cmd->stat_sn); - - iscsit_increment_maxcmdsn(cmd, conn->sess); - hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - - cmd->iov_misc[0].iov_base = cmd->pdu; - cmd->iov_misc[0].iov_len = ISCSI_HDR_LEN; - tx_size += ISCSI_HDR_LEN; - - if (conn->conn_ops->HeaderDigest) { - u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)hdr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)header_digest); - - cmd->iov_misc[0].iov_len += ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - pr_debug("Attaching CRC32 HeaderDigest for Task" - " Mgmt Response PDU 0x%08x\n", *header_digest); - } - - cmd->iov_misc_count = 1; - cmd->tx_size = tx_size; - - pr_debug("Built Task Management Response ITT: 0x%08x," - " StatSN: 0x%08x, Response: 0x%02x, CID: %hu\n", - cmd->init_task_tag, cmd->stat_sn, hdr->response, conn->cid); - - return 0; -} - -static int iscsit_build_sendtargets_response(struct iscsi_cmd *cmd) -{ - char *payload = NULL; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_portal_group *tpg; - struct iscsi_tiqn *tiqn; - struct iscsi_tpg_np *tpg_np; - int buffer_len, end_of_buf = 0, len = 0, payload_len = 0; - unsigned char buf[256]; - - buffer_len = (conn->conn_ops->MaxRecvDataSegmentLength > 32768) ? - 32768 : conn->conn_ops->MaxRecvDataSegmentLength; - - memset(buf, 0, 256); - - payload = kzalloc(buffer_len, GFP_KERNEL); - if (!payload) { - pr_err("Unable to allocate memory for sendtargets" - " response.\n"); - return -ENOMEM; - } - - spin_lock(&tiqn_lock); - list_for_each_entry(tiqn, &g_tiqn_list, tiqn_list) { - len = sprintf(buf, "TargetName=%s", tiqn->tiqn); - len += 1; - - if ((len + payload_len) > buffer_len) { - spin_unlock(&tiqn->tiqn_tpg_lock); - end_of_buf = 1; - goto eob; - } - memcpy((void *)payload + payload_len, buf, len); - payload_len += len; - - spin_lock(&tiqn->tiqn_tpg_lock); - list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) { - - spin_lock(&tpg->tpg_state_lock); - if ((tpg->tpg_state == TPG_STATE_FREE) || - (tpg->tpg_state == TPG_STATE_INACTIVE)) { - spin_unlock(&tpg->tpg_state_lock); - continue; - } - spin_unlock(&tpg->tpg_state_lock); - - spin_lock(&tpg->tpg_np_lock); - list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, - tpg_np_list) { - len = sprintf(buf, "TargetAddress=" - "%s%s%s:%hu,%hu", - (tpg_np->tpg_np->np_sockaddr.ss_family == AF_INET6) ? - "[" : "", tpg_np->tpg_np->np_ip, - (tpg_np->tpg_np->np_sockaddr.ss_family == AF_INET6) ? - "]" : "", tpg_np->tpg_np->np_port, - tpg->tpgt); - len += 1; - - if ((len + payload_len) > buffer_len) { - spin_unlock(&tpg->tpg_np_lock); - spin_unlock(&tiqn->tiqn_tpg_lock); - end_of_buf = 1; - goto eob; - } - memcpy((void *)payload + payload_len, buf, len); - payload_len += len; - } - spin_unlock(&tpg->tpg_np_lock); - } - spin_unlock(&tiqn->tiqn_tpg_lock); -eob: - if (end_of_buf) - break; - } - spin_unlock(&tiqn_lock); - - cmd->buf_ptr = payload; - - return payload_len; -} - -/* - * FIXME: Add support for F_BIT and C_BIT when the length is longer than - * MaxRecvDataSegmentLength. - */ -static int iscsit_send_text_rsp( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - struct iscsi_text_rsp *hdr; - struct kvec *iov; - u32 padding = 0, tx_size = 0; - int text_length, iov_count = 0; - - text_length = iscsit_build_sendtargets_response(cmd); - if (text_length < 0) - return text_length; - - padding = ((-text_length) & 3); - if (padding != 0) { - memset(cmd->buf_ptr + text_length, 0, padding); - pr_debug("Attaching %u additional bytes for" - " padding.\n", padding); - } - - hdr = (struct iscsi_text_rsp *) cmd->pdu; - memset(hdr, 0, ISCSI_HDR_LEN); - hdr->opcode = ISCSI_OP_TEXT_RSP; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - hton24(hdr->dlength, text_length); - hdr->itt = cpu_to_be32(cmd->init_task_tag); - hdr->ttt = cpu_to_be32(cmd->targ_xfer_tag); - cmd->stat_sn = conn->stat_sn++; - hdr->statsn = cpu_to_be32(cmd->stat_sn); - - iscsit_increment_maxcmdsn(cmd, conn->sess); - hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - - iov = &cmd->iov_misc[0]; - - iov[iov_count].iov_base = cmd->pdu; - iov[iov_count++].iov_len = ISCSI_HDR_LEN; - iov[iov_count].iov_base = cmd->buf_ptr; - iov[iov_count++].iov_len = text_length + padding; - - tx_size += (ISCSI_HDR_LEN + text_length + padding); - - if (conn->conn_ops->HeaderDigest) { - u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)hdr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)header_digest); - - iov[0].iov_len += ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - pr_debug("Attaching CRC32 HeaderDigest for" - " Text Response PDU 0x%08x\n", *header_digest); - } - - if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - cmd->buf_ptr, (text_length + padding), - 0, NULL, (u8 *)&cmd->data_crc); - - iov[iov_count].iov_base = &cmd->data_crc; - iov[iov_count++].iov_len = ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - - pr_debug("Attaching DataDigest for %u bytes of text" - " data, CRC 0x%08x\n", (text_length + padding), - cmd->data_crc); - } - - cmd->iov_misc_count = iov_count; - cmd->tx_size = tx_size; - - pr_debug("Built Text Response: ITT: 0x%08x, StatSN: 0x%08x," - " Length: %u, CID: %hu\n", cmd->init_task_tag, cmd->stat_sn, - text_length, conn->cid); - return 0; -} - -static int iscsit_send_reject( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - u32 iov_count = 0, tx_size = 0; - struct iscsi_reject *hdr; - struct kvec *iov; - - hdr = (struct iscsi_reject *) cmd->pdu; - hdr->opcode = ISCSI_OP_REJECT; - hdr->flags |= ISCSI_FLAG_CMD_FINAL; - hton24(hdr->dlength, ISCSI_HDR_LEN); - cmd->stat_sn = conn->stat_sn++; - hdr->statsn = cpu_to_be32(cmd->stat_sn); - hdr->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - hdr->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - - iov = &cmd->iov_misc[0]; - - iov[iov_count].iov_base = cmd->pdu; - iov[iov_count++].iov_len = ISCSI_HDR_LEN; - iov[iov_count].iov_base = cmd->buf_ptr; - iov[iov_count++].iov_len = ISCSI_HDR_LEN; - - tx_size = (ISCSI_HDR_LEN + ISCSI_HDR_LEN); - - if (conn->conn_ops->HeaderDigest) { - u32 *header_digest = (u32 *)&cmd->pdu[ISCSI_HDR_LEN]; - - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)hdr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)header_digest); - - iov[0].iov_len += ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - pr_debug("Attaching CRC32 HeaderDigest for" - " REJECT PDU 0x%08x\n", *header_digest); - } - - if (conn->conn_ops->DataDigest) { - iscsit_do_crypto_hash_buf(&conn->conn_tx_hash, - (unsigned char *)cmd->buf_ptr, ISCSI_HDR_LEN, - 0, NULL, (u8 *)&cmd->data_crc); - - iov[iov_count].iov_base = &cmd->data_crc; - iov[iov_count++].iov_len = ISCSI_CRC_LEN; - tx_size += ISCSI_CRC_LEN; - pr_debug("Attaching CRC32 DataDigest for REJECT" - " PDU 0x%08x\n", cmd->data_crc); - } - - cmd->iov_misc_count = iov_count; - cmd->tx_size = tx_size; - - pr_debug("Built Reject PDU StatSN: 0x%08x, Reason: 0x%02x," - " CID: %hu\n", ntohl(hdr->statsn), hdr->reason, conn->cid); - - return 0; -} - -static void iscsit_tx_thread_wait_for_tcp(struct iscsi_conn *conn) -{ - if ((conn->sock->sk->sk_shutdown & SEND_SHUTDOWN) || - (conn->sock->sk->sk_shutdown & RCV_SHUTDOWN)) { - wait_for_completion_interruptible_timeout( - &conn->tx_half_close_comp, - ISCSI_TX_THREAD_TCP_TIMEOUT * HZ); - } -} - -#ifdef CONFIG_SMP - -void iscsit_thread_get_cpumask(struct iscsi_conn *conn) -{ - struct iscsi_thread_set *ts = conn->thread_set; - int ord, cpu; - /* - * thread_id is assigned from iscsit_global->ts_bitmap from - * within iscsi_thread_set.c:iscsi_allocate_thread_sets() - * - * Here we use thread_id to determine which CPU that this - * iSCSI connection's iscsi_thread_set will be scheduled to - * execute upon. - */ - ord = ts->thread_id % cpumask_weight(cpu_online_mask); -#if 0 - pr_debug(">>>>>>>>>>>>>>>>>>>> Generated ord: %d from" - " thread_id: %d\n", ord, ts->thread_id); -#endif - for_each_online_cpu(cpu) { - if (ord-- == 0) { - cpumask_set_cpu(cpu, conn->conn_cpumask); - return; - } - } - /* - * This should never be reached.. - */ - dump_stack(); - cpumask_setall(conn->conn_cpumask); -} - -static inline void iscsit_thread_check_cpumask( - struct iscsi_conn *conn, - struct task_struct *p, - int mode) -{ - char buf[128]; - /* - * mode == 1 signals iscsi_target_tx_thread() usage. - * mode == 0 signals iscsi_target_rx_thread() usage. - */ - if (mode == 1) { - if (!conn->conn_tx_reset_cpumask) - return; - conn->conn_tx_reset_cpumask = 0; - } else { - if (!conn->conn_rx_reset_cpumask) - return; - conn->conn_rx_reset_cpumask = 0; - } - /* - * Update the CPU mask for this single kthread so that - * both TX and RX kthreads are scheduled to run on the - * same CPU. - */ - memset(buf, 0, 128); - cpumask_scnprintf(buf, 128, conn->conn_cpumask); -#if 0 - pr_debug(">>>>>>>>>>>>>> Calling set_cpus_allowed_ptr():" - " %s for %s\n", buf, p->comm); -#endif - set_cpus_allowed_ptr(p, conn->conn_cpumask); -} - -#else -#define iscsit_thread_get_cpumask(X) ({}) -#define iscsit_thread_check_cpumask(X, Y, Z) ({}) -#endif /* CONFIG_SMP */ - -int iscsi_target_tx_thread(void *arg) -{ - u8 state; - int eodr = 0; - int ret = 0; - int sent_status = 0; - int use_misc = 0; - int map_sg = 0; - struct iscsi_cmd *cmd = NULL; - struct iscsi_conn *conn; - struct iscsi_queue_req *qr = NULL; - struct se_cmd *se_cmd; - struct iscsi_thread_set *ts = (struct iscsi_thread_set *)arg; - /* - * Allow ourselves to be interrupted by SIGINT so that a - * connection recovery / failure event can be triggered externally. - */ - allow_signal(SIGINT); - -restart: - conn = iscsi_tx_thread_pre_handler(ts); - if (!conn) - goto out; - - eodr = map_sg = ret = sent_status = use_misc = 0; - - while (!kthread_should_stop()) { - /* - * Ensure that both TX and RX per connection kthreads - * are scheduled to run on the same CPU. - */ - iscsit_thread_check_cpumask(conn, current, 1); - - schedule_timeout_interruptible(MAX_SCHEDULE_TIMEOUT); - - if ((ts->status == ISCSI_THREAD_SET_RESET) || - signal_pending(current)) - goto transport_err; - -get_immediate: - qr = iscsit_get_cmd_from_immediate_queue(conn); - if (qr) { - atomic_set(&conn->check_immediate_queue, 0); - cmd = qr->cmd; - state = qr->state; - kmem_cache_free(lio_qr_cache, qr); - - spin_lock_bh(&cmd->istate_lock); - switch (state) { - case ISTATE_SEND_R2T: - spin_unlock_bh(&cmd->istate_lock); - ret = iscsit_send_r2t(cmd, conn); - break; - case ISTATE_REMOVE: - spin_unlock_bh(&cmd->istate_lock); - - if (cmd->data_direction == DMA_TO_DEVICE) - iscsit_stop_dataout_timer(cmd); - - spin_lock_bh(&conn->cmd_lock); - list_del(&cmd->i_list); - spin_unlock_bh(&conn->cmd_lock); - /* - * Determine if a struct se_cmd is assoicated with - * this struct iscsi_cmd. - */ - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) && - !(cmd->tmr_req)) - iscsit_release_cmd(cmd); - else - transport_generic_free_cmd(&cmd->se_cmd, - 1, 0); - goto get_immediate; - case ISTATE_SEND_NOPIN_WANT_RESPONSE: - spin_unlock_bh(&cmd->istate_lock); - iscsit_mod_nopin_response_timer(conn); - ret = iscsit_send_unsolicited_nopin(cmd, - conn, 1); - break; - case ISTATE_SEND_NOPIN_NO_RESPONSE: - spin_unlock_bh(&cmd->istate_lock); - ret = iscsit_send_unsolicited_nopin(cmd, - conn, 0); - break; - default: - pr_err("Unknown Opcode: 0x%02x ITT:" - " 0x%08x, i_state: %d on CID: %hu\n", - cmd->iscsi_opcode, cmd->init_task_tag, state, - conn->cid); - spin_unlock_bh(&cmd->istate_lock); - goto transport_err; - } - if (ret < 0) { - conn->tx_immediate_queue = 0; - goto transport_err; - } - - if (iscsit_send_tx_data(cmd, conn, 1) < 0) { - conn->tx_immediate_queue = 0; - iscsit_tx_thread_wait_for_tcp(conn); - goto transport_err; - } - - spin_lock_bh(&cmd->istate_lock); - switch (state) { - case ISTATE_SEND_R2T: - spin_unlock_bh(&cmd->istate_lock); - spin_lock_bh(&cmd->dataout_timeout_lock); - iscsit_start_dataout_timer(cmd, conn); - spin_unlock_bh(&cmd->dataout_timeout_lock); - break; - case ISTATE_SEND_NOPIN_WANT_RESPONSE: - cmd->i_state = ISTATE_SENT_NOPIN_WANT_RESPONSE; - spin_unlock_bh(&cmd->istate_lock); - break; - case ISTATE_SEND_NOPIN_NO_RESPONSE: - cmd->i_state = ISTATE_SENT_STATUS; - spin_unlock_bh(&cmd->istate_lock); - break; - default: - pr_err("Unknown Opcode: 0x%02x ITT:" - " 0x%08x, i_state: %d on CID: %hu\n", - cmd->iscsi_opcode, cmd->init_task_tag, - state, conn->cid); - spin_unlock_bh(&cmd->istate_lock); - goto transport_err; - } - goto get_immediate; - } else - conn->tx_immediate_queue = 0; - -get_response: - qr = iscsit_get_cmd_from_response_queue(conn); - if (qr) { - cmd = qr->cmd; - state = qr->state; - kmem_cache_free(lio_qr_cache, qr); - - spin_lock_bh(&cmd->istate_lock); -check_rsp_state: - switch (state) { - case ISTATE_SEND_DATAIN: - spin_unlock_bh(&cmd->istate_lock); - ret = iscsit_send_data_in(cmd, conn, - &eodr); - map_sg = 1; - break; - case ISTATE_SEND_STATUS: - case ISTATE_SEND_STATUS_RECOVERY: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_status(cmd, conn); - break; - case ISTATE_SEND_LOGOUTRSP: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_logout_response(cmd, conn); - break; - case ISTATE_SEND_ASYNCMSG: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_conn_drop_async_message( - cmd, conn); - break; - case ISTATE_SEND_NOPIN: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_nopin_response(cmd, conn); - break; - case ISTATE_SEND_REJECT: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_reject(cmd, conn); - break; - case ISTATE_SEND_TASKMGTRSP: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_task_mgt_rsp(cmd, conn); - if (ret != 0) - break; - ret = iscsit_tmr_post_handler(cmd, conn); - if (ret != 0) - iscsit_fall_back_to_erl0(conn->sess); - break; - case ISTATE_SEND_TEXTRSP: - spin_unlock_bh(&cmd->istate_lock); - use_misc = 1; - ret = iscsit_send_text_rsp(cmd, conn); - break; - default: - pr_err("Unknown Opcode: 0x%02x ITT:" - " 0x%08x, i_state: %d on CID: %hu\n", - cmd->iscsi_opcode, cmd->init_task_tag, - state, conn->cid); - spin_unlock_bh(&cmd->istate_lock); - goto transport_err; - } - if (ret < 0) { - conn->tx_response_queue = 0; - goto transport_err; - } - - se_cmd = &cmd->se_cmd; - - if (map_sg && !conn->conn_ops->IFMarker) { - if (iscsit_fe_sendpage_sg(cmd, conn) < 0) { - conn->tx_response_queue = 0; - iscsit_tx_thread_wait_for_tcp(conn); - iscsit_unmap_iovec(cmd); - goto transport_err; - } - } else { - if (iscsit_send_tx_data(cmd, conn, use_misc) < 0) { - conn->tx_response_queue = 0; - iscsit_tx_thread_wait_for_tcp(conn); - iscsit_unmap_iovec(cmd); - goto transport_err; - } - } - map_sg = 0; - iscsit_unmap_iovec(cmd); - - spin_lock_bh(&cmd->istate_lock); - switch (state) { - case ISTATE_SEND_DATAIN: - if (!eodr) - goto check_rsp_state; - - if (eodr == 1) { - cmd->i_state = ISTATE_SENT_LAST_DATAIN; - sent_status = 1; - eodr = use_misc = 0; - } else if (eodr == 2) { - cmd->i_state = state = - ISTATE_SEND_STATUS; - sent_status = 0; - eodr = use_misc = 0; - goto check_rsp_state; - } - break; - case ISTATE_SEND_STATUS: - use_misc = 0; - sent_status = 1; - break; - case ISTATE_SEND_ASYNCMSG: - case ISTATE_SEND_NOPIN: - case ISTATE_SEND_STATUS_RECOVERY: - case ISTATE_SEND_TEXTRSP: - use_misc = 0; - sent_status = 1; - break; - case ISTATE_SEND_REJECT: - use_misc = 0; - if (cmd->cmd_flags & ICF_REJECT_FAIL_CONN) { - cmd->cmd_flags &= ~ICF_REJECT_FAIL_CONN; - spin_unlock_bh(&cmd->istate_lock); - complete(&cmd->reject_comp); - goto transport_err; - } - complete(&cmd->reject_comp); - break; - case ISTATE_SEND_TASKMGTRSP: - use_misc = 0; - sent_status = 1; - break; - case ISTATE_SEND_LOGOUTRSP: - spin_unlock_bh(&cmd->istate_lock); - if (!iscsit_logout_post_handler(cmd, conn)) - goto restart; - spin_lock_bh(&cmd->istate_lock); - use_misc = 0; - sent_status = 1; - break; - default: - pr_err("Unknown Opcode: 0x%02x ITT:" - " 0x%08x, i_state: %d on CID: %hu\n", - cmd->iscsi_opcode, cmd->init_task_tag, - cmd->i_state, conn->cid); - spin_unlock_bh(&cmd->istate_lock); - goto transport_err; - } - - if (sent_status) { - cmd->i_state = ISTATE_SENT_STATUS; - sent_status = 0; - } - spin_unlock_bh(&cmd->istate_lock); - - if (atomic_read(&conn->check_immediate_queue)) - goto get_immediate; - - goto get_response; - } else - conn->tx_response_queue = 0; - } - -transport_err: - iscsit_take_action_for_connection_exit(conn); - goto restart; -out: - return 0; -} - -int iscsi_target_rx_thread(void *arg) -{ - int ret; - u8 buffer[ISCSI_HDR_LEN], opcode; - u32 checksum = 0, digest = 0; - struct iscsi_conn *conn = NULL; - struct iscsi_thread_set *ts = (struct iscsi_thread_set *)arg; - struct kvec iov; - /* - * Allow ourselves to be interrupted by SIGINT so that a - * connection recovery / failure event can be triggered externally. - */ - allow_signal(SIGINT); - -restart: - conn = iscsi_rx_thread_pre_handler(ts); - if (!conn) - goto out; - - while (!kthread_should_stop()) { - /* - * Ensure that both TX and RX per connection kthreads - * are scheduled to run on the same CPU. - */ - iscsit_thread_check_cpumask(conn, current, 0); - - memset(buffer, 0, ISCSI_HDR_LEN); - memset(&iov, 0, sizeof(struct kvec)); - - iov.iov_base = buffer; - iov.iov_len = ISCSI_HDR_LEN; - - ret = rx_data(conn, &iov, 1, ISCSI_HDR_LEN); - if (ret != ISCSI_HDR_LEN) { - iscsit_rx_thread_wait_for_tcp(conn); - goto transport_err; - } - - /* - * Set conn->bad_hdr for use with REJECT PDUs. - */ - memcpy(&conn->bad_hdr, &buffer, ISCSI_HDR_LEN); - - if (conn->conn_ops->HeaderDigest) { - iov.iov_base = &digest; - iov.iov_len = ISCSI_CRC_LEN; - - ret = rx_data(conn, &iov, 1, ISCSI_CRC_LEN); - if (ret != ISCSI_CRC_LEN) { - iscsit_rx_thread_wait_for_tcp(conn); - goto transport_err; - } - - iscsit_do_crypto_hash_buf(&conn->conn_rx_hash, - buffer, ISCSI_HDR_LEN, - 0, NULL, (u8 *)&checksum); - - if (digest != checksum) { - pr_err("HeaderDigest CRC32C failed," - " received 0x%08x, computed 0x%08x\n", - digest, checksum); - /* - * Set the PDU to 0xff so it will intentionally - * hit default in the switch below. - */ - memset(buffer, 0xff, ISCSI_HDR_LEN); - spin_lock_bh(&conn->sess->session_stats_lock); - conn->sess->conn_digest_errors++; - spin_unlock_bh(&conn->sess->session_stats_lock); - } else { - pr_debug("Got HeaderDigest CRC32C" - " 0x%08x\n", checksum); - } - } - - if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) - goto transport_err; - - opcode = buffer[0] & ISCSI_OPCODE_MASK; - - if (conn->sess->sess_ops->SessionType && - ((!(opcode & ISCSI_OP_TEXT)) || - (!(opcode & ISCSI_OP_LOGOUT)))) { - pr_err("Received illegal iSCSI Opcode: 0x%02x" - " while in Discovery Session, rejecting.\n", opcode); - iscsit_add_reject(ISCSI_REASON_PROTOCOL_ERROR, 1, - buffer, conn); - goto transport_err; - } - - switch (opcode) { - case ISCSI_OP_SCSI_CMD: - if (iscsit_handle_scsi_cmd(conn, buffer) < 0) - goto transport_err; - break; - case ISCSI_OP_SCSI_DATA_OUT: - if (iscsit_handle_data_out(conn, buffer) < 0) - goto transport_err; - break; - case ISCSI_OP_NOOP_OUT: - if (iscsit_handle_nop_out(conn, buffer) < 0) - goto transport_err; - break; - case ISCSI_OP_SCSI_TMFUNC: - if (iscsit_handle_task_mgt_cmd(conn, buffer) < 0) - goto transport_err; - break; - case ISCSI_OP_TEXT: - if (iscsit_handle_text_cmd(conn, buffer) < 0) - goto transport_err; - break; - case ISCSI_OP_LOGOUT: - ret = iscsit_handle_logout_cmd(conn, buffer); - if (ret > 0) { - wait_for_completion_timeout(&conn->conn_logout_comp, - SECONDS_FOR_LOGOUT_COMP * HZ); - goto transport_err; - } else if (ret < 0) - goto transport_err; - break; - case ISCSI_OP_SNACK: - if (iscsit_handle_snack(conn, buffer) < 0) - goto transport_err; - break; - default: - pr_err("Got unknown iSCSI OpCode: 0x%02x\n", - opcode); - if (!conn->sess->sess_ops->ErrorRecoveryLevel) { - pr_err("Cannot recover from unknown" - " opcode while ERL=0, closing iSCSI connection" - ".\n"); - goto transport_err; - } - if (!conn->conn_ops->OFMarker) { - pr_err("Unable to recover from unknown" - " opcode while OFMarker=No, closing iSCSI" - " connection.\n"); - goto transport_err; - } - if (iscsit_recover_from_unknown_opcode(conn) < 0) { - pr_err("Unable to recover from unknown" - " opcode, closing iSCSI connection.\n"); - goto transport_err; - } - break; - } - } - -transport_err: - if (!signal_pending(current)) - atomic_set(&conn->transport_failed, 1); - iscsit_take_action_for_connection_exit(conn); - goto restart; -out: - return 0; -} - -static void iscsit_release_commands_from_conn(struct iscsi_conn *conn) -{ - struct iscsi_cmd *cmd = NULL, *cmd_tmp = NULL; - struct iscsi_session *sess = conn->sess; - struct se_cmd *se_cmd; - /* - * We expect this function to only ever be called from either RX or TX - * thread context via iscsit_close_connection() once the other context - * has been reset -> returned sleeping pre-handler state. - */ - spin_lock_bh(&conn->cmd_lock); - list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) { - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD)) { - - list_del(&cmd->i_list); - spin_unlock_bh(&conn->cmd_lock); - iscsit_increment_maxcmdsn(cmd, sess); - se_cmd = &cmd->se_cmd; - /* - * Special cases for active iSCSI TMR, and - * transport_lookup_cmd_lun() failing from - * iscsit_get_lun_for_cmd() in iscsit_handle_scsi_cmd(). - */ - if (cmd->tmr_req && se_cmd->transport_wait_for_tasks) - se_cmd->transport_wait_for_tasks(se_cmd, 1, 1); - else if (cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) - transport_release_cmd(se_cmd); - else - iscsit_release_cmd(cmd); - - spin_lock_bh(&conn->cmd_lock); - continue; - } - list_del(&cmd->i_list); - spin_unlock_bh(&conn->cmd_lock); - - iscsit_increment_maxcmdsn(cmd, sess); - se_cmd = &cmd->se_cmd; - - if (se_cmd->transport_wait_for_tasks) - se_cmd->transport_wait_for_tasks(se_cmd, 1, 1); - - spin_lock_bh(&conn->cmd_lock); - } - spin_unlock_bh(&conn->cmd_lock); -} - -static void iscsit_stop_timers_for_cmds( - struct iscsi_conn *conn) -{ - struct iscsi_cmd *cmd; - - spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { - if (cmd->data_direction == DMA_TO_DEVICE) - iscsit_stop_dataout_timer(cmd); - } - spin_unlock_bh(&conn->cmd_lock); -} - -int iscsit_close_connection( - struct iscsi_conn *conn) -{ - int conn_logout = (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT); - struct iscsi_session *sess = conn->sess; - - pr_debug("Closing iSCSI connection CID %hu on SID:" - " %u\n", conn->cid, sess->sid); - /* - * Always up conn_logout_comp just in case the RX Thread is sleeping - * and the logout response never got sent because the connection - * failed. - */ - complete(&conn->conn_logout_comp); - - iscsi_release_thread_set(conn); - - iscsit_stop_timers_for_cmds(conn); - iscsit_stop_nopin_response_timer(conn); - iscsit_stop_nopin_timer(conn); - iscsit_free_queue_reqs_for_conn(conn); - - /* - * During Connection recovery drop unacknowledged out of order - * commands for this connection, and prepare the other commands - * for realligence. - * - * During normal operation clear the out of order commands (but - * do not free the struct iscsi_ooo_cmdsn's) and release all - * struct iscsi_cmds. - */ - if (atomic_read(&conn->connection_recovery)) { - iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(conn); - iscsit_prepare_cmds_for_realligance(conn); - } else { - iscsit_clear_ooo_cmdsns_for_conn(conn); - iscsit_release_commands_from_conn(conn); - } - - /* - * Handle decrementing session or connection usage count if - * a logout response was not able to be sent because the - * connection failed. Fall back to Session Recovery here. - */ - if (atomic_read(&conn->conn_logout_remove)) { - if (conn->conn_logout_reason == ISCSI_LOGOUT_REASON_CLOSE_SESSION) { - iscsit_dec_conn_usage_count(conn); - iscsit_dec_session_usage_count(sess); - } - if (conn->conn_logout_reason == ISCSI_LOGOUT_REASON_CLOSE_CONNECTION) - iscsit_dec_conn_usage_count(conn); - - atomic_set(&conn->conn_logout_remove, 0); - atomic_set(&sess->session_reinstatement, 0); - atomic_set(&sess->session_fall_back_to_erl0, 1); - } - - spin_lock_bh(&sess->conn_lock); - list_del(&conn->conn_list); - - /* - * Attempt to let the Initiator know this connection failed by - * sending an Connection Dropped Async Message on another - * active connection. - */ - if (atomic_read(&conn->connection_recovery)) - iscsit_build_conn_drop_async_message(conn); - - spin_unlock_bh(&sess->conn_lock); - - /* - * If connection reinstatement is being performed on this connection, - * up the connection reinstatement semaphore that is being blocked on - * in iscsit_cause_connection_reinstatement(). - */ - spin_lock_bh(&conn->state_lock); - if (atomic_read(&conn->sleep_on_conn_wait_comp)) { - spin_unlock_bh(&conn->state_lock); - complete(&conn->conn_wait_comp); - wait_for_completion(&conn->conn_post_wait_comp); - spin_lock_bh(&conn->state_lock); - } - - /* - * If connection reinstatement is being performed on this connection - * by receiving a REMOVECONNFORRECOVERY logout request, up the - * connection wait rcfr semaphore that is being blocked on - * an iscsit_connection_reinstatement_rcfr(). - */ - if (atomic_read(&conn->connection_wait_rcfr)) { - spin_unlock_bh(&conn->state_lock); - complete(&conn->conn_wait_rcfr_comp); - wait_for_completion(&conn->conn_post_wait_comp); - spin_lock_bh(&conn->state_lock); - } - atomic_set(&conn->connection_reinstatement, 1); - spin_unlock_bh(&conn->state_lock); - - /* - * If any other processes are accessing this connection pointer we - * must wait until they have completed. - */ - iscsit_check_conn_usage_count(conn); - - if (conn->conn_rx_hash.tfm) - crypto_free_hash(conn->conn_rx_hash.tfm); - if (conn->conn_tx_hash.tfm) - crypto_free_hash(conn->conn_tx_hash.tfm); - - if (conn->conn_cpumask) - free_cpumask_var(conn->conn_cpumask); - - kfree(conn->conn_ops); - conn->conn_ops = NULL; - - if (conn->sock) { - if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) { - kfree(conn->sock->file); - conn->sock->file = NULL; - } - sock_release(conn->sock); - } - conn->thread_set = NULL; - - pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); - conn->conn_state = TARG_CONN_STATE_FREE; - kfree(conn); - - spin_lock_bh(&sess->conn_lock); - atomic_dec(&sess->nconn); - pr_debug("Decremented iSCSI connection count to %hu from node:" - " %s\n", atomic_read(&sess->nconn), - sess->sess_ops->InitiatorName); - /* - * Make sure that if one connection fails in an non ERL=2 iSCSI - * Session that they all fail. - */ - if ((sess->sess_ops->ErrorRecoveryLevel != 2) && !conn_logout && - !atomic_read(&sess->session_logout)) - atomic_set(&sess->session_fall_back_to_erl0, 1); - - /* - * If this was not the last connection in the session, and we are - * performing session reinstatement or falling back to ERL=0, call - * iscsit_stop_session() without sleeping to shutdown the other - * active connections. - */ - if (atomic_read(&sess->nconn)) { - if (!atomic_read(&sess->session_reinstatement) && - !atomic_read(&sess->session_fall_back_to_erl0)) { - spin_unlock_bh(&sess->conn_lock); - return 0; - } - if (!atomic_read(&sess->session_stop_active)) { - atomic_set(&sess->session_stop_active, 1); - spin_unlock_bh(&sess->conn_lock); - iscsit_stop_session(sess, 0, 0); - return 0; - } - spin_unlock_bh(&sess->conn_lock); - return 0; - } - - /* - * If this was the last connection in the session and one of the - * following is occurring: - * - * Session Reinstatement is not being performed, and are falling back - * to ERL=0 call iscsit_close_session(). - * - * Session Logout was requested. iscsit_close_session() will be called - * elsewhere. - * - * Session Continuation is not being performed, start the Time2Retain - * handler and check if sleep_on_sess_wait_sem is active. - */ - if (!atomic_read(&sess->session_reinstatement) && - atomic_read(&sess->session_fall_back_to_erl0)) { - spin_unlock_bh(&sess->conn_lock); - iscsit_close_session(sess); - - return 0; - } else if (atomic_read(&sess->session_logout)) { - pr_debug("Moving to TARG_SESS_STATE_FREE.\n"); - sess->session_state = TARG_SESS_STATE_FREE; - spin_unlock_bh(&sess->conn_lock); - - if (atomic_read(&sess->sleep_on_sess_wait_comp)) - complete(&sess->session_wait_comp); - - return 0; - } else { - pr_debug("Moving to TARG_SESS_STATE_FAILED.\n"); - sess->session_state = TARG_SESS_STATE_FAILED; - - if (!atomic_read(&sess->session_continuation)) { - spin_unlock_bh(&sess->conn_lock); - iscsit_start_time2retain_handler(sess); - } else - spin_unlock_bh(&sess->conn_lock); - - if (atomic_read(&sess->sleep_on_sess_wait_comp)) - complete(&sess->session_wait_comp); - - return 0; - } - spin_unlock_bh(&sess->conn_lock); - - return 0; -} - -int iscsit_close_session(struct iscsi_session *sess) -{ - struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess); - struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; - - if (atomic_read(&sess->nconn)) { - pr_err("%d connection(s) still exist for iSCSI session" - " to %s\n", atomic_read(&sess->nconn), - sess->sess_ops->InitiatorName); - BUG(); - } - - spin_lock_bh(&se_tpg->session_lock); - atomic_set(&sess->session_logout, 1); - atomic_set(&sess->session_reinstatement, 1); - iscsit_stop_time2retain_timer(sess); - spin_unlock_bh(&se_tpg->session_lock); - - /* - * transport_deregister_session_configfs() will clear the - * struct se_node_acl->nacl_sess pointer now as a iscsi_np process context - * can be setting it again with __transport_register_session() in - * iscsi_post_login_handler() again after the iscsit_stop_session() - * completes in iscsi_np context. - */ - transport_deregister_session_configfs(sess->se_sess); - - /* - * If any other processes are accessing this session pointer we must - * wait until they have completed. If we are in an interrupt (the - * time2retain handler) and contain and active session usage count we - * restart the timer and exit. - */ - if (!in_interrupt()) { - if (iscsit_check_session_usage_count(sess) == 1) - iscsit_stop_session(sess, 1, 1); - } else { - if (iscsit_check_session_usage_count(sess) == 2) { - atomic_set(&sess->session_logout, 0); - iscsit_start_time2retain_handler(sess); - return 0; - } - } - - transport_deregister_session(sess->se_sess); - - if (sess->sess_ops->ErrorRecoveryLevel == 2) - iscsit_free_connection_recovery_entires(sess); - - iscsit_free_all_ooo_cmdsns(sess); - - spin_lock_bh(&se_tpg->session_lock); - pr_debug("Moving to TARG_SESS_STATE_FREE.\n"); - sess->session_state = TARG_SESS_STATE_FREE; - pr_debug("Released iSCSI session from node: %s\n", - sess->sess_ops->InitiatorName); - tpg->nsessions--; - if (tpg->tpg_tiqn) - tpg->tpg_tiqn->tiqn_nsessions--; - - pr_debug("Decremented number of active iSCSI Sessions on" - " iSCSI TPG: %hu to %u\n", tpg->tpgt, tpg->nsessions); - - spin_lock(&sess_idr_lock); - idr_remove(&sess_idr, sess->session_index); - spin_unlock(&sess_idr_lock); - - kfree(sess->sess_ops); - sess->sess_ops = NULL; - spin_unlock_bh(&se_tpg->session_lock); - - kfree(sess); - return 0; -} - -static void iscsit_logout_post_handler_closesession( - struct iscsi_conn *conn) -{ - struct iscsi_session *sess = conn->sess; - - iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD); - iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD); - - atomic_set(&conn->conn_logout_remove, 0); - complete(&conn->conn_logout_comp); - - iscsit_dec_conn_usage_count(conn); - iscsit_stop_session(sess, 1, 1); - iscsit_dec_session_usage_count(sess); - iscsit_close_session(sess); -} - -static void iscsit_logout_post_handler_samecid( - struct iscsi_conn *conn) -{ - iscsi_set_thread_clear(conn, ISCSI_CLEAR_TX_THREAD); - iscsi_set_thread_set_signal(conn, ISCSI_SIGNAL_TX_THREAD); - - atomic_set(&conn->conn_logout_remove, 0); - complete(&conn->conn_logout_comp); - - iscsit_cause_connection_reinstatement(conn, 1); - iscsit_dec_conn_usage_count(conn); -} - -static void iscsit_logout_post_handler_diffcid( - struct iscsi_conn *conn, - u16 cid) -{ - struct iscsi_conn *l_conn; - struct iscsi_session *sess = conn->sess; - - if (!sess) - return; - - spin_lock_bh(&sess->conn_lock); - list_for_each_entry(l_conn, &sess->sess_conn_list, conn_list) { - if (l_conn->cid == cid) { - iscsit_inc_conn_usage_count(l_conn); - break; - } - } - spin_unlock_bh(&sess->conn_lock); - - if (!l_conn) - return; - - if (l_conn->sock) - l_conn->sock->ops->shutdown(l_conn->sock, RCV_SHUTDOWN); - - spin_lock_bh(&l_conn->state_lock); - pr_debug("Moving to TARG_CONN_STATE_IN_LOGOUT.\n"); - l_conn->conn_state = TARG_CONN_STATE_IN_LOGOUT; - spin_unlock_bh(&l_conn->state_lock); - - iscsit_cause_connection_reinstatement(l_conn, 1); - iscsit_dec_conn_usage_count(l_conn); -} - -/* - * Return of 0 causes the TX thread to restart. - */ -static int iscsit_logout_post_handler( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - int ret = 0; - - switch (cmd->logout_reason) { - case ISCSI_LOGOUT_REASON_CLOSE_SESSION: - switch (cmd->logout_response) { - case ISCSI_LOGOUT_SUCCESS: - case ISCSI_LOGOUT_CLEANUP_FAILED: - default: - iscsit_logout_post_handler_closesession(conn); - break; - } - ret = 0; - break; - case ISCSI_LOGOUT_REASON_CLOSE_CONNECTION: - if (conn->cid == cmd->logout_cid) { - switch (cmd->logout_response) { - case ISCSI_LOGOUT_SUCCESS: - case ISCSI_LOGOUT_CLEANUP_FAILED: - default: - iscsit_logout_post_handler_samecid(conn); - break; - } - ret = 0; - } else { - switch (cmd->logout_response) { - case ISCSI_LOGOUT_SUCCESS: - iscsit_logout_post_handler_diffcid(conn, - cmd->logout_cid); - break; - case ISCSI_LOGOUT_CID_NOT_FOUND: - case ISCSI_LOGOUT_CLEANUP_FAILED: - default: - break; - } - ret = 1; - } - break; - case ISCSI_LOGOUT_REASON_RECOVERY: - switch (cmd->logout_response) { - case ISCSI_LOGOUT_SUCCESS: - case ISCSI_LOGOUT_CID_NOT_FOUND: - case ISCSI_LOGOUT_RECOVERY_UNSUPPORTED: - case ISCSI_LOGOUT_CLEANUP_FAILED: - default: - break; - } - ret = 1; - break; - default: - break; - - } - return ret; -} - -void iscsit_fail_session(struct iscsi_session *sess) -{ - struct iscsi_conn *conn; - - spin_lock_bh(&sess->conn_lock); - list_for_each_entry(conn, &sess->sess_conn_list, conn_list) { - pr_debug("Moving to TARG_CONN_STATE_CLEANUP_WAIT.\n"); - conn->conn_state = TARG_CONN_STATE_CLEANUP_WAIT; - } - spin_unlock_bh(&sess->conn_lock); - - pr_debug("Moving to TARG_SESS_STATE_FAILED.\n"); - sess->session_state = TARG_SESS_STATE_FAILED; -} - -int iscsit_free_session(struct iscsi_session *sess) -{ - u16 conn_count = atomic_read(&sess->nconn); - struct iscsi_conn *conn, *conn_tmp = NULL; - int is_last; - - spin_lock_bh(&sess->conn_lock); - atomic_set(&sess->sleep_on_sess_wait_comp, 1); - - list_for_each_entry_safe(conn, conn_tmp, &sess->sess_conn_list, - conn_list) { - if (conn_count == 0) - break; - - if (list_is_last(&conn->conn_list, &sess->sess_conn_list)) { - is_last = 1; - } else { - iscsit_inc_conn_usage_count(conn_tmp); - is_last = 0; - } - iscsit_inc_conn_usage_count(conn); - - spin_unlock_bh(&sess->conn_lock); - iscsit_cause_connection_reinstatement(conn, 1); - spin_lock_bh(&sess->conn_lock); - - iscsit_dec_conn_usage_count(conn); - if (is_last == 0) - iscsit_dec_conn_usage_count(conn_tmp); - - conn_count--; - } - - if (atomic_read(&sess->nconn)) { - spin_unlock_bh(&sess->conn_lock); - wait_for_completion(&sess->session_wait_comp); - } else - spin_unlock_bh(&sess->conn_lock); - - iscsit_close_session(sess); - return 0; -} - -void iscsit_stop_session( - struct iscsi_session *sess, - int session_sleep, - int connection_sleep) -{ - u16 conn_count = atomic_read(&sess->nconn); - struct iscsi_conn *conn, *conn_tmp = NULL; - int is_last; - - spin_lock_bh(&sess->conn_lock); - if (session_sleep) - atomic_set(&sess->sleep_on_sess_wait_comp, 1); - - if (connection_sleep) { - list_for_each_entry_safe(conn, conn_tmp, &sess->sess_conn_list, - conn_list) { - if (conn_count == 0) - break; - - if (list_is_last(&conn->conn_list, &sess->sess_conn_list)) { - is_last = 1; - } else { - iscsit_inc_conn_usage_count(conn_tmp); - is_last = 0; - } - iscsit_inc_conn_usage_count(conn); - - spin_unlock_bh(&sess->conn_lock); - iscsit_cause_connection_reinstatement(conn, 1); - spin_lock_bh(&sess->conn_lock); - - iscsit_dec_conn_usage_count(conn); - if (is_last == 0) - iscsit_dec_conn_usage_count(conn_tmp); - conn_count--; - } - } else { - list_for_each_entry(conn, &sess->sess_conn_list, conn_list) - iscsit_cause_connection_reinstatement(conn, 0); - } - - if (session_sleep && atomic_read(&sess->nconn)) { - spin_unlock_bh(&sess->conn_lock); - wait_for_completion(&sess->session_wait_comp); - } else - spin_unlock_bh(&sess->conn_lock); -} - -int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *tpg, int force) -{ - struct iscsi_session *sess; - struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; - struct se_session *se_sess, *se_sess_tmp; - int session_count = 0; - - spin_lock_bh(&se_tpg->session_lock); - if (tpg->nsessions && !force) { - spin_unlock_bh(&se_tpg->session_lock); - return -1; - } - - list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list, - sess_list) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - - spin_lock(&sess->conn_lock); - if (atomic_read(&sess->session_fall_back_to_erl0) || - atomic_read(&sess->session_logout) || - (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) { - spin_unlock(&sess->conn_lock); - continue; - } - atomic_set(&sess->session_reinstatement, 1); - spin_unlock(&sess->conn_lock); - spin_unlock_bh(&se_tpg->session_lock); - - iscsit_free_session(sess); - spin_lock_bh(&se_tpg->session_lock); - - session_count++; - } - spin_unlock_bh(&se_tpg->session_lock); - - pr_debug("Released %d iSCSI Session(s) from Target Portal" - " Group: %hu\n", session_count, tpg->tpgt); - return 0; -} - -MODULE_DESCRIPTION("iSCSI-Target Driver for mainline target infrastructure"); -MODULE_VERSION("4.1.x"); -MODULE_AUTHOR("nab@Linux-iSCSI.org"); -MODULE_LICENSE("GPL"); - -module_init(iscsi_target_init_module); -module_exit(iscsi_target_cleanup_module); diff --git a/trunk/drivers/target/iscsi/iscsi_target.h b/trunk/drivers/target/iscsi/iscsi_target.h deleted file mode 100644 index 5db2ddeed5eb..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target.h +++ /dev/null @@ -1,42 +0,0 @@ -#ifndef ISCSI_TARGET_H -#define ISCSI_TARGET_H - -extern struct iscsi_tiqn *iscsit_get_tiqn_for_login(unsigned char *); -extern struct iscsi_tiqn *iscsit_get_tiqn(unsigned char *, int); -extern void iscsit_put_tiqn_for_login(struct iscsi_tiqn *); -extern struct iscsi_tiqn *iscsit_add_tiqn(unsigned char *); -extern void iscsit_del_tiqn(struct iscsi_tiqn *); -extern int iscsit_access_np(struct iscsi_np *, struct iscsi_portal_group *); -extern int iscsit_deaccess_np(struct iscsi_np *, struct iscsi_portal_group *); -extern struct iscsi_np *iscsit_add_np(struct __kernel_sockaddr_storage *, - char *, int); -extern int iscsit_reset_np_thread(struct iscsi_np *, struct iscsi_tpg_np *, - struct iscsi_portal_group *); -extern int iscsit_del_np(struct iscsi_np *); -extern int iscsit_add_reject_from_cmd(u8, int, int, unsigned char *, struct iscsi_cmd *); -extern int iscsit_logout_closesession(struct iscsi_cmd *, struct iscsi_conn *); -extern int iscsit_logout_closeconnection(struct iscsi_cmd *, struct iscsi_conn *); -extern int iscsit_logout_removeconnforrecovery(struct iscsi_cmd *, struct iscsi_conn *); -extern int iscsit_send_async_msg(struct iscsi_conn *, u16, u8, u8); -extern int iscsit_send_r2t(struct iscsi_cmd *, struct iscsi_conn *); -extern int iscsit_build_r2ts_for_cmd(struct iscsi_cmd *, struct iscsi_conn *, int); -extern void iscsit_thread_get_cpumask(struct iscsi_conn *); -extern int iscsi_target_tx_thread(void *); -extern int iscsi_target_rx_thread(void *); -extern int iscsit_close_connection(struct iscsi_conn *); -extern int iscsit_close_session(struct iscsi_session *); -extern void iscsit_fail_session(struct iscsi_session *); -extern int iscsit_free_session(struct iscsi_session *); -extern void iscsit_stop_session(struct iscsi_session *, int, int); -extern int iscsit_release_sessions_for_tpg(struct iscsi_portal_group *, int); - -extern struct iscsit_global *iscsit_global; -extern struct target_fabric_configfs *lio_target_fabric_configfs; - -extern struct kmem_cache *lio_dr_cache; -extern struct kmem_cache *lio_ooo_cache; -extern struct kmem_cache *lio_cmd_cache; -extern struct kmem_cache *lio_qr_cache; -extern struct kmem_cache *lio_r2t_cache; - -#endif /*** ISCSI_TARGET_H ***/ diff --git a/trunk/drivers/target/iscsi/iscsi_target_auth.c b/trunk/drivers/target/iscsi/iscsi_target_auth.c deleted file mode 100644 index 11fd74307811..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_auth.c +++ /dev/null @@ -1,490 +0,0 @@ -/******************************************************************************* - * This file houses the main functions for the iSCSI CHAP support - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_nego.h" -#include "iscsi_target_auth.h" - -static unsigned char chap_asciihex_to_binaryhex(unsigned char val[2]) -{ - unsigned char result = 0; - /* - * MSB - */ - if ((val[0] >= 'a') && (val[0] <= 'f')) - result = ((val[0] - 'a' + 10) & 0xf) << 4; - else - if ((val[0] >= 'A') && (val[0] <= 'F')) - result = ((val[0] - 'A' + 10) & 0xf) << 4; - else /* digit */ - result = ((val[0] - '0') & 0xf) << 4; - /* - * LSB - */ - if ((val[1] >= 'a') && (val[1] <= 'f')) - result |= ((val[1] - 'a' + 10) & 0xf); - else - if ((val[1] >= 'A') && (val[1] <= 'F')) - result |= ((val[1] - 'A' + 10) & 0xf); - else /* digit */ - result |= ((val[1] - '0') & 0xf); - - return result; -} - -static int chap_string_to_hex(unsigned char *dst, unsigned char *src, int len) -{ - int i, j = 0; - - for (i = 0; i < len; i += 2) { - dst[j++] = (unsigned char) chap_asciihex_to_binaryhex(&src[i]); - } - - dst[j] = '\0'; - return j; -} - -static void chap_binaryhex_to_asciihex(char *dst, char *src, int src_len) -{ - int i; - - for (i = 0; i < src_len; i++) { - sprintf(&dst[i*2], "%02x", (int) src[i] & 0xff); - } -} - -static void chap_set_random(char *data, int length) -{ - long r; - unsigned n; - - while (length > 0) { - get_random_bytes(&r, sizeof(long)); - r = r ^ (r >> 8); - r = r ^ (r >> 4); - n = r & 0x7; - - get_random_bytes(&r, sizeof(long)); - r = r ^ (r >> 8); - r = r ^ (r >> 5); - n = (n << 3) | (r & 0x7); - - get_random_bytes(&r, sizeof(long)); - r = r ^ (r >> 8); - r = r ^ (r >> 5); - n = (n << 2) | (r & 0x3); - - *data++ = n; - length--; - } -} - -static void chap_gen_challenge( - struct iscsi_conn *conn, - int caller, - char *c_str, - unsigned int *c_len) -{ - unsigned char challenge_asciihex[CHAP_CHALLENGE_LENGTH * 2 + 1]; - struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol; - - memset(challenge_asciihex, 0, CHAP_CHALLENGE_LENGTH * 2 + 1); - - chap_set_random(chap->challenge, CHAP_CHALLENGE_LENGTH); - chap_binaryhex_to_asciihex(challenge_asciihex, chap->challenge, - CHAP_CHALLENGE_LENGTH); - /* - * Set CHAP_C, and copy the generated challenge into c_str. - */ - *c_len += sprintf(c_str + *c_len, "CHAP_C=0x%s", challenge_asciihex); - *c_len += 1; - - pr_debug("[%s] Sending CHAP_C=0x%s\n\n", (caller) ? "server" : "client", - challenge_asciihex); -} - - -static struct iscsi_chap *chap_server_open( - struct iscsi_conn *conn, - struct iscsi_node_auth *auth, - const char *a_str, - char *aic_str, - unsigned int *aic_len) -{ - struct iscsi_chap *chap; - - if (!(auth->naf_flags & NAF_USERID_SET) || - !(auth->naf_flags & NAF_PASSWORD_SET)) { - pr_err("CHAP user or password not set for" - " Initiator ACL\n"); - return NULL; - } - - conn->auth_protocol = kzalloc(sizeof(struct iscsi_chap), GFP_KERNEL); - if (!conn->auth_protocol) - return NULL; - - chap = (struct iscsi_chap *) conn->auth_protocol; - /* - * We only support MD5 MDA presently. - */ - if (strncmp(a_str, "CHAP_A=5", 8)) { - pr_err("CHAP_A is not MD5.\n"); - return NULL; - } - pr_debug("[server] Got CHAP_A=5\n"); - /* - * Send back CHAP_A set to MD5. - */ - *aic_len = sprintf(aic_str, "CHAP_A=5"); - *aic_len += 1; - chap->digest_type = CHAP_DIGEST_MD5; - pr_debug("[server] Sending CHAP_A=%d\n", chap->digest_type); - /* - * Set Identifier. - */ - chap->id = ISCSI_TPG_C(conn)->tpg_chap_id++; - *aic_len += sprintf(aic_str + *aic_len, "CHAP_I=%d", chap->id); - *aic_len += 1; - pr_debug("[server] Sending CHAP_I=%d\n", chap->id); - /* - * Generate Challenge. - */ - chap_gen_challenge(conn, 1, aic_str, aic_len); - - return chap; -} - -static void chap_close(struct iscsi_conn *conn) -{ - kfree(conn->auth_protocol); - conn->auth_protocol = NULL; -} - -static int chap_server_compute_md5( - struct iscsi_conn *conn, - struct iscsi_node_auth *auth, - char *nr_in_ptr, - char *nr_out_ptr, - unsigned int *nr_out_len) -{ - char *endptr; - unsigned char id, digest[MD5_SIGNATURE_SIZE]; - unsigned char type, response[MD5_SIGNATURE_SIZE * 2 + 2]; - unsigned char identifier[10], *challenge = NULL; - unsigned char *challenge_binhex = NULL; - unsigned char client_digest[MD5_SIGNATURE_SIZE]; - unsigned char server_digest[MD5_SIGNATURE_SIZE]; - unsigned char chap_n[MAX_CHAP_N_SIZE], chap_r[MAX_RESPONSE_LENGTH]; - struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol; - struct crypto_hash *tfm; - struct hash_desc desc; - struct scatterlist sg; - int auth_ret = -1, ret, challenge_len; - - memset(identifier, 0, 10); - memset(chap_n, 0, MAX_CHAP_N_SIZE); - memset(chap_r, 0, MAX_RESPONSE_LENGTH); - memset(digest, 0, MD5_SIGNATURE_SIZE); - memset(response, 0, MD5_SIGNATURE_SIZE * 2 + 2); - memset(client_digest, 0, MD5_SIGNATURE_SIZE); - memset(server_digest, 0, MD5_SIGNATURE_SIZE); - - challenge = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); - if (!challenge) { - pr_err("Unable to allocate challenge buffer\n"); - goto out; - } - - challenge_binhex = kzalloc(CHAP_CHALLENGE_STR_LEN, GFP_KERNEL); - if (!challenge_binhex) { - pr_err("Unable to allocate challenge_binhex buffer\n"); - goto out; - } - /* - * Extract CHAP_N. - */ - if (extract_param(nr_in_ptr, "CHAP_N", MAX_CHAP_N_SIZE, chap_n, - &type) < 0) { - pr_err("Could not find CHAP_N.\n"); - goto out; - } - if (type == HEX) { - pr_err("Could not find CHAP_N.\n"); - goto out; - } - - if (memcmp(chap_n, auth->userid, strlen(auth->userid)) != 0) { - pr_err("CHAP_N values do not match!\n"); - goto out; - } - pr_debug("[server] Got CHAP_N=%s\n", chap_n); - /* - * Extract CHAP_R. - */ - if (extract_param(nr_in_ptr, "CHAP_R", MAX_RESPONSE_LENGTH, chap_r, - &type) < 0) { - pr_err("Could not find CHAP_R.\n"); - goto out; - } - if (type != HEX) { - pr_err("Could not find CHAP_R.\n"); - goto out; - } - - pr_debug("[server] Got CHAP_R=%s\n", chap_r); - chap_string_to_hex(client_digest, chap_r, strlen(chap_r)); - - tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) { - pr_err("Unable to allocate struct crypto_hash\n"); - goto out; - } - desc.tfm = tfm; - desc.flags = 0; - - ret = crypto_hash_init(&desc); - if (ret < 0) { - pr_err("crypto_hash_init() failed\n"); - crypto_free_hash(tfm); - goto out; - } - - sg_init_one(&sg, (void *)&chap->id, 1); - ret = crypto_hash_update(&desc, &sg, 1); - if (ret < 0) { - pr_err("crypto_hash_update() failed for id\n"); - crypto_free_hash(tfm); - goto out; - } - - sg_init_one(&sg, (void *)&auth->password, strlen(auth->password)); - ret = crypto_hash_update(&desc, &sg, strlen(auth->password)); - if (ret < 0) { - pr_err("crypto_hash_update() failed for password\n"); - crypto_free_hash(tfm); - goto out; - } - - sg_init_one(&sg, (void *)chap->challenge, CHAP_CHALLENGE_LENGTH); - ret = crypto_hash_update(&desc, &sg, CHAP_CHALLENGE_LENGTH); - if (ret < 0) { - pr_err("crypto_hash_update() failed for challenge\n"); - crypto_free_hash(tfm); - goto out; - } - - ret = crypto_hash_final(&desc, server_digest); - if (ret < 0) { - pr_err("crypto_hash_final() failed for server digest\n"); - crypto_free_hash(tfm); - goto out; - } - crypto_free_hash(tfm); - - chap_binaryhex_to_asciihex(response, server_digest, MD5_SIGNATURE_SIZE); - pr_debug("[server] MD5 Server Digest: %s\n", response); - - if (memcmp(server_digest, client_digest, MD5_SIGNATURE_SIZE) != 0) { - pr_debug("[server] MD5 Digests do not match!\n\n"); - goto out; - } else - pr_debug("[server] MD5 Digests match, CHAP connetication" - " successful.\n\n"); - /* - * One way authentication has succeeded, return now if mutual - * authentication is not enabled. - */ - if (!auth->authenticate_target) { - kfree(challenge); - kfree(challenge_binhex); - return 0; - } - /* - * Get CHAP_I. - */ - if (extract_param(nr_in_ptr, "CHAP_I", 10, identifier, &type) < 0) { - pr_err("Could not find CHAP_I.\n"); - goto out; - } - - if (type == HEX) - id = (unsigned char)simple_strtoul((char *)&identifier[2], - &endptr, 0); - else - id = (unsigned char)simple_strtoul(identifier, &endptr, 0); - /* - * RFC 1994 says Identifier is no more than octet (8 bits). - */ - pr_debug("[server] Got CHAP_I=%d\n", id); - /* - * Get CHAP_C. - */ - if (extract_param(nr_in_ptr, "CHAP_C", CHAP_CHALLENGE_STR_LEN, - challenge, &type) < 0) { - pr_err("Could not find CHAP_C.\n"); - goto out; - } - - if (type != HEX) { - pr_err("Could not find CHAP_C.\n"); - goto out; - } - pr_debug("[server] Got CHAP_C=%s\n", challenge); - challenge_len = chap_string_to_hex(challenge_binhex, challenge, - strlen(challenge)); - if (!challenge_len) { - pr_err("Unable to convert incoming challenge\n"); - goto out; - } - /* - * Generate CHAP_N and CHAP_R for mutual authentication. - */ - tfm = crypto_alloc_hash("md5", 0, CRYPTO_ALG_ASYNC); - if (IS_ERR(tfm)) { - pr_err("Unable to allocate struct crypto_hash\n"); - goto out; - } - desc.tfm = tfm; - desc.flags = 0; - - ret = crypto_hash_init(&desc); - if (ret < 0) { - pr_err("crypto_hash_init() failed\n"); - crypto_free_hash(tfm); - goto out; - } - - sg_init_one(&sg, (void *)&id, 1); - ret = crypto_hash_update(&desc, &sg, 1); - if (ret < 0) { - pr_err("crypto_hash_update() failed for id\n"); - crypto_free_hash(tfm); - goto out; - } - - sg_init_one(&sg, (void *)auth->password_mutual, - strlen(auth->password_mutual)); - ret = crypto_hash_update(&desc, &sg, strlen(auth->password_mutual)); - if (ret < 0) { - pr_err("crypto_hash_update() failed for" - " password_mutual\n"); - crypto_free_hash(tfm); - goto out; - } - /* - * Convert received challenge to binary hex. - */ - sg_init_one(&sg, (void *)challenge_binhex, challenge_len); - ret = crypto_hash_update(&desc, &sg, challenge_len); - if (ret < 0) { - pr_err("crypto_hash_update() failed for ma challenge\n"); - crypto_free_hash(tfm); - goto out; - } - - ret = crypto_hash_final(&desc, digest); - if (ret < 0) { - pr_err("crypto_hash_final() failed for ma digest\n"); - crypto_free_hash(tfm); - goto out; - } - crypto_free_hash(tfm); - /* - * Generate CHAP_N and CHAP_R. - */ - *nr_out_len = sprintf(nr_out_ptr, "CHAP_N=%s", auth->userid_mutual); - *nr_out_len += 1; - pr_debug("[server] Sending CHAP_N=%s\n", auth->userid_mutual); - /* - * Convert response from binary hex to ascii hext. - */ - chap_binaryhex_to_asciihex(response, digest, MD5_SIGNATURE_SIZE); - *nr_out_len += sprintf(nr_out_ptr + *nr_out_len, "CHAP_R=0x%s", - response); - *nr_out_len += 1; - pr_debug("[server] Sending CHAP_R=0x%s\n", response); - auth_ret = 0; -out: - kfree(challenge); - kfree(challenge_binhex); - return auth_ret; -} - -static int chap_got_response( - struct iscsi_conn *conn, - struct iscsi_node_auth *auth, - char *nr_in_ptr, - char *nr_out_ptr, - unsigned int *nr_out_len) -{ - struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol; - - switch (chap->digest_type) { - case CHAP_DIGEST_MD5: - if (chap_server_compute_md5(conn, auth, nr_in_ptr, - nr_out_ptr, nr_out_len) < 0) - return -1; - return 0; - default: - pr_err("Unknown CHAP digest type %d!\n", - chap->digest_type); - return -1; - } -} - -u32 chap_main_loop( - struct iscsi_conn *conn, - struct iscsi_node_auth *auth, - char *in_text, - char *out_text, - int *in_len, - int *out_len) -{ - struct iscsi_chap *chap = (struct iscsi_chap *) conn->auth_protocol; - - if (!chap) { - chap = chap_server_open(conn, auth, in_text, out_text, out_len); - if (!chap) - return 2; - chap->chap_state = CHAP_STAGE_SERVER_AIC; - return 0; - } else if (chap->chap_state == CHAP_STAGE_SERVER_AIC) { - convert_null_to_semi(in_text, *in_len); - if (chap_got_response(conn, auth, in_text, out_text, - out_len) < 0) { - chap_close(conn); - return 2; - } - if (auth->authenticate_target) - chap->chap_state = CHAP_STAGE_SERVER_NR; - else - *out_len = 0; - chap_close(conn); - return 1; - } - - return 2; -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_auth.h b/trunk/drivers/target/iscsi/iscsi_target_auth.h deleted file mode 100644 index 2f463c09626d..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_auth.h +++ /dev/null @@ -1,31 +0,0 @@ -#ifndef _ISCSI_CHAP_H_ -#define _ISCSI_CHAP_H_ - -#define CHAP_DIGEST_MD5 5 -#define CHAP_DIGEST_SHA 6 - -#define CHAP_CHALLENGE_LENGTH 16 -#define CHAP_CHALLENGE_STR_LEN 4096 -#define MAX_RESPONSE_LENGTH 64 /* sufficient for MD5 */ -#define MAX_CHAP_N_SIZE 512 - -#define MD5_SIGNATURE_SIZE 16 /* 16 bytes in a MD5 message digest */ - -#define CHAP_STAGE_CLIENT_A 1 -#define CHAP_STAGE_SERVER_AIC 2 -#define CHAP_STAGE_CLIENT_NR 3 -#define CHAP_STAGE_CLIENT_NRIC 4 -#define CHAP_STAGE_SERVER_NR 5 - -extern u32 chap_main_loop(struct iscsi_conn *, struct iscsi_node_auth *, char *, char *, - int *, int *); - -struct iscsi_chap { - unsigned char digest_type; - unsigned char id; - unsigned char challenge[CHAP_CHALLENGE_LENGTH]; - unsigned int authenticate_target; - unsigned int chap_state; -} ____cacheline_aligned; - -#endif /*** _ISCSI_CHAP_H_ ***/ diff --git a/trunk/drivers/target/iscsi/iscsi_target_configfs.c b/trunk/drivers/target/iscsi/iscsi_target_configfs.c deleted file mode 100644 index 32bb92c44450..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_configfs.c +++ /dev/null @@ -1,1882 +0,0 @@ -/******************************************************************************* - * This file contains the configfs implementation for iSCSI Target mode - * from the LIO-Target Project. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ****************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_parameters.h" -#include "iscsi_target_device.h" -#include "iscsi_target_erl0.h" -#include "iscsi_target_nodeattrib.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_util.h" -#include "iscsi_target.h" -#include "iscsi_target_stat.h" -#include "iscsi_target_configfs.h" - -struct target_fabric_configfs *lio_target_fabric_configfs; - -struct lio_target_configfs_attribute { - struct configfs_attribute attr; - ssize_t (*show)(void *, char *); - ssize_t (*store)(void *, const char *, size_t); -}; - -struct iscsi_portal_group *lio_get_tpg_from_tpg_item( - struct config_item *item, - struct iscsi_tiqn **tiqn_out) -{ - struct se_portal_group *se_tpg = container_of(to_config_group(item), - struct se_portal_group, tpg_group); - struct iscsi_portal_group *tpg = - (struct iscsi_portal_group *)se_tpg->se_tpg_fabric_ptr; - int ret; - - if (!tpg) { - pr_err("Unable to locate struct iscsi_portal_group " - "pointer\n"); - return NULL; - } - ret = iscsit_get_tpg(tpg); - if (ret < 0) - return NULL; - - *tiqn_out = tpg->tpg_tiqn; - return tpg; -} - -/* Start items for lio_target_portal_cit */ - -static ssize_t lio_target_np_show_sctp( - struct se_tpg_np *se_tpg_np, - char *page) -{ - struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np, - struct iscsi_tpg_np, se_tpg_np); - struct iscsi_tpg_np *tpg_np_sctp; - ssize_t rb; - - tpg_np_sctp = iscsit_tpg_locate_child_np(tpg_np, ISCSI_SCTP_TCP); - if (tpg_np_sctp) - rb = sprintf(page, "1\n"); - else - rb = sprintf(page, "0\n"); - - return rb; -} - -static ssize_t lio_target_np_store_sctp( - struct se_tpg_np *se_tpg_np, - const char *page, - size_t count) -{ - struct iscsi_np *np; - struct iscsi_portal_group *tpg; - struct iscsi_tpg_np *tpg_np = container_of(se_tpg_np, - struct iscsi_tpg_np, se_tpg_np); - struct iscsi_tpg_np *tpg_np_sctp = NULL; - char *endptr; - u32 op; - int ret; - - op = simple_strtoul(page, &endptr, 0); - if ((op != 1) && (op != 0)) { - pr_err("Illegal value for tpg_enable: %u\n", op); - return -EINVAL; - } - np = tpg_np->tpg_np; - if (!np) { - pr_err("Unable to locate struct iscsi_np from" - " struct iscsi_tpg_np\n"); - return -EINVAL; - } - - tpg = tpg_np->tpg; - if (iscsit_get_tpg(tpg) < 0) - return -EINVAL; - - if (op) { - /* - * Use existing np->np_sockaddr for SCTP network portal reference - */ - tpg_np_sctp = iscsit_tpg_add_network_portal(tpg, &np->np_sockaddr, - np->np_ip, tpg_np, ISCSI_SCTP_TCP); - if (!tpg_np_sctp || IS_ERR(tpg_np_sctp)) - goto out; - } else { - tpg_np_sctp = iscsit_tpg_locate_child_np(tpg_np, ISCSI_SCTP_TCP); - if (!tpg_np_sctp) - goto out; - - ret = iscsit_tpg_del_network_portal(tpg, tpg_np_sctp); - if (ret < 0) - goto out; - } - - iscsit_put_tpg(tpg); - return count; -out: - iscsit_put_tpg(tpg); - return -EINVAL; -} - -TF_NP_BASE_ATTR(lio_target, sctp, S_IRUGO | S_IWUSR); - -static struct configfs_attribute *lio_target_portal_attrs[] = { - &lio_target_np_sctp.attr, - NULL, -}; - -/* Stop items for lio_target_portal_cit */ - -/* Start items for lio_target_np_cit */ - -#define MAX_PORTAL_LEN 256 - -struct se_tpg_np *lio_target_call_addnptotpg( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) -{ - struct iscsi_portal_group *tpg; - struct iscsi_tpg_np *tpg_np; - char *str, *str2, *ip_str, *port_str; - struct __kernel_sockaddr_storage sockaddr; - struct sockaddr_in *sock_in; - struct sockaddr_in6 *sock_in6; - unsigned long port; - int ret; - char buf[MAX_PORTAL_LEN + 1]; - - if (strlen(name) > MAX_PORTAL_LEN) { - pr_err("strlen(name): %d exceeds MAX_PORTAL_LEN: %d\n", - (int)strlen(name), MAX_PORTAL_LEN); - return ERR_PTR(-EOVERFLOW); - } - memset(buf, 0, MAX_PORTAL_LEN + 1); - snprintf(buf, MAX_PORTAL_LEN, "%s", name); - - memset(&sockaddr, 0, sizeof(struct __kernel_sockaddr_storage)); - - str = strstr(buf, "["); - if (str) { - const char *end; - - str2 = strstr(str, "]"); - if (!str2) { - pr_err("Unable to locate trailing \"]\"" - " in IPv6 iSCSI network portal address\n"); - return ERR_PTR(-EINVAL); - } - str++; /* Skip over leading "[" */ - *str2 = '\0'; /* Terminate the IPv6 address */ - str2++; /* Skip over the "]" */ - port_str = strstr(str2, ":"); - if (!port_str) { - pr_err("Unable to locate \":port\"" - " in IPv6 iSCSI network portal address\n"); - return ERR_PTR(-EINVAL); - } - *port_str = '\0'; /* Terminate string for IP */ - port_str++; /* Skip over ":" */ - - ret = strict_strtoul(port_str, 0, &port); - if (ret < 0) { - pr_err("strict_strtoul() failed for port_str: %d\n", ret); - return ERR_PTR(ret); - } - sock_in6 = (struct sockaddr_in6 *)&sockaddr; - sock_in6->sin6_family = AF_INET6; - sock_in6->sin6_port = htons((unsigned short)port); - ret = in6_pton(str, IPV6_ADDRESS_SPACE, - (void *)&sock_in6->sin6_addr.in6_u, -1, &end); - if (ret <= 0) { - pr_err("in6_pton returned: %d\n", ret); - return ERR_PTR(-EINVAL); - } - } else { - str = ip_str = &buf[0]; - port_str = strstr(ip_str, ":"); - if (!port_str) { - pr_err("Unable to locate \":port\"" - " in IPv4 iSCSI network portal address\n"); - return ERR_PTR(-EINVAL); - } - *port_str = '\0'; /* Terminate string for IP */ - port_str++; /* Skip over ":" */ - - ret = strict_strtoul(port_str, 0, &port); - if (ret < 0) { - pr_err("strict_strtoul() failed for port_str: %d\n", ret); - return ERR_PTR(ret); - } - sock_in = (struct sockaddr_in *)&sockaddr; - sock_in->sin_family = AF_INET; - sock_in->sin_port = htons((unsigned short)port); - sock_in->sin_addr.s_addr = in_aton(ip_str); - } - tpg = container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg); - ret = iscsit_get_tpg(tpg); - if (ret < 0) - return ERR_PTR(-EINVAL); - - pr_debug("LIO_Target_ConfigFS: REGISTER -> %s TPGT: %hu" - " PORTAL: %s\n", - config_item_name(&se_tpg->se_tpg_wwn->wwn_group.cg_item), - tpg->tpgt, name); - /* - * Assume ISCSI_TCP by default. Other network portals for other - * iSCSI fabrics: - * - * Traditional iSCSI over SCTP (initial support) - * iSER/TCP (TODO, hardware available) - * iSER/SCTP (TODO, software emulation with osc-iwarp) - * iSER/IB (TODO, hardware available) - * - * can be enabled with atributes under - * sys/kernel/config/iscsi/$IQN/$TPG/np/$IP:$PORT/ - * - */ - tpg_np = iscsit_tpg_add_network_portal(tpg, &sockaddr, str, NULL, - ISCSI_TCP); - if (IS_ERR(tpg_np)) { - iscsit_put_tpg(tpg); - return ERR_PTR(PTR_ERR(tpg_np)); - } - pr_debug("LIO_Target_ConfigFS: addnptotpg done!\n"); - - iscsit_put_tpg(tpg); - return &tpg_np->se_tpg_np; -} - -static void lio_target_call_delnpfromtpg( - struct se_tpg_np *se_tpg_np) -{ - struct iscsi_portal_group *tpg; - struct iscsi_tpg_np *tpg_np; - struct se_portal_group *se_tpg; - int ret; - - tpg_np = container_of(se_tpg_np, struct iscsi_tpg_np, se_tpg_np); - tpg = tpg_np->tpg; - ret = iscsit_get_tpg(tpg); - if (ret < 0) - return; - - se_tpg = &tpg->tpg_se_tpg; - pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s TPGT: %hu" - " PORTAL: %s:%hu\n", config_item_name(&se_tpg->se_tpg_wwn->wwn_group.cg_item), - tpg->tpgt, tpg_np->tpg_np->np_ip, tpg_np->tpg_np->np_port); - - ret = iscsit_tpg_del_network_portal(tpg, tpg_np); - if (ret < 0) - goto out; - - pr_debug("LIO_Target_ConfigFS: delnpfromtpg done!\n"); -out: - iscsit_put_tpg(tpg); -} - -/* End items for lio_target_np_cit */ - -/* Start items for lio_target_nacl_attrib_cit */ - -#define DEF_NACL_ATTRIB(name) \ -static ssize_t iscsi_nacl_attrib_show_##name( \ - struct se_node_acl *se_nacl, \ - char *page) \ -{ \ - struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \ - se_node_acl); \ - \ - return sprintf(page, "%u\n", ISCSI_NODE_ATTRIB(nacl)->name); \ -} \ - \ -static ssize_t iscsi_nacl_attrib_store_##name( \ - struct se_node_acl *se_nacl, \ - const char *page, \ - size_t count) \ -{ \ - struct iscsi_node_acl *nacl = container_of(se_nacl, struct iscsi_node_acl, \ - se_node_acl); \ - char *endptr; \ - u32 val; \ - int ret; \ - \ - val = simple_strtoul(page, &endptr, 0); \ - ret = iscsit_na_##name(nacl, val); \ - if (ret < 0) \ - return ret; \ - \ - return count; \ -} - -#define NACL_ATTR(_name, _mode) TF_NACL_ATTRIB_ATTR(iscsi, _name, _mode); -/* - * Define iscsi_node_attrib_s_dataout_timeout - */ -DEF_NACL_ATTRIB(dataout_timeout); -NACL_ATTR(dataout_timeout, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_dataout_timeout_retries - */ -DEF_NACL_ATTRIB(dataout_timeout_retries); -NACL_ATTR(dataout_timeout_retries, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_default_erl - */ -DEF_NACL_ATTRIB(default_erl); -NACL_ATTR(default_erl, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_nopin_timeout - */ -DEF_NACL_ATTRIB(nopin_timeout); -NACL_ATTR(nopin_timeout, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_nopin_response_timeout - */ -DEF_NACL_ATTRIB(nopin_response_timeout); -NACL_ATTR(nopin_response_timeout, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_random_datain_pdu_offsets - */ -DEF_NACL_ATTRIB(random_datain_pdu_offsets); -NACL_ATTR(random_datain_pdu_offsets, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_random_datain_seq_offsets - */ -DEF_NACL_ATTRIB(random_datain_seq_offsets); -NACL_ATTR(random_datain_seq_offsets, S_IRUGO | S_IWUSR); -/* - * Define iscsi_node_attrib_s_random_r2t_offsets - */ -DEF_NACL_ATTRIB(random_r2t_offsets); -NACL_ATTR(random_r2t_offsets, S_IRUGO | S_IWUSR); - -static struct configfs_attribute *lio_target_nacl_attrib_attrs[] = { - &iscsi_nacl_attrib_dataout_timeout.attr, - &iscsi_nacl_attrib_dataout_timeout_retries.attr, - &iscsi_nacl_attrib_default_erl.attr, - &iscsi_nacl_attrib_nopin_timeout.attr, - &iscsi_nacl_attrib_nopin_response_timeout.attr, - &iscsi_nacl_attrib_random_datain_pdu_offsets.attr, - &iscsi_nacl_attrib_random_datain_seq_offsets.attr, - &iscsi_nacl_attrib_random_r2t_offsets.attr, - NULL, -}; - -/* End items for lio_target_nacl_attrib_cit */ - -/* Start items for lio_target_nacl_auth_cit */ - -#define __DEF_NACL_AUTH_STR(prefix, name, flags) \ -static ssize_t __iscsi_##prefix##_show_##name( \ - struct iscsi_node_acl *nacl, \ - char *page) \ -{ \ - struct iscsi_node_auth *auth = &nacl->node_auth; \ - \ - if (!capable(CAP_SYS_ADMIN)) \ - return -EPERM; \ - return snprintf(page, PAGE_SIZE, "%s\n", auth->name); \ -} \ - \ -static ssize_t __iscsi_##prefix##_store_##name( \ - struct iscsi_node_acl *nacl, \ - const char *page, \ - size_t count) \ -{ \ - struct iscsi_node_auth *auth = &nacl->node_auth; \ - \ - if (!capable(CAP_SYS_ADMIN)) \ - return -EPERM; \ - \ - snprintf(auth->name, PAGE_SIZE, "%s", page); \ - if (!strncmp("NULL", auth->name, 4)) \ - auth->naf_flags &= ~flags; \ - else \ - auth->naf_flags |= flags; \ - \ - if ((auth->naf_flags & NAF_USERID_IN_SET) && \ - (auth->naf_flags & NAF_PASSWORD_IN_SET)) \ - auth->authenticate_target = 1; \ - else \ - auth->authenticate_target = 0; \ - \ - return count; \ -} - -#define __DEF_NACL_AUTH_INT(prefix, name) \ -static ssize_t __iscsi_##prefix##_show_##name( \ - struct iscsi_node_acl *nacl, \ - char *page) \ -{ \ - struct iscsi_node_auth *auth = &nacl->node_auth; \ - \ - if (!capable(CAP_SYS_ADMIN)) \ - return -EPERM; \ - \ - return snprintf(page, PAGE_SIZE, "%d\n", auth->name); \ -} - -#define DEF_NACL_AUTH_STR(name, flags) \ - __DEF_NACL_AUTH_STR(nacl_auth, name, flags) \ -static ssize_t iscsi_nacl_auth_show_##name( \ - struct se_node_acl *nacl, \ - char *page) \ -{ \ - return __iscsi_nacl_auth_show_##name(container_of(nacl, \ - struct iscsi_node_acl, se_node_acl), page); \ -} \ -static ssize_t iscsi_nacl_auth_store_##name( \ - struct se_node_acl *nacl, \ - const char *page, \ - size_t count) \ -{ \ - return __iscsi_nacl_auth_store_##name(container_of(nacl, \ - struct iscsi_node_acl, se_node_acl), page, count); \ -} - -#define DEF_NACL_AUTH_INT(name) \ - __DEF_NACL_AUTH_INT(nacl_auth, name) \ -static ssize_t iscsi_nacl_auth_show_##name( \ - struct se_node_acl *nacl, \ - char *page) \ -{ \ - return __iscsi_nacl_auth_show_##name(container_of(nacl, \ - struct iscsi_node_acl, se_node_acl), page); \ -} - -#define AUTH_ATTR(_name, _mode) TF_NACL_AUTH_ATTR(iscsi, _name, _mode); -#define AUTH_ATTR_RO(_name) TF_NACL_AUTH_ATTR_RO(iscsi, _name); - -/* - * One-way authentication userid - */ -DEF_NACL_AUTH_STR(userid, NAF_USERID_SET); -AUTH_ATTR(userid, S_IRUGO | S_IWUSR); -/* - * One-way authentication password - */ -DEF_NACL_AUTH_STR(password, NAF_PASSWORD_SET); -AUTH_ATTR(password, S_IRUGO | S_IWUSR); -/* - * Enforce mutual authentication - */ -DEF_NACL_AUTH_INT(authenticate_target); -AUTH_ATTR_RO(authenticate_target); -/* - * Mutual authentication userid - */ -DEF_NACL_AUTH_STR(userid_mutual, NAF_USERID_IN_SET); -AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR); -/* - * Mutual authentication password - */ -DEF_NACL_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET); -AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR); - -static struct configfs_attribute *lio_target_nacl_auth_attrs[] = { - &iscsi_nacl_auth_userid.attr, - &iscsi_nacl_auth_password.attr, - &iscsi_nacl_auth_authenticate_target.attr, - &iscsi_nacl_auth_userid_mutual.attr, - &iscsi_nacl_auth_password_mutual.attr, - NULL, -}; - -/* End items for lio_target_nacl_auth_cit */ - -/* Start items for lio_target_nacl_param_cit */ - -#define DEF_NACL_PARAM(name) \ -static ssize_t iscsi_nacl_param_show_##name( \ - struct se_node_acl *se_nacl, \ - char *page) \ -{ \ - struct iscsi_session *sess; \ - struct se_session *se_sess; \ - ssize_t rb; \ - \ - spin_lock_bh(&se_nacl->nacl_sess_lock); \ - se_sess = se_nacl->nacl_sess; \ - if (!se_sess) { \ - rb = snprintf(page, PAGE_SIZE, \ - "No Active iSCSI Session\n"); \ - } else { \ - sess = se_sess->fabric_sess_ptr; \ - rb = snprintf(page, PAGE_SIZE, "%u\n", \ - (u32)sess->sess_ops->name); \ - } \ - spin_unlock_bh(&se_nacl->nacl_sess_lock); \ - \ - return rb; \ -} - -#define NACL_PARAM_ATTR(_name) TF_NACL_PARAM_ATTR_RO(iscsi, _name); - -DEF_NACL_PARAM(MaxConnections); -NACL_PARAM_ATTR(MaxConnections); - -DEF_NACL_PARAM(InitialR2T); -NACL_PARAM_ATTR(InitialR2T); - -DEF_NACL_PARAM(ImmediateData); -NACL_PARAM_ATTR(ImmediateData); - -DEF_NACL_PARAM(MaxBurstLength); -NACL_PARAM_ATTR(MaxBurstLength); - -DEF_NACL_PARAM(FirstBurstLength); -NACL_PARAM_ATTR(FirstBurstLength); - -DEF_NACL_PARAM(DefaultTime2Wait); -NACL_PARAM_ATTR(DefaultTime2Wait); - -DEF_NACL_PARAM(DefaultTime2Retain); -NACL_PARAM_ATTR(DefaultTime2Retain); - -DEF_NACL_PARAM(MaxOutstandingR2T); -NACL_PARAM_ATTR(MaxOutstandingR2T); - -DEF_NACL_PARAM(DataPDUInOrder); -NACL_PARAM_ATTR(DataPDUInOrder); - -DEF_NACL_PARAM(DataSequenceInOrder); -NACL_PARAM_ATTR(DataSequenceInOrder); - -DEF_NACL_PARAM(ErrorRecoveryLevel); -NACL_PARAM_ATTR(ErrorRecoveryLevel); - -static struct configfs_attribute *lio_target_nacl_param_attrs[] = { - &iscsi_nacl_param_MaxConnections.attr, - &iscsi_nacl_param_InitialR2T.attr, - &iscsi_nacl_param_ImmediateData.attr, - &iscsi_nacl_param_MaxBurstLength.attr, - &iscsi_nacl_param_FirstBurstLength.attr, - &iscsi_nacl_param_DefaultTime2Wait.attr, - &iscsi_nacl_param_DefaultTime2Retain.attr, - &iscsi_nacl_param_MaxOutstandingR2T.attr, - &iscsi_nacl_param_DataPDUInOrder.attr, - &iscsi_nacl_param_DataSequenceInOrder.attr, - &iscsi_nacl_param_ErrorRecoveryLevel.attr, - NULL, -}; - -/* End items for lio_target_nacl_param_cit */ - -/* Start items for lio_target_acl_cit */ - -static ssize_t lio_target_nacl_show_info( - struct se_node_acl *se_nacl, - char *page) -{ - struct iscsi_session *sess; - struct iscsi_conn *conn; - struct se_session *se_sess; - ssize_t rb = 0; - - spin_lock_bh(&se_nacl->nacl_sess_lock); - se_sess = se_nacl->nacl_sess; - if (!se_sess) { - rb += sprintf(page+rb, "No active iSCSI Session for Initiator" - " Endpoint: %s\n", se_nacl->initiatorname); - } else { - sess = se_sess->fabric_sess_ptr; - - if (sess->sess_ops->InitiatorName) - rb += sprintf(page+rb, "InitiatorName: %s\n", - sess->sess_ops->InitiatorName); - if (sess->sess_ops->InitiatorAlias) - rb += sprintf(page+rb, "InitiatorAlias: %s\n", - sess->sess_ops->InitiatorAlias); - - rb += sprintf(page+rb, "LIO Session ID: %u " - "ISID: 0x%02x %02x %02x %02x %02x %02x " - "TSIH: %hu ", sess->sid, - sess->isid[0], sess->isid[1], sess->isid[2], - sess->isid[3], sess->isid[4], sess->isid[5], - sess->tsih); - rb += sprintf(page+rb, "SessionType: %s\n", - (sess->sess_ops->SessionType) ? - "Discovery" : "Normal"); - rb += sprintf(page+rb, "Session State: "); - switch (sess->session_state) { - case TARG_SESS_STATE_FREE: - rb += sprintf(page+rb, "TARG_SESS_FREE\n"); - break; - case TARG_SESS_STATE_ACTIVE: - rb += sprintf(page+rb, "TARG_SESS_STATE_ACTIVE\n"); - break; - case TARG_SESS_STATE_LOGGED_IN: - rb += sprintf(page+rb, "TARG_SESS_STATE_LOGGED_IN\n"); - break; - case TARG_SESS_STATE_FAILED: - rb += sprintf(page+rb, "TARG_SESS_STATE_FAILED\n"); - break; - case TARG_SESS_STATE_IN_CONTINUE: - rb += sprintf(page+rb, "TARG_SESS_STATE_IN_CONTINUE\n"); - break; - default: - rb += sprintf(page+rb, "ERROR: Unknown Session" - " State!\n"); - break; - } - - rb += sprintf(page+rb, "---------------------[iSCSI Session" - " Values]-----------------------\n"); - rb += sprintf(page+rb, " CmdSN/WR : CmdSN/WC : ExpCmdSN" - " : MaxCmdSN : ITT : TTT\n"); - rb += sprintf(page+rb, " 0x%08x 0x%08x 0x%08x 0x%08x" - " 0x%08x 0x%08x\n", - sess->cmdsn_window, - (sess->max_cmd_sn - sess->exp_cmd_sn) + 1, - sess->exp_cmd_sn, sess->max_cmd_sn, - sess->init_task_tag, sess->targ_xfer_tag); - rb += sprintf(page+rb, "----------------------[iSCSI" - " Connections]-------------------------\n"); - - spin_lock(&sess->conn_lock); - list_for_each_entry(conn, &sess->sess_conn_list, conn_list) { - rb += sprintf(page+rb, "CID: %hu Connection" - " State: ", conn->cid); - switch (conn->conn_state) { - case TARG_CONN_STATE_FREE: - rb += sprintf(page+rb, - "TARG_CONN_STATE_FREE\n"); - break; - case TARG_CONN_STATE_XPT_UP: - rb += sprintf(page+rb, - "TARG_CONN_STATE_XPT_UP\n"); - break; - case TARG_CONN_STATE_IN_LOGIN: - rb += sprintf(page+rb, - "TARG_CONN_STATE_IN_LOGIN\n"); - break; - case TARG_CONN_STATE_LOGGED_IN: - rb += sprintf(page+rb, - "TARG_CONN_STATE_LOGGED_IN\n"); - break; - case TARG_CONN_STATE_IN_LOGOUT: - rb += sprintf(page+rb, - "TARG_CONN_STATE_IN_LOGOUT\n"); - break; - case TARG_CONN_STATE_LOGOUT_REQUESTED: - rb += sprintf(page+rb, - "TARG_CONN_STATE_LOGOUT_REQUESTED\n"); - break; - case TARG_CONN_STATE_CLEANUP_WAIT: - rb += sprintf(page+rb, - "TARG_CONN_STATE_CLEANUP_WAIT\n"); - break; - default: - rb += sprintf(page+rb, - "ERROR: Unknown Connection State!\n"); - break; - } - - rb += sprintf(page+rb, " Address %s %s", conn->login_ip, - (conn->network_transport == ISCSI_TCP) ? - "TCP" : "SCTP"); - rb += sprintf(page+rb, " StatSN: 0x%08x\n", - conn->stat_sn); - } - spin_unlock(&sess->conn_lock); - } - spin_unlock_bh(&se_nacl->nacl_sess_lock); - - return rb; -} - -TF_NACL_BASE_ATTR_RO(lio_target, info); - -static ssize_t lio_target_nacl_show_cmdsn_depth( - struct se_node_acl *se_nacl, - char *page) -{ - return sprintf(page, "%u\n", se_nacl->queue_depth); -} - -static ssize_t lio_target_nacl_store_cmdsn_depth( - struct se_node_acl *se_nacl, - const char *page, - size_t count) -{ - struct se_portal_group *se_tpg = se_nacl->se_tpg; - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); - struct config_item *acl_ci, *tpg_ci, *wwn_ci; - char *endptr; - u32 cmdsn_depth = 0; - int ret; - - cmdsn_depth = simple_strtoul(page, &endptr, 0); - if (cmdsn_depth > TA_DEFAULT_CMDSN_DEPTH_MAX) { - pr_err("Passed cmdsn_depth: %u exceeds" - " TA_DEFAULT_CMDSN_DEPTH_MAX: %u\n", cmdsn_depth, - TA_DEFAULT_CMDSN_DEPTH_MAX); - return -EINVAL; - } - acl_ci = &se_nacl->acl_group.cg_item; - if (!acl_ci) { - pr_err("Unable to locatel acl_ci\n"); - return -EINVAL; - } - tpg_ci = &acl_ci->ci_parent->ci_group->cg_item; - if (!tpg_ci) { - pr_err("Unable to locate tpg_ci\n"); - return -EINVAL; - } - wwn_ci = &tpg_ci->ci_group->cg_item; - if (!wwn_ci) { - pr_err("Unable to locate config_item wwn_ci\n"); - return -EINVAL; - } - - if (iscsit_get_tpg(tpg) < 0) - return -EINVAL; - /* - * iscsit_tpg_set_initiator_node_queue_depth() assumes force=1 - */ - ret = iscsit_tpg_set_initiator_node_queue_depth(tpg, - config_item_name(acl_ci), cmdsn_depth, 1); - - pr_debug("LIO_Target_ConfigFS: %s/%s Set CmdSN Window: %u for" - "InitiatorName: %s\n", config_item_name(wwn_ci), - config_item_name(tpg_ci), cmdsn_depth, - config_item_name(acl_ci)); - - iscsit_put_tpg(tpg); - return (!ret) ? count : (ssize_t)ret; -} - -TF_NACL_BASE_ATTR(lio_target, cmdsn_depth, S_IRUGO | S_IWUSR); - -static struct configfs_attribute *lio_target_initiator_attrs[] = { - &lio_target_nacl_info.attr, - &lio_target_nacl_cmdsn_depth.attr, - NULL, -}; - -static struct se_node_acl *lio_tpg_alloc_fabric_acl( - struct se_portal_group *se_tpg) -{ - struct iscsi_node_acl *acl; - - acl = kzalloc(sizeof(struct iscsi_node_acl), GFP_KERNEL); - if (!acl) { - pr_err("Unable to allocate memory for struct iscsi_node_acl\n"); - return NULL; - } - - return &acl->se_node_acl; -} - -static struct se_node_acl *lio_target_make_nodeacl( - struct se_portal_group *se_tpg, - struct config_group *group, - const char *name) -{ - struct config_group *stats_cg; - struct iscsi_node_acl *acl; - struct se_node_acl *se_nacl_new, *se_nacl; - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); - u32 cmdsn_depth; - - se_nacl_new = lio_tpg_alloc_fabric_acl(se_tpg); - if (!se_nacl_new) - return ERR_PTR(-ENOMEM); - - acl = container_of(se_nacl_new, struct iscsi_node_acl, - se_node_acl); - - cmdsn_depth = ISCSI_TPG_ATTRIB(tpg)->default_cmdsn_depth; - /* - * se_nacl_new may be released by core_tpg_add_initiator_node_acl() - * when converting a NdoeACL from demo mode -> explict - */ - se_nacl = core_tpg_add_initiator_node_acl(se_tpg, se_nacl_new, - name, cmdsn_depth); - if (IS_ERR(se_nacl)) - return se_nacl; - - stats_cg = &acl->se_node_acl.acl_fabric_stat_group; - - stats_cg->default_groups = kzalloc(sizeof(struct config_group) * 2, - GFP_KERNEL); - if (!stats_cg->default_groups) { - pr_err("Unable to allocate memory for" - " stats_cg->default_groups\n"); - core_tpg_del_initiator_node_acl(se_tpg, se_nacl, 1); - kfree(acl); - return ERR_PTR(-ENOMEM); - } - - stats_cg->default_groups[0] = &NODE_STAT_GRPS(acl)->iscsi_sess_stats_group; - stats_cg->default_groups[1] = NULL; - config_group_init_type_name(&NODE_STAT_GRPS(acl)->iscsi_sess_stats_group, - "iscsi_sess_stats", &iscsi_stat_sess_cit); - - return se_nacl; -} - -static void lio_target_drop_nodeacl( - struct se_node_acl *se_nacl) -{ - struct se_portal_group *se_tpg = se_nacl->se_tpg; - struct iscsi_node_acl *acl = container_of(se_nacl, - struct iscsi_node_acl, se_node_acl); - struct config_item *df_item; - struct config_group *stats_cg; - int i; - - stats_cg = &acl->se_node_acl.acl_fabric_stat_group; - for (i = 0; stats_cg->default_groups[i]; i++) { - df_item = &stats_cg->default_groups[i]->cg_item; - stats_cg->default_groups[i] = NULL; - config_item_put(df_item); - } - kfree(stats_cg->default_groups); - - core_tpg_del_initiator_node_acl(se_tpg, se_nacl, 1); - kfree(acl); -} - -/* End items for lio_target_acl_cit */ - -/* Start items for lio_target_tpg_attrib_cit */ - -#define DEF_TPG_ATTRIB(name) \ - \ -static ssize_t iscsi_tpg_attrib_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ -{ \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ - ssize_t rb; \ - \ - if (iscsit_get_tpg(tpg) < 0) \ - return -EINVAL; \ - \ - rb = sprintf(page, "%u\n", ISCSI_TPG_ATTRIB(tpg)->name); \ - iscsit_put_tpg(tpg); \ - return rb; \ -} \ - \ -static ssize_t iscsi_tpg_attrib_store_##name( \ - struct se_portal_group *se_tpg, \ - const char *page, \ - size_t count) \ -{ \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ - char *endptr; \ - u32 val; \ - int ret; \ - \ - if (iscsit_get_tpg(tpg) < 0) \ - return -EINVAL; \ - \ - val = simple_strtoul(page, &endptr, 0); \ - ret = iscsit_ta_##name(tpg, val); \ - if (ret < 0) \ - goto out; \ - \ - iscsit_put_tpg(tpg); \ - return count; \ -out: \ - iscsit_put_tpg(tpg); \ - return ret; \ -} - -#define TPG_ATTR(_name, _mode) TF_TPG_ATTRIB_ATTR(iscsi, _name, _mode); - -/* - * Define iscsi_tpg_attrib_s_authentication - */ -DEF_TPG_ATTRIB(authentication); -TPG_ATTR(authentication, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_login_timeout - */ -DEF_TPG_ATTRIB(login_timeout); -TPG_ATTR(login_timeout, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_netif_timeout - */ -DEF_TPG_ATTRIB(netif_timeout); -TPG_ATTR(netif_timeout, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_generate_node_acls - */ -DEF_TPG_ATTRIB(generate_node_acls); -TPG_ATTR(generate_node_acls, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_default_cmdsn_depth - */ -DEF_TPG_ATTRIB(default_cmdsn_depth); -TPG_ATTR(default_cmdsn_depth, S_IRUGO | S_IWUSR); -/* - Define iscsi_tpg_attrib_s_cache_dynamic_acls - */ -DEF_TPG_ATTRIB(cache_dynamic_acls); -TPG_ATTR(cache_dynamic_acls, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_demo_mode_write_protect - */ -DEF_TPG_ATTRIB(demo_mode_write_protect); -TPG_ATTR(demo_mode_write_protect, S_IRUGO | S_IWUSR); -/* - * Define iscsi_tpg_attrib_s_prod_mode_write_protect - */ -DEF_TPG_ATTRIB(prod_mode_write_protect); -TPG_ATTR(prod_mode_write_protect, S_IRUGO | S_IWUSR); - -static struct configfs_attribute *lio_target_tpg_attrib_attrs[] = { - &iscsi_tpg_attrib_authentication.attr, - &iscsi_tpg_attrib_login_timeout.attr, - &iscsi_tpg_attrib_netif_timeout.attr, - &iscsi_tpg_attrib_generate_node_acls.attr, - &iscsi_tpg_attrib_default_cmdsn_depth.attr, - &iscsi_tpg_attrib_cache_dynamic_acls.attr, - &iscsi_tpg_attrib_demo_mode_write_protect.attr, - &iscsi_tpg_attrib_prod_mode_write_protect.attr, - NULL, -}; - -/* End items for lio_target_tpg_attrib_cit */ - -/* Start items for lio_target_tpg_param_cit */ - -#define DEF_TPG_PARAM(name) \ -static ssize_t iscsi_tpg_param_show_##name( \ - struct se_portal_group *se_tpg, \ - char *page) \ -{ \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ - struct iscsi_param *param; \ - ssize_t rb; \ - \ - if (iscsit_get_tpg(tpg) < 0) \ - return -EINVAL; \ - \ - param = iscsi_find_param_from_key(__stringify(name), \ - tpg->param_list); \ - if (!param) { \ - iscsit_put_tpg(tpg); \ - return -EINVAL; \ - } \ - rb = snprintf(page, PAGE_SIZE, "%s\n", param->value); \ - \ - iscsit_put_tpg(tpg); \ - return rb; \ -} \ -static ssize_t iscsi_tpg_param_store_##name( \ - struct se_portal_group *se_tpg, \ - const char *page, \ - size_t count) \ -{ \ - struct iscsi_portal_group *tpg = container_of(se_tpg, \ - struct iscsi_portal_group, tpg_se_tpg); \ - char *buf; \ - int ret; \ - \ - buf = kzalloc(PAGE_SIZE, GFP_KERNEL); \ - if (!buf) \ - return -ENOMEM; \ - snprintf(buf, PAGE_SIZE, "%s=%s", __stringify(name), page); \ - buf[strlen(buf)-1] = '\0'; /* Kill newline */ \ - \ - if (iscsit_get_tpg(tpg) < 0) { \ - kfree(buf); \ - return -EINVAL; \ - } \ - \ - ret = iscsi_change_param_value(buf, tpg->param_list, 1); \ - if (ret < 0) \ - goto out; \ - \ - kfree(buf); \ - iscsit_put_tpg(tpg); \ - return count; \ -out: \ - kfree(buf); \ - iscsit_put_tpg(tpg); \ - return -EINVAL; \ -} - -#define TPG_PARAM_ATTR(_name, _mode) TF_TPG_PARAM_ATTR(iscsi, _name, _mode); - -DEF_TPG_PARAM(AuthMethod); -TPG_PARAM_ATTR(AuthMethod, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(HeaderDigest); -TPG_PARAM_ATTR(HeaderDigest, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(DataDigest); -TPG_PARAM_ATTR(DataDigest, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(MaxConnections); -TPG_PARAM_ATTR(MaxConnections, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(TargetAlias); -TPG_PARAM_ATTR(TargetAlias, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(InitialR2T); -TPG_PARAM_ATTR(InitialR2T, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(ImmediateData); -TPG_PARAM_ATTR(ImmediateData, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(MaxRecvDataSegmentLength); -TPG_PARAM_ATTR(MaxRecvDataSegmentLength, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(MaxBurstLength); -TPG_PARAM_ATTR(MaxBurstLength, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(FirstBurstLength); -TPG_PARAM_ATTR(FirstBurstLength, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(DefaultTime2Wait); -TPG_PARAM_ATTR(DefaultTime2Wait, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(DefaultTime2Retain); -TPG_PARAM_ATTR(DefaultTime2Retain, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(MaxOutstandingR2T); -TPG_PARAM_ATTR(MaxOutstandingR2T, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(DataPDUInOrder); -TPG_PARAM_ATTR(DataPDUInOrder, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(DataSequenceInOrder); -TPG_PARAM_ATTR(DataSequenceInOrder, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(ErrorRecoveryLevel); -TPG_PARAM_ATTR(ErrorRecoveryLevel, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(IFMarker); -TPG_PARAM_ATTR(IFMarker, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(OFMarker); -TPG_PARAM_ATTR(OFMarker, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(IFMarkInt); -TPG_PARAM_ATTR(IFMarkInt, S_IRUGO | S_IWUSR); - -DEF_TPG_PARAM(OFMarkInt); -TPG_PARAM_ATTR(OFMarkInt, S_IRUGO | S_IWUSR); - -static struct configfs_attribute *lio_target_tpg_param_attrs[] = { - &iscsi_tpg_param_AuthMethod.attr, - &iscsi_tpg_param_HeaderDigest.attr, - &iscsi_tpg_param_DataDigest.attr, - &iscsi_tpg_param_MaxConnections.attr, - &iscsi_tpg_param_TargetAlias.attr, - &iscsi_tpg_param_InitialR2T.attr, - &iscsi_tpg_param_ImmediateData.attr, - &iscsi_tpg_param_MaxRecvDataSegmentLength.attr, - &iscsi_tpg_param_MaxBurstLength.attr, - &iscsi_tpg_param_FirstBurstLength.attr, - &iscsi_tpg_param_DefaultTime2Wait.attr, - &iscsi_tpg_param_DefaultTime2Retain.attr, - &iscsi_tpg_param_MaxOutstandingR2T.attr, - &iscsi_tpg_param_DataPDUInOrder.attr, - &iscsi_tpg_param_DataSequenceInOrder.attr, - &iscsi_tpg_param_ErrorRecoveryLevel.attr, - &iscsi_tpg_param_IFMarker.attr, - &iscsi_tpg_param_OFMarker.attr, - &iscsi_tpg_param_IFMarkInt.attr, - &iscsi_tpg_param_OFMarkInt.attr, - NULL, -}; - -/* End items for lio_target_tpg_param_cit */ - -/* Start items for lio_target_tpg_cit */ - -static ssize_t lio_target_tpg_show_enable( - struct se_portal_group *se_tpg, - char *page) -{ - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); - ssize_t len; - - spin_lock(&tpg->tpg_state_lock); - len = sprintf(page, "%d\n", - (tpg->tpg_state == TPG_STATE_ACTIVE) ? 1 : 0); - spin_unlock(&tpg->tpg_state_lock); - - return len; -} - -static ssize_t lio_target_tpg_store_enable( - struct se_portal_group *se_tpg, - const char *page, - size_t count) -{ - struct iscsi_portal_group *tpg = container_of(se_tpg, - struct iscsi_portal_group, tpg_se_tpg); - char *endptr; - u32 op; - int ret = 0; - - op = simple_strtoul(page, &endptr, 0); - if ((op != 1) && (op != 0)) { - pr_err("Illegal value for tpg_enable: %u\n", op); - return -EINVAL; - } - - ret = iscsit_get_tpg(tpg); - if (ret < 0) - return -EINVAL; - - if (op) { - ret = iscsit_tpg_enable_portal_group(tpg); - if (ret < 0) - goto out; - } else { - /* - * iscsit_tpg_disable_portal_group() assumes force=1 - */ - ret = iscsit_tpg_disable_portal_group(tpg, 1); - if (ret < 0) - goto out; - } - - iscsit_put_tpg(tpg); - return count; -out: - iscsit_put_tpg(tpg); - return -EINVAL; -} - -TF_TPG_BASE_ATTR(lio_target, enable, S_IRUGO | S_IWUSR); - -static struct configfs_attribute *lio_target_tpg_attrs[] = { - &lio_target_tpg_enable.attr, - NULL, -}; - -/* End items for lio_target_tpg_cit */ - -/* Start items for lio_target_tiqn_cit */ - -struct se_portal_group *lio_target_tiqn_addtpg( - struct se_wwn *wwn, - struct config_group *group, - const char *name) -{ - struct iscsi_portal_group *tpg; - struct iscsi_tiqn *tiqn; - char *tpgt_str, *end_ptr; - int ret = 0; - unsigned short int tpgt; - - tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn); - /* - * Only tpgt_# directory groups can be created below - * target/iscsi/iqn.superturodiskarry/ - */ - tpgt_str = strstr(name, "tpgt_"); - if (!tpgt_str) { - pr_err("Unable to locate \"tpgt_#\" directory" - " group\n"); - return NULL; - } - tpgt_str += 5; /* Skip ahead of "tpgt_" */ - tpgt = (unsigned short int) simple_strtoul(tpgt_str, &end_ptr, 0); - - tpg = iscsit_alloc_portal_group(tiqn, tpgt); - if (!tpg) - return NULL; - - ret = core_tpg_register( - &lio_target_fabric_configfs->tf_ops, - wwn, &tpg->tpg_se_tpg, (void *)tpg, - TRANSPORT_TPG_TYPE_NORMAL); - if (ret < 0) - return NULL; - - ret = iscsit_tpg_add_portal_group(tiqn, tpg); - if (ret != 0) - goto out; - - pr_debug("LIO_Target_ConfigFS: REGISTER -> %s\n", tiqn->tiqn); - pr_debug("LIO_Target_ConfigFS: REGISTER -> Allocated TPG: %s\n", - name); - return &tpg->tpg_se_tpg; -out: - core_tpg_deregister(&tpg->tpg_se_tpg); - kfree(tpg); - return NULL; -} - -void lio_target_tiqn_deltpg(struct se_portal_group *se_tpg) -{ - struct iscsi_portal_group *tpg; - struct iscsi_tiqn *tiqn; - - tpg = container_of(se_tpg, struct iscsi_portal_group, tpg_se_tpg); - tiqn = tpg->tpg_tiqn; - /* - * iscsit_tpg_del_portal_group() assumes force=1 - */ - pr_debug("LIO_Target_ConfigFS: DEREGISTER -> Releasing TPG\n"); - iscsit_tpg_del_portal_group(tiqn, tpg, 1); -} - -/* End items for lio_target_tiqn_cit */ - -/* Start LIO-Target TIQN struct contig_item lio_target_cit */ - -static ssize_t lio_target_wwn_show_attr_lio_version( - struct target_fabric_configfs *tf, - char *page) -{ - return sprintf(page, "RisingTide Systems Linux-iSCSI Target "ISCSIT_VERSION"\n"); -} - -TF_WWN_ATTR_RO(lio_target, lio_version); - -static struct configfs_attribute *lio_target_wwn_attrs[] = { - &lio_target_wwn_lio_version.attr, - NULL, -}; - -struct se_wwn *lio_target_call_coreaddtiqn( - struct target_fabric_configfs *tf, - struct config_group *group, - const char *name) -{ - struct config_group *stats_cg; - struct iscsi_tiqn *tiqn; - - tiqn = iscsit_add_tiqn((unsigned char *)name); - if (IS_ERR(tiqn)) - return ERR_PTR(PTR_ERR(tiqn)); - /* - * Setup struct iscsi_wwn_stat_grps for se_wwn->fabric_stat_group. - */ - stats_cg = &tiqn->tiqn_wwn.fabric_stat_group; - - stats_cg->default_groups = kzalloc(sizeof(struct config_group) * 6, - GFP_KERNEL); - if (!stats_cg->default_groups) { - pr_err("Unable to allocate memory for" - " stats_cg->default_groups\n"); - iscsit_del_tiqn(tiqn); - return ERR_PTR(-ENOMEM); - } - - stats_cg->default_groups[0] = &WWN_STAT_GRPS(tiqn)->iscsi_instance_group; - stats_cg->default_groups[1] = &WWN_STAT_GRPS(tiqn)->iscsi_sess_err_group; - stats_cg->default_groups[2] = &WWN_STAT_GRPS(tiqn)->iscsi_tgt_attr_group; - stats_cg->default_groups[3] = &WWN_STAT_GRPS(tiqn)->iscsi_login_stats_group; - stats_cg->default_groups[4] = &WWN_STAT_GRPS(tiqn)->iscsi_logout_stats_group; - stats_cg->default_groups[5] = NULL; - config_group_init_type_name(&WWN_STAT_GRPS(tiqn)->iscsi_instance_group, - "iscsi_instance", &iscsi_stat_instance_cit); - config_group_init_type_name(&WWN_STAT_GRPS(tiqn)->iscsi_sess_err_group, - "iscsi_sess_err", &iscsi_stat_sess_err_cit); - config_group_init_type_name(&WWN_STAT_GRPS(tiqn)->iscsi_tgt_attr_group, - "iscsi_tgt_attr", &iscsi_stat_tgt_attr_cit); - config_group_init_type_name(&WWN_STAT_GRPS(tiqn)->iscsi_login_stats_group, - "iscsi_login_stats", &iscsi_stat_login_cit); - config_group_init_type_name(&WWN_STAT_GRPS(tiqn)->iscsi_logout_stats_group, - "iscsi_logout_stats", &iscsi_stat_logout_cit); - - pr_debug("LIO_Target_ConfigFS: REGISTER -> %s\n", tiqn->tiqn); - pr_debug("LIO_Target_ConfigFS: REGISTER -> Allocated Node:" - " %s\n", name); - return &tiqn->tiqn_wwn; -} - -void lio_target_call_coredeltiqn( - struct se_wwn *wwn) -{ - struct iscsi_tiqn *tiqn = container_of(wwn, struct iscsi_tiqn, tiqn_wwn); - struct config_item *df_item; - struct config_group *stats_cg; - int i; - - stats_cg = &tiqn->tiqn_wwn.fabric_stat_group; - for (i = 0; stats_cg->default_groups[i]; i++) { - df_item = &stats_cg->default_groups[i]->cg_item; - stats_cg->default_groups[i] = NULL; - config_item_put(df_item); - } - kfree(stats_cg->default_groups); - - pr_debug("LIO_Target_ConfigFS: DEREGISTER -> %s\n", - tiqn->tiqn); - iscsit_del_tiqn(tiqn); -} - -/* End LIO-Target TIQN struct contig_lio_target_cit */ - -/* Start lio_target_discovery_auth_cit */ - -#define DEF_DISC_AUTH_STR(name, flags) \ - __DEF_NACL_AUTH_STR(disc, name, flags) \ -static ssize_t iscsi_disc_show_##name( \ - struct target_fabric_configfs *tf, \ - char *page) \ -{ \ - return __iscsi_disc_show_##name(&iscsit_global->discovery_acl, \ - page); \ -} \ -static ssize_t iscsi_disc_store_##name( \ - struct target_fabric_configfs *tf, \ - const char *page, \ - size_t count) \ -{ \ - return __iscsi_disc_store_##name(&iscsit_global->discovery_acl, \ - page, count); \ -} - -#define DEF_DISC_AUTH_INT(name) \ - __DEF_NACL_AUTH_INT(disc, name) \ -static ssize_t iscsi_disc_show_##name( \ - struct target_fabric_configfs *tf, \ - char *page) \ -{ \ - return __iscsi_disc_show_##name(&iscsit_global->discovery_acl, \ - page); \ -} - -#define DISC_AUTH_ATTR(_name, _mode) TF_DISC_ATTR(iscsi, _name, _mode) -#define DISC_AUTH_ATTR_RO(_name) TF_DISC_ATTR_RO(iscsi, _name) - -/* - * One-way authentication userid - */ -DEF_DISC_AUTH_STR(userid, NAF_USERID_SET); -DISC_AUTH_ATTR(userid, S_IRUGO | S_IWUSR); -/* - * One-way authentication password - */ -DEF_DISC_AUTH_STR(password, NAF_PASSWORD_SET); -DISC_AUTH_ATTR(password, S_IRUGO | S_IWUSR); -/* - * Enforce mutual authentication - */ -DEF_DISC_AUTH_INT(authenticate_target); -DISC_AUTH_ATTR_RO(authenticate_target); -/* - * Mutual authentication userid - */ -DEF_DISC_AUTH_STR(userid_mutual, NAF_USERID_IN_SET); -DISC_AUTH_ATTR(userid_mutual, S_IRUGO | S_IWUSR); -/* - * Mutual authentication password - */ -DEF_DISC_AUTH_STR(password_mutual, NAF_PASSWORD_IN_SET); -DISC_AUTH_ATTR(password_mutual, S_IRUGO | S_IWUSR); - -/* - * enforce_discovery_auth - */ -static ssize_t iscsi_disc_show_enforce_discovery_auth( - struct target_fabric_configfs *tf, - char *page) -{ - struct iscsi_node_auth *discovery_auth = &iscsit_global->discovery_acl.node_auth; - - return sprintf(page, "%d\n", discovery_auth->enforce_discovery_auth); -} - -static ssize_t iscsi_disc_store_enforce_discovery_auth( - struct target_fabric_configfs *tf, - const char *page, - size_t count) -{ - struct iscsi_param *param; - struct iscsi_portal_group *discovery_tpg = iscsit_global->discovery_tpg; - char *endptr; - u32 op; - - op = simple_strtoul(page, &endptr, 0); - if ((op != 1) && (op != 0)) { - pr_err("Illegal value for enforce_discovery_auth:" - " %u\n", op); - return -EINVAL; - } - - if (!discovery_tpg) { - pr_err("iscsit_global->discovery_tpg is NULL\n"); - return -EINVAL; - } - - param = iscsi_find_param_from_key(AUTHMETHOD, - discovery_tpg->param_list); - if (!param) - return -EINVAL; - - if (op) { - /* - * Reset the AuthMethod key to CHAP. - */ - if (iscsi_update_param_value(param, CHAP) < 0) - return -EINVAL; - - discovery_tpg->tpg_attrib.authentication = 1; - iscsit_global->discovery_acl.node_auth.enforce_discovery_auth = 1; - pr_debug("LIO-CORE[0] Successfully enabled" - " authentication enforcement for iSCSI" - " Discovery TPG\n"); - } else { - /* - * Reset the AuthMethod key to CHAP,None - */ - if (iscsi_update_param_value(param, "CHAP,None") < 0) - return -EINVAL; - - discovery_tpg->tpg_attrib.authentication = 0; - iscsit_global->discovery_acl.node_auth.enforce_discovery_auth = 0; - pr_debug("LIO-CORE[0] Successfully disabled" - " authentication enforcement for iSCSI" - " Discovery TPG\n"); - } - - return count; -} - -DISC_AUTH_ATTR(enforce_discovery_auth, S_IRUGO | S_IWUSR); - -static struct configfs_attribute *lio_target_discovery_auth_attrs[] = { - &iscsi_disc_userid.attr, - &iscsi_disc_password.attr, - &iscsi_disc_authenticate_target.attr, - &iscsi_disc_userid_mutual.attr, - &iscsi_disc_password_mutual.attr, - &iscsi_disc_enforce_discovery_auth.attr, - NULL, -}; - -/* End lio_target_discovery_auth_cit */ - -/* Start functions for target_core_fabric_ops */ - -static char *iscsi_get_fabric_name(void) -{ - return "iSCSI"; -} - -static u32 iscsi_get_task_tag(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - return cmd->init_task_tag; -} - -static int iscsi_get_cmd_state(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - return cmd->i_state; -} - -static int iscsi_is_state_remove(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - return (cmd->i_state == ISTATE_REMOVE); -} - -static int lio_sess_logged_in(struct se_session *se_sess) -{ - struct iscsi_session *sess = se_sess->fabric_sess_ptr; - int ret; - /* - * Called with spin_lock_bh(&tpg_lock); and - * spin_lock(&se_tpg->session_lock); held. - */ - spin_lock(&sess->conn_lock); - ret = (sess->session_state != TARG_SESS_STATE_LOGGED_IN); - spin_unlock(&sess->conn_lock); - - return ret; -} - -static u32 lio_sess_get_index(struct se_session *se_sess) -{ - struct iscsi_session *sess = se_sess->fabric_sess_ptr; - - return sess->session_index; -} - -static u32 lio_sess_get_initiator_sid( - struct se_session *se_sess, - unsigned char *buf, - u32 size) -{ - struct iscsi_session *sess = se_sess->fabric_sess_ptr; - /* - * iSCSI Initiator Session Identifier from RFC-3720. - */ - return snprintf(buf, size, "%02x%02x%02x%02x%02x%02x", - sess->isid[0], sess->isid[1], sess->isid[2], - sess->isid[3], sess->isid[4], sess->isid[5]); -} - -static int lio_queue_data_in(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - cmd->i_state = ISTATE_SEND_DATAIN; - iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); - return 0; -} - -static int lio_write_pending(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - if (!cmd->immediate_data && !cmd->unsolicited_data) - return iscsit_build_r2ts_for_cmd(cmd, cmd->conn, 1); - - return 0; -} - -static int lio_write_pending_status(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - int ret; - - spin_lock_bh(&cmd->istate_lock); - ret = !(cmd->cmd_flags & ICF_GOT_LAST_DATAOUT); - spin_unlock_bh(&cmd->istate_lock); - - return ret; -} - -static int lio_queue_status(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - cmd->i_state = ISTATE_SEND_STATUS; - iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); - return 0; -} - -static u16 lio_set_fabric_sense_len(struct se_cmd *se_cmd, u32 sense_length) -{ - unsigned char *buffer = se_cmd->sense_buffer; - /* - * From RFC-3720 10.4.7. Data Segment - Sense and Response Data Segment - * 16-bit SenseLength. - */ - buffer[0] = ((sense_length >> 8) & 0xff); - buffer[1] = (sense_length & 0xff); - /* - * Return two byte offset into allocated sense_buffer. - */ - return 2; -} - -static u16 lio_get_fabric_sense_len(void) -{ - /* - * Return two byte offset into allocated sense_buffer. - */ - return 2; -} - -static int lio_queue_tm_rsp(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - cmd->i_state = ISTATE_SEND_TASKMGTRSP; - iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); - return 0; -} - -static char *lio_tpg_get_endpoint_wwn(struct se_portal_group *se_tpg) -{ - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return &tpg->tpg_tiqn->tiqn[0]; -} - -static u16 lio_tpg_get_tag(struct se_portal_group *se_tpg) -{ - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->tpgt; -} - -static u32 lio_tpg_get_default_depth(struct se_portal_group *se_tpg) -{ - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return ISCSI_TPG_ATTRIB(tpg)->default_cmdsn_depth; -} - -static int lio_tpg_check_demo_mode(struct se_portal_group *se_tpg) -{ - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return ISCSI_TPG_ATTRIB(tpg)->generate_node_acls; -} - -static int lio_tpg_check_demo_mode_cache(struct se_portal_group *se_tpg) -{ - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return ISCSI_TPG_ATTRIB(tpg)->cache_dynamic_acls; -} - -static int lio_tpg_check_demo_mode_write_protect( - struct se_portal_group *se_tpg) -{ - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return ISCSI_TPG_ATTRIB(tpg)->demo_mode_write_protect; -} - -static int lio_tpg_check_prod_mode_write_protect( - struct se_portal_group *se_tpg) -{ - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return ISCSI_TPG_ATTRIB(tpg)->prod_mode_write_protect; -} - -static void lio_tpg_release_fabric_acl( - struct se_portal_group *se_tpg, - struct se_node_acl *se_acl) -{ - struct iscsi_node_acl *acl = container_of(se_acl, - struct iscsi_node_acl, se_node_acl); - kfree(acl); -} - -/* - * Called with spin_lock_bh(struct se_portal_group->session_lock) held.. - * - * Also, this function calls iscsit_inc_session_usage_count() on the - * struct iscsi_session in question. - */ -static int lio_tpg_shutdown_session(struct se_session *se_sess) -{ - struct iscsi_session *sess = se_sess->fabric_sess_ptr; - - spin_lock(&sess->conn_lock); - if (atomic_read(&sess->session_fall_back_to_erl0) || - atomic_read(&sess->session_logout) || - (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED)) { - spin_unlock(&sess->conn_lock); - return 0; - } - atomic_set(&sess->session_reinstatement, 1); - spin_unlock(&sess->conn_lock); - - iscsit_inc_session_usage_count(sess); - iscsit_stop_time2retain_timer(sess); - - return 1; -} - -/* - * Calls iscsit_dec_session_usage_count() as inverse of - * lio_tpg_shutdown_session() - */ -static void lio_tpg_close_session(struct se_session *se_sess) -{ - struct iscsi_session *sess = se_sess->fabric_sess_ptr; - /* - * If the iSCSI Session for the iSCSI Initiator Node exists, - * forcefully shutdown the iSCSI NEXUS. - */ - iscsit_stop_session(sess, 1, 1); - iscsit_dec_session_usage_count(sess); - iscsit_close_session(sess); -} - -static void lio_tpg_stop_session( - struct se_session *se_sess, - int sess_sleep, - int conn_sleep) -{ - struct iscsi_session *sess = se_sess->fabric_sess_ptr; - - iscsit_stop_session(sess, sess_sleep, conn_sleep); -} - -static void lio_tpg_fall_back_to_erl0(struct se_session *se_sess) -{ - struct iscsi_session *sess = se_sess->fabric_sess_ptr; - - iscsit_fall_back_to_erl0(sess); -} - -static u32 lio_tpg_get_inst_index(struct se_portal_group *se_tpg) -{ - struct iscsi_portal_group *tpg = se_tpg->se_tpg_fabric_ptr; - - return tpg->tpg_tiqn->tiqn_index; -} - -static void lio_set_default_node_attributes(struct se_node_acl *se_acl) -{ - struct iscsi_node_acl *acl = container_of(se_acl, struct iscsi_node_acl, - se_node_acl); - - ISCSI_NODE_ATTRIB(acl)->nacl = acl; - iscsit_set_default_node_attribues(acl); -} - -static void lio_release_cmd(struct se_cmd *se_cmd) -{ - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - iscsit_release_cmd(cmd); -} - -/* End functions for target_core_fabric_ops */ - -int iscsi_target_register_configfs(void) -{ - struct target_fabric_configfs *fabric; - int ret; - - lio_target_fabric_configfs = NULL; - fabric = target_fabric_configfs_init(THIS_MODULE, "iscsi"); - if (IS_ERR(fabric)) { - pr_err("target_fabric_configfs_init() for" - " LIO-Target failed!\n"); - return PTR_ERR(fabric); - } - /* - * Setup the fabric API of function pointers used by target_core_mod.. - */ - fabric->tf_ops.get_fabric_name = &iscsi_get_fabric_name; - fabric->tf_ops.get_fabric_proto_ident = &iscsi_get_fabric_proto_ident; - fabric->tf_ops.tpg_get_wwn = &lio_tpg_get_endpoint_wwn; - fabric->tf_ops.tpg_get_tag = &lio_tpg_get_tag; - fabric->tf_ops.tpg_get_default_depth = &lio_tpg_get_default_depth; - fabric->tf_ops.tpg_get_pr_transport_id = &iscsi_get_pr_transport_id; - fabric->tf_ops.tpg_get_pr_transport_id_len = - &iscsi_get_pr_transport_id_len; - fabric->tf_ops.tpg_parse_pr_out_transport_id = - &iscsi_parse_pr_out_transport_id; - fabric->tf_ops.tpg_check_demo_mode = &lio_tpg_check_demo_mode; - fabric->tf_ops.tpg_check_demo_mode_cache = - &lio_tpg_check_demo_mode_cache; - fabric->tf_ops.tpg_check_demo_mode_write_protect = - &lio_tpg_check_demo_mode_write_protect; - fabric->tf_ops.tpg_check_prod_mode_write_protect = - &lio_tpg_check_prod_mode_write_protect; - fabric->tf_ops.tpg_alloc_fabric_acl = &lio_tpg_alloc_fabric_acl; - fabric->tf_ops.tpg_release_fabric_acl = &lio_tpg_release_fabric_acl; - fabric->tf_ops.tpg_get_inst_index = &lio_tpg_get_inst_index; - fabric->tf_ops.release_cmd = &lio_release_cmd; - fabric->tf_ops.shutdown_session = &lio_tpg_shutdown_session; - fabric->tf_ops.close_session = &lio_tpg_close_session; - fabric->tf_ops.stop_session = &lio_tpg_stop_session; - fabric->tf_ops.fall_back_to_erl0 = &lio_tpg_fall_back_to_erl0; - fabric->tf_ops.sess_logged_in = &lio_sess_logged_in; - fabric->tf_ops.sess_get_index = &lio_sess_get_index; - fabric->tf_ops.sess_get_initiator_sid = &lio_sess_get_initiator_sid; - fabric->tf_ops.write_pending = &lio_write_pending; - fabric->tf_ops.write_pending_status = &lio_write_pending_status; - fabric->tf_ops.set_default_node_attributes = - &lio_set_default_node_attributes; - fabric->tf_ops.get_task_tag = &iscsi_get_task_tag; - fabric->tf_ops.get_cmd_state = &iscsi_get_cmd_state; - fabric->tf_ops.queue_data_in = &lio_queue_data_in; - fabric->tf_ops.queue_status = &lio_queue_status; - fabric->tf_ops.queue_tm_rsp = &lio_queue_tm_rsp; - fabric->tf_ops.set_fabric_sense_len = &lio_set_fabric_sense_len; - fabric->tf_ops.get_fabric_sense_len = &lio_get_fabric_sense_len; - fabric->tf_ops.is_state_remove = &iscsi_is_state_remove; - /* - * Setup function pointers for generic logic in target_core_fabric_configfs.c - */ - fabric->tf_ops.fabric_make_wwn = &lio_target_call_coreaddtiqn; - fabric->tf_ops.fabric_drop_wwn = &lio_target_call_coredeltiqn; - fabric->tf_ops.fabric_make_tpg = &lio_target_tiqn_addtpg; - fabric->tf_ops.fabric_drop_tpg = &lio_target_tiqn_deltpg; - fabric->tf_ops.fabric_post_link = NULL; - fabric->tf_ops.fabric_pre_unlink = NULL; - fabric->tf_ops.fabric_make_np = &lio_target_call_addnptotpg; - fabric->tf_ops.fabric_drop_np = &lio_target_call_delnpfromtpg; - fabric->tf_ops.fabric_make_nodeacl = &lio_target_make_nodeacl; - fabric->tf_ops.fabric_drop_nodeacl = &lio_target_drop_nodeacl; - /* - * Setup default attribute lists for various fabric->tf_cit_tmpl - * sturct config_item_type's - */ - TF_CIT_TMPL(fabric)->tfc_discovery_cit.ct_attrs = lio_target_discovery_auth_attrs; - TF_CIT_TMPL(fabric)->tfc_wwn_cit.ct_attrs = lio_target_wwn_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_base_cit.ct_attrs = lio_target_tpg_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_attrib_cit.ct_attrs = lio_target_tpg_attrib_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_param_cit.ct_attrs = lio_target_tpg_param_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_np_base_cit.ct_attrs = lio_target_portal_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_base_cit.ct_attrs = lio_target_initiator_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_attrib_cit.ct_attrs = lio_target_nacl_attrib_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_auth_cit.ct_attrs = lio_target_nacl_auth_attrs; - TF_CIT_TMPL(fabric)->tfc_tpg_nacl_param_cit.ct_attrs = lio_target_nacl_param_attrs; - - ret = target_fabric_configfs_register(fabric); - if (ret < 0) { - pr_err("target_fabric_configfs_register() for" - " LIO-Target failed!\n"); - target_fabric_configfs_free(fabric); - return ret; - } - - lio_target_fabric_configfs = fabric; - pr_debug("LIO_TARGET[0] - Set fabric ->" - " lio_target_fabric_configfs\n"); - return 0; -} - - -void iscsi_target_deregister_configfs(void) -{ - if (!lio_target_fabric_configfs) - return; - /* - * Shutdown discovery sessions and disable discovery TPG - */ - if (iscsit_global->discovery_tpg) - iscsit_tpg_disable_portal_group(iscsit_global->discovery_tpg, 1); - - target_fabric_configfs_deregister(lio_target_fabric_configfs); - lio_target_fabric_configfs = NULL; - pr_debug("LIO_TARGET[0] - Cleared" - " lio_target_fabric_configfs\n"); -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_configfs.h b/trunk/drivers/target/iscsi/iscsi_target_configfs.h deleted file mode 100644 index 8cd5a63c4edc..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_configfs.h +++ /dev/null @@ -1,7 +0,0 @@ -#ifndef ISCSI_TARGET_CONFIGFS_H -#define ISCSI_TARGET_CONFIGFS_H - -extern int iscsi_target_register_configfs(void); -extern void iscsi_target_deregister_configfs(void); - -#endif /* ISCSI_TARGET_CONFIGFS_H */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_core.h b/trunk/drivers/target/iscsi/iscsi_target_core.h deleted file mode 100644 index 470ed551eeb5..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_core.h +++ /dev/null @@ -1,859 +0,0 @@ -#ifndef ISCSI_TARGET_CORE_H -#define ISCSI_TARGET_CORE_H - -#include -#include -#include -#include -#include -#include -#include - -#define ISCSIT_VERSION "v4.1.0-rc1" -#define ISCSI_MAX_DATASN_MISSING_COUNT 16 -#define ISCSI_TX_THREAD_TCP_TIMEOUT 2 -#define ISCSI_RX_THREAD_TCP_TIMEOUT 2 -#define SECONDS_FOR_ASYNC_LOGOUT 10 -#define SECONDS_FOR_ASYNC_TEXT 10 -#define SECONDS_FOR_LOGOUT_COMP 15 -#define WHITE_SPACE " \t\v\f\n\r" - -/* struct iscsi_node_attrib sanity values */ -#define NA_DATAOUT_TIMEOUT 3 -#define NA_DATAOUT_TIMEOUT_MAX 60 -#define NA_DATAOUT_TIMEOUT_MIX 2 -#define NA_DATAOUT_TIMEOUT_RETRIES 5 -#define NA_DATAOUT_TIMEOUT_RETRIES_MAX 15 -#define NA_DATAOUT_TIMEOUT_RETRIES_MIN 1 -#define NA_NOPIN_TIMEOUT 5 -#define NA_NOPIN_TIMEOUT_MAX 60 -#define NA_NOPIN_TIMEOUT_MIN 3 -#define NA_NOPIN_RESPONSE_TIMEOUT 5 -#define NA_NOPIN_RESPONSE_TIMEOUT_MAX 60 -#define NA_NOPIN_RESPONSE_TIMEOUT_MIN 3 -#define NA_RANDOM_DATAIN_PDU_OFFSETS 0 -#define NA_RANDOM_DATAIN_SEQ_OFFSETS 0 -#define NA_RANDOM_R2T_OFFSETS 0 -#define NA_DEFAULT_ERL 0 -#define NA_DEFAULT_ERL_MAX 2 -#define NA_DEFAULT_ERL_MIN 0 - -/* struct iscsi_tpg_attrib sanity values */ -#define TA_AUTHENTICATION 1 -#define TA_LOGIN_TIMEOUT 15 -#define TA_LOGIN_TIMEOUT_MAX 30 -#define TA_LOGIN_TIMEOUT_MIN 5 -#define TA_NETIF_TIMEOUT 2 -#define TA_NETIF_TIMEOUT_MAX 15 -#define TA_NETIF_TIMEOUT_MIN 2 -#define TA_GENERATE_NODE_ACLS 0 -#define TA_DEFAULT_CMDSN_DEPTH 16 -#define TA_DEFAULT_CMDSN_DEPTH_MAX 512 -#define TA_DEFAULT_CMDSN_DEPTH_MIN 1 -#define TA_CACHE_DYNAMIC_ACLS 0 -/* Enabled by default in demo mode (generic_node_acls=1) */ -#define TA_DEMO_MODE_WRITE_PROTECT 1 -/* Disabled by default in production mode w/ explict ACLs */ -#define TA_PROD_MODE_WRITE_PROTECT 0 -#define TA_CACHE_CORE_NPS 0 - -enum tpg_np_network_transport_table { - ISCSI_TCP = 0, - ISCSI_SCTP_TCP = 1, - ISCSI_SCTP_UDP = 2, - ISCSI_IWARP_TCP = 3, - ISCSI_IWARP_SCTP = 4, - ISCSI_INFINIBAND = 5, -}; - -/* RFC-3720 7.1.4 Standard Connection State Diagram for a Target */ -enum target_conn_state_table { - TARG_CONN_STATE_FREE = 0x1, - TARG_CONN_STATE_XPT_UP = 0x3, - TARG_CONN_STATE_IN_LOGIN = 0x4, - TARG_CONN_STATE_LOGGED_IN = 0x5, - TARG_CONN_STATE_IN_LOGOUT = 0x6, - TARG_CONN_STATE_LOGOUT_REQUESTED = 0x7, - TARG_CONN_STATE_CLEANUP_WAIT = 0x8, -}; - -/* RFC-3720 7.3.2 Session State Diagram for a Target */ -enum target_sess_state_table { - TARG_SESS_STATE_FREE = 0x1, - TARG_SESS_STATE_ACTIVE = 0x2, - TARG_SESS_STATE_LOGGED_IN = 0x3, - TARG_SESS_STATE_FAILED = 0x4, - TARG_SESS_STATE_IN_CONTINUE = 0x5, -}; - -/* struct iscsi_data_count->type */ -enum data_count_type { - ISCSI_RX_DATA = 1, - ISCSI_TX_DATA = 2, -}; - -/* struct iscsi_datain_req->dr_complete */ -enum datain_req_comp_table { - DATAIN_COMPLETE_NORMAL = 1, - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY = 2, - DATAIN_COMPLETE_CONNECTION_RECOVERY = 3, -}; - -/* struct iscsi_datain_req->recovery */ -enum datain_req_rec_table { - DATAIN_WITHIN_COMMAND_RECOVERY = 1, - DATAIN_CONNECTION_RECOVERY = 2, -}; - -/* struct iscsi_portal_group->state */ -enum tpg_state_table { - TPG_STATE_FREE = 0, - TPG_STATE_ACTIVE = 1, - TPG_STATE_INACTIVE = 2, - TPG_STATE_COLD_RESET = 3, -}; - -/* struct iscsi_tiqn->tiqn_state */ -enum tiqn_state_table { - TIQN_STATE_ACTIVE = 1, - TIQN_STATE_SHUTDOWN = 2, -}; - -/* struct iscsi_cmd->cmd_flags */ -enum cmd_flags_table { - ICF_GOT_LAST_DATAOUT = 0x00000001, - ICF_GOT_DATACK_SNACK = 0x00000002, - ICF_NON_IMMEDIATE_UNSOLICITED_DATA = 0x00000004, - ICF_SENT_LAST_R2T = 0x00000008, - ICF_WITHIN_COMMAND_RECOVERY = 0x00000010, - ICF_CONTIG_MEMORY = 0x00000020, - ICF_ATTACHED_TO_RQUEUE = 0x00000040, - ICF_OOO_CMDSN = 0x00000080, - ICF_REJECT_FAIL_CONN = 0x00000100, -}; - -/* struct iscsi_cmd->i_state */ -enum cmd_i_state_table { - ISTATE_NO_STATE = 0, - ISTATE_NEW_CMD = 1, - ISTATE_DEFERRED_CMD = 2, - ISTATE_UNSOLICITED_DATA = 3, - ISTATE_RECEIVE_DATAOUT = 4, - ISTATE_RECEIVE_DATAOUT_RECOVERY = 5, - ISTATE_RECEIVED_LAST_DATAOUT = 6, - ISTATE_WITHIN_DATAOUT_RECOVERY = 7, - ISTATE_IN_CONNECTION_RECOVERY = 8, - ISTATE_RECEIVED_TASKMGT = 9, - ISTATE_SEND_ASYNCMSG = 10, - ISTATE_SENT_ASYNCMSG = 11, - ISTATE_SEND_DATAIN = 12, - ISTATE_SEND_LAST_DATAIN = 13, - ISTATE_SENT_LAST_DATAIN = 14, - ISTATE_SEND_LOGOUTRSP = 15, - ISTATE_SENT_LOGOUTRSP = 16, - ISTATE_SEND_NOPIN = 17, - ISTATE_SENT_NOPIN = 18, - ISTATE_SEND_REJECT = 19, - ISTATE_SENT_REJECT = 20, - ISTATE_SEND_R2T = 21, - ISTATE_SENT_R2T = 22, - ISTATE_SEND_R2T_RECOVERY = 23, - ISTATE_SENT_R2T_RECOVERY = 24, - ISTATE_SEND_LAST_R2T = 25, - ISTATE_SENT_LAST_R2T = 26, - ISTATE_SEND_LAST_R2T_RECOVERY = 27, - ISTATE_SENT_LAST_R2T_RECOVERY = 28, - ISTATE_SEND_STATUS = 29, - ISTATE_SEND_STATUS_BROKEN_PC = 30, - ISTATE_SENT_STATUS = 31, - ISTATE_SEND_STATUS_RECOVERY = 32, - ISTATE_SENT_STATUS_RECOVERY = 33, - ISTATE_SEND_TASKMGTRSP = 34, - ISTATE_SENT_TASKMGTRSP = 35, - ISTATE_SEND_TEXTRSP = 36, - ISTATE_SENT_TEXTRSP = 37, - ISTATE_SEND_NOPIN_WANT_RESPONSE = 38, - ISTATE_SENT_NOPIN_WANT_RESPONSE = 39, - ISTATE_SEND_NOPIN_NO_RESPONSE = 40, - ISTATE_REMOVE = 41, - ISTATE_FREE = 42, -}; - -/* Used for iscsi_recover_cmdsn() return values */ -enum recover_cmdsn_ret_table { - CMDSN_ERROR_CANNOT_RECOVER = -1, - CMDSN_NORMAL_OPERATION = 0, - CMDSN_LOWER_THAN_EXP = 1, - CMDSN_HIGHER_THAN_EXP = 2, -}; - -/* Used for iscsi_handle_immediate_data() return values */ -enum immedate_data_ret_table { - IMMEDIATE_DATA_CANNOT_RECOVER = -1, - IMMEDIATE_DATA_NORMAL_OPERATION = 0, - IMMEDIATE_DATA_ERL1_CRC_FAILURE = 1, -}; - -/* Used for iscsi_decide_dataout_action() return values */ -enum dataout_action_ret_table { - DATAOUT_CANNOT_RECOVER = -1, - DATAOUT_NORMAL = 0, - DATAOUT_SEND_R2T = 1, - DATAOUT_SEND_TO_TRANSPORT = 2, - DATAOUT_WITHIN_COMMAND_RECOVERY = 3, -}; - -/* Used for struct iscsi_node_auth->naf_flags */ -enum naf_flags_table { - NAF_USERID_SET = 0x01, - NAF_PASSWORD_SET = 0x02, - NAF_USERID_IN_SET = 0x04, - NAF_PASSWORD_IN_SET = 0x08, -}; - -/* Used by various struct timer_list to manage iSCSI specific state */ -enum iscsi_timer_flags_table { - ISCSI_TF_RUNNING = 0x01, - ISCSI_TF_STOP = 0x02, - ISCSI_TF_EXPIRED = 0x04, -}; - -/* Used for struct iscsi_np->np_flags */ -enum np_flags_table { - NPF_IP_NETWORK = 0x00, - NPF_SCTP_STRUCT_FILE = 0x01 /* Bugfix */ -}; - -/* Used for struct iscsi_np->np_thread_state */ -enum np_thread_state_table { - ISCSI_NP_THREAD_ACTIVE = 1, - ISCSI_NP_THREAD_INACTIVE = 2, - ISCSI_NP_THREAD_RESET = 3, - ISCSI_NP_THREAD_SHUTDOWN = 4, - ISCSI_NP_THREAD_EXIT = 5, -}; - -struct iscsi_conn_ops { - u8 HeaderDigest; /* [0,1] == [None,CRC32C] */ - u8 DataDigest; /* [0,1] == [None,CRC32C] */ - u32 MaxRecvDataSegmentLength; /* [512..2**24-1] */ - u8 OFMarker; /* [0,1] == [No,Yes] */ - u8 IFMarker; /* [0,1] == [No,Yes] */ - u32 OFMarkInt; /* [1..65535] */ - u32 IFMarkInt; /* [1..65535] */ -}; - -struct iscsi_sess_ops { - char InitiatorName[224]; - char InitiatorAlias[256]; - char TargetName[224]; - char TargetAlias[256]; - char TargetAddress[256]; - u16 TargetPortalGroupTag; /* [0..65535] */ - u16 MaxConnections; /* [1..65535] */ - u8 InitialR2T; /* [0,1] == [No,Yes] */ - u8 ImmediateData; /* [0,1] == [No,Yes] */ - u32 MaxBurstLength; /* [512..2**24-1] */ - u32 FirstBurstLength; /* [512..2**24-1] */ - u16 DefaultTime2Wait; /* [0..3600] */ - u16 DefaultTime2Retain; /* [0..3600] */ - u16 MaxOutstandingR2T; /* [1..65535] */ - u8 DataPDUInOrder; /* [0,1] == [No,Yes] */ - u8 DataSequenceInOrder; /* [0,1] == [No,Yes] */ - u8 ErrorRecoveryLevel; /* [0..2] */ - u8 SessionType; /* [0,1] == [Normal,Discovery]*/ -}; - -struct iscsi_queue_req { - int state; - struct iscsi_cmd *cmd; - struct list_head qr_list; -}; - -struct iscsi_data_count { - int data_length; - int sync_and_steering; - enum data_count_type type; - u32 iov_count; - u32 ss_iov_count; - u32 ss_marker_count; - struct kvec *iov; -}; - -struct iscsi_param_list { - struct list_head param_list; - struct list_head extra_response_list; -}; - -struct iscsi_datain_req { - enum datain_req_comp_table dr_complete; - int generate_recovery_values; - enum datain_req_rec_table recovery; - u32 begrun; - u32 runlength; - u32 data_length; - u32 data_offset; - u32 data_offset_end; - u32 data_sn; - u32 next_burst_len; - u32 read_data_done; - u32 seq_send_order; - struct list_head dr_list; -} ____cacheline_aligned; - -struct iscsi_ooo_cmdsn { - u16 cid; - u32 batch_count; - u32 cmdsn; - u32 exp_cmdsn; - struct iscsi_cmd *cmd; - struct list_head ooo_list; -} ____cacheline_aligned; - -struct iscsi_datain { - u8 flags; - u32 data_sn; - u32 length; - u32 offset; -} ____cacheline_aligned; - -struct iscsi_r2t { - int seq_complete; - int recovery_r2t; - int sent_r2t; - u32 r2t_sn; - u32 offset; - u32 targ_xfer_tag; - u32 xfer_len; - struct list_head r2t_list; -} ____cacheline_aligned; - -struct iscsi_cmd { - enum iscsi_timer_flags_table dataout_timer_flags; - /* DataOUT timeout retries */ - u8 dataout_timeout_retries; - /* Within command recovery count */ - u8 error_recovery_count; - /* iSCSI dependent state for out or order CmdSNs */ - enum cmd_i_state_table deferred_i_state; - /* iSCSI dependent state */ - enum cmd_i_state_table i_state; - /* Command is an immediate command (ISCSI_OP_IMMEDIATE set) */ - u8 immediate_cmd; - /* Immediate data present */ - u8 immediate_data; - /* iSCSI Opcode */ - u8 iscsi_opcode; - /* iSCSI Response Code */ - u8 iscsi_response; - /* Logout reason when iscsi_opcode == ISCSI_INIT_LOGOUT_CMND */ - u8 logout_reason; - /* Logout response code when iscsi_opcode == ISCSI_INIT_LOGOUT_CMND */ - u8 logout_response; - /* MaxCmdSN has been incremented */ - u8 maxcmdsn_inc; - /* Immediate Unsolicited Dataout */ - u8 unsolicited_data; - /* CID contained in logout PDU when opcode == ISCSI_INIT_LOGOUT_CMND */ - u16 logout_cid; - /* Command flags */ - enum cmd_flags_table cmd_flags; - /* Initiator Task Tag assigned from Initiator */ - u32 init_task_tag; - /* Target Transfer Tag assigned from Target */ - u32 targ_xfer_tag; - /* CmdSN assigned from Initiator */ - u32 cmd_sn; - /* ExpStatSN assigned from Initiator */ - u32 exp_stat_sn; - /* StatSN assigned to this ITT */ - u32 stat_sn; - /* DataSN Counter */ - u32 data_sn; - /* R2TSN Counter */ - u32 r2t_sn; - /* Last DataSN acknowledged via DataAck SNACK */ - u32 acked_data_sn; - /* Used for echoing NOPOUT ping data */ - u32 buf_ptr_size; - /* Used to store DataDigest */ - u32 data_crc; - /* Total size in bytes associated with command */ - u32 data_length; - /* Counter for MaxOutstandingR2T */ - u32 outstanding_r2ts; - /* Next R2T Offset when DataSequenceInOrder=Yes */ - u32 r2t_offset; - /* Iovec current and orig count for iscsi_cmd->iov_data */ - u32 iov_data_count; - u32 orig_iov_data_count; - /* Number of miscellaneous iovecs used for IP stack calls */ - u32 iov_misc_count; - /* Number of struct iscsi_pdu in struct iscsi_cmd->pdu_list */ - u32 pdu_count; - /* Next struct iscsi_pdu to send in struct iscsi_cmd->pdu_list */ - u32 pdu_send_order; - /* Current struct iscsi_pdu in struct iscsi_cmd->pdu_list */ - u32 pdu_start; - u32 residual_count; - /* Next struct iscsi_seq to send in struct iscsi_cmd->seq_list */ - u32 seq_send_order; - /* Number of struct iscsi_seq in struct iscsi_cmd->seq_list */ - u32 seq_count; - /* Current struct iscsi_seq in struct iscsi_cmd->seq_list */ - u32 seq_no; - /* Lowest offset in current DataOUT sequence */ - u32 seq_start_offset; - /* Highest offset in current DataOUT sequence */ - u32 seq_end_offset; - /* Total size in bytes received so far of READ data */ - u32 read_data_done; - /* Total size in bytes received so far of WRITE data */ - u32 write_data_done; - /* Counter for FirstBurstLength key */ - u32 first_burst_len; - /* Counter for MaxBurstLength key */ - u32 next_burst_len; - /* Transfer size used for IP stack calls */ - u32 tx_size; - /* Buffer used for various purposes */ - void *buf_ptr; - /* See include/linux/dma-mapping.h */ - enum dma_data_direction data_direction; - /* iSCSI PDU Header + CRC */ - unsigned char pdu[ISCSI_HDR_LEN + ISCSI_CRC_LEN]; - /* Number of times struct iscsi_cmd is present in immediate queue */ - atomic_t immed_queue_count; - atomic_t response_queue_count; - atomic_t transport_sent; - spinlock_t datain_lock; - spinlock_t dataout_timeout_lock; - /* spinlock for protecting struct iscsi_cmd->i_state */ - spinlock_t istate_lock; - /* spinlock for adding within command recovery entries */ - spinlock_t error_lock; - /* spinlock for adding R2Ts */ - spinlock_t r2t_lock; - /* DataIN List */ - struct list_head datain_list; - /* R2T List */ - struct list_head cmd_r2t_list; - struct completion reject_comp; - /* Timer for DataOUT */ - struct timer_list dataout_timer; - /* Iovecs for SCSI data payload RX/TX w/ kernel level sockets */ - struct kvec *iov_data; - /* Iovecs for miscellaneous purposes */ -#define ISCSI_MISC_IOVECS 5 - struct kvec iov_misc[ISCSI_MISC_IOVECS]; - /* Array of struct iscsi_pdu used for DataPDUInOrder=No */ - struct iscsi_pdu *pdu_list; - /* Current struct iscsi_pdu used for DataPDUInOrder=No */ - struct iscsi_pdu *pdu_ptr; - /* Array of struct iscsi_seq used for DataSequenceInOrder=No */ - struct iscsi_seq *seq_list; - /* Current struct iscsi_seq used for DataSequenceInOrder=No */ - struct iscsi_seq *seq_ptr; - /* TMR Request when iscsi_opcode == ISCSI_OP_SCSI_TMFUNC */ - struct iscsi_tmr_req *tmr_req; - /* Connection this command is alligient to */ - struct iscsi_conn *conn; - /* Pointer to connection recovery entry */ - struct iscsi_conn_recovery *cr; - /* Session the command is part of, used for connection recovery */ - struct iscsi_session *sess; - /* list_head for connection list */ - struct list_head i_list; - /* The TCM I/O descriptor that is accessed via container_of() */ - struct se_cmd se_cmd; - /* Sense buffer that will be mapped into outgoing status */ -#define ISCSI_SENSE_BUFFER_LEN (TRANSPORT_SENSE_BUFFER + 2) - unsigned char sense_buffer[ISCSI_SENSE_BUFFER_LEN]; - - struct scatterlist *t_mem_sg; - u32 t_mem_sg_nents; - - u32 padding; - u8 pad_bytes[4]; - - struct scatterlist *first_data_sg; - u32 first_data_sg_off; - u32 kmapped_nents; - -} ____cacheline_aligned; - -struct iscsi_tmr_req { - bool task_reassign:1; - u32 ref_cmd_sn; - u32 exp_data_sn; - struct iscsi_conn_recovery *conn_recovery; - struct se_tmr_req *se_tmr_req; -}; - -struct iscsi_conn { - /* Authentication Successful for this connection */ - u8 auth_complete; - /* State connection is currently in */ - u8 conn_state; - u8 conn_logout_reason; - u8 network_transport; - enum iscsi_timer_flags_table nopin_timer_flags; - enum iscsi_timer_flags_table nopin_response_timer_flags; - u8 tx_immediate_queue; - u8 tx_response_queue; - /* Used to know what thread encountered a transport failure */ - u8 which_thread; - /* connection id assigned by the Initiator */ - u16 cid; - /* Remote TCP Port */ - u16 login_port; - int net_size; - u32 auth_id; -#define CONNFLAG_SCTP_STRUCT_FILE 0x01 - u32 conn_flags; - /* Used for iscsi_tx_login_rsp() */ - u32 login_itt; - u32 exp_statsn; - /* Per connection status sequence number */ - u32 stat_sn; - /* IFMarkInt's Current Value */ - u32 if_marker; - /* OFMarkInt's Current Value */ - u32 of_marker; - /* Used for calculating OFMarker offset to next PDU */ - u32 of_marker_offset; - /* Complete Bad PDU for sending reject */ - unsigned char bad_hdr[ISCSI_HDR_LEN]; -#define IPV6_ADDRESS_SPACE 48 - unsigned char login_ip[IPV6_ADDRESS_SPACE]; - int conn_usage_count; - int conn_waiting_on_uc; - atomic_t check_immediate_queue; - atomic_t conn_logout_remove; - atomic_t connection_exit; - atomic_t connection_recovery; - atomic_t connection_reinstatement; - atomic_t connection_wait; - atomic_t connection_wait_rcfr; - atomic_t sleep_on_conn_wait_comp; - atomic_t transport_failed; - struct completion conn_post_wait_comp; - struct completion conn_wait_comp; - struct completion conn_wait_rcfr_comp; - struct completion conn_waiting_on_uc_comp; - struct completion conn_logout_comp; - struct completion tx_half_close_comp; - struct completion rx_half_close_comp; - /* socket used by this connection */ - struct socket *sock; - struct timer_list nopin_timer; - struct timer_list nopin_response_timer; - struct timer_list transport_timer; - /* Spinlock used for add/deleting cmd's from conn_cmd_list */ - spinlock_t cmd_lock; - spinlock_t conn_usage_lock; - spinlock_t immed_queue_lock; - spinlock_t nopin_timer_lock; - spinlock_t response_queue_lock; - spinlock_t state_lock; - /* libcrypto RX and TX contexts for crc32c */ - struct hash_desc conn_rx_hash; - struct hash_desc conn_tx_hash; - /* Used for scheduling TX and RX connection kthreads */ - cpumask_var_t conn_cpumask; - int conn_rx_reset_cpumask:1; - int conn_tx_reset_cpumask:1; - /* list_head of struct iscsi_cmd for this connection */ - struct list_head conn_cmd_list; - struct list_head immed_queue_list; - struct list_head response_queue_list; - struct iscsi_conn_ops *conn_ops; - struct iscsi_param_list *param_list; - /* Used for per connection auth state machine */ - void *auth_protocol; - struct iscsi_login_thread_s *login_thread; - struct iscsi_portal_group *tpg; - /* Pointer to parent session */ - struct iscsi_session *sess; - /* Pointer to thread_set in use for this conn's threads */ - struct iscsi_thread_set *thread_set; - /* list_head for session connection list */ - struct list_head conn_list; -} ____cacheline_aligned; - -struct iscsi_conn_recovery { - u16 cid; - u32 cmd_count; - u32 maxrecvdatasegmentlength; - int ready_for_reallegiance; - struct list_head conn_recovery_cmd_list; - spinlock_t conn_recovery_cmd_lock; - struct timer_list time2retain_timer; - struct iscsi_session *sess; - struct list_head cr_list; -} ____cacheline_aligned; - -struct iscsi_session { - u8 initiator_vendor; - u8 isid[6]; - enum iscsi_timer_flags_table time2retain_timer_flags; - u8 version_active; - u16 cid_called; - u16 conn_recovery_count; - u16 tsih; - /* state session is currently in */ - u32 session_state; - /* session wide counter: initiator assigned task tag */ - u32 init_task_tag; - /* session wide counter: target assigned task tag */ - u32 targ_xfer_tag; - u32 cmdsn_window; - - /* protects cmdsn values */ - struct mutex cmdsn_mutex; - /* session wide counter: expected command sequence number */ - u32 exp_cmd_sn; - /* session wide counter: maximum allowed command sequence number */ - u32 max_cmd_sn; - struct list_head sess_ooo_cmdsn_list; - - /* LIO specific session ID */ - u32 sid; - char auth_type[8]; - /* unique within the target */ - int session_index; - /* Used for session reference counting */ - int session_usage_count; - int session_waiting_on_uc; - u32 cmd_pdus; - u32 rsp_pdus; - u64 tx_data_octets; - u64 rx_data_octets; - u32 conn_digest_errors; - u32 conn_timeout_errors; - u64 creation_time; - spinlock_t session_stats_lock; - /* Number of active connections */ - atomic_t nconn; - atomic_t session_continuation; - atomic_t session_fall_back_to_erl0; - atomic_t session_logout; - atomic_t session_reinstatement; - atomic_t session_stop_active; - atomic_t sleep_on_sess_wait_comp; - atomic_t transport_wait_cmds; - /* connection list */ - struct list_head sess_conn_list; - struct list_head cr_active_list; - struct list_head cr_inactive_list; - spinlock_t conn_lock; - spinlock_t cr_a_lock; - spinlock_t cr_i_lock; - spinlock_t session_usage_lock; - spinlock_t ttt_lock; - struct completion async_msg_comp; - struct completion reinstatement_comp; - struct completion session_wait_comp; - struct completion session_waiting_on_uc_comp; - struct timer_list time2retain_timer; - struct iscsi_sess_ops *sess_ops; - struct se_session *se_sess; - struct iscsi_portal_group *tpg; -} ____cacheline_aligned; - -struct iscsi_login { - u8 auth_complete; - u8 checked_for_existing; - u8 current_stage; - u8 leading_connection; - u8 first_request; - u8 version_min; - u8 version_max; - char isid[6]; - u32 cmd_sn; - u32 init_task_tag; - u32 initial_exp_statsn; - u32 rsp_length; - u16 cid; - u16 tsih; - char *req; - char *rsp; - char *req_buf; - char *rsp_buf; -} ____cacheline_aligned; - -struct iscsi_node_attrib { - u32 dataout_timeout; - u32 dataout_timeout_retries; - u32 default_erl; - u32 nopin_timeout; - u32 nopin_response_timeout; - u32 random_datain_pdu_offsets; - u32 random_datain_seq_offsets; - u32 random_r2t_offsets; - u32 tmr_cold_reset; - u32 tmr_warm_reset; - struct iscsi_node_acl *nacl; -}; - -struct se_dev_entry_s; - -struct iscsi_node_auth { - enum naf_flags_table naf_flags; - int authenticate_target; - /* Used for iscsit_global->discovery_auth, - * set to zero (auth disabled) by default */ - int enforce_discovery_auth; -#define MAX_USER_LEN 256 -#define MAX_PASS_LEN 256 - char userid[MAX_USER_LEN]; - char password[MAX_PASS_LEN]; - char userid_mutual[MAX_USER_LEN]; - char password_mutual[MAX_PASS_LEN]; -}; - -#include "iscsi_target_stat.h" - -struct iscsi_node_stat_grps { - struct config_group iscsi_sess_stats_group; - struct config_group iscsi_conn_stats_group; -}; - -struct iscsi_node_acl { - struct iscsi_node_attrib node_attrib; - struct iscsi_node_auth node_auth; - struct iscsi_node_stat_grps node_stat_grps; - struct se_node_acl se_node_acl; -}; - -#define NODE_STAT_GRPS(nacl) (&(nacl)->node_stat_grps) - -#define ISCSI_NODE_ATTRIB(t) (&(t)->node_attrib) -#define ISCSI_NODE_AUTH(t) (&(t)->node_auth) - -struct iscsi_tpg_attrib { - u32 authentication; - u32 login_timeout; - u32 netif_timeout; - u32 generate_node_acls; - u32 cache_dynamic_acls; - u32 default_cmdsn_depth; - u32 demo_mode_write_protect; - u32 prod_mode_write_protect; - struct iscsi_portal_group *tpg; -}; - -struct iscsi_np { - int np_network_transport; - int np_ip_proto; - int np_sock_type; - enum np_thread_state_table np_thread_state; - enum iscsi_timer_flags_table np_login_timer_flags; - u32 np_exports; - enum np_flags_table np_flags; - unsigned char np_ip[IPV6_ADDRESS_SPACE]; - u16 np_port; - spinlock_t np_thread_lock; - struct completion np_restart_comp; - struct socket *np_socket; - struct __kernel_sockaddr_storage np_sockaddr; - struct task_struct *np_thread; - struct timer_list np_login_timer; - struct iscsi_portal_group *np_login_tpg; - struct list_head np_list; -} ____cacheline_aligned; - -struct iscsi_tpg_np { - struct iscsi_np *tpg_np; - struct iscsi_portal_group *tpg; - struct iscsi_tpg_np *tpg_np_parent; - struct list_head tpg_np_list; - struct list_head tpg_np_child_list; - struct list_head tpg_np_parent_list; - struct se_tpg_np se_tpg_np; - spinlock_t tpg_np_parent_lock; -}; - -struct iscsi_portal_group { - unsigned char tpg_chap_id; - /* TPG State */ - enum tpg_state_table tpg_state; - /* Target Portal Group Tag */ - u16 tpgt; - /* Id assigned to target sessions */ - u16 ntsih; - /* Number of active sessions */ - u32 nsessions; - /* Number of Network Portals available for this TPG */ - u32 num_tpg_nps; - /* Per TPG LIO specific session ID. */ - u32 sid; - /* Spinlock for adding/removing Network Portals */ - spinlock_t tpg_np_lock; - spinlock_t tpg_state_lock; - struct se_portal_group tpg_se_tpg; - struct mutex tpg_access_lock; - struct mutex np_login_lock; - struct iscsi_tpg_attrib tpg_attrib; - /* Pointer to default list of iSCSI parameters for TPG */ - struct iscsi_param_list *param_list; - struct iscsi_tiqn *tpg_tiqn; - struct list_head tpg_gnp_list; - struct list_head tpg_list; -} ____cacheline_aligned; - -#define ISCSI_TPG_C(c) ((struct iscsi_portal_group *)(c)->tpg) -#define ISCSI_TPG_LUN(c, l) ((iscsi_tpg_list_t *)(c)->tpg->tpg_lun_list_t[l]) -#define ISCSI_TPG_S(s) ((struct iscsi_portal_group *)(s)->tpg) -#define ISCSI_TPG_ATTRIB(t) (&(t)->tpg_attrib) -#define SE_TPG(tpg) (&(tpg)->tpg_se_tpg) - -struct iscsi_wwn_stat_grps { - struct config_group iscsi_stat_group; - struct config_group iscsi_instance_group; - struct config_group iscsi_sess_err_group; - struct config_group iscsi_tgt_attr_group; - struct config_group iscsi_login_stats_group; - struct config_group iscsi_logout_stats_group; -}; - -struct iscsi_tiqn { -#define ISCSI_IQN_LEN 224 - unsigned char tiqn[ISCSI_IQN_LEN]; - enum tiqn_state_table tiqn_state; - int tiqn_access_count; - u32 tiqn_active_tpgs; - u32 tiqn_ntpgs; - u32 tiqn_num_tpg_nps; - u32 tiqn_nsessions; - struct list_head tiqn_list; - struct list_head tiqn_tpg_list; - spinlock_t tiqn_state_lock; - spinlock_t tiqn_tpg_lock; - struct se_wwn tiqn_wwn; - struct iscsi_wwn_stat_grps tiqn_stat_grps; - int tiqn_index; - struct iscsi_sess_err_stats sess_err_stats; - struct iscsi_login_stats login_stats; - struct iscsi_logout_stats logout_stats; -} ____cacheline_aligned; - -#define WWN_STAT_GRPS(tiqn) (&(tiqn)->tiqn_stat_grps) - -struct iscsit_global { - /* In core shutdown */ - u32 in_shutdown; - u32 active_ts; - /* Unique identifier used for the authentication daemon */ - u32 auth_id; - u32 inactive_ts; - /* Thread Set bitmap count */ - int ts_bitmap_count; - /* Thread Set bitmap pointer */ - unsigned long *ts_bitmap; - /* Used for iSCSI discovery session authentication */ - struct iscsi_node_acl discovery_acl; - struct iscsi_portal_group *discovery_tpg; -}; - -#endif /* ISCSI_TARGET_CORE_H */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_datain_values.c b/trunk/drivers/target/iscsi/iscsi_target_datain_values.c deleted file mode 100644 index 8c0495129513..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_datain_values.c +++ /dev/null @@ -1,531 +0,0 @@ -/******************************************************************************* - * This file contains the iSCSI Target DataIN value generation functions. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_erl1.h" -#include "iscsi_target_util.h" -#include "iscsi_target.h" -#include "iscsi_target_datain_values.h" - -struct iscsi_datain_req *iscsit_allocate_datain_req(void) -{ - struct iscsi_datain_req *dr; - - dr = kmem_cache_zalloc(lio_dr_cache, GFP_ATOMIC); - if (!dr) { - pr_err("Unable to allocate memory for" - " struct iscsi_datain_req\n"); - return NULL; - } - INIT_LIST_HEAD(&dr->dr_list); - - return dr; -} - -void iscsit_attach_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr) -{ - spin_lock(&cmd->datain_lock); - list_add_tail(&dr->dr_list, &cmd->datain_list); - spin_unlock(&cmd->datain_lock); -} - -void iscsit_free_datain_req(struct iscsi_cmd *cmd, struct iscsi_datain_req *dr) -{ - spin_lock(&cmd->datain_lock); - list_del(&dr->dr_list); - spin_unlock(&cmd->datain_lock); - - kmem_cache_free(lio_dr_cache, dr); -} - -void iscsit_free_all_datain_reqs(struct iscsi_cmd *cmd) -{ - struct iscsi_datain_req *dr, *dr_tmp; - - spin_lock(&cmd->datain_lock); - list_for_each_entry_safe(dr, dr_tmp, &cmd->datain_list, dr_list) { - list_del(&dr->dr_list); - kmem_cache_free(lio_dr_cache, dr); - } - spin_unlock(&cmd->datain_lock); -} - -struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *cmd) -{ - struct iscsi_datain_req *dr; - - if (list_empty(&cmd->datain_list)) { - pr_err("cmd->datain_list is empty for ITT:" - " 0x%08x\n", cmd->init_task_tag); - return NULL; - } - list_for_each_entry(dr, &cmd->datain_list, dr_list) - break; - - return dr; -} - -/* - * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=Yes. - */ -static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_yes( - struct iscsi_cmd *cmd, - struct iscsi_datain *datain) -{ - u32 next_burst_len, read_data_done, read_data_left; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_datain_req *dr; - - dr = iscsit_get_datain_req(cmd); - if (!dr) - return NULL; - - if (dr->recovery && dr->generate_recovery_values) { - if (iscsit_create_recovery_datain_values_datasequenceinorder_yes( - cmd, dr) < 0) - return NULL; - - dr->generate_recovery_values = 0; - } - - next_burst_len = (!dr->recovery) ? - cmd->next_burst_len : dr->next_burst_len; - read_data_done = (!dr->recovery) ? - cmd->read_data_done : dr->read_data_done; - - read_data_left = (cmd->data_length - read_data_done); - if (!read_data_left) { - pr_err("ITT: 0x%08x read_data_left is zero!\n", - cmd->init_task_tag); - return NULL; - } - - if ((read_data_left <= conn->conn_ops->MaxRecvDataSegmentLength) && - (read_data_left <= (conn->sess->sess_ops->MaxBurstLength - - next_burst_len))) { - datain->length = read_data_left; - - datain->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS); - if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) - datain->flags |= ISCSI_FLAG_DATA_ACK; - } else { - if ((next_burst_len + - conn->conn_ops->MaxRecvDataSegmentLength) < - conn->sess->sess_ops->MaxBurstLength) { - datain->length = - conn->conn_ops->MaxRecvDataSegmentLength; - next_burst_len += datain->length; - } else { - datain->length = (conn->sess->sess_ops->MaxBurstLength - - next_burst_len); - next_burst_len = 0; - - datain->flags |= ISCSI_FLAG_CMD_FINAL; - if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) - datain->flags |= ISCSI_FLAG_DATA_ACK; - } - } - - datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; - datain->offset = read_data_done; - - if (!dr->recovery) { - cmd->next_burst_len = next_burst_len; - cmd->read_data_done += datain->length; - } else { - dr->next_burst_len = next_burst_len; - dr->read_data_done += datain->length; - } - - if (!dr->recovery) { - if (datain->flags & ISCSI_FLAG_DATA_STATUS) - dr->dr_complete = DATAIN_COMPLETE_NORMAL; - - return dr; - } - - if (!dr->runlength) { - if (datain->flags & ISCSI_FLAG_DATA_STATUS) { - dr->dr_complete = - (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : - DATAIN_COMPLETE_CONNECTION_RECOVERY; - } - } else { - if ((dr->begrun + dr->runlength) == dr->data_sn) { - dr->dr_complete = - (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : - DATAIN_COMPLETE_CONNECTION_RECOVERY; - } - } - - return dr; -} - -/* - * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=Yes. - */ -static struct iscsi_datain_req *iscsit_set_datain_values_no_and_yes( - struct iscsi_cmd *cmd, - struct iscsi_datain *datain) -{ - u32 offset, read_data_done, read_data_left, seq_send_order; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_datain_req *dr; - struct iscsi_seq *seq; - - dr = iscsit_get_datain_req(cmd); - if (!dr) - return NULL; - - if (dr->recovery && dr->generate_recovery_values) { - if (iscsit_create_recovery_datain_values_datasequenceinorder_no( - cmd, dr) < 0) - return NULL; - - dr->generate_recovery_values = 0; - } - - read_data_done = (!dr->recovery) ? - cmd->read_data_done : dr->read_data_done; - seq_send_order = (!dr->recovery) ? - cmd->seq_send_order : dr->seq_send_order; - - read_data_left = (cmd->data_length - read_data_done); - if (!read_data_left) { - pr_err("ITT: 0x%08x read_data_left is zero!\n", - cmd->init_task_tag); - return NULL; - } - - seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order); - if (!seq) - return NULL; - - seq->sent = 1; - - if (!dr->recovery && !seq->next_burst_len) - seq->first_datasn = cmd->data_sn; - - offset = (seq->offset + seq->next_burst_len); - - if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= - cmd->data_length) { - datain->length = (cmd->data_length - offset); - datain->offset = offset; - - datain->flags |= ISCSI_FLAG_CMD_FINAL; - if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) - datain->flags |= ISCSI_FLAG_DATA_ACK; - - seq->next_burst_len = 0; - seq_send_order++; - } else { - if ((seq->next_burst_len + - conn->conn_ops->MaxRecvDataSegmentLength) < - conn->sess->sess_ops->MaxBurstLength) { - datain->length = - conn->conn_ops->MaxRecvDataSegmentLength; - datain->offset = (seq->offset + seq->next_burst_len); - - seq->next_burst_len += datain->length; - } else { - datain->length = (conn->sess->sess_ops->MaxBurstLength - - seq->next_burst_len); - datain->offset = (seq->offset + seq->next_burst_len); - - datain->flags |= ISCSI_FLAG_CMD_FINAL; - if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) - datain->flags |= ISCSI_FLAG_DATA_ACK; - - seq->next_burst_len = 0; - seq_send_order++; - } - } - - if ((read_data_done + datain->length) == cmd->data_length) - datain->flags |= ISCSI_FLAG_DATA_STATUS; - - datain->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; - if (!dr->recovery) { - cmd->seq_send_order = seq_send_order; - cmd->read_data_done += datain->length; - } else { - dr->seq_send_order = seq_send_order; - dr->read_data_done += datain->length; - } - - if (!dr->recovery) { - if (datain->flags & ISCSI_FLAG_CMD_FINAL) - seq->last_datasn = datain->data_sn; - if (datain->flags & ISCSI_FLAG_DATA_STATUS) - dr->dr_complete = DATAIN_COMPLETE_NORMAL; - - return dr; - } - - if (!dr->runlength) { - if (datain->flags & ISCSI_FLAG_DATA_STATUS) { - dr->dr_complete = - (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : - DATAIN_COMPLETE_CONNECTION_RECOVERY; - } - } else { - if ((dr->begrun + dr->runlength) == dr->data_sn) { - dr->dr_complete = - (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : - DATAIN_COMPLETE_CONNECTION_RECOVERY; - } - } - - return dr; -} - -/* - * For Normal and Recovery DataSequenceInOrder=Yes and DataPDUInOrder=No. - */ -static struct iscsi_datain_req *iscsit_set_datain_values_yes_and_no( - struct iscsi_cmd *cmd, - struct iscsi_datain *datain) -{ - u32 next_burst_len, read_data_done, read_data_left; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_datain_req *dr; - struct iscsi_pdu *pdu; - - dr = iscsit_get_datain_req(cmd); - if (!dr) - return NULL; - - if (dr->recovery && dr->generate_recovery_values) { - if (iscsit_create_recovery_datain_values_datasequenceinorder_yes( - cmd, dr) < 0) - return NULL; - - dr->generate_recovery_values = 0; - } - - next_burst_len = (!dr->recovery) ? - cmd->next_burst_len : dr->next_burst_len; - read_data_done = (!dr->recovery) ? - cmd->read_data_done : dr->read_data_done; - - read_data_left = (cmd->data_length - read_data_done); - if (!read_data_left) { - pr_err("ITT: 0x%08x read_data_left is zero!\n", - cmd->init_task_tag); - return dr; - } - - pdu = iscsit_get_pdu_holder_for_seq(cmd, NULL); - if (!pdu) - return dr; - - if ((read_data_done + pdu->length) == cmd->data_length) { - pdu->flags |= (ISCSI_FLAG_CMD_FINAL | ISCSI_FLAG_DATA_STATUS); - if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) - pdu->flags |= ISCSI_FLAG_DATA_ACK; - - next_burst_len = 0; - } else { - if ((next_burst_len + conn->conn_ops->MaxRecvDataSegmentLength) < - conn->sess->sess_ops->MaxBurstLength) - next_burst_len += pdu->length; - else { - pdu->flags |= ISCSI_FLAG_CMD_FINAL; - if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) - pdu->flags |= ISCSI_FLAG_DATA_ACK; - - next_burst_len = 0; - } - } - - pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; - if (!dr->recovery) { - cmd->next_burst_len = next_burst_len; - cmd->read_data_done += pdu->length; - } else { - dr->next_burst_len = next_burst_len; - dr->read_data_done += pdu->length; - } - - datain->flags = pdu->flags; - datain->length = pdu->length; - datain->offset = pdu->offset; - datain->data_sn = pdu->data_sn; - - if (!dr->recovery) { - if (datain->flags & ISCSI_FLAG_DATA_STATUS) - dr->dr_complete = DATAIN_COMPLETE_NORMAL; - - return dr; - } - - if (!dr->runlength) { - if (datain->flags & ISCSI_FLAG_DATA_STATUS) { - dr->dr_complete = - (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : - DATAIN_COMPLETE_CONNECTION_RECOVERY; - } - } else { - if ((dr->begrun + dr->runlength) == dr->data_sn) { - dr->dr_complete = - (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : - DATAIN_COMPLETE_CONNECTION_RECOVERY; - } - } - - return dr; -} - -/* - * For Normal and Recovery DataSequenceInOrder=No and DataPDUInOrder=No. - */ -static struct iscsi_datain_req *iscsit_set_datain_values_no_and_no( - struct iscsi_cmd *cmd, - struct iscsi_datain *datain) -{ - u32 read_data_done, read_data_left, seq_send_order; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_datain_req *dr; - struct iscsi_pdu *pdu; - struct iscsi_seq *seq = NULL; - - dr = iscsit_get_datain_req(cmd); - if (!dr) - return NULL; - - if (dr->recovery && dr->generate_recovery_values) { - if (iscsit_create_recovery_datain_values_datasequenceinorder_no( - cmd, dr) < 0) - return NULL; - - dr->generate_recovery_values = 0; - } - - read_data_done = (!dr->recovery) ? - cmd->read_data_done : dr->read_data_done; - seq_send_order = (!dr->recovery) ? - cmd->seq_send_order : dr->seq_send_order; - - read_data_left = (cmd->data_length - read_data_done); - if (!read_data_left) { - pr_err("ITT: 0x%08x read_data_left is zero!\n", - cmd->init_task_tag); - return NULL; - } - - seq = iscsit_get_seq_holder_for_datain(cmd, seq_send_order); - if (!seq) - return NULL; - - seq->sent = 1; - - if (!dr->recovery && !seq->next_burst_len) - seq->first_datasn = cmd->data_sn; - - pdu = iscsit_get_pdu_holder_for_seq(cmd, seq); - if (!pdu) - return NULL; - - if (seq->pdu_send_order == seq->pdu_count) { - pdu->flags |= ISCSI_FLAG_CMD_FINAL; - if (conn->sess->sess_ops->ErrorRecoveryLevel > 0) - pdu->flags |= ISCSI_FLAG_DATA_ACK; - - seq->next_burst_len = 0; - seq_send_order++; - } else - seq->next_burst_len += pdu->length; - - if ((read_data_done + pdu->length) == cmd->data_length) - pdu->flags |= ISCSI_FLAG_DATA_STATUS; - - pdu->data_sn = (!dr->recovery) ? cmd->data_sn++ : dr->data_sn++; - if (!dr->recovery) { - cmd->seq_send_order = seq_send_order; - cmd->read_data_done += pdu->length; - } else { - dr->seq_send_order = seq_send_order; - dr->read_data_done += pdu->length; - } - - datain->flags = pdu->flags; - datain->length = pdu->length; - datain->offset = pdu->offset; - datain->data_sn = pdu->data_sn; - - if (!dr->recovery) { - if (datain->flags & ISCSI_FLAG_CMD_FINAL) - seq->last_datasn = datain->data_sn; - if (datain->flags & ISCSI_FLAG_DATA_STATUS) - dr->dr_complete = DATAIN_COMPLETE_NORMAL; - - return dr; - } - - if (!dr->runlength) { - if (datain->flags & ISCSI_FLAG_DATA_STATUS) { - dr->dr_complete = - (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : - DATAIN_COMPLETE_CONNECTION_RECOVERY; - } - } else { - if ((dr->begrun + dr->runlength) == dr->data_sn) { - dr->dr_complete = - (dr->recovery == DATAIN_WITHIN_COMMAND_RECOVERY) ? - DATAIN_COMPLETE_WITHIN_COMMAND_RECOVERY : - DATAIN_COMPLETE_CONNECTION_RECOVERY; - } - } - - return dr; -} - -struct iscsi_datain_req *iscsit_get_datain_values( - struct iscsi_cmd *cmd, - struct iscsi_datain *datain) -{ - struct iscsi_conn *conn = cmd->conn; - - if (conn->sess->sess_ops->DataSequenceInOrder && - conn->sess->sess_ops->DataPDUInOrder) - return iscsit_set_datain_values_yes_and_yes(cmd, datain); - else if (!conn->sess->sess_ops->DataSequenceInOrder && - conn->sess->sess_ops->DataPDUInOrder) - return iscsit_set_datain_values_no_and_yes(cmd, datain); - else if (conn->sess->sess_ops->DataSequenceInOrder && - !conn->sess->sess_ops->DataPDUInOrder) - return iscsit_set_datain_values_yes_and_no(cmd, datain); - else if (!conn->sess->sess_ops->DataSequenceInOrder && - !conn->sess->sess_ops->DataPDUInOrder) - return iscsit_set_datain_values_no_and_no(cmd, datain); - - return NULL; -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_datain_values.h b/trunk/drivers/target/iscsi/iscsi_target_datain_values.h deleted file mode 100644 index 646429ac5a02..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_datain_values.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ISCSI_TARGET_DATAIN_VALUES_H -#define ISCSI_TARGET_DATAIN_VALUES_H - -extern struct iscsi_datain_req *iscsit_allocate_datain_req(void); -extern void iscsit_attach_datain_req(struct iscsi_cmd *, struct iscsi_datain_req *); -extern void iscsit_free_datain_req(struct iscsi_cmd *, struct iscsi_datain_req *); -extern void iscsit_free_all_datain_reqs(struct iscsi_cmd *); -extern struct iscsi_datain_req *iscsit_get_datain_req(struct iscsi_cmd *); -extern struct iscsi_datain_req *iscsit_get_datain_values(struct iscsi_cmd *, - struct iscsi_datain *); - -#endif /*** ISCSI_TARGET_DATAIN_VALUES_H ***/ diff --git a/trunk/drivers/target/iscsi/iscsi_target_device.c b/trunk/drivers/target/iscsi/iscsi_target_device.c deleted file mode 100644 index a19fa5eea88e..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_device.c +++ /dev/null @@ -1,87 +0,0 @@ -/******************************************************************************* - * This file contains the iSCSI Virtual Device and Disk Transport - * agnostic related functions. - * - \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_device.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_util.h" - -int iscsit_get_lun_for_tmr( - struct iscsi_cmd *cmd, - u64 lun) -{ - u32 unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); - - return transport_lookup_tmr_lun(&cmd->se_cmd, unpacked_lun); -} - -int iscsit_get_lun_for_cmd( - struct iscsi_cmd *cmd, - unsigned char *cdb, - u64 lun) -{ - u32 unpacked_lun = scsilun_to_int((struct scsi_lun *)&lun); - - return transport_lookup_cmd_lun(&cmd->se_cmd, unpacked_lun); -} - -void iscsit_determine_maxcmdsn(struct iscsi_session *sess) -{ - struct se_node_acl *se_nacl; - - /* - * This is a discovery session, the single queue slot was already - * assigned in iscsi_login_zero_tsih(). Since only Logout and - * Text Opcodes are allowed during discovery we do not have to worry - * about the HBA's queue depth here. - */ - if (sess->sess_ops->SessionType) - return; - - se_nacl = sess->se_sess->se_node_acl; - - /* - * This is a normal session, set the Session's CmdSN window to the - * struct se_node_acl->queue_depth. The value in struct se_node_acl->queue_depth - * has already been validated as a legal value in - * core_set_queue_depth_for_node(). - */ - sess->cmdsn_window = se_nacl->queue_depth; - sess->max_cmd_sn = (sess->max_cmd_sn + se_nacl->queue_depth) - 1; -} - -void iscsit_increment_maxcmdsn(struct iscsi_cmd *cmd, struct iscsi_session *sess) -{ - if (cmd->immediate_cmd || cmd->maxcmdsn_inc) - return; - - cmd->maxcmdsn_inc = 1; - - mutex_lock(&sess->cmdsn_mutex); - sess->max_cmd_sn += 1; - pr_debug("Updated MaxCmdSN to 0x%08x\n", sess->max_cmd_sn); - mutex_unlock(&sess->cmdsn_mutex); -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_device.h b/trunk/drivers/target/iscsi/iscsi_target_device.h deleted file mode 100644 index bef1cada15f8..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_device.h +++ /dev/null @@ -1,9 +0,0 @@ -#ifndef ISCSI_TARGET_DEVICE_H -#define ISCSI_TARGET_DEVICE_H - -extern int iscsit_get_lun_for_tmr(struct iscsi_cmd *, u64); -extern int iscsit_get_lun_for_cmd(struct iscsi_cmd *, unsigned char *, u64); -extern void iscsit_determine_maxcmdsn(struct iscsi_session *); -extern void iscsit_increment_maxcmdsn(struct iscsi_cmd *, struct iscsi_session *); - -#endif /* ISCSI_TARGET_DEVICE_H */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_erl0.c b/trunk/drivers/target/iscsi/iscsi_target_erl0.c deleted file mode 100644 index b7ffc3cd40cc..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_erl0.c +++ /dev/null @@ -1,1004 +0,0 @@ -/****************************************************************************** - * This file contains error recovery level zero functions used by - * the iSCSI Target driver. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_tq.h" -#include "iscsi_target_erl0.h" -#include "iscsi_target_erl1.h" -#include "iscsi_target_erl2.h" -#include "iscsi_target_util.h" -#include "iscsi_target.h" - -/* - * Used to set values in struct iscsi_cmd that iscsit_dataout_check_sequence() - * checks against to determine a PDU's Offset+Length is within the current - * DataOUT Sequence. Used for DataSequenceInOrder=Yes only. - */ -void iscsit_set_dataout_sequence_values( - struct iscsi_cmd *cmd) -{ - struct iscsi_conn *conn = cmd->conn; - /* - * Still set seq_start_offset and seq_end_offset for Unsolicited - * DataOUT, even if DataSequenceInOrder=No. - */ - if (cmd->unsolicited_data) { - cmd->seq_start_offset = cmd->write_data_done; - cmd->seq_end_offset = (cmd->write_data_done + - (cmd->data_length > - conn->sess->sess_ops->FirstBurstLength) ? - conn->sess->sess_ops->FirstBurstLength : cmd->data_length); - return; - } - - if (!conn->sess->sess_ops->DataSequenceInOrder) - return; - - if (!cmd->seq_start_offset && !cmd->seq_end_offset) { - cmd->seq_start_offset = cmd->write_data_done; - cmd->seq_end_offset = (cmd->data_length > - conn->sess->sess_ops->MaxBurstLength) ? - (cmd->write_data_done + - conn->sess->sess_ops->MaxBurstLength) : cmd->data_length; - } else { - cmd->seq_start_offset = cmd->seq_end_offset; - cmd->seq_end_offset = ((cmd->seq_end_offset + - conn->sess->sess_ops->MaxBurstLength) >= - cmd->data_length) ? cmd->data_length : - (cmd->seq_end_offset + - conn->sess->sess_ops->MaxBurstLength); - } -} - -static int iscsit_dataout_within_command_recovery_check( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - struct iscsi_conn *conn = cmd->conn; - struct iscsi_data *hdr = (struct iscsi_data *) buf; - u32 payload_length = ntoh24(hdr->dlength); - - /* - * We do the within-command recovery checks here as it is - * the first function called in iscsi_check_pre_dataout(). - * Basically, if we are in within-command recovery and - * the PDU does not contain the offset the sequence needs, - * dump the payload. - * - * This only applies to DataPDUInOrder=Yes, for - * DataPDUInOrder=No we only re-request the failed PDU - * and check that all PDUs in a sequence are received - * upon end of sequence. - */ - if (conn->sess->sess_ops->DataSequenceInOrder) { - if ((cmd->cmd_flags & ICF_WITHIN_COMMAND_RECOVERY) && - (cmd->write_data_done != hdr->offset)) - goto dump; - - cmd->cmd_flags &= ~ICF_WITHIN_COMMAND_RECOVERY; - } else { - struct iscsi_seq *seq; - - seq = iscsit_get_seq_holder(cmd, hdr->offset, payload_length); - if (!seq) - return DATAOUT_CANNOT_RECOVER; - /* - * Set the struct iscsi_seq pointer to reuse later. - */ - cmd->seq_ptr = seq; - - if (conn->sess->sess_ops->DataPDUInOrder) { - if ((seq->status == - DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY) && - ((seq->offset != hdr->offset) || - (seq->data_sn != hdr->datasn))) - goto dump; - } else { - if ((seq->status == - DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY) && - (seq->data_sn != hdr->datasn)) - goto dump; - } - - if (seq->status == DATAOUT_SEQUENCE_COMPLETE) - goto dump; - - if (seq->status != DATAOUT_SEQUENCE_COMPLETE) - seq->status = 0; - } - - return DATAOUT_NORMAL; - -dump: - pr_err("Dumping DataOUT PDU Offset: %u Length: %d DataSN:" - " 0x%08x\n", hdr->offset, payload_length, hdr->datasn); - return iscsit_dump_data_payload(conn, payload_length, 1); -} - -static int iscsit_dataout_check_unsolicited_sequence( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - u32 first_burst_len; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_data *hdr = (struct iscsi_data *) buf; - u32 payload_length = ntoh24(hdr->dlength); - - - if ((hdr->offset < cmd->seq_start_offset) || - ((hdr->offset + payload_length) > cmd->seq_end_offset)) { - pr_err("Command ITT: 0x%08x with Offset: %u," - " Length: %u outside of Unsolicited Sequence %u:%u while" - " DataSequenceInOrder=Yes.\n", cmd->init_task_tag, - hdr->offset, payload_length, cmd->seq_start_offset, - cmd->seq_end_offset); - return DATAOUT_CANNOT_RECOVER; - } - - first_burst_len = (cmd->first_burst_len + payload_length); - - if (first_burst_len > conn->sess->sess_ops->FirstBurstLength) { - pr_err("Total %u bytes exceeds FirstBurstLength: %u" - " for this Unsolicited DataOut Burst.\n", - first_burst_len, conn->sess->sess_ops->FirstBurstLength); - transport_send_check_condition_and_sense(&cmd->se_cmd, - TCM_INCORRECT_AMOUNT_OF_DATA, 0); - return DATAOUT_CANNOT_RECOVER; - } - - /* - * Perform various MaxBurstLength and ISCSI_FLAG_CMD_FINAL sanity - * checks for the current Unsolicited DataOUT Sequence. - */ - if (hdr->flags & ISCSI_FLAG_CMD_FINAL) { - /* - * Ignore ISCSI_FLAG_CMD_FINAL checks while DataPDUInOrder=No, end of - * sequence checks are handled in - * iscsit_dataout_datapduinorder_no_fbit(). - */ - if (!conn->sess->sess_ops->DataPDUInOrder) - goto out; - - if ((first_burst_len != cmd->data_length) && - (first_burst_len != conn->sess->sess_ops->FirstBurstLength)) { - pr_err("Unsolicited non-immediate data" - " received %u does not equal FirstBurstLength: %u, and" - " does not equal ExpXferLen %u.\n", first_burst_len, - conn->sess->sess_ops->FirstBurstLength, - cmd->data_length); - transport_send_check_condition_and_sense(&cmd->se_cmd, - TCM_INCORRECT_AMOUNT_OF_DATA, 0); - return DATAOUT_CANNOT_RECOVER; - } - } else { - if (first_burst_len == conn->sess->sess_ops->FirstBurstLength) { - pr_err("Command ITT: 0x%08x reached" - " FirstBurstLength: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol" - " error.\n", cmd->init_task_tag, - conn->sess->sess_ops->FirstBurstLength); - return DATAOUT_CANNOT_RECOVER; - } - if (first_burst_len == cmd->data_length) { - pr_err("Command ITT: 0x%08x reached" - " ExpXferLen: %u, but ISCSI_FLAG_CMD_FINAL is not set. protocol" - " error.\n", cmd->init_task_tag, cmd->data_length); - return DATAOUT_CANNOT_RECOVER; - } - } - -out: - return DATAOUT_NORMAL; -} - -static int iscsit_dataout_check_sequence( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - u32 next_burst_len; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_seq *seq = NULL; - struct iscsi_data *hdr = (struct iscsi_data *) buf; - u32 payload_length = ntoh24(hdr->dlength); - - /* - * For DataSequenceInOrder=Yes: Check that the offset and offset+length - * is within range as defined by iscsi_set_dataout_sequence_values(). - * - * For DataSequenceInOrder=No: Check that an struct iscsi_seq exists for - * offset+length tuple. - */ - if (conn->sess->sess_ops->DataSequenceInOrder) { - /* - * Due to possibility of recovery DataOUT sent by the initiator - * fullfilling an Recovery R2T, it's best to just dump the - * payload here, instead of erroring out. - */ - if ((hdr->offset < cmd->seq_start_offset) || - ((hdr->offset + payload_length) > cmd->seq_end_offset)) { - pr_err("Command ITT: 0x%08x with Offset: %u," - " Length: %u outside of Sequence %u:%u while" - " DataSequenceInOrder=Yes.\n", cmd->init_task_tag, - hdr->offset, payload_length, cmd->seq_start_offset, - cmd->seq_end_offset); - - if (iscsit_dump_data_payload(conn, payload_length, 1) < 0) - return DATAOUT_CANNOT_RECOVER; - return DATAOUT_WITHIN_COMMAND_RECOVERY; - } - - next_burst_len = (cmd->next_burst_len + payload_length); - } else { - seq = iscsit_get_seq_holder(cmd, hdr->offset, payload_length); - if (!seq) - return DATAOUT_CANNOT_RECOVER; - /* - * Set the struct iscsi_seq pointer to reuse later. - */ - cmd->seq_ptr = seq; - - if (seq->status == DATAOUT_SEQUENCE_COMPLETE) { - if (iscsit_dump_data_payload(conn, payload_length, 1) < 0) - return DATAOUT_CANNOT_RECOVER; - return DATAOUT_WITHIN_COMMAND_RECOVERY; - } - - next_burst_len = (seq->next_burst_len + payload_length); - } - - if (next_burst_len > conn->sess->sess_ops->MaxBurstLength) { - pr_err("Command ITT: 0x%08x, NextBurstLength: %u and" - " Length: %u exceeds MaxBurstLength: %u. protocol" - " error.\n", cmd->init_task_tag, - (next_burst_len - payload_length), - payload_length, conn->sess->sess_ops->MaxBurstLength); - return DATAOUT_CANNOT_RECOVER; - } - - /* - * Perform various MaxBurstLength and ISCSI_FLAG_CMD_FINAL sanity - * checks for the current DataOUT Sequence. - */ - if (hdr->flags & ISCSI_FLAG_CMD_FINAL) { - /* - * Ignore ISCSI_FLAG_CMD_FINAL checks while DataPDUInOrder=No, end of - * sequence checks are handled in - * iscsit_dataout_datapduinorder_no_fbit(). - */ - if (!conn->sess->sess_ops->DataPDUInOrder) - goto out; - - if (conn->sess->sess_ops->DataSequenceInOrder) { - if ((next_burst_len < - conn->sess->sess_ops->MaxBurstLength) && - ((cmd->write_data_done + payload_length) < - cmd->data_length)) { - pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL" - " before end of DataOUT sequence, protocol" - " error.\n", cmd->init_task_tag); - return DATAOUT_CANNOT_RECOVER; - } - } else { - if (next_burst_len < seq->xfer_len) { - pr_err("Command ITT: 0x%08x set ISCSI_FLAG_CMD_FINAL" - " before end of DataOUT sequence, protocol" - " error.\n", cmd->init_task_tag); - return DATAOUT_CANNOT_RECOVER; - } - } - } else { - if (conn->sess->sess_ops->DataSequenceInOrder) { - if (next_burst_len == - conn->sess->sess_ops->MaxBurstLength) { - pr_err("Command ITT: 0x%08x reached" - " MaxBurstLength: %u, but ISCSI_FLAG_CMD_FINAL is" - " not set, protocol error.", cmd->init_task_tag, - conn->sess->sess_ops->MaxBurstLength); - return DATAOUT_CANNOT_RECOVER; - } - if ((cmd->write_data_done + payload_length) == - cmd->data_length) { - pr_err("Command ITT: 0x%08x reached" - " last DataOUT PDU in sequence but ISCSI_FLAG_" - "CMD_FINAL is not set, protocol error.\n", - cmd->init_task_tag); - return DATAOUT_CANNOT_RECOVER; - } - } else { - if (next_burst_len == seq->xfer_len) { - pr_err("Command ITT: 0x%08x reached" - " last DataOUT PDU in sequence but ISCSI_FLAG_" - "CMD_FINAL is not set, protocol error.\n", - cmd->init_task_tag); - return DATAOUT_CANNOT_RECOVER; - } - } - } - -out: - return DATAOUT_NORMAL; -} - -static int iscsit_dataout_check_datasn( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - int dump = 0, recovery = 0; - u32 data_sn = 0; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_data *hdr = (struct iscsi_data *) buf; - u32 payload_length = ntoh24(hdr->dlength); - - /* - * Considering the target has no method of re-requesting DataOUT - * by DataSN, if we receieve a greater DataSN than expected we - * assume the functions for DataPDUInOrder=[Yes,No] below will - * handle it. - * - * If the DataSN is less than expected, dump the payload. - */ - if (conn->sess->sess_ops->DataSequenceInOrder) - data_sn = cmd->data_sn; - else { - struct iscsi_seq *seq = cmd->seq_ptr; - data_sn = seq->data_sn; - } - - if (hdr->datasn > data_sn) { - pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x" - " higher than expected 0x%08x.\n", cmd->init_task_tag, - hdr->datasn, data_sn); - recovery = 1; - goto recover; - } else if (hdr->datasn < data_sn) { - pr_err("Command ITT: 0x%08x, received DataSN: 0x%08x" - " lower than expected 0x%08x, discarding payload.\n", - cmd->init_task_tag, hdr->datasn, data_sn); - dump = 1; - goto dump; - } - - return DATAOUT_NORMAL; - -recover: - if (!conn->sess->sess_ops->ErrorRecoveryLevel) { - pr_err("Unable to perform within-command recovery" - " while ERL=0.\n"); - return DATAOUT_CANNOT_RECOVER; - } -dump: - if (iscsit_dump_data_payload(conn, payload_length, 1) < 0) - return DATAOUT_CANNOT_RECOVER; - - return (recovery || dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY : - DATAOUT_NORMAL; -} - -static int iscsit_dataout_pre_datapduinorder_yes( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - int dump = 0, recovery = 0; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_data *hdr = (struct iscsi_data *) buf; - u32 payload_length = ntoh24(hdr->dlength); - - /* - * For DataSequenceInOrder=Yes: If the offset is greater than the global - * DataPDUInOrder=Yes offset counter in struct iscsi_cmd a protcol error has - * occured and fail the connection. - * - * For DataSequenceInOrder=No: If the offset is greater than the per - * sequence DataPDUInOrder=Yes offset counter in struct iscsi_seq a protocol - * error has occured and fail the connection. - */ - if (conn->sess->sess_ops->DataSequenceInOrder) { - if (hdr->offset != cmd->write_data_done) { - pr_err("Command ITT: 0x%08x, received offset" - " %u different than expected %u.\n", cmd->init_task_tag, - hdr->offset, cmd->write_data_done); - recovery = 1; - goto recover; - } - } else { - struct iscsi_seq *seq = cmd->seq_ptr; - - if (hdr->offset > seq->offset) { - pr_err("Command ITT: 0x%08x, received offset" - " %u greater than expected %u.\n", cmd->init_task_tag, - hdr->offset, seq->offset); - recovery = 1; - goto recover; - } else if (hdr->offset < seq->offset) { - pr_err("Command ITT: 0x%08x, received offset" - " %u less than expected %u, discarding payload.\n", - cmd->init_task_tag, hdr->offset, seq->offset); - dump = 1; - goto dump; - } - } - - return DATAOUT_NORMAL; - -recover: - if (!conn->sess->sess_ops->ErrorRecoveryLevel) { - pr_err("Unable to perform within-command recovery" - " while ERL=0.\n"); - return DATAOUT_CANNOT_RECOVER; - } -dump: - if (iscsit_dump_data_payload(conn, payload_length, 1) < 0) - return DATAOUT_CANNOT_RECOVER; - - return (recovery) ? iscsit_recover_dataout_sequence(cmd, - hdr->offset, payload_length) : - (dump) ? DATAOUT_WITHIN_COMMAND_RECOVERY : DATAOUT_NORMAL; -} - -static int iscsit_dataout_pre_datapduinorder_no( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - struct iscsi_pdu *pdu; - struct iscsi_data *hdr = (struct iscsi_data *) buf; - u32 payload_length = ntoh24(hdr->dlength); - - pdu = iscsit_get_pdu_holder(cmd, hdr->offset, payload_length); - if (!pdu) - return DATAOUT_CANNOT_RECOVER; - - cmd->pdu_ptr = pdu; - - switch (pdu->status) { - case ISCSI_PDU_NOT_RECEIVED: - case ISCSI_PDU_CRC_FAILED: - case ISCSI_PDU_TIMED_OUT: - break; - case ISCSI_PDU_RECEIVED_OK: - pr_err("Command ITT: 0x%08x received already gotten" - " Offset: %u, Length: %u\n", cmd->init_task_tag, - hdr->offset, payload_length); - return iscsit_dump_data_payload(cmd->conn, payload_length, 1); - default: - return DATAOUT_CANNOT_RECOVER; - } - - return DATAOUT_NORMAL; -} - -static int iscsit_dataout_update_r2t(struct iscsi_cmd *cmd, u32 offset, u32 length) -{ - struct iscsi_r2t *r2t; - - if (cmd->unsolicited_data) - return 0; - - r2t = iscsit_get_r2t_for_eos(cmd, offset, length); - if (!r2t) - return -1; - - spin_lock_bh(&cmd->r2t_lock); - r2t->seq_complete = 1; - cmd->outstanding_r2ts--; - spin_unlock_bh(&cmd->r2t_lock); - - return 0; -} - -static int iscsit_dataout_update_datapduinorder_no( - struct iscsi_cmd *cmd, - u32 data_sn, - int f_bit) -{ - int ret = 0; - struct iscsi_pdu *pdu = cmd->pdu_ptr; - - pdu->data_sn = data_sn; - - switch (pdu->status) { - case ISCSI_PDU_NOT_RECEIVED: - pdu->status = ISCSI_PDU_RECEIVED_OK; - break; - case ISCSI_PDU_CRC_FAILED: - pdu->status = ISCSI_PDU_RECEIVED_OK; - break; - case ISCSI_PDU_TIMED_OUT: - pdu->status = ISCSI_PDU_RECEIVED_OK; - break; - default: - return DATAOUT_CANNOT_RECOVER; - } - - if (f_bit) { - ret = iscsit_dataout_datapduinorder_no_fbit(cmd, pdu); - if (ret == DATAOUT_CANNOT_RECOVER) - return ret; - } - - return DATAOUT_NORMAL; -} - -static int iscsit_dataout_post_crc_passed( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - int ret, send_r2t = 0; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_seq *seq = NULL; - struct iscsi_data *hdr = (struct iscsi_data *) buf; - u32 payload_length = ntoh24(hdr->dlength); - - if (cmd->unsolicited_data) { - if ((cmd->first_burst_len + payload_length) == - conn->sess->sess_ops->FirstBurstLength) { - if (iscsit_dataout_update_r2t(cmd, hdr->offset, - payload_length) < 0) - return DATAOUT_CANNOT_RECOVER; - send_r2t = 1; - } - - if (!conn->sess->sess_ops->DataPDUInOrder) { - ret = iscsit_dataout_update_datapduinorder_no(cmd, - hdr->datasn, (hdr->flags & ISCSI_FLAG_CMD_FINAL)); - if (ret == DATAOUT_CANNOT_RECOVER) - return ret; - } - - cmd->first_burst_len += payload_length; - - if (conn->sess->sess_ops->DataSequenceInOrder) - cmd->data_sn++; - else { - seq = cmd->seq_ptr; - seq->data_sn++; - seq->offset += payload_length; - } - - if (send_r2t) { - if (seq) - seq->status = DATAOUT_SEQUENCE_COMPLETE; - cmd->first_burst_len = 0; - cmd->unsolicited_data = 0; - } - } else { - if (conn->sess->sess_ops->DataSequenceInOrder) { - if ((cmd->next_burst_len + payload_length) == - conn->sess->sess_ops->MaxBurstLength) { - if (iscsit_dataout_update_r2t(cmd, hdr->offset, - payload_length) < 0) - return DATAOUT_CANNOT_RECOVER; - send_r2t = 1; - } - - if (!conn->sess->sess_ops->DataPDUInOrder) { - ret = iscsit_dataout_update_datapduinorder_no( - cmd, hdr->datasn, - (hdr->flags & ISCSI_FLAG_CMD_FINAL)); - if (ret == DATAOUT_CANNOT_RECOVER) - return ret; - } - - cmd->next_burst_len += payload_length; - cmd->data_sn++; - - if (send_r2t) - cmd->next_burst_len = 0; - } else { - seq = cmd->seq_ptr; - - if ((seq->next_burst_len + payload_length) == - seq->xfer_len) { - if (iscsit_dataout_update_r2t(cmd, hdr->offset, - payload_length) < 0) - return DATAOUT_CANNOT_RECOVER; - send_r2t = 1; - } - - if (!conn->sess->sess_ops->DataPDUInOrder) { - ret = iscsit_dataout_update_datapduinorder_no( - cmd, hdr->datasn, - (hdr->flags & ISCSI_FLAG_CMD_FINAL)); - if (ret == DATAOUT_CANNOT_RECOVER) - return ret; - } - - seq->data_sn++; - seq->offset += payload_length; - seq->next_burst_len += payload_length; - - if (send_r2t) { - seq->next_burst_len = 0; - seq->status = DATAOUT_SEQUENCE_COMPLETE; - } - } - } - - if (send_r2t && conn->sess->sess_ops->DataSequenceInOrder) - cmd->data_sn = 0; - - cmd->write_data_done += payload_length; - - return (cmd->write_data_done == cmd->data_length) ? - DATAOUT_SEND_TO_TRANSPORT : (send_r2t) ? - DATAOUT_SEND_R2T : DATAOUT_NORMAL; -} - -static int iscsit_dataout_post_crc_failed( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - struct iscsi_conn *conn = cmd->conn; - struct iscsi_pdu *pdu; - struct iscsi_data *hdr = (struct iscsi_data *) buf; - u32 payload_length = ntoh24(hdr->dlength); - - if (conn->sess->sess_ops->DataPDUInOrder) - goto recover; - /* - * The rest of this function is only called when DataPDUInOrder=No. - */ - pdu = cmd->pdu_ptr; - - switch (pdu->status) { - case ISCSI_PDU_NOT_RECEIVED: - pdu->status = ISCSI_PDU_CRC_FAILED; - break; - case ISCSI_PDU_CRC_FAILED: - break; - case ISCSI_PDU_TIMED_OUT: - pdu->status = ISCSI_PDU_CRC_FAILED; - break; - default: - return DATAOUT_CANNOT_RECOVER; - } - -recover: - return iscsit_recover_dataout_sequence(cmd, hdr->offset, payload_length); -} - -/* - * Called from iscsit_handle_data_out() before DataOUT Payload is received - * and CRC computed. - */ -extern int iscsit_check_pre_dataout( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - int ret; - struct iscsi_conn *conn = cmd->conn; - - ret = iscsit_dataout_within_command_recovery_check(cmd, buf); - if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) || - (ret == DATAOUT_CANNOT_RECOVER)) - return ret; - - ret = iscsit_dataout_check_datasn(cmd, buf); - if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) || - (ret == DATAOUT_CANNOT_RECOVER)) - return ret; - - if (cmd->unsolicited_data) { - ret = iscsit_dataout_check_unsolicited_sequence(cmd, buf); - if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) || - (ret == DATAOUT_CANNOT_RECOVER)) - return ret; - } else { - ret = iscsit_dataout_check_sequence(cmd, buf); - if ((ret == DATAOUT_WITHIN_COMMAND_RECOVERY) || - (ret == DATAOUT_CANNOT_RECOVER)) - return ret; - } - - return (conn->sess->sess_ops->DataPDUInOrder) ? - iscsit_dataout_pre_datapduinorder_yes(cmd, buf) : - iscsit_dataout_pre_datapduinorder_no(cmd, buf); -} - -/* - * Called from iscsit_handle_data_out() after DataOUT Payload is received - * and CRC computed. - */ -int iscsit_check_post_dataout( - struct iscsi_cmd *cmd, - unsigned char *buf, - u8 data_crc_failed) -{ - struct iscsi_conn *conn = cmd->conn; - - cmd->dataout_timeout_retries = 0; - - if (!data_crc_failed) - return iscsit_dataout_post_crc_passed(cmd, buf); - else { - if (!conn->sess->sess_ops->ErrorRecoveryLevel) { - pr_err("Unable to recover from DataOUT CRC" - " failure while ERL=0, closing session.\n"); - iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR, - 1, 0, buf, cmd); - return DATAOUT_CANNOT_RECOVER; - } - - iscsit_add_reject_from_cmd(ISCSI_REASON_DATA_DIGEST_ERROR, - 0, 0, buf, cmd); - return iscsit_dataout_post_crc_failed(cmd, buf); - } -} - -static void iscsit_handle_time2retain_timeout(unsigned long data) -{ - struct iscsi_session *sess = (struct iscsi_session *) data; - struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess); - struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; - - spin_lock_bh(&se_tpg->session_lock); - if (sess->time2retain_timer_flags & ISCSI_TF_STOP) { - spin_unlock_bh(&se_tpg->session_lock); - return; - } - if (atomic_read(&sess->session_reinstatement)) { - pr_err("Exiting Time2Retain handler because" - " session_reinstatement=1\n"); - spin_unlock_bh(&se_tpg->session_lock); - return; - } - sess->time2retain_timer_flags |= ISCSI_TF_EXPIRED; - - pr_err("Time2Retain timer expired for SID: %u, cleaning up" - " iSCSI session.\n", sess->sid); - { - struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; - - if (tiqn) { - spin_lock(&tiqn->sess_err_stats.lock); - strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, - (void *)sess->sess_ops->InitiatorName); - tiqn->sess_err_stats.last_sess_failure_type = - ISCSI_SESS_ERR_CXN_TIMEOUT; - tiqn->sess_err_stats.cxn_timeout_errors++; - sess->conn_timeout_errors++; - spin_unlock(&tiqn->sess_err_stats.lock); - } - } - - spin_unlock_bh(&se_tpg->session_lock); - iscsit_close_session(sess); -} - -extern void iscsit_start_time2retain_handler(struct iscsi_session *sess) -{ - int tpg_active; - /* - * Only start Time2Retain timer when the assoicated TPG is still in - * an ACTIVE (eg: not disabled or shutdown) state. - */ - spin_lock(&ISCSI_TPG_S(sess)->tpg_state_lock); - tpg_active = (ISCSI_TPG_S(sess)->tpg_state == TPG_STATE_ACTIVE); - spin_unlock(&ISCSI_TPG_S(sess)->tpg_state_lock); - - if (!tpg_active) - return; - - if (sess->time2retain_timer_flags & ISCSI_TF_RUNNING) - return; - - pr_debug("Starting Time2Retain timer for %u seconds on" - " SID: %u\n", sess->sess_ops->DefaultTime2Retain, sess->sid); - - init_timer(&sess->time2retain_timer); - sess->time2retain_timer.expires = - (get_jiffies_64() + sess->sess_ops->DefaultTime2Retain * HZ); - sess->time2retain_timer.data = (unsigned long)sess; - sess->time2retain_timer.function = iscsit_handle_time2retain_timeout; - sess->time2retain_timer_flags &= ~ISCSI_TF_STOP; - sess->time2retain_timer_flags |= ISCSI_TF_RUNNING; - add_timer(&sess->time2retain_timer); -} - -/* - * Called with spin_lock_bh(&struct se_portal_group->session_lock) held - */ -extern int iscsit_stop_time2retain_timer(struct iscsi_session *sess) -{ - struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess); - struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; - - if (sess->time2retain_timer_flags & ISCSI_TF_EXPIRED) - return -1; - - if (!(sess->time2retain_timer_flags & ISCSI_TF_RUNNING)) - return 0; - - sess->time2retain_timer_flags |= ISCSI_TF_STOP; - spin_unlock_bh(&se_tpg->session_lock); - - del_timer_sync(&sess->time2retain_timer); - - spin_lock_bh(&se_tpg->session_lock); - sess->time2retain_timer_flags &= ~ISCSI_TF_RUNNING; - pr_debug("Stopped Time2Retain Timer for SID: %u\n", - sess->sid); - return 0; -} - -void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *conn) -{ - spin_lock_bh(&conn->state_lock); - if (atomic_read(&conn->connection_exit)) { - spin_unlock_bh(&conn->state_lock); - goto sleep; - } - - if (atomic_read(&conn->transport_failed)) { - spin_unlock_bh(&conn->state_lock); - goto sleep; - } - spin_unlock_bh(&conn->state_lock); - - iscsi_thread_set_force_reinstatement(conn); - -sleep: - wait_for_completion(&conn->conn_wait_rcfr_comp); - complete(&conn->conn_post_wait_comp); -} - -void iscsit_cause_connection_reinstatement(struct iscsi_conn *conn, int sleep) -{ - spin_lock_bh(&conn->state_lock); - if (atomic_read(&conn->connection_exit)) { - spin_unlock_bh(&conn->state_lock); - return; - } - - if (atomic_read(&conn->transport_failed)) { - spin_unlock_bh(&conn->state_lock); - return; - } - - if (atomic_read(&conn->connection_reinstatement)) { - spin_unlock_bh(&conn->state_lock); - return; - } - - if (iscsi_thread_set_force_reinstatement(conn) < 0) { - spin_unlock_bh(&conn->state_lock); - return; - } - - atomic_set(&conn->connection_reinstatement, 1); - if (!sleep) { - spin_unlock_bh(&conn->state_lock); - return; - } - - atomic_set(&conn->sleep_on_conn_wait_comp, 1); - spin_unlock_bh(&conn->state_lock); - - wait_for_completion(&conn->conn_wait_comp); - complete(&conn->conn_post_wait_comp); -} - -void iscsit_fall_back_to_erl0(struct iscsi_session *sess) -{ - pr_debug("Falling back to ErrorRecoveryLevel=0 for SID:" - " %u\n", sess->sid); - - atomic_set(&sess->session_fall_back_to_erl0, 1); -} - -static void iscsit_handle_connection_cleanup(struct iscsi_conn *conn) -{ - struct iscsi_session *sess = conn->sess; - - if ((sess->sess_ops->ErrorRecoveryLevel == 2) && - !atomic_read(&sess->session_reinstatement) && - !atomic_read(&sess->session_fall_back_to_erl0)) - iscsit_connection_recovery_transport_reset(conn); - else { - pr_debug("Performing cleanup for failed iSCSI" - " Connection ID: %hu from %s\n", conn->cid, - sess->sess_ops->InitiatorName); - iscsit_close_connection(conn); - } -} - -extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *conn) -{ - spin_lock_bh(&conn->state_lock); - if (atomic_read(&conn->connection_exit)) { - spin_unlock_bh(&conn->state_lock); - return; - } - atomic_set(&conn->connection_exit, 1); - - if (conn->conn_state == TARG_CONN_STATE_IN_LOGOUT) { - spin_unlock_bh(&conn->state_lock); - iscsit_close_connection(conn); - return; - } - - if (conn->conn_state == TARG_CONN_STATE_CLEANUP_WAIT) { - spin_unlock_bh(&conn->state_lock); - return; - } - - pr_debug("Moving to TARG_CONN_STATE_CLEANUP_WAIT.\n"); - conn->conn_state = TARG_CONN_STATE_CLEANUP_WAIT; - spin_unlock_bh(&conn->state_lock); - - iscsit_handle_connection_cleanup(conn); -} - -/* - * This is the simple function that makes the magic of - * sync and steering happen in the follow paradoxical order: - * - * 0) Receive conn->of_marker (bytes left until next OFMarker) - * bytes into an offload buffer. When we pass the exact number - * of bytes in conn->of_marker, iscsit_dump_data_payload() and hence - * rx_data() will automatically receive the identical u32 marker - * values and store it in conn->of_marker_offset; - * 1) Now conn->of_marker_offset will contain the offset to the start - * of the next iSCSI PDU. Dump these remaining bytes into another - * offload buffer. - * 2) We are done! - * Next byte in the TCP stream will contain the next iSCSI PDU! - * Cool Huh?! - */ -int iscsit_recover_from_unknown_opcode(struct iscsi_conn *conn) -{ - /* - * Make sure the remaining bytes to next maker is a sane value. - */ - if (conn->of_marker > (conn->conn_ops->OFMarkInt * 4)) { - pr_err("Remaining bytes to OFMarker: %u exceeds" - " OFMarkInt bytes: %u.\n", conn->of_marker, - conn->conn_ops->OFMarkInt * 4); - return -1; - } - - pr_debug("Advancing %u bytes in TCP stream to get to the" - " next OFMarker.\n", conn->of_marker); - - if (iscsit_dump_data_payload(conn, conn->of_marker, 0) < 0) - return -1; - - /* - * Make sure the offset marker we retrived is a valid value. - */ - if (conn->of_marker_offset > (ISCSI_HDR_LEN + (ISCSI_CRC_LEN * 2) + - conn->conn_ops->MaxRecvDataSegmentLength)) { - pr_err("OfMarker offset value: %u exceeds limit.\n", - conn->of_marker_offset); - return -1; - } - - pr_debug("Discarding %u bytes of TCP stream to get to the" - " next iSCSI Opcode.\n", conn->of_marker_offset); - - if (iscsit_dump_data_payload(conn, conn->of_marker_offset, 0) < 0) - return -1; - - return 0; -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_erl0.h b/trunk/drivers/target/iscsi/iscsi_target_erl0.h deleted file mode 100644 index 21acc9a06376..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_erl0.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef ISCSI_TARGET_ERL0_H -#define ISCSI_TARGET_ERL0_H - -extern void iscsit_set_dataout_sequence_values(struct iscsi_cmd *); -extern int iscsit_check_pre_dataout(struct iscsi_cmd *, unsigned char *); -extern int iscsit_check_post_dataout(struct iscsi_cmd *, unsigned char *, u8); -extern void iscsit_start_time2retain_handler(struct iscsi_session *); -extern int iscsit_stop_time2retain_timer(struct iscsi_session *); -extern void iscsit_connection_reinstatement_rcfr(struct iscsi_conn *); -extern void iscsit_cause_connection_reinstatement(struct iscsi_conn *, int); -extern void iscsit_fall_back_to_erl0(struct iscsi_session *); -extern void iscsit_take_action_for_connection_exit(struct iscsi_conn *); -extern int iscsit_recover_from_unknown_opcode(struct iscsi_conn *); - -#endif /*** ISCSI_TARGET_ERL0_H ***/ diff --git a/trunk/drivers/target/iscsi/iscsi_target_erl1.c b/trunk/drivers/target/iscsi/iscsi_target_erl1.c deleted file mode 100644 index 980650792cf6..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_erl1.c +++ /dev/null @@ -1,1299 +0,0 @@ -/******************************************************************************* - * This file contains error recovery level one used by the iSCSI Target driver. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_datain_values.h" -#include "iscsi_target_device.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_util.h" -#include "iscsi_target_erl0.h" -#include "iscsi_target_erl1.h" -#include "iscsi_target_erl2.h" -#include "iscsi_target.h" - -#define OFFLOAD_BUF_SIZE 32768 - -/* - * Used to dump excess datain payload for certain error recovery - * situations. Receive in OFFLOAD_BUF_SIZE max of datain per rx_data(). - * - * dump_padding_digest denotes if padding and data digests need - * to be dumped. - */ -int iscsit_dump_data_payload( - struct iscsi_conn *conn, - u32 buf_len, - int dump_padding_digest) -{ - char *buf, pad_bytes[4]; - int ret = DATAOUT_WITHIN_COMMAND_RECOVERY, rx_got; - u32 length, padding, offset = 0, size; - struct kvec iov; - - length = (buf_len > OFFLOAD_BUF_SIZE) ? OFFLOAD_BUF_SIZE : buf_len; - - buf = kzalloc(length, GFP_ATOMIC); - if (!buf) { - pr_err("Unable to allocate %u bytes for offload" - " buffer.\n", length); - return -1; - } - memset(&iov, 0, sizeof(struct kvec)); - - while (offset < buf_len) { - size = ((offset + length) > buf_len) ? - (buf_len - offset) : length; - - iov.iov_len = size; - iov.iov_base = buf; - - rx_got = rx_data(conn, &iov, 1, size); - if (rx_got != size) { - ret = DATAOUT_CANNOT_RECOVER; - goto out; - } - - offset += size; - } - - if (!dump_padding_digest) - goto out; - - padding = ((-buf_len) & 3); - if (padding != 0) { - iov.iov_len = padding; - iov.iov_base = pad_bytes; - - rx_got = rx_data(conn, &iov, 1, padding); - if (rx_got != padding) { - ret = DATAOUT_CANNOT_RECOVER; - goto out; - } - } - - if (conn->conn_ops->DataDigest) { - u32 data_crc; - - iov.iov_len = ISCSI_CRC_LEN; - iov.iov_base = &data_crc; - - rx_got = rx_data(conn, &iov, 1, ISCSI_CRC_LEN); - if (rx_got != ISCSI_CRC_LEN) { - ret = DATAOUT_CANNOT_RECOVER; - goto out; - } - } - -out: - kfree(buf); - return ret; -} - -/* - * Used for retransmitting R2Ts from a R2T SNACK request. - */ -static int iscsit_send_recovery_r2t_for_snack( - struct iscsi_cmd *cmd, - struct iscsi_r2t *r2t) -{ - /* - * If the struct iscsi_r2t has not been sent yet, we can safely - * ignore retransmission - * of the R2TSN in question. - */ - spin_lock_bh(&cmd->r2t_lock); - if (!r2t->sent_r2t) { - spin_unlock_bh(&cmd->r2t_lock); - return 0; - } - r2t->sent_r2t = 0; - spin_unlock_bh(&cmd->r2t_lock); - - iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, ISTATE_SEND_R2T); - - return 0; -} - -static int iscsit_handle_r2t_snack( - struct iscsi_cmd *cmd, - unsigned char *buf, - u32 begrun, - u32 runlength) -{ - u32 last_r2tsn; - struct iscsi_r2t *r2t; - - /* - * Make sure the initiator is not requesting retransmission - * of R2TSNs already acknowledged by a TMR TASK_REASSIGN. - */ - if ((cmd->cmd_flags & ICF_GOT_DATACK_SNACK) && - (begrun <= cmd->acked_data_sn)) { - pr_err("ITT: 0x%08x, R2T SNACK requesting" - " retransmission of R2TSN: 0x%08x to 0x%08x but already" - " acked to R2TSN: 0x%08x by TMR TASK_REASSIGN," - " protocol error.\n", cmd->init_task_tag, begrun, - (begrun + runlength), cmd->acked_data_sn); - - return iscsit_add_reject_from_cmd( - ISCSI_REASON_PROTOCOL_ERROR, - 1, 0, buf, cmd); - } - - if (runlength) { - if ((begrun + runlength) > cmd->r2t_sn) { - pr_err("Command ITT: 0x%08x received R2T SNACK" - " with BegRun: 0x%08x, RunLength: 0x%08x, exceeds" - " current R2TSN: 0x%08x, protocol error.\n", - cmd->init_task_tag, begrun, runlength, cmd->r2t_sn); - return iscsit_add_reject_from_cmd( - ISCSI_REASON_BOOKMARK_INVALID, 1, 0, buf, cmd); - } - last_r2tsn = (begrun + runlength); - } else - last_r2tsn = cmd->r2t_sn; - - while (begrun < last_r2tsn) { - r2t = iscsit_get_holder_for_r2tsn(cmd, begrun); - if (!r2t) - return -1; - if (iscsit_send_recovery_r2t_for_snack(cmd, r2t) < 0) - return -1; - - begrun++; - } - - return 0; -} - -/* - * Generates Offsets and NextBurstLength based on Begrun and Runlength - * carried in a Data SNACK or ExpDataSN in TMR TASK_REASSIGN. - * - * For DataSequenceInOrder=Yes and DataPDUInOrder=[Yes,No] only. - * - * FIXME: How is this handled for a RData SNACK? - */ -int iscsit_create_recovery_datain_values_datasequenceinorder_yes( - struct iscsi_cmd *cmd, - struct iscsi_datain_req *dr) -{ - u32 data_sn = 0, data_sn_count = 0; - u32 pdu_start = 0, seq_no = 0; - u32 begrun = dr->begrun; - struct iscsi_conn *conn = cmd->conn; - - while (begrun > data_sn++) { - data_sn_count++; - if ((dr->next_burst_len + - conn->conn_ops->MaxRecvDataSegmentLength) < - conn->sess->sess_ops->MaxBurstLength) { - dr->read_data_done += - conn->conn_ops->MaxRecvDataSegmentLength; - dr->next_burst_len += - conn->conn_ops->MaxRecvDataSegmentLength; - } else { - dr->read_data_done += - (conn->sess->sess_ops->MaxBurstLength - - dr->next_burst_len); - dr->next_burst_len = 0; - pdu_start += data_sn_count; - data_sn_count = 0; - seq_no++; - } - } - - if (!conn->sess->sess_ops->DataPDUInOrder) { - cmd->seq_no = seq_no; - cmd->pdu_start = pdu_start; - cmd->pdu_send_order = data_sn_count; - } - - return 0; -} - -/* - * Generates Offsets and NextBurstLength based on Begrun and Runlength - * carried in a Data SNACK or ExpDataSN in TMR TASK_REASSIGN. - * - * For DataSequenceInOrder=No and DataPDUInOrder=[Yes,No] only. - * - * FIXME: How is this handled for a RData SNACK? - */ -int iscsit_create_recovery_datain_values_datasequenceinorder_no( - struct iscsi_cmd *cmd, - struct iscsi_datain_req *dr) -{ - int found_seq = 0, i; - u32 data_sn, read_data_done = 0, seq_send_order = 0; - u32 begrun = dr->begrun; - u32 runlength = dr->runlength; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_seq *first_seq = NULL, *seq = NULL; - - if (!cmd->seq_list) { - pr_err("struct iscsi_cmd->seq_list is NULL!\n"); - return -1; - } - - /* - * Calculate read_data_done for all sequences containing a - * first_datasn and last_datasn less than the BegRun. - * - * Locate the struct iscsi_seq the BegRun lies within and calculate - * NextBurstLenghth up to the DataSN based on MaxRecvDataSegmentLength. - * - * Also use struct iscsi_seq->seq_send_order to determine where to start. - */ - for (i = 0; i < cmd->seq_count; i++) { - seq = &cmd->seq_list[i]; - - if (!seq->seq_send_order) - first_seq = seq; - - /* - * No data has been transferred for this DataIN sequence, so the - * seq->first_datasn and seq->last_datasn have not been set. - */ - if (!seq->sent) { -#if 0 - pr_err("Ignoring non-sent sequence 0x%08x ->" - " 0x%08x\n\n", seq->first_datasn, - seq->last_datasn); -#endif - continue; - } - - /* - * This DataIN sequence is precedes the received BegRun, add the - * total xfer_len of the sequence to read_data_done and reset - * seq->pdu_send_order. - */ - if ((seq->first_datasn < begrun) && - (seq->last_datasn < begrun)) { -#if 0 - pr_err("Pre BegRun sequence 0x%08x ->" - " 0x%08x\n", seq->first_datasn, - seq->last_datasn); -#endif - read_data_done += cmd->seq_list[i].xfer_len; - seq->next_burst_len = seq->pdu_send_order = 0; - continue; - } - - /* - * The BegRun lies within this DataIN sequence. - */ - if ((seq->first_datasn <= begrun) && - (seq->last_datasn >= begrun)) { -#if 0 - pr_err("Found sequence begrun: 0x%08x in" - " 0x%08x -> 0x%08x\n", begrun, - seq->first_datasn, seq->last_datasn); -#endif - seq_send_order = seq->seq_send_order; - data_sn = seq->first_datasn; - seq->next_burst_len = seq->pdu_send_order = 0; - found_seq = 1; - - /* - * For DataPDUInOrder=Yes, while the first DataSN of - * the sequence is less than the received BegRun, add - * the MaxRecvDataSegmentLength to read_data_done and - * to the sequence's next_burst_len; - * - * For DataPDUInOrder=No, while the first DataSN of the - * sequence is less than the received BegRun, find the - * struct iscsi_pdu of the DataSN in question and add the - * MaxRecvDataSegmentLength to read_data_done and to the - * sequence's next_burst_len; - */ - if (conn->sess->sess_ops->DataPDUInOrder) { - while (data_sn < begrun) { - seq->pdu_send_order++; - read_data_done += - conn->conn_ops->MaxRecvDataSegmentLength; - seq->next_burst_len += - conn->conn_ops->MaxRecvDataSegmentLength; - data_sn++; - } - } else { - int j; - struct iscsi_pdu *pdu; - - while (data_sn < begrun) { - seq->pdu_send_order++; - - for (j = 0; j < seq->pdu_count; j++) { - pdu = &cmd->pdu_list[ - seq->pdu_start + j]; - if (pdu->data_sn == data_sn) { - read_data_done += - pdu->length; - seq->next_burst_len += - pdu->length; - } - } - data_sn++; - } - } - continue; - } - - /* - * This DataIN sequence is larger than the received BegRun, - * reset seq->pdu_send_order and continue. - */ - if ((seq->first_datasn > begrun) || - (seq->last_datasn > begrun)) { -#if 0 - pr_err("Post BegRun sequence 0x%08x -> 0x%08x\n", - seq->first_datasn, seq->last_datasn); -#endif - seq->next_burst_len = seq->pdu_send_order = 0; - continue; - } - } - - if (!found_seq) { - if (!begrun) { - if (!first_seq) { - pr_err("ITT: 0x%08x, Begrun: 0x%08x" - " but first_seq is NULL\n", - cmd->init_task_tag, begrun); - return -1; - } - seq_send_order = first_seq->seq_send_order; - seq->next_burst_len = seq->pdu_send_order = 0; - goto done; - } - - pr_err("Unable to locate struct iscsi_seq for ITT: 0x%08x," - " BegRun: 0x%08x, RunLength: 0x%08x while" - " DataSequenceInOrder=No and DataPDUInOrder=%s.\n", - cmd->init_task_tag, begrun, runlength, - (conn->sess->sess_ops->DataPDUInOrder) ? "Yes" : "No"); - return -1; - } - -done: - dr->read_data_done = read_data_done; - dr->seq_send_order = seq_send_order; - - return 0; -} - -static int iscsit_handle_recovery_datain( - struct iscsi_cmd *cmd, - unsigned char *buf, - u32 begrun, - u32 runlength) -{ - struct iscsi_conn *conn = cmd->conn; - struct iscsi_datain_req *dr; - struct se_cmd *se_cmd = &cmd->se_cmd; - - if (!atomic_read(&se_cmd->t_transport_complete)) { - pr_err("Ignoring ITT: 0x%08x Data SNACK\n", - cmd->init_task_tag); - return 0; - } - - /* - * Make sure the initiator is not requesting retransmission - * of DataSNs already acknowledged by a Data ACK SNACK. - */ - if ((cmd->cmd_flags & ICF_GOT_DATACK_SNACK) && - (begrun <= cmd->acked_data_sn)) { - pr_err("ITT: 0x%08x, Data SNACK requesting" - " retransmission of DataSN: 0x%08x to 0x%08x but" - " already acked to DataSN: 0x%08x by Data ACK SNACK," - " protocol error.\n", cmd->init_task_tag, begrun, - (begrun + runlength), cmd->acked_data_sn); - - return iscsit_add_reject_from_cmd(ISCSI_REASON_PROTOCOL_ERROR, - 1, 0, buf, cmd); - } - - /* - * Make sure BegRun and RunLength in the Data SNACK are sane. - * Note: (cmd->data_sn - 1) will carry the maximum DataSN sent. - */ - if ((begrun + runlength) > (cmd->data_sn - 1)) { - pr_err("Initiator requesting BegRun: 0x%08x, RunLength" - ": 0x%08x greater than maximum DataSN: 0x%08x.\n", - begrun, runlength, (cmd->data_sn - 1)); - return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_INVALID, - 1, 0, buf, cmd); - } - - dr = iscsit_allocate_datain_req(); - if (!dr) - return iscsit_add_reject_from_cmd(ISCSI_REASON_BOOKMARK_NO_RESOURCES, - 1, 0, buf, cmd); - - dr->data_sn = dr->begrun = begrun; - dr->runlength = runlength; - dr->generate_recovery_values = 1; - dr->recovery = DATAIN_WITHIN_COMMAND_RECOVERY; - - iscsit_attach_datain_req(cmd, dr); - - cmd->i_state = ISTATE_SEND_DATAIN; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - - return 0; -} - -int iscsit_handle_recovery_datain_or_r2t( - struct iscsi_conn *conn, - unsigned char *buf, - u32 init_task_tag, - u32 targ_xfer_tag, - u32 begrun, - u32 runlength) -{ - struct iscsi_cmd *cmd; - - cmd = iscsit_find_cmd_from_itt(conn, init_task_tag); - if (!cmd) - return 0; - - /* - * FIXME: This will not work for bidi commands. - */ - switch (cmd->data_direction) { - case DMA_TO_DEVICE: - return iscsit_handle_r2t_snack(cmd, buf, begrun, runlength); - case DMA_FROM_DEVICE: - return iscsit_handle_recovery_datain(cmd, buf, begrun, - runlength); - default: - pr_err("Unknown cmd->data_direction: 0x%02x\n", - cmd->data_direction); - return -1; - } - - return 0; -} - -/* #warning FIXME: Status SNACK needs to be dependent on OPCODE!!! */ -int iscsit_handle_status_snack( - struct iscsi_conn *conn, - u32 init_task_tag, - u32 targ_xfer_tag, - u32 begrun, - u32 runlength) -{ - struct iscsi_cmd *cmd = NULL; - u32 last_statsn; - int found_cmd; - - if (conn->exp_statsn > begrun) { - pr_err("Got Status SNACK Begrun: 0x%08x, RunLength:" - " 0x%08x but already got ExpStatSN: 0x%08x on CID:" - " %hu.\n", begrun, runlength, conn->exp_statsn, - conn->cid); - return 0; - } - - last_statsn = (!runlength) ? conn->stat_sn : (begrun + runlength); - - while (begrun < last_statsn) { - found_cmd = 0; - - spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { - if (cmd->stat_sn == begrun) { - found_cmd = 1; - break; - } - } - spin_unlock_bh(&conn->cmd_lock); - - if (!found_cmd) { - pr_err("Unable to find StatSN: 0x%08x for" - " a Status SNACK, assuming this was a" - " protactic SNACK for an untransmitted" - " StatSN, ignoring.\n", begrun); - begrun++; - continue; - } - - spin_lock_bh(&cmd->istate_lock); - if (cmd->i_state == ISTATE_SEND_DATAIN) { - spin_unlock_bh(&cmd->istate_lock); - pr_err("Ignoring Status SNACK for BegRun:" - " 0x%08x, RunLength: 0x%08x, assuming this was" - " a protactic SNACK for an untransmitted" - " StatSN\n", begrun, runlength); - begrun++; - continue; - } - spin_unlock_bh(&cmd->istate_lock); - - cmd->i_state = ISTATE_SEND_STATUS_RECOVERY; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - begrun++; - } - - return 0; -} - -int iscsit_handle_data_ack( - struct iscsi_conn *conn, - u32 targ_xfer_tag, - u32 begrun, - u32 runlength) -{ - struct iscsi_cmd *cmd = NULL; - - cmd = iscsit_find_cmd_from_ttt(conn, targ_xfer_tag); - if (!cmd) { - pr_err("Data ACK SNACK for TTT: 0x%08x is" - " invalid.\n", targ_xfer_tag); - return -1; - } - - if (begrun <= cmd->acked_data_sn) { - pr_err("ITT: 0x%08x Data ACK SNACK BegRUN: 0x%08x is" - " less than the already acked DataSN: 0x%08x.\n", - cmd->init_task_tag, begrun, cmd->acked_data_sn); - return -1; - } - - /* - * For Data ACK SNACK, BegRun is the next expected DataSN. - * (see iSCSI v19: 10.16.6) - */ - cmd->cmd_flags |= ICF_GOT_DATACK_SNACK; - cmd->acked_data_sn = (begrun - 1); - - pr_debug("Received Data ACK SNACK for ITT: 0x%08x," - " updated acked DataSN to 0x%08x.\n", - cmd->init_task_tag, cmd->acked_data_sn); - - return 0; -} - -static int iscsit_send_recovery_r2t( - struct iscsi_cmd *cmd, - u32 offset, - u32 xfer_len) -{ - int ret; - - spin_lock_bh(&cmd->r2t_lock); - ret = iscsit_add_r2t_to_list(cmd, offset, xfer_len, 1, 0); - spin_unlock_bh(&cmd->r2t_lock); - - return ret; -} - -int iscsit_dataout_datapduinorder_no_fbit( - struct iscsi_cmd *cmd, - struct iscsi_pdu *pdu) -{ - int i, send_recovery_r2t = 0, recovery = 0; - u32 length = 0, offset = 0, pdu_count = 0, xfer_len = 0; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_pdu *first_pdu = NULL; - - /* - * Get an struct iscsi_pdu pointer to the first PDU, and total PDU count - * of the DataOUT sequence. - */ - if (conn->sess->sess_ops->DataSequenceInOrder) { - for (i = 0; i < cmd->pdu_count; i++) { - if (cmd->pdu_list[i].seq_no == pdu->seq_no) { - if (!first_pdu) - first_pdu = &cmd->pdu_list[i]; - xfer_len += cmd->pdu_list[i].length; - pdu_count++; - } else if (pdu_count) - break; - } - } else { - struct iscsi_seq *seq = cmd->seq_ptr; - - first_pdu = &cmd->pdu_list[seq->pdu_start]; - pdu_count = seq->pdu_count; - } - - if (!first_pdu || !pdu_count) - return DATAOUT_CANNOT_RECOVER; - - /* - * Loop through the ending DataOUT Sequence checking each struct iscsi_pdu. - * The following ugly logic does batching of not received PDUs. - */ - for (i = 0; i < pdu_count; i++) { - if (first_pdu[i].status == ISCSI_PDU_RECEIVED_OK) { - if (!send_recovery_r2t) - continue; - - if (iscsit_send_recovery_r2t(cmd, offset, length) < 0) - return DATAOUT_CANNOT_RECOVER; - - send_recovery_r2t = length = offset = 0; - continue; - } - /* - * Set recovery = 1 for any missing, CRC failed, or timed - * out PDUs to let the DataOUT logic know that this sequence - * has not been completed yet. - * - * Also, only send a Recovery R2T for ISCSI_PDU_NOT_RECEIVED. - * We assume if the PDU either failed CRC or timed out - * that a Recovery R2T has already been sent. - */ - recovery = 1; - - if (first_pdu[i].status != ISCSI_PDU_NOT_RECEIVED) - continue; - - if (!offset) - offset = first_pdu[i].offset; - length += first_pdu[i].length; - - send_recovery_r2t = 1; - } - - if (send_recovery_r2t) - if (iscsit_send_recovery_r2t(cmd, offset, length) < 0) - return DATAOUT_CANNOT_RECOVER; - - return (!recovery) ? DATAOUT_NORMAL : DATAOUT_WITHIN_COMMAND_RECOVERY; -} - -static int iscsit_recalculate_dataout_values( - struct iscsi_cmd *cmd, - u32 pdu_offset, - u32 pdu_length, - u32 *r2t_offset, - u32 *r2t_length) -{ - int i; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_pdu *pdu = NULL; - - if (conn->sess->sess_ops->DataSequenceInOrder) { - cmd->data_sn = 0; - - if (conn->sess->sess_ops->DataPDUInOrder) { - *r2t_offset = cmd->write_data_done; - *r2t_length = (cmd->seq_end_offset - - cmd->write_data_done); - return 0; - } - - *r2t_offset = cmd->seq_start_offset; - *r2t_length = (cmd->seq_end_offset - cmd->seq_start_offset); - - for (i = 0; i < cmd->pdu_count; i++) { - pdu = &cmd->pdu_list[i]; - - if (pdu->status != ISCSI_PDU_RECEIVED_OK) - continue; - - if ((pdu->offset >= cmd->seq_start_offset) && - ((pdu->offset + pdu->length) <= - cmd->seq_end_offset)) { - if (!cmd->unsolicited_data) - cmd->next_burst_len -= pdu->length; - else - cmd->first_burst_len -= pdu->length; - - cmd->write_data_done -= pdu->length; - pdu->status = ISCSI_PDU_NOT_RECEIVED; - } - } - } else { - struct iscsi_seq *seq = NULL; - - seq = iscsit_get_seq_holder(cmd, pdu_offset, pdu_length); - if (!seq) - return -1; - - *r2t_offset = seq->orig_offset; - *r2t_length = seq->xfer_len; - - cmd->write_data_done -= (seq->offset - seq->orig_offset); - if (cmd->immediate_data) - cmd->first_burst_len = cmd->write_data_done; - - seq->data_sn = 0; - seq->offset = seq->orig_offset; - seq->next_burst_len = 0; - seq->status = DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY; - - if (conn->sess->sess_ops->DataPDUInOrder) - return 0; - - for (i = 0; i < seq->pdu_count; i++) { - pdu = &cmd->pdu_list[i+seq->pdu_start]; - - if (pdu->status != ISCSI_PDU_RECEIVED_OK) - continue; - - pdu->status = ISCSI_PDU_NOT_RECEIVED; - } - } - - return 0; -} - -int iscsit_recover_dataout_sequence( - struct iscsi_cmd *cmd, - u32 pdu_offset, - u32 pdu_length) -{ - u32 r2t_length = 0, r2t_offset = 0; - - spin_lock_bh(&cmd->istate_lock); - cmd->cmd_flags |= ICF_WITHIN_COMMAND_RECOVERY; - spin_unlock_bh(&cmd->istate_lock); - - if (iscsit_recalculate_dataout_values(cmd, pdu_offset, pdu_length, - &r2t_offset, &r2t_length) < 0) - return DATAOUT_CANNOT_RECOVER; - - iscsit_send_recovery_r2t(cmd, r2t_offset, r2t_length); - - return DATAOUT_WITHIN_COMMAND_RECOVERY; -} - -static struct iscsi_ooo_cmdsn *iscsit_allocate_ooo_cmdsn(void) -{ - struct iscsi_ooo_cmdsn *ooo_cmdsn = NULL; - - ooo_cmdsn = kmem_cache_zalloc(lio_ooo_cache, GFP_ATOMIC); - if (!ooo_cmdsn) { - pr_err("Unable to allocate memory for" - " struct iscsi_ooo_cmdsn.\n"); - return NULL; - } - INIT_LIST_HEAD(&ooo_cmdsn->ooo_list); - - return ooo_cmdsn; -} - -/* - * Called with sess->cmdsn_mutex held. - */ -static int iscsit_attach_ooo_cmdsn( - struct iscsi_session *sess, - struct iscsi_ooo_cmdsn *ooo_cmdsn) -{ - struct iscsi_ooo_cmdsn *ooo_tail, *ooo_tmp; - /* - * We attach the struct iscsi_ooo_cmdsn entry to the out of order - * list in increasing CmdSN order. - * This allows iscsi_execute_ooo_cmdsns() to detect any - * additional CmdSN holes while performing delayed execution. - */ - if (list_empty(&sess->sess_ooo_cmdsn_list)) - list_add_tail(&ooo_cmdsn->ooo_list, - &sess->sess_ooo_cmdsn_list); - else { - ooo_tail = list_entry(sess->sess_ooo_cmdsn_list.prev, - typeof(*ooo_tail), ooo_list); - /* - * CmdSN is greater than the tail of the list. - */ - if (ooo_tail->cmdsn < ooo_cmdsn->cmdsn) - list_add_tail(&ooo_cmdsn->ooo_list, - &sess->sess_ooo_cmdsn_list); - else { - /* - * CmdSN is either lower than the head, or somewhere - * in the middle. - */ - list_for_each_entry(ooo_tmp, &sess->sess_ooo_cmdsn_list, - ooo_list) { - while (ooo_tmp->cmdsn < ooo_cmdsn->cmdsn) - continue; - - list_add(&ooo_cmdsn->ooo_list, - &ooo_tmp->ooo_list); - break; - } - } - } - - return 0; -} - -/* - * Removes an struct iscsi_ooo_cmdsn from a session's list, - * called with struct iscsi_session->cmdsn_mutex held. - */ -void iscsit_remove_ooo_cmdsn( - struct iscsi_session *sess, - struct iscsi_ooo_cmdsn *ooo_cmdsn) -{ - list_del(&ooo_cmdsn->ooo_list); - kmem_cache_free(lio_ooo_cache, ooo_cmdsn); -} - -void iscsit_clear_ooo_cmdsns_for_conn(struct iscsi_conn *conn) -{ - struct iscsi_ooo_cmdsn *ooo_cmdsn; - struct iscsi_session *sess = conn->sess; - - mutex_lock(&sess->cmdsn_mutex); - list_for_each_entry(ooo_cmdsn, &sess->sess_ooo_cmdsn_list, ooo_list) { - if (ooo_cmdsn->cid != conn->cid) - continue; - - ooo_cmdsn->cmd = NULL; - } - mutex_unlock(&sess->cmdsn_mutex); -} - -/* - * Called with sess->cmdsn_mutex held. - */ -int iscsit_execute_ooo_cmdsns(struct iscsi_session *sess) -{ - int ooo_count = 0; - struct iscsi_cmd *cmd = NULL; - struct iscsi_ooo_cmdsn *ooo_cmdsn, *ooo_cmdsn_tmp; - - list_for_each_entry_safe(ooo_cmdsn, ooo_cmdsn_tmp, - &sess->sess_ooo_cmdsn_list, ooo_list) { - if (ooo_cmdsn->cmdsn != sess->exp_cmd_sn) - continue; - - if (!ooo_cmdsn->cmd) { - sess->exp_cmd_sn++; - iscsit_remove_ooo_cmdsn(sess, ooo_cmdsn); - continue; - } - - cmd = ooo_cmdsn->cmd; - cmd->i_state = cmd->deferred_i_state; - ooo_count++; - sess->exp_cmd_sn++; - pr_debug("Executing out of order CmdSN: 0x%08x," - " incremented ExpCmdSN to 0x%08x.\n", - cmd->cmd_sn, sess->exp_cmd_sn); - - iscsit_remove_ooo_cmdsn(sess, ooo_cmdsn); - - if (iscsit_execute_cmd(cmd, 1) < 0) - return -1; - - continue; - } - - return ooo_count; -} - -/* - * Called either: - * - * 1. With sess->cmdsn_mutex held from iscsi_execute_ooo_cmdsns() - * or iscsi_check_received_cmdsn(). - * 2. With no locks held directly from iscsi_handle_XXX_pdu() functions - * for immediate commands. - */ -int iscsit_execute_cmd(struct iscsi_cmd *cmd, int ooo) -{ - struct se_cmd *se_cmd = &cmd->se_cmd; - int lr = 0; - - spin_lock_bh(&cmd->istate_lock); - if (ooo) - cmd->cmd_flags &= ~ICF_OOO_CMDSN; - - switch (cmd->iscsi_opcode) { - case ISCSI_OP_SCSI_CMD: - /* - * Go ahead and send the CHECK_CONDITION status for - * any SCSI CDB exceptions that may have occurred, also - * handle the SCF_SCSI_RESERVATION_CONFLICT case here as well. - */ - if (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION) { - if (se_cmd->se_cmd_flags & - SCF_SCSI_RESERVATION_CONFLICT) { - cmd->i_state = ISTATE_SEND_STATUS; - spin_unlock_bh(&cmd->istate_lock); - iscsit_add_cmd_to_response_queue(cmd, cmd->conn, - cmd->i_state); - return 0; - } - spin_unlock_bh(&cmd->istate_lock); - /* - * Determine if delayed TASK_ABORTED status for WRITEs - * should be sent now if no unsolicited data out - * payloads are expected, or if the delayed status - * should be sent after unsolicited data out with - * ISCSI_FLAG_CMD_FINAL set in iscsi_handle_data_out() - */ - if (transport_check_aborted_status(se_cmd, - (cmd->unsolicited_data == 0)) != 0) - return 0; - /* - * Otherwise send CHECK_CONDITION and sense for - * exception - */ - return transport_send_check_condition_and_sense(se_cmd, - se_cmd->scsi_sense_reason, 0); - } - /* - * Special case for delayed CmdSN with Immediate - * Data and/or Unsolicited Data Out attached. - */ - if (cmd->immediate_data) { - if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) { - spin_unlock_bh(&cmd->istate_lock); - return transport_generic_handle_data( - &cmd->se_cmd); - } - spin_unlock_bh(&cmd->istate_lock); - - if (!(cmd->cmd_flags & - ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) { - /* - * Send the delayed TASK_ABORTED status for - * WRITEs if no more unsolicitied data is - * expected. - */ - if (transport_check_aborted_status(se_cmd, 1) - != 0) - return 0; - - iscsit_set_dataout_sequence_values(cmd); - iscsit_build_r2ts_for_cmd(cmd, cmd->conn, 0); - } - return 0; - } - /* - * The default handler. - */ - spin_unlock_bh(&cmd->istate_lock); - - if ((cmd->data_direction == DMA_TO_DEVICE) && - !(cmd->cmd_flags & ICF_NON_IMMEDIATE_UNSOLICITED_DATA)) { - /* - * Send the delayed TASK_ABORTED status for WRITEs if - * no more nsolicitied data is expected. - */ - if (transport_check_aborted_status(se_cmd, 1) != 0) - return 0; - - iscsit_set_dataout_sequence_values(cmd); - spin_lock_bh(&cmd->dataout_timeout_lock); - iscsit_start_dataout_timer(cmd, cmd->conn); - spin_unlock_bh(&cmd->dataout_timeout_lock); - } - return transport_handle_cdb_direct(&cmd->se_cmd); - - case ISCSI_OP_NOOP_OUT: - case ISCSI_OP_TEXT: - spin_unlock_bh(&cmd->istate_lock); - iscsit_add_cmd_to_response_queue(cmd, cmd->conn, cmd->i_state); - break; - case ISCSI_OP_SCSI_TMFUNC: - if (se_cmd->se_cmd_flags & SCF_SCSI_CDB_EXCEPTION) { - spin_unlock_bh(&cmd->istate_lock); - iscsit_add_cmd_to_response_queue(cmd, cmd->conn, - cmd->i_state); - return 0; - } - spin_unlock_bh(&cmd->istate_lock); - - return transport_generic_handle_tmr(&cmd->se_cmd); - case ISCSI_OP_LOGOUT: - spin_unlock_bh(&cmd->istate_lock); - switch (cmd->logout_reason) { - case ISCSI_LOGOUT_REASON_CLOSE_SESSION: - lr = iscsit_logout_closesession(cmd, cmd->conn); - break; - case ISCSI_LOGOUT_REASON_CLOSE_CONNECTION: - lr = iscsit_logout_closeconnection(cmd, cmd->conn); - break; - case ISCSI_LOGOUT_REASON_RECOVERY: - lr = iscsit_logout_removeconnforrecovery(cmd, cmd->conn); - break; - default: - pr_err("Unknown iSCSI Logout Request Code:" - " 0x%02x\n", cmd->logout_reason); - return -1; - } - - return lr; - default: - spin_unlock_bh(&cmd->istate_lock); - pr_err("Cannot perform out of order execution for" - " unknown iSCSI Opcode: 0x%02x\n", cmd->iscsi_opcode); - return -1; - } - - return 0; -} - -void iscsit_free_all_ooo_cmdsns(struct iscsi_session *sess) -{ - struct iscsi_ooo_cmdsn *ooo_cmdsn, *ooo_cmdsn_tmp; - - mutex_lock(&sess->cmdsn_mutex); - list_for_each_entry_safe(ooo_cmdsn, ooo_cmdsn_tmp, - &sess->sess_ooo_cmdsn_list, ooo_list) { - - list_del(&ooo_cmdsn->ooo_list); - kmem_cache_free(lio_ooo_cache, ooo_cmdsn); - } - mutex_unlock(&sess->cmdsn_mutex); -} - -int iscsit_handle_ooo_cmdsn( - struct iscsi_session *sess, - struct iscsi_cmd *cmd, - u32 cmdsn) -{ - int batch = 0; - struct iscsi_ooo_cmdsn *ooo_cmdsn = NULL, *ooo_tail = NULL; - - cmd->deferred_i_state = cmd->i_state; - cmd->i_state = ISTATE_DEFERRED_CMD; - cmd->cmd_flags |= ICF_OOO_CMDSN; - - if (list_empty(&sess->sess_ooo_cmdsn_list)) - batch = 1; - else { - ooo_tail = list_entry(sess->sess_ooo_cmdsn_list.prev, - typeof(*ooo_tail), ooo_list); - if (ooo_tail->cmdsn != (cmdsn - 1)) - batch = 1; - } - - ooo_cmdsn = iscsit_allocate_ooo_cmdsn(); - if (!ooo_cmdsn) - return CMDSN_ERROR_CANNOT_RECOVER; - - ooo_cmdsn->cmd = cmd; - ooo_cmdsn->batch_count = (batch) ? - (cmdsn - sess->exp_cmd_sn) : 1; - ooo_cmdsn->cid = cmd->conn->cid; - ooo_cmdsn->exp_cmdsn = sess->exp_cmd_sn; - ooo_cmdsn->cmdsn = cmdsn; - - if (iscsit_attach_ooo_cmdsn(sess, ooo_cmdsn) < 0) { - kmem_cache_free(lio_ooo_cache, ooo_cmdsn); - return CMDSN_ERROR_CANNOT_RECOVER; - } - - return CMDSN_HIGHER_THAN_EXP; -} - -static int iscsit_set_dataout_timeout_values( - struct iscsi_cmd *cmd, - u32 *offset, - u32 *length) -{ - struct iscsi_conn *conn = cmd->conn; - struct iscsi_r2t *r2t; - - if (cmd->unsolicited_data) { - *offset = 0; - *length = (conn->sess->sess_ops->FirstBurstLength > - cmd->data_length) ? - cmd->data_length : - conn->sess->sess_ops->FirstBurstLength; - return 0; - } - - spin_lock_bh(&cmd->r2t_lock); - if (list_empty(&cmd->cmd_r2t_list)) { - pr_err("cmd->cmd_r2t_list is empty!\n"); - spin_unlock_bh(&cmd->r2t_lock); - return -1; - } - - list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { - if (r2t->sent_r2t && !r2t->recovery_r2t && !r2t->seq_complete) { - *offset = r2t->offset; - *length = r2t->xfer_len; - spin_unlock_bh(&cmd->r2t_lock); - return 0; - } - } - spin_unlock_bh(&cmd->r2t_lock); - - pr_err("Unable to locate any incomplete DataOUT" - " sequences for ITT: 0x%08x.\n", cmd->init_task_tag); - - return -1; -} - -/* - * NOTE: Called from interrupt (timer) context. - */ -static void iscsit_handle_dataout_timeout(unsigned long data) -{ - u32 pdu_length = 0, pdu_offset = 0; - u32 r2t_length = 0, r2t_offset = 0; - struct iscsi_cmd *cmd = (struct iscsi_cmd *) data; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_session *sess = NULL; - struct iscsi_node_attrib *na; - - iscsit_inc_conn_usage_count(conn); - - spin_lock_bh(&cmd->dataout_timeout_lock); - if (cmd->dataout_timer_flags & ISCSI_TF_STOP) { - spin_unlock_bh(&cmd->dataout_timeout_lock); - iscsit_dec_conn_usage_count(conn); - return; - } - cmd->dataout_timer_flags &= ~ISCSI_TF_RUNNING; - sess = conn->sess; - na = iscsit_tpg_get_node_attrib(sess); - - if (!sess->sess_ops->ErrorRecoveryLevel) { - pr_debug("Unable to recover from DataOut timeout while" - " in ERL=0.\n"); - goto failure; - } - - if (++cmd->dataout_timeout_retries == na->dataout_timeout_retries) { - pr_debug("Command ITT: 0x%08x exceeded max retries" - " for DataOUT timeout %u, closing iSCSI connection.\n", - cmd->init_task_tag, na->dataout_timeout_retries); - goto failure; - } - - cmd->cmd_flags |= ICF_WITHIN_COMMAND_RECOVERY; - - if (conn->sess->sess_ops->DataSequenceInOrder) { - if (conn->sess->sess_ops->DataPDUInOrder) { - pdu_offset = cmd->write_data_done; - if ((pdu_offset + (conn->sess->sess_ops->MaxBurstLength - - cmd->next_burst_len)) > cmd->data_length) - pdu_length = (cmd->data_length - - cmd->write_data_done); - else - pdu_length = (conn->sess->sess_ops->MaxBurstLength - - cmd->next_burst_len); - } else { - pdu_offset = cmd->seq_start_offset; - pdu_length = (cmd->seq_end_offset - - cmd->seq_start_offset); - } - } else { - if (iscsit_set_dataout_timeout_values(cmd, &pdu_offset, - &pdu_length) < 0) - goto failure; - } - - if (iscsit_recalculate_dataout_values(cmd, pdu_offset, pdu_length, - &r2t_offset, &r2t_length) < 0) - goto failure; - - pr_debug("Command ITT: 0x%08x timed out waiting for" - " completion of %sDataOUT Sequence Offset: %u, Length: %u\n", - cmd->init_task_tag, (cmd->unsolicited_data) ? "Unsolicited " : - "", r2t_offset, r2t_length); - - if (iscsit_send_recovery_r2t(cmd, r2t_offset, r2t_length) < 0) - goto failure; - - iscsit_start_dataout_timer(cmd, conn); - spin_unlock_bh(&cmd->dataout_timeout_lock); - iscsit_dec_conn_usage_count(conn); - - return; - -failure: - spin_unlock_bh(&cmd->dataout_timeout_lock); - iscsit_cause_connection_reinstatement(conn, 0); - iscsit_dec_conn_usage_count(conn); -} - -void iscsit_mod_dataout_timer(struct iscsi_cmd *cmd) -{ - struct iscsi_conn *conn = cmd->conn; - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = na = iscsit_tpg_get_node_attrib(sess); - - spin_lock_bh(&cmd->dataout_timeout_lock); - if (!(cmd->dataout_timer_flags & ISCSI_TF_RUNNING)) { - spin_unlock_bh(&cmd->dataout_timeout_lock); - return; - } - - mod_timer(&cmd->dataout_timer, - (get_jiffies_64() + na->dataout_timeout * HZ)); - pr_debug("Updated DataOUT timer for ITT: 0x%08x", - cmd->init_task_tag); - spin_unlock_bh(&cmd->dataout_timeout_lock); -} - -/* - * Called with cmd->dataout_timeout_lock held. - */ -void iscsit_start_dataout_timer( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = na = iscsit_tpg_get_node_attrib(sess); - - if (cmd->dataout_timer_flags & ISCSI_TF_RUNNING) - return; - - pr_debug("Starting DataOUT timer for ITT: 0x%08x on" - " CID: %hu.\n", cmd->init_task_tag, conn->cid); - - init_timer(&cmd->dataout_timer); - cmd->dataout_timer.expires = (get_jiffies_64() + na->dataout_timeout * HZ); - cmd->dataout_timer.data = (unsigned long)cmd; - cmd->dataout_timer.function = iscsit_handle_dataout_timeout; - cmd->dataout_timer_flags &= ~ISCSI_TF_STOP; - cmd->dataout_timer_flags |= ISCSI_TF_RUNNING; - add_timer(&cmd->dataout_timer); -} - -void iscsit_stop_dataout_timer(struct iscsi_cmd *cmd) -{ - spin_lock_bh(&cmd->dataout_timeout_lock); - if (!(cmd->dataout_timer_flags & ISCSI_TF_RUNNING)) { - spin_unlock_bh(&cmd->dataout_timeout_lock); - return; - } - cmd->dataout_timer_flags |= ISCSI_TF_STOP; - spin_unlock_bh(&cmd->dataout_timeout_lock); - - del_timer_sync(&cmd->dataout_timer); - - spin_lock_bh(&cmd->dataout_timeout_lock); - cmd->dataout_timer_flags &= ~ISCSI_TF_RUNNING; - pr_debug("Stopped DataOUT Timer for ITT: 0x%08x\n", - cmd->init_task_tag); - spin_unlock_bh(&cmd->dataout_timeout_lock); -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_erl1.h b/trunk/drivers/target/iscsi/iscsi_target_erl1.h deleted file mode 100644 index 85e67e29de6b..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_erl1.h +++ /dev/null @@ -1,26 +0,0 @@ -#ifndef ISCSI_TARGET_ERL1_H -#define ISCSI_TARGET_ERL1_H - -extern int iscsit_dump_data_payload(struct iscsi_conn *, u32, int); -extern int iscsit_create_recovery_datain_values_datasequenceinorder_yes( - struct iscsi_cmd *, struct iscsi_datain_req *); -extern int iscsit_create_recovery_datain_values_datasequenceinorder_no( - struct iscsi_cmd *, struct iscsi_datain_req *); -extern int iscsit_handle_recovery_datain_or_r2t(struct iscsi_conn *, unsigned char *, - u32, u32, u32, u32); -extern int iscsit_handle_status_snack(struct iscsi_conn *, u32, u32, - u32, u32); -extern int iscsit_handle_data_ack(struct iscsi_conn *, u32, u32, u32); -extern int iscsit_dataout_datapduinorder_no_fbit(struct iscsi_cmd *, struct iscsi_pdu *); -extern int iscsit_recover_dataout_sequence(struct iscsi_cmd *, u32, u32); -extern void iscsit_clear_ooo_cmdsns_for_conn(struct iscsi_conn *); -extern void iscsit_free_all_ooo_cmdsns(struct iscsi_session *); -extern int iscsit_execute_ooo_cmdsns(struct iscsi_session *); -extern int iscsit_execute_cmd(struct iscsi_cmd *, int); -extern int iscsit_handle_ooo_cmdsn(struct iscsi_session *, struct iscsi_cmd *, u32); -extern void iscsit_remove_ooo_cmdsn(struct iscsi_session *, struct iscsi_ooo_cmdsn *); -extern void iscsit_mod_dataout_timer(struct iscsi_cmd *); -extern void iscsit_start_dataout_timer(struct iscsi_cmd *, struct iscsi_conn *); -extern void iscsit_stop_dataout_timer(struct iscsi_cmd *); - -#endif /* ISCSI_TARGET_ERL1_H */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_erl2.c b/trunk/drivers/target/iscsi/iscsi_target_erl2.c deleted file mode 100644 index 91a4d170bda4..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_erl2.c +++ /dev/null @@ -1,474 +0,0 @@ -/******************************************************************************* - * This file contains error recovery level two functions used by - * the iSCSI Target driver. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_datain_values.h" -#include "iscsi_target_util.h" -#include "iscsi_target_erl0.h" -#include "iscsi_target_erl1.h" -#include "iscsi_target_erl2.h" -#include "iscsi_target.h" - -/* - * FIXME: Does RData SNACK apply here as well? - */ -void iscsit_create_conn_recovery_datain_values( - struct iscsi_cmd *cmd, - u32 exp_data_sn) -{ - u32 data_sn = 0; - struct iscsi_conn *conn = cmd->conn; - - cmd->next_burst_len = 0; - cmd->read_data_done = 0; - - while (exp_data_sn > data_sn) { - if ((cmd->next_burst_len + - conn->conn_ops->MaxRecvDataSegmentLength) < - conn->sess->sess_ops->MaxBurstLength) { - cmd->read_data_done += - conn->conn_ops->MaxRecvDataSegmentLength; - cmd->next_burst_len += - conn->conn_ops->MaxRecvDataSegmentLength; - } else { - cmd->read_data_done += - (conn->sess->sess_ops->MaxBurstLength - - cmd->next_burst_len); - cmd->next_burst_len = 0; - } - data_sn++; - } -} - -void iscsit_create_conn_recovery_dataout_values( - struct iscsi_cmd *cmd) -{ - u32 write_data_done = 0; - struct iscsi_conn *conn = cmd->conn; - - cmd->data_sn = 0; - cmd->next_burst_len = 0; - - while (cmd->write_data_done > write_data_done) { - if ((write_data_done + conn->sess->sess_ops->MaxBurstLength) <= - cmd->write_data_done) - write_data_done += conn->sess->sess_ops->MaxBurstLength; - else - break; - } - - cmd->write_data_done = write_data_done; -} - -static int iscsit_attach_active_connection_recovery_entry( - struct iscsi_session *sess, - struct iscsi_conn_recovery *cr) -{ - spin_lock(&sess->cr_a_lock); - list_add_tail(&cr->cr_list, &sess->cr_active_list); - spin_unlock(&sess->cr_a_lock); - - return 0; -} - -static int iscsit_attach_inactive_connection_recovery_entry( - struct iscsi_session *sess, - struct iscsi_conn_recovery *cr) -{ - spin_lock(&sess->cr_i_lock); - list_add_tail(&cr->cr_list, &sess->cr_inactive_list); - - sess->conn_recovery_count++; - pr_debug("Incremented connection recovery count to %u for" - " SID: %u\n", sess->conn_recovery_count, sess->sid); - spin_unlock(&sess->cr_i_lock); - - return 0; -} - -struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry( - struct iscsi_session *sess, - u16 cid) -{ - struct iscsi_conn_recovery *cr; - - spin_lock(&sess->cr_i_lock); - list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) { - if (cr->cid == cid) { - spin_unlock(&sess->cr_i_lock); - return cr; - } - } - spin_unlock(&sess->cr_i_lock); - - return NULL; -} - -void iscsit_free_connection_recovery_entires(struct iscsi_session *sess) -{ - struct iscsi_cmd *cmd, *cmd_tmp; - struct iscsi_conn_recovery *cr, *cr_tmp; - - spin_lock(&sess->cr_a_lock); - list_for_each_entry_safe(cr, cr_tmp, &sess->cr_active_list, cr_list) { - list_del(&cr->cr_list); - spin_unlock(&sess->cr_a_lock); - - spin_lock(&cr->conn_recovery_cmd_lock); - list_for_each_entry_safe(cmd, cmd_tmp, - &cr->conn_recovery_cmd_list, i_list) { - - list_del(&cmd->i_list); - cmd->conn = NULL; - spin_unlock(&cr->conn_recovery_cmd_lock); - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 1); - spin_lock(&cr->conn_recovery_cmd_lock); - } - spin_unlock(&cr->conn_recovery_cmd_lock); - spin_lock(&sess->cr_a_lock); - - kfree(cr); - } - spin_unlock(&sess->cr_a_lock); - - spin_lock(&sess->cr_i_lock); - list_for_each_entry_safe(cr, cr_tmp, &sess->cr_inactive_list, cr_list) { - list_del(&cr->cr_list); - spin_unlock(&sess->cr_i_lock); - - spin_lock(&cr->conn_recovery_cmd_lock); - list_for_each_entry_safe(cmd, cmd_tmp, - &cr->conn_recovery_cmd_list, i_list) { - - list_del(&cmd->i_list); - cmd->conn = NULL; - spin_unlock(&cr->conn_recovery_cmd_lock); - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 1); - spin_lock(&cr->conn_recovery_cmd_lock); - } - spin_unlock(&cr->conn_recovery_cmd_lock); - spin_lock(&sess->cr_i_lock); - - kfree(cr); - } - spin_unlock(&sess->cr_i_lock); -} - -int iscsit_remove_active_connection_recovery_entry( - struct iscsi_conn_recovery *cr, - struct iscsi_session *sess) -{ - spin_lock(&sess->cr_a_lock); - list_del(&cr->cr_list); - - sess->conn_recovery_count--; - pr_debug("Decremented connection recovery count to %u for" - " SID: %u\n", sess->conn_recovery_count, sess->sid); - spin_unlock(&sess->cr_a_lock); - - kfree(cr); - - return 0; -} - -int iscsit_remove_inactive_connection_recovery_entry( - struct iscsi_conn_recovery *cr, - struct iscsi_session *sess) -{ - spin_lock(&sess->cr_i_lock); - list_del(&cr->cr_list); - spin_unlock(&sess->cr_i_lock); - - return 0; -} - -/* - * Called with cr->conn_recovery_cmd_lock help. - */ -int iscsit_remove_cmd_from_connection_recovery( - struct iscsi_cmd *cmd, - struct iscsi_session *sess) -{ - struct iscsi_conn_recovery *cr; - - if (!cmd->cr) { - pr_err("struct iscsi_conn_recovery pointer for ITT: 0x%08x" - " is NULL!\n", cmd->init_task_tag); - BUG(); - } - cr = cmd->cr; - - list_del(&cmd->i_list); - return --cr->cmd_count; -} - -void iscsit_discard_cr_cmds_by_expstatsn( - struct iscsi_conn_recovery *cr, - u32 exp_statsn) -{ - u32 dropped_count = 0; - struct iscsi_cmd *cmd, *cmd_tmp; - struct iscsi_session *sess = cr->sess; - - spin_lock(&cr->conn_recovery_cmd_lock); - list_for_each_entry_safe(cmd, cmd_tmp, - &cr->conn_recovery_cmd_list, i_list) { - - if (((cmd->deferred_i_state != ISTATE_SENT_STATUS) && - (cmd->deferred_i_state != ISTATE_REMOVE)) || - (cmd->stat_sn >= exp_statsn)) { - continue; - } - - dropped_count++; - pr_debug("Dropping Acknowledged ITT: 0x%08x, StatSN:" - " 0x%08x, CID: %hu.\n", cmd->init_task_tag, - cmd->stat_sn, cr->cid); - - iscsit_remove_cmd_from_connection_recovery(cmd, sess); - - spin_unlock(&cr->conn_recovery_cmd_lock); - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 0); - spin_lock(&cr->conn_recovery_cmd_lock); - } - spin_unlock(&cr->conn_recovery_cmd_lock); - - pr_debug("Dropped %u total acknowledged commands on" - " CID: %hu less than old ExpStatSN: 0x%08x\n", - dropped_count, cr->cid, exp_statsn); - - if (!cr->cmd_count) { - pr_debug("No commands to be reassigned for failed" - " connection CID: %hu on SID: %u\n", - cr->cid, sess->sid); - iscsit_remove_inactive_connection_recovery_entry(cr, sess); - iscsit_attach_active_connection_recovery_entry(sess, cr); - pr_debug("iSCSI connection recovery successful for CID:" - " %hu on SID: %u\n", cr->cid, sess->sid); - iscsit_remove_active_connection_recovery_entry(cr, sess); - } else { - iscsit_remove_inactive_connection_recovery_entry(cr, sess); - iscsit_attach_active_connection_recovery_entry(sess, cr); - } -} - -int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *conn) -{ - u32 dropped_count = 0; - struct iscsi_cmd *cmd, *cmd_tmp; - struct iscsi_ooo_cmdsn *ooo_cmdsn, *ooo_cmdsn_tmp; - struct iscsi_session *sess = conn->sess; - - mutex_lock(&sess->cmdsn_mutex); - list_for_each_entry_safe(ooo_cmdsn, ooo_cmdsn_tmp, - &sess->sess_ooo_cmdsn_list, ooo_list) { - - if (ooo_cmdsn->cid != conn->cid) - continue; - - dropped_count++; - pr_debug("Dropping unacknowledged CmdSN:" - " 0x%08x during connection recovery on CID: %hu\n", - ooo_cmdsn->cmdsn, conn->cid); - iscsit_remove_ooo_cmdsn(sess, ooo_cmdsn); - } - mutex_unlock(&sess->cmdsn_mutex); - - spin_lock_bh(&conn->cmd_lock); - list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) { - if (!(cmd->cmd_flags & ICF_OOO_CMDSN)) - continue; - - list_del(&cmd->i_list); - - spin_unlock_bh(&conn->cmd_lock); - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 1); - spin_lock_bh(&conn->cmd_lock); - } - spin_unlock_bh(&conn->cmd_lock); - - pr_debug("Dropped %u total unacknowledged commands on CID:" - " %hu for ExpCmdSN: 0x%08x.\n", dropped_count, conn->cid, - sess->exp_cmd_sn); - return 0; -} - -int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *conn) -{ - u32 cmd_count = 0; - struct iscsi_cmd *cmd, *cmd_tmp; - struct iscsi_conn_recovery *cr; - - /* - * Allocate an struct iscsi_conn_recovery for this connection. - * Each struct iscsi_cmd contains an struct iscsi_conn_recovery pointer - * (struct iscsi_cmd->cr) so we need to allocate this before preparing the - * connection's command list for connection recovery. - */ - cr = kzalloc(sizeof(struct iscsi_conn_recovery), GFP_KERNEL); - if (!cr) { - pr_err("Unable to allocate memory for" - " struct iscsi_conn_recovery.\n"); - return -1; - } - INIT_LIST_HEAD(&cr->cr_list); - INIT_LIST_HEAD(&cr->conn_recovery_cmd_list); - spin_lock_init(&cr->conn_recovery_cmd_lock); - /* - * Only perform connection recovery on ISCSI_OP_SCSI_CMD or - * ISCSI_OP_NOOP_OUT opcodes. For all other opcodes call - * list_del(&cmd->i_list); to release the command to the - * session pool and remove it from the connection's list. - * - * Also stop the DataOUT timer, which will be restarted after - * sending the TMR response. - */ - spin_lock_bh(&conn->cmd_lock); - list_for_each_entry_safe(cmd, cmd_tmp, &conn->conn_cmd_list, i_list) { - - if ((cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD) && - (cmd->iscsi_opcode != ISCSI_OP_NOOP_OUT)) { - pr_debug("Not performing realligence on" - " Opcode: 0x%02x, ITT: 0x%08x, CmdSN: 0x%08x," - " CID: %hu\n", cmd->iscsi_opcode, - cmd->init_task_tag, cmd->cmd_sn, conn->cid); - - list_del(&cmd->i_list); - spin_unlock_bh(&conn->cmd_lock); - - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 0); - spin_lock_bh(&conn->cmd_lock); - continue; - } - - /* - * Special case where commands greater than or equal to - * the session's ExpCmdSN are attached to the connection - * list but not to the out of order CmdSN list. The one - * obvious case is when a command with immediate data - * attached must only check the CmdSN against ExpCmdSN - * after the data is received. The special case below - * is when the connection fails before data is received, - * but also may apply to other PDUs, so it has been - * made generic here. - */ - if (!(cmd->cmd_flags & ICF_OOO_CMDSN) && !cmd->immediate_cmd && - (cmd->cmd_sn >= conn->sess->exp_cmd_sn)) { - list_del(&cmd->i_list); - spin_unlock_bh(&conn->cmd_lock); - - if (!(cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) || - !(cmd->se_cmd.transport_wait_for_tasks)) - iscsit_release_cmd(cmd); - else - cmd->se_cmd.transport_wait_for_tasks( - &cmd->se_cmd, 1, 1); - spin_lock_bh(&conn->cmd_lock); - continue; - } - - cmd_count++; - pr_debug("Preparing Opcode: 0x%02x, ITT: 0x%08x," - " CmdSN: 0x%08x, StatSN: 0x%08x, CID: %hu for" - " realligence.\n", cmd->iscsi_opcode, - cmd->init_task_tag, cmd->cmd_sn, cmd->stat_sn, - conn->cid); - - cmd->deferred_i_state = cmd->i_state; - cmd->i_state = ISTATE_IN_CONNECTION_RECOVERY; - - if (cmd->data_direction == DMA_TO_DEVICE) - iscsit_stop_dataout_timer(cmd); - - cmd->sess = conn->sess; - - list_del(&cmd->i_list); - spin_unlock_bh(&conn->cmd_lock); - - iscsit_free_all_datain_reqs(cmd); - - if ((cmd->se_cmd.se_cmd_flags & SCF_SE_LUN_CMD) && - cmd->se_cmd.transport_wait_for_tasks) - cmd->se_cmd.transport_wait_for_tasks(&cmd->se_cmd, - 0, 0); - /* - * Add the struct iscsi_cmd to the connection recovery cmd list - */ - spin_lock(&cr->conn_recovery_cmd_lock); - list_add_tail(&cmd->i_list, &cr->conn_recovery_cmd_list); - spin_unlock(&cr->conn_recovery_cmd_lock); - - spin_lock_bh(&conn->cmd_lock); - cmd->cr = cr; - cmd->conn = NULL; - } - spin_unlock_bh(&conn->cmd_lock); - /* - * Fill in the various values in the preallocated struct iscsi_conn_recovery. - */ - cr->cid = conn->cid; - cr->cmd_count = cmd_count; - cr->maxrecvdatasegmentlength = conn->conn_ops->MaxRecvDataSegmentLength; - cr->sess = conn->sess; - - iscsit_attach_inactive_connection_recovery_entry(conn->sess, cr); - - return 0; -} - -int iscsit_connection_recovery_transport_reset(struct iscsi_conn *conn) -{ - atomic_set(&conn->connection_recovery, 1); - - if (iscsit_close_connection(conn) < 0) - return -1; - - return 0; -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_erl2.h b/trunk/drivers/target/iscsi/iscsi_target_erl2.h deleted file mode 100644 index 22f8d24780a6..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_erl2.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef ISCSI_TARGET_ERL2_H -#define ISCSI_TARGET_ERL2_H - -extern void iscsit_create_conn_recovery_datain_values(struct iscsi_cmd *, u32); -extern void iscsit_create_conn_recovery_dataout_values(struct iscsi_cmd *); -extern struct iscsi_conn_recovery *iscsit_get_inactive_connection_recovery_entry( - struct iscsi_session *, u16); -extern void iscsit_free_connection_recovery_entires(struct iscsi_session *); -extern int iscsit_remove_active_connection_recovery_entry( - struct iscsi_conn_recovery *, struct iscsi_session *); -extern int iscsit_remove_cmd_from_connection_recovery(struct iscsi_cmd *, - struct iscsi_session *); -extern void iscsit_discard_cr_cmds_by_expstatsn(struct iscsi_conn_recovery *, u32); -extern int iscsit_discard_unacknowledged_ooo_cmdsns_for_conn(struct iscsi_conn *); -extern int iscsit_prepare_cmds_for_realligance(struct iscsi_conn *); -extern int iscsit_connection_recovery_transport_reset(struct iscsi_conn *); - -#endif /*** ISCSI_TARGET_ERL2_H ***/ diff --git a/trunk/drivers/target/iscsi/iscsi_target_login.c b/trunk/drivers/target/iscsi/iscsi_target_login.c deleted file mode 100644 index bcaf82f47037..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_login.c +++ /dev/null @@ -1,1232 +0,0 @@ -/******************************************************************************* - * This file contains the login functions used by the iSCSI Target driver. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_tq.h" -#include "iscsi_target_device.h" -#include "iscsi_target_nego.h" -#include "iscsi_target_erl0.h" -#include "iscsi_target_erl2.h" -#include "iscsi_target_login.h" -#include "iscsi_target_stat.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_util.h" -#include "iscsi_target.h" -#include "iscsi_target_parameters.h" - -extern struct idr sess_idr; -extern struct mutex auth_id_lock; -extern spinlock_t sess_idr_lock; - -static int iscsi_login_init_conn(struct iscsi_conn *conn) -{ - INIT_LIST_HEAD(&conn->conn_list); - INIT_LIST_HEAD(&conn->conn_cmd_list); - INIT_LIST_HEAD(&conn->immed_queue_list); - INIT_LIST_HEAD(&conn->response_queue_list); - init_completion(&conn->conn_post_wait_comp); - init_completion(&conn->conn_wait_comp); - init_completion(&conn->conn_wait_rcfr_comp); - init_completion(&conn->conn_waiting_on_uc_comp); - init_completion(&conn->conn_logout_comp); - init_completion(&conn->rx_half_close_comp); - init_completion(&conn->tx_half_close_comp); - spin_lock_init(&conn->cmd_lock); - spin_lock_init(&conn->conn_usage_lock); - spin_lock_init(&conn->immed_queue_lock); - spin_lock_init(&conn->nopin_timer_lock); - spin_lock_init(&conn->response_queue_lock); - spin_lock_init(&conn->state_lock); - - if (!zalloc_cpumask_var(&conn->conn_cpumask, GFP_KERNEL)) { - pr_err("Unable to allocate conn->conn_cpumask\n"); - return -ENOMEM; - } - - return 0; -} - -/* - * Used by iscsi_target_nego.c:iscsi_target_locate_portal() to setup - * per struct iscsi_conn libcrypto contexts for crc32c and crc32-intel - */ -int iscsi_login_setup_crypto(struct iscsi_conn *conn) -{ - /* - * Setup slicing by CRC32C algorithm for RX and TX libcrypto contexts - * which will default to crc32c_intel.ko for cpu_has_xmm4_2, or fallback - * to software 1x8 byte slicing from crc32c.ko - */ - conn->conn_rx_hash.flags = 0; - conn->conn_rx_hash.tfm = crypto_alloc_hash("crc32c", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(conn->conn_rx_hash.tfm)) { - pr_err("crypto_alloc_hash() failed for conn_rx_tfm\n"); - return -ENOMEM; - } - - conn->conn_tx_hash.flags = 0; - conn->conn_tx_hash.tfm = crypto_alloc_hash("crc32c", 0, - CRYPTO_ALG_ASYNC); - if (IS_ERR(conn->conn_tx_hash.tfm)) { - pr_err("crypto_alloc_hash() failed for conn_tx_tfm\n"); - crypto_free_hash(conn->conn_rx_hash.tfm); - return -ENOMEM; - } - - return 0; -} - -static int iscsi_login_check_initiator_version( - struct iscsi_conn *conn, - u8 version_max, - u8 version_min) -{ - if ((version_max != 0x00) || (version_min != 0x00)) { - pr_err("Unsupported iSCSI IETF Pre-RFC Revision," - " version Min/Max 0x%02x/0x%02x, rejecting login.\n", - version_min, version_max); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_NO_VERSION); - return -1; - } - - return 0; -} - -int iscsi_check_for_session_reinstatement(struct iscsi_conn *conn) -{ - int sessiontype; - struct iscsi_param *initiatorname_param = NULL, *sessiontype_param = NULL; - struct iscsi_portal_group *tpg = conn->tpg; - struct iscsi_session *sess = NULL, *sess_p = NULL; - struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; - struct se_session *se_sess, *se_sess_tmp; - - initiatorname_param = iscsi_find_param_from_key( - INITIATORNAME, conn->param_list); - if (!initiatorname_param) - return -1; - - sessiontype_param = iscsi_find_param_from_key( - SESSIONTYPE, conn->param_list); - if (!sessiontype_param) - return -1; - - sessiontype = (strncmp(sessiontype_param->value, NORMAL, 6)) ? 1 : 0; - - spin_lock_bh(&se_tpg->session_lock); - list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list, - sess_list) { - - sess_p = (struct iscsi_session *)se_sess->fabric_sess_ptr; - spin_lock(&sess_p->conn_lock); - if (atomic_read(&sess_p->session_fall_back_to_erl0) || - atomic_read(&sess_p->session_logout) || - (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED)) { - spin_unlock(&sess_p->conn_lock); - continue; - } - if (!memcmp((void *)sess_p->isid, (void *)conn->sess->isid, 6) && - (!strcmp((void *)sess_p->sess_ops->InitiatorName, - (void *)initiatorname_param->value) && - (sess_p->sess_ops->SessionType == sessiontype))) { - atomic_set(&sess_p->session_reinstatement, 1); - spin_unlock(&sess_p->conn_lock); - iscsit_inc_session_usage_count(sess_p); - iscsit_stop_time2retain_timer(sess_p); - sess = sess_p; - break; - } - spin_unlock(&sess_p->conn_lock); - } - spin_unlock_bh(&se_tpg->session_lock); - /* - * If the Time2Retain handler has expired, the session is already gone. - */ - if (!sess) - return 0; - - pr_debug("%s iSCSI Session SID %u is still active for %s," - " preforming session reinstatement.\n", (sessiontype) ? - "Discovery" : "Normal", sess->sid, - sess->sess_ops->InitiatorName); - - spin_lock_bh(&sess->conn_lock); - if (sess->session_state == TARG_SESS_STATE_FAILED) { - spin_unlock_bh(&sess->conn_lock); - iscsit_dec_session_usage_count(sess); - return iscsit_close_session(sess); - } - spin_unlock_bh(&sess->conn_lock); - - iscsit_stop_session(sess, 1, 1); - iscsit_dec_session_usage_count(sess); - - return iscsit_close_session(sess); -} - -static void iscsi_login_set_conn_values( - struct iscsi_session *sess, - struct iscsi_conn *conn, - u16 cid) -{ - conn->sess = sess; - conn->cid = cid; - /* - * Generate a random Status sequence number (statsn) for the new - * iSCSI connection. - */ - get_random_bytes(&conn->stat_sn, sizeof(u32)); - - mutex_lock(&auth_id_lock); - conn->auth_id = iscsit_global->auth_id++; - mutex_unlock(&auth_id_lock); -} - -/* - * This is the leading connection of a new session, - * or session reinstatement. - */ -static int iscsi_login_zero_tsih_s1( - struct iscsi_conn *conn, - unsigned char *buf) -{ - struct iscsi_session *sess = NULL; - struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; - - sess = kzalloc(sizeof(struct iscsi_session), GFP_KERNEL); - if (!sess) { - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - pr_err("Could not allocate memory for session\n"); - return -1; - } - - iscsi_login_set_conn_values(sess, conn, pdu->cid); - sess->init_task_tag = pdu->itt; - memcpy((void *)&sess->isid, (void *)pdu->isid, 6); - sess->exp_cmd_sn = pdu->cmdsn; - INIT_LIST_HEAD(&sess->sess_conn_list); - INIT_LIST_HEAD(&sess->sess_ooo_cmdsn_list); - INIT_LIST_HEAD(&sess->cr_active_list); - INIT_LIST_HEAD(&sess->cr_inactive_list); - init_completion(&sess->async_msg_comp); - init_completion(&sess->reinstatement_comp); - init_completion(&sess->session_wait_comp); - init_completion(&sess->session_waiting_on_uc_comp); - mutex_init(&sess->cmdsn_mutex); - spin_lock_init(&sess->conn_lock); - spin_lock_init(&sess->cr_a_lock); - spin_lock_init(&sess->cr_i_lock); - spin_lock_init(&sess->session_usage_lock); - spin_lock_init(&sess->ttt_lock); - - if (!idr_pre_get(&sess_idr, GFP_KERNEL)) { - pr_err("idr_pre_get() for sess_idr failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - spin_lock(&sess_idr_lock); - idr_get_new(&sess_idr, NULL, &sess->session_index); - spin_unlock(&sess_idr_lock); - - sess->creation_time = get_jiffies_64(); - spin_lock_init(&sess->session_stats_lock); - /* - * The FFP CmdSN window values will be allocated from the TPG's - * Initiator Node's ACL once the login has been successfully completed. - */ - sess->max_cmd_sn = pdu->cmdsn; - - sess->sess_ops = kzalloc(sizeof(struct iscsi_sess_ops), GFP_KERNEL); - if (!sess->sess_ops) { - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - pr_err("Unable to allocate memory for" - " struct iscsi_sess_ops.\n"); - return -1; - } - - sess->se_sess = transport_init_session(); - if (!sess->se_sess) { - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - - return 0; -} - -static int iscsi_login_zero_tsih_s2( - struct iscsi_conn *conn) -{ - struct iscsi_node_attrib *na; - struct iscsi_session *sess = conn->sess; - unsigned char buf[32]; - - sess->tpg = conn->tpg; - - /* - * Assign a new TPG Session Handle. Note this is protected with - * struct iscsi_portal_group->np_login_sem from iscsit_access_np(). - */ - sess->tsih = ++ISCSI_TPG_S(sess)->ntsih; - if (!sess->tsih) - sess->tsih = ++ISCSI_TPG_S(sess)->ntsih; - - /* - * Create the default params from user defined values.. - */ - if (iscsi_copy_param_list(&conn->param_list, - ISCSI_TPG_C(conn)->param_list, 1) < 0) { - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - - iscsi_set_keys_to_negotiate(0, conn->param_list); - - if (sess->sess_ops->SessionType) - return iscsi_set_keys_irrelevant_for_discovery( - conn->param_list); - - na = iscsit_tpg_get_node_attrib(sess); - - /* - * Need to send TargetPortalGroupTag back in first login response - * on any iSCSI connection where the Initiator provides TargetName. - * See 5.3.1. Login Phase Start - * - * In our case, we have already located the struct iscsi_tiqn at this point. - */ - memset(buf, 0, 32); - sprintf(buf, "TargetPortalGroupTag=%hu", ISCSI_TPG_S(sess)->tpgt); - if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) { - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - - /* - * Workaround for Initiators that have broken connection recovery logic. - * - * "We would really like to get rid of this." Linux-iSCSI.org team - */ - memset(buf, 0, 32); - sprintf(buf, "ErrorRecoveryLevel=%d", na->default_erl); - if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) { - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - - if (iscsi_login_disable_FIM_keys(conn->param_list, conn) < 0) - return -1; - - return 0; -} - -/* - * Remove PSTATE_NEGOTIATE for the four FIM related keys. - * The Initiator node will be able to enable FIM by proposing them itself. - */ -int iscsi_login_disable_FIM_keys( - struct iscsi_param_list *param_list, - struct iscsi_conn *conn) -{ - struct iscsi_param *param; - - param = iscsi_find_param_from_key("OFMarker", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " OFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - param = iscsi_find_param_from_key("OFMarkInt", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " IFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - param = iscsi_find_param_from_key("IFMarker", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " IFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - param = iscsi_find_param_from_key("IFMarkInt", param_list); - if (!param) { - pr_err("iscsi_find_param_from_key() for" - " IFMarker failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - param->state &= ~PSTATE_NEGOTIATE; - - return 0; -} - -static int iscsi_login_non_zero_tsih_s1( - struct iscsi_conn *conn, - unsigned char *buf) -{ - struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; - - iscsi_login_set_conn_values(NULL, conn, pdu->cid); - return 0; -} - -/* - * Add a new connection to an existing session. - */ -static int iscsi_login_non_zero_tsih_s2( - struct iscsi_conn *conn, - unsigned char *buf) -{ - struct iscsi_portal_group *tpg = conn->tpg; - struct iscsi_session *sess = NULL, *sess_p = NULL; - struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; - struct se_session *se_sess, *se_sess_tmp; - struct iscsi_login_req *pdu = (struct iscsi_login_req *)buf; - - spin_lock_bh(&se_tpg->session_lock); - list_for_each_entry_safe(se_sess, se_sess_tmp, &se_tpg->tpg_sess_list, - sess_list) { - - sess_p = (struct iscsi_session *)se_sess->fabric_sess_ptr; - if (atomic_read(&sess_p->session_fall_back_to_erl0) || - atomic_read(&sess_p->session_logout) || - (sess_p->time2retain_timer_flags & ISCSI_TF_EXPIRED)) - continue; - if (!memcmp((const void *)sess_p->isid, - (const void *)pdu->isid, 6) && - (sess_p->tsih == pdu->tsih)) { - iscsit_inc_session_usage_count(sess_p); - iscsit_stop_time2retain_timer(sess_p); - sess = sess_p; - break; - } - } - spin_unlock_bh(&se_tpg->session_lock); - - /* - * If the Time2Retain handler has expired, the session is already gone. - */ - if (!sess) { - pr_err("Initiator attempting to add a connection to" - " a non-existent session, rejecting iSCSI Login.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_NO_SESSION); - return -1; - } - - /* - * Stop the Time2Retain timer if this is a failed session, we restart - * the timer if the login is not successful. - */ - spin_lock_bh(&sess->conn_lock); - if (sess->session_state == TARG_SESS_STATE_FAILED) - atomic_set(&sess->session_continuation, 1); - spin_unlock_bh(&sess->conn_lock); - - iscsi_login_set_conn_values(sess, conn, pdu->cid); - - if (iscsi_copy_param_list(&conn->param_list, - ISCSI_TPG_C(conn)->param_list, 0) < 0) { - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - - iscsi_set_keys_to_negotiate(0, conn->param_list); - /* - * Need to send TargetPortalGroupTag back in first login response - * on any iSCSI connection where the Initiator provides TargetName. - * See 5.3.1. Login Phase Start - * - * In our case, we have already located the struct iscsi_tiqn at this point. - */ - memset(buf, 0, 32); - sprintf(buf, "TargetPortalGroupTag=%hu", ISCSI_TPG_S(sess)->tpgt); - if (iscsi_change_param_value(buf, conn->param_list, 0) < 0) { - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - return -1; - } - - return iscsi_login_disable_FIM_keys(conn->param_list, conn); -} - -int iscsi_login_post_auth_non_zero_tsih( - struct iscsi_conn *conn, - u16 cid, - u32 exp_statsn) -{ - struct iscsi_conn *conn_ptr = NULL; - struct iscsi_conn_recovery *cr = NULL; - struct iscsi_session *sess = conn->sess; - - /* - * By following item 5 in the login table, if we have found - * an existing ISID and a valid/existing TSIH and an existing - * CID we do connection reinstatement. Currently we dont not - * support it so we send back an non-zero status class to the - * initiator and release the new connection. - */ - conn_ptr = iscsit_get_conn_from_cid_rcfr(sess, cid); - if ((conn_ptr)) { - pr_err("Connection exists with CID %hu for %s," - " performing connection reinstatement.\n", - conn_ptr->cid, sess->sess_ops->InitiatorName); - - iscsit_connection_reinstatement_rcfr(conn_ptr); - iscsit_dec_conn_usage_count(conn_ptr); - } - - /* - * Check for any connection recovery entires containing CID. - * We use the original ExpStatSN sent in the first login request - * to acknowledge commands for the failed connection. - * - * Also note that an explict logout may have already been sent, - * but the response may not be sent due to additional connection - * loss. - */ - if (sess->sess_ops->ErrorRecoveryLevel == 2) { - cr = iscsit_get_inactive_connection_recovery_entry( - sess, cid); - if ((cr)) { - pr_debug("Performing implicit logout" - " for connection recovery on CID: %hu\n", - conn->cid); - iscsit_discard_cr_cmds_by_expstatsn(cr, exp_statsn); - } - } - - /* - * Else we follow item 4 from the login table in that we have - * found an existing ISID and a valid/existing TSIH and a new - * CID we go ahead and continue to add a new connection to the - * session. - */ - pr_debug("Adding CID %hu to existing session for %s.\n", - cid, sess->sess_ops->InitiatorName); - - if ((atomic_read(&sess->nconn) + 1) > sess->sess_ops->MaxConnections) { - pr_err("Adding additional connection to this session" - " would exceed MaxConnections %d, login failed.\n", - sess->sess_ops->MaxConnections); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_ISID_ERROR); - return -1; - } - - return 0; -} - -static void iscsi_post_login_start_timers(struct iscsi_conn *conn) -{ - struct iscsi_session *sess = conn->sess; - - if (!sess->sess_ops->SessionType) - iscsit_start_nopin_timer(conn); -} - -static int iscsi_post_login_handler( - struct iscsi_np *np, - struct iscsi_conn *conn, - u8 zero_tsih) -{ - int stop_timer = 0; - struct iscsi_session *sess = conn->sess; - struct se_session *se_sess = sess->se_sess; - struct iscsi_portal_group *tpg = ISCSI_TPG_S(sess); - struct se_portal_group *se_tpg = &tpg->tpg_se_tpg; - struct iscsi_thread_set *ts; - - iscsit_inc_conn_usage_count(conn); - - iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_SUCCESS, - ISCSI_LOGIN_STATUS_ACCEPT); - - pr_debug("Moving to TARG_CONN_STATE_LOGGED_IN.\n"); - conn->conn_state = TARG_CONN_STATE_LOGGED_IN; - - iscsi_set_connection_parameters(conn->conn_ops, conn->param_list); - iscsit_set_sync_and_steering_values(conn); - /* - * SCSI Initiator -> SCSI Target Port Mapping - */ - ts = iscsi_get_thread_set(); - if (!zero_tsih) { - iscsi_set_session_parameters(sess->sess_ops, - conn->param_list, 0); - iscsi_release_param_list(conn->param_list); - conn->param_list = NULL; - - spin_lock_bh(&sess->conn_lock); - atomic_set(&sess->session_continuation, 0); - if (sess->session_state == TARG_SESS_STATE_FAILED) { - pr_debug("Moving to" - " TARG_SESS_STATE_LOGGED_IN.\n"); - sess->session_state = TARG_SESS_STATE_LOGGED_IN; - stop_timer = 1; - } - - pr_debug("iSCSI Login successful on CID: %hu from %s to" - " %s:%hu,%hu\n", conn->cid, conn->login_ip, np->np_ip, - np->np_port, tpg->tpgt); - - list_add_tail(&conn->conn_list, &sess->sess_conn_list); - atomic_inc(&sess->nconn); - pr_debug("Incremented iSCSI Connection count to %hu" - " from node: %s\n", atomic_read(&sess->nconn), - sess->sess_ops->InitiatorName); - spin_unlock_bh(&sess->conn_lock); - - iscsi_post_login_start_timers(conn); - iscsi_activate_thread_set(conn, ts); - /* - * Determine CPU mask to ensure connection's RX and TX kthreads - * are scheduled on the same CPU. - */ - iscsit_thread_get_cpumask(conn); - conn->conn_rx_reset_cpumask = 1; - conn->conn_tx_reset_cpumask = 1; - - iscsit_dec_conn_usage_count(conn); - if (stop_timer) { - spin_lock_bh(&se_tpg->session_lock); - iscsit_stop_time2retain_timer(sess); - spin_unlock_bh(&se_tpg->session_lock); - } - iscsit_dec_session_usage_count(sess); - return 0; - } - - iscsi_set_session_parameters(sess->sess_ops, conn->param_list, 1); - iscsi_release_param_list(conn->param_list); - conn->param_list = NULL; - - iscsit_determine_maxcmdsn(sess); - - spin_lock_bh(&se_tpg->session_lock); - __transport_register_session(&sess->tpg->tpg_se_tpg, - se_sess->se_node_acl, se_sess, (void *)sess); - pr_debug("Moving to TARG_SESS_STATE_LOGGED_IN.\n"); - sess->session_state = TARG_SESS_STATE_LOGGED_IN; - - pr_debug("iSCSI Login successful on CID: %hu from %s to %s:%hu,%hu\n", - conn->cid, conn->login_ip, np->np_ip, np->np_port, tpg->tpgt); - - spin_lock_bh(&sess->conn_lock); - list_add_tail(&conn->conn_list, &sess->sess_conn_list); - atomic_inc(&sess->nconn); - pr_debug("Incremented iSCSI Connection count to %hu from node:" - " %s\n", atomic_read(&sess->nconn), - sess->sess_ops->InitiatorName); - spin_unlock_bh(&sess->conn_lock); - - sess->sid = tpg->sid++; - if (!sess->sid) - sess->sid = tpg->sid++; - pr_debug("Established iSCSI session from node: %s\n", - sess->sess_ops->InitiatorName); - - tpg->nsessions++; - if (tpg->tpg_tiqn) - tpg->tpg_tiqn->tiqn_nsessions++; - - pr_debug("Incremented number of active iSCSI sessions to %u on" - " iSCSI Target Portal Group: %hu\n", tpg->nsessions, tpg->tpgt); - spin_unlock_bh(&se_tpg->session_lock); - - iscsi_post_login_start_timers(conn); - iscsi_activate_thread_set(conn, ts); - /* - * Determine CPU mask to ensure connection's RX and TX kthreads - * are scheduled on the same CPU. - */ - iscsit_thread_get_cpumask(conn); - conn->conn_rx_reset_cpumask = 1; - conn->conn_tx_reset_cpumask = 1; - - iscsit_dec_conn_usage_count(conn); - - return 0; -} - -static void iscsi_handle_login_thread_timeout(unsigned long data) -{ - struct iscsi_np *np = (struct iscsi_np *) data; - - spin_lock_bh(&np->np_thread_lock); - pr_err("iSCSI Login timeout on Network Portal %s:%hu\n", - np->np_ip, np->np_port); - - if (np->np_login_timer_flags & ISCSI_TF_STOP) { - spin_unlock_bh(&np->np_thread_lock); - return; - } - - if (np->np_thread) - send_sig(SIGINT, np->np_thread, 1); - - np->np_login_timer_flags &= ~ISCSI_TF_RUNNING; - spin_unlock_bh(&np->np_thread_lock); -} - -static void iscsi_start_login_thread_timer(struct iscsi_np *np) -{ - /* - * This used the TA_LOGIN_TIMEOUT constant because at this - * point we do not have access to ISCSI_TPG_ATTRIB(tpg)->login_timeout - */ - spin_lock_bh(&np->np_thread_lock); - init_timer(&np->np_login_timer); - np->np_login_timer.expires = (get_jiffies_64() + TA_LOGIN_TIMEOUT * HZ); - np->np_login_timer.data = (unsigned long)np; - np->np_login_timer.function = iscsi_handle_login_thread_timeout; - np->np_login_timer_flags &= ~ISCSI_TF_STOP; - np->np_login_timer_flags |= ISCSI_TF_RUNNING; - add_timer(&np->np_login_timer); - - pr_debug("Added timeout timer to iSCSI login request for" - " %u seconds.\n", TA_LOGIN_TIMEOUT); - spin_unlock_bh(&np->np_thread_lock); -} - -static void iscsi_stop_login_thread_timer(struct iscsi_np *np) -{ - spin_lock_bh(&np->np_thread_lock); - if (!(np->np_login_timer_flags & ISCSI_TF_RUNNING)) { - spin_unlock_bh(&np->np_thread_lock); - return; - } - np->np_login_timer_flags |= ISCSI_TF_STOP; - spin_unlock_bh(&np->np_thread_lock); - - del_timer_sync(&np->np_login_timer); - - spin_lock_bh(&np->np_thread_lock); - np->np_login_timer_flags &= ~ISCSI_TF_RUNNING; - spin_unlock_bh(&np->np_thread_lock); -} - -int iscsi_target_setup_login_socket( - struct iscsi_np *np, - struct __kernel_sockaddr_storage *sockaddr) -{ - struct socket *sock; - int backlog = 5, ret, opt = 0, len; - - switch (np->np_network_transport) { - case ISCSI_TCP: - np->np_ip_proto = IPPROTO_TCP; - np->np_sock_type = SOCK_STREAM; - break; - case ISCSI_SCTP_TCP: - np->np_ip_proto = IPPROTO_SCTP; - np->np_sock_type = SOCK_STREAM; - break; - case ISCSI_SCTP_UDP: - np->np_ip_proto = IPPROTO_SCTP; - np->np_sock_type = SOCK_SEQPACKET; - break; - case ISCSI_IWARP_TCP: - case ISCSI_IWARP_SCTP: - case ISCSI_INFINIBAND: - default: - pr_err("Unsupported network_transport: %d\n", - np->np_network_transport); - return -EINVAL; - } - - ret = sock_create(sockaddr->ss_family, np->np_sock_type, - np->np_ip_proto, &sock); - if (ret < 0) { - pr_err("sock_create() failed.\n"); - return ret; - } - np->np_socket = sock; - /* - * The SCTP stack needs struct socket->file. - */ - if ((np->np_network_transport == ISCSI_SCTP_TCP) || - (np->np_network_transport == ISCSI_SCTP_UDP)) { - if (!sock->file) { - sock->file = kzalloc(sizeof(struct file), GFP_KERNEL); - if (!sock->file) { - pr_err("Unable to allocate struct" - " file for SCTP\n"); - ret = -ENOMEM; - goto fail; - } - np->np_flags |= NPF_SCTP_STRUCT_FILE; - } - } - /* - * Setup the np->np_sockaddr from the passed sockaddr setup - * in iscsi_target_configfs.c code.. - */ - memcpy((void *)&np->np_sockaddr, (void *)sockaddr, - sizeof(struct __kernel_sockaddr_storage)); - - if (sockaddr->ss_family == AF_INET6) - len = sizeof(struct sockaddr_in6); - else - len = sizeof(struct sockaddr_in); - /* - * Set SO_REUSEADDR, and disable Nagel Algorithm with TCP_NODELAY. - */ - opt = 1; - if (np->np_network_transport == ISCSI_TCP) { - ret = kernel_setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - (char *)&opt, sizeof(opt)); - if (ret < 0) { - pr_err("kernel_setsockopt() for TCP_NODELAY" - " failed: %d\n", ret); - goto fail; - } - } - - ret = kernel_setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (char *)&opt, sizeof(opt)); - if (ret < 0) { - pr_err("kernel_setsockopt() for SO_REUSEADDR" - " failed\n"); - goto fail; - } - - ret = kernel_bind(sock, (struct sockaddr *)&np->np_sockaddr, len); - if (ret < 0) { - pr_err("kernel_bind() failed: %d\n", ret); - goto fail; - } - - ret = kernel_listen(sock, backlog); - if (ret != 0) { - pr_err("kernel_listen() failed: %d\n", ret); - goto fail; - } - - return 0; - -fail: - np->np_socket = NULL; - if (sock) { - if (np->np_flags & NPF_SCTP_STRUCT_FILE) { - kfree(sock->file); - sock->file = NULL; - } - - sock_release(sock); - } - return ret; -} - -static int __iscsi_target_login_thread(struct iscsi_np *np) -{ - u8 buffer[ISCSI_HDR_LEN], iscsi_opcode, zero_tsih = 0; - int err, ret = 0, ip_proto, sock_type, set_sctp_conn_flag, stop; - struct iscsi_conn *conn = NULL; - struct iscsi_login *login; - struct iscsi_portal_group *tpg = NULL; - struct socket *new_sock, *sock; - struct kvec iov; - struct iscsi_login_req *pdu; - struct sockaddr_in sock_in; - struct sockaddr_in6 sock_in6; - - flush_signals(current); - set_sctp_conn_flag = 0; - sock = np->np_socket; - ip_proto = np->np_ip_proto; - sock_type = np->np_sock_type; - - spin_lock_bh(&np->np_thread_lock); - if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { - np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; - complete(&np->np_restart_comp); - } else { - np->np_thread_state = ISCSI_NP_THREAD_ACTIVE; - } - spin_unlock_bh(&np->np_thread_lock); - - if (kernel_accept(sock, &new_sock, 0) < 0) { - spin_lock_bh(&np->np_thread_lock); - if (np->np_thread_state == ISCSI_NP_THREAD_RESET) { - spin_unlock_bh(&np->np_thread_lock); - complete(&np->np_restart_comp); - /* Get another socket */ - return 1; - } - spin_unlock_bh(&np->np_thread_lock); - goto out; - } - /* - * The SCTP stack needs struct socket->file. - */ - if ((np->np_network_transport == ISCSI_SCTP_TCP) || - (np->np_network_transport == ISCSI_SCTP_UDP)) { - if (!new_sock->file) { - new_sock->file = kzalloc( - sizeof(struct file), GFP_KERNEL); - if (!new_sock->file) { - pr_err("Unable to allocate struct" - " file for SCTP\n"); - sock_release(new_sock); - /* Get another socket */ - return 1; - } - set_sctp_conn_flag = 1; - } - } - - iscsi_start_login_thread_timer(np); - - conn = kzalloc(sizeof(struct iscsi_conn), GFP_KERNEL); - if (!conn) { - pr_err("Could not allocate memory for" - " new connection\n"); - if (set_sctp_conn_flag) { - kfree(new_sock->file); - new_sock->file = NULL; - } - sock_release(new_sock); - /* Get another socket */ - return 1; - } - - pr_debug("Moving to TARG_CONN_STATE_FREE.\n"); - conn->conn_state = TARG_CONN_STATE_FREE; - conn->sock = new_sock; - - if (set_sctp_conn_flag) - conn->conn_flags |= CONNFLAG_SCTP_STRUCT_FILE; - - pr_debug("Moving to TARG_CONN_STATE_XPT_UP.\n"); - conn->conn_state = TARG_CONN_STATE_XPT_UP; - - /* - * Allocate conn->conn_ops early as a failure calling - * iscsit_tx_login_rsp() below will call tx_data(). - */ - conn->conn_ops = kzalloc(sizeof(struct iscsi_conn_ops), GFP_KERNEL); - if (!conn->conn_ops) { - pr_err("Unable to allocate memory for" - " struct iscsi_conn_ops.\n"); - goto new_sess_out; - } - /* - * Perform the remaining iSCSI connection initialization items.. - */ - if (iscsi_login_init_conn(conn) < 0) - goto new_sess_out; - - memset(buffer, 0, ISCSI_HDR_LEN); - memset(&iov, 0, sizeof(struct kvec)); - iov.iov_base = buffer; - iov.iov_len = ISCSI_HDR_LEN; - - if (rx_data(conn, &iov, 1, ISCSI_HDR_LEN) <= 0) { - pr_err("rx_data() returned an error.\n"); - goto new_sess_out; - } - - iscsi_opcode = (buffer[0] & ISCSI_OPCODE_MASK); - if (!(iscsi_opcode & ISCSI_OP_LOGIN)) { - pr_err("First opcode is not login request," - " failing login request.\n"); - goto new_sess_out; - } - - pdu = (struct iscsi_login_req *) buffer; - pdu->cid = be16_to_cpu(pdu->cid); - pdu->tsih = be16_to_cpu(pdu->tsih); - pdu->itt = be32_to_cpu(pdu->itt); - pdu->cmdsn = be32_to_cpu(pdu->cmdsn); - pdu->exp_statsn = be32_to_cpu(pdu->exp_statsn); - /* - * Used by iscsit_tx_login_rsp() for Login Resonses PDUs - * when Status-Class != 0. - */ - conn->login_itt = pdu->itt; - - spin_lock_bh(&np->np_thread_lock); - if (np->np_thread_state != ISCSI_NP_THREAD_ACTIVE) { - spin_unlock_bh(&np->np_thread_lock); - pr_err("iSCSI Network Portal on %s:%hu currently not" - " active.\n", np->np_ip, np->np_port); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); - goto new_sess_out; - } - spin_unlock_bh(&np->np_thread_lock); - - if (np->np_sockaddr.ss_family == AF_INET6) { - memset(&sock_in6, 0, sizeof(struct sockaddr_in6)); - - if (conn->sock->ops->getname(conn->sock, - (struct sockaddr *)&sock_in6, &err, 1) < 0) { - pr_err("sock_ops->getname() failed.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_TARGET_ERROR); - goto new_sess_out; - } -#if 0 - if (!iscsi_ntop6((const unsigned char *) - &sock_in6.sin6_addr.in6_u, - (char *)&conn->ipv6_login_ip[0], - IPV6_ADDRESS_SPACE)) { - pr_err("iscsi_ntop6() failed\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_TARGET_ERROR); - goto new_sess_out; - } -#else - pr_debug("Skipping iscsi_ntop6()\n"); -#endif - } else { - memset(&sock_in, 0, sizeof(struct sockaddr_in)); - - if (conn->sock->ops->getname(conn->sock, - (struct sockaddr *)&sock_in, &err, 1) < 0) { - pr_err("sock_ops->getname() failed.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_TARGET_ERROR); - goto new_sess_out; - } - sprintf(conn->login_ip, "%pI4", &sock_in.sin_addr.s_addr); - conn->login_port = ntohs(sock_in.sin_port); - } - - conn->network_transport = np->np_network_transport; - - pr_debug("Received iSCSI login request from %s on %s Network" - " Portal %s:%hu\n", conn->login_ip, - (conn->network_transport == ISCSI_TCP) ? "TCP" : "SCTP", - np->np_ip, np->np_port); - - pr_debug("Moving to TARG_CONN_STATE_IN_LOGIN.\n"); - conn->conn_state = TARG_CONN_STATE_IN_LOGIN; - - if (iscsi_login_check_initiator_version(conn, pdu->max_version, - pdu->min_version) < 0) - goto new_sess_out; - - zero_tsih = (pdu->tsih == 0x0000); - if ((zero_tsih)) { - /* - * This is the leading connection of a new session. - * We wait until after authentication to check for - * session reinstatement. - */ - if (iscsi_login_zero_tsih_s1(conn, buffer) < 0) - goto new_sess_out; - } else { - /* - * Add a new connection to an existing session. - * We check for a non-existant session in - * iscsi_login_non_zero_tsih_s2() below based - * on ISID/TSIH, but wait until after authentication - * to check for connection reinstatement, etc. - */ - if (iscsi_login_non_zero_tsih_s1(conn, buffer) < 0) - goto new_sess_out; - } - - /* - * This will process the first login request, and call - * iscsi_target_locate_portal(), and return a valid struct iscsi_login. - */ - login = iscsi_target_init_negotiation(np, conn, buffer); - if (!login) { - tpg = conn->tpg; - goto new_sess_out; - } - - tpg = conn->tpg; - if (!tpg) { - pr_err("Unable to locate struct iscsi_conn->tpg\n"); - goto new_sess_out; - } - - if (zero_tsih) { - if (iscsi_login_zero_tsih_s2(conn) < 0) { - iscsi_target_nego_release(login, conn); - goto new_sess_out; - } - } else { - if (iscsi_login_non_zero_tsih_s2(conn, buffer) < 0) { - iscsi_target_nego_release(login, conn); - goto old_sess_out; - } - } - - if (iscsi_target_start_negotiation(login, conn) < 0) - goto new_sess_out; - - if (!conn->sess) { - pr_err("struct iscsi_conn session pointer is NULL!\n"); - goto new_sess_out; - } - - iscsi_stop_login_thread_timer(np); - - if (signal_pending(current)) - goto new_sess_out; - - ret = iscsi_post_login_handler(np, conn, zero_tsih); - - if (ret < 0) - goto new_sess_out; - - iscsit_deaccess_np(np, tpg); - tpg = NULL; - /* Get another socket */ - return 1; - -new_sess_out: - pr_err("iSCSI Login negotiation failed.\n"); - iscsit_collect_login_stats(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_INIT_ERR); - if (!zero_tsih || !conn->sess) - goto old_sess_out; - if (conn->sess->se_sess) - transport_free_session(conn->sess->se_sess); - if (conn->sess->session_index != 0) { - spin_lock_bh(&sess_idr_lock); - idr_remove(&sess_idr, conn->sess->session_index); - spin_unlock_bh(&sess_idr_lock); - } - if (conn->sess->sess_ops) - kfree(conn->sess->sess_ops); - if (conn->sess) - kfree(conn->sess); -old_sess_out: - iscsi_stop_login_thread_timer(np); - /* - * If login negotiation fails check if the Time2Retain timer - * needs to be restarted. - */ - if (!zero_tsih && conn->sess) { - spin_lock_bh(&conn->sess->conn_lock); - if (conn->sess->session_state == TARG_SESS_STATE_FAILED) { - struct se_portal_group *se_tpg = - &ISCSI_TPG_C(conn)->tpg_se_tpg; - - atomic_set(&conn->sess->session_continuation, 0); - spin_unlock_bh(&conn->sess->conn_lock); - spin_lock_bh(&se_tpg->session_lock); - iscsit_start_time2retain_handler(conn->sess); - spin_unlock_bh(&se_tpg->session_lock); - } else - spin_unlock_bh(&conn->sess->conn_lock); - iscsit_dec_session_usage_count(conn->sess); - } - - if (!IS_ERR(conn->conn_rx_hash.tfm)) - crypto_free_hash(conn->conn_rx_hash.tfm); - if (!IS_ERR(conn->conn_tx_hash.tfm)) - crypto_free_hash(conn->conn_tx_hash.tfm); - - if (conn->conn_cpumask) - free_cpumask_var(conn->conn_cpumask); - - kfree(conn->conn_ops); - - if (conn->param_list) { - iscsi_release_param_list(conn->param_list); - conn->param_list = NULL; - } - if (conn->sock) { - if (conn->conn_flags & CONNFLAG_SCTP_STRUCT_FILE) { - kfree(conn->sock->file); - conn->sock->file = NULL; - } - sock_release(conn->sock); - } - kfree(conn); - - if (tpg) { - iscsit_deaccess_np(np, tpg); - tpg = NULL; - } - -out: - stop = kthread_should_stop(); - if (!stop && signal_pending(current)) { - spin_lock_bh(&np->np_thread_lock); - stop = (np->np_thread_state == ISCSI_NP_THREAD_SHUTDOWN); - spin_unlock_bh(&np->np_thread_lock); - } - /* Wait for another socket.. */ - if (!stop) - return 1; - - iscsi_stop_login_thread_timer(np); - spin_lock_bh(&np->np_thread_lock); - np->np_thread_state = ISCSI_NP_THREAD_EXIT; - spin_unlock_bh(&np->np_thread_lock); - return 0; -} - -int iscsi_target_login_thread(void *arg) -{ - struct iscsi_np *np = (struct iscsi_np *)arg; - int ret; - - allow_signal(SIGINT); - - while (!kthread_should_stop()) { - ret = __iscsi_target_login_thread(np); - /* - * We break and exit here unless another sock_accept() call - * is expected. - */ - if (ret != 1) - break; - } - - return 0; -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_login.h b/trunk/drivers/target/iscsi/iscsi_target_login.h deleted file mode 100644 index 091dcae2532b..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_login.h +++ /dev/null @@ -1,12 +0,0 @@ -#ifndef ISCSI_TARGET_LOGIN_H -#define ISCSI_TARGET_LOGIN_H - -extern int iscsi_login_setup_crypto(struct iscsi_conn *); -extern int iscsi_check_for_session_reinstatement(struct iscsi_conn *); -extern int iscsi_login_post_auth_non_zero_tsih(struct iscsi_conn *, u16, u32); -extern int iscsi_target_setup_login_socket(struct iscsi_np *, - struct __kernel_sockaddr_storage *); -extern int iscsi_target_login_thread(void *); -extern int iscsi_login_disable_FIM_keys(struct iscsi_param_list *, struct iscsi_conn *); - -#endif /*** ISCSI_TARGET_LOGIN_H ***/ diff --git a/trunk/drivers/target/iscsi/iscsi_target_nego.c b/trunk/drivers/target/iscsi/iscsi_target_nego.c deleted file mode 100644 index 713a4d23557a..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_nego.c +++ /dev/null @@ -1,1067 +0,0 @@ -/******************************************************************************* - * This file contains main functions related to iSCSI Parameter negotiation. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_parameters.h" -#include "iscsi_target_login.h" -#include "iscsi_target_nego.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_util.h" -#include "iscsi_target.h" -#include "iscsi_target_auth.h" - -#define MAX_LOGIN_PDUS 7 -#define TEXT_LEN 4096 - -void convert_null_to_semi(char *buf, int len) -{ - int i; - - for (i = 0; i < len; i++) - if (buf[i] == '\0') - buf[i] = ';'; -} - -int strlen_semi(char *buf) -{ - int i = 0; - - while (buf[i] != '\0') { - if (buf[i] == ';') - return i; - i++; - } - - return -1; -} - -int extract_param( - const char *in_buf, - const char *pattern, - unsigned int max_length, - char *out_buf, - unsigned char *type) -{ - char *ptr; - int len; - - if (!in_buf || !pattern || !out_buf || !type) - return -1; - - ptr = strstr(in_buf, pattern); - if (!ptr) - return -1; - - ptr = strstr(ptr, "="); - if (!ptr) - return -1; - - ptr += 1; - if (*ptr == '0' && (*(ptr+1) == 'x' || *(ptr+1) == 'X')) { - ptr += 2; /* skip 0x */ - *type = HEX; - } else - *type = DECIMAL; - - len = strlen_semi(ptr); - if (len < 0) - return -1; - - if (len > max_length) { - pr_err("Length of input: %d exeeds max_length:" - " %d\n", len, max_length); - return -1; - } - memcpy(out_buf, ptr, len); - out_buf[len] = '\0'; - - return 0; -} - -static u32 iscsi_handle_authentication( - struct iscsi_conn *conn, - char *in_buf, - char *out_buf, - int in_length, - int *out_length, - unsigned char *authtype) -{ - struct iscsi_session *sess = conn->sess; - struct iscsi_node_auth *auth; - struct iscsi_node_acl *iscsi_nacl; - struct se_node_acl *se_nacl; - - if (!sess->sess_ops->SessionType) { - /* - * For SessionType=Normal - */ - se_nacl = conn->sess->se_sess->se_node_acl; - if (!se_nacl) { - pr_err("Unable to locate struct se_node_acl for" - " CHAP auth\n"); - return -1; - } - iscsi_nacl = container_of(se_nacl, struct iscsi_node_acl, - se_node_acl); - if (!iscsi_nacl) { - pr_err("Unable to locate struct iscsi_node_acl for" - " CHAP auth\n"); - return -1; - } - - auth = ISCSI_NODE_AUTH(iscsi_nacl); - } else { - /* - * For SessionType=Discovery - */ - auth = &iscsit_global->discovery_acl.node_auth; - } - - if (strstr("CHAP", authtype)) - strcpy(conn->sess->auth_type, "CHAP"); - else - strcpy(conn->sess->auth_type, NONE); - - if (strstr("None", authtype)) - return 1; -#ifdef CANSRP - else if (strstr("SRP", authtype)) - return srp_main_loop(conn, auth, in_buf, out_buf, - &in_length, out_length); -#endif - else if (strstr("CHAP", authtype)) - return chap_main_loop(conn, auth, in_buf, out_buf, - &in_length, out_length); - else if (strstr("SPKM1", authtype)) - return 2; - else if (strstr("SPKM2", authtype)) - return 2; - else if (strstr("KRB5", authtype)) - return 2; - else - return 2; -} - -static void iscsi_remove_failed_auth_entry(struct iscsi_conn *conn) -{ - kfree(conn->auth_protocol); -} - -static int iscsi_target_check_login_request( - struct iscsi_conn *conn, - struct iscsi_login *login) -{ - int req_csg, req_nsg, rsp_csg, rsp_nsg; - u32 payload_length; - struct iscsi_login_req *login_req; - struct iscsi_login_rsp *login_rsp; - - login_req = (struct iscsi_login_req *) login->req; - login_rsp = (struct iscsi_login_rsp *) login->rsp; - payload_length = ntoh24(login_req->dlength); - - switch (login_req->opcode & ISCSI_OPCODE_MASK) { - case ISCSI_OP_LOGIN: - break; - default: - pr_err("Received unknown opcode 0x%02x.\n", - login_req->opcode & ISCSI_OPCODE_MASK); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_INIT_ERR); - return -1; - } - - if ((login_req->flags & ISCSI_FLAG_LOGIN_CONTINUE) && - (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { - pr_err("Login request has both ISCSI_FLAG_LOGIN_CONTINUE" - " and ISCSI_FLAG_LOGIN_TRANSIT set, protocol error.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_INIT_ERR); - return -1; - } - - req_csg = (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2; - rsp_csg = (login_rsp->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2; - req_nsg = (login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK); - rsp_nsg = (login_rsp->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK); - - if (req_csg != login->current_stage) { - pr_err("Initiator unexpectedly changed login stage" - " from %d to %d, login failed.\n", login->current_stage, - req_csg); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_INIT_ERR); - return -1; - } - - if ((req_nsg == 2) || (req_csg >= 2) || - ((login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT) && - (req_nsg <= req_csg))) { - pr_err("Illegal login_req->flags Combination, CSG: %d," - " NSG: %d, ISCSI_FLAG_LOGIN_TRANSIT: %d.\n", req_csg, - req_nsg, (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_INIT_ERR); - return -1; - } - - if ((login_req->max_version != login->version_max) || - (login_req->min_version != login->version_min)) { - pr_err("Login request changed Version Max/Nin" - " unexpectedly to 0x%02x/0x%02x, protocol error\n", - login_req->max_version, login_req->min_version); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_INIT_ERR); - return -1; - } - - if (memcmp(login_req->isid, login->isid, 6) != 0) { - pr_err("Login request changed ISID unexpectedly," - " protocol error.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_INIT_ERR); - return -1; - } - - if (login_req->itt != login->init_task_tag) { - pr_err("Login request changed ITT unexpectedly to" - " 0x%08x, protocol error.\n", login_req->itt); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_INIT_ERR); - return -1; - } - - if (payload_length > MAX_KEY_VALUE_PAIRS) { - pr_err("Login request payload exceeds default" - " MaxRecvDataSegmentLength: %u, protocol error.\n", - MAX_KEY_VALUE_PAIRS); - return -1; - } - - return 0; -} - -static int iscsi_target_check_first_request( - struct iscsi_conn *conn, - struct iscsi_login *login) -{ - struct iscsi_param *param = NULL; - struct se_node_acl *se_nacl; - - login->first_request = 0; - - list_for_each_entry(param, &conn->param_list->param_list, p_list) { - if (!strncmp(param->name, SESSIONTYPE, 11)) { - if (!IS_PSTATE_ACCEPTOR(param)) { - pr_err("SessionType key not received" - " in first login request.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_MISSING_FIELDS); - return -1; - } - if (!strncmp(param->value, DISCOVERY, 9)) - return 0; - } - - if (!strncmp(param->name, INITIATORNAME, 13)) { - if (!IS_PSTATE_ACCEPTOR(param)) { - if (!login->leading_connection) - continue; - - pr_err("InitiatorName key not received" - " in first login request.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_MISSING_FIELDS); - return -1; - } - - /* - * For non-leading connections, double check that the - * received InitiatorName matches the existing session's - * struct iscsi_node_acl. - */ - if (!login->leading_connection) { - se_nacl = conn->sess->se_sess->se_node_acl; - if (!se_nacl) { - pr_err("Unable to locate" - " struct se_node_acl\n"); - iscsit_tx_login_rsp(conn, - ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_TGT_NOT_FOUND); - return -1; - } - - if (strcmp(param->value, - se_nacl->initiatorname)) { - pr_err("Incorrect" - " InitiatorName: %s for this" - " iSCSI Initiator Node.\n", - param->value); - iscsit_tx_login_rsp(conn, - ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_TGT_NOT_FOUND); - return -1; - } - } - } - } - - return 0; -} - -static int iscsi_target_do_tx_login_io(struct iscsi_conn *conn, struct iscsi_login *login) -{ - u32 padding = 0; - struct iscsi_session *sess = conn->sess; - struct iscsi_login_rsp *login_rsp; - - login_rsp = (struct iscsi_login_rsp *) login->rsp; - - login_rsp->opcode = ISCSI_OP_LOGIN_RSP; - hton24(login_rsp->dlength, login->rsp_length); - memcpy(login_rsp->isid, login->isid, 6); - login_rsp->tsih = cpu_to_be16(login->tsih); - login_rsp->itt = cpu_to_be32(login->init_task_tag); - login_rsp->statsn = cpu_to_be32(conn->stat_sn++); - login_rsp->exp_cmdsn = cpu_to_be32(conn->sess->exp_cmd_sn); - login_rsp->max_cmdsn = cpu_to_be32(conn->sess->max_cmd_sn); - - pr_debug("Sending Login Response, Flags: 0x%02x, ITT: 0x%08x," - " ExpCmdSN; 0x%08x, MaxCmdSN: 0x%08x, StatSN: 0x%08x, Length:" - " %u\n", login_rsp->flags, ntohl(login_rsp->itt), - ntohl(login_rsp->exp_cmdsn), ntohl(login_rsp->max_cmdsn), - ntohl(login_rsp->statsn), login->rsp_length); - - padding = ((-login->rsp_length) & 3); - - if (iscsi_login_tx_data( - conn, - login->rsp, - login->rsp_buf, - login->rsp_length + padding) < 0) - return -1; - - login->rsp_length = 0; - login_rsp->tsih = be16_to_cpu(login_rsp->tsih); - login_rsp->itt = be32_to_cpu(login_rsp->itt); - login_rsp->statsn = be32_to_cpu(login_rsp->statsn); - mutex_lock(&sess->cmdsn_mutex); - login_rsp->exp_cmdsn = be32_to_cpu(sess->exp_cmd_sn); - login_rsp->max_cmdsn = be32_to_cpu(sess->max_cmd_sn); - mutex_unlock(&sess->cmdsn_mutex); - - return 0; -} - -static int iscsi_target_do_rx_login_io(struct iscsi_conn *conn, struct iscsi_login *login) -{ - u32 padding = 0, payload_length; - struct iscsi_login_req *login_req; - - if (iscsi_login_rx_data(conn, login->req, ISCSI_HDR_LEN) < 0) - return -1; - - login_req = (struct iscsi_login_req *) login->req; - payload_length = ntoh24(login_req->dlength); - login_req->tsih = be16_to_cpu(login_req->tsih); - login_req->itt = be32_to_cpu(login_req->itt); - login_req->cid = be16_to_cpu(login_req->cid); - login_req->cmdsn = be32_to_cpu(login_req->cmdsn); - login_req->exp_statsn = be32_to_cpu(login_req->exp_statsn); - - pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x," - " CmdSN: 0x%08x, ExpStatSN: 0x%08x, CID: %hu, Length: %u\n", - login_req->flags, login_req->itt, login_req->cmdsn, - login_req->exp_statsn, login_req->cid, payload_length); - - if (iscsi_target_check_login_request(conn, login) < 0) - return -1; - - padding = ((-payload_length) & 3); - memset(login->req_buf, 0, MAX_KEY_VALUE_PAIRS); - - if (iscsi_login_rx_data( - conn, - login->req_buf, - payload_length + padding) < 0) - return -1; - - return 0; -} - -static int iscsi_target_do_login_io(struct iscsi_conn *conn, struct iscsi_login *login) -{ - if (iscsi_target_do_tx_login_io(conn, login) < 0) - return -1; - - if (iscsi_target_do_rx_login_io(conn, login) < 0) - return -1; - - return 0; -} - -static int iscsi_target_get_initial_payload( - struct iscsi_conn *conn, - struct iscsi_login *login) -{ - u32 padding = 0, payload_length; - struct iscsi_login_req *login_req; - - login_req = (struct iscsi_login_req *) login->req; - payload_length = ntoh24(login_req->dlength); - - pr_debug("Got Login Command, Flags 0x%02x, ITT: 0x%08x," - " CmdSN: 0x%08x, ExpStatSN: 0x%08x, Length: %u\n", - login_req->flags, login_req->itt, login_req->cmdsn, - login_req->exp_statsn, payload_length); - - if (iscsi_target_check_login_request(conn, login) < 0) - return -1; - - padding = ((-payload_length) & 3); - - if (iscsi_login_rx_data( - conn, - login->req_buf, - payload_length + padding) < 0) - return -1; - - return 0; -} - -/* - * NOTE: We check for existing sessions or connections AFTER the initiator - * has been successfully authenticated in order to protect against faked - * ISID/TSIH combinations. - */ -static int iscsi_target_check_for_existing_instances( - struct iscsi_conn *conn, - struct iscsi_login *login) -{ - if (login->checked_for_existing) - return 0; - - login->checked_for_existing = 1; - - if (!login->tsih) - return iscsi_check_for_session_reinstatement(conn); - else - return iscsi_login_post_auth_non_zero_tsih(conn, login->cid, - login->initial_exp_statsn); -} - -static int iscsi_target_do_authentication( - struct iscsi_conn *conn, - struct iscsi_login *login) -{ - int authret; - u32 payload_length; - struct iscsi_param *param; - struct iscsi_login_req *login_req; - struct iscsi_login_rsp *login_rsp; - - login_req = (struct iscsi_login_req *) login->req; - login_rsp = (struct iscsi_login_rsp *) login->rsp; - payload_length = ntoh24(login_req->dlength); - - param = iscsi_find_param_from_key(AUTHMETHOD, conn->param_list); - if (!param) - return -1; - - authret = iscsi_handle_authentication( - conn, - login->req_buf, - login->rsp_buf, - payload_length, - &login->rsp_length, - param->value); - switch (authret) { - case 0: - pr_debug("Received OK response" - " from LIO Authentication, continuing.\n"); - break; - case 1: - pr_debug("iSCSI security negotiation" - " completed sucessfully.\n"); - login->auth_complete = 1; - if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) && - (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { - login_rsp->flags |= (ISCSI_FLAG_LOGIN_NEXT_STAGE1 | - ISCSI_FLAG_LOGIN_TRANSIT); - login->current_stage = 1; - } - return iscsi_target_check_for_existing_instances( - conn, login); - case 2: - pr_err("Security negotiation" - " failed.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_AUTH_FAILED); - return -1; - default: - pr_err("Received unknown error %d from LIO" - " Authentication\n", authret); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_TARGET_ERROR); - return -1; - } - - return 0; -} - -static int iscsi_target_handle_csg_zero( - struct iscsi_conn *conn, - struct iscsi_login *login) -{ - int ret; - u32 payload_length; - struct iscsi_param *param; - struct iscsi_login_req *login_req; - struct iscsi_login_rsp *login_rsp; - - login_req = (struct iscsi_login_req *) login->req; - login_rsp = (struct iscsi_login_rsp *) login->rsp; - payload_length = ntoh24(login_req->dlength); - - param = iscsi_find_param_from_key(AUTHMETHOD, conn->param_list); - if (!param) - return -1; - - ret = iscsi_decode_text_input( - PHASE_SECURITY|PHASE_DECLARATIVE, - SENDER_INITIATOR|SENDER_RECEIVER, - login->req_buf, - payload_length, - conn->param_list); - if (ret < 0) - return -1; - - if (ret > 0) { - if (login->auth_complete) { - pr_err("Initiator has already been" - " successfully authenticated, but is still" - " sending %s keys.\n", param->value); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_INIT_ERR); - return -1; - } - - goto do_auth; - } - - if (login->first_request) - if (iscsi_target_check_first_request(conn, login) < 0) - return -1; - - ret = iscsi_encode_text_output( - PHASE_SECURITY|PHASE_DECLARATIVE, - SENDER_TARGET, - login->rsp_buf, - &login->rsp_length, - conn->param_list); - if (ret < 0) - return -1; - - if (!iscsi_check_negotiated_keys(conn->param_list)) { - if (ISCSI_TPG_ATTRIB(ISCSI_TPG_C(conn))->authentication && - !strncmp(param->value, NONE, 4)) { - pr_err("Initiator sent AuthMethod=None but" - " Target is enforcing iSCSI Authentication," - " login failed.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_AUTH_FAILED); - return -1; - } - - if (ISCSI_TPG_ATTRIB(ISCSI_TPG_C(conn))->authentication && - !login->auth_complete) - return 0; - - if (strncmp(param->value, NONE, 4) && !login->auth_complete) - return 0; - - if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE1) && - (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) { - login_rsp->flags |= ISCSI_FLAG_LOGIN_NEXT_STAGE1 | - ISCSI_FLAG_LOGIN_TRANSIT; - login->current_stage = 1; - } - } - - return 0; -do_auth: - return iscsi_target_do_authentication(conn, login); -} - -static int iscsi_target_handle_csg_one(struct iscsi_conn *conn, struct iscsi_login *login) -{ - int ret; - u32 payload_length; - struct iscsi_login_req *login_req; - struct iscsi_login_rsp *login_rsp; - - login_req = (struct iscsi_login_req *) login->req; - login_rsp = (struct iscsi_login_rsp *) login->rsp; - payload_length = ntoh24(login_req->dlength); - - ret = iscsi_decode_text_input( - PHASE_OPERATIONAL|PHASE_DECLARATIVE, - SENDER_INITIATOR|SENDER_RECEIVER, - login->req_buf, - payload_length, - conn->param_list); - if (ret < 0) - return -1; - - if (login->first_request) - if (iscsi_target_check_first_request(conn, login) < 0) - return -1; - - if (iscsi_target_check_for_existing_instances(conn, login) < 0) - return -1; - - ret = iscsi_encode_text_output( - PHASE_OPERATIONAL|PHASE_DECLARATIVE, - SENDER_TARGET, - login->rsp_buf, - &login->rsp_length, - conn->param_list); - if (ret < 0) - return -1; - - if (!login->auth_complete && - ISCSI_TPG_ATTRIB(ISCSI_TPG_C(conn))->authentication) { - pr_err("Initiator is requesting CSG: 1, has not been" - " successfully authenticated, and the Target is" - " enforcing iSCSI Authentication, login failed.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_AUTH_FAILED); - return -1; - } - - if (!iscsi_check_negotiated_keys(conn->param_list)) - if ((login_req->flags & ISCSI_FLAG_LOGIN_NEXT_STAGE3) && - (login_req->flags & ISCSI_FLAG_LOGIN_TRANSIT)) - login_rsp->flags |= ISCSI_FLAG_LOGIN_NEXT_STAGE3 | - ISCSI_FLAG_LOGIN_TRANSIT; - - return 0; -} - -static int iscsi_target_do_login(struct iscsi_conn *conn, struct iscsi_login *login) -{ - int pdu_count = 0; - struct iscsi_login_req *login_req; - struct iscsi_login_rsp *login_rsp; - - login_req = (struct iscsi_login_req *) login->req; - login_rsp = (struct iscsi_login_rsp *) login->rsp; - - while (1) { - if (++pdu_count > MAX_LOGIN_PDUS) { - pr_err("MAX_LOGIN_PDUS count reached.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_TARGET_ERROR); - return -1; - } - - switch ((login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2) { - case 0: - login_rsp->flags |= (0 & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK); - if (iscsi_target_handle_csg_zero(conn, login) < 0) - return -1; - break; - case 1: - login_rsp->flags |= ISCSI_FLAG_LOGIN_CURRENT_STAGE1; - if (iscsi_target_handle_csg_one(conn, login) < 0) - return -1; - if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { - login->tsih = conn->sess->tsih; - if (iscsi_target_do_tx_login_io(conn, - login) < 0) - return -1; - return 0; - } - break; - default: - pr_err("Illegal CSG: %d received from" - " Initiator, protocol error.\n", - (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) - >> 2); - break; - } - - if (iscsi_target_do_login_io(conn, login) < 0) - return -1; - - if (login_rsp->flags & ISCSI_FLAG_LOGIN_TRANSIT) { - login_rsp->flags &= ~ISCSI_FLAG_LOGIN_TRANSIT; - login_rsp->flags &= ~ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK; - } - } - - return 0; -} - -static void iscsi_initiatorname_tolower( - char *param_buf) -{ - char *c; - u32 iqn_size = strlen(param_buf), i; - - for (i = 0; i < iqn_size; i++) { - c = (char *)¶m_buf[i]; - if (!isupper(*c)) - continue; - - *c = tolower(*c); - } -} - -/* - * Processes the first Login Request.. - */ -static int iscsi_target_locate_portal( - struct iscsi_np *np, - struct iscsi_conn *conn, - struct iscsi_login *login) -{ - char *i_buf = NULL, *s_buf = NULL, *t_buf = NULL; - char *tmpbuf, *start = NULL, *end = NULL, *key, *value; - struct iscsi_session *sess = conn->sess; - struct iscsi_tiqn *tiqn; - struct iscsi_login_req *login_req; - struct iscsi_targ_login_rsp *login_rsp; - u32 payload_length; - int sessiontype = 0, ret = 0; - - login_req = (struct iscsi_login_req *) login->req; - login_rsp = (struct iscsi_targ_login_rsp *) login->rsp; - payload_length = ntoh24(login_req->dlength); - - login->first_request = 1; - login->leading_connection = (!login_req->tsih) ? 1 : 0; - login->current_stage = - (login_req->flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2; - login->version_min = login_req->min_version; - login->version_max = login_req->max_version; - memcpy(login->isid, login_req->isid, 6); - login->cmd_sn = login_req->cmdsn; - login->init_task_tag = login_req->itt; - login->initial_exp_statsn = login_req->exp_statsn; - login->cid = login_req->cid; - login->tsih = login_req->tsih; - - if (iscsi_target_get_initial_payload(conn, login) < 0) - return -1; - - tmpbuf = kzalloc(payload_length + 1, GFP_KERNEL); - if (!tmpbuf) { - pr_err("Unable to allocate memory for tmpbuf.\n"); - return -1; - } - - memcpy(tmpbuf, login->req_buf, payload_length); - tmpbuf[payload_length] = '\0'; - start = tmpbuf; - end = (start + payload_length); - - /* - * Locate the initial keys expected from the Initiator node in - * the first login request in order to progress with the login phase. - */ - while (start < end) { - if (iscsi_extract_key_value(start, &key, &value) < 0) { - ret = -1; - goto out; - } - - if (!strncmp(key, "InitiatorName", 13)) - i_buf = value; - else if (!strncmp(key, "SessionType", 11)) - s_buf = value; - else if (!strncmp(key, "TargetName", 10)) - t_buf = value; - - start += strlen(key) + strlen(value) + 2; - } - - /* - * See 5.3. Login Phase. - */ - if (!i_buf) { - pr_err("InitiatorName key not received" - " in first login request.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_MISSING_FIELDS); - ret = -1; - goto out; - } - /* - * Convert the incoming InitiatorName to lowercase following - * RFC-3720 3.2.6.1. section c) that says that iSCSI IQNs - * are NOT case sensitive. - */ - iscsi_initiatorname_tolower(i_buf); - - if (!s_buf) { - if (!login->leading_connection) - goto get_target; - - pr_err("SessionType key not received" - " in first login request.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_MISSING_FIELDS); - ret = -1; - goto out; - } - - /* - * Use default portal group for discovery sessions. - */ - sessiontype = strncmp(s_buf, DISCOVERY, 9); - if (!sessiontype) { - conn->tpg = iscsit_global->discovery_tpg; - if (!login->leading_connection) - goto get_target; - - sess->sess_ops->SessionType = 1; - /* - * Setup crc32c modules from libcrypto - */ - if (iscsi_login_setup_crypto(conn) < 0) { - pr_err("iscsi_login_setup_crypto() failed\n"); - ret = -1; - goto out; - } - /* - * Serialize access across the discovery struct iscsi_portal_group to - * process login attempt. - */ - if (iscsit_access_np(np, conn->tpg) < 0) { - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); - ret = -1; - goto out; - } - ret = 0; - goto out; - } - -get_target: - if (!t_buf) { - pr_err("TargetName key not received" - " in first login request while" - " SessionType=Normal.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_MISSING_FIELDS); - ret = -1; - goto out; - } - - /* - * Locate Target IQN from Storage Node. - */ - tiqn = iscsit_get_tiqn_for_login(t_buf); - if (!tiqn) { - pr_err("Unable to locate Target IQN: %s in" - " Storage Node\n", t_buf); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); - ret = -1; - goto out; - } - pr_debug("Located Storage Object: %s\n", tiqn->tiqn); - - /* - * Locate Target Portal Group from Storage Node. - */ - conn->tpg = iscsit_get_tpg_from_np(tiqn, np); - if (!conn->tpg) { - pr_err("Unable to locate Target Portal Group" - " on %s\n", tiqn->tiqn); - iscsit_put_tiqn_for_login(tiqn); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); - ret = -1; - goto out; - } - pr_debug("Located Portal Group Object: %hu\n", conn->tpg->tpgt); - /* - * Setup crc32c modules from libcrypto - */ - if (iscsi_login_setup_crypto(conn) < 0) { - pr_err("iscsi_login_setup_crypto() failed\n"); - ret = -1; - goto out; - } - /* - * Serialize access across the struct iscsi_portal_group to - * process login attempt. - */ - if (iscsit_access_np(np, conn->tpg) < 0) { - iscsit_put_tiqn_for_login(tiqn); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE); - ret = -1; - conn->tpg = NULL; - goto out; - } - - /* - * conn->sess->node_acl will be set when the referenced - * struct iscsi_session is located from received ISID+TSIH in - * iscsi_login_non_zero_tsih_s2(). - */ - if (!login->leading_connection) { - ret = 0; - goto out; - } - - /* - * This value is required in iscsi_login_zero_tsih_s2() - */ - sess->sess_ops->SessionType = 0; - - /* - * Locate incoming Initiator IQN reference from Storage Node. - */ - sess->se_sess->se_node_acl = core_tpg_check_initiator_node_acl( - &conn->tpg->tpg_se_tpg, i_buf); - if (!sess->se_sess->se_node_acl) { - pr_err("iSCSI Initiator Node: %s is not authorized to" - " access iSCSI target portal group: %hu.\n", - i_buf, conn->tpg->tpgt); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR, - ISCSI_LOGIN_STATUS_TGT_FORBIDDEN); - ret = -1; - goto out; - } - - ret = 0; -out: - kfree(tmpbuf); - return ret; -} - -struct iscsi_login *iscsi_target_init_negotiation( - struct iscsi_np *np, - struct iscsi_conn *conn, - char *login_pdu) -{ - struct iscsi_login *login; - - login = kzalloc(sizeof(struct iscsi_login), GFP_KERNEL); - if (!login) { - pr_err("Unable to allocate memory for struct iscsi_login.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - goto out; - } - - login->req = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); - if (!login->req) { - pr_err("Unable to allocate memory for Login Request.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - goto out; - } - memcpy(login->req, login_pdu, ISCSI_HDR_LEN); - - login->req_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL); - if (!login->req_buf) { - pr_err("Unable to allocate memory for response buffer.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - goto out; - } - /* - * SessionType: Discovery - * - * Locates Default Portal - * - * SessionType: Normal - * - * Locates Target Portal from NP -> Target IQN - */ - if (iscsi_target_locate_portal(np, conn, login) < 0) { - pr_err("iSCSI Login negotiation failed.\n"); - goto out; - } - - return login; -out: - kfree(login->req); - kfree(login->req_buf); - kfree(login); - - return NULL; -} - -int iscsi_target_start_negotiation( - struct iscsi_login *login, - struct iscsi_conn *conn) -{ - int ret = -1; - - login->rsp = kzalloc(ISCSI_HDR_LEN, GFP_KERNEL); - if (!login->rsp) { - pr_err("Unable to allocate memory for" - " Login Response.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - ret = -1; - goto out; - } - - login->rsp_buf = kzalloc(MAX_KEY_VALUE_PAIRS, GFP_KERNEL); - if (!login->rsp_buf) { - pr_err("Unable to allocate memory for" - " request buffer.\n"); - iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR, - ISCSI_LOGIN_STATUS_NO_RESOURCES); - ret = -1; - goto out; - } - - ret = iscsi_target_do_login(conn, login); -out: - if (ret != 0) - iscsi_remove_failed_auth_entry(conn); - - iscsi_target_nego_release(login, conn); - return ret; -} - -void iscsi_target_nego_release( - struct iscsi_login *login, - struct iscsi_conn *conn) -{ - kfree(login->req); - kfree(login->rsp); - kfree(login->req_buf); - kfree(login->rsp_buf); - kfree(login); -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_nego.h b/trunk/drivers/target/iscsi/iscsi_target_nego.h deleted file mode 100644 index 92e133a5158f..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_nego.h +++ /dev/null @@ -1,17 +0,0 @@ -#ifndef ISCSI_TARGET_NEGO_H -#define ISCSI_TARGET_NEGO_H - -#define DECIMAL 0 -#define HEX 1 - -extern void convert_null_to_semi(char *, int); -extern int extract_param(const char *, const char *, unsigned int, char *, - unsigned char *); -extern struct iscsi_login *iscsi_target_init_negotiation( - struct iscsi_np *, struct iscsi_conn *, char *); -extern int iscsi_target_start_negotiation( - struct iscsi_login *, struct iscsi_conn *); -extern void iscsi_target_nego_release( - struct iscsi_login *, struct iscsi_conn *); - -#endif /* ISCSI_TARGET_NEGO_H */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_nodeattrib.c b/trunk/drivers/target/iscsi/iscsi_target_nodeattrib.c deleted file mode 100644 index aeafbe0cd7d1..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_nodeattrib.c +++ /dev/null @@ -1,263 +0,0 @@ -/******************************************************************************* - * This file contains the main functions related to Initiator Node Attributes. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_device.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_util.h" -#include "iscsi_target_nodeattrib.h" - -static inline char *iscsit_na_get_initiatorname( - struct iscsi_node_acl *nacl) -{ - struct se_node_acl *se_nacl = &nacl->se_node_acl; - - return &se_nacl->initiatorname[0]; -} - -void iscsit_set_default_node_attribues( - struct iscsi_node_acl *acl) -{ - struct iscsi_node_attrib *a = &acl->node_attrib; - - a->dataout_timeout = NA_DATAOUT_TIMEOUT; - a->dataout_timeout_retries = NA_DATAOUT_TIMEOUT_RETRIES; - a->nopin_timeout = NA_NOPIN_TIMEOUT; - a->nopin_response_timeout = NA_NOPIN_RESPONSE_TIMEOUT; - a->random_datain_pdu_offsets = NA_RANDOM_DATAIN_PDU_OFFSETS; - a->random_datain_seq_offsets = NA_RANDOM_DATAIN_SEQ_OFFSETS; - a->random_r2t_offsets = NA_RANDOM_R2T_OFFSETS; - a->default_erl = NA_DEFAULT_ERL; -} - -extern int iscsit_na_dataout_timeout( - struct iscsi_node_acl *acl, - u32 dataout_timeout) -{ - struct iscsi_node_attrib *a = &acl->node_attrib; - - if (dataout_timeout > NA_DATAOUT_TIMEOUT_MAX) { - pr_err("Requested DataOut Timeout %u larger than" - " maximum %u\n", dataout_timeout, - NA_DATAOUT_TIMEOUT_MAX); - return -EINVAL; - } else if (dataout_timeout < NA_DATAOUT_TIMEOUT_MIX) { - pr_err("Requested DataOut Timeout %u smaller than" - " minimum %u\n", dataout_timeout, - NA_DATAOUT_TIMEOUT_MIX); - return -EINVAL; - } - - a->dataout_timeout = dataout_timeout; - pr_debug("Set DataOut Timeout to %u for Initiator Node" - " %s\n", a->dataout_timeout, iscsit_na_get_initiatorname(acl)); - - return 0; -} - -extern int iscsit_na_dataout_timeout_retries( - struct iscsi_node_acl *acl, - u32 dataout_timeout_retries) -{ - struct iscsi_node_attrib *a = &acl->node_attrib; - - if (dataout_timeout_retries > NA_DATAOUT_TIMEOUT_RETRIES_MAX) { - pr_err("Requested DataOut Timeout Retries %u larger" - " than maximum %u", dataout_timeout_retries, - NA_DATAOUT_TIMEOUT_RETRIES_MAX); - return -EINVAL; - } else if (dataout_timeout_retries < NA_DATAOUT_TIMEOUT_RETRIES_MIN) { - pr_err("Requested DataOut Timeout Retries %u smaller" - " than minimum %u", dataout_timeout_retries, - NA_DATAOUT_TIMEOUT_RETRIES_MIN); - return -EINVAL; - } - - a->dataout_timeout_retries = dataout_timeout_retries; - pr_debug("Set DataOut Timeout Retries to %u for" - " Initiator Node %s\n", a->dataout_timeout_retries, - iscsit_na_get_initiatorname(acl)); - - return 0; -} - -extern int iscsit_na_nopin_timeout( - struct iscsi_node_acl *acl, - u32 nopin_timeout) -{ - struct iscsi_node_attrib *a = &acl->node_attrib; - struct iscsi_session *sess; - struct iscsi_conn *conn; - struct se_node_acl *se_nacl = &a->nacl->se_node_acl; - struct se_session *se_sess; - u32 orig_nopin_timeout = a->nopin_timeout; - - if (nopin_timeout > NA_NOPIN_TIMEOUT_MAX) { - pr_err("Requested NopIn Timeout %u larger than maximum" - " %u\n", nopin_timeout, NA_NOPIN_TIMEOUT_MAX); - return -EINVAL; - } else if ((nopin_timeout < NA_NOPIN_TIMEOUT_MIN) && - (nopin_timeout != 0)) { - pr_err("Requested NopIn Timeout %u smaller than" - " minimum %u and not 0\n", nopin_timeout, - NA_NOPIN_TIMEOUT_MIN); - return -EINVAL; - } - - a->nopin_timeout = nopin_timeout; - pr_debug("Set NopIn Timeout to %u for Initiator" - " Node %s\n", a->nopin_timeout, - iscsit_na_get_initiatorname(acl)); - /* - * Reenable disabled nopin_timeout timer for all iSCSI connections. - */ - if (!orig_nopin_timeout) { - spin_lock_bh(&se_nacl->nacl_sess_lock); - se_sess = se_nacl->nacl_sess; - if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - - spin_lock(&sess->conn_lock); - list_for_each_entry(conn, &sess->sess_conn_list, - conn_list) { - if (conn->conn_state != - TARG_CONN_STATE_LOGGED_IN) - continue; - - spin_lock(&conn->nopin_timer_lock); - __iscsit_start_nopin_timer(conn); - spin_unlock(&conn->nopin_timer_lock); - } - spin_unlock(&sess->conn_lock); - } - spin_unlock_bh(&se_nacl->nacl_sess_lock); - } - - return 0; -} - -extern int iscsit_na_nopin_response_timeout( - struct iscsi_node_acl *acl, - u32 nopin_response_timeout) -{ - struct iscsi_node_attrib *a = &acl->node_attrib; - - if (nopin_response_timeout > NA_NOPIN_RESPONSE_TIMEOUT_MAX) { - pr_err("Requested NopIn Response Timeout %u larger" - " than maximum %u\n", nopin_response_timeout, - NA_NOPIN_RESPONSE_TIMEOUT_MAX); - return -EINVAL; - } else if (nopin_response_timeout < NA_NOPIN_RESPONSE_TIMEOUT_MIN) { - pr_err("Requested NopIn Response Timeout %u smaller" - " than minimum %u\n", nopin_response_timeout, - NA_NOPIN_RESPONSE_TIMEOUT_MIN); - return -EINVAL; - } - - a->nopin_response_timeout = nopin_response_timeout; - pr_debug("Set NopIn Response Timeout to %u for" - " Initiator Node %s\n", a->nopin_timeout, - iscsit_na_get_initiatorname(acl)); - - return 0; -} - -extern int iscsit_na_random_datain_pdu_offsets( - struct iscsi_node_acl *acl, - u32 random_datain_pdu_offsets) -{ - struct iscsi_node_attrib *a = &acl->node_attrib; - - if (random_datain_pdu_offsets != 0 && random_datain_pdu_offsets != 1) { - pr_err("Requested Random DataIN PDU Offsets: %u not" - " 0 or 1\n", random_datain_pdu_offsets); - return -EINVAL; - } - - a->random_datain_pdu_offsets = random_datain_pdu_offsets; - pr_debug("Set Random DataIN PDU Offsets to %u for" - " Initiator Node %s\n", a->random_datain_pdu_offsets, - iscsit_na_get_initiatorname(acl)); - - return 0; -} - -extern int iscsit_na_random_datain_seq_offsets( - struct iscsi_node_acl *acl, - u32 random_datain_seq_offsets) -{ - struct iscsi_node_attrib *a = &acl->node_attrib; - - if (random_datain_seq_offsets != 0 && random_datain_seq_offsets != 1) { - pr_err("Requested Random DataIN Sequence Offsets: %u" - " not 0 or 1\n", random_datain_seq_offsets); - return -EINVAL; - } - - a->random_datain_seq_offsets = random_datain_seq_offsets; - pr_debug("Set Random DataIN Sequence Offsets to %u for" - " Initiator Node %s\n", a->random_datain_seq_offsets, - iscsit_na_get_initiatorname(acl)); - - return 0; -} - -extern int iscsit_na_random_r2t_offsets( - struct iscsi_node_acl *acl, - u32 random_r2t_offsets) -{ - struct iscsi_node_attrib *a = &acl->node_attrib; - - if (random_r2t_offsets != 0 && random_r2t_offsets != 1) { - pr_err("Requested Random R2T Offsets: %u not" - " 0 or 1\n", random_r2t_offsets); - return -EINVAL; - } - - a->random_r2t_offsets = random_r2t_offsets; - pr_debug("Set Random R2T Offsets to %u for" - " Initiator Node %s\n", a->random_r2t_offsets, - iscsit_na_get_initiatorname(acl)); - - return 0; -} - -extern int iscsit_na_default_erl( - struct iscsi_node_acl *acl, - u32 default_erl) -{ - struct iscsi_node_attrib *a = &acl->node_attrib; - - if (default_erl != 0 && default_erl != 1 && default_erl != 2) { - pr_err("Requested default ERL: %u not 0, 1, or 2\n", - default_erl); - return -EINVAL; - } - - a->default_erl = default_erl; - pr_debug("Set use ERL0 flag to %u for Initiator" - " Node %s\n", a->default_erl, - iscsit_na_get_initiatorname(acl)); - - return 0; -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_nodeattrib.h b/trunk/drivers/target/iscsi/iscsi_target_nodeattrib.h deleted file mode 100644 index c970b326ef23..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_nodeattrib.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef ISCSI_TARGET_NODEATTRIB_H -#define ISCSI_TARGET_NODEATTRIB_H - -extern void iscsit_set_default_node_attribues(struct iscsi_node_acl *); -extern int iscsit_na_dataout_timeout(struct iscsi_node_acl *, u32); -extern int iscsit_na_dataout_timeout_retries(struct iscsi_node_acl *, u32); -extern int iscsit_na_nopin_timeout(struct iscsi_node_acl *, u32); -extern int iscsit_na_nopin_response_timeout(struct iscsi_node_acl *, u32); -extern int iscsit_na_random_datain_pdu_offsets(struct iscsi_node_acl *, u32); -extern int iscsit_na_random_datain_seq_offsets(struct iscsi_node_acl *, u32); -extern int iscsit_na_random_r2t_offsets(struct iscsi_node_acl *, u32); -extern int iscsit_na_default_erl(struct iscsi_node_acl *, u32); - -#endif /* ISCSI_TARGET_NODEATTRIB_H */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_parameters.c b/trunk/drivers/target/iscsi/iscsi_target_parameters.c deleted file mode 100644 index 252e246cf51e..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_parameters.c +++ /dev/null @@ -1,1905 +0,0 @@ -/******************************************************************************* - * This file contains main functions related to iSCSI Parameter negotiation. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_util.h" -#include "iscsi_target_parameters.h" - -int iscsi_login_rx_data( - struct iscsi_conn *conn, - char *buf, - int length) -{ - int rx_got; - struct kvec iov; - - memset(&iov, 0, sizeof(struct kvec)); - iov.iov_len = length; - iov.iov_base = buf; - - /* - * Initial Marker-less Interval. - * Add the values regardless of IFMarker/OFMarker, considering - * it may not be negoitated yet. - */ - conn->of_marker += length; - - rx_got = rx_data(conn, &iov, 1, length); - if (rx_got != length) { - pr_err("rx_data returned %d, expecting %d.\n", - rx_got, length); - return -1; - } - - return 0 ; -} - -int iscsi_login_tx_data( - struct iscsi_conn *conn, - char *pdu_buf, - char *text_buf, - int text_length) -{ - int length, tx_sent; - struct kvec iov[2]; - - length = (ISCSI_HDR_LEN + text_length); - - memset(&iov[0], 0, 2 * sizeof(struct kvec)); - iov[0].iov_len = ISCSI_HDR_LEN; - iov[0].iov_base = pdu_buf; - iov[1].iov_len = text_length; - iov[1].iov_base = text_buf; - - /* - * Initial Marker-less Interval. - * Add the values regardless of IFMarker/OFMarker, considering - * it may not be negoitated yet. - */ - conn->if_marker += length; - - tx_sent = tx_data(conn, &iov[0], 2, length); - if (tx_sent != length) { - pr_err("tx_data returned %d, expecting %d.\n", - tx_sent, length); - return -1; - } - - return 0; -} - -void iscsi_dump_conn_ops(struct iscsi_conn_ops *conn_ops) -{ - pr_debug("HeaderDigest: %s\n", (conn_ops->HeaderDigest) ? - "CRC32C" : "None"); - pr_debug("DataDigest: %s\n", (conn_ops->DataDigest) ? - "CRC32C" : "None"); - pr_debug("MaxRecvDataSegmentLength: %u\n", - conn_ops->MaxRecvDataSegmentLength); - pr_debug("OFMarker: %s\n", (conn_ops->OFMarker) ? "Yes" : "No"); - pr_debug("IFMarker: %s\n", (conn_ops->IFMarker) ? "Yes" : "No"); - if (conn_ops->OFMarker) - pr_debug("OFMarkInt: %u\n", conn_ops->OFMarkInt); - if (conn_ops->IFMarker) - pr_debug("IFMarkInt: %u\n", conn_ops->IFMarkInt); -} - -void iscsi_dump_sess_ops(struct iscsi_sess_ops *sess_ops) -{ - pr_debug("InitiatorName: %s\n", sess_ops->InitiatorName); - pr_debug("InitiatorAlias: %s\n", sess_ops->InitiatorAlias); - pr_debug("TargetName: %s\n", sess_ops->TargetName); - pr_debug("TargetAlias: %s\n", sess_ops->TargetAlias); - pr_debug("TargetPortalGroupTag: %hu\n", - sess_ops->TargetPortalGroupTag); - pr_debug("MaxConnections: %hu\n", sess_ops->MaxConnections); - pr_debug("InitialR2T: %s\n", - (sess_ops->InitialR2T) ? "Yes" : "No"); - pr_debug("ImmediateData: %s\n", (sess_ops->ImmediateData) ? - "Yes" : "No"); - pr_debug("MaxBurstLength: %u\n", sess_ops->MaxBurstLength); - pr_debug("FirstBurstLength: %u\n", sess_ops->FirstBurstLength); - pr_debug("DefaultTime2Wait: %hu\n", sess_ops->DefaultTime2Wait); - pr_debug("DefaultTime2Retain: %hu\n", - sess_ops->DefaultTime2Retain); - pr_debug("MaxOutstandingR2T: %hu\n", - sess_ops->MaxOutstandingR2T); - pr_debug("DataPDUInOrder: %s\n", - (sess_ops->DataPDUInOrder) ? "Yes" : "No"); - pr_debug("DataSequenceInOrder: %s\n", - (sess_ops->DataSequenceInOrder) ? "Yes" : "No"); - pr_debug("ErrorRecoveryLevel: %hu\n", - sess_ops->ErrorRecoveryLevel); - pr_debug("SessionType: %s\n", (sess_ops->SessionType) ? - "Discovery" : "Normal"); -} - -void iscsi_print_params(struct iscsi_param_list *param_list) -{ - struct iscsi_param *param; - - list_for_each_entry(param, ¶m_list->param_list, p_list) - pr_debug("%s: %s\n", param->name, param->value); -} - -static struct iscsi_param *iscsi_set_default_param(struct iscsi_param_list *param_list, - char *name, char *value, u8 phase, u8 scope, u8 sender, - u16 type_range, u8 use) -{ - struct iscsi_param *param = NULL; - - param = kzalloc(sizeof(struct iscsi_param), GFP_KERNEL); - if (!param) { - pr_err("Unable to allocate memory for parameter.\n"); - goto out; - } - INIT_LIST_HEAD(¶m->p_list); - - param->name = kzalloc(strlen(name) + 1, GFP_KERNEL); - if (!param->name) { - pr_err("Unable to allocate memory for parameter name.\n"); - goto out; - } - - param->value = kzalloc(strlen(value) + 1, GFP_KERNEL); - if (!param->value) { - pr_err("Unable to allocate memory for parameter value.\n"); - goto out; - } - - memcpy(param->name, name, strlen(name)); - param->name[strlen(name)] = '\0'; - memcpy(param->value, value, strlen(value)); - param->value[strlen(value)] = '\0'; - param->phase = phase; - param->scope = scope; - param->sender = sender; - param->use = use; - param->type_range = type_range; - - switch (param->type_range) { - case TYPERANGE_BOOL_AND: - param->type = TYPE_BOOL_AND; - break; - case TYPERANGE_BOOL_OR: - param->type = TYPE_BOOL_OR; - break; - case TYPERANGE_0_TO_2: - case TYPERANGE_0_TO_3600: - case TYPERANGE_0_TO_32767: - case TYPERANGE_0_TO_65535: - case TYPERANGE_1_TO_65535: - case TYPERANGE_2_TO_3600: - case TYPERANGE_512_TO_16777215: - param->type = TYPE_NUMBER; - break; - case TYPERANGE_AUTH: - case TYPERANGE_DIGEST: - param->type = TYPE_VALUE_LIST | TYPE_STRING; - break; - case TYPERANGE_MARKINT: - param->type = TYPE_NUMBER_RANGE; - param->type_range |= TYPERANGE_1_TO_65535; - break; - case TYPERANGE_ISCSINAME: - case TYPERANGE_SESSIONTYPE: - case TYPERANGE_TARGETADDRESS: - case TYPERANGE_UTF8: - param->type = TYPE_STRING; - break; - default: - pr_err("Unknown type_range 0x%02x\n", - param->type_range); - goto out; - } - list_add_tail(¶m->p_list, ¶m_list->param_list); - - return param; -out: - if (param) { - kfree(param->value); - kfree(param->name); - kfree(param); - } - - return NULL; -} - -/* #warning Add extension keys */ -int iscsi_create_default_params(struct iscsi_param_list **param_list_ptr) -{ - struct iscsi_param *param = NULL; - struct iscsi_param_list *pl; - - pl = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL); - if (!pl) { - pr_err("Unable to allocate memory for" - " struct iscsi_param_list.\n"); - return -1 ; - } - INIT_LIST_HEAD(&pl->param_list); - INIT_LIST_HEAD(&pl->extra_response_list); - - /* - * The format for setting the initial parameter definitions are: - * - * Parameter name: - * Initial value: - * Allowable phase: - * Scope: - * Allowable senders: - * Typerange: - * Use: - */ - param = iscsi_set_default_param(pl, AUTHMETHOD, INITIAL_AUTHMETHOD, - PHASE_SECURITY, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_AUTH, USE_INITIAL_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, HEADERDIGEST, INITIAL_HEADERDIGEST, - PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_DIGEST, USE_INITIAL_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, DATADIGEST, INITIAL_DATADIGEST, - PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_DIGEST, USE_INITIAL_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, MAXCONNECTIONS, - INITIAL_MAXCONNECTIONS, PHASE_OPERATIONAL, - SCOPE_SESSION_WIDE, SENDER_BOTH, - TYPERANGE_1_TO_65535, USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, SENDTARGETS, INITIAL_SENDTARGETS, - PHASE_FFP0, SCOPE_SESSION_WIDE, SENDER_INITIATOR, - TYPERANGE_UTF8, 0); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, TARGETNAME, INITIAL_TARGETNAME, - PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_BOTH, - TYPERANGE_ISCSINAME, USE_ALL); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, INITIATORNAME, - INITIAL_INITIATORNAME, PHASE_DECLARATIVE, - SCOPE_SESSION_WIDE, SENDER_INITIATOR, - TYPERANGE_ISCSINAME, USE_INITIAL_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, TARGETALIAS, INITIAL_TARGETALIAS, - PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_TARGET, - TYPERANGE_UTF8, USE_ALL); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, INITIATORALIAS, - INITIAL_INITIATORALIAS, PHASE_DECLARATIVE, - SCOPE_SESSION_WIDE, SENDER_INITIATOR, TYPERANGE_UTF8, - USE_ALL); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, TARGETADDRESS, - INITIAL_TARGETADDRESS, PHASE_DECLARATIVE, - SCOPE_SESSION_WIDE, SENDER_TARGET, - TYPERANGE_TARGETADDRESS, USE_ALL); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, TARGETPORTALGROUPTAG, - INITIAL_TARGETPORTALGROUPTAG, - PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_TARGET, - TYPERANGE_0_TO_65535, USE_INITIAL_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, INITIALR2T, INITIAL_INITIALR2T, - PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, - TYPERANGE_BOOL_OR, USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, IMMEDIATEDATA, - INITIAL_IMMEDIATEDATA, PHASE_OPERATIONAL, - SCOPE_SESSION_WIDE, SENDER_BOTH, TYPERANGE_BOOL_AND, - USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, MAXRECVDATASEGMENTLENGTH, - INITIAL_MAXRECVDATASEGMENTLENGTH, - PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_512_TO_16777215, USE_ALL); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, MAXBURSTLENGTH, - INITIAL_MAXBURSTLENGTH, PHASE_OPERATIONAL, - SCOPE_SESSION_WIDE, SENDER_BOTH, - TYPERANGE_512_TO_16777215, USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, FIRSTBURSTLENGTH, - INITIAL_FIRSTBURSTLENGTH, - PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, - TYPERANGE_512_TO_16777215, USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, DEFAULTTIME2WAIT, - INITIAL_DEFAULTTIME2WAIT, - PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, - TYPERANGE_0_TO_3600, USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, DEFAULTTIME2RETAIN, - INITIAL_DEFAULTTIME2RETAIN, - PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, - TYPERANGE_0_TO_3600, USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, MAXOUTSTANDINGR2T, - INITIAL_MAXOUTSTANDINGR2T, - PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, - TYPERANGE_1_TO_65535, USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, DATAPDUINORDER, - INITIAL_DATAPDUINORDER, PHASE_OPERATIONAL, - SCOPE_SESSION_WIDE, SENDER_BOTH, TYPERANGE_BOOL_OR, - USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, DATASEQUENCEINORDER, - INITIAL_DATASEQUENCEINORDER, - PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, - TYPERANGE_BOOL_OR, USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, ERRORRECOVERYLEVEL, - INITIAL_ERRORRECOVERYLEVEL, - PHASE_OPERATIONAL, SCOPE_SESSION_WIDE, SENDER_BOTH, - TYPERANGE_0_TO_2, USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, SESSIONTYPE, INITIAL_SESSIONTYPE, - PHASE_DECLARATIVE, SCOPE_SESSION_WIDE, SENDER_INITIATOR, - TYPERANGE_SESSIONTYPE, USE_LEADING_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, IFMARKER, INITIAL_IFMARKER, - PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_BOOL_AND, USE_INITIAL_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, OFMARKER, INITIAL_OFMARKER, - PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_BOOL_AND, USE_INITIAL_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, IFMARKINT, INITIAL_IFMARKINT, - PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_MARKINT, USE_INITIAL_ONLY); - if (!param) - goto out; - - param = iscsi_set_default_param(pl, OFMARKINT, INITIAL_OFMARKINT, - PHASE_OPERATIONAL, SCOPE_CONNECTION_ONLY, SENDER_BOTH, - TYPERANGE_MARKINT, USE_INITIAL_ONLY); - if (!param) - goto out; - - *param_list_ptr = pl; - return 0; -out: - iscsi_release_param_list(pl); - return -1; -} - -int iscsi_set_keys_to_negotiate( - int sessiontype, - struct iscsi_param_list *param_list) -{ - struct iscsi_param *param; - - list_for_each_entry(param, ¶m_list->param_list, p_list) { - param->state = 0; - if (!strcmp(param->name, AUTHMETHOD)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, HEADERDIGEST)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, DATADIGEST)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, MAXCONNECTIONS)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, TARGETNAME)) { - continue; - } else if (!strcmp(param->name, INITIATORNAME)) { - continue; - } else if (!strcmp(param->name, TARGETALIAS)) { - if (param->value) - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, INITIATORALIAS)) { - continue; - } else if (!strcmp(param->name, TARGETPORTALGROUPTAG)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, INITIALR2T)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, IMMEDIATEDATA)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, MAXBURSTLENGTH)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, FIRSTBURSTLENGTH)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, DEFAULTTIME2WAIT)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, DEFAULTTIME2RETAIN)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, MAXOUTSTANDINGR2T)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, DATAPDUINORDER)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, DATASEQUENCEINORDER)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, ERRORRECOVERYLEVEL)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, SESSIONTYPE)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, IFMARKER)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, OFMARKER)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, IFMARKINT)) { - SET_PSTATE_NEGOTIATE(param); - } else if (!strcmp(param->name, OFMARKINT)) { - SET_PSTATE_NEGOTIATE(param); - } - } - - return 0; -} - -int iscsi_set_keys_irrelevant_for_discovery( - struct iscsi_param_list *param_list) -{ - struct iscsi_param *param; - - list_for_each_entry(param, ¶m_list->param_list, p_list) { - if (!strcmp(param->name, MAXCONNECTIONS)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, INITIALR2T)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, IMMEDIATEDATA)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, MAXBURSTLENGTH)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, FIRSTBURSTLENGTH)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, MAXOUTSTANDINGR2T)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, DATAPDUINORDER)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, DATASEQUENCEINORDER)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, ERRORRECOVERYLEVEL)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, DEFAULTTIME2WAIT)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, DEFAULTTIME2RETAIN)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, IFMARKER)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, OFMARKER)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, IFMARKINT)) - param->state &= ~PSTATE_NEGOTIATE; - else if (!strcmp(param->name, OFMARKINT)) - param->state &= ~PSTATE_NEGOTIATE; - } - - return 0; -} - -int iscsi_copy_param_list( - struct iscsi_param_list **dst_param_list, - struct iscsi_param_list *src_param_list, - int leading) -{ - struct iscsi_param *new_param = NULL, *param = NULL; - struct iscsi_param_list *param_list = NULL; - - param_list = kzalloc(sizeof(struct iscsi_param_list), GFP_KERNEL); - if (!param_list) { - pr_err("Unable to allocate memory for" - " struct iscsi_param_list.\n"); - goto err_out; - } - INIT_LIST_HEAD(¶m_list->param_list); - INIT_LIST_HEAD(¶m_list->extra_response_list); - - list_for_each_entry(param, &src_param_list->param_list, p_list) { - if (!leading && (param->scope & SCOPE_SESSION_WIDE)) { - if ((strcmp(param->name, "TargetName") != 0) && - (strcmp(param->name, "InitiatorName") != 0) && - (strcmp(param->name, "TargetPortalGroupTag") != 0)) - continue; - } - - new_param = kzalloc(sizeof(struct iscsi_param), GFP_KERNEL); - if (!new_param) { - pr_err("Unable to allocate memory for" - " struct iscsi_param.\n"); - goto err_out; - } - - new_param->set_param = param->set_param; - new_param->phase = param->phase; - new_param->scope = param->scope; - new_param->sender = param->sender; - new_param->type = param->type; - new_param->use = param->use; - new_param->type_range = param->type_range; - - new_param->name = kzalloc(strlen(param->name) + 1, GFP_KERNEL); - if (!new_param->name) { - pr_err("Unable to allocate memory for" - " parameter name.\n"); - goto err_out; - } - - new_param->value = kzalloc(strlen(param->value) + 1, - GFP_KERNEL); - if (!new_param->value) { - pr_err("Unable to allocate memory for" - " parameter value.\n"); - goto err_out; - } - - memcpy(new_param->name, param->name, strlen(param->name)); - new_param->name[strlen(param->name)] = '\0'; - memcpy(new_param->value, param->value, strlen(param->value)); - new_param->value[strlen(param->value)] = '\0'; - - list_add_tail(&new_param->p_list, ¶m_list->param_list); - } - - if (!list_empty(¶m_list->param_list)) - *dst_param_list = param_list; - else { - pr_err("No parameters allocated.\n"); - goto err_out; - } - - return 0; - -err_out: - iscsi_release_param_list(param_list); - return -1; -} - -static void iscsi_release_extra_responses(struct iscsi_param_list *param_list) -{ - struct iscsi_extra_response *er, *er_tmp; - - list_for_each_entry_safe(er, er_tmp, ¶m_list->extra_response_list, - er_list) { - list_del(&er->er_list); - kfree(er); - } -} - -void iscsi_release_param_list(struct iscsi_param_list *param_list) -{ - struct iscsi_param *param, *param_tmp; - - list_for_each_entry_safe(param, param_tmp, ¶m_list->param_list, - p_list) { - list_del(¶m->p_list); - - kfree(param->name); - param->name = NULL; - kfree(param->value); - param->value = NULL; - kfree(param); - param = NULL; - } - - iscsi_release_extra_responses(param_list); - - kfree(param_list); -} - -struct iscsi_param *iscsi_find_param_from_key( - char *key, - struct iscsi_param_list *param_list) -{ - struct iscsi_param *param; - - if (!key || !param_list) { - pr_err("Key or parameter list pointer is NULL.\n"); - return NULL; - } - - list_for_each_entry(param, ¶m_list->param_list, p_list) { - if (!strcmp(key, param->name)) - return param; - } - - pr_err("Unable to locate key \"%s\".\n", key); - return NULL; -} - -int iscsi_extract_key_value(char *textbuf, char **key, char **value) -{ - *value = strchr(textbuf, '='); - if (!*value) { - pr_err("Unable to locate \"=\" seperator for key," - " ignoring request.\n"); - return -1; - } - - *key = textbuf; - **value = '\0'; - *value = *value + 1; - - return 0; -} - -int iscsi_update_param_value(struct iscsi_param *param, char *value) -{ - kfree(param->value); - - param->value = kzalloc(strlen(value) + 1, GFP_KERNEL); - if (!param->value) { - pr_err("Unable to allocate memory for value.\n"); - return -1; - } - - memcpy(param->value, value, strlen(value)); - param->value[strlen(value)] = '\0'; - - pr_debug("iSCSI Parameter updated to %s=%s\n", - param->name, param->value); - return 0; -} - -static int iscsi_add_notunderstood_response( - char *key, - char *value, - struct iscsi_param_list *param_list) -{ - struct iscsi_extra_response *extra_response; - - if (strlen(value) > VALUE_MAXLEN) { - pr_err("Value for notunderstood key \"%s\" exceeds %d," - " protocol error.\n", key, VALUE_MAXLEN); - return -1; - } - - extra_response = kzalloc(sizeof(struct iscsi_extra_response), GFP_KERNEL); - if (!extra_response) { - pr_err("Unable to allocate memory for" - " struct iscsi_extra_response.\n"); - return -1; - } - INIT_LIST_HEAD(&extra_response->er_list); - - strncpy(extra_response->key, key, strlen(key) + 1); - strncpy(extra_response->value, NOTUNDERSTOOD, - strlen(NOTUNDERSTOOD) + 1); - - list_add_tail(&extra_response->er_list, - ¶m_list->extra_response_list); - return 0; -} - -static int iscsi_check_for_auth_key(char *key) -{ - /* - * RFC 1994 - */ - if (!strcmp(key, "CHAP_A") || !strcmp(key, "CHAP_I") || - !strcmp(key, "CHAP_C") || !strcmp(key, "CHAP_N") || - !strcmp(key, "CHAP_R")) - return 1; - - /* - * RFC 2945 - */ - if (!strcmp(key, "SRP_U") || !strcmp(key, "SRP_N") || - !strcmp(key, "SRP_g") || !strcmp(key, "SRP_s") || - !strcmp(key, "SRP_A") || !strcmp(key, "SRP_B") || - !strcmp(key, "SRP_M") || !strcmp(key, "SRP_HM")) - return 1; - - return 0; -} - -static void iscsi_check_proposer_for_optional_reply(struct iscsi_param *param) -{ - if (IS_TYPE_BOOL_AND(param)) { - if (!strcmp(param->value, NO)) - SET_PSTATE_REPLY_OPTIONAL(param); - } else if (IS_TYPE_BOOL_OR(param)) { - if (!strcmp(param->value, YES)) - SET_PSTATE_REPLY_OPTIONAL(param); - /* - * Required for gPXE iSCSI boot client - */ - if (!strcmp(param->name, IMMEDIATEDATA)) - SET_PSTATE_REPLY_OPTIONAL(param); - } else if (IS_TYPE_NUMBER(param)) { - if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) - SET_PSTATE_REPLY_OPTIONAL(param); - /* - * The GlobalSAN iSCSI Initiator for MacOSX does - * not respond to MaxBurstLength, FirstBurstLength, - * DefaultTime2Wait or DefaultTime2Retain parameter keys. - * So, we set them to 'reply optional' here, and assume the - * the defaults from iscsi_parameters.h if the initiator - * is not RFC compliant and the keys are not negotiated. - */ - if (!strcmp(param->name, MAXBURSTLENGTH)) - SET_PSTATE_REPLY_OPTIONAL(param); - if (!strcmp(param->name, FIRSTBURSTLENGTH)) - SET_PSTATE_REPLY_OPTIONAL(param); - if (!strcmp(param->name, DEFAULTTIME2WAIT)) - SET_PSTATE_REPLY_OPTIONAL(param); - if (!strcmp(param->name, DEFAULTTIME2RETAIN)) - SET_PSTATE_REPLY_OPTIONAL(param); - /* - * Required for gPXE iSCSI boot client - */ - if (!strcmp(param->name, MAXCONNECTIONS)) - SET_PSTATE_REPLY_OPTIONAL(param); - } else if (IS_PHASE_DECLARATIVE(param)) - SET_PSTATE_REPLY_OPTIONAL(param); -} - -static int iscsi_check_boolean_value(struct iscsi_param *param, char *value) -{ - if (strcmp(value, YES) && strcmp(value, NO)) { - pr_err("Illegal value for \"%s\", must be either" - " \"%s\" or \"%s\".\n", param->name, YES, NO); - return -1; - } - - return 0; -} - -static int iscsi_check_numerical_value(struct iscsi_param *param, char *value_ptr) -{ - char *tmpptr; - int value = 0; - - value = simple_strtoul(value_ptr, &tmpptr, 0); - -/* #warning FIXME: Fix this */ -#if 0 - if (strspn(endptr, WHITE_SPACE) != strlen(endptr)) { - pr_err("Illegal value \"%s\" for \"%s\".\n", - value, param->name); - return -1; - } -#endif - if (IS_TYPERANGE_0_TO_2(param)) { - if ((value < 0) || (value > 2)) { - pr_err("Illegal value for \"%s\", must be" - " between 0 and 2.\n", param->name); - return -1; - } - return 0; - } - if (IS_TYPERANGE_0_TO_3600(param)) { - if ((value < 0) || (value > 3600)) { - pr_err("Illegal value for \"%s\", must be" - " between 0 and 3600.\n", param->name); - return -1; - } - return 0; - } - if (IS_TYPERANGE_0_TO_32767(param)) { - if ((value < 0) || (value > 32767)) { - pr_err("Illegal value for \"%s\", must be" - " between 0 and 32767.\n", param->name); - return -1; - } - return 0; - } - if (IS_TYPERANGE_0_TO_65535(param)) { - if ((value < 0) || (value > 65535)) { - pr_err("Illegal value for \"%s\", must be" - " between 0 and 65535.\n", param->name); - return -1; - } - return 0; - } - if (IS_TYPERANGE_1_TO_65535(param)) { - if ((value < 1) || (value > 65535)) { - pr_err("Illegal value for \"%s\", must be" - " between 1 and 65535.\n", param->name); - return -1; - } - return 0; - } - if (IS_TYPERANGE_2_TO_3600(param)) { - if ((value < 2) || (value > 3600)) { - pr_err("Illegal value for \"%s\", must be" - " between 2 and 3600.\n", param->name); - return -1; - } - return 0; - } - if (IS_TYPERANGE_512_TO_16777215(param)) { - if ((value < 512) || (value > 16777215)) { - pr_err("Illegal value for \"%s\", must be" - " between 512 and 16777215.\n", param->name); - return -1; - } - return 0; - } - - return 0; -} - -static int iscsi_check_numerical_range_value(struct iscsi_param *param, char *value) -{ - char *left_val_ptr = NULL, *right_val_ptr = NULL; - char *tilde_ptr = NULL, *tmp_ptr = NULL; - u32 left_val, right_val, local_left_val, local_right_val; - - if (strcmp(param->name, IFMARKINT) && - strcmp(param->name, OFMARKINT)) { - pr_err("Only parameters \"%s\" or \"%s\" may contain a" - " numerical range value.\n", IFMARKINT, OFMARKINT); - return -1; - } - - if (IS_PSTATE_PROPOSER(param)) - return 0; - - tilde_ptr = strchr(value, '~'); - if (!tilde_ptr) { - pr_err("Unable to locate numerical range indicator" - " \"~\" for \"%s\".\n", param->name); - return -1; - } - *tilde_ptr = '\0'; - - left_val_ptr = value; - right_val_ptr = value + strlen(left_val_ptr) + 1; - - if (iscsi_check_numerical_value(param, left_val_ptr) < 0) - return -1; - if (iscsi_check_numerical_value(param, right_val_ptr) < 0) - return -1; - - left_val = simple_strtoul(left_val_ptr, &tmp_ptr, 0); - right_val = simple_strtoul(right_val_ptr, &tmp_ptr, 0); - *tilde_ptr = '~'; - - if (right_val < left_val) { - pr_err("Numerical range for parameter \"%s\" contains" - " a right value which is less than the left.\n", - param->name); - return -1; - } - - /* - * For now, enforce reasonable defaults for [I,O]FMarkInt. - */ - tilde_ptr = strchr(param->value, '~'); - if (!tilde_ptr) { - pr_err("Unable to locate numerical range indicator" - " \"~\" for \"%s\".\n", param->name); - return -1; - } - *tilde_ptr = '\0'; - - left_val_ptr = param->value; - right_val_ptr = param->value + strlen(left_val_ptr) + 1; - - local_left_val = simple_strtoul(left_val_ptr, &tmp_ptr, 0); - local_right_val = simple_strtoul(right_val_ptr, &tmp_ptr, 0); - *tilde_ptr = '~'; - - if (param->set_param) { - if ((left_val < local_left_val) || - (right_val < local_left_val)) { - pr_err("Passed value range \"%u~%u\" is below" - " minimum left value \"%u\" for key \"%s\"," - " rejecting.\n", left_val, right_val, - local_left_val, param->name); - return -1; - } - } else { - if ((left_val < local_left_val) && - (right_val < local_left_val)) { - pr_err("Received value range \"%u~%u\" is" - " below minimum left value \"%u\" for key" - " \"%s\", rejecting.\n", left_val, right_val, - local_left_val, param->name); - SET_PSTATE_REJECT(param); - if (iscsi_update_param_value(param, REJECT) < 0) - return -1; - } - } - - return 0; -} - -static int iscsi_check_string_or_list_value(struct iscsi_param *param, char *value) -{ - if (IS_PSTATE_PROPOSER(param)) - return 0; - - if (IS_TYPERANGE_AUTH_PARAM(param)) { - if (strcmp(value, KRB5) && strcmp(value, SPKM1) && - strcmp(value, SPKM2) && strcmp(value, SRP) && - strcmp(value, CHAP) && strcmp(value, NONE)) { - pr_err("Illegal value for \"%s\", must be" - " \"%s\", \"%s\", \"%s\", \"%s\", \"%s\"" - " or \"%s\".\n", param->name, KRB5, - SPKM1, SPKM2, SRP, CHAP, NONE); - return -1; - } - } - if (IS_TYPERANGE_DIGEST_PARAM(param)) { - if (strcmp(value, CRC32C) && strcmp(value, NONE)) { - pr_err("Illegal value for \"%s\", must be" - " \"%s\" or \"%s\".\n", param->name, - CRC32C, NONE); - return -1; - } - } - if (IS_TYPERANGE_SESSIONTYPE(param)) { - if (strcmp(value, DISCOVERY) && strcmp(value, NORMAL)) { - pr_err("Illegal value for \"%s\", must be" - " \"%s\" or \"%s\".\n", param->name, - DISCOVERY, NORMAL); - return -1; - } - } - - return 0; -} - -/* - * This function is used to pick a value range number, currently just - * returns the lesser of both right values. - */ -static char *iscsi_get_value_from_number_range( - struct iscsi_param *param, - char *value) -{ - char *end_ptr, *tilde_ptr1 = NULL, *tilde_ptr2 = NULL; - u32 acceptor_right_value, proposer_right_value; - - tilde_ptr1 = strchr(value, '~'); - if (!tilde_ptr1) - return NULL; - *tilde_ptr1++ = '\0'; - proposer_right_value = simple_strtoul(tilde_ptr1, &end_ptr, 0); - - tilde_ptr2 = strchr(param->value, '~'); - if (!tilde_ptr2) - return NULL; - *tilde_ptr2++ = '\0'; - acceptor_right_value = simple_strtoul(tilde_ptr2, &end_ptr, 0); - - return (acceptor_right_value >= proposer_right_value) ? - tilde_ptr1 : tilde_ptr2; -} - -static char *iscsi_check_valuelist_for_support( - struct iscsi_param *param, - char *value) -{ - char *tmp1 = NULL, *tmp2 = NULL; - char *acceptor_values = NULL, *proposer_values = NULL; - - acceptor_values = param->value; - proposer_values = value; - - do { - if (!proposer_values) - return NULL; - tmp1 = strchr(proposer_values, ','); - if (tmp1) - *tmp1 = '\0'; - acceptor_values = param->value; - do { - if (!acceptor_values) { - if (tmp1) - *tmp1 = ','; - return NULL; - } - tmp2 = strchr(acceptor_values, ','); - if (tmp2) - *tmp2 = '\0'; - if (!acceptor_values || !proposer_values) { - if (tmp1) - *tmp1 = ','; - if (tmp2) - *tmp2 = ','; - return NULL; - } - if (!strcmp(acceptor_values, proposer_values)) { - if (tmp2) - *tmp2 = ','; - goto out; - } - if (tmp2) - *tmp2++ = ','; - - acceptor_values = tmp2; - if (!acceptor_values) - break; - } while (acceptor_values); - if (tmp1) - *tmp1++ = ','; - proposer_values = tmp1; - } while (proposer_values); - -out: - return proposer_values; -} - -static int iscsi_check_acceptor_state(struct iscsi_param *param, char *value) -{ - u8 acceptor_boolean_value = 0, proposer_boolean_value = 0; - char *negoitated_value = NULL; - - if (IS_PSTATE_ACCEPTOR(param)) { - pr_err("Received key \"%s\" twice, protocol error.\n", - param->name); - return -1; - } - - if (IS_PSTATE_REJECT(param)) - return 0; - - if (IS_TYPE_BOOL_AND(param)) { - if (!strcmp(value, YES)) - proposer_boolean_value = 1; - if (!strcmp(param->value, YES)) - acceptor_boolean_value = 1; - if (acceptor_boolean_value && proposer_boolean_value) - do {} while (0); - else { - if (iscsi_update_param_value(param, NO) < 0) - return -1; - if (!proposer_boolean_value) - SET_PSTATE_REPLY_OPTIONAL(param); - } - } else if (IS_TYPE_BOOL_OR(param)) { - if (!strcmp(value, YES)) - proposer_boolean_value = 1; - if (!strcmp(param->value, YES)) - acceptor_boolean_value = 1; - if (acceptor_boolean_value || proposer_boolean_value) { - if (iscsi_update_param_value(param, YES) < 0) - return -1; - if (proposer_boolean_value) - SET_PSTATE_REPLY_OPTIONAL(param); - } - } else if (IS_TYPE_NUMBER(param)) { - char *tmpptr, buf[10]; - u32 acceptor_value = simple_strtoul(param->value, &tmpptr, 0); - u32 proposer_value = simple_strtoul(value, &tmpptr, 0); - - memset(buf, 0, 10); - - if (!strcmp(param->name, MAXCONNECTIONS) || - !strcmp(param->name, MAXBURSTLENGTH) || - !strcmp(param->name, FIRSTBURSTLENGTH) || - !strcmp(param->name, MAXOUTSTANDINGR2T) || - !strcmp(param->name, DEFAULTTIME2RETAIN) || - !strcmp(param->name, ERRORRECOVERYLEVEL)) { - if (proposer_value > acceptor_value) { - sprintf(buf, "%u", acceptor_value); - if (iscsi_update_param_value(param, - &buf[0]) < 0) - return -1; - } else { - if (iscsi_update_param_value(param, value) < 0) - return -1; - } - } else if (!strcmp(param->name, DEFAULTTIME2WAIT)) { - if (acceptor_value > proposer_value) { - sprintf(buf, "%u", acceptor_value); - if (iscsi_update_param_value(param, - &buf[0]) < 0) - return -1; - } else { - if (iscsi_update_param_value(param, value) < 0) - return -1; - } - } else { - if (iscsi_update_param_value(param, value) < 0) - return -1; - } - - if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) - SET_PSTATE_REPLY_OPTIONAL(param); - } else if (IS_TYPE_NUMBER_RANGE(param)) { - negoitated_value = iscsi_get_value_from_number_range( - param, value); - if (!negoitated_value) - return -1; - if (iscsi_update_param_value(param, negoitated_value) < 0) - return -1; - } else if (IS_TYPE_VALUE_LIST(param)) { - negoitated_value = iscsi_check_valuelist_for_support( - param, value); - if (!negoitated_value) { - pr_err("Proposer's value list \"%s\" contains" - " no valid values from Acceptor's value list" - " \"%s\".\n", value, param->value); - return -1; - } - if (iscsi_update_param_value(param, negoitated_value) < 0) - return -1; - } else if (IS_PHASE_DECLARATIVE(param)) { - if (iscsi_update_param_value(param, value) < 0) - return -1; - SET_PSTATE_REPLY_OPTIONAL(param); - } - - return 0; -} - -static int iscsi_check_proposer_state(struct iscsi_param *param, char *value) -{ - if (IS_PSTATE_RESPONSE_GOT(param)) { - pr_err("Received key \"%s\" twice, protocol error.\n", - param->name); - return -1; - } - - if (IS_TYPE_NUMBER_RANGE(param)) { - u32 left_val = 0, right_val = 0, recieved_value = 0; - char *left_val_ptr = NULL, *right_val_ptr = NULL; - char *tilde_ptr = NULL, *tmp_ptr = NULL; - - if (!strcmp(value, IRRELEVANT) || !strcmp(value, REJECT)) { - if (iscsi_update_param_value(param, value) < 0) - return -1; - return 0; - } - - tilde_ptr = strchr(value, '~'); - if (tilde_ptr) { - pr_err("Illegal \"~\" in response for \"%s\".\n", - param->name); - return -1; - } - tilde_ptr = strchr(param->value, '~'); - if (!tilde_ptr) { - pr_err("Unable to locate numerical range" - " indicator \"~\" for \"%s\".\n", param->name); - return -1; - } - *tilde_ptr = '\0'; - - left_val_ptr = param->value; - right_val_ptr = param->value + strlen(left_val_ptr) + 1; - left_val = simple_strtoul(left_val_ptr, &tmp_ptr, 0); - right_val = simple_strtoul(right_val_ptr, &tmp_ptr, 0); - recieved_value = simple_strtoul(value, &tmp_ptr, 0); - - *tilde_ptr = '~'; - - if ((recieved_value < left_val) || - (recieved_value > right_val)) { - pr_err("Illegal response \"%s=%u\", value must" - " be between %u and %u.\n", param->name, - recieved_value, left_val, right_val); - return -1; - } - } else if (IS_TYPE_VALUE_LIST(param)) { - char *comma_ptr = NULL, *tmp_ptr = NULL; - - comma_ptr = strchr(value, ','); - if (comma_ptr) { - pr_err("Illegal \",\" in response for \"%s\".\n", - param->name); - return -1; - } - - tmp_ptr = iscsi_check_valuelist_for_support(param, value); - if (!tmp_ptr) - return -1; - } - - if (iscsi_update_param_value(param, value) < 0) - return -1; - - return 0; -} - -static int iscsi_check_value(struct iscsi_param *param, char *value) -{ - char *comma_ptr = NULL; - - if (!strcmp(value, REJECT)) { - if (!strcmp(param->name, IFMARKINT) || - !strcmp(param->name, OFMARKINT)) { - /* - * Reject is not fatal for [I,O]FMarkInt, and causes - * [I,O]FMarker to be reset to No. (See iSCSI v20 A.3.2) - */ - SET_PSTATE_REJECT(param); - return 0; - } - pr_err("Received %s=%s\n", param->name, value); - return -1; - } - if (!strcmp(value, IRRELEVANT)) { - pr_debug("Received %s=%s\n", param->name, value); - SET_PSTATE_IRRELEVANT(param); - return 0; - } - if (!strcmp(value, NOTUNDERSTOOD)) { - if (!IS_PSTATE_PROPOSER(param)) { - pr_err("Received illegal offer %s=%s\n", - param->name, value); - return -1; - } - -/* #warning FIXME: Add check for X-ExtensionKey here */ - pr_err("Standard iSCSI key \"%s\" cannot be answered" - " with \"%s\", protocol error.\n", param->name, value); - return -1; - } - - do { - comma_ptr = NULL; - comma_ptr = strchr(value, ','); - - if (comma_ptr && !IS_TYPE_VALUE_LIST(param)) { - pr_err("Detected value seperator \",\", but" - " key \"%s\" does not allow a value list," - " protocol error.\n", param->name); - return -1; - } - if (comma_ptr) - *comma_ptr = '\0'; - - if (strlen(value) > VALUE_MAXLEN) { - pr_err("Value for key \"%s\" exceeds %d," - " protocol error.\n", param->name, - VALUE_MAXLEN); - return -1; - } - - if (IS_TYPE_BOOL_AND(param) || IS_TYPE_BOOL_OR(param)) { - if (iscsi_check_boolean_value(param, value) < 0) - return -1; - } else if (IS_TYPE_NUMBER(param)) { - if (iscsi_check_numerical_value(param, value) < 0) - return -1; - } else if (IS_TYPE_NUMBER_RANGE(param)) { - if (iscsi_check_numerical_range_value(param, value) < 0) - return -1; - } else if (IS_TYPE_STRING(param) || IS_TYPE_VALUE_LIST(param)) { - if (iscsi_check_string_or_list_value(param, value) < 0) - return -1; - } else { - pr_err("Huh? 0x%02x\n", param->type); - return -1; - } - - if (comma_ptr) - *comma_ptr++ = ','; - - value = comma_ptr; - } while (value); - - return 0; -} - -static struct iscsi_param *__iscsi_check_key( - char *key, - int sender, - struct iscsi_param_list *param_list) -{ - struct iscsi_param *param; - - if (strlen(key) > KEY_MAXLEN) { - pr_err("Length of key name \"%s\" exceeds %d.\n", - key, KEY_MAXLEN); - return NULL; - } - - param = iscsi_find_param_from_key(key, param_list); - if (!param) - return NULL; - - if ((sender & SENDER_INITIATOR) && !IS_SENDER_INITIATOR(param)) { - pr_err("Key \"%s\" may not be sent to %s," - " protocol error.\n", param->name, - (sender & SENDER_RECEIVER) ? "target" : "initiator"); - return NULL; - } - - if ((sender & SENDER_TARGET) && !IS_SENDER_TARGET(param)) { - pr_err("Key \"%s\" may not be sent to %s," - " protocol error.\n", param->name, - (sender & SENDER_RECEIVER) ? "initiator" : "target"); - return NULL; - } - - return param; -} - -static struct iscsi_param *iscsi_check_key( - char *key, - int phase, - int sender, - struct iscsi_param_list *param_list) -{ - struct iscsi_param *param; - /* - * Key name length must not exceed 63 bytes. (See iSCSI v20 5.1) - */ - if (strlen(key) > KEY_MAXLEN) { - pr_err("Length of key name \"%s\" exceeds %d.\n", - key, KEY_MAXLEN); - return NULL; - } - - param = iscsi_find_param_from_key(key, param_list); - if (!param) - return NULL; - - if ((sender & SENDER_INITIATOR) && !IS_SENDER_INITIATOR(param)) { - pr_err("Key \"%s\" may not be sent to %s," - " protocol error.\n", param->name, - (sender & SENDER_RECEIVER) ? "target" : "initiator"); - return NULL; - } - if ((sender & SENDER_TARGET) && !IS_SENDER_TARGET(param)) { - pr_err("Key \"%s\" may not be sent to %s," - " protocol error.\n", param->name, - (sender & SENDER_RECEIVER) ? "initiator" : "target"); - return NULL; - } - - if (IS_PSTATE_ACCEPTOR(param)) { - pr_err("Key \"%s\" received twice, protocol error.\n", - key); - return NULL; - } - - if (!phase) - return param; - - if (!(param->phase & phase)) { - pr_err("Key \"%s\" may not be negotiated during ", - param->name); - switch (phase) { - case PHASE_SECURITY: - pr_debug("Security phase.\n"); - break; - case PHASE_OPERATIONAL: - pr_debug("Operational phase.\n"); - default: - pr_debug("Unknown phase.\n"); - } - return NULL; - } - - return param; -} - -static int iscsi_enforce_integrity_rules( - u8 phase, - struct iscsi_param_list *param_list) -{ - char *tmpptr; - u8 DataSequenceInOrder = 0; - u8 ErrorRecoveryLevel = 0, SessionType = 0; - u8 IFMarker = 0, OFMarker = 0; - u8 IFMarkInt_Reject = 0, OFMarkInt_Reject = 0; - u32 FirstBurstLength = 0, MaxBurstLength = 0; - struct iscsi_param *param = NULL; - - list_for_each_entry(param, ¶m_list->param_list, p_list) { - if (!(param->phase & phase)) - continue; - if (!strcmp(param->name, SESSIONTYPE)) - if (!strcmp(param->value, NORMAL)) - SessionType = 1; - if (!strcmp(param->name, ERRORRECOVERYLEVEL)) - ErrorRecoveryLevel = simple_strtoul(param->value, - &tmpptr, 0); - if (!strcmp(param->name, DATASEQUENCEINORDER)) - if (!strcmp(param->value, YES)) - DataSequenceInOrder = 1; - if (!strcmp(param->name, MAXBURSTLENGTH)) - MaxBurstLength = simple_strtoul(param->value, - &tmpptr, 0); - if (!strcmp(param->name, IFMARKER)) - if (!strcmp(param->value, YES)) - IFMarker = 1; - if (!strcmp(param->name, OFMARKER)) - if (!strcmp(param->value, YES)) - OFMarker = 1; - if (!strcmp(param->name, IFMARKINT)) - if (!strcmp(param->value, REJECT)) - IFMarkInt_Reject = 1; - if (!strcmp(param->name, OFMARKINT)) - if (!strcmp(param->value, REJECT)) - OFMarkInt_Reject = 1; - } - - list_for_each_entry(param, ¶m_list->param_list, p_list) { - if (!(param->phase & phase)) - continue; - if (!SessionType && (!IS_PSTATE_ACCEPTOR(param) && - (strcmp(param->name, IFMARKER) && - strcmp(param->name, OFMARKER) && - strcmp(param->name, IFMARKINT) && - strcmp(param->name, OFMARKINT)))) - continue; - if (!strcmp(param->name, MAXOUTSTANDINGR2T) && - DataSequenceInOrder && (ErrorRecoveryLevel > 0)) { - if (strcmp(param->value, "1")) { - if (iscsi_update_param_value(param, "1") < 0) - return -1; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - } - if (!strcmp(param->name, MAXCONNECTIONS) && !SessionType) { - if (strcmp(param->value, "1")) { - if (iscsi_update_param_value(param, "1") < 0) - return -1; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - } - if (!strcmp(param->name, FIRSTBURSTLENGTH)) { - FirstBurstLength = simple_strtoul(param->value, - &tmpptr, 0); - if (FirstBurstLength > MaxBurstLength) { - char tmpbuf[10]; - memset(tmpbuf, 0, 10); - sprintf(tmpbuf, "%u", MaxBurstLength); - if (iscsi_update_param_value(param, tmpbuf)) - return -1; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - } - if (!strcmp(param->name, IFMARKER) && IFMarkInt_Reject) { - if (iscsi_update_param_value(param, NO) < 0) - return -1; - IFMarker = 0; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - if (!strcmp(param->name, OFMARKER) && OFMarkInt_Reject) { - if (iscsi_update_param_value(param, NO) < 0) - return -1; - OFMarker = 0; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - if (!strcmp(param->name, IFMARKINT) && !IFMarker) { - if (!strcmp(param->value, REJECT)) - continue; - param->state &= ~PSTATE_NEGOTIATE; - if (iscsi_update_param_value(param, IRRELEVANT) < 0) - return -1; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - if (!strcmp(param->name, OFMARKINT) && !OFMarker) { - if (!strcmp(param->value, REJECT)) - continue; - param->state &= ~PSTATE_NEGOTIATE; - if (iscsi_update_param_value(param, IRRELEVANT) < 0) - return -1; - pr_debug("Reset \"%s\" to \"%s\".\n", - param->name, param->value); - } - } - - return 0; -} - -int iscsi_decode_text_input( - u8 phase, - u8 sender, - char *textbuf, - u32 length, - struct iscsi_param_list *param_list) -{ - char *tmpbuf, *start = NULL, *end = NULL; - - tmpbuf = kzalloc(length + 1, GFP_KERNEL); - if (!tmpbuf) { - pr_err("Unable to allocate memory for tmpbuf.\n"); - return -1; - } - - memcpy(tmpbuf, textbuf, length); - tmpbuf[length] = '\0'; - start = tmpbuf; - end = (start + length); - - while (start < end) { - char *key, *value; - struct iscsi_param *param; - - if (iscsi_extract_key_value(start, &key, &value) < 0) { - kfree(tmpbuf); - return -1; - } - - pr_debug("Got key: %s=%s\n", key, value); - - if (phase & PHASE_SECURITY) { - if (iscsi_check_for_auth_key(key) > 0) { - char *tmpptr = key + strlen(key); - *tmpptr = '='; - kfree(tmpbuf); - return 1; - } - } - - param = iscsi_check_key(key, phase, sender, param_list); - if (!param) { - if (iscsi_add_notunderstood_response(key, - value, param_list) < 0) { - kfree(tmpbuf); - return -1; - } - start += strlen(key) + strlen(value) + 2; - continue; - } - if (iscsi_check_value(param, value) < 0) { - kfree(tmpbuf); - return -1; - } - - start += strlen(key) + strlen(value) + 2; - - if (IS_PSTATE_PROPOSER(param)) { - if (iscsi_check_proposer_state(param, value) < 0) { - kfree(tmpbuf); - return -1; - } - SET_PSTATE_RESPONSE_GOT(param); - } else { - if (iscsi_check_acceptor_state(param, value) < 0) { - kfree(tmpbuf); - return -1; - } - SET_PSTATE_ACCEPTOR(param); - } - } - - kfree(tmpbuf); - return 0; -} - -int iscsi_encode_text_output( - u8 phase, - u8 sender, - char *textbuf, - u32 *length, - struct iscsi_param_list *param_list) -{ - char *output_buf = NULL; - struct iscsi_extra_response *er; - struct iscsi_param *param; - - output_buf = textbuf + *length; - - if (iscsi_enforce_integrity_rules(phase, param_list) < 0) - return -1; - - list_for_each_entry(param, ¶m_list->param_list, p_list) { - if (!(param->sender & sender)) - continue; - if (IS_PSTATE_ACCEPTOR(param) && - !IS_PSTATE_RESPONSE_SENT(param) && - !IS_PSTATE_REPLY_OPTIONAL(param) && - (param->phase & phase)) { - *length += sprintf(output_buf, "%s=%s", - param->name, param->value); - *length += 1; - output_buf = textbuf + *length; - SET_PSTATE_RESPONSE_SENT(param); - pr_debug("Sending key: %s=%s\n", - param->name, param->value); - continue; - } - if (IS_PSTATE_NEGOTIATE(param) && - !IS_PSTATE_ACCEPTOR(param) && - !IS_PSTATE_PROPOSER(param) && - (param->phase & phase)) { - *length += sprintf(output_buf, "%s=%s", - param->name, param->value); - *length += 1; - output_buf = textbuf + *length; - SET_PSTATE_PROPOSER(param); - iscsi_check_proposer_for_optional_reply(param); - pr_debug("Sending key: %s=%s\n", - param->name, param->value); - } - } - - list_for_each_entry(er, ¶m_list->extra_response_list, er_list) { - *length += sprintf(output_buf, "%s=%s", er->key, er->value); - *length += 1; - output_buf = textbuf + *length; - pr_debug("Sending key: %s=%s\n", er->key, er->value); - } - iscsi_release_extra_responses(param_list); - - return 0; -} - -int iscsi_check_negotiated_keys(struct iscsi_param_list *param_list) -{ - int ret = 0; - struct iscsi_param *param; - - list_for_each_entry(param, ¶m_list->param_list, p_list) { - if (IS_PSTATE_NEGOTIATE(param) && - IS_PSTATE_PROPOSER(param) && - !IS_PSTATE_RESPONSE_GOT(param) && - !IS_PSTATE_REPLY_OPTIONAL(param) && - !IS_PHASE_DECLARATIVE(param)) { - pr_err("No response for proposed key \"%s\".\n", - param->name); - ret = -1; - } - } - - return ret; -} - -int iscsi_change_param_value( - char *keyvalue, - struct iscsi_param_list *param_list, - int check_key) -{ - char *key = NULL, *value = NULL; - struct iscsi_param *param; - int sender = 0; - - if (iscsi_extract_key_value(keyvalue, &key, &value) < 0) - return -1; - - if (!check_key) { - param = __iscsi_check_key(keyvalue, sender, param_list); - if (!param) - return -1; - } else { - param = iscsi_check_key(keyvalue, 0, sender, param_list); - if (!param) - return -1; - - param->set_param = 1; - if (iscsi_check_value(param, value) < 0) { - param->set_param = 0; - return -1; - } - param->set_param = 0; - } - - if (iscsi_update_param_value(param, value) < 0) - return -1; - - return 0; -} - -void iscsi_set_connection_parameters( - struct iscsi_conn_ops *ops, - struct iscsi_param_list *param_list) -{ - char *tmpptr; - struct iscsi_param *param; - - pr_debug("---------------------------------------------------" - "---------------\n"); - list_for_each_entry(param, ¶m_list->param_list, p_list) { - if (!IS_PSTATE_ACCEPTOR(param) && !IS_PSTATE_PROPOSER(param)) - continue; - if (!strcmp(param->name, AUTHMETHOD)) { - pr_debug("AuthMethod: %s\n", - param->value); - } else if (!strcmp(param->name, HEADERDIGEST)) { - ops->HeaderDigest = !strcmp(param->value, CRC32C); - pr_debug("HeaderDigest: %s\n", - param->value); - } else if (!strcmp(param->name, DATADIGEST)) { - ops->DataDigest = !strcmp(param->value, CRC32C); - pr_debug("DataDigest: %s\n", - param->value); - } else if (!strcmp(param->name, MAXRECVDATASEGMENTLENGTH)) { - ops->MaxRecvDataSegmentLength = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("MaxRecvDataSegmentLength: %s\n", - param->value); - } else if (!strcmp(param->name, OFMARKER)) { - ops->OFMarker = !strcmp(param->value, YES); - pr_debug("OFMarker: %s\n", - param->value); - } else if (!strcmp(param->name, IFMARKER)) { - ops->IFMarker = !strcmp(param->value, YES); - pr_debug("IFMarker: %s\n", - param->value); - } else if (!strcmp(param->name, OFMARKINT)) { - ops->OFMarkInt = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("OFMarkInt: %s\n", - param->value); - } else if (!strcmp(param->name, IFMARKINT)) { - ops->IFMarkInt = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("IFMarkInt: %s\n", - param->value); - } - } - pr_debug("----------------------------------------------------" - "--------------\n"); -} - -void iscsi_set_session_parameters( - struct iscsi_sess_ops *ops, - struct iscsi_param_list *param_list, - int leading) -{ - char *tmpptr; - struct iscsi_param *param; - - pr_debug("----------------------------------------------------" - "--------------\n"); - list_for_each_entry(param, ¶m_list->param_list, p_list) { - if (!IS_PSTATE_ACCEPTOR(param) && !IS_PSTATE_PROPOSER(param)) - continue; - if (!strcmp(param->name, INITIATORNAME)) { - if (!param->value) - continue; - if (leading) - snprintf(ops->InitiatorName, - sizeof(ops->InitiatorName), - "%s", param->value); - pr_debug("InitiatorName: %s\n", - param->value); - } else if (!strcmp(param->name, INITIATORALIAS)) { - if (!param->value) - continue; - snprintf(ops->InitiatorAlias, - sizeof(ops->InitiatorAlias), - "%s", param->value); - pr_debug("InitiatorAlias: %s\n", - param->value); - } else if (!strcmp(param->name, TARGETNAME)) { - if (!param->value) - continue; - if (leading) - snprintf(ops->TargetName, - sizeof(ops->TargetName), - "%s", param->value); - pr_debug("TargetName: %s\n", - param->value); - } else if (!strcmp(param->name, TARGETALIAS)) { - if (!param->value) - continue; - snprintf(ops->TargetAlias, sizeof(ops->TargetAlias), - "%s", param->value); - pr_debug("TargetAlias: %s\n", - param->value); - } else if (!strcmp(param->name, TARGETPORTALGROUPTAG)) { - ops->TargetPortalGroupTag = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("TargetPortalGroupTag: %s\n", - param->value); - } else if (!strcmp(param->name, MAXCONNECTIONS)) { - ops->MaxConnections = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("MaxConnections: %s\n", - param->value); - } else if (!strcmp(param->name, INITIALR2T)) { - ops->InitialR2T = !strcmp(param->value, YES); - pr_debug("InitialR2T: %s\n", - param->value); - } else if (!strcmp(param->name, IMMEDIATEDATA)) { - ops->ImmediateData = !strcmp(param->value, YES); - pr_debug("ImmediateData: %s\n", - param->value); - } else if (!strcmp(param->name, MAXBURSTLENGTH)) { - ops->MaxBurstLength = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("MaxBurstLength: %s\n", - param->value); - } else if (!strcmp(param->name, FIRSTBURSTLENGTH)) { - ops->FirstBurstLength = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("FirstBurstLength: %s\n", - param->value); - } else if (!strcmp(param->name, DEFAULTTIME2WAIT)) { - ops->DefaultTime2Wait = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("DefaultTime2Wait: %s\n", - param->value); - } else if (!strcmp(param->name, DEFAULTTIME2RETAIN)) { - ops->DefaultTime2Retain = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("DefaultTime2Retain: %s\n", - param->value); - } else if (!strcmp(param->name, MAXOUTSTANDINGR2T)) { - ops->MaxOutstandingR2T = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("MaxOutstandingR2T: %s\n", - param->value); - } else if (!strcmp(param->name, DATAPDUINORDER)) { - ops->DataPDUInOrder = !strcmp(param->value, YES); - pr_debug("DataPDUInOrder: %s\n", - param->value); - } else if (!strcmp(param->name, DATASEQUENCEINORDER)) { - ops->DataSequenceInOrder = !strcmp(param->value, YES); - pr_debug("DataSequenceInOrder: %s\n", - param->value); - } else if (!strcmp(param->name, ERRORRECOVERYLEVEL)) { - ops->ErrorRecoveryLevel = - simple_strtoul(param->value, &tmpptr, 0); - pr_debug("ErrorRecoveryLevel: %s\n", - param->value); - } else if (!strcmp(param->name, SESSIONTYPE)) { - ops->SessionType = !strcmp(param->value, DISCOVERY); - pr_debug("SessionType: %s\n", - param->value); - } - } - pr_debug("----------------------------------------------------" - "--------------\n"); - -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_parameters.h b/trunk/drivers/target/iscsi/iscsi_target_parameters.h deleted file mode 100644 index 6a37fd6f1285..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_parameters.h +++ /dev/null @@ -1,269 +0,0 @@ -#ifndef ISCSI_PARAMETERS_H -#define ISCSI_PARAMETERS_H - -struct iscsi_extra_response { - char key[64]; - char value[32]; - struct list_head er_list; -} ____cacheline_aligned; - -struct iscsi_param { - char *name; - char *value; - u8 set_param; - u8 phase; - u8 scope; - u8 sender; - u8 type; - u8 use; - u16 type_range; - u32 state; - struct list_head p_list; -} ____cacheline_aligned; - -extern int iscsi_login_rx_data(struct iscsi_conn *, char *, int); -extern int iscsi_login_tx_data(struct iscsi_conn *, char *, char *, int); -extern void iscsi_dump_conn_ops(struct iscsi_conn_ops *); -extern void iscsi_dump_sess_ops(struct iscsi_sess_ops *); -extern void iscsi_print_params(struct iscsi_param_list *); -extern int iscsi_create_default_params(struct iscsi_param_list **); -extern int iscsi_set_keys_to_negotiate(int, struct iscsi_param_list *); -extern int iscsi_set_keys_irrelevant_for_discovery(struct iscsi_param_list *); -extern int iscsi_copy_param_list(struct iscsi_param_list **, - struct iscsi_param_list *, int); -extern int iscsi_change_param_value(char *, struct iscsi_param_list *, int); -extern void iscsi_release_param_list(struct iscsi_param_list *); -extern struct iscsi_param *iscsi_find_param_from_key(char *, struct iscsi_param_list *); -extern int iscsi_extract_key_value(char *, char **, char **); -extern int iscsi_update_param_value(struct iscsi_param *, char *); -extern int iscsi_decode_text_input(u8, u8, char *, u32, struct iscsi_param_list *); -extern int iscsi_encode_text_output(u8, u8, char *, u32 *, - struct iscsi_param_list *); -extern int iscsi_check_negotiated_keys(struct iscsi_param_list *); -extern void iscsi_set_connection_parameters(struct iscsi_conn_ops *, - struct iscsi_param_list *); -extern void iscsi_set_session_parameters(struct iscsi_sess_ops *, - struct iscsi_param_list *, int); - -#define YES "Yes" -#define NO "No" -#define ALL "All" -#define IRRELEVANT "Irrelevant" -#define NONE "None" -#define NOTUNDERSTOOD "NotUnderstood" -#define REJECT "Reject" - -/* - * The Parameter Names. - */ -#define AUTHMETHOD "AuthMethod" -#define HEADERDIGEST "HeaderDigest" -#define DATADIGEST "DataDigest" -#define MAXCONNECTIONS "MaxConnections" -#define SENDTARGETS "SendTargets" -#define TARGETNAME "TargetName" -#define INITIATORNAME "InitiatorName" -#define TARGETALIAS "TargetAlias" -#define INITIATORALIAS "InitiatorAlias" -#define TARGETADDRESS "TargetAddress" -#define TARGETPORTALGROUPTAG "TargetPortalGroupTag" -#define INITIALR2T "InitialR2T" -#define IMMEDIATEDATA "ImmediateData" -#define MAXRECVDATASEGMENTLENGTH "MaxRecvDataSegmentLength" -#define MAXBURSTLENGTH "MaxBurstLength" -#define FIRSTBURSTLENGTH "FirstBurstLength" -#define DEFAULTTIME2WAIT "DefaultTime2Wait" -#define DEFAULTTIME2RETAIN "DefaultTime2Retain" -#define MAXOUTSTANDINGR2T "MaxOutstandingR2T" -#define DATAPDUINORDER "DataPDUInOrder" -#define DATASEQUENCEINORDER "DataSequenceInOrder" -#define ERRORRECOVERYLEVEL "ErrorRecoveryLevel" -#define SESSIONTYPE "SessionType" -#define IFMARKER "IFMarker" -#define OFMARKER "OFMarker" -#define IFMARKINT "IFMarkInt" -#define OFMARKINT "OFMarkInt" -#define X_EXTENSIONKEY "X-com.sbei.version" -#define X_EXTENSIONKEY_CISCO_NEW "X-com.cisco.protocol" -#define X_EXTENSIONKEY_CISCO_OLD "X-com.cisco.iscsi.draft" - -/* - * For AuthMethod. - */ -#define KRB5 "KRB5" -#define SPKM1 "SPKM1" -#define SPKM2 "SPKM2" -#define SRP "SRP" -#define CHAP "CHAP" - -/* - * Initial values for Parameter Negotiation. - */ -#define INITIAL_AUTHMETHOD CHAP -#define INITIAL_HEADERDIGEST "CRC32C,None" -#define INITIAL_DATADIGEST "CRC32C,None" -#define INITIAL_MAXCONNECTIONS "1" -#define INITIAL_SENDTARGETS ALL -#define INITIAL_TARGETNAME "LIO.Target" -#define INITIAL_INITIATORNAME "LIO.Initiator" -#define INITIAL_TARGETALIAS "LIO Target" -#define INITIAL_INITIATORALIAS "LIO Initiator" -#define INITIAL_TARGETADDRESS "0.0.0.0:0000,0" -#define INITIAL_TARGETPORTALGROUPTAG "1" -#define INITIAL_INITIALR2T YES -#define INITIAL_IMMEDIATEDATA YES -#define INITIAL_MAXRECVDATASEGMENTLENGTH "8192" -#define INITIAL_MAXBURSTLENGTH "262144" -#define INITIAL_FIRSTBURSTLENGTH "65536" -#define INITIAL_DEFAULTTIME2WAIT "2" -#define INITIAL_DEFAULTTIME2RETAIN "20" -#define INITIAL_MAXOUTSTANDINGR2T "1" -#define INITIAL_DATAPDUINORDER YES -#define INITIAL_DATASEQUENCEINORDER YES -#define INITIAL_ERRORRECOVERYLEVEL "0" -#define INITIAL_SESSIONTYPE NORMAL -#define INITIAL_IFMARKER NO -#define INITIAL_OFMARKER NO -#define INITIAL_IFMARKINT "2048~65535" -#define INITIAL_OFMARKINT "2048~65535" - -/* - * For [Header,Data]Digests. - */ -#define CRC32C "CRC32C" - -/* - * For SessionType. - */ -#define DISCOVERY "Discovery" -#define NORMAL "Normal" - -/* - * struct iscsi_param->use - */ -#define USE_LEADING_ONLY 0x01 -#define USE_INITIAL_ONLY 0x02 -#define USE_ALL 0x04 - -#define IS_USE_LEADING_ONLY(p) ((p)->use & USE_LEADING_ONLY) -#define IS_USE_INITIAL_ONLY(p) ((p)->use & USE_INITIAL_ONLY) -#define IS_USE_ALL(p) ((p)->use & USE_ALL) - -#define SET_USE_INITIAL_ONLY(p) ((p)->use |= USE_INITIAL_ONLY) - -/* - * struct iscsi_param->sender - */ -#define SENDER_INITIATOR 0x01 -#define SENDER_TARGET 0x02 -#define SENDER_BOTH 0x03 -/* Used in iscsi_check_key() */ -#define SENDER_RECEIVER 0x04 - -#define IS_SENDER_INITIATOR(p) ((p)->sender & SENDER_INITIATOR) -#define IS_SENDER_TARGET(p) ((p)->sender & SENDER_TARGET) -#define IS_SENDER_BOTH(p) ((p)->sender & SENDER_BOTH) - -/* - * struct iscsi_param->scope - */ -#define SCOPE_CONNECTION_ONLY 0x01 -#define SCOPE_SESSION_WIDE 0x02 - -#define IS_SCOPE_CONNECTION_ONLY(p) ((p)->scope & SCOPE_CONNECTION_ONLY) -#define IS_SCOPE_SESSION_WIDE(p) ((p)->scope & SCOPE_SESSION_WIDE) - -/* - * struct iscsi_param->phase - */ -#define PHASE_SECURITY 0x01 -#define PHASE_OPERATIONAL 0x02 -#define PHASE_DECLARATIVE 0x04 -#define PHASE_FFP0 0x08 - -#define IS_PHASE_SECURITY(p) ((p)->phase & PHASE_SECURITY) -#define IS_PHASE_OPERATIONAL(p) ((p)->phase & PHASE_OPERATIONAL) -#define IS_PHASE_DECLARATIVE(p) ((p)->phase & PHASE_DECLARATIVE) -#define IS_PHASE_FFP0(p) ((p)->phase & PHASE_FFP0) - -/* - * struct iscsi_param->type - */ -#define TYPE_BOOL_AND 0x01 -#define TYPE_BOOL_OR 0x02 -#define TYPE_NUMBER 0x04 -#define TYPE_NUMBER_RANGE 0x08 -#define TYPE_STRING 0x10 -#define TYPE_VALUE_LIST 0x20 - -#define IS_TYPE_BOOL_AND(p) ((p)->type & TYPE_BOOL_AND) -#define IS_TYPE_BOOL_OR(p) ((p)->type & TYPE_BOOL_OR) -#define IS_TYPE_NUMBER(p) ((p)->type & TYPE_NUMBER) -#define IS_TYPE_NUMBER_RANGE(p) ((p)->type & TYPE_NUMBER_RANGE) -#define IS_TYPE_STRING(p) ((p)->type & TYPE_STRING) -#define IS_TYPE_VALUE_LIST(p) ((p)->type & TYPE_VALUE_LIST) - -/* - * struct iscsi_param->type_range - */ -#define TYPERANGE_BOOL_AND 0x0001 -#define TYPERANGE_BOOL_OR 0x0002 -#define TYPERANGE_0_TO_2 0x0004 -#define TYPERANGE_0_TO_3600 0x0008 -#define TYPERANGE_0_TO_32767 0x0010 -#define TYPERANGE_0_TO_65535 0x0020 -#define TYPERANGE_1_TO_65535 0x0040 -#define TYPERANGE_2_TO_3600 0x0080 -#define TYPERANGE_512_TO_16777215 0x0100 -#define TYPERANGE_AUTH 0x0200 -#define TYPERANGE_DIGEST 0x0400 -#define TYPERANGE_ISCSINAME 0x0800 -#define TYPERANGE_MARKINT 0x1000 -#define TYPERANGE_SESSIONTYPE 0x2000 -#define TYPERANGE_TARGETADDRESS 0x4000 -#define TYPERANGE_UTF8 0x8000 - -#define IS_TYPERANGE_0_TO_2(p) ((p)->type_range & TYPERANGE_0_TO_2) -#define IS_TYPERANGE_0_TO_3600(p) ((p)->type_range & TYPERANGE_0_TO_3600) -#define IS_TYPERANGE_0_TO_32767(p) ((p)->type_range & TYPERANGE_0_TO_32767) -#define IS_TYPERANGE_0_TO_65535(p) ((p)->type_range & TYPERANGE_0_TO_65535) -#define IS_TYPERANGE_1_TO_65535(p) ((p)->type_range & TYPERANGE_1_TO_65535) -#define IS_TYPERANGE_2_TO_3600(p) ((p)->type_range & TYPERANGE_2_TO_3600) -#define IS_TYPERANGE_512_TO_16777215(p) ((p)->type_range & \ - TYPERANGE_512_TO_16777215) -#define IS_TYPERANGE_AUTH_PARAM(p) ((p)->type_range & TYPERANGE_AUTH) -#define IS_TYPERANGE_DIGEST_PARAM(p) ((p)->type_range & TYPERANGE_DIGEST) -#define IS_TYPERANGE_SESSIONTYPE(p) ((p)->type_range & \ - TYPERANGE_SESSIONTYPE) - -/* - * struct iscsi_param->state - */ -#define PSTATE_ACCEPTOR 0x01 -#define PSTATE_NEGOTIATE 0x02 -#define PSTATE_PROPOSER 0x04 -#define PSTATE_IRRELEVANT 0x08 -#define PSTATE_REJECT 0x10 -#define PSTATE_REPLY_OPTIONAL 0x20 -#define PSTATE_RESPONSE_GOT 0x40 -#define PSTATE_RESPONSE_SENT 0x80 - -#define IS_PSTATE_ACCEPTOR(p) ((p)->state & PSTATE_ACCEPTOR) -#define IS_PSTATE_NEGOTIATE(p) ((p)->state & PSTATE_NEGOTIATE) -#define IS_PSTATE_PROPOSER(p) ((p)->state & PSTATE_PROPOSER) -#define IS_PSTATE_IRRELEVANT(p) ((p)->state & PSTATE_IRRELEVANT) -#define IS_PSTATE_REJECT(p) ((p)->state & PSTATE_REJECT) -#define IS_PSTATE_REPLY_OPTIONAL(p) ((p)->state & PSTATE_REPLY_OPTIONAL) -#define IS_PSTATE_RESPONSE_GOT(p) ((p)->state & PSTATE_RESPONSE_GOT) -#define IS_PSTATE_RESPONSE_SENT(p) ((p)->state & PSTATE_RESPONSE_SENT) - -#define SET_PSTATE_ACCEPTOR(p) ((p)->state |= PSTATE_ACCEPTOR) -#define SET_PSTATE_NEGOTIATE(p) ((p)->state |= PSTATE_NEGOTIATE) -#define SET_PSTATE_PROPOSER(p) ((p)->state |= PSTATE_PROPOSER) -#define SET_PSTATE_IRRELEVANT(p) ((p)->state |= PSTATE_IRRELEVANT) -#define SET_PSTATE_REJECT(p) ((p)->state |= PSTATE_REJECT) -#define SET_PSTATE_REPLY_OPTIONAL(p) ((p)->state |= PSTATE_REPLY_OPTIONAL) -#define SET_PSTATE_RESPONSE_GOT(p) ((p)->state |= PSTATE_RESPONSE_GOT) -#define SET_PSTATE_RESPONSE_SENT(p) ((p)->state |= PSTATE_RESPONSE_SENT) - -#endif /* ISCSI_PARAMETERS_H */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.c b/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.c deleted file mode 100644 index fc694082bfc0..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.c +++ /dev/null @@ -1,664 +0,0 @@ -/******************************************************************************* - * This file contains main functions related to iSCSI DataSequenceInOrder=No - * and DataPDUInOrder=No. - * - \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_util.h" -#include "iscsi_target_seq_pdu_list.h" - -#define OFFLOAD_BUF_SIZE 32768 - -void iscsit_dump_seq_list(struct iscsi_cmd *cmd) -{ - int i; - struct iscsi_seq *seq; - - pr_debug("Dumping Sequence List for ITT: 0x%08x:\n", - cmd->init_task_tag); - - for (i = 0; i < cmd->seq_count; i++) { - seq = &cmd->seq_list[i]; - pr_debug("i: %d, pdu_start: %d, pdu_count: %d," - " offset: %d, xfer_len: %d, seq_send_order: %d," - " seq_no: %d\n", i, seq->pdu_start, seq->pdu_count, - seq->offset, seq->xfer_len, seq->seq_send_order, - seq->seq_no); - } -} - -void iscsit_dump_pdu_list(struct iscsi_cmd *cmd) -{ - int i; - struct iscsi_pdu *pdu; - - pr_debug("Dumping PDU List for ITT: 0x%08x:\n", - cmd->init_task_tag); - - for (i = 0; i < cmd->pdu_count; i++) { - pdu = &cmd->pdu_list[i]; - pr_debug("i: %d, offset: %d, length: %d," - " pdu_send_order: %d, seq_no: %d\n", i, pdu->offset, - pdu->length, pdu->pdu_send_order, pdu->seq_no); - } -} - -static void iscsit_ordered_seq_lists( - struct iscsi_cmd *cmd, - u8 type) -{ - u32 i, seq_count = 0; - - for (i = 0; i < cmd->seq_count; i++) { - if (cmd->seq_list[i].type != SEQTYPE_NORMAL) - continue; - cmd->seq_list[i].seq_send_order = seq_count++; - } -} - -static void iscsit_ordered_pdu_lists( - struct iscsi_cmd *cmd, - u8 type) -{ - u32 i, pdu_send_order = 0, seq_no = 0; - - for (i = 0; i < cmd->pdu_count; i++) { -redo: - if (cmd->pdu_list[i].seq_no == seq_no) { - cmd->pdu_list[i].pdu_send_order = pdu_send_order++; - continue; - } - seq_no++; - pdu_send_order = 0; - goto redo; - } -} - -/* - * Generate count random values into array. - * Use 0x80000000 to mark generates valued in array[]. - */ -static void iscsit_create_random_array(u32 *array, u32 count) -{ - int i, j, k; - - if (count == 1) { - array[0] = 0; - return; - } - - for (i = 0; i < count; i++) { -redo: - get_random_bytes(&j, sizeof(u32)); - j = (1 + (int) (9999 + 1) - j) % count; - for (k = 0; k < i + 1; k++) { - j |= 0x80000000; - if ((array[k] & 0x80000000) && (array[k] == j)) - goto redo; - } - array[i] = j; - } - - for (i = 0; i < count; i++) - array[i] &= ~0x80000000; -} - -static int iscsit_randomize_pdu_lists( - struct iscsi_cmd *cmd, - u8 type) -{ - int i = 0; - u32 *array, pdu_count, seq_count = 0, seq_no = 0, seq_offset = 0; - - for (pdu_count = 0; pdu_count < cmd->pdu_count; pdu_count++) { -redo: - if (cmd->pdu_list[pdu_count].seq_no == seq_no) { - seq_count++; - continue; - } - array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL); - if (!array) { - pr_err("Unable to allocate memory" - " for random array.\n"); - return -1; - } - iscsit_create_random_array(array, seq_count); - - for (i = 0; i < seq_count; i++) - cmd->pdu_list[seq_offset+i].pdu_send_order = array[i]; - - kfree(array); - - seq_offset += seq_count; - seq_count = 0; - seq_no++; - goto redo; - } - - if (seq_count) { - array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL); - if (!array) { - pr_err("Unable to allocate memory for" - " random array.\n"); - return -1; - } - iscsit_create_random_array(array, seq_count); - - for (i = 0; i < seq_count; i++) - cmd->pdu_list[seq_offset+i].pdu_send_order = array[i]; - - kfree(array); - } - - return 0; -} - -static int iscsit_randomize_seq_lists( - struct iscsi_cmd *cmd, - u8 type) -{ - int i, j = 0; - u32 *array, seq_count = cmd->seq_count; - - if ((type == PDULIST_IMMEDIATE) || (type == PDULIST_UNSOLICITED)) - seq_count--; - else if (type == PDULIST_IMMEDIATE_AND_UNSOLICITED) - seq_count -= 2; - - if (!seq_count) - return 0; - - array = kzalloc(seq_count * sizeof(u32), GFP_KERNEL); - if (!array) { - pr_err("Unable to allocate memory for random array.\n"); - return -1; - } - iscsit_create_random_array(array, seq_count); - - for (i = 0; i < cmd->seq_count; i++) { - if (cmd->seq_list[i].type != SEQTYPE_NORMAL) - continue; - cmd->seq_list[i].seq_send_order = array[j++]; - } - - kfree(array); - return 0; -} - -static void iscsit_determine_counts_for_list( - struct iscsi_cmd *cmd, - struct iscsi_build_list *bl, - u32 *seq_count, - u32 *pdu_count) -{ - int check_immediate = 0; - u32 burstlength = 0, offset = 0; - u32 unsolicited_data_length = 0; - struct iscsi_conn *conn = cmd->conn; - - if ((bl->type == PDULIST_IMMEDIATE) || - (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED)) - check_immediate = 1; - - if ((bl->type == PDULIST_UNSOLICITED) || - (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED)) - unsolicited_data_length = (cmd->data_length > - conn->sess->sess_ops->FirstBurstLength) ? - conn->sess->sess_ops->FirstBurstLength : cmd->data_length; - - while (offset < cmd->data_length) { - *pdu_count += 1; - - if (check_immediate) { - check_immediate = 0; - offset += bl->immediate_data_length; - *seq_count += 1; - if (unsolicited_data_length) - unsolicited_data_length -= - bl->immediate_data_length; - continue; - } - if (unsolicited_data_length > 0) { - if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) - >= cmd->data_length) { - unsolicited_data_length -= - (cmd->data_length - offset); - offset += (cmd->data_length - offset); - continue; - } - if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) - >= conn->sess->sess_ops->FirstBurstLength) { - unsolicited_data_length -= - (conn->sess->sess_ops->FirstBurstLength - - offset); - offset += (conn->sess->sess_ops->FirstBurstLength - - offset); - burstlength = 0; - *seq_count += 1; - continue; - } - - offset += conn->conn_ops->MaxRecvDataSegmentLength; - unsolicited_data_length -= - conn->conn_ops->MaxRecvDataSegmentLength; - continue; - } - if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= - cmd->data_length) { - offset += (cmd->data_length - offset); - continue; - } - if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >= - conn->sess->sess_ops->MaxBurstLength) { - offset += (conn->sess->sess_ops->MaxBurstLength - - burstlength); - burstlength = 0; - *seq_count += 1; - continue; - } - - burstlength += conn->conn_ops->MaxRecvDataSegmentLength; - offset += conn->conn_ops->MaxRecvDataSegmentLength; - } -} - - -/* - * Builds PDU and/or Sequence list, called while DataSequenceInOrder=No - * and DataPDUInOrder=No. - */ -static int iscsit_build_pdu_and_seq_list( - struct iscsi_cmd *cmd, - struct iscsi_build_list *bl) -{ - int check_immediate = 0, datapduinorder, datasequenceinorder; - u32 burstlength = 0, offset = 0, i = 0; - u32 pdu_count = 0, seq_no = 0, unsolicited_data_length = 0; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_pdu *pdu = cmd->pdu_list; - struct iscsi_seq *seq = cmd->seq_list; - - datapduinorder = conn->sess->sess_ops->DataPDUInOrder; - datasequenceinorder = conn->sess->sess_ops->DataSequenceInOrder; - - if ((bl->type == PDULIST_IMMEDIATE) || - (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED)) - check_immediate = 1; - - if ((bl->type == PDULIST_UNSOLICITED) || - (bl->type == PDULIST_IMMEDIATE_AND_UNSOLICITED)) - unsolicited_data_length = (cmd->data_length > - conn->sess->sess_ops->FirstBurstLength) ? - conn->sess->sess_ops->FirstBurstLength : cmd->data_length; - - while (offset < cmd->data_length) { - pdu_count++; - if (!datapduinorder) { - pdu[i].offset = offset; - pdu[i].seq_no = seq_no; - } - if (!datasequenceinorder && (pdu_count == 1)) { - seq[seq_no].pdu_start = i; - seq[seq_no].seq_no = seq_no; - seq[seq_no].offset = offset; - seq[seq_no].orig_offset = offset; - } - - if (check_immediate) { - check_immediate = 0; - if (!datapduinorder) { - pdu[i].type = PDUTYPE_IMMEDIATE; - pdu[i++].length = bl->immediate_data_length; - } - if (!datasequenceinorder) { - seq[seq_no].type = SEQTYPE_IMMEDIATE; - seq[seq_no].pdu_count = 1; - seq[seq_no].xfer_len = - bl->immediate_data_length; - } - offset += bl->immediate_data_length; - pdu_count = 0; - seq_no++; - if (unsolicited_data_length) - unsolicited_data_length -= - bl->immediate_data_length; - continue; - } - if (unsolicited_data_length > 0) { - if ((offset + - conn->conn_ops->MaxRecvDataSegmentLength) >= - cmd->data_length) { - if (!datapduinorder) { - pdu[i].type = PDUTYPE_UNSOLICITED; - pdu[i].length = - (cmd->data_length - offset); - } - if (!datasequenceinorder) { - seq[seq_no].type = SEQTYPE_UNSOLICITED; - seq[seq_no].pdu_count = pdu_count; - seq[seq_no].xfer_len = (burstlength + - (cmd->data_length - offset)); - } - unsolicited_data_length -= - (cmd->data_length - offset); - offset += (cmd->data_length - offset); - continue; - } - if ((offset + - conn->conn_ops->MaxRecvDataSegmentLength) >= - conn->sess->sess_ops->FirstBurstLength) { - if (!datapduinorder) { - pdu[i].type = PDUTYPE_UNSOLICITED; - pdu[i++].length = - (conn->sess->sess_ops->FirstBurstLength - - offset); - } - if (!datasequenceinorder) { - seq[seq_no].type = SEQTYPE_UNSOLICITED; - seq[seq_no].pdu_count = pdu_count; - seq[seq_no].xfer_len = (burstlength + - (conn->sess->sess_ops->FirstBurstLength - - offset)); - } - unsolicited_data_length -= - (conn->sess->sess_ops->FirstBurstLength - - offset); - offset += (conn->sess->sess_ops->FirstBurstLength - - offset); - burstlength = 0; - pdu_count = 0; - seq_no++; - continue; - } - - if (!datapduinorder) { - pdu[i].type = PDUTYPE_UNSOLICITED; - pdu[i++].length = - conn->conn_ops->MaxRecvDataSegmentLength; - } - burstlength += conn->conn_ops->MaxRecvDataSegmentLength; - offset += conn->conn_ops->MaxRecvDataSegmentLength; - unsolicited_data_length -= - conn->conn_ops->MaxRecvDataSegmentLength; - continue; - } - if ((offset + conn->conn_ops->MaxRecvDataSegmentLength) >= - cmd->data_length) { - if (!datapduinorder) { - pdu[i].type = PDUTYPE_NORMAL; - pdu[i].length = (cmd->data_length - offset); - } - if (!datasequenceinorder) { - seq[seq_no].type = SEQTYPE_NORMAL; - seq[seq_no].pdu_count = pdu_count; - seq[seq_no].xfer_len = (burstlength + - (cmd->data_length - offset)); - } - offset += (cmd->data_length - offset); - continue; - } - if ((burstlength + conn->conn_ops->MaxRecvDataSegmentLength) >= - conn->sess->sess_ops->MaxBurstLength) { - if (!datapduinorder) { - pdu[i].type = PDUTYPE_NORMAL; - pdu[i++].length = - (conn->sess->sess_ops->MaxBurstLength - - burstlength); - } - if (!datasequenceinorder) { - seq[seq_no].type = SEQTYPE_NORMAL; - seq[seq_no].pdu_count = pdu_count; - seq[seq_no].xfer_len = (burstlength + - (conn->sess->sess_ops->MaxBurstLength - - burstlength)); - } - offset += (conn->sess->sess_ops->MaxBurstLength - - burstlength); - burstlength = 0; - pdu_count = 0; - seq_no++; - continue; - } - - if (!datapduinorder) { - pdu[i].type = PDUTYPE_NORMAL; - pdu[i++].length = - conn->conn_ops->MaxRecvDataSegmentLength; - } - burstlength += conn->conn_ops->MaxRecvDataSegmentLength; - offset += conn->conn_ops->MaxRecvDataSegmentLength; - } - - if (!datasequenceinorder) { - if (bl->data_direction & ISCSI_PDU_WRITE) { - if (bl->randomize & RANDOM_R2T_OFFSETS) { - if (iscsit_randomize_seq_lists(cmd, bl->type) - < 0) - return -1; - } else - iscsit_ordered_seq_lists(cmd, bl->type); - } else if (bl->data_direction & ISCSI_PDU_READ) { - if (bl->randomize & RANDOM_DATAIN_SEQ_OFFSETS) { - if (iscsit_randomize_seq_lists(cmd, bl->type) - < 0) - return -1; - } else - iscsit_ordered_seq_lists(cmd, bl->type); - } -#if 0 - iscsit_dump_seq_list(cmd); -#endif - } - if (!datapduinorder) { - if (bl->data_direction & ISCSI_PDU_WRITE) { - if (bl->randomize & RANDOM_DATAOUT_PDU_OFFSETS) { - if (iscsit_randomize_pdu_lists(cmd, bl->type) - < 0) - return -1; - } else - iscsit_ordered_pdu_lists(cmd, bl->type); - } else if (bl->data_direction & ISCSI_PDU_READ) { - if (bl->randomize & RANDOM_DATAIN_PDU_OFFSETS) { - if (iscsit_randomize_pdu_lists(cmd, bl->type) - < 0) - return -1; - } else - iscsit_ordered_pdu_lists(cmd, bl->type); - } -#if 0 - iscsit_dump_pdu_list(cmd); -#endif - } - - return 0; -} - -/* - * Only called while DataSequenceInOrder=No or DataPDUInOrder=No. - */ -int iscsit_do_build_list( - struct iscsi_cmd *cmd, - struct iscsi_build_list *bl) -{ - u32 pdu_count = 0, seq_count = 1; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_pdu *pdu = NULL; - struct iscsi_seq *seq = NULL; - - iscsit_determine_counts_for_list(cmd, bl, &seq_count, &pdu_count); - - if (!conn->sess->sess_ops->DataSequenceInOrder) { - seq = kzalloc(seq_count * sizeof(struct iscsi_seq), GFP_ATOMIC); - if (!seq) { - pr_err("Unable to allocate struct iscsi_seq list\n"); - return -1; - } - cmd->seq_list = seq; - cmd->seq_count = seq_count; - } - - if (!conn->sess->sess_ops->DataPDUInOrder) { - pdu = kzalloc(pdu_count * sizeof(struct iscsi_pdu), GFP_ATOMIC); - if (!pdu) { - pr_err("Unable to allocate struct iscsi_pdu list.\n"); - kfree(seq); - return -1; - } - cmd->pdu_list = pdu; - cmd->pdu_count = pdu_count; - } - - return iscsit_build_pdu_and_seq_list(cmd, bl); -} - -struct iscsi_pdu *iscsit_get_pdu_holder( - struct iscsi_cmd *cmd, - u32 offset, - u32 length) -{ - u32 i; - struct iscsi_pdu *pdu = NULL; - - if (!cmd->pdu_list) { - pr_err("struct iscsi_cmd->pdu_list is NULL!\n"); - return NULL; - } - - pdu = &cmd->pdu_list[0]; - - for (i = 0; i < cmd->pdu_count; i++) - if ((pdu[i].offset == offset) && (pdu[i].length == length)) - return &pdu[i]; - - pr_err("Unable to locate PDU holder for ITT: 0x%08x, Offset:" - " %u, Length: %u\n", cmd->init_task_tag, offset, length); - return NULL; -} - -struct iscsi_pdu *iscsit_get_pdu_holder_for_seq( - struct iscsi_cmd *cmd, - struct iscsi_seq *seq) -{ - u32 i; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_pdu *pdu = NULL; - - if (!cmd->pdu_list) { - pr_err("struct iscsi_cmd->pdu_list is NULL!\n"); - return NULL; - } - - if (conn->sess->sess_ops->DataSequenceInOrder) { -redo: - pdu = &cmd->pdu_list[cmd->pdu_start]; - - for (i = 0; pdu[i].seq_no != cmd->seq_no; i++) { -#if 0 - pr_debug("pdu[i].seq_no: %d, pdu[i].pdu" - "_send_order: %d, pdu[i].offset: %d," - " pdu[i].length: %d\n", pdu[i].seq_no, - pdu[i].pdu_send_order, pdu[i].offset, - pdu[i].length); -#endif - if (pdu[i].pdu_send_order == cmd->pdu_send_order) { - cmd->pdu_send_order++; - return &pdu[i]; - } - } - - cmd->pdu_start += cmd->pdu_send_order; - cmd->pdu_send_order = 0; - cmd->seq_no++; - - if (cmd->pdu_start < cmd->pdu_count) - goto redo; - - pr_err("Command ITT: 0x%08x unable to locate" - " struct iscsi_pdu for cmd->pdu_send_order: %u.\n", - cmd->init_task_tag, cmd->pdu_send_order); - return NULL; - } else { - if (!seq) { - pr_err("struct iscsi_seq is NULL!\n"); - return NULL; - } -#if 0 - pr_debug("seq->pdu_start: %d, seq->pdu_count: %d," - " seq->seq_no: %d\n", seq->pdu_start, seq->pdu_count, - seq->seq_no); -#endif - pdu = &cmd->pdu_list[seq->pdu_start]; - - if (seq->pdu_send_order == seq->pdu_count) { - pr_err("Command ITT: 0x%08x seq->pdu_send" - "_order: %u equals seq->pdu_count: %u\n", - cmd->init_task_tag, seq->pdu_send_order, - seq->pdu_count); - return NULL; - } - - for (i = 0; i < seq->pdu_count; i++) { - if (pdu[i].pdu_send_order == seq->pdu_send_order) { - seq->pdu_send_order++; - return &pdu[i]; - } - } - - pr_err("Command ITT: 0x%08x unable to locate iscsi" - "_pdu_t for seq->pdu_send_order: %u.\n", - cmd->init_task_tag, seq->pdu_send_order); - return NULL; - } - - return NULL; -} - -struct iscsi_seq *iscsit_get_seq_holder( - struct iscsi_cmd *cmd, - u32 offset, - u32 length) -{ - u32 i; - - if (!cmd->seq_list) { - pr_err("struct iscsi_cmd->seq_list is NULL!\n"); - return NULL; - } - - for (i = 0; i < cmd->seq_count; i++) { -#if 0 - pr_debug("seq_list[i].orig_offset: %d, seq_list[i]." - "xfer_len: %d, seq_list[i].seq_no %u\n", - cmd->seq_list[i].orig_offset, cmd->seq_list[i].xfer_len, - cmd->seq_list[i].seq_no); -#endif - if ((cmd->seq_list[i].orig_offset + - cmd->seq_list[i].xfer_len) >= - (offset + length)) - return &cmd->seq_list[i]; - } - - pr_err("Unable to locate Sequence holder for ITT: 0x%08x," - " Offset: %u, Length: %u\n", cmd->init_task_tag, offset, - length); - return NULL; -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.h b/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.h deleted file mode 100644 index 0d52a10e3069..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_seq_pdu_list.h +++ /dev/null @@ -1,86 +0,0 @@ -#ifndef ISCSI_SEQ_AND_PDU_LIST_H -#define ISCSI_SEQ_AND_PDU_LIST_H - -/* struct iscsi_pdu->status */ -#define DATAOUT_PDU_SENT 1 - -/* struct iscsi_seq->type */ -#define SEQTYPE_IMMEDIATE 1 -#define SEQTYPE_UNSOLICITED 2 -#define SEQTYPE_NORMAL 3 - -/* struct iscsi_seq->status */ -#define DATAOUT_SEQUENCE_GOT_R2T 1 -#define DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY 2 -#define DATAOUT_SEQUENCE_COMPLETE 3 - -/* iscsi_determine_counts_for_list() type */ -#define PDULIST_NORMAL 1 -#define PDULIST_IMMEDIATE 2 -#define PDULIST_UNSOLICITED 3 -#define PDULIST_IMMEDIATE_AND_UNSOLICITED 4 - -/* struct iscsi_pdu->type */ -#define PDUTYPE_IMMEDIATE 1 -#define PDUTYPE_UNSOLICITED 2 -#define PDUTYPE_NORMAL 3 - -/* struct iscsi_pdu->status */ -#define ISCSI_PDU_NOT_RECEIVED 0 -#define ISCSI_PDU_RECEIVED_OK 1 -#define ISCSI_PDU_CRC_FAILED 2 -#define ISCSI_PDU_TIMED_OUT 3 - -/* struct iscsi_build_list->randomize */ -#define RANDOM_DATAIN_PDU_OFFSETS 0x01 -#define RANDOM_DATAIN_SEQ_OFFSETS 0x02 -#define RANDOM_DATAOUT_PDU_OFFSETS 0x04 -#define RANDOM_R2T_OFFSETS 0x08 - -/* struct iscsi_build_list->data_direction */ -#define ISCSI_PDU_READ 0x01 -#define ISCSI_PDU_WRITE 0x02 - -struct iscsi_build_list { - int data_direction; - int randomize; - int type; - int immediate_data_length; -}; - -struct iscsi_pdu { - int status; - int type; - u8 flags; - u32 data_sn; - u32 length; - u32 offset; - u32 pdu_send_order; - u32 seq_no; -} ____cacheline_aligned; - -struct iscsi_seq { - int sent; - int status; - int type; - u32 data_sn; - u32 first_datasn; - u32 last_datasn; - u32 next_burst_len; - u32 pdu_start; - u32 pdu_count; - u32 offset; - u32 orig_offset; - u32 pdu_send_order; - u32 r2t_sn; - u32 seq_send_order; - u32 seq_no; - u32 xfer_len; -} ____cacheline_aligned; - -extern int iscsit_do_build_list(struct iscsi_cmd *, struct iscsi_build_list *); -extern struct iscsi_pdu *iscsit_get_pdu_holder(struct iscsi_cmd *, u32, u32); -extern struct iscsi_pdu *iscsit_get_pdu_holder_for_seq(struct iscsi_cmd *, struct iscsi_seq *); -extern struct iscsi_seq *iscsit_get_seq_holder(struct iscsi_cmd *, u32, u32); - -#endif /* ISCSI_SEQ_AND_PDU_LIST_H */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_stat.c b/trunk/drivers/target/iscsi/iscsi_target_stat.c deleted file mode 100644 index bbdbe9301b27..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_stat.c +++ /dev/null @@ -1,950 +0,0 @@ -/******************************************************************************* - * Modern ConfigFS group context specific iSCSI statistics based on original - * iscsi_target_mib.c code - * - * Copyright (c) 2011 Rising Tide Systems - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_parameters.h" -#include "iscsi_target_device.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_util.h" -#include "iscsi_target_stat.h" - -#ifndef INITIAL_JIFFIES -#define INITIAL_JIFFIES ((unsigned long)(unsigned int) (-300*HZ)) -#endif - -/* Instance Attributes Table */ -#define ISCSI_INST_NUM_NODES 1 -#define ISCSI_INST_DESCR "Storage Engine Target" -#define ISCSI_INST_LAST_FAILURE_TYPE 0 -#define ISCSI_DISCONTINUITY_TIME 0 - -#define ISCSI_NODE_INDEX 1 - -#define ISPRINT(a) ((a >= ' ') && (a <= '~')) - -/**************************************************************************** - * iSCSI MIB Tables - ****************************************************************************/ -/* - * Instance Attributes Table - */ -CONFIGFS_EATTR_STRUCT(iscsi_stat_instance, iscsi_wwn_stat_grps); -#define ISCSI_STAT_INSTANCE_ATTR(_name, _mode) \ -static struct iscsi_stat_instance_attribute \ - iscsi_stat_instance_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_instance_show_attr_##_name, \ - iscsi_stat_instance_store_attr_##_name); - -#define ISCSI_STAT_INSTANCE_ATTR_RO(_name) \ -static struct iscsi_stat_instance_attribute \ - iscsi_stat_instance_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_instance_show_attr_##_name); - -static ssize_t iscsi_stat_instance_show_attr_inst( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); -} -ISCSI_STAT_INSTANCE_ATTR_RO(inst); - -static ssize_t iscsi_stat_instance_show_attr_min_ver( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DRAFT20_VERSION); -} -ISCSI_STAT_INSTANCE_ATTR_RO(min_ver); - -static ssize_t iscsi_stat_instance_show_attr_max_ver( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DRAFT20_VERSION); -} -ISCSI_STAT_INSTANCE_ATTR_RO(max_ver); - -static ssize_t iscsi_stat_instance_show_attr_portals( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_num_tpg_nps); -} -ISCSI_STAT_INSTANCE_ATTR_RO(portals); - -static ssize_t iscsi_stat_instance_show_attr_nodes( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_INST_NUM_NODES); -} -ISCSI_STAT_INSTANCE_ATTR_RO(nodes); - -static ssize_t iscsi_stat_instance_show_attr_sessions( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_nsessions); -} -ISCSI_STAT_INSTANCE_ATTR_RO(sessions); - -static ssize_t iscsi_stat_instance_show_attr_fail_sess( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; - u32 sess_err_count; - - spin_lock_bh(&sess_err->lock); - sess_err_count = (sess_err->digest_errors + - sess_err->cxn_timeout_errors + - sess_err->pdu_format_errors); - spin_unlock_bh(&sess_err->lock); - - return snprintf(page, PAGE_SIZE, "%u\n", sess_err_count); -} -ISCSI_STAT_INSTANCE_ATTR_RO(fail_sess); - -static ssize_t iscsi_stat_instance_show_attr_fail_type( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; - - return snprintf(page, PAGE_SIZE, "%u\n", - sess_err->last_sess_failure_type); -} -ISCSI_STAT_INSTANCE_ATTR_RO(fail_type); - -static ssize_t iscsi_stat_instance_show_attr_fail_rem_name( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; - - return snprintf(page, PAGE_SIZE, "%s\n", - sess_err->last_sess_fail_rem_name[0] ? - sess_err->last_sess_fail_rem_name : NONE); -} -ISCSI_STAT_INSTANCE_ATTR_RO(fail_rem_name); - -static ssize_t iscsi_stat_instance_show_attr_disc_time( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_DISCONTINUITY_TIME); -} -ISCSI_STAT_INSTANCE_ATTR_RO(disc_time); - -static ssize_t iscsi_stat_instance_show_attr_description( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - return snprintf(page, PAGE_SIZE, "%s\n", ISCSI_INST_DESCR); -} -ISCSI_STAT_INSTANCE_ATTR_RO(description); - -static ssize_t iscsi_stat_instance_show_attr_vendor( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - return snprintf(page, PAGE_SIZE, "RisingTide Systems iSCSI-Target\n"); -} -ISCSI_STAT_INSTANCE_ATTR_RO(vendor); - -static ssize_t iscsi_stat_instance_show_attr_version( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - return snprintf(page, PAGE_SIZE, "%s\n", ISCSIT_VERSION); -} -ISCSI_STAT_INSTANCE_ATTR_RO(version); - -CONFIGFS_EATTR_OPS(iscsi_stat_instance, iscsi_wwn_stat_grps, - iscsi_instance_group); - -static struct configfs_attribute *iscsi_stat_instance_attrs[] = { - &iscsi_stat_instance_inst.attr, - &iscsi_stat_instance_min_ver.attr, - &iscsi_stat_instance_max_ver.attr, - &iscsi_stat_instance_portals.attr, - &iscsi_stat_instance_nodes.attr, - &iscsi_stat_instance_sessions.attr, - &iscsi_stat_instance_fail_sess.attr, - &iscsi_stat_instance_fail_type.attr, - &iscsi_stat_instance_fail_rem_name.attr, - &iscsi_stat_instance_disc_time.attr, - &iscsi_stat_instance_description.attr, - &iscsi_stat_instance_vendor.attr, - &iscsi_stat_instance_version.attr, - NULL, -}; - -static struct configfs_item_operations iscsi_stat_instance_item_ops = { - .show_attribute = iscsi_stat_instance_attr_show, - .store_attribute = iscsi_stat_instance_attr_store, -}; - -struct config_item_type iscsi_stat_instance_cit = { - .ct_item_ops = &iscsi_stat_instance_item_ops, - .ct_attrs = iscsi_stat_instance_attrs, - .ct_owner = THIS_MODULE, -}; - -/* - * Instance Session Failure Stats Table - */ -CONFIGFS_EATTR_STRUCT(iscsi_stat_sess_err, iscsi_wwn_stat_grps); -#define ISCSI_STAT_SESS_ERR_ATTR(_name, _mode) \ -static struct iscsi_stat_sess_err_attribute \ - iscsi_stat_sess_err_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_sess_err_show_attr_##_name, \ - iscsi_stat_sess_err_store_attr_##_name); - -#define ISCSI_STAT_SESS_ERR_ATTR_RO(_name) \ -static struct iscsi_stat_sess_err_attribute \ - iscsi_stat_sess_err_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_sess_err_show_attr_##_name); - -static ssize_t iscsi_stat_sess_err_show_attr_inst( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); -} -ISCSI_STAT_SESS_ERR_ATTR_RO(inst); - -static ssize_t iscsi_stat_sess_err_show_attr_digest_errors( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; - - return snprintf(page, PAGE_SIZE, "%u\n", sess_err->digest_errors); -} -ISCSI_STAT_SESS_ERR_ATTR_RO(digest_errors); - -static ssize_t iscsi_stat_sess_err_show_attr_cxn_errors( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; - - return snprintf(page, PAGE_SIZE, "%u\n", sess_err->cxn_timeout_errors); -} -ISCSI_STAT_SESS_ERR_ATTR_RO(cxn_errors); - -static ssize_t iscsi_stat_sess_err_show_attr_format_errors( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_sess_err_stats *sess_err = &tiqn->sess_err_stats; - - return snprintf(page, PAGE_SIZE, "%u\n", sess_err->pdu_format_errors); -} -ISCSI_STAT_SESS_ERR_ATTR_RO(format_errors); - -CONFIGFS_EATTR_OPS(iscsi_stat_sess_err, iscsi_wwn_stat_grps, - iscsi_sess_err_group); - -static struct configfs_attribute *iscsi_stat_sess_err_attrs[] = { - &iscsi_stat_sess_err_inst.attr, - &iscsi_stat_sess_err_digest_errors.attr, - &iscsi_stat_sess_err_cxn_errors.attr, - &iscsi_stat_sess_err_format_errors.attr, - NULL, -}; - -static struct configfs_item_operations iscsi_stat_sess_err_item_ops = { - .show_attribute = iscsi_stat_sess_err_attr_show, - .store_attribute = iscsi_stat_sess_err_attr_store, -}; - -struct config_item_type iscsi_stat_sess_err_cit = { - .ct_item_ops = &iscsi_stat_sess_err_item_ops, - .ct_attrs = iscsi_stat_sess_err_attrs, - .ct_owner = THIS_MODULE, -}; - -/* - * Target Attributes Table - */ -CONFIGFS_EATTR_STRUCT(iscsi_stat_tgt_attr, iscsi_wwn_stat_grps); -#define ISCSI_STAT_TGT_ATTR(_name, _mode) \ -static struct iscsi_stat_tgt_attr_attribute \ - iscsi_stat_tgt_attr_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_tgt-attr_show_attr_##_name, \ - iscsi_stat_tgt_attr_store_attr_##_name); - -#define ISCSI_STAT_TGT_ATTR_RO(_name) \ -static struct iscsi_stat_tgt_attr_attribute \ - iscsi_stat_tgt_attr_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_tgt_attr_show_attr_##_name); - -static ssize_t iscsi_stat_tgt_attr_show_attr_inst( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); -} -ISCSI_STAT_TGT_ATTR_RO(inst); - -static ssize_t iscsi_stat_tgt_attr_show_attr_indx( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX); -} -ISCSI_STAT_TGT_ATTR_RO(indx); - -static ssize_t iscsi_stat_tgt_attr_show_attr_login_fails( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - u32 fail_count; - - spin_lock(&lstat->lock); - fail_count = (lstat->redirects + lstat->authorize_fails + - lstat->authenticate_fails + lstat->negotiate_fails + - lstat->other_fails); - spin_unlock(&lstat->lock); - - return snprintf(page, PAGE_SIZE, "%u\n", fail_count); -} -ISCSI_STAT_TGT_ATTR_RO(login_fails); - -static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_time( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - u32 last_fail_time; - - spin_lock(&lstat->lock); - last_fail_time = lstat->last_fail_time ? - (u32)(((u32)lstat->last_fail_time - - INITIAL_JIFFIES) * 100 / HZ) : 0; - spin_unlock(&lstat->lock); - - return snprintf(page, PAGE_SIZE, "%u\n", last_fail_time); -} -ISCSI_STAT_TGT_ATTR_RO(last_fail_time); - -static ssize_t iscsi_stat_tgt_attr_show_attr_last_fail_type( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - u32 last_fail_type; - - spin_lock(&lstat->lock); - last_fail_type = lstat->last_fail_type; - spin_unlock(&lstat->lock); - - return snprintf(page, PAGE_SIZE, "%u\n", last_fail_type); -} -ISCSI_STAT_TGT_ATTR_RO(last_fail_type); - -static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_name( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - unsigned char buf[224]; - - spin_lock(&lstat->lock); - snprintf(buf, 224, "%s", lstat->last_intr_fail_name[0] ? - lstat->last_intr_fail_name : NONE); - spin_unlock(&lstat->lock); - - return snprintf(page, PAGE_SIZE, "%s\n", buf); -} -ISCSI_STAT_TGT_ATTR_RO(fail_intr_name); - -static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr_type( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - unsigned char buf[8]; - - spin_lock(&lstat->lock); - snprintf(buf, 8, "%s", (lstat->last_intr_fail_ip_addr != NULL) ? - "ipv6" : "ipv4"); - spin_unlock(&lstat->lock); - - return snprintf(page, PAGE_SIZE, "%s\n", buf); -} -ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr_type); - -static ssize_t iscsi_stat_tgt_attr_show_attr_fail_intr_addr( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - unsigned char buf[32]; - - spin_lock(&lstat->lock); - if (lstat->last_intr_fail_ip_family == AF_INET6) - snprintf(buf, 32, "[%s]", lstat->last_intr_fail_ip_addr); - else - snprintf(buf, 32, "%s", lstat->last_intr_fail_ip_addr); - spin_unlock(&lstat->lock); - - return snprintf(page, PAGE_SIZE, "%s\n", buf); -} -ISCSI_STAT_TGT_ATTR_RO(fail_intr_addr); - -CONFIGFS_EATTR_OPS(iscsi_stat_tgt_attr, iscsi_wwn_stat_grps, - iscsi_tgt_attr_group); - -static struct configfs_attribute *iscsi_stat_tgt_attr_attrs[] = { - &iscsi_stat_tgt_attr_inst.attr, - &iscsi_stat_tgt_attr_indx.attr, - &iscsi_stat_tgt_attr_login_fails.attr, - &iscsi_stat_tgt_attr_last_fail_time.attr, - &iscsi_stat_tgt_attr_last_fail_type.attr, - &iscsi_stat_tgt_attr_fail_intr_name.attr, - &iscsi_stat_tgt_attr_fail_intr_addr_type.attr, - &iscsi_stat_tgt_attr_fail_intr_addr.attr, - NULL, -}; - -static struct configfs_item_operations iscsi_stat_tgt_attr_item_ops = { - .show_attribute = iscsi_stat_tgt_attr_attr_show, - .store_attribute = iscsi_stat_tgt_attr_attr_store, -}; - -struct config_item_type iscsi_stat_tgt_attr_cit = { - .ct_item_ops = &iscsi_stat_tgt_attr_item_ops, - .ct_attrs = iscsi_stat_tgt_attr_attrs, - .ct_owner = THIS_MODULE, -}; - -/* - * Target Login Stats Table - */ -CONFIGFS_EATTR_STRUCT(iscsi_stat_login, iscsi_wwn_stat_grps); -#define ISCSI_STAT_LOGIN(_name, _mode) \ -static struct iscsi_stat_login_attribute \ - iscsi_stat_login_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_login_show_attr_##_name, \ - iscsi_stat_login_store_attr_##_name); - -#define ISCSI_STAT_LOGIN_RO(_name) \ -static struct iscsi_stat_login_attribute \ - iscsi_stat_login_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_login_show_attr_##_name); - -static ssize_t iscsi_stat_login_show_attr_inst( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); -} -ISCSI_STAT_LOGIN_RO(inst); - -static ssize_t iscsi_stat_login_show_attr_indx( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX); -} -ISCSI_STAT_LOGIN_RO(indx); - -static ssize_t iscsi_stat_login_show_attr_accepts( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - ssize_t ret; - - spin_lock(&lstat->lock); - ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->accepts); - spin_unlock(&lstat->lock); - - return ret; -} -ISCSI_STAT_LOGIN_RO(accepts); - -static ssize_t iscsi_stat_login_show_attr_other_fails( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - ssize_t ret; - - spin_lock(&lstat->lock); - ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->other_fails); - spin_unlock(&lstat->lock); - - return ret; -} -ISCSI_STAT_LOGIN_RO(other_fails); - -static ssize_t iscsi_stat_login_show_attr_redirects( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - ssize_t ret; - - spin_lock(&lstat->lock); - ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->redirects); - spin_unlock(&lstat->lock); - - return ret; -} -ISCSI_STAT_LOGIN_RO(redirects); - -static ssize_t iscsi_stat_login_show_attr_authorize_fails( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - ssize_t ret; - - spin_lock(&lstat->lock); - ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->authorize_fails); - spin_unlock(&lstat->lock); - - return ret; -} -ISCSI_STAT_LOGIN_RO(authorize_fails); - -static ssize_t iscsi_stat_login_show_attr_authenticate_fails( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - ssize_t ret; - - spin_lock(&lstat->lock); - ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->authenticate_fails); - spin_unlock(&lstat->lock); - - return ret; -} -ISCSI_STAT_LOGIN_RO(authenticate_fails); - -static ssize_t iscsi_stat_login_show_attr_negotiate_fails( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_login_stats *lstat = &tiqn->login_stats; - ssize_t ret; - - spin_lock(&lstat->lock); - ret = snprintf(page, PAGE_SIZE, "%u\n", lstat->negotiate_fails); - spin_unlock(&lstat->lock); - - return ret; -} -ISCSI_STAT_LOGIN_RO(negotiate_fails); - -CONFIGFS_EATTR_OPS(iscsi_stat_login, iscsi_wwn_stat_grps, - iscsi_login_stats_group); - -static struct configfs_attribute *iscsi_stat_login_stats_attrs[] = { - &iscsi_stat_login_inst.attr, - &iscsi_stat_login_indx.attr, - &iscsi_stat_login_accepts.attr, - &iscsi_stat_login_other_fails.attr, - &iscsi_stat_login_redirects.attr, - &iscsi_stat_login_authorize_fails.attr, - &iscsi_stat_login_authenticate_fails.attr, - &iscsi_stat_login_negotiate_fails.attr, - NULL, -}; - -static struct configfs_item_operations iscsi_stat_login_stats_item_ops = { - .show_attribute = iscsi_stat_login_attr_show, - .store_attribute = iscsi_stat_login_attr_store, -}; - -struct config_item_type iscsi_stat_login_cit = { - .ct_item_ops = &iscsi_stat_login_stats_item_ops, - .ct_attrs = iscsi_stat_login_stats_attrs, - .ct_owner = THIS_MODULE, -}; - -/* - * Target Logout Stats Table - */ - -CONFIGFS_EATTR_STRUCT(iscsi_stat_logout, iscsi_wwn_stat_grps); -#define ISCSI_STAT_LOGOUT(_name, _mode) \ -static struct iscsi_stat_logout_attribute \ - iscsi_stat_logout_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_logout_show_attr_##_name, \ - iscsi_stat_logout_store_attr_##_name); - -#define ISCSI_STAT_LOGOUT_RO(_name) \ -static struct iscsi_stat_logout_attribute \ - iscsi_stat_logout_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_logout_show_attr_##_name); - -static ssize_t iscsi_stat_logout_show_attr_inst( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); -} -ISCSI_STAT_LOGOUT_RO(inst); - -static ssize_t iscsi_stat_logout_show_attr_indx( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - return snprintf(page, PAGE_SIZE, "%u\n", ISCSI_NODE_INDEX); -} -ISCSI_STAT_LOGOUT_RO(indx); - -static ssize_t iscsi_stat_logout_show_attr_normal_logouts( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_logout_stats *lstats = &tiqn->logout_stats; - - return snprintf(page, PAGE_SIZE, "%u\n", lstats->normal_logouts); -} -ISCSI_STAT_LOGOUT_RO(normal_logouts); - -static ssize_t iscsi_stat_logout_show_attr_abnormal_logouts( - struct iscsi_wwn_stat_grps *igrps, char *page) -{ - struct iscsi_tiqn *tiqn = container_of(igrps, - struct iscsi_tiqn, tiqn_stat_grps); - struct iscsi_logout_stats *lstats = &tiqn->logout_stats; - - return snprintf(page, PAGE_SIZE, "%u\n", lstats->abnormal_logouts); -} -ISCSI_STAT_LOGOUT_RO(abnormal_logouts); - -CONFIGFS_EATTR_OPS(iscsi_stat_logout, iscsi_wwn_stat_grps, - iscsi_logout_stats_group); - -static struct configfs_attribute *iscsi_stat_logout_stats_attrs[] = { - &iscsi_stat_logout_inst.attr, - &iscsi_stat_logout_indx.attr, - &iscsi_stat_logout_normal_logouts.attr, - &iscsi_stat_logout_abnormal_logouts.attr, - NULL, -}; - -static struct configfs_item_operations iscsi_stat_logout_stats_item_ops = { - .show_attribute = iscsi_stat_logout_attr_show, - .store_attribute = iscsi_stat_logout_attr_store, -}; - -struct config_item_type iscsi_stat_logout_cit = { - .ct_item_ops = &iscsi_stat_logout_stats_item_ops, - .ct_attrs = iscsi_stat_logout_stats_attrs, - .ct_owner = THIS_MODULE, -}; - -/* - * Session Stats Table - */ - -CONFIGFS_EATTR_STRUCT(iscsi_stat_sess, iscsi_node_stat_grps); -#define ISCSI_STAT_SESS(_name, _mode) \ -static struct iscsi_stat_sess_attribute \ - iscsi_stat_sess_##_name = \ - __CONFIGFS_EATTR(_name, _mode, \ - iscsi_stat_sess_show_attr_##_name, \ - iscsi_stat_sess_store_attr_##_name); - -#define ISCSI_STAT_SESS_RO(_name) \ -static struct iscsi_stat_sess_attribute \ - iscsi_stat_sess_##_name = \ - __CONFIGFS_EATTR_RO(_name, \ - iscsi_stat_sess_show_attr_##_name); - -static ssize_t iscsi_stat_sess_show_attr_inst( - struct iscsi_node_stat_grps *igrps, char *page) -{ - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); - struct se_wwn *wwn = acl->se_node_acl.se_tpg->se_tpg_wwn; - struct iscsi_tiqn *tiqn = container_of(wwn, - struct iscsi_tiqn, tiqn_wwn); - - return snprintf(page, PAGE_SIZE, "%u\n", tiqn->tiqn_index); -} -ISCSI_STAT_SESS_RO(inst); - -static ssize_t iscsi_stat_sess_show_attr_node( - struct iscsi_node_stat_grps *igrps, char *page) -{ - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); - struct se_node_acl *se_nacl = &acl->se_node_acl; - struct iscsi_session *sess; - struct se_session *se_sess; - ssize_t ret = 0; - - spin_lock_bh(&se_nacl->nacl_sess_lock); - se_sess = se_nacl->nacl_sess; - if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - if (sess) - ret = snprintf(page, PAGE_SIZE, "%u\n", - sess->sess_ops->SessionType ? 0 : ISCSI_NODE_INDEX); - } - spin_unlock_bh(&se_nacl->nacl_sess_lock); - - return ret; -} -ISCSI_STAT_SESS_RO(node); - -static ssize_t iscsi_stat_sess_show_attr_indx( - struct iscsi_node_stat_grps *igrps, char *page) -{ - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); - struct se_node_acl *se_nacl = &acl->se_node_acl; - struct iscsi_session *sess; - struct se_session *se_sess; - ssize_t ret = 0; - - spin_lock_bh(&se_nacl->nacl_sess_lock); - se_sess = se_nacl->nacl_sess; - if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - if (sess) - ret = snprintf(page, PAGE_SIZE, "%u\n", - sess->session_index); - } - spin_unlock_bh(&se_nacl->nacl_sess_lock); - - return ret; -} -ISCSI_STAT_SESS_RO(indx); - -static ssize_t iscsi_stat_sess_show_attr_cmd_pdus( - struct iscsi_node_stat_grps *igrps, char *page) -{ - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); - struct se_node_acl *se_nacl = &acl->se_node_acl; - struct iscsi_session *sess; - struct se_session *se_sess; - ssize_t ret = 0; - - spin_lock_bh(&se_nacl->nacl_sess_lock); - se_sess = se_nacl->nacl_sess; - if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - if (sess) - ret = snprintf(page, PAGE_SIZE, "%u\n", sess->cmd_pdus); - } - spin_unlock_bh(&se_nacl->nacl_sess_lock); - - return ret; -} -ISCSI_STAT_SESS_RO(cmd_pdus); - -static ssize_t iscsi_stat_sess_show_attr_rsp_pdus( - struct iscsi_node_stat_grps *igrps, char *page) -{ - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); - struct se_node_acl *se_nacl = &acl->se_node_acl; - struct iscsi_session *sess; - struct se_session *se_sess; - ssize_t ret = 0; - - spin_lock_bh(&se_nacl->nacl_sess_lock); - se_sess = se_nacl->nacl_sess; - if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - if (sess) - ret = snprintf(page, PAGE_SIZE, "%u\n", sess->rsp_pdus); - } - spin_unlock_bh(&se_nacl->nacl_sess_lock); - - return ret; -} -ISCSI_STAT_SESS_RO(rsp_pdus); - -static ssize_t iscsi_stat_sess_show_attr_txdata_octs( - struct iscsi_node_stat_grps *igrps, char *page) -{ - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); - struct se_node_acl *se_nacl = &acl->se_node_acl; - struct iscsi_session *sess; - struct se_session *se_sess; - ssize_t ret = 0; - - spin_lock_bh(&se_nacl->nacl_sess_lock); - se_sess = se_nacl->nacl_sess; - if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - if (sess) - ret = snprintf(page, PAGE_SIZE, "%llu\n", - (unsigned long long)sess->tx_data_octets); - } - spin_unlock_bh(&se_nacl->nacl_sess_lock); - - return ret; -} -ISCSI_STAT_SESS_RO(txdata_octs); - -static ssize_t iscsi_stat_sess_show_attr_rxdata_octs( - struct iscsi_node_stat_grps *igrps, char *page) -{ - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); - struct se_node_acl *se_nacl = &acl->se_node_acl; - struct iscsi_session *sess; - struct se_session *se_sess; - ssize_t ret = 0; - - spin_lock_bh(&se_nacl->nacl_sess_lock); - se_sess = se_nacl->nacl_sess; - if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - if (sess) - ret = snprintf(page, PAGE_SIZE, "%llu\n", - (unsigned long long)sess->rx_data_octets); - } - spin_unlock_bh(&se_nacl->nacl_sess_lock); - - return ret; -} -ISCSI_STAT_SESS_RO(rxdata_octs); - -static ssize_t iscsi_stat_sess_show_attr_conn_digest_errors( - struct iscsi_node_stat_grps *igrps, char *page) -{ - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); - struct se_node_acl *se_nacl = &acl->se_node_acl; - struct iscsi_session *sess; - struct se_session *se_sess; - ssize_t ret = 0; - - spin_lock_bh(&se_nacl->nacl_sess_lock); - se_sess = se_nacl->nacl_sess; - if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - if (sess) - ret = snprintf(page, PAGE_SIZE, "%u\n", - sess->conn_digest_errors); - } - spin_unlock_bh(&se_nacl->nacl_sess_lock); - - return ret; -} -ISCSI_STAT_SESS_RO(conn_digest_errors); - -static ssize_t iscsi_stat_sess_show_attr_conn_timeout_errors( - struct iscsi_node_stat_grps *igrps, char *page) -{ - struct iscsi_node_acl *acl = container_of(igrps, - struct iscsi_node_acl, node_stat_grps); - struct se_node_acl *se_nacl = &acl->se_node_acl; - struct iscsi_session *sess; - struct se_session *se_sess; - ssize_t ret = 0; - - spin_lock_bh(&se_nacl->nacl_sess_lock); - se_sess = se_nacl->nacl_sess; - if (se_sess) { - sess = (struct iscsi_session *)se_sess->fabric_sess_ptr; - if (sess) - ret = snprintf(page, PAGE_SIZE, "%u\n", - sess->conn_timeout_errors); - } - spin_unlock_bh(&se_nacl->nacl_sess_lock); - - return ret; -} -ISCSI_STAT_SESS_RO(conn_timeout_errors); - -CONFIGFS_EATTR_OPS(iscsi_stat_sess, iscsi_node_stat_grps, - iscsi_sess_stats_group); - -static struct configfs_attribute *iscsi_stat_sess_stats_attrs[] = { - &iscsi_stat_sess_inst.attr, - &iscsi_stat_sess_node.attr, - &iscsi_stat_sess_indx.attr, - &iscsi_stat_sess_cmd_pdus.attr, - &iscsi_stat_sess_rsp_pdus.attr, - &iscsi_stat_sess_txdata_octs.attr, - &iscsi_stat_sess_rxdata_octs.attr, - &iscsi_stat_sess_conn_digest_errors.attr, - &iscsi_stat_sess_conn_timeout_errors.attr, - NULL, -}; - -static struct configfs_item_operations iscsi_stat_sess_stats_item_ops = { - .show_attribute = iscsi_stat_sess_attr_show, - .store_attribute = iscsi_stat_sess_attr_store, -}; - -struct config_item_type iscsi_stat_sess_cit = { - .ct_item_ops = &iscsi_stat_sess_stats_item_ops, - .ct_attrs = iscsi_stat_sess_stats_attrs, - .ct_owner = THIS_MODULE, -}; diff --git a/trunk/drivers/target/iscsi/iscsi_target_stat.h b/trunk/drivers/target/iscsi/iscsi_target_stat.h deleted file mode 100644 index 3ff76b4faad3..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_stat.h +++ /dev/null @@ -1,64 +0,0 @@ -#ifndef ISCSI_TARGET_STAT_H -#define ISCSI_TARGET_STAT_H - -/* - * For struct iscsi_tiqn->tiqn_wwn default groups - */ -extern struct config_item_type iscsi_stat_instance_cit; -extern struct config_item_type iscsi_stat_sess_err_cit; -extern struct config_item_type iscsi_stat_tgt_attr_cit; -extern struct config_item_type iscsi_stat_login_cit; -extern struct config_item_type iscsi_stat_logout_cit; - -/* - * For struct iscsi_session->se_sess default groups - */ -extern struct config_item_type iscsi_stat_sess_cit; - -/* iSCSI session error types */ -#define ISCSI_SESS_ERR_UNKNOWN 0 -#define ISCSI_SESS_ERR_DIGEST 1 -#define ISCSI_SESS_ERR_CXN_TIMEOUT 2 -#define ISCSI_SESS_ERR_PDU_FORMAT 3 - -/* iSCSI session error stats */ -struct iscsi_sess_err_stats { - spinlock_t lock; - u32 digest_errors; - u32 cxn_timeout_errors; - u32 pdu_format_errors; - u32 last_sess_failure_type; - char last_sess_fail_rem_name[224]; -} ____cacheline_aligned; - -/* iSCSI login failure types (sub oids) */ -#define ISCSI_LOGIN_FAIL_OTHER 2 -#define ISCSI_LOGIN_FAIL_REDIRECT 3 -#define ISCSI_LOGIN_FAIL_AUTHORIZE 4 -#define ISCSI_LOGIN_FAIL_AUTHENTICATE 5 -#define ISCSI_LOGIN_FAIL_NEGOTIATE 6 - -/* iSCSI login stats */ -struct iscsi_login_stats { - spinlock_t lock; - u32 accepts; - u32 other_fails; - u32 redirects; - u32 authorize_fails; - u32 authenticate_fails; - u32 negotiate_fails; /* used for notifications */ - u64 last_fail_time; /* time stamp (jiffies) */ - u32 last_fail_type; - int last_intr_fail_ip_family; - unsigned char last_intr_fail_ip_addr[IPV6_ADDRESS_SPACE]; - char last_intr_fail_name[224]; -} ____cacheline_aligned; - -/* iSCSI logout stats */ -struct iscsi_logout_stats { - spinlock_t lock; - u32 normal_logouts; - u32 abnormal_logouts; -} ____cacheline_aligned; - -#endif /*** ISCSI_TARGET_STAT_H ***/ diff --git a/trunk/drivers/target/iscsi/iscsi_target_tmr.c b/trunk/drivers/target/iscsi/iscsi_target_tmr.c deleted file mode 100644 index db1fe1ec84df..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_tmr.c +++ /dev/null @@ -1,849 +0,0 @@ -/******************************************************************************* - * This file contains the iSCSI Target specific Task Management functions. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_datain_values.h" -#include "iscsi_target_device.h" -#include "iscsi_target_erl0.h" -#include "iscsi_target_erl1.h" -#include "iscsi_target_erl2.h" -#include "iscsi_target_tmr.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_util.h" -#include "iscsi_target.h" - -u8 iscsit_tmr_abort_task( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - struct iscsi_cmd *ref_cmd; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_tmr_req *tmr_req = cmd->tmr_req; - struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req; - struct iscsi_tm *hdr = (struct iscsi_tm *) buf; - - ref_cmd = iscsit_find_cmd_from_itt(conn, hdr->rtt); - if (!ref_cmd) { - pr_err("Unable to locate RefTaskTag: 0x%08x on CID:" - " %hu.\n", hdr->rtt, conn->cid); - return ((hdr->refcmdsn >= conn->sess->exp_cmd_sn) && - (hdr->refcmdsn <= conn->sess->max_cmd_sn)) ? - ISCSI_TMF_RSP_COMPLETE : ISCSI_TMF_RSP_NO_TASK; - } - if (ref_cmd->cmd_sn != hdr->refcmdsn) { - pr_err("RefCmdSN 0x%08x does not equal" - " task's CmdSN 0x%08x. Rejecting ABORT_TASK.\n", - hdr->refcmdsn, ref_cmd->cmd_sn); - return ISCSI_TMF_RSP_REJECTED; - } - - se_tmr->ref_task_tag = hdr->rtt; - se_tmr->ref_cmd = &ref_cmd->se_cmd; - tmr_req->ref_cmd_sn = hdr->refcmdsn; - tmr_req->exp_data_sn = hdr->exp_datasn; - - return ISCSI_TMF_RSP_COMPLETE; -} - -/* - * Called from iscsit_handle_task_mgt_cmd(). - */ -int iscsit_tmr_task_warm_reset( - struct iscsi_conn *conn, - struct iscsi_tmr_req *tmr_req, - unsigned char *buf) -{ - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); -#if 0 - struct iscsi_init_task_mgt_cmnd *hdr = - (struct iscsi_init_task_mgt_cmnd *) buf; -#endif - if (!na->tmr_warm_reset) { - pr_err("TMR Opcode TARGET_WARM_RESET authorization" - " failed for Initiator Node: %s\n", - sess->se_sess->se_node_acl->initiatorname); - return -1; - } - /* - * Do the real work in transport_generic_do_tmr(). - */ - return 0; -} - -int iscsit_tmr_task_cold_reset( - struct iscsi_conn *conn, - struct iscsi_tmr_req *tmr_req, - unsigned char *buf) -{ - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); - - if (!na->tmr_cold_reset) { - pr_err("TMR Opcode TARGET_COLD_RESET authorization" - " failed for Initiator Node: %s\n", - sess->se_sess->se_node_acl->initiatorname); - return -1; - } - /* - * Do the real work in transport_generic_do_tmr(). - */ - return 0; -} - -u8 iscsit_tmr_task_reassign( - struct iscsi_cmd *cmd, - unsigned char *buf) -{ - struct iscsi_cmd *ref_cmd = NULL; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_conn_recovery *cr = NULL; - struct iscsi_tmr_req *tmr_req = cmd->tmr_req; - struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req; - struct iscsi_tm *hdr = (struct iscsi_tm *) buf; - int ret; - - pr_debug("Got TASK_REASSIGN TMR ITT: 0x%08x," - " RefTaskTag: 0x%08x, ExpDataSN: 0x%08x, CID: %hu\n", - hdr->itt, hdr->rtt, hdr->exp_datasn, conn->cid); - - if (conn->sess->sess_ops->ErrorRecoveryLevel != 2) { - pr_err("TMR TASK_REASSIGN not supported in ERL<2," - " ignoring request.\n"); - return ISCSI_TMF_RSP_NOT_SUPPORTED; - } - - ret = iscsit_find_cmd_for_recovery(conn->sess, &ref_cmd, &cr, hdr->rtt); - if (ret == -2) { - pr_err("Command ITT: 0x%08x is still alligent to CID:" - " %hu\n", ref_cmd->init_task_tag, cr->cid); - return ISCSI_TMF_RSP_TASK_ALLEGIANT; - } else if (ret == -1) { - pr_err("Unable to locate RefTaskTag: 0x%08x in" - " connection recovery command list.\n", hdr->rtt); - return ISCSI_TMF_RSP_NO_TASK; - } - /* - * Temporary check to prevent connection recovery for - * connections with a differing MaxRecvDataSegmentLength. - */ - if (cr->maxrecvdatasegmentlength != - conn->conn_ops->MaxRecvDataSegmentLength) { - pr_err("Unable to perform connection recovery for" - " differing MaxRecvDataSegmentLength, rejecting" - " TMR TASK_REASSIGN.\n"); - return ISCSI_TMF_RSP_REJECTED; - } - - se_tmr->ref_task_tag = hdr->rtt; - se_tmr->ref_cmd = &ref_cmd->se_cmd; - se_tmr->ref_task_lun = get_unaligned_le64(&hdr->lun); - tmr_req->ref_cmd_sn = hdr->refcmdsn; - tmr_req->exp_data_sn = hdr->exp_datasn; - tmr_req->conn_recovery = cr; - tmr_req->task_reassign = 1; - /* - * Command can now be reassigned to a new connection. - * The task management response must be sent before the - * reassignment actually happens. See iscsi_tmr_post_handler(). - */ - return ISCSI_TMF_RSP_COMPLETE; -} - -static void iscsit_task_reassign_remove_cmd( - struct iscsi_cmd *cmd, - struct iscsi_conn_recovery *cr, - struct iscsi_session *sess) -{ - int ret; - - spin_lock(&cr->conn_recovery_cmd_lock); - ret = iscsit_remove_cmd_from_connection_recovery(cmd, sess); - spin_unlock(&cr->conn_recovery_cmd_lock); - if (!ret) { - pr_debug("iSCSI connection recovery successful for CID:" - " %hu on SID: %u\n", cr->cid, sess->sid); - iscsit_remove_active_connection_recovery_entry(cr, sess); - } -} - -static int iscsit_task_reassign_complete_nop_out( - struct iscsi_tmr_req *tmr_req, - struct iscsi_conn *conn) -{ - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - struct iscsi_conn_recovery *cr; - - if (!cmd->cr) { - pr_err("struct iscsi_conn_recovery pointer for ITT: 0x%08x" - " is NULL!\n", cmd->init_task_tag); - return -1; - } - cr = cmd->cr; - - /* - * Reset the StatSN so a new one for this commands new connection - * will be assigned. - * Reset the ExpStatSN as well so we may receive Status SNACKs. - */ - cmd->stat_sn = cmd->exp_stat_sn = 0; - - iscsit_task_reassign_remove_cmd(cmd, cr, conn->sess); - - spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); - spin_unlock_bh(&conn->cmd_lock); - - cmd->i_state = ISTATE_SEND_NOPIN; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - return 0; -} - -static int iscsit_task_reassign_complete_write( - struct iscsi_cmd *cmd, - struct iscsi_tmr_req *tmr_req) -{ - int no_build_r2ts = 0; - u32 length = 0, offset = 0; - struct iscsi_conn *conn = cmd->conn; - struct se_cmd *se_cmd = &cmd->se_cmd; - /* - * The Initiator must not send a R2T SNACK with a Begrun less than - * the TMR TASK_REASSIGN's ExpDataSN. - */ - if (!tmr_req->exp_data_sn) { - cmd->cmd_flags &= ~ICF_GOT_DATACK_SNACK; - cmd->acked_data_sn = 0; - } else { - cmd->cmd_flags |= ICF_GOT_DATACK_SNACK; - cmd->acked_data_sn = (tmr_req->exp_data_sn - 1); - } - - /* - * The TMR TASK_REASSIGN's ExpDataSN contains the next R2TSN the - * Initiator is expecting. The Target controls all WRITE operations - * so if we have received all DataOUT we can safety ignore Initiator. - */ - if (cmd->cmd_flags & ICF_GOT_LAST_DATAOUT) { - if (!atomic_read(&cmd->transport_sent)) { - pr_debug("WRITE ITT: 0x%08x: t_state: %d" - " never sent to transport\n", - cmd->init_task_tag, cmd->se_cmd.t_state); - return transport_generic_handle_data(se_cmd); - } - - cmd->i_state = ISTATE_SEND_STATUS; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - return 0; - } - - /* - * Special case to deal with DataSequenceInOrder=No and Non-Immeidate - * Unsolicited DataOut. - */ - if (cmd->unsolicited_data) { - cmd->unsolicited_data = 0; - - offset = cmd->next_burst_len = cmd->write_data_done; - - if ((conn->sess->sess_ops->FirstBurstLength - offset) >= - cmd->data_length) { - no_build_r2ts = 1; - length = (cmd->data_length - offset); - } else - length = (conn->sess->sess_ops->FirstBurstLength - offset); - - spin_lock_bh(&cmd->r2t_lock); - if (iscsit_add_r2t_to_list(cmd, offset, length, 0, 0) < 0) { - spin_unlock_bh(&cmd->r2t_lock); - return -1; - } - cmd->outstanding_r2ts++; - spin_unlock_bh(&cmd->r2t_lock); - - if (no_build_r2ts) - return 0; - } - /* - * iscsit_build_r2ts_for_cmd() can handle the rest from here. - */ - return iscsit_build_r2ts_for_cmd(cmd, conn, 2); -} - -static int iscsit_task_reassign_complete_read( - struct iscsi_cmd *cmd, - struct iscsi_tmr_req *tmr_req) -{ - struct iscsi_conn *conn = cmd->conn; - struct iscsi_datain_req *dr; - struct se_cmd *se_cmd = &cmd->se_cmd; - /* - * The Initiator must not send a Data SNACK with a BegRun less than - * the TMR TASK_REASSIGN's ExpDataSN. - */ - if (!tmr_req->exp_data_sn) { - cmd->cmd_flags &= ~ICF_GOT_DATACK_SNACK; - cmd->acked_data_sn = 0; - } else { - cmd->cmd_flags |= ICF_GOT_DATACK_SNACK; - cmd->acked_data_sn = (tmr_req->exp_data_sn - 1); - } - - if (!atomic_read(&cmd->transport_sent)) { - pr_debug("READ ITT: 0x%08x: t_state: %d never sent to" - " transport\n", cmd->init_task_tag, - cmd->se_cmd.t_state); - transport_generic_handle_cdb(se_cmd); - return 0; - } - - if (!atomic_read(&se_cmd->t_transport_complete)) { - pr_err("READ ITT: 0x%08x: t_state: %d, never returned" - " from transport\n", cmd->init_task_tag, - cmd->se_cmd.t_state); - return -1; - } - - dr = iscsit_allocate_datain_req(); - if (!dr) - return -1; - /* - * The TMR TASK_REASSIGN's ExpDataSN contains the next DataSN the - * Initiator is expecting. - */ - dr->data_sn = dr->begrun = tmr_req->exp_data_sn; - dr->runlength = 0; - dr->generate_recovery_values = 1; - dr->recovery = DATAIN_CONNECTION_RECOVERY; - - iscsit_attach_datain_req(cmd, dr); - - cmd->i_state = ISTATE_SEND_DATAIN; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - return 0; -} - -static int iscsit_task_reassign_complete_none( - struct iscsi_cmd *cmd, - struct iscsi_tmr_req *tmr_req) -{ - struct iscsi_conn *conn = cmd->conn; - - cmd->i_state = ISTATE_SEND_STATUS; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - return 0; -} - -static int iscsit_task_reassign_complete_scsi_cmnd( - struct iscsi_tmr_req *tmr_req, - struct iscsi_conn *conn) -{ - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - struct iscsi_conn_recovery *cr; - - if (!cmd->cr) { - pr_err("struct iscsi_conn_recovery pointer for ITT: 0x%08x" - " is NULL!\n", cmd->init_task_tag); - return -1; - } - cr = cmd->cr; - - /* - * Reset the StatSN so a new one for this commands new connection - * will be assigned. - * Reset the ExpStatSN as well so we may receive Status SNACKs. - */ - cmd->stat_sn = cmd->exp_stat_sn = 0; - - iscsit_task_reassign_remove_cmd(cmd, cr, conn->sess); - - spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); - spin_unlock_bh(&conn->cmd_lock); - - if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) { - cmd->i_state = ISTATE_SEND_STATUS; - iscsit_add_cmd_to_response_queue(cmd, conn, cmd->i_state); - return 0; - } - - switch (cmd->data_direction) { - case DMA_TO_DEVICE: - return iscsit_task_reassign_complete_write(cmd, tmr_req); - case DMA_FROM_DEVICE: - return iscsit_task_reassign_complete_read(cmd, tmr_req); - case DMA_NONE: - return iscsit_task_reassign_complete_none(cmd, tmr_req); - default: - pr_err("Unknown cmd->data_direction: 0x%02x\n", - cmd->data_direction); - return -1; - } - - return 0; -} - -static int iscsit_task_reassign_complete( - struct iscsi_tmr_req *tmr_req, - struct iscsi_conn *conn) -{ - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd; - struct iscsi_cmd *cmd; - int ret = 0; - - if (!se_tmr->ref_cmd) { - pr_err("TMR Request is missing a RefCmd struct iscsi_cmd.\n"); - return -1; - } - se_cmd = se_tmr->ref_cmd; - cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - cmd->conn = conn; - - switch (cmd->iscsi_opcode) { - case ISCSI_OP_NOOP_OUT: - ret = iscsit_task_reassign_complete_nop_out(tmr_req, conn); - break; - case ISCSI_OP_SCSI_CMD: - ret = iscsit_task_reassign_complete_scsi_cmnd(tmr_req, conn); - break; - default: - pr_err("Illegal iSCSI Opcode 0x%02x during" - " command realligence\n", cmd->iscsi_opcode); - return -1; - } - - if (ret != 0) - return ret; - - pr_debug("Completed connection realligence for Opcode: 0x%02x," - " ITT: 0x%08x to CID: %hu.\n", cmd->iscsi_opcode, - cmd->init_task_tag, conn->cid); - - return 0; -} - -/* - * Handles special after-the-fact actions related to TMRs. - * Right now the only one that its really needed for is - * connection recovery releated TASK_REASSIGN. - */ -extern int iscsit_tmr_post_handler(struct iscsi_cmd *cmd, struct iscsi_conn *conn) -{ - struct iscsi_tmr_req *tmr_req = cmd->tmr_req; - struct se_tmr_req *se_tmr = cmd->se_cmd.se_tmr_req; - - if (tmr_req->task_reassign && - (se_tmr->response == ISCSI_TMF_RSP_COMPLETE)) - return iscsit_task_reassign_complete(tmr_req, conn); - - return 0; -} - -/* - * Nothing to do here, but leave it for good measure. :-) - */ -int iscsit_task_reassign_prepare_read( - struct iscsi_tmr_req *tmr_req, - struct iscsi_conn *conn) -{ - return 0; -} - -static void iscsit_task_reassign_prepare_unsolicited_dataout( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - int i, j; - struct iscsi_pdu *pdu = NULL; - struct iscsi_seq *seq = NULL; - - if (conn->sess->sess_ops->DataSequenceInOrder) { - cmd->data_sn = 0; - - if (cmd->immediate_data) - cmd->r2t_offset += (cmd->first_burst_len - - cmd->seq_start_offset); - - if (conn->sess->sess_ops->DataPDUInOrder) { - cmd->write_data_done -= (cmd->immediate_data) ? - (cmd->first_burst_len - - cmd->seq_start_offset) : - cmd->first_burst_len; - cmd->first_burst_len = 0; - return; - } - - for (i = 0; i < cmd->pdu_count; i++) { - pdu = &cmd->pdu_list[i]; - - if (pdu->status != ISCSI_PDU_RECEIVED_OK) - continue; - - if ((pdu->offset >= cmd->seq_start_offset) && - ((pdu->offset + pdu->length) <= - cmd->seq_end_offset)) { - cmd->first_burst_len -= pdu->length; - cmd->write_data_done -= pdu->length; - pdu->status = ISCSI_PDU_NOT_RECEIVED; - } - } - } else { - for (i = 0; i < cmd->seq_count; i++) { - seq = &cmd->seq_list[i]; - - if (seq->type != SEQTYPE_UNSOLICITED) - continue; - - cmd->write_data_done -= - (seq->offset - seq->orig_offset); - cmd->first_burst_len = 0; - seq->data_sn = 0; - seq->offset = seq->orig_offset; - seq->next_burst_len = 0; - seq->status = DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY; - - if (conn->sess->sess_ops->DataPDUInOrder) - continue; - - for (j = 0; j < seq->pdu_count; j++) { - pdu = &cmd->pdu_list[j+seq->pdu_start]; - - if (pdu->status != ISCSI_PDU_RECEIVED_OK) - continue; - - pdu->status = ISCSI_PDU_NOT_RECEIVED; - } - } - } -} - -int iscsit_task_reassign_prepare_write( - struct iscsi_tmr_req *tmr_req, - struct iscsi_conn *conn) -{ - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - struct iscsi_pdu *pdu = NULL; - struct iscsi_r2t *r2t = NULL, *r2t_tmp; - int first_incomplete_r2t = 1, i = 0; - - /* - * The command was in the process of receiving Unsolicited DataOUT when - * the connection failed. - */ - if (cmd->unsolicited_data) - iscsit_task_reassign_prepare_unsolicited_dataout(cmd, conn); - - /* - * The Initiator is requesting R2Ts starting from zero, skip - * checking acknowledged R2Ts and start checking struct iscsi_r2ts - * greater than zero. - */ - if (!tmr_req->exp_data_sn) - goto drop_unacknowledged_r2ts; - - /* - * We now check that the PDUs in DataOUT sequences below - * the TMR TASK_REASSIGN ExpDataSN (R2TSN the Initiator is - * expecting next) have all the DataOUT they require to complete - * the DataOUT sequence. First scan from R2TSN 0 to TMR - * TASK_REASSIGN ExpDataSN-1. - * - * If we have not received all DataOUT in question, we must - * make sure to make the appropriate changes to values in - * struct iscsi_cmd (and elsewhere depending on session parameters) - * so iscsit_build_r2ts_for_cmd() in iscsit_task_reassign_complete_write() - * will resend a new R2T for the DataOUT sequences in question. - */ - spin_lock_bh(&cmd->r2t_lock); - if (list_empty(&cmd->cmd_r2t_list)) { - spin_unlock_bh(&cmd->r2t_lock); - return -1; - } - - list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { - - if (r2t->r2t_sn >= tmr_req->exp_data_sn) - continue; - /* - * Safely ignore Recovery R2Ts and R2Ts that have completed - * DataOUT sequences. - */ - if (r2t->seq_complete) - continue; - - if (r2t->recovery_r2t) - continue; - - /* - * DataSequenceInOrder=Yes: - * - * Taking into account the iSCSI implementation requirement of - * MaxOutstandingR2T=1 while ErrorRecoveryLevel>0 and - * DataSequenceInOrder=Yes, we must take into consideration - * the following: - * - * DataSequenceInOrder=No: - * - * Taking into account that the Initiator controls the (possibly - * random) PDU Order in (possibly random) Sequence Order of - * DataOUT the target requests with R2Ts, we must take into - * consideration the following: - * - * DataPDUInOrder=Yes for DataSequenceInOrder=[Yes,No]: - * - * While processing non-complete R2T DataOUT sequence requests - * the Target will re-request only the total sequence length - * minus current received offset. This is because we must - * assume the initiator will continue sending DataOUT from the - * last PDU before the connection failed. - * - * DataPDUInOrder=No for DataSequenceInOrder=[Yes,No]: - * - * While processing non-complete R2T DataOUT sequence requests - * the Target will re-request the entire DataOUT sequence if - * any single PDU is missing from the sequence. This is because - * we have no logical method to determine the next PDU offset, - * and we must assume the Initiator will be sending any random - * PDU offset in the current sequence after TASK_REASSIGN - * has completed. - */ - if (conn->sess->sess_ops->DataSequenceInOrder) { - if (!first_incomplete_r2t) { - cmd->r2t_offset -= r2t->xfer_len; - goto next; - } - - if (conn->sess->sess_ops->DataPDUInOrder) { - cmd->data_sn = 0; - cmd->r2t_offset -= (r2t->xfer_len - - cmd->next_burst_len); - first_incomplete_r2t = 0; - goto next; - } - - cmd->data_sn = 0; - cmd->r2t_offset -= r2t->xfer_len; - - for (i = 0; i < cmd->pdu_count; i++) { - pdu = &cmd->pdu_list[i]; - - if (pdu->status != ISCSI_PDU_RECEIVED_OK) - continue; - - if ((pdu->offset >= r2t->offset) && - (pdu->offset < (r2t->offset + - r2t->xfer_len))) { - cmd->next_burst_len -= pdu->length; - cmd->write_data_done -= pdu->length; - pdu->status = ISCSI_PDU_NOT_RECEIVED; - } - } - - first_incomplete_r2t = 0; - } else { - struct iscsi_seq *seq; - - seq = iscsit_get_seq_holder(cmd, r2t->offset, - r2t->xfer_len); - if (!seq) { - spin_unlock_bh(&cmd->r2t_lock); - return -1; - } - - cmd->write_data_done -= - (seq->offset - seq->orig_offset); - seq->data_sn = 0; - seq->offset = seq->orig_offset; - seq->next_burst_len = 0; - seq->status = DATAOUT_SEQUENCE_WITHIN_COMMAND_RECOVERY; - - cmd->seq_send_order--; - - if (conn->sess->sess_ops->DataPDUInOrder) - goto next; - - for (i = 0; i < seq->pdu_count; i++) { - pdu = &cmd->pdu_list[i+seq->pdu_start]; - - if (pdu->status != ISCSI_PDU_RECEIVED_OK) - continue; - - pdu->status = ISCSI_PDU_NOT_RECEIVED; - } - } - -next: - cmd->outstanding_r2ts--; - } - spin_unlock_bh(&cmd->r2t_lock); - - /* - * We now drop all unacknowledged R2Ts, ie: ExpDataSN from TMR - * TASK_REASSIGN to the last R2T in the list.. We are also careful - * to check that the Initiator is not requesting R2Ts for DataOUT - * sequences it has already completed. - * - * Free each R2T in question and adjust values in struct iscsi_cmd - * accordingly so iscsit_build_r2ts_for_cmd() do the rest of - * the work after the TMR TASK_REASSIGN Response is sent. - */ -drop_unacknowledged_r2ts: - - cmd->cmd_flags &= ~ICF_SENT_LAST_R2T; - cmd->r2t_sn = tmr_req->exp_data_sn; - - spin_lock_bh(&cmd->r2t_lock); - list_for_each_entry_safe(r2t, r2t_tmp, &cmd->cmd_r2t_list, r2t_list) { - /* - * Skip up to the R2T Sequence number provided by the - * iSCSI TASK_REASSIGN TMR - */ - if (r2t->r2t_sn < tmr_req->exp_data_sn) - continue; - - if (r2t->seq_complete) { - pr_err("Initiator is requesting R2Ts from" - " R2TSN: 0x%08x, but R2TSN: 0x%08x, Offset: %u," - " Length: %u is already complete." - " BAD INITIATOR ERL=2 IMPLEMENTATION!\n", - tmr_req->exp_data_sn, r2t->r2t_sn, - r2t->offset, r2t->xfer_len); - spin_unlock_bh(&cmd->r2t_lock); - return -1; - } - - if (r2t->recovery_r2t) { - iscsit_free_r2t(r2t, cmd); - continue; - } - - /* DataSequenceInOrder=Yes: - * - * Taking into account the iSCSI implementation requirement of - * MaxOutstandingR2T=1 while ErrorRecoveryLevel>0 and - * DataSequenceInOrder=Yes, it's safe to subtract the R2Ts - * entire transfer length from the commands R2T offset marker. - * - * DataSequenceInOrder=No: - * - * We subtract the difference from struct iscsi_seq between the - * current offset and original offset from cmd->write_data_done - * for account for DataOUT PDUs already received. Then reset - * the current offset to the original and zero out the current - * burst length, to make sure we re-request the entire DataOUT - * sequence. - */ - if (conn->sess->sess_ops->DataSequenceInOrder) - cmd->r2t_offset -= r2t->xfer_len; - else - cmd->seq_send_order--; - - cmd->outstanding_r2ts--; - iscsit_free_r2t(r2t, cmd); - } - spin_unlock_bh(&cmd->r2t_lock); - - return 0; -} - -/* - * Performs sanity checks TMR TASK_REASSIGN's ExpDataSN for - * a given struct iscsi_cmd. - */ -int iscsit_check_task_reassign_expdatasn( - struct iscsi_tmr_req *tmr_req, - struct iscsi_conn *conn) -{ - struct se_tmr_req *se_tmr = tmr_req->se_tmr_req; - struct se_cmd *se_cmd = se_tmr->ref_cmd; - struct iscsi_cmd *ref_cmd = container_of(se_cmd, struct iscsi_cmd, se_cmd); - - if (ref_cmd->iscsi_opcode != ISCSI_OP_SCSI_CMD) - return 0; - - if (se_cmd->se_cmd_flags & SCF_SENT_CHECK_CONDITION) - return 0; - - if (ref_cmd->data_direction == DMA_NONE) - return 0; - - /* - * For READs the TMR TASK_REASSIGNs ExpDataSN contains the next DataSN - * of DataIN the Initiator is expecting. - * - * Also check that the Initiator is not re-requesting DataIN that has - * already been acknowledged with a DataAck SNACK. - */ - if (ref_cmd->data_direction == DMA_FROM_DEVICE) { - if (tmr_req->exp_data_sn > ref_cmd->data_sn) { - pr_err("Received ExpDataSN: 0x%08x for READ" - " in TMR TASK_REASSIGN greater than command's" - " DataSN: 0x%08x.\n", tmr_req->exp_data_sn, - ref_cmd->data_sn); - return -1; - } - if ((ref_cmd->cmd_flags & ICF_GOT_DATACK_SNACK) && - (tmr_req->exp_data_sn <= ref_cmd->acked_data_sn)) { - pr_err("Received ExpDataSN: 0x%08x for READ" - " in TMR TASK_REASSIGN for previously" - " acknowledged DataIN: 0x%08x," - " protocol error\n", tmr_req->exp_data_sn, - ref_cmd->acked_data_sn); - return -1; - } - return iscsit_task_reassign_prepare_read(tmr_req, conn); - } - - /* - * For WRITEs the TMR TASK_REASSIGNs ExpDataSN contains the next R2TSN - * for R2Ts the Initiator is expecting. - * - * Do the magic in iscsit_task_reassign_prepare_write(). - */ - if (ref_cmd->data_direction == DMA_TO_DEVICE) { - if (tmr_req->exp_data_sn > ref_cmd->r2t_sn) { - pr_err("Received ExpDataSN: 0x%08x for WRITE" - " in TMR TASK_REASSIGN greater than command's" - " R2TSN: 0x%08x.\n", tmr_req->exp_data_sn, - ref_cmd->r2t_sn); - return -1; - } - return iscsit_task_reassign_prepare_write(tmr_req, conn); - } - - pr_err("Unknown iSCSI data_direction: 0x%02x\n", - ref_cmd->data_direction); - - return -1; -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_tmr.h b/trunk/drivers/target/iscsi/iscsi_target_tmr.h deleted file mode 100644 index 142e992cb097..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_tmr.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef ISCSI_TARGET_TMR_H -#define ISCSI_TARGET_TMR_H - -extern u8 iscsit_tmr_abort_task(struct iscsi_cmd *, unsigned char *); -extern int iscsit_tmr_task_warm_reset(struct iscsi_conn *, struct iscsi_tmr_req *, - unsigned char *); -extern int iscsit_tmr_task_cold_reset(struct iscsi_conn *, struct iscsi_tmr_req *, - unsigned char *); -extern u8 iscsit_tmr_task_reassign(struct iscsi_cmd *, unsigned char *); -extern int iscsit_tmr_post_handler(struct iscsi_cmd *, struct iscsi_conn *); -extern int iscsit_check_task_reassign_expdatasn(struct iscsi_tmr_req *, - struct iscsi_conn *); - -#endif /* ISCSI_TARGET_TMR_H */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_tpg.c b/trunk/drivers/target/iscsi/iscsi_target_tpg.c deleted file mode 100644 index d4cf2cd25c44..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_tpg.c +++ /dev/null @@ -1,759 +0,0 @@ -/******************************************************************************* - * This file contains iSCSI Target Portal Group related functions. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_erl0.h" -#include "iscsi_target_login.h" -#include "iscsi_target_nodeattrib.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_util.h" -#include "iscsi_target.h" -#include "iscsi_target_parameters.h" - -struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *tiqn, u16 tpgt) -{ - struct iscsi_portal_group *tpg; - - tpg = kzalloc(sizeof(struct iscsi_portal_group), GFP_KERNEL); - if (!tpg) { - pr_err("Unable to allocate struct iscsi_portal_group\n"); - return NULL; - } - - tpg->tpgt = tpgt; - tpg->tpg_state = TPG_STATE_FREE; - tpg->tpg_tiqn = tiqn; - INIT_LIST_HEAD(&tpg->tpg_gnp_list); - INIT_LIST_HEAD(&tpg->tpg_list); - mutex_init(&tpg->tpg_access_lock); - mutex_init(&tpg->np_login_lock); - spin_lock_init(&tpg->tpg_state_lock); - spin_lock_init(&tpg->tpg_np_lock); - - return tpg; -} - -static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *); - -int iscsit_load_discovery_tpg(void) -{ - struct iscsi_param *param; - struct iscsi_portal_group *tpg; - int ret; - - tpg = iscsit_alloc_portal_group(NULL, 1); - if (!tpg) { - pr_err("Unable to allocate struct iscsi_portal_group\n"); - return -1; - } - - ret = core_tpg_register( - &lio_target_fabric_configfs->tf_ops, - NULL, &tpg->tpg_se_tpg, (void *)tpg, - TRANSPORT_TPG_TYPE_DISCOVERY); - if (ret < 0) { - kfree(tpg); - return -1; - } - - tpg->sid = 1; /* First Assigned LIO Session ID */ - iscsit_set_default_tpg_attribs(tpg); - - if (iscsi_create_default_params(&tpg->param_list) < 0) - goto out; - /* - * By default we disable authentication for discovery sessions, - * this can be changed with: - * - * /sys/kernel/config/target/iscsi/discovery_auth/enforce_discovery_auth - */ - param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list); - if (!param) - goto out; - - if (iscsi_update_param_value(param, "CHAP,None") < 0) - goto out; - - tpg->tpg_attrib.authentication = 0; - - spin_lock(&tpg->tpg_state_lock); - tpg->tpg_state = TPG_STATE_ACTIVE; - spin_unlock(&tpg->tpg_state_lock); - - iscsit_global->discovery_tpg = tpg; - pr_debug("CORE[0] - Allocated Discovery TPG\n"); - - return 0; -out: - if (tpg->sid == 1) - core_tpg_deregister(&tpg->tpg_se_tpg); - kfree(tpg); - return -1; -} - -void iscsit_release_discovery_tpg(void) -{ - struct iscsi_portal_group *tpg = iscsit_global->discovery_tpg; - - if (!tpg) - return; - - core_tpg_deregister(&tpg->tpg_se_tpg); - - kfree(tpg); - iscsit_global->discovery_tpg = NULL; -} - -struct iscsi_portal_group *iscsit_get_tpg_from_np( - struct iscsi_tiqn *tiqn, - struct iscsi_np *np) -{ - struct iscsi_portal_group *tpg = NULL; - struct iscsi_tpg_np *tpg_np; - - spin_lock(&tiqn->tiqn_tpg_lock); - list_for_each_entry(tpg, &tiqn->tiqn_tpg_list, tpg_list) { - - spin_lock(&tpg->tpg_state_lock); - if (tpg->tpg_state == TPG_STATE_FREE) { - spin_unlock(&tpg->tpg_state_lock); - continue; - } - spin_unlock(&tpg->tpg_state_lock); - - spin_lock(&tpg->tpg_np_lock); - list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { - if (tpg_np->tpg_np == np) { - spin_unlock(&tpg->tpg_np_lock); - spin_unlock(&tiqn->tiqn_tpg_lock); - return tpg; - } - } - spin_unlock(&tpg->tpg_np_lock); - } - spin_unlock(&tiqn->tiqn_tpg_lock); - - return NULL; -} - -int iscsit_get_tpg( - struct iscsi_portal_group *tpg) -{ - int ret; - - ret = mutex_lock_interruptible(&tpg->tpg_access_lock); - return ((ret != 0) || signal_pending(current)) ? -1 : 0; -} - -void iscsit_put_tpg(struct iscsi_portal_group *tpg) -{ - mutex_unlock(&tpg->tpg_access_lock); -} - -static void iscsit_clear_tpg_np_login_thread( - struct iscsi_tpg_np *tpg_np, - struct iscsi_portal_group *tpg) -{ - if (!tpg_np->tpg_np) { - pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n"); - return; - } - - iscsit_reset_np_thread(tpg_np->tpg_np, tpg_np, tpg); -} - -void iscsit_clear_tpg_np_login_threads( - struct iscsi_portal_group *tpg) -{ - struct iscsi_tpg_np *tpg_np; - - spin_lock(&tpg->tpg_np_lock); - list_for_each_entry(tpg_np, &tpg->tpg_gnp_list, tpg_np_list) { - if (!tpg_np->tpg_np) { - pr_err("struct iscsi_tpg_np->tpg_np is NULL!\n"); - continue; - } - spin_unlock(&tpg->tpg_np_lock); - iscsit_clear_tpg_np_login_thread(tpg_np, tpg); - spin_lock(&tpg->tpg_np_lock); - } - spin_unlock(&tpg->tpg_np_lock); -} - -void iscsit_tpg_dump_params(struct iscsi_portal_group *tpg) -{ - iscsi_print_params(tpg->param_list); -} - -static void iscsit_set_default_tpg_attribs(struct iscsi_portal_group *tpg) -{ - struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; - - a->authentication = TA_AUTHENTICATION; - a->login_timeout = TA_LOGIN_TIMEOUT; - a->netif_timeout = TA_NETIF_TIMEOUT; - a->default_cmdsn_depth = TA_DEFAULT_CMDSN_DEPTH; - a->generate_node_acls = TA_GENERATE_NODE_ACLS; - a->cache_dynamic_acls = TA_CACHE_DYNAMIC_ACLS; - a->demo_mode_write_protect = TA_DEMO_MODE_WRITE_PROTECT; - a->prod_mode_write_protect = TA_PROD_MODE_WRITE_PROTECT; -} - -int iscsit_tpg_add_portal_group(struct iscsi_tiqn *tiqn, struct iscsi_portal_group *tpg) -{ - if (tpg->tpg_state != TPG_STATE_FREE) { - pr_err("Unable to add iSCSI Target Portal Group: %d" - " while not in TPG_STATE_FREE state.\n", tpg->tpgt); - return -EEXIST; - } - iscsit_set_default_tpg_attribs(tpg); - - if (iscsi_create_default_params(&tpg->param_list) < 0) - goto err_out; - - ISCSI_TPG_ATTRIB(tpg)->tpg = tpg; - - spin_lock(&tpg->tpg_state_lock); - tpg->tpg_state = TPG_STATE_INACTIVE; - spin_unlock(&tpg->tpg_state_lock); - - spin_lock(&tiqn->tiqn_tpg_lock); - list_add_tail(&tpg->tpg_list, &tiqn->tiqn_tpg_list); - tiqn->tiqn_ntpgs++; - pr_debug("CORE[%s]_TPG[%hu] - Added iSCSI Target Portal Group\n", - tiqn->tiqn, tpg->tpgt); - spin_unlock(&tiqn->tiqn_tpg_lock); - - return 0; -err_out: - if (tpg->param_list) { - iscsi_release_param_list(tpg->param_list); - tpg->param_list = NULL; - } - kfree(tpg); - return -ENOMEM; -} - -int iscsit_tpg_del_portal_group( - struct iscsi_tiqn *tiqn, - struct iscsi_portal_group *tpg, - int force) -{ - u8 old_state = tpg->tpg_state; - - spin_lock(&tpg->tpg_state_lock); - tpg->tpg_state = TPG_STATE_INACTIVE; - spin_unlock(&tpg->tpg_state_lock); - - if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { - pr_err("Unable to delete iSCSI Target Portal Group:" - " %hu while active sessions exist, and force=0\n", - tpg->tpgt); - tpg->tpg_state = old_state; - return -EPERM; - } - - core_tpg_clear_object_luns(&tpg->tpg_se_tpg); - - if (tpg->param_list) { - iscsi_release_param_list(tpg->param_list); - tpg->param_list = NULL; - } - - core_tpg_deregister(&tpg->tpg_se_tpg); - - spin_lock(&tpg->tpg_state_lock); - tpg->tpg_state = TPG_STATE_FREE; - spin_unlock(&tpg->tpg_state_lock); - - spin_lock(&tiqn->tiqn_tpg_lock); - tiqn->tiqn_ntpgs--; - list_del(&tpg->tpg_list); - spin_unlock(&tiqn->tiqn_tpg_lock); - - pr_debug("CORE[%s]_TPG[%hu] - Deleted iSCSI Target Portal Group\n", - tiqn->tiqn, tpg->tpgt); - - kfree(tpg); - return 0; -} - -int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *tpg) -{ - struct iscsi_param *param; - struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; - - spin_lock(&tpg->tpg_state_lock); - if (tpg->tpg_state == TPG_STATE_ACTIVE) { - pr_err("iSCSI target portal group: %hu is already" - " active, ignoring request.\n", tpg->tpgt); - spin_unlock(&tpg->tpg_state_lock); - return -EINVAL; - } - /* - * Make sure that AuthMethod does not contain None as an option - * unless explictly disabled. Set the default to CHAP if authentication - * is enforced (as per default), and remove the NONE option. - */ - param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list); - if (!param) { - spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; - } - - if (ISCSI_TPG_ATTRIB(tpg)->authentication) { - if (!strcmp(param->value, NONE)) - if (iscsi_update_param_value(param, CHAP) < 0) { - spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; - } - if (iscsit_ta_authentication(tpg, 1) < 0) { - spin_unlock(&tpg->tpg_state_lock); - return -ENOMEM; - } - } - - tpg->tpg_state = TPG_STATE_ACTIVE; - spin_unlock(&tpg->tpg_state_lock); - - spin_lock(&tiqn->tiqn_tpg_lock); - tiqn->tiqn_active_tpgs++; - pr_debug("iSCSI_TPG[%hu] - Enabled iSCSI Target Portal Group\n", - tpg->tpgt); - spin_unlock(&tiqn->tiqn_tpg_lock); - - return 0; -} - -int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *tpg, int force) -{ - struct iscsi_tiqn *tiqn; - u8 old_state = tpg->tpg_state; - - spin_lock(&tpg->tpg_state_lock); - if (tpg->tpg_state == TPG_STATE_INACTIVE) { - pr_err("iSCSI Target Portal Group: %hu is already" - " inactive, ignoring request.\n", tpg->tpgt); - spin_unlock(&tpg->tpg_state_lock); - return -EINVAL; - } - tpg->tpg_state = TPG_STATE_INACTIVE; - spin_unlock(&tpg->tpg_state_lock); - - iscsit_clear_tpg_np_login_threads(tpg); - - if (iscsit_release_sessions_for_tpg(tpg, force) < 0) { - spin_lock(&tpg->tpg_state_lock); - tpg->tpg_state = old_state; - spin_unlock(&tpg->tpg_state_lock); - pr_err("Unable to disable iSCSI Target Portal Group:" - " %hu while active sessions exist, and force=0\n", - tpg->tpgt); - return -EPERM; - } - - tiqn = tpg->tpg_tiqn; - if (!tiqn || (tpg == iscsit_global->discovery_tpg)) - return 0; - - spin_lock(&tiqn->tiqn_tpg_lock); - tiqn->tiqn_active_tpgs--; - pr_debug("iSCSI_TPG[%hu] - Disabled iSCSI Target Portal Group\n", - tpg->tpgt); - spin_unlock(&tiqn->tiqn_tpg_lock); - - return 0; -} - -struct iscsi_node_attrib *iscsit_tpg_get_node_attrib( - struct iscsi_session *sess) -{ - struct se_session *se_sess = sess->se_sess; - struct se_node_acl *se_nacl = se_sess->se_node_acl; - struct iscsi_node_acl *acl = container_of(se_nacl, struct iscsi_node_acl, - se_node_acl); - - return &acl->node_attrib; -} - -struct iscsi_tpg_np *iscsit_tpg_locate_child_np( - struct iscsi_tpg_np *tpg_np, - int network_transport) -{ - struct iscsi_tpg_np *tpg_np_child, *tpg_np_child_tmp; - - spin_lock(&tpg_np->tpg_np_parent_lock); - list_for_each_entry_safe(tpg_np_child, tpg_np_child_tmp, - &tpg_np->tpg_np_parent_list, tpg_np_child_list) { - if (tpg_np_child->tpg_np->np_network_transport == - network_transport) { - spin_unlock(&tpg_np->tpg_np_parent_lock); - return tpg_np_child; - } - } - spin_unlock(&tpg_np->tpg_np_parent_lock); - - return NULL; -} - -struct iscsi_tpg_np *iscsit_tpg_add_network_portal( - struct iscsi_portal_group *tpg, - struct __kernel_sockaddr_storage *sockaddr, - char *ip_str, - struct iscsi_tpg_np *tpg_np_parent, - int network_transport) -{ - struct iscsi_np *np; - struct iscsi_tpg_np *tpg_np; - - tpg_np = kzalloc(sizeof(struct iscsi_tpg_np), GFP_KERNEL); - if (!tpg_np) { - pr_err("Unable to allocate memory for" - " struct iscsi_tpg_np.\n"); - return ERR_PTR(-ENOMEM); - } - - np = iscsit_add_np(sockaddr, ip_str, network_transport); - if (IS_ERR(np)) { - kfree(tpg_np); - return ERR_CAST(np); - } - - INIT_LIST_HEAD(&tpg_np->tpg_np_list); - INIT_LIST_HEAD(&tpg_np->tpg_np_child_list); - INIT_LIST_HEAD(&tpg_np->tpg_np_parent_list); - spin_lock_init(&tpg_np->tpg_np_parent_lock); - tpg_np->tpg_np = np; - tpg_np->tpg = tpg; - - spin_lock(&tpg->tpg_np_lock); - list_add_tail(&tpg_np->tpg_np_list, &tpg->tpg_gnp_list); - tpg->num_tpg_nps++; - if (tpg->tpg_tiqn) - tpg->tpg_tiqn->tiqn_num_tpg_nps++; - spin_unlock(&tpg->tpg_np_lock); - - if (tpg_np_parent) { - tpg_np->tpg_np_parent = tpg_np_parent; - spin_lock(&tpg_np_parent->tpg_np_parent_lock); - list_add_tail(&tpg_np->tpg_np_child_list, - &tpg_np_parent->tpg_np_parent_list); - spin_unlock(&tpg_np_parent->tpg_np_parent_lock); - } - - pr_debug("CORE[%s] - Added Network Portal: %s:%hu,%hu on %s\n", - tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, - (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP"); - - return tpg_np; -} - -static int iscsit_tpg_release_np( - struct iscsi_tpg_np *tpg_np, - struct iscsi_portal_group *tpg, - struct iscsi_np *np) -{ - iscsit_clear_tpg_np_login_thread(tpg_np, tpg); - - pr_debug("CORE[%s] - Removed Network Portal: %s:%hu,%hu on %s\n", - tpg->tpg_tiqn->tiqn, np->np_ip, np->np_port, tpg->tpgt, - (np->np_network_transport == ISCSI_TCP) ? "TCP" : "SCTP"); - - tpg_np->tpg_np = NULL; - tpg_np->tpg = NULL; - kfree(tpg_np); - /* - * iscsit_del_np() will shutdown struct iscsi_np when last TPG reference is released. - */ - return iscsit_del_np(np); -} - -int iscsit_tpg_del_network_portal( - struct iscsi_portal_group *tpg, - struct iscsi_tpg_np *tpg_np) -{ - struct iscsi_np *np; - struct iscsi_tpg_np *tpg_np_child, *tpg_np_child_tmp; - int ret = 0; - - np = tpg_np->tpg_np; - if (!np) { - pr_err("Unable to locate struct iscsi_np from" - " struct iscsi_tpg_np\n"); - return -EINVAL; - } - - if (!tpg_np->tpg_np_parent) { - /* - * We are the parent tpg network portal. Release all of the - * child tpg_np's (eg: the non ISCSI_TCP ones) on our parent - * list first. - */ - list_for_each_entry_safe(tpg_np_child, tpg_np_child_tmp, - &tpg_np->tpg_np_parent_list, - tpg_np_child_list) { - ret = iscsit_tpg_del_network_portal(tpg, tpg_np_child); - if (ret < 0) - pr_err("iscsit_tpg_del_network_portal()" - " failed: %d\n", ret); - } - } else { - /* - * We are not the parent ISCSI_TCP tpg network portal. Release - * our own network portals from the child list. - */ - spin_lock(&tpg_np->tpg_np_parent->tpg_np_parent_lock); - list_del(&tpg_np->tpg_np_child_list); - spin_unlock(&tpg_np->tpg_np_parent->tpg_np_parent_lock); - } - - spin_lock(&tpg->tpg_np_lock); - list_del(&tpg_np->tpg_np_list); - tpg->num_tpg_nps--; - if (tpg->tpg_tiqn) - tpg->tpg_tiqn->tiqn_num_tpg_nps--; - spin_unlock(&tpg->tpg_np_lock); - - return iscsit_tpg_release_np(tpg_np, tpg, np); -} - -int iscsit_tpg_set_initiator_node_queue_depth( - struct iscsi_portal_group *tpg, - unsigned char *initiatorname, - u32 queue_depth, - int force) -{ - return core_tpg_set_initiator_node_queue_depth(&tpg->tpg_se_tpg, - initiatorname, queue_depth, force); -} - -int iscsit_ta_authentication(struct iscsi_portal_group *tpg, u32 authentication) -{ - unsigned char buf1[256], buf2[256], *none = NULL; - int len; - struct iscsi_param *param; - struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; - - if ((authentication != 1) && (authentication != 0)) { - pr_err("Illegal value for authentication parameter:" - " %u, ignoring request.\n", authentication); - return -1; - } - - memset(buf1, 0, sizeof(buf1)); - memset(buf2, 0, sizeof(buf2)); - - param = iscsi_find_param_from_key(AUTHMETHOD, tpg->param_list); - if (!param) - return -EINVAL; - - if (authentication) { - snprintf(buf1, sizeof(buf1), "%s", param->value); - none = strstr(buf1, NONE); - if (!none) - goto out; - if (!strncmp(none + 4, ",", 1)) { - if (!strcmp(buf1, none)) - sprintf(buf2, "%s", none+5); - else { - none--; - *none = '\0'; - len = sprintf(buf2, "%s", buf1); - none += 5; - sprintf(buf2 + len, "%s", none); - } - } else { - none--; - *none = '\0'; - sprintf(buf2, "%s", buf1); - } - if (iscsi_update_param_value(param, buf2) < 0) - return -EINVAL; - } else { - snprintf(buf1, sizeof(buf1), "%s", param->value); - none = strstr(buf1, NONE); - if ((none)) - goto out; - strncat(buf1, ",", strlen(",")); - strncat(buf1, NONE, strlen(NONE)); - if (iscsi_update_param_value(param, buf1) < 0) - return -EINVAL; - } - -out: - a->authentication = authentication; - pr_debug("%s iSCSI Authentication Methods for TPG: %hu.\n", - a->authentication ? "Enforcing" : "Disabling", tpg->tpgt); - - return 0; -} - -int iscsit_ta_login_timeout( - struct iscsi_portal_group *tpg, - u32 login_timeout) -{ - struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; - - if (login_timeout > TA_LOGIN_TIMEOUT_MAX) { - pr_err("Requested Login Timeout %u larger than maximum" - " %u\n", login_timeout, TA_LOGIN_TIMEOUT_MAX); - return -EINVAL; - } else if (login_timeout < TA_LOGIN_TIMEOUT_MIN) { - pr_err("Requested Logout Timeout %u smaller than" - " minimum %u\n", login_timeout, TA_LOGIN_TIMEOUT_MIN); - return -EINVAL; - } - - a->login_timeout = login_timeout; - pr_debug("Set Logout Timeout to %u for Target Portal Group" - " %hu\n", a->login_timeout, tpg->tpgt); - - return 0; -} - -int iscsit_ta_netif_timeout( - struct iscsi_portal_group *tpg, - u32 netif_timeout) -{ - struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; - - if (netif_timeout > TA_NETIF_TIMEOUT_MAX) { - pr_err("Requested Network Interface Timeout %u larger" - " than maximum %u\n", netif_timeout, - TA_NETIF_TIMEOUT_MAX); - return -EINVAL; - } else if (netif_timeout < TA_NETIF_TIMEOUT_MIN) { - pr_err("Requested Network Interface Timeout %u smaller" - " than minimum %u\n", netif_timeout, - TA_NETIF_TIMEOUT_MIN); - return -EINVAL; - } - - a->netif_timeout = netif_timeout; - pr_debug("Set Network Interface Timeout to %u for" - " Target Portal Group %hu\n", a->netif_timeout, tpg->tpgt); - - return 0; -} - -int iscsit_ta_generate_node_acls( - struct iscsi_portal_group *tpg, - u32 flag) -{ - struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; - - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - a->generate_node_acls = flag; - pr_debug("iSCSI_TPG[%hu] - Generate Initiator Portal Group ACLs: %s\n", - tpg->tpgt, (a->generate_node_acls) ? "Enabled" : "Disabled"); - - return 0; -} - -int iscsit_ta_default_cmdsn_depth( - struct iscsi_portal_group *tpg, - u32 tcq_depth) -{ - struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; - - if (tcq_depth > TA_DEFAULT_CMDSN_DEPTH_MAX) { - pr_err("Requested Default Queue Depth: %u larger" - " than maximum %u\n", tcq_depth, - TA_DEFAULT_CMDSN_DEPTH_MAX); - return -EINVAL; - } else if (tcq_depth < TA_DEFAULT_CMDSN_DEPTH_MIN) { - pr_err("Requested Default Queue Depth: %u smaller" - " than minimum %u\n", tcq_depth, - TA_DEFAULT_CMDSN_DEPTH_MIN); - return -EINVAL; - } - - a->default_cmdsn_depth = tcq_depth; - pr_debug("iSCSI_TPG[%hu] - Set Default CmdSN TCQ Depth to %u\n", - tpg->tpgt, a->default_cmdsn_depth); - - return 0; -} - -int iscsit_ta_cache_dynamic_acls( - struct iscsi_portal_group *tpg, - u32 flag) -{ - struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; - - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - a->cache_dynamic_acls = flag; - pr_debug("iSCSI_TPG[%hu] - Cache Dynamic Initiator Portal Group" - " ACLs %s\n", tpg->tpgt, (a->cache_dynamic_acls) ? - "Enabled" : "Disabled"); - - return 0; -} - -int iscsit_ta_demo_mode_write_protect( - struct iscsi_portal_group *tpg, - u32 flag) -{ - struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; - - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - a->demo_mode_write_protect = flag; - pr_debug("iSCSI_TPG[%hu] - Demo Mode Write Protect bit: %s\n", - tpg->tpgt, (a->demo_mode_write_protect) ? "ON" : "OFF"); - - return 0; -} - -int iscsit_ta_prod_mode_write_protect( - struct iscsi_portal_group *tpg, - u32 flag) -{ - struct iscsi_tpg_attrib *a = &tpg->tpg_attrib; - - if ((flag != 0) && (flag != 1)) { - pr_err("Illegal value %d\n", flag); - return -EINVAL; - } - - a->prod_mode_write_protect = flag; - pr_debug("iSCSI_TPG[%hu] - Production Mode Write Protect bit:" - " %s\n", tpg->tpgt, (a->prod_mode_write_protect) ? - "ON" : "OFF"); - - return 0; -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_tpg.h b/trunk/drivers/target/iscsi/iscsi_target_tpg.h deleted file mode 100644 index dda48c141a8c..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_tpg.h +++ /dev/null @@ -1,41 +0,0 @@ -#ifndef ISCSI_TARGET_TPG_H -#define ISCSI_TARGET_TPG_H - -extern struct iscsi_portal_group *iscsit_alloc_portal_group(struct iscsi_tiqn *, u16); -extern int iscsit_load_discovery_tpg(void); -extern void iscsit_release_discovery_tpg(void); -extern struct iscsi_portal_group *iscsit_get_tpg_from_np(struct iscsi_tiqn *, - struct iscsi_np *); -extern int iscsit_get_tpg(struct iscsi_portal_group *); -extern void iscsit_put_tpg(struct iscsi_portal_group *); -extern void iscsit_clear_tpg_np_login_threads(struct iscsi_portal_group *); -extern void iscsit_tpg_dump_params(struct iscsi_portal_group *); -extern int iscsit_tpg_add_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *); -extern int iscsit_tpg_del_portal_group(struct iscsi_tiqn *, struct iscsi_portal_group *, - int); -extern int iscsit_tpg_enable_portal_group(struct iscsi_portal_group *); -extern int iscsit_tpg_disable_portal_group(struct iscsi_portal_group *, int); -extern struct iscsi_node_acl *iscsit_tpg_add_initiator_node_acl( - struct iscsi_portal_group *, const char *, u32); -extern void iscsit_tpg_del_initiator_node_acl(struct iscsi_portal_group *, - struct se_node_acl *); -extern struct iscsi_node_attrib *iscsit_tpg_get_node_attrib(struct iscsi_session *); -extern void iscsit_tpg_del_external_nps(struct iscsi_tpg_np *); -extern struct iscsi_tpg_np *iscsit_tpg_locate_child_np(struct iscsi_tpg_np *, int); -extern struct iscsi_tpg_np *iscsit_tpg_add_network_portal(struct iscsi_portal_group *, - struct __kernel_sockaddr_storage *, char *, struct iscsi_tpg_np *, - int); -extern int iscsit_tpg_del_network_portal(struct iscsi_portal_group *, - struct iscsi_tpg_np *); -extern int iscsit_tpg_set_initiator_node_queue_depth(struct iscsi_portal_group *, - unsigned char *, u32, int); -extern int iscsit_ta_authentication(struct iscsi_portal_group *, u32); -extern int iscsit_ta_login_timeout(struct iscsi_portal_group *, u32); -extern int iscsit_ta_netif_timeout(struct iscsi_portal_group *, u32); -extern int iscsit_ta_generate_node_acls(struct iscsi_portal_group *, u32); -extern int iscsit_ta_default_cmdsn_depth(struct iscsi_portal_group *, u32); -extern int iscsit_ta_cache_dynamic_acls(struct iscsi_portal_group *, u32); -extern int iscsit_ta_demo_mode_write_protect(struct iscsi_portal_group *, u32); -extern int iscsit_ta_prod_mode_write_protect(struct iscsi_portal_group *, u32); - -#endif /* ISCSI_TARGET_TPG_H */ diff --git a/trunk/drivers/target/iscsi/iscsi_target_tq.c b/trunk/drivers/target/iscsi/iscsi_target_tq.c deleted file mode 100644 index 0baac5bcebd4..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_tq.c +++ /dev/null @@ -1,551 +0,0 @@ -/******************************************************************************* - * This file contains the iSCSI Login Thread and Thread Queue functions. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_tq.h" -#include "iscsi_target.h" - -static LIST_HEAD(active_ts_list); -static LIST_HEAD(inactive_ts_list); -static DEFINE_SPINLOCK(active_ts_lock); -static DEFINE_SPINLOCK(inactive_ts_lock); -static DEFINE_SPINLOCK(ts_bitmap_lock); - -static void iscsi_add_ts_to_active_list(struct iscsi_thread_set *ts) -{ - spin_lock(&active_ts_lock); - list_add_tail(&ts->ts_list, &active_ts_list); - iscsit_global->active_ts++; - spin_unlock(&active_ts_lock); -} - -extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *ts) -{ - spin_lock(&inactive_ts_lock); - list_add_tail(&ts->ts_list, &inactive_ts_list); - iscsit_global->inactive_ts++; - spin_unlock(&inactive_ts_lock); -} - -static void iscsi_del_ts_from_active_list(struct iscsi_thread_set *ts) -{ - spin_lock(&active_ts_lock); - list_del(&ts->ts_list); - iscsit_global->active_ts--; - spin_unlock(&active_ts_lock); -} - -static struct iscsi_thread_set *iscsi_get_ts_from_inactive_list(void) -{ - struct iscsi_thread_set *ts; - - spin_lock(&inactive_ts_lock); - if (list_empty(&inactive_ts_list)) { - spin_unlock(&inactive_ts_lock); - return NULL; - } - - list_for_each_entry(ts, &inactive_ts_list, ts_list) - break; - - list_del(&ts->ts_list); - iscsit_global->inactive_ts--; - spin_unlock(&inactive_ts_lock); - - return ts; -} - -extern int iscsi_allocate_thread_sets(u32 thread_pair_count) -{ - int allocated_thread_pair_count = 0, i, thread_id; - struct iscsi_thread_set *ts = NULL; - - for (i = 0; i < thread_pair_count; i++) { - ts = kzalloc(sizeof(struct iscsi_thread_set), GFP_KERNEL); - if (!ts) { - pr_err("Unable to allocate memory for" - " thread set.\n"); - return allocated_thread_pair_count; - } - /* - * Locate the next available regision in the thread_set_bitmap - */ - spin_lock(&ts_bitmap_lock); - thread_id = bitmap_find_free_region(iscsit_global->ts_bitmap, - iscsit_global->ts_bitmap_count, get_order(1)); - spin_unlock(&ts_bitmap_lock); - if (thread_id < 0) { - pr_err("bitmap_find_free_region() failed for" - " thread_set_bitmap\n"); - kfree(ts); - return allocated_thread_pair_count; - } - - ts->thread_id = thread_id; - ts->status = ISCSI_THREAD_SET_FREE; - INIT_LIST_HEAD(&ts->ts_list); - spin_lock_init(&ts->ts_state_lock); - init_completion(&ts->rx_post_start_comp); - init_completion(&ts->tx_post_start_comp); - init_completion(&ts->rx_restart_comp); - init_completion(&ts->tx_restart_comp); - init_completion(&ts->rx_start_comp); - init_completion(&ts->tx_start_comp); - - ts->create_threads = 1; - ts->tx_thread = kthread_run(iscsi_target_tx_thread, ts, "%s", - ISCSI_TX_THREAD_NAME); - if (IS_ERR(ts->tx_thread)) { - dump_stack(); - pr_err("Unable to start iscsi_target_tx_thread\n"); - break; - } - - ts->rx_thread = kthread_run(iscsi_target_rx_thread, ts, "%s", - ISCSI_RX_THREAD_NAME); - if (IS_ERR(ts->rx_thread)) { - kthread_stop(ts->tx_thread); - pr_err("Unable to start iscsi_target_rx_thread\n"); - break; - } - ts->create_threads = 0; - - iscsi_add_ts_to_inactive_list(ts); - allocated_thread_pair_count++; - } - - pr_debug("Spawned %d thread set(s) (%d total threads).\n", - allocated_thread_pair_count, allocated_thread_pair_count * 2); - return allocated_thread_pair_count; -} - -extern void iscsi_deallocate_thread_sets(void) -{ - u32 released_count = 0; - struct iscsi_thread_set *ts = NULL; - - while ((ts = iscsi_get_ts_from_inactive_list())) { - - spin_lock_bh(&ts->ts_state_lock); - ts->status = ISCSI_THREAD_SET_DIE; - spin_unlock_bh(&ts->ts_state_lock); - - if (ts->rx_thread) { - send_sig(SIGINT, ts->rx_thread, 1); - kthread_stop(ts->rx_thread); - } - if (ts->tx_thread) { - send_sig(SIGINT, ts->tx_thread, 1); - kthread_stop(ts->tx_thread); - } - /* - * Release this thread_id in the thread_set_bitmap - */ - spin_lock(&ts_bitmap_lock); - bitmap_release_region(iscsit_global->ts_bitmap, - ts->thread_id, get_order(1)); - spin_unlock(&ts_bitmap_lock); - - released_count++; - kfree(ts); - } - - if (released_count) - pr_debug("Stopped %d thread set(s) (%d total threads)." - "\n", released_count, released_count * 2); -} - -static void iscsi_deallocate_extra_thread_sets(void) -{ - u32 orig_count, released_count = 0; - struct iscsi_thread_set *ts = NULL; - - orig_count = TARGET_THREAD_SET_COUNT; - - while ((iscsit_global->inactive_ts + 1) > orig_count) { - ts = iscsi_get_ts_from_inactive_list(); - if (!ts) - break; - - spin_lock_bh(&ts->ts_state_lock); - ts->status = ISCSI_THREAD_SET_DIE; - spin_unlock_bh(&ts->ts_state_lock); - - if (ts->rx_thread) { - send_sig(SIGINT, ts->rx_thread, 1); - kthread_stop(ts->rx_thread); - } - if (ts->tx_thread) { - send_sig(SIGINT, ts->tx_thread, 1); - kthread_stop(ts->tx_thread); - } - /* - * Release this thread_id in the thread_set_bitmap - */ - spin_lock(&ts_bitmap_lock); - bitmap_release_region(iscsit_global->ts_bitmap, - ts->thread_id, get_order(1)); - spin_unlock(&ts_bitmap_lock); - - released_count++; - kfree(ts); - } - - if (released_count) { - pr_debug("Stopped %d thread set(s) (%d total threads)." - "\n", released_count, released_count * 2); - } -} - -void iscsi_activate_thread_set(struct iscsi_conn *conn, struct iscsi_thread_set *ts) -{ - iscsi_add_ts_to_active_list(ts); - - spin_lock_bh(&ts->ts_state_lock); - conn->thread_set = ts; - ts->conn = conn; - spin_unlock_bh(&ts->ts_state_lock); - /* - * Start up the RX thread and wait on rx_post_start_comp. The RX - * Thread will then do the same for the TX Thread in - * iscsi_rx_thread_pre_handler(). - */ - complete(&ts->rx_start_comp); - wait_for_completion(&ts->rx_post_start_comp); -} - -struct iscsi_thread_set *iscsi_get_thread_set(void) -{ - int allocate_ts = 0; - struct completion comp; - struct iscsi_thread_set *ts = NULL; - /* - * If no inactive thread set is available on the first call to - * iscsi_get_ts_from_inactive_list(), sleep for a second and - * try again. If still none are available after two attempts, - * allocate a set ourselves. - */ -get_set: - ts = iscsi_get_ts_from_inactive_list(); - if (!ts) { - if (allocate_ts == 2) - iscsi_allocate_thread_sets(1); - - init_completion(&comp); - wait_for_completion_timeout(&comp, 1 * HZ); - - allocate_ts++; - goto get_set; - } - - ts->delay_inactive = 1; - ts->signal_sent = 0; - ts->thread_count = 2; - init_completion(&ts->rx_restart_comp); - init_completion(&ts->tx_restart_comp); - - return ts; -} - -void iscsi_set_thread_clear(struct iscsi_conn *conn, u8 thread_clear) -{ - struct iscsi_thread_set *ts = NULL; - - if (!conn->thread_set) { - pr_err("struct iscsi_conn->thread_set is NULL\n"); - return; - } - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - ts->thread_clear &= ~thread_clear; - - if ((thread_clear & ISCSI_CLEAR_RX_THREAD) && - (ts->blocked_threads & ISCSI_BLOCK_RX_THREAD)) - complete(&ts->rx_restart_comp); - else if ((thread_clear & ISCSI_CLEAR_TX_THREAD) && - (ts->blocked_threads & ISCSI_BLOCK_TX_THREAD)) - complete(&ts->tx_restart_comp); - spin_unlock_bh(&ts->ts_state_lock); -} - -void iscsi_set_thread_set_signal(struct iscsi_conn *conn, u8 signal_sent) -{ - struct iscsi_thread_set *ts = NULL; - - if (!conn->thread_set) { - pr_err("struct iscsi_conn->thread_set is NULL\n"); - return; - } - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - ts->signal_sent |= signal_sent; - spin_unlock_bh(&ts->ts_state_lock); -} - -int iscsi_release_thread_set(struct iscsi_conn *conn) -{ - int thread_called = 0; - struct iscsi_thread_set *ts = NULL; - - if (!conn || !conn->thread_set) { - pr_err("connection or thread set pointer is NULL\n"); - BUG(); - } - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - ts->status = ISCSI_THREAD_SET_RESET; - - if (!strncmp(current->comm, ISCSI_RX_THREAD_NAME, - strlen(ISCSI_RX_THREAD_NAME))) - thread_called = ISCSI_RX_THREAD; - else if (!strncmp(current->comm, ISCSI_TX_THREAD_NAME, - strlen(ISCSI_TX_THREAD_NAME))) - thread_called = ISCSI_TX_THREAD; - - if (ts->rx_thread && (thread_called == ISCSI_TX_THREAD) && - (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) { - - if (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD)) { - send_sig(SIGINT, ts->rx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD; - } - ts->blocked_threads |= ISCSI_BLOCK_RX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); - wait_for_completion(&ts->rx_restart_comp); - spin_lock_bh(&ts->ts_state_lock); - ts->blocked_threads &= ~ISCSI_BLOCK_RX_THREAD; - } - if (ts->tx_thread && (thread_called == ISCSI_RX_THREAD) && - (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) { - - if (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD)) { - send_sig(SIGINT, ts->tx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD; - } - ts->blocked_threads |= ISCSI_BLOCK_TX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); - wait_for_completion(&ts->tx_restart_comp); - spin_lock_bh(&ts->ts_state_lock); - ts->blocked_threads &= ~ISCSI_BLOCK_TX_THREAD; - } - - ts->conn = NULL; - ts->status = ISCSI_THREAD_SET_FREE; - spin_unlock_bh(&ts->ts_state_lock); - - return 0; -} - -int iscsi_thread_set_force_reinstatement(struct iscsi_conn *conn) -{ - struct iscsi_thread_set *ts; - - if (!conn->thread_set) - return -1; - ts = conn->thread_set; - - spin_lock_bh(&ts->ts_state_lock); - if (ts->status != ISCSI_THREAD_SET_ACTIVE) { - spin_unlock_bh(&ts->ts_state_lock); - return -1; - } - - if (ts->tx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_TX_THREAD))) { - send_sig(SIGINT, ts->tx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_TX_THREAD; - } - if (ts->rx_thread && (!(ts->signal_sent & ISCSI_SIGNAL_RX_THREAD))) { - send_sig(SIGINT, ts->rx_thread, 1); - ts->signal_sent |= ISCSI_SIGNAL_RX_THREAD; - } - spin_unlock_bh(&ts->ts_state_lock); - - return 0; -} - -static void iscsi_check_to_add_additional_sets(void) -{ - int thread_sets_add; - - spin_lock(&inactive_ts_lock); - thread_sets_add = iscsit_global->inactive_ts; - spin_unlock(&inactive_ts_lock); - if (thread_sets_add == 1) - iscsi_allocate_thread_sets(1); -} - -static int iscsi_signal_thread_pre_handler(struct iscsi_thread_set *ts) -{ - spin_lock_bh(&ts->ts_state_lock); - if ((ts->status == ISCSI_THREAD_SET_DIE) || signal_pending(current)) { - spin_unlock_bh(&ts->ts_state_lock); - return -1; - } - spin_unlock_bh(&ts->ts_state_lock); - - return 0; -} - -struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *ts) -{ - int ret; - - spin_lock_bh(&ts->ts_state_lock); - if (ts->create_threads) { - spin_unlock_bh(&ts->ts_state_lock); - goto sleep; - } - - flush_signals(current); - - if (ts->delay_inactive && (--ts->thread_count == 0)) { - spin_unlock_bh(&ts->ts_state_lock); - iscsi_del_ts_from_active_list(ts); - - if (!iscsit_global->in_shutdown) - iscsi_deallocate_extra_thread_sets(); - - iscsi_add_ts_to_inactive_list(ts); - spin_lock_bh(&ts->ts_state_lock); - } - - if ((ts->status == ISCSI_THREAD_SET_RESET) && - (ts->thread_clear & ISCSI_CLEAR_RX_THREAD)) - complete(&ts->rx_restart_comp); - - ts->thread_clear &= ~ISCSI_CLEAR_RX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); -sleep: - ret = wait_for_completion_interruptible(&ts->rx_start_comp); - if (ret != 0) - return NULL; - - if (iscsi_signal_thread_pre_handler(ts) < 0) - return NULL; - - if (!ts->conn) { - pr_err("struct iscsi_thread_set->conn is NULL for" - " thread_id: %d, going back to sleep\n", ts->thread_id); - goto sleep; - } - iscsi_check_to_add_additional_sets(); - /* - * The RX Thread starts up the TX Thread and sleeps. - */ - ts->thread_clear |= ISCSI_CLEAR_RX_THREAD; - complete(&ts->tx_start_comp); - wait_for_completion(&ts->tx_post_start_comp); - - return ts->conn; -} - -struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *ts) -{ - int ret; - - spin_lock_bh(&ts->ts_state_lock); - if (ts->create_threads) { - spin_unlock_bh(&ts->ts_state_lock); - goto sleep; - } - - flush_signals(current); - - if (ts->delay_inactive && (--ts->thread_count == 0)) { - spin_unlock_bh(&ts->ts_state_lock); - iscsi_del_ts_from_active_list(ts); - - if (!iscsit_global->in_shutdown) - iscsi_deallocate_extra_thread_sets(); - - iscsi_add_ts_to_inactive_list(ts); - spin_lock_bh(&ts->ts_state_lock); - } - if ((ts->status == ISCSI_THREAD_SET_RESET) && - (ts->thread_clear & ISCSI_CLEAR_TX_THREAD)) - complete(&ts->tx_restart_comp); - - ts->thread_clear &= ~ISCSI_CLEAR_TX_THREAD; - spin_unlock_bh(&ts->ts_state_lock); -sleep: - ret = wait_for_completion_interruptible(&ts->tx_start_comp); - if (ret != 0) - return NULL; - - if (iscsi_signal_thread_pre_handler(ts) < 0) - return NULL; - - if (!ts->conn) { - pr_err("struct iscsi_thread_set->conn is NULL for " - " thread_id: %d, going back to sleep\n", - ts->thread_id); - goto sleep; - } - - iscsi_check_to_add_additional_sets(); - /* - * From the TX thread, up the tx_post_start_comp that the RX Thread is - * sleeping on in iscsi_rx_thread_pre_handler(), then up the - * rx_post_start_comp that iscsi_activate_thread_set() is sleeping on. - */ - ts->thread_clear |= ISCSI_CLEAR_TX_THREAD; - complete(&ts->tx_post_start_comp); - complete(&ts->rx_post_start_comp); - - spin_lock_bh(&ts->ts_state_lock); - ts->status = ISCSI_THREAD_SET_ACTIVE; - spin_unlock_bh(&ts->ts_state_lock); - - return ts->conn; -} - -int iscsi_thread_set_init(void) -{ - int size; - - iscsit_global->ts_bitmap_count = ISCSI_TS_BITMAP_BITS; - - size = BITS_TO_LONGS(iscsit_global->ts_bitmap_count) * sizeof(long); - iscsit_global->ts_bitmap = kzalloc(size, GFP_KERNEL); - if (!iscsit_global->ts_bitmap) { - pr_err("Unable to allocate iscsit_global->ts_bitmap\n"); - return -ENOMEM; - } - - spin_lock_init(&active_ts_lock); - spin_lock_init(&inactive_ts_lock); - spin_lock_init(&ts_bitmap_lock); - INIT_LIST_HEAD(&active_ts_list); - INIT_LIST_HEAD(&inactive_ts_list); - - return 0; -} - -void iscsi_thread_set_free(void) -{ - kfree(iscsit_global->ts_bitmap); -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_tq.h b/trunk/drivers/target/iscsi/iscsi_target_tq.h deleted file mode 100644 index 26e6a95ec203..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_tq.h +++ /dev/null @@ -1,88 +0,0 @@ -#ifndef ISCSI_THREAD_QUEUE_H -#define ISCSI_THREAD_QUEUE_H - -/* - * Defines for thread sets. - */ -extern int iscsi_thread_set_force_reinstatement(struct iscsi_conn *); -extern void iscsi_add_ts_to_inactive_list(struct iscsi_thread_set *); -extern int iscsi_allocate_thread_sets(u32); -extern void iscsi_deallocate_thread_sets(void); -extern void iscsi_activate_thread_set(struct iscsi_conn *, struct iscsi_thread_set *); -extern struct iscsi_thread_set *iscsi_get_thread_set(void); -extern void iscsi_set_thread_clear(struct iscsi_conn *, u8); -extern void iscsi_set_thread_set_signal(struct iscsi_conn *, u8); -extern int iscsi_release_thread_set(struct iscsi_conn *); -extern struct iscsi_conn *iscsi_rx_thread_pre_handler(struct iscsi_thread_set *); -extern struct iscsi_conn *iscsi_tx_thread_pre_handler(struct iscsi_thread_set *); -extern int iscsi_thread_set_init(void); -extern void iscsi_thread_set_free(void); - -extern int iscsi_target_tx_thread(void *); -extern int iscsi_target_rx_thread(void *); - -#define TARGET_THREAD_SET_COUNT 4 - -#define ISCSI_RX_THREAD 1 -#define ISCSI_TX_THREAD 2 -#define ISCSI_RX_THREAD_NAME "iscsi_trx" -#define ISCSI_TX_THREAD_NAME "iscsi_ttx" -#define ISCSI_BLOCK_RX_THREAD 0x1 -#define ISCSI_BLOCK_TX_THREAD 0x2 -#define ISCSI_CLEAR_RX_THREAD 0x1 -#define ISCSI_CLEAR_TX_THREAD 0x2 -#define ISCSI_SIGNAL_RX_THREAD 0x1 -#define ISCSI_SIGNAL_TX_THREAD 0x2 - -/* struct iscsi_thread_set->status */ -#define ISCSI_THREAD_SET_FREE 1 -#define ISCSI_THREAD_SET_ACTIVE 2 -#define ISCSI_THREAD_SET_DIE 3 -#define ISCSI_THREAD_SET_RESET 4 -#define ISCSI_THREAD_SET_DEALLOCATE_THREADS 5 - -/* By default allow a maximum of 32K iSCSI connections */ -#define ISCSI_TS_BITMAP_BITS 32768 - -struct iscsi_thread_set { - /* flags used for blocking and restarting sets */ - int blocked_threads; - /* flag for creating threads */ - int create_threads; - /* flag for delaying readding to inactive list */ - int delay_inactive; - /* status for thread set */ - int status; - /* which threads have had signals sent */ - int signal_sent; - /* flag for which threads exited first */ - int thread_clear; - /* Active threads in the thread set */ - int thread_count; - /* Unique thread ID */ - u32 thread_id; - /* pointer to connection if set is active */ - struct iscsi_conn *conn; - /* used for controlling ts state accesses */ - spinlock_t ts_state_lock; - /* Used for rx side post startup */ - struct completion rx_post_start_comp; - /* Used for tx side post startup */ - struct completion tx_post_start_comp; - /* used for restarting thread queue */ - struct completion rx_restart_comp; - /* used for restarting thread queue */ - struct completion tx_restart_comp; - /* used for normal unused blocking */ - struct completion rx_start_comp; - /* used for normal unused blocking */ - struct completion tx_start_comp; - /* OS descriptor for rx thread */ - struct task_struct *rx_thread; - /* OS descriptor for tx thread */ - struct task_struct *tx_thread; - /* struct iscsi_thread_set in list list head*/ - struct list_head ts_list; -}; - -#endif /*** ISCSI_THREAD_QUEUE_H ***/ diff --git a/trunk/drivers/target/iscsi/iscsi_target_util.c b/trunk/drivers/target/iscsi/iscsi_target_util.c deleted file mode 100644 index a1acb0167902..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_util.c +++ /dev/null @@ -1,1819 +0,0 @@ -/******************************************************************************* - * This file contains the iSCSI Target specific utility functions. - * - * \u00a9 Copyright 2007-2011 RisingTide Systems LLC. - * - * Licensed to the Linux Foundation under the General Public License (GPL) version 2. - * - * Author: Nicholas A. Bellinger - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - ******************************************************************************/ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "iscsi_target_core.h" -#include "iscsi_target_parameters.h" -#include "iscsi_target_seq_pdu_list.h" -#include "iscsi_target_datain_values.h" -#include "iscsi_target_erl0.h" -#include "iscsi_target_erl1.h" -#include "iscsi_target_erl2.h" -#include "iscsi_target_tpg.h" -#include "iscsi_target_tq.h" -#include "iscsi_target_util.h" -#include "iscsi_target.h" - -#define PRINT_BUFF(buff, len) \ -{ \ - int zzz; \ - \ - pr_debug("%d:\n", __LINE__); \ - for (zzz = 0; zzz < len; zzz++) { \ - if (zzz % 16 == 0) { \ - if (zzz) \ - pr_debug("\n"); \ - pr_debug("%4i: ", zzz); \ - } \ - pr_debug("%02x ", (unsigned char) (buff)[zzz]); \ - } \ - if ((len + 1) % 16) \ - pr_debug("\n"); \ -} - -extern struct list_head g_tiqn_list; -extern spinlock_t tiqn_lock; - -/* - * Called with cmd->r2t_lock held. - */ -int iscsit_add_r2t_to_list( - struct iscsi_cmd *cmd, - u32 offset, - u32 xfer_len, - int recovery, - u32 r2t_sn) -{ - struct iscsi_r2t *r2t; - - r2t = kmem_cache_zalloc(lio_r2t_cache, GFP_ATOMIC); - if (!r2t) { - pr_err("Unable to allocate memory for struct iscsi_r2t.\n"); - return -1; - } - INIT_LIST_HEAD(&r2t->r2t_list); - - r2t->recovery_r2t = recovery; - r2t->r2t_sn = (!r2t_sn) ? cmd->r2t_sn++ : r2t_sn; - r2t->offset = offset; - r2t->xfer_len = xfer_len; - list_add_tail(&r2t->r2t_list, &cmd->cmd_r2t_list); - spin_unlock_bh(&cmd->r2t_lock); - - iscsit_add_cmd_to_immediate_queue(cmd, cmd->conn, ISTATE_SEND_R2T); - - spin_lock_bh(&cmd->r2t_lock); - return 0; -} - -struct iscsi_r2t *iscsit_get_r2t_for_eos( - struct iscsi_cmd *cmd, - u32 offset, - u32 length) -{ - struct iscsi_r2t *r2t; - - spin_lock_bh(&cmd->r2t_lock); - list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { - if ((r2t->offset <= offset) && - (r2t->offset + r2t->xfer_len) >= (offset + length)) { - spin_unlock_bh(&cmd->r2t_lock); - return r2t; - } - } - spin_unlock_bh(&cmd->r2t_lock); - - pr_err("Unable to locate R2T for Offset: %u, Length:" - " %u\n", offset, length); - return NULL; -} - -struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *cmd) -{ - struct iscsi_r2t *r2t; - - spin_lock_bh(&cmd->r2t_lock); - list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { - if (!r2t->sent_r2t) { - spin_unlock_bh(&cmd->r2t_lock); - return r2t; - } - } - spin_unlock_bh(&cmd->r2t_lock); - - pr_err("Unable to locate next R2T to send for ITT:" - " 0x%08x.\n", cmd->init_task_tag); - return NULL; -} - -/* - * Called with cmd->r2t_lock held. - */ -void iscsit_free_r2t(struct iscsi_r2t *r2t, struct iscsi_cmd *cmd) -{ - list_del(&r2t->r2t_list); - kmem_cache_free(lio_r2t_cache, r2t); -} - -void iscsit_free_r2ts_from_list(struct iscsi_cmd *cmd) -{ - struct iscsi_r2t *r2t, *r2t_tmp; - - spin_lock_bh(&cmd->r2t_lock); - list_for_each_entry_safe(r2t, r2t_tmp, &cmd->cmd_r2t_list, r2t_list) - iscsit_free_r2t(r2t, cmd); - spin_unlock_bh(&cmd->r2t_lock); -} - -/* - * May be called from software interrupt (timer) context for allocating - * iSCSI NopINs. - */ -struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *conn, gfp_t gfp_mask) -{ - struct iscsi_cmd *cmd; - - cmd = kmem_cache_zalloc(lio_cmd_cache, gfp_mask); - if (!cmd) { - pr_err("Unable to allocate memory for struct iscsi_cmd.\n"); - return NULL; - } - - cmd->conn = conn; - INIT_LIST_HEAD(&cmd->i_list); - INIT_LIST_HEAD(&cmd->datain_list); - INIT_LIST_HEAD(&cmd->cmd_r2t_list); - init_completion(&cmd->reject_comp); - spin_lock_init(&cmd->datain_lock); - spin_lock_init(&cmd->dataout_timeout_lock); - spin_lock_init(&cmd->istate_lock); - spin_lock_init(&cmd->error_lock); - spin_lock_init(&cmd->r2t_lock); - - return cmd; -} - -/* - * Called from iscsi_handle_scsi_cmd() - */ -struct iscsi_cmd *iscsit_allocate_se_cmd( - struct iscsi_conn *conn, - u32 data_length, - int data_direction, - int iscsi_task_attr) -{ - struct iscsi_cmd *cmd; - struct se_cmd *se_cmd; - int sam_task_attr; - - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); - if (!cmd) - return NULL; - - cmd->data_direction = data_direction; - cmd->data_length = data_length; - /* - * Figure out the SAM Task Attribute for the incoming SCSI CDB - */ - if ((iscsi_task_attr == ISCSI_ATTR_UNTAGGED) || - (iscsi_task_attr == ISCSI_ATTR_SIMPLE)) - sam_task_attr = MSG_SIMPLE_TAG; - else if (iscsi_task_attr == ISCSI_ATTR_ORDERED) - sam_task_attr = MSG_ORDERED_TAG; - else if (iscsi_task_attr == ISCSI_ATTR_HEAD_OF_QUEUE) - sam_task_attr = MSG_HEAD_TAG; - else if (iscsi_task_attr == ISCSI_ATTR_ACA) - sam_task_attr = MSG_ACA_TAG; - else { - pr_debug("Unknown iSCSI Task Attribute: 0x%02x, using" - " MSG_SIMPLE_TAG\n", iscsi_task_attr); - sam_task_attr = MSG_SIMPLE_TAG; - } - - se_cmd = &cmd->se_cmd; - /* - * Initialize struct se_cmd descriptor from target_core_mod infrastructure - */ - transport_init_se_cmd(se_cmd, &lio_target_fabric_configfs->tf_ops, - conn->sess->se_sess, data_length, data_direction, - sam_task_attr, &cmd->sense_buffer[0]); - return cmd; -} - -struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr( - struct iscsi_conn *conn, - u8 function) -{ - struct iscsi_cmd *cmd; - struct se_cmd *se_cmd; - u8 tcm_function; - - cmd = iscsit_allocate_cmd(conn, GFP_KERNEL); - if (!cmd) - return NULL; - - cmd->data_direction = DMA_NONE; - - cmd->tmr_req = kzalloc(sizeof(struct iscsi_tmr_req), GFP_KERNEL); - if (!cmd->tmr_req) { - pr_err("Unable to allocate memory for" - " Task Management command!\n"); - return NULL; - } - /* - * TASK_REASSIGN for ERL=2 / connection stays inside of - * LIO-Target $FABRIC_MOD - */ - if (function == ISCSI_TM_FUNC_TASK_REASSIGN) - return cmd; - - se_cmd = &cmd->se_cmd; - /* - * Initialize struct se_cmd descriptor from target_core_mod infrastructure - */ - transport_init_se_cmd(se_cmd, &lio_target_fabric_configfs->tf_ops, - conn->sess->se_sess, 0, DMA_NONE, - MSG_SIMPLE_TAG, &cmd->sense_buffer[0]); - - switch (function) { - case ISCSI_TM_FUNC_ABORT_TASK: - tcm_function = TMR_ABORT_TASK; - break; - case ISCSI_TM_FUNC_ABORT_TASK_SET: - tcm_function = TMR_ABORT_TASK_SET; - break; - case ISCSI_TM_FUNC_CLEAR_ACA: - tcm_function = TMR_CLEAR_ACA; - break; - case ISCSI_TM_FUNC_CLEAR_TASK_SET: - tcm_function = TMR_CLEAR_TASK_SET; - break; - case ISCSI_TM_FUNC_LOGICAL_UNIT_RESET: - tcm_function = TMR_LUN_RESET; - break; - case ISCSI_TM_FUNC_TARGET_WARM_RESET: - tcm_function = TMR_TARGET_WARM_RESET; - break; - case ISCSI_TM_FUNC_TARGET_COLD_RESET: - tcm_function = TMR_TARGET_COLD_RESET; - break; - default: - pr_err("Unknown iSCSI TMR Function:" - " 0x%02x\n", function); - goto out; - } - - se_cmd->se_tmr_req = core_tmr_alloc_req(se_cmd, - (void *)cmd->tmr_req, tcm_function); - if (!se_cmd->se_tmr_req) - goto out; - - cmd->tmr_req->se_tmr_req = se_cmd->se_tmr_req; - - return cmd; -out: - iscsit_release_cmd(cmd); - if (se_cmd) - transport_free_se_cmd(se_cmd); - return NULL; -} - -int iscsit_decide_list_to_build( - struct iscsi_cmd *cmd, - u32 immediate_data_length) -{ - struct iscsi_build_list bl; - struct iscsi_conn *conn = cmd->conn; - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na; - - if (sess->sess_ops->DataSequenceInOrder && - sess->sess_ops->DataPDUInOrder) - return 0; - - if (cmd->data_direction == DMA_NONE) - return 0; - - na = iscsit_tpg_get_node_attrib(sess); - memset(&bl, 0, sizeof(struct iscsi_build_list)); - - if (cmd->data_direction == DMA_FROM_DEVICE) { - bl.data_direction = ISCSI_PDU_READ; - bl.type = PDULIST_NORMAL; - if (na->random_datain_pdu_offsets) - bl.randomize |= RANDOM_DATAIN_PDU_OFFSETS; - if (na->random_datain_seq_offsets) - bl.randomize |= RANDOM_DATAIN_SEQ_OFFSETS; - } else { - bl.data_direction = ISCSI_PDU_WRITE; - bl.immediate_data_length = immediate_data_length; - if (na->random_r2t_offsets) - bl.randomize |= RANDOM_R2T_OFFSETS; - - if (!cmd->immediate_data && !cmd->unsolicited_data) - bl.type = PDULIST_NORMAL; - else if (cmd->immediate_data && !cmd->unsolicited_data) - bl.type = PDULIST_IMMEDIATE; - else if (!cmd->immediate_data && cmd->unsolicited_data) - bl.type = PDULIST_UNSOLICITED; - else if (cmd->immediate_data && cmd->unsolicited_data) - bl.type = PDULIST_IMMEDIATE_AND_UNSOLICITED; - } - - return iscsit_do_build_list(cmd, &bl); -} - -struct iscsi_seq *iscsit_get_seq_holder_for_datain( - struct iscsi_cmd *cmd, - u32 seq_send_order) -{ - u32 i; - - for (i = 0; i < cmd->seq_count; i++) - if (cmd->seq_list[i].seq_send_order == seq_send_order) - return &cmd->seq_list[i]; - - return NULL; -} - -struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *cmd) -{ - u32 i; - - if (!cmd->seq_list) { - pr_err("struct iscsi_cmd->seq_list is NULL!\n"); - return NULL; - } - - for (i = 0; i < cmd->seq_count; i++) { - if (cmd->seq_list[i].type != SEQTYPE_NORMAL) - continue; - if (cmd->seq_list[i].seq_send_order == cmd->seq_send_order) { - cmd->seq_send_order++; - return &cmd->seq_list[i]; - } - } - - return NULL; -} - -struct iscsi_r2t *iscsit_get_holder_for_r2tsn( - struct iscsi_cmd *cmd, - u32 r2t_sn) -{ - struct iscsi_r2t *r2t; - - spin_lock_bh(&cmd->r2t_lock); - list_for_each_entry(r2t, &cmd->cmd_r2t_list, r2t_list) { - if (r2t->r2t_sn == r2t_sn) { - spin_unlock_bh(&cmd->r2t_lock); - return r2t; - } - } - spin_unlock_bh(&cmd->r2t_lock); - - return NULL; -} - -static inline int iscsit_check_received_cmdsn(struct iscsi_session *sess, u32 cmdsn) -{ - int ret; - - /* - * This is the proper method of checking received CmdSN against - * ExpCmdSN and MaxCmdSN values, as well as accounting for out - * or order CmdSNs due to multiple connection sessions and/or - * CRC failures. - */ - if (iscsi_sna_gt(cmdsn, sess->max_cmd_sn)) { - pr_err("Received CmdSN: 0x%08x is greater than" - " MaxCmdSN: 0x%08x, protocol error.\n", cmdsn, - sess->max_cmd_sn); - ret = CMDSN_ERROR_CANNOT_RECOVER; - - } else if (cmdsn == sess->exp_cmd_sn) { - sess->exp_cmd_sn++; - pr_debug("Received CmdSN matches ExpCmdSN," - " incremented ExpCmdSN to: 0x%08x\n", - sess->exp_cmd_sn); - ret = CMDSN_NORMAL_OPERATION; - - } else if (iscsi_sna_gt(cmdsn, sess->exp_cmd_sn)) { - pr_debug("Received CmdSN: 0x%08x is greater" - " than ExpCmdSN: 0x%08x, not acknowledging.\n", - cmdsn, sess->exp_cmd_sn); - ret = CMDSN_HIGHER_THAN_EXP; - - } else { - pr_err("Received CmdSN: 0x%08x is less than" - " ExpCmdSN: 0x%08x, ignoring.\n", cmdsn, - sess->exp_cmd_sn); - ret = CMDSN_LOWER_THAN_EXP; - } - - return ret; -} - -/* - * Commands may be received out of order if MC/S is in use. - * Ensure they are executed in CmdSN order. - */ -int iscsit_sequence_cmd( - struct iscsi_conn *conn, - struct iscsi_cmd *cmd, - u32 cmdsn) -{ - int ret; - int cmdsn_ret; - - mutex_lock(&conn->sess->cmdsn_mutex); - - cmdsn_ret = iscsit_check_received_cmdsn(conn->sess, cmdsn); - switch (cmdsn_ret) { - case CMDSN_NORMAL_OPERATION: - ret = iscsit_execute_cmd(cmd, 0); - if ((ret >= 0) && !list_empty(&conn->sess->sess_ooo_cmdsn_list)) - iscsit_execute_ooo_cmdsns(conn->sess); - break; - case CMDSN_HIGHER_THAN_EXP: - ret = iscsit_handle_ooo_cmdsn(conn->sess, cmd, cmdsn); - break; - case CMDSN_LOWER_THAN_EXP: - cmd->i_state = ISTATE_REMOVE; - iscsit_add_cmd_to_immediate_queue(cmd, conn, cmd->i_state); - ret = cmdsn_ret; - break; - default: - ret = cmdsn_ret; - break; - } - mutex_unlock(&conn->sess->cmdsn_mutex); - - return ret; -} - -int iscsit_check_unsolicited_dataout(struct iscsi_cmd *cmd, unsigned char *buf) -{ - struct iscsi_conn *conn = cmd->conn; - struct se_cmd *se_cmd = &cmd->se_cmd; - struct iscsi_data *hdr = (struct iscsi_data *) buf; - u32 payload_length = ntoh24(hdr->dlength); - - if (conn->sess->sess_ops->InitialR2T) { - pr_err("Received unexpected unsolicited data" - " while InitialR2T=Yes, protocol error.\n"); - transport_send_check_condition_and_sense(se_cmd, - TCM_UNEXPECTED_UNSOLICITED_DATA, 0); - return -1; - } - - if ((cmd->first_burst_len + payload_length) > - conn->sess->sess_ops->FirstBurstLength) { - pr_err("Total %u bytes exceeds FirstBurstLength: %u" - " for this Unsolicited DataOut Burst.\n", - (cmd->first_burst_len + payload_length), - conn->sess->sess_ops->FirstBurstLength); - transport_send_check_condition_and_sense(se_cmd, - TCM_INCORRECT_AMOUNT_OF_DATA, 0); - return -1; - } - - if (!(hdr->flags & ISCSI_FLAG_CMD_FINAL)) - return 0; - - if (((cmd->first_burst_len + payload_length) != cmd->data_length) && - ((cmd->first_burst_len + payload_length) != - conn->sess->sess_ops->FirstBurstLength)) { - pr_err("Unsolicited non-immediate data received %u" - " does not equal FirstBurstLength: %u, and does" - " not equal ExpXferLen %u.\n", - (cmd->first_burst_len + payload_length), - conn->sess->sess_ops->FirstBurstLength, cmd->data_length); - transport_send_check_condition_and_sense(se_cmd, - TCM_INCORRECT_AMOUNT_OF_DATA, 0); - return -1; - } - return 0; -} - -struct iscsi_cmd *iscsit_find_cmd_from_itt( - struct iscsi_conn *conn, - u32 init_task_tag) -{ - struct iscsi_cmd *cmd; - - spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { - if (cmd->init_task_tag == init_task_tag) { - spin_unlock_bh(&conn->cmd_lock); - return cmd; - } - } - spin_unlock_bh(&conn->cmd_lock); - - pr_err("Unable to locate ITT: 0x%08x on CID: %hu", - init_task_tag, conn->cid); - return NULL; -} - -struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump( - struct iscsi_conn *conn, - u32 init_task_tag, - u32 length) -{ - struct iscsi_cmd *cmd; - - spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { - if (cmd->init_task_tag == init_task_tag) { - spin_unlock_bh(&conn->cmd_lock); - return cmd; - } - } - spin_unlock_bh(&conn->cmd_lock); - - pr_err("Unable to locate ITT: 0x%08x on CID: %hu," - " dumping payload\n", init_task_tag, conn->cid); - if (length) - iscsit_dump_data_payload(conn, length, 1); - - return NULL; -} - -struct iscsi_cmd *iscsit_find_cmd_from_ttt( - struct iscsi_conn *conn, - u32 targ_xfer_tag) -{ - struct iscsi_cmd *cmd = NULL; - - spin_lock_bh(&conn->cmd_lock); - list_for_each_entry(cmd, &conn->conn_cmd_list, i_list) { - if (cmd->targ_xfer_tag == targ_xfer_tag) { - spin_unlock_bh(&conn->cmd_lock); - return cmd; - } - } - spin_unlock_bh(&conn->cmd_lock); - - pr_err("Unable to locate TTT: 0x%08x on CID: %hu\n", - targ_xfer_tag, conn->cid); - return NULL; -} - -int iscsit_find_cmd_for_recovery( - struct iscsi_session *sess, - struct iscsi_cmd **cmd_ptr, - struct iscsi_conn_recovery **cr_ptr, - u32 init_task_tag) -{ - struct iscsi_cmd *cmd = NULL; - struct iscsi_conn_recovery *cr; - /* - * Scan through the inactive connection recovery list's command list. - * If init_task_tag matches the command is still alligent. - */ - spin_lock(&sess->cr_i_lock); - list_for_each_entry(cr, &sess->cr_inactive_list, cr_list) { - spin_lock(&cr->conn_recovery_cmd_lock); - list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_list) { - if (cmd->init_task_tag == init_task_tag) { - spin_unlock(&cr->conn_recovery_cmd_lock); - spin_unlock(&sess->cr_i_lock); - - *cr_ptr = cr; - *cmd_ptr = cmd; - return -2; - } - } - spin_unlock(&cr->conn_recovery_cmd_lock); - } - spin_unlock(&sess->cr_i_lock); - /* - * Scan through the active connection recovery list's command list. - * If init_task_tag matches the command is ready to be reassigned. - */ - spin_lock(&sess->cr_a_lock); - list_for_each_entry(cr, &sess->cr_active_list, cr_list) { - spin_lock(&cr->conn_recovery_cmd_lock); - list_for_each_entry(cmd, &cr->conn_recovery_cmd_list, i_list) { - if (cmd->init_task_tag == init_task_tag) { - spin_unlock(&cr->conn_recovery_cmd_lock); - spin_unlock(&sess->cr_a_lock); - - *cr_ptr = cr; - *cmd_ptr = cmd; - return 0; - } - } - spin_unlock(&cr->conn_recovery_cmd_lock); - } - spin_unlock(&sess->cr_a_lock); - - return -1; -} - -void iscsit_add_cmd_to_immediate_queue( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn, - u8 state) -{ - struct iscsi_queue_req *qr; - - qr = kmem_cache_zalloc(lio_qr_cache, GFP_ATOMIC); - if (!qr) { - pr_err("Unable to allocate memory for" - " struct iscsi_queue_req\n"); - return; - } - INIT_LIST_HEAD(&qr->qr_list); - qr->cmd = cmd; - qr->state = state; - - spin_lock_bh(&conn->immed_queue_lock); - list_add_tail(&qr->qr_list, &conn->immed_queue_list); - atomic_inc(&cmd->immed_queue_count); - atomic_set(&conn->check_immediate_queue, 1); - spin_unlock_bh(&conn->immed_queue_lock); - - wake_up_process(conn->thread_set->tx_thread); -} - -struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *conn) -{ - struct iscsi_queue_req *qr; - - spin_lock_bh(&conn->immed_queue_lock); - if (list_empty(&conn->immed_queue_list)) { - spin_unlock_bh(&conn->immed_queue_lock); - return NULL; - } - list_for_each_entry(qr, &conn->immed_queue_list, qr_list) - break; - - list_del(&qr->qr_list); - if (qr->cmd) - atomic_dec(&qr->cmd->immed_queue_count); - spin_unlock_bh(&conn->immed_queue_lock); - - return qr; -} - -static void iscsit_remove_cmd_from_immediate_queue( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - struct iscsi_queue_req *qr, *qr_tmp; - - spin_lock_bh(&conn->immed_queue_lock); - if (!atomic_read(&cmd->immed_queue_count)) { - spin_unlock_bh(&conn->immed_queue_lock); - return; - } - - list_for_each_entry_safe(qr, qr_tmp, &conn->immed_queue_list, qr_list) { - if (qr->cmd != cmd) - continue; - - atomic_dec(&qr->cmd->immed_queue_count); - list_del(&qr->qr_list); - kmem_cache_free(lio_qr_cache, qr); - } - spin_unlock_bh(&conn->immed_queue_lock); - - if (atomic_read(&cmd->immed_queue_count)) { - pr_err("ITT: 0x%08x immed_queue_count: %d\n", - cmd->init_task_tag, - atomic_read(&cmd->immed_queue_count)); - } -} - -void iscsit_add_cmd_to_response_queue( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn, - u8 state) -{ - struct iscsi_queue_req *qr; - - qr = kmem_cache_zalloc(lio_qr_cache, GFP_ATOMIC); - if (!qr) { - pr_err("Unable to allocate memory for" - " struct iscsi_queue_req\n"); - return; - } - INIT_LIST_HEAD(&qr->qr_list); - qr->cmd = cmd; - qr->state = state; - - spin_lock_bh(&conn->response_queue_lock); - list_add_tail(&qr->qr_list, &conn->response_queue_list); - atomic_inc(&cmd->response_queue_count); - spin_unlock_bh(&conn->response_queue_lock); - - wake_up_process(conn->thread_set->tx_thread); -} - -struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *conn) -{ - struct iscsi_queue_req *qr; - - spin_lock_bh(&conn->response_queue_lock); - if (list_empty(&conn->response_queue_list)) { - spin_unlock_bh(&conn->response_queue_lock); - return NULL; - } - - list_for_each_entry(qr, &conn->response_queue_list, qr_list) - break; - - list_del(&qr->qr_list); - if (qr->cmd) - atomic_dec(&qr->cmd->response_queue_count); - spin_unlock_bh(&conn->response_queue_lock); - - return qr; -} - -static void iscsit_remove_cmd_from_response_queue( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - struct iscsi_queue_req *qr, *qr_tmp; - - spin_lock_bh(&conn->response_queue_lock); - if (!atomic_read(&cmd->response_queue_count)) { - spin_unlock_bh(&conn->response_queue_lock); - return; - } - - list_for_each_entry_safe(qr, qr_tmp, &conn->response_queue_list, - qr_list) { - if (qr->cmd != cmd) - continue; - - atomic_dec(&qr->cmd->response_queue_count); - list_del(&qr->qr_list); - kmem_cache_free(lio_qr_cache, qr); - } - spin_unlock_bh(&conn->response_queue_lock); - - if (atomic_read(&cmd->response_queue_count)) { - pr_err("ITT: 0x%08x response_queue_count: %d\n", - cmd->init_task_tag, - atomic_read(&cmd->response_queue_count)); - } -} - -void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *conn) -{ - struct iscsi_queue_req *qr, *qr_tmp; - - spin_lock_bh(&conn->immed_queue_lock); - list_for_each_entry_safe(qr, qr_tmp, &conn->immed_queue_list, qr_list) { - list_del(&qr->qr_list); - if (qr->cmd) - atomic_dec(&qr->cmd->immed_queue_count); - - kmem_cache_free(lio_qr_cache, qr); - } - spin_unlock_bh(&conn->immed_queue_lock); - - spin_lock_bh(&conn->response_queue_lock); - list_for_each_entry_safe(qr, qr_tmp, &conn->response_queue_list, - qr_list) { - list_del(&qr->qr_list); - if (qr->cmd) - atomic_dec(&qr->cmd->response_queue_count); - - kmem_cache_free(lio_qr_cache, qr); - } - spin_unlock_bh(&conn->response_queue_lock); -} - -void iscsit_release_cmd(struct iscsi_cmd *cmd) -{ - struct iscsi_conn *conn = cmd->conn; - int i; - - iscsit_free_r2ts_from_list(cmd); - iscsit_free_all_datain_reqs(cmd); - - kfree(cmd->buf_ptr); - kfree(cmd->pdu_list); - kfree(cmd->seq_list); - kfree(cmd->tmr_req); - kfree(cmd->iov_data); - - for (i = 0; i < cmd->t_mem_sg_nents; i++) - __free_page(sg_page(&cmd->t_mem_sg[i])); - - kfree(cmd->t_mem_sg); - - if (conn) { - iscsit_remove_cmd_from_immediate_queue(cmd, conn); - iscsit_remove_cmd_from_response_queue(cmd, conn); - } - - kmem_cache_free(lio_cmd_cache, cmd); -} - -int iscsit_check_session_usage_count(struct iscsi_session *sess) -{ - spin_lock_bh(&sess->session_usage_lock); - if (sess->session_usage_count != 0) { - sess->session_waiting_on_uc = 1; - spin_unlock_bh(&sess->session_usage_lock); - if (in_interrupt()) - return 2; - - wait_for_completion(&sess->session_waiting_on_uc_comp); - return 1; - } - spin_unlock_bh(&sess->session_usage_lock); - - return 0; -} - -void iscsit_dec_session_usage_count(struct iscsi_session *sess) -{ - spin_lock_bh(&sess->session_usage_lock); - sess->session_usage_count--; - - if (!sess->session_usage_count && sess->session_waiting_on_uc) - complete(&sess->session_waiting_on_uc_comp); - - spin_unlock_bh(&sess->session_usage_lock); -} - -void iscsit_inc_session_usage_count(struct iscsi_session *sess) -{ - spin_lock_bh(&sess->session_usage_lock); - sess->session_usage_count++; - spin_unlock_bh(&sess->session_usage_lock); -} - -/* - * Used before iscsi_do[rx,tx]_data() to determine iov and [rx,tx]_marker - * array counts needed for sync and steering. - */ -static int iscsit_determine_sync_and_steering_counts( - struct iscsi_conn *conn, - struct iscsi_data_count *count) -{ - u32 length = count->data_length; - u32 marker, markint; - - count->sync_and_steering = 1; - - marker = (count->type == ISCSI_RX_DATA) ? - conn->of_marker : conn->if_marker; - markint = (count->type == ISCSI_RX_DATA) ? - (conn->conn_ops->OFMarkInt * 4) : - (conn->conn_ops->IFMarkInt * 4); - count->ss_iov_count = count->iov_count; - - while (length > 0) { - if (length >= marker) { - count->ss_iov_count += 3; - count->ss_marker_count += 2; - - length -= marker; - marker = markint; - } else - length = 0; - } - - return 0; -} - -/* - * Setup conn->if_marker and conn->of_marker values based upon - * the initial marker-less interval. (see iSCSI v19 A.2) - */ -int iscsit_set_sync_and_steering_values(struct iscsi_conn *conn) -{ - int login_ifmarker_count = 0, login_ofmarker_count = 0, next_marker = 0; - /* - * IFMarkInt and OFMarkInt are negotiated as 32-bit words. - */ - u32 IFMarkInt = (conn->conn_ops->IFMarkInt * 4); - u32 OFMarkInt = (conn->conn_ops->OFMarkInt * 4); - - if (conn->conn_ops->OFMarker) { - /* - * Account for the first Login Command received not - * via iscsi_recv_msg(). - */ - conn->of_marker += ISCSI_HDR_LEN; - if (conn->of_marker <= OFMarkInt) { - conn->of_marker = (OFMarkInt - conn->of_marker); - } else { - login_ofmarker_count = (conn->of_marker / OFMarkInt); - next_marker = (OFMarkInt * (login_ofmarker_count + 1)) + - (login_ofmarker_count * MARKER_SIZE); - conn->of_marker = (next_marker - conn->of_marker); - } - conn->of_marker_offset = 0; - pr_debug("Setting OFMarker value to %u based on Initial" - " Markerless Interval.\n", conn->of_marker); - } - - if (conn->conn_ops->IFMarker) { - if (conn->if_marker <= IFMarkInt) { - conn->if_marker = (IFMarkInt - conn->if_marker); - } else { - login_ifmarker_count = (conn->if_marker / IFMarkInt); - next_marker = (IFMarkInt * (login_ifmarker_count + 1)) + - (login_ifmarker_count * MARKER_SIZE); - conn->if_marker = (next_marker - conn->if_marker); - } - pr_debug("Setting IFMarker value to %u based on Initial" - " Markerless Interval.\n", conn->if_marker); - } - - return 0; -} - -struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *sess, u16 cid) -{ - struct iscsi_conn *conn; - - spin_lock_bh(&sess->conn_lock); - list_for_each_entry(conn, &sess->sess_conn_list, conn_list) { - if ((conn->cid == cid) && - (conn->conn_state == TARG_CONN_STATE_LOGGED_IN)) { - iscsit_inc_conn_usage_count(conn); - spin_unlock_bh(&sess->conn_lock); - return conn; - } - } - spin_unlock_bh(&sess->conn_lock); - - return NULL; -} - -struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *sess, u16 cid) -{ - struct iscsi_conn *conn; - - spin_lock_bh(&sess->conn_lock); - list_for_each_entry(conn, &sess->sess_conn_list, conn_list) { - if (conn->cid == cid) { - iscsit_inc_conn_usage_count(conn); - spin_lock(&conn->state_lock); - atomic_set(&conn->connection_wait_rcfr, 1); - spin_unlock(&conn->state_lock); - spin_unlock_bh(&sess->conn_lock); - return conn; - } - } - spin_unlock_bh(&sess->conn_lock); - - return NULL; -} - -void iscsit_check_conn_usage_count(struct iscsi_conn *conn) -{ - spin_lock_bh(&conn->conn_usage_lock); - if (conn->conn_usage_count != 0) { - conn->conn_waiting_on_uc = 1; - spin_unlock_bh(&conn->conn_usage_lock); - - wait_for_completion(&conn->conn_waiting_on_uc_comp); - return; - } - spin_unlock_bh(&conn->conn_usage_lock); -} - -void iscsit_dec_conn_usage_count(struct iscsi_conn *conn) -{ - spin_lock_bh(&conn->conn_usage_lock); - conn->conn_usage_count--; - - if (!conn->conn_usage_count && conn->conn_waiting_on_uc) - complete(&conn->conn_waiting_on_uc_comp); - - spin_unlock_bh(&conn->conn_usage_lock); -} - -void iscsit_inc_conn_usage_count(struct iscsi_conn *conn) -{ - spin_lock_bh(&conn->conn_usage_lock); - conn->conn_usage_count++; - spin_unlock_bh(&conn->conn_usage_lock); -} - -static int iscsit_add_nopin(struct iscsi_conn *conn, int want_response) -{ - u8 state; - struct iscsi_cmd *cmd; - - cmd = iscsit_allocate_cmd(conn, GFP_ATOMIC); - if (!cmd) - return -1; - - cmd->iscsi_opcode = ISCSI_OP_NOOP_IN; - state = (want_response) ? ISTATE_SEND_NOPIN_WANT_RESPONSE : - ISTATE_SEND_NOPIN_NO_RESPONSE; - cmd->init_task_tag = 0xFFFFFFFF; - spin_lock_bh(&conn->sess->ttt_lock); - cmd->targ_xfer_tag = (want_response) ? conn->sess->targ_xfer_tag++ : - 0xFFFFFFFF; - if (want_response && (cmd->targ_xfer_tag == 0xFFFFFFFF)) - cmd->targ_xfer_tag = conn->sess->targ_xfer_tag++; - spin_unlock_bh(&conn->sess->ttt_lock); - - spin_lock_bh(&conn->cmd_lock); - list_add_tail(&cmd->i_list, &conn->conn_cmd_list); - spin_unlock_bh(&conn->cmd_lock); - - if (want_response) - iscsit_start_nopin_response_timer(conn); - iscsit_add_cmd_to_immediate_queue(cmd, conn, state); - - return 0; -} - -static void iscsit_handle_nopin_response_timeout(unsigned long data) -{ - struct iscsi_conn *conn = (struct iscsi_conn *) data; - - iscsit_inc_conn_usage_count(conn); - - spin_lock_bh(&conn->nopin_timer_lock); - if (conn->nopin_response_timer_flags & ISCSI_TF_STOP) { - spin_unlock_bh(&conn->nopin_timer_lock); - iscsit_dec_conn_usage_count(conn); - return; - } - - pr_debug("Did not receive response to NOPIN on CID: %hu on" - " SID: %u, failing connection.\n", conn->cid, - conn->sess->sid); - conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING; - spin_unlock_bh(&conn->nopin_timer_lock); - - { - struct iscsi_portal_group *tpg = conn->sess->tpg; - struct iscsi_tiqn *tiqn = tpg->tpg_tiqn; - - if (tiqn) { - spin_lock_bh(&tiqn->sess_err_stats.lock); - strcpy(tiqn->sess_err_stats.last_sess_fail_rem_name, - (void *)conn->sess->sess_ops->InitiatorName); - tiqn->sess_err_stats.last_sess_failure_type = - ISCSI_SESS_ERR_CXN_TIMEOUT; - tiqn->sess_err_stats.cxn_timeout_errors++; - conn->sess->conn_timeout_errors++; - spin_unlock_bh(&tiqn->sess_err_stats.lock); - } - } - - iscsit_cause_connection_reinstatement(conn, 0); - iscsit_dec_conn_usage_count(conn); -} - -void iscsit_mod_nopin_response_timer(struct iscsi_conn *conn) -{ - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); - - spin_lock_bh(&conn->nopin_timer_lock); - if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) { - spin_unlock_bh(&conn->nopin_timer_lock); - return; - } - - mod_timer(&conn->nopin_response_timer, - (get_jiffies_64() + na->nopin_response_timeout * HZ)); - spin_unlock_bh(&conn->nopin_timer_lock); -} - -/* - * Called with conn->nopin_timer_lock held. - */ -void iscsit_start_nopin_response_timer(struct iscsi_conn *conn) -{ - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); - - spin_lock_bh(&conn->nopin_timer_lock); - if (conn->nopin_response_timer_flags & ISCSI_TF_RUNNING) { - spin_unlock_bh(&conn->nopin_timer_lock); - return; - } - - init_timer(&conn->nopin_response_timer); - conn->nopin_response_timer.expires = - (get_jiffies_64() + na->nopin_response_timeout * HZ); - conn->nopin_response_timer.data = (unsigned long)conn; - conn->nopin_response_timer.function = iscsit_handle_nopin_response_timeout; - conn->nopin_response_timer_flags &= ~ISCSI_TF_STOP; - conn->nopin_response_timer_flags |= ISCSI_TF_RUNNING; - add_timer(&conn->nopin_response_timer); - - pr_debug("Started NOPIN Response Timer on CID: %d to %u" - " seconds\n", conn->cid, na->nopin_response_timeout); - spin_unlock_bh(&conn->nopin_timer_lock); -} - -void iscsit_stop_nopin_response_timer(struct iscsi_conn *conn) -{ - spin_lock_bh(&conn->nopin_timer_lock); - if (!(conn->nopin_response_timer_flags & ISCSI_TF_RUNNING)) { - spin_unlock_bh(&conn->nopin_timer_lock); - return; - } - conn->nopin_response_timer_flags |= ISCSI_TF_STOP; - spin_unlock_bh(&conn->nopin_timer_lock); - - del_timer_sync(&conn->nopin_response_timer); - - spin_lock_bh(&conn->nopin_timer_lock); - conn->nopin_response_timer_flags &= ~ISCSI_TF_RUNNING; - spin_unlock_bh(&conn->nopin_timer_lock); -} - -static void iscsit_handle_nopin_timeout(unsigned long data) -{ - struct iscsi_conn *conn = (struct iscsi_conn *) data; - - iscsit_inc_conn_usage_count(conn); - - spin_lock_bh(&conn->nopin_timer_lock); - if (conn->nopin_timer_flags & ISCSI_TF_STOP) { - spin_unlock_bh(&conn->nopin_timer_lock); - iscsit_dec_conn_usage_count(conn); - return; - } - conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING; - spin_unlock_bh(&conn->nopin_timer_lock); - - iscsit_add_nopin(conn, 1); - iscsit_dec_conn_usage_count(conn); -} - -/* - * Called with conn->nopin_timer_lock held. - */ -void __iscsit_start_nopin_timer(struct iscsi_conn *conn) -{ - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); - /* - * NOPIN timeout is disabled. - */ - if (!na->nopin_timeout) - return; - - if (conn->nopin_timer_flags & ISCSI_TF_RUNNING) - return; - - init_timer(&conn->nopin_timer); - conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ); - conn->nopin_timer.data = (unsigned long)conn; - conn->nopin_timer.function = iscsit_handle_nopin_timeout; - conn->nopin_timer_flags &= ~ISCSI_TF_STOP; - conn->nopin_timer_flags |= ISCSI_TF_RUNNING; - add_timer(&conn->nopin_timer); - - pr_debug("Started NOPIN Timer on CID: %d at %u second" - " interval\n", conn->cid, na->nopin_timeout); -} - -void iscsit_start_nopin_timer(struct iscsi_conn *conn) -{ - struct iscsi_session *sess = conn->sess; - struct iscsi_node_attrib *na = iscsit_tpg_get_node_attrib(sess); - /* - * NOPIN timeout is disabled.. - */ - if (!na->nopin_timeout) - return; - - spin_lock_bh(&conn->nopin_timer_lock); - if (conn->nopin_timer_flags & ISCSI_TF_RUNNING) { - spin_unlock_bh(&conn->nopin_timer_lock); - return; - } - - init_timer(&conn->nopin_timer); - conn->nopin_timer.expires = (get_jiffies_64() + na->nopin_timeout * HZ); - conn->nopin_timer.data = (unsigned long)conn; - conn->nopin_timer.function = iscsit_handle_nopin_timeout; - conn->nopin_timer_flags &= ~ISCSI_TF_STOP; - conn->nopin_timer_flags |= ISCSI_TF_RUNNING; - add_timer(&conn->nopin_timer); - - pr_debug("Started NOPIN Timer on CID: %d at %u second" - " interval\n", conn->cid, na->nopin_timeout); - spin_unlock_bh(&conn->nopin_timer_lock); -} - -void iscsit_stop_nopin_timer(struct iscsi_conn *conn) -{ - spin_lock_bh(&conn->nopin_timer_lock); - if (!(conn->nopin_timer_flags & ISCSI_TF_RUNNING)) { - spin_unlock_bh(&conn->nopin_timer_lock); - return; - } - conn->nopin_timer_flags |= ISCSI_TF_STOP; - spin_unlock_bh(&conn->nopin_timer_lock); - - del_timer_sync(&conn->nopin_timer); - - spin_lock_bh(&conn->nopin_timer_lock); - conn->nopin_timer_flags &= ~ISCSI_TF_RUNNING; - spin_unlock_bh(&conn->nopin_timer_lock); -} - -int iscsit_send_tx_data( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn, - int use_misc) -{ - int tx_sent, tx_size; - u32 iov_count; - struct kvec *iov; - -send_data: - tx_size = cmd->tx_size; - - if (!use_misc) { - iov = &cmd->iov_data[0]; - iov_count = cmd->iov_data_count; - } else { - iov = &cmd->iov_misc[0]; - iov_count = cmd->iov_misc_count; - } - - tx_sent = tx_data(conn, &iov[0], iov_count, tx_size); - if (tx_size != tx_sent) { - if (tx_sent == -EAGAIN) { - pr_err("tx_data() returned -EAGAIN\n"); - goto send_data; - } else - return -1; - } - cmd->tx_size = 0; - - return 0; -} - -int iscsit_fe_sendpage_sg( - struct iscsi_cmd *cmd, - struct iscsi_conn *conn) -{ - struct scatterlist *sg = cmd->first_data_sg; - struct kvec iov; - u32 tx_hdr_size, data_len; - u32 offset = cmd->first_data_sg_off; - int tx_sent; - -send_hdr: - tx_hdr_size = ISCSI_HDR_LEN; - if (conn->conn_ops->HeaderDigest) - tx_hdr_size += ISCSI_CRC_LEN; - - iov.iov_base = cmd->pdu; - iov.iov_len = tx_hdr_size; - - tx_sent = tx_data(conn, &iov, 1, tx_hdr_size); - if (tx_hdr_size != tx_sent) { - if (tx_sent == -EAGAIN) { - pr_err("tx_data() returned -EAGAIN\n"); - goto send_hdr; - } - return -1; - } - - data_len = cmd->tx_size - tx_hdr_size - cmd->padding; - if (conn->conn_ops->DataDigest) - data_len -= ISCSI_CRC_LEN; - - /* - * Perform sendpage() for each page in the scatterlist - */ - while (data_len) { - u32 space = (sg->length - offset); - u32 sub_len = min_t(u32, data_len, space); -send_pg: - tx_sent = conn->sock->ops->sendpage(conn->sock, - sg_page(sg), sg->offset + offset, sub_len, 0); - if (tx_sent != sub_len) { - if (tx_sent == -EAGAIN) { - pr_err("tcp_sendpage() returned" - " -EAGAIN\n"); - goto send_pg; - } - - pr_err("tcp_sendpage() failure: %d\n", - tx_sent); - return -1; - } - - data_len -= sub_len; - offset = 0; - sg = sg_next(sg); - } - -send_padding: - if (cmd->padding) { - struct kvec *iov_p = - &cmd->iov_data[cmd->iov_data_count-1]; - - tx_sent = tx_data(conn, iov_p, 1, cmd->padding); - if (cmd->padding != tx_sent) { - if (tx_sent == -EAGAIN) { - pr_err("tx_data() returned -EAGAIN\n"); - goto send_padding; - } - return -1; - } - } - -send_datacrc: - if (conn->conn_ops->DataDigest) { - struct kvec *iov_d = - &cmd->iov_data[cmd->iov_data_count]; - - tx_sent = tx_data(conn, iov_d, 1, ISCSI_CRC_LEN); - if (ISCSI_CRC_LEN != tx_sent) { - if (tx_sent == -EAGAIN) { - pr_err("tx_data() returned -EAGAIN\n"); - goto send_datacrc; - } - return -1; - } - } - - return 0; -} - -/* - * This function is used for mainly sending a ISCSI_TARG_LOGIN_RSP PDU - * back to the Initiator when an expection condition occurs with the - * errors set in status_class and status_detail. - * - * Parameters: iSCSI Connection, Status Class, Status Detail. - * Returns: 0 on success, -1 on error. - */ -int iscsit_tx_login_rsp(struct iscsi_conn *conn, u8 status_class, u8 status_detail) -{ - u8 iscsi_hdr[ISCSI_HDR_LEN]; - int err; - struct kvec iov; - struct iscsi_login_rsp *hdr; - - iscsit_collect_login_stats(conn, status_class, status_detail); - - memset(&iov, 0, sizeof(struct kvec)); - memset(&iscsi_hdr, 0x0, ISCSI_HDR_LEN); - - hdr = (struct iscsi_login_rsp *)&iscsi_hdr; - hdr->opcode = ISCSI_OP_LOGIN_RSP; - hdr->status_class = status_class; - hdr->status_detail = status_detail; - hdr->itt = cpu_to_be32(conn->login_itt); - - iov.iov_base = &iscsi_hdr; - iov.iov_len = ISCSI_HDR_LEN; - - PRINT_BUFF(iscsi_hdr, ISCSI_HDR_LEN); - - err = tx_data(conn, &iov, 1, ISCSI_HDR_LEN); - if (err != ISCSI_HDR_LEN) { - pr_err("tx_data returned less than expected\n"); - return -1; - } - - return 0; -} - -void iscsit_print_session_params(struct iscsi_session *sess) -{ - struct iscsi_conn *conn; - - pr_debug("-----------------------------[Session Params for" - " SID: %u]-----------------------------\n", sess->sid); - spin_lock_bh(&sess->conn_lock); - list_for_each_entry(conn, &sess->sess_conn_list, conn_list) - iscsi_dump_conn_ops(conn->conn_ops); - spin_unlock_bh(&sess->conn_lock); - - iscsi_dump_sess_ops(sess->sess_ops); -} - -static int iscsit_do_rx_data( - struct iscsi_conn *conn, - struct iscsi_data_count *count) -{ - int data = count->data_length, rx_loop = 0, total_rx = 0, iov_len; - u32 rx_marker_val[count->ss_marker_count], rx_marker_iov = 0; - struct kvec iov[count->ss_iov_count], *iov_p; - struct msghdr msg; - - if (!conn || !conn->sock || !conn->conn_ops) - return -1; - - memset(&msg, 0, sizeof(struct msghdr)); - - if (count->sync_and_steering) { - int size = 0; - u32 i, orig_iov_count = 0; - u32 orig_iov_len = 0, orig_iov_loc = 0; - u32 iov_count = 0, per_iov_bytes = 0; - u32 *rx_marker, old_rx_marker = 0; - struct kvec *iov_record; - - memset(&rx_marker_val, 0, - count->ss_marker_count * sizeof(u32)); - memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec)); - - iov_record = count->iov; - orig_iov_count = count->iov_count; - rx_marker = &conn->of_marker; - - i = 0; - size = data; - orig_iov_len = iov_record[orig_iov_loc].iov_len; - while (size > 0) { - pr_debug("rx_data: #1 orig_iov_len %u," - " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc); - pr_debug("rx_data: #2 rx_marker %u, size" - " %u\n", *rx_marker, size); - - if (orig_iov_len >= *rx_marker) { - iov[iov_count].iov_len = *rx_marker; - iov[iov_count++].iov_base = - (iov_record[orig_iov_loc].iov_base + - per_iov_bytes); - - iov[iov_count].iov_len = (MARKER_SIZE / 2); - iov[iov_count++].iov_base = - &rx_marker_val[rx_marker_iov++]; - iov[iov_count].iov_len = (MARKER_SIZE / 2); - iov[iov_count++].iov_base = - &rx_marker_val[rx_marker_iov++]; - old_rx_marker = *rx_marker; - - /* - * OFMarkInt is in 32-bit words. - */ - *rx_marker = (conn->conn_ops->OFMarkInt * 4); - size -= old_rx_marker; - orig_iov_len -= old_rx_marker; - per_iov_bytes += old_rx_marker; - - pr_debug("rx_data: #3 new_rx_marker" - " %u, size %u\n", *rx_marker, size); - } else { - iov[iov_count].iov_len = orig_iov_len; - iov[iov_count++].iov_base = - (iov_record[orig_iov_loc].iov_base + - per_iov_bytes); - - per_iov_bytes = 0; - *rx_marker -= orig_iov_len; - size -= orig_iov_len; - - if (size) - orig_iov_len = - iov_record[++orig_iov_loc].iov_len; - - pr_debug("rx_data: #4 new_rx_marker" - " %u, size %u\n", *rx_marker, size); - } - } - data += (rx_marker_iov * (MARKER_SIZE / 2)); - - iov_p = &iov[0]; - iov_len = iov_count; - - if (iov_count > count->ss_iov_count) { - pr_err("iov_count: %d, count->ss_iov_count:" - " %d\n", iov_count, count->ss_iov_count); - return -1; - } - if (rx_marker_iov > count->ss_marker_count) { - pr_err("rx_marker_iov: %d, count->ss_marker" - "_count: %d\n", rx_marker_iov, - count->ss_marker_count); - return -1; - } - } else { - iov_p = count->iov; - iov_len = count->iov_count; - } - - while (total_rx < data) { - rx_loop = kernel_recvmsg(conn->sock, &msg, iov_p, iov_len, - (data - total_rx), MSG_WAITALL); - if (rx_loop <= 0) { - pr_debug("rx_loop: %d total_rx: %d\n", - rx_loop, total_rx); - return rx_loop; - } - total_rx += rx_loop; - pr_debug("rx_loop: %d, total_rx: %d, data: %d\n", - rx_loop, total_rx, data); - } - - if (count->sync_and_steering) { - int j; - for (j = 0; j < rx_marker_iov; j++) { - pr_debug("rx_data: #5 j: %d, offset: %d\n", - j, rx_marker_val[j]); - conn->of_marker_offset = rx_marker_val[j]; - } - total_rx -= (rx_marker_iov * (MARKER_SIZE / 2)); - } - - return total_rx; -} - -static int iscsit_do_tx_data( - struct iscsi_conn *conn, - struct iscsi_data_count *count) -{ - int data = count->data_length, total_tx = 0, tx_loop = 0, iov_len; - u32 tx_marker_val[count->ss_marker_count], tx_marker_iov = 0; - struct kvec iov[count->ss_iov_count], *iov_p; - struct msghdr msg; - - if (!conn || !conn->sock || !conn->conn_ops) - return -1; - - if (data <= 0) { - pr_err("Data length is: %d\n", data); - return -1; - } - - memset(&msg, 0, sizeof(struct msghdr)); - - if (count->sync_and_steering) { - int size = 0; - u32 i, orig_iov_count = 0; - u32 orig_iov_len = 0, orig_iov_loc = 0; - u32 iov_count = 0, per_iov_bytes = 0; - u32 *tx_marker, old_tx_marker = 0; - struct kvec *iov_record; - - memset(&tx_marker_val, 0, - count->ss_marker_count * sizeof(u32)); - memset(&iov, 0, count->ss_iov_count * sizeof(struct kvec)); - - iov_record = count->iov; - orig_iov_count = count->iov_count; - tx_marker = &conn->if_marker; - - i = 0; - size = data; - orig_iov_len = iov_record[orig_iov_loc].iov_len; - while (size > 0) { - pr_debug("tx_data: #1 orig_iov_len %u," - " orig_iov_loc %u\n", orig_iov_len, orig_iov_loc); - pr_debug("tx_data: #2 tx_marker %u, size" - " %u\n", *tx_marker, size); - - if (orig_iov_len >= *tx_marker) { - iov[iov_count].iov_len = *tx_marker; - iov[iov_count++].iov_base = - (iov_record[orig_iov_loc].iov_base + - per_iov_bytes); - - tx_marker_val[tx_marker_iov] = - (size - *tx_marker); - iov[iov_count].iov_len = (MARKER_SIZE / 2); - iov[iov_count++].iov_base = - &tx_marker_val[tx_marker_iov++]; - iov[iov_count].iov_len = (MARKER_SIZE / 2); - iov[iov_count++].iov_base = - &tx_marker_val[tx_marker_iov++]; - old_tx_marker = *tx_marker; - - /* - * IFMarkInt is in 32-bit words. - */ - *tx_marker = (conn->conn_ops->IFMarkInt * 4); - size -= old_tx_marker; - orig_iov_len -= old_tx_marker; - per_iov_bytes += old_tx_marker; - - pr_debug("tx_data: #3 new_tx_marker" - " %u, size %u\n", *tx_marker, size); - pr_debug("tx_data: #4 offset %u\n", - tx_marker_val[tx_marker_iov-1]); - } else { - iov[iov_count].iov_len = orig_iov_len; - iov[iov_count++].iov_base - = (iov_record[orig_iov_loc].iov_base + - per_iov_bytes); - - per_iov_bytes = 0; - *tx_marker -= orig_iov_len; - size -= orig_iov_len; - - if (size) - orig_iov_len = - iov_record[++orig_iov_loc].iov_len; - - pr_debug("tx_data: #5 new_tx_marker" - " %u, size %u\n", *tx_marker, size); - } - } - - data += (tx_marker_iov * (MARKER_SIZE / 2)); - - iov_p = &iov[0]; - iov_len = iov_count; - - if (iov_count > count->ss_iov_count) { - pr_err("iov_count: %d, count->ss_iov_count:" - " %d\n", iov_count, count->ss_iov_count); - return -1; - } - if (tx_marker_iov > count->ss_marker_count) { - pr_err("tx_marker_iov: %d, count->ss_marker" - "_count: %d\n", tx_marker_iov, - count->ss_marker_count); - return -1; - } - } else { - iov_p = count->iov; - iov_len = count->iov_count; - } - - while (total_tx < data) { - tx_loop = kernel_sendmsg(conn->sock, &msg, iov_p, iov_len, - (data - total_tx)); - if (tx_loop <= 0) { - pr_debug("tx_loop: %d total_tx %d\n", - tx_loop, total_tx); - return tx_loop; - } - total_tx += tx_loop; - pr_debug("tx_loop: %d, total_tx: %d, data: %d\n", - tx_loop, total_tx, data); - } - - if (count->sync_and_steering) - total_tx -= (tx_marker_iov * (MARKER_SIZE / 2)); - - return total_tx; -} - -int rx_data( - struct iscsi_conn *conn, - struct kvec *iov, - int iov_count, - int data) -{ - struct iscsi_data_count c; - - if (!conn || !conn->sock || !conn->conn_ops) - return -1; - - memset(&c, 0, sizeof(struct iscsi_data_count)); - c.iov = iov; - c.iov_count = iov_count; - c.data_length = data; - c.type = ISCSI_RX_DATA; - - if (conn->conn_ops->OFMarker && - (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) { - if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0) - return -1; - } - - return iscsit_do_rx_data(conn, &c); -} - -int tx_data( - struct iscsi_conn *conn, - struct kvec *iov, - int iov_count, - int data) -{ - struct iscsi_data_count c; - - if (!conn || !conn->sock || !conn->conn_ops) - return -1; - - memset(&c, 0, sizeof(struct iscsi_data_count)); - c.iov = iov; - c.iov_count = iov_count; - c.data_length = data; - c.type = ISCSI_TX_DATA; - - if (conn->conn_ops->IFMarker && - (conn->conn_state >= TARG_CONN_STATE_LOGGED_IN)) { - if (iscsit_determine_sync_and_steering_counts(conn, &c) < 0) - return -1; - } - - return iscsit_do_tx_data(conn, &c); -} - -void iscsit_collect_login_stats( - struct iscsi_conn *conn, - u8 status_class, - u8 status_detail) -{ - struct iscsi_param *intrname = NULL; - struct iscsi_tiqn *tiqn; - struct iscsi_login_stats *ls; - - tiqn = iscsit_snmp_get_tiqn(conn); - if (!tiqn) - return; - - ls = &tiqn->login_stats; - - spin_lock(&ls->lock); - if (!strcmp(conn->login_ip, ls->last_intr_fail_ip_addr) && - ((get_jiffies_64() - ls->last_fail_time) < 10)) { - /* We already have the failure info for this login */ - spin_unlock(&ls->lock); - return; - } - - if (status_class == ISCSI_STATUS_CLS_SUCCESS) - ls->accepts++; - else if (status_class == ISCSI_STATUS_CLS_REDIRECT) { - ls->redirects++; - ls->last_fail_type = ISCSI_LOGIN_FAIL_REDIRECT; - } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) && - (status_detail == ISCSI_LOGIN_STATUS_AUTH_FAILED)) { - ls->authenticate_fails++; - ls->last_fail_type = ISCSI_LOGIN_FAIL_AUTHENTICATE; - } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) && - (status_detail == ISCSI_LOGIN_STATUS_TGT_FORBIDDEN)) { - ls->authorize_fails++; - ls->last_fail_type = ISCSI_LOGIN_FAIL_AUTHORIZE; - } else if ((status_class == ISCSI_STATUS_CLS_INITIATOR_ERR) && - (status_detail == ISCSI_LOGIN_STATUS_INIT_ERR)) { - ls->negotiate_fails++; - ls->last_fail_type = ISCSI_LOGIN_FAIL_NEGOTIATE; - } else { - ls->other_fails++; - ls->last_fail_type = ISCSI_LOGIN_FAIL_OTHER; - } - - /* Save initiator name, ip address and time, if it is a failed login */ - if (status_class != ISCSI_STATUS_CLS_SUCCESS) { - if (conn->param_list) - intrname = iscsi_find_param_from_key(INITIATORNAME, - conn->param_list); - strcpy(ls->last_intr_fail_name, - (intrname ? intrname->value : "Unknown")); - - ls->last_intr_fail_ip_family = conn->sock->sk->sk_family; - snprintf(ls->last_intr_fail_ip_addr, IPV6_ADDRESS_SPACE, - "%s", conn->login_ip); - ls->last_fail_time = get_jiffies_64(); - } - - spin_unlock(&ls->lock); -} - -struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *conn) -{ - struct iscsi_portal_group *tpg; - - if (!conn || !conn->sess) - return NULL; - - tpg = conn->sess->tpg; - if (!tpg) - return NULL; - - if (!tpg->tpg_tiqn) - return NULL; - - return tpg->tpg_tiqn; -} diff --git a/trunk/drivers/target/iscsi/iscsi_target_util.h b/trunk/drivers/target/iscsi/iscsi_target_util.h deleted file mode 100644 index 2cd49d607bda..000000000000 --- a/trunk/drivers/target/iscsi/iscsi_target_util.h +++ /dev/null @@ -1,60 +0,0 @@ -#ifndef ISCSI_TARGET_UTIL_H -#define ISCSI_TARGET_UTIL_H - -#define MARKER_SIZE 8 - -extern int iscsit_add_r2t_to_list(struct iscsi_cmd *, u32, u32, int, u32); -extern struct iscsi_r2t *iscsit_get_r2t_for_eos(struct iscsi_cmd *, u32, u32); -extern struct iscsi_r2t *iscsit_get_r2t_from_list(struct iscsi_cmd *); -extern void iscsit_free_r2t(struct iscsi_r2t *, struct iscsi_cmd *); -extern void iscsit_free_r2ts_from_list(struct iscsi_cmd *); -extern struct iscsi_cmd *iscsit_allocate_cmd(struct iscsi_conn *, gfp_t); -extern struct iscsi_cmd *iscsit_allocate_se_cmd(struct iscsi_conn *, u32, int, int); -extern struct iscsi_cmd *iscsit_allocate_se_cmd_for_tmr(struct iscsi_conn *, u8); -extern int iscsit_decide_list_to_build(struct iscsi_cmd *, u32); -extern struct iscsi_seq *iscsit_get_seq_holder_for_datain(struct iscsi_cmd *, u32); -extern struct iscsi_seq *iscsit_get_seq_holder_for_r2t(struct iscsi_cmd *); -extern struct iscsi_r2t *iscsit_get_holder_for_r2tsn(struct iscsi_cmd *, u32); -int iscsit_sequence_cmd(struct iscsi_conn *conn, struct iscsi_cmd *cmd, u32 cmdsn); -extern int iscsit_check_unsolicited_dataout(struct iscsi_cmd *, unsigned char *); -extern struct iscsi_cmd *iscsit_find_cmd_from_itt(struct iscsi_conn *, u32); -extern struct iscsi_cmd *iscsit_find_cmd_from_itt_or_dump(struct iscsi_conn *, - u32, u32); -extern struct iscsi_cmd *iscsit_find_cmd_from_ttt(struct iscsi_conn *, u32); -extern int iscsit_find_cmd_for_recovery(struct iscsi_session *, struct iscsi_cmd **, - struct iscsi_conn_recovery **, u32); -extern void iscsit_add_cmd_to_immediate_queue(struct iscsi_cmd *, struct iscsi_conn *, u8); -extern struct iscsi_queue_req *iscsit_get_cmd_from_immediate_queue(struct iscsi_conn *); -extern void iscsit_add_cmd_to_response_queue(struct iscsi_cmd *, struct iscsi_conn *, u8); -extern struct iscsi_queue_req *iscsit_get_cmd_from_response_queue(struct iscsi_conn *); -extern void iscsit_remove_cmd_from_tx_queues(struct iscsi_cmd *, struct iscsi_conn *); -extern void iscsit_free_queue_reqs_for_conn(struct iscsi_conn *); -extern void iscsit_release_cmd(struct iscsi_cmd *); -extern int iscsit_check_session_usage_count(struct iscsi_session *); -extern void iscsit_dec_session_usage_count(struct iscsi_session *); -extern void iscsit_inc_session_usage_count(struct iscsi_session *); -extern int iscsit_set_sync_and_steering_values(struct iscsi_conn *); -extern struct iscsi_conn *iscsit_get_conn_from_cid(struct iscsi_session *, u16); -extern struct iscsi_conn *iscsit_get_conn_from_cid_rcfr(struct iscsi_session *, u16); -extern void iscsit_check_conn_usage_count(struct iscsi_conn *); -extern void iscsit_dec_conn_usage_count(struct iscsi_conn *); -extern void iscsit_inc_conn_usage_count(struct iscsi_conn *); -extern void iscsit_mod_nopin_response_timer(struct iscsi_conn *); -extern void iscsit_start_nopin_response_timer(struct iscsi_conn *); -extern void iscsit_stop_nopin_response_timer(struct iscsi_conn *); -extern void __iscsit_start_nopin_timer(struct iscsi_conn *); -extern void iscsit_start_nopin_timer(struct iscsi_conn *); -extern void iscsit_stop_nopin_timer(struct iscsi_conn *); -extern int iscsit_send_tx_data(struct iscsi_cmd *, struct iscsi_conn *, int); -extern int iscsit_fe_sendpage_sg(struct iscsi_cmd *, struct iscsi_conn *); -extern int iscsit_tx_login_rsp(struct iscsi_conn *, u8, u8); -extern void iscsit_print_session_params(struct iscsi_session *); -extern int iscsit_print_dev_to_proc(char *, char **, off_t, int); -extern int iscsit_print_sessions_to_proc(char *, char **, off_t, int); -extern int iscsit_print_tpg_to_proc(char *, char **, off_t, int); -extern int rx_data(struct iscsi_conn *, struct kvec *, int, int); -extern int tx_data(struct iscsi_conn *, struct kvec *, int, int); -extern void iscsit_collect_login_stats(struct iscsi_conn *, u8, u8); -extern struct iscsi_tiqn *iscsit_snmp_get_tiqn(struct iscsi_conn *); - -#endif /*** ISCSI_TARGET_UTIL_H ***/ diff --git a/trunk/drivers/target/target_core_transport.c b/trunk/drivers/target/target_core_transport.c index c75a01a1c475..46352d658e35 100644 --- a/trunk/drivers/target/target_core_transport.c +++ b/trunk/drivers/target/target_core_transport.c @@ -4052,16 +4052,17 @@ static int transport_allocate_data_tasks( struct se_task *task; struct se_device *dev = cmd->se_dev; unsigned long flags; + sector_t sectors; int task_count, i, ret; - sector_t sectors, dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors; + sector_t dev_max_sectors = dev->se_sub_dev->se_dev_attrib.max_sectors; u32 sector_size = dev->se_sub_dev->se_dev_attrib.block_size; struct scatterlist *sg; struct scatterlist *cmd_sg; WARN_ON(cmd->data_length % sector_size); sectors = DIV_ROUND_UP(cmd->data_length, sector_size); - task_count = DIV_ROUND_UP_SECTOR_T(sectors, dev_max_sectors); - + task_count = DIV_ROUND_UP(sectors, dev_max_sectors); + cmd_sg = sgl; for (i = 0; i < task_count; i++) { unsigned int task_size; diff --git a/trunk/fs/anon_inodes.c b/trunk/fs/anon_inodes.c index f11e43ed907d..4d433d34736f 100644 --- a/trunk/fs/anon_inodes.c +++ b/trunk/fs/anon_inodes.c @@ -187,7 +187,7 @@ EXPORT_SYMBOL_GPL(anon_inode_getfd); */ static struct inode *anon_inode_mkinode(void) { - struct inode *inode = new_inode_pseudo(anon_inode_mnt->mnt_sb); + struct inode *inode = new_inode(anon_inode_mnt->mnt_sb); if (!inode) return ERR_PTR(-ENOMEM); diff --git a/trunk/fs/btrfs/inode.c b/trunk/fs/btrfs/inode.c index caa26ab5ed68..e91b097e7252 100644 --- a/trunk/fs/btrfs/inode.c +++ b/trunk/fs/btrfs/inode.c @@ -4467,7 +4467,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, inode->i_generation = BTRFS_I(inode)->generation; btrfs_set_inode_space_info(root, inode); - if (S_ISDIR(mode)) + if (mode & S_IFDIR) owner = 0; else owner = 1; @@ -4512,7 +4512,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans, btrfs_inherit_iflags(inode, dir); - if (S_ISREG(mode)) { + if ((mode & S_IFREG)) { if (btrfs_test_opt(root, NODATASUM)) BTRFS_I(inode)->flags |= BTRFS_INODE_NODATASUM; if (btrfs_test_opt(root, NODATACOW) || diff --git a/trunk/fs/dcache.c b/trunk/fs/dcache.c index b05aac3a8cfc..be18598c7fd7 100644 --- a/trunk/fs/dcache.c +++ b/trunk/fs/dcache.c @@ -2138,9 +2138,8 @@ static void dentry_unlock_parents_for_move(struct dentry *dentry, * @target: new dentry * * Update the dcache to reflect the move of a file name. Negative - * dcache entries should not be moved in this way. Caller must hold - * rename_lock, the i_mutex of the source and target directories, - * and the sb->s_vfs_rename_mutex if they differ. See lock_rename(). + * dcache entries should not be moved in this way. Caller hold + * rename_lock. */ static void __d_move(struct dentry * dentry, struct dentry * target) { @@ -2203,8 +2202,7 @@ static void __d_move(struct dentry * dentry, struct dentry * target) * @target: new dentry * * Update the dcache to reflect the move of a file name. Negative - * dcache entries should not be moved in this way. See the locking - * requirements for __d_move. + * dcache entries should not be moved in this way. */ void d_move(struct dentry *dentry, struct dentry *target) { @@ -2322,8 +2320,7 @@ static void __d_materialise_dentry(struct dentry *dentry, struct dentry *anon) * @inode: inode to bind to the dentry, to which aliases may be attached * * Introduces an dentry into the tree, substituting an extant disconnected - * root directory alias in its place if there is one. Caller must hold the - * i_mutex of the parent directory. + * root directory alias in its place if there is one */ struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode) { diff --git a/trunk/fs/gfs2/ops_fstype.c b/trunk/fs/gfs2/ops_fstype.c index 3bc073a4cf82..516516e0c2a2 100644 --- a/trunk/fs/gfs2/ops_fstype.c +++ b/trunk/fs/gfs2/ops_fstype.c @@ -1018,13 +1018,13 @@ static int gfs2_lm_mount(struct gfs2_sbd *sdp, int silent) fsname++; if (lm->lm_mount == NULL) { fs_info(sdp, "Now mounting FS...\n"); - complete_all(&sdp->sd_locking_init); + complete(&sdp->sd_locking_init); return 0; } ret = lm->lm_mount(sdp, fsname); if (ret == 0) fs_info(sdp, "Joined cluster. Now mounting FS...\n"); - complete_all(&sdp->sd_locking_init); + complete(&sdp->sd_locking_init); return ret; } diff --git a/trunk/fs/inode.c b/trunk/fs/inode.c index d0c72ff6b30e..a48fa5355fb4 100644 --- a/trunk/fs/inode.c +++ b/trunk/fs/inode.c @@ -361,11 +361,9 @@ EXPORT_SYMBOL_GPL(inode_sb_list_add); static inline void inode_sb_list_del(struct inode *inode) { - if (!list_empty(&inode->i_sb_list)) { - spin_lock(&inode_sb_list_lock); - list_del_init(&inode->i_sb_list); - spin_unlock(&inode_sb_list_lock); - } + spin_lock(&inode_sb_list_lock); + list_del_init(&inode->i_sb_list); + spin_unlock(&inode_sb_list_lock); } static unsigned long hash(struct super_block *sb, unsigned long hashval) @@ -797,29 +795,6 @@ unsigned int get_next_ino(void) } EXPORT_SYMBOL(get_next_ino); -/** - * new_inode_pseudo - obtain an inode - * @sb: superblock - * - * Allocates a new inode for given superblock. - * Inode wont be chained in superblock s_inodes list - * This means : - * - fs can't be unmount - * - quotas, fsnotify, writeback can't work - */ -struct inode *new_inode_pseudo(struct super_block *sb) -{ - struct inode *inode = alloc_inode(sb); - - if (inode) { - spin_lock(&inode->i_lock); - inode->i_state = 0; - spin_unlock(&inode->i_lock); - INIT_LIST_HEAD(&inode->i_sb_list); - } - return inode; -} - /** * new_inode - obtain an inode * @sb: superblock @@ -838,9 +813,13 @@ struct inode *new_inode(struct super_block *sb) spin_lock_prefetch(&inode_sb_list_lock); - inode = new_inode_pseudo(sb); - if (inode) + inode = alloc_inode(sb); + if (inode) { + spin_lock(&inode->i_lock); + inode->i_state = 0; + spin_unlock(&inode->i_lock); inode_sb_list_add(inode); + } return inode; } EXPORT_SYMBOL(new_inode); diff --git a/trunk/fs/jffs2/fs.c b/trunk/fs/jffs2/fs.c index b81b35ddf4e4..eeead33d8ef0 100644 --- a/trunk/fs/jffs2/fs.c +++ b/trunk/fs/jffs2/fs.c @@ -80,7 +80,7 @@ int jffs2_do_setattr (struct inode *inode, struct iattr *iattr) ALLOC_NORMAL, JFFS2_SUMMARY_INODE_SIZE); if (ret) { jffs2_free_raw_inode(ri); - if (S_ISLNK(inode->i_mode)) + if (S_ISLNK(inode->i_mode & S_IFMT)) kfree(mdata); return ret; } diff --git a/trunk/fs/jfs/jfs_dmap.c b/trunk/fs/jfs/jfs_dmap.c index 9cbd11a3f804..4496872cf4e7 100644 --- a/trunk/fs/jfs/jfs_dmap.c +++ b/trunk/fs/jfs/jfs_dmap.c @@ -3161,7 +3161,7 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno, { int rc; int dbitno, word, rembits, nb, nwords, wbitno, agno; - s8 oldroot; + s8 oldroot, *leaf; struct dmaptree *tp = (struct dmaptree *) & dp->tree; /* save the current value of the root (i.e. maximum free string) @@ -3169,6 +3169,9 @@ static int dbAllocDmapBU(struct bmap * bmp, struct dmap * dp, s64 blkno, */ oldroot = tp->stree[ROOT]; + /* pick up a pointer to the leaves of the dmap tree */ + leaf = tp->stree + LEAFIND; + /* determine the bit number and word within the dmap of the * starting block. */ diff --git a/trunk/fs/jfs/jfs_txnmgr.c b/trunk/fs/jfs/jfs_txnmgr.c index af9606057dde..f6cc0c09ec63 100644 --- a/trunk/fs/jfs/jfs_txnmgr.c +++ b/trunk/fs/jfs/jfs_txnmgr.c @@ -1143,6 +1143,7 @@ int txCommit(tid_t tid, /* transaction identifier */ struct jfs_log *log; struct tblock *tblk; struct lrd *lrd; + int lsn; struct inode *ip; struct jfs_inode_info *jfs_ip; int k, n; @@ -1309,7 +1310,7 @@ int txCommit(tid_t tid, /* transaction identifier */ */ lrd->type = cpu_to_le16(LOG_COMMIT); lrd->length = 0; - lmLog(log, tblk, lrd, NULL); + lsn = lmLog(log, tblk, lrd, NULL); lmGroupCommit(log, tblk); @@ -2934,6 +2935,7 @@ int jfs_sync(void *arg) { struct inode *ip; struct jfs_inode_info *jfs_ip; + int rc; tid_t tid; do { @@ -2959,7 +2961,7 @@ int jfs_sync(void *arg) */ TXN_UNLOCK(); tid = txBegin(ip->i_sb, COMMIT_INODE); - txCommit(tid, 1, &ip, 0); + rc = txCommit(tid, 1, &ip, 0); txEnd(tid); mutex_unlock(&jfs_ip->commit_mutex); diff --git a/trunk/fs/jfs/namei.c b/trunk/fs/jfs/namei.c index e17545e15664..29b1f1a21142 100644 --- a/trunk/fs/jfs/namei.c +++ b/trunk/fs/jfs/namei.c @@ -893,7 +893,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, unchar *i_fastsymlink; s64 xlen = 0; int bmask = 0, xsize; - s64 xaddr; + s64 extent = 0, xaddr; struct metapage *mp; struct super_block *sb; struct tblock *tblk; @@ -993,6 +993,7 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry, txAbort(tid, 0); goto out3; } + extent = xaddr; ip->i_size = ssize - 1; while (ssize) { /* This is kind of silly since PATH_MAX == 4K */ diff --git a/trunk/fs/lockd/clntproc.c b/trunk/fs/lockd/clntproc.c index 8392cb85bd54..e374050a911c 100644 --- a/trunk/fs/lockd/clntproc.c +++ b/trunk/fs/lockd/clntproc.c @@ -302,8 +302,7 @@ nlmclnt_call(struct rpc_cred *cred, struct nlm_rqst *req, u32 proc) /* We appear to be out of the grace period */ wake_up_all(&host->h_gracewait); } - dprintk("lockd: server returns status %d\n", - ntohl(resp->status)); + dprintk("lockd: server returns status %d\n", resp->status); return 0; /* Okay, call complete */ } @@ -691,8 +690,7 @@ nlmclnt_unlock(struct nlm_rqst *req, struct file_lock *fl) goto out; if (resp->status != nlm_lck_denied_nolocks) - printk("lockd: unexpected unlock status: %d\n", - ntohl(resp->status)); + printk("lockd: unexpected unlock status: %d\n", resp->status); /* What to do now? I'm out of my depth... */ status = -ENOLCK; out: @@ -845,7 +843,6 @@ nlm_stat_to_errno(__be32 status) return -ENOLCK; #endif } - printk(KERN_NOTICE "lockd: unexpected server status %d\n", - ntohl(status)); + printk(KERN_NOTICE "lockd: unexpected server status %d\n", status); return -ENOLCK; } diff --git a/trunk/fs/nfs/Kconfig b/trunk/fs/nfs/Kconfig index 2cde5d954750..81515545ba75 100644 --- a/trunk/fs/nfs/Kconfig +++ b/trunk/fs/nfs/Kconfig @@ -77,7 +77,6 @@ config NFS_V4 config NFS_V4_1 bool "NFS client support for NFSv4.1 (EXPERIMENTAL)" depends on NFS_FS && NFS_V4 && EXPERIMENTAL - select SUNRPC_BACKCHANNEL select PNFS_FILE_LAYOUT help This option enables support for minor version 1 of the NFSv4 protocol diff --git a/trunk/fs/nfs/callback_proc.c b/trunk/fs/nfs/callback_proc.c index 74780f9f852c..d4d1954e9bb9 100644 --- a/trunk/fs/nfs/callback_proc.c +++ b/trunk/fs/nfs/callback_proc.c @@ -111,7 +111,6 @@ int nfs4_validate_delegation_stateid(struct nfs_delegation *delegation, const nf static u32 initiate_file_draining(struct nfs_client *clp, struct cb_layoutrecallargs *args) { - struct nfs_server *server; struct pnfs_layout_hdr *lo; struct inode *ino; bool found = false; @@ -119,28 +118,21 @@ static u32 initiate_file_draining(struct nfs_client *clp, LIST_HEAD(free_me_list); spin_lock(&clp->cl_lock); - rcu_read_lock(); - list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { - list_for_each_entry(lo, &server->layouts, plh_layouts) { - if (nfs_compare_fh(&args->cbl_fh, - &NFS_I(lo->plh_inode)->fh)) - continue; - ino = igrab(lo->plh_inode); - if (!ino) - continue; - found = true; - /* Without this, layout can be freed as soon - * as we release cl_lock. - */ - get_layout_hdr(lo); - break; - } - if (found) - break; + list_for_each_entry(lo, &clp->cl_layouts, plh_layouts) { + if (nfs_compare_fh(&args->cbl_fh, + &NFS_I(lo->plh_inode)->fh)) + continue; + ino = igrab(lo->plh_inode); + if (!ino) + continue; + found = true; + /* Without this, layout can be freed as soon + * as we release cl_lock. + */ + get_layout_hdr(lo); + break; } - rcu_read_unlock(); spin_unlock(&clp->cl_lock); - if (!found) return NFS4ERR_NOMATCHING_LAYOUT; @@ -162,7 +154,6 @@ static u32 initiate_file_draining(struct nfs_client *clp, static u32 initiate_bulk_draining(struct nfs_client *clp, struct cb_layoutrecallargs *args) { - struct nfs_server *server; struct pnfs_layout_hdr *lo; struct inode *ino; u32 rv = NFS4ERR_NOMATCHING_LAYOUT; @@ -176,24 +167,18 @@ static u32 initiate_bulk_draining(struct nfs_client *clp, }; spin_lock(&clp->cl_lock); - rcu_read_lock(); - list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { + list_for_each_entry(lo, &clp->cl_layouts, plh_layouts) { if ((args->cbl_recall_type == RETURN_FSID) && - memcmp(&server->fsid, &args->cbl_fsid, - sizeof(struct nfs_fsid))) + memcmp(&NFS_SERVER(lo->plh_inode)->fsid, + &args->cbl_fsid, sizeof(struct nfs_fsid))) continue; - - list_for_each_entry(lo, &server->layouts, plh_layouts) { - if (!igrab(lo->plh_inode)) - continue; - get_layout_hdr(lo); - BUG_ON(!list_empty(&lo->plh_bulk_recall)); - list_add(&lo->plh_bulk_recall, &recall_list); - } + if (!igrab(lo->plh_inode)) + continue; + get_layout_hdr(lo); + BUG_ON(!list_empty(&lo->plh_bulk_recall)); + list_add(&lo->plh_bulk_recall, &recall_list); } - rcu_read_unlock(); spin_unlock(&clp->cl_lock); - list_for_each_entry_safe(lo, tmp, &recall_list, plh_bulk_recall) { ino = lo->plh_inode; diff --git a/trunk/fs/nfs/client.c b/trunk/fs/nfs/client.c index 19ea7d9c75e6..b3dc2b88b65b 100644 --- a/trunk/fs/nfs/client.c +++ b/trunk/fs/nfs/client.c @@ -188,6 +188,9 @@ static struct nfs_client *nfs_alloc_client(const struct nfs_client_initdata *cl_ cred = rpc_lookup_machine_cred(); if (!IS_ERR(cred)) clp->cl_machine_cred = cred; +#if defined(CONFIG_NFS_V4_1) + INIT_LIST_HEAD(&clp->cl_layouts); +#endif nfs_fscache_get_client_cookie(clp); return clp; @@ -290,7 +293,6 @@ static void nfs_free_client(struct nfs_client *clp) nfs4_deviceid_purge_client(clp); kfree(clp->cl_hostname); - kfree(clp->server_scope); kfree(clp); dprintk("<-- nfs_free_client()\n"); @@ -1060,7 +1062,6 @@ static struct nfs_server *nfs_alloc_server(void) INIT_LIST_HEAD(&server->client_link); INIT_LIST_HEAD(&server->master_link); INIT_LIST_HEAD(&server->delegations); - INIT_LIST_HEAD(&server->layouts); atomic_set(&server->active, 0); @@ -1463,7 +1464,7 @@ struct nfs_client *nfs4_set_ds_client(struct nfs_client* mds_clp, dprintk("<-- %s %p\n", __func__, clp); return clp; } -EXPORT_SYMBOL_GPL(nfs4_set_ds_client); +EXPORT_SYMBOL(nfs4_set_ds_client); /* * Session has been established, and the client marked ready. diff --git a/trunk/fs/nfs/delegation.c b/trunk/fs/nfs/delegation.c index 321a66bc3846..dd25c2aec375 100644 --- a/trunk/fs/nfs/delegation.c +++ b/trunk/fs/nfs/delegation.c @@ -398,11 +398,12 @@ int nfs_inode_return_delegation(struct inode *inode) return err; } -static void nfs_mark_return_delegation(struct nfs_server *server, - struct nfs_delegation *delegation) +static void nfs_mark_return_delegation(struct nfs_delegation *delegation) { + struct nfs_client *clp = NFS_SERVER(delegation->inode)->nfs_client; + set_bit(NFS_DELEGATION_RETURN, &delegation->flags); - set_bit(NFS4CLNT_DELEGRETURN, &server->nfs_client->cl_state); + set_bit(NFS4CLNT_DELEGRETURN, &clp->cl_state); } /** @@ -440,7 +441,7 @@ static void nfs_mark_return_all_delegation_types(struct nfs_server *server, if ((delegation->type == (FMODE_READ|FMODE_WRITE)) && !(flags & FMODE_WRITE)) continue; if (delegation->type & flags) - nfs_mark_return_delegation(server, delegation); + nfs_mark_return_delegation(delegation); } } @@ -507,7 +508,7 @@ static void nfs_mark_return_unreferenced_delegations(struct nfs_server *server) list_for_each_entry_rcu(delegation, &server->delegations, super_list) { if (test_and_clear_bit(NFS_DELEGATION_REFERENCED, &delegation->flags)) continue; - nfs_mark_return_delegation(server, delegation); + nfs_mark_return_delegation(delegation); } } @@ -538,8 +539,7 @@ void nfs_expire_unreferenced_delegations(struct nfs_client *clp) int nfs_async_inode_return_delegation(struct inode *inode, const nfs4_stateid *stateid) { - struct nfs_server *server = NFS_SERVER(inode); - struct nfs_client *clp = server->nfs_client; + struct nfs_client *clp = NFS_SERVER(inode)->nfs_client; struct nfs_delegation *delegation; rcu_read_lock(); @@ -549,7 +549,7 @@ int nfs_async_inode_return_delegation(struct inode *inode, rcu_read_unlock(); return -ENOENT; } - nfs_mark_return_delegation(server, delegation); + nfs_mark_return_delegation(delegation); rcu_read_unlock(); nfs_delegation_run_state_manager(clp); diff --git a/trunk/fs/nfs/internal.h b/trunk/fs/nfs/internal.h index ab12913dd473..2a55347a2daa 100644 --- a/trunk/fs/nfs/internal.h +++ b/trunk/fs/nfs/internal.h @@ -277,9 +277,6 @@ extern void nfs_sb_deactive(struct super_block *sb); extern char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen); extern struct vfsmount *nfs_d_automount(struct path *path); -#ifdef CONFIG_NFS_V4 -rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *); -#endif /* getroot.c */ extern struct dentry *nfs_get_root(struct super_block *, struct nfs_fh *, @@ -291,22 +288,12 @@ extern struct dentry *nfs4_get_root(struct super_block *, struct nfs_fh *, extern int nfs4_get_rootfh(struct nfs_server *server, struct nfs_fh *mntfh); #endif -struct nfs_pageio_descriptor; /* read.c */ extern int nfs_initiate_read(struct nfs_read_data *data, struct rpc_clnt *clnt, const struct rpc_call_ops *call_ops); extern void nfs_read_prepare(struct rpc_task *task, void *calldata); -extern int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, - struct list_head *head); - -extern void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio); -extern void nfs_readdata_release(struct nfs_read_data *rdata); /* write.c */ -extern int nfs_generic_flush(struct nfs_pageio_descriptor *desc, - struct list_head *head); -extern void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio); -extern void nfs_writedata_release(struct nfs_write_data *wdata); extern void nfs_commit_free(struct nfs_write_data *p); extern int nfs_initiate_write(struct nfs_write_data *data, struct rpc_clnt *clnt, diff --git a/trunk/fs/nfs/namespace.c b/trunk/fs/nfs/namespace.c index 8102391bb374..1f063bacd285 100644 --- a/trunk/fs/nfs/namespace.c +++ b/trunk/fs/nfs/namespace.c @@ -119,7 +119,7 @@ char *nfs_path(char **p, struct dentry *dentry, char *buffer, ssize_t buflen) } #ifdef CONFIG_NFS_V4 -rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) +static rpc_authflavor_t nfs_find_best_sec(struct nfs4_secinfo_flavors *flavors) { struct gss_api_mech *mech; struct xdr_netobj oid; diff --git a/trunk/fs/nfs/nfs4_fs.h b/trunk/fs/nfs/nfs4_fs.h index 1909ee8be350..b788f2eb1ba0 100644 --- a/trunk/fs/nfs/nfs4_fs.h +++ b/trunk/fs/nfs/nfs4_fs.h @@ -48,7 +48,6 @@ enum nfs4_client_state { NFS4CLNT_SESSION_RESET, NFS4CLNT_RECALL_SLOT, NFS4CLNT_LEASE_CONFIRM, - NFS4CLNT_SERVER_SCOPE_MISMATCH, }; enum nfs4_session_state { @@ -67,8 +66,6 @@ struct nfs4_minor_version_ops { int cache_reply); int (*validate_stateid)(struct nfs_delegation *, const nfs4_stateid *); - int (*find_root_sec)(struct nfs_server *, struct nfs_fh *, - struct nfs_fsinfo *); const struct nfs4_state_recovery_ops *reboot_recovery_ops; const struct nfs4_state_recovery_ops *nograce_recovery_ops; const struct nfs4_state_maintenance_ops *state_renewal_ops; @@ -352,8 +349,6 @@ extern void nfs4_schedule_state_manager(struct nfs_client *); extern void nfs4_schedule_stateid_recovery(const struct nfs_server *, struct nfs4_state *); extern void nfs41_handle_sequence_flag_errors(struct nfs_client *clp, u32 flags); extern void nfs41_handle_recall_slot(struct nfs_client *clp); -extern void nfs41_handle_server_scope(struct nfs_client *, - struct server_scope **); extern void nfs4_put_lock_state(struct nfs4_lock_state *lsp); extern int nfs4_set_lock_state(struct nfs4_state *state, struct file_lock *fl); extern void nfs4_copy_stateid(nfs4_stateid *, struct nfs4_state *, fl_owner_t, pid_t); diff --git a/trunk/fs/nfs/nfs4filelayout.c b/trunk/fs/nfs/nfs4filelayout.c index be93a622872c..f9d03abcd04c 100644 --- a/trunk/fs/nfs/nfs4filelayout.c +++ b/trunk/fs/nfs/nfs4filelayout.c @@ -334,9 +334,6 @@ filelayout_read_pagelist(struct nfs_read_data *data) __func__, data->inode->i_ino, data->args.pgbase, (size_t)data->args.count, offset); - if (test_bit(NFS_DEVICEID_INVALID, &FILELAYOUT_DEVID_NODE(lseg)->flags)) - return PNFS_NOT_ATTEMPTED; - /* Retrieve the correct rpc_client for the byte range */ j = nfs4_fl_calc_j_index(lseg, offset); idx = nfs4_fl_calc_ds_index(lseg, j); @@ -347,7 +344,8 @@ filelayout_read_pagelist(struct nfs_read_data *data) set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); return PNFS_NOT_ATTEMPTED; } - dprintk("%s USE DS: %s\n", __func__, ds->ds_remotestr); + dprintk("%s USE DS:ip %x %hu\n", __func__, + ntohl(ds->ds_ip_addr), ntohs(ds->ds_port)); /* No multipath support. Use first DS */ data->ds_clp = ds->ds_clp; @@ -376,9 +374,6 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) struct nfs_fh *fh; int status; - if (test_bit(NFS_DEVICEID_INVALID, &FILELAYOUT_DEVID_NODE(lseg)->flags)) - return PNFS_NOT_ATTEMPTED; - /* Retrieve the correct rpc_client for the byte range */ j = nfs4_fl_calc_j_index(lseg, offset); idx = nfs4_fl_calc_ds_index(lseg, j); @@ -389,9 +384,9 @@ filelayout_write_pagelist(struct nfs_write_data *data, int sync) set_bit(lo_fail_bit(IOMODE_READ), &lseg->pls_layout->plh_flags); return PNFS_NOT_ATTEMPTED; } - dprintk("%s ino %lu sync %d req %Zu@%llu DS: %s\n", __func__, + dprintk("%s ino %lu sync %d req %Zu@%llu DS:%x:%hu\n", __func__, data->inode->i_ino, sync, (size_t) data->args.count, offset, - ds->ds_remotestr); + ntohl(ds->ds_ip_addr), ntohs(ds->ds_port)); data->write_done_cb = filelayout_write_done_cb; data->ds_clp = ds->ds_clp; @@ -433,14 +428,6 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, dprintk("--> %s\n", __func__); - /* FIXME: remove this check when layout segment support is added */ - if (lgr->range.offset != 0 || - lgr->range.length != NFS4_MAX_UINT64) { - dprintk("%s Only whole file layouts supported. Use MDS i/o\n", - __func__); - goto out; - } - if (fl->pattern_offset > lgr->range.offset) { dprintk("%s pattern_offset %lld too large\n", __func__, fl->pattern_offset); @@ -462,10 +449,6 @@ filelayout_check_layout(struct pnfs_layout_hdr *lo, goto out; } else dsaddr = container_of(d, struct nfs4_file_layout_dsaddr, id_node); - /* Found deviceid is being reaped */ - if (test_bit(NFS_DEVICEID_INVALID, &dsaddr->id_node.flags)) - goto out_put; - fl->dsaddr = dsaddr; if (fl->first_stripe_index < 0 || @@ -676,7 +659,7 @@ filelayout_alloc_lseg(struct pnfs_layout_hdr *layoutid, * return true : coalesce page * return false : don't coalesce page */ -static bool +bool filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, struct nfs_page *req) { @@ -687,6 +670,8 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, !nfs_generic_pg_test(pgio, prev, req)) return false; + if (!pgio->pg_lseg) + return 1; p_stripe = (u64)prev->wb_index << PAGE_CACHE_SHIFT; r_stripe = (u64)req->wb_index << PAGE_CACHE_SHIFT; stripe_unit = FILELAYOUT_LSEG(pgio->pg_lseg)->stripe_unit; @@ -697,52 +682,6 @@ filelayout_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, return (p_stripe == r_stripe); } -void -filelayout_pg_init_read(struct nfs_pageio_descriptor *pgio, - struct nfs_page *req) -{ - BUG_ON(pgio->pg_lseg != NULL); - - pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, - req->wb_context, - 0, - NFS4_MAX_UINT64, - IOMODE_READ, - GFP_KERNEL); - /* If no lseg, fall back to read through mds */ - if (pgio->pg_lseg == NULL) - nfs_pageio_reset_read_mds(pgio); -} - -void -filelayout_pg_init_write(struct nfs_pageio_descriptor *pgio, - struct nfs_page *req) -{ - BUG_ON(pgio->pg_lseg != NULL); - - pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, - req->wb_context, - 0, - NFS4_MAX_UINT64, - IOMODE_RW, - GFP_NOFS); - /* If no lseg, fall back to write through mds */ - if (pgio->pg_lseg == NULL) - nfs_pageio_reset_write_mds(pgio); -} - -static const struct nfs_pageio_ops filelayout_pg_read_ops = { - .pg_init = filelayout_pg_init_read, - .pg_test = filelayout_pg_test, - .pg_doio = pnfs_generic_pg_readpages, -}; - -static const struct nfs_pageio_ops filelayout_pg_write_ops = { - .pg_init = filelayout_pg_init_write, - .pg_test = filelayout_pg_test, - .pg_doio = pnfs_generic_pg_writepages, -}; - static bool filelayout_mark_pnfs_commit(struct pnfs_layout_segment *lseg) { return !FILELAYOUT_LSEG(lseg)->commit_through_mds; @@ -940,8 +879,7 @@ static struct pnfs_layoutdriver_type filelayout_type = { .owner = THIS_MODULE, .alloc_lseg = filelayout_alloc_lseg, .free_lseg = filelayout_free_lseg, - .pg_read_ops = &filelayout_pg_read_ops, - .pg_write_ops = &filelayout_pg_write_ops, + .pg_test = filelayout_pg_test, .mark_pnfs_commit = filelayout_mark_pnfs_commit, .choose_commit_list = filelayout_choose_commit_list, .commit_pagelist = filelayout_commit_pagelist, @@ -964,7 +902,5 @@ static void __exit nfs4filelayout_exit(void) pnfs_unregister_layoutdriver(&filelayout_type); } -MODULE_ALIAS("nfs-layouttype4-1"); - module_init(nfs4filelayout_init); module_exit(nfs4filelayout_exit); diff --git a/trunk/fs/nfs/nfs4filelayout.h b/trunk/fs/nfs/nfs4filelayout.h index 2e42284253fa..cebe01e3795e 100644 --- a/trunk/fs/nfs/nfs4filelayout.h +++ b/trunk/fs/nfs/nfs4filelayout.h @@ -47,17 +47,10 @@ enum stripetype4 { }; /* Individual ip address */ -struct nfs4_pnfs_ds_addr { - struct sockaddr_storage da_addr; - size_t da_addrlen; - struct list_head da_node; /* nfs4_pnfs_dev_hlist dev_dslist */ - char *da_remotestr; /* human readable addr+port */ -}; - struct nfs4_pnfs_ds { struct list_head ds_node; /* nfs4_pnfs_dev_hlist dev_dslist */ - char *ds_remotestr; /* comma sep list of addrs */ - struct list_head ds_addrs; + u32 ds_ip_addr; + u32 ds_port; struct nfs_client *ds_clp; atomic_t ds_count; }; @@ -96,12 +89,6 @@ FILELAYOUT_LSEG(struct pnfs_layout_segment *lseg) generic_hdr); } -static inline struct nfs4_deviceid_node * -FILELAYOUT_DEVID_NODE(struct pnfs_layout_segment *lseg) -{ - return &FILELAYOUT_LSEG(lseg)->dsaddr->id_node; -} - extern struct nfs_fh * nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j); diff --git a/trunk/fs/nfs/nfs4filelayoutdev.c b/trunk/fs/nfs/nfs4filelayoutdev.c index ed388aae9689..3b7bf1377264 100644 --- a/trunk/fs/nfs/nfs4filelayoutdev.c +++ b/trunk/fs/nfs/nfs4filelayoutdev.c @@ -56,139 +56,54 @@ print_ds(struct nfs4_pnfs_ds *ds) printk("%s NULL device\n", __func__); return; } - printk(" ds %s\n" + printk(" ip_addr %x port %hu\n" " ref count %d\n" " client %p\n" " cl_exchange_flags %x\n", - ds->ds_remotestr, + ntohl(ds->ds_ip_addr), ntohs(ds->ds_port), atomic_read(&ds->ds_count), ds->ds_clp, ds->ds_clp ? ds->ds_clp->cl_exchange_flags : 0); } -static bool -same_sockaddr(struct sockaddr *addr1, struct sockaddr *addr2) -{ - struct sockaddr_in *a, *b; - struct sockaddr_in6 *a6, *b6; - - if (addr1->sa_family != addr2->sa_family) - return false; - - switch (addr1->sa_family) { - case AF_INET: - a = (struct sockaddr_in *)addr1; - b = (struct sockaddr_in *)addr2; - - if (a->sin_addr.s_addr == b->sin_addr.s_addr && - a->sin_port == b->sin_port) - return true; - break; - - case AF_INET6: - a6 = (struct sockaddr_in6 *)addr1; - b6 = (struct sockaddr_in6 *)addr2; - - /* LINKLOCAL addresses must have matching scope_id */ - if (ipv6_addr_scope(&a6->sin6_addr) == - IPV6_ADDR_SCOPE_LINKLOCAL && - a6->sin6_scope_id != b6->sin6_scope_id) - return false; - - if (ipv6_addr_equal(&a6->sin6_addr, &b6->sin6_addr) && - a6->sin6_port == b6->sin6_port) - return true; - break; - - default: - dprintk("%s: unhandled address family: %u\n", - __func__, addr1->sa_family); - return false; - } - - return false; -} - -/* - * Lookup DS by addresses. The first matching address returns true. - * nfs4_ds_cache_lock is held - */ +/* nfs4_ds_cache_lock is held */ static struct nfs4_pnfs_ds * -_data_server_lookup_locked(struct list_head *dsaddrs) +_data_server_lookup_locked(u32 ip_addr, u32 port) { struct nfs4_pnfs_ds *ds; - struct nfs4_pnfs_ds_addr *da1, *da2; - - list_for_each_entry(da1, dsaddrs, da_node) { - list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) { - list_for_each_entry(da2, &ds->ds_addrs, da_node) { - if (same_sockaddr( - (struct sockaddr *)&da1->da_addr, - (struct sockaddr *)&da2->da_addr)) - return ds; - } - } - } - return NULL; -} -/* - * Compare two lists of addresses. - */ -static bool -_data_server_match_all_addrs_locked(struct list_head *dsaddrs1, - struct list_head *dsaddrs2) -{ - struct nfs4_pnfs_ds_addr *da1, *da2; - size_t count1 = 0, - count2 = 0; - - list_for_each_entry(da1, dsaddrs1, da_node) - count1++; - - list_for_each_entry(da2, dsaddrs2, da_node) { - bool found = false; - count2++; - list_for_each_entry(da1, dsaddrs1, da_node) { - if (same_sockaddr((struct sockaddr *)&da1->da_addr, - (struct sockaddr *)&da2->da_addr)) { - found = true; - break; - } + dprintk("_data_server_lookup: ip_addr=%x port=%hu\n", + ntohl(ip_addr), ntohs(port)); + + list_for_each_entry(ds, &nfs4_data_server_cache, ds_node) { + if (ds->ds_ip_addr == ip_addr && + ds->ds_port == port) { + return ds; } - if (!found) - return false; } - - return (count1 == count2); + return NULL; } /* * Create an rpc connection to the nfs4_pnfs_ds data server - * Currently only supports IPv4 and IPv6 addresses + * Currently only support IPv4 */ static int nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) { - struct nfs_client *clp = ERR_PTR(-EIO); - struct nfs4_pnfs_ds_addr *da; + struct nfs_client *clp; + struct sockaddr_in sin; int status = 0; - dprintk("--> %s DS %s au_flavor %d\n", __func__, ds->ds_remotestr, + dprintk("--> %s ip:port %x:%hu au_flavor %d\n", __func__, + ntohl(ds->ds_ip_addr), ntohs(ds->ds_port), mds_srv->nfs_client->cl_rpcclient->cl_auth->au_flavor); - BUG_ON(list_empty(&ds->ds_addrs)); - - list_for_each_entry(da, &ds->ds_addrs, da_node) { - dprintk("%s: DS %s: trying address %s\n", - __func__, ds->ds_remotestr, da->da_remotestr); - - clp = nfs4_set_ds_client(mds_srv->nfs_client, - (struct sockaddr *)&da->da_addr, - da->da_addrlen, IPPROTO_TCP); - if (!IS_ERR(clp)) - break; - } + sin.sin_family = AF_INET; + sin.sin_addr.s_addr = ds->ds_ip_addr; + sin.sin_port = ds->ds_port; + clp = nfs4_set_ds_client(mds_srv->nfs_client, (struct sockaddr *)&sin, + sizeof(sin), IPPROTO_TCP); if (IS_ERR(clp)) { status = PTR_ERR(clp); goto out; @@ -200,8 +115,8 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) goto out_put; } ds->ds_clp = clp; - dprintk("%s [existing] server=%s\n", __func__, - ds->ds_remotestr); + dprintk("%s [existing] ip=%x, port=%hu\n", __func__, + ntohl(ds->ds_ip_addr), ntohs(ds->ds_port)); goto out; } @@ -220,7 +135,8 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) goto out_put; ds->ds_clp = clp; - dprintk("%s [new] addr: %s\n", __func__, ds->ds_remotestr); + dprintk("%s [new] ip=%x, port=%hu\n", __func__, ntohl(ds->ds_ip_addr), + ntohs(ds->ds_port)); out: return status; out_put: @@ -231,25 +147,12 @@ nfs4_ds_connect(struct nfs_server *mds_srv, struct nfs4_pnfs_ds *ds) static void destroy_ds(struct nfs4_pnfs_ds *ds) { - struct nfs4_pnfs_ds_addr *da; - dprintk("--> %s\n", __func__); ifdebug(FACILITY) print_ds(ds); if (ds->ds_clp) nfs_put_client(ds->ds_clp); - - while (!list_empty(&ds->ds_addrs)) { - da = list_first_entry(&ds->ds_addrs, - struct nfs4_pnfs_ds_addr, - da_node); - list_del_init(&da->da_node); - kfree(da->da_remotestr); - kfree(da); - } - - kfree(ds->ds_remotestr); kfree(ds); } @@ -276,96 +179,31 @@ nfs4_fl_free_deviceid(struct nfs4_file_layout_dsaddr *dsaddr) kfree(dsaddr); } -/* - * Create a string with a human readable address and port to avoid - * complicated setup around many dprinks. - */ -static char * -nfs4_pnfs_remotestr(struct list_head *dsaddrs, gfp_t gfp_flags) -{ - struct nfs4_pnfs_ds_addr *da; - char *remotestr; - size_t len; - char *p; - - len = 3; /* '{', '}' and eol */ - list_for_each_entry(da, dsaddrs, da_node) { - len += strlen(da->da_remotestr) + 1; /* string plus comma */ - } - - remotestr = kzalloc(len, gfp_flags); - if (!remotestr) - return NULL; - - p = remotestr; - *(p++) = '{'; - len--; - list_for_each_entry(da, dsaddrs, da_node) { - size_t ll = strlen(da->da_remotestr); - - if (ll > len) - goto out_err; - - memcpy(p, da->da_remotestr, ll); - p += ll; - len -= ll; - - if (len < 1) - goto out_err; - (*p++) = ','; - len--; - } - if (len < 2) - goto out_err; - *(p++) = '}'; - *p = '\0'; - return remotestr; -out_err: - kfree(remotestr); - return NULL; -} - static struct nfs4_pnfs_ds * -nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags) +nfs4_pnfs_ds_add(struct inode *inode, u32 ip_addr, u32 port, gfp_t gfp_flags) { - struct nfs4_pnfs_ds *tmp_ds, *ds = NULL; - char *remotestr; + struct nfs4_pnfs_ds *tmp_ds, *ds; - if (list_empty(dsaddrs)) { - dprintk("%s: no addresses defined\n", __func__); - goto out; - } - - ds = kzalloc(sizeof(*ds), gfp_flags); + ds = kzalloc(sizeof(*tmp_ds), gfp_flags); if (!ds) goto out; - /* this is only used for debugging, so it's ok if its NULL */ - remotestr = nfs4_pnfs_remotestr(dsaddrs, gfp_flags); - spin_lock(&nfs4_ds_cache_lock); - tmp_ds = _data_server_lookup_locked(dsaddrs); + tmp_ds = _data_server_lookup_locked(ip_addr, port); if (tmp_ds == NULL) { - INIT_LIST_HEAD(&ds->ds_addrs); - list_splice_init(dsaddrs, &ds->ds_addrs); - ds->ds_remotestr = remotestr; + ds->ds_ip_addr = ip_addr; + ds->ds_port = port; atomic_set(&ds->ds_count, 1); INIT_LIST_HEAD(&ds->ds_node); ds->ds_clp = NULL; list_add(&ds->ds_node, &nfs4_data_server_cache); - dprintk("%s add new data server %s\n", __func__, - ds->ds_remotestr); + dprintk("%s add new data server ip 0x%x\n", __func__, + ds->ds_ip_addr); } else { - if (!_data_server_match_all_addrs_locked(&tmp_ds->ds_addrs, - dsaddrs)) { - dprintk("%s: multipath address mismatch: %s != %s", - __func__, tmp_ds->ds_remotestr, remotestr); - } - kfree(remotestr); kfree(ds); atomic_inc(&tmp_ds->ds_count); - dprintk("%s data server %s found, inc'ed ds_count to %d\n", - __func__, tmp_ds->ds_remotestr, + dprintk("%s data server found ip 0x%x, inc'ed ds_count to %d\n", + __func__, tmp_ds->ds_ip_addr, atomic_read(&tmp_ds->ds_count)); ds = tmp_ds; } @@ -375,22 +213,18 @@ nfs4_pnfs_ds_add(struct list_head *dsaddrs, gfp_t gfp_flags) } /* - * Currently only supports ipv4, ipv6 and one multi-path address. + * Currently only support ipv4, and one multi-path address. */ -static struct nfs4_pnfs_ds_addr * -decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags) +static struct nfs4_pnfs_ds * +decode_and_add_ds(struct xdr_stream *streamp, struct inode *inode, gfp_t gfp_flags) { - struct nfs4_pnfs_ds_addr *da = NULL; - char *buf, *portstr; - u32 port; - int nlen, rlen; + struct nfs4_pnfs_ds *ds = NULL; + char *buf; + const char *ipend, *pstr; + u32 ip_addr, port; + int nlen, rlen, i; int tmp[2]; __be32 *p; - char *netid, *match_netid; - size_t len, match_netid_len; - char *startsep = ""; - char *endsep = ""; - /* r_netid */ p = xdr_inline_decode(streamp, 4); @@ -402,123 +236,64 @@ decode_ds_addr(struct xdr_stream *streamp, gfp_t gfp_flags) if (unlikely(!p)) goto out_err; - netid = kmalloc(nlen+1, gfp_flags); - if (unlikely(!netid)) + /* Check that netid is "tcp" */ + if (nlen != 3 || memcmp((char *)p, "tcp", 3)) { + dprintk("%s: ERROR: non ipv4 TCP r_netid\n", __func__); goto out_err; + } - netid[nlen] = '\0'; - memcpy(netid, p, nlen); - - /* r_addr: ip/ip6addr with port in dec octets - see RFC 5665 */ + /* r_addr */ p = xdr_inline_decode(streamp, 4); if (unlikely(!p)) - goto out_free_netid; + goto out_err; rlen = be32_to_cpup(p); p = xdr_inline_decode(streamp, rlen); if (unlikely(!p)) - goto out_free_netid; + goto out_err; - /* port is ".ABC.DEF", 8 chars max */ - if (rlen > INET6_ADDRSTRLEN + IPV6_SCOPE_ID_LEN + 8) { + /* ipv6 length plus port is legal */ + if (rlen > INET6_ADDRSTRLEN + 8) { dprintk("%s: Invalid address, length %d\n", __func__, rlen); - goto out_free_netid; + goto out_err; } buf = kmalloc(rlen + 1, gfp_flags); if (!buf) { dprintk("%s: Not enough memory\n", __func__); - goto out_free_netid; + goto out_err; } buf[rlen] = '\0'; memcpy(buf, p, rlen); - /* replace port '.' with '-' */ - portstr = strrchr(buf, '.'); - if (!portstr) { - dprintk("%s: Failed finding expected dot in port\n", - __func__); - goto out_free_buf; - } - *portstr = '-'; - - /* find '.' between address and port */ - portstr = strrchr(buf, '.'); - if (!portstr) { - dprintk("%s: Failed finding expected dot between address and " - "port\n", __func__); - goto out_free_buf; + /* replace the port dots with dashes for the in4_pton() delimiter*/ + for (i = 0; i < 2; i++) { + char *res = strrchr(buf, '.'); + if (!res) { + dprintk("%s: Failed finding expected dots in port\n", + __func__); + goto out_free; + } + *res = '-'; } - *portstr = '\0'; - - da = kzalloc(sizeof(*da), gfp_flags); - if (unlikely(!da)) - goto out_free_buf; - INIT_LIST_HEAD(&da->da_node); - - if (!rpc_pton(buf, portstr-buf, (struct sockaddr *)&da->da_addr, - sizeof(da->da_addr))) { - dprintk("%s: error parsing address %s\n", __func__, buf); - goto out_free_da; + /* Currently only support ipv4 address */ + if (in4_pton(buf, rlen, (u8 *)&ip_addr, '-', &ipend) == 0) { + dprintk("%s: Only ipv4 addresses supported\n", __func__); + goto out_free; } - portstr++; - sscanf(portstr, "%d-%d", &tmp[0], &tmp[1]); + /* port */ + pstr = ipend; + sscanf(pstr, "-%d-%d", &tmp[0], &tmp[1]); port = htons((tmp[0] << 8) | (tmp[1])); - switch (da->da_addr.ss_family) { - case AF_INET: - ((struct sockaddr_in *)&da->da_addr)->sin_port = port; - da->da_addrlen = sizeof(struct sockaddr_in); - match_netid = "tcp"; - match_netid_len = 3; - break; - - case AF_INET6: - ((struct sockaddr_in6 *)&da->da_addr)->sin6_port = port; - da->da_addrlen = sizeof(struct sockaddr_in6); - match_netid = "tcp6"; - match_netid_len = 4; - startsep = "["; - endsep = "]"; - break; - - default: - dprintk("%s: unsupported address family: %u\n", - __func__, da->da_addr.ss_family); - goto out_free_da; - } - - if (nlen != match_netid_len || strncmp(netid, match_netid, nlen)) { - dprintk("%s: ERROR: r_netid \"%s\" != \"%s\"\n", - __func__, netid, match_netid); - goto out_free_da; - } - - /* save human readable address */ - len = strlen(startsep) + strlen(buf) + strlen(endsep) + 7; - da->da_remotestr = kzalloc(len, gfp_flags); - - /* NULL is ok, only used for dprintk */ - if (da->da_remotestr) - snprintf(da->da_remotestr, len, "%s%s%s:%u", startsep, - buf, endsep, ntohs(port)); - - dprintk("%s: Parsed DS addr %s\n", __func__, da->da_remotestr); - kfree(buf); - kfree(netid); - return da; - -out_free_da: - kfree(da); -out_free_buf: - dprintk("%s: Error parsing DS addr: %s\n", __func__, buf); + ds = nfs4_pnfs_ds_add(inode, ip_addr, port, gfp_flags); + dprintk("%s: Decoded address and port %s\n", __func__, buf); +out_free: kfree(buf); -out_free_netid: - kfree(netid); out_err: - return NULL; + return ds; } /* Decode opaque device data and return the result */ @@ -535,8 +310,6 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) struct xdr_stream stream; struct xdr_buf buf; struct page *scratch; - struct list_head dsaddrs; - struct nfs4_pnfs_ds_addr *da; /* set up xdr stream */ scratch = alloc_page(gfp_flags); @@ -613,8 +386,6 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) NFS_SERVER(ino)->nfs_client, &pdev->dev_id); - INIT_LIST_HEAD(&dsaddrs); - for (i = 0; i < dsaddr->ds_num; i++) { int j; u32 mp_count; @@ -624,43 +395,48 @@ decode_device(struct inode *ino, struct pnfs_device *pdev, gfp_t gfp_flags) goto out_err_free_deviceid; mp_count = be32_to_cpup(p); /* multipath count */ - for (j = 0; j < mp_count; j++) { - da = decode_ds_addr(&stream, gfp_flags); - if (da) - list_add_tail(&da->da_node, &dsaddrs); - } - if (list_empty(&dsaddrs)) { - dprintk("%s: no suitable DS addresses found\n", - __func__); - goto out_err_free_deviceid; + if (mp_count > 1) { + printk(KERN_WARNING + "%s: Multipath count %d not supported, " + "skipping all greater than 1\n", __func__, + mp_count); } - - dsaddr->ds_list[i] = nfs4_pnfs_ds_add(&dsaddrs, gfp_flags); - if (!dsaddr->ds_list[i]) - goto out_err_drain_dsaddrs; - - /* If DS was already in cache, free ds addrs */ - while (!list_empty(&dsaddrs)) { - da = list_first_entry(&dsaddrs, - struct nfs4_pnfs_ds_addr, - da_node); - list_del_init(&da->da_node); - kfree(da->da_remotestr); - kfree(da); + for (j = 0; j < mp_count; j++) { + if (j == 0) { + dsaddr->ds_list[i] = decode_and_add_ds(&stream, + ino, gfp_flags); + if (dsaddr->ds_list[i] == NULL) + goto out_err_free_deviceid; + } else { + u32 len; + /* skip extra multipath */ + + /* read len, skip */ + p = xdr_inline_decode(&stream, 4); + if (unlikely(!p)) + goto out_err_free_deviceid; + len = be32_to_cpup(p); + + p = xdr_inline_decode(&stream, len); + if (unlikely(!p)) + goto out_err_free_deviceid; + + /* read len, skip */ + p = xdr_inline_decode(&stream, 4); + if (unlikely(!p)) + goto out_err_free_deviceid; + len = be32_to_cpup(p); + + p = xdr_inline_decode(&stream, len); + if (unlikely(!p)) + goto out_err_free_deviceid; + } } } __free_page(scratch); return dsaddr; -out_err_drain_dsaddrs: - while (!list_empty(&dsaddrs)) { - da = list_first_entry(&dsaddrs, struct nfs4_pnfs_ds_addr, - da_node); - list_del_init(&da->da_node); - kfree(da->da_remotestr); - kfree(da); - } out_err_free_deviceid: nfs4_fl_free_deviceid(dsaddr); /* stripe_indicies was part of dsaddr */ @@ -815,13 +591,13 @@ nfs4_fl_select_ds_fh(struct pnfs_layout_segment *lseg, u32 j) static void filelayout_mark_devid_negative(struct nfs4_file_layout_dsaddr *dsaddr, - int err, const char *ds_remotestr) + int err, u32 ds_addr) { u32 *p = (u32 *)&dsaddr->id_node.deviceid; - printk(KERN_ERR "NFS: data server %s connection error %d." + printk(KERN_ERR "NFS: data server %x connection error %d." " Deviceid [%x%x%x%x] marked out of use.\n", - ds_remotestr, err, p[0], p[1], p[2], p[3]); + ds_addr, err, p[0], p[1], p[2], p[3]); spin_lock(&nfs4_ds_cache_lock); dsaddr->flags |= NFS4_DEVICE_ID_NEG_ENTRY; @@ -852,7 +628,7 @@ nfs4_fl_prepare_ds(struct pnfs_layout_segment *lseg, u32 ds_idx) err = nfs4_ds_connect(s, ds); if (err) { filelayout_mark_devid_negative(dsaddr, err, - ds->ds_remotestr); + ntohl(ds->ds_ip_addr)); return NULL; } } diff --git a/trunk/fs/nfs/nfs4proc.c b/trunk/fs/nfs/nfs4proc.c index 079614deca3f..26bece8f3083 100644 --- a/trunk/fs/nfs/nfs4proc.c +++ b/trunk/fs/nfs/nfs4proc.c @@ -80,10 +80,7 @@ static int _nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs4_do_setattr(struct inode *inode, struct rpc_cred *cred, struct nfs_fattr *fattr, struct iattr *sattr, struct nfs4_state *state); -#ifdef CONFIG_NFS_V4_1 -static int nfs41_test_stateid(struct nfs_server *, struct nfs4_state *); -static int nfs41_free_stateid(struct nfs_server *, struct nfs4_state *); -#endif + /* Prevent leaks of NFSv4 errors into userland */ static int nfs4_map_errors(int err) { @@ -1692,20 +1689,6 @@ static int nfs4_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *sta return ret; } -#if defined(CONFIG_NFS_V4_1) -static int nfs41_open_expired(struct nfs4_state_owner *sp, struct nfs4_state *state) -{ - int status; - struct nfs_server *server = NFS_SERVER(state->inode); - - status = nfs41_test_stateid(server, state); - if (status == NFS_OK) - return 0; - nfs41_free_stateid(server, state); - return nfs4_open_expired(sp, state); -} -#endif - /* * on an EXCLUSIVE create, the server should send back a bitmask with FATTR4-* * fields corresponding to attributes that were used to store the verifier. @@ -2269,14 +2252,13 @@ static int nfs4_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, static int nfs4_proc_get_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { - int minor_version = server->nfs_client->cl_minorversion; int status = nfs4_lookup_root(server, fhandle, info); if ((status == -NFS4ERR_WRONGSEC) && !(server->flags & NFS_MOUNT_SECFLAVOUR)) /* * A status of -NFS4ERR_WRONGSEC will be mapped to -EPERM * by nfs4_map_errors() as this function exits. */ - status = nfs_v4_minor_ops[minor_version]->find_root_sec(server, fhandle, info); + status = nfs4_find_root_sec(server, fhandle, info); if (status == 0) status = nfs4_server_capabilities(server, fhandle); if (status == 0) @@ -4459,20 +4441,6 @@ static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request return err; } -#if defined(CONFIG_NFS_V4_1) -static int nfs41_lock_expired(struct nfs4_state *state, struct file_lock *request) -{ - int status; - struct nfs_server *server = NFS_SERVER(state->inode); - - status = nfs41_test_stateid(server, state); - if (status == NFS_OK) - return 0; - nfs41_free_stateid(server, state); - return nfs4_lock_expired(state, request); -} -#endif - static int _nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) { struct nfs_inode *nfsi = NFS_I(state->inode); @@ -4811,16 +4779,6 @@ static int nfs4_check_cl_exchange_flags(u32 flags) return -NFS4ERR_INVAL; } -static bool -nfs41_same_server_scope(struct server_scope *a, struct server_scope *b) -{ - if (a->server_scope_sz == b->server_scope_sz && - memcmp(a->server_scope, b->server_scope, a->server_scope_sz) == 0) - return true; - - return false; -} - /* * nfs4_proc_exchange_id() * @@ -4863,31 +4821,9 @@ int nfs4_proc_exchange_id(struct nfs_client *clp, struct rpc_cred *cred) init_utsname()->domainname, clp->cl_rpcclient->cl_auth->au_flavor); - res.server_scope = kzalloc(sizeof(struct server_scope), GFP_KERNEL); - if (unlikely(!res.server_scope)) - return -ENOMEM; - status = rpc_call_sync(clp->cl_rpcclient, &msg, RPC_TASK_TIMEOUT); if (!status) status = nfs4_check_cl_exchange_flags(clp->cl_exchange_flags); - - if (!status) { - if (clp->server_scope && - !nfs41_same_server_scope(clp->server_scope, - res.server_scope)) { - dprintk("%s: server_scope mismatch detected\n", - __func__); - set_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, &clp->cl_state); - kfree(clp->server_scope); - clp->server_scope = NULL; - } - - if (!clp->server_scope) - clp->server_scope = res.server_scope; - else - kfree(res.server_scope); - } - dprintk("<-- %s status= %d\n", __func__, status); return status; } @@ -5768,7 +5704,7 @@ static void nfs4_layoutreturn_done(struct rpc_task *task, void *calldata) { struct nfs4_layoutreturn *lrp = calldata; struct nfs_server *server; - struct pnfs_layout_hdr *lo = lrp->args.layout; + struct pnfs_layout_hdr *lo = NFS_I(lrp->args.inode)->layout; dprintk("--> %s\n", __func__); @@ -5797,7 +5733,7 @@ static void nfs4_layoutreturn_release(void *calldata) struct nfs4_layoutreturn *lrp = calldata; dprintk("--> %s\n", __func__); - put_layout_hdr(lrp->args.layout); + put_layout_hdr(NFS_I(lrp->args.inode)->layout); kfree(calldata); dprintk("<-- %s\n", __func__); } @@ -5965,143 +5901,6 @@ nfs4_proc_layoutcommit(struct nfs4_layoutcommit_data *data, bool sync) rpc_put_task(task); return status; } - -static int -_nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors) -{ - struct nfs41_secinfo_no_name_args args = { - .style = SECINFO_STYLE_CURRENT_FH, - }; - struct nfs4_secinfo_res res = { - .flavors = flavors, - }; - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_SECINFO_NO_NAME], - .rpc_argp = &args, - .rpc_resp = &res, - }; - return nfs4_call_sync(server->client, server, &msg, &args.seq_args, &res.seq_res, 0); -} - -static int -nfs41_proc_secinfo_no_name(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fsinfo *info, struct nfs4_secinfo_flavors *flavors) -{ - struct nfs4_exception exception = { }; - int err; - do { - err = _nfs41_proc_secinfo_no_name(server, fhandle, info, flavors); - switch (err) { - case 0: - case -NFS4ERR_WRONGSEC: - case -NFS4ERR_NOTSUPP: - break; - default: - err = nfs4_handle_exception(server, err, &exception); - } - } while (exception.retry); - return err; -} - -static int -nfs41_find_root_sec(struct nfs_server *server, struct nfs_fh *fhandle, - struct nfs_fsinfo *info) -{ - int err; - struct page *page; - rpc_authflavor_t flavor; - struct nfs4_secinfo_flavors *flavors; - - page = alloc_page(GFP_KERNEL); - if (!page) { - err = -ENOMEM; - goto out; - } - - flavors = page_address(page); - err = nfs41_proc_secinfo_no_name(server, fhandle, info, flavors); - - /* - * Fall back on "guess and check" method if - * the server doesn't support SECINFO_NO_NAME - */ - if (err == -NFS4ERR_WRONGSEC || err == -NFS4ERR_NOTSUPP) { - err = nfs4_find_root_sec(server, fhandle, info); - goto out_freepage; - } - if (err) - goto out_freepage; - - flavor = nfs_find_best_sec(flavors); - if (err == 0) - err = nfs4_lookup_root_sec(server, fhandle, info, flavor); - -out_freepage: - put_page(page); - if (err == -EACCES) - return -EPERM; -out: - return err; -} -static int _nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state) -{ - int status; - struct nfs41_test_stateid_args args = { - .stateid = &state->stateid, - }; - struct nfs41_test_stateid_res res; - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_TEST_STATEID], - .rpc_argp = &args, - .rpc_resp = &res, - }; - args.seq_args.sa_session = res.seq_res.sr_session = NULL; - status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1); - return status; -} - -static int nfs41_test_stateid(struct nfs_server *server, struct nfs4_state *state) -{ - struct nfs4_exception exception = { }; - int err; - do { - err = nfs4_handle_exception(server, - _nfs41_test_stateid(server, state), - &exception); - } while (exception.retry); - return err; -} - -static int _nfs4_free_stateid(struct nfs_server *server, struct nfs4_state *state) -{ - int status; - struct nfs41_free_stateid_args args = { - .stateid = &state->stateid, - }; - struct nfs41_free_stateid_res res; - struct rpc_message msg = { - .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_FREE_STATEID], - .rpc_argp = &args, - .rpc_resp = &res, - }; - - args.seq_args.sa_session = res.seq_res.sr_session = NULL; - status = nfs4_call_sync_sequence(server->client, server, &msg, &args.seq_args, &res.seq_res, 0, 1); - return status; -} - -static int nfs41_free_stateid(struct nfs_server *server, struct nfs4_state *state) -{ - struct nfs4_exception exception = { }; - int err; - do { - err = nfs4_handle_exception(server, - _nfs4_free_stateid(server, state), - &exception); - } while (exception.retry); - return err; -} #endif /* CONFIG_NFS_V4_1 */ struct nfs4_state_recovery_ops nfs40_reboot_recovery_ops = { @@ -6138,8 +5937,8 @@ struct nfs4_state_recovery_ops nfs40_nograce_recovery_ops = { struct nfs4_state_recovery_ops nfs41_nograce_recovery_ops = { .owner_flag_bit = NFS_OWNER_RECLAIM_NOGRACE, .state_flag_bit = NFS_STATE_RECLAIM_NOGRACE, - .recover_open = nfs41_open_expired, - .recover_lock = nfs41_lock_expired, + .recover_open = nfs4_open_expired, + .recover_lock = nfs4_lock_expired, .establish_clid = nfs41_init_clientid, .get_clid_cred = nfs4_get_exchange_id_cred, }; @@ -6163,7 +5962,6 @@ static const struct nfs4_minor_version_ops nfs_v4_0_minor_ops = { .minor_version = 0, .call_sync = _nfs4_call_sync, .validate_stateid = nfs4_validate_delegation_stateid, - .find_root_sec = nfs4_find_root_sec, .reboot_recovery_ops = &nfs40_reboot_recovery_ops, .nograce_recovery_ops = &nfs40_nograce_recovery_ops, .state_renewal_ops = &nfs40_state_renewal_ops, @@ -6174,7 +5972,6 @@ static const struct nfs4_minor_version_ops nfs_v4_1_minor_ops = { .minor_version = 1, .call_sync = _nfs4_call_sync_session, .validate_stateid = nfs41_validate_delegation_stateid, - .find_root_sec = nfs41_find_root_sec, .reboot_recovery_ops = &nfs41_reboot_recovery_ops, .nograce_recovery_ops = &nfs41_nograce_recovery_ops, .state_renewal_ops = &nfs41_state_renewal_ops, diff --git a/trunk/fs/nfs/nfs4state.c b/trunk/fs/nfs/nfs4state.c index 72ab97ef3d61..7acfe8843626 100644 --- a/trunk/fs/nfs/nfs4state.c +++ b/trunk/fs/nfs/nfs4state.c @@ -1643,14 +1643,7 @@ static void nfs4_state_manager(struct nfs_client *clp) goto out_error; } clear_bit(NFS4CLNT_CHECK_LEASE, &clp->cl_state); - - if (test_and_clear_bit(NFS4CLNT_SERVER_SCOPE_MISMATCH, - &clp->cl_state)) - nfs4_state_start_reclaim_nograce(clp); - else - set_bit(NFS4CLNT_RECLAIM_REBOOT, - &clp->cl_state); - + set_bit(NFS4CLNT_RECLAIM_REBOOT, &clp->cl_state); pnfs_destroy_all_layouts(clp); } diff --git a/trunk/fs/nfs/nfs4xdr.c b/trunk/fs/nfs/nfs4xdr.c index c191a9baa422..e6e8f3b9a1de 100644 --- a/trunk/fs/nfs/nfs4xdr.c +++ b/trunk/fs/nfs/nfs4xdr.c @@ -343,14 +343,6 @@ static int nfs4_stat_to_errno(int); 1 /* FIXME: opaque lrf_body always empty at the moment */) #define decode_layoutreturn_maxsz (op_decode_hdr_maxsz + \ 1 + decode_stateid_maxsz) -#define encode_secinfo_no_name_maxsz (op_encode_hdr_maxsz + 1) -#define decode_secinfo_no_name_maxsz decode_secinfo_maxsz -#define encode_test_stateid_maxsz (op_encode_hdr_maxsz + 2 + \ - XDR_QUADLEN(NFS4_STATEID_SIZE)) -#define decode_test_stateid_maxsz (op_decode_hdr_maxsz + 2 + 1) -#define encode_free_stateid_maxsz (op_encode_hdr_maxsz + 1 + \ - XDR_QUADLEN(NFS4_STATEID_SIZE)) -#define decode_free_stateid_maxsz (op_decode_hdr_maxsz + 1) #else /* CONFIG_NFS_V4_1 */ #define encode_sequence_maxsz 0 #define decode_sequence_maxsz 0 @@ -780,26 +772,6 @@ static int nfs4_stat_to_errno(int); decode_sequence_maxsz + \ decode_putfh_maxsz + \ decode_layoutreturn_maxsz) -#define NFS4_enc_secinfo_no_name_sz (compound_encode_hdr_maxsz + \ - encode_sequence_maxsz + \ - encode_putrootfh_maxsz +\ - encode_secinfo_no_name_maxsz) -#define NFS4_dec_secinfo_no_name_sz (compound_decode_hdr_maxsz + \ - decode_sequence_maxsz + \ - decode_putrootfh_maxsz + \ - decode_secinfo_no_name_maxsz) -#define NFS4_enc_test_stateid_sz (compound_encode_hdr_maxsz + \ - encode_sequence_maxsz + \ - encode_test_stateid_maxsz) -#define NFS4_dec_test_stateid_sz (compound_decode_hdr_maxsz + \ - decode_sequence_maxsz + \ - decode_test_stateid_maxsz) -#define NFS4_enc_free_stateid_sz (compound_encode_hdr_maxsz + \ - encode_sequence_maxsz + \ - encode_free_stateid_maxsz) -#define NFS4_dec_free_stateid_sz (compound_decode_hdr_maxsz + \ - decode_sequence_maxsz + \ - decode_free_stateid_maxsz) const u32 nfs41_maxwrite_overhead = ((RPC_MAX_HEADER_WITH_AUTH + compound_encode_hdr_maxsz + @@ -1966,46 +1938,6 @@ encode_layoutreturn(struct xdr_stream *xdr, hdr->nops++; hdr->replen += decode_layoutreturn_maxsz; } - -static int -encode_secinfo_no_name(struct xdr_stream *xdr, - const struct nfs41_secinfo_no_name_args *args, - struct compound_hdr *hdr) -{ - __be32 *p; - p = reserve_space(xdr, 8); - *p++ = cpu_to_be32(OP_SECINFO_NO_NAME); - *p++ = cpu_to_be32(args->style); - hdr->nops++; - hdr->replen += decode_secinfo_no_name_maxsz; - return 0; -} - -static void encode_test_stateid(struct xdr_stream *xdr, - struct nfs41_test_stateid_args *args, - struct compound_hdr *hdr) -{ - __be32 *p; - - p = reserve_space(xdr, 8 + NFS4_STATEID_SIZE); - *p++ = cpu_to_be32(OP_TEST_STATEID); - *p++ = cpu_to_be32(1); - xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE); - hdr->nops++; - hdr->replen += decode_test_stateid_maxsz; -} - -static void encode_free_stateid(struct xdr_stream *xdr, - struct nfs41_free_stateid_args *args, - struct compound_hdr *hdr) -{ - __be32 *p; - p = reserve_space(xdr, 4 + NFS4_STATEID_SIZE); - *p++ = cpu_to_be32(OP_FREE_STATEID); - xdr_encode_opaque_fixed(p, args->stateid->data, NFS4_STATEID_SIZE); - hdr->nops++; - hdr->replen += decode_free_stateid_maxsz; -} #endif /* CONFIG_NFS_V4_1 */ /* @@ -2858,59 +2790,6 @@ static void nfs4_xdr_enc_layoutreturn(struct rpc_rqst *req, encode_layoutreturn(xdr, args, &hdr); encode_nops(&hdr); } - -/* - * Encode SECINFO_NO_NAME request - */ -static int nfs4_xdr_enc_secinfo_no_name(struct rpc_rqst *req, - struct xdr_stream *xdr, - struct nfs41_secinfo_no_name_args *args) -{ - struct compound_hdr hdr = { - .minorversion = nfs4_xdr_minorversion(&args->seq_args), - }; - - encode_compound_hdr(xdr, req, &hdr); - encode_sequence(xdr, &args->seq_args, &hdr); - encode_putrootfh(xdr, &hdr); - encode_secinfo_no_name(xdr, args, &hdr); - encode_nops(&hdr); - return 0; -} - -/* - * Encode TEST_STATEID request - */ -static void nfs4_xdr_enc_test_stateid(struct rpc_rqst *req, - struct xdr_stream *xdr, - struct nfs41_test_stateid_args *args) -{ - struct compound_hdr hdr = { - .minorversion = nfs4_xdr_minorversion(&args->seq_args), - }; - - encode_compound_hdr(xdr, req, &hdr); - encode_sequence(xdr, &args->seq_args, &hdr); - encode_test_stateid(xdr, args, &hdr); - encode_nops(&hdr); -} - -/* - * Encode FREE_STATEID request - */ -static void nfs4_xdr_enc_free_stateid(struct rpc_rqst *req, - struct xdr_stream *xdr, - struct nfs41_free_stateid_args *args) -{ - struct compound_hdr hdr = { - .minorversion = nfs4_xdr_minorversion(&args->seq_args), - }; - - encode_compound_hdr(xdr, req, &hdr); - encode_sequence(xdr, &args->seq_args, &hdr); - encode_free_stateid(xdr, args, &hdr); - encode_nops(&hdr); -} #endif /* CONFIG_NFS_V4_1 */ static void print_overflow_msg(const char *func, const struct xdr_stream *xdr) @@ -5098,17 +4977,11 @@ static int decode_exchange_id(struct xdr_stream *xdr, if (unlikely(status)) return status; - /* Save server_scope */ + /* Throw away server_scope */ status = decode_opaque_inline(xdr, &dummy, &dummy_str); if (unlikely(status)) return status; - if (unlikely(dummy > NFS4_OPAQUE_LIMIT)) - return -EIO; - - memcpy(res->server_scope->server_scope, dummy_str, dummy); - res->server_scope->server_scope_sz = dummy; - /* Throw away Implementation id array */ status = decode_opaque_inline(xdr, &dummy, &dummy_str); if (unlikely(status)) @@ -5449,55 +5322,6 @@ static int decode_layoutcommit(struct xdr_stream *xdr, print_overflow_msg(__func__, xdr); return -EIO; } - -static int decode_test_stateid(struct xdr_stream *xdr, - struct nfs41_test_stateid_res *res) -{ - __be32 *p; - int status; - int num_res; - - status = decode_op_hdr(xdr, OP_TEST_STATEID); - if (status) - return status; - - p = xdr_inline_decode(xdr, 4); - if (unlikely(!p)) - goto out_overflow; - num_res = be32_to_cpup(p++); - if (num_res != 1) - goto out; - - p = xdr_inline_decode(xdr, 4); - if (unlikely(!p)) - goto out_overflow; - res->status = be32_to_cpup(p++); - return res->status; -out_overflow: - print_overflow_msg(__func__, xdr); -out: - return -EIO; -} - -static int decode_free_stateid(struct xdr_stream *xdr, - struct nfs41_free_stateid_res *res) -{ - __be32 *p; - int status; - - status = decode_op_hdr(xdr, OP_FREE_STATEID); - if (status) - return status; - - p = xdr_inline_decode(xdr, 4); - if (unlikely(!p)) - goto out_overflow; - res->status = be32_to_cpup(p++); - return res->status; -out_overflow: - print_overflow_msg(__func__, xdr); - return -EIO; -} #endif /* CONFIG_NFS_V4_1 */ /* @@ -6637,72 +6461,6 @@ static int nfs4_xdr_dec_layoutcommit(struct rpc_rqst *rqstp, out: return status; } - -/* - * Decode SECINFO_NO_NAME response - */ -static int nfs4_xdr_dec_secinfo_no_name(struct rpc_rqst *rqstp, - struct xdr_stream *xdr, - struct nfs4_secinfo_res *res) -{ - struct compound_hdr hdr; - int status; - - status = decode_compound_hdr(xdr, &hdr); - if (status) - goto out; - status = decode_sequence(xdr, &res->seq_res, rqstp); - if (status) - goto out; - status = decode_putrootfh(xdr); - if (status) - goto out; - status = decode_secinfo(xdr, res); -out: - return status; -} - -/* - * Decode TEST_STATEID response - */ -static int nfs4_xdr_dec_test_stateid(struct rpc_rqst *rqstp, - struct xdr_stream *xdr, - struct nfs41_test_stateid_res *res) -{ - struct compound_hdr hdr; - int status; - - status = decode_compound_hdr(xdr, &hdr); - if (status) - goto out; - status = decode_sequence(xdr, &res->seq_res, rqstp); - if (status) - goto out; - status = decode_test_stateid(xdr, res); -out: - return status; -} - -/* - * Decode FREE_STATEID response - */ -static int nfs4_xdr_dec_free_stateid(struct rpc_rqst *rqstp, - struct xdr_stream *xdr, - struct nfs41_free_stateid_res *res) -{ - struct compound_hdr hdr; - int status; - - status = decode_compound_hdr(xdr, &hdr); - if (status) - goto out; - status = decode_sequence(xdr, &res->seq_res, rqstp); - if (status) - goto out; - status = decode_free_stateid(xdr, res); -out: - return status; -} #endif /* CONFIG_NFS_V4_1 */ /** @@ -6905,9 +6663,6 @@ struct rpc_procinfo nfs4_procedures[] = { PROC(LAYOUTGET, enc_layoutget, dec_layoutget), PROC(LAYOUTCOMMIT, enc_layoutcommit, dec_layoutcommit), PROC(LAYOUTRETURN, enc_layoutreturn, dec_layoutreturn), - PROC(SECINFO_NO_NAME, enc_secinfo_no_name, dec_secinfo_no_name), - PROC(TEST_STATEID, enc_test_stateid, dec_test_stateid), - PROC(FREE_STATEID, enc_free_stateid, dec_free_stateid), #endif /* CONFIG_NFS_V4_1 */ }; diff --git a/trunk/fs/nfs/objlayout/objio_osd.c b/trunk/fs/nfs/objlayout/objio_osd.c index 9383ca7245bc..8ff2ea3f10ef 100644 --- a/trunk/fs/nfs/objlayout/objio_osd.c +++ b/trunk/fs/nfs/objlayout/objio_osd.c @@ -1000,22 +1000,13 @@ static bool objio_pg_test(struct nfs_pageio_descriptor *pgio, if (!pnfs_generic_pg_test(pgio, prev, req)) return false; + if (pgio->pg_lseg == NULL) + return true; + return pgio->pg_count + req->wb_bytes <= OBJIO_LSEG(pgio->pg_lseg)->max_io_size; } -static const struct nfs_pageio_ops objio_pg_read_ops = { - .pg_init = pnfs_generic_pg_init_read, - .pg_test = objio_pg_test, - .pg_doio = pnfs_generic_pg_readpages, -}; - -static const struct nfs_pageio_ops objio_pg_write_ops = { - .pg_init = pnfs_generic_pg_init_write, - .pg_test = objio_pg_test, - .pg_doio = pnfs_generic_pg_writepages, -}; - static struct pnfs_layoutdriver_type objlayout_type = { .id = LAYOUT_OSD2_OBJECTS, .name = "LAYOUT_OSD2_OBJECTS", @@ -1029,8 +1020,7 @@ static struct pnfs_layoutdriver_type objlayout_type = { .read_pagelist = objlayout_read_pagelist, .write_pagelist = objlayout_write_pagelist, - .pg_read_ops = &objio_pg_read_ops, - .pg_write_ops = &objio_pg_write_ops, + .pg_test = objio_pg_test, .free_deviceid_node = objio_free_deviceid_node, @@ -1065,7 +1055,5 @@ objlayout_exit(void) __func__); } -MODULE_ALIAS("nfs-layouttype4-2"); - module_init(objlayout_init); module_exit(objlayout_exit); diff --git a/trunk/fs/nfs/pagelist.c b/trunk/fs/nfs/pagelist.c index b60970cc7f1f..18449f43c568 100644 --- a/trunk/fs/nfs/pagelist.c +++ b/trunk/fs/nfs/pagelist.c @@ -230,7 +230,7 @@ EXPORT_SYMBOL_GPL(nfs_generic_pg_test); */ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, struct inode *inode, - const struct nfs_pageio_ops *pg_ops, + int (*doio)(struct nfs_pageio_descriptor *), size_t bsize, int io_flags) { @@ -240,12 +240,13 @@ void nfs_pageio_init(struct nfs_pageio_descriptor *desc, desc->pg_bsize = bsize; desc->pg_base = 0; desc->pg_moreio = 0; - desc->pg_recoalesce = 0; desc->pg_inode = inode; - desc->pg_ops = pg_ops; + desc->pg_doio = doio; desc->pg_ioflags = io_flags; desc->pg_error = 0; desc->pg_lseg = NULL; + desc->pg_test = nfs_generic_pg_test; + pnfs_pageio_init(desc, inode); } /** @@ -275,7 +276,7 @@ static bool nfs_can_coalesce_requests(struct nfs_page *prev, return false; if (prev->wb_pgbase + prev->wb_bytes != PAGE_CACHE_SIZE) return false; - return pgio->pg_ops->pg_test(pgio, prev, req); + return pgio->pg_test(pgio, prev, req); } /** @@ -296,8 +297,6 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, if (!nfs_can_coalesce_requests(prev, req, desc)) return 0; } else { - if (desc->pg_ops->pg_init) - desc->pg_ops->pg_init(desc, req); desc->pg_base = req->wb_pgbase; } nfs_list_remove_request(req); @@ -312,7 +311,7 @@ static int nfs_pageio_do_add_request(struct nfs_pageio_descriptor *desc, static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) { if (!list_empty(&desc->pg_list)) { - int error = desc->pg_ops->pg_doio(desc); + int error = desc->pg_doio(desc); if (error < 0) desc->pg_error = error; else @@ -332,7 +331,7 @@ static void nfs_pageio_doio(struct nfs_pageio_descriptor *desc) * Returns true if the request 'req' was successfully coalesced into the * existing list of pages 'desc'. */ -static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, +int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, struct nfs_page *req) { while (!nfs_pageio_do_add_request(desc, req)) { @@ -341,67 +340,17 @@ static int __nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, if (desc->pg_error < 0) return 0; desc->pg_moreio = 0; - if (desc->pg_recoalesce) - return 0; } return 1; } -static int nfs_do_recoalesce(struct nfs_pageio_descriptor *desc) -{ - LIST_HEAD(head); - - do { - list_splice_init(&desc->pg_list, &head); - desc->pg_bytes_written -= desc->pg_count; - desc->pg_count = 0; - desc->pg_base = 0; - desc->pg_recoalesce = 0; - - while (!list_empty(&head)) { - struct nfs_page *req; - - req = list_first_entry(&head, struct nfs_page, wb_list); - nfs_list_remove_request(req); - if (__nfs_pageio_add_request(desc, req)) - continue; - if (desc->pg_error < 0) - return 0; - break; - } - } while (desc->pg_recoalesce); - return 1; -} - -int nfs_pageio_add_request(struct nfs_pageio_descriptor *desc, - struct nfs_page *req) -{ - int ret; - - do { - ret = __nfs_pageio_add_request(desc, req); - if (ret) - break; - if (desc->pg_error < 0) - break; - ret = nfs_do_recoalesce(desc); - } while (ret); - return ret; -} - /** * nfs_pageio_complete - Complete I/O on an nfs_pageio_descriptor * @desc: pointer to io descriptor */ void nfs_pageio_complete(struct nfs_pageio_descriptor *desc) { - for (;;) { - nfs_pageio_doio(desc); - if (!desc->pg_recoalesce) - break; - if (!nfs_do_recoalesce(desc)) - break; - } + nfs_pageio_doio(desc); } /** @@ -420,7 +369,7 @@ void nfs_pageio_cond_complete(struct nfs_pageio_descriptor *desc, pgoff_t index) if (!list_empty(&desc->pg_list)) { struct nfs_page *prev = nfs_list_entry(desc->pg_list.prev); if (index != prev->wb_index + 1) - nfs_pageio_complete(desc); + nfs_pageio_doio(desc); } } diff --git a/trunk/fs/nfs/pnfs.c b/trunk/fs/nfs/pnfs.c index 38e5508555c6..29c0ca7fc347 100644 --- a/trunk/fs/nfs/pnfs.c +++ b/trunk/fs/nfs/pnfs.c @@ -28,7 +28,6 @@ */ #include -#include #include "internal.h" #include "pnfs.h" #include "iostat.h" @@ -449,20 +448,11 @@ pnfs_destroy_layout(struct nfs_inode *nfsi) void pnfs_destroy_all_layouts(struct nfs_client *clp) { - struct nfs_server *server; struct pnfs_layout_hdr *lo; LIST_HEAD(tmp_list); - nfs4_deviceid_mark_client_invalid(clp); - nfs4_deviceid_purge_client(clp); - spin_lock(&clp->cl_lock); - rcu_read_lock(); - list_for_each_entry_rcu(server, &clp->cl_superblocks, client_link) { - if (!list_empty(&server->layouts)) - list_splice_init(&server->layouts, &tmp_list); - } - rcu_read_unlock(); + list_splice_init(&clp->cl_layouts, &tmp_list); spin_unlock(&clp->cl_lock); while (!list_empty(&tmp_list)) { @@ -671,7 +661,6 @@ _pnfs_return_layout(struct inode *ino) lrp->args.stateid = stateid; lrp->args.layout_type = NFS_SERVER(ino)->pnfs_curr_ld->id; lrp->args.inode = ino; - lrp->args.layout = lo; lrp->clp = NFS_SERVER(ino)->nfs_client; status = nfs4_proc_layoutreturn(lrp); @@ -931,8 +920,7 @@ pnfs_update_layout(struct inode *ino, }; unsigned pg_offset; struct nfs_inode *nfsi = NFS_I(ino); - struct nfs_server *server = NFS_SERVER(ino); - struct nfs_client *clp = server->nfs_client; + struct nfs_client *clp = NFS_SERVER(ino)->nfs_client; struct pnfs_layout_hdr *lo; struct pnfs_layout_segment *lseg = NULL; bool first = false; @@ -976,7 +964,7 @@ pnfs_update_layout(struct inode *ino, */ spin_lock(&clp->cl_lock); BUG_ON(!list_empty(&lo->plh_layouts)); - list_add_tail(&lo->plh_layouts, &server->layouts); + list_add_tail(&lo->plh_layouts, &clp->cl_layouts); spin_unlock(&clp->cl_lock); } @@ -985,8 +973,7 @@ pnfs_update_layout(struct inode *ino, arg.offset -= pg_offset; arg.length += pg_offset; } - if (arg.length != NFS4_MAX_UINT64) - arg.length = PAGE_CACHE_ALIGN(arg.length); + arg.length = PAGE_CACHE_ALIGN(arg.length); lseg = send_layoutget(lo, ctx, &arg, gfp_flags); if (!lseg && first) { @@ -1004,7 +991,6 @@ pnfs_update_layout(struct inode *ino, spin_unlock(&ino->i_lock); goto out; } -EXPORT_SYMBOL_GPL(pnfs_update_layout); int pnfs_layout_process(struct nfs4_layoutget *lgp) @@ -1062,71 +1048,35 @@ pnfs_layout_process(struct nfs4_layoutget *lgp) goto out; } -void -pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) -{ - BUG_ON(pgio->pg_lseg != NULL); - - pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, - req->wb_context, - req_offset(req), - req->wb_bytes, - IOMODE_READ, - GFP_KERNEL); - /* If no lseg, fall back to read through mds */ - if (pgio->pg_lseg == NULL) - nfs_pageio_reset_read_mds(pgio); - -} -EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_read); - -void -pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *pgio, struct nfs_page *req) -{ - BUG_ON(pgio->pg_lseg != NULL); - - pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, - req->wb_context, - req_offset(req), - req->wb_bytes, - IOMODE_RW, - GFP_NOFS); - /* If no lseg, fall back to write through mds */ - if (pgio->pg_lseg == NULL) - nfs_pageio_reset_write_mds(pgio); -} -EXPORT_SYMBOL_GPL(pnfs_generic_pg_init_write); - -bool -pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode) -{ - struct nfs_server *server = NFS_SERVER(inode); - struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld; - - if (ld == NULL) - return false; - nfs_pageio_init(pgio, inode, ld->pg_read_ops, server->rsize, 0); - return true; -} - -bool -pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags) -{ - struct nfs_server *server = NFS_SERVER(inode); - struct pnfs_layoutdriver_type *ld = server->pnfs_curr_ld; - - if (ld == NULL) - return false; - nfs_pageio_init(pgio, inode, ld->pg_write_ops, server->wsize, ioflags); - return true; -} - bool pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, struct nfs_page *req) { - if (pgio->pg_lseg == NULL) - return nfs_generic_pg_test(pgio, prev, req); + enum pnfs_iomode access_type; + gfp_t gfp_flags; + + /* We assume that pg_ioflags == 0 iff we're reading a page */ + if (pgio->pg_ioflags == 0) { + access_type = IOMODE_READ; + gfp_flags = GFP_KERNEL; + } else { + access_type = IOMODE_RW; + gfp_flags = GFP_NOFS; + } + + if (pgio->pg_lseg == NULL) { + if (pgio->pg_count != prev->wb_bytes) + return true; + /* This is first coelesce call for a series of nfs_pages */ + pgio->pg_lseg = pnfs_update_layout(pgio->pg_inode, + prev->wb_context, + req_offset(prev), + pgio->pg_count, + access_type, + gfp_flags); + if (pgio->pg_lseg == NULL) + return true; + } /* * Test if a nfs_page is fully contained in the pnfs_layout_range. @@ -1170,30 +1120,15 @@ pnfs_ld_write_done(struct nfs_write_data *data) } EXPORT_SYMBOL_GPL(pnfs_ld_write_done); -static void -pnfs_write_through_mds(struct nfs_pageio_descriptor *desc, - struct nfs_write_data *data) -{ - list_splice_tail_init(&data->pages, &desc->pg_list); - if (data->req && list_empty(&data->req->wb_list)) - nfs_list_add_request(data->req, &desc->pg_list); - nfs_pageio_reset_write_mds(desc); - desc->pg_recoalesce = 1; - nfs_writedata_release(data); -} - -static enum pnfs_try_status +enum pnfs_try_status pnfs_try_to_write_data(struct nfs_write_data *wdata, - const struct rpc_call_ops *call_ops, - struct pnfs_layout_segment *lseg, - int how) + const struct rpc_call_ops *call_ops, int how) { struct inode *inode = wdata->inode; enum pnfs_try_status trypnfs; struct nfs_server *nfss = NFS_SERVER(inode); wdata->mds_ops = call_ops; - wdata->lseg = get_lseg(lseg); dprintk("%s: Writing ino:%lu %u@%llu (how %d)\n", __func__, inode->i_ino, wdata->args.count, wdata->args.offset, how); @@ -1209,44 +1144,6 @@ pnfs_try_to_write_data(struct nfs_write_data *wdata, return trypnfs; } -static void -pnfs_do_multiple_writes(struct nfs_pageio_descriptor *desc, struct list_head *head, int how) -{ - struct nfs_write_data *data; - const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; - struct pnfs_layout_segment *lseg = desc->pg_lseg; - - desc->pg_lseg = NULL; - while (!list_empty(head)) { - enum pnfs_try_status trypnfs; - - data = list_entry(head->next, struct nfs_write_data, list); - list_del_init(&data->list); - - trypnfs = pnfs_try_to_write_data(data, call_ops, lseg, how); - if (trypnfs == PNFS_NOT_ATTEMPTED) - pnfs_write_through_mds(desc, data); - } - put_lseg(lseg); -} - -int -pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) -{ - LIST_HEAD(head); - int ret; - - ret = nfs_generic_flush(desc, &head); - if (ret != 0) { - put_lseg(desc->pg_lseg); - desc->pg_lseg = NULL; - return ret; - } - pnfs_do_multiple_writes(desc, &head, desc->pg_ioflags); - return 0; -} -EXPORT_SYMBOL_GPL(pnfs_generic_pg_writepages); - /* * Called by non rpc-based layout drivers */ @@ -1270,32 +1167,18 @@ pnfs_ld_read_done(struct nfs_read_data *data) } EXPORT_SYMBOL_GPL(pnfs_ld_read_done); -static void -pnfs_read_through_mds(struct nfs_pageio_descriptor *desc, - struct nfs_read_data *data) -{ - list_splice_tail_init(&data->pages, &desc->pg_list); - if (data->req && list_empty(&data->req->wb_list)) - nfs_list_add_request(data->req, &desc->pg_list); - nfs_pageio_reset_read_mds(desc); - desc->pg_recoalesce = 1; - nfs_readdata_release(data); -} - /* * Call the appropriate parallel I/O subsystem read function. */ -static enum pnfs_try_status +enum pnfs_try_status pnfs_try_to_read_data(struct nfs_read_data *rdata, - const struct rpc_call_ops *call_ops, - struct pnfs_layout_segment *lseg) + const struct rpc_call_ops *call_ops) { struct inode *inode = rdata->inode; struct nfs_server *nfss = NFS_SERVER(inode); enum pnfs_try_status trypnfs; rdata->mds_ops = call_ops; - rdata->lseg = get_lseg(lseg); dprintk("%s: Reading ino:%lu %u@%llu\n", __func__, inode->i_ino, rdata->args.count, rdata->args.offset); @@ -1311,44 +1194,6 @@ pnfs_try_to_read_data(struct nfs_read_data *rdata, return trypnfs; } -static void -pnfs_do_multiple_reads(struct nfs_pageio_descriptor *desc, struct list_head *head) -{ - struct nfs_read_data *data; - const struct rpc_call_ops *call_ops = desc->pg_rpc_callops; - struct pnfs_layout_segment *lseg = desc->pg_lseg; - - desc->pg_lseg = NULL; - while (!list_empty(head)) { - enum pnfs_try_status trypnfs; - - data = list_entry(head->next, struct nfs_read_data, list); - list_del_init(&data->list); - - trypnfs = pnfs_try_to_read_data(data, call_ops, lseg); - if (trypnfs == PNFS_NOT_ATTEMPTED) - pnfs_read_through_mds(desc, data); - } - put_lseg(lseg); -} - -int -pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) -{ - LIST_HEAD(head); - int ret; - - ret = nfs_generic_pagein(desc, &head); - if (ret != 0) { - put_lseg(desc->pg_lseg); - desc->pg_lseg = NULL; - return ret; - } - pnfs_do_multiple_reads(desc, &head); - return 0; -} -EXPORT_SYMBOL_GPL(pnfs_generic_pg_readpages); - /* * Currently there is only one (whole file) write lseg. */ diff --git a/trunk/fs/nfs/pnfs.h b/trunk/fs/nfs/pnfs.h index 078670dfbe04..96bf4e6f45be 100644 --- a/trunk/fs/nfs/pnfs.h +++ b/trunk/fs/nfs/pnfs.h @@ -87,8 +87,7 @@ struct pnfs_layoutdriver_type { void (*free_lseg) (struct pnfs_layout_segment *lseg); /* test for nfs page cache coalescing */ - const struct nfs_pageio_ops *pg_read_ops; - const struct nfs_pageio_ops *pg_write_ops; + bool (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *); /* Returns true if layoutdriver wants to divert this request to * driver's commit routine. @@ -149,16 +148,16 @@ extern int nfs4_proc_layoutreturn(struct nfs4_layoutreturn *lrp); /* pnfs.c */ void get_layout_hdr(struct pnfs_layout_hdr *lo); void put_lseg(struct pnfs_layout_segment *lseg); - -bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *, struct inode *); -bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *, struct inode *, int); - +struct pnfs_layout_segment * +pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx, + loff_t pos, u64 count, enum pnfs_iomode access_type, + gfp_t gfp_flags); void set_pnfs_layoutdriver(struct nfs_server *, u32 id); void unset_pnfs_layoutdriver(struct nfs_server *); -void pnfs_generic_pg_init_read(struct nfs_pageio_descriptor *, struct nfs_page *); -int pnfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc); -void pnfs_generic_pg_init_write(struct nfs_pageio_descriptor *, struct nfs_page *); -int pnfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc); +enum pnfs_try_status pnfs_try_to_write_data(struct nfs_write_data *, + const struct rpc_call_ops *, int); +enum pnfs_try_status pnfs_try_to_read_data(struct nfs_read_data *, + const struct rpc_call_ops *); bool pnfs_generic_pg_test(struct nfs_pageio_descriptor *pgio, struct nfs_page *prev, struct nfs_page *req); int pnfs_layout_process(struct nfs4_layoutget *lgp); void pnfs_free_lseg_list(struct list_head *tmp_list); @@ -183,19 +182,6 @@ int pnfs_layoutcommit_inode(struct inode *inode, bool sync); int _pnfs_return_layout(struct inode *); int pnfs_ld_write_done(struct nfs_write_data *); int pnfs_ld_read_done(struct nfs_read_data *); -struct pnfs_layout_segment *pnfs_update_layout(struct inode *ino, - struct nfs_open_context *ctx, - loff_t pos, - u64 count, - enum pnfs_iomode iomode, - gfp_t gfp_flags); - -void nfs4_deviceid_mark_client_invalid(struct nfs_client *clp); - -/* nfs4_deviceid_flags */ -enum { - NFS_DEVICEID_INVALID = 0, /* set when MDS clientid recalled */ -}; /* pnfs_dev.c */ struct nfs4_deviceid_node { @@ -203,13 +189,13 @@ struct nfs4_deviceid_node { struct hlist_node tmpnode; const struct pnfs_layoutdriver_type *ld; const struct nfs_client *nfs_client; - unsigned long flags; struct nfs4_deviceid deviceid; atomic_t ref; }; void nfs4_print_deviceid(const struct nfs4_deviceid *dev_id); struct nfs4_deviceid_node *nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *); +struct nfs4_deviceid_node *nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *); void nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *, const struct nfs_client *, const struct nfs4_deviceid *); void nfs4_init_deviceid_node(struct nfs4_deviceid_node *, const struct pnfs_layoutdriver_type *, @@ -307,6 +293,15 @@ static inline int pnfs_return_layout(struct inode *ino) return 0; } +static inline void pnfs_pageio_init(struct nfs_pageio_descriptor *pgio, + struct inode *inode) +{ + struct pnfs_layoutdriver_type *ld = NFS_SERVER(inode)->pnfs_curr_ld; + + if (ld) + pgio->pg_test = ld->pg_test; +} + #else /* CONFIG_NFS_V4_1 */ static inline void pnfs_destroy_all_layouts(struct nfs_client *clp) @@ -327,6 +322,28 @@ static inline void put_lseg(struct pnfs_layout_segment *lseg) { } +static inline struct pnfs_layout_segment * +pnfs_update_layout(struct inode *ino, struct nfs_open_context *ctx, + loff_t pos, u64 count, enum pnfs_iomode access_type, + gfp_t gfp_flags) +{ + return NULL; +} + +static inline enum pnfs_try_status +pnfs_try_to_read_data(struct nfs_read_data *data, + const struct rpc_call_ops *call_ops) +{ + return PNFS_NOT_ATTEMPTED; +} + +static inline enum pnfs_try_status +pnfs_try_to_write_data(struct nfs_write_data *data, + const struct rpc_call_ops *call_ops, int how) +{ + return PNFS_NOT_ATTEMPTED; +} + static inline int pnfs_return_layout(struct inode *ino) { return 0; @@ -368,14 +385,9 @@ static inline void unset_pnfs_layoutdriver(struct nfs_server *s) { } -static inline bool pnfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, struct inode *inode) +static inline void pnfs_pageio_init(struct nfs_pageio_descriptor *pgio, + struct inode *inode) { - return false; -} - -static inline bool pnfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags) -{ - return false; } static inline void diff --git a/trunk/fs/nfs/pnfs_dev.c b/trunk/fs/nfs/pnfs_dev.c index 6fda5228ef56..f0f8e1e22f6c 100644 --- a/trunk/fs/nfs/pnfs_dev.c +++ b/trunk/fs/nfs/pnfs_dev.c @@ -100,8 +100,8 @@ _find_get_deviceid(const struct pnfs_layoutdriver_type *ld, rcu_read_lock(); d = _lookup_deviceid(ld, clp, id, hash); - if (d != NULL) - atomic_inc(&d->ref); + if (d && !atomic_inc_not_zero(&d->ref)) + d = NULL; rcu_read_unlock(); return d; } @@ -115,15 +115,15 @@ nfs4_find_get_deviceid(const struct pnfs_layoutdriver_type *ld, EXPORT_SYMBOL_GPL(nfs4_find_get_deviceid); /* - * Remove a deviceid from cache + * Unhash and put deviceid * * @clp nfs_client associated with deviceid * @id the deviceid to unhash * * @ret the unhashed node, if found and dereferenced to zero, NULL otherwise. */ -void -nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld, +struct nfs4_deviceid_node * +nfs4_unhash_put_deviceid(const struct pnfs_layoutdriver_type *ld, const struct nfs_client *clp, const struct nfs4_deviceid *id) { struct nfs4_deviceid_node *d; @@ -134,7 +134,7 @@ nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld, rcu_read_unlock(); if (!d) { spin_unlock(&nfs4_deviceid_lock); - return; + return NULL; } hlist_del_init_rcu(&d->node); spin_unlock(&nfs4_deviceid_lock); @@ -142,7 +142,28 @@ nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld, /* balance the initial ref set in pnfs_insert_deviceid */ if (atomic_dec_and_test(&d->ref)) - d->ld->free_deviceid_node(d); + return d; + + return NULL; +} +EXPORT_SYMBOL_GPL(nfs4_unhash_put_deviceid); + +/* + * Delete a deviceid from cache + * + * @clp struct nfs_client qualifying the deviceid + * @id deviceid to delete + */ +void +nfs4_delete_deviceid(const struct pnfs_layoutdriver_type *ld, + const struct nfs_client *clp, const struct nfs4_deviceid *id) +{ + struct nfs4_deviceid_node *d; + + d = nfs4_unhash_put_deviceid(ld, clp, id); + if (!d) + return; + d->ld->free_deviceid_node(d); } EXPORT_SYMBOL_GPL(nfs4_delete_deviceid); @@ -156,7 +177,6 @@ nfs4_init_deviceid_node(struct nfs4_deviceid_node *d, INIT_HLIST_NODE(&d->tmpnode); d->ld = ld; d->nfs_client = nfs_client; - d->flags = 0; d->deviceid = *id; atomic_set(&d->ref, 1); } @@ -201,15 +221,16 @@ EXPORT_SYMBOL_GPL(nfs4_insert_deviceid_node); * * @d deviceid node to put * - * return true iff the node was deleted - * Note that since the test for d->ref == 0 is sufficient to establish - * that the node is no longer hashed in the global device id cache. + * @ret true iff the node was deleted */ bool nfs4_put_deviceid_node(struct nfs4_deviceid_node *d) { - if (!atomic_dec_and_test(&d->ref)) + if (!atomic_dec_and_lock(&d->ref, &nfs4_deviceid_lock)) return false; + hlist_del_init_rcu(&d->node); + spin_unlock(&nfs4_deviceid_lock); + synchronize_rcu(); d->ld->free_deviceid_node(d); return true; } @@ -254,22 +275,3 @@ nfs4_deviceid_purge_client(const struct nfs_client *clp) for (h = 0; h < NFS4_DEVICE_ID_HASH_SIZE; h++) _deviceid_purge_client(clp, h); } - -/* - * Stop use of all deviceids associated with an nfs_client - */ -void -nfs4_deviceid_mark_client_invalid(struct nfs_client *clp) -{ - struct nfs4_deviceid_node *d; - struct hlist_node *n; - int i; - - rcu_read_lock(); - for (i = 0; i < NFS4_DEVICE_ID_HASH_SIZE; i ++){ - hlist_for_each_entry_rcu(d, n, &nfs4_deviceid_cache[i], node) - if (d->nfs_client == clp) - set_bit(NFS_DEVICEID_INVALID, &d->flags); - } - rcu_read_unlock(); -} diff --git a/trunk/fs/nfs/read.c b/trunk/fs/nfs/read.c index 2171c043ab08..a68679f538fc 100644 --- a/trunk/fs/nfs/read.c +++ b/trunk/fs/nfs/read.c @@ -30,7 +30,8 @@ #define NFSDBG_FACILITY NFSDBG_PAGECACHE -static const struct nfs_pageio_ops nfs_pageio_read_ops; +static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc); +static int nfs_pagein_one(struct nfs_pageio_descriptor *desc); static const struct rpc_call_ops nfs_read_partial_ops; static const struct rpc_call_ops nfs_read_full_ops; @@ -67,7 +68,7 @@ void nfs_readdata_free(struct nfs_read_data *p) mempool_free(p, nfs_rdata_mempool); } -void nfs_readdata_release(struct nfs_read_data *rdata) +static void nfs_readdata_release(struct nfs_read_data *rdata) { put_lseg(rdata->lseg); put_nfs_open_context(rdata->args.context); @@ -112,27 +113,6 @@ static void nfs_readpage_truncate_uninitialised_page(struct nfs_read_data *data) } } -static void nfs_pageio_init_read_mds(struct nfs_pageio_descriptor *pgio, - struct inode *inode) -{ - nfs_pageio_init(pgio, inode, &nfs_pageio_read_ops, - NFS_SERVER(inode)->rsize, 0); -} - -void nfs_pageio_reset_read_mds(struct nfs_pageio_descriptor *pgio) -{ - pgio->pg_ops = &nfs_pageio_read_ops; - pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->rsize; -} -EXPORT_SYMBOL_GPL(nfs_pageio_reset_read_mds); - -static void nfs_pageio_init_read(struct nfs_pageio_descriptor *pgio, - struct inode *inode) -{ - if (!pnfs_pageio_init_read(pgio, inode)) - nfs_pageio_init_read_mds(pgio, inode); -} - int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, struct page *page) { @@ -151,9 +131,14 @@ int nfs_readpage_async(struct nfs_open_context *ctx, struct inode *inode, if (len < PAGE_CACHE_SIZE) zero_user_segment(page, len, PAGE_CACHE_SIZE); - nfs_pageio_init_read(&pgio, inode); - nfs_pageio_add_request(&pgio, new); - nfs_pageio_complete(&pgio); + nfs_pageio_init(&pgio, inode, NULL, 0, 0); + nfs_list_add_request(new, &pgio.pg_list); + pgio.pg_count = len; + + if (NFS_SERVER(inode)->rsize < PAGE_CACHE_SIZE) + nfs_pagein_multi(&pgio); + else + nfs_pagein_one(&pgio); return 0; } @@ -217,14 +202,17 @@ EXPORT_SYMBOL_GPL(nfs_initiate_read); /* * Set up the NFS read request struct */ -static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, - unsigned int count, unsigned int offset) +static int nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, + const struct rpc_call_ops *call_ops, + unsigned int count, unsigned int offset, + struct pnfs_layout_segment *lseg) { struct inode *inode = req->wb_context->dentry->d_inode; data->req = req; data->inode = inode; data->cred = req->wb_context->cred; + data->lseg = get_lseg(lseg); data->args.fh = NFS_FH(inode); data->args.offset = req_offset(req) + offset; @@ -238,36 +226,14 @@ static void nfs_read_rpcsetup(struct nfs_page *req, struct nfs_read_data *data, data->res.count = count; data->res.eof = 0; nfs_fattr_init(&data->fattr); -} -static int nfs_do_read(struct nfs_read_data *data, - const struct rpc_call_ops *call_ops) -{ - struct inode *inode = data->args.context->dentry->d_inode; + if (data->lseg && + (pnfs_try_to_read_data(data, call_ops) == PNFS_ATTEMPTED)) + return 0; return nfs_initiate_read(data, NFS_CLIENT(inode), call_ops); } -static int -nfs_do_multiple_reads(struct list_head *head, - const struct rpc_call_ops *call_ops) -{ - struct nfs_read_data *data; - int ret = 0; - - while (!list_empty(head)) { - int ret2; - - data = list_entry(head->next, struct nfs_read_data, list); - list_del_init(&data->list); - - ret2 = nfs_do_read(data, call_ops); - if (ret == 0) - ret = ret2; - } - return ret; -} - static void nfs_async_read_error(struct list_head *head) { @@ -294,19 +260,20 @@ nfs_async_read_error(struct list_head *head) * won't see the new data until our attribute cache is updated. This is more * or less conventional NFS client behavior. */ -static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head *res) +static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc) { struct nfs_page *req = nfs_list_entry(desc->pg_list.next); struct page *page = req->wb_page; struct nfs_read_data *data; - size_t rsize = desc->pg_bsize, nbytes; + size_t rsize = NFS_SERVER(desc->pg_inode)->rsize, nbytes; unsigned int offset; int requests = 0; int ret = 0; + struct pnfs_layout_segment *lseg; + LIST_HEAD(list); nfs_list_remove_request(req); - offset = 0; nbytes = desc->pg_count; do { size_t len = min(nbytes,rsize); @@ -314,21 +281,45 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head data = nfs_readdata_alloc(1); if (!data) goto out_bad; - data->pagevec[0] = page; - nfs_read_rpcsetup(req, data, len, offset); - list_add(&data->list, res); + list_add(&data->pages, &list); requests++; nbytes -= len; - offset += len; } while(nbytes != 0); atomic_set(&req->wb_complete, requests); + + BUG_ON(desc->pg_lseg != NULL); + lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, + req_offset(req), desc->pg_count, + IOMODE_READ, GFP_KERNEL); ClearPageError(page); - desc->pg_rpc_callops = &nfs_read_partial_ops; + offset = 0; + nbytes = desc->pg_count; + do { + int ret2; + + data = list_entry(list.next, struct nfs_read_data, pages); + list_del_init(&data->pages); + + data->pagevec[0] = page; + + if (nbytes < rsize) + rsize = nbytes; + ret2 = nfs_read_rpcsetup(req, data, &nfs_read_partial_ops, + rsize, offset, lseg); + if (ret == 0) + ret = ret2; + offset += rsize; + nbytes -= rsize; + } while (nbytes != 0); + put_lseg(lseg); + desc->pg_lseg = NULL; + return ret; + out_bad: - while (!list_empty(res)) { - data = list_entry(res->next, struct nfs_read_data, list); - list_del(&data->list); + while (!list_empty(&list)) { + data = list_entry(list.next, struct nfs_read_data, pages); + list_del(&data->pages); nfs_readdata_free(data); } SetPageError(page); @@ -336,19 +327,19 @@ static int nfs_pagein_multi(struct nfs_pageio_descriptor *desc, struct list_head return -ENOMEM; } -static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, struct list_head *res) +static int nfs_pagein_one(struct nfs_pageio_descriptor *desc) { struct nfs_page *req; struct page **pages; struct nfs_read_data *data; struct list_head *head = &desc->pg_list; - int ret = 0; + struct pnfs_layout_segment *lseg = desc->pg_lseg; + int ret = -ENOMEM; data = nfs_readdata_alloc(nfs_page_array_len(desc->pg_base, desc->pg_count)); if (!data) { nfs_async_read_error(head); - ret = -ENOMEM; goto out; } @@ -361,37 +352,19 @@ static int nfs_pagein_one(struct nfs_pageio_descriptor *desc, struct list_head * *pages++ = req->wb_page; } req = nfs_list_entry(data->pages.next); + if ((!lseg) && list_is_singular(&data->pages)) + lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, + req_offset(req), desc->pg_count, + IOMODE_READ, GFP_KERNEL); - nfs_read_rpcsetup(req, data, desc->pg_count, 0); - list_add(&data->list, res); - desc->pg_rpc_callops = &nfs_read_full_ops; + ret = nfs_read_rpcsetup(req, data, &nfs_read_full_ops, desc->pg_count, + 0, lseg); out: + put_lseg(lseg); + desc->pg_lseg = NULL; return ret; } -int nfs_generic_pagein(struct nfs_pageio_descriptor *desc, struct list_head *head) -{ - if (desc->pg_bsize < PAGE_CACHE_SIZE) - return nfs_pagein_multi(desc, head); - return nfs_pagein_one(desc, head); -} - -static int nfs_generic_pg_readpages(struct nfs_pageio_descriptor *desc) -{ - LIST_HEAD(head); - int ret; - - ret = nfs_generic_pagein(desc, &head); - if (ret == 0) - ret = nfs_do_multiple_reads(&head, desc->pg_rpc_callops); - return ret; -} - -static const struct nfs_pageio_ops nfs_pageio_read_ops = { - .pg_test = nfs_generic_pg_test, - .pg_doio = nfs_generic_pg_readpages, -}; - /* * This is the callback from RPC telling us whether a reply was * received or some error occurred (timeout or socket shutdown). @@ -662,6 +635,8 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, .pgio = &pgio, }; struct inode *inode = mapping->host; + struct nfs_server *server = NFS_SERVER(inode); + size_t rsize = server->rsize; unsigned long npages; int ret = -ESTALE; @@ -689,7 +664,10 @@ int nfs_readpages(struct file *filp, struct address_space *mapping, if (ret == 0) goto read_complete; /* all pages were read */ - nfs_pageio_init_read(&pgio, inode); + if (rsize < PAGE_CACHE_SIZE) + nfs_pageio_init(&pgio, inode, nfs_pagein_multi, rsize, 0); + else + nfs_pageio_init(&pgio, inode, nfs_pagein_one, rsize, 0); ret = read_cache_pages(mapping, pages, readpage_async_filler, &desc); diff --git a/trunk/fs/nfs/unlink.c b/trunk/fs/nfs/unlink.c index b2fbbde58e44..8d6864c2a5fa 100644 --- a/trunk/fs/nfs/unlink.c +++ b/trunk/fs/nfs/unlink.c @@ -147,7 +147,7 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n alias = d_lookup(parent, &data->args.name); if (alias != NULL) { - int ret; + int ret = 0; void *devname_garbage = NULL; /* @@ -155,16 +155,14 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n * the sillyrename information to the aliased dentry. */ nfs_free_dname(data); - ret = nfs_copy_dname(alias, data); spin_lock(&alias->d_lock); - if (ret == 0 && alias->d_inode != NULL && + if (alias->d_inode != NULL && !(alias->d_flags & DCACHE_NFSFS_RENAMED)) { devname_garbage = alias->d_fsdata; alias->d_fsdata = data; alias->d_flags |= DCACHE_NFSFS_RENAMED; ret = 1; - } else - ret = 0; + } spin_unlock(&alias->d_lock); nfs_dec_sillycount(dir); dput(alias); @@ -173,7 +171,8 @@ static int nfs_do_call_unlink(struct dentry *parent, struct inode *dir, struct n * point dentry is definitely not a root, so we won't need * that anymore. */ - kfree(devname_garbage); + if (devname_garbage) + kfree(devname_garbage); return ret; } data->dir = igrab(dir); @@ -205,6 +204,8 @@ static int nfs_call_unlink(struct dentry *dentry, struct nfs_unlinkdata *data) if (parent == NULL) goto out_free; dir = parent->d_inode; + if (nfs_copy_dname(dentry, data) != 0) + goto out_dput; /* Non-exclusive lock protects against concurrent lookup() calls */ spin_lock(&dir->i_lock); if (atomic_inc_not_zero(&NFS_I(dir)->silly_count) == 0) { @@ -365,8 +366,6 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata) struct nfs_renamedata *data = calldata; struct inode *old_dir = data->old_dir; struct inode *new_dir = data->new_dir; - struct dentry *old_dentry = data->old_dentry; - struct dentry *new_dentry = data->new_dentry; if (!NFS_PROTO(old_dir)->rename_done(task, old_dir, new_dir)) { nfs_restart_rpc(task, NFS_SERVER(old_dir)->nfs_client); @@ -374,12 +373,12 @@ static void nfs_async_rename_done(struct rpc_task *task, void *calldata) } if (task->tk_status != 0) { - nfs_cancel_async_unlink(old_dentry); + nfs_cancel_async_unlink(data->old_dentry); return; } - d_drop(old_dentry); - d_drop(new_dentry); + nfs_set_verifier(data->old_dentry, nfs_save_change_attribute(old_dir)); + d_move(data->old_dentry, data->new_dentry); } /** @@ -502,14 +501,6 @@ nfs_async_rename(struct inode *old_dir, struct inode *new_dir, * and only performs the unlink once the last reference to it is put. * * The final cleanup is done during dentry_iput. - * - * (Note: NFSv4 is stateful, and has opens, so in theory an NFSv4 server - * could take responsibility for keeping open files referenced. The server - * would also need to ensure that opened-but-deleted files were kept over - * reboots. However, we may not assume a server does so. (RFC 5661 - * does provide an OPEN4_RESULT_PRESERVE_UNLINKED flag that a server can - * use to advertise that it does this; some day we may take advantage of - * it.)) */ int nfs_sillyrename(struct inode *dir, struct dentry *dentry) @@ -569,14 +560,6 @@ nfs_sillyrename(struct inode *dir, struct dentry *dentry) if (error) goto out_dput; - /* populate unlinkdata with the right dname */ - error = nfs_copy_dname(sdentry, - (struct nfs_unlinkdata *)dentry->d_fsdata); - if (error) { - nfs_cancel_async_unlink(dentry); - goto out_dput; - } - /* run the rename task, undo unlink if it fails */ task = nfs_async_rename(dir, dir, dentry, sdentry); if (IS_ERR(task)) { diff --git a/trunk/fs/nfs/write.c b/trunk/fs/nfs/write.c index b39b37f80913..00e37501fa3b 100644 --- a/trunk/fs/nfs/write.c +++ b/trunk/fs/nfs/write.c @@ -97,7 +97,7 @@ void nfs_writedata_free(struct nfs_write_data *p) mempool_free(p, nfs_wdata_mempool); } -void nfs_writedata_release(struct nfs_write_data *wdata) +static void nfs_writedata_release(struct nfs_write_data *wdata) { put_lseg(wdata->lseg); put_nfs_open_context(wdata->args.context); @@ -845,9 +845,11 @@ EXPORT_SYMBOL_GPL(nfs_initiate_write); /* * Set up the argument/result storage required for the RPC call. */ -static void nfs_write_rpcsetup(struct nfs_page *req, +static int nfs_write_rpcsetup(struct nfs_page *req, struct nfs_write_data *data, + const struct rpc_call_ops *call_ops, unsigned int count, unsigned int offset, + struct pnfs_layout_segment *lseg, int how) { struct inode *inode = req->wb_context->dentry->d_inode; @@ -858,6 +860,7 @@ static void nfs_write_rpcsetup(struct nfs_page *req, data->req = req; data->inode = inode = req->wb_context->dentry->d_inode; data->cred = req->wb_context->cred; + data->lseg = get_lseg(lseg); data->args.fh = NFS_FH(inode); data->args.offset = req_offset(req) + offset; @@ -869,51 +872,24 @@ static void nfs_write_rpcsetup(struct nfs_page *req, data->args.context = get_nfs_open_context(req->wb_context); data->args.lock_context = req->wb_lock_context; data->args.stable = NFS_UNSTABLE; - switch (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { - case 0: - break; - case FLUSH_COND_STABLE: - if (nfs_need_commit(NFS_I(inode))) - break; - default: - data->args.stable = NFS_FILE_SYNC; + if (how & (FLUSH_STABLE | FLUSH_COND_STABLE)) { + data->args.stable = NFS_DATA_SYNC; + if (!nfs_need_commit(NFS_I(inode))) + data->args.stable = NFS_FILE_SYNC; } data->res.fattr = &data->fattr; data->res.count = count; data->res.verf = &data->verf; nfs_fattr_init(&data->fattr); -} -static int nfs_do_write(struct nfs_write_data *data, - const struct rpc_call_ops *call_ops, - int how) -{ - struct inode *inode = data->args.context->dentry->d_inode; + if (data->lseg && + (pnfs_try_to_write_data(data, call_ops, how) == PNFS_ATTEMPTED)) + return 0; return nfs_initiate_write(data, NFS_CLIENT(inode), call_ops, how); } -static int nfs_do_multiple_writes(struct list_head *head, - const struct rpc_call_ops *call_ops, - int how) -{ - struct nfs_write_data *data; - int ret = 0; - - while (!list_empty(head)) { - int ret2; - - data = list_entry(head->next, struct nfs_write_data, list); - list_del_init(&data->list); - - ret2 = nfs_do_write(data, call_ops, how); - if (ret == 0) - ret = ret2; - } - return ret; -} - /* If a nfs_flush_* function fails, it should remove reqs from @head and * call this on each, which will prepare them to be retried on next * writeback using standard nfs. @@ -931,15 +907,17 @@ static void nfs_redirty_request(struct nfs_page *req) * Generate multiple small requests to write out a single * contiguous dirty area on one page. */ -static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head *res) +static int nfs_flush_multi(struct nfs_pageio_descriptor *desc) { struct nfs_page *req = nfs_list_entry(desc->pg_list.next); struct page *page = req->wb_page; struct nfs_write_data *data; - size_t wsize = desc->pg_bsize, nbytes; + size_t wsize = NFS_SERVER(desc->pg_inode)->wsize, nbytes; unsigned int offset; int requests = 0; int ret = 0; + struct pnfs_layout_segment *lseg; + LIST_HEAD(list); nfs_list_remove_request(req); @@ -949,7 +927,6 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head desc->pg_ioflags &= ~FLUSH_COND_STABLE; - offset = 0; nbytes = desc->pg_count; do { size_t len = min(nbytes, wsize); @@ -957,21 +934,45 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head data = nfs_writedata_alloc(1); if (!data) goto out_bad; - data->pagevec[0] = page; - nfs_write_rpcsetup(req, data, wsize, offset, desc->pg_ioflags); - list_add(&data->list, res); + list_add(&data->pages, &list); requests++; nbytes -= len; - offset += len; } while (nbytes != 0); atomic_set(&req->wb_complete, requests); - desc->pg_rpc_callops = &nfs_write_partial_ops; + + BUG_ON(desc->pg_lseg); + lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, + req_offset(req), desc->pg_count, + IOMODE_RW, GFP_NOFS); + ClearPageError(page); + offset = 0; + nbytes = desc->pg_count; + do { + int ret2; + + data = list_entry(list.next, struct nfs_write_data, pages); + list_del_init(&data->pages); + + data->pagevec[0] = page; + + if (nbytes < wsize) + wsize = nbytes; + ret2 = nfs_write_rpcsetup(req, data, &nfs_write_partial_ops, + wsize, offset, lseg, desc->pg_ioflags); + if (ret == 0) + ret = ret2; + offset += wsize; + nbytes -= wsize; + } while (nbytes != 0); + + put_lseg(lseg); + desc->pg_lseg = NULL; return ret; out_bad: - while (!list_empty(res)) { - data = list_entry(res->next, struct nfs_write_data, list); - list_del(&data->list); + while (!list_empty(&list)) { + data = list_entry(list.next, struct nfs_write_data, pages); + list_del(&data->pages); nfs_writedata_free(data); } nfs_redirty_request(req); @@ -986,13 +987,14 @@ static int nfs_flush_multi(struct nfs_pageio_descriptor *desc, struct list_head * This is the case if nfs_updatepage detects a conflicting request * that has been written but not committed. */ -static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *res) +static int nfs_flush_one(struct nfs_pageio_descriptor *desc) { struct nfs_page *req; struct page **pages; struct nfs_write_data *data; struct list_head *head = &desc->pg_list; - int ret = 0; + struct pnfs_layout_segment *lseg = desc->pg_lseg; + int ret; data = nfs_writedata_alloc(nfs_page_array_len(desc->pg_base, desc->pg_count)); @@ -1014,62 +1016,32 @@ static int nfs_flush_one(struct nfs_pageio_descriptor *desc, struct list_head *r *pages++ = req->wb_page; } req = nfs_list_entry(data->pages.next); + if ((!lseg) && list_is_singular(&data->pages)) + lseg = pnfs_update_layout(desc->pg_inode, req->wb_context, + req_offset(req), desc->pg_count, + IOMODE_RW, GFP_NOFS); if ((desc->pg_ioflags & FLUSH_COND_STABLE) && (desc->pg_moreio || NFS_I(desc->pg_inode)->ncommit)) desc->pg_ioflags &= ~FLUSH_COND_STABLE; /* Set up the argument struct */ - nfs_write_rpcsetup(req, data, desc->pg_count, 0, desc->pg_ioflags); - list_add(&data->list, res); - desc->pg_rpc_callops = &nfs_write_full_ops; + ret = nfs_write_rpcsetup(req, data, &nfs_write_full_ops, desc->pg_count, 0, lseg, desc->pg_ioflags); out: + put_lseg(lseg); /* Cleans any gotten in ->pg_test */ + desc->pg_lseg = NULL; return ret; } -int nfs_generic_flush(struct nfs_pageio_descriptor *desc, struct list_head *head) -{ - if (desc->pg_bsize < PAGE_CACHE_SIZE) - return nfs_flush_multi(desc, head); - return nfs_flush_one(desc, head); -} - -static int nfs_generic_pg_writepages(struct nfs_pageio_descriptor *desc) -{ - LIST_HEAD(head); - int ret; - - ret = nfs_generic_flush(desc, &head); - if (ret == 0) - ret = nfs_do_multiple_writes(&head, desc->pg_rpc_callops, - desc->pg_ioflags); - return ret; -} - -static const struct nfs_pageio_ops nfs_pageio_write_ops = { - .pg_test = nfs_generic_pg_test, - .pg_doio = nfs_generic_pg_writepages, -}; - -static void nfs_pageio_init_write_mds(struct nfs_pageio_descriptor *pgio, - struct inode *inode, int ioflags) -{ - nfs_pageio_init(pgio, inode, &nfs_pageio_write_ops, - NFS_SERVER(inode)->wsize, ioflags); -} - -void nfs_pageio_reset_write_mds(struct nfs_pageio_descriptor *pgio) -{ - pgio->pg_ops = &nfs_pageio_write_ops; - pgio->pg_bsize = NFS_SERVER(pgio->pg_inode)->wsize; -} -EXPORT_SYMBOL_GPL(nfs_pageio_reset_write_mds); - static void nfs_pageio_init_write(struct nfs_pageio_descriptor *pgio, struct inode *inode, int ioflags) { - if (!pnfs_pageio_init_write(pgio, inode, ioflags)) - nfs_pageio_init_write_mds(pgio, inode, ioflags); + size_t wsize = NFS_SERVER(inode)->wsize; + + if (wsize < PAGE_CACHE_SIZE) + nfs_pageio_init(pgio, inode, nfs_flush_multi, wsize, ioflags); + else + nfs_pageio_init(pgio, inode, nfs_flush_one, wsize, ioflags); } /* diff --git a/trunk/fs/omfs/dir.c b/trunk/fs/omfs/dir.c index 98e544274390..3b8d3979e03b 100644 --- a/trunk/fs/omfs/dir.c +++ b/trunk/fs/omfs/dir.c @@ -93,7 +93,7 @@ int omfs_make_empty(struct inode *inode, struct super_block *sb) memset(bh->b_data, 0, sizeof(struct omfs_inode)); - if (S_ISDIR(inode->i_mode)) { + if (inode->i_mode & S_IFDIR) { memset(&bh->b_data[OMFS_DIR_START], 0xff, sbi->s_sys_blocksize - OMFS_DIR_START); } else diff --git a/trunk/fs/open.c b/trunk/fs/open.c index f71192109457..739b751aa73e 100644 --- a/trunk/fs/open.c +++ b/trunk/fs/open.c @@ -446,52 +446,74 @@ SYSCALL_DEFINE1(chroot, const char __user *, filename) return error; } -static int chmod_common(struct path *path, umode_t mode) +SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) { - struct inode *inode = path->dentry->d_inode; + struct inode * inode; + struct dentry * dentry; + struct file * file; + int err = -EBADF; struct iattr newattrs; - int error; - error = mnt_want_write(path->mnt); - if (error) - return error; + file = fget(fd); + if (!file) + goto out; + + dentry = file->f_path.dentry; + inode = dentry->d_inode; + + audit_inode(NULL, dentry); + + err = mnt_want_write_file(file); + if (err) + goto out_putf; mutex_lock(&inode->i_mutex); - error = security_path_chmod(path->dentry, path->mnt, mode); - if (error) + err = security_path_chmod(dentry, file->f_vfsmnt, mode); + if (err) goto out_unlock; + if (mode == (mode_t) -1) + mode = inode->i_mode; newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; - error = notify_change(path->dentry, &newattrs); + err = notify_change(dentry, &newattrs); out_unlock: mutex_unlock(&inode->i_mutex); - mnt_drop_write(path->mnt); - return error; -} - -SYSCALL_DEFINE2(fchmod, unsigned int, fd, mode_t, mode) -{ - struct file * file; - int err = -EBADF; - - file = fget(fd); - if (file) { - audit_inode(NULL, file->f_path.dentry); - err = chmod_common(&file->f_path, mode); - fput(file); - } + mnt_drop_write(file->f_path.mnt); +out_putf: + fput(file); +out: return err; } SYSCALL_DEFINE3(fchmodat, int, dfd, const char __user *, filename, mode_t, mode) { struct path path; + struct inode *inode; int error; + struct iattr newattrs; error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); - if (!error) { - error = chmod_common(&path, mode); - path_put(&path); - } + if (error) + goto out; + inode = path.dentry->d_inode; + + error = mnt_want_write(path.mnt); + if (error) + goto dput_and_out; + mutex_lock(&inode->i_mutex); + error = security_path_chmod(path.dentry, path.mnt, mode); + if (error) + goto out_unlock; + if (mode == (mode_t) -1) + mode = inode->i_mode; + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); + newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; + error = notify_change(path.dentry, &newattrs); +out_unlock: + mutex_unlock(&inode->i_mutex); + mnt_drop_write(path.mnt); +dput_and_out: + path_put(&path); +out: return error; } diff --git a/trunk/fs/pipe.c b/trunk/fs/pipe.c index 0e0be1dc0f8e..1b7f9af67ccf 100644 --- a/trunk/fs/pipe.c +++ b/trunk/fs/pipe.c @@ -948,7 +948,7 @@ static const struct dentry_operations pipefs_dentry_operations = { static struct inode * get_pipe_inode(void) { - struct inode *inode = new_inode_pseudo(pipe_mnt->mnt_sb); + struct inode *inode = new_inode(pipe_mnt->mnt_sb); struct pipe_inode_info *pipe; if (!inode) diff --git a/trunk/fs/proc/generic.c b/trunk/fs/proc/generic.c index 9d99131d0d65..f1637f17c37c 100644 --- a/trunk/fs/proc/generic.c +++ b/trunk/fs/proc/generic.c @@ -620,7 +620,8 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent, if (!ent) goto out; memset(ent, 0, sizeof(struct proc_dir_entry)); - memcpy(ent->name, fn, len + 1); + memcpy(((char *) ent) + sizeof(struct proc_dir_entry), fn, len + 1); + ent->name = ((char *) ent) + sizeof(*ent); ent->namelen = len; ent->mode = mode; ent->nlink = nlink; diff --git a/trunk/fs/proc/proc_net.c b/trunk/fs/proc/proc_net.c index f738024ccc8e..9020ac15baaa 100644 --- a/trunk/fs/proc/proc_net.c +++ b/trunk/fs/proc/proc_net.c @@ -197,15 +197,15 @@ static __net_init int proc_net_ns_init(struct net *net) int err; err = -ENOMEM; - netd = kzalloc(sizeof(*netd) + 4, GFP_KERNEL); + netd = kzalloc(sizeof(*netd), GFP_KERNEL); if (!netd) goto out; netd->data = net; netd->nlink = 2; + netd->name = "net"; netd->namelen = 3; netd->parent = &proc_root; - memcpy(netd->name, "net", 4); err = -EEXIST; net_statd = proc_net_mkdir(net, "stat", netd); diff --git a/trunk/fs/proc/root.c b/trunk/fs/proc/root.c index 9a8a2b77b874..d6c3b416529b 100644 --- a/trunk/fs/proc/root.c +++ b/trunk/fs/proc/root.c @@ -186,13 +186,13 @@ static const struct inode_operations proc_root_inode_operations = { struct proc_dir_entry proc_root = { .low_ino = PROC_ROOT_INO, .namelen = 5, + .name = "/proc", .mode = S_IFDIR | S_IRUGO | S_IXUGO, .nlink = 2, .count = ATOMIC_INIT(1), .proc_iops = &proc_root_inode_operations, .proc_fops = &proc_root_operations, .parent = &proc_root, - .name = "/proc", }; int pid_ns_prepare_proc(struct pid_namespace *ns) diff --git a/trunk/fs/read_write.c b/trunk/fs/read_write.c index 179f1c33ea57..5907b49e4d7e 100644 --- a/trunk/fs/read_write.c +++ b/trunk/fs/read_write.c @@ -166,10 +166,8 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) * long as offset isn't at the end of the file then the * offset is data. */ - if (offset >= inode->i_size) { - retval = -ENXIO; - goto out; - } + if (offset >= inode->i_size) + return -ENXIO; break; case SEEK_HOLE: /* @@ -177,10 +175,8 @@ loff_t default_llseek(struct file *file, loff_t offset, int origin) * as long as offset isn't i_size or larger, return * i_size. */ - if (offset >= inode->i_size) { - retval = -ENXIO; - goto out; - } + if (offset >= inode->i_size) + return -ENXIO; offset = inode->i_size; break; } diff --git a/trunk/fs/xfs/linux-2.6/xfs_ioctl.c b/trunk/fs/xfs/linux-2.6/xfs_ioctl.c index f7ce7debe14c..acca2c5ca3fa 100644 --- a/trunk/fs/xfs/linux-2.6/xfs_ioctl.c +++ b/trunk/fs/xfs/linux-2.6/xfs_ioctl.c @@ -265,7 +265,7 @@ xfs_open_by_handle( return PTR_ERR(filp); } - if (S_ISREG(inode->i_mode)) { + if (inode->i_mode & S_IFREG) { filp->f_flags |= O_NOATIME; filp->f_mode |= FMODE_NOCMTIME; } @@ -850,14 +850,14 @@ xfs_set_diflags( di_flags |= XFS_DIFLAG_NODEFRAG; if (xflags & XFS_XFLAG_FILESTREAM) di_flags |= XFS_DIFLAG_FILESTREAM; - if (S_ISDIR(ip->i_d.di_mode)) { + if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { if (xflags & XFS_XFLAG_RTINHERIT) di_flags |= XFS_DIFLAG_RTINHERIT; if (xflags & XFS_XFLAG_NOSYMLINKS) di_flags |= XFS_DIFLAG_NOSYMLINKS; if (xflags & XFS_XFLAG_EXTSZINHERIT) di_flags |= XFS_DIFLAG_EXTSZINHERIT; - } else if (S_ISREG(ip->i_d.di_mode)) { + } else if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) { if (xflags & XFS_XFLAG_REALTIME) di_flags |= XFS_DIFLAG_REALTIME; if (xflags & XFS_XFLAG_EXTSIZE) diff --git a/trunk/fs/xfs/xfs_bmap.c b/trunk/fs/xfs/xfs_bmap.c index ab3e5c6c4642..c51a3f903633 100644 --- a/trunk/fs/xfs/xfs_bmap.c +++ b/trunk/fs/xfs/xfs_bmap.c @@ -414,7 +414,7 @@ xfs_bmap_add_attrfork_local( if (ip->i_df.if_bytes <= XFS_IFORK_DSIZE(ip)) return 0; - if (S_ISDIR(ip->i_d.di_mode)) { + if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { mp = ip->i_mount; memset(&dargs, 0, sizeof(dargs)); dargs.dp = ip; @@ -3344,7 +3344,8 @@ xfs_bmap_local_to_extents( * We don't want to deal with the case of keeping inode data inline yet. * So sending the data fork of a regular inode is invalid. */ - ASSERT(!(S_ISREG(ip->i_d.di_mode) && whichfork == XFS_DATA_FORK)); + ASSERT(!((ip->i_d.di_mode & S_IFMT) == S_IFREG && + whichfork == XFS_DATA_FORK)); ifp = XFS_IFORK_PTR(ip, whichfork); ASSERT(XFS_IFORK_FORMAT(ip, whichfork) == XFS_DINODE_FMT_LOCAL); flags = 0; @@ -4051,7 +4052,7 @@ xfs_bmap_one_block( #ifndef DEBUG if (whichfork == XFS_DATA_FORK) { - return S_ISREG(ip->i_d.di_mode) ? + return ((ip->i_d.di_mode & S_IFMT) == S_IFREG) ? (ip->i_size == ip->i_mount->m_sb.sb_blocksize) : (ip->i_d.di_size == ip->i_mount->m_sb.sb_blocksize); } diff --git a/trunk/fs/xfs/xfs_da_btree.c b/trunk/fs/xfs/xfs_da_btree.c index 2925726529f8..5bfcb8779f9f 100644 --- a/trunk/fs/xfs/xfs_da_btree.c +++ b/trunk/fs/xfs/xfs_da_btree.c @@ -692,6 +692,24 @@ xfs_da_join(xfs_da_state_t *state) return(error); } +#ifdef DEBUG +static void +xfs_da_blkinfo_onlychild_validate(struct xfs_da_blkinfo *blkinfo, __u16 level) +{ + __be16 magic = blkinfo->magic; + + if (level == 1) { + ASSERT(magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || + magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)); + } else + ASSERT(magic == cpu_to_be16(XFS_DA_NODE_MAGIC)); + ASSERT(!blkinfo->forw); + ASSERT(!blkinfo->back); +} +#else /* !DEBUG */ +#define xfs_da_blkinfo_onlychild_validate(blkinfo, level) +#endif /* !DEBUG */ + /* * We have only one entry in the root. Copy the only remaining child of * the old root to block 0 as the new root node. @@ -700,8 +718,6 @@ STATIC int xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk) { xfs_da_intnode_t *oldroot; - /* REFERENCED */ - xfs_da_blkinfo_t *blkinfo; xfs_da_args_t *args; xfs_dablk_t child; xfs_dabuf_t *bp; @@ -732,15 +748,9 @@ xfs_da_root_join(xfs_da_state_t *state, xfs_da_state_blk_t *root_blk) if (error) return(error); ASSERT(bp != NULL); - blkinfo = bp->data; - if (be16_to_cpu(oldroot->hdr.level) == 1) { - ASSERT(blkinfo->magic == cpu_to_be16(XFS_DIR2_LEAFN_MAGIC) || - blkinfo->magic == cpu_to_be16(XFS_ATTR_LEAF_MAGIC)); - } else { - ASSERT(blkinfo->magic == cpu_to_be16(XFS_DA_NODE_MAGIC)); - } - ASSERT(!blkinfo->forw); - ASSERT(!blkinfo->back); + xfs_da_blkinfo_onlychild_validate(bp->data, + be16_to_cpu(oldroot->hdr.level)); + memcpy(root_blk->bp->data, bp->data, state->blocksize); xfs_da_log_buf(args->trans, root_blk->bp, 0, state->blocksize - 1); error = xfs_da_shrink_inode(args, child, bp); diff --git a/trunk/fs/xfs/xfs_dir2.c b/trunk/fs/xfs/xfs_dir2.c index a2e27010c7fb..4580ce00aeb4 100644 --- a/trunk/fs/xfs/xfs_dir2.c +++ b/trunk/fs/xfs/xfs_dir2.c @@ -121,7 +121,7 @@ xfs_dir_isempty( { xfs_dir2_sf_hdr_t *sfp; - ASSERT(S_ISDIR(dp->i_d.di_mode)); + ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); if (dp->i_d.di_size == 0) /* might happen during shutdown. */ return 1; if (dp->i_d.di_size > XFS_IFORK_DSIZE(dp)) @@ -179,7 +179,7 @@ xfs_dir_init( memset((char *)&args, 0, sizeof(args)); args.dp = dp; args.trans = tp; - ASSERT(S_ISDIR(dp->i_d.di_mode)); + ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); if ((error = xfs_dir_ino_validate(tp->t_mountp, pdp->i_ino))) return error; return xfs_dir2_sf_create(&args, pdp->i_ino); @@ -202,7 +202,7 @@ xfs_dir_createname( int rval; int v; /* type-checking value */ - ASSERT(S_ISDIR(dp->i_d.di_mode)); + ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) return rval; XFS_STATS_INC(xs_dir_create); @@ -278,7 +278,7 @@ xfs_dir_lookup( int rval; int v; /* type-checking value */ - ASSERT(S_ISDIR(dp->i_d.di_mode)); + ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); XFS_STATS_INC(xs_dir_lookup); memset(&args, 0, sizeof(xfs_da_args_t)); @@ -333,7 +333,7 @@ xfs_dir_removename( int rval; int v; /* type-checking value */ - ASSERT(S_ISDIR(dp->i_d.di_mode)); + ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); XFS_STATS_INC(xs_dir_remove); memset(&args, 0, sizeof(xfs_da_args_t)); @@ -382,7 +382,7 @@ xfs_readdir( if (XFS_FORCED_SHUTDOWN(dp->i_mount)) return XFS_ERROR(EIO); - ASSERT(S_ISDIR(dp->i_d.di_mode)); + ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); XFS_STATS_INC(xs_dir_getdents); if (dp->i_d.di_format == XFS_DINODE_FMT_LOCAL) @@ -414,7 +414,7 @@ xfs_dir_replace( int rval; int v; /* type-checking value */ - ASSERT(S_ISDIR(dp->i_d.di_mode)); + ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); if ((rval = xfs_dir_ino_validate(tp->t_mountp, inum))) return rval; @@ -464,7 +464,7 @@ xfs_dir_canenter( if (resblks) return 0; - ASSERT(S_ISDIR(dp->i_d.di_mode)); + ASSERT((dp->i_d.di_mode & S_IFMT) == S_IFDIR); memset(&args, 0, sizeof(xfs_da_args_t)); args.name = name->name; diff --git a/trunk/fs/xfs/xfs_filestream.c b/trunk/fs/xfs/xfs_filestream.c index 3ff3d9e23ded..9124425b7f2f 100644 --- a/trunk/fs/xfs/xfs_filestream.c +++ b/trunk/fs/xfs/xfs_filestream.c @@ -344,9 +344,9 @@ _xfs_filestream_update_ag( * Either ip is a regular file and pip is a directory, or ip is a * directory and pip is NULL. */ - ASSERT(ip && ((S_ISREG(ip->i_d.di_mode) && pip && - S_ISDIR(pip->i_d.di_mode)) || - (S_ISDIR(ip->i_d.di_mode) && !pip))); + ASSERT(ip && (((ip->i_d.di_mode & S_IFREG) && pip && + (pip->i_d.di_mode & S_IFDIR)) || + ((ip->i_d.di_mode & S_IFDIR) && !pip))); mp = ip->i_mount; cache = mp->m_filestream; @@ -537,7 +537,7 @@ xfs_filestream_lookup_ag( xfs_agnumber_t ag; int ref; - if (!S_ISREG(ip->i_d.di_mode) && !S_ISDIR(ip->i_d.di_mode)) { + if (!(ip->i_d.di_mode & (S_IFREG | S_IFDIR))) { ASSERT(0); return NULLAGNUMBER; } @@ -579,9 +579,9 @@ xfs_filestream_associate( xfs_agnumber_t ag, rotorstep, startag; int err = 0; - ASSERT(S_ISDIR(pip->i_d.di_mode)); - ASSERT(S_ISREG(ip->i_d.di_mode)); - if (!S_ISDIR(pip->i_d.di_mode) || !S_ISREG(ip->i_d.di_mode)) + ASSERT(pip->i_d.di_mode & S_IFDIR); + ASSERT(ip->i_d.di_mode & S_IFREG); + if (!(pip->i_d.di_mode & S_IFDIR) || !(ip->i_d.di_mode & S_IFREG)) return -EINVAL; mp = pip->i_mount; diff --git a/trunk/fs/xfs/xfs_inode.c b/trunk/fs/xfs/xfs_inode.c index 2fcca4b03ed3..3cc21ddf9f7e 100644 --- a/trunk/fs/xfs/xfs_inode.c +++ b/trunk/fs/xfs/xfs_inode.c @@ -368,7 +368,7 @@ xfs_iformat( /* * no local regular files yet */ - if (unlikely(S_ISREG(be16_to_cpu(dip->di_mode)))) { + if (unlikely((be16_to_cpu(dip->di_mode) & S_IFMT) == S_IFREG)) { xfs_warn(ip->i_mount, "corrupt inode %Lu (local format for regular file).", (unsigned long long) ip->i_ino); @@ -1040,7 +1040,7 @@ xfs_ialloc( if (pip && XFS_INHERIT_GID(pip)) { ip->i_d.di_gid = pip->i_d.di_gid; - if ((pip->i_d.di_mode & S_ISGID) && S_ISDIR(mode)) { + if ((pip->i_d.di_mode & S_ISGID) && (mode & S_IFMT) == S_IFDIR) { ip->i_d.di_mode |= S_ISGID; } } @@ -1097,14 +1097,14 @@ xfs_ialloc( if (pip && (pip->i_d.di_flags & XFS_DIFLAG_ANY)) { uint di_flags = 0; - if (S_ISDIR(mode)) { + if ((mode & S_IFMT) == S_IFDIR) { if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) di_flags |= XFS_DIFLAG_RTINHERIT; if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { di_flags |= XFS_DIFLAG_EXTSZINHERIT; ip->i_d.di_extsize = pip->i_d.di_extsize; } - } else if (S_ISREG(mode)) { + } else if ((mode & S_IFMT) == S_IFREG) { if (pip->i_d.di_flags & XFS_DIFLAG_RTINHERIT) di_flags |= XFS_DIFLAG_REALTIME; if (pip->i_d.di_flags & XFS_DIFLAG_EXTSZINHERIT) { @@ -1188,7 +1188,7 @@ xfs_isize_check( int nimaps; xfs_bmbt_irec_t imaps[2]; - if (!S_ISREG(ip->i_d.di_mode)) + if ((ip->i_d.di_mode & S_IFMT) != S_IFREG) return; if (XFS_IS_REALTIME_INODE(ip)) @@ -1828,7 +1828,7 @@ xfs_ifree( ASSERT(ip->i_d.di_nextents == 0); ASSERT(ip->i_d.di_anextents == 0); ASSERT((ip->i_d.di_size == 0 && ip->i_size == 0) || - (!S_ISREG(ip->i_d.di_mode))); + ((ip->i_d.di_mode & S_IFMT) != S_IFREG)); ASSERT(ip->i_d.di_nblocks == 0); /* @@ -2671,7 +2671,7 @@ xfs_iflush_int( __func__, ip->i_ino, ip, ip->i_d.di_magic); goto corrupt_out; } - if (S_ISREG(ip->i_d.di_mode)) { + if ((ip->i_d.di_mode & S_IFMT) == S_IFREG) { if (XFS_TEST_ERROR( (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && (ip->i_d.di_format != XFS_DINODE_FMT_BTREE), @@ -2681,7 +2681,7 @@ xfs_iflush_int( __func__, ip->i_ino, ip); goto corrupt_out; } - } else if (S_ISDIR(ip->i_d.di_mode)) { + } else if ((ip->i_d.di_mode & S_IFMT) == S_IFDIR) { if (XFS_TEST_ERROR( (ip->i_d.di_format != XFS_DINODE_FMT_EXTENTS) && (ip->i_d.di_format != XFS_DINODE_FMT_BTREE) && diff --git a/trunk/fs/xfs/xfs_inode.h b/trunk/fs/xfs/xfs_inode.h index 2380a4bcbece..a97644ab945a 100644 --- a/trunk/fs/xfs/xfs_inode.h +++ b/trunk/fs/xfs/xfs_inode.h @@ -263,7 +263,7 @@ typedef struct xfs_inode { struct inode i_vnode; /* embedded VFS inode */ } xfs_inode_t; -#define XFS_ISIZE(ip) S_ISREG((ip)->i_d.di_mode) ? \ +#define XFS_ISIZE(ip) (((ip)->i_d.di_mode & S_IFMT) == S_IFREG) ? \ (ip)->i_size : (ip)->i_d.di_size; /* Convert from vfs inode to xfs inode */ diff --git a/trunk/fs/xfs/xfs_log_recover.c b/trunk/fs/xfs/xfs_log_recover.c index 052a2c0ec5fb..8fe4206de057 100644 --- a/trunk/fs/xfs/xfs_log_recover.c +++ b/trunk/fs/xfs/xfs_log_recover.c @@ -2283,7 +2283,7 @@ xlog_recover_inode_pass2( /* Take the opportunity to reset the flush iteration count */ dicp->di_flushiter = 0; - if (unlikely(S_ISREG(dicp->di_mode))) { + if (unlikely((dicp->di_mode & S_IFMT) == S_IFREG)) { if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && (dicp->di_format != XFS_DINODE_FMT_BTREE)) { XFS_CORRUPTION_ERROR("xlog_recover_inode_pass2(3)", @@ -2296,7 +2296,7 @@ xlog_recover_inode_pass2( error = EFSCORRUPTED; goto error; } - } else if (unlikely(S_ISDIR(dicp->di_mode))) { + } else if (unlikely((dicp->di_mode & S_IFMT) == S_IFDIR)) { if ((dicp->di_format != XFS_DINODE_FMT_EXTENTS) && (dicp->di_format != XFS_DINODE_FMT_BTREE) && (dicp->di_format != XFS_DINODE_FMT_LOCAL)) { diff --git a/trunk/fs/xfs/xfs_mount.c b/trunk/fs/xfs/xfs_mount.c index 092e16ae4d9d..7f25245da289 100644 --- a/trunk/fs/xfs/xfs_mount.c +++ b/trunk/fs/xfs/xfs_mount.c @@ -1331,7 +1331,7 @@ xfs_mountfs( ASSERT(rip != NULL); - if (unlikely(!S_ISDIR(rip->i_d.di_mode))) { + if (unlikely((rip->i_d.di_mode & S_IFMT) != S_IFDIR)) { xfs_warn(mp, "corrupted root inode %llu: not a directory", (unsigned long long)rip->i_ino); xfs_iunlock(rip, XFS_ILOCK_EXCL); diff --git a/trunk/fs/xfs/xfs_rename.c b/trunk/fs/xfs/xfs_rename.c index df78c297d1a1..77a59891734e 100644 --- a/trunk/fs/xfs/xfs_rename.c +++ b/trunk/fs/xfs/xfs_rename.c @@ -116,7 +116,7 @@ xfs_rename( trace_xfs_rename(src_dp, target_dp, src_name, target_name); new_parent = (src_dp != target_dp); - src_is_directory = S_ISDIR(src_ip->i_d.di_mode); + src_is_directory = ((src_ip->i_d.di_mode & S_IFMT) == S_IFDIR); if (src_is_directory) { /* @@ -226,7 +226,7 @@ xfs_rename( * target and source are directories and that target can be * destroyed, or that neither is a directory. */ - if (S_ISDIR(target_ip->i_d.di_mode)) { + if ((target_ip->i_d.di_mode & S_IFMT) == S_IFDIR) { /* * Make sure target dir is empty. */ diff --git a/trunk/fs/xfs/xfs_vnodeops.c b/trunk/fs/xfs/xfs_vnodeops.c index 9322e13f0c63..88d121486c52 100644 --- a/trunk/fs/xfs/xfs_vnodeops.c +++ b/trunk/fs/xfs/xfs_vnodeops.c @@ -121,7 +121,7 @@ xfs_readlink( xfs_ilock(ip, XFS_ILOCK_SHARED); - ASSERT(S_ISLNK(ip->i_d.di_mode)); + ASSERT((ip->i_d.di_mode & S_IFMT) == S_IFLNK); ASSERT(ip->i_d.di_size <= MAXPATHLEN); pathlen = ip->i_d.di_size; @@ -529,7 +529,7 @@ xfs_release( if (ip->i_d.di_nlink == 0) return 0; - if ((S_ISREG(ip->i_d.di_mode) && + if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) && (ip->i_df.if_flags & XFS_IFEXTENTS)) && @@ -610,7 +610,7 @@ xfs_inactive( truncate = ((ip->i_d.di_nlink == 0) && ((ip->i_d.di_size != 0) || (ip->i_size != 0) || (ip->i_d.di_nextents > 0) || (ip->i_delayed_blks > 0)) && - S_ISREG(ip->i_d.di_mode)); + ((ip->i_d.di_mode & S_IFMT) == S_IFREG)); mp = ip->i_mount; @@ -621,7 +621,7 @@ xfs_inactive( goto out; if (ip->i_d.di_nlink != 0) { - if ((S_ISREG(ip->i_d.di_mode) && + if ((((ip->i_d.di_mode & S_IFMT) == S_IFREG) && ((ip->i_size > 0) || (VN_CACHED(VFS_I(ip)) > 0 || ip->i_delayed_blks > 0)) && (ip->i_df.if_flags & XFS_IFEXTENTS) && @@ -669,7 +669,7 @@ xfs_inactive( xfs_iunlock(ip, XFS_IOLOCK_EXCL | XFS_ILOCK_EXCL); return VN_INACTIVE_CACHE; } - } else if (S_ISLNK(ip->i_d.di_mode)) { + } else if ((ip->i_d.di_mode & S_IFMT) == S_IFLNK) { /* * If we get an error while cleaning up a diff --git a/trunk/include/linux/fs.h b/trunk/include/linux/fs.h index f23bcb77260c..5f523eb9bb8d 100644 --- a/trunk/include/linux/fs.h +++ b/trunk/include/linux/fs.h @@ -2310,8 +2310,7 @@ extern void __iget(struct inode * inode); extern void iget_failed(struct inode *); extern void end_writeback(struct inode *); extern void __destroy_inode(struct inode *); -extern struct inode *new_inode_pseudo(struct super_block *sb); -extern struct inode *new_inode(struct super_block *sb); +extern struct inode *new_inode(struct super_block *); extern void free_inode_nonrcu(struct inode *inode); extern int should_remove_suid(struct dentry *); extern int file_remove_suid(struct file *); diff --git a/trunk/include/linux/input.h b/trunk/include/linux/input.h index 068784e17972..771d6d85667d 100644 --- a/trunk/include/linux/input.h +++ b/trunk/include/linux/input.h @@ -119,9 +119,9 @@ struct input_keymap_entry { #define EVIOCGSND(len) _IOC(_IOC_READ, 'E', 0x1a, len) /* get all sounds status */ #define EVIOCGSW(len) _IOC(_IOC_READ, 'E', 0x1b, len) /* get all switch states */ -#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + (ev), len) /* get event bits */ -#define EVIOCGABS(abs) _IOR('E', 0x40 + (abs), struct input_absinfo) /* get abs value/limits */ -#define EVIOCSABS(abs) _IOW('E', 0xc0 + (abs), struct input_absinfo) /* set abs value/limits */ +#define EVIOCGBIT(ev,len) _IOC(_IOC_READ, 'E', 0x20 + ev, len) /* get event bits */ +#define EVIOCGABS(abs) _IOR('E', 0x40 + abs, struct input_absinfo) /* get abs value/limits */ +#define EVIOCSABS(abs) _IOW('E', 0xc0 + abs, struct input_absinfo) /* set abs value/limits */ #define EVIOCSFF _IOC(_IOC_WRITE, 'E', 0x80, sizeof(struct ff_effect)) /* send a force effect to a force feedback device */ #define EVIOCRMFF _IOW('E', 0x81, int) /* Erase a force effect */ diff --git a/trunk/include/linux/input/kxtj9.h b/trunk/include/linux/input/kxtj9.h deleted file mode 100644 index f6bac89537b8..000000000000 --- a/trunk/include/linux/input/kxtj9.h +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Copyright (C) 2011 Kionix, Inc. - * Written by Chris Hudson - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License version 2 as - * published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA - * 02111-1307, USA - */ - -#ifndef __KXTJ9_H__ -#define __KXTJ9_H__ - -#define KXTJ9_I2C_ADDR 0x0F - -struct kxtj9_platform_data { - unsigned int min_interval; /* minimum poll interval (in milli-seconds) */ - - /* - * By default, x is axis 0, y is axis 1, z is axis 2; these can be - * changed to account for sensor orientation within the host device. - */ - u8 axis_map_x; - u8 axis_map_y; - u8 axis_map_z; - - /* - * Each axis can be negated to account for sensor orientation within - * the host device. - */ - bool negate_x; - bool negate_y; - bool negate_z; - - /* CTRL_REG1: set resolution, g-range, data ready enable */ - /* Output resolution: 8-bit valid or 12-bit valid */ - #define RES_8BIT 0 - #define RES_12BIT (1 << 6) - u8 res_12bit; - /* Output g-range: +/-2g, 4g, or 8g */ - #define KXTJ9_G_2G 0 - #define KXTJ9_G_4G (1 << 3) - #define KXTJ9_G_8G (1 << 4) - u8 g_range; - - /* DATA_CTRL_REG: controls the output data rate of the part */ - #define ODR12_5F 0 - #define ODR25F 1 - #define ODR50F 2 - #define ODR100F 3 - #define ODR200F 4 - #define ODR400F 5 - #define ODR800F 6 - u8 data_odr_init; - - int (*init)(void); - void (*exit)(void); - int (*power_on)(void); - int (*power_off)(void); -}; -#endif /* __KXTJ9_H__ */ diff --git a/trunk/include/linux/kernel.h b/trunk/include/linux/kernel.h index 46ac9a50528d..9a43ad792cfc 100644 --- a/trunk/include/linux/kernel.h +++ b/trunk/include/linux/kernel.h @@ -56,14 +56,6 @@ #define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f)) #define DIV_ROUND_UP(n,d) (((n) + (d) - 1) / (d)) -#define DIV_ROUND_UP_ULL(ll,d) \ - ({ unsigned long long _tmp = (ll)+(d)-1; do_div(_tmp, d); _tmp; }) - -#if BITS_PER_LONG == 32 -# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP_ULL(ll, d) -#else -# define DIV_ROUND_UP_SECTOR_T(ll,d) DIV_ROUND_UP(ll,d) -#endif /* The `const' in roundup() prevents gcc-3.3 from calling __divdi3 */ #define roundup(x, y) ( \ diff --git a/trunk/include/linux/nfs4.h b/trunk/include/linux/nfs4.h index a3c4bc800dce..504b289ba680 100644 --- a/trunk/include/linux/nfs4.h +++ b/trunk/include/linux/nfs4.h @@ -563,9 +563,6 @@ enum { NFSPROC4_CLNT_GETDEVICEINFO, NFSPROC4_CLNT_LAYOUTCOMMIT, NFSPROC4_CLNT_LAYOUTRETURN, - NFSPROC4_CLNT_SECINFO_NO_NAME, - NFSPROC4_CLNT_TEST_STATEID, - NFSPROC4_CLNT_FREE_STATEID, }; /* nfs41 types */ diff --git a/trunk/include/linux/nfs_fs_sb.h b/trunk/include/linux/nfs_fs_sb.h index 50a661f8b45a..08c444aa0411 100644 --- a/trunk/include/linux/nfs_fs_sb.h +++ b/trunk/include/linux/nfs_fs_sb.h @@ -16,7 +16,6 @@ struct nfs4_sequence_args; struct nfs4_sequence_res; struct nfs_server; struct nfs4_minor_version_ops; -struct server_scope; /* * The nfs_client identifies our client state to the server. @@ -78,13 +77,12 @@ struct nfs_client { /* The flags used for obtaining the clientid during EXCHANGE_ID */ u32 cl_exchange_flags; struct nfs4_session *cl_session; /* sharred session */ + struct list_head cl_layouts; #endif /* CONFIG_NFS_V4 */ #ifdef CONFIG_NFS_FSCACHE struct fscache_cookie *fscache; /* client index cache cookie */ #endif - - struct server_scope *server_scope; /* from exchange_id */ }; /* @@ -151,7 +149,6 @@ struct nfs_server { struct rb_root openowner_id; struct rb_root lockowner_id; #endif - struct list_head layouts; struct list_head delegations; void (*destroy)(struct nfs_server *); diff --git a/trunk/include/linux/nfs_page.h b/trunk/include/linux/nfs_page.h index e2791a27a901..25311b3bedf8 100644 --- a/trunk/include/linux/nfs_page.h +++ b/trunk/include/linux/nfs_page.h @@ -55,28 +55,20 @@ struct nfs_page { struct nfs_writeverf wb_verf; /* Commit cookie */ }; -struct nfs_pageio_descriptor; -struct nfs_pageio_ops { - void (*pg_init)(struct nfs_pageio_descriptor *, struct nfs_page *); - bool (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *); - int (*pg_doio)(struct nfs_pageio_descriptor *); -}; - struct nfs_pageio_descriptor { struct list_head pg_list; unsigned long pg_bytes_written; size_t pg_count; size_t pg_bsize; unsigned int pg_base; - unsigned char pg_moreio : 1, - pg_recoalesce : 1; + char pg_moreio; struct inode *pg_inode; - const struct nfs_pageio_ops *pg_ops; + int (*pg_doio)(struct nfs_pageio_descriptor *); int pg_ioflags; int pg_error; - const struct rpc_call_ops *pg_rpc_callops; struct pnfs_layout_segment *pg_lseg; + bool (*pg_test)(struct nfs_pageio_descriptor *, struct nfs_page *, struct nfs_page *); }; #define NFS_WBACK_BUSY(req) (test_bit(PG_BUSY,&(req)->wb_flags)) @@ -93,7 +85,7 @@ extern int nfs_scan_list(struct nfs_inode *nfsi, struct list_head *dst, pgoff_t idx_start, unsigned int npages, int tag); extern void nfs_pageio_init(struct nfs_pageio_descriptor *desc, struct inode *inode, - const struct nfs_pageio_ops *pg_ops, + int (*doio)(struct nfs_pageio_descriptor *desc), size_t bsize, int how); extern int nfs_pageio_add_request(struct nfs_pageio_descriptor *, @@ -108,6 +100,7 @@ extern void nfs_unlock_request(struct nfs_page *req); extern int nfs_set_page_tag_locked(struct nfs_page *req); extern void nfs_clear_page_tag_locked(struct nfs_page *req); + /* * Lock the page of an asynchronous request without getting a new reference */ diff --git a/trunk/include/linux/nfs_xdr.h b/trunk/include/linux/nfs_xdr.h index 5b115956abac..00848d86ffb2 100644 --- a/trunk/include/linux/nfs_xdr.h +++ b/trunk/include/linux/nfs_xdr.h @@ -269,10 +269,9 @@ struct nfs4_layoutcommit_data { }; struct nfs4_layoutreturn_args { - struct pnfs_layout_hdr *layout; + __u32 layout_type; struct inode *inode; nfs4_stateid stateid; - __u32 layout_type; struct nfs4_sequence_args seq_args; }; @@ -1061,7 +1060,6 @@ struct server_scope { struct nfs41_exchange_id_res { struct nfs_client *client; u32 flags; - struct server_scope *server_scope; }; struct nfs41_create_session_args { @@ -1085,34 +1083,6 @@ struct nfs41_reclaim_complete_args { struct nfs41_reclaim_complete_res { struct nfs4_sequence_res seq_res; }; - -#define SECINFO_STYLE_CURRENT_FH 0 -#define SECINFO_STYLE_PARENT 1 -struct nfs41_secinfo_no_name_args { - int style; - struct nfs4_sequence_args seq_args; -}; - -struct nfs41_test_stateid_args { - nfs4_stateid *stateid; - struct nfs4_sequence_args seq_args; -}; - -struct nfs41_test_stateid_res { - unsigned int status; - struct nfs4_sequence_res seq_res; -}; - -struct nfs41_free_stateid_args { - nfs4_stateid *stateid; - struct nfs4_sequence_args seq_args; -}; - -struct nfs41_free_stateid_res { - unsigned int status; - struct nfs4_sequence_res seq_res; -}; - #endif /* CONFIG_NFS_V4_1 */ struct nfs_page; @@ -1126,7 +1096,6 @@ struct nfs_read_data { struct rpc_cred *cred; struct nfs_fattr fattr; /* fattr storage */ struct list_head pages; /* Coalesced read requests */ - struct list_head list; /* lists of struct nfs_read_data */ struct nfs_page *req; /* multi ops per nfs_page */ struct page **pagevec; unsigned int npages; /* Max length of pagevec */ @@ -1150,7 +1119,6 @@ struct nfs_write_data { struct nfs_fattr fattr; struct nfs_writeverf verf; struct list_head pages; /* Coalesced requests we wish to flush */ - struct list_head list; /* lists of struct nfs_write_data */ struct nfs_page *req; /* multi ops per nfs_page */ struct page **pagevec; unsigned int npages; /* Max length of pagevec */ diff --git a/trunk/include/linux/pnfs_osd_xdr.h b/trunk/include/linux/pnfs_osd_xdr.h index 435dd5fa7453..76efbdd01622 100644 --- a/trunk/include/linux/pnfs_osd_xdr.h +++ b/trunk/include/linux/pnfs_osd_xdr.h @@ -41,6 +41,9 @@ #include #include +#include + +#define PNFS_OSD_OSDNAME_MAXSIZE 256 /* * draft-ietf-nfsv4-minorversion-22 @@ -96,6 +99,12 @@ struct pnfs_osd_objid { #define _DEVID_HI(oid_device_id) \ (unsigned long long)be64_to_cpup(((__be64 *)(oid_device_id)->data) + 1) +static inline int +pnfs_osd_objid_xdr_sz(void) +{ + return (NFS4_DEVICEID4_SIZE / 4) + 2 + 2; +} + enum pnfs_osd_version { PNFS_OSD_MISSING = 0, PNFS_OSD_VERSION_1 = 1, @@ -180,6 +189,8 @@ struct pnfs_osd_targetid { struct nfs4_string oti_scsi_device_id; }; +enum { PNFS_OSD_TARGETID_MAX = 1 + PNFS_OSD_OSDNAME_MAXSIZE / 4 }; + /* struct netaddr4 { * // see struct rpcb in RFC1833 * string r_netid<>; // network id @@ -196,6 +207,12 @@ struct pnfs_osd_targetaddr { struct pnfs_osd_net_addr ota_netaddr; }; +enum { + NETWORK_ID_MAX = 16 / 4, + UNIVERSAL_ADDRESS_MAX = 64 / 4, + PNFS_OSD_TARGETADDR_MAX = 3 + NETWORK_ID_MAX + UNIVERSAL_ADDRESS_MAX, +}; + struct pnfs_osd_deviceaddr { struct pnfs_osd_targetid oda_targetid; struct pnfs_osd_targetaddr oda_targetaddr; @@ -205,6 +222,15 @@ struct pnfs_osd_deviceaddr { struct nfs4_string oda_osdname; }; +enum { + ODA_OSDNAME_MAX = PNFS_OSD_OSDNAME_MAXSIZE / 4, + PNFS_OSD_DEVICEADDR_MAX = + PNFS_OSD_TARGETID_MAX + PNFS_OSD_TARGETADDR_MAX + + 2 /*oda_lun*/ + + 1 + OSD_SYSTEMID_LEN + + 1 + ODA_OSDNAME_MAX, +}; + /* LAYOUTCOMMIT: layoutupdate */ /* union pnfs_osd_deltaspaceused4 switch (bool dsu_valid) { @@ -253,7 +279,7 @@ struct pnfs_osd_ioerr { u32 oer_errno; }; -/* OSD XDR Client API */ +/* OSD XDR API */ /* Layout helpers */ /* Layout decoding is done in two parts: * 1. First Call pnfs_osd_xdr_decode_layout_map to read in only the header part @@ -311,7 +337,8 @@ extern int pnfs_osd_xdr_encode_layoutupdate(struct xdr_stream *xdr, struct pnfs_osd_layoutupdate *lou); -/* osd_ioerror encoding (layout_return) */ +/* osd_ioerror encoding/decoding (layout_return) */ +/* Client */ extern __be32 *pnfs_osd_xdr_ioerr_reserve_space(struct xdr_stream *xdr); extern void pnfs_osd_xdr_encode_ioerr(__be32 *p, struct pnfs_osd_ioerr *ioerr); diff --git a/trunk/include/linux/proc_fs.h b/trunk/include/linux/proc_fs.h index 643b96c7a94f..650af6deaf8f 100644 --- a/trunk/include/linux/proc_fs.h +++ b/trunk/include/linux/proc_fs.h @@ -50,6 +50,8 @@ typedef int (write_proc_t)(struct file *file, const char __user *buffer, struct proc_dir_entry { unsigned int low_ino; + unsigned int namelen; + const char *name; mode_t mode; nlink_t nlink; uid_t uid; @@ -71,11 +73,9 @@ struct proc_dir_entry { write_proc_t *write_proc; atomic_t count; /* use count */ int pde_users; /* number of callers into module in progress */ + spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */ struct completion *pde_unload_completion; struct list_head pde_openers; /* who did ->open, but not ->release */ - spinlock_t pde_unload_lock; /* proc_fops checks and pde_users bumps */ - u8 namelen; - char name[]; }; enum kcore_type { diff --git a/trunk/include/linux/sunrpc/bc_xprt.h b/trunk/include/linux/sunrpc/bc_xprt.h index f7f3ce340c08..082884295f80 100644 --- a/trunk/include/linux/sunrpc/bc_xprt.h +++ b/trunk/include/linux/sunrpc/bc_xprt.h @@ -31,7 +31,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include #include -#ifdef CONFIG_SUNRPC_BACKCHANNEL +#ifdef CONFIG_NFS_V4_1 struct rpc_rqst *xprt_alloc_bc_request(struct rpc_xprt *xprt); void xprt_free_bc_request(struct rpc_rqst *req); int xprt_setup_backchannel(struct rpc_xprt *, unsigned int min_reqs); @@ -47,7 +47,7 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp) return 1; return 0; } -#else /* CONFIG_SUNRPC_BACKCHANNEL */ +#else /* CONFIG_NFS_V4_1 */ static inline int xprt_setup_backchannel(struct rpc_xprt *xprt, unsigned int min_reqs) { @@ -62,6 +62,6 @@ static inline int svc_is_backchannel(const struct svc_rqst *rqstp) static inline void xprt_free_bc_request(struct rpc_rqst *req) { } -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ #endif /* _LINUX_SUNRPC_BC_XPRT_H */ diff --git a/trunk/include/linux/sunrpc/sched.h b/trunk/include/linux/sunrpc/sched.h index e7756896f3ca..fe2d8e6b923b 100644 --- a/trunk/include/linux/sunrpc/sched.h +++ b/trunk/include/linux/sunrpc/sched.h @@ -227,10 +227,6 @@ void rpc_init_wait_queue(struct rpc_wait_queue *, const char *); void rpc_destroy_wait_queue(struct rpc_wait_queue *); void rpc_sleep_on(struct rpc_wait_queue *, struct rpc_task *, rpc_action action); -void rpc_sleep_on_priority(struct rpc_wait_queue *, - struct rpc_task *, - rpc_action action, - int priority); void rpc_wake_up_queued_task(struct rpc_wait_queue *, struct rpc_task *); void rpc_wake_up(struct rpc_wait_queue *); diff --git a/trunk/include/linux/sunrpc/svc.h b/trunk/include/linux/sunrpc/svc.h index 223588a976a0..2f1e5186e049 100644 --- a/trunk/include/linux/sunrpc/svc.h +++ b/trunk/include/linux/sunrpc/svc.h @@ -92,7 +92,7 @@ struct svc_serv { struct module * sv_module; /* optional module to count when * adding threads */ svc_thread_fn sv_function; /* main function for threads */ -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) struct list_head sv_cb_list; /* queue for callback requests * that arrive over the same * connection */ @@ -100,7 +100,7 @@ struct svc_serv { wait_queue_head_t sv_cb_waitq; /* sleep here if there are no * entries in the svc_cb_list */ struct svc_xprt *sv_bc_xprt; /* callback on fore channel */ -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ }; /* diff --git a/trunk/include/linux/sunrpc/xprt.h b/trunk/include/linux/sunrpc/xprt.h index 15518a152ac3..81cce3b3ee66 100644 --- a/trunk/include/linux/sunrpc/xprt.h +++ b/trunk/include/linux/sunrpc/xprt.h @@ -22,7 +22,6 @@ #define RPC_MIN_SLOT_TABLE (2U) #define RPC_DEF_SLOT_TABLE (16U) #define RPC_MAX_SLOT_TABLE (128U) -#define RPC_MAX_SLOT_TABLE_LIMIT (65536U) /* * This describes a timeout strategy @@ -101,18 +100,18 @@ struct rpc_rqst { ktime_t rq_xtime; /* transmit time stamp */ int rq_ntrans; -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) struct list_head rq_bc_list; /* Callback service list */ unsigned long rq_bc_pa_state; /* Backchannel prealloc state */ struct list_head rq_bc_pa_list; /* Backchannel prealloc list */ -#endif /* CONFIG_SUNRPC_BACKCHANEL */ +#endif /* CONFIG_NFS_V4_1 */ }; #define rq_svec rq_snd_buf.head #define rq_slen rq_snd_buf.len struct rpc_xprt_ops { void (*set_buffer_size)(struct rpc_xprt *xprt, size_t sndsize, size_t rcvsize); - int (*reserve_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); + int (*reserve_xprt)(struct rpc_task *task); void (*release_xprt)(struct rpc_xprt *xprt, struct rpc_task *task); void (*rpcbind)(struct rpc_task *task); void (*set_port)(struct rpc_xprt *xprt, unsigned short port); @@ -165,12 +164,12 @@ struct rpc_xprt { struct rpc_wait_queue binding; /* requests waiting on rpcbind */ struct rpc_wait_queue sending; /* requests waiting to send */ + struct rpc_wait_queue resend; /* requests waiting to resend */ struct rpc_wait_queue pending; /* requests in flight */ struct rpc_wait_queue backlog; /* waiting for slot */ struct list_head free; /* free slots */ - unsigned int max_reqs; /* max number of slots */ - unsigned int min_reqs; /* min number of slots */ - atomic_t num_reqs; /* total slots */ + struct rpc_rqst * slot; /* slot table storage */ + unsigned int max_reqs; /* total slots */ unsigned long state; /* transport state */ unsigned char shutdown : 1, /* being shut down */ resvport : 1; /* use a reserved port */ @@ -201,7 +200,7 @@ struct rpc_xprt { u32 xid; /* Next XID value to use */ struct rpc_task * snd_task; /* Task blocked in send */ struct svc_xprt *bc_xprt; /* NFSv4.1 backchannel */ -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) struct svc_serv *bc_serv; /* The RPC service which will */ /* process the callback */ unsigned int bc_alloc_count; /* Total number of preallocs */ @@ -209,7 +208,7 @@ struct rpc_xprt { * items */ struct list_head bc_pa_list; /* List of preallocated * backchannel rpc_rqst's */ -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ struct list_head recv; struct { @@ -229,15 +228,15 @@ struct rpc_xprt { const char *address_strings[RPC_DISPLAY_MAX]; }; -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) /* * Backchannel flags */ #define RPC_BC_PA_IN_USE 0x0001 /* Preallocated backchannel */ /* buffer in use */ -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) static inline int bc_prealloc(struct rpc_rqst *req) { return test_bit(RPC_BC_PA_IN_USE, &req->rq_bc_pa_state); @@ -247,7 +246,7 @@ static inline int bc_prealloc(struct rpc_rqst *req) { return 0; } -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ struct xprt_create { int ident; /* XPRT_TRANSPORT identifier */ @@ -272,8 +271,8 @@ struct xprt_class { struct rpc_xprt *xprt_create_transport(struct xprt_create *args); void xprt_connect(struct rpc_task *task); void xprt_reserve(struct rpc_task *task); -int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task); -int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); +int xprt_reserve_xprt(struct rpc_task *task); +int xprt_reserve_xprt_cong(struct rpc_task *task); int xprt_prepare_transmit(struct rpc_task *task); void xprt_transmit(struct rpc_task *task); void xprt_end_transmit(struct rpc_task *task); @@ -283,9 +282,7 @@ void xprt_release_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task); void xprt_release(struct rpc_task *task); struct rpc_xprt * xprt_get(struct rpc_xprt *xprt); void xprt_put(struct rpc_xprt *xprt); -struct rpc_xprt * xprt_alloc(struct net *net, size_t size, - unsigned int num_prealloc, - unsigned int max_req); +struct rpc_xprt * xprt_alloc(struct net *net, int size, int max_req); void xprt_free(struct rpc_xprt *); static inline __be32 *xprt_skip_transport_header(struct rpc_xprt *xprt, __be32 *p) @@ -324,6 +321,7 @@ void xprt_conditional_disconnect(struct rpc_xprt *xprt, unsigned int cookie); #define XPRT_CLOSING (6) #define XPRT_CONNECTION_ABORT (7) #define XPRT_CONNECTION_CLOSE (8) +#define XPRT_INITIALIZED (9) static inline void xprt_set_connected(struct rpc_xprt *xprt) { diff --git a/trunk/include/linux/wm97xx.h b/trunk/include/linux/wm97xx.h index fd98bb968219..38e8c4d9289e 100644 --- a/trunk/include/linux/wm97xx.h +++ b/trunk/include/linux/wm97xx.h @@ -38,11 +38,7 @@ #define WM97XX_ADCSEL_X 0x1000 /* x coord measurement */ #define WM97XX_ADCSEL_Y 0x2000 /* y coord measurement */ #define WM97XX_ADCSEL_PRES 0x3000 /* pressure measurement */ -#define WM97XX_AUX_ID1 0x4000 -#define WM97XX_AUX_ID2 0x5000 -#define WM97XX_AUX_ID3 0x6000 -#define WM97XX_AUX_ID4 0x7000 -#define WM97XX_ADCSEL_MASK 0x7000 /* ADC selection mask */ +#define WM97XX_ADCSEL_MASK 0x7000 #define WM97XX_COO 0x0800 /* enable coordinate mode */ #define WM97XX_CTC 0x0400 /* enable continuous mode */ #define WM97XX_CM_RATE_93 0x0000 /* 93.75Hz continuous rate */ @@ -65,6 +61,13 @@ #define WM97XX_PRP_DET_DIG 0xc000 /* setect on, digitise on */ #define WM97XX_RPR 0x2000 /* wake up on pen down */ #define WM97XX_PEN_DOWN 0x8000 /* pen is down */ +#define WM97XX_ADCSRC_MASK 0x7000 /* ADC source mask */ + +#define WM97XX_AUX_ID1 0x8001 +#define WM97XX_AUX_ID2 0x8002 +#define WM97XX_AUX_ID3 0x8003 +#define WM97XX_AUX_ID4 0x8004 + /* WM9712 Bits */ #define WM9712_45W 0x1000 /* set for 5-wire touchscreen */ diff --git a/trunk/include/scsi/iscsi_proto.h b/trunk/include/scsi/iscsi_proto.h index 988ba06b3ad6..ea68b3c56dbf 100644 --- a/trunk/include/scsi/iscsi_proto.h +++ b/trunk/include/scsi/iscsi_proto.h @@ -29,39 +29,9 @@ /* default iSCSI listen port for incoming connections */ #define ISCSI_LISTEN_PORT 3260 -/* iSCSI header length */ -#define ISCSI_HDR_LEN 48 - -/* iSCSI CRC32C length */ -#define ISCSI_CRC_LEN 4 - /* Padding word length */ #define ISCSI_PAD_LEN 4 -/* - * Serial Number Arithmetic, 32 bits, RFC1982 - */ - -static inline int iscsi_sna_lt(u32 n1, u32 n2) -{ - return (s32)(n1 - n2) < 0; -} - -static inline int iscsi_sna_lte(u32 n1, u32 n2) -{ - return (s32)(n1 - n2) <= 0; -} - -static inline int iscsi_sna_gt(u32 n1, u32 n2) -{ - return (s32)(n1 - n2) > 0; -} - -static inline int iscsi_sna_gte(u32 n1, u32 n2) -{ - return (s32)(n1 - n2) >= 0; -} - /* * useful common(control and data pathes) macro */ @@ -146,7 +116,7 @@ struct iscsi_ahs_hdr { #define ISCSI_CDB_SIZE 16 /* iSCSI PDU Header */ -struct iscsi_scsi_req { +struct iscsi_cmd { uint8_t opcode; uint8_t flags; __be16 rsvd2; @@ -191,7 +161,7 @@ struct iscsi_ecdb_ahdr { }; /* SCSI Response Header */ -struct iscsi_scsi_rsp { +struct iscsi_cmd_rsp { uint8_t opcode; uint8_t flags; uint8_t response; @@ -436,7 +406,7 @@ struct iscsi_text_rsp { }; /* Login Header */ -struct iscsi_login_req { +struct iscsi_login { uint8_t opcode; uint8_t flags; uint8_t max_version; /* Max. version supported */ @@ -457,13 +427,7 @@ struct iscsi_login_req { #define ISCSI_FLAG_LOGIN_TRANSIT 0x80 #define ISCSI_FLAG_LOGIN_CONTINUE 0x40 #define ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK 0x0C /* 2 bits */ -#define ISCSI_FLAG_LOGIN_CURRENT_STAGE1 0x04 -#define ISCSI_FLAG_LOGIN_CURRENT_STAGE2 0x08 -#define ISCSI_FLAG_LOGIN_CURRENT_STAGE3 0x0C #define ISCSI_FLAG_LOGIN_NEXT_STAGE_MASK 0x03 /* 2 bits */ -#define ISCSI_FLAG_LOGIN_NEXT_STAGE1 0x01 -#define ISCSI_FLAG_LOGIN_NEXT_STAGE2 0x02 -#define ISCSI_FLAG_LOGIN_NEXT_STAGE3 0x03 #define ISCSI_LOGIN_CURRENT_STAGE(flags) \ ((flags & ISCSI_FLAG_LOGIN_CURRENT_STAGE_MASK) >> 2) @@ -586,25 +550,17 @@ struct iscsi_logout_rsp { struct iscsi_snack { uint8_t opcode; uint8_t flags; - uint8_t rsvd2[2]; - uint8_t hlength; - uint8_t dlength[3]; - uint8_t lun[8]; + uint8_t rsvd2[14]; itt_t itt; - __be32 ttt; - uint8_t rsvd3[4]; - __be32 exp_statsn; - uint8_t rsvd4[8]; __be32 begrun; __be32 runlength; + __be32 exp_statsn; + __be32 rsvd3; + __be32 exp_datasn; + uint8_t rsvd6[8]; }; /* SNACK PDU flags */ -#define ISCSI_FLAG_SNACK_TYPE_DATA 0 -#define ISCSI_FLAG_SNACK_TYPE_R2T 0 -#define ISCSI_FLAG_SNACK_TYPE_STATUS 1 -#define ISCSI_FLAG_SNACK_TYPE_DATA_ACK 2 -#define ISCSI_FLAG_SNACK_TYPE_RDATA 3 #define ISCSI_FLAG_SNACK_TYPE_MASK 0x0F /* 4 bits */ /* Reject Message Header */ diff --git a/trunk/include/sound/pcm.h b/trunk/include/sound/pcm.h index 57e71fa33f7c..e1bad1130616 100644 --- a/trunk/include/sound/pcm.h +++ b/trunk/include/sound/pcm.h @@ -507,18 +507,6 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream); void snd_pcm_vma_notify_data(void *client, void *data); int snd_pcm_mmap_data(struct snd_pcm_substream *substream, struct file *file, struct vm_area_struct *area); - -#ifdef CONFIG_SND_DEBUG -void snd_pcm_debug_name(struct snd_pcm_substream *substream, - char *name, size_t len); -#else -static inline void -snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) -{ - *buf = 0; -} -#endif - /* * PCM library */ @@ -761,18 +749,17 @@ static inline const struct snd_interval *hw_param_interval_c(const struct snd_pc return ¶ms->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL]; } -#define params_channels(p) \ - (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min) -#define params_rate(p) \ - (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_RATE)->min) -#define params_period_size(p) \ - (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min) -#define params_periods(p) \ - (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_PERIODS)->min) -#define params_buffer_size(p) \ - (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min) -#define params_buffer_bytes(p) \ - (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min) +#define params_access(p) ((__force snd_pcm_access_t)snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_ACCESS))) +#define params_format(p) ((__force snd_pcm_format_t)snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_FORMAT))) +#define params_subformat(p) snd_mask_min(hw_param_mask((p), SNDRV_PCM_HW_PARAM_SUBFORMAT)) +#define params_channels(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min +#define params_rate(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_RATE)->min +#define params_period_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min +#define params_period_bytes(p) ((params_period_size(p)*snd_pcm_format_physical_width(params_format(p))*params_channels(p))/8) +#define params_periods(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_PERIODS)->min +#define params_buffer_size(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min +#define params_buffer_bytes(p) hw_param_interval((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min + int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v); void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c); diff --git a/trunk/include/sound/pcm_params.h b/trunk/include/sound/pcm_params.h index f494f1e3c900..85cf1cf4f31a 100644 --- a/trunk/include/sound/pcm_params.h +++ b/trunk/include/sound/pcm_params.h @@ -337,19 +337,5 @@ static inline unsigned int sub(unsigned int a, unsigned int b) return 0; } -#define params_access(p) ((__force snd_pcm_access_t)\ - snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_ACCESS))) -#define params_format(p) ((__force snd_pcm_format_t)\ - snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_FORMAT))) -#define params_subformat(p) \ - snd_mask_min(hw_param_mask_c((p), SNDRV_PCM_HW_PARAM_SUBFORMAT)) - -static inline unsigned int -params_period_bytes(const struct snd_pcm_hw_params *p) -{ - return (params_period_size(p) * - snd_pcm_format_physical_width(params_format(p)) * - params_channels(p)) / 8; -} - #endif /* __SOUND_PCM_PARAMS_H */ + diff --git a/trunk/include/sound/soc-dapm.h b/trunk/include/sound/soc-dapm.h index e0583b7769cb..e09505c5a490 100644 --- a/trunk/include/sound/soc-dapm.h +++ b/trunk/include/sound/soc-dapm.h @@ -266,12 +266,6 @@ .get = snd_soc_dapm_get_enum_virt, \ .put = snd_soc_dapm_put_enum_virt, \ .private_value = (unsigned long)&xenum } -#define SOC_DAPM_ENUM_EXT(xname, xenum, xget, xput) \ -{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ - .info = snd_soc_info_enum_double, \ - .get = xget, \ - .put = xput, \ - .private_value = (unsigned long)&xenum } #define SOC_DAPM_VALUE_ENUM(xname, xenum) \ { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \ .info = snd_soc_info_enum_double, \ diff --git a/trunk/kernel/compat.c b/trunk/kernel/compat.c index 616c78197cca..18197ae2d465 100644 --- a/trunk/kernel/compat.c +++ b/trunk/kernel/compat.c @@ -992,8 +992,11 @@ asmlinkage long compat_sys_rt_sigsuspend(compat_sigset_t __user *unewset, compat sigset_from_compat(&newset, &newset32); sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); + spin_lock_irq(¤t->sighand->siglock); current->saved_sigmask = current->blocked; - set_current_blocked(&newset); + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; schedule(); diff --git a/trunk/kernel/signal.c b/trunk/kernel/signal.c index 291c9700be75..d7f70aed1cc0 100644 --- a/trunk/kernel/signal.c +++ b/trunk/kernel/signal.c @@ -3102,11 +3102,15 @@ SYSCALL_DEFINE0(sgetmask) SYSCALL_DEFINE1(ssetmask, int, newmask) { - int old = current->blocked.sig[0]; - sigset_t newset; + int old; - siginitset(&newset, newmask & ~(sigmask(SIGKILL) | sigmask(SIGSTOP))); - set_current_blocked(&newset); + spin_lock_irq(¤t->sighand->siglock); + old = current->blocked.sig[0]; + + siginitset(¤t->blocked, newmask & ~(sigmask(SIGKILL)| + sigmask(SIGSTOP))); + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); return old; } @@ -3163,8 +3167,11 @@ SYSCALL_DEFINE2(rt_sigsuspend, sigset_t __user *, unewset, size_t, sigsetsize) return -EFAULT; sigdelsetmask(&newset, sigmask(SIGKILL)|sigmask(SIGSTOP)); + spin_lock_irq(¤t->sighand->siglock); current->saved_sigmask = current->blocked; - set_current_blocked(&newset); + current->blocked = newset; + recalc_sigpending(); + spin_unlock_irq(¤t->sighand->siglock); current->state = TASK_INTERRUPTIBLE; schedule(); diff --git a/trunk/net/socket.c b/trunk/net/socket.c index 26ed35c7751e..02dc82db3d23 100644 --- a/trunk/net/socket.c +++ b/trunk/net/socket.c @@ -467,7 +467,7 @@ static struct socket *sock_alloc(void) struct inode *inode; struct socket *sock; - inode = new_inode_pseudo(sock_mnt->mnt_sb); + inode = new_inode(sock_mnt->mnt_sb); if (!inode) return NULL; diff --git a/trunk/net/sunrpc/Kconfig b/trunk/net/sunrpc/Kconfig index ffd243d09188..b2198e65d8bb 100644 --- a/trunk/net/sunrpc/Kconfig +++ b/trunk/net/sunrpc/Kconfig @@ -4,10 +4,6 @@ config SUNRPC config SUNRPC_GSS tristate -config SUNRPC_BACKCHANNEL - bool - depends on SUNRPC - config SUNRPC_XPRT_RDMA tristate depends on SUNRPC && INFINIBAND && INFINIBAND_ADDR_TRANS && EXPERIMENTAL diff --git a/trunk/net/sunrpc/Makefile b/trunk/net/sunrpc/Makefile index 8209a0411bca..9d2fca5ad14a 100644 --- a/trunk/net/sunrpc/Makefile +++ b/trunk/net/sunrpc/Makefile @@ -13,6 +13,6 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \ addr.o rpcb_clnt.o timer.o xdr.o \ sunrpc_syms.o cache.o rpc_pipe.o \ svc_xprt.o -sunrpc-$(CONFIG_SUNRPC_BACKCHANNEL) += backchannel_rqst.o bc_svc.o +sunrpc-$(CONFIG_NFS_V4_1) += backchannel_rqst.o bc_svc.o sunrpc-$(CONFIG_PROC_FS) += stats.o sunrpc-$(CONFIG_SYSCTL) += sysctl.o diff --git a/trunk/net/sunrpc/backchannel_rqst.c b/trunk/net/sunrpc/backchannel_rqst.c index 91eaa26e4c42..cf06af3b63c6 100644 --- a/trunk/net/sunrpc/backchannel_rqst.c +++ b/trunk/net/sunrpc/backchannel_rqst.c @@ -29,6 +29,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #define RPCDBG_FACILITY RPCDBG_TRANS #endif +#if defined(CONFIG_NFS_V4_1) + /* * Helper routines that track the number of preallocation elements * on the transport. @@ -172,7 +174,7 @@ int xprt_setup_backchannel(struct rpc_xprt *xprt, unsigned int min_reqs) dprintk("RPC: setup backchannel transport failed\n"); return -1; } -EXPORT_SYMBOL_GPL(xprt_setup_backchannel); +EXPORT_SYMBOL(xprt_setup_backchannel); /* * Destroys the backchannel preallocated structures. @@ -202,7 +204,7 @@ void xprt_destroy_backchannel(struct rpc_xprt *xprt, unsigned int max_reqs) dprintk("RPC: backchannel list empty= %s\n", list_empty(&xprt->bc_pa_list) ? "true" : "false"); } -EXPORT_SYMBOL_GPL(xprt_destroy_backchannel); +EXPORT_SYMBOL(xprt_destroy_backchannel); /* * One or more rpc_rqst structure have been preallocated during the @@ -277,3 +279,4 @@ void xprt_free_bc_request(struct rpc_rqst *req) spin_unlock_bh(&xprt->bc_pa_lock); } +#endif /* CONFIG_NFS_V4_1 */ diff --git a/trunk/net/sunrpc/bc_svc.c b/trunk/net/sunrpc/bc_svc.c index 0b2eb388cbda..1dd1a6890007 100644 --- a/trunk/net/sunrpc/bc_svc.c +++ b/trunk/net/sunrpc/bc_svc.c @@ -27,6 +27,8 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * reply over an existing open connection previously established by the client. */ +#if defined(CONFIG_NFS_V4_1) + #include #include @@ -61,3 +63,4 @@ int bc_send(struct rpc_rqst *req) return ret; } +#endif /* CONFIG_NFS_V4_1 */ diff --git a/trunk/net/sunrpc/clnt.c b/trunk/net/sunrpc/clnt.c index c5347d29cfb7..c50818f0473b 100644 --- a/trunk/net/sunrpc/clnt.c +++ b/trunk/net/sunrpc/clnt.c @@ -64,9 +64,9 @@ static void call_decode(struct rpc_task *task); static void call_bind(struct rpc_task *task); static void call_bind_status(struct rpc_task *task); static void call_transmit(struct rpc_task *task); -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) static void call_bc_transmit(struct rpc_task *task); -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ static void call_status(struct rpc_task *task); static void call_transmit_status(struct rpc_task *task); static void call_refresh(struct rpc_task *task); @@ -715,7 +715,7 @@ rpc_call_async(struct rpc_clnt *clnt, const struct rpc_message *msg, int flags, } EXPORT_SYMBOL_GPL(rpc_call_async); -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) /** * rpc_run_bc_task - Allocate a new RPC task for backchannel use, then run * rpc_execute against it @@ -758,7 +758,7 @@ struct rpc_task *rpc_run_bc_task(struct rpc_rqst *req, dprintk("RPC: rpc_run_bc_task: task= %p\n", task); return task; } -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ void rpc_call_start(struct rpc_task *task) @@ -1361,7 +1361,7 @@ call_transmit_status(struct rpc_task *task) } } -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) /* * 5b. Send the backchannel RPC reply. On error, drop the reply. In * addition, disconnect on connectivity errors. @@ -1425,7 +1425,7 @@ call_bc_transmit(struct rpc_task *task) } rpc_wake_up_queued_task(&req->rq_xprt->pending, task); } -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ /* * 6. Sort out the RPC call status @@ -1550,7 +1550,8 @@ call_decode(struct rpc_task *task) kxdrdproc_t decode = task->tk_msg.rpc_proc->p_decode; __be32 *p; - dprint_status(task); + dprintk("RPC: %5u call_decode (status %d)\n", + task->tk_pid, task->tk_status); if (task->tk_flags & RPC_CALL_MAJORSEEN) { if (clnt->cl_chatty) diff --git a/trunk/net/sunrpc/sched.c b/trunk/net/sunrpc/sched.c index d12ffa545811..4814e246a874 100644 --- a/trunk/net/sunrpc/sched.c +++ b/trunk/net/sunrpc/sched.c @@ -97,16 +97,14 @@ __rpc_add_timer(struct rpc_wait_queue *queue, struct rpc_task *task) /* * Add new request to a priority queue. */ -static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, - struct rpc_task *task, - unsigned char queue_priority) +static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, struct rpc_task *task) { struct list_head *q; struct rpc_task *t; INIT_LIST_HEAD(&task->u.tk_wait.links); - q = &queue->tasks[queue_priority]; - if (unlikely(queue_priority > queue->maxpriority)) + q = &queue->tasks[task->tk_priority]; + if (unlikely(task->tk_priority > queue->maxpriority)) q = &queue->tasks[queue->maxpriority]; list_for_each_entry(t, q, u.tk_wait.list) { if (t->tk_owner == task->tk_owner) { @@ -125,14 +123,12 @@ static void __rpc_add_wait_queue_priority(struct rpc_wait_queue *queue, * improve overall performance. * Everyone else gets appended to the queue to ensure proper FIFO behavior. */ -static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, - struct rpc_task *task, - unsigned char queue_priority) +static void __rpc_add_wait_queue(struct rpc_wait_queue *queue, struct rpc_task *task) { BUG_ON (RPC_IS_QUEUED(task)); if (RPC_IS_PRIORITY(queue)) - __rpc_add_wait_queue_priority(queue, task, queue_priority); + __rpc_add_wait_queue_priority(queue, task); else if (RPC_IS_SWAPPER(task)) list_add(&task->u.tk_wait.list, &queue->tasks[0]); else @@ -315,15 +311,13 @@ static void rpc_make_runnable(struct rpc_task *task) * NB: An RPC task will only receive interrupt-driven events as long * as it's on a wait queue. */ -static void __rpc_sleep_on_priority(struct rpc_wait_queue *q, - struct rpc_task *task, - rpc_action action, - unsigned char queue_priority) +static void __rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, + rpc_action action) { dprintk("RPC: %5u sleep_on(queue \"%s\" time %lu)\n", task->tk_pid, rpc_qname(q), jiffies); - __rpc_add_wait_queue(q, task, queue_priority); + __rpc_add_wait_queue(q, task); BUG_ON(task->tk_callback != NULL); task->tk_callback = action; @@ -340,25 +334,11 @@ void rpc_sleep_on(struct rpc_wait_queue *q, struct rpc_task *task, * Protect the queue operations. */ spin_lock_bh(&q->lock); - __rpc_sleep_on_priority(q, task, action, task->tk_priority); + __rpc_sleep_on(q, task, action); spin_unlock_bh(&q->lock); } EXPORT_SYMBOL_GPL(rpc_sleep_on); -void rpc_sleep_on_priority(struct rpc_wait_queue *q, struct rpc_task *task, - rpc_action action, int priority) -{ - /* We shouldn't ever put an inactive task to sleep */ - BUG_ON(!RPC_IS_ACTIVATED(task)); - - /* - * Protect the queue operations. - */ - spin_lock_bh(&q->lock); - __rpc_sleep_on_priority(q, task, action, priority - RPC_PRIORITY_LOW); - spin_unlock_bh(&q->lock); -} - /** * __rpc_do_wake_up_task - wake up a single rpc_task * @queue: wait queue diff --git a/trunk/net/sunrpc/svc.c b/trunk/net/sunrpc/svc.c index 6a69a1131fb7..2b90292e9505 100644 --- a/trunk/net/sunrpc/svc.c +++ b/trunk/net/sunrpc/svc.c @@ -1252,7 +1252,7 @@ svc_process(struct svc_rqst *rqstp) } } -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) /* * Process a backchannel RPC request that arrived over an existing * outbound connection @@ -1300,8 +1300,8 @@ bc_svc_process(struct svc_serv *serv, struct rpc_rqst *req, return 0; } } -EXPORT_SYMBOL_GPL(bc_svc_process); -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +EXPORT_SYMBOL(bc_svc_process); +#endif /* CONFIG_NFS_V4_1 */ /* * Return (transport-specific) limit on the rpc payload. diff --git a/trunk/net/sunrpc/svcsock.c b/trunk/net/sunrpc/svcsock.c index 767d494de7a2..f2cb5b881dea 100644 --- a/trunk/net/sunrpc/svcsock.c +++ b/trunk/net/sunrpc/svcsock.c @@ -68,12 +68,12 @@ static void svc_sock_free(struct svc_xprt *); static struct svc_xprt *svc_create_socket(struct svc_serv *, int, struct net *, struct sockaddr *, int, int); -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) static struct svc_xprt *svc_bc_create_socket(struct svc_serv *, int, struct net *, struct sockaddr *, int, int); static void svc_bc_sock_free(struct svc_xprt *xprt); -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ #ifdef CONFIG_DEBUG_LOCK_ALLOC static struct lock_class_key svc_key[2]; @@ -1243,7 +1243,7 @@ static struct svc_xprt *svc_tcp_create(struct svc_serv *serv, return svc_create_socket(serv, IPPROTO_TCP, net, sa, salen, flags); } -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) static struct svc_xprt *svc_bc_create_socket(struct svc_serv *, int, struct net *, struct sockaddr *, int, int); @@ -1284,7 +1284,7 @@ static void svc_cleanup_bc_xprt_sock(void) { svc_unreg_xprt_class(&svc_tcp_bc_class); } -#else /* CONFIG_SUNRPC_BACKCHANNEL */ +#else /* CONFIG_NFS_V4_1 */ static void svc_init_bc_xprt_sock(void) { } @@ -1292,7 +1292,7 @@ static void svc_init_bc_xprt_sock(void) static void svc_cleanup_bc_xprt_sock(void) { } -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ static struct svc_xprt_ops svc_tcp_ops = { .xpo_create = svc_tcp_create, @@ -1623,7 +1623,7 @@ static void svc_sock_free(struct svc_xprt *xprt) kfree(svsk); } -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) /* * Create a back channel svc_xprt which shares the fore channel socket. */ @@ -1662,4 +1662,4 @@ static void svc_bc_sock_free(struct svc_xprt *xprt) if (xprt) kfree(container_of(xprt, struct svc_sock, sk_xprt)); } -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ diff --git a/trunk/net/sunrpc/xdr.c b/trunk/net/sunrpc/xdr.c index 277ebd4bf095..f008c14ad34c 100644 --- a/trunk/net/sunrpc/xdr.c +++ b/trunk/net/sunrpc/xdr.c @@ -126,7 +126,7 @@ xdr_terminate_string(struct xdr_buf *buf, const u32 len) kaddr[buf->page_base + len] = '\0'; kunmap_atomic(kaddr, KM_USER0); } -EXPORT_SYMBOL_GPL(xdr_terminate_string); +EXPORT_SYMBOL(xdr_terminate_string); void xdr_encode_pages(struct xdr_buf *xdr, struct page **pages, unsigned int base, diff --git a/trunk/net/sunrpc/xprt.c b/trunk/net/sunrpc/xprt.c index 9b6a4d1ea8f8..ce5eb68a9664 100644 --- a/trunk/net/sunrpc/xprt.c +++ b/trunk/net/sunrpc/xprt.c @@ -62,7 +62,6 @@ /* * Local functions */ -static void xprt_init(struct rpc_xprt *xprt, struct net *net); static void xprt_request_init(struct rpc_task *, struct rpc_xprt *); static void xprt_connect_status(struct rpc_task *task); static int __xprt_get_cong(struct rpc_xprt *, struct rpc_task *); @@ -192,10 +191,10 @@ EXPORT_SYMBOL_GPL(xprt_load_transport); * transport connects from colliding with writes. No congestion control * is provided. */ -int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) +int xprt_reserve_xprt(struct rpc_task *task) { struct rpc_rqst *req = task->tk_rqstp; - int priority; + struct rpc_xprt *xprt = req->rq_xprt; if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { if (task == xprt->snd_task) @@ -203,10 +202,8 @@ int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) goto out_sleep; } xprt->snd_task = task; - if (req != NULL) { - req->rq_bytes_sent = 0; - req->rq_ntrans++; - } + req->rq_bytes_sent = 0; + req->rq_ntrans++; return 1; @@ -215,13 +212,10 @@ int xprt_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) task->tk_pid, xprt); task->tk_timeout = 0; task->tk_status = -EAGAIN; - if (req == NULL) - priority = RPC_PRIORITY_LOW; - else if (!req->rq_ntrans) - priority = RPC_PRIORITY_NORMAL; + if (req->rq_ntrans) + rpc_sleep_on(&xprt->resend, task, NULL); else - priority = RPC_PRIORITY_HIGH; - rpc_sleep_on_priority(&xprt->sending, task, NULL, priority); + rpc_sleep_on(&xprt->sending, task, NULL); return 0; } EXPORT_SYMBOL_GPL(xprt_reserve_xprt); @@ -245,24 +239,22 @@ static void xprt_clear_locked(struct rpc_xprt *xprt) * integrated into the decision of whether a request is allowed to be * woken up and given access to the transport. */ -int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) +int xprt_reserve_xprt_cong(struct rpc_task *task) { + struct rpc_xprt *xprt = task->tk_xprt; struct rpc_rqst *req = task->tk_rqstp; - int priority; if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) { if (task == xprt->snd_task) return 1; goto out_sleep; } - if (req == NULL) { - xprt->snd_task = task; - return 1; - } if (__xprt_get_cong(xprt, task)) { xprt->snd_task = task; - req->rq_bytes_sent = 0; - req->rq_ntrans++; + if (req) { + req->rq_bytes_sent = 0; + req->rq_ntrans++; + } return 1; } xprt_clear_locked(xprt); @@ -270,13 +262,10 @@ int xprt_reserve_xprt_cong(struct rpc_xprt *xprt, struct rpc_task *task) dprintk("RPC: %5u failed to lock transport %p\n", task->tk_pid, xprt); task->tk_timeout = 0; task->tk_status = -EAGAIN; - if (req == NULL) - priority = RPC_PRIORITY_LOW; - else if (!req->rq_ntrans) - priority = RPC_PRIORITY_NORMAL; + if (req && req->rq_ntrans) + rpc_sleep_on(&xprt->resend, task, NULL); else - priority = RPC_PRIORITY_HIGH; - rpc_sleep_on_priority(&xprt->sending, task, NULL, priority); + rpc_sleep_on(&xprt->sending, task, NULL); return 0; } EXPORT_SYMBOL_GPL(xprt_reserve_xprt_cong); @@ -286,7 +275,7 @@ static inline int xprt_lock_write(struct rpc_xprt *xprt, struct rpc_task *task) int retval; spin_lock_bh(&xprt->transport_lock); - retval = xprt->ops->reserve_xprt(xprt, task); + retval = xprt->ops->reserve_xprt(task); spin_unlock_bh(&xprt->transport_lock); return retval; } @@ -299,9 +288,12 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt) if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) return; - task = rpc_wake_up_next(&xprt->sending); - if (task == NULL) - goto out_unlock; + task = rpc_wake_up_next(&xprt->resend); + if (!task) { + task = rpc_wake_up_next(&xprt->sending); + if (!task) + goto out_unlock; + } req = task->tk_rqstp; xprt->snd_task = task; @@ -318,25 +310,24 @@ static void __xprt_lock_write_next(struct rpc_xprt *xprt) static void __xprt_lock_write_next_cong(struct rpc_xprt *xprt) { struct rpc_task *task; - struct rpc_rqst *req; if (test_and_set_bit(XPRT_LOCKED, &xprt->state)) return; if (RPCXPRT_CONGESTED(xprt)) goto out_unlock; - task = rpc_wake_up_next(&xprt->sending); - if (task == NULL) - goto out_unlock; - - req = task->tk_rqstp; - if (req == NULL) { - xprt->snd_task = task; - return; + task = rpc_wake_up_next(&xprt->resend); + if (!task) { + task = rpc_wake_up_next(&xprt->sending); + if (!task) + goto out_unlock; } if (__xprt_get_cong(xprt, task)) { + struct rpc_rqst *req = task->tk_rqstp; xprt->snd_task = task; - req->rq_bytes_sent = 0; - req->rq_ntrans++; + if (req) { + req->rq_bytes_sent = 0; + req->rq_ntrans++; + } return; } out_unlock: @@ -861,7 +852,7 @@ int xprt_prepare_transmit(struct rpc_task *task) err = req->rq_reply_bytes_recvd; goto out_unlock; } - if (!xprt->ops->reserve_xprt(xprt, task)) + if (!xprt->ops->reserve_xprt(task)) err = -EAGAIN; out_unlock: spin_unlock_bh(&xprt->transport_lock); @@ -937,66 +928,28 @@ void xprt_transmit(struct rpc_task *task) spin_unlock_bh(&xprt->transport_lock); } -static struct rpc_rqst *xprt_dynamic_alloc_slot(struct rpc_xprt *xprt, gfp_t gfp_flags) -{ - struct rpc_rqst *req = ERR_PTR(-EAGAIN); - - if (!atomic_add_unless(&xprt->num_reqs, 1, xprt->max_reqs)) - goto out; - req = kzalloc(sizeof(struct rpc_rqst), gfp_flags); - if (req != NULL) - goto out; - atomic_dec(&xprt->num_reqs); - req = ERR_PTR(-ENOMEM); -out: - return req; -} - -static bool xprt_dynamic_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) -{ - if (atomic_add_unless(&xprt->num_reqs, -1, xprt->min_reqs)) { - kfree(req); - return true; - } - return false; -} - static void xprt_alloc_slot(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - struct rpc_rqst *req; + task->tk_status = 0; + if (task->tk_rqstp) + return; if (!list_empty(&xprt->free)) { - req = list_entry(xprt->free.next, struct rpc_rqst, rq_list); - list_del(&req->rq_list); - goto out_init_req; - } - req = xprt_dynamic_alloc_slot(xprt, GFP_NOWAIT); - if (!IS_ERR(req)) - goto out_init_req; - switch (PTR_ERR(req)) { - case -ENOMEM: - rpc_delay(task, HZ >> 2); - dprintk("RPC: dynamic allocation of request slot " - "failed! Retrying\n"); - break; - case -EAGAIN: - rpc_sleep_on(&xprt->backlog, task, NULL); - dprintk("RPC: waiting for request slot\n"); + struct rpc_rqst *req = list_entry(xprt->free.next, struct rpc_rqst, rq_list); + list_del_init(&req->rq_list); + task->tk_rqstp = req; + xprt_request_init(task, xprt); + return; } + dprintk("RPC: waiting for request slot\n"); task->tk_status = -EAGAIN; - return; -out_init_req: - task->tk_status = 0; - task->tk_rqstp = req; - xprt_request_init(task, xprt); + task->tk_timeout = 0; + rpc_sleep_on(&xprt->backlog, task, NULL); } static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) { - if (xprt_dynamic_free_slot(xprt, req)) - return; - memset(req, 0, sizeof(*req)); /* mark unused */ spin_lock(&xprt->reserve_lock); @@ -1005,49 +958,25 @@ static void xprt_free_slot(struct rpc_xprt *xprt, struct rpc_rqst *req) spin_unlock(&xprt->reserve_lock); } -static void xprt_free_all_slots(struct rpc_xprt *xprt) -{ - struct rpc_rqst *req; - while (!list_empty(&xprt->free)) { - req = list_first_entry(&xprt->free, struct rpc_rqst, rq_list); - list_del(&req->rq_list); - kfree(req); - } -} - -struct rpc_xprt *xprt_alloc(struct net *net, size_t size, - unsigned int num_prealloc, - unsigned int max_alloc) +struct rpc_xprt *xprt_alloc(struct net *net, int size, int max_req) { struct rpc_xprt *xprt; - struct rpc_rqst *req; - int i; xprt = kzalloc(size, GFP_KERNEL); if (xprt == NULL) goto out; + atomic_set(&xprt->count, 1); - xprt_init(xprt, net); - - for (i = 0; i < num_prealloc; i++) { - req = kzalloc(sizeof(struct rpc_rqst), GFP_KERNEL); - if (!req) - break; - list_add(&req->rq_list, &xprt->free); - } - if (i < num_prealloc) + xprt->max_reqs = max_req; + xprt->slot = kcalloc(max_req, sizeof(struct rpc_rqst), GFP_KERNEL); + if (xprt->slot == NULL) goto out_free; - if (max_alloc > num_prealloc) - xprt->max_reqs = max_alloc; - else - xprt->max_reqs = num_prealloc; - xprt->min_reqs = num_prealloc; - atomic_set(&xprt->num_reqs, num_prealloc); + xprt->xprt_net = get_net(net); return xprt; out_free: - xprt_free(xprt); + kfree(xprt); out: return NULL; } @@ -1056,7 +985,7 @@ EXPORT_SYMBOL_GPL(xprt_alloc); void xprt_free(struct rpc_xprt *xprt) { put_net(xprt->xprt_net); - xprt_free_all_slots(xprt); + kfree(xprt->slot); kfree(xprt); } EXPORT_SYMBOL_GPL(xprt_free); @@ -1072,24 +1001,10 @@ void xprt_reserve(struct rpc_task *task) { struct rpc_xprt *xprt = task->tk_xprt; - task->tk_status = 0; - if (task->tk_rqstp != NULL) - return; - - /* Note: grabbing the xprt_lock_write() here is not strictly needed, - * but ensures that we throttle new slot allocation if the transport - * is congested (e.g. if reconnecting or if we're out of socket - * write buffer space). - */ - task->tk_timeout = 0; - task->tk_status = -EAGAIN; - if (!xprt_lock_write(xprt, task)) - return; - + task->tk_status = -EIO; spin_lock(&xprt->reserve_lock); xprt_alloc_slot(task); spin_unlock(&xprt->reserve_lock); - xprt_release_write(xprt, task); } static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt) @@ -1106,7 +1021,6 @@ static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt) { struct rpc_rqst *req = task->tk_rqstp; - INIT_LIST_HEAD(&req->rq_list); req->rq_timeout = task->tk_client->cl_timeout->to_initval; req->rq_task = task; req->rq_xprt = xprt; @@ -1159,34 +1073,6 @@ void xprt_release(struct rpc_task *task) xprt_free_bc_request(req); } -static void xprt_init(struct rpc_xprt *xprt, struct net *net) -{ - atomic_set(&xprt->count, 1); - - spin_lock_init(&xprt->transport_lock); - spin_lock_init(&xprt->reserve_lock); - - INIT_LIST_HEAD(&xprt->free); - INIT_LIST_HEAD(&xprt->recv); -#if defined(CONFIG_SUNRPC_BACKCHANNEL) - spin_lock_init(&xprt->bc_pa_lock); - INIT_LIST_HEAD(&xprt->bc_pa_list); -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ - - xprt->last_used = jiffies; - xprt->cwnd = RPC_INITCWND; - xprt->bind_index = 0; - - rpc_init_wait_queue(&xprt->binding, "xprt_binding"); - rpc_init_wait_queue(&xprt->pending, "xprt_pending"); - rpc_init_priority_wait_queue(&xprt->sending, "xprt_sending"); - rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog"); - - xprt_init_xid(xprt); - - xprt->xprt_net = get_net(net); -} - /** * xprt_create_transport - create an RPC transport * @args: rpc transport creation arguments @@ -1195,6 +1081,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net) struct rpc_xprt *xprt_create_transport(struct xprt_create *args) { struct rpc_xprt *xprt; + struct rpc_rqst *req; struct xprt_class *t; spin_lock(&xprt_list_lock); @@ -1213,17 +1100,46 @@ struct rpc_xprt *xprt_create_transport(struct xprt_create *args) if (IS_ERR(xprt)) { dprintk("RPC: xprt_create_transport: failed, %ld\n", -PTR_ERR(xprt)); - goto out; + return xprt; } + if (test_and_set_bit(XPRT_INITIALIZED, &xprt->state)) + /* ->setup returned a pre-initialized xprt: */ + return xprt; + + spin_lock_init(&xprt->transport_lock); + spin_lock_init(&xprt->reserve_lock); + + INIT_LIST_HEAD(&xprt->free); + INIT_LIST_HEAD(&xprt->recv); +#if defined(CONFIG_NFS_V4_1) + spin_lock_init(&xprt->bc_pa_lock); + INIT_LIST_HEAD(&xprt->bc_pa_list); +#endif /* CONFIG_NFS_V4_1 */ + INIT_WORK(&xprt->task_cleanup, xprt_autoclose); if (xprt_has_timer(xprt)) setup_timer(&xprt->timer, xprt_init_autodisconnect, (unsigned long)xprt); else init_timer(&xprt->timer); + xprt->last_used = jiffies; + xprt->cwnd = RPC_INITCWND; + xprt->bind_index = 0; + + rpc_init_wait_queue(&xprt->binding, "xprt_binding"); + rpc_init_wait_queue(&xprt->pending, "xprt_pending"); + rpc_init_wait_queue(&xprt->sending, "xprt_sending"); + rpc_init_wait_queue(&xprt->resend, "xprt_resend"); + rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog"); + + /* initialize free list */ + for (req = &xprt->slot[xprt->max_reqs-1]; req >= &xprt->slot[0]; req--) + list_add(&req->rq_list, &xprt->free); + + xprt_init_xid(xprt); + dprintk("RPC: created transport %p with %u slots\n", xprt, xprt->max_reqs); -out: return xprt; } @@ -1241,6 +1157,7 @@ static void xprt_destroy(struct rpc_xprt *xprt) rpc_destroy_wait_queue(&xprt->binding); rpc_destroy_wait_queue(&xprt->pending); rpc_destroy_wait_queue(&xprt->sending); + rpc_destroy_wait_queue(&xprt->resend); rpc_destroy_wait_queue(&xprt->backlog); cancel_work_sync(&xprt->task_cleanup); /* diff --git a/trunk/net/sunrpc/xprtrdma/transport.c b/trunk/net/sunrpc/xprtrdma/transport.c index b446e100286f..0867070bb5ca 100644 --- a/trunk/net/sunrpc/xprtrdma/transport.c +++ b/trunk/net/sunrpc/xprtrdma/transport.c @@ -283,7 +283,6 @@ xprt_setup_rdma(struct xprt_create *args) } xprt = xprt_alloc(args->net, sizeof(struct rpcrdma_xprt), - xprt_rdma_slot_table_entries, xprt_rdma_slot_table_entries); if (xprt == NULL) { dprintk("RPC: %s: couldn't allocate rpcrdma_xprt\n", @@ -453,8 +452,9 @@ xprt_rdma_connect(struct rpc_task *task) } static int -xprt_rdma_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) +xprt_rdma_reserve_xprt(struct rpc_task *task) { + struct rpc_xprt *xprt = task->tk_xprt; struct rpcrdma_xprt *r_xprt = rpcx_to_rdmax(xprt); int credits = atomic_read(&r_xprt->rx_buf.rb_credits); @@ -466,7 +466,7 @@ xprt_rdma_reserve_xprt(struct rpc_xprt *xprt, struct rpc_task *task) BUG_ON(r_xprt->rx_buf.rb_cwndscale <= 0); } xprt->cwnd = credits * r_xprt->rx_buf.rb_cwndscale; - return xprt_reserve_xprt_cong(xprt, task); + return xprt_reserve_xprt_cong(task); } /* diff --git a/trunk/net/sunrpc/xprtrdma/xprt_rdma.h b/trunk/net/sunrpc/xprtrdma/xprt_rdma.h index 08c5d5a128fc..ddf05288d9f1 100644 --- a/trunk/net/sunrpc/xprtrdma/xprt_rdma.h +++ b/trunk/net/sunrpc/xprtrdma/xprt_rdma.h @@ -109,7 +109,7 @@ struct rpcrdma_ep { */ /* temporary static scatter/gather max */ -#define RPCRDMA_MAX_DATA_SEGS (64) /* max scatter/gather */ +#define RPCRDMA_MAX_DATA_SEGS (8) /* max scatter/gather */ #define RPCRDMA_MAX_SEGS (RPCRDMA_MAX_DATA_SEGS + 2) /* head+tail = 2 */ #define MAX_RPCRDMAHDR (\ /* max supported RPC/RDMA header */ \ diff --git a/trunk/net/sunrpc/xprtsock.c b/trunk/net/sunrpc/xprtsock.c index d7f97ef26590..72abb7358933 100644 --- a/trunk/net/sunrpc/xprtsock.c +++ b/trunk/net/sunrpc/xprtsock.c @@ -37,7 +37,7 @@ #include #include #include -#ifdef CONFIG_SUNRPC_BACKCHANNEL +#ifdef CONFIG_NFS_V4_1 #include #endif @@ -54,8 +54,7 @@ static void xs_close(struct rpc_xprt *xprt); * xprtsock tunables */ unsigned int xprt_udp_slot_table_entries = RPC_DEF_SLOT_TABLE; -unsigned int xprt_tcp_slot_table_entries = RPC_MIN_SLOT_TABLE; -unsigned int xprt_max_tcp_slot_table_entries = RPC_MAX_SLOT_TABLE; +unsigned int xprt_tcp_slot_table_entries = RPC_DEF_SLOT_TABLE; unsigned int xprt_min_resvport = RPC_DEF_MIN_RESVPORT; unsigned int xprt_max_resvport = RPC_DEF_MAX_RESVPORT; @@ -76,7 +75,6 @@ static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO; static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE; static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE; -static unsigned int max_tcp_slot_table_limit = RPC_MAX_SLOT_TABLE_LIMIT; static unsigned int xprt_min_resvport_limit = RPC_MIN_RESVPORT; static unsigned int xprt_max_resvport_limit = RPC_MAX_RESVPORT; @@ -105,15 +103,6 @@ static ctl_table xs_tunables_table[] = { .extra1 = &min_slot_table_size, .extra2 = &max_slot_table_size }, - { - .procname = "tcp_max_slot_table_entries", - .data = &xprt_max_tcp_slot_table_entries, - .maxlen = sizeof(unsigned int), - .mode = 0644, - .proc_handler = proc_dointvec_minmax, - .extra1 = &min_slot_table_size, - .extra2 = &max_tcp_slot_table_limit - }, { .procname = "min_resvport", .data = &xprt_min_resvport, @@ -766,8 +755,6 @@ static void xs_tcp_release_xprt(struct rpc_xprt *xprt, struct rpc_task *task) if (task == NULL) goto out_release; req = task->tk_rqstp; - if (req == NULL) - goto out_release; if (req->rq_bytes_sent == 0) goto out_release; if (req->rq_bytes_sent == req->rq_snd_buf.len) @@ -1249,7 +1236,7 @@ static inline int xs_tcp_read_reply(struct rpc_xprt *xprt, return 0; } -#if defined(CONFIG_SUNRPC_BACKCHANNEL) +#if defined(CONFIG_NFS_V4_1) /* * Obtains an rpc_rqst previously allocated and invokes the common * tcp read code to read the data. The result is placed in the callback @@ -1312,7 +1299,7 @@ static inline int _xs_tcp_read_data(struct rpc_xprt *xprt, { return xs_tcp_read_reply(xprt, desc); } -#endif /* CONFIG_SUNRPC_BACKCHANNEL */ +#endif /* CONFIG_NFS_V4_1 */ /* * Read data off the transport. This can be either an RPC_CALL or an @@ -2502,8 +2489,7 @@ static int xs_init_anyaddr(const int family, struct sockaddr *sap) } static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, - unsigned int slot_table_size, - unsigned int max_slot_table_size) + unsigned int slot_table_size) { struct rpc_xprt *xprt; struct sock_xprt *new; @@ -2513,8 +2499,7 @@ static struct rpc_xprt *xs_setup_xprt(struct xprt_create *args, return ERR_PTR(-EBADF); } - xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size, - max_slot_table_size); + xprt = xprt_alloc(args->net, sizeof(*new), slot_table_size); if (xprt == NULL) { dprintk("RPC: xs_setup_xprt: couldn't allocate " "rpc_xprt\n"); @@ -2556,8 +2541,7 @@ static struct rpc_xprt *xs_setup_local(struct xprt_create *args) struct rpc_xprt *xprt; struct rpc_xprt *ret; - xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, - xprt_max_tcp_slot_table_entries); + xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); if (IS_ERR(xprt)) return xprt; transport = container_of(xprt, struct sock_xprt, xprt); @@ -2621,8 +2605,7 @@ static struct rpc_xprt *xs_setup_udp(struct xprt_create *args) struct sock_xprt *transport; struct rpc_xprt *ret; - xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries, - xprt_udp_slot_table_entries); + xprt = xs_setup_xprt(args, xprt_udp_slot_table_entries); if (IS_ERR(xprt)) return xprt; transport = container_of(xprt, struct sock_xprt, xprt); @@ -2698,8 +2681,7 @@ static struct rpc_xprt *xs_setup_tcp(struct xprt_create *args) struct sock_xprt *transport; struct rpc_xprt *ret; - xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, - xprt_max_tcp_slot_table_entries); + xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); if (IS_ERR(xprt)) return xprt; transport = container_of(xprt, struct sock_xprt, xprt); @@ -2778,8 +2760,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args) */ return args->bc_xprt->xpt_bc_xprt; } - xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries, - xprt_tcp_slot_table_entries); + xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries); if (IS_ERR(xprt)) return xprt; transport = container_of(xprt, struct sock_xprt, xprt); @@ -2966,26 +2947,8 @@ static struct kernel_param_ops param_ops_slot_table_size = { #define param_check_slot_table_size(name, p) \ __param_check(name, p, unsigned int); -static int param_set_max_slot_table_size(const char *val, - const struct kernel_param *kp) -{ - return param_set_uint_minmax(val, kp, - RPC_MIN_SLOT_TABLE, - RPC_MAX_SLOT_TABLE_LIMIT); -} - -static struct kernel_param_ops param_ops_max_slot_table_size = { - .set = param_set_max_slot_table_size, - .get = param_get_uint, -}; - -#define param_check_max_slot_table_size(name, p) \ - __param_check(name, p, unsigned int); - module_param_named(tcp_slot_table_entries, xprt_tcp_slot_table_entries, slot_table_size, 0644); -module_param_named(tcp_max_slot_table_entries, xprt_max_tcp_slot_table_entries, - max_slot_table_size, 0644); module_param_named(udp_slot_table_entries, xprt_udp_slot_table_entries, slot_table_size, 0644); diff --git a/trunk/security/integrity/ima/ima_main.c b/trunk/security/integrity/ima/ima_main.c index 26b46ff74663..39d66dc2b8e9 100644 --- a/trunk/security/integrity/ima/ima_main.c +++ b/trunk/security/integrity/ima/ima_main.c @@ -86,7 +86,7 @@ static void ima_check_last_writer(struct ima_iint_cache *iint, struct inode *inode, struct file *file) { - fmode_t mode = file->f_mode; + mode_t mode = file->f_mode; mutex_lock(&iint->mutex); if (mode & FMODE_WRITE && diff --git a/trunk/sound/core/pcm_lib.c b/trunk/sound/core/pcm_lib.c index 86d0caf91b35..f1341308beda 100644 --- a/trunk/sound/core/pcm_lib.c +++ b/trunk/sound/core/pcm_lib.c @@ -128,8 +128,7 @@ void snd_pcm_playback_silence(struct snd_pcm_substream *substream, snd_pcm_ufram } } -#ifdef CONFIG_SND_DEBUG -void snd_pcm_debug_name(struct snd_pcm_substream *substream, +static void pcm_debug_name(struct snd_pcm_substream *substream, char *name, size_t len) { snprintf(name, len, "pcmC%dD%d%c:%d", @@ -138,8 +137,6 @@ void snd_pcm_debug_name(struct snd_pcm_substream *substream, substream->stream ? 'c' : 'p', substream->number); } -EXPORT_SYMBOL(snd_pcm_debug_name); -#endif #define XRUN_DEBUG_BASIC (1<<0) #define XRUN_DEBUG_STACK (1<<1) /* dump also stack */ @@ -171,7 +168,7 @@ static void xrun(struct snd_pcm_substream *substream) snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN); if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { char name[16]; - snd_pcm_debug_name(substream, name, sizeof(name)); + pcm_debug_name(substream, name, sizeof(name)); snd_printd(KERN_DEBUG "XRUN: %s\n", name); dump_stack_on_xrun(substream); } @@ -246,7 +243,7 @@ static void xrun_log_show(struct snd_pcm_substream *substream) return; if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit) return; - snd_pcm_debug_name(substream, name, sizeof(name)); + pcm_debug_name(substream, name, sizeof(name)); for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) { entry = &log->entries[idx]; if (entry->period_size == 0) @@ -322,7 +319,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (pos >= runtime->buffer_size) { if (printk_ratelimit()) { char name[16]; - snd_pcm_debug_name(substream, name, sizeof(name)); + pcm_debug_name(substream, name, sizeof(name)); xrun_log_show(substream); snd_printd(KERN_ERR "BUG: %s, pos = %ld, " "buffer size = %ld, period size = %ld\n", @@ -367,7 +364,7 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream, if (xrun_debug(substream, in_interrupt ? XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) { char name[16]; - snd_pcm_debug_name(substream, name, sizeof(name)); + pcm_debug_name(substream, name, sizeof(name)); snd_printd("%s_update: %s: pos=%u/%u/%u, " "hwptr=%ld/%ld/%ld/%ld\n", in_interrupt ? "period" : "hwptr", diff --git a/trunk/sound/isa/msnd/msnd.h b/trunk/sound/isa/msnd/msnd.h index a168ba3313ac..3773e242b58e 100644 --- a/trunk/sound/isa/msnd/msnd.h +++ b/trunk/sound/isa/msnd/msnd.h @@ -249,7 +249,7 @@ struct snd_msnd { /* State variables */ enum { msndClassic, msndPinnacle } type; - fmode_t mode; + mode_t mode; unsigned long flags; #define F_RESETTING 0 #define F_HAVEDIGITAL 1 diff --git a/trunk/sound/pci/asihpi/asihpi.c b/trunk/sound/pci/asihpi/asihpi.c index eae62ebbd295..b941d2541dda 100644 --- a/trunk/sound/pci/asihpi/asihpi.c +++ b/trunk/sound/pci/asihpi/asihpi.c @@ -41,10 +41,31 @@ #include #include + MODULE_LICENSE("GPL"); MODULE_AUTHOR("AudioScience inc. "); MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx"); +#if defined CONFIG_SND_DEBUG +/* copied from pcm_lib.c, hope later patch will make that version public +and this copy can be removed */ +static inline void +snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) +{ + snprintf(buf, size, "pcmC%dD%d%c:%d", + substream->pcm->card->number, + substream->pcm->device, + substream->stream ? 'c' : 'p', + substream->number); +} +#else +static inline void +snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size) +{ + *buf = 0; +} +#endif + #if defined CONFIG_SND_DEBUG_VERBOSE /** * snd_printddd - very verbose debug printk diff --git a/trunk/sound/pci/hda/Kconfig b/trunk/sound/pci/hda/Kconfig index bb7e102d6726..7489b4608551 100644 --- a/trunk/sound/pci/hda/Kconfig +++ b/trunk/sound/pci/hda/Kconfig @@ -243,7 +243,6 @@ config SND_HDA_GENERIC config SND_HDA_POWER_SAVE bool "Aggressive power-saving on HD-audio" - depends on PM help Say Y here to enable more aggressive power-saving mode on HD-audio driver. The power-saving timeout can be configured diff --git a/trunk/sound/pci/hda/hda_codec.c b/trunk/sound/pci/hda/hda_codec.c index 3e7850c238c3..9c27a3a4c4d5 100644 --- a/trunk/sound/pci/hda/hda_codec.c +++ b/trunk/sound/pci/hda/hda_codec.c @@ -91,10 +91,8 @@ EXPORT_SYMBOL_HDA(snd_hda_delete_codec_preset); #ifdef CONFIG_SND_HDA_POWER_SAVE static void hda_power_work(struct work_struct *work); static void hda_keep_power_on(struct hda_codec *codec); -#define hda_codec_is_power_on(codec) ((codec)->power_on) #else static inline void hda_keep_power_on(struct hda_codec *codec) {} -#define hda_codec_is_power_on(codec) 1 #endif /** @@ -1103,7 +1101,7 @@ void snd_hda_shutup_pins(struct hda_codec *codec) } EXPORT_SYMBOL_HDA(snd_hda_shutup_pins); -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ static void restore_shutup_pins(struct hda_codec *codec) { @@ -1501,7 +1499,7 @@ static void purify_inactive_streams(struct hda_codec *codec) } } -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME /* clean up all streams; called from suspend */ static void hda_cleanup_all_streams(struct hda_codec *codec) { @@ -1840,7 +1838,7 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, } EXPORT_SYMBOL_HDA(snd_hda_codec_amp_stereo); -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME /** * snd_hda_codec_resume_amp - Resume all AMP commands from the cache * @codec: HD-audio codec @@ -1870,7 +1868,7 @@ void snd_hda_codec_resume_amp(struct hda_codec *codec) } } EXPORT_SYMBOL_HDA(snd_hda_codec_resume_amp); -#endif /* CONFIG_PM */ +#endif /* SND_HDA_NEEDS_RESUME */ static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir, unsigned int ofs) @@ -3084,7 +3082,7 @@ int snd_hda_create_spdif_in_ctls(struct hda_codec *codec, hda_nid_t nid) } EXPORT_SYMBOL_HDA(snd_hda_create_spdif_in_ctls); -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME /* * command cache */ @@ -3201,32 +3199,53 @@ void snd_hda_sequence_write_cache(struct hda_codec *codec, seq->param); } EXPORT_SYMBOL_HDA(snd_hda_sequence_write_cache); -#endif /* CONFIG_PM */ +#endif /* SND_HDA_NEEDS_RESUME */ -void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state, - bool eapd_workaround) +/* + * set power state of the codec + */ +static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, + unsigned int power_state) { - hda_nid_t nid = codec->start_nid; + hda_nid_t nid; int i; + /* this delay seems necessary to avoid click noise at power-down */ + if (power_state == AC_PWRST_D3) + msleep(100); + snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, + power_state); + /* partial workaround for "azx_get_response timeout" */ + if (power_state == AC_PWRST_D0 && + (codec->vendor_id & 0xffff0000) == 0x14f10000) + msleep(10); + + nid = codec->start_nid; for (i = 0; i < codec->num_nodes; i++, nid++) { unsigned int wcaps = get_wcaps(codec, nid); - if (!(wcaps & AC_WCAP_POWER)) - continue; - /* don't power down the widget if it controls eapd and - * EAPD_BTLENABLE is set. - */ - if (eapd_workaround && power_state == AC_PWRST_D3 && - get_wcaps_type(wcaps) == AC_WID_PIN && - (snd_hda_query_pin_caps(codec, nid) & AC_PINCAP_EAPD)) { - int eapd = snd_hda_codec_read(codec, nid, 0, + if (wcaps & AC_WCAP_POWER) { + unsigned int wid_type = get_wcaps_type(wcaps); + if (power_state == AC_PWRST_D3 && + wid_type == AC_WID_PIN) { + unsigned int pincap; + /* + * don't power down the widget if it controls + * eapd and EAPD_BTLENABLE is set. + */ + pincap = snd_hda_query_pin_caps(codec, nid); + if (pincap & AC_PINCAP_EAPD) { + int eapd = snd_hda_codec_read(codec, + nid, 0, AC_VERB_GET_EAPD_BTLENABLE, 0); - if (eapd & 0x02) - continue; + eapd &= 0x02; + if (eapd) + continue; + } + } + snd_hda_codec_write(codec, nid, 0, + AC_VERB_SET_POWER_STATE, + power_state); } - snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_POWER_STATE, - power_state); } if (power_state == AC_PWRST_D0) { @@ -3243,26 +3262,6 @@ void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, } while (time_after_eq(end_time, jiffies)); } } -EXPORT_SYMBOL_HDA(snd_hda_codec_set_power_to_all); - -/* - * set power state of the codec - */ -static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state) -{ - if (codec->patch_ops.set_power_state) { - codec->patch_ops.set_power_state(codec, fg, power_state); - return; - } - - /* this delay seems necessary to avoid click noise at power-down */ - if (power_state == AC_PWRST_D3) - msleep(100); - snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, - power_state); - snd_hda_codec_set_power_to_all(codec, fg, power_state, true); -} #ifdef CONFIG_SND_HDA_HWDEP /* execute additional init verbs */ @@ -3275,7 +3274,7 @@ static void hda_exec_init_verbs(struct hda_codec *codec) static inline void hda_exec_init_verbs(struct hda_codec *codec) {} #endif -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME /* * call suspend and power-down; used both from PM and power-save */ @@ -3316,7 +3315,7 @@ static void hda_call_codec_resume(struct hda_codec *codec) snd_hda_codec_resume_cache(codec); } } -#endif /* CONFIG_PM */ +#endif /* SND_HDA_NEEDS_RESUME */ /** @@ -4072,6 +4071,9 @@ int snd_hda_add_new_ctls(struct hda_codec *codec, EXPORT_SYMBOL_HDA(snd_hda_add_new_ctls); #ifdef CONFIG_SND_HDA_POWER_SAVE +static void hda_set_power_state(struct hda_codec *codec, hda_nid_t fg, + unsigned int power_state); + static void hda_power_work(struct work_struct *work) { struct hda_codec *codec = @@ -4374,8 +4376,11 @@ void snd_hda_bus_reboot_notify(struct hda_bus *bus) if (!bus) return; list_for_each_entry(codec, &bus->codec_list, list) { - if (hda_codec_is_power_on(codec) && - codec->patch_ops.reboot_notify) +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!codec->power_on) + continue; +#endif + if (codec->patch_ops.reboot_notify) codec->patch_ops.reboot_notify(codec); } } @@ -5074,10 +5079,11 @@ int snd_hda_suspend(struct hda_bus *bus) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { - if (hda_codec_is_power_on(codec)) - hda_call_codec_suspend(codec); - if (codec->patch_ops.post_suspend) - codec->patch_ops.post_suspend(codec); +#ifdef CONFIG_SND_HDA_POWER_SAVE + if (!codec->power_on) + continue; +#endif + hda_call_codec_suspend(codec); } return 0; } @@ -5097,8 +5103,6 @@ int snd_hda_resume(struct hda_bus *bus) struct hda_codec *codec; list_for_each_entry(codec, &bus->codec_list, list) { - if (codec->patch_ops.pre_resume) - codec->patch_ops.pre_resume(codec); if (snd_hda_codec_needs_resume(codec)) hda_call_codec_resume(codec); } diff --git a/trunk/sound/pci/hda/hda_codec.h b/trunk/sound/pci/hda/hda_codec.h index 755f2b0f9d8e..f465e07a4879 100644 --- a/trunk/sound/pci/hda/hda_codec.h +++ b/trunk/sound/pci/hda/hda_codec.h @@ -26,6 +26,10 @@ #include #include +#if defined(CONFIG_PM) || defined(CONFIG_SND_HDA_POWER_SAVE) +#define SND_HDA_NEEDS_RESUME /* resume control code is required */ +#endif + /* * nodes */ @@ -700,12 +704,8 @@ struct hda_codec_ops { int (*init)(struct hda_codec *codec); void (*free)(struct hda_codec *codec); void (*unsol_event)(struct hda_codec *codec, unsigned int res); - void (*set_power_state)(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state); -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME int (*suspend)(struct hda_codec *codec, pm_message_t state); - int (*post_suspend)(struct hda_codec *codec); - int (*pre_resume)(struct hda_codec *codec); int (*resume)(struct hda_codec *codec); #endif #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -927,7 +927,7 @@ void snd_hda_sequence_write(struct hda_codec *codec, int snd_hda_queue_unsol_event(struct hda_bus *bus, u32 res, u32 res_ex); /* cached write */ -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME int snd_hda_codec_write_cache(struct hda_codec *codec, hda_nid_t nid, int direct, unsigned int verb, unsigned int parm); void snd_hda_sequence_write_cache(struct hda_codec *codec, @@ -1008,9 +1008,6 @@ int snd_hda_is_supported_format(struct hda_codec *codec, hda_nid_t nid, */ void snd_hda_get_codec_name(struct hda_codec *codec, char *name, int namelen); void snd_hda_bus_reboot_notify(struct hda_bus *bus); -void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state, - bool eapd_workaround); /* * power management diff --git a/trunk/sound/pci/hda/hda_local.h b/trunk/sound/pci/hda/hda_local.h index 2e7ac31afa8d..88b277e97409 100644 --- a/trunk/sound/pci/hda/hda_local.h +++ b/trunk/sound/pci/hda/hda_local.h @@ -131,7 +131,7 @@ int snd_hda_codec_amp_update(struct hda_codec *codec, hda_nid_t nid, int ch, int direction, int idx, int mask, int val); int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid, int dir, int idx, int mask, int val); -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME void snd_hda_codec_resume_amp(struct hda_codec *codec); #endif diff --git a/trunk/sound/pci/hda/patch_analog.c b/trunk/sound/pci/hda/patch_analog.c index 8648917acffb..1362c8ba4d1f 100644 --- a/trunk/sound/pci/hda/patch_analog.c +++ b/trunk/sound/pci/hda/patch_analog.c @@ -563,7 +563,7 @@ static void ad198x_free(struct hda_codec *codec) snd_hda_detach_beep_device(codec); } -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME static int ad198x_suspend(struct hda_codec *codec, pm_message_t state) { ad198x_shutup(codec); @@ -579,7 +579,7 @@ static const struct hda_codec_ops ad198x_patch_ops = { #ifdef CONFIG_SND_HDA_POWER_SAVE .check_power_status = ad198x_check_power_status, #endif -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME .suspend = ad198x_suspend, #endif .reboot_notify = ad198x_shutup, diff --git a/trunk/sound/pci/hda/patch_cirrus.c b/trunk/sound/pci/hda/patch_cirrus.c index 47d6ffc9b5b5..7f93739b1e33 100644 --- a/trunk/sound/pci/hda/patch_cirrus.c +++ b/trunk/sound/pci/hda/patch_cirrus.c @@ -25,7 +25,6 @@ #include #include "hda_codec.h" #include "hda_local.h" -#include /* */ @@ -62,15 +61,9 @@ struct cs_spec { unsigned int hp_detect:1; unsigned int mic_detect:1; - /* CS421x */ - unsigned int spdif_detect:1; - unsigned int sense_b:1; - hda_nid_t vendor_nid; - struct hda_input_mux input_mux; - unsigned int last_input; }; -/* available models with CS420x */ +/* available models */ enum { CS420X_MBP53, CS420X_MBP55, @@ -79,12 +72,6 @@ enum { CS420X_MODELS }; -/* CS421x boards */ -enum { - CS421X_CDB4210, - CS421X_MODELS -}; - /* Vendor-specific processing widget */ #define CS420X_VENDOR_NID 0x11 #define CS_DIG_OUT1_PIN_NID 0x10 @@ -124,42 +111,21 @@ enum { /* 0x0009 - 0x0014 -> 12 test regs */ /* 0x0015 - visibility reg */ -/* - * Cirrus Logic CS4210 - * - * 1 DAC => HP(sense) / Speakers, - * 1 ADC <= LineIn(sense) / MicIn / DMicIn, - * 1 SPDIF OUT => SPDIF Trasmitter(sense) -*/ -#define CS4210_DAC_NID 0x02 -#define CS4210_ADC_NID 0x03 -#define CS421X_VENDOR_NID 0x0B -#define CS421X_DMIC_PIN_NID 0x09 /* Port E */ -#define CS421X_SPDIF_PIN_NID 0x0A /* Port H */ - -#define CS421X_IDX_DEV_CFG 0x01 -#define CS421X_IDX_ADC_CFG 0x02 -#define CS421X_IDX_DAC_CFG 0x03 -#define CS421X_IDX_SPK_CTL 0x04 - -#define SPDIF_EVENT 0x04 static inline int cs_vendor_coef_get(struct hda_codec *codec, unsigned int idx) { - struct cs_spec *spec = codec->spec; - snd_hda_codec_write(codec, spec->vendor_nid, 0, + snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, AC_VERB_SET_COEF_INDEX, idx); - return snd_hda_codec_read(codec, spec->vendor_nid, 0, + return snd_hda_codec_read(codec, CS420X_VENDOR_NID, 0, AC_VERB_GET_PROC_COEF, 0); } static inline void cs_vendor_coef_set(struct hda_codec *codec, unsigned int idx, unsigned int coef) { - struct cs_spec *spec = codec->spec; - snd_hda_codec_write(codec, spec->vendor_nid, 0, + snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, AC_VERB_SET_COEF_INDEX, idx); - snd_hda_codec_write(codec, spec->vendor_nid, 0, + snd_hda_codec_write(codec, CS420X_VENDOR_NID, 0, AC_VERB_SET_PROC_COEF, coef); } @@ -381,12 +347,15 @@ static hda_nid_t get_adc(struct hda_codec *codec, hda_nid_t pin, nid = codec->start_nid; for (i = 0; i < codec->num_nodes; i++, nid++) { unsigned int type; + int idx; type = get_wcaps_type(get_wcaps(codec, nid)); if (type != AC_WID_AUD_IN) continue; - *idxp = snd_hda_get_conn_index(codec, nid, pin, false); - if (*idxp >= 0) + idx = snd_hda_get_conn_index(codec, nid, pin, 0); + if (idx >= 0) { + *idxp = idx; return nid; + } } return 0; } @@ -866,8 +835,6 @@ static int build_digital_input(struct hda_codec *codec) /* * auto-mute and auto-mic switching - * CS421x auto-output redirecting - * HP/SPK/SPDIF */ static void cs_automute(struct hda_codec *codec) @@ -875,25 +842,9 @@ static void cs_automute(struct hda_codec *codec) struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; unsigned int hp_present; - unsigned int spdif_present; hda_nid_t nid; int i; - spdif_present = 0; - if (cfg->dig_outs) { - nid = cfg->dig_out_pins[0]; - if (is_jack_detectable(codec, nid)) { - /* - TODO: SPDIF output redirect when SENSE_B is enabled. - Shared (SENSE_A) jack (e.g HP/mini-TOSLINK) - assumed. - */ - if (snd_hda_jack_detect(codec, nid) - /* && spec->sense_b */) - spdif_present = 1; - } - } - hp_present = 0; for (i = 0; i < cfg->hp_outs; i++) { nid = cfg->hp_pins[i]; @@ -903,19 +854,11 @@ static void cs_automute(struct hda_codec *codec) if (hp_present) break; } - - /* mute speakers if spdif or hp jack is plugged in */ for (i = 0; i < cfg->speaker_outs; i++) { nid = cfg->speaker_pins[i]; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, hp_present ? 0 : PIN_OUT); - /* detect on spdif is specific to CS421x */ - if (spec->vendor_nid == CS421X_VENDOR_NID) { - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - spdif_present ? 0 : PIN_OUT); - } } if (spec->board_config == CS420X_MBP53 || spec->board_config == CS420X_MBP55 || @@ -924,62 +867,21 @@ static void cs_automute(struct hda_codec *codec) snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, gpio); } - - /* specific to CS421x */ - if (spec->vendor_nid == CS421X_VENDOR_NID) { - /* mute HPs if spdif jack (SENSE_B) is present */ - for (i = 0; i < cfg->hp_outs; i++) { - nid = cfg->hp_pins[i]; - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - (spdif_present && spec->sense_b) ? 0 : PIN_HP); - } - - /* SPDIF TX on/off */ - if (cfg->dig_outs) { - nid = cfg->dig_out_pins[0]; - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_PIN_WIDGET_CONTROL, - spdif_present ? PIN_OUT : 0); - - } - /* Update board GPIOs if neccessary ... */ - } } -/* - * Auto-input redirect for CS421x - * Switch max 3 inputs of a single ADC (nid 3) -*/ - static void cs_automic(struct hda_codec *codec) { struct cs_spec *spec = codec->spec; struct auto_pin_cfg *cfg = &spec->autocfg; hda_nid_t nid; unsigned int present; - + nid = cfg->inputs[spec->automic_idx].pin; present = snd_hda_jack_detect(codec, nid); - - /* specific to CS421x, single ADC */ - if (spec->vendor_nid == CS421X_VENDOR_NID) { - if (present) { - spec->last_input = spec->cur_input; - spec->cur_input = spec->automic_idx; - } else { - spec->cur_input = spec->last_input; - } - - snd_hda_codec_write_cache(codec, spec->cur_adc, 0, - AC_VERB_SET_CONNECT_SEL, - spec->adc_idx[spec->cur_input]); - } else { - if (present) - change_cur_input(codec, spec->automic_idx, 0); - else - change_cur_input(codec, !spec->automic_idx, 0); - } + if (present) + change_cur_input(codec, spec->automic_idx, 0); + else + change_cur_input(codec, !spec->automic_idx, 0); } /* @@ -1009,28 +911,23 @@ static void init_output(struct hda_codec *codec) for (i = 0; i < cfg->line_outs; i++) snd_hda_codec_write(codec, cfg->line_out_pins[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - /* HP */ for (i = 0; i < cfg->hp_outs; i++) { hda_nid_t nid = cfg->hp_pins[i]; snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_HP); if (!cfg->speaker_outs) continue; - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { + if (is_jack_detectable(codec, nid)) { snd_hda_codec_write(codec, nid, 0, AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | HP_EVENT); spec->hp_detect = 1; } } - - /* Speaker */ for (i = 0; i < cfg->speaker_outs; i++) snd_hda_codec_write(codec, cfg->speaker_pins[i], 0, AC_VERB_SET_PIN_WIDGET_CONTROL, PIN_OUT); - - /* SPDIF is enabled on presence detect for CS421x */ - if (spec->hp_detect || spec->spdif_detect) + if (spec->hp_detect) cs_automute(codec); } @@ -1064,31 +961,19 @@ static void init_input(struct hda_codec *codec) AC_VERB_SET_UNSOLICITED_ENABLE, AC_USRSP_EN | MIC_EVENT); } - /* specific to CS421x */ - if (spec->vendor_nid == CS421X_VENDOR_NID) { - if (spec->mic_detect) - cs_automic(codec); - else { - spec->cur_adc = spec->adc_nid[spec->cur_input]; - snd_hda_codec_write(codec, spec->cur_adc, 0, - AC_VERB_SET_CONNECT_SEL, - spec->adc_idx[spec->cur_input]); - } - } else { - change_cur_input(codec, spec->cur_input, 1); - if (spec->mic_detect) - cs_automic(codec); - - coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ - if (is_active_pin(codec, CS_DMIC2_PIN_NID)) - coef |= 0x0500; /* DMIC2 2 chan on, GPIO1 off */ - if (is_active_pin(codec, CS_DMIC1_PIN_NID)) - coef |= 0x1800; /* DMIC1 2 chan on, GPIO0 off - * No effect if SPDIF_OUT2 is - * selected in IDX_SPDIF_CTL. - */ - cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); - } + change_cur_input(codec, spec->cur_input, 1); + if (spec->mic_detect) + cs_automic(codec); + + coef = 0x000a; /* ADC1/2 - Digital and Analog Soft Ramp */ + if (is_active_pin(codec, CS_DMIC2_PIN_NID)) + coef |= 0x0500; /* DMIC2 enable 2 channels, disable GPIO1 */ + if (is_active_pin(codec, CS_DMIC1_PIN_NID)) + coef |= 0x1800; /* DMIC1 enable 2 channels, disable GPIO0 + * No effect if SPDIF_OUT2 is selected in + * IDX_SPDIF_CTL. + */ + cs_vendor_coef_set(codec, IDX_ADC_CFG, coef); } static const struct hda_verb cs_coef_init_verbs[] = { @@ -1336,16 +1221,16 @@ static const struct cs_pincfg *cs_pincfgs[CS420X_MODELS] = { [CS420X_IMAC27] = imac27_pincfgs, }; -static void fix_pincfg(struct hda_codec *codec, int model, - const struct cs_pincfg **pin_configs) +static void fix_pincfg(struct hda_codec *codec, int model) { - const struct cs_pincfg *cfg = pin_configs[model]; + const struct cs_pincfg *cfg = cs_pincfgs[model]; if (!cfg) return; for (; cfg->nid; cfg++) snd_hda_codec_set_pincfg(codec, cfg->nid, cfg->val); } + static int patch_cs420x(struct hda_codec *codec) { struct cs_spec *spec; @@ -1356,13 +1241,11 @@ static int patch_cs420x(struct hda_codec *codec) return -ENOMEM; codec->spec = spec; - spec->vendor_nid = CS420X_VENDOR_NID; - spec->board_config = snd_hda_check_board_config(codec, CS420X_MODELS, cs420x_models, cs420x_cfg_tbl); if (spec->board_config >= 0) - fix_pincfg(codec, spec->board_config, cs_pincfgs); + fix_pincfg(codec, spec->board_config); switch (spec->board_config) { case CS420X_IMAC27: @@ -1389,562 +1272,6 @@ static int patch_cs420x(struct hda_codec *codec) return err; } -/* - * Cirrus Logic CS4210 - * - * 1 DAC => HP(sense) / Speakers, - * 1 ADC <= LineIn(sense) / MicIn / DMicIn, - * 1 SPDIF OUT => SPDIF Trasmitter(sense) -*/ - -/* CS4210 board names */ -static const char *cs421x_models[CS421X_MODELS] = { - [CS421X_CDB4210] = "cdb4210", -}; - -static const struct snd_pci_quirk cs421x_cfg_tbl[] = { - /* Test Intel board + CDB2410 */ - SND_PCI_QUIRK(0x8086, 0x5001, "DP45SG/CDB4210", CS421X_CDB4210), - {} /* terminator */ -}; - -/* CS4210 board pinconfigs */ -/* Default CS4210 (CDB4210)*/ -static const struct cs_pincfg cdb4210_pincfgs[] = { - { 0x05, 0x0321401f }, - { 0x06, 0x90170010 }, - { 0x07, 0x03813031 }, - { 0x08, 0xb7a70037 }, - { 0x09, 0xb7a6003e }, - { 0x0a, 0x034510f0 }, - {} /* terminator */ -}; - -static const struct cs_pincfg *cs421x_pincfgs[CS421X_MODELS] = { - [CS421X_CDB4210] = cdb4210_pincfgs, -}; - -static const struct hda_verb cs421x_coef_init_verbs[] = { - {0x0B, AC_VERB_SET_PROC_STATE, 1}, - {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DEV_CFG}, - /* - Disable Coefficient Index Auto-Increment(DAI)=1, - PDREF=0 - */ - {0x0B, AC_VERB_SET_PROC_COEF, 0x0001 }, - - {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_ADC_CFG}, - /* ADC SZCMode = Digital Soft Ramp */ - {0x0B, AC_VERB_SET_PROC_COEF, 0x0002 }, - - {0x0B, AC_VERB_SET_COEF_INDEX, CS421X_IDX_DAC_CFG}, - {0x0B, AC_VERB_SET_PROC_COEF, - (0x0002 /* DAC SZCMode = Digital Soft Ramp */ - | 0x0004 /* Mute DAC on FIFO error */ - | 0x0008 /* Enable DAC High Pass Filter */ - )}, - {} /* terminator */ -}; - -/* Errata: CS4210 rev A1 Silicon - * - * http://www.cirrus.com/en/pubs/errata/ - * - * Description: - * 1. Performance degredation is present in the ADC. - * 2. Speaker output is not completely muted upon HP detect. - * 3. Noise is present when clipping occurs on the amplified - * speaker outputs. - * - * Workaround: - * The following verb sequence written to the registers during - * initialization will correct the issues listed above. - */ - -static const struct hda_verb cs421x_coef_init_verbs_A1_silicon_fixes[] = { - {0x0B, AC_VERB_SET_PROC_STATE, 0x01}, /* VPW: processing on */ - - {0x0B, AC_VERB_SET_COEF_INDEX, 0x0006}, - {0x0B, AC_VERB_SET_PROC_COEF, 0x9999}, /* Test mode: on */ - - {0x0B, AC_VERB_SET_COEF_INDEX, 0x000A}, - {0x0B, AC_VERB_SET_PROC_COEF, 0x14CB}, /* Chop double */ - - {0x0B, AC_VERB_SET_COEF_INDEX, 0x0011}, - {0x0B, AC_VERB_SET_PROC_COEF, 0xA2D0}, /* Increase ADC current */ - - {0x0B, AC_VERB_SET_COEF_INDEX, 0x001A}, - {0x0B, AC_VERB_SET_PROC_COEF, 0x02A9}, /* Mute speaker */ - - {0x0B, AC_VERB_SET_COEF_INDEX, 0x001B}, - {0x0B, AC_VERB_SET_PROC_COEF, 0X1006}, /* Remove noise */ - - {} /* terminator */ -}; - -/* Speaker Amp Gain is controlled by the vendor widget's coef 4 */ -static const DECLARE_TLV_DB_SCALE(cs421x_speaker_boost_db_scale, 900, 300, 0); - -static int cs421x_boost_vol_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; - uinfo->count = 1; - uinfo->value.integer.min = 0; - uinfo->value.integer.max = 3; - return 0; -} - -static int cs421x_boost_vol_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - ucontrol->value.integer.value[0] = - cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL) & 0x0003; - return 0; -} - -static int cs421x_boost_vol_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - - unsigned int vol = ucontrol->value.integer.value[0]; - unsigned int coef = - cs_vendor_coef_get(codec, CS421X_IDX_SPK_CTL); - unsigned int original_coef = coef; - - coef &= ~0x0003; - coef |= (vol & 0x0003); - if (original_coef == coef) - return 0; - else { - cs_vendor_coef_set(codec, CS421X_IDX_SPK_CTL, coef); - return 1; - } -} - -static const struct snd_kcontrol_new cs421x_speaker_bost_ctl = { - - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .access = (SNDRV_CTL_ELEM_ACCESS_READWRITE | - SNDRV_CTL_ELEM_ACCESS_TLV_READ), - .name = "Speaker Boost Playback Volume", - .info = cs421x_boost_vol_info, - .get = cs421x_boost_vol_get, - .put = cs421x_boost_vol_put, - .tlv = { .p = cs421x_speaker_boost_db_scale }, -}; - -static void cs421x_pinmux_init(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - unsigned int def_conf, coef; - - /* GPIO, DMIC_SCL, DMIC_SDA and SENSE_B are multiplexed */ - coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); - - if (spec->gpio_mask) - coef |= 0x0008; /* B1,B2 are GPIOs */ - else - coef &= ~0x0008; - - if (spec->sense_b) - coef |= 0x0010; /* B2 is SENSE_B, not inverted */ - else - coef &= ~0x0010; - - cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); - - if ((spec->gpio_mask || spec->sense_b) && - is_active_pin(codec, CS421X_DMIC_PIN_NID)) { - - /* - GPIO or SENSE_B forced - disconnect the DMIC pin. - */ - def_conf = snd_hda_codec_get_pincfg(codec, CS421X_DMIC_PIN_NID); - def_conf &= ~AC_DEFCFG_PORT_CONN; - def_conf |= (AC_JACK_PORT_NONE << AC_DEFCFG_PORT_CONN_SHIFT); - snd_hda_codec_set_pincfg(codec, CS421X_DMIC_PIN_NID, def_conf); - } -} - -static void init_cs421x_digital(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - - for (i = 0; i < cfg->dig_outs; i++) { - hda_nid_t nid = cfg->dig_out_pins[i]; - if (!cfg->speaker_outs) - continue; - if (get_wcaps(codec, nid) & AC_WCAP_UNSOL_CAP) { - - snd_hda_codec_write(codec, nid, 0, - AC_VERB_SET_UNSOLICITED_ENABLE, - AC_USRSP_EN | SPDIF_EVENT); - spec->spdif_detect = 1; - } - } -} - -static int cs421x_init(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - - snd_hda_sequence_write(codec, cs421x_coef_init_verbs); - snd_hda_sequence_write(codec, cs421x_coef_init_verbs_A1_silicon_fixes); - - cs421x_pinmux_init(codec); - - if (spec->gpio_mask) { - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_MASK, - spec->gpio_mask); - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DIRECTION, - spec->gpio_dir); - snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, - spec->gpio_data); - } - - init_output(codec); - init_input(codec); - init_cs421x_digital(codec); - - return 0; -} - -/* - * CS4210 Input MUX (1 ADC) - */ -static int cs421x_mux_enum_info(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_info *uinfo) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - - return snd_hda_input_mux_info(&spec->input_mux, uinfo); -} - -static int cs421x_mux_enum_get(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - - ucontrol->value.enumerated.item[0] = spec->cur_input; - return 0; -} - -static int cs421x_mux_enum_put(struct snd_kcontrol *kcontrol, - struct snd_ctl_elem_value *ucontrol) -{ - struct hda_codec *codec = snd_kcontrol_chip(kcontrol); - struct cs_spec *spec = codec->spec; - - return snd_hda_input_mux_put(codec, &spec->input_mux, ucontrol, - spec->adc_nid[0], &spec->cur_input); - -} - -static struct snd_kcontrol_new cs421x_capture_source = { - - .iface = SNDRV_CTL_ELEM_IFACE_MIXER, - .name = "Capture Source", - .access = SNDRV_CTL_ELEM_ACCESS_READWRITE, - .info = cs421x_mux_enum_info, - .get = cs421x_mux_enum_get, - .put = cs421x_mux_enum_put, -}; - -static int cs421x_add_input_volume_control(struct hda_codec *codec, int item) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - const struct hda_input_mux *imux = &spec->input_mux; - hda_nid_t pin = cfg->inputs[item].pin; - struct snd_kcontrol *kctl; - u32 caps; - - if (!(get_wcaps(codec, pin) & AC_WCAP_IN_AMP)) - return 0; - - caps = query_amp_caps(codec, pin, HDA_INPUT); - caps = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; - if (caps <= 1) - return 0; - - return add_volume(codec, imux->items[item].label, 0, - HDA_COMPOSE_AMP_VAL(pin, 3, 0, HDA_INPUT), 1, &kctl); -} - -/* add a (input-boost) volume control to the given input pin */ -static int build_cs421x_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct hda_input_mux *imux = &spec->input_mux; - int i, err, type_idx; - const char *label; - - if (!spec->num_inputs) - return 0; - - /* make bind-capture */ - spec->capture_bind[0] = make_bind_capture(codec, &snd_hda_bind_sw); - spec->capture_bind[1] = make_bind_capture(codec, &snd_hda_bind_vol); - for (i = 0; i < 2; i++) { - struct snd_kcontrol *kctl; - int n; - if (!spec->capture_bind[i]) - return -ENOMEM; - kctl = snd_ctl_new1(&cs_capture_ctls[i], codec); - if (!kctl) - return -ENOMEM; - kctl->private_value = (long)spec->capture_bind[i]; - err = snd_hda_ctl_add(codec, 0, kctl); - if (err < 0) - return err; - for (n = 0; n < AUTO_PIN_LAST; n++) { - if (!spec->adc_nid[n]) - continue; - err = snd_hda_add_nid(codec, kctl, 0, spec->adc_nid[n]); - if (err < 0) - return err; - } - } - - /* Add Input MUX Items + Capture Volume/Switch */ - for (i = 0; i < spec->num_inputs; i++) { - label = hda_get_autocfg_input_label(codec, cfg, i); - snd_hda_add_imux_item(imux, label, spec->adc_idx[i], &type_idx); - - err = cs421x_add_input_volume_control(codec, i); - if (err < 0) - return err; - } - - /* - Add 'Capture Source' Switch if - * 2 inputs and no mic detec - * 3 inputs - */ - if ((spec->num_inputs == 2 && !spec->mic_detect) || - (spec->num_inputs == 3)) { - - err = snd_hda_ctl_add(codec, spec->adc_nid[0], - snd_ctl_new1(&cs421x_capture_source, codec)); - if (err < 0) - return err; - } - - return 0; -} - -/* Single DAC (Mute/Gain) */ -static int build_cs421x_output(struct hda_codec *codec) -{ - hda_nid_t dac = CS4210_DAC_NID; - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - struct snd_kcontrol *kctl; - int err; - char *name = "HP/Speakers"; - - fix_volume_caps(codec, dac); - if (!spec->vmaster_sw) { - err = add_vmaster(codec, dac); - if (err < 0) - return err; - } - - err = add_mute(codec, name, 0, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); - if (err < 0) - return err; - err = snd_ctl_add_slave(spec->vmaster_sw, kctl); - if (err < 0) - return err; - - err = add_volume(codec, name, 0, - HDA_COMPOSE_AMP_VAL(dac, 3, 0, HDA_OUTPUT), 0, &kctl); - if (err < 0) - return err; - err = snd_ctl_add_slave(spec->vmaster_vol, kctl); - if (err < 0) - return err; - - if (cfg->speaker_outs) { - err = snd_hda_ctl_add(codec, 0, - snd_ctl_new1(&cs421x_speaker_bost_ctl, codec)); - if (err < 0) - return err; - } - return err; -} - -static int cs421x_build_controls(struct hda_codec *codec) -{ - int err; - - err = build_cs421x_output(codec); - if (err < 0) - return err; - err = build_cs421x_input(codec); - if (err < 0) - return err; - err = build_digital_output(codec); - if (err < 0) - return err; - return cs421x_init(codec); -} - -static void cs421x_unsol_event(struct hda_codec *codec, unsigned int res) -{ - switch ((res >> 26) & 0x3f) { - case HP_EVENT: - case SPDIF_EVENT: - cs_automute(codec); - break; - - case MIC_EVENT: - cs_automic(codec); - break; - } -} - -static int parse_cs421x_input(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - struct auto_pin_cfg *cfg = &spec->autocfg; - int i; - - for (i = 0; i < cfg->num_inputs; i++) { - hda_nid_t pin = cfg->inputs[i].pin; - spec->adc_nid[i] = get_adc(codec, pin, &spec->adc_idx[i]); - spec->cur_input = spec->last_input = i; - spec->num_inputs++; - - /* check whether the automatic mic switch is available */ - if (is_ext_mic(codec, i) && cfg->num_inputs >= 2) { - spec->mic_detect = 1; - spec->automic_idx = i; - } - } - return 0; -} - -static int cs421x_parse_auto_config(struct hda_codec *codec) -{ - struct cs_spec *spec = codec->spec; - int err; - - err = snd_hda_parse_pin_def_config(codec, &spec->autocfg, NULL); - if (err < 0) - return err; - err = parse_output(codec); - if (err < 0) - return err; - err = parse_cs421x_input(codec); - if (err < 0) - return err; - err = parse_digital_output(codec); - if (err < 0) - return err; - return 0; -} - -#ifdef CONFIG_PM -/* - Manage PDREF, when transitioning to D3hot - (DAC,ADC) -> D3, PDREF=1, AFG->D3 -*/ -static int cs421x_suspend(struct hda_codec *codec, pm_message_t state) -{ - unsigned int coef; - - snd_hda_shutup_pins(codec); - - snd_hda_codec_write(codec, CS4210_DAC_NID, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - snd_hda_codec_write(codec, CS4210_ADC_NID, 0, - AC_VERB_SET_POWER_STATE, AC_PWRST_D3); - - coef = cs_vendor_coef_get(codec, CS421X_IDX_DEV_CFG); - coef |= 0x0004; /* PDREF */ - cs_vendor_coef_set(codec, CS421X_IDX_DEV_CFG, coef); - - return 0; -} -#endif - -static struct hda_codec_ops cs4210_patch_ops = { - .build_controls = cs421x_build_controls, - .build_pcms = cs_build_pcms, - .init = cs421x_init, - .free = cs_free, - .unsol_event = cs421x_unsol_event, -#ifdef CONFIG_PM - .suspend = cs421x_suspend, -#endif -}; - -static int patch_cs421x(struct hda_codec *codec) -{ - struct cs_spec *spec; - int err; - - spec = kzalloc(sizeof(*spec), GFP_KERNEL); - if (!spec) - return -ENOMEM; - codec->spec = spec; - - spec->vendor_nid = CS421X_VENDOR_NID; - - spec->board_config = - snd_hda_check_board_config(codec, CS421X_MODELS, - cs421x_models, cs421x_cfg_tbl); - if (spec->board_config >= 0) - fix_pincfg(codec, spec->board_config, cs421x_pincfgs); - /* - Setup GPIO/SENSE for each board (if used) - */ - switch (spec->board_config) { - case CS421X_CDB4210: - snd_printd("CS4210 board: %s\n", - cs421x_models[spec->board_config]); -/* spec->gpio_mask = 3; - spec->gpio_dir = 3; - spec->gpio_data = 3; -*/ - spec->sense_b = 1; - - break; - } - - /* - Update the GPIO/DMIC/SENSE_B pinmux before the configuration - is auto-parsed. If GPIO or SENSE_B is forced, DMIC input - is disabled. - */ - cs421x_pinmux_init(codec); - - err = cs421x_parse_auto_config(codec); - if (err < 0) - goto error; - - codec->patch_ops = cs4210_patch_ops; - - return 0; - - error: - kfree(codec->spec); - codec->spec = NULL; - return err; -} - /* * patch entries @@ -1952,13 +1279,11 @@ static int patch_cs421x(struct hda_codec *codec) static const struct hda_codec_preset snd_hda_preset_cirrus[] = { { .id = 0x10134206, .name = "CS4206", .patch = patch_cs420x }, { .id = 0x10134207, .name = "CS4207", .patch = patch_cs420x }, - { .id = 0x10134210, .name = "CS4210", .patch = patch_cs421x }, {} /* terminator */ }; MODULE_ALIAS("snd-hda-codec-id:10134206"); MODULE_ALIAS("snd-hda-codec-id:10134207"); -MODULE_ALIAS("snd-hda-codec-id:10134210"); MODULE_LICENSE("GPL"); MODULE_DESCRIPTION("Cirrus Logic HD-audio codec"); diff --git a/trunk/sound/pci/hda/patch_conexant.c b/trunk/sound/pci/hda/patch_conexant.c index 502fc9499453..884f67b8f4e0 100644 --- a/trunk/sound/pci/hda/patch_conexant.c +++ b/trunk/sound/pci/hda/patch_conexant.c @@ -446,19 +446,6 @@ static int conexant_init_jacks(struct hda_codec *codec) return 0; } -static void conexant_set_power(struct hda_codec *codec, hda_nid_t fg, - unsigned int power_state) -{ - if (power_state == AC_PWRST_D3) - msleep(100); - snd_hda_codec_read(codec, fg, 0, AC_VERB_SET_POWER_STATE, - power_state); - /* partial workaround for "azx_get_response timeout" */ - if (power_state == AC_PWRST_D0) - msleep(10); - snd_hda_codec_set_power_to_all(codec, fg, power_state, true); -} - static int conexant_init(struct hda_codec *codec) { struct conexant_spec *spec = codec->spec; @@ -601,7 +588,6 @@ static const struct hda_codec_ops conexant_patch_ops = { .build_pcms = conexant_build_pcms, .init = conexant_init, .free = conexant_free, - .set_power_state = conexant_set_power, #ifdef CONFIG_SND_HDA_POWER_SAVE .suspend = conexant_suspend, #endif diff --git a/trunk/sound/pci/hda/patch_realtek.c b/trunk/sound/pci/hda/patch_realtek.c index 694327ae8b71..52ce07534e5b 100644 --- a/trunk/sound/pci/hda/patch_realtek.c +++ b/trunk/sound/pci/hda/patch_realtek.c @@ -2386,7 +2386,7 @@ static int alc_suspend(struct hda_codec *codec, pm_message_t state) } #endif -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME static int alc_resume(struct hda_codec *codec) { msleep(150); /* to avoid pop noise */ @@ -2406,7 +2406,7 @@ static const struct hda_codec_ops alc_patch_ops = { .init = alc_init, .free = alc_free, .unsol_event = alc_unsol_event, -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME .resume = alc_resume, #endif #ifdef CONFIG_SND_HDA_POWER_SAVE @@ -2801,8 +2801,7 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) int i; again: - /* set num_dacs once to full for alc_auto_look_for_dac() */ - spec->multiout.num_dacs = cfg->line_outs; + spec->multiout.num_dacs = 0; spec->multiout.hp_nid = 0; spec->multiout.extra_out_nid[0] = 0; memset(spec->private_dac_nids, 0, sizeof(spec->private_dac_nids)); @@ -2835,8 +2834,6 @@ static int alc_auto_fill_dac_nids(struct hda_codec *codec) } } - /* re-count num_dacs and squash invalid entries */ - spec->multiout.num_dacs = 0; for (i = 0; i < cfg->line_outs; i++) { if (spec->private_dac_nids[i]) spec->multiout.num_dacs++; @@ -4413,7 +4410,7 @@ static void alc269_shutup(struct hda_codec *codec) } } -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME static int alc269_resume(struct hda_codec *codec) { if ((alc_read_coef_idx(codec, 0) & 0x00ff) == 0x018) { @@ -4436,7 +4433,7 @@ static int alc269_resume(struct hda_codec *codec) hda_call_check_power_status(codec, 0x01); return 0; } -#endif /* CONFIG_PM */ +#endif /* SND_HDA_NEEDS_RESUME */ static void alc269_fixup_hweq(struct hda_codec *codec, const struct alc_fixup *fix, int action) @@ -4728,7 +4725,7 @@ static int patch_alc269(struct hda_codec *codec) spec->vmaster_nid = 0x02; codec->patch_ops = alc_patch_ops; -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME codec->patch_ops.resume = alc269_resume; #endif if (board_config == ALC_MODEL_AUTO) diff --git a/trunk/sound/pci/hda/patch_sigmatel.c b/trunk/sound/pci/hda/patch_sigmatel.c index fcf4c7142103..56425a53cf1b 100644 --- a/trunk/sound/pci/hda/patch_sigmatel.c +++ b/trunk/sound/pci/hda/patch_sigmatel.c @@ -95,7 +95,6 @@ enum { STAC_92HD83XXX_PWR_REF, STAC_DELL_S14, STAC_92HD83XXX_HP, - STAC_92HD83XXX_HP_cNB11_INTQUAD, STAC_HP_DV7_4000, STAC_92HD83XXX_MODELS }; @@ -1637,17 +1636,10 @@ static const unsigned int hp_dv7_4000_pin_configs[10] = { 0x40f000f0, 0x40f000f0, }; -static const unsigned int hp_cNB11_intquad_pin_configs[10] = { - 0x40f000f0, 0x0221101f, 0x02a11020, 0x92170110, - 0x40f000f0, 0x92170110, 0x40f000f0, 0xd5a30130, - 0x40f000f0, 0x40f000f0, -}; - static const unsigned int *stac92hd83xxx_brd_tbl[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_REF] = ref92hd83xxx_pin_configs, [STAC_92HD83XXX_PWR_REF] = ref92hd83xxx_pin_configs, [STAC_DELL_S14] = dell_s14_pin_configs, - [STAC_92HD83XXX_HP_cNB11_INTQUAD] = hp_cNB11_intquad_pin_configs, [STAC_HP_DV7_4000] = hp_dv7_4000_pin_configs, }; @@ -1657,7 +1649,6 @@ static const char * const stac92hd83xxx_models[STAC_92HD83XXX_MODELS] = { [STAC_92HD83XXX_PWR_REF] = "mic-ref", [STAC_DELL_S14] = "dell-s14", [STAC_92HD83XXX_HP] = "hp", - [STAC_92HD83XXX_HP_cNB11_INTQUAD] = "hp_cNB11_intquad", [STAC_HP_DV7_4000] = "hp-dv7-4000", }; @@ -1670,47 +1661,7 @@ static const struct snd_pci_quirk stac92hd83xxx_cfg_tbl[] = { SND_PCI_QUIRK(PCI_VENDOR_ID_DELL, 0x02ba, "unknown Dell", STAC_DELL_S14), SND_PCI_QUIRK_MASK(PCI_VENDOR_ID_HP, 0xff00, 0x3600, - "HP", STAC_92HD83XXX_HP), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1656, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1657, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1658, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x1659, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165A, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x165B, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3388, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3389, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355B, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355C, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355D, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355E, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x355F, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3560, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358B, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358C, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x358D, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3591, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3592, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), - SND_PCI_QUIRK(PCI_VENDOR_ID_HP, 0x3593, - "HP", STAC_92HD83XXX_HP_cNB11_INTQUAD), + "HP", STAC_92HD83XXX_HP), {} /* terminator */ }; @@ -4934,18 +4885,7 @@ static void stac927x_proc_hook(struct snd_info_buffer *buffer, #define stac927x_proc_hook NULL #endif -#ifdef CONFIG_PM -static int stac92xx_pre_resume(struct hda_codec *codec) -{ - struct sigmatel_spec *spec = codec->spec; - - /* sync mute LED */ - if (spec->gpio_led) - stac_gpio_set(codec, spec->gpio_mask, - spec->gpio_dir, spec->gpio_data); - return 0; -} - +#ifdef SND_HDA_NEEDS_RESUME static int stac92xx_resume(struct hda_codec *codec) { struct sigmatel_spec *spec = codec->spec; @@ -4961,19 +4901,29 @@ static int stac92xx_resume(struct hda_codec *codec) stac_issue_unsol_event(codec, spec->autocfg.line_out_pins[0]); } + /* sync mute LED */ + if (spec->gpio_led) + hda_call_check_power_status(codec, 0x01); return 0; } -#ifdef CONFIG_SND_HDA_POWER_SAVE /* - * For this feature CONFIG_SND_HDA_POWER_SAVE is needed - * as mute LED state is updated in check_power_status hook + * using power check for controlling mute led of HP notebooks + * check for mute state only on Speakers (nid = 0x10) + * + * For this feature CONFIG_SND_HDA_POWER_SAVE is needed, otherwise + * the LED is NOT working properly ! + * + * Changed name to reflect that it now works for any designated + * model, not just HP HDX. */ -static int stac92xx_update_led_status(struct hda_codec *codec) + +#ifdef CONFIG_SND_HDA_POWER_SAVE +static int stac92xx_hp_check_power_status(struct hda_codec *codec, + hda_nid_t nid) { struct sigmatel_spec *spec = codec->spec; - int i, num_ext_dacs, muted = 1; - hda_nid_t nid; + int i, muted = 1; for (i = 0; i < spec->multiout.num_dacs; i++) { nid = spec->multiout.dac_nids[i]; @@ -4983,22 +4933,6 @@ static int stac92xx_update_led_status(struct hda_codec *codec) break; } } - if (muted && spec->multiout.hp_nid) - if (!(snd_hda_codec_amp_read(codec, - spec->multiout.hp_nid, 0, HDA_OUTPUT, 0) & - HDA_AMP_MUTE)) { - muted = 0; /* HP is not muted */ - } - num_ext_dacs = ARRAY_SIZE(spec->multiout.extra_out_nid); - for (i = 0; muted && i < num_ext_dacs; i++) { - nid = spec->multiout.extra_out_nid[i]; - if (nid == 0) - break; - if (!(snd_hda_codec_amp_read(codec, nid, 0, HDA_OUTPUT, 0) & - HDA_AMP_MUTE)) { - muted = 0; /* extra output is not muted */ - } - } if (muted) spec->gpio_data &= ~spec->gpio_led; /* orange */ else @@ -5012,17 +4946,6 @@ static int stac92xx_update_led_status(struct hda_codec *codec) stac_gpio_set(codec, spec->gpio_mask, spec->gpio_dir, spec->gpio_data); return 0; } - -/* - * use power check for controlling mute led of HP notebooks - */ -static int stac92xx_check_power_status(struct hda_codec *codec, - hda_nid_t nid) -{ - stac92xx_update_led_status(codec); - - return 0; -} #endif static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) @@ -5030,7 +4953,7 @@ static int stac92xx_suspend(struct hda_codec *codec, pm_message_t state) stac92xx_shutup(codec); return 0; } -#endif /* CONFIG_PM */ +#endif static const struct hda_codec_ops stac92xx_patch_ops = { .build_controls = stac92xx_build_controls, @@ -5038,10 +4961,9 @@ static const struct hda_codec_ops stac92xx_patch_ops = { .init = stac92xx_init, .free = stac92xx_free, .unsol_event = stac92xx_unsol_event, -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME .suspend = stac92xx_suspend, .resume = stac92xx_resume, - .pre_resume = stac92xx_pre_resume, #endif .reboot_notify = stac92xx_shutup, }; @@ -5560,7 +5482,7 @@ static int patch_stac92hd83xxx(struct hda_codec *codec) spec->gpio_data |= spec->gpio_led; /* register check_power_status callback. */ codec->patch_ops.check_power_status = - stac92xx_check_power_status; + stac92xx_hp_check_power_status; } #endif @@ -5888,7 +5810,7 @@ static int patch_stac92hd71bxx(struct hda_codec *codec) spec->gpio_data |= spec->gpio_led; /* register check_power_status callback. */ codec->patch_ops.check_power_status = - stac92xx_check_power_status; + stac92xx_hp_check_power_status; } #endif diff --git a/trunk/sound/pci/hda/patch_via.c b/trunk/sound/pci/hda/patch_via.c index 84d8798bf33a..f38160b00e16 100644 --- a/trunk/sound/pci/hda/patch_via.c +++ b/trunk/sound/pci/hda/patch_via.c @@ -1708,7 +1708,7 @@ static void via_unsol_event(struct hda_codec *codec, via_gpio_control(codec); } -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME static int via_suspend(struct hda_codec *codec, pm_message_t state) { struct via_spec *spec = codec->spec; @@ -1736,7 +1736,7 @@ static const struct hda_codec_ops via_patch_ops = { .init = via_init, .free = via_free, .unsol_event = via_unsol_event, -#ifdef CONFIG_PM +#ifdef SND_HDA_NEEDS_RESUME .suspend = via_suspend, #endif #ifdef CONFIG_SND_HDA_POWER_SAVE diff --git a/trunk/sound/soc/codecs/sgtl5000.c b/trunk/sound/soc/codecs/sgtl5000.c index 76258f2a2ffb..ff29380c9ed3 100644 --- a/trunk/sound/soc/codecs/sgtl5000.c +++ b/trunk/sound/soc/codecs/sgtl5000.c @@ -907,7 +907,6 @@ static int ldo_regulator_register(struct snd_soc_codec *codec, struct regulator_init_data *init_data, int voltage) { - dev_err(codec->dev, "this setup needs regulator support in the kernel\n"); return -EINVAL; } @@ -1219,34 +1218,6 @@ static int sgtl5000_set_power_regs(struct snd_soc_codec *codec) return 0; } -static int sgtl5000_replace_vddd_with_ldo(struct snd_soc_codec *codec) -{ - struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(codec); - int ret; - - /* set internal ldo to 1.2v */ - ret = ldo_regulator_register(codec, &ldo_init_data, LDO_VOLTAGE); - if (ret) { - dev_err(codec->dev, - "Failed to register vddd internal supplies: %d\n", ret); - return ret; - } - - sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; - - ret = regulator_bulk_get(codec->dev, ARRAY_SIZE(sgtl5000->supplies), - sgtl5000->supplies); - - if (ret) { - ldo_regulator_remove(codec); - dev_err(codec->dev, "Failed to request supplies: %d\n", ret); - return ret; - } - - dev_info(codec->dev, "Using internal LDO instead of VDDD\n"); - return 0; -} - static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) { u16 reg; @@ -1264,9 +1235,30 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) if (!ret) external_vddd = 1; else { - ret = sgtl5000_replace_vddd_with_ldo(codec); - if (ret) + /* set internal ldo to 1.2v */ + int voltage = LDO_VOLTAGE; + + ret = ldo_regulator_register(codec, &ldo_init_data, voltage); + if (ret) { + dev_err(codec->dev, + "Failed to register vddd internal supplies: %d\n", + ret); return ret; + } + + sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; + + ret = regulator_bulk_get(codec->dev, + ARRAY_SIZE(sgtl5000->supplies), + sgtl5000->supplies); + + if (ret) { + ldo_regulator_remove(codec); + dev_err(codec->dev, + "Failed to request supplies: %d\n", ret); + + return ret; + } } ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), @@ -1295,6 +1287,7 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) * roll back to use internal LDO */ if (external_vddd && rev >= 0x11) { + int voltage = LDO_VOLTAGE; /* disable all regulator first */ regulator_bulk_disable(ARRAY_SIZE(sgtl5000->supplies), sgtl5000->supplies); @@ -1302,10 +1295,23 @@ static int sgtl5000_enable_regulators(struct snd_soc_codec *codec) regulator_bulk_free(ARRAY_SIZE(sgtl5000->supplies), sgtl5000->supplies); - ret = sgtl5000_replace_vddd_with_ldo(codec); + ret = ldo_regulator_register(codec, &ldo_init_data, voltage); if (ret) return ret; + sgtl5000->supplies[VDDD].supply = LDO_CONSUMER_NAME; + + ret = regulator_bulk_get(codec->dev, + ARRAY_SIZE(sgtl5000->supplies), + sgtl5000->supplies); + if (ret) { + ldo_regulator_remove(codec); + dev_err(codec->dev, + "Failed to request supplies: %d\n", ret); + + return ret; + } + ret = regulator_bulk_enable(ARRAY_SIZE(sgtl5000->supplies), sgtl5000->supplies); if (ret) diff --git a/trunk/sound/soc/codecs/wm8962.c b/trunk/sound/soc/codecs/wm8962.c index 60d740ebeb5b..8499c563a9b5 100644 --- a/trunk/sound/soc/codecs/wm8962.c +++ b/trunk/sound/soc/codecs/wm8962.c @@ -3409,9 +3409,6 @@ static irqreturn_t wm8962_irq(int irq, void *data) active = snd_soc_read(codec, WM8962_INTERRUPT_STATUS_2); active &= ~mask; - /* Acknowledge the interrupts */ - snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active); - if (active & WM8962_FLL_LOCK_EINT) { dev_dbg(codec->dev, "FLL locked\n"); complete(&wm8962->fll_lock); @@ -3436,6 +3433,9 @@ static irqreturn_t wm8962_irq(int irq, void *data) msecs_to_jiffies(250)); } + /* Acknowledge the interrupts */ + snd_soc_write(codec, WM8962_INTERRUPT_STATUS_2, active); + return IRQ_HANDLED; } diff --git a/trunk/sound/soc/davinci/davinci-vcif.c b/trunk/sound/soc/davinci/davinci-vcif.c index 1f11525d97e8..9259f1f34899 100644 --- a/trunk/sound/soc/davinci/davinci-vcif.c +++ b/trunk/sound/soc/davinci/davinci-vcif.c @@ -62,9 +62,9 @@ static void davinci_vcif_start(struct snd_pcm_substream *substream) w = readl(davinci_vc->base + DAVINCI_VC_CTRL); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0); + MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1); else - MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0); + MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1); writel(w, davinci_vc->base + DAVINCI_VC_CTRL); } @@ -80,9 +80,9 @@ static void davinci_vcif_stop(struct snd_pcm_substream *substream) /* Reset transmitter/receiver and sample rate/frame sync generators */ w = readl(davinci_vc->base + DAVINCI_VC_CTRL); if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) - MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 1); + MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTDAC, 0); else - MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 1); + MOD_REG_BIT(w, DAVINCI_VC_CTRL_RSTADC, 0); writel(w, davinci_vc->base + DAVINCI_VC_CTRL); } @@ -159,7 +159,6 @@ static int davinci_vcif_trigger(struct snd_pcm_substream *substream, int cmd, case SNDRV_PCM_TRIGGER_RESUME: case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: davinci_vcif_start(substream); - break; case SNDRV_PCM_TRIGGER_STOP: case SNDRV_PCM_TRIGGER_SUSPEND: case SNDRV_PCM_TRIGGER_PAUSE_PUSH: diff --git a/trunk/sound/soc/samsung/i2s.c b/trunk/sound/soc/samsung/i2s.c index c086b78539ee..1568eea31f41 100644 --- a/trunk/sound/soc/samsung/i2s.c +++ b/trunk/sound/soc/samsung/i2s.c @@ -21,7 +21,6 @@ #include #include "dma.h" -#include "idma.h" #include "i2s.h" #include "i2s-regs.h" @@ -61,7 +60,6 @@ struct i2s_dai { /* DMA parameters */ struct s3c_dma_params dma_playback; struct s3c_dma_params dma_capture; - struct s3c_dma_params idma_playback; u32 quirks; u32 suspend_i2smod; u32 suspend_i2scon; @@ -879,10 +877,6 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai) if (i2s->quirks & QUIRK_NEED_RSTCLR) writel(CON_RSTCLR, i2s->addr + I2SCON); - if (i2s->quirks & QUIRK_SEC_DAI) - idma_reg_addr_init((void *)i2s->addr, - i2s->sec_dai->idma_playback.dma_addr); - probe_exit: /* Reset any constraint on RFS and BFS */ i2s->rfs = 0; @@ -1083,7 +1077,6 @@ static __devinit int samsung_i2s_probe(struct platform_device *pdev) sec_dai->dma_playback.dma_size = 4; sec_dai->base = regs_base; sec_dai->quirks = quirks; - sec_dai->idma_playback.dma_addr = i2s_cfg->idma_addr; sec_dai->pri_dai = pri_dai; pri_dai->sec_dai = sec_dai; } diff --git a/trunk/sound/soc/soc-core.c b/trunk/sound/soc/soc-core.c index 83ad8ca27490..e44267f66216 100644 --- a/trunk/sound/soc/soc-core.c +++ b/trunk/sound/soc/soc-core.c @@ -577,7 +577,6 @@ int snd_soc_suspend(struct device *dev) case SND_SOC_BIAS_OFF: codec->driver->suspend(codec, PMSG_SUSPEND); codec->suspended = 1; - codec->cache_sync = 1; break; default: dev_dbg(codec->dev, "CODEC is on over suspend\n"); @@ -1141,7 +1140,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) } } cpu_dai->probed = 1; - /* mark cpu_dai as probed and add to card dai list */ + /* mark cpu_dai as probed and add to card cpu_dai list */ list_add(&cpu_dai->card_list, &card->dai_dev_list); } @@ -1172,7 +1171,7 @@ static int soc_probe_dai_link(struct snd_soc_card *card, int num, int order) } } - /* mark codec_dai as probed and add to card dai list */ + /* mark cpu_dai as probed and add to card cpu_dai list */ codec_dai->probed = 1; list_add(&codec_dai->card_list, &card->dai_dev_list); } diff --git a/trunk/sound/soc/soc-dapm.c b/trunk/sound/soc/soc-dapm.c index 7e15914b3633..fbfcda062839 100644 --- a/trunk/sound/soc/soc-dapm.c +++ b/trunk/sound/soc/soc-dapm.c @@ -124,36 +124,6 @@ static inline struct snd_soc_dapm_widget *dapm_cnew_widget( return kmemdup(_widget, sizeof(*_widget), GFP_KERNEL); } -/* get snd_card from DAPM context */ -static inline struct snd_card *dapm_get_snd_card( - struct snd_soc_dapm_context *dapm) -{ - if (dapm->codec) - return dapm->codec->card->snd_card; - else if (dapm->platform) - return dapm->platform->card->snd_card; - else - BUG(); - - /* unreachable */ - return NULL; -} - -/* get soc_card from DAPM context */ -static inline struct snd_soc_card *dapm_get_soc_card( - struct snd_soc_dapm_context *dapm) -{ - if (dapm->codec) - return dapm->codec->card; - else if (dapm->platform) - return dapm->platform->card; - else - BUG(); - - /* unreachable */ - return NULL; -} - static int soc_widget_read(struct snd_soc_dapm_widget *w, int reg) { if (w->codec)