diff -aupr linux-2.6.13/drivers/scsi-r/cpqfcTSinit.c linux-2.6.13/drivers/scsi/cpqfcTSinit.c --- linux-2.6.13/drivers/scsi/cpqfcTSinit.c 2005-09-01 21:27:12.000000000 +0200 +++ linux-2.6.13-e/drivers/scsi/cpqfcTSinit.c 2005-09-01 21:39:50.000000000 +0200 @@ -64,6 +64,7 @@ MODULE_DESCRIPTION("Driver for Compaq 64 MODULE_LICENSE("GPL"); int cpqfcTS_TargetDeviceReset( Scsi_Device *ScsiDev, unsigned int reset_flags); +static void cpqfc_tasklet_func(unsigned long); // This struct was originally defined in // /usr/src/linux/include/linux/proc_fs.h @@ -315,6 +316,7 @@ int cpqfcTS_detect(Scsi_Host_Template *S memset(cpqfcHBAdata, 0, sizeof(*cpqfcHBAdata)); // initialize our HBA info + tasklet_init(&cpqfcHBAdata->hosttask, cpqfc_tasklet_func, (unsigned long) cpqfcHBAdata); cpqfcHBAdata->HBAnum = NumberOfAdapters; cpqfcHBAdata->HostAdapter = HostAdapter; // back ptr @@ -716,7 +718,9 @@ int cpqfcTS_release(struct Scsi_Host *Ho ENTER("cpqfcTS_release"); - + + tasklet_kill(&cpqfcHBAdata->hosttask); + DEBUG_PCI( printk(" cpqfcTS: delete timer...\n")); del_timer( &cpqfcHBAdata->cpqfcTStimer); @@ -1631,17 +1635,40 @@ int cpqfcTS_biosparam(struct scsi_device return 0; } - +static void +cpqfc_tasklet_func(unsigned long data) +{ + CPQFCHBA *cpqfcHBA = (void*) data; + struct Scsi_Host *scsihost = cpqfcHBA->HostAdapter; + unsigned long flags; + int i = 0, r = 1; + + ENTER(__FUNCTION__); + spin_lock_irqsave(scsihost->host_lock, flags); + /* broken boards can generate messages forever, so + * prevent the infinite loop */ +#define INFINITE_IMQ_BREAK 10000 + while ((++i < INFINITE_IMQ_BREAK) && (r > 0)) { + r = CpqTsProcessIMQEntry(scsihost); + } + if (i >= INFINITE_IMQ_BREAK) { + printk(KERN_WARNING "Compaq FC adapter generating excessive interrupts\n"); + } else { + /* working normally - re-enable INTs and continue */ + writeb(0x1F, cpqfcHBA->fcChip.Registers.INTEN.address); + } + spin_unlock_irqrestore(scsihost->host_lock, flags); + LEAVE(__FUNCTION__); +} irqreturn_t cpqfcTS_intr_handler( int irq, void *dev_id, struct pt_regs *regs) { - unsigned long flags, InfLoopBrk=0; + unsigned long flags; struct Scsi_Host *HostAdapter = dev_id; CPQFCHBA *cpqfcHBA = (CPQFCHBA *)HostAdapter->hostdata; - int MoreMessages = 1; // assume we have something to do UCHAR IntPending; int handled = 0; @@ -1650,34 +1679,18 @@ irqreturn_t cpqfcTS_intr_handler( int ir // is this our INT? IntPending = readb( cpqfcHBA->fcChip.Registers.INTPEND.address); - // broken boards can generate messages forever, so - // prevent the infinite loop -#define INFINITE_IMQ_BREAK 10000 if( IntPending ) { handled = 1; // mask our HBA interrupts until we handle it... writeb( 0, cpqfcHBA->fcChip.Registers.INTEN.address); - if( IntPending & 0x4) // "INT" - Tach wrote to IMQ - { - while( (++InfLoopBrk < INFINITE_IMQ_BREAK) && (MoreMessages ==1) ) - { - MoreMessages = CpqTsProcessIMQEntry( HostAdapter); // ret 0 when done - } - if( InfLoopBrk >= INFINITE_IMQ_BREAK ) - { - printk("WARNING: Compaq FC adapter generating excessive INTs -REPLACE\n"); - printk("or investigate alternate causes (e.g. physical FC layer)\n"); - } - - else // working normally - re-enable INTs and continue - writeb( 0x1F, cpqfcHBA->fcChip.Registers.INTEN.address); - - } // (...ProcessIMQEntry() clears INT by writing IMQ consumer) - else // indications of errors or problems... - // these usually indicate critical system hardware problems. - { + if (IntPending & 0x4) { + /* normal IRQ, schedule tasklet for handling */ + tasklet_schedule(&cpqfcHBA->hosttask); + } else { + /* indications of errors or problems... + * these usually indicate critical system hardware problems. */ if( IntPending & 0x10 ) printk(" cpqfcTS adapter external memory parity error detected\n"); if( IntPending & 0x8 ) diff -aupr linux-2.6.13/drivers/scsi-r/cpqfcTSstructs.h linux-2.6.13/drivers/scsi/cpqfcTSstructs.h --- linux-2.6.13/drivers/scsi/cpqfcTSstructs.h 2005-09-01 21:27:12.000000000 +0200 +++ linux-2.6.13-e/drivers/scsi/cpqfcTSstructs.h 2005-09-01 21:27:59.000000000 +0200 @@ -952,6 +952,7 @@ typedef struct cpqfc_passthru_private_t *private_data_pool; unsigned long *private_data_bits; + struct tasklet_struct hosttask; } CPQFCHBA; #define CPQ_SPINLOCK_HBA( x ) spin_lock(&x->hba_spinlock);