]> git.neil.brown.name Git - history.git/commitdiff
Linux 2.2.21rc3 2.2.21-rc3
authorAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:24:15 +0000 (15:24 -0500)
committerAlan Cox <alan@lxorguk.ukuu.org.uk>
Fri, 23 Nov 2007 20:24:15 +0000 (15:24 -0500)
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
drivers/char/nvram.c
drivers/char/planb.c
drivers/char/planb.h
drivers/char/rtc.c
drivers/macintosh/mac_hid.c
drivers/net/zlib.c
drivers/scsi/3w-xxxx.c
drivers/scsi/3w-xxxx.h
drivers/usb/ov511.c
x1 [new file with mode: 0644]

index e04be4482fb3e6efb37da2c83377b8a0d065a9f8..8b3d7c2ade199a67239f2d66053ba40afd1af6e3 100644 (file)
--- 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/)
 
index 0a7d9c69551e9bb148494b3b6de8707667ad6b67..8614523132cebe278a1a05cdd86cf41965b4fbed 100644 (file)
@@ -329,7 +329,7 @@ static int nvram_ioctl( struct inode *inode, struct file *file,
                return( 0 );
 
          default:
-               return( -EINVAL );
+               return( -ENOTTY );
        }
 }
 
index ede49febce596c1abcc7c13768dfb7275ef3cfee..973887d70e3496b606a5ba04ad03dc4b6b021fc3 100644 (file)
@@ -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 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; 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;
index 716163f6c851e6ad5512cf93fab9a8e043997960..9d87cb8d6fe04b583bb21e2feb63ed17da848863 100644 (file)
@@ -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
 };
index 2b38762b090e03432fa1b52ba54c38893487af4c..52856483faf1b1183b4bb7d132353a0132a9b542 100644 (file)
@@ -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;
 }
index 07b082715dc72f05231076f951c9ebef42b75571..986c6cf98384f165a73d3e73f49b449e4b76348c 100644 (file)
@@ -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
        }
index a8edce8edde16c20d8641c5826287323eee33408..af8427ecdd5a417a081eeca6c3beb7c9e2e906a9 100644 (file)
@@ -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;
index 15e362f2336c59882069627be57c40cc74b8ba23..83ff7c98b1e4e533b7484dbb1f9f03423b24f6be 100644 (file)
    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 @@ 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; 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 @@ 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;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 @@ 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 */
index 21ad360e605701f55dbf14ce85332257000c6b2b..75f28edaba82b2a7beb85c99aaff41ca331e1004 100644 (file)
@@ -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,               \
index 64880abecaa178491e70c5a78965fc751a9a7471..21027ce030eba688ab6c175a55928667884fb936 100644 (file)
@@ -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 @@ 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 (file)
index 0000000..959be61
--- /dev/null
+++ b/x1
@@ -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/
+