From a3191e7fa4ad60031378cdc8d4df86e4b2b310dc Mon Sep 17 00:00:00 2001 From: Alan Cox Date: Fri, 23 Nov 2007 15:24:15 -0500 Subject: [PATCH] Linux 2.2.21rc3 o Plan B driver updates (Michel Lanners) o 3ware raid update (Adam Radford) o Fix PowerMac compile (Krzysiek Taraszka) o Fix nvram/rtc ioctl returns (Paul Gortmaker) o OV511 compile/build fixes (Toru SAGAMI) o Final ppp zlib bits (Paul Mackerras) --- Makefile | 2 +- drivers/char/nvram.c | 2 +- drivers/char/planb.c | 326 ++++++++++++----------------- drivers/char/planb.h | 15 +- drivers/char/rtc.c | 2 +- drivers/macintosh/mac_hid.c | 4 +- drivers/net/zlib.c | 7 +- drivers/scsi/3w-xxxx.c | 407 ++++++++++++++++++++---------------- drivers/scsi/3w-xxxx.h | 56 ++++- drivers/usb/ov511.c | 4 +- x1 | 180 ++++++++++++++++ 11 files changed, 611 insertions(+), 394 deletions(-) create mode 100644 x1 diff --git a/Makefile b/Makefile index e04be4482fb3..8b3d7c2ade19 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ VERSION = 2 PATCHLEVEL = 2 SUBLEVEL = 21 -EXTRAVERSION = rc2 +EXTRAVERSION = rc3 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff --git a/drivers/char/nvram.c b/drivers/char/nvram.c index 0a7d9c69551e..8614523132ce 100644 --- a/drivers/char/nvram.c +++ b/drivers/char/nvram.c @@ -329,7 +329,7 @@ static int nvram_ioctl( struct inode *inode, struct file *file, return( 0 ); default: - return( -EINVAL ); + return( -ENOTTY ); } } diff --git a/drivers/char/planb.c b/drivers/char/planb.c index ede49febce59..973887d70e34 100644 --- a/drivers/char/planb.c +++ b/drivers/char/planb.c @@ -8,9 +8,7 @@ Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) - Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) - (Some codes are stolen from proposed v4l2 videodev.c - of Bill Dirks ) + Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) 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 @@ -94,11 +92,7 @@ static void saa_write_reg(unsigned char, unsigned char); static unsigned char saa_status(int, struct planb *); static void saa_set(unsigned char, unsigned char, struct planb *); static void saa_init_regs(struct planb *); -static void * rvmalloc(unsigned long); -static void rvfree(void *, unsigned long); -static unsigned long vmalloc_to_bus(void *); -static unsigned long vmalloc_to_phys(void *); -static int fbuffer_alloc(struct planb *); +static int grabbuf_alloc(struct planb *); static int vgrab(struct planb *, struct video_mmap *); static void add_clip(struct planb *, struct video_clip *); static void fill_cmd_buff(struct planb *); @@ -125,82 +119,36 @@ static inline int overlay_is_active(struct planb *); /* Memory management functions */ /*******************************/ -static void * rvmalloc(unsigned long size) +static int grabbuf_alloc(struct planb *pb) { - void *mem, *memptr; - unsigned long page; - - mem=vmalloc(size); - if (mem) - { - memset(mem, 0, size); /* Clear the ram out, leave no junk */ - memptr = mem; - while (size > 0) - { - page = vmalloc_to_phys(memptr); - mem_map_reserve(MAP_NR(phys_to_virt(page))); - memptr+=PAGE_SIZE; - size-=PAGE_SIZE; - } - } - return mem; -} + int i, npage; -static void rvfree(void * mem, unsigned long size) -{ - void *memptr; - unsigned long page; - - if (mem) - { - memptr = mem; - while (size > 0) - { - page = vmalloc_to_phys(memptr); - mem_map_unreserve(MAP_NR(phys_to_virt(page))); - memptr += PAGE_SIZE; - size-=PAGE_SIZE; - } - vfree(mem); + npage = MAX_GBUFFERS * ((PLANB_MAX_FBUF / PAGE_SIZE + 1) +#ifndef PLANB_GSCANLINE + + MAX_LNUM +#endif /* PLANB_GSCANLINE */ + ); + if ((pb->rawbuf = (unsigned char**) kmalloc (npage + * sizeof(unsigned long), GFP_KERNEL)) == 0) + return -ENOMEM; + for (i = 0; i < npage; i++) { + pb->rawbuf[i] = (unsigned char *)__get_free_pages(GFP_KERNEL + |GFP_DMA, 0); + if (!pb->rawbuf[i]) + break; + set_bit(PG_reserved, &mem_map[MAP_NR(pb->rawbuf[i])].flags); } -} - -/* Useful for using vmalloc()ed memory as DMA target */ -static unsigned long vmalloc_to_bus(void *virt) -{ - pgd_t *pgd; - pmd_t *pmd; - pte_t *pte; - unsigned long a = (unsigned long)virt; - - if (pgd_none(*(pgd = pgd_offset(current->mm, a))) || - pmd_none(*(pmd = pmd_offset(pgd, a))) || - pte_none(*(pte = pte_offset(pmd, a)))) - return 0; - return virt_to_bus((void *)pte_page(*pte)) - + (a & (PAGE_SIZE - 1)); -} - -static unsigned long vmalloc_to_phys(void *virt) { - return virt_to_phys(bus_to_virt(vmalloc_to_bus(virt))); -} - -/* - * Create the giant waste of buffer space we need for now - * until we get DMA to user space sorted out (probably 2.3.x) - * - * We only create this as and when someone uses mmap - */ - -static int fbuffer_alloc(struct planb *pb) -{ - if(!pb->fbuffer) - pb->fbuffer=(unsigned char *) rvmalloc(MAX_GBUFFERS - * PLANB_MAX_FBUF); - else - printk(KERN_ERR "PlanB: Double alloc of fbuffer!\n"); - if(!pb->fbuffer) + if (i-- < npage) { + printk(KERN_DEBUG "PlanB: init_grab: grab buffer not allocated\n"); + for (; i > 0; i--) { + clear_bit(PG_reserved, + &mem_map[MAP_NR(pb->rawbuf[i])].flags); + free_pages((unsigned long)pb->rawbuf[i], 0); + } + kfree(pb->rawbuf); return -ENOBUFS; + } + pb->rawbuf_size = npage; return 0; } @@ -446,11 +394,8 @@ static int planb_prepare_open(struct planb *pb) + PLANB_DUMMY); pb->mask = (unsigned char *)(pb->frame_stat+MAX_GBUFFERS); - pb->fbuffer = (unsigned char *)rvmalloc(MAX_GBUFFERS * PLANB_MAX_FBUF); - if (!pb->fbuffer) { - kfree(pb->priv_space); - return -ENOMEM; - } + pb->rawbuf = NULL; + pb->rawbuf_size = 0; pb->grabbing = 0; for (i = 0; i < MAX_GBUFFERS; i++) { pb->frame_stat[i] = GBUFFER_UNUSED; @@ -461,31 +406,23 @@ static int planb_prepare_open(struct planb *pb) #ifndef PLANB_GSCANLINE pb->lsize[i] = 0; pb->lnum[i] = 0; - pb->l_fr_addr[i]=(unsigned char *)rvmalloc(PAGE_SIZE*MAX_LNUM); - if (!pb->l_fr_addr[i]) { - int j; - kfree(pb->priv_space); - rvfree((void *)pb->fbuffer, MAX_GBUFFERS - * PLANB_MAX_FBUF); - for(j = 0; j < i; j++) - rvfree((void *)pb->l_fr_addr[j], PAGE_SIZE - * MAX_LNUM); - return -ENOMEM; - } #endif /* PLANB_GSCANLINE */ } pb->gcount = 0; pb->suspend = 0; pb->last_fr = -999; pb->prev_last_fr = -999; - return 0; + + /* Reset DMA controllers */ + planb_dbdma_stop(&pb->planb_base->ch2); + planb_dbdma_stop(&pb->planb_base->ch1); + + return 0; } static void planb_prepare_close(struct planb *pb) { -#ifndef PLANB_GSCANLINE int i; -#endif /* make sure the dma's are idle */ planb_dbdma_stop(&pb->planb_base->ch2); @@ -496,16 +433,15 @@ static void planb_prepare_close(struct planb *pb) pb->priv_space = 0; pb->cmd_buff_inited = 0; } - if(pb->fbuffer) - rvfree((void *)pb->fbuffer, MAX_GBUFFERS*PLANB_MAX_FBUF); - pb->fbuffer = NULL; -#ifndef PLANB_GSCANLINE - for(i = 0; i < MAX_GBUFFERS; i++) { - if(pb->l_fr_addr[i]) - rvfree((void *)pb->l_fr_addr[i], PAGE_SIZE * MAX_LNUM); - pb->l_fr_addr[i] = NULL; + if(pb->rawbuf) { + for (i = 0; i < pb->rawbuf_size; i++) { + clear_bit(PG_reserved, + &mem_map[MAP_NR(pb->rawbuf[i])].flags); + free_pages((unsigned long)pb->rawbuf[i], 0); + } + kfree(pb->rawbuf); } -#endif /* PLANB_GSCANLINE */ + pb->rawbuf = NULL; } /*****************************/ @@ -940,12 +876,8 @@ static int palette2fmt[] = { 0, 0, }; -#define PLANB_PALETTE_MAX 15 -#define SWAP4(x) (((x>>24) & 0x000000ff) |\ - ((x>>8) & 0x0000ff00) |\ - ((x<<8) & 0x00ff0000) |\ - ((x<<24) & 0xff000000)) +#define PLANB_PALETTE_MAX 15 static inline int overlay_is_active(struct planb *pb) { @@ -962,9 +894,10 @@ static int vgrab(struct planb *pb, struct video_mmap *mp) unsigned int fr = mp->frame; unsigned int format; - if(pb->fbuffer==NULL) { - if(fbuffer_alloc(pb)) - return -ENOBUFS; + if(pb->rawbuf==NULL) { + int err; + if((err=grabbuf_alloc(pb))) + return err; } IDEBUG("PlanB: grab %d: %dx%d(%u)\n", pb->grabbing, @@ -984,12 +917,10 @@ static int vgrab(struct planb *pb, struct video_mmap *mp) return -EINVAL; planb_lock(pb); - pb->gbuffer[fr] = (unsigned char *)(pb->fbuffer + PLANB_MAX_FBUF * fr); if(mp->width != pb->gwidth[fr] || mp->height != pb->gheight[fr] || format != pb->gfmt[fr] || (pb->gnorm_switch[fr])) { -#ifdef PLANB_GSCANLINE int i; -#else +#ifndef PLANB_GSCANLINE unsigned int osize = pb->gwidth[fr] * pb->gheight[fr] * pb->gfmt[fr]; unsigned int nsize = mp->width * mp->height * format; @@ -1001,10 +932,15 @@ static int vgrab(struct planb *pb, struct video_mmap *mp) #ifndef PLANB_GSCANLINE if(pb->gnorm_switch[fr]) nsize = 0; - if(nsize < osize) - memset((void *)(pb->gbuffer[fr] + nsize), 0, - osize - nsize); - memset((void *)pb->l_fr_addr[fr], 0, PAGE_SIZE * pb->lnum[fr]); + if (nsize < osize) { + for(i = pb->gbuf_idx[fr]; osize > 0; i++) { + memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); + osize -= PAGE_SIZE; + } + } + for(i = pb->l_fr_addr_idx[fr]; i < pb->l_fr_addr_idx[fr] + + pb->lnum[fr]; i++) + memset((void *)pb->rawbuf[i], 0, PAGE_SIZE); #else /* XXX TODO */ /* @@ -1228,7 +1164,7 @@ static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) unsigned long base; #endif unsigned long jump; - unsigned char *vaddr; + int pagei; volatile struct dbdma_cmd *c1; volatile struct dbdma_cmd *jump_addr; @@ -1277,11 +1213,12 @@ static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) /* even field data: */ - vaddr = pb->gbuffer[fr]; + pagei = pb->gbuf_idx[fr]; #ifdef PLANB_GSCANLINE for (i = 0; i < nlines; i += stepsize) { tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - vmalloc_to_bus(vaddr + i * scanline), jump); + virt_to_bus(pb->rawbuf[pagei + + i * scanline / PAGE_SIZE]), jump); } #else i = 0; @@ -1289,7 +1226,7 @@ static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) do { int j; - base = vmalloc_to_bus((void*)vaddr); + base = virt_to_bus(pb->rawbuf[pagei]); nlpp = (PAGE_SIZE - leftover1) / count / stepsize; for(j = 0; j < nlpp && i < nlines; j++, i += stepsize, c1++) tab_cmd_gen(c1, INPUT_MORE | KEY_STREAM0 | BR_IFSET, @@ -1304,11 +1241,13 @@ static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, base + count * nlpp * stepsize + leftover1, jump); } else { - pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count * nlpp - * stepsize + leftover1; + pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] + + count * nlpp * stepsize + leftover1; + pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; + pb->l_to_next_size[fr][pb->lnum[fr]] = count - lov0; tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE - * pb->lnum[fr]), jump); + virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] + + pb->lnum[fr]]), jump); if(++pb->lnum[fr] > MAX_LNUM) pb->lnum[fr]--; } @@ -1316,7 +1255,7 @@ static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) i += stepsize; } } - vaddr += PAGE_SIZE; + pagei++; } while(i < nlines); tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); c1 = jump_addr; @@ -1341,18 +1280,19 @@ static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) #ifdef PLANB_GSCANLINE for (i = 1; i < nlines; i += stepsize) { tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - vmalloc_to_bus(vaddr + i * scanline), jump); + virt_to_bus(pb->rawbuf[pagei + + i * scanline / PAGE_SIZE]), jump); } #else i = 1; leftover1 = 0; - vaddr = pb->gbuffer[fr]; + pagei = pb->gbuf_idx[fr]; if(nlines <= 1) goto skip; do { int j; - base = vmalloc_to_bus((void*)vaddr); + base = virt_to_bus(pb->rawbuf[pagei]); nlpp = (PAGE_SIZE - leftover1) / count / stepsize; if(leftover1 >= count) { tab_cmd_gen(c1++, INPUT_MORE | KEY_STREAM0 | BR_IFSET, count, @@ -1369,11 +1309,14 @@ static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) leftover1 = 0; else { if(lov0 > count) { - pb->l_to_addr[fr][pb->lnum[fr]] = vaddr + count - * (nlpp * stepsize + 1) + leftover1; + pb->l_to_addr[fr][pb->lnum[fr]] = pb->rawbuf[pagei] + + count * (nlpp * stepsize + 1) + leftover1; + pb->l_to_next_idx[fr][pb->lnum[fr]] = pagei + 1; + pb->l_to_next_size[fr][pb->lnum[fr]] = count * stepsize + - lov0; tab_cmd_gen(c1++, INPUT_MORE | BR_IFSET, count, - vmalloc_to_bus(pb->l_fr_addr[fr] + PAGE_SIZE - * pb->lnum[fr]), jump); + virt_to_bus(pb->rawbuf[pb->l_fr_addr_idx[fr] + + pb->lnum[fr]]), jump); if(++pb->lnum[fr] > MAX_LNUM) pb->lnum[fr]--; i += stepsize; @@ -1381,7 +1324,7 @@ static volatile struct dbdma_cmd *setup_grab_cmd(int fr, struct planb *pb) leftover1 = count * stepsize - lov0; } } - vaddr += PAGE_SIZE; + pagei++; } while(i < nlines); skip: tab_cmd_dbdma(c1, DBDMA_NOP | BR_ALWAYS, jump); @@ -1390,7 +1333,7 @@ skip: cmd_tab_data_end: tab_cmd_store(c1++, (unsigned)(&pb->planb_base_phys->intr_stat), - (fr << 2) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); + (fr << 9) | PLANB_FRM_IRQ | PLANB_GEN_IRQ); /* stop it */ tab_cmd_dbdma(c1, DBDMA_STOP, 0); @@ -1406,13 +1349,15 @@ static void planb_irq(int irq, void *dev_id, struct pt_regs * regs) IDEBUG("PlanB: planb_irq()\n"); /* get/clear interrupt status bits */ + eieio(); stat = in_le32(&pb->planb_base->intr_stat); astat = stat & pb->intr_mask; - out_le32(&pb->planb_base->intr_stat, PLANB_IRQ_CMD_MASK + out_le32(&pb->planb_base->intr_stat, PLANB_FRM_IRQ & ~astat & stat & ~PLANB_GEN_IRQ); + IDEBUG("PlanB: stat = %X, astat = %X\n", stat, astat); if(astat & PLANB_FRM_IRQ) { - unsigned int fr = stat >> 2; + unsigned int fr = stat >> 9; #ifndef PLANB_GSCANLINE int i; #endif @@ -1425,9 +1370,16 @@ static void planb_irq(int irq, void *dev_id, struct pt_regs * regs) #ifndef PLANB_GSCANLINE IDEBUG("PlanB: %d * %d bytes are being copied over\n", pb->lnum[fr], pb->lsize[fr]); - for(i = 0; i < pb->lnum[fr]; i++) - memcpy(pb->l_to_addr[fr][i], pb->l_fr_addr[fr] - + PAGE_SIZE * i, pb->lsize[fr]); + for(i = 0; i < pb->lnum[fr]; i++) { + int first = pb->lsize[fr] - pb->l_to_next_size[fr][i]; + + memcpy(pb->l_to_addr[fr][i], + pb->rawbuf[pb->l_fr_addr_idx[fr] + i], + first); + memcpy(pb->rawbuf[pb->l_to_next_idx[fr][i]], + pb->rawbuf[pb->l_fr_addr_idx[fr] + i] + first, + pb->l_to_next_size[fr][i]); + } #endif pb->frame_stat[fr] = GBUFFER_DONE; pb->grabbing--; @@ -1848,6 +1800,8 @@ chk_grab: IDEBUG("PlanB: waiting for grab" " done (%d)\n", i); interruptible_sleep_on(&pb->capq); + if(signal_pending(current)) + return -EINTR; goto chk_grab; case GBUFFER_DONE: pb->frame_stat[i] = GBUFFER_UNUSED; @@ -2058,38 +2012,27 @@ unimplemented: return 0; } -/* - * This maps the vmalloced and reserved fbuffer to user space. - * - * FIXME: - * - PAGE_READONLY should suffice!? - * - remap_page_range is kind of inefficient for page by page remapping. - * But e.g. pte_alloc() does not work in modules ... :-( - */ - static int planb_mmap(struct video_device *dev, const char *adr, unsigned long size) { - struct planb *pb=(struct planb *)dev; - unsigned long start=(unsigned long) adr; - unsigned long page; - void *pos; + int i; + struct planb *pb = (struct planb *)dev; + unsigned long start = (unsigned long)adr; - if (size>MAX_GBUFFERS*PLANB_MAX_FBUF) + if (size > MAX_GBUFFERS * PLANB_MAX_FBUF) return -EINVAL; - if (!pb->fbuffer) - { - if(fbuffer_alloc(pb)) - return -EINVAL; + if (!pb->rawbuf) { + int err; + if((err=grabbuf_alloc(pb))) + return err; } - pos = (void *)pb->fbuffer; - while (size > 0) - { - page = vmalloc_to_phys(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) - return -EAGAIN; - start+=PAGE_SIZE; - pos+=PAGE_SIZE; - size-=PAGE_SIZE; + for (i = 0; i < pb->rawbuf_size; i++) { + if (remap_page_range(start, virt_to_phys((void *)pb->rawbuf[i]), + PAGE_SIZE, PAGE_SHARED)) + return -EAGAIN; + start += PAGE_SIZE; + if (size <= PAGE_SIZE) + break; + size -= PAGE_SIZE; } return 0; } @@ -2125,6 +2068,7 @@ static int init_planb(struct planb *pb) { unsigned char saa_rev; int i, result; + unsigned long flags; memset ((void *) &pb->win, 0, sizeof (struct planb_window)); /* Simple sanity check */ @@ -2191,19 +2135,20 @@ static int init_planb(struct planb *pb) /* clear interrupt mask */ pb->intr_mask = PLANB_CLR_IRQ; + save_flags(flags); cli(); result = request_irq(pb->irq, planb_irq, 0, "PlanB", (void *)pb); - if (result==-EINVAL) { - printk(KERN_ERR "PlanB: Bad irq number (%d) or handler\n", - (int)pb->irq); - return result; - } - if (result==-EBUSY) { - printk(KERN_ERR "PlanB: I don't know why, but IRQ %d busy\n", - (int)pb->irq); - return result; - } - if (result < 0) - return result; + if (result < 0) { + if (result==-EINVAL) + printk(KERN_ERR "PlanB: Bad irq number (%d) " + "or handler\n", (int)pb->irq); + else if (result==-EBUSY) + printk(KERN_ERR "PlanB: I don't know why, " + "but IRQ %d is busy\n", (int)pb->irq); + restore_flags(flags); + return result; + } + disable_irq(pb->irq); + restore_flags(flags); /* Now add the template and register the device unit. */ memcpy(&pb->video_dev,&planb_template,sizeof(planb_template)); @@ -2218,24 +2163,25 @@ static int init_planb(struct planb *pb) pb->frame_stat=NULL; pb->capq=NULL; for(i=0; igbuffer[i]=NULL; + pb->gbuf_idx[i] = PLANB_MAX_FBUF * i / PAGE_SIZE; pb->gwidth[i]=0; pb->gheight[i]=0; pb->gfmt[i]=0; pb->cap_cmd[i]=NULL; #ifndef PLANB_GSCANLINE - pb->l_fr_addr[i]=NULL; + pb->l_fr_addr_idx[i] = MAX_GBUFFERS * (PLANB_MAX_FBUF + / PAGE_SIZE + 1) + MAX_LNUM * i; pb->lsize[i] = 0; pb->lnum[i] = 0; #endif } - pb->fbuffer=NULL; + pb->rawbuf=NULL; pb->grabbing=0; - /* clear interrupts */ + /* enable interrupts */ out_le32(&pb->planb_base->intr_stat, PLANB_CLR_IRQ); - /* set interrupt mask */ pb->intr_mask = PLANB_FRM_IRQ; + enable_irq(pb->irq); if(video_register_device(&pb->video_dev, VFL_TYPE_GRABBER)<0) return -1; diff --git a/drivers/char/planb.h b/drivers/char/planb.h index 716163f6c851..9d87cb8d6fe0 100644 --- a/drivers/char/planb.h +++ b/drivers/char/planb.h @@ -8,7 +8,7 @@ Based largely on the bttv driver by Ralph Metzler (rjkm@thp.uni-koeln.de) - Additional debugging and coding by Takashi Oe (toe@unlinfo.unl.edu) + Additional debugging and coding by Takashi Oe (toe@unlserve.unl.edu) This program is free software; you can redistribute it and/or modify @@ -69,6 +69,7 @@ /* for capture operations */ #define MAX_GBUFFERS 2 +/* note PLANB_MAX_FBUF must be divisible by PAGE_SIZE */ #ifdef PLANB_GSCANLINE #define PLANB_MAX_FBUF 0x240000 /* 576 * 1024 * 4 */ #define TAB_FACTOR (1) @@ -132,8 +133,7 @@ struct planb_registers { volatile unsigned int intr_stat; /* 0x104: irq status */ #define PLANB_CLR_IRQ 0x00 /* clear Plan B interrupt */ #define PLANB_GEN_IRQ 0x01 /* assert Plan B interrupt */ -#define PLANB_FRM_IRQ 0x02 /* end of frame */ -#define PLANB_IRQ_CMD_MASK 0x00000003U /* reserve 2 lsbs for command */ +#define PLANB_FRM_IRQ 0x0100 /* end of frame */ unsigned int pad3[1]; /* empty? */ volatile unsigned int reg5; /* 0x10c: ??? */ unsigned int pad4[60]; /* empty? */ @@ -199,8 +199,9 @@ struct planb { struct wait_queue *capq; int last_fr; int prev_last_fr; - unsigned char *fbuffer; - unsigned char *gbuffer[MAX_GBUFFERS]; + unsigned char **rawbuf; + int rawbuf_size; + int gbuf_idx[MAX_GBUFFERS]; volatile struct dbdma_cmd *cap_cmd[MAX_GBUFFERS]; volatile struct dbdma_cmd *last_cmd[MAX_GBUFFERS]; volatile struct dbdma_cmd *pre_cmd[MAX_GBUFFERS]; @@ -218,8 +219,10 @@ struct planb { #else #define MAX_LNUM 431 /* change this if PLANB_MAXLINES or */ /* PLANB_MAXPIXELS changes */ - unsigned char *l_fr_addr[MAX_GBUFFERS]; + int l_fr_addr_idx[MAX_GBUFFERS]; unsigned char *l_to_addr[MAX_GBUFFERS][MAX_LNUM]; + int l_to_next_idx[MAX_GBUFFERS][MAX_LNUM]; + int l_to_next_size[MAX_GBUFFERS][MAX_LNUM]; int lsize[MAX_GBUFFERS], lnum[MAX_GBUFFERS]; #endif }; diff --git a/drivers/char/rtc.c b/drivers/char/rtc.c index 2b38762b090e..52856483faf1 100644 --- a/drivers/char/rtc.c +++ b/drivers/char/rtc.c @@ -435,7 +435,7 @@ static int rtc_ioctl(struct inode *inode, struct file *file, unsigned int cmd, } #endif default: - return -EINVAL; + return -ENOTTY; } return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; } diff --git a/drivers/macintosh/mac_hid.c b/drivers/macintosh/mac_hid.c index 07b082715dc7..986c6cf98384 100644 --- a/drivers/macintosh/mac_hid.c +++ b/drivers/macintosh/mac_hid.c @@ -480,13 +480,13 @@ void __init mac_hid_init_hw(void) if (!keyboard_sends_linux_keycodes) { #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = mac_hid_kbd_sysrq_xlate; + ppc_md.sysrq_xlate = mac_hid_kbd_sysrq_xlate; SYSRQ_KEY = 0x69; #endif memcpy(key_maps, mac_key_maps_save, sizeof(key_maps)); } else { #ifdef CONFIG_MAGIC_SYSRQ - ppc_md.ppc_kbd_sysrq_xlate = pckbd_sysrq_xlate; + ppc_md.sysrq_xlate = pckbd_sysrq_xlate; SYSRQ_KEY = 0x54; #endif } diff --git a/drivers/net/zlib.c b/drivers/net/zlib.c index a8edce8edde1..af8427ecdd5a 100644 --- a/drivers/net/zlib.c +++ b/drivers/net/zlib.c @@ -14,7 +14,7 @@ */ /* - * ==FILEVERSION 971210== + * ==FILEVERSION 20020318== * * This marker is used by the Linux installation script to determine * whether an up-to-date version of this file is already installed. @@ -772,7 +772,7 @@ int deflateInit2_(strm, level, method, windowBits, memLevel, strategy, windowBits = -windowBits; } if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || - windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || + windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || strategy < 0 || strategy > Z_HUFFMAN_ONLY) { return Z_STREAM_ERROR; } @@ -3932,8 +3932,8 @@ int r; if (t != Z_OK) { if (t == (uInt)Z_DATA_ERROR) { - s->mode = BADB; ZFREE(z, s->sub.trees.blens); + s->mode = BADB; } r = t; LEAVE @@ -3948,6 +3948,7 @@ int r; r = Z_MEM_ERROR; LEAVE } + ZFREE(z, s->sub.trees.blens); s->sub.decode.codes = c; s->sub.decode.tl = tl; s->sub.decode.td = td; diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c index 15e362f2336c..83ff7c98b1e4 100644 --- a/drivers/scsi/3w-xxxx.c +++ b/drivers/scsi/3w-xxxx.c @@ -117,6 +117,21 @@ 1.02.00.014 - Fix bug in tw_findcards() where AEN code could be lost. Increase timeout in tw_aen_drain_queue() to 30 seconds. 1.02.00.015 - Re-write raw command post with data ioctl method. + 1.02.00.016 - Modified pci parity error handling/clearing from config space + during initialization. + 1.02.00.017 - Better handling of request sense opcode and sense information + for failed commands. Add tw_decode_sense(). + Replace all mdelay()'s with scsi_sleep(). + 1.02.00.018 - Revert mdelay's and scsi_sleep's, this caused problems on + some SMP systems. + 1.02.00.019 - Bump cmd_per_lun in SHT to 255 for better jbod performance. + Improve handling of errors in tw_interrupt(). + Add handling/clearing of controller queue error. + Better alignment checking in tw_allocate_memory(). + Cleanup tw_initialize_device_extension(). + Empty stale responses before draining aen queue. + Fix tw_scsi_eh_abort() to not reset on every io abort. + Set can_queue in SHT to 255 to prevent hang from AEN. */ #include @@ -168,7 +183,7 @@ struct proc_dir_entry tw_scsi_proc_entry = { }; /* Globals */ -char *tw_driver_version="1.02.00.015"; +char *tw_driver_version="1.02.00.019"; TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT]; int tw_device_extension_count = 0; @@ -269,6 +284,9 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev) } tw_clear_attention_interrupt(tw_dev); + /* Empty response queue */ + tw_empty_response_que(tw_dev); + /* Initialize command packet */ if (tw_dev->command_packet_virtual_address[request_id] == NULL) { printk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad command packet virtual address.\n"); @@ -322,7 +340,7 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev) status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 0); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { @@ -338,8 +356,7 @@ int tw_aen_drain_queue(TW_Device_Extension *tw_dev) if (command_packet->status != 0) { if (command_packet->flags != TW_AEN_TABLE_UNDEFINED) { /* Bad response */ - dprintk(KERN_WARNING "3w-xxxx: tw_aen_drain_queue(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); + tw_decode_sense(tw_dev, request_id, 0); return 1; } else { /* We know this is a 3w-1x00, and doesn't support aen's */ @@ -437,7 +454,7 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id) status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_aen_read_queue(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 1); return 1; } if (tw_dev->command_packet_virtual_address[request_id] == NULL) { @@ -504,9 +521,9 @@ int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, in return 1; } - if ((u32)virt_addr % TW_ALIGNMENT) { + if ((u32)virt_addr % (tw_dev->tw_pci_dev->device == TW_DEVICE_ID ? TW_ALIGNMENT_6000 : TW_ALIGNMENT_7000)) { kfree(virt_addr); - printk(KERN_WARNING "3w-xxxx: tw_allocate_memory(): Found unaligned address.\n"); + printk(KERN_WARNING "3w-xxxx: Couldn't allocate correctly aligned memory.\n"); return 1; } switch(which) { @@ -553,12 +570,24 @@ int tw_check_errors(TW_Device_Extension *tw_dev) status_reg_addr = tw_dev->registers.status_reg_addr; status_reg_value = inl(status_reg_addr); - if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) + if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) { + tw_decode_bits(tw_dev, status_reg_value, 0); return 1; + } return 0; } /* End tw_check_errors() */ +/* This function will clear all interrupts on the controller */ +void tw_clear_all_interrupts(TW_Device_Extension *tw_dev) +{ + u32 control_reg_addr, control_reg_value; + + control_reg_addr = tw_dev->registers.control_reg_addr; + control_reg_value = TW_STATUS_VALID_INTERRUPT; + outl(control_reg_value, control_reg_addr); +} /* End tw_clear_all_interrupts() */ + /* This function will clear the attention interrupt */ void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev) { @@ -613,48 +642,91 @@ static void tw_copy_mem_info(TW_Info *info, char *data, int len) } } /* End tw_copy_mem_info() */ -/* This function will print readable messages from statsu register errors */ -void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value) +/* This function will print readable messages from status register errors */ +int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host) { + char host[16]; + dprintk(KERN_WARNING "3w-xxxx: tw_decode_bits()\n"); + + if (print_host) + sprintf(host, " scsi%d:", tw_dev->host->host_no); + else + host[0] = '\0'; + switch (status_reg_value & TW_STATUS_UNEXPECTED_BITS) { case TW_STATUS_PCI_PARITY_ERROR: - printk(KERN_WARNING "3w-xxxx: PCI Parity Error: Reseat card, move card, or buggy device on the bus.\n"); + printk(KERN_WARNING "3w-xxxx:%s PCI Parity Error: clearing.\n", host); outl(TW_CONTROL_CLEAR_PARITY_ERROR, tw_dev->registers.control_reg_addr); - pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PARITY_ERRORS); break; case TW_STATUS_MICROCONTROLLER_ERROR: - printk(KERN_WARNING "3w-xxxx: Microcontroller Error.\n"); - break; + if (tw_dev->reset_print == 0) { + printk(KERN_WARNING "3w-xxxx:%s Microcontroller Error: clearing.\n", host); + tw_dev->reset_print = 1; + } + return 1; case TW_STATUS_PCI_ABORT: - printk(KERN_WARNING "3w-xxxx: PCI Abort: clearing.\n"); + printk(KERN_WARNING "3w-xxxx:%s PCI Abort: clearing.\n", host); outl(TW_CONTROL_CLEAR_PCI_ABORT, tw_dev->registers.control_reg_addr); pci_write_config_word(tw_dev->tw_pci_dev, PCI_STATUS, TW_PCI_CLEAR_PCI_ABORT); break; + case TW_STATUS_QUEUE_ERROR: + printk(KERN_WARNING "3w-xxxx:%s Controller Queue Error: clearing.\n", host); + outl(TW_CONTROL_CLEAR_QUEUE_ERROR, tw_dev->registers.control_reg_addr); + break; + case TW_STATUS_SBUF_WRITE_ERROR: + printk(KERN_WARNING "3w-xxxx:%s SBUF Write Error: clearing.\n", host); + outl(TW_CONTROL_CLEAR_SBUF_WRITE_ERROR, tw_dev->registers.control_reg_addr); + break; } + + return 0; } /* End tw_decode_bits() */ -/* This function will print readable messages from flags and status values */ -void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit) +/* This function will return valid sense buffer information for failed cmds */ +int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense) { - dprintk(KERN_WARNING "3w-xxxx: tw_decode_error()\n"); - switch (status) { - case 0xc7: - switch (flags) { - case 0x1b: - printk(KERN_WARNING "3w-xxxx: scsi%d: Drive timeout on unit %d, check drive and drive cables.\n", tw_dev->host->host_no, unit); - break; - case 0x51: - printk(KERN_WARNING "3w-xxxx: scsi%d: Unrecoverable drive error on unit %d, check/replace cabling, or possible bad drive.\n", tw_dev->host->host_no, unit); - break; - default: - printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit); + int i; + TW_Command *command; + + dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n"); + command = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; + + printk(KERN_WARNING "3w-xxxx: scsi%d: Command failed: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, command->status, command->flags, command->byte3.unit); + + /* Attempt to return intelligent sense information */ + if (fill_sense) { + if ((command->status == 0xc7) || (command->status == 0xcb)) { + for (i=0;i<(sizeof(tw_sense_table)/sizeof(tw_sense_table[0]));i++) { + if (command->flags == tw_sense_table[i][0]) { + + /* Valid bit and 'current errors' */ + tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70); + + /* Sense key */ + tw_dev->srb[request_id]->sense_buffer[2] = tw_sense_table[i][1]; + + /* Additional sense length */ + tw_dev->srb[request_id]->sense_buffer[7] = 0xa; /* 10 bytes */ + + /* Additional sense code */ + tw_dev->srb[request_id]->sense_buffer[12] = tw_sense_table[i][2]; + + /* Additional sense code qualifier */ + tw_dev->srb[request_id]->sense_buffer[13] = tw_sense_table[i][3]; + + tw_dev->srb[request_id]->result = (DID_OK << 16) | (CHECK_CONDITION << 1); + return TW_ISR_DONT_RESULT; /* Special case for isr to not over-write result */ + } + } } - break; - default: - printk(KERN_WARNING "3w-xxxx: scsi%d: Controller error: status = 0x%x, flags = 0x%x, unit #%d.\n", tw_dev->host->host_no, status, flags, unit); + + /* If no table match, error so we get a reset */ + return 1; } -} /* End tw_decode_error() */ + + return 0; +} /* End tw_decode_sense() */ /* This function will disable interrupts on the controller */ void tw_disable_interrupts(TW_Device_Extension *tw_dev) @@ -667,7 +739,7 @@ void tw_disable_interrupts(TW_Device_Extension *tw_dev) } /* End tw_disable_interrupts() */ /* This function will empty the response que */ -int tw_empty_response_que(TW_Device_Extension *tw_dev) +void tw_empty_response_que(TW_Device_Extension *tw_dev) { u32 status_reg_addr, status_reg_value; u32 response_que_addr, response_que_value; @@ -677,22 +749,10 @@ int tw_empty_response_que(TW_Device_Extension *tw_dev) status_reg_value = inl(status_reg_addr); - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 1.\n"); - tw_decode_bits(tw_dev, status_reg_value); - return 1; - } - while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { response_que_value = inl(response_que_addr); status_reg_value = inl(status_reg_addr); - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_empty_response_queue(): Unexpected bits 2.\n"); - tw_decode_bits(tw_dev, status_reg_value); - return 1; - } } - return 0; } /* End tw_empty_response_que() */ /* This function will enable interrupts on the controller */ @@ -743,6 +803,9 @@ int tw_findcards(Scsi_Host_Template *tw_host) } memset(tw_dev, 0, sizeof(TW_Device_Extension)); + /* Save pci_dev struct to device extension */ + tw_dev->tw_pci_dev = tw_pci_dev; + error = tw_initialize_device_extension(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize device extension for card %d.\n", numcards); @@ -757,13 +820,11 @@ int tw_findcards(Scsi_Host_Template *tw_host) tw_dev->registers.status_reg_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x4); tw_dev->registers.command_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0x8); tw_dev->registers.response_que_addr = ((tw_pci_dev->base_address[0] & ~15) + 0xC); - /* Save pci_dev struct to device extension */ - tw_dev->tw_pci_dev = tw_pci_dev; /* Check for errors and clear them */ status_reg_value = inl(tw_dev->registers.status_reg_addr); if (TW_STATUS_ERRORS(status_reg_value)) - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 0); /* Poll status register for 60 secs for 'Controller Ready' flag */ if (tw_poll_status(tw_dev, TW_STATUS_MICROCONTROLLER_READY, 60)) { @@ -779,7 +840,7 @@ int tw_findcards(Scsi_Host_Template *tw_host) while (tries < TW_MAX_RESET_TRIES) { /* Do soft reset */ tw_soft_reset(tw_dev); - + error = tw_aen_drain_queue(tw_dev); if (error) { printk(KERN_WARNING "3w-xxxx: AEN drain failed for card %d.\n", numcards); @@ -794,14 +855,6 @@ int tw_findcards(Scsi_Host_Template *tw_host) continue; } - /* Empty the response queue */ - error = tw_empty_response_que(tw_dev); - if (error) { - printk(KERN_WARNING "3w-xxxx: Couldn't empty response queue, retrying for card %d.\n", numcards); - tries++; - continue; - } - /* Now the controller is in a good state */ break; } @@ -828,7 +881,7 @@ int tw_findcards(Scsi_Host_Template *tw_host) request_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE, TW_DEVICE_NAME); error = tw_initialize_units(tw_dev); if (error) { - printk(KERN_WARNING "3w-xxxx: tw_findcards(): Couldn't initialize units for card %d.\n", numcards); + printk(KERN_WARNING "3w-xxxx: No valid units for card %d.\n", numcards); release_region((tw_dev->tw_pci_dev->base_address[0]), TW_IO_ADDRESS_RANGE); tw_free_device_extension(tw_dev); kfree(tw_dev); @@ -852,7 +905,7 @@ int tw_findcards(Scsi_Host_Template *tw_host) tw_dev->free_tail = TW_MAX_BOUNCEBUF - 1; tw_dev->free_wrap = TW_MAX_BOUNCEBUF - 1; } else { - tw_host->cmd_per_lun = (TW_Q_LENGTH-1)/tw_dev->num_units; + /* Use SHT cmd_per_lun here */ tw_dev->free_head = TW_Q_START; tw_dev->free_tail = TW_Q_LENGTH - 1; tw_dev->free_wrap = TW_Q_LENGTH - 1; @@ -1015,7 +1068,7 @@ int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 0); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { @@ -1028,8 +1081,7 @@ int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) } if (command_packet->status != 0) { /* bad response */ - dprintk(KERN_WARNING "3w-xxxx: tw_initconnection(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); + tw_decode_sense(tw_dev, request_id, 0); return 1; } break; /* Response was okay, so we exit */ @@ -1041,12 +1093,11 @@ int tw_initconnection(TW_Device_Extension *tw_dev, int message_credits) /* This function will initialize the fields of a device extension */ int tw_initialize_device_extension(TW_Device_Extension *tw_dev) { - int i, imax; + int i; dprintk(KERN_NOTICE "3w-xxxx: tw_initialize_device_extension()\n"); - imax = TW_Q_LENGTH; - for (i=0; icommand_packet_virtual_address[i] == NULL) { @@ -1065,33 +1116,12 @@ int tw_initialize_device_extension(TW_Device_Extension *tw_dev) tw_dev->free_queue[i] = i; tw_dev->state[i] = TW_S_INITIAL; - tw_dev->ioctl_size[i] = 0; - tw_dev->aen_queue[i] = 0; - tw_dev->ioctl_data[i] = NULL; - } - - for (i=0;iis_unit_present[i] = 0; - tw_dev->is_raid_five[i] = 0; } - tw_dev->num_units = 0; - tw_dev->num_aborts = 0; - tw_dev->num_resets = 0; - tw_dev->posted_request_count = 0; - tw_dev->max_posted_request_count = 0; - tw_dev->max_sgl_entries = 0; - tw_dev->sgl_entries = 0; - tw_dev->host = NULL; tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; - tw_dev->aen_head = 0; - tw_dev->aen_tail = 0; - tw_dev->sector_count = 0; - tw_dev->max_sector_count = 0; - tw_dev->aen_count = 0; - tw_dev->num_raid_five = 0; spin_lock_init(&tw_dev->tw_lock); + return 0; } /* End tw_initialize_device_extension() */ @@ -1168,7 +1198,7 @@ int tw_initialize_units(TW_Device_Extension *tw_dev) status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 0); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { @@ -1181,8 +1211,7 @@ int tw_initialize_units(TW_Device_Extension *tw_dev) } if (command_packet->status != 0) { /* bad response */ - dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); + tw_decode_sense(tw_dev, request_id, 0); return 1; } found = 1; @@ -1272,7 +1301,7 @@ int tw_initialize_units(TW_Device_Extension *tw_dev) status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 0); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { @@ -1285,8 +1314,7 @@ int tw_initialize_units(TW_Device_Extension *tw_dev) } if (command_packet->status != 0) { /* bad response */ - dprintk(KERN_WARNING "3w-xxxx: tw_initialize_units(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); + tw_decode_sense(tw_dev, request_id, 0); return 1; } found = 1; @@ -1332,44 +1360,52 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) u32 response_que_addr; TW_Device_Extension *tw_dev = (TW_Device_Extension *)dev_instance; TW_Response_Queue response_que; - int error = 0; - int do_response_interrupt=0; - int do_attention_interrupt=0; - int do_host_interrupt=0; - int do_command_interrupt=0; + int error = 0, retval = 0; unsigned long flags = 0; TW_Command *command_packet; + + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n"); + + /* See if we are already running on another processor */ + if (test_and_set_bit(TW_IN_INTR, &tw_dev->flags)) + return; + + /* Get the block layer lock for io completions */ spin_lock_irqsave(&io_request_lock, flags); + /* See if the interrupt matches this instance */ if (tw_dev->tw_pci_dev->irq == irq) { + + /* Make sure io isn't queueing */ spin_lock(&tw_dev->tw_lock); - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt()\n"); /* Read the registers */ status_reg_addr = tw_dev->registers.status_reg_addr; response_que_addr = tw_dev->registers.response_que_addr; status_reg_value = inl(status_reg_addr); - /* Check which interrupt */ - if (status_reg_value & TW_STATUS_HOST_INTERRUPT) - do_host_interrupt=1; - if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) - do_attention_interrupt=1; - if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) - do_command_interrupt=1; - if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) - do_response_interrupt=1; + /* Check if this is our interrupt, otherwise bail */ + if (!(status_reg_value & TW_STATUS_VALID_INTERRUPT)) + goto tw_interrupt_bail; + + /* Check controller for errors */ + if (tw_check_bits(status_reg_value)) { + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); + if (tw_decode_bits(tw_dev, status_reg_value, 1)) { + tw_clear_all_interrupts(tw_dev); + goto tw_interrupt_bail; + } + } /* Handle host interrupt */ - if (do_host_interrupt) { + if (status_reg_value & TW_STATUS_HOST_INTERRUPT) { dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received host interrupt.\n"); tw_clear_host_interrupt(tw_dev); } /* Handle attention interrupt */ - if (do_attention_interrupt) { + if (status_reg_value & TW_STATUS_ATTENTION_INTERRUPT) { dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Received attention interrupt.\n"); - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Clearing attention interrupt.\n"); tw_clear_attention_interrupt(tw_dev); tw_state_request_start(tw_dev, &request_id); error = tw_aen_read_queue(tw_dev, request_id); @@ -1381,7 +1417,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) } /* Handle command interrupt */ - if (do_command_interrupt) { + if (status_reg_value & TW_STATUS_COMMAND_INTERRUPT) { /* Drain as many pending commands as we can */ while (tw_dev->pending_request_count > 0) { request_id = tw_dev->pending_queue[tw_dev->pending_head]; @@ -1397,6 +1433,7 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) } tw_dev->pending_request_count--; } else { + printk(KERN_WARNING "3w-xxxx: scsi%d: Error posting pending commands.\n", tw_dev->host->host_no); break; } } @@ -1406,40 +1443,41 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) } /* Handle response interrupt */ - if (do_response_interrupt) { + if (status_reg_value & TW_STATUS_RESPONSE_INTERRUPT) { /* Drain the response queue from the board */ while ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { + /* Read response queue register */ response_que.value = inl(response_que_addr); request_id = response_que.u.response_id; command_packet = (TW_Command *)tw_dev->command_packet_virtual_address[request_id]; error = 0; + + /* Check for bad response */ if (command_packet->status != 0) { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Bad response, status = 0x%x, flags = 0x%x, unit = 0x%x.\n", command_packet->status, command_packet->flags, command_packet->byte3.unit); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); - error = 1; + /* If internal commands, don't error, don't fill sense */ + if (tw_dev->srb[request_id] == 0) { + tw_decode_sense(tw_dev, request_id, 0); + } else { + error = tw_decode_sense(tw_dev, request_id, 1); + } } + + /* Check for correct state */ if (tw_dev->state[request_id] != TW_S_POSTED) { printk(KERN_WARNING "3w-xxxx: scsi%d: Received a request id (%d) (opcode = 0x%x) that wasn't posted.\n", tw_dev->host->host_no, request_id, command_packet->byte0.opcode); error = 1; } - if (TW_STATUS_ERRORS(status_reg_value)) { - tw_decode_bits(tw_dev, status_reg_value); - error = 1; - } + dprintk(KERN_NOTICE "3w-xxxx: tw_interrupt(): Response queue request id: %d.\n", request_id); - /* Check for internal command */ + + /* Check for internal command completion */ if (tw_dev->srb[request_id] == 0) { dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Found internally posted command.\n"); - error = tw_aen_complete(tw_dev, request_id); - if (error) { + retval = tw_aen_complete(tw_dev, request_id); + if (retval) { printk(KERN_WARNING "3w-xxxx: scsi%d: Error completing aen.\n", tw_dev->host->host_no); } - status_reg_value = inl(status_reg_addr); - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); - } - } else { + } else { switch (tw_dev->srb[request_id]->cmnd[0]) { case READ_10: case READ_6: @@ -1462,36 +1500,47 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs) error = tw_ioctl_complete(tw_dev, request_id); break; default: - printk(KERN_WARNING "3w-xxxx: scsi%d: Unknown scsi opcode: 0x%x.\n", tw_dev->host->host_no, tw_dev->srb[request_id]->cmnd[0]); - tw_dev->srb[request_id]->result = (DID_BAD_TARGET << 16); - tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); - } - if (error == 1) { - /* Tell scsi layer there was an error */ - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Scsi Error.\n"); - tw_dev->srb[request_id]->result = (DID_RESET << 16); + printk(KERN_WARNING "3w-xxxx: case slip in tw_interrupt()\n"); + error = 1; } + + /* If no error command was a success */ if (error == 0) { - /* Tell scsi layer command was a success */ tw_dev->srb[request_id]->result = (DID_OK << 16); } - if (error != 2) { + + /* If error, command failed */ + if (error == 1) { + tw_dev->srb[request_id]->result = (DID_RESET << 16); + } + + /* Now complete the io */ + if ((error != TW_ISR_DONT_COMPLETE)) { tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); tw_dev->posted_request_count--; tw_dev->srb[request_id]->scsi_done(tw_dev->srb[request_id]); } - status_reg_value = inl(status_reg_addr); - if (tw_check_bits(status_reg_value)) { - dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + } + + /* Check for valid status after each drain */ + status_reg_value = inl(status_reg_addr); + if (tw_check_bits(status_reg_value)) { + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt(): Unexpected bits.\n"); + if (tw_decode_bits(tw_dev, status_reg_value, 1)) { + tw_clear_all_interrupts(tw_dev); + goto tw_interrupt_bail; } } } } +tw_interrupt_bail: spin_unlock(&tw_dev->tw_lock); - } + } else + dprintk(KERN_WARNING "3w-xxxx: tw_interrupt() called for wrong instance.\n"); + spin_unlock_irqrestore(&io_request_lock, flags); + clear_bit(TW_IN_INTR, &tw_dev->flags); } /* End tw_interrupt() */ /* This function handles ioctls from userspace to the driver */ @@ -1851,7 +1900,7 @@ int tw_ioctl_complete(TW_Device_Extension *tw_dev, int request_id) break; case TW_CMD_PACKET_WITH_DATA: dprintk(KERN_WARNING "3w-xxxx: tw_ioctl_complete(): caught TW_CMD_PACKET_WITH_DATA.\n"); - return 2; /* Special case for isr to not complete io */ + return TW_ISR_DONT_COMPLETE; /* Special case for isr to not complete io */ default: memset(buff, 0, tw_dev->srb[request_id]->request_bufflen); param = (TW_Param *)tw_dev->alignment_virtual_address[request_id]; @@ -1885,14 +1934,25 @@ int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds) do_gettimeofday(&before); status_reg_value = inl(status_reg_addr); + if (tw_check_bits(status_reg_value)) { + dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n"); + tw_decode_bits(tw_dev, status_reg_value, 0); + } + while ((status_reg_value & flag) != flag) { status_reg_value = inl(status_reg_addr); + + if (tw_check_bits(status_reg_value)) { + dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Unexpected bits.\n"); + tw_decode_bits(tw_dev, status_reg_value, 0); + } + do_gettimeofday(&timeout); if (before.tv_sec + seconds < timeout.tv_sec) { dprintk(KERN_WARNING "3w-xxxx: tw_poll_status(): Flag 0x%x not found.\n", flag); return 1; } - mdelay(1); + mdelay(5); } return 0; } /* End tw_poll_status() */ @@ -1911,7 +1971,7 @@ int tw_post_command_packet(TW_Device_Extension *tw_dev, int request_id) if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_post_command_packet(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 1); } if ((status_reg_value & TW_STATUS_COMMAND_QUEUE_FULL) == 0) { @@ -1982,6 +2042,7 @@ int tw_reset_device_extension(TW_Device_Extension *tw_dev) tw_dev->pending_request_count = 0; tw_dev->pending_head = TW_Q_START; tw_dev->pending_tail = TW_Q_START; + tw_dev->reset_print = 0; return 0; } /* End tw_reset_device_extension() */ @@ -2013,14 +2074,6 @@ int tw_reset_sequence(TW_Device_Extension *tw_dev) continue; } - /* Empty the response queue again */ - error = tw_empty_response_que(tw_dev); - if (error) { - printk(KERN_WARNING "3w-xxxx: scsi%d: Couldn't empty response queue, retrying.\n", tw_dev->host->host_no); - tries++; - continue; - } - /* Now the controller is in a good state */ break; } @@ -2110,11 +2163,6 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt) return (FAILED); } - /* We have to let AEN requests through before the reset */ - spin_unlock_irq(&io_request_lock); - mdelay(TW_AEN_WAIT_TIME); - spin_lock_irq(&io_request_lock); - spin_lock(&tw_dev->tw_lock); tw_dev->num_aborts++; @@ -2141,18 +2189,26 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt) spin_unlock(&tw_dev->tw_lock); return (SUCCESS); } + if (tw_dev->state[i] == TW_S_POSTED) { + /* If the command has already been posted, we have to reset the card */ + printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt); + /* We have to let AEN requests through before the reset */ + spin_unlock(&tw_dev->tw_lock); + spin_unlock_irq(&io_request_lock); + mdelay(TW_AEN_WAIT_TIME); + spin_lock_irq(&io_request_lock); + spin_lock(&tw_dev->tw_lock); + + if (tw_reset_device_extension(tw_dev)) { + dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no); + spin_unlock(&tw_dev->tw_lock); + return (FAILED); + } + } } } - /* If the command has already been posted, we have to reset the card */ - printk(KERN_WARNING "3w-xxxx: scsi%d: Command (0x%x) timed out, resetting card.\n", tw_dev->host->host_no, (u32)SCpnt); - if (tw_reset_device_extension(tw_dev)) { - dprintk(KERN_WARNING "3w-xxxx: tw_scsi_eh_abort(): Reset failed for card %d.\n", tw_dev->host->host_no); - spin_unlock(&tw_dev->tw_lock); - return (FAILED); - } spin_unlock(&tw_dev->tw_lock); - return (SUCCESS); } /* End tw_scsi_eh_abort() */ @@ -2618,7 +2674,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) } command_packet->byte0.sgl_offset = 3; - command_packet->size = 5; + command_packet->size = 3; command_packet->request_id = request_id; command_packet->byte3.unit = srb->target; command_packet->byte3.host_id = 0; @@ -2654,6 +2710,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_read_write(): SG = 0\n"); command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->srb[request_id]->request_buffer); command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen; + command_packet->size+=2; } /* Do this if we have multiple sg list entries */ @@ -2663,8 +2720,6 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) command_packet->byte8.io.sgl[i].length = sglist[i].length; command_packet->size+=2; } - if (tw_dev->srb[request_id]->use_sg >= 1) - command_packet->size-=2; } } else { /* Do this if there are no sg list entries for raid 5 */ @@ -2673,6 +2728,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id) memcpy(tw_dev->bounce_buffer[request_id], tw_dev->srb[request_id]->request_buffer, tw_dev->srb[request_id]->request_bufflen); command_packet->byte8.io.sgl[0].address = virt_to_bus(tw_dev->bounce_buffer[request_id]); command_packet->byte8.io.sgl[0].length = tw_dev->srb[request_id]->request_bufflen; + command_packet->size+=2; } /* Do this if we have multiple sg list entries for raid 5 */ @@ -2711,7 +2767,7 @@ int tw_scsiop_request_sense(TW_Device_Extension *tw_dev, int request_id) { dprintk(KERN_NOTICE "3w-xxxx: tw_scsiop_request_sense()\n"); - /* For now we just zero the sense buffer */ + /* For now we just zero the request buffer */ memset(tw_dev->srb[request_id]->request_buffer, 0, tw_dev->srb[request_id]->request_bufflen); tw_dev->state[request_id] = TW_S_COMPLETED; tw_state_request_finish(tw_dev, request_id); @@ -2801,7 +2857,7 @@ int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, status_reg_value = inl(status_reg_addr); if (tw_check_bits(status_reg_value)) { dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Unexpected bits.\n"); - tw_decode_bits(tw_dev, status_reg_value); + tw_decode_bits(tw_dev, status_reg_value, 1); return 1; } if ((status_reg_value & TW_STATUS_RESPONSE_QUEUE_EMPTY) == 0) { @@ -2814,8 +2870,7 @@ int tw_setfeature(TW_Device_Extension *tw_dev, int parm, int param_size, } if (command_packet->status != 0) { /* bad response */ - dprintk(KERN_WARNING "3w-xxxx: tw_setfeature(): Bad response, status = 0x%x, flags = 0x%x.\n", command_packet->status, command_packet->flags); - tw_decode_error(tw_dev, command_packet->status, command_packet->flags, command_packet->byte3.unit); + tw_decode_sense(tw_dev, request_id, 0); return 1; } break; /* Response was okay, so we exit */ diff --git a/drivers/scsi/3w-xxxx.h b/drivers/scsi/3w-xxxx.h index 21ad360e6057..75f28edaba82 100644 --- a/drivers/scsi/3w-xxxx.h +++ b/drivers/scsi/3w-xxxx.h @@ -92,10 +92,35 @@ static char *tw_aen_string[] = { "Verify failed: Port #", // 0x02A "Verify complete: Unit #", // 0x02B "Overwrote bad sector during rebuild: Port #", //0x2C - "Encountered bad sector during rebuild: Port #" //0x2D + "Encountered bad sector during rebuild: Port #", //0x2D + "Replacement drive is too small: Port #" //0x2E }; -#define TW_AEN_STRING_MAX 0x02E +#define TW_AEN_STRING_MAX 0x02F + +/* + Sense key lookup table + Format: ESDC/flags,SenseKey,AdditionalSenseCode,AdditionalSenseCodeQualifier +*/ +static unsigned char tw_sense_table[][4] = +{ + /* Codes for newer firmware */ + // ATA Error SCSI Error + {0x01, 0x03, 0x13, 0x00}, // Address mark not found Address mark not found for data field + {0x04, 0x0b, 0x00, 0x00}, // Aborted command Aborted command + {0x10, 0x0b, 0x14, 0x00}, // ID not found Recorded entity not found + {0x40, 0x03, 0x11, 0x00}, // Uncorrectable ECC error Unrecovered read error + {0x61, 0x04, 0x00, 0x00}, // Device fault Hardware error + {0x84, 0x0b, 0x47, 0x00}, // Data CRC error SCSI parity error + {0xd0, 0x0b, 0x00, 0x00}, // Device busy Aborted command + {0xd1, 0x0b, 0x00, 0x00}, // Device busy Aborted command + + /* Codes for older firmware */ + // 3ware Error SCSI Error + {0x09, 0x0b, 0x00, 0x00}, // Unrecovered disk error Aborted command + {0x37, 0x0b, 0x04, 0x00}, // Unit offline Logical unit not ready + {0x51, 0x0b, 0x00, 0x00} // Unspecified Aborted command +}; /* Control register bit definitions */ #define TW_CONTROL_CLEAR_HOST_INTERRUPT 0x00080000 @@ -110,7 +135,9 @@ static char *tw_aen_string[] = { #define TW_CONTROL_DISABLE_INTERRUPTS 0x00000040 #define TW_CONTROL_ISSUE_HOST_INTERRUPT 0x00000020 #define TW_CONTROL_CLEAR_PARITY_ERROR 0x00800000 +#define TW_CONTROL_CLEAR_QUEUE_ERROR 0x00400000 #define TW_CONTROL_CLEAR_PCI_ABORT 0x00100000 +#define TW_CONTROL_CLEAR_SBUF_WRITE_ERROR 0x00000008 /* Status register bit definitions */ #define TW_STATUS_MAJOR_VERSION_MASK 0xF0000000 @@ -130,7 +157,9 @@ static char *tw_aen_string[] = { #define TW_STATUS_ALL_INTERRUPTS 0x000F0000 #define TW_STATUS_CLEARABLE_BITS 0x00D00000 #define TW_STATUS_EXPECTED_BITS 0x00002000 -#define TW_STATUS_UNEXPECTED_BITS 0x00F80000 +#define TW_STATUS_UNEXPECTED_BITS 0x00F00008 +#define TW_STATUS_SBUF_WRITE_ERROR 0x00000008 +#define TW_STATUS_VALID_INTERRUPT 0x00DF0008 /* RESPONSE QUEUE BIT DEFINITIONS */ #define TW_RESPONSE_ID_MASK 0x00000FF0 @@ -174,7 +203,8 @@ static char *tw_aen_string[] = { #define TW_AEN_SBUF_FAIL 0x0024 /* Misc defines */ -#define TW_ALIGNMENT 0x200 /* 16 D-WORDS */ +#define TW_ALIGNMENT_6000 64 /* 64 bytes */ +#define TW_ALIGNMENT_7000 4 /* 4 bytes */ #define TW_MAX_UNITS 16 #define TW_COMMAND_ALIGNMENT_MASK 0x1ff #define TW_INIT_MESSAGE_CREDITS 0x100 @@ -190,7 +220,7 @@ static char *tw_aen_string[] = { #define TW_MAX_PCI_BUSES 255 #define TW_MAX_RESET_TRIES 3 #define TW_UNIT_INFORMATION_TABLE_BASE 0x300 -#define TW_MAX_CMDS_PER_LUN (TW_Q_LENGTH-2)/TW_MAX_UNITS +#define TW_MAX_CMDS_PER_LUN 255 #define TW_BLOCK_SIZE 0x200 /* 512-byte blocks */ #define TW_IOCTL 0x80 #define TW_MAX_AEN_TRIES 100 @@ -199,6 +229,8 @@ static char *tw_aen_string[] = { #define TW_MAX_SECTORS 128 #define TW_AEN_WAIT_TIME 1000 #define TW_IOCTL_WAIT_TIME (1 * HZ) /* 1 second */ +#define TW_ISR_DONT_COMPLETE 2 +#define TW_ISR_DONT_RESULT 3 /* Macros */ #define TW_STATUS_ERRORS(x) \ @@ -211,7 +243,7 @@ static char *tw_aen_string[] = { #ifdef TW_DEBUG #define dprintk(msg...) printk(msg) #else -#define dprintk(msg...) do { } while(0); +#define dprintk(msg...) do { } while(0) #endif extern struct proc_dir_entry tw_scsi_proc_entry; @@ -384,8 +416,9 @@ typedef struct TAG_TW_Device_Extension { unsigned short aen_queue[TW_Q_LENGTH]; unsigned char aen_head; unsigned char aen_tail; - u32 flags; + volatile long flags; char *ioctl_data[TW_Q_LENGTH]; + int reset_print; } TW_Device_Extension; /* Function prototypes */ @@ -395,12 +428,13 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id); int tw_allocate_memory(TW_Device_Extension *tw_dev, int request_id, int size, int which); int tw_check_bits(u32 status_reg_value); int tw_check_errors(TW_Device_Extension *tw_dev); +void tw_clear_all_interrupts(TW_Device_Extension *tw_dev); void tw_clear_attention_interrupt(TW_Device_Extension *tw_dev); void tw_clear_host_interrupt(TW_Device_Extension *tw_dev); -void tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value); -void tw_decode_error(TW_Device_Extension *tw_dev, unsigned char status, unsigned char flags, unsigned char unit); +int tw_decode_bits(TW_Device_Extension *tw_dev, u32 status_reg_value, int print_host); +int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense); void tw_disable_interrupts(TW_Device_Extension *tw_dev); -int tw_empty_response_que(TW_Device_Extension *tw_dev); +void tw_empty_response_que(TW_Device_Extension *tw_dev); void tw_enable_interrupts(TW_Device_Extension *tw_dev); void tw_enable_and_clear_interrupts(TW_Device_Extension *tw_dev); int tw_findcards(Scsi_Host_Template *tw_host); @@ -460,7 +494,7 @@ void tw_unmask_command_interrupt(TW_Device_Extension *tw_dev); reset : NULL, \ slave_attach : NULL, \ bios_param : tw_scsi_biosparam, \ - can_queue : TW_Q_LENGTH, \ + can_queue : TW_Q_LENGTH-1, \ this_id: -1, \ sg_tablesize : TW_MAX_SGL_LENGTH, \ cmd_per_lun: TW_MAX_CMDS_PER_LUN, \ diff --git a/drivers/usb/ov511.c b/drivers/usb/ov511.c index 64880abecaa1..21027ce030eb 100644 --- a/drivers/usb/ov511.c +++ b/drivers/usb/ov511.c @@ -30,8 +30,6 @@ * Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ -#define __NO_VERSION__ - #include #include #include @@ -330,7 +328,7 @@ static int ov511_read_proc(char *page, char **start, off_t off, /* IMPORTANT: This output MUST be kept under PAGE_SIZE * or we need to get more sophisticated. */ - out += sprintf (out, "driver_version : %s\n", version); + out += sprintf (out, "driver_version : %s\n", DRIVER_VERSION); out += sprintf (out, "custom_id : %d\n", ov511->customid); out += sprintf (out, "model : %s\n", ov511->desc ? clist[ov511->desc].description : "unknown"); diff --git a/x1 b/x1 new file mode 100644 index 000000000000..959be611020d --- /dev/null +++ b/x1 @@ -0,0 +1,180 @@ +From: Paul Mackerras +Date: Tue, 19 Mar 2002 16:01:22 +1100 (EST) +To: marcelo@conectiva.com.br, linux-kernel@vger.kernel.org +Subject: Re: [PATCH] zlib double-free bug + +Someone pointed me at a previously-posted patch for the zlib +vulnerability. While I was looking at that patch I realized that both +that patch and mine were buggy in different ways. My patch was +freeing s->sub.trees.blens after that word had been overwritten by an +assignment to s->sub.decode.codes, whereas with the previously-posted +patch, it is still possible to get a double-free (if inflate_codes_new +returns NULL, it will leave s->mode == DTREE but s->sub.trees.blens +has already been freed). + +Here is a new patch which should fix both those problems. + +Paul. + +diff -urN linux-2.4.19-pre3/arch/ppc/boot/lib/zlib.c pmac/arch/ppc/boot/lib/zlib.c +--- linux-2.4.19-pre3/arch/ppc/boot/lib/zlib.c Mon Mar 18 13:34:47 2002 ++++ pmac/arch/ppc/boot/lib/zlib.c Tue Mar 19 15:46:09 2002 +@@ -1,5 +1,5 @@ + /* +- * BK Id: SCCS/s.zlib.c 1.10 01/11/02 10:46:07 trini ++ * BK Id: SCCS/s.zlib.c 1.9 12/05/01 16:19:42 mporter + */ + /* + * This file is derived from various .h and .c files from the zlib-0.95 +@@ -928,7 +928,10 @@ + { + r = t; + if (r == Z_DATA_ERROR) ++ { ++ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); + s->mode = BADB; ++ } + LEAVE + } + s->sub.trees.index = 0; +@@ -964,6 +967,7 @@ + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { ++ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); + s->mode = BADB; + z->msg = "invalid bit length repeat"; + r = Z_DATA_ERROR; +@@ -991,7 +995,10 @@ + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) ++ { ++ ZFREE(z, s->sub.trees.blens, s->sub.trees.nblens * sizeof(uInt)); + s->mode = BADB; ++ } + r = t; + LEAVE + } +diff -urN linux-2.4.19-pre3/drivers/net/zlib.c pmac/drivers/net/zlib.c +--- linux-2.4.19-pre3/drivers/net/zlib.c Sat Apr 28 23:02:45 2001 ++++ pmac/drivers/net/zlib.c Tue Mar 19 15:45:40 2002 +@@ -14,7 +14,7 @@ + */ + + /* +- * ==FILEVERSION 971210== ++ * ==FILEVERSION 20020318== + * + * This marker is used by the Linux installation script to determine + * whether an up-to-date version of this file is already installed. +@@ -772,7 +772,7 @@ + windowBits = -windowBits; + } + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || +- windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || ++ windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } +@@ -3860,10 +3860,12 @@ + &s->sub.trees.tb, z); + if (t != Z_OK) + { +- ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) ++ { ++ ZFREE(z, s->sub.trees.blens); + s->mode = BADB; ++ } + LEAVE + } + s->sub.trees.index = 0; +@@ -3928,11 +3930,13 @@ + #endif + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, z); +- ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) ++ { ++ ZFREE(z, s->sub.trees.blens); + s->mode = BADB; ++ } + r = t; + LEAVE + } +@@ -3945,6 +3949,7 @@ + r = Z_MEM_ERROR; + LEAVE + } ++ ZFREE(z, s->sub.trees.blens); + s->sub.decode.codes = c; + s->sub.decode.tl = tl; + s->sub.decode.td = td; +diff -urN linux-2.4.19-pre3/fs/jffs2/zlib.c pmac/fs/jffs2/zlib.c +--- linux-2.4.19-pre3/fs/jffs2/zlib.c Mon Sep 24 09:31:33 2001 ++++ pmac/fs/jffs2/zlib.c Tue Mar 19 15:46:47 2002 +@@ -14,7 +14,7 @@ + */ + + /* +- * ==FILEVERSION 971210== ++ * ==FILEVERSION 20020318== + * + * This marker is used by the Linux installation script to determine + * whether an up-to-date version of this file is already installed. +@@ -772,7 +772,7 @@ + windowBits = -windowBits; + } + if (memLevel < 1 || memLevel > MAX_MEM_LEVEL || method != Z_DEFLATED || +- windowBits < 8 || windowBits > 15 || level < 0 || level > 9 || ++ windowBits < 9 || windowBits > 15 || level < 0 || level > 9 || + strategy < 0 || strategy > Z_HUFFMAN_ONLY) { + return Z_STREAM_ERROR; + } +@@ -3860,10 +3860,12 @@ + &s->sub.trees.tb, z); + if (t != Z_OK) + { +- ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) ++ { ++ ZFREE(z, s->sub.trees.blens); + s->mode = BADB; ++ } + LEAVE + } + s->sub.trees.index = 0; +@@ -3928,11 +3930,13 @@ + #endif + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, z); +- ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) ++ { ++ ZFREE(z, s->sub.trees.blens); + s->mode = BADB; ++ } + r = t; + LEAVE + } +@@ -3945,6 +3949,7 @@ + r = Z_MEM_ERROR; + LEAVE + } ++ ZFREE(z, s->sub.trees.blens); + s->sub.decode.codes = c; + s->sub.decode.tl = tl; + s->sub.decode.td = td; +- +To unsubscribe from this list: send the line "unsubscribe linux-kernel" in +the body of a message to majordomo@vger.kernel.org +More majordomo info at http://vger.kernel.org/majordomo-info.html +Please read the FAQ at http://www.tux.org/lkml/ + -- 2.39.5