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);
--------------764668D6992FC4E35F504368
Content-Type: text/plain; charset=us-ascii;
name="advansys_253p1.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="advansys_253p1.diff"
--- 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);
--------------764668D6992FC4E35F504368--
-
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/