regulator: Fix check of unsigned return value and transmit errors in wm831x_gp_ldo_ge...
[safe/jmp/linux-2.6] / drivers / scsi / aha152x.c
index 630b115..1e5478a 100644 (file)
@@ -1,6 +1,6 @@
 /* aha152x.c -- Adaptec AHA-152x driver
- * Author: Jürgen E. Fischer, fischer@norbit.de
- * Copyright 1993-2004 Jürgen E. Fischer
+ * Author: Jürgen E. Fischer, fischer@norbit.de
+ * Copyright 1993-2004 Jürgen E. Fischer
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of the GNU General Public License as published by the
  **************************************************************************/
 
 #include <linux/module.h>
-#include <linux/sched.h>
 #include <asm/irq.h>
-#include <asm/io.h>
+#include <linux/io.h>
 #include <linux/blkdev.h>
 #include <asm/system.h>
+#include <linux/completion.h>
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/wait.h>
 #include <linux/isapnp.h>
 #include <linux/spinlock.h>
 #include <linux/workqueue.h>
-#include <asm/semaphore.h>
+#include <linux/list.h>
 #include <scsi/scsicam.h>
 
 #include "scsi.h"
 #include <scsi/scsi_dbg.h>
 #include <scsi/scsi_host.h>
+#include <scsi/scsi_transport_spi.h>
+#include <scsi/scsi_eh.h>
 #include "aha152x.h"
 
+static LIST_HEAD(aha152x_host_list);
+
 
 /* DEFINES */
 
 #define DO_LOCK(flags) \
        do { \
                if(spin_is_locked(&QLOCK)) { \
-                       DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+                       DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \
                } \
-               DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+               DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
                spin_lock_irqsave(&QLOCK,flags); \
-               DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
-               QLOCKER=__FUNCTION__; \
+               DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
+               QLOCKER=__func__; \
                QLOCKERL=__LINE__; \
        } while(0)
 
 #define DO_UNLOCK(flags)       \
        do { \
-               DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__, QLOCKER, QLOCKERL); \
+               DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \
                spin_unlock_irqrestore(&QLOCK,flags); \
-               DPRINTK(debug_locks, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __FUNCTION__, __LINE__); \
+               DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
                QLOCKER="(not locked)"; \
                QLOCKERL=0; \
        } while(0)
                         (cmd) ? ((cmd)->device->id & 0x0f) : -1, \
                        (cmd) ? ((cmd)->device->lun & 0x07) : -1
 
+static inline void
+CMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
+{
+       scsi_set_resid(cmd, scsi_get_resid(cmd) + inc);
+}
+
 #define DELAY_DEFAULT 1000
 
 #if defined(PCMCIA)
 #else
 #define IRQ_MIN 9
 #if defined(__PPC)
-#define IRQ_MAX (NR_IRQS-1)
+#define IRQ_MAX (nr_irqs-1)
 #else
 #define IRQ_MAX 12
 #endif
@@ -348,7 +358,7 @@ enum {
        check_condition = 0x0800,       /* requesting sense after CHECK CONDITION */
 };
 
-MODULE_AUTHOR("Jürgen Fischer");
+MODULE_AUTHOR("Jürgen Fischer");
 MODULE_DESCRIPTION(AHA152X_REVID);
 MODULE_LICENSE("GPL");
 
@@ -422,9 +432,7 @@ MODULE_DEVICE_TABLE(isapnp, id_table);
 
 #endif /* !PCMCIA */
 
-static int registered_count=0;
-static struct Scsi_Host *aha152x_host[2];
-static Scsi_Host_Template aha152x_driver_template;
+static struct scsi_host_template aha152x_driver_template;
 
 /*
  * internal states of the host
@@ -540,6 +548,7 @@ struct aha152x_hostdata {
 #ifdef __ISAPNP__
        struct pnp_dev *pnpdev;
 #endif
+       struct list_head host_list;
 };
 
 
@@ -549,10 +558,10 @@ struct aha152x_hostdata {
  */
 struct aha152x_scdata {
        Scsi_Cmnd *next;        /* next sc in queue */
-       struct semaphore *sem;  /* semaphore to block on */
+       struct completion *done;/* semaphore to block on */
+       struct scsi_eh_save ses;
 };
 
-
 /* access macros for hostdata */
 
 #define HOSTDATA(shpnt)                ((struct aha152x_hostdata *) &shpnt->hostdata)
