[PATCH] advansys scsi driver 2.5.3-pre1

From: Douglas Gilbert (dougg@torque.net)
Date: Wed Jan 16 2002 - 00:49:52 EST


Here is another attempt to fix the advansys scsi
adapter driver (it has been functionally broken
for the lk 2.5 series to date).
This time for lk 2.5.3-pre1 .

It has been tested on advansys U2W and 940U adapters on
a Athlon UP box. It has also been tested on UW adapter
on a dual Celeron (SMP) box. This post is being
written on the former system.

Note for other scsi adapter driver patchers in lk 2.5.2+ ...
'host_lock' is now a pointer to a spinlock_t (before 2.5.2
it was an instance).

After today's "patch included or attached" thread this patch
appears below and is attached.

Doug Gilbert

--- linux/drivers/scsi/advansys.c Tue Jan 15 19:11:49 2002
+++ linux/drivers/scsi/advansys.cmin4 Wed Jan 16 00:13:21 2002
@@ -1,4 +1,4 @@
-#define ASC_VERSION "3.3G" /* AdvanSys Driver Version */
+#define ASC_VERSION "3.3GH" /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
@@ -670,6 +670,9 @@
          1. Return an error from narrow boards if passed a 16 byte
             CDB. The wide board can already handle 16 byte CDBs.
 
+ 3.3GH (1/15/02):
+ 1. hacks for lk 2.5 series (D. Gilbert)
+
   I. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
@@ -4054,6 +4057,7 @@
         ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
     } eep_config;
     ulong last_reset; /* Saved last reset time */
+ spinlock_t lock; /* Board spinlock */
 #ifdef CONFIG_PROC_FS
     /* /proc/scsi/advansys/[0...] */
     char *prtbuf; /* /proc print buffer */
@@ -4206,7 +4210,7 @@
 STATIC void advansys_interrupt(int, void *, struct pt_regs *);
 STATIC void advansys_select_queue_depths(struct Scsi_Host *,
                                                Scsi_Device *);
-STATIC void asc_scsi_done_list(Scsi_Cmnd *);
+STATIC void asc_scsi_done_list(Scsi_Cmnd *, int from_isr);
 STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int asc_build_req(asc_board_t *, Scsi_Cmnd *);
 STATIC int adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
@@ -4799,6 +4803,9 @@
             memset(boardp, 0, sizeof(asc_board_t));
             boardp->id = asc_board_count - 1;
 
+ /* Initialize spinlock. */
+ boardp->lock = SPIN_LOCK_UNLOCKED;
+
             /*
              * Handle both narrow and wide boards.
              *
@@ -5511,7 +5518,7 @@
                 }
             } else {
                 ADV_CARR_T *carrp;
- int req_cnt;
+ int req_cnt = 0;
                 adv_req_t *reqp = NULL;
                 int sg_cnt = 0;
 
@@ -5845,7 +5852,9 @@
     boardp = ASC_BOARDP(shp);
     ASC_STATS(shp, queuecommand);
 
- spin_lock_irqsave(&shp->host_lock, flags);
+ /* host_lock taken by mid-level prior to call but need to protect */
+ /* against own ISR */
+ spin_lock_irqsave(&boardp->lock, flags);
 
     /*
      * Block new commands while handling a reset or abort request.
@@ -5862,7 +5871,7 @@
          * handling.
          */
         asc_enqueue(&boardp->done, scp, ASC_BACK);
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
         return 0;
     }
 
@@ -5902,11 +5911,11 @@
     default:
         done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
         /* Interrupts could be enabled here. */
- asc_scsi_done_list(done_scp);
+ asc_scsi_done_list(done_scp, 0);
         break;
     }
+ spin_unlock_irqrestore(&boardp->lock, flags);
 
- spin_unlock_irqrestore(&shp->host_lock, flags);
     return 0;
 }
 
@@ -5952,13 +5961,13 @@
     /*
      * Check for re-entrancy.
      */
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
     if (boardp->flags & ASC_HOST_IN_RESET) {
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
         return FAILED;
     }
     boardp->flags |= ASC_HOST_IN_RESET;
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
 
     if (ASC_NARROW_BOARD(boardp)) {
         /*
@@ -5989,11 +5998,7 @@
         }
 
         ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
-
- /*
- * Acquire the board lock.
- */
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
 
     } else {
         /*
@@ -6020,14 +6025,9 @@
             ret = FAILED;
             break;
         }
- /*
- * Acquire the board lock and ensure all requests completed by the
- * microcode have been processed by calling AdvISR().
- */
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
         (void) AdvISR(adv_dvc_varp);
     }
