]> git.hungrycats.org Git - linux/commitdiff
[PATCH] cciss: retry bus resets
authorAndrew Morton <akpm@digeo.com>
Sun, 2 Mar 2003 12:38:09 +0000 (04:38 -0800)
committerDavid S. Miller <davem@nuts.ninka.net>
Sun, 2 Mar 2003 12:38:09 +0000 (04:38 -0800)
Patch from Stephen Cameron <steve.cameron@hp.com>

Make cciss driver retry 3rd party bus reset aborted commands up to 3 times.
(ported to 2.5 by me, original patch by Charles White)

This is needed for a multi port storage box that can have multiple hosts
connected to it, or be used in a multipath configuration.  In certain
configurations SCSI bus resets initiated by one host may affect another host.

drivers/block/cciss.c
drivers/block/cciss_cmd.h

index 4e2ce7ab22b3a4731a3e7d50a5517c08fa351078..69fa9ec0d99fab91b2895c77171366f4d12cfbb5 100644 (file)
@@ -90,6 +90,9 @@ static struct board_type products[] = {
 #define MAX_CONFIG_WAIT 30000 
 #define MAX_IOCTL_CONFIG_WAIT 1000
 
+/*define how many times we will try a command because of bus resets */
+#define MAX_CMD_RETRIES 3
+
 #define READ_AHEAD      128
 #define NR_CMDS                 384 /* #commands that can be outstanding */
 #define MAX_CTLR 8
@@ -922,6 +925,7 @@ static int sendcmd_withirq(__u8     cmd,
                c->SG[0].Len = size;
                c->SG[0].Ext = 0;  // we are not chaining
        }
+resend_cmd2:
        c->waiting = &wait;
        
        /* Put the request on the tail of the queue and send it */
@@ -933,10 +937,6 @@ static int sendcmd_withirq(__u8    cmd,
        
        wait_for_completion(&wait);
 
-       /* unlock the buffers from DMA */
-        pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
-                       size, PCI_DMA_BIDIRECTIONAL);
-
        if(c->err_info->CommandStatus != 0) 
        { /* an error has occurred */ 
                switch(c->err_info->CommandStatus)
@@ -988,11 +988,22 @@ case CMD_HARDWARE_ERR:
                                return_status = IO_ERROR;
                        break;
                        case CMD_UNSOLICITED_ABORT:
-                               printk(KERN_WARNING "cciss: cmd %p aborted "
-                                       "do to an unsolicited abort\n", c);
+                               printk(KERN_WARNING 
+                                       "cciss%d: unsolicited abort %p\n",
+                                       ctlr, c);
+                               if (c->retry_count < MAX_CMD_RETRIES) {
+                                       printk(KERN_WARNING 
+                                               "cciss%d: retrying %p\n", 
+                                               ctlr, c);
+                                       c->retry_count++;
+                                       /* erase the old error information */
+                                       memset(c->err_info, 0,
+                                               sizeof(ErrorInfo_struct));
+                                       return_status = IO_OK;
+                                       INIT_COMPLETION(wait);
+                                       goto resend_cmd2;
+                               }
                                return_status = IO_ERROR;
-
-
                        break;
                        default:
                                printk(KERN_WARNING "cciss: cmd %p returned "
@@ -1001,6 +1012,9 @@ case CMD_HARDWARE_ERR:
                                return_status = IO_ERROR;
                }
        }       
+       /* unlock the buffers from DMA */
+       pci_unmap_single( h->pdev, (dma_addr_t) buff_dma_handle.val,
+                       size, PCI_DMA_BIDIRECTIONAL);
        cmd_free(h, c, 0);
         return(return_status);
 
@@ -1271,6 +1285,7 @@ static int sendcmd(
        unsigned long complete;
        ctlr_info_t *info_p= hba[ctlr];
        u64bit buff_dma_handle;
+       int status = IO_OK;
 
        c = cmd_alloc(info_p, 1);
        if (c == NULL)
@@ -1384,6 +1399,7 @@ static int sendcmd(
                c->SG[0].Len = size;
                c->SG[0].Ext = 0;  // we are not chaining
        }
+resend_cmd1:
        /*
          * Disable interrupt
          */
@@ -1416,9 +1432,6 @@ static int sendcmd(
        printk(KERN_DEBUG "cciss: command completed\n");
 #endif /* CCISS_DEBUG */
 
-       /* unlock the data buffer from DMA */
-       pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
-                                size, PCI_DMA_BIDIRECTIONAL);
        if (complete != 1) {
                if ( (complete & CISS_ERROR_BIT)
                     && (complete & ~CISS_ERROR_BIT) == c->busaddr)
@@ -1436,8 +1449,30 @@ static int sendcmd(
                                ))
                        {
                                complete = c->busaddr;
-                       } else
-                       {
+                       } else {
+                               if (c->err_info->CommandStatus ==
+                                               CMD_UNSOLICITED_ABORT) {
+                                       printk(KERN_WARNING "cciss%d: "
+                                               "unsolicited abort %p\n",
+                                               ctlr, c);
+                                       if (c->retry_count < MAX_CMD_RETRIES) {
+                                               printk(KERN_WARNING
+                                                  "cciss%d: retrying %p\n",
+                                                  ctlr, c);
+                                               c->retry_count++;
+                                               /* erase the old error */
+                                               /* information */
+                                               memset(c->err_info, 0,
+                                                  sizeof(ErrorInfo_struct));
+                                               goto resend_cmd1;
+                                       } else {
+                                               printk(KERN_WARNING
+                                                  "cciss%d: retried %p too "
+                                                  "many times\n", ctlr, c);
+                                               status = IO_ERROR;
+                                               goto cleanup1;
+                                       }
+                               }
                                printk(KERN_WARNING "ciss ciss%d: sendcmd"
                                " Error %x \n", ctlr, 
                                        c->err_info->CommandStatus); 
@@ -1447,27 +1482,31 @@ static int sendcmd(
                                  c->err_info->MoreErrInfo.Invalid_Cmd.offense_size,
                                  c->err_info->MoreErrInfo.Invalid_Cmd.offense_num,
                                  c->err_info->MoreErrInfo.Invalid_Cmd.offense_value);
-                               cmd_free(info_p,c, 1);
-                               return(IO_ERROR);
+                               status = IO_ERROR;
+                               goto cleanup1;
                        }
                }
                 if (complete != c->busaddr) {
                         printk( KERN_WARNING "cciss cciss%d: SendCmd "
                       "Invalid command list address returned! (%lx)\n",
                                 ctlr, complete);
-                        cmd_free(info_p, c, 1);
-                        return (IO_ERROR);
+                       status = IO_ERROR;
+                       goto cleanup1;
                 }
         } else {
                 printk( KERN_WARNING
                         "cciss cciss%d: SendCmd Timeout out, "
                         "No command list address returned!\n",
                         ctlr);
-                cmd_free(info_p, c, 1);
-                return (IO_ERROR);
+               status = IO_ERROR;
         }