@@ -601,9 +610,9 @@ struct aha152x_scdata {
 
 #define SCDATA(SCpnt)          ((struct aha152x_scdata *) (SCpnt)->host_scribble)
 #define SCNEXT(SCpnt)          SCDATA(SCpnt)->next
-#define SCSEM(SCpnt)           SCDATA(SCpnt)->sem
+#define SCSEM(SCpnt)           SCDATA(SCpnt)->done
 
-#define SG_ADDRESS(buffer)     ((char *) (page_address((buffer)->page)+(buffer)->offset))
+#define SG_ADDRESS(buffer)     ((char *) sg_virt((buffer)))
 
 /* state handling */
 static void seldi_run(struct Scsi_Host *shpnt);
@@ -665,7 +674,7 @@ static struct {
 };
 
 /* setup & interrupt */
-static irqreturn_t intr(int irq, void *dev_id, struct pt_regs *);
+static irqreturn_t intr(int irq, void *dev_id);
 static void reset_ports(struct Scsi_Host *shpnt);
 static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
 static void done(struct Scsi_Host *shpnt, int error);
@@ -749,25 +758,9 @@ static inline Scsi_Cmnd *remove_SC(Scsi_Cmnd **SC, Scsi_Cmnd *SCp)
        return ptr;
 }
 
