]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] 3ware driver update for 2.5.8-pre1
authorAdam Radford <adam@nmt.edu>
Wed, 3 Apr 2002 03:20:06 +0000 (19:20 -0800)
committerDave Jones <davej@suse.de>
Wed, 3 Apr 2002 03:20:06 +0000 (19:20 -0800)
Self explanatory driver update from vendor.

drivers/scsi/3w-xxxx.c
drivers/scsi/3w-xxxx.h

index 4b02451d2877afe12c72cb3fd407ac2d14e9c57f..c7ccb6c0ad21b30dc1d8b3e6cf27d437cc3242f6 100644 (file)
                  some SMP systems.
    1.02.00.020 - Add pci_set_dma_mask(), rewrite kmalloc()/virt_to_bus() to
                  pci_alloc/free_consistent().
+                 Better alignment checking in tw_allocate_memory().
+                 Cleanup tw_initialize_device_extension().
+   1.02.00.021 - 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.
+                 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>
@@ -182,7 +190,7 @@ static struct notifier_block tw_notifier = {
 };
 
 /* Globals */
-char *tw_driver_version="1.02.00.020";
+char *tw_driver_version="1.02.00.021";
 TW_Device_Extension *tw_device_extension_list[TW_MAX_SLOT];
 int tw_device_extension_count = 0;
 
@@ -284,6 +292,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");
@@ -337,7 +348,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) {
@@ -451,7 +462,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) {
@@ -571,13 +582,23 @@ int tw_check_errors(TW_Device_Extension *tw_dev)
        status_reg_value = inl(status_reg_addr);
 
        if (TW_STATUS_ERRORS(status_reg_value) || tw_check_bits(status_reg_value)) {
-               tw_decode_bits(tw_dev, 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)
 {
@@ -632,30 +653,51 @@ 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: clearing.\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);
                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 return valid sense buffer information for failed cmds */
-void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
+int tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense)
 {
-       int i, found=0;
+       int i;
        TW_Command *command;
 
         dprintk(KERN_WARNING "3w-xxxx: tw_decode_sense()\n");
@@ -668,7 +710,6 @@ void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int 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]) {
-                                       found=1;
 
                                        /* Valid bit and 'current errors' */
                                        tw_dev->srb[request_id]->sense_buffer[0] = (0x1 << 7 | 0x70);
@@ -686,13 +727,16 @@ void tw_decode_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense
                                        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 */
                                }
                        }
                }
+
                /* If no table match, error so we get a reset */
-               if (found == 0)
-                       tw_dev->srb[request_id]->result = (DID_RESET << 16);
+               return 1;
        }
+
+       return 0;
 } /* End tw_decode_sense() */
 
 /* This function will disable interrupts on the controller */  
@@ -706,7 +750,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;
@@ -716,22 +760,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 */
@@ -811,8 +843,8 @@ int tw_findcards(Scsi_Host_Template *tw_host)
 
                        /* 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);
+                       if (TW_STATUS_ERRORS(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)) {
@@ -843,14 +875,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;
                        }
@@ -877,7 +901,7 @@ int tw_findcards(Scsi_Host_Template *tw_host)
                        request_region((tw_dev->tw_pci_dev->resource[0].start), 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 for card %d.\n", numcards);
                                release_region((tw_dev->tw_pci_dev->resource[0].start), TW_IO_ADDRESS_RANGE);
                                tw_free_device_extension(tw_dev);
                                kfree(tw_dev);
@@ -895,7 +919,7 @@ int tw_findcards(Scsi_Host_Template *tw_host)
 
                        /* Calculate max cmds per lun, and setup queues */
                        if (tw_dev->num_units > 0) {
-                               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;
@@ -1064,7 +1088,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) {
@@ -1191,7 +1215,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) {
@@ -1251,51 +1275,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 host lock for io completions */
        spin_lock_irqsave(tw_dev->host->host_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 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");
-                       tw_decode_bits(tw_dev, status_reg_value);
+                       if (tw_decode_bits(tw_dev, status_reg_value, 1)) {
+                               tw_clear_all_interrupts(tw_dev);
+                               goto tw_interrupt_bail;
+                       }
                }
 
-               /* 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;
-
                /* 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);
@@ -1307,7 +1332,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];
@@ -1323,6 +1348,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;
                                }
                        }
@@ -1332,40 +1358,40 @@ 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) {
-                                       /* Bad response */
-                                       if (tw_dev->srb[request_id] != 0)
-                                               tw_decode_sense(tw_dev, request_id, 1);
-                                       error = 3;
+                                       /* If internal command, 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 {
                                switch (tw_dev->srb[request_id]->cmnd[0]) {
                                        case READ_10:
@@ -1389,20 +1415,22 @@ 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--;
@@ -1410,16 +1438,24 @@ static void tw_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
 
                                                tw_unmap_scsi_data(tw_dev->tw_pci_dev, 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(tw_dev->host->host_lock, flags);
        clear_bit(TW_IN_INTR, &tw_dev->flags);
 } /* End tw_interrupt() */
@@ -1782,7 +1818,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];
@@ -1852,7 +1888,7 @@ int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
 
        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);