+               
+cleanup1:      
+       /* unlock the data buffer from DMA */
+       pci_unmap_single(info_p->pdev, (dma_addr_t) buff_dma_handle.val,
+                               size, PCI_DMA_BIDIRECTIONAL);
        cmd_free(info_p, c, 1);
-        return (IO_OK);
+       return (status);
 } 
 /*
  * Map (physical) PCI mem into (virtual) kernel space
@@ -1551,27 +1590,35 @@ static inline void complete_buffers(struct bio *bio, int status)
        }
 
 } 
+/* Assumes that CCISS_LOCK(h->ctlr) is held. */
+/* Zeros out the error record and then resends the command back */
+/* to the controller */
+static inline void resend_cciss_cmd( ctlr_info_t *h, CommandList_struct *c)
+{
+       /* erase the old error information */
+       memset(c->err_info, 0, sizeof(ErrorInfo_struct));
+
+       /* add it to software queue and then send it to the controller */
+       addQ(&(h->reqQ),c);
+       h->Qdepth++;
+       if(h->Qdepth > h->maxQsinceinit)
+               h->maxQsinceinit = h->Qdepth;
+
+       start_io(h);
+}
 /* checks the status of the job and calls complete buffers to mark all 
  * buffers for the completed job. 
  */ 
-static inline void complete_command( CommandList_struct *cmd, int timeout)
+static inline void complete_command( ctlr_info_t *h, CommandList_struct *cmd,
+               int timeout)
 {
        int status = 1;
        int i;
+       int retry_cmd = 0;
        u64bit temp64;
                
        if (timeout)
                status = 0; 
-       /* unmap the DMA mapping for all the scatter gather elements */
-       for(i=0; i<cmd->Header.SGList; i++)
-       {
-               temp64.val32.lower = cmd->SG[i].Addr.lower;
-               temp64.val32.upper = cmd->SG[i].Addr.upper;
-               pci_unmap_page(hba[cmd->ctlr]->pdev,
-                       temp64.val, cmd->SG[i].Len, 
-                       (cmd->Request.Type.Direction == XFER_READ) ? 
-                               PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
-       }
 
        if(cmd->err_info->CommandStatus != 0) 
        { /* an error has occurred */ 
@@ -1645,8 +1692,18 @@ static inline void complete_command( CommandList_struct *cmd, int timeout)
                                status=0;
                        break;
                        case CMD_UNSOLICITED_ABORT:
-                               printk(KERN_WARNING "cciss: cmd %p aborted "
-                                       "do to an unsolicited abort\n", cmd);
+                               printk(KERN_WARNING "cciss%d: unsolicited "
+                                       "abort %p\n", h->ctlr, cmd);
+                               if (cmd->retry_count < MAX_CMD_RETRIES) {
+                                       retry_cmd=1;
+                                       printk(KERN_WARNING
+                                               "cciss%d: retrying %p\n",
+                                               h->ctlr, cmd);
+                                       cmd->retry_count++;
+                               } else
+                                       printk(KERN_WARNING
+                                               "cciss%d: %p retried too "
+                                               "many times\n", h->ctlr, cmd);
                                status=0;
                        break;
                        case CMD_TIMEOUT:
@@ -1661,7 +1718,21 @@ static inline void complete_command( CommandList_struct *cmd, int timeout)
                                status=0;
                }
        }
-
+       /* We need to return this command */
+       if(retry_cmd) {
+               resend_cciss_cmd(h,cmd);
+               return;
+       }       
+       /* command did not need to be retried */
+       /* unmap the DMA mapping for all the scatter gather elements */
+       for(i=0; i<cmd->Header.SGList; i++) {
+               temp64.val32.lower = cmd->SG[i].Addr.lower;
+               temp64.val32.upper = cmd->SG[i].Addr.upper;
+               pci_unmap_page(hba[cmd->ctlr]->pdev,
+                       temp64.val, cmd->SG[i].Len,
+                       (cmd->Request.Type.Direction == XFER_READ) ?
+                               PCI_DMA_FROMDEVICE : PCI_DMA_TODEVICE);
+       }
        complete_buffers(cmd->rq->bio, status);
 
 #ifdef CCISS_DEBUG
@@ -1669,6 +1740,7 @@ static inline void complete_command( CommandList_struct *cmd, int timeout)
 #endif /* CCISS_DEBUG */ 
 
        end_that_request_last(cmd->rq);
+       cmd_free(h,cmd,1);
 }
 
 /* 
@@ -1815,8 +1887,7 @@ static void do_cciss_intr(int irq, void *dev_id, struct pt_regs *regs)
                         if (c->busaddr == a) {
                                removeQ(&h->cmpQ, c);
                                if (c->cmd_type == CMD_RWREQ) {
-                                       complete_command(c, 0);
-                                       cmd_free(h, c, 1);
+                                       complete_command(h, c, 0);
                                } else if (c->cmd_type == CMD_IOCTL_PEND) {
                                        complete(c->waiting);
                                }
index f2449b22ec8623501720a33ef874ed7f5ba88d4e..568c74e44f2d7f056fc2874a77ff518bcccf7fd2 100644 (file)
@@ -240,6 +240,7 @@ typedef struct _CommandList_struct {
   struct _CommandList_struct *next;
   struct request *        rq;
   struct completion *waiting;
+  int   retry_count;
 #ifdef CONFIG_CISS_SCSI_TAPE
   void * scsi_cmd;
 #endif