-static inline struct Scsi_Host *lookup_irq(int irqno)
-{
-       int i;
-
-       for(i=0; i<ARRAY_SIZE(aha152x_host); i++)
-               if(aha152x_host[i] && aha152x_host[i]->irq==irqno)
-                       return aha152x_host[i];
-
-       return NULL;
-}
-
-static irqreturn_t swintr(int irqno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t swintr(int irqno, void *dev_id)
 {
-       struct Scsi_Host *shpnt = lookup_irq(irqno);
-
-       if (!shpnt) {
-               printk(KERN_ERR "aha152x: catched software interrupt %d for unknown controller.\n", irqno);
-               return IRQ_NONE;
-       }
+       struct Scsi_Host *shpnt = dev_id;
 
        HOSTDATA(shpnt)->swint++;
 
@@ -785,10 +778,11 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
                return NULL;
        }
 
-       /* need to have host registered before triggering any interrupt */
-       aha152x_host[registered_count] = shpnt;
-
        memset(HOSTDATA(shpnt), 0, sizeof *HOSTDATA(shpnt));
+       INIT_LIST_HEAD(&HOSTDATA(shpnt)->host_list);
+
+       /* need to have host registered before triggering any interrupt */
+       list_add_tail(&HOSTDATA(shpnt)->host_list, &aha152x_host_list);
 
        shpnt->io_port   = setup->io_port;
        shpnt->n_io_port = IO_RANGE;
@@ -854,7 +848,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
        SETPORT(SIMODE0, 0);
        SETPORT(SIMODE1, 0);
 
-       if( request_irq(shpnt->irq, swintr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {
+       if( request_irq(shpnt->irq, swintr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) {
                printk(KERN_ERR "aha152x%d: irq %d busy.\n", shpnt->host_no, shpnt->irq);
                goto out_host_put;
        }
@@ -888,7 +882,7 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
        SETPORT(SSTAT0, 0x7f);
        SETPORT(SSTAT1, 0xef);
 
-       if ( request_irq(shpnt->irq, intr, SA_INTERRUPT|SA_SHIRQ, "aha152x", shpnt) ) {
+       if ( request_irq(shpnt->irq, intr, IRQF_DISABLED|IRQF_SHARED, "aha152x", shpnt) ) {
                printk(KERN_ERR "aha152x%d: failed to reassign irq %d.\n", shpnt->host_no, shpnt->irq);
                goto out_host_put;
        }
@@ -901,12 +895,10 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
 
        scsi_scan_host(shpnt);
 
-       registered_count++;
-
        return shpnt;
 
 out_host_put:
-       aha152x_host[registered_count]=NULL;
+       list_del(&HOSTDATA(shpnt)->host_list);
        scsi_host_put(shpnt);
 
        return NULL;
@@ -914,9 +906,10 @@ out_host_put:
 
 void aha152x_release(struct Scsi_Host *shpnt)
 {
-       if(!shpnt)
+       if (!shpnt)
                return;
 
+       scsi_remove_host(shpnt);
        if (shpnt->irq)
                free_irq(shpnt->irq, shpnt);
 
@@ -930,7 +923,7 @@ void aha152x_release(struct Scsi_Host *shpnt)
                pnp_device_detach(HOSTDATA(shpnt)->pnpdev);
 #endif
 
-       scsi_remove_host(shpnt);
+       list_del(&HOSTDATA(shpnt)->host_list);
        scsi_host_put(shpnt);
 }
 
@@ -978,7 +971,8 @@ static int setup_expected_interrupts(struct Scsi_Host *shpnt)
 /* 
  *  Queue a command and setup interrupts for a free bus.
  */
-static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int phase, void (*done)(Scsi_Cmnd *))
+static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
+               int phase, void (*done)(Scsi_Cmnd *))
 {
        struct Scsi_Host *shpnt = SCpnt->device->host;
        unsigned long flags;
@@ -986,34 +980,34 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int p
 #if defined(AHA152X_DEBUG)
        if (HOSTDATA(shpnt)->debug & debug_queue) {
                printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=",
-                      CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen);
+                      CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len,
+                      scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
                __scsi_print_command(SCpnt->cmnd);
        }
 #endif
 
        SCpnt->scsi_done        = done;
-       SCpnt->resid            = SCpnt->request_bufflen;
        SCpnt->SCp.phase        = not_issued | phase;
-       SCpnt->SCp.Status       = CHECK_CONDITION;
+       SCpnt->SCp.Status       = 0x1; /* Ilegal status by SCSI standard */
        SCpnt->SCp.Message      = 0;
        SCpnt->SCp.have_data_in = 0;
        SCpnt->SCp.sent_command = 0;
 
        if(SCpnt->SCp.phase & (resetting|check_condition)) {
-               if(SCpnt->host_scribble==0 || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
+               if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
                        printk(ERR_LEAD "cannot reuse command\n", CMDINFO(SCpnt));
                        return FAILED;
                }
        } else {
                SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
-               if(SCpnt->host_scribble==0) {
+               if(!SCpnt->host_scribble) {
                        printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
                        return FAILED;
                }
        }
 
        SCNEXT(SCpnt)           = NULL;
-       SCSEM(SCpnt)            = sem;
+       SCSEM(SCpnt)            = complete;
 
        /* setup scratch area
           SCp.ptr              : buffer pointer
@@ -1021,16 +1015,19 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct semaphore *sem, int p
           SCp.buffer           : next buffer
           SCp.buffers_residual : left buffers in list
           SCp.phase            : current state of the command */
-       if (SCpnt->use_sg) {
-               SCpnt->SCp.buffer           = (struct scatterlist *) SCpnt->request_buffer;
-               SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
-               SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
-               SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1;
-       } else {
-               SCpnt->SCp.ptr              = (char *) SCpnt->request_buffer;
-               SCpnt->SCp.this_residual    = SCpnt->request_bufflen;
+
+       if ((phase & resetting) || !scsi_sglist(SCpnt)) {
+               SCpnt->SCp.ptr           = NULL;
+               SCpnt->SCp.this_residual = 0;
+               scsi_set_resid(SCpnt, 0);
                SCpnt->SCp.buffer           = NULL;
                SCpnt->SCp.buffers_residual = 0;
+       } else {
+               scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
+               SCpnt->SCp.buffer           = scsi_sglist(SCpnt);
+               SCpnt->SCp.ptr              = SG_ADDRESS(SCpnt->SCp.buffer);
+               SCpnt->SCp.this_residual    = SCpnt->SCp.buffer->length;
+               SCpnt->SCp.buffers_residual = scsi_sg_count(SCpnt) - 1;
        }
 
        DO_LOCK(flags);
@@ -1084,9 +1081,9 @@ static void reset_done(Scsi_Cmnd *SCpnt)
        DPRINTK(debug_eh, INFO_LEAD "reset_done called\n", CMDINFO(SCpnt));
 #endif
        if(SCSEM(SCpnt)) {
-               up(SCSEM(SCpnt));
+               complete(SCSEM(SCpnt));
        } else {
-               printk(KERN_ERR "aha152x: reset_done w/o semaphore\n");
+               printk(KERN_ERR "aha152x: reset_done w/o completion\n");
        }
 }
 
@@ -1139,21 +1136,6 @@ static int aha152x_abort(Scsi_Cmnd *SCpnt)
        return FAILED;
 }
 
-static void timer_expired(unsigned long p)
-{
-       Scsi_Cmnd        *SCp   = (Scsi_Cmnd *)p;
-       struct semaphore *sem   = SCSEM(SCp);
-       struct Scsi_Host *shpnt = SCp->device->host;
-       unsigned long flags;
-
-       /* remove command from issue queue */
-       DO_LOCK(flags);
-       remove_SC(&ISSUE_SC, SCp);
-       DO_UNLOCK(flags);
-
-       up(sem);
-}
-
 /*
  * Reset a device
  *
@@ -1161,10 +1143,11 @@ static void timer_expired(unsigned long p)
 static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
 {
        struct Scsi_Host *shpnt = SCpnt->device->host;
-       DECLARE_MUTEX_LOCKED(sem);
-       struct timer_list timer;
+       DECLARE_COMPLETION(done);
        int ret, issued, disconnected;
+       unsigned char old_cmd_len = SCpnt->cmd_len;
        unsigned long flags;
+       unsigned long timeleft;
 
 #if defined(AHA152X_DEBUG)
        if(HOSTDATA(shpnt)->debug & debug_eh) {
@@ -1179,29 +1162,23 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
        }
 
        DO_LOCK(flags);
-       issued       = remove_SC(&ISSUE_SC, SCpnt)==0;
+       issued       = remove_SC(&ISSUE_SC, SCpnt) == NULL;
        disconnected = issued && remove_SC(&DISCONNECTED_SC, SCpnt);
        DO_UNLOCK(flags);
 
        SCpnt->cmd_len         = 0;
-       SCpnt->use_sg          = 0;
-       SCpnt->request_buffer  = NULL;
-       SCpnt->request_bufflen = 0;
-
-       init_timer(&timer);
-       timer.data     = (unsigned long) SCpnt;
-       timer.expires  = jiffies + 100*HZ;   /* 10s */
-       timer.function = (void (*)(unsigned long)) timer_expired;
-
-       aha152x_internal_queue(SCpnt, &sem, resetting, reset_done);
-       add_timer(&timer);
-       down(&sem);
-       del_timer(&timer);
-       
-       SCpnt->cmd_len         = SCpnt->old_cmd_len;
-       SCpnt->use_sg          = SCpnt->old_use_sg;
-       SCpnt->request_buffer  = SCpnt->buffer;
-               SCpnt->request_bufflen = SCpnt->bufflen;
+
+       aha152x_internal_queue(SCpnt, &done, resetting, reset_done);
+
+       timeleft = wait_for_completion_timeout(&done, 100*HZ);
+       if (!timeleft) {
+               /* remove command from issue queue */
+               DO_LOCK(flags);
+               remove_SC(&ISSUE_SC, SCpnt);
+               DO_UNLOCK(flags);
+       }
+
+       SCpnt->cmd_len         = old_cmd_len;
 
        DO_LOCK(flags);
 
@@ -1259,16 +1236,15 @@ static void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs)
  * Reset the bus
  *
  */
-static int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
+static int aha152x_bus_reset_host(struct Scsi_Host *shpnt)
 {
-       struct Scsi_Host *shpnt = SCpnt->device->host;
        unsigned long flags;
 
        DO_LOCK(flags);
 
 #if defined(AHA152X_DEBUG)
        if(HOSTDATA(shpnt)->debug & debug_eh) {
-               printk(DEBUG_LEAD "aha152x_bus_reset(%p)", CMDINFO(SCpnt), SCpnt);
+               printk(KERN_DEBUG "scsi%d: bus reset", shpnt->host_no);
                show_queues(shpnt);
        }
 #endif
@@ -1276,14 +1252,14 @@ static int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
        free_hard_reset_SCs(shpnt, &ISSUE_SC);
        free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
 
-       DPRINTK(debug_eh, DEBUG_LEAD "resetting bus\n", CMDINFO(SCpnt));
+       DPRINTK(debug_eh, KERN_DEBUG "scsi%d: resetting bus\n", shpnt->host_no);
 
        SETPORT(SCSISEQ, SCSIRSTO);
        mdelay(256);
        SETPORT(SCSISEQ, 0);
        mdelay(DELAY);
 
-       DPRINTK(debug_eh, DEBUG_LEAD "bus resetted\n", CMDINFO(SCpnt));
+       DPRINTK(debug_eh, KERN_DEBUG "scsi%d: bus resetted\n", shpnt->host_no);
 
        setup_expected_interrupts(shpnt);
        if(HOSTDATA(shpnt)->commands==0)
@@ -1294,6 +1270,14 @@ static int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
        return SUCCESS;
 }
 
+/*
+ * Reset the bus
+ *
+ */
+static int aha152x_bus_reset(Scsi_Cmnd *SCpnt)
+{
+       return aha152x_bus_reset_host(SCpnt->device->host);
+}
 
 /*
  *  Restore default values to the AIC-6260 registers and reset the fifos
@@ -1336,23 +1320,28 @@ static void reset_ports(struct Scsi_Host *shpnt)
  * Reset the host (bus and controller)
  *
  */
-int aha152x_host_reset(Scsi_Cmnd * SCpnt)
+int aha152x_host_reset_host(struct Scsi_Host *shpnt)
 {
-#if defined(AHA152X_DEBUG)
-       struct Scsi_Host *shpnt = SCpnt->device->host;
-#endif
-
-       DPRINTK(debug_eh, DEBUG_LEAD "aha152x_host_reset(%p)\n", CMDINFO(SCpnt), SCpnt);
+       DPRINTK(debug_eh, KERN_DEBUG "scsi%d: host reset\n", shpnt->host_no);
 
-       aha152x_bus_reset(SCpnt);
+       aha152x_bus_reset_host(shpnt);
 
-       DPRINTK(debug_eh, DEBUG_LEAD "resetting ports\n", CMDINFO(SCpnt));
-       reset_ports(SCpnt->device->host);
+       DPRINTK(debug_eh, KERN_DEBUG "scsi%d: resetting ports\n", shpnt->host_no);
+       reset_ports(shpnt);
 
        return SUCCESS;
 }
 
 /*
+ * Reset the host (bus and controller)
+ * 
+ */
+static int aha152x_host_reset(Scsi_Cmnd *SCpnt)
+{
+       return aha152x_host_reset_host(SCpnt->device->host);
+}
+
+/*
  * Return the "logical geometry"
  *
  */
@@ -1426,33 +1415,27 @@ static struct work_struct aha152x_tq;
  * Run service completions on the card with interrupts enabled.
  *
  */
-static void run(void)
+static void run(struct work_struct *work)
 {
-       int i;
-       for (i = 0; i<ARRAY_SIZE(aha152x_host); i++) {
-               struct Scsi_Host *shpnt = aha152x_host[i];
-               if (shpnt && HOSTDATA(shpnt)->service) {
-                       HOSTDATA(shpnt)->service=0;
-                       is_complete(shpnt);
-               }
+       struct aha152x_hostdata *hd;
+
+       list_for_each_entry(hd, &aha152x_host_list, host_list) {
+               struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
+
+               is_complete(shost);
        }
 }
 
 /*
- *    Interrupts handler
+ * Interrupt handler
  *
  */
-
-static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
+static irqreturn_t intr(int irqno, void *dev_id)
 {
-       struct Scsi_Host *shpnt = lookup_irq(irqno);
+       struct Scsi_Host *shpnt = dev_id;
+       unsigned long flags;
        unsigned char rev, dmacntrl0;
 
-       if (!shpnt) {
-               printk(KERN_ERR "aha152x: catched interrupt %d for unknown controller.\n", irqno);
-               return IRQ_NONE;
-       }
-
        /*
         * Read a couple of registers that are known to not be all 1's. If
         * we read all 1's (-1), that means that either:
@@ -1471,23 +1454,23 @@ static irqreturn_t intr(int irqno, void *dev_id, struct pt_regs *regs)
        if ((rev == 0xFF) && (dmacntrl0 == 0xFF))
                return IRQ_NONE;
 
+       if( TESTLO(DMASTAT, INTSTAT) )
+               return IRQ_NONE;        
+
        /* no more interrupts from the controller, while we're busy.
           INTEN is restored by the BH handler */
        CLRBITS(DMACNTRL0, INTEN);
 
-#if 0
-       /* check if there is already something to be
-           serviced; should not happen */
-       if(HOSTDATA(shpnt)->service) {
-               printk(KERN_ERR "aha152x%d: lost interrupt (%d)\n", HOSTNO, HOSTDATA(shpnt)->service);
-               show_queues(shpnt);
+       DO_LOCK(flags);
+       if( HOSTDATA(shpnt)->service==0 ) {
+               HOSTDATA(shpnt)->service=1;
+
+               /* Poke the BH handler */
+               INIT_WORK(&aha152x_tq, run);
+               schedule_work(&aha152x_tq);
        }
-#endif
-       
-       /* Poke the BH handler */
-       HOSTDATA(shpnt)->service++;
-       INIT_WORK(&aha152x_tq, (void *) run, NULL);
-       schedule_work(&aha152x_tq);
+       DO_UNLOCK(flags);
+
        return IRQ_HANDLED;
 }
 
@@ -1530,8 +1513,8 @@ static void busfree_run(struct Scsi_Host *shpnt)
                        /* target sent DISCONNECT */
                        DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n",
                                CMDINFO(CURRENT_SC),
-                               CURRENT_SC->resid,
-                               CURRENT_SC->request_bufflen);
+                               scsi_get_resid(CURRENT_SC),
+                               scsi_bufflen(CURRENT_SC));
 #if defined(AHA152X_STAT)
                        HOSTDATA(shpnt)->disconnections++;
 #endif
@@ -1556,6 +1539,9 @@ static void busfree_run(struct Scsi_Host *shpnt)
 #endif
 
                if(DONE_SC->SCp.phase & check_condition) {
+                       struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
+                       struct aha152x_scdata *sc = SCDATA(cmd);
+
 #if 0
                        if(HOSTDATA(shpnt)->debug & debug_eh) {
                                printk(ERR_LEAD "received sense: ", CMDINFO(DONE_SC));
@@ -1563,19 +1549,14 @@ static void busfree_run(struct Scsi_Host *shpnt)
                        }
 #endif
 
-                       /* restore old command */
-                       memcpy((void *) DONE_SC->cmnd, (void *) DONE_SC->data_cmnd, sizeof(DONE_SC->data_cmnd));
-                       DONE_SC->request_buffer  = DONE_SC->buffer;
-                       DONE_SC->request_bufflen = DONE_SC->bufflen;
-                       DONE_SC->use_sg          = DONE_SC->old_use_sg;
-                       DONE_SC->cmd_len         = DONE_SC->old_cmd_len;
+                       scsi_eh_restore_cmnd(cmd, &sc->ses);
 
-                       DONE_SC->SCp.Status = 0x02;
+                       cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
 
                        HOSTDATA(shpnt)->commands--;
                        if (!HOSTDATA(shpnt)->commands)
                                SETPORT(PORTA, 0);      /* turn led off */
-               } else if(DONE_SC->SCp.Status==0x02) {
+               } else if(DONE_SC->SCp.Status==SAM_STAT_CHECK_CONDITION) {
 #if defined(AHA152X_STAT)
                        HOSTDATA(shpnt)->busfree_with_check_condition++;
 #endif
@@ -1583,24 +1564,19 @@ static void busfree_run(struct Scsi_Host *shpnt)
                        DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC));
 #endif
 
-                       if(!(DONE_SC->SCp.Status & not_issued)) {
+                       if(!(DONE_SC->SCp.phase & not_issued)) {
+                               struct aha152x_scdata *sc;
                                Scsi_Cmnd *ptr = DONE_SC;
                                DONE_SC=NULL;
 #if 0
                                DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
 #endif
 
-                               ptr->cmnd[0]         = REQUEST_SENSE;
-                               ptr->cmnd[1]         = 0;
-                               ptr->cmnd[2]         = 0;
-                               ptr->cmnd[3]         = 0;
-                               ptr->cmnd[4]         = sizeof(ptr->sense_buffer);
-                               ptr->cmnd[5]         = 0;
-                               ptr->cmd_len         = 6;
-                               ptr->use_sg          = 0; 
-                               ptr->request_buffer  = ptr->sense_buffer;
-                               ptr->request_bufflen = sizeof(ptr->sense_buffer);
-                       
+                               sc = SCDATA(ptr);
+                               /* It was allocated in aha152x_internal_queue? */
+                               BUG_ON(!sc);
+                               scsi_eh_prep_cmnd(ptr, &sc->ses, NULL, 0, ~0);
+
                                DO_UNLOCK(flags);
                                aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
                                DO_LOCK(flags);
@@ -1707,12 +1683,7 @@ static void seldo_run(struct Scsi_Host *shpnt)
                ADDMSGO(BUS_DEVICE_RESET);
        } else if (SYNCNEG==0 && SYNCHRONOUS) {
                CURRENT_SC->SCp.phase |= syncneg;
-               ADDMSGO(EXTENDED_MESSAGE);
-               ADDMSGO(3);
-               ADDMSGO(EXTENDED_SDTR);
-               ADDMSGO(50);            /* 200ns */
-               ADDMSGO(8);             /* 8 byte req/ack offset */
-
+               MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8);
                SYNCNEG=1;              /* negotiation in progress */
        }
 
@@ -1845,7 +1816,7 @@ static void msgi_run(struct Scsi_Host *shpnt)
 #if defined(AHA152X_DEBUG)
                if (HOSTDATA(shpnt)->debug & debug_msgi) {
                        printk(INFO_LEAD "inbound message %02x ", CMDINFO(CURRENT_SC), MSGI(0));
-                       scsi_print_msg(&MSGI(0));
+                       spi_print_msg(&MSGI(0));
                        printk("\n");
                }
 #endif
@@ -1933,7 +1904,7 @@ static void msgi_run(struct Scsi_Host *shpnt)
                                                break;
 
                                        printk(INFO_LEAD, CMDINFO(CURRENT_SC));
-                                       scsi_print_msg(&MSGI(0));
+                                       spi_print_msg(&MSGI(0));
                                        printk("\n");
 
                                        ticks = (MSGI(3) * 4 + 49) / 50;
@@ -2031,7 +2002,7 @@ static void msgo_init(struct Scsi_Host *shpnt)
                int i;
 
                printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC));
