## Automatically generated incremental diff
## From:   linux-2.2.21-rc2
## To:     linux-2.2.21-rc3
## Robot:  $Id: make-incremental-diff,v 1.11 2002/02/20 02:59:33 hpa Exp $

diff -urN linux-2.2.21-rc2/Makefile linux-2.2.21-rc3/Makefile
--- linux-2.2.21-rc2/Makefile	Mon Apr  1 08:27:30 2002
+++ linux-2.2.21-rc3/Makefile	Mon Apr  1 08:27:32 2002
@@ -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 -urN linux-2.2.21-rc2/drivers/char/nvram.c linux-2.2.21-rc3/drivers/char/nvram.c
--- linux-2.2.21-rc2/drivers/char/nvram.c	Sun Mar 25 08:31:26 2001
+++ linux-2.2.21-rc3/drivers/char/nvram.c	Mon Apr  1 08:27:32 2002
@@ -329,7 +329,7 @@
 		return( 0 );
 
 	  default:
-		return( -EINVAL );
+		return( -ENOTTY );
 	}
 }
 
diff -urN linux-2.2.21-rc2/drivers/char/planb.c linux-2.2.21-rc3/drivers/char/planb.c
--- linux-2.2.21-rc2/drivers/char/planb.c	Sun Mar 25 08:31:27 2001
+++ linux-2.2.21-rc3/drivers/char/planb.c	Mon Apr  1 08:27:32 2002
@@ -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 <dirks@rendition.com>)
+    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 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 @@
 /* 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;
-}
-
-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);
-	}
-}
-
-/*  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));
-}
+	int i, npage;
 
-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)
+	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);
+	}
+	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 @@
 						+ 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 @@
 #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 @@
 		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 @@
        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 @@
 	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 @@
 		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 @@
 #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 @@
 	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 @@
 
 	/* 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 @@
 	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 @@
 			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 @@
 		    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 @@
 #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 @@
 		    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 @@
 		    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 @@
 
 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 @@
 	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 @@
 #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 @@
 				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 @@
 	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;
-	}
-	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;    
+	if (!pb->rawbuf) {
+		int err;
+		if((err=grabbuf_alloc(pb)))
+			return err;
+	}
+	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 @@
 {
 	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 @@
 	/* 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 @@
 	pb->frame_stat=NULL;
 	pb->capq=NULL;
 	for(i=0; i<MAX_GBUFFERS; i++) {
-		pb->gbuffer[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 -urN linux-2.2.21-rc2/drivers/char/planb.h linux-2.2.21-rc3/drivers/char/planb.h
--- linux-2.2.21-rc2/drivers/char/planb.h	Sun Mar 25 08:31:27 2001
+++ linux-2.2.21-rc3/drivers/char/planb.h	Mon Apr  1 08:27:32 2002
@@ -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 @@
 	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 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 @@
 #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 -urN linux-2.2.21-rc2/drivers/char/rtc.c linux-2.2.21-rc3/drivers/char/rtc.c
--- linux-2.2.21-rc2/drivers/char/rtc.c	Sun Mar 25 08:31:26 2001
+++ linux-2.2.21-rc3/drivers/char/rtc.c	Mon Apr  1 08:27:32 2002
@@ -435,7 +435,7 @@
 	}
 #endif
 	default:
-		return -EINVAL;
+		return -ENOTTY;
 	}
 	return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0;
 }
diff -urN linux-2.2.21-rc2/drivers/macintosh/mac_hid.c linux-2.2.21-rc3/drivers/macintosh/mac_hid.c
--- linux-2.2.21-rc2/drivers/macintosh/mac_hid.c	Fri Nov  2 08:39:07 2001
+++ linux-2.2.21-rc3/drivers/macintosh/mac_hid.c	Mon Apr  1 08:27:33 2002
@@ -480,13 +480,13 @@
 
 	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 -urN linux-2.2.21-rc2/drivers/net/zlib.c linux-2.2.21-rc3/drivers/net/zlib.c
--- linux-2.2.21-rc2/drivers/net/zlib.c	Mon Apr  1 08:27:31 2002
+++ linux-2.2.21-rc3/drivers/net/zlib.c	Mon Apr  1 08:27:33 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;
     }
@@ -3932,8 +3932,8 @@
         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 @@
           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.2.21-rc2/drivers/scsi/3w-xxxx.c linux-2.2.21-rc3/drivers/scsi/3w-xxxx.c
--- linux-2.2.21-rc2/drivers/scsi/3w-xxxx.c	Mon Apr  1 08:27:31 2002
+++ linux-2.2.21-rc3/drivers/scsi/3w-xxxx.c	Mon Apr  1 08:27:33 2002
@@ -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 <linux/module.h>
@@ -168,7 +183,7 @@
 };
 
 /* 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 @@
 	}
 	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 @@
 			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 @@
 				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 @@
 	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 @@
 		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 @@
 	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 @@
 	}
 } /* 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 @@
 } /* 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 @@
   
 	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 @@
 			}
 			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 @@
 			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 @@
 			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 @@
 					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 @@
 			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 @@
 					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 @@
 		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 @@
 			}
 			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 @@
 /* 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; i<imax; i++) {
+	for (i=0; i<TW_Q_LENGTH;i++) {
 		/* Initialize command packet buffers */
 		tw_allocate_memory(tw_dev, i, sizeof(TW_Sector), 0);
 		if (tw_dev->command_packet_virtual_address[i] == NULL) {
@@ -1065,33 +1116,12 @@
 
 		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;i<TW_MAX_UNITS;i++) {
-		tw_dev->is_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 @@
 		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 @@
 			}
 			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 @@
 			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 @@
 				}
 				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 @@
 	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 @@
 		}
 
 		/* 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 @@
 					}
 					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 @@
 		}
 
 		/* 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 @@
 						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 @@
 			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 @@
 	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 @@
 
 	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 @@
 	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 @@
 			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 @@
 		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 @@
 				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 @@
 	}
 
 	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 @@
 			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 @@
 				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 @@
 			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 @@
 {
 	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 @@
 		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 @@
 			}
 			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 -urN linux-2.2.21-rc2/drivers/scsi/3w-xxxx.h linux-2.2.21-rc3/drivers/scsi/3w-xxxx.h
--- linux-2.2.21-rc2/drivers/scsi/3w-xxxx.h	Mon Apr  1 08:27:31 2002
+++ linux-2.2.21-rc3/drivers/scsi/3w-xxxx.h	Mon Apr  1 08:27:33 2002
@@ -92,10 +92,35 @@
 	"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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 #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 @@
 	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_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 @@
 	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 -urN linux-2.2.21-rc2/drivers/usb/ov511.c linux-2.2.21-rc3/drivers/usb/ov511.c
--- linux-2.2.21-rc2/drivers/usb/ov511.c	Fri Nov  2 08:39:08 2001
+++ linux-2.2.21-rc3/drivers/usb/ov511.c	Mon Apr  1 08:27:33 2002
@@ -30,8 +30,6 @@
  * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  */
 
-#define __NO_VERSION__
-
 #include <linux/config.h>
 #include <linux/module.h>
 #include <linux/version.h>
@@ -330,7 +328,7 @@
 	/* 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 -urN linux-2.2.21-rc2/x1 linux-2.2.21-rc3/x1
--- linux-2.2.21-rc2/x1	Wed Dec 31 16:00:00 1969
+++ linux-2.2.21-rc3/x1	Mon Apr  1 08:27:35 2002
@@ -0,0 +1,180 @@
+From: Paul Mackerras <paulus@samba.org>
+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/
+