-
     /* Board lock is held. */
 
     /*
@@ -6088,15 +6088,13 @@
 
     /* Clear reset flag. */
     boardp->flags &= ~ASC_HOST_IN_RESET;
-
- /* Release the board. */
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
 
     /*
      * Complete all the 'done_scp' requests.
      */
     if (done_scp != NULL) {
- asc_scsi_done_list(done_scp);
+ asc_scsi_done_list(done_scp, 0);
     }
 
     ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
@@ -6259,6 +6257,7 @@
     asc_board_t *boardp;
     Scsi_Cmnd *done_scp = NULL, *last_scp = NULL;
     Scsi_Cmnd *new_last_scp;
+ struct Scsi_Host *shp;
 
     ASC_DBG(1, "advansys_interrupt: begin\n");
 
@@ -6267,17 +6266,17 @@
      * AscISR() will call asc_isr_callback().
      */
     for (i = 0; i < asc_board_count; i++) {
- struct Scsi_Host *shp = asc_host[i];
+ shp = asc_host[i];
         boardp = ASC_BOARDP(shp);
         ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
             i, (ulong) boardp);
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
         if (ASC_NARROW_BOARD(boardp)) {
             /*
              * Narrow Board
              */
- if (AscIsIntPending(asc_host[i]->io_port)) {
- ASC_STATS(asc_host[i], interrupt);
+ if (AscIsIntPending(shp->io_port)) {
+ ASC_STATS(shp, interrupt);
                 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
                 AscISR(&boardp->dvc_var.asc_dvc_var);
             }
@@ -6287,7 +6286,7 @@
              */
             ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
             if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
- ASC_STATS(asc_host[i], interrupt);
+ ASC_STATS(shp, interrupt);
             }
         }
 
@@ -6327,7 +6326,7 @@
                 }
             }
         }
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
     }
 
     /*
@@ -6336,7 +6335,8 @@
      *
      * Complete all requests on the done list.
      */
- asc_scsi_done_list(done_scp);
+
+ asc_scsi_done_list(done_scp, 1);
 
     ASC_DBG(1, "advansys_interrupt: end\n");
     return;
@@ -6383,9 +6383,10 @@
  * Interrupts can be enabled on entry.
  */
 STATIC void
-asc_scsi_done_list(Scsi_Cmnd *scp)
+asc_scsi_done_list(Scsi_Cmnd *scp, int from_isr)
 {
     Scsi_Cmnd *tscp;
+ ulong flags = 0;
 
     ASC_DBG(2, "asc_scsi_done_list: begin\n");
     while (scp != NULL) {
@@ -6394,7 +6395,11 @@
         REQPNEXT(scp) = NULL;
         ASC_STATS(scp->host, done);
         ASC_ASSERT(scp->scsi_done != NULL);
+ if (from_isr)
+ spin_lock_irqsave(scp->host->host_lock, flags);
         scp->scsi_done(scp);
+ if (from_isr)
+ spin_unlock_irqrestore(scp->host->host_lock, flags);
         scp = tscp;
     }
     ASC_DBG(2, "asc_scsi_done_list: done\n");
@@ -6728,7 +6733,9 @@
         slp = (struct scatterlist *) scp->request_buffer;
         for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
             asc_sg_head.sg_list[sgcnt].addr =
- cpu_to_le32(virt_to_bus(slp->address));
+ cpu_to_le32(virt_to_bus(slp->address ?
+ (unsigned char *)slp->address :
+ (unsigned char *)page_address(slp->page) + slp->offset));
             asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
         }
@@ -6986,7 +6993,9 @@
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
             sg_block->sg_list[i].sg_addr =
- cpu_to_le32(virt_to_bus(slp->address));
+ cpu_to_le32(virt_to_bus(slp->address ?
+ (unsigned char *)slp->address :
+ (unsigned char *)page_address(slp->page) + slp->offset));
             sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 
@@ -9411,8 +9420,9 @@
         s->dma_channel, s->this_id, s->can_queue);
 
     printk(
-" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
- s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
+" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n",
+ s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma,
+ s->loaded_as_module);
 
     if (ASC_NARROW_BOARD(boardp)) {
         asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);