-               for (i=0; i<MSGOLEN; i+=scsi_print_msg(&MSGO(i)), printk(" "))
+               for (i=0; i<MSGOLEN; i+=spi_print_msg(&MSGO(i)), printk(" "))
                        ;
                printk(")\n");
        }
@@ -2181,7 +2152,8 @@ static void datai_init(struct Scsi_Host *shpnt)
        DATA_LEN=0;
        DPRINTK(debug_datai,
                DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n",
-               CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+               CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
+               scsi_get_resid(CURRENT_SC));
 }
 
 static void datai_run(struct Scsi_Host *shpnt)
@@ -2294,11 +2266,12 @@ static void datai_run(struct Scsi_Host *shpnt)
 
 static void datai_end(struct Scsi_Host *shpnt)
 {
-       CURRENT_SC->resid -= GETSTCNT();
+       CMD_INC_RESID(CURRENT_SC, -GETSTCNT());
 
        DPRINTK(debug_datai,
                DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n",
-               CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid, GETSTCNT());
+               CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
+               scsi_get_resid(CURRENT_SC), GETSTCNT());
 
        SETPORT(SXFRCTL0, CH1|CLRSTCNT);
        SETPORT(DMACNTRL0, 0);
@@ -2319,11 +2292,12 @@ static void datao_init(struct Scsi_Host *shpnt)
        SETPORT(SIMODE0, 0);
        SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
 