+               tw_decode_bits(tw_dev, status_reg_value, 0);
        }
                
        while ((status_reg_value & flag) != flag) {
@@ -1860,7 +1896,7 @@ int tw_poll_status(TW_Device_Extension *tw_dev, u32 flag, int seconds)
 
                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);
+                       tw_decode_bits(tw_dev, status_reg_value, 0);
                }
 
                do_gettimeofday(&timeout);
@@ -1887,7 +1923,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) {
@@ -1941,7 +1977,6 @@ int tw_reset_device_extension(TW_Device_Extension *tw_dev)
                    (tw_dev->state[i] != TW_S_COMPLETED)) {
                        srb = tw_dev->srb[i];
                        if (srb != NULL) {
-                               srb = tw_dev->srb[i];
                                srb->result = (DID_RESET << 16);
                                tw_dev->srb[i]->scsi_done(tw_dev->srb[i]);
                                tw_unmap_scsi_data(tw_dev->tw_pci_dev, tw_dev->srb[i]);
@@ -1960,6 +1995,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() */
@@ -1991,14 +2027,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;
        }
@@ -2086,11 +2114,6 @@ int tw_scsi_eh_abort(Scsi_Cmnd *SCpnt)
                return (FAILED);
        }
 
-       /* We have to let AEN requests through before the reset */
-       spin_unlock_irq(tw_dev->host->host_lock);
-       mdelay(TW_AEN_WAIT_TIME);
-       spin_lock_irq(tw_dev->host->host_lock);
-
        spin_lock(&tw_dev->tw_lock);
        tw_dev->num_aborts++;
 
@@ -2117,18 +2140,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(tw_dev->host->host_lock);
+                               mdelay(TW_AEN_WAIT_TIME);
+                               spin_lock_irq(tw_dev->host->host_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() */
 
@@ -2593,7 +2624,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;
@@ -2628,6 +2659,7 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
                buffaddr = tw_map_scsi_single_data(tw_dev->tw_pci_dev, tw_dev->srb[request_id]);
                command_packet->byte8.io.sgl[0].address = buffaddr;
                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 */
@@ -2638,8 +2670,6 @@ int tw_scsiop_read_write(TW_Device_Extension *tw_dev, int request_id)
                        command_packet->byte8.io.sgl[i].length = sg_dma_len(&sglist[i]);
                        command_packet->size+=2;
                }
-               if (tw_dev->srb[request_id]->use_sg >= 1)
-                       command_packet->size-=2;
        }
 
        /* Update SG statistics */
@@ -2754,7 +2784,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) {
index 5ab618c7168bef0bfe7ec7ddbf66da5fa0ed6c98..37ae5521d0d9e223fd8c5f2f4e6ed2b6fc907b88 100644 (file)
@@ -92,10 +92,11 @@ 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
@@ -134,7 +135,9 @@ static unsigned char tw_sense_table[][4] =
 #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
@@ -154,7 +157,9 @@ static unsigned char tw_sense_table[][4] =
 #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
@@ -214,7 +219,7 @@ static unsigned char tw_sense_table[][4] =
 #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
@@ -223,6 +228,8 @@ static unsigned char tw_sense_table[][4] =
 #define TW_MAX_SECTORS                        256
 #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) \
@@ -235,7 +242,7 @@ static unsigned char tw_sense_table[][4] =
 #ifdef TW_DEBUG
 #define dprintk(msg...) printk(msg)
 #else
-#define dprintk(msg...) do { } while(0);
+#define dprintk(msg...) do { } while(0)
 #endif
 
 /* Scatter Gather List Entry */
@@ -402,8 +409,9 @@ typedef struct TAG_TW_Device_Extension {
        unsigned short          aen_queue[TW_Q_LENGTH];
        unsigned char           aen_head;
        unsigned char           aen_tail;
-       long                    flags; /* long req'd for set_bit --RR */
+       volatile long           flags; /* long req'd for set_bit --RR */
        char                    *ioctl_data[TW_Q_LENGTH];
+       int                     reset_print;
 } TW_Device_Extension;
 
 /* Function prototypes */
@@ -413,12 +421,13 @@ int tw_aen_read_queue(TW_Device_Extension *tw_dev, int request_id);
 int tw_allocate_memory(TW_Device_Extension *tw_dev, 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_sense(TW_Device_Extension *tw_dev, int request_id, int fill_sense);
+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);
@@ -478,7 +487,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,               \