--- linux/drivers/scsi/advansys.c Tue Jan 15 19:11:49 2002
+++ linux/drivers/scsi/advansys.cmin4 Wed Jan 16 00:13:21 2002
@@ -1,4 +1,4 @@
-#define ASC_VERSION "3.3G" /* AdvanSys Driver Version */
+#define ASC_VERSION "3.3GH" /* AdvanSys Driver Version */
 
 /*
  * advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
@@ -670,6 +670,9 @@
          1. Return an error from narrow boards if passed a 16 byte
             CDB. The wide board can already handle 16 byte CDBs.
 
+ 3.3GH (1/15/02):
+ 1. hacks for lk 2.5 series (D. Gilbert)
+
   I. Known Problems/Fix List (XXX)
 
      1. Need to add memory mapping workaround. Test the memory mapping.
@@ -4054,6 +4057,7 @@
         ADVEEP_38C1600_CONFIG adv_38C1600_eep; /* 38C1600 EEPROM config. */
     } eep_config;
     ulong last_reset; /* Saved last reset time */
+ spinlock_t lock; /* Board spinlock */
 #ifdef CONFIG_PROC_FS
     /* /proc/scsi/advansys/[0...] */
     char *prtbuf; /* /proc print buffer */
@@ -4206,7 +4210,7 @@
 STATIC void advansys_interrupt(int, void *, struct pt_regs *);
 STATIC void advansys_select_queue_depths(struct Scsi_Host *,
                                                Scsi_Device *);
-STATIC void asc_scsi_done_list(Scsi_Cmnd *);
+STATIC void asc_scsi_done_list(Scsi_Cmnd *, int from_isr);
 STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *);
 STATIC int asc_build_req(asc_board_t *, Scsi_Cmnd *);
 STATIC int adv_build_req(asc_board_t *, Scsi_Cmnd *, ADV_SCSI_REQ_Q **);
@@ -4799,6 +4803,9 @@
             memset(boardp, 0, sizeof(asc_board_t));
             boardp->id = asc_board_count - 1;
 
+ /* Initialize spinlock. */
+ boardp->lock = SPIN_LOCK_UNLOCKED;
+
             /*
              * Handle both narrow and wide boards.
              *
@@ -5511,7 +5518,7 @@
                 }
             } else {
                 ADV_CARR_T *carrp;
- int req_cnt;
+ int req_cnt = 0;
                 adv_req_t *reqp = NULL;
                 int sg_cnt = 0;
 
@@ -5845,7 +5852,9 @@
     boardp = ASC_BOARDP(shp);
     ASC_STATS(shp, queuecommand);
 
- spin_lock_irqsave(&shp->host_lock, flags);
+ /* host_lock taken by mid-level prior to call but need to protect */
+ /* against own ISR */
+ spin_lock_irqsave(&boardp->lock, flags);
 
     /*
      * Block new commands while handling a reset or abort request.
@@ -5862,7 +5871,7 @@
          * handling.
          */
         asc_enqueue(&boardp->done, scp, ASC_BACK);
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
         return 0;
     }
 
@@ -5902,11 +5911,11 @@
     default:
         done_scp = asc_dequeue_list(&boardp->done, NULL, ASC_TID_ALL);
         /* Interrupts could be enabled here. */
- asc_scsi_done_list(done_scp);
+ asc_scsi_done_list(done_scp, 0);
         break;
     }
+ spin_unlock_irqrestore(&boardp->lock, flags);
 
- spin_unlock_irqrestore(&shp->host_lock, flags);
     return 0;
 }
 
@@ -5952,13 +5961,13 @@
     /*
      * Check for re-entrancy.
      */
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
     if (boardp->flags & ASC_HOST_IN_RESET) {
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
         return FAILED;
     }
     boardp->flags |= ASC_HOST_IN_RESET;
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
 
     if (ASC_NARROW_BOARD(boardp)) {
         /*
@@ -5989,11 +5998,7 @@
         }
 
         ASC_DBG(1, "advansys_reset: after AscInitAsc1000Driver()\n");
-
- /*
- * Acquire the board lock.
- */
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
 
     } else {
         /*
@@ -6020,14 +6025,9 @@
             ret = FAILED;
             break;
         }
- /*
- * Acquire the board lock and ensure all requests completed by the
- * microcode have been processed by calling AdvISR().
- */
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
         (void) AdvISR(adv_dvc_varp);
     }
-
     /* Board lock is held. */
 
     /*
@@ -6088,15 +6088,13 @@
 
     /* Clear reset flag. */
     boardp->flags &= ~ASC_HOST_IN_RESET;
-
- /* Release the board. */
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
 
     /*
      * Complete all the 'done_scp' requests.
      */
     if (done_scp != NULL) {
- asc_scsi_done_list(done_scp);
+ asc_scsi_done_list(done_scp, 0);
     }
 
     ASC_DBG1(1, "advansys_reset: ret %d\n", ret);