-       DATA_LEN = CURRENT_SC->resid;
+       DATA_LEN = scsi_get_resid(CURRENT_SC);
 
        DPRINTK(debug_datao,
                DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
-               CMDINFO(CURRENT_SC), CURRENT_SC->request_bufflen, CURRENT_SC->resid);
+               CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
+               scsi_get_resid(CURRENT_SC));
 }
 
 static void datao_run(struct Scsi_Host *shpnt)
@@ -2347,7 +2321,7 @@ static void datao_run(struct Scsi_Host *shpnt)
                        SETPORT(DMACNTRL0,WRITE_READ|ENDMA|_8BIT);
                        SETPORT(DATAPORT, *CURRENT_SC->SCp.ptr++);
                        CURRENT_SC->SCp.this_residual--;
-                       CURRENT_SC->resid--;
+                       CMD_INC_RESID(CURRENT_SC, -1);
                        SETPORT(DMACNTRL0,WRITE_READ|ENDMA);
                }
 
@@ -2356,7 +2330,7 @@ static void datao_run(struct Scsi_Host *shpnt)
                        outsw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
                        CURRENT_SC->SCp.ptr           += 2 * data_count;
                        CURRENT_SC->SCp.this_residual -= 2 * data_count;
-                       CURRENT_SC->resid             -= 2 * data_count;
+                       CMD_INC_RESID(CURRENT_SC, -2 * data_count);
                }
 
                if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
