diff -Nur -p linux-2.4.32/arch/alpha/kernel/pci_iommu.c linux-2.4.33-rc2/arch/alpha/kernel/pci_iommu.c --- linux-2.4.32/arch/alpha/kernel/pci_iommu.c 2003-06-13 11:51:29.000000000 -0300 +++ linux-2.4.33-rc2/arch/alpha/kernel/pci_iommu.c 2006-06-21 10:40:43.000000000 -0300 @@ -503,7 +503,7 @@ sg_classify(struct scatterlist *sg, stru /* Given a scatterlist leader, choose an allocation method and fill in the blanks. */ -static inline int +static int sg_fill(struct scatterlist *leader, struct scatterlist *end, struct scatterlist *out, struct pci_iommu_arena *arena, dma_addr_t max_dma, int dac_allowed) diff -Nur -p linux-2.4.32/arch/i386/config.in linux-2.4.33-rc2/arch/i386/config.in --- linux-2.4.32/arch/i386/config.in 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/arch/i386/config.in 2006-06-21 10:40:43.000000000 -0300 @@ -65,6 +65,7 @@ else define_bool CONFIG_X86_POPAD_OK y define_bool CONFIG_RWSEM_GENERIC_SPINLOCK n define_bool CONFIG_RWSEM_XCHGADD_ALGORITHM y + define_bool CONFIG_X86_TSC n fi if [ "$CONFIG_M486" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 4 @@ -72,6 +73,7 @@ if [ "$CONFIG_M486" = "y" ]; then define_bool CONFIG_X86_ALIGNMENT_16 y define_bool CONFIG_X86_PPRO_FENCE y define_bool CONFIG_X86_F00F_WORKS_OK n + define_bool CONFIG_X86_TSC n fi if [ "$CONFIG_M586" = "y" ]; then define_int CONFIG_X86_L1_CACHE_SHIFT 5 diff -Nur -p linux-2.4.32/arch/i386/kernel/dmi_scan.c linux-2.4.33-rc2/arch/i386/kernel/dmi_scan.c --- linux-2.4.32/arch/i386/kernel/dmi_scan.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/arch/i386/kernel/dmi_scan.c 2006-06-21 10:40:43.000000000 -0300 @@ -411,7 +411,7 @@ typedef void (pm_kbd_func) (void); static __init int broken_ps2_resume(struct dmi_blacklist *d) { -#ifdef CONFIG_VT +#if defined(CONFIG_VT) && !defined(CONFIG_DUMMY_KEYB) if (pm_kbd_request_override == NULL) { pm_kbd_request_override = pckbd_pm_resume; diff -Nur -p linux-2.4.32/arch/i386/kernel/i387.c linux-2.4.33-rc2/arch/i386/kernel/i387.c --- linux-2.4.32/arch/i386/kernel/i387.c 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/arch/i386/kernel/i387.c 2006-06-21 10:40:43.000000000 -0300 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include @@ -70,8 +71,12 @@ void init_fpu(void) static inline void __save_init_fpu( struct task_struct *tsk ) { if ( cpu_has_fxsr ) { - asm volatile( "fxsave %0 ; fnclex" + asm volatile( "fxsave %0" : "=m" (tsk->thread.i387.fxsave) ); + if (tsk->thread.i387.fxsave.swd & (1<<7)) + asm volatile("fnclex"); + /* AMD CPUs leak F?P. Clear it here */ + asm volatile("ffree %%st(7) ; fildl %0" :: "m" (kstat.context_swtch)); } else { asm volatile( "fnsave %0 ; fwait" : "=m" (tsk->thread.i387.fsave) ); diff -Nur -p linux-2.4.32/arch/i386/kernel/io_apic.c linux-2.4.33-rc2/arch/i386/kernel/io_apic.c --- linux-2.4.32/arch/i386/kernel/io_apic.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/arch/i386/kernel/io_apic.c 2006-06-21 10:40:43.000000000 -0300 @@ -1194,7 +1194,7 @@ static int __init timer_irq_works(void) * might have cached one ExtINT interrupt. Finally, at * least one tick may be lost due to delays. */ - if (jiffies - t1 > 4) + if (jiffies - t1 > 4 && jiffies - t1 < 16) return 1; return 0; diff -Nur -p linux-2.4.32/arch/ia64/ia32/sys_ia32.c linux-2.4.33-rc2/arch/ia64/ia32/sys_ia32.c --- linux-2.4.32/arch/ia64/ia32/sys_ia32.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/arch/ia64/ia32/sys_ia32.c 2006-06-21 10:40:43.000000000 -0300 @@ -1442,6 +1442,7 @@ get_cmsghdr32 (struct msghdr *kmsg, unsi tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); + tmp = CMSG_ALIGN(tmp); kcmlen += tmp; ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); } @@ -1478,7 +1479,7 @@ get_cmsghdr32 (struct msghdr *kmsg, unsi goto out_free_efault; /* Advance. */ - kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); + kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp); ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); } diff -Nur -p linux-2.4.32/arch/parisc/kernel/ioctl32.c linux-2.4.33-rc2/arch/parisc/kernel/ioctl32.c --- linux-2.4.32/arch/parisc/kernel/ioctl32.c 2005-01-19 12:09:34.000000000 -0200 +++ linux-2.4.33-rc2/arch/parisc/kernel/ioctl32.c 2006-06-21 10:40:43.000000000 -0300 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff -Nur -p linux-2.4.32/arch/parisc/kernel/sys_parisc32.c linux-2.4.33-rc2/arch/parisc/kernel/sys_parisc32.c --- linux-2.4.32/arch/parisc/kernel/sys_parisc32.c 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/arch/parisc/kernel/sys_parisc32.c 2006-06-21 10:40:43.000000000 -0300 @@ -1934,12 +1934,13 @@ static int cmsghdr_from_user32_to_kern(s struct cmsghdr *kcmsg, *kcmsg_base; __kernel_size_t32 ucmlen; __kernel_size_t kcmlen, tmp; + int err = -EFAULT; kcmlen = 0; kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; ucmsg = CMSG32_FIRSTHDR(kmsg); while(ucmsg != NULL) { - if(get_user(ucmlen, &ucmsg->cmsg_len)) + if (get_user(ucmlen, &ucmsg->cmsg_len)) return -EFAULT; /* Catch bogons. */ @@ -1948,6 +1949,7 @@ static int cmsghdr_from_user32_to_kern(s tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); + tmp = CMSG_ALIGN(tmp); kcmlen += tmp; ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); } @@ -1968,21 +1970,23 @@ static int cmsghdr_from_user32_to_kern(s memset(kcmsg, 0, kcmlen); ucmsg = CMSG32_FIRSTHDR(kmsg); while(ucmsg != NULL) { - __get_user(ucmlen, &ucmsg->cmsg_len); + if (__get_user(ucmlen, &ucmsg->cmsg_len)) + goto Efault; tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); + if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp)) + goto Einval; kcmsg->cmsg_len = tmp; - __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); - __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); - - /* Copy over the data. */ - if(copy_from_user(CMSG_DATA(kcmsg), - CMSG32_DATA(ucmsg), - (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) - goto out_free_efault; + tmp = CMSG_ALIGN(tmp); + if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) || + __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) || + copy_from_user(CMSG_DATA(kcmsg), + CMSG32_DATA(ucmsg), + (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) + goto Efault; /* Advance. */ - kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); + kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp); ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); } @@ -1991,10 +1995,12 @@ static int cmsghdr_from_user32_to_kern(s kmsg->msg_controllen = kcmlen; return 0; -out_free_efault: - if(kcmsg_base != (struct cmsghdr *)stackbuf) +Einval: + err = -EINVAL; +Efault: + if (kcmsg_base != (struct cmsghdr *)stackbuf) kfree(kcmsg_base); - return -EFAULT; + return err; } static void put_cmsg32(struct msghdr *kmsg, int level, int type, diff -Nur -p linux-2.4.32/arch/ppc64/kernel/ioctl32.c linux-2.4.33-rc2/arch/ppc64/kernel/ioctl32.c --- linux-2.4.32/arch/ppc64/kernel/ioctl32.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/arch/ppc64/kernel/ioctl32.c 2006-06-21 10:40:43.000000000 -0300 @@ -49,6 +49,7 @@ #include #include #include +#include #include #include #include diff -Nur -p linux-2.4.32/arch/ppc64/kernel/signal.c linux-2.4.33-rc2/arch/ppc64/kernel/signal.c --- linux-2.4.32/arch/ppc64/kernel/signal.c 2005-01-19 12:09:36.000000000 -0200 +++ linux-2.4.33-rc2/arch/ppc64/kernel/signal.c 2006-06-21 10:40:43.000000000 -0300 @@ -332,7 +332,7 @@ setup_trampoline(unsigned int syscall, u } -asmlinkage int +asmlinkage long sys_rt_sigreturn(unsigned long r3, unsigned long r4, unsigned long r5, unsigned long r6, unsigned long r7, unsigned long r8, struct pt_regs *regs) diff -Nur -p linux-2.4.32/arch/ppc64/kernel/sys_ppc32.c linux-2.4.33-rc2/arch/ppc64/kernel/sys_ppc32.c --- linux-2.4.32/arch/ppc64/kernel/sys_ppc32.c 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/arch/ppc64/kernel/sys_ppc32.c 2006-06-21 10:40:43.000000000 -0300 @@ -3442,12 +3442,13 @@ static int cmsghdr_from_user32_to_kern(s struct cmsghdr *kcmsg, *kcmsg_base; __kernel_size_t32 ucmlen; __kernel_size_t kcmlen, tmp; + int err = -EFAULT; kcmlen = 0; kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; ucmsg = CMSG32_FIRSTHDR(kmsg); while(ucmsg != NULL) { - if(get_user(ucmlen, &ucmsg->cmsg_len)) + if (get_user(ucmlen, &ucmsg->cmsg_len)) return -EFAULT; /* Catch bogons. */ @@ -3456,6 +3457,7 @@ static int cmsghdr_from_user32_to_kern(s tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); + tmp = CMSG_ALIGN(tmp); kcmlen += tmp; ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); } @@ -3476,21 +3478,23 @@ static int cmsghdr_from_user32_to_kern(s memset(kcmsg, 0, kcmlen); ucmsg = CMSG32_FIRSTHDR(kmsg); while (ucmsg != NULL) { - __get_user(ucmlen, &ucmsg->cmsg_len); + if (__get_user(ucmlen, &ucmsg->cmsg_len)) + goto Efault; tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); + if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp)) + goto Einval; kcmsg->cmsg_len = tmp; - __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); - __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); - - /* Copy over the data. */ - if(copy_from_user(CMSG_DATA(kcmsg), - CMSG32_DATA(ucmsg), - (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) - goto out_free_efault; + tmp = CMSG_ALIGN(tmp); + if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) || + __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) || + copy_from_user(CMSG_DATA(kcmsg), + CMSG32_DATA(ucmsg), + (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) + goto Efault; /* Advance. */ - kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); + kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp); ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); } @@ -3499,10 +3503,12 @@ static int cmsghdr_from_user32_to_kern(s kmsg->msg_controllen = kcmlen; return 0; -out_free_efault: - if(kcmsg_base != (struct cmsghdr *)stackbuf) +Einval: + err = -EINVAL; +Efault: + if (kcmsg_base != (struct cmsghdr *)stackbuf) kfree(kcmsg_base); - return -EFAULT; + return err; } asmlinkage long sys32_sendmsg(int fd, struct msghdr32* user_msg, unsigned int user_flags) diff -Nur -p linux-2.4.32/arch/s390x/kernel/linux32.c linux-2.4.33-rc2/arch/s390x/kernel/linux32.c --- linux-2.4.32/arch/s390x/kernel/linux32.c 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/arch/s390x/kernel/linux32.c 2006-06-21 10:40:43.000000000 -0300 @@ -2425,12 +2425,13 @@ static int cmsghdr_from_user32_to_kern(s struct cmsghdr *kcmsg, *kcmsg_base; __kernel_size_t32 ucmlen; __kernel_size_t kcmlen, tmp; + int err = -EFAULT; kcmlen = 0; kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; ucmsg = CMSG32_FIRSTHDR(kmsg); while(ucmsg != NULL) { - if(get_user(ucmlen, &ucmsg->cmsg_len)) + if (get_user(ucmlen, &ucmsg->cmsg_len)) return -EFAULT; /* Catch bogons. */ @@ -2439,6 +2440,7 @@ static int cmsghdr_from_user32_to_kern(s tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); + tmp = CMSG_ALIGN(tmp); kcmlen += tmp; ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); } @@ -2459,21 +2461,23 @@ static int cmsghdr_from_user32_to_kern(s memset(kcmsg, 0, kcmlen); ucmsg = CMSG32_FIRSTHDR(kmsg); while(ucmsg != NULL) { - __get_user(ucmlen, &ucmsg->cmsg_len); + if (__get_user(ucmlen, &ucmsg->cmsg_len)) + goto Efault; tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); + if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp)) + goto Einval; kcmsg->cmsg_len = tmp; - __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); - __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); - - /* Copy over the data. */ - if(copy_from_user(CMSG_DATA(kcmsg), - CMSG32_DATA(ucmsg), - (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) - goto out_free_efault; + tmp = CMSG_ALIGN(tmp); + if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) || + __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) || + copy_from_user(CMSG_DATA(kcmsg), + CMSG32_DATA(ucmsg), + (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) + goto Efault; /* Advance. */ - kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); + kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp); ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); } @@ -2482,10 +2486,12 @@ static int cmsghdr_from_user32_to_kern(s kmsg->msg_controllen = kcmlen; return 0; -out_free_efault: - if(kcmsg_base != (struct cmsghdr *)stackbuf) +Einval: + err = -EINVAL; +Efault: + if (kcmsg_base != (struct cmsghdr *)stackbuf) kfree(kcmsg_base); - return -EFAULT; + return err; } static void put_cmsg32(struct msghdr *kmsg, int level, int type, diff -Nur -p linux-2.4.32/arch/sparc/math-emu/math.c linux-2.4.33-rc2/arch/sparc/math-emu/math.c --- linux-2.4.32/arch/sparc/math-emu/math.c 1999-12-02 21:28:54.000000000 -0200 +++ linux-2.4.33-rc2/arch/sparc/math-emu/math.c 2006-06-21 10:40:43.000000000 -0300 @@ -323,10 +323,6 @@ static int do_one_mathemu(u32 insn, unsi case FMOVS: case FABSS: case FNEGS: TYPE(2,1,0,1,0,0,0); break; - default: -#ifdef DEBUG_MATHEMU - printk("unknown FPop1: %03lx\n",(insn>>5)&0x1ff); -#endif } } else if ((insn & 0xc1f80000) == 0x81a80000) /* FPOP2 */ { switch ((insn >> 5) & 0x1ff) { @@ -336,10 +332,6 @@ static int do_one_mathemu(u32 insn, unsi case FCMPED: TYPE(3,0,0,2,1,2,1); break; case FCMPQ: TYPE(3,0,0,3,1,3,1); break; case FCMPEQ: TYPE(3,0,0,3,1,3,1); break; - default: -#ifdef DEBUG_MATHEMU - printk("unknown FPop2: %03lx\n",(insn>>5)&0x1ff); -#endif } } diff -Nur -p linux-2.4.32/arch/sparc64/kernel/entry.S linux-2.4.33-rc2/arch/sparc64/kernel/entry.S --- linux-2.4.32/arch/sparc64/kernel/entry.S 2003-11-28 16:26:19.000000000 -0200 +++ linux-2.4.33-rc2/arch/sparc64/kernel/entry.S 2006-06-21 10:40:43.000000000 -0300 @@ -21,6 +21,7 @@ #include #include #include +#include /* #define SYSCALL_TRACING 1 */ @@ -727,14 +728,159 @@ netbsd_syscall: retl nop - /* These next few routines must be sure to clear the - * SFSR FaultValid bit so that the fast tlb data protection - * handler does not flush the wrong context and lock up the - * box. - */ - .globl __do_data_access_exception - .globl __do_data_access_exception_tl1 -__do_data_access_exception_tl1: + /* We need to carefully read the error status, ACK + * the errors, prevent recursive traps, and pass the + * information on to C code for logging. + * + * We pass the AFAR in as-is, and we encode the status + * information as described in asm-sparc64/sfafsr.h + */ + .globl __spitfire_access_error +__spitfire_access_error: + /* Disable ESTATE error reporting so that we do not + * take recursive traps and RED state the processor. + */ + stxa %g0, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + mov UDBE_UE, %g1 + ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR + + /* __spitfire_cee_trap branches here with AFSR in %g4 and + * UDBE_CE in %g1. It only clears ESTATE_ERR_CE in the + * ESTATE Error Enable register. + */ +__spitfire_cee_trap_continue: + ldxa [%g0] ASI_AFAR, %g5 ! Get AFAR + + rdpr %tt, %g3 + and %g3, 0x1ff, %g3 ! Paranoia + sllx %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3 + or %g4, %g3, %g4 + rdpr %tl, %g3 + cmp %g3, 1 + mov 1, %g3 + bleu %xcc, 1f + sllx %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3 + + or %g4, %g3, %g4 + + /* Read in the UDB error register state, clearing the + * sticky error bits as-needed. We only clear them if + * the UE bit is set. Likewise, __spitfire_cee_trap + * below will only do so if the CE bit is set. + * + * NOTE: UltraSparc-I/II have high and low UDB error + * registers, corresponding to the two UDB units + * present on those chips. UltraSparc-IIi only + * has a single UDB, called "SDB" in the manual. + * For IIi the upper UDB register always reads + * as zero so for our purposes things will just + * work with the checks below. + */ +1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3 + and %g3, 0x3ff, %g7 ! Paranoia + sllx %g7, SFSTAT_UDBH_SHIFT, %g7 + or %g4, %g7, %g4 + andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE + be,pn %xcc, 1f + nop + stxa %g3, [%g0] ASI_UDB_ERROR_W + membar #Sync + +1: mov 0x18, %g3 + ldxa [%g3] ASI_UDBL_ERROR_R, %g3 + and %g3, 0x3ff, %g7 ! Paranoia + sllx %g7, SFSTAT_UDBL_SHIFT, %g7 + or %g4, %g7, %g4 + andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE + be,pn %xcc, 1f + nop + mov 0x18, %g7 + stxa %g3, [%g7] ASI_UDB_ERROR_W + membar #Sync + +1: /* Ok, now that we've latched the error state, + * clear the sticky bits in the AFSR. + */ + stxa %g4, [%g0] ASI_AFSR + membar #Sync + + rdpr %tl, %g2 + cmp %g2, 1 + rdpr %pil, %g2 + bleu,pt %xcc, 1f + wrpr %g0, 15, %pil + + ba,pt %xcc, etraptl1 + rd %pc, %g7 + + ba,pt %xcc, 2f + nop + +1: ba,pt %xcc, etrap_irq + rd %pc, %g7 + +2: mov %l4, %o1 + mov %l5, %o2 + call spitfire_access_error + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + clr %l6 + + /* This is the trap handler entry point for ECC correctable + * errors. They are corrected, but we listen for the trap + * so that the event can be logged. + * + * Disrupting errors are either: + * 1) single-bit ECC errors during UDB reads to system + * memory + * 2) data parity errors during write-back events + * + * As far as I can make out from the manual, the CEE trap + * is only for correctable errors during memory read + * accesses by the front-end of the processor. + * + * The code below is only for trap level 1 CEE events, + * as it is the only situation where we can safely record + * and log. For trap level >1 we just clear the CE bit + * in the AFSR and return. + * + * This is just like __spiftire_access_error above, but it + * specifically handles correctable errors. If an + * uncorrectable error is indicated in the AFSR we + * will branch directly above to __spitfire_access_error + * to handle it instead. Uncorrectable therefore takes + * priority over correctable, and the error logging + * C code will notice this case by inspecting the + * trap type. + */ + .globl __spitfire_cee_trap +__spitfire_cee_trap: + ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR + mov 1, %g3 + sllx %g3, SFAFSR_UE_SHIFT, %g3 + andcc %g4, %g3, %g0 ! Check for UE + bne,pn %xcc, __spitfire_access_error + nop + + /* Ok, in this case we only have a correctable error. + * Indicate we only wish to capture that state in register + * %g1, and we only disable CE error reporting unlike UE + * handling which disables all errors. + */ + ldxa [%g0] ASI_ESTATE_ERROR_EN, %g3 + andn %g3, ESTATE_ERR_CE, %g3 + stxa %g3, [%g0] ASI_ESTATE_ERROR_EN + membar #Sync + + /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */ + ba,pt %xcc, __spitfire_cee_trap_continue + mov UDBE_CE, %g1 + + .globl __spitfire_data_access_exception + .globl __spitfire_data_access_exception_tl1 +__spitfire_data_access_exception_tl1: rdpr %pstate, %g4 wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate mov TLB_SFSR, %g3 @@ -743,9 +889,25 @@ __do_data_access_exception_tl1: ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit membar #Sync + rdpr %tt, %g3 + cmp %g3, 0x80 ! first win spill/fill trap + blu,pn %xcc, 1f + cmp %g3, 0xff ! last win spill/fill trap + bgu,pn %xcc, 1f + nop ba,pt %xcc, winfix_dax rdpr %tpc, %g3 -__do_data_access_exception: +1: sethi %hi(109f), %g7 + ba,pt %xcc, etraptl1 +109: or %g7, %lo(109b), %g7 + mov %l4, %o1 + mov %l5, %o2 + call spitfire_data_access_exception_tl1 + add %sp, PTREGS_OFF, %o0 + ba,pt %xcc, rtrap + clr %l6 + +__spitfire_data_access_exception: rdpr %pstate, %g4 wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate mov TLB_SFSR, %g3 @@ -759,20 +921,19 @@ __do_data_access_exception: 109: or %g7, %lo(109b), %g7 mov %l4, %o1 mov %l5, %o2 - call data_access_exception + call spitfire_data_access_exception add %sp, PTREGS_OFF, %o0 ba,pt %xcc, rtrap clr %l6 - .globl __do_instruction_access_exception - .globl __do_instruction_access_exception_tl1 -__do_instruction_access_exception_tl1: + .globl __spitfire_insn_access_exception + .globl __spitfire_insn_access_exception_tl1 +__spitfire_insn_access_exception_tl1: rdpr %pstate, %g4 wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate mov TLB_SFSR, %g3 - mov DMMU_SFAR, %g5 - ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR - ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR + ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR + rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit membar #Sync sethi %hi(109f), %g7 @@ -780,18 +941,17 @@ __do_instruction_access_exception_tl1: 109: or %g7, %lo(109b), %g7 mov %l4, %o1 mov %l5, %o2 - call instruction_access_exception_tl1 + call spitfire_insn_access_exception_tl1 add %sp, PTREGS_OFF, %o0 ba,pt %xcc, rtrap clr %l6 -__do_instruction_access_exception: +__spitfire_insn_access_exception: rdpr %pstate, %g4 wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate mov TLB_SFSR, %g3 - mov DMMU_SFAR, %g5 - ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR - ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR + ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR + rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit membar #Sync sethi %hi(109f), %g7 @@ -799,102 +959,11 @@ __do_instruction_access_exception: 109: or %g7, %lo(109b), %g7 mov %l4, %o1 mov %l5, %o2 - call instruction_access_exception + call spitfire_insn_access_exception add %sp, PTREGS_OFF, %o0 ba,pt %xcc, rtrap clr %l6 - /* This is the trap handler entry point for ECC correctable - * errors. They are corrected, but we listen for the trap - * so that the event can be logged. - * - * Disrupting errors are either: - * 1) single-bit ECC errors during UDB reads to system - * memory - * 2) data parity errors during write-back events - * - * As far as I can make out from the manual, the CEE trap - * is only for correctable errors during memory read - * accesses by the front-end of the processor. - * - * The code below is only for trap level 1 CEE events, - * as it is the only situation where we can safely record - * and log. For trap level >1 we just clear the CE bit - * in the AFSR and return. - */ - - /* Our trap handling infrastructure allows us to preserve - * two 64-bit values during etrap for arguments to - * subsequent C code. Therefore we encode the information - * as follows: - * - * value 1) Full 64-bits of AFAR - * value 2) Low 33-bits of AFSR, then bits 33-->42 - * are UDBL error status and bits 43-->52 - * are UDBH error status - */ - .align 64 - .globl cee_trap -cee_trap: - ldxa [%g0] ASI_AFSR, %g1 ! Read AFSR - ldxa [%g0] ASI_AFAR, %g2 ! Read AFAR - sllx %g1, 31, %g1 ! Clear reserved bits - srlx %g1, 31, %g1 ! in AFSR - - /* NOTE: UltraSparc-I/II have high and low UDB error - * registers, corresponding to the two UDB units - * present on those chips. UltraSparc-IIi only - * has a single UDB, called "SDB" in the manual. - * For IIi the upper UDB register always reads - * as zero so for our purposes things will just - * work with the checks below. - */ - ldxa [%g0] ASI_UDBL_ERROR_R, %g3 ! Read UDB-Low error status - andcc %g3, (1 << 8), %g4 ! Check CE bit - sllx %g3, (64 - 10), %g3 ! Clear reserved bits - srlx %g3, (64 - 10), %g3 ! in UDB-Low error status - - sllx %g3, (33 + 0), %g3 ! Shift up to encoding area - or %g1, %g3, %g1 ! Or it in - be,pn %xcc, 1f ! Branch if CE bit was clear - nop - stxa %g4, [%g0] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBL - membar #Sync ! Synchronize ASI stores -1: mov 0x18, %g5 ! Addr of UDB-High error status - ldxa [%g5] ASI_UDBH_ERROR_R, %g3 ! Read it - - andcc %g3, (1 << 8), %g4 ! Check CE bit - sllx %g3, (64 - 10), %g3 ! Clear reserved bits - srlx %g3, (64 - 10), %g3 ! in UDB-High error status - sllx %g3, (33 + 10), %g3 ! Shift up to encoding area - or %g1, %g3, %g1 ! Or it in - be,pn %xcc, 1f ! Branch if CE bit was clear - nop - nop - - stxa %g4, [%g5] ASI_UDB_ERROR_W ! Clear CE sticky bit in UDBH - membar #Sync ! Synchronize ASI stores -1: mov 1, %g5 ! AFSR CE bit is - sllx %g5, 20, %g5 ! bit 20 - stxa %g5, [%g0] ASI_AFSR ! Clear CE sticky bit in AFSR - membar #Sync ! Synchronize ASI stores - sllx %g2, (64 - 41), %g2 ! Clear reserved bits - srlx %g2, (64 - 41), %g2 ! in latched AFAR - - andn %g2, 0x0f, %g2 ! Finish resv bit clearing - mov %g1, %g4 ! Move AFSR+UDB* into save reg - mov %g2, %g5 ! Move AFAR into save reg - rdpr %pil, %g2 - wrpr %g0, 15, %pil - ba,pt %xcc, etrap_irq - rd %pc, %g7 - mov %l4, %o0 - - mov %l5, %o1 - call cee_log - add %sp, PTREGS_OFF, %o2 - ba,a,pt %xcc, rtrap_clr_l6 - /* Capture I/D/E-cache state into per-cpu error scoreboard. * * %g1: (TL>=0) ? 1 : 0 diff -Nur -p linux-2.4.32/arch/sparc64/kernel/irq.c linux-2.4.33-rc2/arch/sparc64/kernel/irq.c --- linux-2.4.32/arch/sparc64/kernel/irq.c 2003-11-28 16:26:19.000000000 -0200 +++ linux-2.4.33-rc2/arch/sparc64/kernel/irq.c 2006-06-21 10:40:43.000000000 -0300 @@ -599,7 +599,7 @@ static void show(char * str) #if 0 #define SYNC_OTHER_ULTRAS(x) udelay(x+1) #else -#define SYNC_OTHER_ULTRAS(x) membar("#Sync"); +#define SYNC_OTHER_ULTRAS(x) membar_safe("#Sync"); #endif void synchronize_irq(void) diff -Nur -p linux-2.4.32/arch/sparc64/kernel/pci_iommu.c linux-2.4.33-rc2/arch/sparc64/kernel/pci_iommu.c --- linux-2.4.32/arch/sparc64/kernel/pci_iommu.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/arch/sparc64/kernel/pci_iommu.c 2006-06-21 10:40:43.000000000 -0300 @@ -436,7 +436,7 @@ void pci_unmap_single(struct pci_dev *pd pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); (void) pci_iommu_read(iommu->write_complete_reg); while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); + rmb(); } /* Step 2: Clear out first TSB entry. */ @@ -674,7 +674,7 @@ void pci_unmap_sg(struct pci_dev *pdev, pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); (void) pci_iommu_read(iommu->write_complete_reg); while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); + rmb(); } /* Step 2: Clear out first TSB entry. */ @@ -742,7 +742,7 @@ void pci_dma_sync_single(struct pci_dev pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); (void) pci_iommu_read(iommu->write_complete_reg); while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); + rmb(); spin_unlock_irqrestore(&iommu->lock, flags); } @@ -807,7 +807,7 @@ void pci_dma_sync_sg(struct pci_dev *pde pci_iommu_write(strbuf->strbuf_fsync, strbuf->strbuf_flushflag_pa); (void) pci_iommu_read(iommu->write_complete_reg); while (!PCI_STC_FLUSHFLAG_SET(strbuf)) - membar("#LoadLoad"); + rmb(); spin_unlock_irqrestore(&iommu->lock, flags); } diff -Nur -p linux-2.4.32/arch/sparc64/kernel/process.c linux-2.4.33-rc2/arch/sparc64/kernel/process.c --- linux-2.4.32/arch/sparc64/kernel/process.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/arch/sparc64/kernel/process.c 2006-06-21 10:40:43.000000000 -0300 @@ -100,7 +100,7 @@ int cpu_idle(void) * other cpus see our increasing idleness for the buddy * redistribution algorithm. -DaveM */ - membar("#StoreStore | #StoreLoad"); + membar_safe("#StoreStore | #StoreLoad"); } } diff -Nur -p linux-2.4.32/arch/sparc64/kernel/sbus.c linux-2.4.33-rc2/arch/sparc64/kernel/sbus.c --- linux-2.4.32/arch/sparc64/kernel/sbus.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/arch/sparc64/kernel/sbus.c 2006-06-21 10:40:43.000000000 -0300 @@ -128,7 +128,7 @@ static void strbuf_flush(struct sbus_iom iommu->strbuf_regs + STRBUF_FSYNC); upa_readq(iommu->sbus_control_reg); while (iommu->strbuf_flushflag == 0UL) - membar("#LoadLoad"); + rmb(); } static iopte_t *alloc_streaming_cluster(struct sbus_iommu *iommu, unsigned long npages) diff -Nur -p linux-2.4.32/arch/sparc64/kernel/smp.c linux-2.4.33-rc2/arch/sparc64/kernel/smp.c --- linux-2.4.32/arch/sparc64/kernel/smp.c 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/arch/sparc64/kernel/smp.c 2006-06-21 10:40:43.000000000 -0300 @@ -163,7 +163,7 @@ void __init smp_callin(void) current->active_mm = &init_mm; while (!smp_threads_ready) - membar("#LoadLoad"); + rmb(); } extern int cpu_idle(void); @@ -211,11 +211,11 @@ static inline long get_delta (long *rt, for (i = 0; i < NUM_ITERS; i++) { t0 = tick_ops->get_tick(); go[MASTER] = 1; - membar("#StoreLoad"); + membar_safe("#StoreLoad"); while (!(tm = go[SLAVE])) - membar("#LoadLoad"); + rmb(); go[SLAVE] = 0; - membar("#StoreStore"); + membar_safe("#StoreStore"); t1 = tick_ops->get_tick(); if (t1 - t0 < best_t1 - best_t0) @@ -248,7 +248,7 @@ void smp_synchronize_tick_client(void) go[MASTER] = 1; while (go[MASTER]) - membar("#LoadLoad"); + rmb(); local_irq_save(flags); { @@ -300,21 +300,21 @@ static void smp_synchronize_one_tick(int /* wait for client to be ready */ while (!go[MASTER]) - membar("#LoadLoad"); + rmb(); /* now let the client proceed into his loop */ go[MASTER] = 0; - membar("#StoreLoad"); + membar_safe("#StoreLoad"); spin_lock_irqsave(&itc_sync_lock, flags); { for (i = 0; i < NUM_ROUNDS*NUM_ITERS; i++) { while (!go[MASTER]) - membar("#LoadLoad"); + rmb(); go[MASTER] = 0; - membar("#StoreStore"); + membar_safe("#StoreStore"); go[SLAVE] = tick_ops->get_tick(); - membar("#StoreLoad"); + membar_safe("#StoreLoad"); } } spin_unlock_irqrestore(&itc_sync_lock, flags); @@ -431,7 +431,7 @@ ignorecpu: smp_num_cpus = cpucount + 1; } smp_processors_ready = 1; - membar("#StoreStore | #StoreLoad"); + membar_safe("#StoreStore | #StoreLoad"); smp_synchronize_tick(); } @@ -1036,7 +1036,7 @@ void smp_capture(void) if (smp_processors_ready) { int result = atomic_add_ret(1, &smp_capture_depth); - membar("#StoreStore | #LoadStore"); + membar_safe("#StoreStore | #LoadStore"); if (result == 1) { int ncpus = smp_num_cpus; @@ -1045,11 +1045,11 @@ void smp_capture(void) smp_processor_id()); #endif penguins_are_doing_time = 1; - membar("#StoreStore | #LoadStore"); + membar_safe("#StoreStore | #LoadStore"); atomic_inc(&smp_capture_registry); smp_cross_call(&xcall_capture, 0, 0, 0); while (atomic_read(&smp_capture_registry) != ncpus) - membar("#LoadLoad"); + rmb(); #ifdef CAPTURE_DEBUG printk("done\n"); #endif @@ -1066,7 +1066,7 @@ void smp_release(void) smp_processor_id()); #endif penguins_are_doing_time = 0; - membar("#StoreStore | #StoreLoad"); + membar_safe("#StoreStore | #StoreLoad"); atomic_dec(&smp_capture_registry); } } @@ -1088,9 +1088,9 @@ void smp_penguin_jailcell(int irq, struc save_alternate_globals(global_save); prom_world(1); atomic_inc(&smp_capture_registry); - membar("#StoreLoad | #StoreStore"); + membar_safe("#StoreLoad | #StoreStore"); while (penguins_are_doing_time) - membar("#LoadLoad"); + rmb(); restore_alternate_globals(global_save); atomic_dec(&smp_capture_registry); prom_world(0); diff -Nur -p linux-2.4.32/arch/sparc64/kernel/sys_sparc32.c linux-2.4.33-rc2/arch/sparc64/kernel/sys_sparc32.c --- linux-2.4.32/arch/sparc64/kernel/sys_sparc32.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/arch/sparc64/kernel/sys_sparc32.c 2006-06-21 10:40:43.000000000 -0300 @@ -2497,12 +2497,13 @@ static int cmsghdr_from_user32_to_kern(s struct cmsghdr *kcmsg, *kcmsg_base; __kernel_size_t32 ucmlen; __kernel_size_t kcmlen, tmp; + int err = -EFAULT; kcmlen = 0; kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; ucmsg = CMSG32_FIRSTHDR(kmsg); while(ucmsg != NULL) { - if(get_user(ucmlen, &ucmsg->cmsg_len)) + if (get_user(ucmlen, &ucmsg->cmsg_len)) return -EFAULT; /* Catch bogons. */ @@ -2511,6 +2512,7 @@ static int cmsghdr_from_user32_to_kern(s tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); + tmp = CMSG_ALIGN(tmp); kcmlen += tmp; ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); } @@ -2531,21 +2533,23 @@ static int cmsghdr_from_user32_to_kern(s memset(kcmsg, 0, kcmlen); ucmsg = CMSG32_FIRSTHDR(kmsg); while(ucmsg != NULL) { - __get_user(ucmlen, &ucmsg->cmsg_len); + if (__get_user(ucmlen, &ucmsg->cmsg_len)) + goto Efault; tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); + if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp)) + goto Einval; kcmsg->cmsg_len = tmp; - __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); - __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); - - /* Copy over the data. */ - if(copy_from_user(CMSG_DATA(kcmsg), - CMSG32_DATA(ucmsg), - (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) - goto out_free_efault; + tmp = CMSG_ALIGN(tmp); + if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) || + __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) || + copy_from_user(CMSG_DATA(kcmsg), + CMSG32_DATA(ucmsg), + (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) + goto Efault; /* Advance. */ - kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); + kcmsg = (struct cmsghdr *)((char *)kcmsg + tmp); ucmsg = CMSG32_NXTHDR(kmsg, ucmsg, ucmlen); } @@ -2554,10 +2558,12 @@ static int cmsghdr_from_user32_to_kern(s kmsg->msg_controllen = kcmlen; return 0; -out_free_efault: - if(kcmsg_base != (struct cmsghdr *)stackbuf) +Einval: + err = -EINVAL; +Efault: + if (kcmsg_base != (struct cmsghdr *)stackbuf) kfree(kcmsg_base); - return -EFAULT; + return err; } static void put_cmsg32(struct msghdr *kmsg, int level, int type, diff -Nur -p linux-2.4.32/arch/sparc64/kernel/traps.c linux-2.4.33-rc2/arch/sparc64/kernel/traps.c --- linux-2.4.32/arch/sparc64/kernel/traps.c 2003-11-28 16:26:19.000000000 -0200 +++ linux-2.4.33-rc2/arch/sparc64/kernel/traps.c 2006-06-21 10:40:43.000000000 -0300 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_KMOD @@ -112,14 +113,13 @@ void do_BUG(const char *file, int line) } #endif -void instruction_access_exception(struct pt_regs *regs, - unsigned long sfsr, unsigned long sfar) +void spitfire_insn_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) { siginfo_t info; if (regs->tstate & TSTATE_PRIV) { - printk("instruction_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", - sfsr, sfar); + printk("spitfire_insn_access_exception: SFSR[%016lx] " + "SFAR[%016lx], going.\n", sfsr, sfar); die_if_kernel("Iax", regs); } if ((current->thread.flags & SPARC_FLAG_32BIT) != 0) { @@ -134,15 +134,13 @@ void instruction_access_exception(struct force_sig_info(SIGSEGV, &info, current); } -void instruction_access_exception_tl1(struct pt_regs *regs, - unsigned long sfsr, unsigned long sfar) +void spitfire_insn_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) { dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); - instruction_access_exception(regs, sfsr, sfar); + spitfire_insn_access_exception(regs, sfsr, sfar); } -void data_access_exception (struct pt_regs *regs, - unsigned long sfsr, unsigned long sfar) +void spitfire_data_access_exception(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) { siginfo_t info; @@ -164,8 +162,8 @@ void data_access_exception (struct pt_re return; } /* Shit... */ - printk("data_access_exception: SFSR[%016lx] SFAR[%016lx], going.\n", - sfsr, sfar); + printk("spitfire_data_access_exception: SFSR[%016lx] " + "SFAR[%016lx], going.\n", sfsr, sfar); die_if_kernel("Dax", regs); } @@ -177,6 +175,12 @@ void data_access_exception (struct pt_re force_sig_info(SIGSEGV, &info, current); } +void spitfire_data_access_exception_tl1(struct pt_regs *regs, unsigned long sfsr, unsigned long sfar) +{ + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); + spitfire_data_access_exception(regs, sfsr, sfar); +} + #ifdef CONFIG_PCI /* This is really pathetic... */ extern volatile int pci_poke_in_progress; @@ -210,37 +214,13 @@ static void spitfire_clean_and_reenable_ : "memory"); } -void do_iae(struct pt_regs *regs) +static void spitfire_enable_estate_errors(void) { - siginfo_t info; - - spitfire_clean_and_reenable_l1_caches(); - - info.si_signo = SIGBUS; - info.si_errno = 0; - info.si_code = BUS_OBJERR; - info.si_addr = (void *)0; - info.si_trapno = 0; - force_sig_info(SIGBUS, &info, current); -} - -void do_dae(struct pt_regs *regs) -{ -#ifdef CONFIG_PCI - if (pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { - spitfire_clean_and_reenable_l1_caches(); - - pci_poke_faulted = 1; - - /* Why the fuck did they have to change this? */ - if (tlb_type == cheetah || tlb_type == cheetah_plus) - regs->tpc += 4; - - regs->tnpc = regs->tpc + 4; - return; - } -#endif - do_iae(regs); + __asm__ __volatile__("stxa %0, [%%g0] %1\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (ESTATE_ERR_ALL), + "i" (ASI_ESTATE_ERROR_EN)); } static char ecc_syndrome_table[] = { @@ -278,65 +258,15 @@ static char ecc_syndrome_table[] = { 0x0b, 0x48, 0x48, 0x4b, 0x48, 0x4b, 0x4b, 0x4a }; -/* cee_trap in entry.S encodes AFSR/UDBH/UDBL error status - * in the following format. The AFAR is left as is, with - * reserved bits cleared, and is a raw 40-bit physical - * address. - */ -#define CE_STATUS_UDBH_UE (1UL << (43 + 9)) -#define CE_STATUS_UDBH_CE (1UL << (43 + 8)) -#define CE_STATUS_UDBH_ESYNDR (0xffUL << 43) -#define CE_STATUS_UDBH_SHIFT 43 -#define CE_STATUS_UDBL_UE (1UL << (33 + 9)) -#define CE_STATUS_UDBL_CE (1UL << (33 + 8)) -#define CE_STATUS_UDBL_ESYNDR (0xffUL << 33) -#define CE_STATUS_UDBL_SHIFT 33 -#define CE_STATUS_AFSR_MASK (0x1ffffffffUL) -#define CE_STATUS_AFSR_ME (1UL << 32) -#define CE_STATUS_AFSR_PRIV (1UL << 31) -#define CE_STATUS_AFSR_ISAP (1UL << 30) -#define CE_STATUS_AFSR_ETP (1UL << 29) -#define CE_STATUS_AFSR_IVUE (1UL << 28) -#define CE_STATUS_AFSR_TO (1UL << 27) -#define CE_STATUS_AFSR_BERR (1UL << 26) -#define CE_STATUS_AFSR_LDP (1UL << 25) -#define CE_STATUS_AFSR_CP (1UL << 24) -#define CE_STATUS_AFSR_WP (1UL << 23) -#define CE_STATUS_AFSR_EDP (1UL << 22) -#define CE_STATUS_AFSR_UE (1UL << 21) -#define CE_STATUS_AFSR_CE (1UL << 20) -#define CE_STATUS_AFSR_ETS (0xfUL << 16) -#define CE_STATUS_AFSR_ETS_SHIFT 16 -#define CE_STATUS_AFSR_PSYND (0xffffUL << 0) -#define CE_STATUS_AFSR_PSYND_SHIFT 0 - -/* Layout of Ecache TAG Parity Syndrome of AFSR */ -#define AFSR_ETSYNDROME_7_0 0x1UL /* E$-tag bus bits <7:0> */ -#define AFSR_ETSYNDROME_15_8 0x2UL /* E$-tag bus bits <15:8> */ -#define AFSR_ETSYNDROME_21_16 0x4UL /* E$-tag bus bits <21:16> */ -#define AFSR_ETSYNDROME_24_22 0x8UL /* E$-tag bus bits <24:22> */ - static char *syndrome_unknown = ""; -asmlinkage void cee_log(unsigned long ce_status, - unsigned long afar, - struct pt_regs *regs) -{ - char memmod_str[64]; - char *p; - unsigned short scode, udb_reg; +static void spitfire_log_udb_syndrome(unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long bit) +{ + unsigned short scode; + char memmod_str[64], *p; - printk(KERN_WARNING "CPU[%d]: Correctable ECC Error " - "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx]\n", - smp_processor_id(), - (ce_status & CE_STATUS_AFSR_MASK), - afar, - ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL), - ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL)); - - udb_reg = ((ce_status >> CE_STATUS_UDBL_SHIFT) & 0x3ffUL); - if (udb_reg & (1 << 8)) { - scode = ecc_syndrome_table[udb_reg & 0xff]; + if (udbl & bit) { + scode = ecc_syndrome_table[udbl & 0xff]; if (prom_getunumber(scode, afar, memmod_str, sizeof(memmod_str)) == -1) p = syndrome_unknown; @@ -347,9 +277,8 @@ asmlinkage void cee_log(unsigned long ce smp_processor_id(), scode, p); } - udb_reg = ((ce_status >> CE_STATUS_UDBH_SHIFT) & 0x3ffUL); - if (udb_reg & (1 << 8)) { - scode = ecc_syndrome_table[udb_reg & 0xff]; + if (udbh & bit) { + scode = ecc_syndrome_table[udbh & 0xff]; if (prom_getunumber(scode, afar, memmod_str, sizeof(memmod_str)) == -1) p = syndrome_unknown; @@ -359,6 +288,115 @@ asmlinkage void cee_log(unsigned long ce "Memory Module \"%s\"\n", smp_processor_id(), scode, p); } + +} + +static void spitfire_cee_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, int tl1, struct pt_regs *regs) +{ + + printk(KERN_WARNING "CPU[%d]: Correctable ECC Error " + "AFSR[%lx] AFAR[%016lx] UDBL[%lx] UDBH[%lx] TL>1[%d]\n", + smp_processor_id(), afsr, afar, udbl, udbh, tl1); + + spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_CE); + + /* The Correctable ECC Error trap does not disable I/D caches. So + * we only have to restore the ESTATE Error Enable register. + */ + spitfire_enable_estate_errors(); +} + +static void spitfire_ue_log(unsigned long afsr, unsigned long afar, unsigned long udbh, unsigned long udbl, unsigned long tt, int tl1, struct pt_regs *regs) +{ + siginfo_t info; + + printk(KERN_WARNING "CPU[%d]: Uncorrectable Error AFSR[%lx] " + "AFAR[%lx] UDBL[%lx] UDBH[%ld] TT[%lx] TL>1[%d]\n", + smp_processor_id(), afsr, afar, udbl, udbh, tt, tl1); + + /* XXX add more human friendly logging of the error status + * XXX as is implemented for cheetah + */ + + spitfire_log_udb_syndrome(afar, udbh, udbl, UDBE_UE); + + if (regs->tstate & TSTATE_PRIV) { + if (tl1) + dump_tl1_traplog((struct tl1_traplog *)(regs + 1)); + die_if_kernel("UE", regs); + } + + /* XXX need more intelligent processing here, such as is implemented + * XXX for cheetah errors, in fact if the E-cache still holds the + * XXX line with bad parity this will loop + */ + + spitfire_clean_and_reenable_l1_caches(); + spitfire_enable_estate_errors(); + + if (current->thread.flags & SPARC_FLAG_32BIT) { + regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } + info.si_signo = SIGBUS; + info.si_errno = 0; + info.si_code = BUS_OBJERR; + info.si_addr = (void *)0; + info.si_trapno = 0; + force_sig_info(SIGBUS, &info, current); +} + +void spitfire_access_error(struct pt_regs *regs, unsigned long status_encoded, unsigned long afar) +{ + unsigned long afsr, tt, udbh, udbl; + int tl1; + + afsr = (status_encoded & SFSTAT_AFSR_MASK) >> SFSTAT_AFSR_SHIFT; + tt = (status_encoded & SFSTAT_TRAP_TYPE) >> SFSTAT_TRAP_TYPE_SHIFT; + tl1 = (status_encoded & SFSTAT_TL_GT_ONE) ? 1 : 0; + udbl = (status_encoded & SFSTAT_UDBL_MASK) >> SFSTAT_UDBL_SHIFT; + udbh = (status_encoded & SFSTAT_UDBH_MASK) >> SFSTAT_UDBH_SHIFT; + +#ifdef CONFIG_PCI + if (tt == TRAP_TYPE_DAE && + pci_poke_in_progress && pci_poke_cpu == smp_processor_id()) { + spitfire_clean_and_reenable_l1_caches(); + spitfire_enable_estate_errors(); + + pci_poke_faulted = 1; + regs->tnpc = regs->tpc + 4; + return; + } +#endif + + if (afsr & SFAFSR_UE) + spitfire_ue_log(afsr, afar, udbh, udbl, tt, tl1, regs); + + if (tt == TRAP_TYPE_CEE) { + /* Handle the case where we took a CEE trap, but ACK'd + * only the UE state in the UDB error registers. + */ + if (afsr & SFAFSR_UE) { + if (udbh & UDBE_CE) { + __asm__ __volatile__( + "stxa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (udbh & UDBE_CE), + "r" (0x0), "i" (ASI_UDB_ERROR_W)); + } + if (udbl & UDBE_CE) { + __asm__ __volatile__( + "stxa %0, [%1] %2\n\t" + "membar #Sync" + : /* no outputs */ + : "r" (udbl & UDBE_CE), + "r" (0x18), "i" (ASI_UDB_ERROR_W)); + } + } + + spitfire_cee_log(afsr, afar, udbh, udbl, tl1, regs); + } } /* Cheetah error trap handling. */ diff -Nur -p linux-2.4.32/arch/sparc64/kernel/ttable.S linux-2.4.33-rc2/arch/sparc64/kernel/ttable.S --- linux-2.4.32/arch/sparc64/kernel/ttable.S 2002-11-28 21:53:12.000000000 -0200 +++ linux-2.4.33-rc2/arch/sparc64/kernel/ttable.S 2006-06-21 10:40:43.000000000 -0300 @@ -18,9 +18,10 @@ sparc64_ttable_tl0: tl0_resv000: BOOT_KERNEL BTRAP(0x1) BTRAP(0x2) BTRAP(0x3) tl0_resv004: BTRAP(0x4) BTRAP(0x5) BTRAP(0x6) BTRAP(0x7) tl0_iax: membar #Sync - TRAP_NOSAVE_7INSNS(__do_instruction_access_exception) + TRAP_NOSAVE_7INSNS(__spitfire_insn_access_exception) tl0_resv009: BTRAP(0x9) -tl0_iae: TRAP(do_iae) +tl0_iae: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_access_error) tl0_resv00b: BTRAP(0xb) BTRAP(0xc) BTRAP(0xd) BTRAP(0xe) BTRAP(0xf) tl0_ill: membar #Sync TRAP_7INSNS(do_illegal_instruction) @@ -36,9 +37,10 @@ tl0_cwin: CLEAN_WINDOW tl0_div0: TRAP(do_div0) tl0_resv029: BTRAP(0x29) BTRAP(0x2a) BTRAP(0x2b) BTRAP(0x2c) BTRAP(0x2d) BTRAP(0x2e) tl0_resv02f: BTRAP(0x2f) -tl0_dax: TRAP_NOSAVE(__do_data_access_exception) +tl0_dax: TRAP_NOSAVE(__spitfire_data_access_exception) tl0_resv031: BTRAP(0x31) -tl0_dae: TRAP(do_dae) +tl0_dae: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_access_error) tl0_resv033: BTRAP(0x33) tl0_mna: TRAP_NOSAVE(do_mna) tl0_lddfmna: TRAP_NOSAVE(do_lddfmna) @@ -73,7 +75,8 @@ tl0_resv05c: BTRAP(0x5c) BTRAP(0x5d) BTR tl0_ivec: TRAP_IVEC tl0_paw: TRAP(do_paw) tl0_vaw: TRAP(do_vaw) -tl0_cee: TRAP_NOSAVE(cee_trap) +tl0_cee: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_cee_trap) tl0_iamiss: #include "itlb_base.S" tl0_damiss: @@ -175,9 +178,10 @@ tl0_resv1f0: BTRAPS(0x1f0) BTRAPS(0x1f8) sparc64_ttable_tl1: tl1_resv000: BOOT_KERNEL BTRAPTL1(0x1) BTRAPTL1(0x2) BTRAPTL1(0x3) tl1_resv004: BTRAPTL1(0x4) BTRAPTL1(0x5) BTRAPTL1(0x6) BTRAPTL1(0x7) -tl1_iax: TRAP_NOSAVE(__do_instruction_access_exception_tl1) +tl1_iax: TRAP_NOSAVE(__spitfire_insn_access_exception_tl1) tl1_resv009: BTRAPTL1(0x9) -tl1_iae: TRAPTL1(do_iae_tl1) +tl1_iae: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_access_error) tl1_resv00b: BTRAPTL1(0xb) BTRAPTL1(0xc) BTRAPTL1(0xd) BTRAPTL1(0xe) BTRAPTL1(0xf) tl1_ill: TRAPTL1(do_ill_tl1) tl1_privop: BTRAPTL1(0x11) @@ -193,9 +197,10 @@ tl1_cwin: CLEAN_WINDOW tl1_div0: TRAPTL1(do_div0_tl1) tl1_resv029: BTRAPTL1(0x29) BTRAPTL1(0x2a) BTRAPTL1(0x2b) BTRAPTL1(0x2c) tl1_resv02d: BTRAPTL1(0x2d) BTRAPTL1(0x2e) BTRAPTL1(0x2f) -tl1_dax: TRAP_NOSAVE(__do_data_access_exception_tl1) +tl1_dax: TRAP_NOSAVE(__spitfire_data_access_exception_tl1) tl1_resv031: BTRAPTL1(0x31) -tl1_dae: TRAPTL1(do_dae_tl1) +tl1_dae: membar #Sync + TRAP_NOSAVE_7INSNS(__spitfire_access_error) tl1_resv033: BTRAPTL1(0x33) tl1_mna: TRAP_NOSAVE(do_mna) tl1_lddfmna: TRAPTL1(do_lddfmna_tl1) @@ -218,11 +223,12 @@ tl1_ivec: TRAP_IVEC tl1_paw: TRAPTL1(do_paw_tl1) tl1_vaw: TRAPTL1(do_vaw_tl1) - /* The grotty trick to save %g1 into current->thread.kernel_cntd0 - * is because when we take this trap we could be interrupting trap - * code already using the trap alternate global registers. It is - * better to corrupt a performance counter than corrupt trap register - * state. We cross our fingers and pray that this store/load does + /* The grotty trick to save %g1 into + * current->thread.kernel_cntd0 is because when we take this + * trap we could be interrupting trap code already using the + * trap alternate global registers. It is better to corrupt + * a performance counter than corrupt trap register state. + * We cross our fingers and pray that this store/load does * not cause yet another CEE trap. */ tl1_cee: membar #Sync diff -Nur -p linux-2.4.32/arch/sparc64/kernel/unaligned.c linux-2.4.33-rc2/arch/sparc64/kernel/unaligned.c --- linux-2.4.32/arch/sparc64/kernel/unaligned.c 2004-08-07 20:26:04.000000000 -0300 +++ linux-2.4.33-rc2/arch/sparc64/kernel/unaligned.c 2006-06-21 10:40:43.000000000 -0300 @@ -479,9 +479,9 @@ int handle_popc(u32 insn, struct pt_regs extern void do_fpother(struct pt_regs *regs); extern void do_privact(struct pt_regs *regs); -extern void data_access_exception(struct pt_regs *regs, - unsigned long sfsr, - unsigned long sfar); +extern void spitfire_data_access_exception(struct pt_regs *regs, + unsigned long sfsr, + unsigned long sfar); int handle_ldf_stq(u32 insn, struct pt_regs *regs) { @@ -524,14 +524,14 @@ int handle_ldf_stq(u32 insn, struct pt_r break; } default: - data_access_exception(regs, 0, addr); + spitfire_data_access_exception(regs, 0, addr); return 1; } if (put_user (first >> 32, (u32 *)addr) || __put_user ((u32)first, (u32 *)(addr + 4)) || __put_user (second >> 32, (u32 *)(addr + 8)) || __put_user ((u32)second, (u32 *)(addr + 12))) { - data_access_exception(regs, 0, addr); + spitfire_data_access_exception(regs, 0, addr); return 1; } } else { @@ -544,7 +544,7 @@ int handle_ldf_stq(u32 insn, struct pt_r do_privact(regs); return 1; } else if (asi > ASI_SNFL) { - data_access_exception(regs, 0, addr); + spitfire_data_access_exception(regs, 0, addr); return 1; } switch (insn & 0x180000) { @@ -561,7 +561,7 @@ int handle_ldf_stq(u32 insn, struct pt_r err |= __get_user (data[i], (u32 *)(addr + 4*i)); } if (err && !(asi & 0x2 /* NF */)) { - data_access_exception(regs, 0, addr); + spitfire_data_access_exception(regs, 0, addr); return 1; } if (asi & 0x8) /* Little */ { @@ -664,7 +664,7 @@ void handle_lddfmna(struct pt_regs *regs *(u64 *)(f->regs + freg) = value; current->thread.fpsaved[0] |= flag; } else { -daex: data_access_exception(regs, sfsr, sfar); +daex: spitfire_data_access_exception(regs, sfsr, sfar); return; } advance(regs); @@ -708,7 +708,7 @@ void handle_stdfmna(struct pt_regs *regs __put_user ((u32)value, (u32 *)(sfar + 4))) goto daex; } else { -daex: data_access_exception(regs, sfsr, sfar); +daex: spitfire_data_access_exception(regs, sfsr, sfar); return; } advance(regs); diff -Nur -p linux-2.4.32/arch/sparc64/kernel/winfixup.S linux-2.4.33-rc2/arch/sparc64/kernel/winfixup.S --- linux-2.4.32/arch/sparc64/kernel/winfixup.S 2003-06-13 11:51:32.000000000 -0300 +++ linux-2.4.33-rc2/arch/sparc64/kernel/winfixup.S 2006-06-21 10:40:43.000000000 -0300 @@ -296,7 +296,7 @@ fill_fixup_dax: flush %g6 ! Flush instruction buffers rdpr %pstate, %l1 ! Prepare to change globals. mov %g4, %o1 ! Setup args for - mov %g5, %o2 ! final call to data_access_exception. + mov %g5, %o2 ! final call to spitfire_data_access_exception. andn %l1, PSTATE_MM, %l1 ! We want to be in RMO mov %g6, %o7 ! Stash away current. @@ -305,7 +305,7 @@ fill_fixup_dax: sethi %uhi(PAGE_OFFSET), %g4 ! Set page_offset global reg. mov %o7, %g6 ! Get current back. sllx %g4, 32, %g4 ! Finish it. - call data_access_exception + call spitfire_data_access_exception add %sp, PTREGS_OFF, %o0 b,pt %xcc, rtrap @@ -366,7 +366,7 @@ window_dax_from_user_common: 109: or %g7, %lo(109b), %g7 mov %l4, %o1 mov %l5, %o2 - call data_access_exception + call spitfire_data_access_exception add %sp, PTREGS_OFF, %o0 ba,pt %xcc, rtrap clr %l6 diff -Nur -p linux-2.4.32/arch/sparc64/lib/debuglocks.c linux-2.4.33-rc2/arch/sparc64/lib/debuglocks.c --- linux-2.4.32/arch/sparc64/lib/debuglocks.c 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/arch/sparc64/lib/debuglocks.c 2006-06-21 10:40:43.000000000 -0300 @@ -61,7 +61,7 @@ again: : "=r" (val) : "r" (&(lock->lock)) : "memory"); - membar("#StoreLoad | #StoreStore"); + membar_safe("#StoreLoad | #StoreStore"); if (val) { while (lock->lock) { if (!--stuck) { @@ -69,7 +69,7 @@ again: show(str, lock, caller); stuck = INIT_STUCK; } - membar("#LoadLoad"); + rmb(); } goto again; } @@ -89,7 +89,7 @@ int _spin_trylock(spinlock_t *lock) : "=r" (val) : "r" (&(lock->lock)) : "memory"); - membar("#StoreLoad | #StoreStore"); + membar_safe("#StoreLoad | #StoreStore"); if (!val) { lock->owner_pc = ((unsigned int)caller); lock->owner_cpu = cpu; @@ -103,7 +103,7 @@ void _do_spin_unlock(spinlock_t *lock) { lock->owner_pc = 0; lock->owner_cpu = NO_PROC_ID; - membar("#StoreStore | #LoadStore"); + membar_safe("#StoreStore | #LoadStore"); lock->lock = 0; current->thread.smp_lock_count--; } @@ -126,7 +126,7 @@ wlock_again: show_read(str, rw, caller); stuck = INIT_STUCK; } - membar("#LoadLoad"); + rmb(); } /* Try once to increment the counter. */ __asm__ __volatile__( @@ -139,7 +139,7 @@ wlock_again: "2:" : "=r" (val) : "0" (&(rw->lock)) : "g5", "g7", "memory"); - membar("#StoreLoad | #StoreStore"); + membar_safe("#StoreLoad | #StoreStore"); if (val) goto wlock_again; rw->reader_pc[cpu] = ((unsigned int)caller); @@ -197,7 +197,7 @@ wlock_again: show_write(str, rw, caller); stuck = INIT_STUCK; } - membar("#LoadLoad"); + rmb(); } /* Try to acuire the write bit. */ @@ -251,7 +251,7 @@ wlock_again: show_write(str, rw, caller); stuck = INIT_STUCK; } - membar("#LoadLoad"); + rmb(); } goto wlock_again; } diff -Nur -p linux-2.4.32/arch/x86_64/ia32/socket32.c linux-2.4.33-rc2/arch/x86_64/ia32/socket32.c --- linux-2.4.32/arch/x86_64/ia32/socket32.c 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/arch/x86_64/ia32/socket32.c 2006-06-21 10:40:43.000000000 -0300 @@ -127,12 +127,13 @@ static int cmsghdr_from_user32_to_kern(s struct cmsghdr *kcmsg, *kcmsg_base; __kernel_size_t32 ucmlen; __kernel_size_t kcmlen, tmp; + int err = -EFAULT; kcmlen = 0; kcmsg_base = kcmsg = (struct cmsghdr *)stackbuf; ucmsg = CMSG32_FIRSTHDR(kmsg); while(ucmsg != NULL) { - if(get_user(ucmlen, &ucmsg->cmsg_len)) + if (get_user(ucmlen, &ucmsg->cmsg_len)) return -EFAULT; /* Catch bogons. */ @@ -164,18 +165,19 @@ static int cmsghdr_from_user32_to_kern(s memset(kcmsg, 0, kcmlen); ucmsg = CMSG32_FIRSTHDR(kmsg); while(ucmsg != NULL) { - __get_user(ucmlen, &ucmsg->cmsg_len); + if (__get_user(ucmlen, &ucmsg->cmsg_len)) + goto Efault; tmp = ((ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))) + CMSG_ALIGN(sizeof(struct cmsghdr))); + if ((char *)kcmsg_base + kcmlen - (char *)kcmsg < CMSG_ALIGN(tmp)) + goto Einval; kcmsg->cmsg_len = tmp; - __get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level); - __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type); - - /* Copy over the data. */ - if(copy_from_user(CMSG_DATA(kcmsg), - CMSG32_DATA(ucmsg), - (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) - goto out_free_efault; + if (__get_user(kcmsg->cmsg_level, &ucmsg->cmsg_level) || + __get_user(kcmsg->cmsg_type, &ucmsg->cmsg_type) || + copy_from_user(CMSG_DATA(kcmsg), + CMSG32_DATA(ucmsg), + (ucmlen - CMSG32_ALIGN(sizeof(*ucmsg))))) + goto Efault; /* Advance. */ kcmsg = (struct cmsghdr *)((char *)kcmsg + CMSG_ALIGN(tmp)); @@ -187,10 +189,12 @@ static int cmsghdr_from_user32_to_kern(s kmsg->msg_controllen = kcmlen; return 0; -out_free_efault: - if(kcmsg_base != (struct cmsghdr *)stackbuf) +Einval: + err = -EINVAL; +Efault: + if (kcmsg_base != (struct cmsghdr *)stackbuf) kfree(kcmsg_base); - return -EFAULT; + return err; } static void put_cmsg32(struct msghdr *kmsg, int level, int type, diff -Nur -p linux-2.4.32/arch/x86_64/kernel/process.c linux-2.4.33-rc2/arch/x86_64/kernel/process.c --- linux-2.4.32/arch/x86_64/kernel/process.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/arch/x86_64/kernel/process.c 2006-06-21 10:40:43.000000000 -0300 @@ -564,8 +564,6 @@ struct task_struct *__switch_to(struct t *next = &next_p->thread; struct tss_struct *tss = init_tss + smp_processor_id(); - unlazy_fpu(prev_p); - /* * Reload rsp0, LDT and the page table pointer: */ @@ -583,6 +581,11 @@ struct task_struct *__switch_to(struct t loadsegment(ds, next->ds); /* + * Must be after DS reload for AMD workaround. + */ + unlazy_fpu(prev_p); + + /* * Switch FS and GS. */ { diff -Nur -p linux-2.4.32/arch/x86_64/kernel/signal.c linux-2.4.33-rc2/arch/x86_64/kernel/signal.c --- linux-2.4.32/arch/x86_64/kernel/signal.c 2005-01-19 12:09:40.000000000 -0200 +++ linux-2.4.33-rc2/arch/x86_64/kernel/signal.c 2006-06-21 10:40:43.000000000 -0300 @@ -137,15 +137,16 @@ restore_sigcontext(struct pt_regs *regs, #define COPY(x) err |= __get_user(regs->x, &sc->x) -#define COPY_CANON(x) \ - COPY(x); \ - if ((regs->x >> 48) != 0 && (regs->x >> 48) != 0xffff) \ - regs->x = 0; /* fs and gs are ignored because we cannot handle the 64bit base easily */ - COPY(rdi); COPY(rsi); COPY(rbp); COPY_CANON(rsp); COPY(rbx); - COPY(rdx); COPY(rcx); COPY_CANON(rip); + COPY(rdi); COPY(rsi); COPY(rbp); COPY(rsp); COPY(rbx); + COPY(rdx); COPY(rcx); + COPY(rip); + if (regs->rip >= TASK_SIZE && regs->rip < VSYSCALL_START) { + regs->rip = 0; + return -EFAULT; + } COPY(r8); COPY(r9); COPY(r10); @@ -357,6 +358,11 @@ static void setup_rt_frame(int sig, stru regs->rdx = (unsigned long)&frame->uc; regs->rsp = (unsigned long) frame; regs->rip = (unsigned long) ka->sa.sa_handler; + if (regs->rip >= TASK_SIZE) { + if (sig == SIGSEGV) + ka->sa.sa_handler = SIG_DFL; + regs->rip = 0; + } regs->cs = __USER_CS; regs->ss = __USER_DS; diff -Nur -p linux-2.4.32/CREDITS linux-2.4.33-rc2/CREDITS --- linux-2.4.32/CREDITS 2005-01-19 12:09:22.000000000 -0200 +++ linux-2.4.33-rc2/CREDITS 2006-06-21 10:40:43.000000000 -0300 @@ -2996,7 +2996,7 @@ S: Santa Clara, California 95051 S: USA N: Marcelo W. Tosatti -E: marcelo.tosatti@cyclades.com +E: marcelo@kvack.org D: Miscellaneous kernel hacker (mostly VM/MM work) D: 2.4 maintainer S: Av Cristovao Colombo, 462. Floresta. diff -Nur -p linux-2.4.32/Documentation/Changes linux-2.4.33-rc2/Documentation/Changes --- linux-2.4.32/Documentation/Changes 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/Documentation/Changes 2006-06-21 10:40:43.000000000 -0300 @@ -91,6 +91,8 @@ The Red Hat gcc 2.96 compiler subtree ca You should ensure you use gcc-2.96-74 or later. gcc-2.96-54 will not build the kernel correctly. +gcc 4 is not supported. + In addition, please pay attention to compiler optimization. Anything greater than -O2 may not be wise. Similarly, if you choose to use gcc-2.95.x or derivatives, be sure not to use -fstrict-aliasing (which, depending on diff -Nur -p linux-2.4.32/Documentation/Configure.help linux-2.4.33-rc2/Documentation/Configure.help --- linux-2.4.32/Documentation/Configure.help 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/Documentation/Configure.help 2006-06-21 10:40:43.000000000 -0300 @@ -8148,7 +8148,7 @@ CONFIG_AIC7XXX_DEBUG_ENABLE Debug code enable mask (2048 for all debugging) CONFIG_AIC7XXX_DEBUG_MASK Bit mask of debug options that is only valid if the - CONFIG_AIC7XXX_DEBUG_ENBLE option is enabled. The bits in this mask + CONFIG_AIC7XXX_DEBUG_ENABLE option is enabled. The bits in this mask are defined in the drivers/scsi/aic7xxx/aic7xxx.h - search for the variable ahc_debug in that file to find them. @@ -8322,7 +8322,7 @@ CONFIG_AIC79XX_DEBUG_ENABLE CONFIG_AIC79XX_DEBUG_MASK Bit mask of debug options that is only valid if the - CONFIG_AIC79XX_DEBUG_ENBLE option is enabled. The bits in this mask + CONFIG_AIC79XX_DEBUG_ENABLE option is enabled. The bits in this mask are defined in the drivers/scsi/aic7xxx/aic79xx.h - search for the variable ahd_debug in that file to find them. @@ -15240,6 +15240,24 @@ CONFIG_INPUT_JOYDEV The module will be called joydev.o. If you want to compile it as a module, say M here and read . +Dummy keyboard driver +CONFIG_DUMMY_KEYB + What is this for? + + Not all systems have keyboards. Some don't even have a keyboard + port. However, some of those systems have video support and can + use the virtual terminal support for display. However, the virtual + terminal code expects a keyboard of some kind. This driver keeps + the virtual terminal code happy by providing it a "keyboard", albeit + a very quiet one. + + If you want to use the virtual terminal support but your system + does not support a keyboard, define CONFIG_DUMMY_KEYB along with + CONFIG_VT. + + This can also be selected lonesome without any VT support (i.e. no + monitor or keyboard attached) - just define CONFIG_DUMMY_KEYB. + Event interface support CONFIG_INPUT_EVDEV Say Y here if you want your USB or ADB HID device events be diff -Nur -p linux-2.4.32/drivers/acpi/system.c linux-2.4.33-rc2/drivers/acpi/system.c --- linux-2.4.32/drivers/acpi/system.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/drivers/acpi/system.c 2006-06-21 10:40:43.000000000 -0300 @@ -748,7 +748,7 @@ acpi_system_write_sleep ( state = simple_strtoul(state_string, NULL, 0); - if (!system->states[state]) + if (state >= ACPI_S_STATE_COUNT || !system->states[state]) return_VALUE(-ENODEV); /* diff -Nur -p linux-2.4.32/drivers/block/ll_rw_blk.c linux-2.4.33-rc2/drivers/block/ll_rw_blk.c --- linux-2.4.32/drivers/block/ll_rw_blk.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/drivers/block/ll_rw_blk.c 2006-06-21 10:40:43.000000000 -0300 @@ -285,21 +285,6 @@ void blk_queue_make_request(request_queu void blk_queue_bounce_limit(request_queue_t *q, u64 dma_addr) { unsigned long bounce_pfn = dma_addr >> PAGE_SHIFT; - unsigned long mb = dma_addr >> 20; - static request_queue_t *old_q; - - /* - * keep this for debugging for now... - */ - if (dma_addr != BLK_BOUNCE_HIGH && q != old_q) { - old_q = q; - printk("blk: queue %p, ", q); - if (dma_addr == BLK_BOUNCE_ANY) - printk("no I/O memory limit\n"); - else - printk("I/O limit %luMb (mask 0x%Lx)\n", mb, - (long long) dma_addr); - } q->bounce_pfn = bounce_pfn; } diff -Nur -p linux-2.4.32/drivers/char/drm/drm_stub.h linux-2.4.33-rc2/drivers/char/drm/drm_stub.h --- linux-2.4.32/drivers/char/drm/drm_stub.h 2003-11-28 16:26:20.000000000 -0200 +++ linux-2.4.33-rc2/drivers/char/drm/drm_stub.h 2006-06-21 10:40:43.000000000 -0300 @@ -52,6 +52,7 @@ static int DRM(stub_open)(struct inode * int err = -ENODEV; struct file_operations *old_fops; + if (minor < 0 || minor >=DRM_STUB_MAXCARDS) return -ENODEV; if (!DRM(stub_list) || !DRM(stub_list)[minor].fops) return -ENODEV; old_fops = filp->f_op; filp->f_op = fops_get(DRM(stub_list)[minor].fops); diff -Nur -p linux-2.4.32/drivers/char/drm/radeon_mem.c linux-2.4.33-rc2/drivers/char/drm/radeon_mem.c --- linux-2.4.32/drivers/char/drm/radeon_mem.c 2003-11-28 16:26:20.000000000 -0200 +++ linux-2.4.33-rc2/drivers/char/drm/radeon_mem.c 2006-06-21 10:40:43.000000000 -0300 @@ -131,6 +131,7 @@ static void free_block( struct mem_block } } +#if 0 static void print_heap( struct mem_block *heap ) { struct mem_block *p; @@ -140,6 +141,7 @@ static void print_heap( struct mem_block p->start, p->start + p->size, p->size, p->pid); } +#endif /* Initialize. How to check for an uninitialized heap? */ diff -Nur -p linux-2.4.32/drivers/char/dummy_keyb.c linux-2.4.33-rc2/drivers/char/dummy_keyb.c --- linux-2.4.32/drivers/char/dummy_keyb.c 2003-08-25 08:44:41.000000000 -0300 +++ linux-2.4.33-rc2/drivers/char/dummy_keyb.c 2006-06-21 10:40:43.000000000 -0300 @@ -29,6 +29,7 @@ #include #include #include +#include void kbd_leds(unsigned char leds) { diff -Nur -p linux-2.4.32/drivers/i2c/scx200_acb.c linux-2.4.33-rc2/drivers/i2c/scx200_acb.c --- linux-2.4.32/drivers/i2c/scx200_acb.c 2003-06-13 11:51:33.000000000 -0300 +++ linux-2.4.33-rc2/drivers/i2c/scx200_acb.c 2006-06-21 10:40:43.000000000 -0300 @@ -467,7 +467,6 @@ static int __init scx200_acb_create(int struct scx200_acb_iface *iface; struct i2c_adapter *adapter; int rc = 0; - char description[64]; iface = kmalloc(sizeof(*iface), GFP_KERNEL); if (!iface) { @@ -489,8 +488,7 @@ static int __init scx200_acb_create(int init_MUTEX(&iface->sem); - sprintf(description, "NatSemi SCx200 ACCESS.bus [%s]", adapter->name); - if (request_region(base, 8, description) == 0) { + if (request_region(base, 8, adapter->name) == 0) { printk(KERN_ERR NAME ": %s, can't allocate io 0x%x-0x%x\n", adapter->name, base, base + 8-1); rc = -EBUSY; diff -Nur -p linux-2.4.32/drivers/ide/ide-dma.c linux-2.4.33-rc2/drivers/ide/ide-dma.c --- linux-2.4.32/drivers/ide/ide-dma.c 2003-08-25 08:44:41.000000000 -0300 +++ linux-2.4.33-rc2/drivers/ide/ide-dma.c 2006-06-21 10:40:43.000000000 -0300 @@ -137,6 +137,7 @@ struct drive_list_entry drive_blacklist { "CD-ROM Drive/F5A", "ALL" }, { "RICOH CD-R/RW MP7083A", "ALL" }, { "WPI CDD-820", "ALL" }, + { "SAMSUNG CD-ROM SC-140", "ALL" }, { "SAMSUNG CD-ROM SC-148C", "ALL" }, { "SAMSUNG CD-ROM SC-148F", "ALL" }, { "SAMSUNG CD-ROM SC", "ALL" }, @@ -566,6 +567,18 @@ static int dma_timer_expiry (ide_drive_t } /** + * __ide_dma_no_op - dummy DMA function. + * + * This empty function prevents non-DMA controllers from causing an oops. + */ + +static int __ide_dma_no_op (ide_drive_t *ignored) +{ + return 0; +} + + +/** * __ide_dma_host_off - Generic DMA kill * @drive: drive to control * @@ -1214,3 +1227,20 @@ void ide_setup_dma (ide_hwif_t *hwif, un } EXPORT_SYMBOL_GPL(ide_setup_dma); + +/* + * For IDE interfaces that do not support DMA, we still need to + * initialize some pointers to dummy functions. + */ +void ide_setup_no_dma (ide_hwif_t *hwif) +{ + if (!hwif->ide_dma_off_quietly) + hwif->ide_dma_off_quietly = &__ide_dma_no_op; + if (!hwif->ide_dma_host_off) + hwif->ide_dma_host_off = &__ide_dma_no_op; + if (!hwif->ide_dma_host_on) + hwif->ide_dma_host_on = &__ide_dma_no_op; +} + +EXPORT_SYMBOL_GPL(ide_setup_no_dma); + diff -Nur -p linux-2.4.32/drivers/ide/ide-io.c linux-2.4.33-rc2/drivers/ide/ide-io.c --- linux-2.4.32/drivers/ide/ide-io.c 2003-11-28 16:26:20.000000000 -0200 +++ linux-2.4.33-rc2/drivers/ide/ide-io.c 2006-06-21 10:40:43.000000000 -0300 @@ -899,11 +899,13 @@ static ide_startstop_t ide_dma_timeout_r rq = HWGROUP(drive)->rq; HWGROUP(drive)->rq = NULL; - rq->errors = 0; - rq->sector = rq->bh->b_rsector; - rq->current_nr_sectors = rq->bh->b_size >> 9; - rq->hard_cur_sectors = rq->current_nr_sectors; - rq->buffer = rq->bh->b_data; + if (rq) { + rq->errors = 0; + rq->sector = rq->bh->b_rsector; + rq->current_nr_sectors = rq->bh->b_size >> 9; + rq->hard_cur_sectors = rq->current_nr_sectors; + rq->buffer = rq->bh->b_data; + } return ret; } diff -Nur -p linux-2.4.32/drivers/ide/pci/atiixp.c linux-2.4.33-rc2/drivers/ide/pci/atiixp.c --- linux-2.4.32/drivers/ide/pci/atiixp.c 2004-04-14 10:05:29.000000000 -0300 +++ linux-2.4.33-rc2/drivers/ide/pci/atiixp.c 2006-06-21 10:40:43.000000000 -0300 @@ -467,15 +467,35 @@ static void __devinit init_hwif_atiixp(i static ide_pci_device_t atiixp_pci_info[] __devinitdata = { { /* 0 */ .vendor = PCI_VENDOR_ID_ATI, - .device = PCI_DEVICE_ID_ATI_IXP_IDE, - .name = "ATIIXP", + .device = PCI_DEVICE_ID_ATI_IXP200_IDE, + .name = "ATI-IXP200", .init_chipset = init_chipset_atiixp, .init_hwif = init_hwif_atiixp, .channels = 2, .autodma = AUTODMA, .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}}, .bootable = ON_BOARD, - } + },{ /* 1 */ + .vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_IXP300_IDE, + .name = "ATI-IXP300", + .init_chipset = init_chipset_atiixp, + .init_hwif = init_hwif_atiixp, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}}, + .bootable = ON_BOARD, + },{ /* 2 */ + .vendor = PCI_VENDOR_ID_ATI, + .device = PCI_DEVICE_ID_ATI_IXP400_IDE, + .name = "ATI-IXP400", + .init_chipset = init_chipset_atiixp, + .init_hwif = init_hwif_atiixp, + .channels = 2, + .autodma = AUTODMA, + .enablebits = {{0x48,0x01,0x00}, {0x48,0x08,0x00}}, + .bootable = ON_BOARD, + } }; /** @@ -498,7 +518,9 @@ static int __devinit atiixp_init_one(str } static struct pci_device_id atiixp_pci_tbl[] = { - { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP200_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP300_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 1}, + { PCI_VENDOR_ID_ATI, PCI_DEVICE_ID_ATI_IXP400_IDE, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 2}, { 0, }, }; diff -Nur -p linux-2.4.32/drivers/ide/setup-pci.c linux-2.4.33-rc2/drivers/ide/setup-pci.c --- linux-2.4.32/drivers/ide/setup-pci.c 2003-08-25 08:44:41.000000000 -0300 +++ linux-2.4.33-rc2/drivers/ide/setup-pci.c 2006-06-21 10:40:43.000000000 -0300 @@ -507,6 +507,7 @@ static void ide_hwif_setup_dma(struct pc } else { printk(KERN_INFO "%s: %s Bus-Master DMA disabled " "(BIOS)\n", hwif->name, d->name); + ide_setup_no_dma(hwif); } } } diff -Nur -p linux-2.4.32/drivers/input/Config.in linux-2.4.33-rc2/drivers/input/Config.in --- linux-2.4.32/drivers/input/Config.in 2004-02-18 10:36:31.000000000 -0300 +++ linux-2.4.33-rc2/drivers/input/Config.in 2006-06-21 10:40:43.000000000 -0300 @@ -7,6 +7,11 @@ comment 'Input core support' tristate 'Input core support' CONFIG_INPUT dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT + +if [ "$CONFIG_INPUT_KEYBDEV" = "n" ]; then + bool ' Use dummy keyboard driver' CONFIG_DUMMY_KEYB $CONFIG_INPUT +fi + dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024 diff -Nur -p linux-2.4.32/drivers/mtd/chips/amd_flash.c linux-2.4.33-rc2/drivers/mtd/chips/amd_flash.c --- linux-2.4.32/drivers/mtd/chips/amd_flash.c 2003-06-13 11:51:34.000000000 -0300 +++ linux-2.4.33-rc2/drivers/mtd/chips/amd_flash.c 2006-06-21 10:40:43.000000000 -0300 @@ -1350,6 +1350,7 @@ static void amd_flash_sync(struct mtd_in default: /* Not an idle state */ + set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock_bh(chip->mutex); diff -Nur -p linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0001.c linux-2.4.33-rc2/drivers/mtd/chips/cfi_cmdset_0001.c --- linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0001.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/drivers/mtd/chips/cfi_cmdset_0001.c 2006-06-21 10:40:43.000000000 -0300 @@ -1687,6 +1687,7 @@ static void cfi_intelext_sync (struct mt default: /* Not an idle state */ + set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock(chip->mutex); diff -Nur -p linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0002.c linux-2.4.33-rc2/drivers/mtd/chips/cfi_cmdset_0002.c --- linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0002.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/drivers/mtd/chips/cfi_cmdset_0002.c 2006-06-21 10:40:43.000000000 -0300 @@ -1172,6 +1172,7 @@ static void cfi_amdstd_sync (struct mtd_ default: /* Not an idle state */ + set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); cfi_spin_unlock(chip->mutex); diff -Nur -p linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0020.c linux-2.4.33-rc2/drivers/mtd/chips/cfi_cmdset_0020.c --- linux-2.4.32/drivers/mtd/chips/cfi_cmdset_0020.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/drivers/mtd/chips/cfi_cmdset_0020.c 2006-06-21 10:40:43.000000000 -0300 @@ -1036,6 +1036,7 @@ static void cfi_staa_sync (struct mtd_in default: /* Not an idle state */ + set_current_state(TASK_UNINTERRUPTIBLE); add_wait_queue(&chip->wq, &wait); spin_unlock_bh(chip->mutex); diff -Nur -p linux-2.4.32/drivers/net/3c59x.c linux-2.4.33-rc2/drivers/net/3c59x.c --- linux-2.4.32/drivers/net/3c59x.c 2005-01-19 12:09:56.000000000 -0200 +++ linux-2.4.33-rc2/drivers/net/3c59x.c 2006-06-21 10:40:43.000000000 -0300 @@ -413,7 +413,7 @@ enum { IS_VORTEX=1, IS_BOOMERANG=2, IS_C HAS_PWR_CTRL=0x20, HAS_MII=0x40, HAS_NWAY=0x80, HAS_CB_FNS=0x100, INVERT_MII_PWR=0x200, INVERT_LED_PWR=0x400, MAX_COLLISION_RESET=0x800, EEPROM_OFFSET=0x1000, HAS_HWCKSM=0x2000, WNO_XCVR_PWR=0x4000, - EXTRA_PREAMBLE=0x8000, }; + EXTRA_PREAMBLE=0x8000, EEPROM_RESET=0x10000, }; enum vortex_chips { CH_3C590 = 0, @@ -489,9 +489,9 @@ static struct vortex_chip_info { {"3c595 Vortex 100base-MII", PCI_USES_IO|PCI_USES_MASTER, IS_VORTEX, 32, }, {"3c900 Boomerang 10baseT", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, {"3c900 Boomerang 10Mbps Combo", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|EEPROM_RESET, 64, }, {"3c900 Cyclone 10Mbps TPO", /* AKPM: from Don's 0.99M */ PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c900 Cyclone 10Mbps Combo", @@ -502,9 +502,9 @@ static struct vortex_chip_info { {"3c900B-FL Cyclone 10base-FL", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_HWCKSM, 128, }, {"3c905 Boomerang 100baseTx", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, {"3c905 Boomerang 100baseT4", - PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII, 64, }, + PCI_USES_IO|PCI_USES_MASTER, IS_BOOMERANG|HAS_MII|EEPROM_RESET, 64, }, {"3c905B Cyclone 100baseTx", PCI_USES_IO|PCI_USES_MASTER, IS_CYCLONE|HAS_NWAY|HAS_HWCKSM|EXTRA_PREAMBLE, 128, }, @@ -3094,7 +3094,8 @@ static void __devexit vortex_remove_one pci_restore_state(VORTEX_PCI(vp), vp->power_state); } /* Should really use issue_and_wait() here */ - outw(TotalReset|0x14, dev->base_addr + EL3_CMD); + outw(TotalReset | ((vp->drv_flags & EEPROM_RESET) ? 0x04 : 0x14), + dev->base_addr + EL3_CMD); pci_free_consistent(pdev, sizeof(struct boom_rx_desc) * RX_RING_SIZE diff -Nur -p linux-2.4.32/drivers/net/au1000_eth.c linux-2.4.33-rc2/drivers/net/au1000_eth.c --- linux-2.4.32/drivers/net/au1000_eth.c 2005-01-19 12:09:56.000000000 -0200 +++ linux-2.4.33-rc2/drivers/net/au1000_eth.c 2006-06-21 10:40:43.000000000 -0300 @@ -83,8 +83,6 @@ static void au1000_tx_timeout(struct net static int au1000_set_config(struct net_device *dev, struct ifmap *map); static void set_rx_mode(struct net_device *); static struct net_device_stats *au1000_get_stats(struct net_device *); -static inline void update_tx_stats(struct net_device *, u32, u32); -static inline void update_rx_stats(struct net_device *, u32); static void au1000_timer(unsigned long); static int au1000_ioctl(struct net_device *, struct ifreq *, int); static int mdio_read(struct net_device *, int, int); @@ -1540,16 +1538,11 @@ static void __exit au1000_cleanup_module } } - -static inline void -update_tx_stats(struct net_device *dev, u32 status, u32 pkt_len) +static void update_tx_stats(struct net_device *dev, u32 status) { struct au1000_private *aup = (struct au1000_private *) dev->priv; struct net_device_stats *ps = &aup->stats; - ps->tx_packets++; - ps->tx_bytes += pkt_len; - if (status & TX_FRAME_ABORTED) { if (dev->if_port == IF_PORT_100BASEFX) { if (status & (TX_JAB_TIMEOUT | TX_UNDERRUN)) { @@ -1582,7 +1575,7 @@ static void au1000_tx_ack(struct net_dev ptxd = aup->tx_dma_ring[aup->tx_tail]; while (ptxd->buff_stat & TX_T_DONE) { - update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff); + update_tx_stats(dev, ptxd->status); ptxd->buff_stat &= ~TX_T_DONE; ptxd->len = 0; au_sync(); @@ -1604,6 +1597,7 @@ static void au1000_tx_ack(struct net_dev static int au1000_tx(struct sk_buff *skb, struct net_device *dev) { struct au1000_private *aup = (struct au1000_private *) dev->priv; + struct net_device_stats *ps = &aup->stats; volatile tx_dma_t *ptxd; u32 buff_stat; db_dest_t *pDB; @@ -1623,7 +1617,7 @@ static int au1000_tx(struct sk_buff *skb return 1; } else if (buff_stat & TX_T_DONE) { - update_tx_stats(dev, ptxd->status, ptxd->len & 0x3ff); + update_tx_stats(dev, ptxd->status); ptxd->len = 0; } @@ -1643,6 +1637,9 @@ static int au1000_tx(struct sk_buff *skb else ptxd->len = skb->len; + ps->tx_packets++; + ps->tx_bytes += ptxd->len; + ptxd->buff_stat = pDB->dma_addr | TX_DMA_ENABLE; au_sync(); dev_kfree_skb(skb); @@ -1651,7 +1648,6 @@ static int au1000_tx(struct sk_buff *skb return 0; } - static inline void update_rx_stats(struct net_device *dev, u32 status) { struct au1000_private *aup = (struct au1000_private *) dev->priv; diff -Nur -p linux-2.4.32/drivers/net/b44.c linux-2.4.33-rc2/drivers/net/b44.c --- linux-2.4.32/drivers/net/b44.c 2004-08-07 20:26:05.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/b44.c 2006-06-21 10:40:43.000000000 -0300 @@ -1183,8 +1183,9 @@ static void b44_init_hw(struct b44 *bp) b44_chip_reset(bp); b44_phy_reset(bp); b44_setup_phy(bp); - val = br32(B44_MAC_CTRL); - bw32(B44_MAC_CTRL, val | MAC_CTRL_CRC32_ENAB); + + /* Enable CRC32, set proper LED modes and power on PHY */ + bw32(B44_MAC_CTRL, MAC_CTRL_CRC32_ENAB | MAC_CTRL_PHY_LEDCTRL); bw32(B44_RCV_LAZY, (1 << RCV_LAZY_FC_SHIFT)); /* This sets the MAC address too. */ @@ -1319,12 +1320,15 @@ static struct net_device_stats *b44_get_ hwstat->rx_symbol_errs); nstat->tx_aborted_errors = hwstat->tx_underruns; +#if 0 + /* Carrier lost counter seems to be broken for some devices */ nstat->tx_carrier_errors = hwstat->tx_carrier_lost; +#endif return nstat; } -static void __b44_load_mcast(struct b44 *bp, struct net_device *dev) +static int __b44_load_mcast(struct b44 *bp, struct net_device *dev) { struct dev_mc_list *mclist; int i, num_ents; @@ -1334,12 +1338,15 @@ static void __b44_load_mcast(struct b44 for (i = 0; mclist && i < num_ents; i++, mclist = mclist->next) { __b44_cam_write(bp, mclist->dmi_addr, i + 1); } + return i+1; } static void __b44_set_rx_mode(struct net_device *dev) { struct b44 *bp = dev->priv; u32 val; + int i=0; + unsigned char zero[6] = {0,0,0,0,0,0}; val = br32(B44_RXCONFIG); val &= ~(RXCONFIG_PROMISC | RXCONFIG_ALLMULTI); @@ -1352,8 +1359,11 @@ static void __b44_set_rx_mode(struct net if (dev->flags & IFF_ALLMULTI) val |= RXCONFIG_ALLMULTI; else - __b44_load_mcast(bp, dev); - + i=__b44_load_mcast(bp, dev); + + for(;i<64;i++) { + __b44_cam_write(bp, zero, i); + } bw32(B44_RXCONFIG, val); val = br32(B44_CAM_CTRL); bw32(B44_CAM_CTRL, val | CAM_CTRL_ENABLE); diff -Nur -p linux-2.4.32/drivers/net/bonding/bond_alb.c linux-2.4.33-rc2/drivers/net/bonding/bond_alb.c --- linux-2.4.32/drivers/net/bonding/bond_alb.c 2004-04-14 10:05:30.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/bonding/bond_alb.c 2006-06-21 10:40:43.000000000 -0300 @@ -37,6 +37,9 @@ * * 2004/01/14 - Shmulik Hen * - Add capability to tag self generated packets in ALB/TLB modes. + * + * 2005/12/02 - Michael O'Donnell + * - Stratus88746: tlb_clear_slave() must tlb_init_slave() while locked. */ //#define BONDING_DEBUG 1 @@ -187,9 +190,9 @@ static void tlb_clear_slave(struct bondi index = next_index; } - _unlock_tx_hashtbl(bond); + tlb_init_slave(slave); /* Stratus88746: do this before unlocking */ - tlb_init_slave(slave); + _unlock_tx_hashtbl(bond); } /* Must be called before starting the monitor timer */ @@ -1275,7 +1278,7 @@ void bond_alb_deinitialize(struct bondin int bond_alb_xmit(struct sk_buff *skb, struct net_device *bond_dev) { struct bonding *bond = bond_dev->priv; - struct ethhdr *eth_data = (struct ethhdr *)skb->mac.raw = skb->data; + struct ethhdr *eth_data = (struct ethhdr *)(skb->mac.raw = skb->data); struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond)); struct slave *tx_slave = NULL; static u32 ip_bcast = 0xffffffff; diff -Nur -p linux-2.4.32/drivers/net/e1000/e1000_hw.c linux-2.4.33-rc2/drivers/net/e1000/e1000_hw.c --- linux-2.4.32/drivers/net/e1000/e1000_hw.c 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/e1000/e1000_hw.c 2006-06-21 10:40:43.000000000 -0300 @@ -5049,7 +5049,7 @@ e1000_config_dsp_after_link_change(struc if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); ret_val = e1000_write_phy_reg(hw, 0x0000, IGP01E1000_IEEE_FORCE_GIGA); @@ -5073,7 +5073,7 @@ e1000_config_dsp_after_link_change(struc if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); /* Now enable the transmitter */ ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data); @@ -5098,7 +5098,7 @@ e1000_config_dsp_after_link_change(struc if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); ret_val = e1000_write_phy_reg(hw, 0x0000, IGP01E1000_IEEE_FORCE_GIGA); @@ -5114,7 +5114,7 @@ e1000_config_dsp_after_link_change(struc if(ret_val) return ret_val; - msec_delay(20); + msec_delay_irq(20); /* Now enable the transmitter */ ret_val = e1000_write_phy_reg(hw, 0x2F5B, phy_saved_data); diff -Nur -p linux-2.4.32/drivers/net/e1000/e1000_main.c linux-2.4.33-rc2/drivers/net/e1000/e1000_main.c --- linux-2.4.32/drivers/net/e1000/e1000_main.c 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/e1000/e1000_main.c 2006-06-21 10:40:43.000000000 -0300 @@ -2755,7 +2755,7 @@ e1000_mii_ioctl(struct net_device *netde if (e1000_write_phy_reg(&adapter->hw, data->reg_num, mii_reg)) return -EIO; - if (adapter->hw.phy_type == e1000_phy_m88) { + if (adapter->hw.media_type == e1000_media_type_copper) { switch (data->reg_num) { case PHY_CTRL: if(mii_reg & MII_CR_POWER_DOWN) @@ -2771,8 +2771,8 @@ e1000_mii_ioctl(struct net_device *netde else spddplx = SPEED_10; spddplx += (mii_reg & 0x100) - ? FULL_DUPLEX : - HALF_DUPLEX; + ? DUPLEX_FULL : + DUPLEX_HALF; retval = e1000_set_spd_dplx(adapter, spddplx); if(retval) diff -Nur -p linux-2.4.32/drivers/net/forcedeth.c linux-2.4.33-rc2/drivers/net/forcedeth.c --- linux-2.4.32/drivers/net/forcedeth.c 2005-01-19 12:09:56.000000000 -0200 +++ linux-2.4.33-rc2/drivers/net/forcedeth.c 2006-06-21 10:40:43.000000000 -0300 @@ -10,7 +10,7 @@ * trademarks of NVIDIA Corporation in the United States and other * countries. * - * Copyright (C) 2003,4 Manfred Spraul + * Copyright (C) 2003,4,5 Manfred Spraul * Copyright (C) 2004 Andrew de Quincey (wol support) * Copyright (C) 2004 Carl-Daniel Hailfinger (invalid MAC handling, insane * IRQ rate fixes, bigendian fixes, cleanups, verification) @@ -79,6 +79,30 @@ * 0.30: 25 Sep 2004: rx checksum support for nf 250 Gb. Add rx reset * into nv_close, otherwise reenabling for wol can * cause DMA to kfree'd memory. + * 0.31: 14 Nov 2004: ethtool support for getting/setting link + * capabilities. + * 0.32: 16 Apr 2005: RX_ERROR4 handling added. + * 0.33: 16 May 2005: Support for MCP51 added. + * 0.34: 18 Jun 2005: Add DEV_NEED_LINKTIMER to all nForce nics. + * 0.35: 26 Jun 2005: Support for MCP55 added. + * 0.36: 28 Jun 2005: Add jumbo frame support. + * 0.37: 10 Jul 2005: Additional ethtool support, cleanup of pci id list + * 0.38: 16 Jul 2005: tx irq rewrite: Use global flags instead of + * per-packet flags. + * 0.39: 18 Jul 2005: Add 64bit descriptor support. + * 0.40: 19 Jul 2005: Add support for mac address change. + * 0.41: 30 Jul 2005: Write back original MAC in nv_close instead + * of nv_remove + * 0.42: 06 Aug 2005: Fix lack of link speed initialization + * in the second (and later) nv_open call + * 0.43: 10 Aug 2005: Add support for tx checksum. + * 0.44: 20 Aug 2005: Add support for scatter gather and segmentation. + * 0.45: 18 Sep 2005: Remove nv_stop/start_rx from every link check + * 0.46: 20 Oct 2005: Add irq optimization modes. + * 0.47: 26 Oct 2005: Add phyaddr 0 in phy scan. + * 0.48: 24 Dec 2005: Disable TSO, bugfix for pci_map_single + * 0.49: 10 Dec 2005: Fix tso for large buffers. + * 0.50: 20 Jan 2006: Add 8021pq tagging support. * * Known bugs: * We suspect that on some hardware no TX done interrupts are generated. @@ -90,7 +114,7 @@ * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few * superfluous timer interrupts from the nic. */ -#define FORCEDETH_VERSION "0.30" +#define FORCEDETH_VERSION "0.50" #define DRV_NAME "forcedeth" #include @@ -108,6 +132,7 @@ #include #include #include +#include #include #include @@ -120,16 +145,22 @@ #define dprintk(x...) do { } while (0) #endif +/* not present in 2.4 */ +#ifndef NETDEV_TX_OK +#define NETDEV_TX_OK 0 +#define NETDEV_TX_BUSY 1 +#endif /* * Hardware access: */ -#define DEV_NEED_LASTPACKET1 0x0001 /* set LASTPACKET1 in tx flags */ -#define DEV_IRQMASK_1 0x0002 /* use NVREG_IRQMASK_WANTED_1 for irq mask */ -#define DEV_IRQMASK_2 0x0004 /* use NVREG_IRQMASK_WANTED_2 for irq mask */ -#define DEV_NEED_TIMERIRQ 0x0008 /* set the timer irq flag in the irq mask */ -#define DEV_NEED_LINKTIMER 0x0010 /* poll link settings. Relies on the timer irq */ +#define DEV_NEED_TIMERIRQ 0x0001 /* set the timer irq flag in the irq mask */ +#define DEV_NEED_LINKTIMER 0x0002 /* poll link settings. Relies on the timer irq */ +#define DEV_HAS_LARGEDESC 0x0004 /* device supports jumbo frames and needs packet format 2 */ +#define DEV_HAS_HIGH_DMA 0x0008 /* device supports 64bit dma */ +#define DEV_HAS_CHECKSUM 0x0010 /* device supports tx and rx checksum offloads */ +#define DEV_HAS_VLAN 0x0020 /* device supports vlan tagging and striping */ enum { NvRegIrqStatus = 0x000, @@ -140,13 +171,17 @@ enum { #define NVREG_IRQ_RX 0x0002 #define NVREG_IRQ_RX_NOBUF 0x0004 #define NVREG_IRQ_TX_ERR 0x0008 -#define NVREG_IRQ_TX2 0x0010 +#define NVREG_IRQ_TX_OK 0x0010 #define NVREG_IRQ_TIMER 0x0020 #define NVREG_IRQ_LINK 0x0040 +#define NVREG_IRQ_TX_ERROR 0x0080 #define NVREG_IRQ_TX1 0x0100 -#define NVREG_IRQMASK_WANTED_1 0x005f -#define NVREG_IRQMASK_WANTED_2 0x0147 -#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR|NVREG_IRQ_TX2|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX1)) +#define NVREG_IRQMASK_THROUGHPUT 0x00df +#define NVREG_IRQMASK_CPU 0x0040 + +#define NVREG_IRQ_UNKNOWN (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \ + NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_TX_ERROR| \ + NVREG_IRQ_TX1)) NvRegUnknownSetupReg6 = 0x008, #define NVREG_UNKSETUP6_VAL 3 @@ -156,7 +191,8 @@ enum { * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms */ NvRegPollingInterval = 0x00c, -#define NVREG_POLL_DEFAULT 970 +#define NVREG_POLL_DEFAULT_THROUGHPUT 970 +#define NVREG_POLL_DEFAULT_CPU 13 NvRegMisc1 = 0x080, #define NVREG_MISC1_HD 0x02 #define NVREG_MISC1_FORCE 0x3b0f3c @@ -211,6 +247,7 @@ enum { #define NVREG_LINKSPEED_10 1000 #define NVREG_LINKSPEED_100 100 #define NVREG_LINKSPEED_1000 50 +#define NVREG_LINKSPEED_MASK (0xFFF) NvRegUnknownSetupReg5 = 0x130, #define NVREG_UNKSETUP5_BIT31 (1<<31) NvRegUnknownSetupReg3 = 0x13c, @@ -222,6 +259,11 @@ enum { #define NVREG_TXRXCTL_IDLE 0x0008 #define NVREG_TXRXCTL_RESET 0x0010 #define NVREG_TXRXCTL_RXCHECK 0x0400 +#define NVREG_TXRXCTL_DESC_1 0 +#define NVREG_TXRXCTL_DESC_2 0x02100 +#define NVREG_TXRXCTL_DESC_3 0x02200 +#define NVREG_TXRXCTL_VLANSTRIP 0x00040 +#define NVREG_TXRXCTL_VLANINS 0x00080 NvRegMIIStatus = 0x180, #define NVREG_MIISTAT_ERROR 0x0001 #define NVREG_MIISTAT_LINKCHANGE 0x0008 @@ -271,6 +313,8 @@ enum { #define NVREG_POWERSTATE_D1 0x0001 #define NVREG_POWERSTATE_D2 0x0002 #define NVREG_POWERSTATE_D3 0x0003 + NvRegVlanControl = 0x300, +#define NVREG_VLANCONTROL_ENABLE 0x2000 }; /* Big endian: should work, but is untested */ @@ -279,6 +323,18 @@ struct ring_desc { u32 FlagLen; }; +struct ring_desc_ex { + u32 PacketBufferHigh; + u32 PacketBufferLow; + u32 TxVlan; + u32 FlagLen; +}; + +typedef union _ring_type { + struct ring_desc* orig; + struct ring_desc_ex* ex; +} ring_type; + #define FLAG_MASK_V1 0xffff0000 #define FLAG_MASK_V2 0xffffc000 #define LEN_MASK_V1 (0xffffffff ^ FLAG_MASK_V1) @@ -286,7 +342,7 @@ struct ring_desc { #define NV_TX_LASTPACKET (1<<16) #define NV_TX_RETRYERROR (1<<19) -#define NV_TX_LASTPACKET1 (1<<24) +#define NV_TX_FORCED_INTERRUPT (1<<24) #define NV_TX_DEFERRED (1<<26) #define NV_TX_CARRIERLOST (1<<27) #define NV_TX_LATECOLLISION (1<<28) @@ -296,7 +352,7 @@ struct ring_desc { #define NV_TX2_LASTPACKET (1<<29) #define NV_TX2_RETRYERROR (1<<18) -#define NV_TX2_LASTPACKET1 (1<<23) +#define NV_TX2_FORCED_INTERRUPT (1<<30) #define NV_TX2_DEFERRED (1<<25) #define NV_TX2_CARRIERLOST (1<<26) #define NV_TX2_LATECOLLISION (1<<27) @@ -304,6 +360,14 @@ struct ring_desc { /* error and valid are the same for both */ #define NV_TX2_ERROR (1<<30) #define NV_TX2_VALID (1<<31) +#define NV_TX2_TSO (1<<28) +#define NV_TX2_TSO_SHIFT 14 +#define NV_TX2_TSO_MAX_SHIFT 14 +#define NV_TX2_TSO_MAX_SIZE (1<desc_ver with DESC_VER_xy. - * - It contains bits that are forced on when writing to NvRegTxRxControl. + * The nic supports three different descriptor types: + * - DESC_VER_1: Original + * - DESC_VER_2: support for jumbo frames. + * - DESC_VER_3: 64-bit format. */ -#define DESC_VER_1 0x0 -#define DESC_VER_2 (0x02100|NVREG_TXRXCTL_RXCHECK) +#define DESC_VER_1 1 +#define DESC_VER_2 2 +#define DESC_VER_3 3 /* PHY defines */ #define PHY_OUI_MARVELL 0x5043 @@ -442,6 +514,8 @@ struct fe_priv { int in_shutdown; u32 linkspeed; int duplex; + int autoneg; + int fixed_mode; int phyaddr; int wolenabled; unsigned int phy_oui; @@ -453,15 +527,20 @@ struct fe_priv { u32 orig_mac[2]; u32 irqmask; u32 desc_ver; + u32 txrxctl_bits; + u32 vlanctl_bits; + + void __iomem *base; /* rx specific fields. * Locking: Within irq hander or disable_irq+spin_lock(&np->lock); */ - struct ring_desc *rx_ring; + ring_type rx_ring; unsigned int cur_rx, refill_rx; struct sk_buff *rx_skbuff[RX_RING]; dma_addr_t rx_dma[RX_RING]; unsigned int rx_buf_sz; + unsigned int pkt_limit; struct timer_list oom_kick; struct timer_list nic_poll; @@ -473,11 +552,15 @@ struct fe_priv { /* * tx specific fields. */ - struct ring_desc *tx_ring; + ring_type tx_ring; unsigned int next_tx, nic_tx; struct sk_buff *tx_skbuff[TX_RING]; dma_addr_t tx_dma[TX_RING]; + unsigned int tx_dma_len[TX_RING]; u32 tx_flags; + + /* vlan fields */ + struct vlan_group *vlangrp; }; /* @@ -486,17 +569,36 @@ struct fe_priv { */ static int max_interrupt_work = 5; +/* + * Optimization can be either throuput mode or cpu mode + * + * Throughput Mode: Every tx and rx packet will generate an interrupt. + * CPU Mode: Interrupts are controlled by a timer. + */ +#define NV_OPTIMIZATION_MODE_THROUGHPUT 0 +#define NV_OPTIMIZATION_MODE_CPU 1 +static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT; + +/* + * Poll interval for timer irq + * + * This interval determines how frequent an interrupt is generated. + * The is value is determined by [(time_in_micro_secs * 100) / (2^10)] + * Min = 0, and Max = 65535 + */ +static int poll_interval = -1; + static inline struct fe_priv *get_nvpriv(struct net_device *dev) { - return (struct fe_priv *) dev->priv; + return netdev_priv(dev); } -static inline u8 *get_hwbase(struct net_device *dev) +static inline u8 __iomem *get_hwbase(struct net_device *dev) { - return (u8 *) dev->base_addr; + return ((struct fe_priv *)netdev_priv(dev))->base; } -static inline void pci_push(u8 * base) +static inline void pci_push(u8 __iomem *base) { /* force out pending posted writes */ readl(base); @@ -508,10 +610,15 @@ static inline u32 nv_descr_getlength(str & ((v == DESC_VER_1) ? LEN_MASK_V1 : LEN_MASK_V2); } +static inline u32 nv_descr_getlength_ex(struct ring_desc_ex *prd, u32 v) +{ + return le32_to_cpu(prd->FlagLen) & LEN_MASK_V2; +} + static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target, int delay, int delaymax, const char *msg) { - u8 *base = get_hwbase(dev); + u8 __iomem *base = get_hwbase(dev); pci_push(base); do { @@ -533,7 +640,7 @@ static int reg_delay(struct net_device * */ static int mii_rw(struct net_device *dev, int addr, int miireg, int value) { - u8 *base = get_hwbase(dev); + u8 __iomem *base = get_hwbase(dev); u32 reg; int retval; @@ -577,7 +684,7 @@ static int mii_rw(struct net_device *dev static int phy_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 miicontrol; unsigned int tries = 0; @@ -604,7 +711,7 @@ static int phy_reset(struct net_device * static int phy_init(struct net_device *dev) { struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); + u8 __iomem *base = get_hwbase(dev); u32 phyinterface, phy_reserved, mii_status, mii_control, mii_control_1000,reg; /* set advertise register */ @@ -680,8 +787,8 @@ static int phy_init(struct net_device *d static void nv_start_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_start_rx\n", dev->name); /* Already running? Stop it. */ @@ -699,7 +806,7 @@ static void nv_start_rx(struct net_devic static void nv_stop_rx(struct net_device *dev) { - u8 *base = get_hwbase(dev); + u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_stop_rx\n", dev->name); writel(0, base + NvRegReceiverControl); @@ -713,7 +820,7 @@ static void nv_stop_rx(struct net_device static void nv_start_tx(struct net_device *dev) { - u8 *base = get_hwbase(dev); + u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_start_tx\n", dev->name); writel(NVREG_XMITCTL_START, base + NvRegTransmitterControl); @@ -722,7 +829,7 @@ static void nv_start_tx(struct net_devic static void nv_stop_tx(struct net_device *dev) { - u8 *base = get_hwbase(dev); + u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_stop_tx\n", dev->name); writel(0, base + NvRegTransmitterControl); @@ -736,14 +843,14 @@ static void nv_stop_tx(struct net_device static void nv_txrx_reset(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); dprintk(KERN_DEBUG "%s: nv_txrx_reset\n", dev->name); - writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT2 | NVREG_TXRXCTL_RESET | np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); udelay(NV_TXRX_RESET_DELAY); - writel(NVREG_TXRXCTL_BIT2 | np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT2 | np->txrxctl_bits, base + NvRegTxRxControl); pci_push(base); } @@ -755,7 +862,7 @@ static void nv_txrx_reset(struct net_dev */ static struct net_device_stats *nv_get_stats(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); /* It seems that the nic always generates interrupts and doesn't * accumulate errors internally. Thus the current values in np->stats @@ -764,50 +871,6 @@ static struct net_device_stats *nv_get_s return &np->stats; } -static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) -{ - struct fe_priv *np = get_nvpriv(dev); - strcpy(info->driver, "forcedeth"); - strcpy(info->version, FORCEDETH_VERSION); - strcpy(info->bus_info, pci_name(np->pci_dev)); -} - -static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) -{ - struct fe_priv *np = get_nvpriv(dev); - wolinfo->supported = WAKE_MAGIC; - - spin_lock_irq(&np->lock); - if (np->wolenabled) - wolinfo->wolopts = WAKE_MAGIC; - spin_unlock_irq(&np->lock); -} - -static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) -{ - struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); - - spin_lock_irq(&np->lock); - if (wolinfo->wolopts == 0) { - writel(0, base + NvRegWakeUpFlags); - np->wolenabled = 0; - } - if (wolinfo->wolopts & WAKE_MAGIC) { - writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags); - np->wolenabled = 1; - } - spin_unlock_irq(&np->lock); - return 0; -} - -static struct ethtool_ops ops = { - .get_drvinfo = nv_get_drvinfo, - .get_link = ethtool_op_get_link, - .get_wol = nv_get_wol, - .set_wol = nv_set_wol, -}; - /* * nv_alloc_rx: fill rx ring entries. * Return 1 if the allocations for the skbs failed and the @@ -815,7 +878,7 @@ static struct ethtool_ops ops = { */ static int nv_alloc_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); unsigned int refill_rx = np->refill_rx; int nr; @@ -825,7 +888,7 @@ static int nv_alloc_rx(struct net_device nr = refill_rx % RX_RING; if (np->rx_skbuff[nr] == NULL) { - skb = dev_alloc_skb(RX_ALLOC_BUFSIZE); + skb = dev_alloc_skb(np->rx_buf_sz + NV_RX_ALLOC_PAD); if (!skb) break; @@ -834,11 +897,18 @@ static int nv_alloc_rx(struct net_device } else { skb = np->rx_skbuff[nr]; } - np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, skb->len, - PCI_DMA_FROMDEVICE); - np->rx_ring[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); - wmb(); - np->rx_ring[nr].FlagLen = cpu_to_le32(RX_NIC_BUFSIZE | NV_RX_AVAIL); + np->rx_dma[nr] = pci_map_single(np->pci_dev, skb->data, + skb->end-skb->data, PCI_DMA_FROMDEVICE); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->rx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->rx_dma[nr]); + wmb(); + np->rx_ring.orig[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX_AVAIL); + } else { + np->rx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->rx_dma[nr]) >> 32; + np->rx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->rx_dma[nr]) & 0x0FFFFFFFF; + wmb(); + np->rx_ring.ex[nr].FlagLen = cpu_to_le32(np->rx_buf_sz | NV_RX2_AVAIL); + } dprintk(KERN_DEBUG "%s: nv_alloc_rx: Packet %d marked as Available\n", dev->name, refill_rx); refill_rx++; @@ -852,7 +922,7 @@ static int nv_alloc_rx(struct net_device static void nv_do_rx_refill(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); disable_irq(dev->irq); if (nv_alloc_rx(dev)) { @@ -864,49 +934,94 @@ static void nv_do_rx_refill(unsigned lon enable_irq(dev->irq); } -static int nv_init_ring(struct net_device *dev) +static void nv_init_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; - np->next_tx = np->nic_tx = 0; - for (i = 0; i < TX_RING; i++) - np->tx_ring[i].FlagLen = 0; - np->cur_rx = RX_RING; np->refill_rx = 0; for (i = 0; i < RX_RING; i++) - np->rx_ring[i].FlagLen = 0; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->rx_ring.orig[i].FlagLen = 0; + else + np->rx_ring.ex[i].FlagLen = 0; +} + +static void nv_init_tx(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + int i; + + np->next_tx = np->nic_tx = 0; + for (i = 0; i < TX_RING; i++) { + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->tx_ring.orig[i].FlagLen = 0; + else + np->tx_ring.ex[i].FlagLen = 0; + np->tx_skbuff[i] = NULL; + np->tx_dma[i] = 0; + } +} + +static int nv_init_ring(struct net_device *dev) +{ + nv_init_tx(dev); + nv_init_rx(dev); return nv_alloc_rx(dev); } +static int nv_release_txskb(struct net_device *dev, unsigned int skbnr) +{ + struct fe_priv *np = netdev_priv(dev); + + dprintk(KERN_INFO "%s: nv_release_txskb for skbnr %d\n", + dev->name, skbnr); + + if (np->tx_dma[skbnr]) { + pci_unmap_page(np->pci_dev, np->tx_dma[skbnr], + np->tx_dma_len[skbnr], + PCI_DMA_TODEVICE); + np->tx_dma[skbnr] = 0; + } + + if (np->tx_skbuff[skbnr]) { + dev_kfree_skb_irq(np->tx_skbuff[skbnr]); + np->tx_skbuff[skbnr] = NULL; + return 1; + } else { + return 0; + } +} + static void nv_drain_tx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - int i; + struct fe_priv *np = netdev_priv(dev); + unsigned int i; + for (i = 0; i < TX_RING; i++) { - np->tx_ring[i].FlagLen = 0; - if (np->tx_skbuff[i]) { - pci_unmap_single(np->pci_dev, np->tx_dma[i], - np->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb(np->tx_skbuff[i]); - np->tx_skbuff[i] = NULL; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->tx_ring.orig[i].FlagLen = 0; + else + np->tx_ring.ex[i].FlagLen = 0; + if (nv_release_txskb(dev, i)) np->stats.tx_dropped++; - } } } static void nv_drain_rx(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); int i; for (i = 0; i < RX_RING; i++) { - np->rx_ring[i].FlagLen = 0; + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + np->rx_ring.orig[i].FlagLen = 0; + else + np->rx_ring.ex[i].FlagLen = 0; wmb(); if (np->rx_skbuff[i]) { pci_unmap_single(np->pci_dev, np->rx_dma[i], - np->rx_skbuff[i]->len, + np->rx_skbuff[i]->end-np->rx_skbuff[i]->data, PCI_DMA_FROMDEVICE); dev_kfree_skb(np->rx_skbuff[i]); np->rx_skbuff[i] = NULL; @@ -926,20 +1041,113 @@ static void drain_ring(struct net_device */ static int nv_start_xmit(struct sk_buff *skb, struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - int nr = np->next_tx % TX_RING; + struct fe_priv *np = netdev_priv(dev); + u32 tx_flags = 0; + u32 tx_flags_extra = (np->desc_ver == DESC_VER_1 ? NV_TX_LASTPACKET : NV_TX2_LASTPACKET); + unsigned int fragments = skb_shinfo(skb)->nr_frags; + unsigned int nr = (np->next_tx - 1) % TX_RING; + unsigned int start_nr = np->next_tx % TX_RING; + unsigned int i; + u32 offset = 0; + u32 bcnt; + u32 size = skb->len-skb->data_len; + u32 entries = (size >> NV_TX2_TSO_MAX_SHIFT) + ((size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + u32 tx_flags_vlan = 0; + + /* add fragments to entries count */ + for (i = 0; i < fragments; i++) { + entries += (skb_shinfo(skb)->frags[i].size >> NV_TX2_TSO_MAX_SHIFT) + + ((skb_shinfo(skb)->frags[i].size & (NV_TX2_TSO_MAX_SIZE-1)) ? 1 : 0); + } + + spin_lock_irq(&np->lock); + + if ((np->next_tx - np->nic_tx + entries - 1) > TX_LIMIT_STOP) { + spin_unlock_irq(&np->lock); + netif_stop_queue(dev); + return NETDEV_TX_BUSY; + } + + /* setup the header buffer */ + do { + bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + nr = (nr + 1) % TX_RING; + + np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data + offset, bcnt, + PCI_DMA_TODEVICE); + np->tx_dma_len[nr] = bcnt; + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + } else { + np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + } + tx_flags = np->tx_flags; + offset += bcnt; + size -= bcnt; + } while(size); + + /* setup the fragments */ + for (i = 0; i < fragments; i++) { + skb_frag_t *frag = &skb_shinfo(skb)->frags[i]; + u32 size = frag->size; + offset = 0; + + do { + bcnt = (size > NV_TX2_TSO_MAX_SIZE) ? NV_TX2_TSO_MAX_SIZE : size; + nr = (nr + 1) % TX_RING; + + np->tx_dma[nr] = pci_map_page(np->pci_dev, frag->page, frag->page_offset+offset, bcnt, + PCI_DMA_TODEVICE); + np->tx_dma_len[nr] = bcnt; + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); + np->tx_ring.orig[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + } else { + np->tx_ring.ex[nr].PacketBufferHigh = cpu_to_le64(np->tx_dma[nr]) >> 32; + np->tx_ring.ex[nr].PacketBufferLow = cpu_to_le64(np->tx_dma[nr]) & 0x0FFFFFFFF; + np->tx_ring.ex[nr].FlagLen = cpu_to_le32((bcnt-1) | tx_flags); + } + offset += bcnt; + size -= bcnt; + } while (size); + } + + /* set last fragment flag */ + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[nr].FlagLen |= cpu_to_le32(tx_flags_extra); + } else { + np->tx_ring.ex[nr].FlagLen |= cpu_to_le32(tx_flags_extra); + } np->tx_skbuff[nr] = skb; - np->tx_dma[nr] = pci_map_single(np->pci_dev, skb->data,skb->len, - PCI_DMA_TODEVICE); - np->tx_ring[nr].PacketBuffer = cpu_to_le32(np->tx_dma[nr]); +#ifdef NETIF_F_TSO + if (skb_shinfo(skb)->tso_size) + tx_flags_extra = NV_TX2_TSO | (skb_shinfo(skb)->tso_size << NV_TX2_TSO_SHIFT); + else +#endif + tx_flags_extra = (skb->ip_summed == CHECKSUM_HW ? (NV_TX2_CHECKSUM_L3|NV_TX2_CHECKSUM_L4) : 0); - spin_lock_irq(&np->lock); - wmb(); - np->tx_ring[nr].FlagLen = cpu_to_le32( (skb->len-1) | np->tx_flags ); - dprintk(KERN_DEBUG "%s: nv_start_xmit: packet packet %d queued for transmission.\n", - dev->name, np->next_tx); + /* vlan tag */ + if (np->vlangrp && vlan_tx_tag_present(skb)) { + tx_flags_vlan = NV_TX3_VLAN_TAG_PRESENT | vlan_tx_tag_get(skb); + } + + /* set tx flags */ + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->tx_ring.orig[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); + } else { + np->tx_ring.ex[start_nr].TxVlan = cpu_to_le32(tx_flags_vlan); + np->tx_ring.ex[start_nr].FlagLen |= cpu_to_le32(tx_flags | tx_flags_extra); + } + + dprintk(KERN_DEBUG "%s: nv_start_xmit: packet %d (entries %d) queued for transmission. tx_flags_extra: %x\n", + dev->name, np->next_tx, entries, tx_flags_extra); { int j; for (j=0; j<64; j++) { @@ -950,15 +1158,13 @@ static int nv_start_xmit(struct sk_buff dprintk("\n"); } - np->next_tx++; + np->next_tx += entries; dev->trans_start = jiffies; - if (np->next_tx - np->nic_tx >= TX_LIMIT_STOP) - netif_stop_queue(dev); spin_unlock_irq(&np->lock); - writel(NVREG_TXRXCTL_KICK|np->desc_ver, get_hwbase(dev) + NvRegTxRxControl); + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); pci_push(get_hwbase(dev)); - return 0; + return NETDEV_TX_OK; } /* @@ -968,49 +1174,55 @@ static int nv_start_xmit(struct sk_buff */ static void nv_tx_done(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 Flags; - int i; + unsigned int i; + struct sk_buff *skb; while (np->nic_tx != np->next_tx) { i = np->nic_tx % TX_RING; - Flags = le32_to_cpu(np->tx_ring[i].FlagLen); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + Flags = le32_to_cpu(np->tx_ring.orig[i].FlagLen); + else + Flags = le32_to_cpu(np->tx_ring.ex[i].FlagLen); dprintk(KERN_DEBUG "%s: nv_tx_done: looking at packet %d, Flags 0x%x.\n", dev->name, np->nic_tx, Flags); if (Flags & NV_TX_VALID) break; if (np->desc_ver == DESC_VER_1) { - if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| - NV_TX_UNDERFLOW|NV_TX_ERROR)) { - if (Flags & NV_TX_UNDERFLOW) - np->stats.tx_fifo_errors++; - if (Flags & NV_TX_CARRIERLOST) - np->stats.tx_carrier_errors++; - np->stats.tx_errors++; - } else { - np->stats.tx_packets++; - np->stats.tx_bytes += np->tx_skbuff[i]->len; + if (Flags & NV_TX_LASTPACKET) { + skb = np->tx_skbuff[i]; + if (Flags & (NV_TX_RETRYERROR|NV_TX_CARRIERLOST|NV_TX_LATECOLLISION| + NV_TX_UNDERFLOW|NV_TX_ERROR)) { + if (Flags & NV_TX_UNDERFLOW) + np->stats.tx_fifo_errors++; + if (Flags & NV_TX_CARRIERLOST) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += skb->len; + } } } else { - if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| - NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { - if (Flags & NV_TX2_UNDERFLOW) - np->stats.tx_fifo_errors++; - if (Flags & NV_TX2_CARRIERLOST) - np->stats.tx_carrier_errors++; - np->stats.tx_errors++; - } else { - np->stats.tx_packets++; - np->stats.tx_bytes += np->tx_skbuff[i]->len; + if (Flags & NV_TX2_LASTPACKET) { + skb = np->tx_skbuff[i]; + if (Flags & (NV_TX2_RETRYERROR|NV_TX2_CARRIERLOST|NV_TX2_LATECOLLISION| + NV_TX2_UNDERFLOW|NV_TX2_ERROR)) { + if (Flags & NV_TX2_UNDERFLOW) + np->stats.tx_fifo_errors++; + if (Flags & NV_TX2_CARRIERLOST) + np->stats.tx_carrier_errors++; + np->stats.tx_errors++; + } else { + np->stats.tx_packets++; + np->stats.tx_bytes += skb->len; + } } } - pci_unmap_single(np->pci_dev, np->tx_dma[i], - np->tx_skbuff[i]->len, - PCI_DMA_TODEVICE); - dev_kfree_skb_irq(np->tx_skbuff[i]); - np->tx_skbuff[i] = NULL; + nv_release_txskb(dev, i); np->nic_tx++; } if (np->next_tx - np->nic_tx < TX_LIMIT_START) @@ -1023,12 +1235,59 @@ static void nv_tx_done(struct net_device */ static void nv_tx_timeout(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); - dprintk(KERN_DEBUG "%s: Got tx_timeout. irq: %08x\n", dev->name, + printk(KERN_INFO "%s: Got tx_timeout. irq: %08x\n", dev->name, readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK); + { + int i; + + printk(KERN_INFO "%s: Ring at %lx: next %d nic %d\n", + dev->name, (unsigned long)np->ring_addr, + np->next_tx, np->nic_tx); + printk(KERN_INFO "%s: Dumping tx registers\n", dev->name); + for (i=0;i<0x400;i+= 32) { + printk(KERN_INFO "%3x: %08x %08x %08x %08x %08x %08x %08x %08x\n", + i, + readl(base + i + 0), readl(base + i + 4), + readl(base + i + 8), readl(base + i + 12), + readl(base + i + 16), readl(base + i + 20), + readl(base + i + 24), readl(base + i + 28)); + } + printk(KERN_INFO "%s: Dumping tx ring\n", dev->name); + for (i=0;idesc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + printk(KERN_INFO "%03x: %08x %08x // %08x %08x // %08x %08x // %08x %08x\n", + i, + le32_to_cpu(np->tx_ring.orig[i].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i].FlagLen), + le32_to_cpu(np->tx_ring.orig[i+1].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i+1].FlagLen), + le32_to_cpu(np->tx_ring.orig[i+2].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i+2].FlagLen), + le32_to_cpu(np->tx_ring.orig[i+3].PacketBuffer), + le32_to_cpu(np->tx_ring.orig[i+3].FlagLen)); + } else { + printk(KERN_INFO "%03x: %08x %08x %08x // %08x %08x %08x // %08x %08x %08x // %08x %08x %08x\n", + i, + le32_to_cpu(np->tx_ring.ex[i].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i].FlagLen), + le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i+1].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i+1].FlagLen), + le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i+2].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i+2].FlagLen), + le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferHigh), + le32_to_cpu(np->tx_ring.ex[i+3].PacketBufferLow), + le32_to_cpu(np->tx_ring.ex[i+3].FlagLen)); + } + } + } + spin_lock_irq(&np->lock); /* 1) stop tx engine */ @@ -1042,7 +1301,10 @@ static void nv_tx_timeout(struct net_dev printk(KERN_DEBUG "%s: tx_timeout: dead entries!\n", dev->name); nv_drain_tx(dev); np->next_tx = np->nic_tx = 0; - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + else + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); netif_wake_queue(dev); } @@ -1051,10 +1313,65 @@ static void nv_tx_timeout(struct net_dev spin_unlock_irq(&np->lock); } +/* + * Called when the nic notices a mismatch between the actual data len on the + * wire and the len indicated in the 802 header + */ +static int nv_getlen(struct net_device *dev, void *packet, int datalen) +{ + int hdrlen; /* length of the 802 header */ + int protolen; /* length as stored in the proto field */ + + /* 1) calculate len according to header */ + if ( ((struct vlan_ethhdr *)packet)->h_vlan_proto == __constant_htons(ETH_P_8021Q)) { + protolen = ntohs( ((struct vlan_ethhdr *)packet)->h_vlan_encapsulated_proto ); + hdrlen = VLAN_HLEN; + } else { + protolen = ntohs( ((struct ethhdr *)packet)->h_proto); + hdrlen = ETH_HLEN; + } + dprintk(KERN_DEBUG "%s: nv_getlen: datalen %d, protolen %d, hdrlen %d\n", + dev->name, datalen, protolen, hdrlen); + if (protolen > ETH_DATA_LEN) + return datalen; /* Value in proto field not a len, no checks possible */ + + protolen += hdrlen; + /* consistency checks: */ + if (datalen > ETH_ZLEN) { + if (datalen >= protolen) { + /* more data on wire than in 802 header, trim of + * additional data. + */ + dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n", + dev->name, protolen); + return protolen; + } else { + /* less data on wire than mentioned in header. + * Discard the packet. + */ + dprintk(KERN_DEBUG "%s: nv_getlen: discarding long packet.\n", + dev->name); + return -1; + } + } else { + /* short packet. Accept only if 802 values are also short */ + if (protolen > ETH_ZLEN) { + dprintk(KERN_DEBUG "%s: nv_getlen: discarding short packet.\n", + dev->name); + return -1; + } + dprintk(KERN_DEBUG "%s: nv_getlen: accepting %d bytes.\n", + dev->name, datalen); + return datalen; + } +} + static void nv_rx_process(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); + struct fe_priv *np = netdev_priv(dev); u32 Flags; + u32 vlanflags = 0; + for (;;) { struct sk_buff *skb; @@ -1064,8 +1381,14 @@ static void nv_rx_process(struct net_dev break; /* we scanned the whole ring - do not continue */ i = np->cur_rx % RX_RING; - Flags = le32_to_cpu(np->rx_ring[i].FlagLen); - len = nv_descr_getlength(&np->rx_ring[i], np->desc_ver); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + Flags = le32_to_cpu(np->rx_ring.orig[i].FlagLen); + len = nv_descr_getlength(&np->rx_ring.orig[i], np->desc_ver); + } else { + Flags = le32_to_cpu(np->rx_ring.ex[i].FlagLen); + len = nv_descr_getlength_ex(&np->rx_ring.ex[i], np->desc_ver); + vlanflags = le32_to_cpu(np->rx_ring.ex[i].PacketBufferLow); + } dprintk(KERN_DEBUG "%s: nv_rx_process: looking at packet %d, Flags 0x%x.\n", dev->name, np->cur_rx, Flags); @@ -1079,7 +1402,7 @@ static void nv_rx_process(struct net_dev * the performance. */ pci_unmap_single(np->pci_dev, np->rx_dma[i], - np->rx_skbuff[i]->len, + np->rx_skbuff[i]->end-np->rx_skbuff[i]->data, PCI_DMA_FROMDEVICE); { @@ -1097,63 +1420,71 @@ static void nv_rx_process(struct net_dev if (!(Flags & NV_RX_DESCRIPTORVALID)) goto next_pkt; - if (Flags & NV_RX_MISSEDFRAME) { - np->stats.rx_missed_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3|NV_RX_ERROR4)) { - np->stats.rx_errors++; - goto next_pkt; - } - if (Flags & NV_RX_CRCERR) { - np->stats.rx_crc_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (Flags & NV_RX_OVERFLOW) { - np->stats.rx_over_errors++; - np->stats.rx_errors++; - goto next_pkt; - } if (Flags & NV_RX_ERROR) { - /* framing errors are soft errors, the rest is fatal. */ + if (Flags & NV_RX_MISSEDFRAME) { + np->stats.rx_missed_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & (NV_RX_ERROR1|NV_RX_ERROR2|NV_RX_ERROR3)) { + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX_CRCERR) { + np->stats.rx_crc_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX_OVERFLOW) { + np->stats.rx_over_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX_ERROR4) { + len = nv_getlen(dev, np->rx_skbuff[i]->data, len); + if (len < 0) { + np->stats.rx_errors++; + goto next_pkt; + } + } + /* framing errors are soft errors. */ if (Flags & NV_RX_FRAMINGERR) { if (Flags & NV_RX_SUBSTRACT1) { len--; } - } else { - np->stats.rx_errors++; - goto next_pkt; } } } else { if (!(Flags & NV_RX2_DESCRIPTORVALID)) goto next_pkt; - if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3|NV_RX2_ERROR4)) { - np->stats.rx_errors++; - goto next_pkt; - } - if (Flags & NV_RX2_CRCERR) { - np->stats.rx_crc_errors++; - np->stats.rx_errors++; - goto next_pkt; - } - if (Flags & NV_RX2_OVERFLOW) { - np->stats.rx_over_errors++; - np->stats.rx_errors++; - goto next_pkt; - } if (Flags & NV_RX2_ERROR) { - /* framing errors are soft errors, the rest is fatal. */ + if (Flags & (NV_RX2_ERROR1|NV_RX2_ERROR2|NV_RX2_ERROR3)) { + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX2_CRCERR) { + np->stats.rx_crc_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX2_OVERFLOW) { + np->stats.rx_over_errors++; + np->stats.rx_errors++; + goto next_pkt; + } + if (Flags & NV_RX2_ERROR4) { + len = nv_getlen(dev, np->rx_skbuff[i]->data, len); + if (len < 0) { + np->stats.rx_errors++; + goto next_pkt; + } + } + /* framing errors are soft errors */ if (Flags & NV_RX2_FRAMINGERR) { if (Flags & NV_RX2_SUBSTRACT1) { len--; } - } else { - np->stats.rx_errors++; - goto next_pkt; } } Flags &= NV_RX2_CHECKSUMMASK; @@ -1174,7 +1505,11 @@ static void nv_rx_process(struct net_dev skb->protocol = eth_type_trans(skb, dev); dprintk(KERN_DEBUG "%s: nv_rx_process: packet %d with %d bytes, proto %d accepted.\n", dev->name, np->cur_rx, len, skb->protocol); - netif_rx(skb); + if (np->vlangrp && (vlanflags & NV_RX3_VLAN_TAG_PRESENT)) { + vlan_hwaccel_rx(skb, np->vlangrp, vlanflags & NV_RX3_VLAN_TAG_MASK); + } else { + netif_rx(skb); + } dev->last_rx = jiffies; np->stats.rx_packets++; np->stats.rx_bytes += len; @@ -1183,15 +1518,133 @@ next_pkt: } } +static void set_bufsize(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + + if (dev->mtu <= ETH_DATA_LEN) + np->rx_buf_sz = ETH_DATA_LEN + NV_RX_HEADERS; + else + np->rx_buf_sz = dev->mtu + NV_RX_HEADERS; +} + /* * nv_change_mtu: dev->change_mtu function * Called with dev_base_lock held for read. */ static int nv_change_mtu(struct net_device *dev, int new_mtu) { - if (new_mtu > ETH_DATA_LEN) + struct fe_priv *np = netdev_priv(dev); + int old_mtu; + + if (new_mtu < 64 || new_mtu > np->pkt_limit) return -EINVAL; + + old_mtu = dev->mtu; dev->mtu = new_mtu; + + /* return early if the buffer sizes will not change */ + if (old_mtu <= ETH_DATA_LEN && new_mtu <= ETH_DATA_LEN) + return 0; + if (old_mtu == new_mtu) + return 0; + + /* synchronized against open : rtnl_lock() held by caller */ + if (netif_running(dev)) { + u8 __iomem *base = get_hwbase(dev); + /* + * It seems that the nic preloads valid ring entries into an + * internal buffer. The procedure for flushing everything is + * guessed, there is probably a simpler approach. + * Changing the MTU is a rare event, it shouldn't matter. + */ + disable_irq(dev->irq); + spin_lock_bh(&dev->xmit_lock); + spin_lock(&np->lock); + /* stop engines */ + nv_stop_rx(dev); + nv_stop_tx(dev); + nv_txrx_reset(dev); + /* drain rx queue */ + nv_drain_rx(dev); + nv_drain_tx(dev); + /* reinit driver view of the rx queue */ + nv_init_rx(dev); + nv_init_tx(dev); + /* alloc new rx buffers */ + set_bufsize(dev); + if (nv_alloc_rx(dev)) { + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); + } + /* reinit nic view of the rx queue */ + writel(np->rx_buf_sz, base + NvRegOffloadConfig); + writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + else + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); + writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), + base + NvRegRingSizes); + pci_push(base); + writel(NVREG_TXRXCTL_KICK|np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); + pci_push(base); + + /* restart rx engine */ + nv_start_rx(dev); + nv_start_tx(dev); + spin_unlock(&np->lock); + spin_unlock_bh(&dev->xmit_lock); + enable_irq(dev->irq); + } + return 0; +} + +static void nv_copy_mac_to_hw(struct net_device *dev) +{ + u8 __iomem *base = get_hwbase(dev); + u32 mac[2]; + + mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + + (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); + mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); + + writel(mac[0], base + NvRegMacAddrA); + writel(mac[1], base + NvRegMacAddrB); +} + +/* + * nv_set_mac_address: dev->set_mac_address function + * Called with rtnl_lock() held. + */ +static int nv_set_mac_address(struct net_device *dev, void *addr) +{ + struct fe_priv *np = netdev_priv(dev); + struct sockaddr *macaddr = (struct sockaddr*)addr; + + if(!is_valid_ether_addr(macaddr->sa_data)) + return -EADDRNOTAVAIL; + + /* synchronized against open : rtnl_lock() held by caller */ + memcpy(dev->dev_addr, macaddr->sa_data, ETH_ALEN); + + if (netif_running(dev)) { + spin_lock_bh(&dev->xmit_lock); + spin_lock_irq(&np->lock); + + /* stop rx engine */ + nv_stop_rx(dev); + + /* set mac address */ + nv_copy_mac_to_hw(dev); + + /* restart rx engine */ + nv_start_rx(dev); + spin_unlock_irq(&np->lock); + spin_unlock_bh(&dev->xmit_lock); + } else { + nv_copy_mac_to_hw(dev); + } return 0; } @@ -1201,8 +1654,8 @@ static int nv_change_mtu(struct net_devi */ static void nv_set_multicast(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); u32 addr[2]; u32 mask[2]; u32 pff; @@ -1259,10 +1712,21 @@ static void nv_set_multicast(struct net_ spin_unlock_irq(&np->lock); } +/** + * nv_update_linkspeed: Setup the MAC according to the link partner + * @dev: Network device to be configured + * + * The function queries the PHY and checks if there is a link partner. + * If yes, then it sets up the MAC accordingly. Otherwise, the MAC is + * set to 10 MBit HD. + * + * The function returns 0 if there is no link partner and 1 if there is + * a good link partner. + */ static int nv_update_linkspeed(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); int adv, lpa; int newls = np->linkspeed; int newdup = np->duplex; @@ -1285,6 +1749,25 @@ static int nv_update_linkspeed(struct ne goto set_speed; } + if (np->autoneg == 0) { + dprintk(KERN_DEBUG "%s: nv_update_linkspeed: autoneg off, PHY set to 0x%04x.\n", + dev->name, np->fixed_mode); + if (np->fixed_mode & LPA_100FULL) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100; + newdup = 1; + } else if (np->fixed_mode & LPA_100HALF) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_100; + newdup = 0; + } else if (np->fixed_mode & LPA_10FULL) { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 1; + } else { + newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + newdup = 0; + } + retval = 1; + goto set_speed; + } /* check auto negotiation is complete */ if (!(mii_status & BMSR_ANEGCOMPLETE)) { /* still in autonegotiation - configure nic for 10 MBit HD and wait. */ @@ -1302,7 +1785,7 @@ static int nv_update_linkspeed(struct ne if ((control_1000 & ADVERTISE_1000FULL) && (status_1000 & LPA_1000FULL)) { - dprintk(KERN_DEBUG "%s: nv_update_linkspeed: GBit ethernet detected.\n", + dprintk(KERN_DEBUG "%s: nv_update_linkspeed: GBit ethernet detected.\n", dev->name); newls = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_1000; newdup = 1; @@ -1361,9 +1844,9 @@ set_speed: phyreg &= ~(PHY_HALF|PHY_100|PHY_1000); if (np->duplex == 0) phyreg |= PHY_HALF; - if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_100) + if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_100) phyreg |= PHY_100; - else if ((np->linkspeed & 0xFFF) == NVREG_LINKSPEED_1000) + else if ((np->linkspeed & NVREG_LINKSPEED_MASK) == NVREG_LINKSPEED_1000) phyreg |= PHY_1000; writel(phyreg, base + NvRegPhyInterface); @@ -1379,13 +1862,11 @@ set_speed: static void nv_linkchange(struct net_device *dev) { if (nv_update_linkspeed(dev)) { - if (netif_carrier_ok(dev)) { - nv_stop_rx(dev); - } else { + if (!netif_carrier_ok(dev)) { netif_carrier_on(dev); printk(KERN_INFO "%s: link up.\n", dev->name); + nv_start_rx(dev); } - nv_start_rx(dev); } else { if (netif_carrier_ok(dev)) { netif_carrier_off(dev); @@ -1397,7 +1878,7 @@ static void nv_linkchange(struct net_dev static void nv_link_irq(struct net_device *dev) { - u8 *base = get_hwbase(dev); + u8 __iomem *base = get_hwbase(dev); u32 miistat; miistat = readl(base + NvRegMIIStatus); @@ -1412,8 +1893,8 @@ static void nv_link_irq(struct net_devic static irqreturn_t nv_nic_irq(int foo, void *data, struct pt_regs *regs) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); u32 events; int i; @@ -1427,22 +1908,18 @@ static irqreturn_t nv_nic_irq(int foo, v if (!(events & np->irqmask)) break; - if (events & (NVREG_IRQ_TX1|NVREG_IRQ_TX2|NVREG_IRQ_TX_ERR)) { + spin_lock(&np->lock); + nv_tx_done(dev); + spin_unlock(&np->lock); + + nv_rx_process(dev); + if (nv_alloc_rx(dev)) { spin_lock(&np->lock); - nv_tx_done(dev); + if (!np->in_shutdown) + mod_timer(&np->oom_kick, jiffies + OOM_REFILL); spin_unlock(&np->lock); } - - if (events & (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF)) { - nv_rx_process(dev); - if (nv_alloc_rx(dev)) { - spin_lock(&np->lock); - if (!np->in_shutdown) - mod_timer(&np->oom_kick, jiffies + OOM_REFILL); - spin_unlock(&np->lock); - } - } - + if (events & NVREG_IRQ_LINK) { spin_lock(&np->lock); nv_link_irq(dev); @@ -1484,8 +1961,8 @@ static irqreturn_t nv_nic_irq(int foo, v static void nv_do_nic_poll(unsigned long data) { struct net_device *dev = (struct net_device *) data; - struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); disable_irq(dev->irq); /* FIXME: Do we need synchronize_irq(dev->irq) here? */ @@ -1499,10 +1976,313 @@ static void nv_do_nic_poll(unsigned long enable_irq(dev->irq); } -static int nv_open(struct net_device *dev) +#ifdef CONFIG_NET_POLL_CONTROLLER +static void nv_poll_controller(struct net_device *dev) +{ + nv_do_nic_poll((unsigned long) dev); +} +#endif + +static void nv_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info) +{ + struct fe_priv *np = netdev_priv(dev); + strcpy(info->driver, "forcedeth"); + strcpy(info->version, FORCEDETH_VERSION); + strcpy(info->bus_info, pci_name(np->pci_dev)); +} + +static void nv_get_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) +{ + struct fe_priv *np = netdev_priv(dev); + wolinfo->supported = WAKE_MAGIC; + + spin_lock_irq(&np->lock); + if (np->wolenabled) + wolinfo->wolopts = WAKE_MAGIC; + spin_unlock_irq(&np->lock); +} + +static int nv_set_wol(struct net_device *dev, struct ethtool_wolinfo *wolinfo) +{ + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + + spin_lock_irq(&np->lock); + if (wolinfo->wolopts == 0) { + writel(0, base + NvRegWakeUpFlags); + np->wolenabled = 0; + } + if (wolinfo->wolopts & WAKE_MAGIC) { + writel(NVREG_WAKEUPFLAGS_ENABLE, base + NvRegWakeUpFlags); + np->wolenabled = 1; + } + spin_unlock_irq(&np->lock); + return 0; +} + +static int nv_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + struct fe_priv *np = netdev_priv(dev); + int adv; + + spin_lock_irq(&np->lock); + ecmd->port = PORT_MII; + if (!netif_running(dev)) { + /* We do not track link speed / duplex setting if the + * interface is disabled. Force a link check */ + nv_update_linkspeed(dev); + } + switch(np->linkspeed & (NVREG_LINKSPEED_MASK)) { + case NVREG_LINKSPEED_10: + ecmd->speed = SPEED_10; + break; + case NVREG_LINKSPEED_100: + ecmd->speed = SPEED_100; + break; + case NVREG_LINKSPEED_1000: + ecmd->speed = SPEED_1000; + break; + } + ecmd->duplex = DUPLEX_HALF; + if (np->duplex) + ecmd->duplex = DUPLEX_FULL; + + ecmd->autoneg = np->autoneg; + + ecmd->advertising = ADVERTISED_MII; + if (np->autoneg) { + ecmd->advertising |= ADVERTISED_Autoneg; + adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); + } else { + adv = np->fixed_mode; + } + if (adv & ADVERTISE_10HALF) + ecmd->advertising |= ADVERTISED_10baseT_Half; + if (adv & ADVERTISE_10FULL) + ecmd->advertising |= ADVERTISED_10baseT_Full; + if (adv & ADVERTISE_100HALF) + ecmd->advertising |= ADVERTISED_100baseT_Half; + if (adv & ADVERTISE_100FULL) + ecmd->advertising |= ADVERTISED_100baseT_Full; + if (np->autoneg && np->gigabit == PHY_GIGABIT) { + adv = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ); + if (adv & ADVERTISE_1000FULL) + ecmd->advertising |= ADVERTISED_1000baseT_Full; + } + + ecmd->supported = (SUPPORTED_Autoneg | + SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | + SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | + SUPPORTED_MII); + if (np->gigabit == PHY_GIGABIT) + ecmd->supported |= SUPPORTED_1000baseT_Full; + + ecmd->phy_address = np->phyaddr; + ecmd->transceiver = XCVR_EXTERNAL; + + /* ignore maxtxpkt, maxrxpkt for now */ + spin_unlock_irq(&np->lock); + return 0; +} + +static int nv_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd) +{ + struct fe_priv *np = netdev_priv(dev); + + if (ecmd->port != PORT_MII) + return -EINVAL; + if (ecmd->transceiver != XCVR_EXTERNAL) + return -EINVAL; + if (ecmd->phy_address != np->phyaddr) { + /* TODO: support switching between multiple phys. Should be + * trivial, but not enabled due to lack of test hardware. */ + return -EINVAL; + } + if (ecmd->autoneg == AUTONEG_ENABLE) { + u32 mask; + + mask = ADVERTISED_10baseT_Half | ADVERTISED_10baseT_Full | + ADVERTISED_100baseT_Half | ADVERTISED_100baseT_Full; + if (np->gigabit == PHY_GIGABIT) + mask |= ADVERTISED_1000baseT_Full; + + if ((ecmd->advertising & mask) == 0) + return -EINVAL; + + } else if (ecmd->autoneg == AUTONEG_DISABLE) { + /* Note: autonegotiation disable, speed 1000 intentionally + * forbidden - noone should need that. */ + + if (ecmd->speed != SPEED_10 && ecmd->speed != SPEED_100) + return -EINVAL; + if (ecmd->duplex != DUPLEX_HALF && ecmd->duplex != DUPLEX_FULL) + return -EINVAL; + } else { + return -EINVAL; + } + + spin_lock_irq(&np->lock); + if (ecmd->autoneg == AUTONEG_ENABLE) { + int adv, bmcr; + + np->autoneg = 1; + + /* advertise only what has been requested */ + adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (ecmd->advertising & ADVERTISED_10baseT_Half) + adv |= ADVERTISE_10HALF; + if (ecmd->advertising & ADVERTISED_10baseT_Full) + adv |= ADVERTISE_10FULL; + if (ecmd->advertising & ADVERTISED_100baseT_Half) + adv |= ADVERTISE_100HALF; + if (ecmd->advertising & ADVERTISED_100baseT_Full) + adv |= ADVERTISE_100FULL; + mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); + + if (np->gigabit == PHY_GIGABIT) { + adv = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ); + adv &= ~ADVERTISE_1000FULL; + if (ecmd->advertising & ADVERTISED_1000baseT_Full) + adv |= ADVERTISE_1000FULL; + mii_rw(dev, np->phyaddr, MII_1000BT_CR, adv); + } + + bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); + bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); + mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); + + } else { + int adv, bmcr; + + np->autoneg = 0; + + adv = mii_rw(dev, np->phyaddr, MII_ADVERTISE, MII_READ); + adv &= ~(ADVERTISE_ALL | ADVERTISE_100BASE4); + if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_HALF) + adv |= ADVERTISE_10HALF; + if (ecmd->speed == SPEED_10 && ecmd->duplex == DUPLEX_FULL) + adv |= ADVERTISE_10FULL; + if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_HALF) + adv |= ADVERTISE_100HALF; + if (ecmd->speed == SPEED_100 && ecmd->duplex == DUPLEX_FULL) + adv |= ADVERTISE_100FULL; + mii_rw(dev, np->phyaddr, MII_ADVERTISE, adv); + np->fixed_mode = adv; + + if (np->gigabit == PHY_GIGABIT) { + adv = mii_rw(dev, np->phyaddr, MII_1000BT_CR, MII_READ); + adv &= ~ADVERTISE_1000FULL; + mii_rw(dev, np->phyaddr, MII_1000BT_CR, adv); + } + + bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); + bmcr |= ~(BMCR_ANENABLE|BMCR_SPEED100|BMCR_FULLDPLX); + if (adv & (ADVERTISE_10FULL|ADVERTISE_100FULL)) + bmcr |= BMCR_FULLDPLX; + if (adv & (ADVERTISE_100HALF|ADVERTISE_100FULL)) + bmcr |= BMCR_SPEED100; + mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); + + if (netif_running(dev)) { + /* Wait a bit and then reconfigure the nic. */ + udelay(10); + nv_linkchange(dev); + } + } + spin_unlock_irq(&np->lock); + + return 0; +} + +#define FORCEDETH_REGS_VER 1 +#define FORCEDETH_REGS_SIZE 0x400 /* 256 32-bit registers */ + +static int nv_get_regs_len(struct net_device *dev) +{ + return FORCEDETH_REGS_SIZE; +} + +static void nv_get_regs(struct net_device *dev, struct ethtool_regs *regs, void *buf) +{ + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); + u32 *rbuf = buf; + int i; + + regs->version = FORCEDETH_REGS_VER; + spin_lock_irq(&np->lock); + for (i=0;ilock); +} + +static int nv_nway_reset(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + int ret; + + spin_lock_irq(&np->lock); + if (np->autoneg) { + int bmcr; + + bmcr = mii_rw(dev, np->phyaddr, MII_BMCR, MII_READ); + bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART); + mii_rw(dev, np->phyaddr, MII_BMCR, bmcr); + + ret = 0; + } else { + ret = -EINVAL; + } + spin_unlock_irq(&np->lock); + + return ret; +} + +static struct ethtool_ops ops = { + .get_drvinfo = nv_get_drvinfo, + .get_link = ethtool_op_get_link, + .get_wol = nv_get_wol, + .set_wol = nv_set_wol, + .get_settings = nv_get_settings, + .set_settings = nv_set_settings, + .get_regs_len = nv_get_regs_len, + .get_regs = nv_get_regs, + .nway_reset = nv_nway_reset, +}; + +static void nv_vlan_rx_register(struct net_device *dev, struct vlan_group *grp) { struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); + + spin_lock_irq(&np->lock); + + /* save vlan group */ + np->vlangrp = grp; + + if (grp) { + /* enable vlan on MAC */ + np->txrxctl_bits |= NVREG_TXRXCTL_VLANSTRIP | NVREG_TXRXCTL_VLANINS; + } else { + /* disable vlan on MAC */ + np->txrxctl_bits &= ~NVREG_TXRXCTL_VLANSTRIP; + np->txrxctl_bits &= ~NVREG_TXRXCTL_VLANINS; + } + + writel(np->txrxctl_bits, get_hwbase(dev) + NvRegTxRxControl); + + spin_unlock_irq(&np->lock); +}; + +static void nv_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid) +{ + /* nothing to do */ +}; + +static int nv_open(struct net_device *dev) +{ + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base = get_hwbase(dev); int ret, oom, i; dprintk(KERN_DEBUG "nv_open: begin\n"); @@ -1521,6 +2301,7 @@ static int nv_open(struct net_device *de writel(0, base + NvRegAdapterControl); /* 2) initialize descriptor rings */ + set_bufsize(dev); oom = nv_init_ring(dev); writel(0, base + NvRegLinkSpeed); @@ -1531,32 +2312,24 @@ static int nv_open(struct net_device *de np->in_shutdown = 0; /* 3) set mac address */ - { - u32 mac[2]; - - mac[0] = (dev->dev_addr[0] << 0) + (dev->dev_addr[1] << 8) + - (dev->dev_addr[2] << 16) + (dev->dev_addr[3] << 24); - mac[1] = (dev->dev_addr[4] << 0) + (dev->dev_addr[5] << 8); - - writel(mac[0], base + NvRegMacAddrA); - writel(mac[1], base + NvRegMacAddrB); - } + nv_copy_mac_to_hw(dev); /* 4) give hw rings */ writel((u32) np->ring_addr, base + NvRegRxRingPhysAddr); - writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc)), base + NvRegTxRingPhysAddr); + else + writel((u32) (np->ring_addr + RX_RING*sizeof(struct ring_desc_ex)), base + NvRegTxRingPhysAddr); writel( ((RX_RING-1) << NVREG_RINGSZ_RXSHIFT) + ((TX_RING-1) << NVREG_RINGSZ_TXSHIFT), base + NvRegRingSizes); /* 5) continue setup */ - np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; - np->duplex = 0; - writel(np->linkspeed, base + NvRegLinkSpeed); writel(NVREG_UNKSETUP3_VAL1, base + NvRegUnknownSetupReg3); - writel(np->desc_ver, base + NvRegTxRxControl); + writel(np->txrxctl_bits, base + NvRegTxRxControl); + writel(np->vlanctl_bits, base + NvRegVlanControl); pci_push(base); - writel(NVREG_TXRXCTL_BIT1|np->desc_ver, base + NvRegTxRxControl); + writel(NVREG_TXRXCTL_BIT1|np->txrxctl_bits, base + NvRegTxRxControl); reg_delay(dev, NvRegUnknownSetupReg5, NVREG_UNKSETUP5_BIT31, NVREG_UNKSETUP5_BIT31, NV_SETUP5_DELAY, NV_SETUP5_DELAYMAX, KERN_INFO "open: SetupReg5, Bit 31 remained off\n"); @@ -1569,14 +2342,21 @@ static int nv_open(struct net_device *de writel(NVREG_MISC1_FORCE | NVREG_MISC1_HD, base + NvRegMisc1); writel(readl(base + NvRegTransmitterStatus), base + NvRegTransmitterStatus); writel(NVREG_PFF_ALWAYS, base + NvRegPacketFilterFlags); - writel(NVREG_OFFLOAD_NORMAL, base + NvRegOffloadConfig); + writel(np->rx_buf_sz, base + NvRegOffloadConfig); writel(readl(base + NvRegReceiverStatus), base + NvRegReceiverStatus); get_random_bytes(&i, sizeof(i)); writel(NVREG_RNDSEED_FORCE | (i&NVREG_RNDSEED_MASK), base + NvRegRandomSeed); writel(NVREG_UNKSETUP1_VAL, base + NvRegUnknownSetupReg1); writel(NVREG_UNKSETUP2_VAL, base + NvRegUnknownSetupReg2); - writel(NVREG_POLL_DEFAULT, base + NvRegPollingInterval); + if (poll_interval == -1) { + if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) + writel(NVREG_POLL_DEFAULT_THROUGHPUT, base + NvRegPollingInterval); + else + writel(NVREG_POLL_DEFAULT_CPU, base + NvRegPollingInterval); + } + else + writel(poll_interval & 0xFFFF, base + NvRegPollingInterval); writel(NVREG_UNKSETUP6_VAL, base + NvRegUnknownSetupReg6); writel((np->phyaddr << NVREG_ADAPTCTL_PHYSHIFT)|NVREG_ADAPTCTL_PHYVALID|NVREG_ADAPTCTL_RUNNING, base + NvRegAdapterControl); @@ -1620,6 +2400,9 @@ static int nv_open(struct net_device *de writel(NVREG_MIISTAT_MASK, base + NvRegMIIStatus); dprintk(KERN_INFO "startup: got 0x%08x.\n", miistat); } + /* set linkspeed to invalid value, thus force nv_update_linkspeed + * to init hw */ + np->linkspeed = 0; ret = nv_update_linkspeed(dev); nv_start_rx(dev); nv_start_tx(dev); @@ -1642,8 +2425,8 @@ out_drain: static int nv_close(struct net_device *dev) { - struct fe_priv *np = get_nvpriv(dev); - u8 *base; + struct fe_priv *np = netdev_priv(dev); + u8 __iomem *base; spin_lock_irq(&np->lock); np->in_shutdown = 1; @@ -1674,6 +2457,12 @@ static int nv_close(struct net_device *d if (np->wolenabled) nv_start_rx(dev); + /* special op: write back the misordered MAC address - otherwise + * the next nv_probe would see a wrong address. + */ + writel(np->orig_mac[0], base + NvRegMacAddrA); + writel(np->orig_mac[1], base + NvRegMacAddrB); + /* FIXME: power down nic */ return 0; @@ -1684,7 +2473,7 @@ static int __devinit nv_probe(struct pci struct net_device *dev; struct fe_priv *np; unsigned long addr; - u8 *base; + u8 __iomem *base; int err, i; dev = alloc_etherdev(sizeof(struct fe_priv)); @@ -1692,7 +2481,7 @@ static int __devinit nv_probe(struct pci if (!dev) goto out; - np = get_nvpriv(dev); + np = netdev_priv(dev); np->pci_dev = pci_dev; spin_lock_init(&np->lock); SET_MODULE_OWNER(dev); @@ -1738,30 +2527,80 @@ static int __devinit nv_probe(struct pci } /* handle different descriptor versions */ - if (pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_1 || - pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_2 || - pci_dev->device == PCI_DEVICE_ID_NVIDIA_NVENET_3) - np->desc_ver = DESC_VER_1; - else + if (id->driver_data & DEV_HAS_HIGH_DMA) { + /* packet format 3: supports 40-bit addressing */ + np->desc_ver = DESC_VER_3; + if (pci_set_dma_mask(pci_dev, 0x0000007fffffffffULL)) { + printk(KERN_INFO "forcedeth: 64-bit DMA failed, using 32-bit addressing for device %s.\n", + pci_name(pci_dev)); + } else { + dev->features |= NETIF_F_HIGHDMA; + } + np->txrxctl_bits = NVREG_TXRXCTL_DESC_3; + } else if (id->driver_data & DEV_HAS_LARGEDESC) { + /* packet format 2: supports jumbo frames */ np->desc_ver = DESC_VER_2; + np->txrxctl_bits = NVREG_TXRXCTL_DESC_2; + } else { + /* original packet format */ + np->desc_ver = DESC_VER_1; + np->txrxctl_bits = NVREG_TXRXCTL_DESC_1; + } + + np->pkt_limit = NV_PKTLIMIT_1; + if (id->driver_data & DEV_HAS_LARGEDESC) + np->pkt_limit = NV_PKTLIMIT_2; + + if (id->driver_data & DEV_HAS_CHECKSUM) { + np->txrxctl_bits |= NVREG_TXRXCTL_RXCHECK; + dev->features |= NETIF_F_HW_CSUM | NETIF_F_SG; +#ifdef NETIF_F_TSO + dev->features |= NETIF_F_TSO; +#endif + } + + np->vlanctl_bits = 0; + if (id->driver_data & DEV_HAS_VLAN) { + np->vlanctl_bits = NVREG_VLANCONTROL_ENABLE; + dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX; + dev->vlan_rx_register = nv_vlan_rx_register; + dev->vlan_rx_kill_vid = nv_vlan_rx_kill_vid; + } err = -ENOMEM; - dev->base_addr = (unsigned long) ioremap(addr, NV_PCI_REGSZ); - if (!dev->base_addr) + np->base = ioremap(addr, NV_PCI_REGSZ); + if (!np->base) goto out_relreg; + dev->base_addr = (unsigned long)np->base; + dev->irq = pci_dev->irq; - np->rx_ring = pci_alloc_consistent(pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), - &np->ring_addr); - if (!np->rx_ring) - goto out_unmap; - np->tx_ring = &np->rx_ring[RX_RING]; + + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) { + np->rx_ring.orig = pci_alloc_consistent(pci_dev, + sizeof(struct ring_desc) * (RX_RING + TX_RING), + &np->ring_addr); + if (!np->rx_ring.orig) + goto out_unmap; + np->tx_ring.orig = &np->rx_ring.orig[RX_RING]; + } else { + np->rx_ring.ex = pci_alloc_consistent(pci_dev, + sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), + &np->ring_addr); + if (!np->rx_ring.ex) + goto out_unmap; + np->tx_ring.ex = &np->rx_ring.ex[RX_RING]; + } dev->open = nv_open; dev->stop = nv_close; dev->hard_start_xmit = nv_start_xmit; dev->get_stats = nv_get_stats; dev->change_mtu = nv_change_mtu; + dev->set_mac_address = nv_set_mac_address; dev->set_multicast_list = nv_set_multicast; +#ifdef CONFIG_NET_POLL_CONTROLLER + dev->poll_controller = nv_poll_controller; +#endif SET_ETHTOOL_OPS(dev, &ops); dev->tx_timeout = nv_tx_timeout; dev->watchdog_timeo = NV_WATCHDOG_TIMEO; @@ -1805,18 +2644,15 @@ static int __devinit nv_probe(struct pci np->wolenabled = 0; if (np->desc_ver == DESC_VER_1) { - np->tx_flags = NV_TX_LASTPACKET|NV_TX_VALID; - if (id->driver_data & DEV_NEED_LASTPACKET1) - np->tx_flags |= NV_TX_LASTPACKET1; + np->tx_flags = NV_TX_VALID; } else { - np->tx_flags = NV_TX2_LASTPACKET|NV_TX2_VALID; - if (id->driver_data & DEV_NEED_LASTPACKET1) - np->tx_flags |= NV_TX2_LASTPACKET1; - } - if (id->driver_data & DEV_IRQMASK_1) - np->irqmask = NVREG_IRQMASK_WANTED_1; - if (id->driver_data & DEV_IRQMASK_2) - np->irqmask = NVREG_IRQMASK_WANTED_2; + np->tx_flags = NV_TX2_VALID; + } + if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) + np->irqmask = NVREG_IRQMASK_THROUGHPUT; + else + np->irqmask = NVREG_IRQMASK_CPU; + if (id->driver_data & DEV_NEED_TIMERIRQ) np->irqmask |= NVREG_IRQ_TIMER; if (id->driver_data & DEV_NEED_LINKTIMER) { @@ -1829,16 +2665,17 @@ static int __devinit nv_probe(struct pci } /* find a suitable phy */ - for (i = 1; i < 32; i++) { + for (i = 1; i <= 32; i++) { int id1, id2; + int phyaddr = i & 0x1F; spin_lock_irq(&np->lock); - id1 = mii_rw(dev, i, MII_PHYSID1, MII_READ); + id1 = mii_rw(dev, phyaddr, MII_PHYSID1, MII_READ); spin_unlock_irq(&np->lock); if (id1 < 0 || id1 == 0xffff) continue; spin_lock_irq(&np->lock); - id2 = mii_rw(dev, i, MII_PHYSID2, MII_READ); + id2 = mii_rw(dev, phyaddr, MII_PHYSID2, MII_READ); spin_unlock_irq(&np->lock); if (id2 < 0 || id2 == 0xffff) continue; @@ -1846,23 +2683,24 @@ static int __devinit nv_probe(struct pci id1 = (id1 & PHYID1_OUI_MASK) << PHYID1_OUI_SHFT; id2 = (id2 & PHYID2_OUI_MASK) >> PHYID2_OUI_SHFT; dprintk(KERN_DEBUG "%s: open: Found PHY %04x:%04x at address %d.\n", - pci_name(pci_dev), id1, id2, i); - np->phyaddr = i; + pci_name(pci_dev), id1, id2, phyaddr); + np->phyaddr = phyaddr; np->phy_oui = id1 | id2; break; } - if (i == 32) { - /* PHY in isolate mode? No phy attached and user wants to - * test loopback? Very odd, but can be correct. - */ + if (i == 33) { printk(KERN_INFO "%s: open: Could not find a valid PHY.\n", - pci_name(pci_dev)); + pci_name(pci_dev)); + goto out_freering; } + + /* reset it */ + phy_init(dev); - if (i != 32) { - /* reset it */ - phy_init(dev); - } + /* set default link speed settings */ + np->linkspeed = NVREG_LINKSPEED_FORCE|NVREG_LINKSPEED_10; + np->duplex = 0; + np->autoneg = 1; err = register_netdev(dev); if (err) { @@ -1876,8 +2714,12 @@ static int __devinit nv_probe(struct pci return 0; out_freering: - pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), - np->rx_ring, np->ring_addr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), + np->rx_ring.orig, np->ring_addr); + else + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), + np->rx_ring.ex, np->ring_addr); pci_set_drvdata(pci_dev, NULL); out_unmap: iounmap(get_hwbase(dev)); @@ -1894,19 +2736,15 @@ out: static void __devexit nv_remove(struct pci_dev *pci_dev) { struct net_device *dev = pci_get_drvdata(pci_dev); - struct fe_priv *np = get_nvpriv(dev); - u8 *base = get_hwbase(dev); + struct fe_priv *np = netdev_priv(dev); unregister_netdev(dev); - /* special op: write back the misordered MAC address - otherwise - * the next nv_probe would see a wrong address. - */ - writel(np->orig_mac[0], base + NvRegMacAddrA); - writel(np->orig_mac[1], base + NvRegMacAddrB); - /* free all structures */ - pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring, np->ring_addr); + if (np->desc_ver == DESC_VER_1 || np->desc_ver == DESC_VER_2) + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc) * (RX_RING + TX_RING), np->rx_ring.orig, np->ring_addr); + else + pci_free_consistent(np->pci_dev, sizeof(struct ring_desc_ex) * (RX_RING + TX_RING), np->rx_ring.ex, np->ring_addr); iounmap(get_hwbase(dev)); pci_release_regions(pci_dev); pci_disable_device(pci_dev); @@ -1916,81 +2754,64 @@ static void __devexit nv_remove(struct p static struct pci_device_id pci_tbl[] = { { /* nForce Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_1, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_IRQMASK_1|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_1), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce2 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_2, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_2), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_3, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_3), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_4, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_4), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_5, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_5), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_6, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_6), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* nForce3 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_7, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_7), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM, }, { /* CK804 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_8, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_8), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* CK804 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_9, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_9), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_10, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, }, { /* MCP04 Ethernet Controller */ - .vendor = PCI_VENDOR_ID_NVIDIA, - .device = PCI_DEVICE_ID_NVIDIA_NVENET_11, - .subvendor = PCI_ANY_ID, - .subdevice = PCI_ANY_ID, - .driver_data = DEV_NEED_LASTPACKET1|DEV_IRQMASK_2|DEV_NEED_TIMERIRQ, + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA, + }, + { /* MCP51 Ethernet Controller */ + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA, + }, + { /* MCP51 Ethernet Controller */ + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA, + }, + { /* MCP55 Ethernet Controller */ + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN, + }, + { /* MCP55 Ethernet Controller */ + PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_15), + .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_VLAN, }, {0,}, }; @@ -2016,7 +2837,11 @@ static void __exit exit_nic(void) module_param(max_interrupt_work, int, 0); MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt"); - +module_param(optimization_mode, int, 0); +MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer."); +module_param(poll_interval, int, 0); +MODULE_PARM_DESC(poll_interval, "Interval determines how frequent timer interrupt is generated by [(time_in_micro_secs * 100) / (2^10)]. Min is 0 and Max is 65535."); + MODULE_AUTHOR("Manfred Spraul "); MODULE_DESCRIPTION("Reverse Engineered nForce ethernet driver"); MODULE_LICENSE("GPL"); diff -Nur -p linux-2.4.32/drivers/net/sis900.c linux-2.4.33-rc2/drivers/net/sis900.c --- linux-2.4.32/drivers/net/sis900.c 2004-08-07 20:26:05.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/sis900.c 2006-06-21 10:40:43.000000000 -0300 @@ -1613,15 +1613,20 @@ static int sis900_rx(struct net_device * long ioaddr = net_dev->base_addr; unsigned int entry = sis_priv->cur_rx % NUM_RX_DESC; u32 rx_status = sis_priv->rx_ring[entry].cmdsts; + int rx_work_limit; if (sis900_debug > 3) printk(KERN_INFO "sis900_rx, cur_rx:%4.4d, dirty_rx:%4.4d " "status:0x%8.8x\n", sis_priv->cur_rx, sis_priv->dirty_rx, rx_status); + rx_work_limit = sis_priv->dirty_rx + NUM_RX_DESC - sis_priv->cur_rx; while (rx_status & OWN) { unsigned int rx_size; + if (--rx_work_limit < 0) + break; + rx_size = (rx_status & DSIZE) - CRC_SIZE; if (rx_status & (ABORT|OVERRUN|TOOLONG|RUNT|RXISERR|CRCERR|FAERR)) { @@ -1648,9 +1653,11 @@ static int sis900_rx(struct net_device * some unknow bugs, it is possible that we are working on NULL sk_buff :-( */ if (sis_priv->rx_skbuff[entry] == NULL) { - printk(KERN_INFO "%s: NULL pointer " - "encountered in Rx ring, skipping\n", - net_dev->name); + printk(KERN_WARNING "%s: NULL pointer " + "encountered in Rx ring\n" + "cur_rx:%4.4d, dirty_rx:%4.4d\n", + net_dev->name, sis_priv->cur_rx, + sis_priv->dirty_rx); break; } @@ -1688,6 +1695,7 @@ static int sis900_rx(struct net_device * sis_priv->rx_ring[entry].cmdsts = 0; sis_priv->rx_ring[entry].bufptr = 0; sis_priv->stats.rx_dropped++; + sis_priv->cur_rx++; break; } skb->dev = net_dev; @@ -1705,7 +1713,7 @@ static int sis900_rx(struct net_device * /* refill the Rx buffer, what if the rate of refilling is slower than consuming ?? */ - for (;sis_priv->cur_rx - sis_priv->dirty_rx > 0; sis_priv->dirty_rx++) { + for (; sis_priv->cur_rx != sis_priv->dirty_rx; sis_priv->dirty_rx++) { struct sk_buff *skb; entry = sis_priv->dirty_rx % NUM_RX_DESC; diff -Nur -p linux-2.4.32/drivers/net/via-rhine.c linux-2.4.33-rc2/drivers/net/via-rhine.c --- linux-2.4.32/drivers/net/via-rhine.c 2004-08-07 20:26:05.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/via-rhine.c 2006-06-21 10:40:43.000000000 -0300 @@ -124,6 +124,7 @@ LK1.1.19 (Roger Luethi) - Increase Tx threshold for unspecified errors + - Craig Brind: Zero padded aligned buffers for short packets */ @@ -1308,10 +1309,14 @@ static int via_rhine_start_tx(struct sk_ np->stats.tx_dropped++; return 0; } + /* Padding is not copied and so must be redone. */ skb_copy_and_csum_dev(skb, np->tx_buf[entry]); + if (skb->len < ETH_ZLEN) + memset(np->tx_buf[entry] + skb->len, 0, + ETH_ZLEN - skb->len); np->tx_skbuff_dma[entry] = 0; np->tx_ring[entry].addr = cpu_to_le32(np->tx_bufs_dma + - (np->tx_buf[entry] - np->tx_bufs)); + (np->tx_buf[entry] - np->tx_bufs)); } else { np->tx_skbuff_dma[entry] = pci_map_single(np->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); diff -Nur -p linux-2.4.32/drivers/net/wan/sdla.c linux-2.4.33-rc2/drivers/net/wan/sdla.c --- linux-2.4.32/drivers/net/wan/sdla.c 2005-01-19 12:09:56.000000000 -0200 +++ linux-2.4.33-rc2/drivers/net/wan/sdla.c 2006-06-21 10:40:43.000000000 -0300 @@ -1201,6 +1201,7 @@ static int sdla_xfer(struct net_device * temp = kmalloc(mem.len, GFP_KERNEL); if (!temp) return(-ENOMEM); + memset(temp, 0, mem.len); sdla_read(dev, mem.addr, temp, mem.len); if(copy_to_user(mem.data, temp, mem.len)) { diff -Nur -p linux-2.4.32/drivers/net/wireless/airo.c linux-2.4.33-rc2/drivers/net/wireless/airo.c --- linux-2.4.32/drivers/net/wireless/airo.c 2004-08-07 20:26:05.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/wireless/airo.c 2006-06-21 10:40:43.000000000 -0300 @@ -43,6 +43,8 @@ #include #include +#include "airo.h" + #ifdef CONFIG_PCI static struct pci_device_id card_ids[] = { { 0x14b9, 1, PCI_ANY_ID, PCI_ANY_ID, }, diff -Nur -p linux-2.4.32/drivers/net/wireless/airo_cs.c linux-2.4.33-rc2/drivers/net/wireless/airo_cs.c --- linux-2.4.32/drivers/net/wireless/airo_cs.c 2002-11-28 21:53:14.000000000 -0200 +++ linux-2.4.33-rc2/drivers/net/wireless/airo_cs.c 2006-06-21 10:40:43.000000000 -0300 @@ -45,6 +45,8 @@ #include #include +#include "airo.h" + /* All the PCMCIA modules use PCMCIA_DEBUG to control debugging. If you do not define PCMCIA_DEBUG at all, all the debug code will be @@ -91,10 +93,6 @@ MODULE_PARM(irq_list, "1-4i"); event handler. */ -struct net_device *init_airo_card( int, int, int ); -void stop_airo_card( struct net_device *, int ); -int reset_airo_card( struct net_device * ); - static void airo_config(dev_link_t *link); static void airo_release(u_long arg); static int airo_event(event_t event, int priority, diff -Nur -p linux-2.4.32/drivers/net/wireless/airo.h linux-2.4.33-rc2/drivers/net/wireless/airo.h --- linux-2.4.32/drivers/net/wireless/airo.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/wireless/airo.h 2006-06-21 10:40:43.000000000 -0300 @@ -0,0 +1,8 @@ +#ifndef _AIRO_H_ +#define _AIRO_H_ + +struct net_device *init_airo_card(unsigned short irq, int port, int is_pcmcia); +void stop_airo_card(struct net_device *dev, int freeres); +int reset_airo_card(struct net_device *dev); + +#endif /* _AIRO_H_ */ diff -Nur -p linux-2.4.32/drivers/net/wireless/hermes.c linux-2.4.33-rc2/drivers/net/wireless/hermes.c --- linux-2.4.32/drivers/net/wireless/hermes.c 2003-08-25 08:44:42.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/wireless/hermes.c 2006-06-21 10:40:43.000000000 -0300 @@ -448,6 +448,43 @@ int hermes_bap_pwrite(hermes_t *hw, int return err; } +/* Write a block of data to the chip's buffer with padding if + * neccessary, via the BAP. Synchronization/serialization is the + * caller's problem. len must be even. + * + * Returns: < 0 on internal failure (errno), 0 on success, > 0 on error from firmware + */ +int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, unsigned data_len, unsigned len, + u16 id, u16 offset) +{ + int dreg = bap ? HERMES_DATA1 : HERMES_DATA0; + int err = 0; + + if (len < 0 || len % 2 || data_len > len) + return -EINVAL; + + err = hermes_bap_seek(hw, bap, id, offset); + if (err) + goto out; + + /* Transfer all the complete words of data */ + hermes_write_words(hw, dreg, buf, data_len/2); + /* If there is an odd byte left over pad and transfer it */ + if (data_len & 1) { + u8 end[2]; + end[1] = 0; + end[0] = ((unsigned char *)buf)[data_len - 1]; + hermes_write_words(hw, dreg, end, 1); + data_len ++; + } + /* Now send zeros for the padding */ + if (data_len < len) + hermes_clear_words(hw, dreg, (len - data_len) / 2); + /* Complete */ + out: + return err; +} + /* Read a Length-Type-Value record from the card. * * If length is NULL, we ignore the length read from the card, and @@ -534,6 +571,7 @@ EXPORT_SYMBOL(hermes_allocate); EXPORT_SYMBOL(hermes_bap_pread); EXPORT_SYMBOL(hermes_bap_pwrite); +EXPORT_SYMBOL(hermes_bap_pwrite_pad); EXPORT_SYMBOL(hermes_read_ltv); EXPORT_SYMBOL(hermes_write_ltv); diff -Nur -p linux-2.4.32/drivers/net/wireless/hermes.h linux-2.4.33-rc2/drivers/net/wireless/hermes.h --- linux-2.4.32/drivers/net/wireless/hermes.h 2003-08-25 08:44:42.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/wireless/hermes.h 2006-06-21 10:40:43.000000000 -0300 @@ -319,6 +319,8 @@ int hermes_bap_pread(hermes_t *hw, int b u16 id, u16 offset); int hermes_bap_pwrite(hermes_t *hw, int bap, const void *buf, unsigned len, u16 id, u16 offset); +int hermes_bap_pwrite_pad(hermes_t *hw, int bap, const void *buf, + unsigned data_len, unsigned len, u16 id, u16 offset); int hermes_read_ltv(hermes_t *hw, int bap, u16 rid, unsigned buflen, u16 *length, void *buf); int hermes_write_ltv(hermes_t *hw, int bap, u16 rid, diff -Nur -p linux-2.4.32/drivers/net/wireless/orinoco.c linux-2.4.33-rc2/drivers/net/wireless/orinoco.c --- linux-2.4.32/drivers/net/wireless/orinoco.c 2003-08-25 08:44:42.000000000 -0300 +++ linux-2.4.33-rc2/drivers/net/wireless/orinoco.c 2006-06-21 10:40:43.000000000 -0300 @@ -2312,6 +2312,8 @@ orinoco_stat_gather(struct net_device *d } } +#define ALIGN(x,a) (((x)+(a)-1)&~((a)-1)) + static int orinoco_xmit(struct sk_buff *skb, struct net_device *dev) { @@ -2407,14 +2409,22 @@ orinoco_xmit(struct sk_buff *skb, struct stats->tx_errors++; goto fail; } + /* Actual xfer length - allow for padding */ + len = ALIGN(data_len, 2); + if (len < ETH_ZLEN - ETH_HLEN) + len = ETH_ZLEN - ETH_HLEN; } else { /* IEEE 802.3 frame */ data_len = len + ETH_HLEN; data_off = HERMES_802_3_OFFSET; p = skb->data; + /* Actual xfer length - round up for odd length packets */ + len = ALIGN(data_len, 2); + if (len < ETH_ZLEN) + len = ETH_ZLEN; } - /* Round up for odd length packets */ - err = hermes_bap_pwrite(hw, USER_BAP, p, RUP_EVEN(data_len), txfid, data_off); + err = hermes_bap_pwrite_pad(hw, USER_BAP, p, data_len, len, + txfid, data_off); if (err) { printk(KERN_ERR "%s: Error %d writing packet to BAP\n", dev->name, err); diff -Nur -p linux-2.4.32/drivers/scsi/ahci.c linux-2.4.33-rc2/drivers/scsi/ahci.c --- linux-2.4.32/drivers/scsi/ahci.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/ahci.c 2006-06-21 10:40:43.000000000 -0300 @@ -1,26 +1,34 @@ /* * ahci.c - AHCI SATA support * - * Copyright 2004 Red Hat, Inc. + * Maintained by: Jeff Garzik + * Please ALWAYS copy linux-ide@vger.kernel.org + * on emails. * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. + * Copyright 2004-2005 Red Hat, Inc. * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. * - * Version 1.0 of the AHCI specification: + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * AHCI hardware documentation: * http://www.intel.com/technology/serialata/pdf/rev1_0.pdf + * http://www.intel.com/technology/serialata/pdf/rev1_1.pdf * */ @@ -38,7 +46,7 @@ #include #define DRV_NAME "ahci" -#define DRV_VERSION "1.01" +#define DRV_VERSION "1.2" enum { @@ -124,6 +132,7 @@ enum { PORT_IRQ_D2H_REG_FIS, /* PORT_CMD bits */ + PORT_CMD_ATAPI = (1 << 24), /* Device is ATAPI */ PORT_CMD_LIST_ON = (1 << 15), /* cmd list DMA engine running */ PORT_CMD_FIS_ON = (1 << 14), /* FIS DMA engine running */ PORT_CMD_FIS_RX = (1 << 4), /* Enable FIS receive DMA engine */ @@ -180,11 +189,9 @@ static void ahci_irq_clear(struct ata_po static void ahci_eng_timeout(struct ata_port *ap); static int ahci_port_start(struct ata_port *ap); static void ahci_port_stop(struct ata_port *ap); -static void ahci_host_stop(struct ata_host_set *host_set); static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); static void ahci_qc_prep(struct ata_queued_cmd *qc); static u8 ahci_check_status(struct ata_port *ap); -static u8 ahci_check_err(struct ata_port *ap); static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); static void ahci_remove_one (struct pci_dev *pdev); @@ -208,12 +215,11 @@ static Scsi_Host_Template ahci_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations ahci_ops = { +static const struct ata_port_operations ahci_ops = { .port_disable = ata_port_disable, .check_status = ahci_check_status, .check_altstatus = ahci_check_status, - .check_err = ahci_check_err, .dev_select = ata_noop_dev_select, .tf_read = ahci_tf_read, @@ -233,7 +239,6 @@ static struct ata_port_operations ahci_o .port_start = ahci_port_start, .port_stop = ahci_port_stop, - .host_stop = ahci_host_stop, }; static struct ata_port_info ahci_port_info[] = { @@ -243,13 +248,13 @@ static struct ata_port_info ahci_port_in .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | ATA_FLAG_PIO_DMA, - .pio_mask = 0x03, /* pio3-4 */ + .pio_mask = 0x1f, /* pio0-4 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ .port_ops = &ahci_ops, }, }; -static struct pci_device_id ahci_pci_tbl[] = { +static const struct pci_device_id ahci_pci_tbl[] = { { PCI_VENDOR_ID_INTEL, 0x2652, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_ahci }, /* ICH6 */ { PCI_VENDOR_ID_INTEL, 0x2653, PCI_ANY_ID, PCI_ANY_ID, 0, 0, @@ -268,6 +273,8 @@ static struct pci_device_id ahci_pci_tbl board_ahci }, /* ESB2 */ { PCI_VENDOR_ID_INTEL, 0x2683, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_ahci }, /* ESB2 */ + { PCI_VENDOR_ID_INTEL, 0x27c6, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_ahci }, /* ICH7-M DH */ { } /* terminate list */ }; @@ -285,17 +292,9 @@ static inline unsigned long ahci_port_ba return base + 0x100 + (port * 0x80); } -static inline void *ahci_port_base (void *base, unsigned int port) -{ - return (void *) ahci_port_base_ul((unsigned long)base, port); -} - -static void ahci_host_stop(struct ata_host_set *host_set) +static inline void __iomem *ahci_port_base (void __iomem *base, unsigned int port) { - struct ahci_host_priv *hpriv = host_set->private_data; - kfree(hpriv); - - ata_host_stop(host_set); + return (void __iomem *) ahci_port_base_ul((unsigned long)base, port); } static int ahci_port_start(struct ata_port *ap) @@ -303,17 +302,26 @@ static int ahci_port_start(struct ata_po struct device *dev = ap->host_set->dev; struct ahci_host_priv *hpriv = ap->host_set->private_data; struct ahci_port_priv *pp; - void *mem, *mmio = ap->host_set->mmio_base; - void *port_mmio = ahci_port_base(mmio, ap->port_no); + void __iomem *mmio = ap->host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); + void *mem; dma_addr_t mem_dma; + int rc; pp = kmalloc(sizeof(*pp), GFP_KERNEL); if (!pp) return -ENOMEM; memset(pp, 0, sizeof(*pp)); + rc = ata_pad_alloc(ap, dev); + if (rc) { + kfree(pp); + return rc; + } + mem = dma_alloc_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, &mem_dma, GFP_KERNEL); if (!mem) { + ata_pad_free(ap, dev); kfree(pp); return -ENOMEM; } @@ -372,8 +380,8 @@ static void ahci_port_stop(struct ata_po { struct device *dev = ap->host_set->dev; struct ahci_port_priv *pp = ap->private_data; - void *mmio = ap->host_set->mmio_base; - void *port_mmio = ahci_port_base(mmio, ap->port_no); + void __iomem *mmio = ap->host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); u32 tmp; tmp = readl(port_mmio + PORT_CMD); @@ -389,6 +397,7 @@ static void ahci_port_stop(struct ata_po ap->private_data = NULL; dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, pp->cmd_slot, pp->cmd_slot_dma); + ata_pad_free(ap, dev); kfree(pp); } @@ -405,7 +414,7 @@ static u32 ahci_scr_read (struct ata_por return 0xffffffffU; } - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -423,7 +432,7 @@ static void ahci_scr_write (struct ata_p return; } - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void ahci_phy_reset(struct ata_port *ap) @@ -431,7 +440,7 @@ static void ahci_phy_reset(struct ata_po void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; struct ata_taskfile tf; struct ata_device *dev = &ap->device[0]; - u32 tmp; + u32 new_tmp, tmp; __sata_phy_reset(ap); @@ -445,24 +454,30 @@ static void ahci_phy_reset(struct ata_po tf.nsect = (tmp) & 0xff; dev->class = ata_dev_classify(&tf); - if (!ata_dev_present(dev)) + if (!ata_dev_present(dev)) { ata_port_disable(ap); + return; + } + + /* Make sure port's ATAPI bit is set appropriately */ + new_tmp = tmp = readl(port_mmio + PORT_CMD); + if (dev->class == ATA_DEV_ATAPI) + new_tmp |= PORT_CMD_ATAPI; + else + new_tmp &= ~PORT_CMD_ATAPI; + if (new_tmp != tmp) { + writel(new_tmp, port_mmio + PORT_CMD); + readl(port_mmio + PORT_CMD); /* flush */ + } } static u8 ahci_check_status(struct ata_port *ap) { - void *mmio = (void *) ap->ioaddr.cmd_addr; + void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr; return readl(mmio + PORT_TFDATA) & 0xFF; } -static u8 ahci_check_err(struct ata_port *ap) -{ - void *mmio = (void *) ap->ioaddr.cmd_addr; - - return (readl(mmio + PORT_TFDATA) >> 8) & 0xFF; -} - static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ahci_port_priv *pp = ap->private_data; @@ -471,27 +486,32 @@ static void ahci_tf_read(struct ata_port ata_tf_from_fis(d2h_fis, tf); } -static void ahci_fill_sg(struct ata_queued_cmd *qc) +static unsigned int ahci_fill_sg(struct ata_queued_cmd *qc) { struct ahci_port_priv *pp = qc->ap->private_data; - unsigned int i; + struct scatterlist *sg; + struct ahci_sg *ahci_sg; + unsigned int n_sg = 0; VPRINTK("ENTER\n"); /* * Next, the S/G list. */ - for (i = 0; i < qc->n_elem; i++) { - u32 sg_len; - dma_addr_t addr; - - addr = sg_dma_address(&qc->sg[i]); - sg_len = sg_dma_len(&qc->sg[i]); - - pp->cmd_tbl_sg[i].addr = cpu_to_le32(addr & 0xffffffff); - pp->cmd_tbl_sg[i].addr_hi = cpu_to_le32((addr >> 16) >> 16); - pp->cmd_tbl_sg[i].flags_size = cpu_to_le32(sg_len - 1); + ahci_sg = pp->cmd_tbl_sg; + ata_for_each_sg(sg, qc) { + dma_addr_t addr = sg_dma_address(sg); + u32 sg_len = sg_dma_len(sg); + + ahci_sg->addr = cpu_to_le32(addr & 0xffffffff); + ahci_sg->addr_hi = cpu_to_le32((addr >> 16) >> 16); + ahci_sg->flags_size = cpu_to_le32(sg_len - 1); + + ahci_sg++; + n_sg++; } + + return n_sg; } static void ahci_qc_prep(struct ata_queued_cmd *qc) @@ -500,13 +520,14 @@ static void ahci_qc_prep(struct ata_queu struct ahci_port_priv *pp = ap->private_data; u32 opts; const u32 cmd_fis_len = 5; /* five dwords */ + unsigned int n_elem; /* * Fill in command slot information (currently only one slot, * slot 0, is currently since we don't do queueing) */ - opts = (qc->n_elem << 16) | cmd_fis_len; + opts = cmd_fis_len; if (qc->tf.flags & ATA_TFLAG_WRITE) opts |= AHCI_CMD_WRITE; if (is_atapi_taskfile(&qc->tf)) @@ -530,16 +551,31 @@ static void ahci_qc_prep(struct ata_queu if (!(qc->flags & ATA_QCFLAG_DMAMAP)) return; - ahci_fill_sg(qc); + n_elem = ahci_fill_sg(qc); + + pp->cmd_slot[0].opts |= cpu_to_le32(n_elem << 16); } -static void ahci_intr_error(struct ata_port *ap, u32 irq_stat) +static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) { - void *mmio = ap->host_set->mmio_base; - void *port_mmio = ahci_port_base(mmio, ap->port_no); + void __iomem *mmio = ap->host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); u32 tmp; int work; + if ((ap->device[0].class != ATA_DEV_ATAPI) || + ((irq_stat & PORT_IRQ_TF_ERR) == 0)) + printk(KERN_WARNING "ata%u: port reset, " + "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n", + ap->id, + irq_stat, + readl(mmio + HOST_IRQ_STAT), + readl(port_mmio + PORT_IRQ_STAT), + readl(port_mmio + PORT_CMD), + readl(port_mmio + PORT_TFDATA), + readl(port_mmio + PORT_SCR_STAT), + readl(port_mmio + PORT_SCR_ERR)); + /* stop DMA */ tmp = readl(port_mmio + PORT_CMD); tmp &= ~PORT_CMD_START; @@ -577,25 +613,27 @@ static void ahci_intr_error(struct ata_p tmp |= PORT_CMD_START; writel(tmp, port_mmio + PORT_CMD); readl(port_mmio + PORT_CMD); /* flush */ - - printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->id); } static void ahci_eng_timeout(struct ata_port *ap) { - void *mmio = ap->host_set->mmio_base; - void *port_mmio = ahci_port_base(mmio, ap->port_no); + struct ata_host_set *host_set = ap->host_set; + void __iomem *mmio = host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); struct ata_queued_cmd *qc; + unsigned long flags; - DPRINTK("ENTER\n"); + printk(KERN_WARNING "ata%u: handling error/timeout\n", ap->id); - ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT)); + spin_lock_irqsave(&host_set->lock, flags); qc = ata_qc_from_tag(ap, ap->active_tag); if (!qc) { printk(KERN_ERR "ata%u: BUG: timeout without command\n", ap->id); } else { + ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT)); + /* hack alert! We cannot use the supplied completion * function from inside the ->eh_strategy_handler() thread. * libata is the only user of ->eh_strategy_handler() in @@ -603,15 +641,16 @@ static void ahci_eng_timeout(struct ata_ * not being called from the SCSI EH. */ qc->scsidone = scsi_finish_command; - ata_qc_complete(qc, ATA_ERR); + ata_qc_complete(qc, AC_ERR_OTHER); } + spin_unlock_irqrestore(&host_set->lock, flags); } static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc) { - void *mmio = ap->host_set->mmio_base; - void *port_mmio = ahci_port_base(mmio, ap->port_no); + void __iomem *mmio = ap->host_set->mmio_base; + void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); u32 status, serr, ci; serr = readl(port_mmio + PORT_SCR_ERR); @@ -629,9 +668,19 @@ static inline int ahci_host_intr(struct } if (status & PORT_IRQ_FATAL) { - ahci_intr_error(ap, status); + unsigned int err_mask; + if (status & PORT_IRQ_TF_ERR) + err_mask = AC_ERR_DEV; + else if (status & PORT_IRQ_IF_ERR) + err_mask = AC_ERR_ATA_BUS; + else + err_mask = AC_ERR_HOST_BUS; + + /* command processing has stopped due to error; restart */ + ahci_restart_port(ap, status); + if (qc) - ata_qc_complete(qc, ATA_ERR); + ata_qc_complete(qc, err_mask); } return 1; @@ -647,7 +696,7 @@ static irqreturn_t ahci_interrupt (int i struct ata_host_set *host_set = dev_instance; struct ahci_host_priv *hpriv; unsigned int i, handled = 0; - void *mmio; + void __iomem *mmio; u32 irq_stat, irq_ack = 0; VPRINTK("ENTER\n"); @@ -665,17 +714,35 @@ static irqreturn_t ahci_interrupt (int i for (i = 0; i < host_set->n_ports; i++) { struct ata_port *ap; - u32 tmp; - VPRINTK("port %u\n", i); + if (!(irq_stat & (1 << i))) + continue; + ap = host_set->ports[i]; - tmp = irq_stat & (1 << i); - if (tmp && ap) { + if (ap) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); - if (ahci_host_intr(ap, qc)) - irq_ack |= (1 << i); + if (!ahci_host_intr(ap, qc)) + if (ata_ratelimit()) { + struct pci_dev *pdev = + to_pci_dev(ap->host_set->dev); + pdev_printk(KERN_WARNING, pdev, + "unhandled interrupt on port %u\n", + i); + } + + VPRINTK("port %u\n", i); + } else { + VPRINTK("port %u (no irq)\n", i); + if (ata_ratelimit()) { + struct pci_dev *pdev = + to_pci_dev(ap->host_set->dev); + pdev_printk(KERN_WARNING, pdev, + "interrupt on disabled port %u\n", i); + } } + + irq_ack |= (1 << i); } if (irq_ack) { @@ -693,10 +760,7 @@ static irqreturn_t ahci_interrupt (int i static int ahci_qc_issue(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - void *port_mmio = (void *) ap->ioaddr.cmd_addr; - - writel(1, port_mmio + PORT_SCR_ACT); - readl(port_mmio + PORT_SCR_ACT); /* flush */ + void __iomem *port_mmio = (void __iomem *) ap->ioaddr.cmd_addr; writel(1, port_mmio + PORT_CMD_ISSUE); readl(port_mmio + PORT_CMD_ISSUE); /* flush */ @@ -746,8 +810,8 @@ static int ahci_host_init(struct ata_pro tmp = readl(mmio + HOST_CTL); if (tmp & HOST_RESET) { - printk(KERN_ERR DRV_NAME "(%s): controller reset failed (0x%x)\n", - pci_name(pdev), tmp); + pdev_printk(KERN_ERR, pdev, + "controller reset failed (0x%x)\n", tmp); return -EIO; } @@ -771,12 +835,26 @@ static int ahci_host_init(struct ata_pro using_dac = hpriv->cap & HOST_CAP_64; if (using_dac && !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { - hpriv->flags |= HOST_CAP_64; + rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (rc) { + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + pdev_printk(KERN_ERR, pdev, + "64-bit DMA enable failed\n"); + return rc; + } + } } else { rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { - printk(KERN_ERR DRV_NAME "(%s): 32-bit DMA enable failed\n", - pci_name(pdev)); + pdev_printk(KERN_ERR, pdev, + "32-bit DMA enable failed\n"); + return rc; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + pdev_printk(KERN_ERR, pdev, + "32-bit consistent DMA enable failed\n"); return rc; } } @@ -847,27 +925,11 @@ static int ahci_host_init(struct ata_pro return 0; } -/* move to PCI layer, integrate w/ MSI stuff */ -static void pci_intx(struct pci_dev *pdev, int enable) -{ - u16 pci_command, new; - - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - - if (enable) - new = pci_command & ~PCI_COMMAND_INTX_DISABLE; - else - new = pci_command | PCI_COMMAND_INTX_DISABLE; - - if (new != pci_command) - pci_write_config_word(pdev, PCI_COMMAND, pci_command); -} - static void ahci_print_info(struct ata_probe_ent *probe_ent) { struct ahci_host_priv *hpriv = probe_ent->private_data; struct pci_dev *pdev = to_pci_dev(probe_ent->dev); - void *mmio = probe_ent->mmio_base; + void __iomem *mmio = probe_ent->mmio_base; u32 vers, cap, impl, speed; const char *speed_s; u16 cc; @@ -895,10 +957,10 @@ static void ahci_print_info(struct ata_p else scc_s = "unknown"; - printk(KERN_INFO DRV_NAME "(%s) AHCI %02x%02x.%02x%02x " + pdev_printk(KERN_INFO, pdev, + "AHCI %02x%02x.%02x%02x " "%u slots %u ports %s Gbps 0x%x impl %s mode\n" , - pci_name(pdev), (vers >> 24) & 0xff, (vers >> 16) & 0xff, @@ -911,11 +973,11 @@ static void ahci_print_info(struct ata_p impl, scc_s); - printk(KERN_INFO DRV_NAME "(%s) flags: " + pdev_printk(KERN_INFO, pdev, + "flags: " "%s%s%s%s%s%s" "%s%s%s%s%s%s%s\n" , - pci_name(pdev), cap & (1 << 31) ? "64bit " : "", cap & (1 << 30) ? "ncq " : "", @@ -940,7 +1002,7 @@ static int ahci_init_one (struct pci_dev struct ata_probe_ent *probe_ent = NULL; struct ahci_host_priv *hpriv; unsigned long base; - void *mmio_base; + void __iomem *mmio_base; unsigned int board_idx = (unsigned int) ent->driver_data; int have_msi, pci_dev_busy = 0; int rc; @@ -948,7 +1010,7 @@ static int ahci_init_one (struct pci_dev VPRINTK("ENTER\n"); if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + pdev_printk(KERN_DEBUG, pdev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) @@ -977,8 +1039,7 @@ static int ahci_init_one (struct pci_dev probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = ioremap(pci_resource_start(pdev, AHCI_PCI_BAR), - pci_resource_len(pdev, AHCI_PCI_BAR)); + mmio_base = pci_iomap(pdev, AHCI_PCI_BAR, 0); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_free_ent; @@ -1020,7 +1081,7 @@ static int ahci_init_one (struct pci_dev err_out_hpriv: kfree(hpriv); err_out_iounmap: - iounmap(mmio_base); + pci_iounmap(pdev, mmio_base); err_out_free_ent: kfree(probe_ent); err_out_msi: @@ -1056,7 +1117,8 @@ static void ahci_remove_one (struct pci_ have_msi = hpriv->flags & AHCI_FLAG_MSI; free_irq(host_set->irq, host_set); - host_set->ops->host_stop(host_set); + kfree(hpriv); + pci_iounmap(pdev, host_set->mmio_base); kfree(host_set); if (have_msi) @@ -1101,6 +1163,7 @@ MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("AHCI SATA low-level driver"); MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, ahci_pci_tbl); +MODULE_VERSION(DRV_VERSION); module_init(ahci_init); module_exit(ahci_exit); diff -Nur -p linux-2.4.32/drivers/scsi/aic7xxx/aic7xxx_osm.c linux-2.4.33-rc2/drivers/scsi/aic7xxx/aic7xxx_osm.c --- linux-2.4.32/drivers/scsi/aic7xxx/aic7xxx_osm.c 2003-11-28 16:26:20.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/aic7xxx/aic7xxx_osm.c 2006-06-21 10:40:43.000000000 -0300 @@ -4826,7 +4826,7 @@ ahc_linux_queue_recovery_cmd(Scsi_Cmnd * if (ahc_match_scb(ahc, pending_scb, cmd->device->id, cmd->device->channel + 'A', CAM_LUN_WILDCARD, - SCB_LIST_NULL, ROLE_INITIATOR) == 0) + SCB_LIST_NULL, ROLE_INITIATOR)) break; } } diff -Nur -p linux-2.4.32/drivers/scsi/ata_piix.c linux-2.4.33-rc2/drivers/scsi/ata_piix.c --- linux-2.4.32/drivers/scsi/ata_piix.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/ata_piix.c 2006-06-21 10:40:43.000000000 -0300 @@ -1,24 +1,42 @@ /* - - ata_piix.c - Intel PATA/SATA controllers - - Maintained by: Jeff Garzik - Please ALWAYS copy linux-ide@vger.kernel.org - on emails. - - - Copyright 2003-2004 Red Hat Inc - Copyright 2003-2004 Jeff Garzik - - - Copyright header from piix.c: - - Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer - Copyright (C) 1998-2000 Andre Hedrick - Copyright (C) 2003 Red Hat Inc - - May be copied or modified under the terms of the GNU General Public License - + * ata_piix.c - Intel PATA/SATA controllers + * + * Maintained by: Jeff Garzik + * Please ALWAYS copy linux-ide@vger.kernel.org + * on emails. + * + * + * Copyright 2003-2005 Red Hat Inc + * Copyright 2003-2005 Jeff Garzik + * + * + * Copyright header from piix.c: + * + * Copyright (C) 1998-1999 Andrzej Krzysztofowicz, Author and Maintainer + * Copyright (C) 1998-2000 Andre Hedrick + * Copyright (C) 2003 Red Hat Inc + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware documentation available at http://developer.intel.com/ + * */ #include @@ -32,12 +50,13 @@ #include #define DRV_NAME "ata_piix" -#define DRV_VERSION "1.03" +#define DRV_VERSION "1.05" enum { PIIX_IOCFG = 0x54, /* IDE I/O configuration register */ ICH5_PMR = 0x90, /* port mapping register */ ICH5_PCS = 0x92, /* port control and status */ + PIIX_SCC = 0x0A, /* sub-class code register */ PIIX_FLAG_AHCI = (1 << 28), /* AHCI possible */ PIIX_FLAG_CHECKINTR = (1 << 29), /* make sure PCI INTx enabled */ @@ -49,8 +68,8 @@ enum { PIIX_COMB_PATA_P0 = (1 << 1), PIIX_COMB = (1 << 2), /* combined mode enabled? */ - PIIX_PORT_PRESENT = (1 << 0), - PIIX_PORT_ENABLED = (1 << 4), + PIIX_PORT_ENABLED = (1 << 0), + PIIX_PORT_PRESENT = (1 << 4), PIIX_80C_PRI = (1 << 5) | (1 << 4), PIIX_80C_SEC = (1 << 7) | (1 << 6), @@ -62,6 +81,8 @@ enum { ich6_sata_rm = 4, ich7_sata = 5, esb2_sata = 6, + + PIIX_AHCI_DEVICE = 6, }; static int piix_init_one (struct pci_dev *pdev, @@ -74,7 +95,7 @@ static void piix_set_dmamode (struct ata static unsigned int in_module_init = 1; -static struct pci_device_id piix_pci_tbl[] = { +static const struct pci_device_id piix_pci_tbl[] = { #ifdef ATA_ENABLE_PATA { 0x8086, 0x7111, PCI_ANY_ID, PCI_ANY_ID, 0, 0, piix4_pata }, { 0x8086, 0x24db, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich5_pata }, @@ -126,7 +147,7 @@ static Scsi_Host_Template piix_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations piix_pata_ops = { +static const struct ata_port_operations piix_pata_ops = { .port_disable = ata_port_disable, .set_piomode = piix_set_piomode, .set_dmamode = piix_set_dmamode, @@ -156,7 +177,7 @@ static struct ata_port_operations piix_p .host_stop = ata_host_stop, }; -static struct ata_port_operations piix_sata_ops = { +static const struct ata_port_operations piix_sata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -356,7 +377,9 @@ static void piix_pata_phy_reset(struct a * None (inherited from caller). * * RETURNS: - * Non-zero if device detected, zero otherwise. + * Non-zero if port is enabled, it may or may not have a device + * attached in that case (PRESENT bit would only be set if BIOS probe + * was done). Zero is returned if port is disabled. */ static int piix_sata_probe (struct ata_port *ap) { @@ -380,7 +403,7 @@ static int piix_sata_probe (struct ata_p */ for (i = 0; i < 4; i++) { - mask = (PIIX_PORT_PRESENT << i) | (PIIX_PORT_ENABLED << i); + mask = (PIIX_PORT_ENABLED << i); if ((orig_mask & mask) == mask) if (combined || (i == ap->hard_port_no)) @@ -419,7 +442,6 @@ static void piix_sata_phy_reset(struct a * piix_set_piomode - Initialize host controller PATA PIO timings * @ap: Port whose timings we are configuring * @adev: um - * @pio: PIO mode, 0 - 4 * * Set PIO mode for device, in host controller PCI config space. * @@ -545,25 +567,12 @@ static void piix_set_dmamode (struct ata } } -/* move to PCI layer, integrate w/ MSI stuff */ -static void pci_enable_intx(struct pci_dev *pdev) -{ - u16 pci_command; - - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - if (pci_command & PCI_COMMAND_INTX_DISABLE) { - pci_command &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(pdev, PCI_COMMAND, pci_command); - } -} - #define AHCI_PCI_BAR 5 #define AHCI_GLOBAL_CTL 0x04 #define AHCI_ENABLE (1 << 31) static int piix_disable_ahci(struct pci_dev *pdev) { - void *mmio; - unsigned long addr; + void __iomem *mmio; u32 tmp; int rc = 0; @@ -571,14 +580,14 @@ static int piix_disable_ahci(struct pci_ * works because this device is usually set up by BIOS. */ - addr = pci_resource_start(pdev, AHCI_PCI_BAR); - if (!addr || !pci_resource_len(pdev, AHCI_PCI_BAR)) + if (!pci_resource_start(pdev, AHCI_PCI_BAR) || + !pci_resource_len(pdev, AHCI_PCI_BAR)) return 0; - - mmio = ioremap(addr, 64); + + mmio = pci_iomap(pdev, AHCI_PCI_BAR, 64); if (!mmio) return -ENOMEM; - + tmp = readl(mmio + AHCI_GLOBAL_CTL); if (tmp & AHCI_ENABLE) { tmp &= ~AHCI_ENABLE; @@ -588,8 +597,8 @@ static int piix_disable_ahci(struct pci_ if (tmp & AHCI_ENABLE) rc = -EIO; } - - iounmap(mmio); + + pci_iounmap(pdev, mmio); return rc; } @@ -612,23 +621,28 @@ static int piix_init_one (struct pci_dev { static int printed_version; struct ata_port_info *port_info[2]; - unsigned int combined = 0, n_ports = 1; + unsigned int combined = 0; unsigned int pata_chan = 0, sata_chan = 0; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + pdev_printk(KERN_DEBUG, pdev, + "version " DRV_VERSION "\n"); /* no hotplugging support (FIXME) */ if (!in_module_init) return -ENODEV; port_info[0] = &piix_port_info[ent->driver_data]; - port_info[1] = NULL; + port_info[1] = &piix_port_info[ent->driver_data]; if (port_info[0]->host_flags & PIIX_FLAG_AHCI) { - int rc = piix_disable_ahci(pdev); - if (rc) - return rc; + u8 tmp; + pci_read_config_byte(pdev, PIIX_SCC, &tmp); + if (tmp == PIIX_AHCI_DEVICE) { + int rc = piix_disable_ahci(pdev); + if (rc) + return rc; + } } if (port_info[0]->host_flags & PIIX_FLAG_COMBINED) { @@ -651,19 +665,19 @@ static int piix_init_one (struct pci_dev * message-signalled interrupts currently). */ if (port_info[0]->host_flags & PIIX_FLAG_CHECKINTR) - pci_enable_intx(pdev); + pci_intx(pdev, 1); if (combined) { port_info[sata_chan] = &piix_port_info[ent->driver_data]; port_info[sata_chan]->host_flags |= ATA_FLAG_SLAVE_POSS; port_info[pata_chan] = &piix_port_info[ich5_pata]; - n_ports++; - printk(KERN_ERR DRV_NAME ": combined mode not supported\n"); - return -ENODEV; + pdev_printk(KERN_WARNING, pdev, + "combined mode detected (p=%u, s=%u)\n", + pata_chan, sata_chan); } - return ata_pci_init_one(pdev, port_info, n_ports); + return ata_pci_init_one(pdev, port_info, 2); } static int __init piix_init(void) diff -Nur -p linux-2.4.32/drivers/scsi/dpt_i2o.c linux-2.4.33-rc2/drivers/scsi/dpt_i2o.c --- linux-2.4.32/drivers/scsi/dpt_i2o.c 2005-01-19 12:10:02.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/dpt_i2o.c 2006-06-21 10:40:43.000000000 -0300 @@ -807,7 +807,7 @@ static int adpt_hba_reset(adpt_hba* pHba static void adpt_i2o_sys_shutdown(void) { adpt_hba *pHba, *pNext; - struct adpt_i2o_post_wait_data *p1, *p2; + struct adpt_i2o_post_wait_data *p1, *old; printk(KERN_INFO"Shutting down Adaptec I2O controllers.\n"); printk(KERN_INFO" This could take a few minutes if there are many devices attached\n"); @@ -821,13 +821,14 @@ static void adpt_i2o_sys_shutdown(void) } /* Remove any timedout entries from the wait queue. */ - p2 = NULL; // spin_lock_irqsave(&adpt_post_wait_lock, flags); /* Nothing should be outstanding at this point so just * free them */ - for(p1 = adpt_post_wait_queue; p1; p2 = p1, p1 = p2->next) { - kfree(p1); + for(p1 = adpt_post_wait_queue; p1;) { + old = p1; + p1 = p1->next; + kfree(old); } // spin_unlock_irqrestore(&adpt_post_wait_lock, flags); adpt_post_wait_queue = 0; diff -Nur -p linux-2.4.32/drivers/scsi/libata-core.c linux-2.4.33-rc2/drivers/scsi/libata-core.c --- linux-2.4.32/drivers/scsi/libata-core.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/libata-core.c 2006-06-21 10:40:43.000000000 -0300 @@ -1,25 +1,35 @@ /* - libata-core.c - helper library for ATA - - Copyright 2003-2004 Red Hat, Inc. All rights reserved. - Copyright 2003-2004 Jeff Garzik - - The contents of this file are subject to the Open - Software License version 1.1 that can be found at - http://www.opensource.org/licenses/osl-1.1.txt and is included herein - by reference. - - Alternatively, the contents of this file may be used under the terms - of the GNU General Public License version 2 (the "GPL") as distributed - in the kernel source COPYING file, in which case the provisions of - the GPL are applicable instead of the above. If you wish to allow - the use of your version of this file only under the terms of the - GPL and not to allow others to use your version of this file under - the OSL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the GPL. - If you do not delete the provisions above, a recipient may use your - version of this file under either the OSL or the GPL. - + * libata-core.c - helper library for ATA + * + * Maintained by: Jeff Garzik + * Please ALWAYS copy linux-ide@vger.kernel.org + * on emails. + * + * Copyright 2003-2004 Red Hat, Inc. All rights reserved. + * Copyright 2003-2004 Jeff Garzik + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware documentation available from http://www.t13.org/ and + * http://www.sata-io.org/ + * */ #include @@ -50,27 +60,32 @@ static unsigned int ata_busy_sleep (struct ata_port *ap, unsigned long tmout_pat, unsigned long tmout); +static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev); +static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev); static void ata_set_mode(struct ata_port *ap); static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); -static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); +static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift); static int fgb(u32 bitmap); -static int ata_choose_xfer_mode(struct ata_port *ap, +static int ata_choose_xfer_mode(const struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out); -static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); static void __ata_qc_complete(struct ata_queued_cmd *qc); static unsigned int ata_unique_id = 1; static LIST_HEAD(ata_probe_list); static spinlock_t ata_module_lock = SPIN_LOCK_UNLOCKED; +int atapi_enabled = 0; +MODULE_PARM(atapi_enabled, "i"); +MODULE_PARM_DESC(atapi_enabled, "Enable discovery of ATAPI devices (0=off, 1=on)"); + MODULE_AUTHOR("Jeff Garzik"); MODULE_DESCRIPTION("Library module for ATA devices"); MODULE_LICENSE("GPL"); MODULE_VERSION(DRV_VERSION); /** - * ata_tf_load - send taskfile registers to host controller + * ata_tf_load_pio - send taskfile registers to host controller * @ap: Port to which output is sent * @tf: ATA taskfile register set * @@ -80,7 +95,7 @@ MODULE_VERSION(DRV_VERSION); * Inherited from caller. */ -static void ata_tf_load_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_pio(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -138,7 +153,7 @@ static void ata_tf_load_pio(struct ata_p * Inherited from caller. */ -static void ata_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -207,7 +222,7 @@ static void ata_tf_load_mmio(struct ata_ * LOCKING: * Inherited from caller. */ -void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { if (ap->flags & ATA_FLAG_MMIO) ata_tf_load_mmio(ap, tf); @@ -227,7 +242,7 @@ void ata_tf_load(struct ata_port *ap, st * spin_lock_irqsave(host_set lock) */ -static void ata_exec_command_pio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_pio(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -248,7 +263,7 @@ static void ata_exec_command_pio(struct * spin_lock_irqsave(host_set lock) */ -static void ata_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void ata_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); @@ -268,7 +283,7 @@ static void ata_exec_command_mmio(struct * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf) +void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf) { if (ap->flags & ATA_FLAG_MMIO) ata_exec_command_mmio(ap, tf); @@ -277,28 +292,6 @@ void ata_exec_command(struct ata_port *a } /** - * ata_exec - issue ATA command to host controller - * @ap: port to which command is being issued - * @tf: ATA taskfile register set - * - * Issues PIO/MMIO write to ATA command register, with proper - * synchronization with interrupt handler / other threads. - * - * LOCKING: - * Obtains host_set lock. - */ - -static inline void ata_exec(struct ata_port *ap, struct ata_taskfile *tf) -{ - unsigned long flags; - - DPRINTK("ata%u: cmd 0x%X\n", ap->id, tf->command); - spin_lock_irqsave(&ap->host_set->lock, flags); - ap->ops->exec_command(ap, tf); - spin_unlock_irqrestore(&ap->host_set->lock, flags); -} - -/** * ata_tf_to_host - issue ATA taskfile to host controller * @ap: port to which command is being issued * @tf: ATA taskfile register set @@ -308,30 +301,11 @@ static inline void ata_exec(struct ata_p * other threads. * * LOCKING: - * Obtains host_set lock. - */ - -static void ata_tf_to_host(struct ata_port *ap, struct ata_taskfile *tf) -{ - ap->ops->tf_load(ap, tf); - - ata_exec(ap, tf); -} - -/** - * ata_tf_to_host_nolock - issue ATA taskfile to host controller - * @ap: port to which command is being issued - * @tf: ATA taskfile register set - * - * Issues ATA taskfile register set to ATA host controller, - * with proper synchronization with interrupt handler and - * other threads. - * - * LOCKING: * spin_lock_irqsave(host_set lock) */ -void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf) +static inline void ata_tf_to_host(struct ata_port *ap, + const struct ata_taskfile *tf) { ap->ops->tf_load(ap, tf); ap->ops->exec_command(ap, tf); @@ -353,6 +327,8 @@ static void ata_tf_read_pio(struct ata_p { struct ata_ioports *ioaddr = &ap->ioaddr; + tf->command = ata_check_status(ap); + tf->feature = inb(ioaddr->error_addr); tf->nsect = inb(ioaddr->nsect_addr); tf->lbal = inb(ioaddr->lbal_addr); tf->lbam = inb(ioaddr->lbam_addr); @@ -385,6 +361,8 @@ static void ata_tf_read_mmio(struct ata_ { struct ata_ioports *ioaddr = &ap->ioaddr; + tf->command = ata_check_status(ap); + tf->feature = readb((void __iomem *)ioaddr->error_addr); tf->nsect = readb((void __iomem *)ioaddr->nsect_addr); tf->lbal = readb((void __iomem *)ioaddr->lbal_addr); tf->lbam = readb((void __iomem *)ioaddr->lbam_addr); @@ -505,30 +483,6 @@ u8 ata_altstatus(struct ata_port *ap) /** - * ata_chk_err - Read device error reg - * @ap: port where the device is - * - * Reads ATA taskfile error register for - * currently-selected device and return its value. - * - * Note: may NOT be used as the check_err() entry in - * ata_port_operations. - * - * LOCKING: - * Inherited from caller. - */ -u8 ata_chk_err(struct ata_port *ap) -{ - if (ap->ops->check_err) - return ap->ops->check_err(ap); - - if (ap->flags & ATA_FLAG_MMIO) { - return readb((void __iomem *) ap->ioaddr.error_addr); - } - return inb(ap->ioaddr.error_addr); -} - -/** * ata_tf_to_fis - Convert ATA taskfile to SATA FIS structure * @tf: Taskfile to convert * @fis: Buffer into which data will output @@ -541,7 +495,7 @@ u8 ata_chk_err(struct ata_port *ap) * Inherited from caller. */ -void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp) +void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp) { fis[0] = 0x27; /* Register - Host to Device FIS */ fis[1] = (pmp & 0xf) | (1 << 7); /* Port multiplier number, @@ -575,14 +529,13 @@ void ata_tf_to_fis(struct ata_taskfile * * @fis: Buffer from which data will be input * @tf: Taskfile to output * - * Converts a standard ATA taskfile to a Serial ATA - * FIS structure (Register - Host to Device). + * Converts a serial ATA FIS structure to a standard ATA taskfile. * * LOCKING: * Inherited from caller. */ -void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf) +void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf) { tf->command = fis[2]; /* status */ tf->feature = fis[3]; /* error */ @@ -600,79 +553,53 @@ void ata_tf_from_fis(u8 *fis, struct ata tf->hob_nsect = fis[13]; } -/** - * ata_prot_to_cmd - determine which read/write opcodes to use - * @protocol: ATA_PROT_xxx taskfile protocol - * @lba48: true is lba48 is present - * - * Given necessary input, determine which read/write commands - * to use to transfer data. - * - * LOCKING: - * None. - */ -static int ata_prot_to_cmd(int protocol, int lba48) -{ - int rcmd = 0, wcmd = 0; - - switch (protocol) { - case ATA_PROT_PIO: - if (lba48) { - rcmd = ATA_CMD_PIO_READ_EXT; - wcmd = ATA_CMD_PIO_WRITE_EXT; - } else { - rcmd = ATA_CMD_PIO_READ; - wcmd = ATA_CMD_PIO_WRITE; - } - break; - - case ATA_PROT_DMA: - if (lba48) { - rcmd = ATA_CMD_READ_EXT; - wcmd = ATA_CMD_WRITE_EXT; - } else { - rcmd = ATA_CMD_READ; - wcmd = ATA_CMD_WRITE; - } - break; - - default: - return -1; - } - - return rcmd | (wcmd << 8); -} +static const u8 ata_rw_cmds[] = { + /* pio multi */ + ATA_CMD_READ_MULTI, + ATA_CMD_WRITE_MULTI, + ATA_CMD_READ_MULTI_EXT, + ATA_CMD_WRITE_MULTI_EXT, + /* pio */ + ATA_CMD_PIO_READ, + ATA_CMD_PIO_WRITE, + ATA_CMD_PIO_READ_EXT, + ATA_CMD_PIO_WRITE_EXT, + /* dma */ + ATA_CMD_READ, + ATA_CMD_WRITE, + ATA_CMD_READ_EXT, + ATA_CMD_WRITE_EXT +}; /** - * ata_dev_set_protocol - set taskfile protocol and r/w commands - * @dev: device to examine and configure + * ata_rwcmd_protocol - set taskfile r/w commands and protocol + * @qc: command to examine and configure * - * Examine the device configuration, after we have - * read the identify-device page and configured the - * data transfer mode. Set internal state related to - * the ATA taskfile protocol (pio, pio mult, dma, etc.) - * and calculate the proper read/write commands to use. + * Examine the device configuration and tf->flags to calculate + * the proper read/write commands and protocol to use. * * LOCKING: * caller. */ -static void ata_dev_set_protocol(struct ata_device *dev) +void ata_rwcmd_protocol(struct ata_queued_cmd *qc) { - int pio = (dev->flags & ATA_DFLAG_PIO); - int lba48 = (dev->flags & ATA_DFLAG_LBA48); - int proto, cmd; + struct ata_taskfile *tf = &qc->tf; + struct ata_device *dev = qc->dev; - if (pio) - proto = dev->xfer_protocol = ATA_PROT_PIO; - else - proto = dev->xfer_protocol = ATA_PROT_DMA; + int index, lba48, write; + + lba48 = (tf->flags & ATA_TFLAG_LBA48) ? 2 : 0; + write = (tf->flags & ATA_TFLAG_WRITE) ? 1 : 0; - cmd = ata_prot_to_cmd(proto, lba48); - if (cmd < 0) - BUG(); + if (dev->flags & ATA_DFLAG_PIO) { + tf->protocol = ATA_PROT_PIO; + index = dev->multi_count ? 0 : 4; + } else { + tf->protocol = ATA_PROT_DMA; + index = 8; + } - dev->read_cmd = cmd & 0xff; - dev->write_cmd = (cmd >> 8) & 0xff; + tf->command = ata_rw_cmds[index + lba48 + write]; } static const char * xfer_mode_str[] = { @@ -854,7 +781,7 @@ static unsigned int ata_devchk(struct at * the event of failure. */ -unsigned int ata_dev_classify(struct ata_taskfile *tf) +unsigned int ata_dev_classify(const struct ata_taskfile *tf) { /* Apple's open source Darwin code hints that some devices only * put a proper signature into the LBA mid/high registers, @@ -906,8 +833,8 @@ static u8 ata_dev_try_classify(struct at memset(&tf, 0, sizeof(tf)); - err = ata_chk_err(ap); ap->ops->tf_read(ap, &tf); + err = tf.feature; dev->class = ATA_DEV_NONE; @@ -946,7 +873,7 @@ static u8 ata_dev_try_classify(struct at * caller. */ -void ata_dev_id_string(u16 *id, unsigned char *s, +void ata_dev_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len) { unsigned int c; @@ -1063,7 +990,7 @@ void ata_dev_select(struct ata_port *ap, * caller. */ -static inline void ata_dump_id(struct ata_device *dev) +static inline void ata_dump_id(const struct ata_device *dev) { DPRINTK("49==0x%04x " "53==0x%04x " @@ -1091,6 +1018,41 @@ static inline void ata_dump_id(struct at dev->id[93]); } +/* + * Compute the PIO modes available for this device. This is not as + * trivial as it seems if we must consider early devices correctly. + * + * FIXME: pre IDE drive timing (do we care ?). + */ + +static unsigned int ata_pio_modes(const struct ata_device *adev) +{ + u16 modes; + + /* Usual case. Word 53 indicates word 88 is valid */ + if (adev->id[ATA_ID_FIELD_VALID] & (1 << 2)) { + modes = adev->id[ATA_ID_PIO_MODES] & 0x03; + modes <<= 3; + modes |= 0x7; + return modes; + } + + /* If word 88 isn't valid then Word 51 holds the PIO timing number + for the maximum. Turn it into a mask and return it */ + modes = (2 << (adev->id[ATA_ID_OLD_PIO_MODES] & 0xFF)) - 1 ; + return modes; +} + +static int ata_qc_wait_err(struct ata_queued_cmd *qc, + struct completion *wait) +{ + int rc = 0; + + wait_for_completion(wait); + + return rc; +} + /** * ata_dev_identify - obtain IDENTIFY x DEVICE page * @ap: port on which device we wish to probe resides @@ -1116,10 +1078,9 @@ static inline void ata_dump_id(struct at static void ata_dev_identify(struct ata_port *ap, unsigned int device) { struct ata_device *dev = &ap->device[device]; - unsigned int i; + unsigned int major_version; u16 tmp; unsigned long xfer_modes; - u8 status; unsigned int using_edd; DECLARE_COMPLETION(wait); struct ata_queued_cmd *qc; @@ -1171,10 +1132,13 @@ retry: if (rc) goto err_out; else - wait_for_completion(&wait); + ata_qc_wait_err(qc, &wait); - status = ata_chk_status(ap); - if (status & ATA_ERR) { + spin_lock_irqsave(&ap->host_set->lock, flags); + ap->ops->tf_read(ap, &qc->tf); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (qc->tf.command & ATA_ERR) { /* * arg! EDD works for all test cases, but seems to return * the ATA signature for some ATAPI devices. Until the @@ -1186,8 +1150,8 @@ retry: * ATA software reset (SRST, the default) does not appear * to have this problem. */ - if ((using_edd) && (qc->tf.command == ATA_CMD_ID_ATA)) { - u8 err = ata_chk_err(ap); + if ((using_edd) && (dev->class == ATA_DEV_ATA)) { + u8 err = qc->tf.feature; if (err & ATA_ABORTED) { dev->class = ATA_DEV_ATAPI; qc->cursg = 0; @@ -1214,9 +1178,9 @@ retry: * common ATA, ATAPI feature tests */ - /* we require LBA and DMA support (bits 8 & 9 of word 49) */ - if (!ata_id_has_dma(dev->id) || !ata_id_has_lba(dev->id)) { - printk(KERN_DEBUG "ata%u: no dma/lba\n", ap->id); + /* we require DMA support (bits 8 of word 49) */ + if (!ata_id_has_dma(dev->id)) { + printk(KERN_DEBUG "ata%u: no dma\n", ap->id); goto err_out_nosup; } @@ -1224,10 +1188,8 @@ retry: xfer_modes = dev->id[ATA_ID_UDMA_MODES]; if (!xfer_modes) xfer_modes = (dev->id[ATA_ID_MWDMA_MODES]) << ATA_SHIFT_MWDMA; - if (!xfer_modes) { - xfer_modes = (dev->id[ATA_ID_PIO_MODES]) << (ATA_SHIFT_PIO + 3); - xfer_modes |= (0x7 << ATA_SHIFT_PIO); - } + if (!xfer_modes) + xfer_modes = ata_pio_modes(dev); ata_dump_id(dev); @@ -1236,36 +1198,79 @@ retry: if (!ata_id_is_ata(dev->id)) /* sanity check */ goto err_out_nosup; + /* get major version */ tmp = dev->id[ATA_ID_MAJOR_VER]; - for (i = 14; i >= 1; i--) - if (tmp & (1 << i)) + for (major_version = 14; major_version >= 1; major_version--) + if (tmp & (1 << major_version)) break; - /* we require at least ATA-3 */ - if (i < 3) { - printk(KERN_DEBUG "ata%u: no ATA-3\n", ap->id); - goto err_out_nosup; + /* + * The exact sequence expected by certain pre-ATA4 drives is: + * SRST RESET + * IDENTIFY + * INITIALIZE DEVICE PARAMETERS + * anything else.. + * Some drives were very specific about that exact sequence. + */ + if (major_version < 4 || (!ata_id_has_lba(dev->id))) { + ata_dev_init_params(ap, dev); + + /* current CHS translation info (id[53-58]) might be + * changed. reread the identify device info. + */ + ata_dev_reread_id(ap, dev); } - if (ata_id_has_lba48(dev->id)) { - dev->flags |= ATA_DFLAG_LBA48; - dev->n_sectors = ata_id_u64(dev->id, 100); - } else { - dev->n_sectors = ata_id_u32(dev->id, 60); + if (ata_id_has_lba(dev->id)) { + dev->flags |= ATA_DFLAG_LBA; + + if (ata_id_has_lba48(dev->id)) { + dev->flags |= ATA_DFLAG_LBA48; + dev->n_sectors = ata_id_u64(dev->id, 100); + } else { + dev->n_sectors = ata_id_u32(dev->id, 60); + } + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n", + ap->id, device, + major_version, + ata_mode_string(xfer_modes), + (unsigned long long)dev->n_sectors, + dev->flags & ATA_DFLAG_LBA48 ? " LBA48" : " LBA"); + } else { + /* CHS */ + + /* Default translation */ + dev->cylinders = dev->id[1]; + dev->heads = dev->id[3]; + dev->sectors = dev->id[6]; + dev->n_sectors = dev->cylinders * dev->heads * dev->sectors; + + if (ata_id_current_chs_valid(dev->id)) { + /* Current CHS translation is valid. */ + dev->cylinders = dev->id[54]; + dev->heads = dev->id[55]; + dev->sectors = dev->id[56]; + + dev->n_sectors = ata_id_u32(dev->id, 57); + } + + /* print device info to dmesg */ + printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors: CHS %d/%d/%d\n", + ap->id, device, + major_version, + ata_mode_string(xfer_modes), + (unsigned long long)dev->n_sectors, + (int)dev->cylinders, (int)dev->heads, (int)dev->sectors); + } ap->host->max_cmd_len = 16; - - /* print device info to dmesg */ - printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", - ap->id, device, - ata_mode_string(xfer_modes), - (unsigned long long)dev->n_sectors, - dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); } /* ATAPI-specific feature tests */ - else { + else if (dev->class == ATA_DEV_ATAPI) { if (ata_id_is_ata(dev->id)) /* sanity check */ goto err_out_nosup; @@ -1295,7 +1300,7 @@ err_out: } -static inline u8 ata_dev_knobble(struct ata_port *ap) +static inline u8 ata_dev_knobble(const struct ata_port *ap) { return ((ap->cbl == ATA_CBL_SATA) && (!ata_id_is_sata(ap->device->id))); } @@ -1303,12 +1308,12 @@ static inline u8 ata_dev_knobble(struct /** * ata_dev_config - Run device specific handlers and check for * SATA->PATA bridges - * @ap: Bus + * @ap: Bus * @i: Device * * LOCKING: */ - + void ata_dev_config(struct ata_port *ap, unsigned int i) { /* limit bridge transfers to udma5, 200 sectors */ @@ -1481,7 +1486,155 @@ void ata_port_disable(struct ata_port *a ap->flags |= ATA_FLAG_PORT_DISABLED; } -static struct { +/* + * This mode timing computation functionality is ported over from + * drivers/ide/ide-timing.h and was originally written by Vojtech Pavlik + */ +/* + * PIO 0-5, MWDMA 0-2 and UDMA 0-6 timings (in nanoseconds). + * These were taken from ATA/ATAPI-6 standard, rev 0a, except + * for PIO 5, which is a nonstandard extension and UDMA6, which + * is currently supported only by Maxtor drives. + */ + +static const struct ata_timing ata_timing[] = { + + { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, + { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, + { XFER_UDMA_4, 0, 0, 0, 0, 0, 0, 0, 30 }, + { XFER_UDMA_3, 0, 0, 0, 0, 0, 0, 0, 45 }, + + { XFER_UDMA_2, 0, 0, 0, 0, 0, 0, 0, 60 }, + { XFER_UDMA_1, 0, 0, 0, 0, 0, 0, 0, 80 }, + { XFER_UDMA_0, 0, 0, 0, 0, 0, 0, 0, 120 }, + +/* { XFER_UDMA_SLOW, 0, 0, 0, 0, 0, 0, 0, 150 }, */ + + { XFER_MW_DMA_2, 25, 0, 0, 0, 70, 25, 120, 0 }, + { XFER_MW_DMA_1, 45, 0, 0, 0, 80, 50, 150, 0 }, + { XFER_MW_DMA_0, 60, 0, 0, 0, 215, 215, 480, 0 }, + + { XFER_SW_DMA_2, 60, 0, 0, 0, 120, 120, 240, 0 }, + { XFER_SW_DMA_1, 90, 0, 0, 0, 240, 240, 480, 0 }, + { XFER_SW_DMA_0, 120, 0, 0, 0, 480, 480, 960, 0 }, + +/* { XFER_PIO_5, 20, 50, 30, 100, 50, 30, 100, 0 }, */ + { XFER_PIO_4, 25, 70, 25, 120, 70, 25, 120, 0 }, + { XFER_PIO_3, 30, 80, 70, 180, 80, 70, 180, 0 }, + + { XFER_PIO_2, 30, 290, 40, 330, 100, 90, 240, 0 }, + { XFER_PIO_1, 50, 290, 93, 383, 125, 100, 383, 0 }, + { XFER_PIO_0, 70, 290, 240, 600, 165, 150, 600, 0 }, + +/* { XFER_PIO_SLOW, 120, 290, 240, 960, 290, 240, 960, 0 }, */ + + { 0xFF } +}; + +#define ENOUGH(v,unit) (((v)-1)/(unit)+1) +#define EZ(v,unit) ((v)?ENOUGH(v,unit):0) + +static void ata_timing_quantize(const struct ata_timing *t, struct ata_timing *q, int T, int UT) +{ + q->setup = EZ(t->setup * 1000, T); + q->act8b = EZ(t->act8b * 1000, T); + q->rec8b = EZ(t->rec8b * 1000, T); + q->cyc8b = EZ(t->cyc8b * 1000, T); + q->active = EZ(t->active * 1000, T); + q->recover = EZ(t->recover * 1000, T); + q->cycle = EZ(t->cycle * 1000, T); + q->udma = EZ(t->udma * 1000, UT); +} + +void ata_timing_merge(const struct ata_timing *a, const struct ata_timing *b, + struct ata_timing *m, unsigned int what) +{ + if (what & ATA_TIMING_SETUP ) m->setup = max(a->setup, b->setup); + if (what & ATA_TIMING_ACT8B ) m->act8b = max(a->act8b, b->act8b); + if (what & ATA_TIMING_REC8B ) m->rec8b = max(a->rec8b, b->rec8b); + if (what & ATA_TIMING_CYC8B ) m->cyc8b = max(a->cyc8b, b->cyc8b); + if (what & ATA_TIMING_ACTIVE ) m->active = max(a->active, b->active); + if (what & ATA_TIMING_RECOVER) m->recover = max(a->recover, b->recover); + if (what & ATA_TIMING_CYCLE ) m->cycle = max(a->cycle, b->cycle); + if (what & ATA_TIMING_UDMA ) m->udma = max(a->udma, b->udma); +} + +static const struct ata_timing* ata_timing_find_mode(unsigned short speed) +{ + const struct ata_timing *t; + + for (t = ata_timing; t->mode != speed; t++) + if (t->mode == 0xFF) + return NULL; + return t; +} + +int ata_timing_compute(struct ata_device *adev, unsigned short speed, + struct ata_timing *t, int T, int UT) +{ + const struct ata_timing *s; + struct ata_timing p; + + /* + * Find the mode. + */ + + if (!(s = ata_timing_find_mode(speed))) + return -EINVAL; + + memcpy(t, s, sizeof(*s)); + + /* + * If the drive is an EIDE drive, it can tell us it needs extended + * PIO/MW_DMA cycle timing. + */ + + if (adev->id[ATA_ID_FIELD_VALID] & 2) { /* EIDE drive */ + memset(&p, 0, sizeof(p)); + if(speed >= XFER_PIO_0 && speed <= XFER_SW_DMA_0) { + if (speed <= XFER_PIO_2) p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO]; + else p.cycle = p.cyc8b = adev->id[ATA_ID_EIDE_PIO_IORDY]; + } else if(speed >= XFER_MW_DMA_0 && speed <= XFER_MW_DMA_2) { + p.cycle = adev->id[ATA_ID_EIDE_DMA_MIN]; + } + ata_timing_merge(&p, t, t, ATA_TIMING_CYCLE | ATA_TIMING_CYC8B); + } + + /* + * Convert the timing to bus clock counts. + */ + + ata_timing_quantize(t, t, T, UT); + + /* + * Even in DMA/UDMA modes we still use PIO access for IDENTIFY, S.M.A.R.T + * and some other commands. We have to ensure that the DMA cycle timing is + * slower/equal than the fastest PIO timing. + */ + + if (speed > XFER_PIO_4) { + ata_timing_compute(adev, adev->pio_mode, &p, T, UT); + ata_timing_merge(&p, t, t, ATA_TIMING_ALL); + } + + /* + * Lenghten active & recovery time so that cycle time is correct. + */ + + if (t->act8b + t->rec8b < t->cyc8b) { + t->act8b += (t->cyc8b - (t->act8b + t->rec8b)) / 2; + t->rec8b = t->cyc8b - t->act8b; + } + + if (t->active + t->recover < t->cycle) { + t->active += (t->cycle - (t->active + t->recover)) / 2; + t->recover = t->cycle - t->active; + } + + return 0; +} + +static const struct { unsigned int shift; u8 base; } xfer_mode_classes[] = { @@ -1588,7 +1741,7 @@ static void ata_host_set_dma(struct ata_ */ static void ata_set_mode(struct ata_port *ap) { - unsigned int i, xfer_shift; + unsigned int xfer_shift; u8 xfer_mode; int rc; @@ -1617,11 +1770,6 @@ static void ata_set_mode(struct ata_port if (ap->ops->post_set_mode) ap->ops->post_set_mode(ap); - for (i = 0; i < 2; i++) { - struct ata_device *dev = &ap->device[i]; - ata_dev_set_protocol(dev); - } - return; err_out: @@ -1731,12 +1879,14 @@ static void ata_bus_post_reset(struct at * * LOCKING: * PCI/etc. bus probe sem. + * Obtains host_set lock. * */ static unsigned int ata_bus_edd(struct ata_port *ap) { struct ata_taskfile tf; + unsigned long flags; /* set up execute-device-diag (bus reset) taskfile */ /* also, take interrupts to a known state (disabled) */ @@ -1747,7 +1897,9 @@ static unsigned int ata_bus_edd(struct a tf.protocol = ATA_PROT_NODATA; /* do bus reset */ + spin_lock_irqsave(&ap->host_set->lock, flags); ata_tf_to_host(ap, &tf); + spin_unlock_irqrestore(&ap->host_set->lock, flags); /* spec says at least 2ms. but who knows with those * crazy ATAPI devices... @@ -1895,7 +2047,8 @@ err_out: DPRINTK("EXIT\n"); } -static void ata_pr_blacklisted(struct ata_port *ap, struct ata_device *dev) +static void ata_pr_blacklisted(const struct ata_port *ap, + const struct ata_device *dev) { printk(KERN_WARNING "ata%u: dev %u is on DMA blacklist, disabling DMA\n", ap->id, dev->devno); @@ -1933,7 +2086,7 @@ static const char * ata_dma_blacklist [] "_NEC DV5800A", }; -static int ata_dma_blacklisted(struct ata_port *ap, struct ata_device *dev) +static int ata_dma_blacklisted(const struct ata_device *dev) { unsigned char model_num[40]; char *s; @@ -1958,9 +2111,9 @@ static int ata_dma_blacklisted(struct at return 0; } -static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift) +static unsigned int ata_get_mode_mask(const struct ata_port *ap, int shift) { - struct ata_device *master, *slave; + const struct ata_device *master, *slave; unsigned int mask; master = &ap->device[0]; @@ -1972,14 +2125,14 @@ static unsigned int ata_get_mode_mask(st mask = ap->udma_mask; if (ata_dev_present(master)) { mask &= (master->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dma_blacklisted(ap, master)) { + if (ata_dma_blacklisted(master)) { mask = 0; ata_pr_blacklisted(ap, master); } } if (ata_dev_present(slave)) { mask &= (slave->id[ATA_ID_UDMA_MODES] & 0xff); - if (ata_dma_blacklisted(ap, slave)) { + if (ata_dma_blacklisted(slave)) { mask = 0; ata_pr_blacklisted(ap, slave); } @@ -1989,14 +2142,14 @@ static unsigned int ata_get_mode_mask(st mask = ap->mwdma_mask; if (ata_dev_present(master)) { mask &= (master->id[ATA_ID_MWDMA_MODES] & 0x07); - if (ata_dma_blacklisted(ap, master)) { + if (ata_dma_blacklisted(master)) { mask = 0; ata_pr_blacklisted(ap, master); } } if (ata_dev_present(slave)) { mask &= (slave->id[ATA_ID_MWDMA_MODES] & 0x07); - if (ata_dma_blacklisted(ap, slave)) { + if (ata_dma_blacklisted(slave)) { mask = 0; ata_pr_blacklisted(ap, slave); } @@ -2060,7 +2213,7 @@ static int fgb(u32 bitmap) * Zero on success, negative on error. */ -static int ata_choose_xfer_mode(struct ata_port *ap, +static int ata_choose_xfer_mode(const struct ata_port *ap, u8 *xfer_mode_out, unsigned int *xfer_shift_out) { @@ -2123,49 +2276,178 @@ static void ata_dev_set_xfermode(struct if (rc) ata_port_disable(ap); else - wait_for_completion(&wait); + ata_qc_wait_err(qc, &wait); DPRINTK("EXIT\n"); } /** - * ata_sg_clean - Unmap DMA memory associated with command - * @qc: Command containing DMA memory to be released - * - * Unmap all mapped DMA memory associated with this command. + * ata_dev_reread_id - Reread the device identify device info + * @ap: port where the device is + * @dev: device to reread the identify device info * * LOCKING: - * spin_lock_irqsave(host_set lock) */ -static void ata_sg_clean(struct ata_queued_cmd *qc) +static void ata_dev_reread_id(struct ata_port *ap, struct ata_device *dev) { - struct ata_port *ap = qc->ap; - struct scatterlist *sg = qc->sg; - int dir = qc->dma_dir; + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + unsigned long flags; + int rc; - assert(qc->flags & ATA_QCFLAG_DMAMAP); - assert(sg != NULL); + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); - if (qc->flags & ATA_QCFLAG_SINGLE) - assert(qc->n_elem == 1); + ata_sg_init_one(qc, dev->id, sizeof(dev->id)); + qc->dma_dir = DMA_FROM_DEVICE; + + if (dev->class == ATA_DEV_ATA) { + qc->tf.command = ATA_CMD_ID_ATA; + DPRINTK("do ATA identify\n"); + } else { + qc->tf.command = ATA_CMD_ID_ATAPI; + DPRINTK("do ATAPI identify\n"); + } + + qc->tf.flags |= ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_PIO; + qc->nsect = 1; - DPRINTK("unmapping %u sg elements\n", qc->n_elem); + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; - if (qc->flags & ATA_QCFLAG_SG) - dma_unmap_sg(ap->host_set->dev, sg, qc->n_elem, dir); - else - dma_unmap_single(ap->host_set->dev, sg_dma_address(&sg[0]), - sg_dma_len(&sg[0]), dir); + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); - qc->flags &= ~ATA_QCFLAG_DMAMAP; - qc->sg = NULL; + if (rc) + goto err_out; + + ata_qc_wait_err(qc, &wait); + + swap_buf_le16(dev->id, ATA_ID_WORDS); + + ata_dump_id(dev); + + DPRINTK("EXIT\n"); + + return; +err_out: + ata_port_disable(ap); } /** - * ata_fill_sg - Fill PCI IDE PRD table - * @qc: Metadata associated with taskfile to be transferred - * + * ata_dev_init_params - Issue INIT DEV PARAMS command + * @ap: Port associated with device @dev + * @dev: Device to which command will be sent + * + * LOCKING: + */ + +static void ata_dev_init_params(struct ata_port *ap, struct ata_device *dev) +{ + DECLARE_COMPLETION(wait); + struct ata_queued_cmd *qc; + int rc; + unsigned long flags; + u16 sectors = dev->id[6]; + u16 heads = dev->id[3]; + + /* Number of sectors per track 1-255. Number of heads 1-16 */ + if (sectors < 1 || sectors > 255 || heads < 1 || heads > 16) + return; + + /* set up init dev params taskfile */ + DPRINTK("init dev params \n"); + + qc = ata_qc_new_init(ap, dev); + BUG_ON(qc == NULL); + + qc->tf.command = ATA_CMD_INIT_DEV_PARAMS; + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.protocol = ATA_PROT_NODATA; + qc->tf.nsect = sectors; + qc->tf.device |= (heads - 1) & 0x0f; /* max head = num. of heads - 1 */ + + qc->waiting = &wait; + qc->complete_fn = ata_qc_complete_noop; + + spin_lock_irqsave(&ap->host_set->lock, flags); + rc = ata_qc_issue(qc); + spin_unlock_irqrestore(&ap->host_set->lock, flags); + + if (rc) + ata_port_disable(ap); + else + ata_qc_wait_err(qc, &wait); + + DPRINTK("EXIT\n"); +} + +/** + * ata_sg_clean - Unmap DMA memory associated with command + * @qc: Command containing DMA memory to be released + * + * Unmap all mapped DMA memory associated with this command. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ + +static void ata_sg_clean(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scatterlist *sg = qc->__sg; + int dir = qc->dma_dir; + void *pad_buf = NULL; + + assert(qc->flags & ATA_QCFLAG_DMAMAP); + assert(sg != NULL); + + if (qc->flags & ATA_QCFLAG_SINGLE) + assert(qc->n_elem == 1); + + VPRINTK("unmapping %u sg elements\n", qc->n_elem); + + /* if we padded the buffer out to 32-bit bound, and data + * xfer direction is from-device, we must copy from the + * pad buffer back into the supplied buffer + */ + if (qc->pad_len && !(qc->tf.flags & ATA_TFLAG_WRITE)) + pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ); + + if (qc->flags & ATA_QCFLAG_SG) { + if (qc->n_elem) + dma_unmap_sg(ap->host_set->dev, sg, qc->n_elem, dir); + /* restore last sg */ + sg[qc->orig_n_elem - 1].length += qc->pad_len; + if (pad_buf) { + struct scatterlist *psg = &qc->pad_sgent; + void *addr = kmap_atomic(psg->page, KM_IRQ0); + memcpy(addr + psg->offset, pad_buf, qc->pad_len); + kunmap_atomic(psg->page, KM_IRQ0); + } + } else { + if (sg_dma_len(&sg[0]) > 0) + dma_unmap_single(ap->host_set->dev, + sg_dma_address(&sg[0]), sg_dma_len(&sg[0]), + dir); + /* restore sg */ + sg->length += qc->pad_len; + if (pad_buf) + memcpy(qc->buf_virt + sg->length - qc->pad_len, + pad_buf, qc->pad_len); + } + + qc->flags &= ~ATA_QCFLAG_DMAMAP; + qc->__sg = NULL; +} + +/** + * ata_fill_sg - Fill PCI IDE PRD table + * @qc: Metadata associated with taskfile to be transferred + * * Fill PCI IDE PRD (scatter-gather) table with segments * associated with the current disk command. * @@ -2175,15 +2457,15 @@ static void ata_sg_clean(struct ata_queu */ static void ata_fill_sg(struct ata_queued_cmd *qc) { - struct scatterlist *sg = qc->sg; struct ata_port *ap = qc->ap; - unsigned int idx, nelem; + struct scatterlist *sg; + unsigned int idx; - assert(sg != NULL); + assert(qc->__sg != NULL); assert(qc->n_elem > 0); idx = 0; - for (nelem = qc->n_elem; nelem; nelem--,sg++) { + ata_for_each_sg(sg, qc) { u32 addr, offset; u32 sg_len, len; @@ -2267,19 +2549,6 @@ void ata_qc_prep(struct ata_queued_cmd * * spin_lock_irqsave(host_set lock) */ - - -/** - * ata_sg_init_one - Prepare a one-entry scatter-gather list. - * @qc: Queued command - * @buf: transfer buffer - * @buflen: length of buf - * - * Builds a single-entry scatter-gather list to initiate a - * transfer utilizing the specified buffer. - * - * LOCKING: - */ void ata_sg_init_one(struct ata_queued_cmd *qc, void *buf, unsigned int buflen) { struct scatterlist *sg; @@ -2287,14 +2556,13 @@ void ata_sg_init_one(struct ata_queued_c qc->flags |= ATA_QCFLAG_SINGLE; memset(&qc->sgent, 0, sizeof(qc->sgent)); - qc->sg = &qc->sgent; + qc->__sg = &qc->sgent; qc->n_elem = 1; + qc->orig_n_elem = 1; qc->buf_virt = buf; - sg = qc->sg; - sg->page = virt_to_page(buf); - sg->offset = (unsigned long) buf & ~PAGE_MASK; - sg->length = buflen; + sg = qc->__sg; + sg_init_one(sg, buf, buflen); } /** @@ -2311,24 +2579,13 @@ void ata_sg_init_one(struct ata_queued_c * spin_lock_irqsave(host_set lock) */ - -/** - * ata_sg_init - Assign a scatter gather list to a queued command - * @qc: Queued command - * @sg: Scatter-gather list - * @n_elem: length of sg list - * - * Attaches a scatter-gather list to a queued command. - * - * LOCKING: - */ - void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, unsigned int n_elem) { qc->flags |= ATA_QCFLAG_SG; - qc->sg = sg; + qc->__sg = sg; qc->n_elem = n_elem; + qc->orig_n_elem = n_elem; } /** @@ -2348,15 +2605,47 @@ static int ata_sg_setup_one(struct ata_q { struct ata_port *ap = qc->ap; int dir = qc->dma_dir; - struct scatterlist *sg = qc->sg; + struct scatterlist *sg = qc->__sg; dma_addr_t dma_address; + /* we must lengthen transfers to end on a 32-bit boundary */ + qc->pad_len = sg->length & 3; + if (qc->pad_len) { + void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ); + struct scatterlist *psg = &qc->pad_sgent; + + assert(qc->dev->class == ATA_DEV_ATAPI); + + memset(pad_buf, 0, ATA_DMA_PAD_SZ); + + if (qc->tf.flags & ATA_TFLAG_WRITE) + memcpy(pad_buf, qc->buf_virt + sg->length - qc->pad_len, + qc->pad_len); + + sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ); + sg_dma_len(psg) = ATA_DMA_PAD_SZ; + /* trim sg */ + sg->length -= qc->pad_len; + + DPRINTK("padding done, sg->length=%u pad_len=%u\n", + sg->length, qc->pad_len); + } + + if (!sg->length) { + sg_dma_address(sg) = 0; + goto skip_map; + } + dma_address = dma_map_single(ap->host_set->dev, qc->buf_virt, sg->length, dir); - if (dma_mapping_error(dma_address)) + if (dma_mapping_error(dma_address)) { + /* restore sg */ + sg->length += qc->pad_len; return -1; + } sg_dma_address(sg) = dma_address; +skip_map: sg_dma_len(sg) = sg->length; DPRINTK("mapped buffer of %d bytes for %s\n", sg_dma_len(sg), @@ -2382,52 +2671,122 @@ static int ata_sg_setup_one(struct ata_q static int ata_sg_setup(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct scatterlist *sg = qc->sg; - int n_elem, dir; + struct scatterlist *sg = qc->__sg; + struct scatterlist *lsg = &sg[qc->n_elem - 1]; + int n_elem, pre_n_elem, dir, trim_sg = 0; VPRINTK("ENTER, ata%u\n", ap->id); assert(qc->flags & ATA_QCFLAG_SG); + /* we must lengthen transfers to end on a 32-bit boundary */ + qc->pad_len = lsg->length & 3; + if (qc->pad_len) { + void *pad_buf = ap->pad + (qc->tag * ATA_DMA_PAD_SZ); + struct scatterlist *psg = &qc->pad_sgent; + unsigned int offset; + + assert(qc->dev->class == ATA_DEV_ATAPI); + + memset(pad_buf, 0, ATA_DMA_PAD_SZ); + + /* + * psg->page/offset are used to copy to-be-written + * data in this function or read data in ata_sg_clean. + */ + offset = lsg->offset + lsg->length - qc->pad_len; + psg->page = nth_page(lsg->page, offset >> PAGE_SHIFT); + psg->offset = offset_in_page(offset); + + if (qc->tf.flags & ATA_TFLAG_WRITE) { + void *addr = kmap_atomic(psg->page, KM_IRQ0); + memcpy(pad_buf, addr + psg->offset, qc->pad_len); + kunmap_atomic(psg->page, KM_IRQ0); + } + + sg_dma_address(psg) = ap->pad_dma + (qc->tag * ATA_DMA_PAD_SZ); + sg_dma_len(psg) = ATA_DMA_PAD_SZ; + /* trim last sg */ + lsg->length -= qc->pad_len; + if (lsg->length == 0) + trim_sg = 1; + + DPRINTK("padding done, sg[%d].length=%u pad_len=%u\n", + qc->n_elem - 1, lsg->length, qc->pad_len); + } + + pre_n_elem = qc->n_elem; + if (trim_sg && pre_n_elem) + pre_n_elem--; + + if (!pre_n_elem) { + n_elem = 0; + goto skip_map; + } + dir = qc->dma_dir; - n_elem = dma_map_sg(ap->host_set->dev, sg, qc->n_elem, dir); - if (n_elem < 1) + n_elem = dma_map_sg(ap->host_set->dev, sg, pre_n_elem, dir); + if (n_elem < 1) { + /* restore last sg */ + lsg->length += qc->pad_len; return -1; + } DPRINTK("%d sg elements mapped\n", n_elem); +skip_map: qc->n_elem = n_elem; return 0; } /** + * ata_poll_qc_complete - turn irq back on and finish qc + * @qc: Command to complete + * @err_mask: ATA status register content + * + * LOCKING: + * None. (grabs host lock) + */ + +void ata_poll_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask) +{ + struct ata_port *ap = qc->ap; + unsigned long flags; + + spin_lock_irqsave(&ap->host_set->lock, flags); + ap->flags &= ~ATA_FLAG_NOINTR; + ata_irq_on(ap); + ata_qc_complete(qc, err_mask); + spin_unlock_irqrestore(&ap->host_set->lock, flags); +} + +/** * ata_pio_poll - - * @ap: + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) * * RETURNS: - * + * timeout value to use */ static unsigned long ata_pio_poll(struct ata_port *ap) { u8 status; - unsigned int poll_state = PIO_ST_UNKNOWN; - unsigned int reg_state = PIO_ST_UNKNOWN; - const unsigned int tmout_state = PIO_ST_TMOUT; - - switch (ap->pio_task_state) { - case PIO_ST: - case PIO_ST_POLL: - poll_state = PIO_ST_POLL; - reg_state = PIO_ST; + unsigned int poll_state = HSM_ST_UNKNOWN; + unsigned int reg_state = HSM_ST_UNKNOWN; + + switch (ap->hsm_task_state) { + case HSM_ST: + case HSM_ST_POLL: + poll_state = HSM_ST_POLL; + reg_state = HSM_ST; break; - case PIO_ST_LAST: - case PIO_ST_LAST_POLL: - poll_state = PIO_ST_LAST_POLL; - reg_state = PIO_ST_LAST; + case HSM_ST_LAST: + case HSM_ST_LAST_POLL: + poll_state = HSM_ST_LAST_POLL; + reg_state = HSM_ST_LAST; break; default: BUG(); @@ -2437,68 +2796,72 @@ static unsigned long ata_pio_poll(struct status = ata_chk_status(ap); if (status & ATA_BUSY) { if (time_after(jiffies, ap->pio_task_timeout)) { - ap->pio_task_state = tmout_state; + ap->hsm_task_state = HSM_ST_TMOUT; return 0; } - ap->pio_task_state = poll_state; + ap->hsm_task_state = poll_state; return ATA_SHORT_PAUSE; } - ap->pio_task_state = reg_state; + ap->hsm_task_state = reg_state; return 0; } /** - * ata_pio_complete - - * @ap: + * ata_pio_complete - check if drive is busy or idle + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) + * + * RETURNS: + * Non-zero if qc completed, zero otherwise. */ -static void ata_pio_complete (struct ata_port *ap) +static int ata_pio_complete (struct ata_port *ap) { struct ata_queued_cmd *qc; u8 drv_stat; /* - * This is purely hueristic. This is a fast path. - * Sometimes when we enter, BSY will be cleared in - * a chk-status or two. If not, the drive is probably seeking - * or something. Snooze for a couple msecs, then - * chk-status again. If still busy, fall back to - * PIO_ST_POLL state. + * This is purely heuristic. This is a fast path. Sometimes when + * we enter, BSY will be cleared in a chk-status or two. If not, + * the drive is probably seeking or something. Snooze for a couple + * msecs, then chk-status again. If still busy, fall back to + * HSM_ST_POLL state. */ drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); if (drv_stat & (ATA_BUSY | ATA_DRQ)) { msleep(2); drv_stat = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 10); if (drv_stat & (ATA_BUSY | ATA_DRQ)) { - ap->pio_task_state = PIO_ST_LAST_POLL; + ap->hsm_task_state = HSM_ST_LAST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; - return; + return 0; } } drv_stat = ata_wait_idle(ap); if (!ata_ok(drv_stat)) { - ap->pio_task_state = PIO_ST_ERR; - return; + ap->hsm_task_state = HSM_ST_ERR; + return 0; } qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); - ap->pio_task_state = PIO_ST_IDLE; + ap->hsm_task_state = HSM_ST_IDLE; - ata_irq_on(ap); + ata_poll_qc_complete(qc, 0); + + /* another command may start at this point */ - ata_qc_complete(qc, drv_stat); + return 1; } /** - * swap_buf_le16 - + * swap_buf_le16 - swap halves of 16-words in place * @buf: Buffer to swap * @buf_words: Number of 16-bit words in buffer. * @@ -2507,6 +2870,7 @@ static void ata_pio_complete (struct ata * vice-versa. * * LOCKING: + * Inherited from caller. */ void swap_buf_le16(u16 *buf, unsigned int buf_words) { @@ -2518,6 +2882,19 @@ void swap_buf_le16(u16 *buf, unsigned in #endif /* __BIG_ENDIAN */ } +/** + * ata_mmio_data_xfer - Transfer data by MMIO + * @ap: port to read/write + * @buf: data buffer + * @buflen: buffer length + * @write_data: read/write + * + * Transfer data from/to the device data register by MMIO. + * + * LOCKING: + * Inherited from caller. + */ + static void ata_mmio_data_xfer(struct ata_port *ap, unsigned char *buf, unsigned int buflen, int write_data) { @@ -2526,6 +2903,7 @@ static void ata_mmio_data_xfer(struct at u16 *buf16 = (u16 *) buf; void __iomem *mmio = (void __iomem *)ap->ioaddr.data_addr; + /* Transfer multiple of 2 bytes */ if (write_data) { for (i = 0; i < words; i++) writew(le16_to_cpu(buf16[i]), mmio); @@ -2533,19 +2911,74 @@ static void ata_mmio_data_xfer(struct at for (i = 0; i < words; i++) buf16[i] = cpu_to_le16(readw(mmio)); } + + /* Transfer trailing 1 byte, if any. */ + if (unlikely(buflen & 0x01)) { + u16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (write_data) { + memcpy(align_buf, trailing_buf, 1); + writew(le16_to_cpu(align_buf[0]), mmio); + } else { + align_buf[0] = cpu_to_le16(readw(mmio)); + memcpy(trailing_buf, align_buf, 1); + } + } } +/** + * ata_pio_data_xfer - Transfer data by PIO + * @ap: port to read/write + * @buf: data buffer + * @buflen: buffer length + * @write_data: read/write + * + * Transfer data from/to the device data register by PIO. + * + * LOCKING: + * Inherited from caller. + */ + static void ata_pio_data_xfer(struct ata_port *ap, unsigned char *buf, unsigned int buflen, int write_data) { - unsigned int dwords = buflen >> 1; + unsigned int words = buflen >> 1; + /* Transfer multiple of 2 bytes */ if (write_data) - outsw(ap->ioaddr.data_addr, buf, dwords); + outsw(ap->ioaddr.data_addr, buf, words); else - insw(ap->ioaddr.data_addr, buf, dwords); + insw(ap->ioaddr.data_addr, buf, words); + + /* Transfer trailing 1 byte, if any. */ + if (unlikely(buflen & 0x01)) { + u16 align_buf[1] = { 0 }; + unsigned char *trailing_buf = buf + buflen - 1; + + if (write_data) { + memcpy(align_buf, trailing_buf, 1); + outw(le16_to_cpu(align_buf[0]), ap->ioaddr.data_addr); + } else { + align_buf[0] = cpu_to_le16(inw(ap->ioaddr.data_addr)); + memcpy(trailing_buf, align_buf, 1); + } + } } +/** + * ata_data_xfer - Transfer data from/to the data register. + * @ap: port to read/write + * @buf: data buffer + * @buflen: buffer length + * @do_write: read/write + * + * Transfer data from/to the device data register. + * + * LOCKING: + * Inherited from caller. + */ + static void ata_data_xfer(struct ata_port *ap, unsigned char *buf, unsigned int buflen, int do_write) { @@ -2555,17 +2988,27 @@ static void ata_data_xfer(struct ata_por ata_pio_data_xfer(ap, buf, buflen, do_write); } +/** + * ata_pio_sector - Transfer ATA_SECT_SIZE (512 bytes) of data. + * @qc: Command on going + * + * Transfer ATA_SECT_SIZE of data from/to the ATA device. + * + * LOCKING: + * Inherited from caller. + */ + static void ata_pio_sector(struct ata_queued_cmd *qc) { int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); - struct scatterlist *sg = qc->sg; + struct scatterlist *sg = qc->__sg; struct ata_port *ap = qc->ap; struct page *page; unsigned int offset; unsigned char *buf; if (qc->cursect == (qc->nsect - 1)) - ap->pio_task_state = PIO_ST_LAST; + ap->hsm_task_state = HSM_ST_LAST; page = sg[qc->cursg].page; offset = sg[qc->cursg].offset + qc->cursg_ofs * ATA_SECT_SIZE; @@ -2593,20 +3036,55 @@ static void ata_pio_sector(struct ata_qu kunmap(page); } +/** + * __atapi_pio_bytes - Transfer data from/to the ATAPI device. + * @qc: Command on going + * @bytes: number of bytes + * + * Transfer Transfer data from/to the ATAPI device. + * + * LOCKING: + * Inherited from caller. + * + */ + static void __atapi_pio_bytes(struct ata_queued_cmd *qc, unsigned int bytes) { int do_write = (qc->tf.flags & ATA_TFLAG_WRITE); - struct scatterlist *sg = qc->sg; + struct scatterlist *sg = qc->__sg; struct ata_port *ap = qc->ap; struct page *page; unsigned char *buf; unsigned int offset, count; - if (qc->curbytes == qc->nbytes - bytes) - ap->pio_task_state = PIO_ST_LAST; + if (qc->curbytes + bytes >= qc->nbytes) + ap->hsm_task_state = HSM_ST_LAST; next_sg: - sg = &qc->sg[qc->cursg]; + if (unlikely(qc->cursg >= qc->n_elem)) { + /* + * The end of qc->sg is reached and the device expects + * more data to transfer. In order not to overrun qc->sg + * and fulfill length specified in the byte count register, + * - for read case, discard trailing data from the device + * - for write case, padding zero data to the device + */ + u16 pad_buf[1] = { 0 }; + unsigned int words = bytes >> 1; + unsigned int i; + + if (words) /* warning if bytes > 1 */ + printk(KERN_WARNING "ata%u: %u bytes trailing data\n", + ap->id, bytes); + + for (i = 0; i < words; i++) + ata_data_xfer(ap, (unsigned char*)pad_buf, 2, do_write); + + ap->hsm_task_state = HSM_ST_LAST; + return; + } + + sg = &qc->__sg[qc->cursg]; page = sg->page; offset = sg->offset + qc->cursg_ofs; @@ -2639,11 +3117,20 @@ next_sg: kunmap(page); - if (bytes) { + if (bytes) goto next_sg; - } } +/** + * atapi_pio_bytes - Transfer data from/to the ATAPI device. + * @qc: Command on going + * + * Transfer Transfer data from/to the ATAPI device. + * + * LOCKING: + * Inherited from caller. + */ + static void atapi_pio_bytes(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; @@ -2673,12 +3160,12 @@ static void atapi_pio_bytes(struct ata_q err_out: printk(KERN_INFO "ata%u: dev %u: ATAPI check failed\n", ap->id, dev->devno); - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; } /** - * ata_pio_sector - - * @ap: + * ata_pio_block - start PIO on a block + * @ap: the target ata_port * * LOCKING: * None. (executing in kernel thread context) @@ -2690,19 +3177,19 @@ static void ata_pio_block(struct ata_por u8 status; /* - * This is purely hueristic. This is a fast path. + * This is purely heuristic. This is a fast path. * Sometimes when we enter, BSY will be cleared in * a chk-status or two. If not, the drive is probably seeking * or something. Snooze for a couple msecs, then * chk-status again. If still busy, fall back to - * PIO_ST_POLL state. + * HSM_ST_POLL state. */ status = ata_busy_wait(ap, ATA_BUSY, 5); if (status & ATA_BUSY) { msleep(2); status = ata_busy_wait(ap, ATA_BUSY, 10); if (status & ATA_BUSY) { - ap->pio_task_state = PIO_ST_POLL; + ap->hsm_task_state = HSM_ST_POLL; ap->pio_task_timeout = jiffies + ATA_TMOUT_PIO; return; } @@ -2714,11 +3201,7 @@ static void ata_pio_block(struct ata_por if (is_atapi_taskfile(&qc->tf)) { /* no more data to transfer or unsupported ATAPI command */ if ((status & ATA_DRQ) == 0) { - ap->pio_task_state = PIO_ST_IDLE; - - ata_irq_on(ap); - - ata_qc_complete(qc, status); + ap->hsm_task_state = HSM_ST_LAST; return; } @@ -2726,7 +3209,7 @@ static void ata_pio_block(struct ata_por } else { /* handle BSY=0, DRQ=0 as error */ if ((status & ATA_DRQ) == 0) { - ap->pio_task_state = PIO_ST_ERR; + ap->hsm_task_state = HSM_ST_ERR; return; } @@ -2737,46 +3220,46 @@ static void ata_pio_block(struct ata_por static void ata_pio_error(struct ata_port *ap) { struct ata_queued_cmd *qc; - u8 drv_stat; + + printk(KERN_WARNING "ata%u: PIO error\n", ap->id); qc = ata_qc_from_tag(ap, ap->active_tag); assert(qc != NULL); - drv_stat = ata_chk_status(ap); - printk(KERN_WARNING "ata%u: PIO error, drv_stat 0x%x\n", - ap->id, drv_stat); - - ap->pio_task_state = PIO_ST_IDLE; + ap->hsm_task_state = HSM_ST_IDLE; - ata_irq_on(ap); - - ata_qc_complete(qc, drv_stat | ATA_ERR); + ata_poll_qc_complete(qc, AC_ERR_ATA_BUS); } static void ata_pio_task(void *_data) { struct ata_port *ap = _data; - unsigned long timeout = 0; + unsigned long timeout; + int qc_completed; + +fsm_start: + timeout = 0; + qc_completed = 0; - switch (ap->pio_task_state) { - case PIO_ST_IDLE: + switch (ap->hsm_task_state) { + case HSM_ST_IDLE: return; - case PIO_ST: + case HSM_ST: ata_pio_block(ap); break; - case PIO_ST_LAST: - ata_pio_complete(ap); + case HSM_ST_LAST: + qc_completed = ata_pio_complete(ap); break; - case PIO_ST_POLL: - case PIO_ST_LAST_POLL: + case HSM_ST_POLL: + case HSM_ST_LAST_POLL: timeout = ata_pio_poll(ap); break; - case PIO_ST_TMOUT: - case PIO_ST_ERR: + case HSM_ST_TMOUT: + case HSM_ST_ERR: ata_pio_error(ap); return; } @@ -2784,55 +3267,10 @@ static void ata_pio_task(void *_data) if (timeout) { set_current_state(TASK_UNINTERRUPTIBLE); schedule_timeout(timeout); + schedule_task(&ap->pio_task); } - - schedule_task(&ap->pio_task); -} - -static void atapi_request_sense(struct ata_port *ap, struct ata_device *dev, - struct scsi_cmnd *cmd) -{ - DECLARE_COMPLETION(wait); - struct ata_queued_cmd *qc; - unsigned long flags; - int rc; - - DPRINTK("ATAPI request sense\n"); - - qc = ata_qc_new_init(ap, dev); - BUG_ON(qc == NULL); - - /* FIXME: is this needed? */ - memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); - - ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); - qc->dma_dir = DMA_FROM_DEVICE; - - memset(&qc->cdb, 0, ap->cdb_len); - qc->cdb[0] = REQUEST_SENSE; - qc->cdb[4] = SCSI_SENSE_BUFFERSIZE; - - qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - qc->tf.command = ATA_CMD_PACKET; - - qc->tf.protocol = ATA_PROT_ATAPI; - qc->tf.lbam = (8 * 1024) & 0xff; - qc->tf.lbah = (8 * 1024) >> 8; - qc->nbytes = SCSI_SENSE_BUFFERSIZE; - - qc->waiting = &wait; - qc->complete_fn = ata_qc_complete_noop; - - spin_lock_irqsave(&ap->host_set->lock, flags); - rc = ata_qc_issue(qc); - spin_unlock_irqrestore(&ap->host_set->lock, flags); - - if (rc) - ata_port_disable(ap); - else - wait_for_completion(&wait); - - DPRINTK("EXIT\n"); + else if (!qc_completed) + goto fsm_start; } /** @@ -2857,28 +3295,13 @@ static void atapi_request_sense(struct a static void ata_qc_timeout(struct ata_queued_cmd *qc) { struct ata_port *ap = qc->ap; - struct ata_device *dev = qc->dev; + struct ata_host_set *host_set = ap->host_set; u8 host_stat = 0, drv_stat; + unsigned long flags; DPRINTK("ENTER\n"); - /* FIXME: doesn't this conflict with timeout handling? */ - if (qc->dev->class == ATA_DEV_ATAPI && qc->scsicmd) { - struct scsi_cmnd *cmd = qc->scsicmd; - - if (cmd->owner == SCSI_OWNER_ERROR_HANDLER) { - - /* finish completing original command */ - __ata_qc_complete(qc); - - atapi_request_sense(ap, dev, cmd); - - cmd->result = (CHECK_CONDITION << 1) | (DID_OK << 16); - scsi_finish_command(cmd); - - goto out; - } - } + spin_lock_irqsave(&host_set->lock, flags); /* hack alert! We cannot use the supplied completion * function from inside the ->eh_strategy_handler() thread. @@ -2895,7 +3318,7 @@ static void ata_qc_timeout(struct ata_qu host_stat = ap->ops->bmdma_status(ap); /* before we do anything else, clear DMA-Start bit */ - ap->ops->bmdma_stop(ap); + ap->ops->bmdma_stop(qc); /* fall through */ @@ -2910,10 +3333,12 @@ static void ata_qc_timeout(struct ata_qu ap->id, qc->tf.command, drv_stat, host_stat); /* complete taskfile transaction */ - ata_qc_complete(qc, drv_stat); + ata_qc_complete(qc, ac_err_mask(drv_stat)); break; } -out: + + spin_unlock_irqrestore(&host_set->lock, flags); + DPRINTK("EXIT\n"); } @@ -2943,14 +3368,14 @@ void ata_eng_timeout(struct ata_port *ap DPRINTK("ENTER\n"); qc = ata_qc_from_tag(ap, ap->active_tag); - if (!qc) { + if (qc) + ata_qc_timeout(qc); + else { printk(KERN_ERR "ata%u: BUG: timeout without command\n", ap->id); goto out; } - ata_qc_timeout(qc); - out: DPRINTK("EXIT\n"); } @@ -2997,25 +3422,17 @@ struct ata_queued_cmd *ata_qc_new_init(s qc = ata_qc_new(ap); if (qc) { - qc->sg = NULL; - qc->flags = 0; qc->scsicmd = NULL; qc->ap = ap; qc->dev = dev; - qc->cursect = qc->cursg = qc->cursg_ofs = 0; - qc->nsect = 0; - qc->nbytes = qc->curbytes = 0; - ata_tf_init(ap, &qc->tf, dev->devno); - - if (dev->flags & ATA_DFLAG_LBA48) - qc->tf.flags |= ATA_TFLAG_LBA48; + ata_qc_reinit(qc); } return qc; } -static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) +int ata_qc_complete_noop(struct ata_queued_cmd *qc, unsigned int err_mask) { return 0; } @@ -3053,7 +3470,6 @@ static void __ata_qc_complete(struct ata * * LOCKING: * spin_lock_irqsave(host_set lock) - * */ void ata_qc_free(struct ata_queued_cmd *qc) { @@ -3066,17 +3482,16 @@ void ata_qc_free(struct ata_queued_cmd * /** * ata_qc_complete - Complete an active ATA command * @qc: Command to complete - * @drv_stat: ATA Status register contents + * @err_mask: ATA Status register contents * * Indicate to the mid and upper layers that an ATA * command has completed, with either an ok or not-ok status. * * LOCKING: * spin_lock_irqsave(host_set lock) - * */ -void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask) { int rc; @@ -3086,10 +3501,15 @@ void ata_qc_complete(struct ata_queued_c if (likely(qc->flags & ATA_QCFLAG_DMAMAP)) ata_sg_clean(qc); - /* call completion callback */ - rc = qc->complete_fn(qc, drv_stat); + /* atapi: mark qc as inactive to prevent the interrupt handler + * from completing the command twice later, before the error handler + * is called. (when rc != 0 and atapi request sense is needed) + */ qc->flags &= ~ATA_QCFLAG_ACTIVE; + /* call completion callback */ + rc = qc->complete_fn(qc, err_mask); + /* if callback indicates not to complete command (non-zero), * return immediately */ @@ -3195,7 +3615,7 @@ int ata_qc_issue_prot(struct ata_queued_ switch (qc->tf.protocol) { case ATA_PROT_NODATA: - ata_tf_to_host_nolock(ap, &qc->tf); + ata_tf_to_host(ap, &qc->tf); break; case ATA_PROT_DMA: @@ -3206,23 +3626,25 @@ int ata_qc_issue_prot(struct ata_queued_ case ATA_PROT_PIO: /* load tf registers, initiate polling pio */ ata_qc_set_polling(qc); - ata_tf_to_host_nolock(ap, &qc->tf); - ap->pio_task_state = PIO_ST; + ata_tf_to_host(ap, &qc->tf); + ap->hsm_task_state = HSM_ST; schedule_task(&ap->pio_task); break; case ATA_PROT_ATAPI: ata_qc_set_polling(qc); - ata_tf_to_host_nolock(ap, &qc->tf); + ata_tf_to_host(ap, &qc->tf); schedule_task(&ap->packet_task); break; case ATA_PROT_ATAPI_NODATA: - ata_tf_to_host_nolock(ap, &qc->tf); + ap->flags |= ATA_FLAG_NOINTR; + ata_tf_to_host(ap, &qc->tf); schedule_task(&ap->packet_task); break; case ATA_PROT_ATAPI_DMA: + ap->flags |= ATA_FLAG_NOINTR; ap->ops->tf_load(ap, &qc->tf); /* load tf registers */ ap->ops->bmdma_setup(qc); /* set up bmdma */ schedule_task(&ap->packet_task); @@ -3267,7 +3689,7 @@ static void ata_bmdma_setup_mmio (struct } /** - * ata_bmdma_start - Start a PCI IDE BMDMA transaction + * ata_bmdma_start_mmio - Start a PCI IDE BMDMA transaction * @qc: Info associated with this ATA transaction. * * LOCKING: @@ -3431,14 +3853,14 @@ u8 ata_bmdma_status(struct ata_port *ap) void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; host_stat = readb(mmio + ATA_DMA_STATUS); } else - host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); + host_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); return host_stat; } /** * ata_bmdma_stop - Stop PCI IDE BMDMA transfer - * @ap: Port associated with this ATA transaction. + * @qc: Command we are ending DMA for * * Clears the ATA_DMA_START flag in the dma control register * @@ -3448,8 +3870,9 @@ u8 ata_bmdma_status(struct ata_port *ap) * spin_lock_irqsave(host_set lock) */ -void ata_bmdma_stop(struct ata_port *ap) +void ata_bmdma_stop(struct ata_queued_cmd *qc) { + struct ata_port *ap = qc->ap; if (ap->flags & ATA_FLAG_MMIO) { void __iomem *mmio = (void __iomem *) ap->ioaddr.bmdma_addr; @@ -3501,7 +3924,7 @@ inline unsigned int ata_host_intr (struc goto idle_irq; /* before we do anything else, clear DMA-Start bit */ - ap->ops->bmdma_stop(ap); + ap->ops->bmdma_stop(qc); /* fall through */ @@ -3523,7 +3946,7 @@ inline unsigned int ata_host_intr (struc ap->ops->irq_clear(ap); /* complete taskfile transaction */ - ata_qc_complete(qc, status); + ata_qc_complete(qc, ac_err_mask(status)); break; default: @@ -3559,7 +3982,6 @@ idle_irq: * * RETURNS: * IRQ_NONE or IRQ_HANDLED. - * */ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs) @@ -3576,7 +3998,8 @@ irqreturn_t ata_interrupt (int irq, void struct ata_port *ap; ap = host_set->ports[i]; - if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (ap && + !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); @@ -3618,7 +4041,7 @@ static void atapi_packet_task(void *_dat /* sleep-wait for BSY to clear */ DPRINTK("busy wait\n"); if (ata_busy_sleep(ap, ATA_TMOUT_CDB_QUICK, ATA_TMOUT_CDB)) - goto err_out; + goto err_out_status; /* make sure DRQ is set */ status = ata_chk_status(ap); @@ -3628,27 +4051,37 @@ static void atapi_packet_task(void *_dat /* send SCSI cdb */ DPRINTK("send cdb\n"); assert(ap->cdb_len >= 12); - ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); - - /* if we are DMA'ing, irq handler takes over from here */ - if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) - ap->ops->bmdma_start(qc); /* initiate bmdma */ - /* non-data commands are also handled via irq */ - else if (qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { - /* do nothing */ - } + if (qc->tf.protocol == ATA_PROT_ATAPI_DMA || + qc->tf.protocol == ATA_PROT_ATAPI_NODATA) { + unsigned long flags; + + /* Once we're done issuing command and kicking bmdma, + * irq handler takes over. To not lose irq, we need + * to clear NOINTR flag before sending cdb, but + * interrupt handler shouldn't be invoked before we're + * finished. Hence, the following locking. + */ + spin_lock_irqsave(&ap->host_set->lock, flags); + ap->flags &= ~ATA_FLAG_NOINTR; + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); + if (qc->tf.protocol == ATA_PROT_ATAPI_DMA) + ap->ops->bmdma_start(qc); /* initiate bmdma */ + spin_unlock_irqrestore(&ap->host_set->lock, flags); + } else { + ata_data_xfer(ap, qc->cdb, ap->cdb_len, 1); - /* PIO commands are handled by polling */ - else { - ap->pio_task_state = PIO_ST; + /* PIO commands are handled by polling */ + ap->hsm_task_state = HSM_ST; schedule_task(&ap->pio_task); } return; +err_out_status: + status = ata_chk_status(ap); err_out: - ata_qc_complete(qc, ATA_ERR); + ata_poll_qc_complete(qc, __ac_err_mask(status)); } @@ -3662,16 +4095,24 @@ err_out: * May be used as the port_start() entry in ata_port_operations. * * LOCKING: + * Inherited from caller. */ int ata_port_start (struct ata_port *ap) { struct device *dev = ap->host_set->dev; + int rc; ap->prd = dma_alloc_coherent(dev, ATA_PRD_TBL_SZ, &ap->prd_dma, GFP_KERNEL); if (!ap->prd) return -ENOMEM; + rc = ata_pad_alloc(ap, dev); + if (rc) { + dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); + return rc; + } + DPRINTK("prd alloc, virt %p, dma %llx\n", ap->prd, (unsigned long long) ap->prd_dma); return 0; @@ -3687,6 +4128,7 @@ int ata_port_start (struct ata_port *ap) * May be used as the port_stop() entry in ata_port_operations. * * LOCKING: + * Inherited from caller. */ void ata_port_stop (struct ata_port *ap) @@ -3694,6 +4136,7 @@ void ata_port_stop (struct ata_port *ap) struct device *dev = ap->host_set->dev; dma_free_coherent(dev, ATA_PRD_TBL_SZ, ap->prd, ap->prd_dma); + ata_pad_free(ap, dev); } void ata_host_stop (struct ata_host_set *host_set) @@ -3709,6 +4152,7 @@ void ata_host_stop (struct ata_host_set * @do_unregister: 1 if we fully unregister, 0 to just stop the port * * LOCKING: + * Inherited from caller. */ static void ata_host_remove(struct ata_port *ap, unsigned int do_unregister) @@ -3736,12 +4180,11 @@ static void ata_host_remove(struct ata_p * * LOCKING: * Inherited from caller. - * */ static void ata_host_init(struct ata_port *ap, struct Scsi_Host *host, struct ata_host_set *host_set, - struct ata_probe_ent *ent, unsigned int port_no) + const struct ata_probe_ent *ent, unsigned int port_no) { unsigned int i; @@ -3796,10 +4239,9 @@ static void ata_host_init(struct ata_por * * RETURNS: * New ata_port on success, for NULL on error. - * */ -static struct ata_port * ata_host_add(struct ata_probe_ent *ent, +static struct ata_port * ata_host_add(const struct ata_probe_ent *ent, struct ata_host_set *host_set, unsigned int port_no) { @@ -3844,10 +4286,9 @@ err_out: * * RETURNS: * Number of ports registered. Zero on error (no ports registered). - * */ -int ata_device_add(struct ata_probe_ent *ent) +int ata_device_add(const struct ata_probe_ent *ent) { unsigned int count = 0, i; struct device *dev = ent->dev; @@ -3855,11 +4296,10 @@ int ata_device_add(struct ata_probe_ent DPRINTK("ENTER\n"); /* alloc a container for our list of ATA ports (buses) */ - host_set = kmalloc(sizeof(struct ata_host_set) + + host_set = kzalloc(sizeof(struct ata_host_set) + (ent->n_ports * sizeof(void *)), GFP_KERNEL); if (!host_set) return 0; - memset(host_set, 0, sizeof(struct ata_host_set) + (ent->n_ports * sizeof(void *))); spin_lock_init(&host_set->lock); host_set->dev = dev; @@ -3899,10 +4339,8 @@ int ata_device_add(struct ata_probe_ent count++; } - if (!count) { - kfree(host_set); - return 0; - } + if (!count) + goto err_free_ret; /* obtain irq, that is shared between channels */ if (request_irq(ent->irq, ent->port_ops->irq_handler, ent->irq_flags, @@ -3939,13 +4377,63 @@ int ata_device_add(struct ata_probe_ent err_out: for (i = 0; i < count; i++) { ata_host_remove(host_set->ports[i], 1); + /* scsi_host_put(host_set->ports[i]->host); */ } +err_free_ret: kfree(host_set); VPRINTK("EXIT, returning 0\n"); return 0; } /** + * ata_host_set_remove - PCI layer callback for device removal + * @host_set: ATA host set that was removed + * + * Unregister all objects associated with this host set. Free those + * objects. + * + * LOCKING: + * Inherited from calling layer (may sleep). + */ + +void ata_host_set_remove(struct ata_host_set *host_set) +{ + struct ata_port *ap; + Scsi_Host_Template *sht; + unsigned int i; + int rc; + + /* FIXME: this unregisters all ports attached to the + * Scsi_Host_Template given. We _might_ have multiple + * templates (though we don't ATM), so this is ok... for now. + */ + ap = host_set->ports[0]; + sht = ap->host->hostt; + rc = scsi_unregister_module(MODULE_SCSI_HA, sht); + /* FIXME: handle 'rc' failure? */ + + free_irq(host_set->irq, host_set); + + for (i = 0; i < host_set->n_ports; i++) { + ap = host_set->ports[i]; + + if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) { + struct ata_ioports *ioaddr = &ap->ioaddr; + + if (ioaddr->cmd_addr == 0x1f0) + release_region(0x1f0, 8); + else if (ioaddr->cmd_addr == 0x170) + release_region(0x170, 8); + } + } + + if (host_set->ops->host_stop) + host_set->ops->host_stop(host_set); + + kfree(host_set); +} + +/** * ata_scsi_detect - * @sht: * @@ -4038,19 +4526,17 @@ void ata_std_ports(struct ata_ioports *i } static struct ata_probe_ent * -ata_probe_ent_alloc(struct device *dev, struct ata_port_info *port) +ata_probe_ent_alloc(struct device *dev, const struct ata_port_info *port) { struct ata_probe_ent *probe_ent; - probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); + probe_ent = kzalloc(sizeof(*probe_ent), GFP_KERNEL); if (!probe_ent) { printk(KERN_ERR DRV_NAME "(%s): out of memory\n", pci_name(to_pci_dev(dev))); return NULL; } - memset(probe_ent, 0, sizeof(*probe_ent)); - INIT_LIST_HEAD(&probe_ent->node); probe_ent->dev = dev; @@ -4064,92 +4550,117 @@ ata_probe_ent_alloc(struct device *dev, return probe_ent; } +/** + * ata_add_to_probe_list - add an entry to the list of things + * to be probed. + * @probe_ent: describes device to be probed. + * + * LOCKING: + */ + +void ata_add_to_probe_list(struct ata_probe_ent *probe_ent) +{ + spin_lock(&ata_module_lock); + list_add_tail(&probe_ent->node, &ata_probe_list); + spin_unlock(&ata_module_lock); +} + +#ifdef CONFIG_PCI + +void ata_pci_host_stop (struct ata_host_set *host_set) +{ + struct pci_dev *pdev = to_pci_dev(host_set->dev); + + pci_iounmap(pdev, host_set->mmio_base); +} /** * ata_pci_init_native_mode - Initialize native-mode driver * @pdev: pci device to be initialized * @port: array[2] of pointers to port info structures. + * @ports: bitmap of ports present * * Utility function which allocates and initializes an * ata_probe_ent structure for a standard dual-port * PIO-based IDE controller. The returned ata_probe_ent * structure can be passed to ata_device_add(). The returned * ata_probe_ent structure should then be freed with kfree(). + * + * The caller need only pass the address of the primary port, the + * secondary will be deduced automatically. If the device has non + * standard secondary port mappings this function can be called twice, + * once for each interface. */ -#ifdef CONFIG_PCI struct ata_probe_ent * -ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port) +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int ports) { struct ata_probe_ent *probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); + int p = 0; + if (!probe_ent) return NULL; - probe_ent->n_ports = 2; probe_ent->irq = pdev->irq; probe_ent->irq_flags = SA_SHIRQ; + probe_ent->private_data = port[0]->private_data; - probe_ent->port[0].cmd_addr = pci_resource_start(pdev, 0); - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = - pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - - probe_ent->port[1].cmd_addr = pci_resource_start(pdev, 2); - probe_ent->port[1].altstatus_addr = - probe_ent->port[1].ctl_addr = - pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; - probe_ent->port[1].bmdma_addr = pci_resource_start(pdev, 4) + 8; - - ata_std_ports(&probe_ent->port[0]); - ata_std_ports(&probe_ent->port[1]); + if (ports & ATA_PORT_PRIMARY) { + probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 0); + probe_ent->port[p].altstatus_addr = + probe_ent->port[p].ctl_addr = + pci_resource_start(pdev, 1) | ATA_PCI_CTL_OFS; + probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4); + ata_std_ports(&probe_ent->port[p]); + p++; + } + + if (ports & ATA_PORT_SECONDARY) { + probe_ent->port[p].cmd_addr = pci_resource_start(pdev, 2); + probe_ent->port[p].altstatus_addr = + probe_ent->port[p].ctl_addr = + pci_resource_start(pdev, 3) | ATA_PCI_CTL_OFS; + probe_ent->port[p].bmdma_addr = pci_resource_start(pdev, 4) + 8; + ata_std_ports(&probe_ent->port[p]); + p++; + } + probe_ent->n_ports = p; return probe_ent; } -static struct ata_probe_ent * -ata_pci_init_legacy_mode(struct pci_dev *pdev, struct ata_port_info **port, - struct ata_probe_ent **ppe2) +static struct ata_probe_ent *ata_pci_init_legacy_port(struct pci_dev *pdev, struct ata_port_info *port, int port_num) { - struct ata_probe_ent *probe_ent, *probe_ent2; + struct ata_probe_ent *probe_ent; - probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[0]); + probe_ent = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port); if (!probe_ent) return NULL; - probe_ent2 = ata_probe_ent_alloc(pci_dev_to_dev(pdev), port[1]); - if (!probe_ent2) { - kfree(probe_ent); - return NULL; - } - - probe_ent->n_ports = 1; - probe_ent->irq = 14; - probe_ent->hard_port_no = 0; probe_ent->legacy_mode = 1; + probe_ent->n_ports = 1; + probe_ent->hard_port_no = port_num; + probe_ent->private_data = port->private_data; - probe_ent2->n_ports = 1; - probe_ent2->irq = 15; - - probe_ent2->hard_port_no = 1; - probe_ent2->legacy_mode = 1; - - probe_ent->port[0].cmd_addr = 0x1f0; - probe_ent->port[0].altstatus_addr = - probe_ent->port[0].ctl_addr = 0x3f6; - probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4); - - probe_ent2->port[0].cmd_addr = 0x170; - probe_ent2->port[0].altstatus_addr = - probe_ent2->port[0].ctl_addr = 0x376; - probe_ent2->port[0].bmdma_addr = pci_resource_start(pdev, 4)+8; - + switch(port_num) + { + case 0: + probe_ent->irq = 14; + probe_ent->port[0].cmd_addr = 0x1f0; + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = 0x3f6; + break; + case 1: + probe_ent->irq = 15; + probe_ent->port[0].cmd_addr = 0x170; + probe_ent->port[0].altstatus_addr = + probe_ent->port[0].ctl_addr = 0x376; + break; + } + probe_ent->port[0].bmdma_addr = pci_resource_start(pdev, 4) + 8 * port_num; ata_std_ports(&probe_ent->port[0]); - ata_std_ports(&probe_ent2->port[0]); - - *ppe2 = probe_ent2; return probe_ent; } @@ -4172,13 +4683,12 @@ ata_pci_init_legacy_mode(struct pci_dev * * RETURNS: * Zero on success, negative on errno-based value on error. - * */ int ata_pci_init_one (struct pci_dev *pdev, struct ata_port_info **port_info, unsigned int n_ports) { - struct ata_probe_ent *probe_ent, *probe_ent2 = NULL; + struct ata_probe_ent *probe_ent = NULL, *probe_ent2 = NULL; struct ata_port_info *port[2]; u8 tmp8, mask; unsigned int legacy_mode = 0; @@ -4195,7 +4705,7 @@ int ata_pci_init_one (struct pci_dev *pd if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0 && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { - /* TODO: support transitioning to native mode? */ + /* TODO: What if one channel is in native mode ... */ pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); mask = (1 << 2) | (1 << 0); if ((tmp8 & mask) != mask) @@ -4203,11 +4713,20 @@ int ata_pci_init_one (struct pci_dev *pd } /* FIXME... */ - if ((!legacy_mode) && (n_ports > 1)) { - printk(KERN_ERR "ata: BUG: native mode, n_ports > 1\n"); - return -EINVAL; + if ((!legacy_mode) && (n_ports > 2)) { + printk(KERN_ERR "ata: BUG: native mode, n_ports > 2\n"); + n_ports = 2; + /* For now */ } + /* FIXME: Really for ATA it isn't safe because the device may be + multi-purpose and we want to leave it alone if it was already + enabled. Secondly for shared use as Arjan says we want refcounting + + Checking dev->is_enabled is insufficient as this is not set at + boot for the primary video which is BIOS enabled + */ + rc = pci_enable_device(pdev); if (rc) return rc; @@ -4241,12 +4760,22 @@ int ata_pci_init_one (struct pci_dev *pd rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; if (legacy_mode) { - probe_ent = ata_pci_init_legacy_mode(pdev, port, &probe_ent2); - } else - probe_ent = ata_pci_init_native_mode(pdev, port); - if (!probe_ent) { + if (legacy_mode & (1 << 0)) + probe_ent = ata_pci_init_legacy_port(pdev, port[0], 0); + if (legacy_mode & (1 << 1)) + probe_ent2 = ata_pci_init_legacy_port(pdev, port[1], 1); + } else { + if (n_ports == 2) + probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); + else + probe_ent = ata_pci_init_native_mode(pdev, port, ATA_PORT_PRIMARY); + } + if (!probe_ent && !probe_ent2) { rc = -ENOMEM; goto err_out_regions; } @@ -4287,7 +4816,7 @@ err_out: * @pdev: PCI device that was removed * * PCI layer indicates to libata via this hook that - * hot-unplug or module unload event has occured. + * hot-unplug or module unload event has occurred. * Handle this by unregistering all objects associated * with this PCI device. Free those objects. Then finally * release PCI resources and disable device. @@ -4300,62 +4829,15 @@ void ata_pci_remove_one (struct pci_dev { struct device *dev = pci_dev_to_dev(pdev); struct ata_host_set *host_set = dev_get_drvdata(dev); - struct ata_port *ap; - unsigned int i; - Scsi_Host_Template *sht; - int rc; - - /* FIXME: this unregisters all ports attached to the - * Scsi_Host_Template given. We _might_ have multiple - * templates (though we don't ATM), so this is ok... for now. - */ - ap = host_set->ports[0]; - sht = ap->host->hostt; - rc = scsi_unregister_module(MODULE_SCSI_HA, sht); - /* FIXME: handle 'rc' failure? */ - - free_irq(host_set->irq, host_set); - - for (i = 0; i < host_set->n_ports; i++) { - ap = host_set->ports[i]; - - if ((ap->flags & ATA_FLAG_NO_LEGACY) == 0) { - struct ata_ioports *ioaddr = &ap->ioaddr; - - if (ioaddr->cmd_addr == 0x1f0) - release_region(0x1f0, 8); - else if (ioaddr->cmd_addr == 0x170) - release_region(0x170, 8); - } - } - - if (host_set->ops->host_stop) - host_set->ops->host_stop(host_set); - - kfree(host_set); + ata_host_set_remove(host_set); pci_release_regions(pdev); pci_disable_device(pdev); dev_set_drvdata(dev, NULL); } -/** - * ata_add_to_probe_list - add an entry to the list of things - * to be probed. - * @probe_ent: describes device to be probed. - * - * LOCKING: - */ - -void ata_add_to_probe_list(struct ata_probe_ent *probe_ent) -{ - spin_lock(&ata_module_lock); - list_add_tail(&probe_ent->node, &ata_probe_list); - spin_unlock(&ata_module_lock); -} - /* move to PCI subsystem */ -int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits) +int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits) { unsigned long tmp = 0; @@ -4403,6 +4885,27 @@ static void __exit ata_exit(void) module_init(ata_init); module_exit(ata_exit); +static unsigned long ratelimit_time; +static spinlock_t ata_ratelimit_lock = SPIN_LOCK_UNLOCKED; + +int ata_ratelimit(void) +{ + int rc; + unsigned long flags; + + spin_lock_irqsave(&ata_ratelimit_lock, flags); + + if (time_after(jiffies, ratelimit_time)) { + rc = 1; + ratelimit_time = jiffies + (HZ/5); + } else + rc = 0; + + spin_unlock_irqrestore(&ata_ratelimit_lock, flags); + + return rc; +} + /* * libata is essentially a library of internal helper functions for * low-level ATA host controller drivers. As such, the API/ABI is @@ -4413,6 +4916,7 @@ module_exit(ata_exit); EXPORT_SYMBOL_GPL(ata_std_bios_param); EXPORT_SYMBOL_GPL(ata_std_ports); EXPORT_SYMBOL_GPL(ata_device_add); +EXPORT_SYMBOL_GPL(ata_host_set_remove); EXPORT_SYMBOL_GPL(ata_sg_init); EXPORT_SYMBOL_GPL(ata_sg_init_one); EXPORT_SYMBOL_GPL(ata_qc_complete); @@ -4426,7 +4930,6 @@ EXPORT_SYMBOL_GPL(ata_tf_to_fis); EXPORT_SYMBOL_GPL(ata_tf_from_fis); EXPORT_SYMBOL_GPL(ata_check_status); EXPORT_SYMBOL_GPL(ata_altstatus); -EXPORT_SYMBOL_GPL(ata_chk_err); EXPORT_SYMBOL_GPL(ata_exec_command); EXPORT_SYMBOL_GPL(ata_port_start); EXPORT_SYMBOL_GPL(ata_port_stop); @@ -4443,6 +4946,7 @@ EXPORT_SYMBOL_GPL(sata_phy_reset); EXPORT_SYMBOL_GPL(__sata_phy_reset); EXPORT_SYMBOL_GPL(ata_bus_reset); EXPORT_SYMBOL_GPL(ata_port_disable); +EXPORT_SYMBOL_GPL(ata_ratelimit); EXPORT_SYMBOL_GPL(ata_scsi_ioctl); EXPORT_SYMBOL_GPL(ata_scsi_queuecmd); EXPORT_SYMBOL_GPL(ata_scsi_error); @@ -4456,8 +4960,12 @@ EXPORT_SYMBOL_GPL(ata_dev_id_string); EXPORT_SYMBOL_GPL(ata_dev_config); EXPORT_SYMBOL_GPL(ata_scsi_simulate); +EXPORT_SYMBOL_GPL(ata_timing_compute); +EXPORT_SYMBOL_GPL(ata_timing_merge); + #ifdef CONFIG_PCI EXPORT_SYMBOL_GPL(pci_test_config_bits); +EXPORT_SYMBOL_GPL(ata_pci_host_stop); EXPORT_SYMBOL_GPL(ata_pci_init_native_mode); EXPORT_SYMBOL_GPL(ata_pci_init_one); EXPORT_SYMBOL_GPL(ata_pci_remove_one); diff -Nur -p linux-2.4.32/drivers/scsi/libata.h linux-2.4.33-rc2/drivers/scsi/libata.h --- linux-2.4.32/drivers/scsi/libata.h 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/libata.h 2006-06-21 10:40:43.000000000 -0300 @@ -1,32 +1,35 @@ /* - libata.h - helper library for ATA - - Copyright 2003-2004 Red Hat, Inc. All rights reserved. - Copyright 2003-2004 Jeff Garzik - - The contents of this file are subject to the Open - Software License version 1.1 that can be found at - http://www.opensource.org/licenses/osl-1.1.txt and is included herein - by reference. - - Alternatively, the contents of this file may be used under the terms - of the GNU General Public License version 2 (the "GPL") as distributed - in the kernel source COPYING file, in which case the provisions of - the GPL are applicable instead of the above. If you wish to allow - the use of your version of this file only under the terms of the - GPL and not to allow others to use your version of this file under - the OSL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the GPL. - If you do not delete the provisions above, a recipient may use your - version of this file under either the OSL or the GPL. - + * libata.h - helper library for ATA + * + * Copyright 2003-2004 Red Hat, Inc. All rights reserved. + * Copyright 2003-2004 Jeff Garzik + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * */ #ifndef __LIBATA_H__ #define __LIBATA_H__ #define DRV_NAME "libata" -#define DRV_VERSION "1.11" /* must be exactly four chars */ +#define DRV_VERSION "1.20" /* must be exactly four chars */ struct ata_scsi_args { u16 *id; @@ -35,19 +38,22 @@ struct ata_scsi_args { }; /* libata-core.c */ +extern int atapi_enabled; +extern int ata_qc_complete_noop(struct ata_queued_cmd *qc, unsigned int err_mask); extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, struct ata_device *dev); +extern void ata_rwcmd_protocol(struct ata_queued_cmd *qc); extern void ata_qc_free(struct ata_queued_cmd *qc); extern int ata_qc_issue(struct ata_queued_cmd *qc); extern int ata_check_atapi_dma(struct ata_queued_cmd *qc); extern void ata_dev_select(struct ata_port *ap, unsigned int device, unsigned int wait, unsigned int can_sleep); -extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); extern void swap_buf_le16(u16 *buf, unsigned int buf_words); +extern int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg); +extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg); /* libata-scsi.c */ -extern void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat); extern int ata_scsi_error(struct Scsi_Host *host); extern unsigned int ata_scsiop_inq_std(struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen); @@ -72,18 +78,10 @@ extern unsigned int ata_scsiop_report_lu extern void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq); -extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, +extern void ata_scsi_set_sense(struct scsi_cmnd *cmd, + u8 sk, u8 asc, u8 ascq); +extern void ata_scsi_rbuf_fill(struct ata_scsi_args *args, unsigned int (*actor) (struct ata_scsi_args *args, u8 *rbuf, unsigned int buflen)); -static inline void ata_bad_scsiop(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - ata_scsi_badcmd(cmd, done, 0x20, 0x00); -} - -static inline void ata_bad_cdb(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)) -{ - ata_scsi_badcmd(cmd, done, 0x24, 0x00); -} - #endif /* __LIBATA_H__ */ diff -Nur -p linux-2.4.32/drivers/scsi/libata-scsi.c linux-2.4.33-rc2/drivers/scsi/libata-scsi.c --- linux-2.4.32/drivers/scsi/libata-scsi.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/libata-scsi.c 2006-06-21 10:40:43.000000000 -0300 @@ -1,25 +1,36 @@ /* - libata-scsi.c - helper library for ATA - - Copyright 2003-2004 Red Hat, Inc. All rights reserved. - Copyright 2003-2004 Jeff Garzik - - The contents of this file are subject to the Open - Software License version 1.1 that can be found at - http://www.opensource.org/licenses/osl-1.1.txt and is included herein - by reference. - - Alternatively, the contents of this file may be used under the terms - of the GNU General Public License version 2 (the "GPL") as distributed - in the kernel source COPYING file, in which case the provisions of - the GPL are applicable instead of the above. If you wish to allow - the use of your version of this file only under the terms of the - GPL and not to allow others to use your version of this file under - the OSL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the GPL. - If you do not delete the provisions above, a recipient may use your - version of this file under either the OSL or the GPL. - + * libata-scsi.c - helper library for ATA + * + * Maintained by: Jeff Garzik + * Please ALWAYS copy linux-ide@vger.kernel.org + * on emails. + * + * Copyright 2003-2004 Red Hat, Inc. All rights reserved. + * Copyright 2003-2004 Jeff Garzik + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware documentation available from + * - http://www.t10.org/ + * - http://www.t13.org/ + * */ #include @@ -31,15 +42,65 @@ #include #include "sd.h" #include +#include #include #include "libata.h" -typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, u8 *scsicmd); +#define SECTOR_SIZE 512 + +typedef unsigned int (*ata_xlat_func_t)(struct ata_queued_cmd *qc, const u8 *scsicmd); static struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev); +ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev); + +#define RW_RECOVERY_MPAGE 0x1 +#define RW_RECOVERY_MPAGE_LEN 12 +#define CACHE_MPAGE 0x8 +#define CACHE_MPAGE_LEN 20 +#define CONTROL_MPAGE 0xa +#define CONTROL_MPAGE_LEN 12 +#define ALL_MPAGES 0x3f +#define ALL_SUB_MPAGES 0xff + + +static const u8 def_rw_recovery_mpage[] = { + RW_RECOVERY_MPAGE, + RW_RECOVERY_MPAGE_LEN - 2, + (1 << 7) | /* AWRE, sat-r06 say it shall be 0 */ + (1 << 6), /* ARRE (auto read reallocation) */ + 0, /* read retry count */ + 0, 0, 0, 0, + 0, /* write retry count */ + 0, 0, 0 +}; + +static const u8 def_cache_mpage[CACHE_MPAGE_LEN] = { + CACHE_MPAGE, + CACHE_MPAGE_LEN - 2, + 0, /* contains WCE, needs to be 0 for logic */ + 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, /* contains DRA, needs to be 0 for logic */ + 0, 0, 0, 0, 0, 0, 0 +}; + +static const u8 def_control_mpage[CONTROL_MPAGE_LEN] = { + CONTROL_MPAGE, + CONTROL_MPAGE_LEN - 2, + 2, /* DSENSE=0, GLTSD=1 */ + 0, /* [QAM+QERR may be 1, see 05-359r1] */ + 0, 0, 0, 0, 0xff, 0xff, + 0, 30 /* extended self test time, see 05-359r1 */ +}; +static void ata_scsi_invalid_field(struct scsi_cmnd *cmd, + void (*done)(struct scsi_cmnd *)) +{ + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + done(cmd); +} + /** * ata_std_bios_param - generic bios head/sector/cylinder calculator used by sd. * @disk: SCSI device for which BIOS geometry is to be determined @@ -68,6 +129,150 @@ int ata_std_bios_param(Disk * disk, /* S return 0; } +/** + * ata_cmd_ioctl - Handler for HDIO_DRIVE_CMD ioctl + * @scsidev: Device to which we are issuing command + * @arg: User provided data for issuing command + * + * LOCKING: + * Defined by the SCSI layer. We don't really care. + * + * RETURNS: + * Zero on success, negative errno on error. + */ + +int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg) +{ + int rc = 0; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 args[4], *argbuf = NULL; + int argsize = 0; + struct scsi_request *sreq; + + if (NULL == (void *)arg) + return -EINVAL; + + if (copy_from_user(args, arg, sizeof(args))) + return -EFAULT; + + sreq = scsi_allocate_request(scsidev); + if (!sreq) + return -EINTR; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + + if (args[3]) { + argsize = SECTOR_SIZE * args[3]; + argbuf = kmalloc(argsize, GFP_KERNEL); + if (argbuf == NULL) { + rc = -ENOMEM; + goto error; + } + + scsi_cmd[1] = (4 << 1); /* PIO Data-in */ + scsi_cmd[2] = 0x0e; /* no off.line or cc, read from dev, + block count in sector count field */ + sreq->sr_data_direction = DMA_FROM_DEVICE; + } else { + scsi_cmd[1] = (3 << 1); /* Non-data */ + /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ + sreq->sr_data_direction = DMA_NONE; + } + + scsi_cmd[0] = ATA_16; + + scsi_cmd[4] = args[2]; + if (args[0] == WIN_SMART) { /* hack -- ide driver does this too... */ + scsi_cmd[6] = args[3]; + scsi_cmd[8] = args[1]; + scsi_cmd[10] = 0x4f; + scsi_cmd[12] = 0xc2; + } else { + scsi_cmd[6] = args[1]; + } + scsi_cmd[14] = args[0]; + + /* Good values for timeout and retries? Values below + from scsi_ioctl_send_command() for default case... */ + scsi_wait_req(sreq, scsi_cmd, argbuf, argsize, (10*HZ), 5); + + if (sreq->sr_result) { + rc = -EIO; + goto error; + } + + /* Need code to retrieve data from check condition? */ + + if ((argbuf) + && copy_to_user((void *)(arg + sizeof(args)), argbuf, argsize)) + rc = -EFAULT; +error: + scsi_release_request(sreq); + + if (argbuf) + kfree(argbuf); + + return rc; +} + +/** + * ata_task_ioctl - Handler for HDIO_DRIVE_TASK ioctl + * @scsidev: Device to which we are issuing command + * @arg: User provided data for issuing command + * + * LOCKING: + * Defined by the SCSI layer. We don't really care. + * + * RETURNS: + * Zero on success, negative errno on error. + */ +int ata_task_ioctl(struct scsi_device *scsidev, void __user *arg) +{ + int rc = 0; + u8 scsi_cmd[MAX_COMMAND_SIZE]; + u8 args[7]; + struct scsi_request *sreq; + + if (NULL == (void *)arg) + return -EINVAL; + + if (copy_from_user(args, arg, sizeof(args))) + return -EFAULT; + + memset(scsi_cmd, 0, sizeof(scsi_cmd)); + scsi_cmd[0] = ATA_16; + scsi_cmd[1] = (3 << 1); /* Non-data */ + /* scsi_cmd[2] is already 0 -- no off.line, cc, or data xfer */ + scsi_cmd[4] = args[1]; + scsi_cmd[6] = args[2]; + scsi_cmd[8] = args[3]; + scsi_cmd[10] = args[4]; + scsi_cmd[12] = args[5]; + scsi_cmd[14] = args[0]; + + sreq = scsi_allocate_request(scsidev); + if (!sreq) { + rc = -EINTR; + goto error; + } + + sreq->sr_data_direction = DMA_NONE; + /* Good values for timeout and retries? Values below + from scsi_ioctl_send_command() for default case... */ + scsi_wait_req(sreq, scsi_cmd, NULL, 0, (10*HZ), 5); + + if (sreq->sr_result) { + rc = -EIO; + goto error; + } + + /* Need code to retrieve data from check condition? */ + +error: + scsi_release_request(sreq); + return rc; +} + int ata_scsi_ioctl(struct scsi_device *scsidev, int cmd, void __user *arg) { struct ata_port *ap; @@ -97,6 +302,16 @@ int ata_scsi_ioctl(struct scsi_device *s return -EINVAL; return 0; + case HDIO_DRIVE_CMD: + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + return ata_cmd_ioctl(scsidev, arg); + + case HDIO_DRIVE_TASK: + if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO)) + return -EACCES; + return ata_task_ioctl(scsidev, arg); + default: rc = -ENOTTY; break; @@ -140,10 +355,10 @@ struct ata_queued_cmd *ata_scsi_qc_new(s qc->scsidone = done; if (cmd->use_sg) { - qc->sg = (struct scatterlist *) cmd->request_buffer; + qc->__sg = (struct scatterlist *) cmd->request_buffer; qc->n_elem = cmd->use_sg; } else { - qc->sg = &qc->sgent; + qc->__sg = &qc->sgent; qc->n_elem = 1; } } else { @@ -155,24 +370,71 @@ struct ata_queued_cmd *ata_scsi_qc_new(s } /** + * ata_dump_status - user friendly display of error info + * @id: id of the port in question + * @tf: ptr to filled out taskfile + * + * Decode and dump the ATA error/status registers for the user so + * that they have some idea what really happened at the non + * make-believe layer. + * + * LOCKING: + * inherited from caller + */ +void ata_dump_status(unsigned id, struct ata_taskfile *tf) +{ + u8 stat = tf->command, err = tf->feature; + + printk(KERN_WARNING "ata%u: status=0x%02x { ", id, stat); + if (stat & ATA_BUSY) { + printk("Busy }\n"); /* Data is not valid in this case */ + } else { + if (stat & 0x40) printk("DriveReady "); + if (stat & 0x20) printk("DeviceFault "); + if (stat & 0x10) printk("SeekComplete "); + if (stat & 0x08) printk("DataRequest "); + if (stat & 0x04) printk("CorrectedError "); + if (stat & 0x02) printk("Index "); + if (stat & 0x01) printk("Error "); + printk("}\n"); + + if (err) { + printk(KERN_WARNING "ata%u: error=0x%02x { ", id, err); + if (err & 0x04) printk("DriveStatusError "); + if (err & 0x80) { + if (err & 0x04) printk("BadCRC "); + else printk("Sector "); + } + if (err & 0x40) printk("UncorrectableError "); + if (err & 0x10) printk("SectorIdNotFound "); + if (err & 0x02) printk("TrackZeroNotFound "); + if (err & 0x01) printk("AddrMarkNotFound "); + printk("}\n"); + } + } +} + +/** * ata_to_sense_error - convert ATA error to SCSI error - * @qc: Command that we are erroring out + * @id: ATA device number * @drv_stat: value contained in ATA status register + * @drv_err: value contained in ATA error register + * @sk: the sense key we'll fill out + * @asc: the additional sense code we'll fill out + * @ascq: the additional sense code qualifier we'll fill out * - * Converts an ATA error into a SCSI error. While we are at it - * we decode and dump the ATA error for the user so that they - * have some idea what really happened at the non make-believe - * layer. + * Converts an ATA error into a SCSI error. Fill out pointers to + * SK, ASC, and ASCQ bytes for later use in fixed or descriptor + * format sense blocks. * * LOCKING: * spin_lock_irqsave(host_set lock) */ - -void ata_to_sense_error(struct ata_queued_cmd *qc, u8 drv_stat) +void ata_to_sense_error(unsigned id, u8 drv_stat, u8 drv_err, u8 *sk, u8 *asc, + u8 *ascq) { - struct scsi_cmnd *cmd = qc->scsicmd; - u8 err = 0; - unsigned char *sb = cmd->sense_buffer; + int i; + /* Based on the 3ware driver translation table */ static unsigned char sense_table[][4] = { /* BBD|ECC|ID|MAR */ @@ -213,105 +475,192 @@ void ata_to_sense_error(struct ata_queue {0x04, RECOVERED_ERROR, 0x11, 0x00}, // Recovered ECC error Medium error, recovered {0xFF, 0xFF, 0xFF, 0xFF}, // END mark }; - int i = 0; - - cmd->result = SAM_STAT_CHECK_CONDITION; /* * Is this an error we can process/parse */ + if (drv_stat & ATA_BUSY) { + drv_err = 0; /* Ignore the err bits, they're invalid */ + } - if(drv_stat & ATA_ERR) - /* Read the err bits */ - err = ata_chk_err(qc->ap); - - /* Display the ATA level error info */ - - printk(KERN_WARNING "ata%u: status=0x%02x { ", qc->ap->id, drv_stat); - if(drv_stat & 0x80) - { - printk("Busy "); - err = 0; /* Data is not valid in this case */ + if (drv_err) { + /* Look for drv_err */ + for (i = 0; sense_table[i][0] != 0xFF; i++) { + /* Look for best matches first */ + if ((sense_table[i][0] & drv_err) == + sense_table[i][0]) { + *sk = sense_table[i][1]; + *asc = sense_table[i][2]; + *ascq = sense_table[i][3]; + goto translate_done; + } + } + /* No immediate match */ + printk(KERN_WARNING "ata%u: no sense translation for " + "error 0x%02x\n", id, drv_err); } - else { - if(drv_stat & 0x40) printk("DriveReady "); - if(drv_stat & 0x20) printk("DeviceFault "); - if(drv_stat & 0x10) printk("SeekComplete "); - if(drv_stat & 0x08) printk("DataRequest "); - if(drv_stat & 0x04) printk("CorrectedError "); - if(drv_stat & 0x02) printk("Index "); - if(drv_stat & 0x01) printk("Error "); - } - printk("}\n"); - - if(err) - { - printk(KERN_WARNING "ata%u: error=0x%02x { ", qc->ap->id, err); - if(err & 0x04) printk("DriveStatusError "); - if(err & 0x80) - { - if(err & 0x04) - printk("BadCRC "); - else - printk("Sector "); + + /* Fall back to interpreting status bits */ + for (i = 0; stat_table[i][0] != 0xFF; i++) { + if (stat_table[i][0] & drv_stat) { + *sk = stat_table[i][1]; + *asc = stat_table[i][2]; + *ascq = stat_table[i][3]; + goto translate_done; } - if(err & 0x40) printk("UncorrectableError "); - if(err & 0x10) printk("SectorIdNotFound "); - if(err & 0x02) printk("TrackZeroNotFound "); - if(err & 0x01) printk("AddrMarkNotFound "); - printk("}\n"); + } + /* No error? Undecoded? */ + printk(KERN_WARNING "ata%u: no sense translation for status: 0x%02x\n", + id, drv_stat); + + /* For our last chance pick, use medium read error because + * it's much more common than an ATA drive telling you a write + * has failed. + */ + *sk = MEDIUM_ERROR; + *asc = 0x11; /* "unrecovered read error" */ + *ascq = 0x04; /* "auto-reallocation failed" */ + + translate_done: + printk(KERN_ERR "ata%u: translated ATA stat/err 0x%02x/%02x to " + "SCSI SK/ASC/ASCQ 0x%x/%02x/%02x\n", id, drv_stat, drv_err, + *sk, *asc, *ascq); + return; +} + +/* + * ata_gen_ata_desc_sense - Generate check condition sense block. + * @qc: Command that completed. + * + * This function is specific to the ATA descriptor format sense + * block specified for the ATA pass through commands. Regardless + * of whether the command errored or not, return a sense + * block. Copy all controller registers into the sense + * block. Clear sense key, ASC & ASCQ if there is no error. + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + */ +void ata_gen_ata_desc_sense(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + unsigned char *desc = sb + 8; + + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; - /* Should we dump sector info here too ?? */ + /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ + if (tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[1], &sb[2], &sb[3]); + sb[1] &= 0x0f; } + /* + * Sense data is current and format is descriptor. + */ + sb[0] = 0x72; - /* Look for err */ - while(sense_table[i][0] != 0xFF) - { - /* Look for best matches first */ - if((sense_table[i][0] & err) == sense_table[i][0]) - { - sb[0] = 0x70; - sb[2] = sense_table[i][1]; - sb[7] = 0x0a; - sb[12] = sense_table[i][2]; - sb[13] = sense_table[i][3]; - return; - } - i++; + desc[0] = 0x09; + + /* + * Set length of additional sense data. + * Since we only populate descriptor 0, the total + * length is the same (fixed) length as descriptor 0. + */ + desc[1] = sb[7] = 14; + + /* + * Copy registers into sense buffer. + */ + desc[2] = 0x00; + desc[3] = tf->feature; /* == error reg */ + desc[5] = tf->nsect; + desc[7] = tf->lbal; + desc[9] = tf->lbam; + desc[11] = tf->lbah; + desc[12] = tf->device; + desc[13] = tf->command; /* == status reg */ + + /* + * Fill in Extend bit, and the high order bytes + * if applicable. + */ + if (tf->flags & ATA_TFLAG_LBA48) { + desc[2] |= 0x01; + desc[4] = tf->hob_nsect; + desc[6] = tf->hob_lbal; + desc[8] = tf->hob_lbam; + desc[10] = tf->hob_lbah; } - /* No immediate match */ - if(err) - printk(KERN_DEBUG "ata%u: no sense translation for 0x%02x\n", qc->ap->id, err); +} - i = 0; - /* Fall back to interpreting status bits */ - while(stat_table[i][0] != 0xFF) - { - if(stat_table[i][0] & drv_stat) - { - sb[0] = 0x70; - sb[2] = stat_table[i][1]; - sb[7] = 0x0a; - sb[12] = stat_table[i][2]; - sb[13] = stat_table[i][3]; - return; - } - i++; +/** + * ata_gen_fixed_sense - generate a SCSI fixed sense block + * @qc: Command that we are erroring out + * + * Leverage ata_to_sense_error() to give us the codes. Fit our + * LBA in here if there's room. + * + * LOCKING: + * inherited from caller + */ +void ata_gen_fixed_sense(struct ata_queued_cmd *qc) +{ + struct scsi_cmnd *cmd = qc->scsicmd; + struct ata_taskfile *tf = &qc->tf; + unsigned char *sb = cmd->sense_buffer; + + memset(sb, 0, SCSI_SENSE_BUFFERSIZE); + + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + + /* + * Read the controller registers. + */ + assert(NULL != qc->ap->ops->tf_read); + qc->ap->ops->tf_read(qc->ap, tf); + + /* + * Use ata_to_sense_error() to map status register bits + * onto sense key, asc & ascq. + */ + if (tf->command & (ATA_BUSY | ATA_DF | ATA_ERR | ATA_DRQ)) { + ata_to_sense_error(qc->ap->id, tf->command, tf->feature, + &sb[2], &sb[12], &sb[13]); + sb[2] &= 0x0f; } - /* No error ?? */ - printk(KERN_ERR "ata%u: called with no error (%02X)!\n", qc->ap->id, drv_stat); - /* additional-sense-code[-qualifier] */ sb[0] = 0x70; - sb[2] = MEDIUM_ERROR; - sb[7] = 0x0A; - if (cmd->sc_data_direction == SCSI_DATA_READ) { - sb[12] = 0x11; /* "unrecovered read error" */ - sb[13] = 0x04; - } else { - sb[12] = 0x0C; /* "write error - */ - sb[13] = 0x02; /* auto-reallocation failed" */ + sb[7] = 0x0a; + + if (tf->flags & ATA_TFLAG_LBA48) { + /* TODO: find solution for LBA48 descriptors */ + } + + else if (tf->flags & ATA_TFLAG_LBA) { + /* A small (28b) LBA will fit in the 32b info field */ + sb[0] |= 0x80; /* set valid bit */ + sb[3] = tf->device & 0x0f; + sb[4] = tf->lbah; + sb[5] = tf->lbam; + sb[6] = tf->lbal; + } + + else { + /* TODO: C/H/S */ } } @@ -350,6 +699,76 @@ int ata_scsi_error(struct Scsi_Host *hos } /** + * ata_scsi_start_stop_xlat - Translate SCSI START STOP UNIT command + * @qc: Storage for translated ATA taskfile + * @scsicmd: SCSI command to translate + * + * Sets up an ATA taskfile to issue STANDBY (to stop) or READ VERIFY + * (to start). Perhaps these commands should be preceded by + * CHECK POWER MODE to see what power mode the device is already in. + * [See SAT revision 5 at www.t10.org] + * + * LOCKING: + * spin_lock_irqsave(host_set lock) + * + * RETURNS: + * Zero on success, non-zero on error. + */ + +static unsigned int ata_scsi_start_stop_xlat(struct ata_queued_cmd *qc, + const u8 *scsicmd) +{ + struct ata_taskfile *tf = &qc->tf; + + tf->flags |= ATA_TFLAG_DEVICE | ATA_TFLAG_ISADDR; + tf->protocol = ATA_PROT_NODATA; + if (scsicmd[1] & 0x1) { + ; /* ignore IMMED bit, violates sat-r05 */ + } + if (scsicmd[4] & 0x2) + goto invalid_fld; /* LOEJ bit set not supported */ + if (((scsicmd[4] >> 4) & 0xf) != 0) + goto invalid_fld; /* power conditions not supported */ + if (scsicmd[4] & 0x1) { + tf->nsect = 1; /* 1 sector, lba=0 */ + + if (qc->dev->flags & ATA_DFLAG_LBA) { + qc->tf.flags |= ATA_TFLAG_LBA; + + tf->lbah = 0x0; + tf->lbam = 0x0; + tf->lbal = 0x0; + tf->device |= ATA_LBA; + } else { + /* CHS */ + tf->lbal = 0x1; /* sect */ + tf->lbam = 0x0; /* cyl low */ + tf->lbah = 0x0; /* cyl high */ + } + + tf->command = ATA_CMD_VERIFY; /* READ VERIFY */ + } else { + tf->nsect = 0; /* time period value (0 implies now) */ + tf->command = ATA_CMD_STANDBY; + /* Consider: ATA STANDBY IMMEDIATE command */ + } + /* + * Standby and Idle condition timers could be implemented but that + * would require libata to implement the Power condition mode page + * and allow the user to change it. Changing mode pages requires + * MODE SELECT to be implemented. + */ + + return 0; + +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; +} + + +/** * ata_scsi_flush_xlat - Translate SCSI SYNCHRONIZE CACHE command * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate (ignored) @@ -364,14 +783,14 @@ int ata_scsi_error(struct Scsi_Host *hos * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_flush_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; tf->flags |= ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - if ((tf->flags & ATA_TFLAG_LBA48) && + if ((qc->dev->flags & ATA_DFLAG_LBA48) && (ata_id_has_flush_ext(qc->dev->id))) tf->command = ATA_CMD_FLUSH_EXT; else @@ -381,6 +800,99 @@ static unsigned int ata_scsi_flush_xlat( } /** + * scsi_6_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 6-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_6_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("six-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 8; + lba |= ((u64)scsicmd[3]); + + len |= ((u32)scsicmd[4]); + + *plba = lba; + *plen = len; +} + +/** + * scsi_10_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 10-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_10_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("ten-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 24; + lba |= ((u64)scsicmd[3]) << 16; + lba |= ((u64)scsicmd[4]) << 8; + lba |= ((u64)scsicmd[5]); + + len |= ((u32)scsicmd[7]) << 8; + len |= ((u32)scsicmd[8]); + + *plba = lba; + *plen = len; +} + +/** + * scsi_16_lba_len - Get LBA and transfer length + * @scsicmd: SCSI command to translate + * + * Calculate LBA and transfer length for 16-byte commands. + * + * RETURNS: + * @plba: the LBA + * @plen: the transfer length + */ + +static void scsi_16_lba_len(const u8 *scsicmd, u64 *plba, u32 *plen) +{ + u64 lba = 0; + u32 len = 0; + + VPRINTK("sixteen-byte command\n"); + + lba |= ((u64)scsicmd[2]) << 56; + lba |= ((u64)scsicmd[3]) << 48; + lba |= ((u64)scsicmd[4]) << 40; + lba |= ((u64)scsicmd[5]) << 32; + lba |= ((u64)scsicmd[6]) << 24; + lba |= ((u64)scsicmd[7]) << 16; + lba |= ((u64)scsicmd[8]) << 8; + lba |= ((u64)scsicmd[9]); + + len |= ((u32)scsicmd[10]) << 24; + len |= ((u32)scsicmd[11]) << 16; + len |= ((u32)scsicmd[12]) << 8; + len |= ((u32)scsicmd[13]); + + *plba = lba; + *plen = len; +} + +/** * ata_scsi_verify_xlat - Translate SCSI VERIFY command into an ATA one * @qc: Storage for translated ATA taskfile * @scsicmd: SCSI command to translate @@ -394,82 +906,110 @@ static unsigned int ata_scsi_flush_xlat( * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_verify_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; - unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + struct ata_device *dev = qc->dev; u64 dev_sectors = qc->dev->n_sectors; - u64 sect = 0; - u32 n_sect = 0; + u64 block; + u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; tf->protocol = ATA_PROT_NODATA; - tf->device |= ATA_LBA; - - if (scsicmd[0] == VERIFY) { - sect |= ((u64)scsicmd[2]) << 24; - sect |= ((u64)scsicmd[3]) << 16; - sect |= ((u64)scsicmd[4]) << 8; - sect |= ((u64)scsicmd[5]); - - n_sect |= ((u32)scsicmd[7]) << 8; - n_sect |= ((u32)scsicmd[8]); - } - - else if (scsicmd[0] == VERIFY_16) { - sect |= ((u64)scsicmd[2]) << 56; - sect |= ((u64)scsicmd[3]) << 48; - sect |= ((u64)scsicmd[4]) << 40; - sect |= ((u64)scsicmd[5]) << 32; - sect |= ((u64)scsicmd[6]) << 24; - sect |= ((u64)scsicmd[7]) << 16; - sect |= ((u64)scsicmd[8]) << 8; - sect |= ((u64)scsicmd[9]); - - n_sect |= ((u32)scsicmd[10]) << 24; - n_sect |= ((u32)scsicmd[11]) << 16; - n_sect |= ((u32)scsicmd[12]) << 8; - n_sect |= ((u32)scsicmd[13]); - } + if (scsicmd[0] == VERIFY) + scsi_10_lba_len(scsicmd, &block, &n_block); + else if (scsicmd[0] == VERIFY_16) + scsi_16_lba_len(scsicmd, &block, &n_block); else - return 1; + goto invalid_fld; - if (!n_sect) - return 1; - if (sect >= dev_sectors) - return 1; - if ((sect + n_sect) > dev_sectors) - return 1; - if (lba48) { - if (n_sect > (64 * 1024)) - return 1; - } else { - if (n_sect > 256) - return 1; - } + if (!n_block) + goto nothing_to_do; + if (block >= dev_sectors) + goto out_of_range; + if ((block + n_block) > dev_sectors) + goto out_of_range; + + if (dev->flags & ATA_DFLAG_LBA) { + tf->flags |= ATA_TFLAG_LBA; + + if (dev->flags & ATA_DFLAG_LBA48) { + if (n_block > (64 * 1024)) + goto invalid_fld; + + /* use LBA48 */ + tf->flags |= ATA_TFLAG_LBA48; + tf->command = ATA_CMD_VERIFY_EXT; + + tf->hob_nsect = (n_block >> 8) & 0xff; + + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else { + if (n_block > 256) + goto invalid_fld; + + /* use LBA28 */ + tf->command = ATA_CMD_VERIFY; - if (lba48) { - tf->command = ATA_CMD_VERIFY_EXT; + tf->device |= (block >> 24) & 0xf; + } - tf->hob_nsect = (n_sect >> 8) & 0xff; + tf->nsect = n_block & 0xff; - tf->hob_lbah = (sect >> 40) & 0xff; - tf->hob_lbam = (sect >> 32) & 0xff; - tf->hob_lbal = (sect >> 24) & 0xff; + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; + + tf->device |= ATA_LBA; } else { - tf->command = ATA_CMD_VERIFY; + /* CHS */ + u32 sect, head, cyl, track; - tf->device |= (sect >> 24) & 0xf; + if (n_block > 256) + goto invalid_fld; + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block %u track %u cyl %u head %u sect %u\n", + (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + goto out_of_range; + + tf->command = ATA_CMD_VERIFY; + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; } - tf->nsect = n_sect & 0xff; + return 0; - tf->lbah = (sect >> 16) & 0xff; - tf->lbam = (sect >> 8) & 0xff; - tf->lbal = sect & 0xff; +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; - return 0; +out_of_range: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0); + /* "Logical Block Address out of range" */ + return 1; + +nothing_to_do: + qc->scsicmd->result = SAM_STAT_GOOD; + return 1; } /** @@ -492,107 +1032,177 @@ static unsigned int ata_scsi_verify_xlat * Zero on success, non-zero on error. */ -static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int ata_scsi_rw_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct ata_taskfile *tf = &qc->tf; - unsigned int lba48 = tf->flags & ATA_TFLAG_LBA48; + struct ata_device *dev = qc->dev; + u64 block; + u32 n_block; tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - tf->protocol = qc->dev->xfer_protocol; - tf->device |= ATA_LBA; - if (scsicmd[0] == READ_10 || scsicmd[0] == READ_6 || - scsicmd[0] == READ_16) { - tf->command = qc->dev->read_cmd; - } else { - tf->command = qc->dev->write_cmd; + if (scsicmd[0] == WRITE_10 || scsicmd[0] == WRITE_6 || + scsicmd[0] == WRITE_16) tf->flags |= ATA_TFLAG_WRITE; - } - if (scsicmd[0] == READ_10 || scsicmd[0] == WRITE_10) { - if (lba48) { - tf->hob_nsect = scsicmd[7]; - tf->hob_lbal = scsicmd[2]; + /* Calculate the SCSI LBA and transfer length. */ + switch (scsicmd[0]) { + case READ_10: + case WRITE_10: + scsi_10_lba_len(scsicmd, &block, &n_block); + break; + case READ_6: + case WRITE_6: + scsi_6_lba_len(scsicmd, &block, &n_block); - qc->nsect = ((unsigned int)scsicmd[7] << 8) | - scsicmd[8]; - } else { - /* if we don't support LBA48 addressing, the request - * -may- be too large. */ - if ((scsicmd[2] & 0xf0) || scsicmd[7]) - return 1; + /* for 6-byte r/w commands, transfer length 0 + * means 256 blocks of data, not 0 block. + */ + if (!n_block) + n_block = 256; + break; + case READ_16: + case WRITE_16: + scsi_16_lba_len(scsicmd, &block, &n_block); + break; + default: + DPRINTK("no-byte command\n"); + goto invalid_fld; + } - /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[2]; + /* Check and compose ATA command */ + if (!n_block) + /* For 10-byte and 16-byte SCSI R/W commands, transfer + * length 0 means transfer 0 block of data. + * However, for ATA R/W commands, sector count 0 means + * 256 or 65536 sectors, not 0 sectors as in SCSI. + * + * WARNING: one or two older ATA drives treat 0 as 0... + */ + goto nothing_to_do; + + if (dev->flags & ATA_DFLAG_LBA) { + tf->flags |= ATA_TFLAG_LBA; + + if (dev->flags & ATA_DFLAG_LBA48) { + /* The request -may- be too large for LBA48. */ + if ((block >> 48) || (n_block > 65536)) + goto out_of_range; + + /* use LBA48 */ + tf->flags |= ATA_TFLAG_LBA48; + + tf->hob_nsect = (n_block >> 8) & 0xff; + + tf->hob_lbah = (block >> 40) & 0xff; + tf->hob_lbam = (block >> 32) & 0xff; + tf->hob_lbal = (block >> 24) & 0xff; + } else { + /* use LBA28 */ + + /* The request -may- be too large for LBA28. */ + if ((block >> 28) || (n_block > 256)) + goto out_of_range; - qc->nsect = scsicmd[8]; + tf->device |= (block >> 24) & 0xf; } - tf->nsect = scsicmd[8]; - tf->lbal = scsicmd[5]; - tf->lbam = scsicmd[4]; - tf->lbah = scsicmd[3]; - - VPRINTK("ten-byte command\n"); - return 0; - } + ata_rwcmd_protocol(qc); - if (scsicmd[0] == READ_6 || scsicmd[0] == WRITE_6) { - qc->nsect = tf->nsect = scsicmd[4]; - tf->lbal = scsicmd[3]; - tf->lbam = scsicmd[2]; - tf->lbah = scsicmd[1] & 0x1f; /* mask out reserved bits */ + qc->nsect = n_block; + tf->nsect = n_block & 0xff; - VPRINTK("six-byte command\n"); - return 0; + tf->lbah = (block >> 16) & 0xff; + tf->lbam = (block >> 8) & 0xff; + tf->lbal = block & 0xff; + + tf->device |= ATA_LBA; + } else { + /* CHS */ + u32 sect, head, cyl, track; + + /* The request -may- be too large for CHS addressing. */ + if ((block >> 28) || (n_block > 256)) + goto out_of_range; + + ata_rwcmd_protocol(qc); + + /* Convert LBA to CHS */ + track = (u32)block / dev->sectors; + cyl = track / dev->heads; + head = track % dev->heads; + sect = (u32)block % dev->sectors + 1; + + DPRINTK("block %u track %u cyl %u head %u sect %u\n", + (u32)block, track, cyl, head, sect); + + /* Check whether the converted CHS can fit. + Cylinder: 0-65535 + Head: 0-15 + Sector: 1-255*/ + if ((cyl >> 16) || (head >> 4) || (sect >> 8) || (!sect)) + goto out_of_range; + + qc->nsect = n_block; + tf->nsect = n_block & 0xff; /* Sector count 0 means 256 sectors */ + tf->lbal = sect; + tf->lbam = cyl; + tf->lbah = cyl >> 8; + tf->device |= head; } - if (scsicmd[0] == READ_16 || scsicmd[0] == WRITE_16) { - /* rule out impossible LBAs and sector counts */ - if (scsicmd[2] || scsicmd[3] || scsicmd[10] || scsicmd[11]) - return 1; - - if (lba48) { - tf->hob_nsect = scsicmd[12]; - tf->hob_lbal = scsicmd[6]; - tf->hob_lbam = scsicmd[5]; - tf->hob_lbah = scsicmd[4]; - - qc->nsect = ((unsigned int)scsicmd[12] << 8) | - scsicmd[13]; - } else { - /* once again, filter out impossible non-zero values */ - if (scsicmd[4] || scsicmd[5] || scsicmd[12] || - (scsicmd[6] & 0xf0)) - return 1; - - /* stores LBA27:24 in lower 4 bits of device reg */ - tf->device |= scsicmd[6]; - - qc->nsect = scsicmd[13]; - } + return 0; - tf->nsect = scsicmd[13]; - tf->lbal = scsicmd[9]; - tf->lbam = scsicmd[8]; - tf->lbah = scsicmd[7]; +invalid_fld: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; - VPRINTK("sixteen-byte command\n"); - return 0; - } +out_of_range: + ata_scsi_set_sense(qc->scsicmd, ILLEGAL_REQUEST, 0x21, 0x0); + /* "Logical Block Address out of range" */ + return 1; - DPRINTK("no-byte command\n"); +nothing_to_do: + qc->scsicmd->result = SAM_STAT_GOOD; return 1; } -static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +static int ata_scsi_qc_complete(struct ata_queued_cmd *qc, + unsigned int err_mask) { struct scsi_cmnd *cmd = qc->scsicmd; + u8 *cdb = cmd->cmnd; + int need_sense = (err_mask != 0); - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) - ata_to_sense_error(qc, drv_stat); - else - cmd->result = SAM_STAT_GOOD; + /* For ATA pass thru (SAT) commands, generate a sense block if + * user mandated it or if there's an error. Note that if we + * generate because the user forced us to, a check condition + * is generated and the ATA register values are returned + * whether the command completed successfully or not. If there + * was no error, SK, ASC and ASCQ will all be zero. + */ + if (((cdb[0] == ATA_16) || (cdb[0] == ATA_12)) && + ((cdb[2] & 0x20) || need_sense)) { + ata_gen_ata_desc_sense(qc); + } else { + if (!need_sense) { + cmd->result = SAM_STAT_GOOD; + } else { + /* TODO: decide which descriptor format to use + * for 48b LBA devices and call that here + * instead of the fixed desc, which is only + * good for smaller LBA (and maybe CHS?) + * devices. + */ + ata_gen_fixed_sense(qc); + } + } + + if (need_sense) { + /* The ata_gen_..._sense routines fill in tf */ + ata_dump_status(qc->ap->id, &qc->tf); + } qc->scsidone(cmd); @@ -614,6 +1224,12 @@ static int ata_scsi_qc_complete(struct a * This function sets up an ata_queued_cmd structure for the * SCSI command, and sends that ata_queued_cmd to the hardware. * + * The xlat_func argument (actor) returns 0 if ready to execute + * ATA command, else 1 to finish translation. If 1 is returned + * then cmd->result (and possibly cmd->sense_buffer) are assumed + * to be set reflecting an error condition or clean (early) + * termination. + * * LOCKING: * spin_lock_irqsave(host_set lock) */ @@ -630,15 +1246,15 @@ static void ata_scsi_translate(struct at qc = ata_scsi_qc_new(ap, dev, cmd, done); if (!qc) - return; + goto err_mem; /* data is present; dma-map it */ - if (cmd->sc_data_direction == SCSI_DATA_READ || - cmd->sc_data_direction == SCSI_DATA_WRITE) { + if (cmd->sc_data_direction == DMA_FROM_DEVICE || + cmd->sc_data_direction == DMA_TO_DEVICE) { if (unlikely(cmd->request_bufflen < 1)) { printk(KERN_WARNING "ata%u(%u): WARNING: zero len r/w req\n", ap->id, dev->devno); - goto err_out; + goto err_did; } if (cmd->use_sg) @@ -653,19 +1269,28 @@ static void ata_scsi_translate(struct at qc->complete_fn = ata_scsi_qc_complete; if (xlat_func(qc, scsicmd)) - goto err_out; + goto early_finish; /* select device, send command to hardware */ if (ata_qc_issue(qc)) - goto err_out; + goto err_did; VPRINTK("EXIT\n"); return; -err_out: +early_finish: + ata_qc_free(qc); + done(cmd); + DPRINTK("EXIT - early finish (good or error)\n"); + return; + +err_did: ata_qc_free(qc); - ata_bad_cdb(cmd, done); - DPRINTK("EXIT - badcmd\n"); +err_mem: + cmd->result = (DID_ERROR << 16); + done(cmd); + DPRINTK("EXIT - internal\n"); + return; } /** @@ -732,7 +1357,8 @@ static inline void ata_scsi_rbuf_put(str * Mapping the response buffer, calling the command's handler, * and handling the handler's return value. This return value * indicates whether the handler wishes the SCSI command to be - * completed successfully, or not. + * completed successfully (0), or not (in which case cmd->result + * and sense buffer are assumed to be set). * * LOCKING: * spin_lock_irqsave(host_set lock) @@ -751,12 +1377,9 @@ void ata_scsi_rbuf_fill(struct ata_scsi_ rc = actor(args, rbuf, buflen); ata_scsi_rbuf_put(cmd, rbuf); - if (rc) - ata_bad_cdb(cmd, args->done); - else { + if (rc == 0) cmd->result = SAM_STAT_GOOD; - args->done(cmd); - } + args->done(cmd); } /** @@ -970,13 +1593,9 @@ static void ata_msense_push(u8 **ptr_io, static unsigned int ata_msense_caching(u16 *id, u8 **ptr_io, const u8 *last) { - u8 page[] = { - 0x8, /* page code */ - 0x12, /* page length */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 10 zeroes */ - 0, 0, 0, 0, 0, 0, 0, 0 /* 8 zeroes */ - }; + u8 page[CACHE_MPAGE_LEN]; + memcpy(page, def_cache_mpage, sizeof(page)); if (ata_id_wcache_enabled(id)) page[2] |= (1 << 2); /* write cache enable */ if (!ata_id_rahead_enabled(id)) @@ -1000,15 +1619,9 @@ static unsigned int ata_msense_caching(u static unsigned int ata_msense_ctl_mode(u8 **ptr_io, const u8 *last) { - const u8 page[] = {0xa, 0xa, 6, 0, 0, 0, 0, 0, 0xff, 0xff, 0, 30}; - - /* byte 2: set the descriptor format sense data bit (bit 2) - * since we need to support returning this format for SAT - * commands and any SCSI commands against a 48b LBA device. - */ - - ata_msense_push(ptr_io, last, page, sizeof(page)); - return sizeof(page); + ata_msense_push(ptr_io, last, def_control_mpage, + sizeof(def_control_mpage)); + return sizeof(def_control_mpage); } /** @@ -1025,15 +1638,10 @@ static unsigned int ata_msense_ctl_mode( static unsigned int ata_msense_rw_recovery(u8 **ptr_io, const u8 *last) { - const u8 page[] = { - 0x1, /* page code */ - 0xa, /* page length */ - (1 << 7) | (1 << 6), /* note auto r/w reallocation */ - 0, 0, 0, 0, 0, 0, 0, 0, 0 /* 9 zeroes */ - }; - ata_msense_push(ptr_io, last, page, sizeof(page)); - return sizeof(page); + ata_msense_push(ptr_io, last, def_rw_recovery_mpage, + sizeof(def_rw_recovery_mpage)); + return sizeof(def_rw_recovery_mpage); } /** @@ -1042,7 +1650,9 @@ static unsigned int ata_msense_rw_recove * @rbuf: Response buffer, to which simulated SCSI cmd output is sent. * @buflen: Response buffer length. * - * Simulate MODE SENSE commands. + * Simulate MODE SENSE commands. Assume this is invoked for direct + * access devices (e.g. disks) only. There should be no block + * descriptor for other device types. * * LOCKING: * spin_lock_irqsave(host_set lock) @@ -1052,61 +1662,115 @@ unsigned int ata_scsiop_mode_sense(struc unsigned int buflen) { u8 *scsicmd = args->cmd->cmnd, *p, *last; - unsigned int page_control, six_byte, output_len; + const u8 sat_blk_desc[] = { + 0, 0, 0, 0, /* number of blocks: sat unspecified */ + 0, + 0, 0x2, 0x0 /* block length: 512 bytes */ + }; + u8 pg, spg; + unsigned int ebd, page_control, six_byte, output_len, alloc_len, minlen; VPRINTK("ENTER\n"); six_byte = (scsicmd[0] == MODE_SENSE); - - /* we only support saved and current values (which we treat - * in the same manner) + ebd = !(scsicmd[1] & 0x8); /* dbd bit inverted == edb */ + /* + * LLBA bit in msense(10) ignored (compliant) */ + page_control = scsicmd[2] >> 6; - if ((page_control != 0) && (page_control != 3)) - return 1; + switch (page_control) { + case 0: /* current */ + break; /* supported */ + case 3: /* saved */ + goto saving_not_supp; + case 1: /* changeable */ + case 2: /* defaults */ + default: + goto invalid_fld; + } - if (six_byte) - output_len = 4; - else - output_len = 8; + if (six_byte) { + output_len = 4 + (ebd ? 8 : 0); + alloc_len = scsicmd[4]; + } else { + output_len = 8 + (ebd ? 8 : 0); + alloc_len = (scsicmd[7] << 8) + scsicmd[8]; + } + minlen = (alloc_len < buflen) ? alloc_len : buflen; p = rbuf + output_len; - last = rbuf + buflen - 1; + last = rbuf + minlen - 1; - switch(scsicmd[2] & 0x3f) { - case 0x01: /* r/w error recovery */ + pg = scsicmd[2] & 0x3f; + spg = scsicmd[3]; + /* + * No mode subpages supported (yet) but asking for _all_ + * subpages may be valid + */ + if (spg && (spg != ALL_SUB_MPAGES)) + goto invalid_fld; + + switch(pg) { + case RW_RECOVERY_MPAGE: output_len += ata_msense_rw_recovery(&p, last); break; - case 0x08: /* caching */ + case CACHE_MPAGE: output_len += ata_msense_caching(args->id, &p, last); break; - case 0x0a: { /* control mode */ + case CONTROL_MPAGE: { output_len += ata_msense_ctl_mode(&p, last); break; } - case 0x3f: /* all pages */ + case ALL_MPAGES: output_len += ata_msense_rw_recovery(&p, last); output_len += ata_msense_caching(args->id, &p, last); output_len += ata_msense_ctl_mode(&p, last); break; default: /* invalid page code */ - return 1; + goto invalid_fld; } + if (minlen < 1) + return 0; if (six_byte) { output_len--; rbuf[0] = output_len; + if (ebd) { + if (minlen > 3) + rbuf[3] = sizeof(sat_blk_desc); + if (minlen > 11) + memcpy(rbuf + 4, sat_blk_desc, + sizeof(sat_blk_desc)); + } } else { output_len -= 2; rbuf[0] = output_len >> 8; - rbuf[1] = output_len; + if (minlen > 1) + rbuf[1] = output_len; + if (ebd) { + if (minlen > 7) + rbuf[7] = sizeof(sat_blk_desc); + if (minlen > 15) + memcpy(rbuf + 8, sat_blk_desc, + sizeof(sat_blk_desc)); + } } - return 0; + +invalid_fld: + ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x24, 0x0); + /* "Invalid field in cbd" */ + return 1; + +saving_not_supp: + ata_scsi_set_sense(args->cmd, ILLEGAL_REQUEST, 0x39, 0x0); + /* "Saving parameters not supported" */ + return 1; } /** @@ -1129,10 +1793,20 @@ unsigned int ata_scsiop_read_cap(struct VPRINTK("ENTER\n"); - if (ata_id_has_lba48(args->id)) - n_sectors = ata_id_u64(args->id, 100); - else - n_sectors = ata_id_u32(args->id, 60); + if (ata_id_has_lba(args->id)) { + if (ata_id_has_lba48(args->id)) + n_sectors = ata_id_u64(args->id, 100); + else + n_sectors = ata_id_u32(args->id, 60); + } else { + /* CHS default translation */ + n_sectors = args->id[1] * args->id[3] * args->id[6]; + + if (ata_id_current_chs_valid(args->id)) + /* CHS current translation */ + n_sectors = ata_id_u32(args->id, 57); + } + n_sectors--; /* ATA TotalUserSectors - 1 */ if (args->cmd->cmnd[0] == READ_CAPACITY) { @@ -1196,6 +1870,34 @@ unsigned int ata_scsiop_report_luns(stru } /** + * ata_scsi_set_sense - Set SCSI sense data and status + * @cmd: SCSI request to be handled + * @sk: SCSI-defined sense key + * @asc: SCSI-defined additional sense code + * @ascq: SCSI-defined additional sense code qualifier + * + * Helper function that builds a valid fixed format, current + * response code and the given sense key (sk), additional sense + * code (asc) and additional sense code qualifier (ascq) with + * a SCSI command status of %SAM_STAT_CHECK_CONDITION and + * DRIVER_SENSE set in the upper bits of scsi_cmnd::result . + * + * LOCKING: + * Not required + */ + +void ata_scsi_set_sense(struct scsi_cmnd *cmd, u8 sk, u8 asc, u8 ascq) +{ + cmd->result = (DRIVER_SENSE << 24) | SAM_STAT_CHECK_CONDITION; + + cmd->sense_buffer[0] = 0x70; /* fixed format, current */ + cmd->sense_buffer[2] = sk; + cmd->sense_buffer[7] = 18 - 8; /* additional sense length */ + cmd->sense_buffer[12] = asc; + cmd->sense_buffer[13] = ascq; +} + +/** * ata_scsi_badcmd - End a SCSI request with an error * @cmd: SCSI request to be handled * @done: SCSI command completion function @@ -1213,30 +1915,98 @@ unsigned int ata_scsiop_report_luns(stru void ata_scsi_badcmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *), u8 asc, u8 ascq) { DPRINTK("ENTER\n"); - cmd->result = SAM_STAT_CHECK_CONDITION; + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, asc, ascq); + + done(cmd); +} + +static int atapi_sense_complete(struct ata_queued_cmd *qc,unsigned int err_mask) +{ + if (err_mask && ((err_mask & AC_ERR_DEV) == 0)) + /* FIXME: not quite right; we don't want the + * translation of taskfile registers into + * a sense descriptors, since that's only + * correct for ATA, not ATAPI + */ + ata_gen_ata_desc_sense(qc); + + qc->scsidone(qc->scsicmd); + return 0; +} + +/* is it pointless to prefer PIO for "safety reasons"? */ +static inline int ata_pio_use_silly(struct ata_port *ap) +{ + return (ap->flags & ATA_FLAG_PIO_DMA); +} + +static void atapi_request_sense(struct ata_queued_cmd *qc) +{ + struct ata_port *ap = qc->ap; + struct scsi_cmnd *cmd = qc->scsicmd; + + DPRINTK("ATAPI request sense\n"); + + /* FIXME: is this needed? */ + memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer)); + + ap->ops->tf_read(ap, &qc->tf); + /* fill these in, for the case where they are -not- overwritten */ cmd->sense_buffer[0] = 0x70; - cmd->sense_buffer[2] = ILLEGAL_REQUEST; - cmd->sense_buffer[7] = 14 - 8; /* addnl. sense len. FIXME: correct? */ - cmd->sense_buffer[12] = asc; - cmd->sense_buffer[13] = ascq; + cmd->sense_buffer[2] = qc->tf.feature >> 4; - done(cmd); + ata_qc_reinit(qc); + + ata_sg_init_one(qc, cmd->sense_buffer, sizeof(cmd->sense_buffer)); + qc->dma_dir = DMA_FROM_DEVICE; + + memset(&qc->cdb, 0, ap->cdb_len); + qc->cdb[0] = REQUEST_SENSE; + qc->cdb[4] = SCSI_SENSE_BUFFERSIZE; + + qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + qc->tf.command = ATA_CMD_PACKET; + + if (ata_pio_use_silly(ap)) { + qc->tf.protocol = ATA_PROT_ATAPI_DMA; + qc->tf.feature |= ATAPI_PKT_DMA; + } else { + qc->tf.protocol = ATA_PROT_ATAPI; + qc->tf.lbam = (8 * 1024) & 0xff; + qc->tf.lbah = (8 * 1024) >> 8; + } + qc->nbytes = SCSI_SENSE_BUFFERSIZE; + + qc->complete_fn = atapi_sense_complete; + + if (ata_qc_issue(qc)) + ata_qc_complete(qc, AC_ERR_OTHER); + + DPRINTK("EXIT\n"); } -static int atapi_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat) +static int atapi_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask) { struct scsi_cmnd *cmd = qc->scsicmd; - if (unlikely(drv_stat & (ATA_ERR | ATA_BUSY | ATA_DRQ))) { - DPRINTK("request check condition\n"); + VPRINTK("ENTER, err_mask 0x%X\n", err_mask); + if (unlikely(err_mask & AC_ERR_DEV)) { cmd->result = SAM_STAT_CHECK_CONDITION; + atapi_request_sense(qc); + return 1; + } - qc->scsidone(cmd); + else if (unlikely(err_mask)) + /* FIXME: not quite right; we don't want the + * translation of taskfile registers into + * a sense descriptors, since that's only + * correct for ATA, not ATAPI + */ + ata_gen_ata_desc_sense(qc); - return 1; - } else { + else { u8 *scsicmd = cmd->cmnd; if (scsicmd[0] == INQUIRY) { @@ -1244,15 +2014,30 @@ static int atapi_qc_complete(struct ata_ unsigned int buflen; buflen = ata_scsi_rbuf_get(cmd, &buf); - buf[2] = 0x5; - buf[3] = (buf[3] & 0xf0) | 2; + + /* ATAPI devices typically report zero for their SCSI version, + * and sometimes deviate from the spec WRT response data + * format. If SCSI version is reported as zero like normal, + * then we make the following fixups: 1) Fake MMC-5 version, + * to indicate to the Linux scsi midlayer this is a modern + * device. 2) Ensure response data format / ATAPI information + * are always correct. + */ + /* FIXME: do we ever override EVPD pages and the like, with + * this code? + */ + if (buf[2] == 0) { + buf[2] = 0x5; + buf[3] = 0x32; + } + ata_scsi_rbuf_put(cmd, buf); } + cmd->result = SAM_STAT_GOOD; } qc->scsidone(cmd); - return 0; } /** @@ -1267,12 +2052,12 @@ static int atapi_qc_complete(struct ata_ * Zero on success, non-zero on failure. */ -static unsigned int atapi_xlat(struct ata_queued_cmd *qc, u8 *scsicmd) +static unsigned int atapi_xlat(struct ata_queued_cmd *qc, const u8 *scsicmd) { struct scsi_cmnd *cmd = qc->scsicmd; struct ata_device *dev = qc->dev; int using_pio = (dev->flags & ATA_DFLAG_PIO); - int nodata = (cmd->sc_data_direction == SCSI_DATA_NONE); + int nodata = (cmd->sc_data_direction == DMA_NONE); if (!using_pio) /* Check whether ATAPI DMA is safe */ @@ -1284,7 +2069,7 @@ static unsigned int atapi_xlat(struct at qc->complete_fn = atapi_qc_complete; qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; - if (cmd->sc_data_direction == SCSI_DATA_WRITE) { + if (cmd->sc_data_direction == DMA_TO_DEVICE) { qc->tf.flags |= ATA_TFLAG_WRITE; DPRINTK("direction: write\n"); } @@ -1308,7 +2093,7 @@ static unsigned int atapi_xlat(struct at #ifdef ATAPI_ENABLE_DMADIR /* some SATA bridges need us to indicate data xfer direction */ - if (cmd->sc_data_direction != SCSI_DATA_WRITE) + if (cmd->sc_data_direction != DMA_TO_DEVICE) qc->tf.feature |= ATAPI_DMADIR; #endif } @@ -1336,7 +2121,7 @@ static unsigned int atapi_xlat(struct at */ static struct ata_device * -ata_scsi_find_dev(struct ata_port *ap, struct scsi_device *scsidev) +ata_scsi_find_dev(struct ata_port *ap, const struct scsi_device *scsidev) { struct ata_device *dev; @@ -1353,14 +2138,157 @@ ata_scsi_find_dev(struct ata_port *ap, s if (unlikely(!ata_dev_present(dev))) return NULL; -#ifndef ATA_ENABLE_ATAPI - if (unlikely(dev->class == ATA_DEV_ATAPI)) - return NULL; -#endif + if (!atapi_enabled) { + if (unlikely(dev->class == ATA_DEV_ATAPI)) + return NULL; + } return dev; } +/* + * ata_scsi_map_proto - Map pass-thru protocol value to taskfile value. + * @byte1: Byte 1 from pass-thru CDB. + * + * RETURNS: + * ATA_PROT_UNKNOWN if mapping failed/unimplemented, protocol otherwise. + */ +static u8 +ata_scsi_map_proto(u8 byte1) +{ + switch((byte1 & 0x1e) >> 1) { + case 3: /* Non-data */ + return ATA_PROT_NODATA; + + case 6: /* DMA */ + return ATA_PROT_DMA; + + case 4: /* PIO Data-in */ + case 5: /* PIO Data-out */ + if (byte1 & 0xe0) { + return ATA_PROT_PIO_MULT; + } + return ATA_PROT_PIO; + + case 10: /* Device Reset */ + case 0: /* Hard Reset */ + case 1: /* SRST */ + case 2: /* Bus Idle */ + case 7: /* Packet */ + case 8: /* DMA Queued */ + case 9: /* Device Diagnostic */ + case 11: /* UDMA Data-in */ + case 12: /* UDMA Data-Out */ + case 13: /* FPDMA */ + default: /* Reserved */ + break; + } + + return ATA_PROT_UNKNOWN; +} + +/** + * ata_scsi_pass_thru - convert ATA pass-thru CDB to taskfile + * @qc: command structure to be initialized + * @scsicmd: SCSI command to convert + * + * Handles either 12 or 16-byte versions of the CDB. + * + * RETURNS: + * Zero on success, non-zero on failure. + */ +static unsigned int +ata_scsi_pass_thru(struct ata_queued_cmd *qc, const u8 *scsicmd) +{ + struct ata_taskfile *tf = &(qc->tf); + struct scsi_cmnd *cmd = qc->scsicmd; + + if ((tf->protocol = ata_scsi_map_proto(scsicmd[1])) == ATA_PROT_UNKNOWN) + return 1; + + /* + * 12 and 16 byte CDBs use different offsets to + * provide the various register values. + */ + if (scsicmd[0] == ATA_16) { + /* + * 16-byte CDB - may contain extended commands. + * + * If that is the case, copy the upper byte register values. + */ + if (scsicmd[1] & 0x01) { + tf->hob_feature = scsicmd[3]; + tf->hob_nsect = scsicmd[5]; + tf->hob_lbal = scsicmd[7]; + tf->hob_lbam = scsicmd[9]; + tf->hob_lbah = scsicmd[11]; + tf->flags |= ATA_TFLAG_LBA48; + } else + tf->flags &= ~ATA_TFLAG_LBA48; + + /* + * Always copy low byte, device and command registers. + */ + tf->feature = scsicmd[4]; + tf->nsect = scsicmd[6]; + tf->lbal = scsicmd[8]; + tf->lbam = scsicmd[10]; + tf->lbah = scsicmd[12]; + tf->device = scsicmd[13]; + tf->command = scsicmd[14]; + } else { + /* + * 12-byte CDB - incapable of extended commands. + */ + tf->flags &= ~ATA_TFLAG_LBA48; + + tf->feature = scsicmd[3]; + tf->nsect = scsicmd[4]; + tf->lbal = scsicmd[5]; + tf->lbam = scsicmd[6]; + tf->lbah = scsicmd[7]; + tf->device = scsicmd[8]; + tf->command = scsicmd[9]; + } + /* + * If slave is possible, enforce correct master/slave bit + */ + if (qc->ap->flags & ATA_FLAG_SLAVE_POSS) + tf->device = qc->dev->devno ? + tf->device | ATA_DEV1 : tf->device & ~ATA_DEV1; + + /* + * Filter SET_FEATURES - XFER MODE command -- otherwise, + * SET_FEATURES - XFER MODE must be preceded/succeeded + * by an update to hardware-specific registers for each + * controller (i.e. the reason for ->set_piomode(), + * ->set_dmamode(), and ->post_set_mode() hooks). + */ + if ((tf->command == ATA_CMD_SET_FEATURES) + && (tf->feature == SETFEATURES_XFER)) + return 1; + + /* + * Set flags so that all registers will be written, + * and pass on write indication (used for PIO/DMA + * setup.) + */ + tf->flags |= (ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE); + + if (cmd->sc_data_direction == DMA_TO_DEVICE) + tf->flags |= ATA_TFLAG_WRITE; + + /* + * Set transfer length. + * + * TODO: find out if we need to do more here to + * cover scatter/gather case. + */ + qc->nsect = cmd->bufflen / ATA_SECT_SIZE; + + return 0; +} + /** * ata_get_xlat_func - check if SCSI to ATA translation is possible * @dev: ATA device @@ -1393,6 +2321,13 @@ static inline ata_xlat_func_t ata_get_xl case VERIFY: case VERIFY_16: return ata_scsi_verify_xlat; + + case ATA_12: + case ATA_16: + return ata_scsi_pass_thru; + + case START_STOP: + return ata_scsi_start_stop_xlat; } return NULL; @@ -1447,11 +2382,9 @@ int ata_scsi_queuecmd(struct scsi_cmnd * struct ata_device *dev; struct scsi_device *scsidev = cmd->device; - /* Note: spin_lock_irqsave is held by caller... */ - spin_unlock(&io_request_lock); - ap = (struct ata_port *) &scsidev->host->hostdata[0]; + spin_unlock(&io_request_lock); spin_lock(&ap->host_set->lock); ata_scsi_dump_cdb(ap, cmd); @@ -1498,7 +2431,7 @@ void ata_scsi_simulate(u16 *id, void (*done)(struct scsi_cmnd *)) { struct ata_scsi_args args; - u8 *scsicmd = cmd->cmnd; + const u8 *scsicmd = cmd->cmnd; args.id = id; args.cmd = cmd; @@ -1518,7 +2451,7 @@ void ata_scsi_simulate(u16 *id, case INQUIRY: if (scsicmd[1] & 2) /* is CmdDt set? */ - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); else if ((scsicmd[1] & 1) == 0) /* is EVPD clear? */ ata_scsi_rbuf_fill(&args, ata_scsiop_inq_std); else if (scsicmd[2] == 0x00) @@ -1528,7 +2461,7 @@ void ata_scsi_simulate(u16 *id, else if (scsicmd[2] == 0x83) ata_scsi_rbuf_fill(&args, ata_scsiop_inq_83); else - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case MODE_SENSE: @@ -1538,7 +2471,7 @@ void ata_scsi_simulate(u16 *id, case MODE_SELECT: /* unconditionally return */ case MODE_SELECT_10: /* bad-field-in-cdb */ - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case READ_CAPACITY: @@ -1549,19 +2482,21 @@ void ata_scsi_simulate(u16 *id, if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16) ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap); else - ata_bad_cdb(cmd, done); + ata_scsi_invalid_field(cmd, done); break; case REPORT_LUNS: ata_scsi_rbuf_fill(&args, ata_scsiop_report_luns); break; - /* mandantory commands we haven't implemented yet */ + /* mandatory commands we haven't implemented yet */ case REQUEST_SENSE: /* all other commands */ default: - ata_bad_scsiop(cmd, done); + ata_scsi_set_sense(cmd, ILLEGAL_REQUEST, 0x20, 0x0); + /* "Invalid command operation code" */ + done(cmd); break; } } diff -Nur -p linux-2.4.32/drivers/scsi/sata_nv.c linux-2.4.33-rc2/drivers/scsi/sata_nv.c --- linux-2.4.32/drivers/scsi/sata_nv.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/sata_nv.c 2006-06-21 10:40:43.000000000 -0300 @@ -4,21 +4,39 @@ * Copyright 2004 NVIDIA Corp. All rights reserved. * Copyright 2004 Andrew Chew * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. - * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * No hardware documentation available outside of NVIDIA. + * This driver programs the NVIDIA SATA controller in a similar + * fashion as with other PCI IDE BMDMA controllers, with a few + * NV-specific details such as register offsets, SATA phy location, + * hotplug info, etc. + * + * 0.09 + * - Fixed bug introduced by 0.08's MCP51 and MCP55 support. + * + * 0.08 + * - Added support for MCP51 and MCP55. + * + * 0.07 + * - Added support for RAID class code. * * 0.06 * - Added generic SATA support by using a pci_device_id that filters on @@ -48,7 +66,7 @@ #include #define DRV_NAME "sata_nv" -#define DRV_VERSION "0.6" +#define DRV_VERSION "0.8" #define NV_PORTS 2 #define NV_PIO_MASK 0x1f @@ -119,7 +137,7 @@ enum nv_host_type CK804 }; -static struct pci_device_id nv_pci_tbl[] = { +static const struct pci_device_id nv_pci_tbl[] = { { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE2S_SATA, PCI_ANY_ID, PCI_ANY_ID, 0, 0, NFORCE2 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE3S_SATA, @@ -134,9 +152,20 @@ static struct pci_device_id nv_pci_tbl[] PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP04_SATA2, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CK804 }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, + { PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2, + PCI_ANY_ID, PCI_ANY_ID, 0, 0, GENERIC }, { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_IDE<<8, 0xffff00, GENERIC }, + { PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, + PCI_ANY_ID, PCI_ANY_ID, + PCI_CLASS_STORAGE_RAID<<8, 0xffff00, GENERIC }, { 0, } /* terminate list */ }; @@ -209,7 +238,7 @@ static Scsi_Host_Template nv_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations nv_ops = { +static const struct ata_port_operations nv_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -274,7 +303,8 @@ static irqreturn_t nv_interrupt (int irq struct ata_port *ap; ap = host_set->ports[i]; - if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (ap && + !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); @@ -301,7 +331,7 @@ static u32 nv_scr_read (struct ata_port return 0xffffffffU; if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) - return readl((void*)ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); else return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -315,7 +345,7 @@ static void nv_scr_write (struct ata_por return; if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) - writel(val, (void*)ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *)ap->ioaddr.scr_addr + (sc_reg * 4)); else outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -323,6 +353,7 @@ static void nv_scr_write (struct ata_por static void nv_host_stop (struct ata_host_set *host_set) { struct nv_host *host = host_set->private_data; + struct pci_dev *pdev = to_pci_dev(host_set->dev); // Disable hotplug event interrupts. if (host->host_desc->disable_hotplug) @@ -330,7 +361,8 @@ static void nv_host_stop (struct ata_hos kfree(host); - ata_host_stop(host_set); + if (host_set->mmio_base) + pci_iounmap(pdev, host_set->mmio_base); } static int nv_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) @@ -351,7 +383,7 @@ static int nv_init_one (struct pci_dev * return -ENODEV; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + pdev_printk(KERN_DEBUG, pdev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) @@ -366,11 +398,14 @@ static int nv_init_one (struct pci_dev * rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; rc = -ENOMEM; ppi = &nv_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) goto err_out_regions; @@ -389,8 +424,7 @@ static int nv_init_one (struct pci_dev * if (host->host_flags & NV_HOST_FLAGS_SCR_MMIO) { unsigned long base; - probe_ent->mmio_base = ioremap(pci_resource_start(pdev, 5), - pci_resource_len(pdev, 5)); + probe_ent->mmio_base = pci_iomap(pdev, 5, 0); if (probe_ent->mmio_base == NULL) { rc = -EIO; goto err_out_free_host; diff -Nur -p linux-2.4.32/drivers/scsi/sata_promise.c linux-2.4.33-rc2/drivers/scsi/sata_promise.c --- linux-2.4.32/drivers/scsi/sata_promise.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/sata_promise.c 2006-06-21 10:40:43.000000000 -0300 @@ -7,21 +7,26 @@ * * Copyright 2003-2004 Red Hat, Inc. * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware information only available under NDA. * */ @@ -40,7 +45,7 @@ #include "sata_promise.h" #define DRV_NAME "sata_promise" -#define DRV_VERSION "1.01" +#define DRV_VERSION "1.03" enum { @@ -79,13 +84,15 @@ static irqreturn_t pdc_interrupt (int ir static void pdc_eng_timeout(struct ata_port *ap); static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); -static void pdc_phy_reset(struct ata_port *ap); +static void pdc_pata_phy_reset(struct ata_port *ap); +static void pdc_sata_phy_reset(struct ata_port *ap); static void pdc_qc_prep(struct ata_queued_cmd *qc); -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc_irq_clear(struct ata_port *ap); static int pdc_qc_issue_prot(struct ata_queued_cmd *qc); + static Scsi_Host_Template pdc_ata_sht = { .module = THIS_MODULE, .name = DRV_NAME, @@ -106,24 +113,48 @@ static Scsi_Host_Template pdc_ata_sht = .bios_param = ata_std_bios_param, }; -static struct ata_port_operations pdc_ata_ops = { +static const struct ata_port_operations pdc_sata_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, .check_status = ata_check_status, .exec_command = pdc_exec_command_mmio, .dev_select = ata_std_dev_select, - .phy_reset = pdc_phy_reset, + + .phy_reset = pdc_sata_phy_reset, + .qc_prep = pdc_qc_prep, .qc_issue = pdc_qc_issue_prot, .eng_timeout = pdc_eng_timeout, .irq_handler = pdc_interrupt, .irq_clear = pdc_irq_clear, + .scr_read = pdc_sata_scr_read, .scr_write = pdc_sata_scr_write, .port_start = pdc_port_start, .port_stop = pdc_port_stop, - .host_stop = ata_host_stop, + .host_stop = ata_pci_host_stop, +}; + +static const struct ata_port_operations pdc_pata_ops = { + .port_disable = ata_port_disable, + .tf_load = pdc_tf_load_mmio, + .tf_read = ata_tf_read, + .check_status = ata_check_status, + .exec_command = pdc_exec_command_mmio, + .dev_select = ata_std_dev_select, + + .phy_reset = pdc_pata_phy_reset, + + .qc_prep = pdc_qc_prep, + .qc_issue = pdc_qc_issue_prot, + .eng_timeout = pdc_eng_timeout, + .irq_handler = pdc_interrupt, + .irq_clear = pdc_irq_clear, + + .port_start = pdc_port_start, + .port_stop = pdc_port_stop, + .host_stop = ata_pci_host_stop, }; static struct ata_port_info pdc_port_info[] = { @@ -135,7 +166,7 @@ static struct ata_port_info pdc_port_inf .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &pdc_ata_ops, + .port_ops = &pdc_sata_ops, }, /* board_20319 */ @@ -146,7 +177,7 @@ static struct ata_port_info pdc_port_inf .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &pdc_ata_ops, + .port_ops = &pdc_sata_ops, }, /* board_20619 */ @@ -157,13 +188,15 @@ static struct ata_port_info pdc_port_inf .pio_mask = 0x1f, /* pio0-4 */ .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x7f, /* udma0-6 ; FIXME */ - .port_ops = &pdc_ata_ops, + .port_ops = &pdc_pata_ops, }, }; -static struct pci_device_id pdc_ata_pci_tbl[] = { +static const struct pci_device_id pdc_ata_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x3371, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, + { PCI_VENDOR_ID_PROMISE, 0x3570, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3571, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3373, PCI_ANY_ID, PCI_ANY_ID, 0, 0, @@ -176,11 +209,17 @@ static struct pci_device_id pdc_ata_pci_ board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3d75, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2037x }, + { PCI_VENDOR_ID_PROMISE, 0x3d73, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_2037x }, { PCI_VENDOR_ID_PROMISE, 0x3318, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20319 }, { PCI_VENDOR_ID_PROMISE, 0x3319, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20319 }, + { PCI_VENDOR_ID_PROMISE, 0x3519, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_20319 }, + { PCI_VENDOR_ID_PROMISE, 0x3d17, PCI_ANY_ID, PCI_ANY_ID, 0, 0, + board_20319 }, { PCI_VENDOR_ID_PROMISE, 0x3d18, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20319 }, @@ -248,7 +287,7 @@ static void pdc_port_stop(struct ata_por static void pdc_reset_port(struct ata_port *ap) { - void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_CTLSTAT; + void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_CTLSTAT; unsigned int i; u32 tmp; @@ -268,17 +307,28 @@ static void pdc_reset_port(struct ata_po readl(mmio); /* flush */ } -static void pdc_phy_reset(struct ata_port *ap) +static void pdc_sata_phy_reset(struct ata_port *ap) { pdc_reset_port(ap); sata_phy_reset(ap); } +static void pdc_pata_phy_reset(struct ata_port *ap) +{ + /* FIXME: add cable detect. Don't assume 40-pin cable */ + ap->cbl = ATA_CBL_PATA40; + ap->udma_mask &= ATA_UDMA_MASK_40C; + + pdc_reset_port(ap); + ata_port_probe(ap); + ata_bus_reset(ap); +} + static u32 pdc_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -287,7 +337,7 @@ static void pdc_sata_scr_write (struct a { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void pdc_qc_prep(struct ata_queued_cmd *qc) @@ -321,11 +371,15 @@ static void pdc_qc_prep(struct ata_queue static void pdc_eng_timeout(struct ata_port *ap) { + struct ata_host_set *host_set = ap->host_set; u8 drv_stat; struct ata_queued_cmd *qc; + unsigned long flags; DPRINTK("ENTER\n"); + spin_lock_irqsave(&host_set->lock, flags); + qc = ata_qc_from_tag(ap, ap->active_tag); if (!qc) { printk(KERN_ERR "ata%u: BUG: timeout without command\n", @@ -345,7 +399,8 @@ static void pdc_eng_timeout(struct ata_p case ATA_PROT_DMA: case ATA_PROT_NODATA: printk(KERN_ERR "ata%u: command timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); + drv_stat = ata_wait_idle(ap); + ata_qc_complete(qc, __ac_err_mask(drv_stat)); break; default: @@ -354,50 +409,48 @@ static void pdc_eng_timeout(struct ata_p printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n", ap->id, qc->tf.command, drv_stat); - ata_qc_complete(qc, drv_stat); + ata_qc_complete(qc, ac_err_mask(drv_stat)); break; } out: + spin_unlock_irqrestore(&host_set->lock, flags); DPRINTK("EXIT\n"); } static inline unsigned int pdc_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc) { - u8 status; - unsigned int handled = 0, have_err = 0; + unsigned int handled = 0, err_mask = 0; u32 tmp; - void *mmio = (void *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL; + void __iomem *mmio = (void __iomem *) ap->ioaddr.cmd_addr + PDC_GLOBAL_CTL; tmp = readl(mmio); if (tmp & PDC_ERR_MASK) { - have_err = 1; + err_mask = AC_ERR_DEV; pdc_reset_port(ap); } switch (qc->tf.protocol) { case ATA_PROT_DMA: case ATA_PROT_NODATA: - status = ata_wait_idle(ap); - if (have_err) - status |= ATA_ERR; - ata_qc_complete(qc, status); + err_mask |= ac_err_mask(ata_wait_idle(ap)); + ata_qc_complete(qc, err_mask); handled = 1; break; default: - ap->stats.idle_irq++; - break; + ap->stats.idle_irq++; + break; } - return handled; + return handled; } static void pdc_irq_clear(struct ata_port *ap) { struct ata_host_set *host_set = ap->host_set; - void *mmio = host_set->mmio_base; + void __iomem *mmio = host_set->mmio_base; readl(mmio + PDC_INT_SEQMASK); } @@ -409,7 +462,7 @@ static irqreturn_t pdc_interrupt (int ir u32 mask = 0; unsigned int i, tmp; unsigned int handled = 0; - void *mmio_base; + void __iomem *mmio_base; VPRINTK("ENTER\n"); @@ -441,7 +494,8 @@ static irqreturn_t pdc_interrupt (int ir VPRINTK("port %u\n", i); ap = host_set->ports[i]; tmp = mask & (1 << (i + 1)); - if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (tmp && ap && + !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); @@ -471,8 +525,8 @@ static inline void pdc_packet_start(stru pp->pkt[2] = seq; wmb(); /* flush PRD, pkt writes */ - writel(pp->pkt_dma, (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ + writel(pp->pkt_dma, (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); /* flush */ } static int pdc_qc_issue_prot(struct ata_queued_cmd *qc) @@ -494,7 +548,7 @@ static int pdc_qc_issue_prot(struct ata_ return ata_qc_issue_prot(qc); } -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -502,7 +556,7 @@ static void pdc_tf_load_mmio(struct ata_ } -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -530,7 +584,7 @@ static void pdc_ata_setup_port(struct at static void pdc_host_init(unsigned int chip_id, struct ata_probe_ent *pe) { - void *mmio = pe->mmio_base; + void __iomem *mmio = pe->mmio_base; u32 tmp; /* @@ -573,13 +627,13 @@ static int pdc_ata_init_one (struct pci_ static int printed_version; struct ata_probe_ent *probe_ent = NULL; unsigned long base; - void *mmio_base; + void __iomem *mmio_base; unsigned int board_idx = (unsigned int) ent->driver_data; int pci_dev_busy = 0; int rc; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + pdev_printk(KERN_DEBUG, pdev, "version " DRV_VERSION "\n"); /* * If this driver happens to only be useful on Apple's K2, then @@ -598,6 +652,9 @@ static int pdc_ata_init_one (struct pci_ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { @@ -609,8 +666,7 @@ static int pdc_ata_init_one (struct pci_ probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = ioremap(pci_resource_start(pdev, 3), - pci_resource_len(pdev, 3)); + mmio_base = pci_iomap(pdev, 3, 0); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_free_ent; @@ -656,7 +712,7 @@ static int pdc_ata_init_one (struct pci_ probe_ent->port[2].scr_addr = base + 0x600; probe_ent->port[3].scr_addr = base + 0x700; - break; + break; default: BUG(); break; diff -Nur -p linux-2.4.32/drivers/scsi/sata_promise.h linux-2.4.33-rc2/drivers/scsi/sata_promise.h --- linux-2.4.32/drivers/scsi/sata_promise.h 2004-08-07 20:26:05.000000000 -0300 +++ linux-2.4.33-rc2/drivers/scsi/sata_promise.h 2006-06-21 10:40:43.000000000 -0300 @@ -3,21 +3,24 @@ * * Copyright 2003-2004 Red Hat, Inc. * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. - * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* * */ diff -Nur -p linux-2.4.32/drivers/scsi/sata_qstor.c linux-2.4.33-rc2/drivers/scsi/sata_qstor.c --- linux-2.4.32/drivers/scsi/sata_qstor.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/sata_qstor.c 2006-06-21 10:40:43.000000000 -0300 @@ -6,21 +6,24 @@ * Copyright 2005 Pacific Digital Corporation. * (OSL/GPL code release authorized by Jalil Fadavi). * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* * */ @@ -38,7 +41,7 @@ #include #define DRV_NAME "sata_qstor" -#define DRV_VERSION "0.04" +#define DRV_VERSION "0.05" enum { QS_PORTS = 4, @@ -48,8 +51,6 @@ enum { QS_PRD_BYTES = QS_MAX_PRD * 16, QS_PKT_BYTES = QS_CPB_BYTES + QS_PRD_BYTES, - QS_DMA_BOUNDARY = ~0UL, - /* global register offsets */ QS_HCF_CNFG3 = 0x0003, /* host configuration offset */ QS_HID_HPHY = 0x0004, /* host physical interface info */ @@ -98,6 +99,10 @@ enum { board_2068_idx = 0, /* QStor 4-port SATA/RAID */ }; +enum { + QS_DMA_BOUNDARY = ~0UL +}; + typedef enum { qs_state_idle, qs_state_pkt, qs_state_mmio } qs_state_t; struct qs_port_priv { @@ -117,7 +122,7 @@ static void qs_phy_reset(struct ata_port static void qs_qc_prep(struct ata_queued_cmd *qc); static int qs_qc_issue(struct ata_queued_cmd *qc); static int qs_check_atapi_dma(struct ata_queued_cmd *qc); -static void qs_bmdma_stop(struct ata_port *ap); +static void qs_bmdma_stop(struct ata_queued_cmd *qc); static u8 qs_bmdma_status(struct ata_port *ap); static void qs_irq_clear(struct ata_port *ap); static void qs_eng_timeout(struct ata_port *ap); @@ -143,7 +148,7 @@ static Scsi_Host_Template qs_ata_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations qs_ata_ops = { +static const struct ata_port_operations qs_ata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -180,7 +185,7 @@ static struct ata_port_info qs_port_info }, }; -static struct pci_device_id qs_ata_pci_tbl[] = { +static const struct pci_device_id qs_ata_pci_tbl[] = { { PCI_VENDOR_ID_PDC, 0x2068, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_2068_idx }, @@ -199,7 +204,7 @@ static int qs_check_atapi_dma(struct ata return 1; /* ATAPI DMA not supported */ } -static void qs_bmdma_stop(struct ata_port *ap) +static void qs_bmdma_stop(struct ata_queued_cmd *qc) { /* nothing */ } @@ -264,18 +269,19 @@ static void qs_scr_write (struct ata_por writel(val, (void __iomem *)(ap->ioaddr.scr_addr + (sc_reg * 8))); } -static void qs_fill_sg(struct ata_queued_cmd *qc) +static unsigned int qs_fill_sg(struct ata_queued_cmd *qc) { - struct scatterlist *sg = qc->sg; + struct scatterlist *sg; struct ata_port *ap = qc->ap; struct qs_port_priv *pp = ap->private_data; unsigned int nelem; u8 *prd = pp->pkt + QS_CPB_BYTES; - assert(sg != NULL); + assert(qc->__sg != NULL); assert(qc->n_elem > 0); - for (nelem = 0; nelem < qc->n_elem; nelem++,sg++) { + nelem = 0; + ata_for_each_sg(sg, qc) { u64 addr; u32 len; @@ -289,7 +295,10 @@ static void qs_fill_sg(struct ata_queued VPRINTK("PRD[%u] = (0x%llX, 0x%X)\n", nelem, (unsigned long long)addr, len); + nelem++; } + + return nelem; } static void qs_qc_prep(struct ata_queued_cmd *qc) @@ -298,6 +307,7 @@ static void qs_qc_prep(struct ata_queued u8 dflags = QS_DF_PORD, *buf = pp->pkt; u8 hflags = QS_HF_DAT | QS_HF_IEN | QS_HF_VLD; u64 addr; + unsigned int nelem; VPRINTK("ENTER\n"); @@ -307,7 +317,7 @@ static void qs_qc_prep(struct ata_queued return; } - qs_fill_sg(qc); + nelem = qs_fill_sg(qc); if ((qc->tf.flags & ATA_TFLAG_WRITE)) hflags |= QS_HF_DIRO; @@ -318,7 +328,7 @@ static void qs_qc_prep(struct ata_queued buf[ 0] = QS_HCB_HDR; buf[ 1] = hflags; *(__le32 *)(&buf[ 4]) = cpu_to_le32(qc->nsect * ATA_SECT_SIZE); - *(__le32 *)(&buf[ 8]) = cpu_to_le32(qc->n_elem); + *(__le32 *)(&buf[ 8]) = cpu_to_le32(nelem); addr = ((u64)pp->pkt_dma) + QS_CPB_BYTES; *(__le64 *)(&buf[16]) = cpu_to_le64(addr); @@ -387,7 +397,8 @@ static inline unsigned int qs_intr_pkt(s DPRINTK("SFF=%08x%08x: sCHAN=%u sHST=%d sDST=%02x\n", sff1, sff0, port_no, sHST, sDST); handled = 1; - if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (ap && !(ap->flags & + (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_pkt) @@ -395,11 +406,12 @@ static inline unsigned int qs_intr_pkt(s qc = ata_qc_from_tag(ap, ap->active_tag); if (qc && (!(qc->tf.ctl & ATA_NIEN))) { switch (sHST) { - case 0: /* sucessful CPB */ + case 0: /* successful CPB */ case 3: /* device error */ pp->state = qs_state_idle; qs_enter_reg_mode(qc->ap); - ata_qc_complete(qc, sDST); + ata_qc_complete(qc, + ac_err_mask(sDST)); break; default: break; @@ -418,7 +430,8 @@ static inline unsigned int qs_intr_mmio( for (port_no = 0; port_no < host_set->n_ports; ++port_no) { struct ata_port *ap; ap = host_set->ports[port_no]; - if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (ap && + !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; struct qs_port_priv *pp = ap->private_data; if (!pp || pp->state != qs_state_mmio) @@ -427,15 +440,15 @@ static inline unsigned int qs_intr_mmio( if (qc && (!(qc->tf.ctl & ATA_NIEN))) { /* check main status, clearing INTRQ */ - u8 status = ata_chk_status(ap); + u8 status = ata_check_status(ap); if ((status & ATA_BUSY)) continue; DPRINTK("ata%u: protocol %d (dev_stat 0x%X)\n", ap->id, qc->tf.protocol, status); - + /* complete taskfile transaction */ pp->state = qs_state_idle; - ata_qc_complete(qc, status); + ata_qc_complete(qc, ac_err_mask(status)); handled = 1; } } @@ -490,7 +503,7 @@ static int qs_port_start(struct ata_port if (rc) return rc; qs_enter_reg_mode(ap); - pp = kcalloc(1, sizeof(*pp), GFP_KERNEL); + pp = kzalloc(sizeof(*pp), GFP_KERNEL); if (!pp) { rc = -ENOMEM; goto err_out; @@ -534,11 +547,12 @@ static void qs_port_stop(struct ata_port static void qs_host_stop(struct ata_host_set *host_set) { void __iomem *mmio_base = host_set->mmio_base; + struct pci_dev *pdev = to_pci_dev(host_set->dev); writeb(0, mmio_base + QS_HCT_CTRL); /* disable host interrupts */ writeb(QS_CNFG3_GSRST, mmio_base + QS_HCF_CNFG3); /* global reset */ - ata_host_stop(host_set); + pci_iounmap(pdev, mmio_base); } static void qs_host_init(unsigned int chip_id, struct ata_probe_ent *pe) @@ -588,13 +602,26 @@ static int qs_set_dma_masks(struct pci_d if (have_64bit_bus && !pci_set_dma_mask(pdev, DMA_64BIT_MASK)) { - /* do nothing */ + rc = pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK); + if (rc) { + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + pdev_printk(KERN_ERR, pdev, + "64-bit DMA enable failed\n"); + return rc; + } + } } else { rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc) { - printk(KERN_ERR DRV_NAME - "(%s): 32-bit DMA enable failed\n", - pci_name(pdev)); + pdev_printk(KERN_ERR, pdev, + "32-bit DMA enable failed\n"); + return rc; + } + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) { + pdev_printk(KERN_ERR, pdev, + "32-bit consistent DMA enable failed\n"); return rc; } } @@ -611,7 +638,7 @@ static int qs_ata_init_one(struct pci_de int rc, port_no; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + pdev_printk(KERN_DEBUG, pdev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) @@ -626,8 +653,7 @@ static int qs_ata_init_one(struct pci_de goto err_out_regions; } - mmio_base = ioremap(pci_resource_start(pdev, 4), - pci_resource_len(pdev, 4)); + mmio_base = pci_iomap(pdev, 4, 0); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_regions; @@ -674,7 +700,7 @@ static int qs_ata_init_one(struct pci_de return 0; err_out_iounmap: - iounmap(mmio_base); + pci_iounmap(pdev, mmio_base); err_out_regions: pci_release_regions(pdev); err_out: diff -Nur -p linux-2.4.32/drivers/scsi/sata_sil.c linux-2.4.33-rc2/drivers/scsi/sata_sil.c --- linux-2.4.32/drivers/scsi/sata_sil.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/sata_sil.c 2006-06-21 10:40:43.000000000 -0300 @@ -5,24 +5,32 @@ * Please ALWAYS copy linux-ide@vger.kernel.org * on emails. * - * Copyright 2003 Red Hat, Inc. + * Copyright 2003-2005 Red Hat, Inc. * Copyright 2003 Benjamin Herrenschmidt * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. - * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Documentation for SiI 3112: + * http://gkernel.sourceforge.net/specs/sii/3112A_SiI-DS-0095-B2.pdf.bz2 + * + * Other errata and documentation available under NDA. * */ @@ -41,8 +49,11 @@ #define DRV_VERSION "0.9" enum { + SIL_FLAG_MOD15WRITE = (1 << 30), + sil_3112 = 0, - sil_3114 = 1, + sil_3112_m15w = 1, + sil_3114 = 2, SIL_FIFO_R0 = 0x40, SIL_FIFO_W0 = 0x41, @@ -75,14 +86,15 @@ static u32 sil_scr_read (struct ata_port static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); static void sil_post_set_mode (struct ata_port *ap); -static struct pci_device_id sil_pci_tbl[] = { - { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, - { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, + +static const struct pci_device_id sil_pci_tbl[] = { + { 0x1095, 0x3112, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w }, + { 0x1095, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w }, { 0x1095, 0x3512, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, { 0x1095, 0x3114, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3114 }, - { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, - { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, - { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112 }, + { 0x1002, 0x436e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w }, + { 0x1002, 0x4379, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w }, + { 0x1002, 0x437a, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sil_3112_m15w }, { } /* terminate list */ }; @@ -138,7 +150,7 @@ static Scsi_Host_Template sil_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations sil_ops = { +static const struct ata_port_operations sil_ops = { .port_disable = ata_port_disable, .dev_config = sil_dev_config, .tf_load = ata_tf_load, @@ -161,7 +173,7 @@ static struct ata_port_operations sil_op .scr_write = sil_scr_write, .port_start = ata_port_start, .port_stop = ata_port_stop, - .host_stop = ata_host_stop, + .host_stop = ata_pci_host_stop, }; static struct ata_port_info sil_port_info[] = { @@ -174,6 +186,16 @@ static struct ata_port_info sil_port_inf .mwdma_mask = 0x07, /* mwdma0-2 */ .udma_mask = 0x3f, /* udma0-5 */ .port_ops = &sil_ops, + }, /* sil_3112_15w - keep it sync'd w/ sil_3112 */ + { + .sht = &sil_sht, + .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | + ATA_FLAG_SRST | ATA_FLAG_MMIO | + SIL_FLAG_MOD15WRITE, + .pio_mask = 0x1f, /* pio0-4 */ + .mwdma_mask = 0x07, /* mwdma0-2 */ + .udma_mask = 0x3f, /* udma0-5 */ + .port_ops = &sil_ops, }, /* sil_3114 */ { .sht = &sil_sht, @@ -210,6 +232,7 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, sil_pci_tbl); MODULE_VERSION(DRV_VERSION); + static unsigned char sil_get_device_cache_line(struct pci_dev *pdev) { u8 cache_line = 0; @@ -221,7 +244,8 @@ static void sil_post_set_mode (struct at { struct ata_host_set *host_set = ap->host_set; struct ata_device *dev; - void *addr = host_set->mmio_base + sil_port[ap->port_no].xfer_mode; + void __iomem *addr = + host_set->mmio_base + sil_port[ap->port_no].xfer_mode; u32 tmp, dev_mode[2]; unsigned int i; @@ -265,7 +289,7 @@ static inline unsigned long sil_scr_addr static u32 sil_scr_read (struct ata_port *ap, unsigned int sc_reg) { - void *mmio = (void *) sil_scr_addr(ap, sc_reg); + void __iomem *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); if (mmio) return readl(mmio); return 0xffffffffU; @@ -273,7 +297,7 @@ static u32 sil_scr_read (struct ata_port static void sil_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { - void *mmio = (void *) sil_scr_addr(ap, sc_reg); + void *mmio = (void __iomem *) sil_scr_addr(ap, sc_reg); if (mmio) writel(val, mmio); } @@ -323,15 +347,15 @@ static void sil_dev_config(struct ata_po while ((len > 0) && (s[len - 1] == ' ')) len--; - for (n = 0; sil_blacklist[n].product; n++) + for (n = 0; sil_blacklist[n].product; n++) if (!memcmp(sil_blacklist[n].product, s, strlen(sil_blacklist[n].product))) { quirks = sil_blacklist[n].quirk; break; } - + /* limit requests to 15 sectors */ - if (quirks & SIL_QUIRK_MOD15WRITE) { + if ((ap->flags & SIL_FLAG_MOD15WRITE) && (quirks & SIL_QUIRK_MOD15WRITE)) { printk(KERN_INFO "ata%u(%u): applying Seagate errata fix\n", ap->id, dev->devno); ap->host->max_sectors = 15; @@ -354,7 +378,7 @@ static int sil_init_one (struct pci_dev static int printed_version; struct ata_probe_ent *probe_ent = NULL; unsigned long base; - void *mmio_base; + void __iomem *mmio_base; int rc; unsigned int i; int pci_dev_busy = 0; @@ -362,7 +386,7 @@ static int sil_init_one (struct pci_dev u8 cls; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + pdev_printk(KERN_DEBUG, pdev, "version " DRV_VERSION "\n"); /* * If this driver happens to only be useful on Apple's K2, then @@ -381,6 +405,9 @@ static int sil_init_one (struct pci_dev rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { @@ -401,8 +428,7 @@ static int sil_init_one (struct pci_dev probe_ent->irq_flags = SA_SHIRQ; probe_ent->host_flags = sil_port_info[ent->driver_data].host_flags; - mmio_base = ioremap(pci_resource_start(pdev, 5), - pci_resource_len(pdev, 5)); + mmio_base = pci_iomap(pdev, 5, 0); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_free_ent; @@ -437,8 +463,8 @@ static int sil_init_one (struct pci_dev writeb(cls, mmio_base + SIL_FIFO_W3); } } else - printk(KERN_WARNING DRV_NAME "(%s): cache line size not set. Driver may not function\n", - pci_name(pdev)); + pdev_printk(KERN_WARNING, pdev, + "cache line size not set. Driver may not function\n"); if (ent->driver_data == sil_3114) { irq_mask = SIL_MASK_4PORT; diff -Nur -p linux-2.4.32/drivers/scsi/sata_sis.c linux-2.4.33-rc2/drivers/scsi/sata_sis.c --- linux-2.4.32/drivers/scsi/sata_sis.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/sata_sis.c 2006-06-21 10:40:43.000000000 -0300 @@ -7,21 +7,26 @@ * * Copyright 2004 Uwe Koziolek * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware documentation available under NDA. * */ @@ -47,7 +52,10 @@ enum { /* PCI configuration registers */ SIS_GENCTL = 0x54, /* IDE General Control register */ SIS_SCR_BASE = 0xc0, /* sata0 phy SCR registers */ - SIS_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */ + SIS180_SATA1_OFS = 0x10, /* offset from sata0->sata1 phy regs */ + SIS182_SATA1_OFS = 0x20, /* offset from sata0->sata1 phy regs */ + SIS_PMR = 0x90, /* port mapping register */ + SIS_PMR_COMBINED = 0x30, /* random bits */ SIS_FLAG_CFGSCR = (1 << 30), /* host flag: SCRs via PCI cfg */ @@ -59,9 +67,10 @@ static int sis_init_one (struct pci_dev static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg); static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); -static struct pci_device_id sis_pci_tbl[] = { +static const struct pci_device_id sis_pci_tbl[] = { { PCI_VENDOR_ID_SI, 0x180, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, { PCI_VENDOR_ID_SI, 0x181, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, + { PCI_VENDOR_ID_SI, 0x182, PCI_ANY_ID, PCI_ANY_ID, 0, 0, sis_180 }, { } /* terminate list */ }; @@ -93,7 +102,7 @@ static Scsi_Host_Template sis_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations sis_ops = { +static const struct ata_port_operations sis_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, .tf_read = ata_tf_read, @@ -134,77 +143,111 @@ MODULE_LICENSE("GPL"); MODULE_DEVICE_TABLE(pci, sis_pci_tbl); MODULE_VERSION(DRV_VERSION); -static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg) +static unsigned int get_scr_cfg_addr(unsigned int port_no, unsigned int sc_reg, int device) { unsigned int addr = SIS_SCR_BASE + (4 * sc_reg); - if (port_no) - addr += SIS_SATA1_OFS; + if (port_no) { + if (device == 0x182) + addr += SIS182_SATA1_OFS; + else + addr += SIS180_SATA1_OFS; + } + return addr; } static u32 sis_scr_cfg_read (struct ata_port *ap, unsigned int sc_reg) { struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); - unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg); - u32 val; + unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, sc_reg, pdev->device); + u32 val, val2 = 0; + u8 pmr; if (sc_reg == SCR_ERROR) /* doesn't exist in PCI cfg space */ return 0xffffffff; + + pci_read_config_byte(pdev, SIS_PMR, &pmr); + pci_read_config_dword(pdev, cfg_addr, &val); - return val; + + if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) + pci_read_config_dword(pdev, cfg_addr+0x10, &val2); + + return val|val2; } static void sis_scr_cfg_write (struct ata_port *ap, unsigned int scr, u32 val) { struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); - unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr); + unsigned int cfg_addr = get_scr_cfg_addr(ap->port_no, scr, pdev->device); + u8 pmr; if (scr == SCR_ERROR) /* doesn't exist in PCI cfg space */ return; + + pci_read_config_byte(pdev, SIS_PMR, &pmr); + pci_write_config_dword(pdev, cfg_addr, val); + + if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) + pci_write_config_dword(pdev, cfg_addr+0x10, val); } static u32 sis_scr_read (struct ata_port *ap, unsigned int sc_reg) { + struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); + u32 val, val2 = 0; + u8 pmr; + if (sc_reg > SCR_CONTROL) return 0xffffffffU; if (ap->flags & SIS_FLAG_CFGSCR) return sis_scr_cfg_read(ap, sc_reg); - return inl(ap->ioaddr.scr_addr + (sc_reg * 4)); + + pci_read_config_byte(pdev, SIS_PMR, &pmr); + + val = inl(ap->ioaddr.scr_addr + (sc_reg * 4)); + + if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) + val2 = inl(ap->ioaddr.scr_addr + (sc_reg * 4) + 0x10); + + return val | val2; } static void sis_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val) { + struct pci_dev *pdev = to_pci_dev(ap->host_set->dev); + u8 pmr; + if (sc_reg > SCR_CONTROL) return; + pci_read_config_byte(pdev, SIS_PMR, &pmr); + if (ap->flags & SIS_FLAG_CFGSCR) sis_scr_cfg_write(ap, sc_reg, val); - else + else { outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)); -} - -/* move to PCI layer, integrate w/ MSI stuff */ -static void pci_enable_intx(struct pci_dev *pdev) -{ - u16 pci_command; - - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - if (pci_command & PCI_COMMAND_INTX_DISABLE) { - pci_command &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(pdev, PCI_COMMAND, pci_command); + if ((pdev->device == 0x182) || (pmr & SIS_PMR_COMBINED)) + outl(val, ap->ioaddr.scr_addr + (sc_reg * 4)+0x10); } } static int sis_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; struct ata_probe_ent *probe_ent = NULL; int rc; u32 genctl; struct ata_port_info *ppi; int pci_dev_busy = 0; + u8 pmr; + u8 port2_start; + + if (!printed_version++) + pdev_printk(KERN_INFO, pdev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) @@ -219,9 +262,12 @@ static int sis_init_one (struct pci_dev rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; ppi = &sis_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; @@ -231,7 +277,7 @@ static int sis_init_one (struct pci_dev pci_read_config_dword(pdev, SIS_GENCTL, &genctl); if ((genctl & GENCTL_IOMAPPED_SCR) == 0) probe_ent->host_flags |= SIS_FLAG_CFGSCR; - + /* if hardware thinks SCRs are in IO space, but there are * no IO resources assigned, change to PCI cfg space. */ @@ -243,15 +289,33 @@ static int sis_init_one (struct pci_dev probe_ent->host_flags |= SIS_FLAG_CFGSCR; } + pci_read_config_byte(pdev, SIS_PMR, &pmr); + if (ent->device != 0x182) { + if ((pmr & SIS_PMR_COMBINED) == 0) { + pdev_printk(KERN_INFO, pdev, + "Detected SiS 180/181 chipset in SATA mode\n"); + port2_start = 64; + } + else { + pdev_printk(KERN_INFO, pdev, + "Detected SiS 180/181 chipset in combined mode\n"); + port2_start=0; + } + } + else { + pdev_printk(KERN_INFO, pdev, "Detected SiS 182 chipset\n"); + port2_start = 0x20; + } + if (!(probe_ent->host_flags & SIS_FLAG_CFGSCR)) { probe_ent->port[0].scr_addr = pci_resource_start(pdev, SIS_SCR_PCI_BAR); probe_ent->port[1].scr_addr = - pci_resource_start(pdev, SIS_SCR_PCI_BAR) + 64; + pci_resource_start(pdev, SIS_SCR_PCI_BAR) + port2_start; } pci_set_master(pdev); - pci_enable_intx(pdev); + pci_intx(pdev, 1); ata_add_to_probe_list(probe_ent); diff -Nur -p linux-2.4.32/drivers/scsi/sata_svw.c linux-2.4.33-rc2/drivers/scsi/sata_svw.c --- linux-2.4.32/drivers/scsi/sata_svw.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/sata_svw.c 2006-06-21 10:40:43.000000000 -0300 @@ -13,21 +13,26 @@ * This driver probably works with non-Apple versions of the * Broadcom chipset... * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware documentation available under NDA. * */ @@ -49,7 +54,7 @@ #endif /* CONFIG_PPC_OF */ #define DRV_NAME "sata_svw" -#define DRV_VERSION "1.06" +#define DRV_VERSION "1.07" /* Taskfile registers offsets */ #define K2_SATA_TF_CMD_OFFSET 0x00 @@ -79,6 +84,8 @@ /* Port stride */ #define K2_SATA_PORT_OFFSET 0x100 +static u8 k2_stat_check_status(struct ata_port *ap); + static u32 k2_sata_scr_read (struct ata_port *ap, unsigned int sc_reg) { @@ -97,7 +104,7 @@ static void k2_sata_scr_write (struct at } -static void k2_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +static void k2_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -131,16 +138,24 @@ static void k2_sata_tf_load(struct ata_p static void k2_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - u16 nsect, lbal, lbam, lbah; + u16 nsect, lbal, lbam, lbah, feature; - nsect = tf->nsect = readw(ioaddr->nsect_addr); - lbal = tf->lbal = readw(ioaddr->lbal_addr); - lbam = tf->lbam = readw(ioaddr->lbam_addr); - lbah = tf->lbah = readw(ioaddr->lbah_addr); + tf->command = k2_stat_check_status(ap); tf->device = readw(ioaddr->device_addr); + feature = readw(ioaddr->error_addr); + nsect = readw(ioaddr->nsect_addr); + lbal = readw(ioaddr->lbal_addr); + lbam = readw(ioaddr->lbam_addr); + lbah = readw(ioaddr->lbah_addr); + + tf->feature = feature; + tf->nsect = nsect; + tf->lbal = lbal; + tf->lbam = lbam; + tf->lbah = lbah; if (tf->flags & ATA_TFLAG_LBA48) { - tf->hob_feature = readw(ioaddr->error_addr) >> 8; + tf->hob_feature = feature >> 8; tf->hob_nsect = nsect >> 8; tf->hob_lbal = lbal >> 8; tf->hob_lbam = lbam >> 8; @@ -195,18 +210,18 @@ static void k2_bmdma_start_mmio (struct /* start host DMA transaction */ dmactl = readb(mmio + ATA_DMA_CMD); writeb(dmactl | ATA_DMA_START, mmio + ATA_DMA_CMD); - /* There is a race condition in certain SATA controllers that can - be seen when the r/w command is given to the controller before the + /* There is a race condition in certain SATA controllers that can + be seen when the r/w command is given to the controller before the host DMA is started. On a Read command, the controller would initiate the command to the drive even before it sees the DMA start. When there - are very fast drives connected to the controller, or when the data request + are very fast drives connected to the controller, or when the data request hits in the drive cache, there is the possibility that the drive returns a part or all of the requested data to the controller before the DMA start is issued. In this case, the controller would become confused as to what to do with the data. In the worst case when all the data is returned back to the controller, the controller could hang. In other cases it could return partial data returning in data corruption. This problem has been seen in PPC systems and can also appear - on an system with very fast disks, where the SATA controller is sitting behind a + on an system with very fast disks, where the SATA controller is sitting behind a number of bridges, and hence there is significant latency between the r/w command and the start command. */ /* issue r/w command if the access is to ATA*/ @@ -214,7 +229,7 @@ static void k2_bmdma_start_mmio (struct ap->ops->exec_command(ap, &qc->tf); } - + static u8 k2_stat_check_status(struct ata_port *ap) { return readl((void *) ap->ioaddr.status_addr); @@ -292,7 +307,7 @@ static Scsi_Host_Template k2_sata_sht = }; -static struct ata_port_operations k2_sata_ops = { +static const struct ata_port_operations k2_sata_ops = { .port_disable = ata_port_disable, .tf_load = k2_sata_tf_load, .tf_read = k2_sata_tf_read, @@ -313,7 +328,7 @@ static struct ata_port_operations k2_sat .scr_write = k2_sata_scr_write, .port_start = ata_port_start, .port_stop = ata_port_stop, - .host_stop = ata_host_stop, + .host_stop = ata_pci_host_stop, }; static void k2_sata_setup_port(struct ata_ioports *port, unsigned long base) @@ -341,13 +356,13 @@ static int k2_sata_init_one (struct pci_ static int printed_version; struct ata_probe_ent *probe_ent = NULL; unsigned long base; - void *mmio_base; + void __iomem *mmio_base; int pci_dev_busy = 0; int rc; int i; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + pdev_printk(KERN_DEBUG, pdev, "version " DRV_VERSION "\n"); /* * If this driver happens to only be useful on Apple's K2, then @@ -373,6 +388,9 @@ static int k2_sata_init_one (struct pci_ rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { @@ -384,8 +402,7 @@ static int k2_sata_init_one (struct pci_ probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = ioremap(pci_resource_start(pdev, 5), - pci_resource_len(pdev, 5)); + mmio_base = pci_iomap(pdev, 5, 0); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_free_ent; @@ -447,7 +464,7 @@ err_out: * 0x24a is device ID for BCM5785 (aka HT1000) HT southbridge integrated SATA * controller * */ -static struct pci_device_id k2_sata_pci_tbl[] = { +static const struct pci_device_id k2_sata_pci_tbl[] = { { 0x1166, 0x0240, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, { 0x1166, 0x0241, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, { 0x1166, 0x0242, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 8 }, diff -Nur -p linux-2.4.32/drivers/scsi/sata_sx4.c linux-2.4.33-rc2/drivers/scsi/sata_sx4.c --- linux-2.4.32/drivers/scsi/sata_sx4.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/sata_sx4.c 2006-06-21 10:40:43.000000000 -0300 @@ -7,21 +7,26 @@ * * Copyright 2003-2004 Red Hat, Inc. * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware documentation available under NDA. * */ @@ -40,7 +45,7 @@ #include "sata_promise.h" #define DRV_NAME "sata_sx4" -#define DRV_VERSION "0.7" +#define DRV_VERSION "0.8" enum { @@ -94,7 +99,7 @@ enum { PDC_DIMM1_CONTROL_OFFSET = 0x84, PDC_SDRAM_CONTROL_OFFSET = 0x88, PDC_I2C_WRITE = 0x00000000, - PDC_I2C_READ = 0x00000040, + PDC_I2C_READ = 0x00000040, PDC_I2C_START = 0x00000080, PDC_I2C_MASK_INT = 0x00000020, PDC_I2C_COMPLETE = 0x00010000, @@ -105,16 +110,16 @@ enum { PDC_DIMM_SPD_COLUMN_NUM = 4, PDC_DIMM_SPD_MODULE_ROW = 5, PDC_DIMM_SPD_TYPE = 11, - PDC_DIMM_SPD_FRESH_RATE = 12, - PDC_DIMM_SPD_BANK_NUM = 17, + PDC_DIMM_SPD_FRESH_RATE = 12, + PDC_DIMM_SPD_BANK_NUM = 17, PDC_DIMM_SPD_CAS_LATENCY = 18, - PDC_DIMM_SPD_ATTRIBUTE = 21, + PDC_DIMM_SPD_ATTRIBUTE = 21, PDC_DIMM_SPD_ROW_PRE_CHARGE = 27, - PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28, + PDC_DIMM_SPD_ROW_ACTIVE_DELAY = 28, PDC_DIMM_SPD_RAS_CAS_DELAY = 29, PDC_DIMM_SPD_ACTIVE_PRECHARGE = 30, PDC_DIMM_SPD_SYSTEM_FREQ = 126, - PDC_CTL_STATUS = 0x08, + PDC_CTL_STATUS = 0x08, PDC_DIMM_WINDOW_CTLR = 0x0C, PDC_TIME_CONTROL = 0x3C, PDC_TIME_PERIOD = 0x40, @@ -132,7 +137,7 @@ struct pdc_port_priv { }; struct pdc_host_priv { - void *dimm_mmio; + void __iomem *dimm_mmio; unsigned int doing_hdma; unsigned int hdma_prod; @@ -152,20 +157,20 @@ static void pdc_20621_phy_reset (struct static int pdc_port_start(struct ata_port *ap); static void pdc_port_stop(struct ata_port *ap); static void pdc20621_qc_prep(struct ata_queued_cmd *qc); -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf); -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf); +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf); +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf); static void pdc20621_host_stop(struct ata_host_set *host_set); static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe); static int pdc20621_detect_dimm(struct ata_probe_ent *pe); -static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, +static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, u32 subaddr, u32 *pdata); static int pdc20621_prog_dimm0(struct ata_probe_ent *pe); static unsigned int pdc20621_prog_dimm_global(struct ata_probe_ent *pe); #ifdef ATA_VERBOSE_DEBUG -static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, +static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); #endif -static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, +static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size); static void pdc20621_irq_clear(struct ata_port *ap); static int pdc20621_qc_issue_prot(struct ata_queued_cmd *qc); @@ -191,7 +196,7 @@ static Scsi_Host_Template pdc_sata_sht = .bios_param = ata_std_bios_param, }; -static struct ata_port_operations pdc_20621_ops = { +static const struct ata_port_operations pdc_20621_ops = { .port_disable = ata_port_disable, .tf_load = pdc_tf_load_mmio, .tf_read = ata_tf_read, @@ -223,7 +228,7 @@ static struct ata_port_info pdc_port_inf }; -static struct pci_device_id pdc_sata_pci_tbl[] = { +static const struct pci_device_id pdc_sata_pci_tbl[] = { { PCI_VENDOR_ID_PROMISE, 0x6622, PCI_ANY_ID, PCI_ANY_ID, 0, 0, board_20621 }, { } /* terminate list */ @@ -240,13 +245,14 @@ static struct pci_driver pdc_sata_pci_dr static void pdc20621_host_stop(struct ata_host_set *host_set) { + struct pci_dev *pdev = to_pci_dev(host_set->dev); struct pdc_host_priv *hpriv = host_set->private_data; - void *dimm_mmio = hpriv->dimm_mmio; + void __iomem *dimm_mmio = hpriv->dimm_mmio; - iounmap(dimm_mmio); + pci_iounmap(pdev, dimm_mmio); kfree(hpriv); - ata_host_stop(host_set); + pci_iounmap(pdev, host_set->mmio_base); } static int pdc_port_start(struct ata_port *ap) @@ -443,14 +449,14 @@ static inline void pdc20621_host_pkt(str static void pdc20621_dma_prep(struct ata_queued_cmd *qc) { - struct scatterlist *sg = qc->sg; + struct scatterlist *sg; struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; - void *mmio = ap->host_set->mmio_base; + void __iomem *mmio = ap->host_set->mmio_base; struct pdc_host_priv *hpriv = ap->host_set->private_data; - void *dimm_mmio = hpriv->dimm_mmio; + void __iomem *dimm_mmio = hpriv->dimm_mmio; unsigned int portno = ap->port_no; - unsigned int i, last, idx, total_len = 0, sgt_len; + unsigned int i, idx, total_len = 0, sgt_len; u32 *buf = (u32 *) &pp->dimm_buf[PDC_DIMM_HEADER_SZ]; assert(qc->flags & ATA_QCFLAG_DMAMAP); @@ -463,12 +469,11 @@ static void pdc20621_dma_prep(struct ata /* * Build S/G table */ - last = qc->n_elem; idx = 0; - for (i = 0; i < last; i++) { - buf[idx++] = cpu_to_le32(sg_dma_address(&sg[i])); - buf[idx++] = cpu_to_le32(sg_dma_len(&sg[i])); - total_len += sg[i].length; + ata_for_each_sg(sg, qc) { + buf[idx++] = cpu_to_le32(sg_dma_address(sg)); + buf[idx++] = cpu_to_le32(sg_dma_len(sg)); + total_len += sg_dma_len(sg); } buf[idx - 1] |= cpu_to_le32(ATA_PRD_EOT); sgt_len = idx * 4; @@ -508,9 +513,9 @@ static void pdc20621_nodata_prep(struct { struct ata_port *ap = qc->ap; struct pdc_port_priv *pp = ap->private_data; - void *mmio = ap->host_set->mmio_base; + void __iomem *mmio = ap->host_set->mmio_base; struct pdc_host_priv *hpriv = ap->host_set->private_data; - void *dimm_mmio = hpriv->dimm_mmio; + void __iomem *dimm_mmio = hpriv->dimm_mmio; unsigned int portno = ap->port_no; unsigned int i; @@ -560,7 +565,7 @@ static void __pdc20621_push_hdma(struct { struct ata_port *ap = qc->ap; struct ata_host_set *host_set = ap->host_set; - void *mmio = host_set->mmio_base; + void __iomem *mmio = host_set->mmio_base; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -634,7 +639,7 @@ static void pdc20621_packet_start(struct struct ata_port *ap = qc->ap; struct ata_host_set *host_set = ap->host_set; unsigned int port_no = ap->port_no; - void *mmio = host_set->mmio_base; + void __iomem *mmio = host_set->mmio_base; unsigned int rw = (qc->tf.flags & ATA_TFLAG_WRITE); u8 seq = (u8) (port_no + 1); unsigned int port_ofs; @@ -663,8 +668,8 @@ static void pdc20621_packet_start(struct readl(mmio + PDC_20621_SEQCTL + (seq * 4)); /* flush */ writel(port_ofs + PDC_DIMM_ATA_PKT, - (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); VPRINTK("submitted ofs 0x%x (%u), seq %u\n", port_ofs + PDC_DIMM_ATA_PKT, port_ofs + PDC_DIMM_ATA_PKT, @@ -694,7 +699,7 @@ static int pdc20621_qc_issue_prot(struct static inline unsigned int pdc20621_host_intr( struct ata_port *ap, struct ata_queued_cmd *qc, unsigned int doing_hdma, - void *mmio) + void __iomem *mmio) { unsigned int port_no = ap->port_no; unsigned int port_ofs = @@ -712,7 +717,7 @@ static inline unsigned int pdc20621_host VPRINTK("ata%u: read hdma, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap)); + ata_qc_complete(qc, ac_err_mask(ata_wait_idle(ap))); pdc20621_pop_hdma(qc); } @@ -741,8 +746,8 @@ static inline unsigned int pdc20621_host writel(0x00000001, mmio + PDC_20621_SEQCTL + (seq * 4)); readl(mmio + PDC_20621_SEQCTL + (seq * 4)); writel(port_ofs + PDC_DIMM_ATA_PKT, - (void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); - readl((void *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + (void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); + readl((void __iomem *) ap->ioaddr.cmd_addr + PDC_PKT_SUBMIT); } /* step two - execute ATA command */ @@ -750,7 +755,7 @@ static inline unsigned int pdc20621_host VPRINTK("ata%u: write ata, 0x%x 0x%x\n", ap->id, readl(mmio + 0x104), readl(mmio + PDC_HDMA_CTLSTAT)); /* get drive status; clear intr; complete txn */ - ata_qc_complete(qc, ata_wait_idle(ap)); + ata_qc_complete(qc, ac_err_mask(ata_wait_idle(ap))); pdc20621_pop_hdma(qc); } handled = 1; @@ -760,7 +765,7 @@ static inline unsigned int pdc20621_host status = ata_busy_wait(ap, ATA_BUSY | ATA_DRQ, 1000); DPRINTK("BUS_NODATA (drv_stat 0x%X)\n", status); - ata_qc_complete(qc, status); + ata_qc_complete(qc, ac_err_mask(status)); handled = 1; } else { @@ -773,7 +778,7 @@ static inline unsigned int pdc20621_host static void pdc20621_irq_clear(struct ata_port *ap) { struct ata_host_set *host_set = ap->host_set; - void *mmio = host_set->mmio_base; + void __iomem *mmio = host_set->mmio_base; mmio += PDC_CHIP0_OFS; @@ -787,7 +792,7 @@ static irqreturn_t pdc20621_interrupt (i u32 mask = 0; unsigned int i, tmp, port_no; unsigned int handled = 0; - void *mmio_base; + void __iomem *mmio_base; VPRINTK("ENTER\n"); @@ -825,7 +830,8 @@ static irqreturn_t pdc20621_interrupt (i ap = host_set->ports[port_no]; tmp = mask & (1 << i); VPRINTK("seq %u, port_no %u, ap %p, tmp %x\n", i, port_no, ap, tmp); - if (tmp && ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (tmp && ap && + !(ap->flags & (ATA_FLAG_PORT_DISABLED | ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); @@ -847,10 +853,14 @@ static irqreturn_t pdc20621_interrupt (i static void pdc_eng_timeout(struct ata_port *ap) { u8 drv_stat; + struct ata_host_set *host_set = ap->host_set; struct ata_queued_cmd *qc; + unsigned long flags; DPRINTK("ENTER\n"); + spin_lock_irqsave(&host_set->lock, flags); + qc = ata_qc_from_tag(ap, ap->active_tag); if (!qc) { printk(KERN_ERR "ata%u: BUG: timeout without command\n", @@ -870,7 +880,7 @@ static void pdc_eng_timeout(struct ata_p case ATA_PROT_DMA: case ATA_PROT_NODATA: printk(KERN_ERR "ata%u: command timeout\n", ap->id); - ata_qc_complete(qc, ata_wait_idle(ap) | ATA_ERR); + ata_qc_complete(qc, __ac_err_mask(ata_wait_idle(ap))); break; default: @@ -879,15 +889,16 @@ static void pdc_eng_timeout(struct ata_p printk(KERN_ERR "ata%u: unknown timeout, cmd 0x%x stat 0x%x\n", ap->id, qc->tf.command, drv_stat); - ata_qc_complete(qc, drv_stat); + ata_qc_complete(qc, ac_err_mask(drv_stat)); break; } out: + spin_unlock_irqrestore(&host_set->lock, flags); DPRINTK("EXIT\n"); } -static void pdc_tf_load_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_tf_load_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -895,7 +906,7 @@ static void pdc_tf_load_mmio(struct ata_ } -static void pdc_exec_command_mmio(struct ata_port *ap, struct ata_taskfile *tf) +static void pdc_exec_command_mmio(struct ata_port *ap, const struct ata_taskfile *tf) { WARN_ON (tf->protocol == ATA_PROT_DMA || tf->protocol == ATA_PROT_NODATA); @@ -922,23 +933,23 @@ static void pdc_sata_setup_port(struct a #ifdef ATA_VERBOSE_DEBUG -static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, +static void pdc20621_get_from_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size) { u32 window_size; u16 idx; u8 page_mask; long dist; - void *mmio = pe->mmio_base; + void __iomem *mmio = pe->mmio_base; struct pdc_host_priv *hpriv = pe->private_data; - void *dimm_mmio = hpriv->dimm_mmio; + void __iomem *dimm_mmio = hpriv->dimm_mmio; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; - page_mask = 0x00; - window_size = 0x2000 * 4; /* 32K byte uchar size */ - idx = (u16) (offset / window_size); + page_mask = 0x00; + window_size = 0x2000 * 4; /* 32K byte uchar size */ + idx = (u16) (offset / window_size); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); @@ -947,19 +958,19 @@ static void pdc20621_get_from_dimm(struc offset -= (idx * window_size); idx++; - dist = ((long) (window_size - (offset + size))) >= 0 ? size : + dist = ((long) (window_size - (offset + size))) >= 0 ? size : (long) (window_size - offset); - memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), + memcpy_fromio((char *) psource, (char *) (dimm_mmio + offset / 4), dist); - psource += dist; + psource += dist; size -= dist; for (; (long) size >= (long) window_size ;) { writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_fromio((char *) psource, (char *) (dimm_mmio), + memcpy_fromio((char *) psource, (char *) (dimm_mmio), window_size / 4); psource += window_size; size -= window_size; @@ -971,71 +982,70 @@ static void pdc20621_get_from_dimm(struc readl(mmio + PDC_GENERAL_CTLR); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_fromio((char *) psource, (char *) (dimm_mmio), + memcpy_fromio((char *) psource, (char *) (dimm_mmio), size / 4); } } #endif -static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, +static void pdc20621_put_to_dimm(struct ata_probe_ent *pe, void *psource, u32 offset, u32 size) { u32 window_size; u16 idx; u8 page_mask; long dist; - void *mmio = pe->mmio_base; + void __iomem *mmio = pe->mmio_base; struct pdc_host_priv *hpriv = pe->private_data; - void *dimm_mmio = hpriv->dimm_mmio; + void __iomem *dimm_mmio = hpriv->dimm_mmio; - /* hard-code chip #0 */ + /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; - page_mask = 0x00; - window_size = 0x2000 * 4; /* 32K byte uchar size */ + page_mask = 0x00; + window_size = 0x2000 * 4; /* 32K byte uchar size */ idx = (u16) (offset / window_size); writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - offset -= (idx * window_size); + offset -= (idx * window_size); idx++; dist = ((long)(s32)(window_size - (offset + size))) >= 0 ? size : (long) (window_size - offset); - memcpy_toio((char *) (dimm_mmio + offset / 4), (char *) psource, dist); + memcpy_toio(dimm_mmio + offset / 4, psource, dist); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); - psource += dist; + psource += dist; size -= dist; for (; (long) size >= (long) window_size ;) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_toio((char *) (dimm_mmio), (char *) psource, - window_size / 4); + memcpy_toio(dimm_mmio, psource, window_size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); psource += window_size; size -= window_size; idx ++; } - + if (size) { writel(((idx) << page_mask), mmio + PDC_DIMM_WINDOW_CTLR); readl(mmio + PDC_DIMM_WINDOW_CTLR); - memcpy_toio((char *) (dimm_mmio), (char *) psource, size / 4); + memcpy_toio(dimm_mmio, psource, size / 4); writel(0x01, mmio + PDC_GENERAL_CTLR); readl(mmio + PDC_GENERAL_CTLR); } } -static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, +static unsigned int pdc20621_i2c_read(struct ata_probe_ent *pe, u32 device, u32 subaddr, u32 *pdata) { - void *mmio = pe->mmio_base; + void __iomem *mmio = pe->mmio_base; u32 i2creg = 0; - u32 status; + u32 status; u32 count =0; /* hard-code chip #0 */ @@ -1049,7 +1059,7 @@ static unsigned int pdc20621_i2c_read(st readl(mmio + PDC_I2C_ADDR_DATA_OFFSET); /* Write Control to perform read operation, mask int */ - writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, + writel(PDC_I2C_READ | PDC_I2C_START | PDC_I2C_MASK_INT, mmio + PDC_I2C_CONTROL_OFFSET); for (count = 0; count <= 1000; count ++) { @@ -1062,26 +1072,26 @@ static unsigned int pdc20621_i2c_read(st } *pdata = (status >> 8) & 0x000000ff; - return 1; + return 1; } static int pdc20621_detect_dimm(struct ata_probe_ent *pe) { u32 data=0 ; - if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, + if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_SYSTEM_FREQ, &data)) { if (data == 100) return 100; } else return 0; - + if (pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, 9, &data)) { - if(data <= 0x75) + if(data <= 0x75) return 133; } else return 0; - + return 0; } @@ -1091,15 +1101,15 @@ static int pdc20621_prog_dimm0(struct at u32 spd0[50]; u32 data = 0; int size, i; - u8 bdimmsize; - void *mmio = pe->mmio_base; + u8 bdimmsize; + void __iomem *mmio = pe->mmio_base; static const struct { unsigned int reg; unsigned int ofs; } pdc_i2c_read_data [] = { - { PDC_DIMM_SPD_TYPE, 11 }, + { PDC_DIMM_SPD_TYPE, 11 }, { PDC_DIMM_SPD_FRESH_RATE, 12 }, - { PDC_DIMM_SPD_COLUMN_NUM, 4 }, + { PDC_DIMM_SPD_COLUMN_NUM, 4 }, { PDC_DIMM_SPD_ATTRIBUTE, 21 }, { PDC_DIMM_SPD_ROW_NUM, 3 }, { PDC_DIMM_SPD_BANK_NUM, 17 }, @@ -1108,7 +1118,7 @@ static int pdc20621_prog_dimm0(struct at { PDC_DIMM_SPD_ROW_ACTIVE_DELAY, 28 }, { PDC_DIMM_SPD_RAS_CAS_DELAY, 29 }, { PDC_DIMM_SPD_ACTIVE_PRECHARGE, 30 }, - { PDC_DIMM_SPD_CAS_LATENCY, 18 }, + { PDC_DIMM_SPD_CAS_LATENCY, 18 }, }; /* hard-code chip #0 */ @@ -1116,17 +1126,17 @@ static int pdc20621_prog_dimm0(struct at for(i=0; i spd0[28]) - ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; + data |= (((((spd0[29] > spd0[28]) + ? spd0[29] : spd0[28]) + 9) / 10) - 1) << 10; data |= ((spd0[30] - spd0[29] + 9) / 10 - 2) << 12; - - if (spd0[18] & 0x08) + + if (spd0[18] & 0x08) data |= ((0x03) << 14); else if (spd0[18] & 0x04) data |= ((0x02) << 14); @@ -1135,7 +1145,7 @@ static int pdc20621_prog_dimm0(struct at else data |= (0 << 14); - /* + /* Calculate the size of bDIMMSize (power of 2) and merge the DIMM size by program start/end address. */ @@ -1145,9 +1155,9 @@ static int pdc20621_prog_dimm0(struct at data |= (((size / 16) - 1) << 16); data |= (0 << 23); data |= 8; - writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); + writel(data, mmio + PDC_DIMM0_CONTROL_OFFSET); readl(mmio + PDC_DIMM0_CONTROL_OFFSET); - return size; + return size; } @@ -1155,7 +1165,7 @@ static unsigned int pdc20621_prog_dimm_g { u32 data, spd0; int error, i; - void *mmio = pe->mmio_base; + void __iomem *mmio = pe->mmio_base; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1167,12 +1177,12 @@ static unsigned int pdc20621_prog_dimm_g Refresh Enable (bit 17) */ - data = 0x022259F1; + data = 0x022259F1; writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); readl(mmio + PDC_SDRAM_CONTROL_OFFSET); /* Turn on for ECC */ - pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, + pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE, &spd0); if (spd0 == 0x02) { data |= (0x01 << 16); @@ -1186,22 +1196,22 @@ static unsigned int pdc20621_prog_dimm_g data |= (1<<19); writel(data, mmio + PDC_SDRAM_CONTROL_OFFSET); - error = 1; + error = 1; for (i = 1; i <= 10; i++) { /* polling ~5 secs */ data = readl(mmio + PDC_SDRAM_CONTROL_OFFSET); if (!(data & (1<<19))) { error = 0; - break; + break; } msleep(i*100); } return error; } - + static unsigned int pdc20621_dimm_init(struct ata_probe_ent *pe) { - int speed, size, length; + int speed, size, length; u32 addr,spd0,pci_status; u32 tmp=0; u32 time_period=0; @@ -1209,7 +1219,7 @@ static unsigned int pdc20621_dimm_init(s u32 ticks=0; u32 clock=0; u32 fparam=0; - void *mmio = pe->mmio_base; + void __iomem *mmio = pe->mmio_base; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1228,7 +1238,7 @@ static unsigned int pdc20621_dimm_init(s /* Wait 3 seconds */ msleep(3000); - /* + /* When timer is enabled, counter is decreased every internal clock cycle. */ @@ -1236,24 +1246,24 @@ static unsigned int pdc20621_dimm_init(s tcount = readl(mmio + PDC_TIME_COUNTER); VPRINTK("Time Counter Register (0x44): 0x%x\n", tcount); - /* + /* If SX4 is on PCI-X bus, after 3 seconds, the timer counter register should be >= (0xffffffff - 3x10^8). */ if(tcount >= PCI_X_TCOUNT) { ticks = (time_period - tcount); VPRINTK("Num counters 0x%x (%d)\n", ticks, ticks); - + clock = (ticks / 300000); VPRINTK("10 * Internal clk = 0x%x (%d)\n", clock, clock); - + clock = (clock * 33); VPRINTK("10 * Internal clk * 33 = 0x%x (%d)\n", clock, clock); /* PLL F Param (bit 22:16) */ fparam = (1400000 / clock) - 2; VPRINTK("PLL F Param: 0x%x (%d)\n", fparam, fparam); - + /* OD param = 0x2 (bit 31:30), R param = 0x5 (bit 29:25) */ pci_status = (0x8a001824 | (fparam << 16)); } else @@ -1264,21 +1274,21 @@ static unsigned int pdc20621_dimm_init(s writel(pci_status, mmio + PDC_CTL_STATUS); readl(mmio + PDC_CTL_STATUS); - /* + /* Read SPD of DIMM by I2C interface, and program the DIMM Module Controller. */ if (!(speed = pdc20621_detect_dimm(pe))) { - printk(KERN_ERR "Detect Local DIMM Fail\n"); + printk(KERN_ERR "Detect Local DIMM Fail\n"); return 1; /* DIMM error */ } VPRINTK("Local DIMM Speed = %d\n", speed); - /* Programming DIMM0 Module Control Register (index_CID0:80h) */ + /* Programming DIMM0 Module Control Register (index_CID0:80h) */ size = pdc20621_prog_dimm0(pe); VPRINTK("Local DIMM Size = %dMB\n",size); - /* Programming DIMM Module Global Control Register (index_CID0:88h) */ + /* Programming DIMM Module Global Control Register (index_CID0:88h) */ if (pdc20621_prog_dimm_global(pe)) { printk(KERN_ERR "Programming DIMM Module Global Control Register Fail\n"); return 1; @@ -1297,30 +1307,30 @@ static unsigned int pdc20621_dimm_init(s pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x10040, 40); pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40); - printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], + printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); - pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, + pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x10040, 40); - printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], + printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); pdc20621_put_to_dimm(pe, (void *) test_parttern1, 0x40, 40); pdc20621_get_from_dimm(pe, (void *) test_parttern2, 0x40, 40); - printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], + printk(KERN_ERR "%x, %x, %s\n", test_parttern2[0], test_parttern2[1], &(test_parttern2[2])); } #endif /* ECC initiliazation. */ - pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, + pdc20621_i2c_read(pe, PDC_DIMM0_SPD_DEV_ADDRESS, PDC_DIMM_SPD_TYPE, &spd0); if (spd0 == 0x02) { VPRINTK("Start ECC initialization\n"); addr = 0; length = size * 1024 * 1024; while (addr < length) { - pdc20621_put_to_dimm(pe, (void *) &tmp, addr, + pdc20621_put_to_dimm(pe, (void *) &tmp, addr, sizeof(u32)); addr += sizeof(u32); } @@ -1333,7 +1343,7 @@ static unsigned int pdc20621_dimm_init(s static void pdc_20621_init(struct ata_probe_ent *pe) { u32 tmp; - void *mmio = pe->mmio_base; + void __iomem *mmio = pe->mmio_base; /* hard-code chip #0 */ mmio += PDC_CHIP0_OFS; @@ -1366,14 +1376,15 @@ static int pdc_sata_init_one (struct pci static int printed_version; struct ata_probe_ent *probe_ent = NULL; unsigned long base; - void *mmio_base, *dimm_mmio = NULL; + void __iomem *mmio_base; + void __iomem *dimm_mmio = NULL; struct pdc_host_priv *hpriv = NULL; unsigned int board_idx = (unsigned int) ent->driver_data; int pci_dev_busy = 0; int rc; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + pdev_printk(KERN_DEBUG, pdev, "version " DRV_VERSION "\n"); /* * If this driver happens to only be useful on Apple's K2, then @@ -1392,6 +1403,9 @@ static int pdc_sata_init_one (struct pci rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { @@ -1403,8 +1417,7 @@ static int pdc_sata_init_one (struct pci probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = ioremap(pci_resource_start(pdev, 3), - pci_resource_len(pdev, 3)); + mmio_base = pci_iomap(pdev, 3, 0); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_free_ent; @@ -1418,8 +1431,7 @@ static int pdc_sata_init_one (struct pci } memset(hpriv, 0, sizeof(*hpriv)); - dimm_mmio = ioremap(pci_resource_start(pdev, 4), - pci_resource_len(pdev, 4)); + dimm_mmio = pci_iomap(pdev, 4, 0); if (!dimm_mmio) { kfree(hpriv); rc = -ENOMEM; @@ -1464,9 +1476,9 @@ static int pdc_sata_init_one (struct pci err_out_iounmap_dimm: /* only get to this label if 20621 */ kfree(hpriv); - iounmap(dimm_mmio); + pci_iounmap(pdev, dimm_mmio); err_out_iounmap: - iounmap(mmio_base); + pci_iounmap(pdev, mmio_base); err_out_free_ent: kfree(probe_ent); err_out_regions: diff -Nur -p linux-2.4.32/drivers/scsi/sata_uli.c linux-2.4.33-rc2/drivers/scsi/sata_uli.c --- linux-2.4.32/drivers/scsi/sata_uli.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/sata_uli.c 2006-06-21 10:40:43.000000000 -0300 @@ -1,21 +1,26 @@ /* * sata_uli.c - ULi Electronics SATA * - * The contents of this file are subject to the Open - * Software License version 1.1 that can be found at - * http://www.opensource.org/licenses/osl-1.1.txt and is included herein - * by reference. * - * Alternatively, the contents of this file may be used under the terms - * of the GNU General Public License version 2 (the "GPL") as distributed - * in the kernel source COPYING file, in which case the provisions of - * the GPL are applicable instead of the above. If you wish to allow - * the use of your version of this file only under the terms of the - * GPL and not to allow others to use your version of this file under - * the OSL, indicate your decision by deleting the provisions above and - * replace them with the notice and other provisions required by the GPL. - * If you do not delete the provisions above, a recipient may use your - * version of this file under either the OSL or the GPL. + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware documentation available under NDA. * */ @@ -50,7 +55,7 @@ static int uli_init_one (struct pci_dev static u32 uli_scr_read (struct ata_port *ap, unsigned int sc_reg); static void uli_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); -static struct pci_device_id uli_pci_tbl[] = { +static const struct pci_device_id uli_pci_tbl[] = { { PCI_VENDOR_ID_AL, 0x5289, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5289 }, { PCI_VENDOR_ID_AL, 0x5287, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5287 }, { PCI_VENDOR_ID_AL, 0x5281, PCI_ANY_ID, PCI_ANY_ID, 0, 0, uli_5281 }, @@ -85,7 +90,7 @@ static Scsi_Host_Template uli_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations uli_ops = { +static const struct ata_port_operations uli_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -120,8 +125,8 @@ static struct ata_port_info uli_port_inf .sht = &uli_sht, .host_flags = ATA_FLAG_SATA | ATA_FLAG_SATA_RESET | ATA_FLAG_NO_LEGACY, - .pio_mask = 0x03, //support pio mode 4 (FIXME) - .udma_mask = 0x7f, //support udma mode 6 + .pio_mask = 0x1f, /* pio0-4 */ + .udma_mask = 0x7f, /* udma0-6 */ .port_ops = &uli_ops, }; @@ -171,26 +176,18 @@ static void uli_scr_write (struct ata_po uli_scr_cfg_write(ap, sc_reg, val); } -/* move to PCI layer, integrate w/ MSI stuff */ -static void pci_enable_intx(struct pci_dev *pdev) -{ - u16 pci_command; - - pci_read_config_word(pdev, PCI_COMMAND, &pci_command); - if (pci_command & PCI_COMMAND_INTX_DISABLE) { - pci_command &= ~PCI_COMMAND_INTX_DISABLE; - pci_write_config_word(pdev, PCI_COMMAND, pci_command); - } -} - static int uli_init_one (struct pci_dev *pdev, const struct pci_device_id *ent) { + static int printed_version; struct ata_probe_ent *probe_ent; struct ata_port_info *ppi; int rc; unsigned int board_idx = (unsigned int) ent->driver_data; int pci_dev_busy = 0; + if (!printed_version++) + pdev_printk(KERN_INFO, pdev, "version " DRV_VERSION "\n"); + rc = pci_enable_device(pdev); if (rc) return rc; @@ -204,14 +201,17 @@ static int uli_init_one (struct pci_dev rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; ppi = &uli_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) { rc = -ENOMEM; goto err_out_regions; } - + switch (board_idx) { case uli_5287: probe_ent->port[0].scr_addr = ULI5287_BASE; @@ -252,7 +252,7 @@ static int uli_init_one (struct pci_dev } pci_set_master(pdev); - pci_enable_intx(pdev); + pci_intx(pdev, 1); ata_add_to_probe_list(probe_ent); diff -Nur -p linux-2.4.32/drivers/scsi/sata_via.c linux-2.4.33-rc2/drivers/scsi/sata_via.c --- linux-2.4.32/drivers/scsi/sata_via.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/sata_via.c 2006-06-21 10:40:43.000000000 -0300 @@ -1,34 +1,38 @@ /* - sata_via.c - VIA Serial ATA controllers - - Maintained by: Jeff Garzik - Please ALWAYS copy linux-ide@vger.kernel.org + * sata_via.c - VIA Serial ATA controllers + * + * Maintained by: Jeff Garzik + * Please ALWAYS copy linux-ide@vger.kernel.org on emails. - - Copyright 2003-2004 Red Hat, Inc. All rights reserved. - Copyright 2003-2004 Jeff Garzik - - The contents of this file are subject to the Open - Software License version 1.1 that can be found at - http://www.opensource.org/licenses/osl-1.1.txt and is included herein - by reference. - - Alternatively, the contents of this file may be used under the terms - of the GNU General Public License version 2 (the "GPL") as distributed - in the kernel source COPYING file, in which case the provisions of - the GPL are applicable instead of the above. If you wish to allow - the use of your version of this file only under the terms of the - GPL and not to allow others to use your version of this file under - the OSL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the GPL. - If you do not delete the provisions above, a recipient may use your - version of this file under either the OSL or the GPL. - - ---------------------------------------------------------------------- - - To-do list: - * VT6421 PATA support - + * + * Copyright 2003-2004 Red Hat, Inc. All rights reserved. + * Copyright 2003-2004 Jeff Garzik + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware documentation available under NDA. + * + * + * To-do list: + * - VT6421 PATA support + * */ #include @@ -71,7 +75,7 @@ static int svia_init_one (struct pci_dev static u32 svia_scr_read (struct ata_port *ap, unsigned int sc_reg); static void svia_scr_write (struct ata_port *ap, unsigned int sc_reg, u32 val); -static struct pci_device_id svia_pci_tbl[] = { +static const struct pci_device_id svia_pci_tbl[] = { { 0x1106, 0x3149, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6420 }, { 0x1106, 0x3249, PCI_ANY_ID, PCI_ANY_ID, 0, 0, vt6421 }, @@ -105,7 +109,7 @@ static Scsi_Host_Template svia_sht = { .bios_param = ata_std_bios_param, }; -static struct ata_port_operations svia_sata_ops = { +static const struct ata_port_operations svia_sata_ops = { .port_disable = ata_port_disable, .tf_load = ata_tf_load, @@ -208,7 +212,7 @@ static struct ata_probe_ent *vt6420_init struct ata_probe_ent *probe_ent; struct ata_port_info *ppi = &svia_port_info; - probe_ent = ata_pci_init_native_mode(pdev, &ppi); + probe_ent = ata_pci_init_native_mode(pdev, &ppi, ATA_PORT_PRIMARY | ATA_PORT_SECONDARY); if (!probe_ent) return NULL; @@ -255,15 +259,15 @@ static void svia_configure(struct pci_de u8 tmp8; pci_read_config_byte(pdev, PCI_INTERRUPT_LINE, &tmp8); - printk(KERN_INFO DRV_NAME "(%s): routed to hard irq line %d\n", - pci_name(pdev), + pdev_printk(KERN_INFO, pdev, "routed to hard irq line %d\n", (int) (tmp8 & 0xf0) == 0xf0 ? 0 : tmp8 & 0x0f); /* make sure SATA channels are enabled */ pci_read_config_byte(pdev, SATA_CHAN_ENAB, &tmp8); if ((tmp8 & ALL_PORTS) != ALL_PORTS) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channels (0x%x)\n", - pci_name(pdev), (int) tmp8); + pdev_printk(KERN_DEBUG, pdev, + "enabling SATA channels (0x%x)\n", + (int) tmp8); tmp8 |= ALL_PORTS; pci_write_config_byte(pdev, SATA_CHAN_ENAB, tmp8); } @@ -271,8 +275,9 @@ static void svia_configure(struct pci_de /* make sure interrupts for each channel sent to us */ pci_read_config_byte(pdev, SATA_INT_GATE, &tmp8); if ((tmp8 & ALL_PORTS) != ALL_PORTS) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel interrupts (0x%x)\n", - pci_name(pdev), (int) tmp8); + pdev_printk(KERN_DEBUG, pdev, + "enabling SATA channel interrupts (0x%x)\n", + (int) tmp8); tmp8 |= ALL_PORTS; pci_write_config_byte(pdev, SATA_INT_GATE, tmp8); } @@ -280,8 +285,9 @@ static void svia_configure(struct pci_de /* make sure native mode is enabled */ pci_read_config_byte(pdev, SATA_NATIVE_MODE, &tmp8); if ((tmp8 & NATIVE_MODE_ALL) != NATIVE_MODE_ALL) { - printk(KERN_DEBUG DRV_NAME "(%s): enabling SATA channel native mode (0x%x)\n", - pci_name(pdev), (int) tmp8); + pdev_printk(KERN_DEBUG, pdev, + "enabling SATA channel native mode (0x%x)\n", + (int) tmp8); tmp8 |= NATIVE_MODE_ALL; pci_write_config_byte(pdev, SATA_NATIVE_MODE, tmp8); } @@ -299,7 +305,7 @@ static int svia_init_one (struct pci_dev u8 tmp8; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + pdev_printk(KERN_DEBUG, pdev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) @@ -314,8 +320,9 @@ static int svia_init_one (struct pci_dev if (board_id == vt6420) { pci_read_config_byte(pdev, SATA_PATA_SHARING, &tmp8); if (tmp8 & SATA_2DEV) { - printk(KERN_ERR DRV_NAME "(%s): SATA master/slave not supported (0x%x)\n", - pci_name(pdev), (int) tmp8); + pdev_printk(KERN_ERR, pdev, + "SATA master/slave not supported (0x%x)\n", + (int) tmp8); rc = -EIO; goto err_out_regions; } @@ -328,10 +335,11 @@ static int svia_init_one (struct pci_dev for (i = 0; i < ARRAY_SIZE(svia_bar_sizes); i++) if ((pci_resource_start(pdev, i) == 0) || (pci_resource_len(pdev, i) < bar_sizes[i])) { - printk(KERN_ERR DRV_NAME "(%s): invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n", - pci_name(pdev), i, - pci_resource_start(pdev, i), - pci_resource_len(pdev, i)); + pdev_printk(KERN_ERR, pdev, + "invalid PCI BAR %u (sz 0x%lx, val 0x%lx)\n", + i, + pci_resource_start(pdev, i), + pci_resource_len(pdev, i)); rc = -ENODEV; goto err_out_regions; } @@ -339,15 +347,17 @@ static int svia_init_one (struct pci_dev rc = pci_set_dma_mask(pdev, ATA_DMA_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, ATA_DMA_MASK); + if (rc) + goto err_out_regions; if (board_id == vt6420) probe_ent = vt6420_init_probe_ent(pdev); else probe_ent = vt6421_init_probe_ent(pdev); - + if (!probe_ent) { - printk(KERN_ERR DRV_NAME "(%s): out of memory\n", - pci_name(pdev)); + pdev_printk(KERN_ERR, pdev, "out of memory\n"); rc = -ENOMEM; goto err_out_regions; } diff -Nur -p linux-2.4.32/drivers/scsi/sata_vsc.c linux-2.4.33-rc2/drivers/scsi/sata_vsc.c --- linux-2.4.32/drivers/scsi/sata_vsc.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/sata_vsc.c 2006-06-21 10:40:43.000000000 -0300 @@ -9,9 +9,29 @@ * * Bits from Jeff Garzik, Copyright RedHat, Inc. * - * This file is subject to the terms and conditions of the GNU General Public - * License. See the file "COPYING" in the main directory of this archive - * for more details. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Vitesse hardware documentation presumably available under NDA. + * Intel 31244 (same hardware interface) documentation presumably + * available from http://developer.intel.com/ + * */ #include @@ -26,7 +46,7 @@ #include #define DRV_NAME "sata_vsc" -#define DRV_VERSION "1.0" +#define DRV_VERSION "1.1" /* Interrupt register offsets (from chip base address) */ #define VSC_SATA_INT_STAT_OFFSET 0x00 @@ -65,7 +85,7 @@ static u32 vsc_sata_scr_read (struct ata { if (sc_reg > SCR_CONTROL) return 0xffffffffU; - return readl((void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + return readl((void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } @@ -74,16 +94,16 @@ static void vsc_sata_scr_write (struct a { if (sc_reg > SCR_CONTROL) return; - writel(val, (void *) ap->ioaddr.scr_addr + (sc_reg * 4)); + writel(val, (void __iomem *) ap->ioaddr.scr_addr + (sc_reg * 4)); } static void vsc_intr_mask_update(struct ata_port *ap, u8 ctl) { - unsigned long mask_addr; + void __iomem *mask_addr; u8 mask; - mask_addr = (unsigned long) ap->host_set->mmio_base + + mask_addr = ap->host_set->mmio_base + VSC_SATA_INT_MASK_OFFSET + ap->port_no; mask = readb(mask_addr); if (ctl & ATA_NIEN) @@ -94,7 +114,7 @@ static void vsc_intr_mask_update(struct } -static void vsc_sata_tf_load(struct ata_port *ap, struct ata_taskfile *tf) +static void vsc_sata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; unsigned int is_addr = tf->flags & ATA_TFLAG_ISADDR; @@ -132,16 +152,24 @@ static void vsc_sata_tf_load(struct ata_ static void vsc_sata_tf_read(struct ata_port *ap, struct ata_taskfile *tf) { struct ata_ioports *ioaddr = &ap->ioaddr; - u16 nsect, lbal, lbam, lbah; + u16 nsect, lbal, lbam, lbah, feature; - nsect = tf->nsect = readw(ioaddr->nsect_addr); - lbal = tf->lbal = readw(ioaddr->lbal_addr); - lbam = tf->lbam = readw(ioaddr->lbam_addr); - lbah = tf->lbah = readw(ioaddr->lbah_addr); + tf->command = ata_check_status(ap); tf->device = readw(ioaddr->device_addr); + feature = readw(ioaddr->error_addr); + nsect = readw(ioaddr->nsect_addr); + lbal = readw(ioaddr->lbal_addr); + lbam = readw(ioaddr->lbam_addr); + lbah = readw(ioaddr->lbah_addr); + + tf->feature = feature; + tf->nsect = nsect; + tf->lbal = lbal; + tf->lbam = lbam; + tf->lbah = lbah; if (tf->flags & ATA_TFLAG_LBA48) { - tf->hob_feature = readb(ioaddr->error_addr); + tf->hob_feature = feature >> 8; tf->hob_nsect = nsect >> 8; tf->hob_lbal = lbal >> 8; tf->hob_lbam = lbam >> 8; @@ -172,7 +200,8 @@ static irqreturn_t vsc_sata_interrupt (i struct ata_port *ap; ap = host_set->ports[i]; - if (ap && (!(ap->flags & ATA_FLAG_PORT_DISABLED))) { + if (ap && !(ap->flags & + (ATA_FLAG_PORT_DISABLED|ATA_FLAG_NOINTR))) { struct ata_queued_cmd *qc; qc = ata_qc_from_tag(ap, ap->active_tag); @@ -209,7 +238,7 @@ static Scsi_Host_Template vsc_sata_sht = }; -static struct ata_port_operations vsc_sata_ops = { +static const struct ata_port_operations vsc_sata_ops = { .port_disable = ata_port_disable, .tf_load = vsc_sata_tf_load, .tf_read = vsc_sata_tf_read, @@ -230,7 +259,7 @@ static struct ata_port_operations vsc_sa .scr_write = vsc_sata_scr_write, .port_start = ata_port_start, .port_stop = ata_port_stop, - .host_stop = ata_host_stop, + .host_stop = ata_pci_host_stop, }; static void __devinit vsc_sata_setup_port(struct ata_ioports *port, unsigned long base) @@ -261,11 +290,11 @@ static int __devinit vsc_sata_init_one ( struct ata_probe_ent *probe_ent = NULL; unsigned long base; int pci_dev_busy = 0; - void *mmio_base; + void __iomem *mmio_base; int rc; if (!printed_version++) - printk(KERN_DEBUG DRV_NAME " version " DRV_VERSION "\n"); + pdev_printk(KERN_DEBUG, pdev, "version " DRV_VERSION "\n"); rc = pci_enable_device(pdev); if (rc) @@ -291,6 +320,9 @@ static int __devinit vsc_sata_init_one ( rc = pci_set_dma_mask(pdev, DMA_32BIT_MASK); if (rc) goto err_out_regions; + rc = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK); + if (rc) + goto err_out_regions; probe_ent = kmalloc(sizeof(*probe_ent), GFP_KERNEL); if (probe_ent == NULL) { @@ -301,8 +333,7 @@ static int __devinit vsc_sata_init_one ( probe_ent->dev = pci_dev_to_dev(pdev); INIT_LIST_HEAD(&probe_ent->node); - mmio_base = ioremap(pci_resource_start(pdev, 0), - pci_resource_len(pdev, 0)); + mmio_base = pci_iomap(pdev, 0, 0); if (mmio_base == NULL) { rc = -ENOMEM; goto err_out_free_ent; @@ -338,7 +369,7 @@ static int __devinit vsc_sata_init_one ( pci_set_master(pdev); - /* + /* * Config offset 0x98 is "Extended Control and Status Register 0" * Default value is (1 << 28). All bits except bit 28 are reserved in * DPA mode. If bit 28 is set, LED 0 reflects all ports' activity. @@ -366,7 +397,7 @@ err_out: * 0x8086/0x3200 is the Intel 31244, which is supposed to be identical * compatibility is untested as of yet */ -static struct pci_device_id vsc_sata_pci_tbl[] = { +static const struct pci_device_id vsc_sata_pci_tbl[] = { { 0x1725, 0x7174, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, { 0x8086, 0x3200, PCI_ANY_ID, PCI_ANY_ID, 0x10600, 0xFFFFFF, 0 }, { } diff -Nur -p linux-2.4.32/drivers/scsi/scsi_scan.c linux-2.4.33-rc2/drivers/scsi/scsi_scan.c --- linux-2.4.32/drivers/scsi/scsi_scan.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/drivers/scsi/scsi_scan.c 2006-06-21 10:40:43.000000000 -0300 @@ -145,6 +145,7 @@ static struct dev_info device_list[] = {"PIONEER", "CD-ROM DRM-600", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-602X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER", "CD-ROM DRM-604X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, + {"PIONEER", "CD-ROM DRM-624X", "*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"EMULEX", "MD21/S2 ESDI", "*", BLIST_SINGLELUN}, {"CANON", "IPUBJD", "*", BLIST_SPARSELUN}, {"nCipher", "Fastness Crypto", "*", BLIST_FORCELUN}, diff -Nur -p linux-2.4.32/drivers/usb/gadget/rndis.c linux-2.4.33-rc2/drivers/usb/gadget/rndis.c --- linux-2.4.32/drivers/usb/gadget/rndis.c 2005-01-19 12:10:06.000000000 -0200 +++ linux-2.4.33-rc2/drivers/usb/gadget/rndis.c 2006-06-21 10:40:43.000000000 -0300 @@ -853,9 +853,12 @@ static int rndis_query_response (int con /* * we need more memory: - * oid_supported_list is the largest answer + * gen_ndis_query_resp expects enough space for + * rndis_query_cmplt_type followed by data. + * oid_supported_list is the largest data reply */ - r = rndis_add_response (configNr, sizeof (oid_supported_list)); + r = rndis_add_response (configNr, + sizeof (oid_supported_list) + sizeof(rndis_query_cmplt_type)); if (!r) return -ENOMEM; resp = (rndis_query_cmplt_type *) r->buf; diff -Nur -p linux-2.4.32/drivers/usb/host/ehci-hcd.c linux-2.4.33-rc2/drivers/usb/host/ehci-hcd.c --- linux-2.4.32/drivers/usb/host/ehci-hcd.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/drivers/usb/host/ehci-hcd.c 2006-06-21 10:40:43.000000000 -0300 @@ -796,6 +796,30 @@ static int ehci_urb_enqueue ( } } +static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh) +{ + /* if we need to use IAA and it's busy, defer */ + if (qh->qh_state == QH_STATE_LINKED + && ehci->reclaim + && HCD_IS_RUNNING (ehci->hcd.state)) { + struct ehci_qh *last; + + for (last = ehci->reclaim; + last->reclaim; + last = last->reclaim) + continue; + qh->qh_state = QH_STATE_UNLINK_WAIT; + last->reclaim = qh; + + /* bypass IAA if the hc can't care */ + } else if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim) + end_unlink_async (ehci, NULL); + + /* something else might have unlinked the qh by now */ + if (qh->qh_state == QH_STATE_LINKED) + start_unlink_async (ehci, qh); +} + /* remove from hardware lists * completions normally happen asynchronously */ @@ -814,28 +838,7 @@ static int ehci_urb_dequeue (struct usb_ qh = (struct ehci_qh *) urb->hcpriv; if (!qh) break; - - /* if we need to use IAA and it's busy, defer */ - if (qh->qh_state == QH_STATE_LINKED - && ehci->reclaim - && HCD_IS_RUNNING (ehci->hcd.state) - ) { - struct ehci_qh *last; - - for (last = ehci->reclaim; - last->reclaim; - last = last->reclaim) - continue; - qh->qh_state = QH_STATE_UNLINK_WAIT; - last->reclaim = qh; - - /* bypass IAA if the hc can't care */ - } else if (!HCD_IS_RUNNING (ehci->hcd.state) && ehci->reclaim) - end_unlink_async (ehci, NULL); - - /* something else might have unlinked the qh by now */ - if (qh->qh_state == QH_STATE_LINKED) - start_unlink_async (ehci, qh); + unlink_async (ehci, qh); break; case PIPE_INTERRUPT: diff -Nur -p linux-2.4.32/drivers/usb/host/ehci-q.c linux-2.4.33-rc2/drivers/usb/host/ehci-q.c --- linux-2.4.32/drivers/usb/host/ehci-q.c 2005-01-19 12:10:07.000000000 -0200 +++ linux-2.4.33-rc2/drivers/usb/host/ehci-q.c 2006-06-21 10:40:43.000000000 -0300 @@ -199,8 +199,6 @@ ehci_urb_done (struct ehci_hcd *ehci, st #ifdef INTR_AUTOMAGIC struct urb *resubmit = 0; struct usb_device *dev = 0; - - static int ehci_urb_enqueue (struct usb_hcd *, struct urb *, int); #endif if (likely (urb->hcpriv != 0)) { @@ -280,6 +278,7 @@ ehci_urb_done (struct ehci_hcd *ehci, st } static void start_unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); +static void unlink_async (struct ehci_hcd *ehci, struct ehci_qh *qh); /* * Process and free completed qtds for a qh, returning URBs to drivers. @@ -430,7 +429,7 @@ halt: qh_refresh(ehci, qh); break; case QH_STATE_LINKED: - start_unlink_async (ehci, qh); + unlink_async (ehci, qh); break; /* otherwise, unlink already started */ } diff -Nur -p linux-2.4.32/drivers/usb/host/usb-uhci.c linux-2.4.33-rc2/drivers/usb/host/usb-uhci.c --- linux-2.4.32/drivers/usb/host/usb-uhci.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/drivers/usb/host/usb-uhci.c 2006-06-21 10:40:43.000000000 -0300 @@ -2491,7 +2491,7 @@ _static int process_interrupt (uhci_t *s ((urb_priv_t*)urb->hcpriv)->flags=0; } - if ((urb->status != -ECONNABORTED) && (urb->status != ECONNRESET) && + if ((urb->status != -ECONNABORTED) && (urb->status != -ECONNRESET) && (urb->status != -ENOENT)) { urb->status = -EINPROGRESS; diff -Nur -p linux-2.4.32/drivers/usb/serial/usbserial.c linux-2.4.33-rc2/drivers/usb/serial/usbserial.c --- linux-2.4.32/drivers/usb/serial/usbserial.c 2005-04-03 22:42:19.000000000 -0300 +++ linux-2.4.33-rc2/drivers/usb/serial/usbserial.c 2006-06-21 10:40:43.000000000 -0300 @@ -488,7 +488,7 @@ static void post_helper(void *arg) struct usb_serial_post_job *job; struct usb_serial_port *port; struct usb_serial *serial; - unsigned int flags; + unsigned long flags; spin_lock_irqsave(&post_lock, flags); pos = post_list.next; diff -Nur -p linux-2.4.32/fs/binfmt_elf.c linux-2.4.33-rc2/fs/binfmt_elf.c --- linux-2.4.32/fs/binfmt_elf.c 2005-05-31 21:56:56.000000000 -0300 +++ linux-2.4.33-rc2/fs/binfmt_elf.c 2006-06-21 10:40:43.000000000 -0300 @@ -643,6 +643,11 @@ static int load_elf_binary(struct linux_ SET_PERSONALITY(elf_ex, ibcs2_interpreter); } + if (BAD_ADDR(elf_ex.e_entry)) { + retval = -ENOEXEC; + goto out_free_dentry; + } + /* OK, we are done with that, now set up the arg stuff, and then start this sucker up */ @@ -820,7 +825,7 @@ static int load_elf_binary(struct linux_ printk(KERN_ERR "Unable to load interpreter %.128s\n", elf_interpreter); force_sig(SIGSEGV, current); - retval = -ENOEXEC; /* Nobody gets to see this, but.. */ + retval = IS_ERR((void *)elf_entry) ? PTR_ERR((void *)elf_entry) : -ENOEXEC; goto out_free_dentry; } reloc_func_desc = interp_load_addr; diff -Nur -p linux-2.4.32/fs/dcache.c linux-2.4.33-rc2/fs/dcache.c --- linux-2.4.32/fs/dcache.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/fs/dcache.c 2006-06-21 10:40:43.000000000 -0300 @@ -221,7 +221,7 @@ int d_invalidate(struct dentry * dentry) static inline struct dentry * __dget_locked(struct dentry *dentry) { atomic_inc(&dentry->d_count); - if (atomic_read(&dentry->d_count) == 1) { + if (!list_empty(&dentry->d_lru)) { dentry_stat.nr_unused--; list_del_init(&dentry->d_lru); } diff -Nur -p linux-2.4.32/fs/ext2/namei.c linux-2.4.33-rc2/fs/ext2/namei.c --- linux-2.4.32/fs/ext2/namei.c 2001-10-04 02:57:36.000000000 -0300 +++ linux-2.4.33-rc2/fs/ext2/namei.c 2006-06-21 10:40:43.000000000 -0300 @@ -313,6 +313,13 @@ static int ext2_rename (struct inode * o ext2_inc_count(new_dir); } + /* + * Like most other Unix systems, set the ctime for inodes on a + * rename. Note that other 2.4 FS as well as EXT2 on 2.2 and 2.6 + * do this. ext2_dec_count() will mark the inode dirty. + */ + old_inode->i_ctime = CURRENT_TIME; + ext2_delete_entry (old_de, old_page); ext2_dec_count(old_inode); diff -Nur -p linux-2.4.32/fs/inode.c linux-2.4.33-rc2/fs/inode.c --- linux-2.4.32/fs/inode.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/fs/inode.c 2006-06-21 10:40:43.000000000 -0300 @@ -854,8 +854,8 @@ void prune_icache(int goal) */ if (goal <= 0) return; - if (inodes_stat.nr_unused * sizeof(struct inode) * 10 < - freeable_lowmem() * PAGE_SIZE) + if (inodes_stat.nr_unused < + (freeable_lowmem() * PAGE_SIZE) / (sizeof(struct inode) * 10)) return; wakeup_bdflush(); diff -Nur -p linux-2.4.32/fs/jbd/recovery.c linux-2.4.33-rc2/fs/jbd/recovery.c --- linux-2.4.32/fs/jbd/recovery.c 2003-06-13 11:51:37.000000000 -0300 +++ linux-2.4.33-rc2/fs/jbd/recovery.c 2006-06-21 10:40:43.000000000 -0300 @@ -138,8 +138,11 @@ static int jread(struct buffer_head **bh *bhp = NULL; - J_ASSERT (offset < journal->j_maxlen); - + if (offset >= journal->j_maxlen) { + printk(KERN_ERR "JBD: corrupted journal superblock\n"); + return -EIO; + } + err = journal_bmap(journal, offset, &blocknr); if (err) { @@ -534,6 +537,7 @@ static int do_one_pass(journal_t *journa default: jbd_debug(3, "Unrecognised magic %d, end of scan.\n", blocktype); + brelse(bh); goto done; } } diff -Nur -p linux-2.4.32/fs/locks.c linux-2.4.33-rc2/fs/locks.c --- linux-2.4.32/fs/locks.c 2004-04-14 10:05:40.000000000 -0300 +++ linux-2.4.33-rc2/fs/locks.c 2006-06-21 10:40:43.000000000 -0300 @@ -1087,7 +1087,6 @@ static void time_out_leases(struct inode before = &fl->fl_next; continue; } - printk(KERN_INFO "lease broken - owner pid = %d\n", fl->fl_pid); lease_modify(before, fl->fl_type & ~F_INPROGRESS); if (fl == *before) /* lease_modify may have freed fl */ before = &fl->fl_next; diff -Nur -p linux-2.4.32/fs/namei.c linux-2.4.33-rc2/fs/namei.c --- linux-2.4.32/fs/namei.c 2005-04-03 22:42:20.000000000 -0300 +++ linux-2.4.33-rc2/fs/namei.c 2006-06-21 10:40:43.000000000 -0300 @@ -1478,27 +1478,34 @@ exit: int vfs_unlink(struct inode *dir, struct dentry *dentry) { int error; + struct inode *inode; - down(&dir->i_zombie); error = may_delete(dir, dentry, 0); - if (!error) { - error = -EPERM; - if (dir->i_op && dir->i_op->unlink) { - DQUOT_INIT(dir); - if (d_mountpoint(dentry)) - error = -EBUSY; - else { - lock_kernel(); - error = dir->i_op->unlink(dir, dentry); - unlock_kernel(); - if (!error) - d_delete(dentry); - } + if (error) + return error; + + inode = dentry->d_inode; + atomic_inc(&inode->i_count); + double_down(&dir->i_zombie, &inode->i_zombie); + + error = -EPERM; + if (dir->i_op && dir->i_op->unlink) { + DQUOT_INIT(dir); + if (d_mountpoint(dentry)) + error = -EBUSY; + else { + lock_kernel(); + error = dir->i_op->unlink(dir, dentry); + unlock_kernel(); } } - up(&dir->i_zombie); - if (!error) + double_up(&dir->i_zombie, &inode->i_zombie); + iput(inode); + + if (!error) { + d_delete(dentry); inode_dir_notify(dir, DN_DELETE); + } return error; } @@ -1607,18 +1614,19 @@ int vfs_link(struct dentry *old_dentry, struct inode *inode; int error; - down(&dir->i_zombie); error = -ENOENT; inode = old_dentry->d_inode; if (!inode) - goto exit_lock; - - error = may_create(dir, new_dentry); - if (error) - goto exit_lock; + goto exit; error = -EXDEV; if (dir->i_dev != inode->i_dev) + goto exit; + + double_down(&dir->i_zombie, &old_dentry->d_inode->i_zombie); + + error = may_create(dir, new_dentry); + if (error) goto exit_lock; /* @@ -1636,9 +1644,10 @@ int vfs_link(struct dentry *old_dentry, unlock_kernel(); exit_lock: - up(&dir->i_zombie); + double_up(&dir->i_zombie, &old_dentry->d_inode->i_zombie); if (!error) inode_dir_notify(dir, DN_CREATE); +exit: return error; } diff -Nur -p linux-2.4.32/fs/nfs/inode.c linux-2.4.33-rc2/fs/nfs/inode.c --- linux-2.4.32/fs/nfs/inode.c 2004-04-14 10:05:40.000000000 -0300 +++ linux-2.4.33-rc2/fs/nfs/inode.c 2006-06-21 10:40:43.000000000 -0300 @@ -1047,6 +1047,13 @@ __nfs_refresh_inode(struct inode *inode, invalid = 0; } + /* set the invalid flag if the last attempt at invalidating + * the inode didn't empty the clean_pages list */ + if ( NFS_FLAGS(inode) & NFS_INO_MAPPED) { + NFS_FLAGS(inode) &= ~NFS_INO_MAPPED; + invalid = 1; + } + /* * If we have pending writebacks, things can get * messy. @@ -1092,6 +1099,12 @@ __nfs_refresh_inode(struct inode *inode, NFS_ATTRTIMEO(inode) = NFS_MINATTRTIMEO(inode); NFS_ATTRTIMEO_UPDATE(inode) = jiffies; invalidate_inode_pages(inode); + if (! list_empty(&inode->i_mapping->clean_pages)) { + dfprintk(PAGECACHE, + "NFS: clean_pages for %x/%ld is not empty\n", + inode->i_dev, inode->i_ino); + NFS_FLAGS(inode) |= NFS_INO_MAPPED; + } memset(NFS_COOKIEVERF(inode), 0, sizeof(NFS_COOKIEVERF(inode))); } else if (time_after(jiffies, NFS_ATTRTIMEO_UPDATE(inode)+NFS_ATTRTIMEO(inode))) { if ((NFS_ATTRTIMEO(inode) <<= 1) > NFS_MAXATTRTIMEO(inode)) diff -Nur -p linux-2.4.32/fs/nfsd/nfsctl.c linux-2.4.33-rc2/fs/nfsd/nfsctl.c --- linux-2.4.32/fs/nfsd/nfsctl.c 2002-08-02 21:39:45.000000000 -0300 +++ linux-2.4.33-rc2/fs/nfsd/nfsctl.c 2006-06-21 10:40:43.000000000 -0300 @@ -212,8 +212,13 @@ static struct { }; #define CMD_MAX (sizeof(sizes)/sizeof(sizes[0])-1) +#ifdef MODULE +long +handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp) +#else long asmlinkage handle_sys_nfsservctl(int cmd, void *opaque_argp, void *opaque_resp) +#endif { struct nfsctl_arg * argp = opaque_argp; union nfsctl_res * resp = opaque_resp; diff -Nur -p linux-2.4.32/fs/partitions/msdos.c linux-2.4.33-rc2/fs/partitions/msdos.c --- linux-2.4.32/fs/partitions/msdos.c 2002-11-28 21:53:15.000000000 -0200 +++ linux-2.4.33-rc2/fs/partitions/msdos.c 2006-06-21 10:40:43.000000000 -0300 @@ -572,6 +572,19 @@ int msdos_partition(struct gendisk *hd, put_dev_sector(sect); return 0; } + /* + * Now that the 55aa signature is present, this is probably + * either the boot sector of a FAT filesystem or a DOS-type + * partition table. Reject this in case the boot indicator + * is not 0 or 0x80. + */ + p = (struct partition *) (data + 0x1be); + for (i = 1; i <= 4; i++, p++) { + if (p->boot_ind != 0 && p->boot_ind != 0x80) { + put_dev_sector(sect); + return 0; + } + } p = (struct partition *) (data + 0x1be); /* diff -Nur -p linux-2.4.32/fs/proc/base.c linux-2.4.33-rc2/fs/proc/base.c --- linux-2.4.32/fs/proc/base.c 2005-01-19 12:10:11.000000000 -0200 +++ linux-2.4.33-rc2/fs/proc/base.c 2006-06-21 10:40:43.000000000 -0300 @@ -185,8 +185,12 @@ static int proc_pid_cmdline(struct task_ int res = 0; task_lock(task); mm = task->mm; - if (mm) - atomic_inc(&mm->mm_users); + if (mm) { + if (mm->arg_end) + atomic_inc(&mm->mm_users); + else + mm = NULL; + } task_unlock(task); if (mm && mm->arg_start && mm->arg_start < mm->arg_end) { unsigned long len = mm->arg_end - mm->arg_start; diff -Nur -p linux-2.4.32/fs/quota_v2.c linux-2.4.33-rc2/fs/quota_v2.c --- linux-2.4.32/fs/quota_v2.c 2003-08-25 08:44:43.000000000 -0300 +++ linux-2.4.33-rc2/fs/quota_v2.c 2006-06-21 10:40:43.000000000 -0300 @@ -14,6 +14,10 @@ #include #include +MODULE_AUTHOR("Jan Kara"); +MODULE_DESCRIPTION("Quota format v2 support"); +MODULE_LICENSE("GPL"); + #define __QUOTA_V2_PARANOIA typedef char *dqbuf_t; diff -Nur -p linux-2.4.32/fs/smbfs/dir.c linux-2.4.33-rc2/fs/smbfs/dir.c --- linux-2.4.32/fs/smbfs/dir.c 2004-02-18 10:36:31.000000000 -0300 +++ linux-2.4.33-rc2/fs/smbfs/dir.c 2006-06-21 10:40:43.000000000 -0300 @@ -416,6 +416,11 @@ smb_lookup(struct inode *dir, struct den if (dentry->d_name.len > SMB_MAXNAMELEN) goto out; + /* Do not allow lookup of names with backslashes in */ + error = -EINVAL; + if (memchr(dentry->d_name.name, '\\', dentry->d_name.len)) + goto out; + error = smb_proc_getattr(dentry, &finfo); #ifdef SMBFS_PARANOIA if (error && error != -ENOENT) diff -Nur -p linux-2.4.32/fs/smbfs/proc.c linux-2.4.33-rc2/fs/smbfs/proc.c --- linux-2.4.32/fs/smbfs/proc.c 2004-11-17 09:54:21.000000000 -0200 +++ linux-2.4.33-rc2/fs/smbfs/proc.c 2006-06-21 10:40:43.000000000 -0300 @@ -2945,7 +2945,7 @@ retry: LSET(data, 32, SMB_TIME_NO_CHANGE); LSET(data, 40, SMB_UID_NO_CHANGE); LSET(data, 48, SMB_GID_NO_CHANGE); - LSET(data, 56, smb_filetype_from_mode(attr->ia_mode)); + DSET(data, 56, smb_filetype_from_mode(attr->ia_mode)); LSET(data, 60, major); LSET(data, 68, minor); LSET(data, 76, 0); diff -Nur -p linux-2.4.32/include/asm-sparc64/atomic.h linux-2.4.33-rc2/include/asm-sparc64/atomic.h --- linux-2.4.32/include/asm-sparc64/atomic.h 2005-04-03 22:42:20.000000000 -0300 +++ linux-2.4.33-rc2/include/asm-sparc64/atomic.h 2006-06-21 10:40:43.000000000 -0300 @@ -52,10 +52,10 @@ extern int atomic_sub_ret(int, atomic_t /* Atomic operations are already serializing */ #ifdef CONFIG_SMP -#define smp_mb__before_atomic_dec() membar("#StoreLoad | #LoadLoad") -#define smp_mb__after_atomic_dec() membar("#StoreLoad | #StoreStore") -#define smp_mb__before_atomic_inc() membar("#StoreLoad | #LoadLoad") -#define smp_mb__after_atomic_inc() membar("#StoreLoad | #StoreStore") +#define smp_mb__before_atomic_dec() membar_safe("#StoreLoad | #LoadLoad") +#define smp_mb__after_atomic_dec() membar_safe("#StoreLoad | #StoreStore") +#define smp_mb__before_atomic_inc() membar_safe("#StoreLoad | #LoadLoad") +#define smp_mb__after_atomic_inc() membar_safe("#StoreLoad | #StoreStore") #else #define smp_mb__before_atomic_dec() barrier() #define smp_mb__after_atomic_dec() barrier() diff -Nur -p linux-2.4.32/include/asm-sparc64/bitops.h linux-2.4.33-rc2/include/asm-sparc64/bitops.h --- linux-2.4.32/include/asm-sparc64/bitops.h 2005-04-03 22:42:20.000000000 -0300 +++ linux-2.4.33-rc2/include/asm-sparc64/bitops.h 2006-06-21 10:40:43.000000000 -0300 @@ -75,8 +75,8 @@ static __inline__ int __test_and_change_ } #ifdef CONFIG_SMP -#define smp_mb__before_clear_bit() membar("#StoreLoad | #LoadLoad") -#define smp_mb__after_clear_bit() membar("#StoreLoad | #StoreStore") +#define smp_mb__before_clear_bit() membar_safe("#StoreLoad | #LoadLoad") +#define smp_mb__after_clear_bit() membar_safe("#StoreLoad | #StoreStore") #else #define smp_mb__before_clear_bit() barrier() #define smp_mb__after_clear_bit() barrier() diff -Nur -p linux-2.4.32/include/asm-sparc64/const.h linux-2.4.33-rc2/include/asm-sparc64/const.h --- linux-2.4.32/include/asm-sparc64/const.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.4.33-rc2/include/asm-sparc64/const.h 2006-06-21 10:40:43.000000000 -0300 @@ -0,0 +1,19 @@ +/* const.h: Macros for dealing with constants. */ + +#ifndef _SPARC64_CONST_H +#define _SPARC64_CONST_H + +/* Some constant macros are used in both assembler and + * C code. Therefore we cannot annotate them always with + * 'UL' and other type specificers unilaterally. We + * use the following macros to deal with this. + */ + +#ifdef __ASSEMBLY__ +#define _AC(X,Y) X +#else +#define _AC(X,Y) (X##Y) +#endif + + +#endif /* !(_SPARC64_CONST_H) */ diff -Nur -p linux-2.4.32/include/asm-sparc64/sfafsr.h linux-2.4.33-rc2/include/asm-sparc64/sfafsr.h --- linux-2.4.32/include/asm-sparc64/sfafsr.h 1969-12-31 21:00:00.000000000 -0300 +++ linux-2.4.33-rc2/include/asm-sparc64/sfafsr.h 2006-06-21 10:40:43.000000000 -0300 @@ -0,0 +1,82 @@ +#ifndef _SPARC64_SFAFSR_H +#define _SPARC64_SFAFSR_H + +#include + +/* Spitfire Asynchronous Fault Status register, ASI=0x4C VA<63:0>=0x0 */ + +#define SFAFSR_ME (_AC(1,UL) << SFAFSR_ME_SHIFT) +#define SFAFSR_ME_SHIFT 32 +#define SFAFSR_PRIV (_AC(1,UL) << SFAFSR_PRIV_SHIFT) +#define SFAFSR_PRIV_SHIFT 31 +#define SFAFSR_ISAP (_AC(1,UL) << SFAFSR_ISAP_SHIFT) +#define SFAFSR_ISAP_SHIFT 30 +#define SFAFSR_ETP (_AC(1,UL) << SFAFSR_ETP_SHIFT) +#define SFAFSR_ETP_SHIFT 29 +#define SFAFSR_IVUE (_AC(1,UL) << SFAFSR_IVUE_SHIFT) +#define SFAFSR_IVUE_SHIFT 28 +#define SFAFSR_TO (_AC(1,UL) << SFAFSR_TO_SHIFT) +#define SFAFSR_TO_SHIFT 27 +#define SFAFSR_BERR (_AC(1,UL) << SFAFSR_BERR_SHIFT) +#define SFAFSR_BERR_SHIFT 26 +#define SFAFSR_LDP (_AC(1,UL) << SFAFSR_LDP_SHIFT) +#define SFAFSR_LDP_SHIFT 25 +#define SFAFSR_CP (_AC(1,UL) << SFAFSR_CP_SHIFT) +#define SFAFSR_CP_SHIFT 24 +#define SFAFSR_WP (_AC(1,UL) << SFAFSR_WP_SHIFT) +#define SFAFSR_WP_SHIFT 23 +#define SFAFSR_EDP (_AC(1,UL) << SFAFSR_EDP_SHIFT) +#define SFAFSR_EDP_SHIFT 22 +#define SFAFSR_UE (_AC(1,UL) << SFAFSR_UE_SHIFT) +#define SFAFSR_UE_SHIFT 21 +#define SFAFSR_CE (_AC(1,UL) << SFAFSR_CE_SHIFT) +#define SFAFSR_CE_SHIFT 20 +#define SFAFSR_ETS (_AC(0xf,UL) << SFAFSR_ETS_SHIFT) +#define SFAFSR_ETS_SHIFT 16 +#define SFAFSR_PSYND (_AC(0xffff,UL) << SFAFSR_PSYND_SHIFT) +#define SFAFSR_PSYND_SHIFT 0 + +/* UDB Error Register, ASI=0x7f VA<63:0>=0x0(High),0x18(Low) for read + * ASI=0x77 VA<63:0>=0x0(High),0x18(Low) for write + */ + +#define UDBE_UE (_AC(1,UL) << 9) +#define UDBE_CE (_AC(1,UL) << 8) +#define UDBE_E_SYNDR (_AC(0xff,UL) << 0) + +/* The trap handlers for asynchronous errors encode the AFSR and + * other pieces of information into a 64-bit argument for C code + * encoded as follows: + * + * ----------------------------------------------- + * | UDB_H | UDB_L | TL>1 | TT | AFSR | + * ----------------------------------------------- + * 63 54 53 44 42 41 33 32 0 + * + * The AFAR is passed in unchanged. + */ +#define SFSTAT_UDBH_MASK (_AC(0x3ff,UL) << SFSTAT_UDBH_SHIFT) +#define SFSTAT_UDBH_SHIFT 54 +#define SFSTAT_UDBL_MASK (_AC(0x3ff,UL) << SFSTAT_UDBH_SHIFT) +#define SFSTAT_UDBL_SHIFT 44 +#define SFSTAT_TL_GT_ONE (_AC(1,UL) << SFSTAT_TL_GT_ONE_SHIFT) +#define SFSTAT_TL_GT_ONE_SHIFT 42 +#define SFSTAT_TRAP_TYPE (_AC(0x1FF,UL) << SFSTAT_TRAP_TYPE_SHIFT) +#define SFSTAT_TRAP_TYPE_SHIFT 33 +#define SFSTAT_AFSR_MASK (_AC(0x1ffffffff,UL) << SFSTAT_AFSR_SHIFT) +#define SFSTAT_AFSR_SHIFT 0 + +/* ESTATE Error Enable Register, ASI=0x4b VA<63:0>=0x0 */ +#define ESTATE_ERR_CE 0x1 /* Correctable errors */ +#define ESTATE_ERR_NCE 0x2 /* TO, BERR, LDP, ETP, EDP, WP, UE, IVUE */ +#define ESTATE_ERR_ISAP 0x4 /* System address parity error */ +#define ESTATE_ERR_ALL (ESTATE_ERR_CE | \ + ESTATE_ERR_NCE | \ + ESTATE_ERR_ISAP) + +/* The various trap types that report using the above state. */ +#define TRAP_TYPE_IAE 0x09 /* Instruction Access Error */ +#define TRAP_TYPE_DAE 0x32 /* Data Access Error */ +#define TRAP_TYPE_CEE 0x63 /* Correctable ECC Error */ + +#endif /* _SPARC64_SFAFSR_H */ diff -Nur -p linux-2.4.32/include/asm-sparc64/softirq.h linux-2.4.33-rc2/include/asm-sparc64/softirq.h --- linux-2.4.32/include/asm-sparc64/softirq.h 2001-09-08 16:02:32.000000000 -0300 +++ linux-2.4.33-rc2/include/asm-sparc64/softirq.h 2006-06-21 10:40:43.000000000 -0300 @@ -8,7 +8,7 @@ #include #include -#include /* for membar() */ +#include /* for membar_safe() */ #define local_bh_disable() (local_bh_count(smp_processor_id())++) #define __local_bh_enable() (local_bh_count(smp_processor_id())--) diff -Nur -p linux-2.4.32/include/asm-sparc64/spinlock.h linux-2.4.33-rc2/include/asm-sparc64/spinlock.h --- linux-2.4.32/include/asm-sparc64/spinlock.h 2001-12-21 15:42:03.000000000 -0200 +++ linux-2.4.33-rc2/include/asm-sparc64/spinlock.h 2006-06-21 10:40:43.000000000 -0300 @@ -37,7 +37,7 @@ typedef unsigned char spinlock_t; #define spin_is_locked(lock) (*((volatile unsigned char *)(lock)) != 0) #define spin_unlock_wait(lock) \ -do { membar("#LoadLoad"); \ +do { rmb(); \ } while(*((volatile unsigned char *)lock)) extern __inline__ void spin_lock(spinlock_t *lock) @@ -92,7 +92,7 @@ do { (__lock)->lock = 0; \ #define spin_is_locked(__lock) (*((volatile unsigned char *)(&((__lock)->lock))) != 0) #define spin_unlock_wait(__lock) \ do { \ - membar("#LoadLoad"); \ + rmb(); \ } while(*((volatile unsigned char *)(&((__lock)->lock)))) extern void _do_spin_lock (spinlock_t *lock, char *str); diff -Nur -p linux-2.4.32/include/asm-sparc64/system.h linux-2.4.33-rc2/include/asm-sparc64/system.h --- linux-2.4.32/include/asm-sparc64/system.h 2005-04-03 22:42:20.000000000 -0300 +++ linux-2.4.33-rc2/include/asm-sparc64/system.h 2006-06-21 10:40:43.000000000 -0300 @@ -106,15 +106,47 @@ extern void __global_restore_flags(unsig #define nop() __asm__ __volatile__ ("nop") -#define membar(type) __asm__ __volatile__ ("membar " type : : : "memory") +/* These are here in an effort to more fully work around Spitfire Errata + * #51. Essentially, if a memory barrier occurs soon after a mispredicted + * branch, the chip can stop executing instructions until a trap occurs. + * Therefore, if interrupts are disabled, the chip can hang forever. + * + * It used to be believed that the memory barrier had to be right in the + * delay slot, but a case has been traced recently wherein the memory barrier + * was one instruction after the branch delay slot and the chip still hung. + * The offending sequence was the following in sym_wakeup_done() of the + * sym53c8xx_2 driver: + * + * call sym_ccb_from_dsa, 0 + * movge %icc, 0, %l0 + * brz,pn %o0, .LL1303 + * mov %o0, %l2 + * membar #LoadLoad + * + * The branch has to be mispredicted for the bug to occur. Therefore, we put + * the memory barrier explicitly into a "branch always, predicted taken" + * delay slot to avoid the problem case. + */ +#define membar_safe(type) \ +do { __asm__ __volatile__("ba,pt %%xcc, 1f\n\t" \ + " membar " type "\n" \ + "1:\n" \ + : : : "memory"); \ +} while (0) #define mb() \ - membar("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad") -#define rmb() membar("#LoadLoad") -#define wmb() membar("#StoreStore") + membar_safe("#LoadLoad | #LoadStore | #StoreStore | #StoreLoad") +#define rmb() \ + membar_safe("#LoadLoad") +#define wmb() \ + membar_safe("#StoreStore") #define set_mb(__var, __value) \ - do { __var = __value; membar("#StoreLoad | #StoreStore"); } while(0) +do { __var = __value; \ + membar_safe("#StoreLoad | #StoreStore"); \ +} while(0) #define set_wmb(__var, __value) \ - do { __var = __value; membar("#StoreStore"); } while(0) +do { __var = __value; \ + membar_safe("#StoreStore"); \ +} while(0) #ifdef CONFIG_SMP #define smp_mb() mb() diff -Nur -p linux-2.4.32/include/asm-x86_64/i387.h linux-2.4.33-rc2/include/asm-x86_64/i387.h --- linux-2.4.32/include/asm-x86_64/i387.h 2004-08-07 20:26:06.000000000 -0300 +++ linux-2.4.33-rc2/include/asm-x86_64/i387.h 2006-06-21 10:40:43.000000000 -0300 @@ -125,8 +125,12 @@ static inline void kernel_fpu_begin(void static inline void save_init_fpu( struct task_struct *tsk ) { - asm volatile( "fxsave %0 ; fnclex" + asm volatile( "fxsave %0" : "=m" (tsk->thread.i387.fxsave)); + if (tsk->thread.i387.fxsave.swd & (1<<7)) + asm volatile("fnclex"); + /* AMD CPUs leak F?P through FXSAVE. Clear it here */ + asm volatile("ffree %st(7) ; fildl %gs:0"); tsk->flags &= ~PF_USEDFPU; stts(); } diff -Nur -p linux-2.4.32/include/linux/ata.h linux-2.4.33-rc2/include/linux/ata.h --- linux-2.4.32/include/linux/ata.h 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/include/linux/ata.h 2006-06-21 10:40:43.000000000 -0300 @@ -1,24 +1,29 @@ /* - Copyright 2003-2004 Red Hat, Inc. All rights reserved. - Copyright 2003-2004 Jeff Garzik - - The contents of this file are subject to the Open - Software License version 1.1 that can be found at - http://www.opensource.org/licenses/osl-1.1.txt and is included herein - by reference. - - Alternatively, the contents of this file may be used under the terms - of the GNU General Public License version 2 (the "GPL") as distributed - in the kernel source COPYING file, in which case the provisions of - the GPL are applicable instead of the above. If you wish to allow - the use of your version of this file only under the terms of the - GPL and not to allow others to use your version of this file under - the OSL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the GPL. - If you do not delete the provisions above, a recipient may use your - version of this file under either the OSL or the GPL. - + * Copyright 2003-2004 Red Hat, Inc. All rights reserved. + * Copyright 2003-2004 Jeff Garzik + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * + * Hardware documentation available from http://www.t13.org/ + * */ #ifndef __LINUX_ATA_H__ @@ -37,13 +42,18 @@ enum { ATA_SECT_SIZE = 512, ATA_ID_WORDS = 256, - ATA_ID_PROD_OFS = 27, - ATA_ID_FW_REV_OFS = 23, ATA_ID_SERNO_OFS = 10, - ATA_ID_MAJOR_VER = 80, - ATA_ID_PIO_MODES = 64, + ATA_ID_FW_REV_OFS = 23, + ATA_ID_PROD_OFS = 27, + ATA_ID_OLD_PIO_MODES = 51, + ATA_ID_FIELD_VALID = 53, ATA_ID_MWDMA_MODES = 63, + ATA_ID_PIO_MODES = 64, + ATA_ID_EIDE_DMA_MIN = 65, + ATA_ID_EIDE_PIO = 67, + ATA_ID_EIDE_PIO_IORDY = 68, ATA_ID_UDMA_MODES = 88, + ATA_ID_MAJOR_VER = 80, ATA_ID_PIO4 = (1 << 1), ATA_PCI_CTL_OFS = 2, @@ -108,6 +118,8 @@ enum { /* ATA device commands */ ATA_CMD_CHK_POWER = 0xE5, /* check power mode */ + ATA_CMD_STANDBY = 0xE2, /* place in standby power mode */ + ATA_CMD_IDLE = 0xE3, /* place in idle power mode */ ATA_CMD_EDD = 0x90, /* execute device diagnostic */ ATA_CMD_FLUSH = 0xE7, ATA_CMD_FLUSH_EXT = 0xEA, @@ -121,10 +133,15 @@ enum { ATA_CMD_PIO_READ_EXT = 0x24, ATA_CMD_PIO_WRITE = 0x30, ATA_CMD_PIO_WRITE_EXT = 0x34, + ATA_CMD_READ_MULTI = 0xC4, + ATA_CMD_READ_MULTI_EXT = 0x29, + ATA_CMD_WRITE_MULTI = 0xC5, + ATA_CMD_WRITE_MULTI_EXT = 0x39, ATA_CMD_SET_FEATURES = 0xEF, ATA_CMD_PACKET = 0xA0, ATA_CMD_VERIFY = 0x40, ATA_CMD_VERIFY_EXT = 0x42, + ATA_CMD_INIT_DEV_PARAMS = 0x91, /* SETFEATURES stuff */ SETFEATURES_XFER = 0x03, @@ -139,14 +156,14 @@ enum { XFER_MW_DMA_2 = 0x22, XFER_MW_DMA_1 = 0x21, XFER_MW_DMA_0 = 0x20, + XFER_SW_DMA_2 = 0x12, + XFER_SW_DMA_1 = 0x11, + XFER_SW_DMA_0 = 0x10, XFER_PIO_4 = 0x0C, XFER_PIO_3 = 0x0B, XFER_PIO_2 = 0x0A, XFER_PIO_1 = 0x09, XFER_PIO_0 = 0x08, - XFER_SW_DMA_2 = 0x12, - XFER_SW_DMA_1 = 0x11, - XFER_SW_DMA_0 = 0x10, XFER_PIO_SLOW = 0x00, /* ATAPI stuff */ @@ -174,6 +191,7 @@ enum { ATA_TFLAG_ISADDR = (1 << 1), /* enable r/w to nsect/lba regs */ ATA_TFLAG_DEVICE = (1 << 2), /* enable r/w to device reg */ ATA_TFLAG_WRITE = (1 << 3), /* data dir: host->dev==1 (write) */ + ATA_TFLAG_LBA = (1 << 4), /* enable LBA */ }; enum ata_tf_protocols { @@ -243,7 +261,19 @@ struct ata_taskfile { ((u64) (id)[(n) + 1] << 16) | \ ((u64) (id)[(n) + 0]) ) -static inline int atapi_cdb_len(u16 *dev_id) +static inline int ata_id_current_chs_valid(const u16 *id) +{ + /* For ATA-1 devices, if the INITIALIZE DEVICE PARAMETERS command + has not been issued to the device then the values of + id[54] to id[56] are vendor specific. */ + return (id[53] & 0x01) && /* Current translation valid */ + id[54] && /* cylinders in current translation */ + id[55] && /* heads in current translation */ + id[55] <= 16 && + id[56]; /* sectors in current translation */ +} + +static inline int atapi_cdb_len(const u16 *dev_id) { u16 tmp = dev_id[0] & 0x3; switch (tmp) { @@ -253,7 +283,7 @@ static inline int atapi_cdb_len(u16 *dev } } -static inline int is_atapi_taskfile(struct ata_taskfile *tf) +static inline int is_atapi_taskfile(const struct ata_taskfile *tf) { return (tf->protocol == ATA_PROT_ATAPI) || (tf->protocol == ATA_PROT_ATAPI_NODATA) || diff -Nur -p linux-2.4.32/include/linux/i2c.h linux-2.4.33-rc2/include/linux/i2c.h --- linux-2.4.32/include/linux/i2c.h 2005-05-31 21:56:56.000000000 -0300 +++ linux-2.4.33-rc2/include/linux/i2c.h 2006-06-21 10:40:43.000000000 -0300 @@ -464,11 +464,6 @@ union i2c_smbus_data { #define I2C_SMBUS 0x0720 /* SMBus-level access */ -/* ... algo-bit.c recognizes */ -#define I2C_UDELAY 0x0705 /* set delay in microsecs between each */ - /* written byte (except address) */ -#define I2C_MDELAY 0x0706 /* millisec delay between written bytes */ - /* ----- I2C-DEV: char device interface stuff ------------------------- */ #define I2C_MAJOR 89 /* Device major number */ diff -Nur -p linux-2.4.32/include/linux/ide.h linux-2.4.33-rc2/include/linux/ide.h --- linux-2.4.32/include/linux/ide.h 2004-11-17 09:54:22.000000000 -0200 +++ linux-2.4.33-rc2/include/linux/ide.h 2006-06-21 10:40:43.000000000 -0300 @@ -1691,6 +1691,7 @@ extern void ide_destroy_dmatable(ide_dri extern ide_startstop_t ide_dma_intr(ide_drive_t *); extern int ide_release_dma(ide_hwif_t *); extern void ide_setup_dma(ide_hwif_t *, unsigned long, unsigned int); +extern void ide_setup_no_dma(ide_hwif_t *); extern int __ide_dma_host_off(ide_drive_t *); extern int __ide_dma_off_quietly(ide_drive_t *); @@ -1713,6 +1714,7 @@ extern int __ide_dma_timeout(ide_drive_t #else static inline void ide_setup_dma(ide_hwif_t *x, unsigned long y, unsigned int z) {;} static inline void ide_release_dma(ide_hwif_t *x) {;} +static inline void ide_setup_no_dma(ide_hwif_t *x) {;} #endif extern void hwif_unregister(ide_hwif_t *); diff -Nur -p linux-2.4.32/include/linux/libata-compat.h linux-2.4.33-rc2/include/linux/libata-compat.h --- linux-2.4.32/include/linux/libata-compat.h 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/include/linux/libata-compat.h 2006-06-21 10:40:43.000000000 -0300 @@ -12,8 +12,25 @@ typedef u64 __le64; #define DMA_64BIT_MASK 0xffffffffffffffffULL #define DMA_32BIT_MASK 0x00000000ffffffffULL +/* These definitions mirror those in pci.h, so they can be used + * interchangeably with their PCI_ counterparts */ +enum dma_data_direction { + DMA_BIDIRECTIONAL = 0, + DMA_TO_DEVICE = 1, + DMA_FROM_DEVICE = 2, + DMA_NONE = 3, +}; + +#define offset_in_page(p) ((unsigned long)(p) & ~PAGE_MASK) + #define MODULE_VERSION(ver_str) +/* remaps usage of KM_IRQ0 onto KM_SOFTIRQ0. KM_IRQ0 only exists on ia64 in + * 2.4. Warning: this will also remap KM_IRQ0 on ia64, so be careful about + * the files included after this file. */ + +#define KM_IRQ0 KM_SOFTIRQ0 + struct device { struct pci_dev pdev; }; @@ -23,12 +40,24 @@ static inline struct pci_dev *to_pci_dev return (struct pci_dev *) dev; } +#define pdev_printk(lvl, pdev, fmt, args...) \ + do { \ + printk("%s%s(%s): ", lvl, \ + (pdev)->driver && (pdev)->driver->name ? \ + (pdev)->driver->name : "PCI", \ + pci_name(pdev)); \ + printk(fmt, ## args); \ + } while (0) + static inline int pci_enable_msi(struct pci_dev *dev) { return -1; } static inline void pci_disable_msi(struct pci_dev *dev) {} -#define pci_set_consistent_dma_mask(pdev,mask) (0) - -#define DMA_FROM_DEVICE PCI_DMA_FROMDEVICE +static inline int pci_set_consistent_dma_mask(struct pci_dev *dev, u64 mask) +{ + if (mask == (u64)dev->dma_mask) + return 0; + return -EIO; +} /* NOTE: dangerous! we ignore the 'gfp' argument */ #define dma_alloc_coherent(dev,sz,dma,gfp) \ @@ -62,4 +91,77 @@ static inline void *kcalloc(size_t nmemb return mem; } +static inline void *kzalloc(size_t size, int flags) +{ + return kcalloc(1, size, flags); +} + +static inline void pci_iounmap(struct pci_dev *pdev, void *mem) +{ + iounmap(mem); +} + +/** + * pci_intx - enables/disables PCI INTx for device dev + * @pdev: the PCI device to operate on + * @enable: boolean: whether to enable or disable PCI INTx + * + * Enables/disables PCI INTx for device dev + */ +static inline void +pci_intx(struct pci_dev *pdev, int enable) +{ + u16 pci_command, new; + + pci_read_config_word(pdev, PCI_COMMAND, &pci_command); + + if (enable) { + new = pci_command & ~PCI_COMMAND_INTX_DISABLE; + } else { + new = pci_command | PCI_COMMAND_INTX_DISABLE; + } + + if (new != pci_command) { + pci_write_config_word(pdev, PCI_COMMAND, new); + } +} + +static inline void __iomem * +pci_iomap(struct pci_dev *dev, int bar, unsigned long maxlen) +{ + unsigned long start = pci_resource_start(dev, bar); + unsigned long len = pci_resource_len(dev, bar); + unsigned long flags = pci_resource_flags(dev, bar); + + if (!len || !start) + return NULL; + if (maxlen && len > maxlen) + len = maxlen; + if (flags & IORESOURCE_IO) { + BUG(); + } + if (flags & IORESOURCE_MEM) { + if (flags & IORESOURCE_CACHEABLE) + return ioremap(start, len); + return ioremap_nocache(start, len); + } + /* What? */ + return NULL; +} + +static inline void sg_set_buf(struct scatterlist *sg, void *buf, + unsigned int buflen) +{ + sg->page = virt_to_page(buf); + sg->offset = offset_in_page(buf); + sg->length = buflen; +} + +static inline void sg_init_one(struct scatterlist *sg, void *buf, + unsigned int buflen) +{ + memset(sg, 0, sizeof(*sg)); + sg_set_buf(sg, buf, buflen); +} + #endif /* __LIBATA_COMPAT_H__ */ diff -Nur -p linux-2.4.32/include/linux/libata.h linux-2.4.33-rc2/include/linux/libata.h --- linux-2.4.32/include/linux/libata.h 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/include/linux/libata.h 2006-06-21 10:40:43.000000000 -0300 @@ -1,23 +1,26 @@ /* - Copyright 2003-2004 Red Hat, Inc. All rights reserved. - Copyright 2003-2004 Jeff Garzik - - The contents of this file are subject to the Open - Software License version 1.1 that can be found at - http://www.opensource.org/licenses/osl-1.1.txt and is included herein - by reference. - - Alternatively, the contents of this file may be used under the terms - of the GNU General Public License version 2 (the "GPL") as distributed - in the kernel source COPYING file, in which case the provisions of - the GPL are applicable instead of the above. If you wish to allow - the use of your version of this file only under the terms of the - GPL and not to allow others to use your version of this file under - the OSL, indicate your decision by deleting the provisions above and - replace them with the notice and other provisions required by the GPL. - If you do not delete the provisions above, a recipient may use your - version of this file under either the OSL or the GPL. - + * Copyright 2003-2005 Red Hat, Inc. All rights reserved. + * Copyright 2003-2005 Jeff Garzik + * + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * libata documentation is available via 'make {ps|pdf}docs', + * as Documentation/DocBook/libata.* + * */ #ifndef __LINUX_LIBATA_H__ @@ -38,7 +41,6 @@ #undef ATA_VERBOSE_DEBUG /* yet more debugging output */ #undef ATA_IRQ_TRAP /* define to ack screaming irqs */ #undef ATA_NDEBUG /* define to disable quick runtime checks */ -#undef ATA_ENABLE_ATAPI /* define to enable ATAPI support */ #undef ATA_ENABLE_PATA /* define to enable PATA support in some * low-level drivers */ #undef ATAPI_ENABLE_DMADIR /* enables ATAPI DMADIR bridge support */ @@ -57,6 +59,8 @@ #define VPRINTK(fmt, args...) #endif /* ATA_DEBUG */ +#define BPRINTK(fmt, args...) if (ap->flags & ATA_FLAG_DEBUGMSG) printk(KERN_ERR "%s: " fmt, __FUNCTION__, ## args) + #ifdef ATA_NDEBUG #define assert(expr) #else @@ -90,12 +94,13 @@ enum { ATA_SHT_NEW_EH_CODE = 0, /* IORL hack, part one */ ATA_SHT_CMD_PER_LUN = 1, ATA_SHT_THIS_ID = -1, - ATA_SHT_USE_CLUSTERING = 0, + ATA_SHT_USE_CLUSTERING = 1, /* struct ata_device stuff */ ATA_DFLAG_LBA48 = (1 << 0), /* device supports LBA48 */ ATA_DFLAG_PIO = (1 << 1), /* device currently in PIO mode */ ATA_DFLAG_LOCK_SECTORS = (1 << 2), /* don't adjust max_sectors */ + ATA_DFLAG_LBA = (1 << 3), /* device supports LBA */ ATA_DEV_UNKNOWN = 0, /* unknown device */ ATA_DEV_ATA = 1, /* ATA device */ @@ -114,6 +119,9 @@ enum { ATA_FLAG_MMIO = (1 << 6), /* use MMIO, not PIO */ ATA_FLAG_SATA_RESET = (1 << 7), /* use COMRESET */ ATA_FLAG_PIO_DMA = (1 << 8), /* PIO cmds via DMA */ + ATA_FLAG_NOINTR = (1 << 9), /* FIXME: Remove this once + * proper HSM is in place. */ + ATA_FLAG_DEBUGMSG = (1 << 10), ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ @@ -151,17 +159,32 @@ enum { ATA_SHIFT_UDMA = 0, ATA_SHIFT_MWDMA = 8, ATA_SHIFT_PIO = 11, -}; -enum pio_task_states { - PIO_ST_UNKNOWN, - PIO_ST_IDLE, - PIO_ST_POLL, - PIO_ST_TMOUT, - PIO_ST, - PIO_ST_LAST, - PIO_ST_LAST_POLL, - PIO_ST_ERR, + /* size of buffer to pad xfers ending on unaligned boundaries */ + ATA_DMA_PAD_SZ = 4, + ATA_DMA_PAD_BUF_SZ = ATA_DMA_PAD_SZ * ATA_MAX_QUEUE, + + /* Masks for port functions */ + ATA_PORT_PRIMARY = (1 << 0), + ATA_PORT_SECONDARY = (1 << 1), +}; + +enum hsm_task_states { + HSM_ST_UNKNOWN, + HSM_ST_IDLE, + HSM_ST_POLL, + HSM_ST_TMOUT, + HSM_ST, + HSM_ST_LAST, + HSM_ST_LAST_POLL, + HSM_ST_ERR, +}; + +enum ata_completion_errors { + AC_ERR_OTHER = (1 << 0), + AC_ERR_DEV = (1 << 1), + AC_ERR_ATA_BUS = (1 << 2), + AC_ERR_HOST_BUS = (1 << 3), }; /* forward declarations */ @@ -171,7 +194,7 @@ struct ata_port; struct ata_queued_cmd; /* typedefs */ -typedef int (*ata_qc_cb_t) (struct ata_queued_cmd *qc, u8 drv_stat); +typedef int (*ata_qc_cb_t) (struct ata_queued_cmd *qc, unsigned int err_mask); struct ata_ioports { unsigned long cmd_addr; @@ -194,7 +217,7 @@ struct ata_ioports { struct ata_probe_ent { struct list_head node; struct device *dev; - struct ata_port_operations *port_ops; + const struct ata_port_operations *port_ops; Scsi_Host_Template *sht; struct ata_ioports port[ATA_MAX_PORTS]; unsigned int n_ports; @@ -217,7 +240,7 @@ struct ata_host_set { void __iomem *mmio_base; unsigned int n_ports; void *private_data; - struct ata_port_operations *ops; + const struct ata_port_operations *ops; struct ata_port * ports[0]; }; @@ -234,9 +257,12 @@ struct ata_queued_cmd { unsigned long flags; /* ATA_QCFLAG_xxx */ unsigned int tag; unsigned int n_elem; + unsigned int orig_n_elem; int dma_dir; + unsigned int pad_len; + unsigned int nsect; unsigned int cursect; @@ -247,9 +273,11 @@ struct ata_queued_cmd { unsigned int cursg_ofs; struct scatterlist sgent; + struct scatterlist pad_sgent; void *buf_virt; - struct scatterlist *sg; + /* DO NOT iterate over __sg manually, use ata_for_each_sg() */ + struct scatterlist *__sg; ata_qc_cb_t complete_fn; @@ -275,15 +303,18 @@ struct ata_device { u8 xfer_mode; unsigned int xfer_shift; /* ATA_SHIFT_xxx */ - /* cache info about current transfer mode */ - u8 xfer_protocol; /* taskfile xfer protocol */ - u8 read_cmd; /* opcode to use on read */ - u8 write_cmd; /* opcode to use on write */ + unsigned int multi_count; /* sectors count for + READ/WRITE MULTIPLE */ + + /* for CHS addressing */ + u16 cylinders; /* Number of cylinders */ + u16 heads; /* Number of heads */ + u16 sectors; /* Number of sectors per track */ }; struct ata_port { struct Scsi_Host *host; /* our co-allocated scsi host */ - struct ata_port_operations *ops; + const struct ata_port_operations *ops; unsigned long flags; /* ATA_FLAG_xxx */ unsigned int id; /* unique id req'd by scsi midlyr */ unsigned int port_no; /* unique port #; from zero */ @@ -292,6 +323,9 @@ struct ata_port { struct ata_prd *prd; /* our SG list */ dma_addr_t prd_dma; /* and its DMA mapping */ + void *pad; /* array of DMA pad buffers */ + dma_addr_t pad_dma; + struct ata_ioports ioaddr; /* ATA cmd/ctl/dma register blocks */ u8 ctl; /* cache of ATA control register */ @@ -316,7 +350,7 @@ struct ata_port { struct tq_struct packet_task; struct tq_struct pio_task; - unsigned int pio_task_state; + unsigned int hsm_task_state; unsigned long pio_task_timeout; void *private_data; @@ -330,13 +364,12 @@ struct ata_port_operations { void (*set_piomode) (struct ata_port *, struct ata_device *); void (*set_dmamode) (struct ata_port *, struct ata_device *); - void (*tf_load) (struct ata_port *ap, struct ata_taskfile *tf); + void (*tf_load) (struct ata_port *ap, const struct ata_taskfile *tf); void (*tf_read) (struct ata_port *ap, struct ata_taskfile *tf); - void (*exec_command)(struct ata_port *ap, struct ata_taskfile *tf); + void (*exec_command)(struct ata_port *ap, const struct ata_taskfile *tf); u8 (*check_status)(struct ata_port *ap); u8 (*check_altstatus)(struct ata_port *ap); - u8 (*check_err)(struct ata_port *ap); void (*dev_select)(struct ata_port *ap, unsigned int device); void (*phy_reset) (struct ata_port *ap); @@ -364,7 +397,7 @@ struct ata_port_operations { void (*host_stop) (struct ata_host_set *host_set); - void (*bmdma_stop) (struct ata_port *ap); + void (*bmdma_stop) (struct ata_queued_cmd *qc); u8 (*bmdma_status) (struct ata_port *ap); }; @@ -374,9 +407,23 @@ struct ata_port_info { unsigned long pio_mask; unsigned long mwdma_mask; unsigned long udma_mask; - struct ata_port_operations *port_ops; + const struct ata_port_operations *port_ops; + void *private_data; }; +struct ata_timing { + unsigned short mode; /* ATA mode */ + unsigned short setup; /* t1 */ + unsigned short act8b; /* t2 for 8-bit I/O */ + unsigned short rec8b; /* t2i for 8-bit I/O */ + unsigned short cyc8b; /* t0 for 8-bit I/O */ + unsigned short active; /* t2 or tD */ + unsigned short recover; /* t2i or tK */ + unsigned short cycle; /* t0 */ + unsigned short udma; /* t2CYCTYP/2 */ +}; + +#define FIT(v,vmin,vmax) max_t(short,min_t(short,v,vmax),vmin) extern void ata_port_probe(struct ata_port *); extern void __sata_phy_reset(struct ata_port *ap); @@ -389,26 +436,28 @@ extern int ata_pci_init_one (struct pci_ unsigned int n_ports); extern void ata_pci_remove_one (struct pci_dev *pdev); #endif /* CONFIG_PCI */ -extern int ata_device_add(struct ata_probe_ent *ent); +extern int ata_device_add(const struct ata_probe_ent *ent); +extern void ata_host_set_remove(struct ata_host_set *host_set); extern int ata_scsi_detect(Scsi_Host_Template *sht); extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg); extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); extern int ata_scsi_error(struct Scsi_Host *host); extern int ata_scsi_release(struct Scsi_Host *host); extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); +extern int ata_ratelimit(void); + /* * Default driver ops implementations */ -extern void ata_tf_load(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_tf_load(struct ata_port *ap, const struct ata_taskfile *tf); extern void ata_tf_read(struct ata_port *ap, struct ata_taskfile *tf); -extern void ata_tf_to_fis(struct ata_taskfile *tf, u8 *fis, u8 pmp); -extern void ata_tf_from_fis(u8 *fis, struct ata_taskfile *tf); +extern void ata_tf_to_fis(const struct ata_taskfile *tf, u8 *fis, u8 pmp); +extern void ata_tf_from_fis(const u8 *fis, struct ata_taskfile *tf); extern void ata_noop_dev_select (struct ata_port *ap, unsigned int device); extern void ata_std_dev_select (struct ata_port *ap, unsigned int device); extern u8 ata_check_status(struct ata_port *ap); extern u8 ata_altstatus(struct ata_port *ap); -extern u8 ata_chk_err(struct ata_port *ap); -extern void ata_exec_command(struct ata_port *ap, struct ata_taskfile *tf); +extern void ata_exec_command(struct ata_port *ap, const struct ata_taskfile *tf); extern int ata_port_start (struct ata_port *ap); extern void ata_port_stop (struct ata_port *ap); extern void ata_host_stop (struct ata_host_set *host_set); @@ -419,22 +468,48 @@ extern void ata_sg_init_one(struct ata_q unsigned int buflen); extern void ata_sg_init(struct ata_queued_cmd *qc, struct scatterlist *sg, unsigned int n_elem); -extern unsigned int ata_dev_classify(struct ata_taskfile *tf); -extern void ata_dev_id_string(u16 *id, unsigned char *s, +extern unsigned int ata_dev_classify(const struct ata_taskfile *tf); +extern void ata_dev_id_string(const u16 *id, unsigned char *s, unsigned int ofs, unsigned int len); extern void ata_dev_config(struct ata_port *ap, unsigned int i); extern void ata_bmdma_setup (struct ata_queued_cmd *qc); extern void ata_bmdma_start (struct ata_queued_cmd *qc); -extern void ata_bmdma_stop(struct ata_port *ap); +extern void ata_bmdma_stop(struct ata_queued_cmd *qc); extern u8 ata_bmdma_status(struct ata_port *ap); extern void ata_bmdma_irq_clear(struct ata_port *ap); -extern void ata_qc_complete(struct ata_queued_cmd *qc, u8 drv_stat); +extern void ata_qc_complete(struct ata_queued_cmd *qc, unsigned int err_mask); extern void ata_eng_timeout(struct ata_port *ap); extern void ata_scsi_simulate(u16 *id, struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *)); extern void ata_add_to_probe_list (struct ata_probe_ent *probe_ent); extern int ata_std_bios_param(Disk * disk, kdev_t dev, int *ip); +/* + * Timing helpers + */ +extern int ata_timing_compute(struct ata_device *, unsigned short, + struct ata_timing *, int, int); +extern void ata_timing_merge(const struct ata_timing *, + const struct ata_timing *, struct ata_timing *, + unsigned int); + +enum { + ATA_TIMING_SETUP = (1 << 0), + ATA_TIMING_ACT8B = (1 << 1), + ATA_TIMING_REC8B = (1 << 2), + ATA_TIMING_CYC8B = (1 << 3), + ATA_TIMING_8BIT = ATA_TIMING_ACT8B | ATA_TIMING_REC8B | + ATA_TIMING_CYC8B, + ATA_TIMING_ACTIVE = (1 << 4), + ATA_TIMING_RECOVER = (1 << 5), + ATA_TIMING_CYCLE = (1 << 6), + ATA_TIMING_UDMA = (1 << 7), + ATA_TIMING_ALL = ATA_TIMING_SETUP | ATA_TIMING_ACT8B | + ATA_TIMING_REC8B | ATA_TIMING_CYC8B | + ATA_TIMING_ACTIVE | ATA_TIMING_RECOVER | + ATA_TIMING_CYCLE | ATA_TIMING_UDMA, +}; + #ifdef CONFIG_PCI struct pci_bits { @@ -444,19 +519,45 @@ struct pci_bits { unsigned long val; }; +extern void ata_pci_host_stop (struct ata_host_set *host_set); extern struct ata_probe_ent * -ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port); -extern int pci_test_config_bits(struct pci_dev *pdev, struct pci_bits *bits); +ata_pci_init_native_mode(struct pci_dev *pdev, struct ata_port_info **port, int portmask); +extern int pci_test_config_bits(struct pci_dev *pdev, const struct pci_bits *bits); #endif /* CONFIG_PCI */ +static inline int +ata_sg_is_last(struct scatterlist *sg, struct ata_queued_cmd *qc) +{ + if (sg == &qc->pad_sgent) + return 1; + if (qc->pad_len) + return 0; + if (((sg - qc->__sg) + 1) == qc->n_elem) + return 1; + return 0; +} + +static inline struct scatterlist * +ata_qc_next_sg(struct scatterlist *sg, struct ata_queued_cmd *qc) +{ + if (sg == &qc->pad_sgent) + return NULL; + if (++sg - qc->__sg < qc->n_elem) + return sg; + return qc->pad_len ? &qc->pad_sgent : NULL; +} + +#define ata_for_each_sg(sg, qc) \ + for (sg = qc->__sg; sg; sg = ata_qc_next_sg(sg, qc)) + static inline unsigned int ata_tag_valid(unsigned int tag) { return (tag < ATA_MAX_QUEUE) ? 1 : 0; } -static inline unsigned int ata_dev_present(struct ata_device *dev) +static inline unsigned int ata_dev_present(const struct ata_device *dev) { return ((dev->class == ATA_DEV_ATA) || (dev->class == ATA_DEV_ATAPI)); @@ -559,6 +660,17 @@ static inline void ata_tf_init(struct at tf->device = ATA_DEVICE_OBS | ATA_DEV1; } +static inline void ata_qc_reinit(struct ata_queued_cmd *qc) +{ + qc->__sg = NULL; + qc->flags = 0; + qc->cursect = qc->cursg = qc->cursg_ofs = 0; + qc->nsect = 0; + qc->nbytes = qc->curbytes = 0; + + ata_tf_init(qc->ap, &qc->tf, qc->dev->devno); +} + /** * ata_irq_on - Enable interrupts on a port. @@ -643,7 +755,7 @@ static inline void scr_write(struct ata_ ap->ops->scr_write(ap, reg, val); } -static inline void scr_write_flush(struct ata_port *ap, unsigned int reg, +static inline void scr_write_flush(struct ata_port *ap, unsigned int reg, u32 val) { ap->ops->scr_write(ap, reg, val); @@ -655,11 +767,41 @@ static inline unsigned int sata_dev_pres return ((scr_read(ap, SCR_STATUS) & 0xf) == 0x3) ? 1 : 0; } -static inline int ata_try_flush_cache(struct ata_device *dev) +static inline int ata_try_flush_cache(const struct ata_device *dev) { return ata_id_wcache_enabled(dev->id) || ata_id_has_flush(dev->id) || ata_id_has_flush_ext(dev->id); } +static inline unsigned int ac_err_mask(u8 status) +{ + if (status & ATA_BUSY) + return AC_ERR_ATA_BUS; + if (status & (ATA_ERR | ATA_DF)) + return AC_ERR_DEV; + return 0; +} + +static inline unsigned int __ac_err_mask(u8 status) +{ + unsigned int mask = ac_err_mask(status); + if (mask == 0) + return AC_ERR_OTHER; + return mask; +} + +static inline int ata_pad_alloc(struct ata_port *ap, struct device *dev) +{ + ap->pad_dma = 0; + ap->pad = dma_alloc_coherent(dev, ATA_DMA_PAD_BUF_SZ, + &ap->pad_dma, GFP_KERNEL); + return (ap->pad == NULL) ? -ENOMEM : 0; +} + +static inline void ata_pad_free(struct ata_port *ap, struct device *dev) +{ + dma_free_coherent(dev, ATA_DMA_PAD_BUF_SZ, ap->pad, ap->pad_dma); +} + #endif /* __LINUX_LIBATA_H__ */ diff -Nur -p linux-2.4.32/include/linux/nfs_fs_i.h linux-2.4.33-rc2/include/linux/nfs_fs_i.h --- linux-2.4.32/include/linux/nfs_fs_i.h 2002-08-02 21:39:45.000000000 -0300 +++ linux-2.4.33-rc2/include/linux/nfs_fs_i.h 2006-06-21 10:40:43.000000000 -0300 @@ -85,6 +85,7 @@ struct nfs_inode_info { #define NFS_INO_REVALIDATING 0x0004 /* revalidating attrs */ #define NFS_IS_SNAPSHOT 0x0010 /* a snapshot file */ #define NFS_INO_FLUSH 0x0020 /* inode is due for flushing */ +#define NFS_INO_MAPPED 0x0040 /* page invalidation failed */ /* * NFS lock info diff -Nur -p linux-2.4.32/include/linux/pci_ids.h linux-2.4.33-rc2/include/linux/pci_ids.h --- linux-2.4.32/include/linux/pci_ids.h 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/include/linux/pci_ids.h 2006-06-21 10:40:43.000000000 -0300 @@ -319,7 +319,11 @@ /* RadeonIGP */ #define PCI_DEVICE_ID_ATI_RADEON_IGP 0xCAB0 /* ATI IXP Chipset */ -#define PCI_DEVICE_ID_ATI_IXP_IDE 0x4349 +#define PCI_DEVICE_ID_ATI_IXP200_IDE 0x4349 +#define PCI_DEVICE_ID_ATI_IXP300_IDE 0x4369 +#define PCI_DEVICE_ID_ATI_IXP300_SATA 0x436e +#define PCI_DEVICE_ID_ATI_IXP400_IDE 0x4376 +#define PCI_DEVICE_ID_ATI_IXP400_SATA 0x4379 #define PCI_VENDOR_ID_VLSI 0x1004 #define PCI_DEVICE_ID_VLSI_82C592 0x0005 @@ -1038,6 +1042,16 @@ #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_1 0x0201 #define PCI_DEVICE_ID_NVIDIA_GEFORCE3_2 0x0202 #define PCI_DEVICE_ID_NVIDIA_QUADRO_DDC 0x0203 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_IDE 0x0265 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA 0x0266 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP51_SATA2 0x0267 +#define PCI_DEVICE_ID_NVIDIA_NVENET_12 0x0268 +#define PCI_DEVICE_ID_NVIDIA_NVENET_13 0x0269 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_IDE 0x036E +#define PCI_DEVICE_ID_NVIDIA_NVENET_14 0x0372 +#define PCI_DEVICE_ID_NVIDIA_NVENET_15 0x0373 +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA 0x037E +#define PCI_DEVICE_ID_NVIDIA_NFORCE_MCP55_SATA2 0x037F #define PCI_VENDOR_ID_IMS 0x10e0 #define PCI_DEVICE_ID_IMS_8849 0x8849 diff -Nur -p linux-2.4.32/include/linux/proc_fs.h linux-2.4.33-rc2/include/linux/proc_fs.h --- linux-2.4.32/include/linux/proc_fs.h 2005-01-19 12:10:12.000000000 -0200 +++ linux-2.4.33-rc2/include/linux/proc_fs.h 2006-06-21 10:40:43.000000000 -0300 @@ -70,6 +70,7 @@ struct proc_dir_entry { atomic_t count; /* use count */ int deleted; /* delete flag */ kdev_t rdev; + void *set; }; #define PROC_INODE_PROPER(inode) ((inode)->i_ino & ~0xffff) diff -Nur -p linux-2.4.32/include/linux/sysctl.h linux-2.4.33-rc2/include/linux/sysctl.h --- linux-2.4.32/include/linux/sysctl.h 2005-04-03 22:42:20.000000000 -0300 +++ linux-2.4.33-rc2/include/linux/sysctl.h 2006-06-21 10:40:43.000000000 -0300 @@ -29,6 +29,7 @@ #include struct file; +struct completion; #define CTL_MAXNAME 10 @@ -829,6 +830,8 @@ struct ctl_table_header { ctl_table *ctl_table; struct list_head ctl_entry; + int used; + struct completion *unregistering; }; struct ctl_table_header * register_sysctl_table(ctl_table * table, diff -Nur -p linux-2.4.32/include/net/sctp/sctp.h linux-2.4.33-rc2/include/net/sctp/sctp.h --- linux-2.4.32/include/net/sctp/sctp.h 2005-01-19 12:10:13.000000000 -0200 +++ linux-2.4.33-rc2/include/net/sctp/sctp.h 2006-06-21 10:40:43.000000000 -0300 @@ -466,12 +466,12 @@ static inline int sctp_frag_point(const * there is room for a param header too. */ #define sctp_walk_params(pos, chunk, member)\ -_sctp_walk_params((pos), (chunk), WORD_ROUND(ntohs((chunk)->chunk_hdr.length)), member) +_sctp_walk_params((pos), (chunk), ntohs((chunk)->chunk_hdr.length), member) #define _sctp_walk_params(pos, chunk, end, member)\ for (pos.v = chunk->member;\ pos.v <= (void *)chunk + end - sizeof(sctp_paramhdr_t) &&\ - pos.v <= (void *)chunk + end - WORD_ROUND(ntohs(pos.p->length)) &&\ + pos.v <= (void *)chunk + end - ntohs(pos.p->length) &&\ ntohs(pos.p->length) >= sizeof(sctp_paramhdr_t);\ pos.v += WORD_ROUND(ntohs(pos.p->length))) @@ -482,7 +482,7 @@ _sctp_walk_errors((err), (chunk_hdr), nt for (err = (sctp_errhdr_t *)((void *)chunk_hdr + \ sizeof(sctp_chunkhdr_t));\ (void *)err <= (void *)chunk_hdr + end - sizeof(sctp_errhdr_t) &&\ - (void *)err <= (void *)chunk_hdr + end - WORD_ROUND(ntohs(err->length)) &&\ + (void *)err <= (void *)chunk_hdr + end - ntohs(err->length) &&\ ntohs(err->length) >= sizeof(sctp_errhdr_t); \ err = (sctp_errhdr_t *)((void *)err + WORD_ROUND(ntohs(err->length)))) diff -Nur -p linux-2.4.32/include/scsi/scsi.h linux-2.4.33-rc2/include/scsi/scsi.h --- linux-2.4.32/include/scsi/scsi.h 2004-11-17 09:54:22.000000000 -0200 +++ linux-2.4.33-rc2/include/scsi/scsi.h 2006-06-21 10:40:43.000000000 -0300 @@ -96,6 +96,10 @@ /* values for service action in */ #define SAI_READ_CAPACITY_16 0x10 +/* Values for T10/04-262r7 */ +#define ATA_16 0x85 /* 16-byte pass-thru */ +#define ATA_12 0xa1 /* 12-byte pass-thru */ + #define SCSI_RETRY_10(c) ((c) == READ_6 || (c) == WRITE_6 || (c) == SEEK_6) /* diff -Nur -p linux-2.4.32/init/main.c linux-2.4.33-rc2/init/main.c --- linux-2.4.32/init/main.c 2004-11-17 09:54:22.000000000 -0200 +++ linux-2.4.33-rc2/init/main.c 2006-06-21 10:40:43.000000000 -0300 @@ -84,6 +84,13 @@ extern int irda_device_init(void); #error Sorry, your GCC is too old. It builds incorrect kernels. #endif +/* + * gcc >= 4 is not supported by kernel 2.4 + */ +#if __GNUC__ > 3 +#error Sorry, your GCC is too recent for kernel 2.4 +#endif + extern char _stext, _etext; extern char *linux_banner; diff -Nur -p linux-2.4.32/ipc/shm.c linux-2.4.33-rc2/ipc/shm.c --- linux-2.4.32/ipc/shm.c 2002-08-02 21:39:46.000000000 -0300 +++ linux-2.4.33-rc2/ipc/shm.c 2006-06-21 10:40:43.000000000 -0300 @@ -161,6 +161,8 @@ static int shm_mmap(struct file * file, { UPDATE_ATIME(file->f_dentry->d_inode); vma->vm_ops = &shm_vm_ops; + if (!(vma->vm_flags & VM_WRITE)) + vma->vm_flags &= ~VM_MAYWRITE; shm_inc(file->f_dentry->d_inode->i_ino); return 0; } diff -Nur -p linux-2.4.32/kernel/kmod.c linux-2.4.33-rc2/kernel/kmod.c --- linux-2.4.32/kernel/kmod.c 2003-11-28 16:26:21.000000000 -0200 +++ linux-2.4.33-rc2/kernel/kmod.c 2006-06-21 10:40:43.000000000 -0300 @@ -125,6 +125,8 @@ int exec_usermodehelper(char *program_pa curtask->euid = curtask->uid = curtask->suid = curtask->fsuid = 0; curtask->egid = curtask->gid = curtask->sgid = curtask->fsgid = 0; + memcpy(&curtask->rlim, &init_task.rlim, sizeof(struct rlimit)*RLIM_NLIMITS); + curtask->ngroups = 0; cap_set_full(curtask->cap_effective); diff -Nur -p linux-2.4.32/kernel/panic.c linux-2.4.33-rc2/kernel/panic.c --- linux-2.4.32/kernel/panic.c 2004-11-17 09:54:22.000000000 -0200 +++ linux-2.4.33-rc2/kernel/panic.c 2006-06-21 10:40:43.000000000 -0300 @@ -104,7 +104,7 @@ NORET_TYPE void panic(const char * fmt, #endif sti(); for(;;) { -#if defined(CONFIG_X86) && defined(CONFIG_VT) +#if defined(CONFIG_X86) && defined(CONFIG_VT) && !defined(CONFIG_DUMMY_KEYB) extern void panic_blink(void); panic_blink(); #endif diff -Nur -p linux-2.4.32/kernel/ptrace.c linux-2.4.33-rc2/kernel/ptrace.c --- linux-2.4.32/kernel/ptrace.c 2003-08-25 08:44:44.000000000 -0300 +++ linux-2.4.33-rc2/kernel/ptrace.c 2006-06-21 10:40:43.000000000 -0300 @@ -58,7 +58,7 @@ int ptrace_attach(struct task_struct *ta task_lock(task); if (task->pid <= 1) goto bad; - if (task == current) + if (task->tgid == current->tgid) goto bad; if (!task->mm) goto bad; diff -Nur -p linux-2.4.32/kernel/sysctl.c linux-2.4.33-rc2/kernel/sysctl.c --- linux-2.4.32/kernel/sysctl.c 2005-01-19 12:10:13.000000000 -0200 +++ linux-2.4.33-rc2/kernel/sysctl.c 2006-06-21 10:40:43.000000000 -0300 @@ -147,7 +147,7 @@ static struct inode_operations proc_sys_ extern struct proc_dir_entry *proc_sys_root; -static void register_proc_table(ctl_table *, struct proc_dir_entry *); +static void register_proc_table(ctl_table *, struct proc_dir_entry *, void *); static void unregister_proc_table(ctl_table *, struct proc_dir_entry *); #endif @@ -360,10 +360,51 @@ static ctl_table dev_table[] = { extern void init_irq_proc (void); +static spinlock_t sysctl_lock = SPIN_LOCK_UNLOCKED; + +/* called under sysctl_lock */ +static int use_table(struct ctl_table_header *p) +{ + if (unlikely(p->unregistering != NULL)) + return 0; + p->used++; + return 1; +} + +/* called under sysctl_lock */ +static void unuse_table(struct ctl_table_header *p) +{ + if (!--p->used) + if (unlikely(p->unregistering != NULL)) + complete(p->unregistering); +} + +/* called under sysctl_lock, will reacquire if has to wait */ +static void start_unregistering(struct ctl_table_header *p) +{ + /* + * if p->used is 0, nobody will ever touch that entry again; + * we'll eliminate all paths to it before dropping sysctl_lock + */ + if (unlikely(p->used)) { + struct completion wait; + init_completion(&wait); + p->unregistering = &wait; + spin_unlock(&sysctl_lock); + wait_for_completion(&wait); + spin_lock(&sysctl_lock); + } + /* + * do not remove from the list until nobody holds it; walking the + * list in do_sysctl() relies on that. + */ + list_del_init(&p->ctl_entry); +} + void __init sysctl_init(void) { #ifdef CONFIG_PROC_FS - register_proc_table(root_table, proc_sys_root); + register_proc_table(root_table, proc_sys_root, &root_table_header); init_irq_proc(); #endif } @@ -372,6 +413,7 @@ int do_sysctl(int *name, int nlen, void void *newval, size_t newlen) { struct list_head *tmp; + int error = -ENOTDIR; if (nlen <= 0 || nlen >= CTL_MAXNAME) return -ENOTDIR; @@ -383,21 +425,31 @@ int do_sysctl(int *name, int nlen, void if ((ssize_t)old_len < 0) return -EINVAL; } + spin_lock(&sysctl_lock); tmp = &root_table_header.ctl_entry; do { struct ctl_table_header *head = list_entry(tmp, struct ctl_table_header, ctl_entry); void *context = NULL; - int error = parse_table(name, nlen, oldval, oldlenp, + + if (!use_table(head)) + continue; + + spin_unlock(&sysctl_lock); + + error = parse_table(name, nlen, oldval, oldlenp, newval, newlen, head->ctl_table, &context); if (context) kfree(context); + + spin_lock(&sysctl_lock); + unuse_table(head); if (error != -ENOTDIR) - return error; - tmp = tmp->next; - } while (tmp != &root_table_header.ctl_entry); - return -ENOTDIR; + break; + } while ((tmp = tmp->next) != &root_table_header.ctl_entry); + spin_unlock(&sysctl_lock); + return error; } extern asmlinkage long sys_sysctl(struct __sysctl_args *args) @@ -604,12 +656,16 @@ struct ctl_table_header *register_sysctl return NULL; tmp->ctl_table = table; INIT_LIST_HEAD(&tmp->ctl_entry); + tmp->used = 0; + tmp->unregistering = NULL; + spin_lock(&sysctl_lock); if (insert_at_head) list_add(&tmp->ctl_entry, &root_table_header.ctl_entry); else list_add_tail(&tmp->ctl_entry, &root_table_header.ctl_entry); + spin_unlock(&sysctl_lock); #ifdef CONFIG_PROC_FS - register_proc_table(table, proc_sys_root); + register_proc_table(table, proc_sys_root, tmp); #endif return tmp; } @@ -623,10 +679,12 @@ struct ctl_table_header *register_sysctl */ void unregister_sysctl_table(struct ctl_table_header * header) { - list_del(&header->ctl_entry); + spin_lock(&sysctl_lock); + start_unregistering(header); #ifdef CONFIG_PROC_FS unregister_proc_table(header->ctl_table, proc_sys_root); #endif + spin_unlock(&sysctl_lock); kfree(header); } @@ -637,7 +695,7 @@ void unregister_sysctl_table(struct ctl_ #ifdef CONFIG_PROC_FS /* Scan the sysctl entries in table and add them all into /proc */ -static void register_proc_table(ctl_table * table, struct proc_dir_entry *root) +static void register_proc_table(ctl_table * table, struct proc_dir_entry *root, void *set) { struct proc_dir_entry *de; int len; @@ -673,6 +731,7 @@ static void register_proc_table(ctl_tabl de = create_proc_entry(table->procname, mode, root); if (!de) continue; + de->set = set; de->data = (void *) table; if (table->proc_handler) { de->proc_fops = &proc_sys_file_operations; @@ -681,7 +740,7 @@ static void register_proc_table(ctl_tabl } table->de = de; if (de->mode & S_IFDIR) - register_proc_table(table->child, de); + register_proc_table(table->child, de, set); } } @@ -706,6 +765,13 @@ static void unregister_proc_table(ctl_ta continue; } + /* + * In any case, mark the entry as goner; we'll keep it + * around if it's busy, but we'll know to do nothing with + * its fields. We are under sysctl_lock here. + */ + de->data = NULL; + /* Don't unregister proc entries that are still being used.. */ if (atomic_read(&de->count)) continue; @@ -719,31 +785,44 @@ static ssize_t do_rw_proc(int write, str size_t count, loff_t *ppos) { int op; - struct proc_dir_entry *de; + struct proc_dir_entry *de = + (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip; struct ctl_table *table; size_t res; - ssize_t error; - - de = (struct proc_dir_entry*) file->f_dentry->d_inode->u.generic_ip; - if (!de || !de->data) - return -ENOTDIR; - table = (struct ctl_table *) de->data; - if (!table || !table->proc_handler) - return -ENOTDIR; - op = (write ? 002 : 004); - if (ctl_perm(table, op)) - return -EPERM; - - res = count; + ssize_t error = -ENOTDIR; - /* - * FIXME: we need to pass on ppos to the handler. - */ + spin_lock(&sysctl_lock); + if (de && de->data && use_table(de->set)) { + /* + * at that point we know that sysctl was not unregistered + * and won't be until we finish + */ + spin_unlock(&sysctl_lock); + table = (struct ctl_table *) de->data; + if (!table || !table->proc_handler) + goto out; + error = -EPERM; + op = (write ? 002 : 004); + if (ctl_perm(table, op)) + goto out; + + /* careful: calling conventions are nasty here */ + res = count; - error = (*table->proc_handler) (table, write, file, buf, &res); - if (error) - return error; - return res; + /* + * FIXME: we need to pass on ppos to the handler. + */ + + error = (*table->proc_handler)(table, write, file, + buf, &res); + if (!error) + error = res; + out: + spin_lock(&sysctl_lock); + unuse_table(de->set); + } + spin_unlock(&sysctl_lock); + return error; } static ssize_t proc_readsys(struct file * file, char * buf, diff -Nur -p linux-2.4.32/Makefile linux-2.4.33-rc2/Makefile --- linux-2.4.32/Makefile 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/Makefile 2006-06-21 10:40:43.000000000 -0300 @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 4 -SUBLEVEL = 32 -EXTRAVERSION = +SUBLEVEL = 33 +EXTRAVERSION = -rc2 KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION) diff -Nur -p linux-2.4.32/net/8021q/vlan.c linux-2.4.33-rc2/net/8021q/vlan.c --- linux-2.4.32/net/8021q/vlan.c 2004-02-18 10:36:32.000000000 -0300 +++ linux-2.4.33-rc2/net/8021q/vlan.c 2006-06-21 10:40:43.000000000 -0300 @@ -757,6 +757,8 @@ int vlan_ioctl_handler(unsigned long arg case GET_VLAN_REALDEV_NAME_CMD: err = vlan_dev_get_realdev_name(args.device1, args.u.device2); + if (err) + goto out; if (copy_to_user((void*)arg, &args, sizeof(struct vlan_ioctl_args))) { err = -EFAULT; @@ -765,6 +767,8 @@ int vlan_ioctl_handler(unsigned long arg case GET_VLAN_VID_CMD: err = vlan_dev_get_vid(args.device1, &vid); + if (err) + goto out; args.u.VID = vid; if (copy_to_user((void*)arg, &args, sizeof(struct vlan_ioctl_args))) { @@ -778,7 +782,7 @@ int vlan_ioctl_handler(unsigned long arg __FUNCTION__, args.cmd); return -EINVAL; }; - +out: return err; } diff -Nur -p linux-2.4.32/net/core/neighbour.c linux-2.4.33-rc2/net/core/neighbour.c --- linux-2.4.32/net/core/neighbour.c 2005-04-03 22:42:20.000000000 -0300 +++ linux-2.4.33-rc2/net/core/neighbour.c 2006-06-21 10:40:43.000000000 -0300 @@ -14,6 +14,7 @@ * Vitaly E. Lavrov releasing NULL neighbor in neigh_add. * Harald Welte Add neighbour cache statistics like rtstat * Harald Welte port neighbour cache rework from 2.6.9-rcX + * Pradeep Vincent Move neighbour cache entry to stale state */ #include @@ -705,6 +706,14 @@ static void SMP_TIMER_NAME(neigh_periodi neigh_release(n); continue; } + + /* Mark it stale - To be reconfirmed later when used */ + if (n->nud_state & NUD_REACHABLE && + now - n->confirmed > n->parms->reachable_time) { + n->nud_state = NUD_STALE; + neigh_suspect(n); + } + write_unlock(&n->lock); next_elt: diff -Nur -p linux-2.4.32/net/ipv4/af_inet.c linux-2.4.33-rc2/net/ipv4/af_inet.c --- linux-2.4.32/net/ipv4/af_inet.c 2005-01-19 12:10:13.000000000 -0200 +++ linux-2.4.33-rc2/net/ipv4/af_inet.c 2006-06-21 10:40:43.000000000 -0300 @@ -724,6 +724,7 @@ int inet_getname(struct socket *sock, st sin->sin_port = sk->sport; sin->sin_addr.s_addr = addr; } + memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); *uaddr_len = sizeof(*sin); return(0); } diff -Nur -p linux-2.4.32/net/ipv4/igmp.c linux-2.4.33-rc2/net/ipv4/igmp.c --- linux-2.4.32/net/ipv4/igmp.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/net/ipv4/igmp.c 2006-06-21 10:40:43.000000000 -0300 @@ -876,6 +876,10 @@ int igmp_rcv(struct sk_buff *skb) /* Is it our report looped back? */ if (((struct rtable*)skb->dst)->key.iif == 0) break; + /* don't rely on MC router hearing unicast reports */ + if (skb->pkt_type == PACKET_MULTICAST || + skb->pkt_type == PACKET_BROADCAST) + igmp_heard_report(in_dev, ih->group); igmp_heard_report(in_dev, ih->group); break; case IGMP_PIM: @@ -1876,8 +1880,11 @@ int ip_mc_msfilter(struct sock *sk, stru sock_kfree_s(sk, newpsl, IP_SFLSIZE(newpsl->sl_max)); goto done; } - } else - newpsl = 0; + } else { + newpsl = NULL; + (void) ip_mc_add_src(in_dev, &msf->imsf_multiaddr, + msf->imsf_fmode, 0, NULL, 0); + } psl = pmc->sflist; if (psl) { (void) ip_mc_del_src(in_dev, &msf->imsf_multiaddr, pmc->sfmode, diff -Nur -p linux-2.4.32/net/ipv4/netfilter/arp_tables.c linux-2.4.33-rc2/net/ipv4/netfilter/arp_tables.c --- linux-2.4.32/net/ipv4/netfilter/arp_tables.c 2004-11-17 09:54:22.000000000 -0200 +++ linux-2.4.33-rc2/net/ipv4/netfilter/arp_tables.c 2006-06-21 10:40:43.000000000 -0300 @@ -871,6 +871,13 @@ static int do_replace(void *user, unsign if (len != sizeof(tmp) + tmp.size) return -ENOPROTOOPT; + /* overflow check */ + if (tmp.size >= (INT_MAX - sizeof(struct arpt_table_info)) / NR_CPUS - + SMP_CACHE_BYTES) + return -ENOMEM; + if (tmp.num_counters >= INT_MAX / sizeof(struct arpt_counters)) + return -ENOMEM; + /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages) return -ENOMEM; @@ -991,7 +998,7 @@ static int do_add_counters(void *user, u goto free; write_lock_bh(&t->lock); - if (t->private->number != paddc->num_counters) { + if (t->private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } diff -Nur -p linux-2.4.32/net/ipv4/netfilter/ip_conntrack_core.c linux-2.4.33-rc2/net/ipv4/netfilter/ip_conntrack_core.c --- linux-2.4.32/net/ipv4/netfilter/ip_conntrack_core.c 2005-04-03 22:42:20.000000000 -0300 +++ linux-2.4.33-rc2/net/ipv4/netfilter/ip_conntrack_core.c 2006-06-21 10:40:43.000000000 -0300 @@ -1349,6 +1349,7 @@ getorigdst(struct sock *sk, int optval, .tuple.dst.u.tcp.port; sin.sin_addr.s_addr = h->ctrack->tuplehash[IP_CT_DIR_ORIGINAL] .tuple.dst.ip; + memset(sin.sin_zero, 0, sizeof(sin.sin_zero)); DEBUGP("SO_ORIGINAL_DST: %u.%u.%u.%u %u\n", NIPQUAD(sin.sin_addr.s_addr), ntohs(sin.sin_port)); diff -Nur -p linux-2.4.32/net/ipv4/netfilter/ip_nat_snmp_basic.c linux-2.4.33-rc2/net/ipv4/netfilter/ip_nat_snmp_basic.c --- linux-2.4.32/net/ipv4/netfilter/ip_nat_snmp_basic.c 2004-11-17 09:54:22.000000000 -0200 +++ linux-2.4.33-rc2/net/ipv4/netfilter/ip_nat_snmp_basic.c 2006-06-21 10:40:43.000000000 -0300 @@ -996,12 +996,12 @@ static unsigned char snmp_trap_decode(st return 1; +err_addr_free: + kfree((unsigned long *)trap->ip_address); + err_id_free: kfree(trap->id); -err_addr_free: - kfree((unsigned long *)trap->ip_address); - return 0; } @@ -1119,11 +1119,10 @@ static int snmp_parse_mangle(unsigned ch struct snmp_v1_trap trap; unsigned char ret = snmp_trap_decode(&ctx, &trap, map, check); - /* Discard trap allocations regardless */ - kfree(trap.id); - kfree((unsigned long *)trap.ip_address); - - if (!ret) + if (ret) { + kfree(trap.id); + kfree((unsigned long *)trap.ip_address); + } else return ret; } else { diff -Nur -p linux-2.4.32/net/ipv4/netfilter/ip_queue.c linux-2.4.33-rc2/net/ipv4/netfilter/ip_queue.c --- linux-2.4.32/net/ipv4/netfilter/ip_queue.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/net/ipv4/netfilter/ip_queue.c 2006-06-21 10:40:43.000000000 -0300 @@ -519,7 +519,7 @@ ipq_rcv_skb(struct sk_buff *skb) write_unlock_bh(&queue_lock); status = ipq_receive_peer(NLMSG_DATA(nlh), type, - skblen - NLMSG_LENGTH(0)); + nlmsglen - NLMSG_LENGTH(0)); if (status < 0) RCV_SKB_FAIL(status); diff -Nur -p linux-2.4.32/net/ipv4/netfilter/ip_tables.c linux-2.4.33-rc2/net/ipv4/netfilter/ip_tables.c --- linux-2.4.32/net/ipv4/netfilter/ip_tables.c 2005-04-03 22:42:20.000000000 -0300 +++ linux-2.4.33-rc2/net/ipv4/netfilter/ip_tables.c 2006-06-21 10:40:43.000000000 -0300 @@ -1066,6 +1066,13 @@ do_replace(void *user, unsigned int len) if (len != sizeof(tmp) + tmp.size) return -ENOPROTOOPT; + /* overflow check */ + if (tmp.size >= (INT_MAX - sizeof(struct ipt_table_info)) / NR_CPUS - + SMP_CACHE_BYTES) + return -ENOMEM; + if (tmp.num_counters >= INT_MAX / sizeof(struct ipt_counters)) + return -ENOMEM; + /* Pedantry: prevent them from hitting BUG() in vmalloc.c --RR */ if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages) return -ENOMEM; @@ -1195,7 +1202,7 @@ do_add_counters(void *user, unsigned int goto free; write_lock_bh(&t->lock); - if (t->private->number != paddc->num_counters) { + if (t->private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } diff -Nur -p linux-2.4.32/net/ipv4/netfilter/ipt_recent.c linux-2.4.33-rc2/net/ipv4/netfilter/ipt_recent.c --- linux-2.4.32/net/ipv4/netfilter/ipt_recent.c 2005-04-03 22:42:20.000000000 -0300 +++ linux-2.4.33-rc2/net/ipv4/netfilter/ipt_recent.c 2006-06-21 10:40:43.000000000 -0300 @@ -820,6 +820,7 @@ checkentry(const char *tablename, /* Create our proc 'status' entry. */ curr_table->status_proc = create_proc_entry(curr_table->name, ip_list_perms, proc_net_ipt_recent); if (!curr_table->status_proc) { + vfree(hold); printk(KERN_INFO RECENT_NAME ": checkentry: unable to allocate for /proc entry.\n"); /* Destroy the created table */ spin_lock_bh(&recent_lock); @@ -844,7 +845,6 @@ checkentry(const char *tablename, spin_unlock_bh(&recent_lock); vfree(curr_table->time_info); vfree(curr_table->hash_table); - vfree(hold); vfree(curr_table->table); vfree(curr_table); return 0; diff -Nur -p linux-2.4.32/net/ipv4/route.c linux-2.4.33-rc2/net/ipv4/route.c --- linux-2.4.32/net/ipv4/route.c 2004-11-17 09:54:22.000000000 -0200 +++ linux-2.4.33-rc2/net/ipv4/route.c 2006-06-21 10:40:43.000000000 -0300 @@ -2214,7 +2214,10 @@ int inet_rtm_getroute(struct sk_buff *in /* Reserve room for dummy headers, this skb can pass through good chunk of routing engine. */ - skb->mac.raw = skb->data; + skb->mac.raw = skb->nh.raw = skb->data; + + /* Bugfix: need to give ip_route_input enough of an IP header to not gag. */ + skb->nh.iph->protocol = IPPROTO_ICMP; skb_reserve(skb, MAX_HEADER + sizeof(struct iphdr)); if (rta[RTA_SRC - 1]) diff -Nur -p linux-2.4.32/net/ipv6/ip6_flowlabel.c linux-2.4.33-rc2/net/ipv6/ip6_flowlabel.c --- linux-2.4.32/net/ipv6/ip6_flowlabel.c 2000-08-07 02:20:09.000000000 -0300 +++ linux-2.4.33-rc2/net/ipv6/ip6_flowlabel.c 2006-06-21 10:40:43.000000000 -0300 @@ -475,7 +475,7 @@ int ipv6_flowlabel_opt(struct sock *sk, goto done; } fl1 = sfl->fl; - atomic_inc(&fl->users); + atomic_inc(&fl1->users); break; } } diff -Nur -p linux-2.4.32/net/ipv6/mcast.c linux-2.4.33-rc2/net/ipv6/mcast.c --- linux-2.4.32/net/ipv6/mcast.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/net/ipv6/mcast.c 2006-06-21 10:40:43.000000000 -0300 @@ -505,8 +505,11 @@ int ip6_mc_msfilter(struct sock *sk, str sock_kfree_s(sk, newpsl, IP6_SFLSIZE(newpsl->sl_max)); goto done; } - } else - newpsl = 0; + } else { + newpsl = NULL; + (void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0); + } + psl = pmc->sflist; if (psl) { (void) ip6_mc_del_src(idev, group, pmc->sfmode, @@ -1142,6 +1145,11 @@ int igmp6_event_report(struct sk_buff *s if (skb->pkt_type == PACKET_LOOPBACK) return 0; + /* send our report if the MC router may not have heard this report */ + if (skb->pkt_type != PACKET_MULTICAST && + skb->pkt_type != PACKET_BROADCAST) + return 0; + if (!pskb_may_pull(skb, sizeof(struct in6_addr))) return -EINVAL; diff -Nur -p linux-2.4.32/net/ipv6/netfilter/ip6_queue.c linux-2.4.33-rc2/net/ipv6/netfilter/ip6_queue.c --- linux-2.4.32/net/ipv6/netfilter/ip6_queue.c 2005-11-16 17:12:54.000000000 -0200 +++ linux-2.4.33-rc2/net/ipv6/netfilter/ip6_queue.c 2006-06-21 10:40:43.000000000 -0300 @@ -523,7 +523,7 @@ ipq_rcv_skb(struct sk_buff *skb) write_unlock_bh(&queue_lock); status = ipq_receive_peer(NLMSG_DATA(nlh), type, - skblen - NLMSG_LENGTH(0)); + nlmsglen - NLMSG_LENGTH(0)); if (status < 0) RCV_SKB_FAIL(status); diff -Nur -p linux-2.4.32/net/ipv6/netfilter/ip6_tables.c linux-2.4.33-rc2/net/ipv6/netfilter/ip6_tables.c --- linux-2.4.32/net/ipv6/netfilter/ip6_tables.c 2005-04-03 22:42:20.000000000 -0300 +++ linux-2.4.33-rc2/net/ipv6/netfilter/ip6_tables.c 2006-06-21 10:40:43.000000000 -0300 @@ -1151,6 +1151,13 @@ do_replace(void *user, unsigned int len) if ((SMP_ALIGN(tmp.size) >> PAGE_SHIFT) + 2 > num_physpages) return -ENOMEM; + /* overflow check */ + if (tmp.size >= (INT_MAX - sizeof(struct ip6t_table_info)) / NR_CPUS - + SMP_CACHE_BYTES) + return -ENOMEM; + if (tmp.num_counters >= INT_MAX / sizeof(struct ip6t_counters)) + return -ENOMEM; + newinfo = vmalloc(sizeof(struct ip6t_table_info) + SMP_ALIGN(tmp.size) * smp_num_cpus); if (!newinfo) @@ -1276,7 +1283,7 @@ do_add_counters(void *user, unsigned int goto free; write_lock_bh(&t->lock); - if (t->private->number != paddc->num_counters) { + if (t->private->number != tmp.num_counters) { ret = -EINVAL; goto unlock_up_free; } diff -Nur -p linux-2.4.32/net/sctp/sm_statefuns.c linux-2.4.33-rc2/net/sctp/sm_statefuns.c --- linux-2.4.32/net/sctp/sm_statefuns.c 2005-01-19 12:10:14.000000000 -0200 +++ linux-2.4.33-rc2/net/sctp/sm_statefuns.c 2006-06-21 10:40:43.000000000 -0300 @@ -619,8 +619,9 @@ sctp_disposition_t sctp_sf_do_5_1D_ce(co */ chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data; - skb_pull(chunk->skb, - ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t)); + if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - + sizeof(sctp_chunkhdr_t))) + goto nomem; /* 5.1 D) Upon reception of the COOKIE ECHO chunk, Endpoint * "Z" will reply with a COOKIE ACK chunk after building a TCB @@ -949,7 +950,8 @@ sctp_disposition_t sctp_sf_beat_8_3(cons */ chunk->subh.hb_hdr = (sctp_heartbeathdr_t *) chunk->skb->data; paylen = ntohs(chunk->chunk_hdr->length) - sizeof(sctp_chunkhdr_t); - skb_pull(chunk->skb, paylen); + if (!pskb_pull(chunk->skb, paylen)) + goto nomem; reply = sctp_make_heartbeat_ack(asoc, chunk, chunk->subh.hb_hdr, paylen); @@ -1012,6 +1014,12 @@ sctp_disposition_t sctp_sf_backbeat_8_3( commands); hbinfo = (sctp_sender_hb_info_t *) chunk->skb->data; + /* Make sure that the length of the parameter is what we expect */ + if (ntohs(hbinfo->param_hdr.length) != + sizeof(sctp_sender_hb_info_t)) { + return SCTP_DISPOSITION_DISCARD; + } + from_addr = hbinfo->daddr; link = sctp_assoc_lookup_paddr(asoc, &from_addr); @@ -1832,8 +1840,9 @@ sctp_disposition_t sctp_sf_do_5_2_4_dupc * are in good shape. */ chunk->subh.cookie_hdr = (struct sctp_signed_cookie *)chunk->skb->data; - skb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - - sizeof(sctp_chunkhdr_t)); + if (!pskb_pull(chunk->skb, ntohs(chunk->chunk_hdr->length) - + sizeof(sctp_chunkhdr_t))) + goto nomem; /* In RFC 2960 5.2.4 3, if both Verification Tags in the State Cookie * of a duplicate COOKIE ECHO match the Verification Tags of the diff -Nur -p linux-2.4.32/net/sctp/sm_statetable.c linux-2.4.33-rc2/net/sctp/sm_statetable.c --- linux-2.4.32/net/sctp/sm_statetable.c 2005-01-19 12:10:14.000000000 -0200 +++ linux-2.4.33-rc2/net/sctp/sm_statetable.c 2006-06-21 10:40:43.000000000 -0300 @@ -366,9 +366,9 @@ const sctp_sm_table_entry_t *sctp_sm_loo /* SCTP_STATE_EMPTY */ \ {.fn = sctp_sf_ootb, .name = "sctp_sf_ootb"}, \ /* SCTP_STATE_CLOSED */ \ - {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ - {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ /* SCTP_STATE_COOKIE_ECHOED */ \ {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \ /* SCTP_STATE_ESTABLISHED */ \ @@ -380,7 +380,7 @@ const sctp_sm_table_entry_t *sctp_sm_loo /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ {.fn = sctp_sf_do_ecne, .name = "sctp_sf_do_ecne"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ } /* TYPE_SCTP_ECN_ECNE */ #define TYPE_SCTP_ECN_CWR { \ @@ -401,7 +401,7 @@ const sctp_sm_table_entry_t *sctp_sm_loo /* SCTP_STATE_SHUTDOWN_RECEIVED */ \ {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ /* SCTP_STATE_SHUTDOWN_ACK_SENT */ \ - {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + {.fn = sctp_sf_discard_chunk, .name = "sctp_sf_discard_chunk"}, \ } /* TYPE_SCTP_ECN_CWR */ #define TYPE_SCTP_SHUTDOWN_COMPLETE { \ @@ -647,7 +647,7 @@ chunk_event_table_unknown[SCTP_STATE_NUM /* SCTP_STATE_EMPTY */ \ {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ /* SCTP_STATE_CLOSED */ \ - {.fn = sctp_sf_bug, .name = "sctp_sf_bug"}, \ + {.fn = sctp_sf_error_closed, .name = "sctp_sf_error_closed"}, \ /* SCTP_STATE_COOKIE_WAIT */ \ {.fn = sctp_sf_do_prm_requestheartbeat, \ .name = "sctp_sf_do_prm_requestheartbeat"}, \ diff -Nur -p linux-2.4.32/net/sctp/ulpqueue.c linux-2.4.33-rc2/net/sctp/ulpqueue.c --- linux-2.4.32/net/sctp/ulpqueue.c 2005-01-19 12:10:14.000000000 -0200 +++ linux-2.4.33-rc2/net/sctp/ulpqueue.c 2006-06-21 10:40:43.000000000 -0300 @@ -273,6 +273,7 @@ static inline void sctp_ulpq_store_reasm static struct sctp_ulpevent *sctp_make_reassembled_event(struct sk_buff *f_frag, struct sk_buff *l_frag) { struct sk_buff *pos; + struct sk_buff *new = NULL; struct sctp_ulpevent *event; struct sk_buff *pnext, *last; struct sk_buff *list = skb_shinfo(f_frag)->frag_list; @@ -291,11 +292,33 @@ static struct sctp_ulpevent *sctp_make_r */ if (last) last->next = pos; - else - skb_shinfo(f_frag)->frag_list = pos; + else { + if (skb_cloned(f_frag)) { + /* This is a cloned skb, we can't just modify + * the frag_list. We need a new skb to do that. + * Instead of calling skb_unshare(), we'll do it + * ourselves since we need to delay the free. + */ + new = skb_copy(f_frag, GFP_ATOMIC); + if (!new) + return NULL; /* try again later */ + + new->sk = f_frag->sk; + + skb_shinfo(new)->frag_list = pos; + } else + skb_shinfo(f_frag)->frag_list = pos; + } /* Remove the first fragment from the reassembly queue. */ __skb_unlink(f_frag, f_frag->list); + + /* if we did unshare, then free the old skb and re-assign */ + if (new) { + kfree_skb(f_frag); + f_frag = new; + } + while (pos) { pnext = pos->next; diff -Nur -p linux-2.4.32/README linux-2.4.33-rc2/README --- linux-2.4.32/README 2003-08-25 08:44:39.000000000 -0300 +++ linux-2.4.33-rc2/README 2006-06-21 10:40:43.000000000 -0300 @@ -152,6 +152,7 @@ COMPILING the kernel: - Make sure you have gcc 2.95.3 available. gcc 2.91.66 (egcs-1.1.2) may also work but is not as safe, and *gcc 2.7.2.3 is no longer supported*. + gcc 4 is *not* supported. Also remember to upgrade your binutils package (for as/ld/nm and company) if necessary. For more information, refer to ./Documentation/Changes. diff -Nur -p linux-2.4.32/scripts/ver_linux linux-2.4.33-rc2/scripts/ver_linux --- linux-2.4.32/scripts/ver_linux 2004-02-18 10:36:32.000000000 -0300 +++ linux-2.4.33-rc2/scripts/ver_linux 2006-06-21 10:40:43.000000000 -0300 @@ -22,7 +22,8 @@ make --version 2>&1 | awk -F, '{print $1 '/GNU Make/{print "Gnu make ",$NF}' ld -v 2>&1 | awk -F\) '{print $1}' | awk \ - '/BFD/{print "binutils ",$NF}' + '/BFD/{print "binutils ",$NF} \ + /^GNU/{print "binutils ",$4}' fdformat --version | awk -F\- '{print "util-linux ", $NF}'