@@ -6259,6 +6257,7 @@
     asc_board_t *boardp;
     Scsi_Cmnd *done_scp = NULL, *last_scp = NULL;
     Scsi_Cmnd *new_last_scp;
+ struct Scsi_Host *shp;
 
     ASC_DBG(1, "advansys_interrupt: begin\n");
 
@@ -6267,17 +6266,17 @@
      * AscISR() will call asc_isr_callback().
      */
     for (i = 0; i < asc_board_count; i++) {
- struct Scsi_Host *shp = asc_host[i];
+ shp = asc_host[i];
         boardp = ASC_BOARDP(shp);
         ASC_DBG2(2, "advansys_interrupt: i %d, boardp 0x%lx\n",
             i, (ulong) boardp);
- spin_lock_irqsave(&shp->host_lock, flags);
+ spin_lock_irqsave(&boardp->lock, flags);
         if (ASC_NARROW_BOARD(boardp)) {
             /*
              * Narrow Board
              */
- if (AscIsIntPending(asc_host[i]->io_port)) {
- ASC_STATS(asc_host[i], interrupt);
+ if (AscIsIntPending(shp->io_port)) {
+ ASC_STATS(shp, interrupt);
                 ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
                 AscISR(&boardp->dvc_var.asc_dvc_var);
             }
@@ -6287,7 +6286,7 @@
              */
             ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
             if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
- ASC_STATS(asc_host[i], interrupt);
+ ASC_STATS(shp, interrupt);
             }
         }
 
@@ -6327,7 +6326,7 @@
                 }
             }
         }
- spin_unlock_irqrestore(&shp->host_lock, flags);
+ spin_unlock_irqrestore(&boardp->lock, flags);
     }
 
     /*
@@ -6336,7 +6335,8 @@
      *
      * Complete all requests on the done list.
      */
- asc_scsi_done_list(done_scp);
+
+ asc_scsi_done_list(done_scp, 1);
 
     ASC_DBG(1, "advansys_interrupt: end\n");
     return;
@@ -6383,9 +6383,10 @@
  * Interrupts can be enabled on entry.
  */
 STATIC void
-asc_scsi_done_list(Scsi_Cmnd *scp)
+asc_scsi_done_list(Scsi_Cmnd *scp, int from_isr)
 {
     Scsi_Cmnd *tscp;
+ ulong flags = 0;
 
     ASC_DBG(2, "asc_scsi_done_list: begin\n");
     while (scp != NULL) {
@@ -6394,7 +6395,11 @@
         REQPNEXT(scp) = NULL;
         ASC_STATS(scp->host, done);
         ASC_ASSERT(scp->scsi_done != NULL);
+ if (from_isr)
+ spin_lock_irqsave(scp->host->host_lock, flags);
         scp->scsi_done(scp);
+ if (from_isr)
+ spin_unlock_irqrestore(scp->host->host_lock, flags);
         scp = tscp;
     }
     ASC_DBG(2, "asc_scsi_done_list: done\n");
@@ -6728,7 +6733,9 @@
         slp = (struct scatterlist *) scp->request_buffer;
         for (sgcnt = 0; sgcnt < scp->use_sg; sgcnt++, slp++) {
             asc_sg_head.sg_list[sgcnt].addr =
- cpu_to_le32(virt_to_bus(slp->address));
+ cpu_to_le32(virt_to_bus(slp->address ?
+ (unsigned char *)slp->address :
+ (unsigned char *)page_address(slp->page) + slp->offset));
             asc_sg_head.sg_list[sgcnt].bytes = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
         }
@@ -6986,7 +6993,9 @@
         for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
         {
             sg_block->sg_list[i].sg_addr =
- cpu_to_le32(virt_to_bus(slp->address));
+ cpu_to_le32(virt_to_bus(slp->address ?
+ (unsigned char *)slp->address :
+ (unsigned char *)page_address(slp->page) + slp->offset));
             sg_block->sg_list[i].sg_count = cpu_to_le32(slp->length);
             ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
 
@@ -9411,8 +9420,9 @@
         s->dma_channel, s->this_id, s->can_queue);
 
     printk(
-" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d\n",
- s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma);
+" cmd_per_lun %d, sg_tablesize %d, unchecked_isa_dma %d, loaded_as_module %d\n",
+ s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma,
+ s->loaded_as_module);
 
     if (ASC_NARROW_BOARD(boardp)) {
         asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed Jan 23 2002 - 21:00:14 EST