@@ -2382,35 +2356,34 @@ static void datao_run(struct Scsi_Host *shpnt)
 static void datao_end(struct Scsi_Host *shpnt)
 {
        if(TESTLO(DMASTAT, DFIFOEMP)) {
-               int data_count = (DATA_LEN - CURRENT_SC->resid) - GETSTCNT();
+               int data_count = (DATA_LEN - scsi_get_resid(CURRENT_SC)) -
+                                                                   GETSTCNT();
 
                DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transferred)\n",
                        CMDINFO(CURRENT_SC),
                        data_count,
-                       DATA_LEN-CURRENT_SC->resid,
+                       DATA_LEN - scsi_get_resid(CURRENT_SC),
                        GETSTCNT());
 
-               CURRENT_SC->resid += data_count;
+               CMD_INC_RESID(CURRENT_SC, data_count);
 
-               if(CURRENT_SC->use_sg) {
-                       data_count -= CURRENT_SC->SCp.ptr - SG_ADDRESS(CURRENT_SC->SCp.buffer);
-                       while(data_count>0) {
-                               CURRENT_SC->SCp.buffer--;
-                               CURRENT_SC->SCp.buffers_residual++;
-                               data_count -= CURRENT_SC->SCp.buffer->length;
-                       }
-                       CURRENT_SC->SCp.ptr           = SG_ADDRESS(CURRENT_SC->SCp.buffer) - data_count;
-                       CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length + data_count;
-               } else {
-                       CURRENT_SC->SCp.ptr           -= data_count;
-                       CURRENT_SC->SCp.this_residual += data_count;
+               data_count -= CURRENT_SC->SCp.ptr -
+                                            SG_ADDRESS(CURRENT_SC->SCp.buffer);
+               while(data_count>0) {
+                       CURRENT_SC->SCp.buffer--;
+                       CURRENT_SC->SCp.buffers_residual++;
+                       data_count -= CURRENT_SC->SCp.buffer->length;
                }
+               CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) -
+                                                                    data_count;
+               CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length +
+                                                                    data_count;
        }
 
        DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n",
                CMDINFO(CURRENT_SC),
-               CURRENT_SC->request_bufflen,
-               CURRENT_SC->resid,
+               scsi_bufflen(CURRENT_SC),
+               scsi_get_resid(CURRENT_SC),
                GETSTCNT());
 
        SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
@@ -2526,7 +2499,18 @@ static void is_complete(struct Scsi_Host *shpnt)
        unsigned long flags;
        int pending;
 
+       if(!shpnt)
+               return;
+
        DO_LOCK(flags);
+
+       if( HOSTDATA(shpnt)->service==0 )  {
+               DO_UNLOCK(flags);
+               return;
+       }
+
+       HOSTDATA(shpnt)->service = 0;
+
        if(HOSTDATA(shpnt)->in_intr) {
                DO_UNLOCK(flags);
                /* aha152x_error never returns.. */
@@ -2921,13 +2905,12 @@ static void disp_enintr(struct Scsi_Host *shpnt)
  */
 static void show_command(Scsi_Cmnd *ptr)
 {
-       printk(KERN_DEBUG "0x%08x: target=%d; lun=%d; cmnd=(",
-              (unsigned int) ptr, ptr->device->id, ptr->device->lun);
+       scmd_printk(KERN_DEBUG, ptr, "%p: cmnd=(", ptr);
 
        __scsi_print_command(ptr->cmnd);
 
        printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |",
-              ptr->request_bufflen, ptr->resid);
+              scsi_bufflen(ptr), scsi_get_resid(ptr));
 
        if (ptr->SCp.phase & not_issued)
                printk("not issued|");
@@ -2997,7 +2980,8 @@ static int get_command(char *pos, Scsi_Cmnd * ptr)
                SPRINTF("0x%02x ", ptr->cmnd[i]);
 
        SPRINTF("); resid=%d; residual=%d; buffers=%d; phase |",
-               ptr->resid, ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+               scsi_get_resid(ptr), ptr->SCp.this_residual,
+               ptr->SCp.buffers_residual);
 
        if (ptr->SCp.phase & not_issued)
                SPRINTF("not issued|");
@@ -3386,7 +3370,7 @@ static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start
        PDEBUG(debug_datai, "data in");
        PDEBUG(debug_datao, "data out");
        PDEBUG(debug_eh, "eh");
-       PDEBUG(debug_locks, "locks");
+       PDEBUG(debug_locking, "locks");
        PDEBUG(debug_phases, "phases");
 
        SPRINTF("\n");
@@ -3465,7 +3449,13 @@ static int aha152x_proc_info(struct Scsi_Host *shpnt, char *buffer, char **start
        return thislength < length ? thislength : length;
 }
 
-static Scsi_Host_Template aha152x_driver_template = {
+static int aha152x_adjust_queue(struct scsi_device *device)
+{
+       blk_queue_bounce_limit(device->request_queue, BLK_BOUNCE_HIGH);
+       return 0;
+}
+
+static struct scsi_host_template aha152x_driver_template = {
        .module                         = THIS_MODULE,
        .name                           = AHA152X_REVID,
        .proc_name                      = "aha152x",
@@ -3481,6 +3471,7 @@ static Scsi_Host_Template aha152x_driver_template = {
        .sg_tablesize                   = SG_ALL,
        .cmd_per_lun                    = 1,
        .use_clustering                 = DISABLE_CLUSTERING,
+       .slave_alloc                    = aha152x_adjust_queue,
 };
 
 #if !defined(PCMCIA)
@@ -3591,7 +3582,7 @@ static int checksetup(struct aha152x_setup *setup)
        if (i == ARRAY_SIZE(ports))
                return 0;
 
-       if ( request_region(setup->io_port, IO_RANGE, "aha152x")==0 ) {
+       if (!request_region(setup->io_port, IO_RANGE, "aha152x")) {
                printk(KERN_ERR "aha152x: io port 0x%x busy.\n", setup->io_port);
                return 0;
        }
@@ -3839,7 +3830,7 @@ static int __init aha152x_init(void)
                        iounmap(p);
                }
                if (!ok && setup_count == 0)
-                       return 0;
+                       return -ENODEV;
 
                printk(KERN_INFO "aha152x: BIOS test: passed, ");
 #else
@@ -3851,7 +3842,7 @@ static int __init aha152x_init(void)
                        if ((setup_count == 1) && (setup[0].io_port == ports[i]))
                                continue;
 
-                       if ( request_region(ports[i], IO_RANGE, "aha152x")==0 ) {
+                       if (!request_region(ports[i], IO_RANGE, "aha152x")) {
                                printk(KERN_ERR "aha152x: io port 0x%x busy.\n", ports[i]);
                                continue;
                        }
@@ -3918,16 +3909,17 @@ static int __init aha152x_init(void)
 #endif
        }
 
-       return registered_count>0;
+       return 0;
 }
 
 static void __exit aha152x_exit(void)
 {
-       int i;
+       struct aha152x_hostdata *hd, *tmp;
+
+       list_for_each_entry_safe(hd, tmp, &aha152x_host_list, host_list) {
+               struct Scsi_Host *shost = container_of((void *)hd, struct Scsi_Host, hostdata);
 
-       for(i=0; i<ARRAY_SIZE(setup); i++) {
-               aha152x_release(aha152x_host[i]);
-               aha152x_host[i]=NULL;
+               aha152x_release(shost);
        }
 }