summaryrefslogtreecommitdiffstats
path: root/drivers/scsi
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/scsi')
-rw-r--r--drivers/scsi/.cvsignore1
-rw-r--r--drivers/scsi/53c7,8xx.c2
-rw-r--r--drivers/scsi/53c7,8xx.h68
-rw-r--r--drivers/scsi/53c7xx.c3
-rw-r--r--drivers/scsi/AM53C974.c86
-rw-r--r--drivers/scsi/AM53C974.h41
-rw-r--r--drivers/scsi/BusLogic.c2659
-rw-r--r--drivers/scsi/BusLogic.h483
-rw-r--r--drivers/scsi/ChangeLog.ncr53c8xx27
-rw-r--r--drivers/scsi/Config.in26
-rw-r--r--drivers/scsi/FlashPoint.c513
-rw-r--r--drivers/scsi/Makefile47
-rw-r--r--drivers/scsi/NCR5380.c3
-rw-r--r--drivers/scsi/NCR53c406a.c2
-rw-r--r--drivers/scsi/NCR53c406a.h36
-rw-r--r--drivers/scsi/README.BusLogic512
-rw-r--r--drivers/scsi/README.Mylex6
-rw-r--r--drivers/scsi/README.ncr53c8xx112
-rw-r--r--drivers/scsi/a2091.h33
-rw-r--r--drivers/scsi/a3000.h34
-rw-r--r--drivers/scsi/advansys.c7234
-rw-r--r--drivers/scsi/advansys.h38
-rw-r--r--drivers/scsi/aha152x.h38
-rw-r--r--drivers/scsi/aha1542.c270
-rw-r--r--drivers/scsi/aha1542.h47
-rw-r--r--drivers/scsi/aha1740.h34
-rw-r--r--drivers/scsi/aic7xxx.c2
-rw-r--r--drivers/scsi/aic7xxx.h35
-rw-r--r--drivers/scsi/amiga7xx.h32
-rw-r--r--drivers/scsi/atari_scsi.h32
-rw-r--r--drivers/scsi/constants.c5
-rw-r--r--drivers/scsi/dc390.h126
-rw-r--r--drivers/scsi/dtc.h19
-rw-r--r--drivers/scsi/eata.h33
-rw-r--r--drivers/scsi/eata_dma.h31
-rw-r--r--drivers/scsi/eata_dma_proc.c12
-rw-r--r--drivers/scsi/eata_pio.h31
-rw-r--r--drivers/scsi/eata_pio_proc.c10
-rw-r--r--drivers/scsi/esp.c2
-rw-r--r--drivers/scsi/fdomain.h34
-rw-r--r--drivers/scsi/g_NCR5380.c4
-rw-r--r--drivers/scsi/g_NCR5380.h25
-rw-r--r--drivers/scsi/gdth.h59
-rw-r--r--drivers/scsi/gdth_proc.c10
-rw-r--r--drivers/scsi/gvp11.h33
-rw-r--r--drivers/scsi/hosts.c55
-rw-r--r--drivers/scsi/hosts.h92
-rw-r--r--drivers/scsi/ibmmca.c335
-rw-r--r--drivers/scsi/ibmmca.h48
-rw-r--r--drivers/scsi/ide-scsi.c67
-rw-r--r--drivers/scsi/ide-scsi.h36
-rw-r--r--drivers/scsi/in2000.h37
-rw-r--r--drivers/scsi/jazz_esp.h38
-rw-r--r--drivers/scsi/mac53c94.h33
-rw-r--r--drivers/scsi/mesh.h33
-rw-r--r--drivers/scsi/ncr53c8xx.c176
-rw-r--r--drivers/scsi/ncr53c8xx.h90
-rw-r--r--drivers/scsi/pas16.c4
-rw-r--r--drivers/scsi/pas16.h19
-rw-r--r--drivers/scsi/pci2000.c2
-rw-r--r--drivers/scsi/pci2000.h33
-rw-r--r--drivers/scsi/pci2220i.h33
-rw-r--r--drivers/scsi/pluto.c313
-rw-r--r--drivers/scsi/pluto.h59
-rw-r--r--drivers/scsi/ppa.h36
-rw-r--r--drivers/scsi/psi240i.h33
-rw-r--r--drivers/scsi/qlogicfas.h33
-rw-r--r--drivers/scsi/qlogicisp.h35
-rw-r--r--drivers/scsi/qlogicpti.h34
-rw-r--r--drivers/scsi/scsi.c2898
-rw-r--r--drivers/scsi/scsi.h598
-rw-r--r--drivers/scsi/scsi_debug.c268
-rw-r--r--drivers/scsi/scsi_debug.h35
-rw-r--r--drivers/scsi/scsi_error.c1897
-rw-r--r--drivers/scsi/scsi_ioctl.c53
-rw-r--r--drivers/scsi/scsi_obsolete.c1132
-rw-r--r--drivers/scsi/scsi_obsolete.h106
-rw-r--r--drivers/scsi/scsi_proc.c8
-rw-r--r--drivers/scsi/scsi_queue.c321
-rw-r--r--drivers/scsi/scsi_syms.c20
-rw-r--r--drivers/scsi/scsicam.c5
-rw-r--r--drivers/scsi/scsiiom.c21
-rw-r--r--drivers/scsi/sd.c287
-rw-r--r--drivers/scsi/sd_ioctl.c16
-rw-r--r--drivers/scsi/seagate.h19
-rw-r--r--drivers/scsi/sg.c56
-rw-r--r--drivers/scsi/sgiwd93.c12
-rw-r--r--drivers/scsi/sgiwd93.h37
-rw-r--r--drivers/scsi/sparc_esp.h41
-rw-r--r--drivers/scsi/sr.c89
-rw-r--r--drivers/scsi/sr_ioctl.c35
-rw-r--r--drivers/scsi/sr_vendor.c67
-rw-r--r--drivers/scsi/st.c161
-rw-r--r--drivers/scsi/t128.c16
-rw-r--r--drivers/scsi/t128.h19
-rw-r--r--drivers/scsi/tmscsim.c19
-rw-r--r--drivers/scsi/tmscsim.h6
-rw-r--r--drivers/scsi/u14-34f.h33
-rw-r--r--drivers/scsi/ultrastor.h33
-rw-r--r--drivers/scsi/wd7000.c2
-rw-r--r--drivers/scsi/wd7000.h28
101 files changed, 16579 insertions, 6323 deletions
diff --git a/drivers/scsi/.cvsignore b/drivers/scsi/.cvsignore
index 38d1d3090..6d007a06f 100644
--- a/drivers/scsi/.cvsignore
+++ b/drivers/scsi/.cvsignore
@@ -1,3 +1,4 @@
.depend
+.*.flags
aic7xxx_asm
aic7xxx_seq.h
diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c
index 5f1a4d8da..092b8500a 100644
--- a/drivers/scsi/53c7,8xx.c
+++ b/drivers/scsi/53c7,8xx.c
@@ -5958,7 +5958,7 @@ print_queues (struct Scsi_Host *host) {
host->host_no, cmd->pid);
/* print_dsa does sanity check on address, no need to check */
else
- print_dsa (host, le32_to_cpu(((struct NCR53c7x0_cmd *) cmd->host_scribble)-> dsa), "");
+ print_dsa (host, bus_to_virt(le32_to_cpu(((struct NCR53c7x0_cmd *) cmd->host_scribble)-> dsa)), "");
} else
printk ("scsi%d : scsi pid %ld for target %d lun %d has no NCR53c7x0_cmd\n",
host->host_no, cmd->pid, cmd->target, cmd->lun);
diff --git a/drivers/scsi/53c7,8xx.h b/drivers/scsi/53c7,8xx.h
index cb0071e9d..994577ab0 100644
--- a/drivers/scsi/53c7,8xx.h
+++ b/drivers/scsi/53c7,8xx.h
@@ -66,66 +66,22 @@ extern int NCR53c7xx_release(struct Scsi_Host *);
#define NCR53c7xx_release NULL
#endif
-#ifdef LINUX_1_2
-#define NCR53c7xx {NULL, NULL, "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
- NULL, /* info */ NULL, /* command, deprecated */ NULL, \
- NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset, \
- NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
- /* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, \
- /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING}
-#else
-#define NCR53c7xx {NULL, NULL, NULL, NULL, \
- "NCR53c{7,8}xx (rel 17)", NCR53c7xx_detect,\
- NULL, /* info */ NULL, /* command, deprecated */ NULL, \
- NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset, \
- NULL /* slave attach */, scsicam_bios_param, /* can queue */ 24, \
- /* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 3, \
- /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING}
-#endif
+#define NCR53c7xx { \
+ name: "NCR53c{7,8}xx (rel 17)", \
+ detect: NCR53c7xx_detect, \
+ queuecommand: NCR53c7xx_queue_command, \
+ abort: NCR53c7xx_abort, \
+ reset: NCR53c7xx_reset, \
+ bios_param: scsicam_bios_param, \
+ can_queue: 24, \
+ this_id: 7, \
+ sg_tablesize: 127, \
+ cmd_per_lun: 3, \
+ use_clustering: DISABLE_CLUSTERING}
#endif /* defined(HOSTS_C) || defined(MODULE) */
#ifndef HOSTS_C
-#ifdef LINUX_1_2
-/*
- * Change virtual addresses to physical addresses and vv.
- * These are trivial on the 1:1 Linux/i386 mapping (but if we ever
- * make the kernel segment mapped at 0, we need to do translation
- * on the i386 as well)
- */
-extern inline unsigned long virt_to_phys(volatile void * address)
-{
- return (unsigned long) address;
-}
-
-extern inline void * phys_to_virt(unsigned long address)
-{
- return (void *) address;
-}
-
-/*
- * IO bus memory addresses are also 1:1 with the physical address
- */
-#define virt_to_bus virt_to_phys
-#define bus_to_virt phys_to_virt
-
-/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the x86 architecture, we just read/write the
- * memory location directly.
- */
-#define readb(addr) (*(volatile unsigned char *) (addr))
-#define readw(addr) (*(volatile unsigned short *) (addr))
-#define readl(addr) (*(volatile unsigned int *) (addr))
-
-#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
-#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
-#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
-
-#define mb()
-
-#endif /* def LINUX_1_2 */
/* Register addresses, ordered numerically */
diff --git a/drivers/scsi/53c7xx.c b/drivers/scsi/53c7xx.c
index a8cd93828..95400fe68 100644
--- a/drivers/scsi/53c7xx.c
+++ b/drivers/scsi/53c7xx.c
@@ -100,8 +100,6 @@
* the fourth byte from 50 to 25.
*/
-#include <linux/config.h>
-
/*
* Sponsored by
* iX Multiuser Multitasking Magazine
@@ -233,7 +231,6 @@
#endif
#include <linux/config.h>
-
#include <asm/dma.h>
#include <asm/io.h>
#include <asm/system.h>
diff --git a/drivers/scsi/AM53C974.c b/drivers/scsi/AM53C974.c
index 0ea714166..f19065027 100644
--- a/drivers/scsi/AM53C974.c
+++ b/drivers/scsi/AM53C974.c
@@ -2543,52 +2543,54 @@ return(SCSI_ABORT_NOT_RUNNING);
* Inputs : cmd -- which command within the command block was responsible for the reset
*
* Returns : status (SCSI_ABORT_SUCCESS)
+*
+* FIXME(eric) the reset_flags are ignored.
**************************************************************************/
-int AM53C974_reset(Scsi_Cmnd *cmd)
+int AM53C974_reset(Scsi_Cmnd *cmd, unsigned int reset_flags)
{
-AM53C974_local_declare();
-int i;
-struct Scsi_Host *instance = cmd->host;
-struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata;
-AM53C974_setio(instance);
-
-cli();
-DEB(printk("AM53C974_reset called; "));
-
-printk("AM53C974_reset called\n");
-AM53C974_print(instance);
-AM53C974_keywait();
-
+ AM53C974_local_declare();
+ int i;
+ struct Scsi_Host *instance = cmd->host;
+ struct AM53C974_hostdata *hostdata = (struct AM53C974_hostdata *)instance->hostdata;
+ AM53C974_setio(instance);
+
+ cli();
+ DEB(printk("AM53C974_reset called; "));
+
+ printk("AM53C974_reset called\n");
+ AM53C974_print(instance);
+ AM53C974_keywait();
+
/* do hard reset */
-AM53C974_write_8(CMDREG, CMDREG_RDEV);
-AM53C974_write_8(CMDREG, CMDREG_NOP);
-hostdata->msgout[0] = NOP;
-for (i = 0; i < 8; i++) {
- hostdata->busy[i] = 0;
- hostdata->sync_per[i] = DEF_STP;
- hostdata->sync_off[i] = 0;
- hostdata->sync_neg[i] = 0; }
-hostdata->last_message[0] = NOP;
-hostdata->sel_cmd = NULL;
-hostdata->connected = NULL;
-hostdata->issue_queue = NULL;
-hostdata->disconnected_queue = NULL;
-hostdata->in_reset = 0;
-hostdata->aborted = 0;
-hostdata->selecting = 0;
-hostdata->disconnecting = 0;
-hostdata->dma_busy = 0;
-
+ AM53C974_write_8(CMDREG, CMDREG_RDEV);
+ AM53C974_write_8(CMDREG, CMDREG_NOP);
+ hostdata->msgout[0] = NOP;
+ for (i = 0; i < 8; i++) {
+ hostdata->busy[i] = 0;
+ hostdata->sync_per[i] = DEF_STP;
+ hostdata->sync_off[i] = 0;
+ hostdata->sync_neg[i] = 0; }
+ hostdata->last_message[0] = NOP;
+ hostdata->sel_cmd = NULL;
+ hostdata->connected = NULL;
+ hostdata->issue_queue = NULL;
+ hostdata->disconnected_queue = NULL;
+ hostdata->in_reset = 0;
+ hostdata->aborted = 0;
+ hostdata->selecting = 0;
+ hostdata->disconnecting = 0;
+ hostdata->dma_busy = 0;
+
/* reset bus */
-AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); /* disable interrupt upon SCSI RESET */
-AM53C974_write_8(CMDREG, CMDREG_RBUS); /* reset SCSI bus */
-udelay(40);
-AM53C974_config_after_reset(instance);
-
-sti();
-cmd->result = DID_RESET << 16;
-cmd->scsi_done(cmd);
-return SCSI_ABORT_SUCCESS;
+ AM53C974_write_8(CNTLREG1, CNTLREG1_DISR | instance->this_id); /* disable interrupt upon SCSI RESET */
+ AM53C974_write_8(CMDREG, CMDREG_RBUS); /* reset SCSI bus */
+ udelay(40);
+ AM53C974_config_after_reset(instance);
+
+ sti();
+ cmd->result = DID_RESET << 16;
+ cmd->scsi_done(cmd);
+ return SCSI_ABORT_SUCCESS;
}
diff --git a/drivers/scsi/AM53C974.h b/drivers/scsi/AM53C974.h
index 4e187d993..f4542c778 100644
--- a/drivers/scsi/AM53C974.h
+++ b/drivers/scsi/AM53C974.h
@@ -52,29 +52,22 @@ struct AM53C974_hostdata {
extern struct proc_dir_entry proc_scsi_am53c974;
-#define AM53C974 { \
- NULL, /* pointer to next in list */ \
- NULL, /* struct module *module */ \
- &proc_scsi_am53c974, /* struct proc_dir_entry *proc_dir */ \
- NULL, /* int (*proc_info)(char *, char **, off_t, int, int, int); */ \
- "AM53C974", /* name */ \
- AM53C974_detect, /* int (* detect)(struct SHT *) */ \
- AM53C974_release, /* int (*release)(struct Scsi_Host *) */ \
- AM53C974_info, /* const char *(* info)(struct Scsi_Host *) */ \
- AM53C974_command, /* int (* command)(Scsi_Cmnd *) */ \
- AM53C974_queue_command, /* int (* queuecommand)(Scsi_Cmnd *, \
- void (*done)(Scsi_Cmnd *)) */ \
- AM53C974_abort, /* int (* abort)(Scsi_Cmnd *) */ \
- AM53C974_reset, /* int (* reset)(Scsi_Cmnd *) */ \
- NULL, /* int (* slave_attach)(int, int) */ \
- scsicam_bios_param, /* int (* bios_param)(Disk *, int, int[]) */ \
- 12, /* can_queue */ \
- -1, /* this_id */ \
- SG_ALL, /* sg_tablesize */ \
- 1, /* cmd_per_lun */ \
- 0, /* present, i.e. how many adapters of this kind */ \
- 0, /* unchecked_isa_dma */ \
- DISABLE_CLUSTERING /* use_clustering */ \
+#define AM53C974 { \
+ proc_dir: &proc_scsi_am53c974, \
+ name: "AM53C974", \
+ detect: AM53C974_detect, \
+ release: AM53C974_release, \
+ info: AM53C974_info, \
+ command: AM53C974_command, \
+ queuecommand: AM53C974_queue_command, \
+ abort: AM53C974_abort, \
+ reset: AM53C974_reset, \
+ bios_param: scsicam_bios_param, \
+ can_queue: 12, \
+ this_id: -1, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING \
}
void AM53C974_setup(char *str, int *ints);
@@ -85,7 +78,7 @@ const char *AM53C974_info(struct Scsi_Host *);
int AM53C974_command(Scsi_Cmnd *SCpnt);
int AM53C974_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
int AM53C974_abort(Scsi_Cmnd *cmd);
-int AM53C974_reset (Scsi_Cmnd *cmd);
+int AM53C974_reset (Scsi_Cmnd *cmd, unsigned int);
#endif /* AM53C974_H */
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 9119be7f3..b81756cc8 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -6,8 +6,7 @@
This program is free software; you may redistribute and/or modify it under
the terms of the GNU General Public License Version 2 as published by the
- Free Software Foundation, provided that none of the source code or runtime
- copyright notices are removed or modified.
+ Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
@@ -27,17 +26,17 @@
*/
-#define BusLogic_DriverVersion "2.0.10"
-#define BusLogic_DriverDate "11 August 1997"
+#define BusLogic_DriverVersion "2.0.11"
+#define BusLogic_DriverDate "31 January 1998"
+#include <linux/version.h>
#include <linux/module.h>
#include <linux/config.h>
#include <linux/types.h>
#include <linux/blkdev.h>
#include <linux/delay.h>
#include <linux/ioport.h>
-#include <linux/kernel_stat.h>
#include <linux/mm.h>
#include <linux/sched.h>
#include <linux/stat.h>
@@ -45,30 +44,43 @@
#include <linux/bios32.h>
#include <asm/dma.h>
#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/system.h>
#include "scsi.h"
#include "hosts.h"
#include "sd.h"
#include "BusLogic.h"
+#include "FlashPoint.c"
/*
- BusLogic_CommandLineEntryCount is a count of the number of "BusLogic="
- entries provided on the Linux Kernel Command Line.
+ BusLogic_DriverOptionsCount is a count of the number of BusLogic Driver
+ Options specifications provided via the Linux Kernel Command Line or via
+ the Loadable Kernel Module Installation Facility.
*/
static int
- BusLogic_CommandLineEntryCount = 0;
+ BusLogic_DriverOptionsCount = 0;
/*
- BusLogic_CommandLineEntries is an array of Command Line Entry structures
- representing the "BusLogic=" entries provided on the Linux Kernel Command
- Line.
+ BusLogic_DriverOptions is an array of Driver Options structures representing
+ BusLogic Driver Options specifications provided via the Linux Kernel Command
+ Line or via the Loadable Kernel Module Installation Facility.
*/
-static BusLogic_CommandLineEntry_T
- BusLogic_CommandLineEntries[BusLogic_MaxHostAdapters];
+static BusLogic_DriverOptions_T
+ BusLogic_DriverOptions[BusLogic_MaxHostAdapters];
+
+
+/*
+ BusLogic_Options can be assigned a string by the Loadable Kernel Module
+ Installation Facility to be parsed for BusLogic Driver Options
+ specifications.
+*/
+
+static char
+ *BusLogic_Options = NULL;
/*
@@ -77,7 +89,7 @@ static BusLogic_CommandLineEntry_T
*/
static BusLogic_ProbeOptions_T
- BusLogic_ProbeOptions = { 0 };
+ BusLogic_ProbeOptions = { 0 };
/*
@@ -86,7 +98,17 @@ static BusLogic_ProbeOptions_T
*/
static BusLogic_GlobalOptions_T
- BusLogic_GlobalOptions = { 0 };
+ BusLogic_GlobalOptions = { 0 };
+
+
+/*
+ BusLogic_FirstRegisteredHostAdapter and BusLogic_LastRegisteredHostAdapter
+ are pointers to the first and last registered BusLogic Host Adapters.
+*/
+
+static BusLogic_HostAdapter_T
+ *BusLogic_FirstRegisteredHostAdapter = NULL,
+ *BusLogic_LastRegisteredHostAdapter = NULL;
/*
@@ -99,11 +121,11 @@ static BusLogic_HostAdapter_T
/*
- BusLogic_ProbeInfoCount is the numbers of entries in BusLogic_ProbeInfoList.
+ BusLogic_ProbeInfoCount is the number of entries in BusLogic_ProbeInfoList.
*/
static int
- BusLogic_ProbeInfoCount = 0;
+ BusLogic_ProbeInfoCount = 0;
/*
@@ -114,7 +136,7 @@ static int
*/
static BusLogic_ProbeInfo_T
- BusLogic_ProbeInfoList[BusLogic_MaxHostAdapters] = { { 0 } };
+ *BusLogic_ProbeInfoList = NULL;
/*
@@ -133,8 +155,8 @@ static char
*/
static BusLogic_CCB_T
- *BusLogic_FirstCompletedCCB = NULL,
- *BusLogic_LastCompletedCCB = NULL;
+ *BusLogic_FirstCompletedCCB = NULL,
+ *BusLogic_LastCompletedCCB = NULL;
/*
@@ -181,6 +203,17 @@ const char *BusLogic_DriverInfo(SCSI_Host_T *Host)
static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
{
+ HostAdapter->NextAll = NULL;
+ if (BusLogic_FirstRegisteredHostAdapter == NULL)
+ {
+ BusLogic_FirstRegisteredHostAdapter = HostAdapter;
+ BusLogic_LastRegisteredHostAdapter = HostAdapter;
+ }
+ else
+ {
+ BusLogic_LastRegisteredHostAdapter->NextAll = HostAdapter;
+ BusLogic_LastRegisteredHostAdapter = HostAdapter;
+ }
HostAdapter->Next = NULL;
if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != NULL)
{
@@ -202,14 +235,33 @@ static void BusLogic_RegisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
{
+ if (HostAdapter == BusLogic_FirstRegisteredHostAdapter)
+ {
+ BusLogic_FirstRegisteredHostAdapter =
+ BusLogic_FirstRegisteredHostAdapter->NextAll;
+ if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
+ BusLogic_LastRegisteredHostAdapter = NULL;
+ }
+ else
+ {
+ BusLogic_HostAdapter_T *PreviousHostAdapter =
+ BusLogic_FirstRegisteredHostAdapter;
+ while (PreviousHostAdapter != NULL &&
+ PreviousHostAdapter->NextAll != HostAdapter)
+ PreviousHostAdapter = PreviousHostAdapter->NextAll;
+ if (PreviousHostAdapter != NULL)
+ PreviousHostAdapter->NextAll = HostAdapter->NextAll;
+ }
+ HostAdapter->NextAll = NULL;
if (BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] != HostAdapter)
{
- BusLogic_HostAdapter_T *LastHostAdapter =
+ BusLogic_HostAdapter_T *PreviousHostAdapter =
BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel];
- while (LastHostAdapter != NULL && LastHostAdapter->Next != HostAdapter)
- LastHostAdapter = LastHostAdapter->Next;
- if (LastHostAdapter != NULL)
- LastHostAdapter->Next = HostAdapter->Next;
+ while (PreviousHostAdapter != NULL &&
+ PreviousHostAdapter->Next != HostAdapter)
+ PreviousHostAdapter = PreviousHostAdapter->Next;
+ if (PreviousHostAdapter != NULL)
+ PreviousHostAdapter->Next = HostAdapter->Next;
}
else BusLogic_RegisteredHostAdapters[HostAdapter->IRQ_Channel] =
HostAdapter->Next;
@@ -218,85 +270,33 @@ static void BusLogic_UnregisterHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
/*
- BusLogic_CreateMailboxes allocates the Outgoing and Incoming Mailboxes for
- Host Adapter.
+ BusLogic_InitializeCCBs initializes a group of Command Control Blocks (CCBs)
+ for Host Adapter from the BlockSize bytes located at BlockPointer. The newly
+ created CCBs are added to Host Adapter's free list.
*/
-static boolean BusLogic_CreateMailboxes(BusLogic_HostAdapter_T *HostAdapter)
+static void BusLogic_InitializeCCBs(BusLogic_HostAdapter_T *HostAdapter,
+ void *BlockPointer, int BlockSize)
{
- /*
- FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes.
- */
- if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
- /*
- Allocate space for the Outgoing and Incoming Mailboxes.
- */
- HostAdapter->FirstOutgoingMailbox =
- (BusLogic_OutgoingMailbox_T *)
- scsi_init_malloc(HostAdapter->MailboxCount
- * (sizeof(BusLogic_OutgoingMailbox_T)
- + sizeof(BusLogic_IncomingMailbox_T)),
- (HostAdapter->BounceBuffersRequired
- ? GFP_ATOMIC | GFP_DMA
- : GFP_ATOMIC));
- if (HostAdapter->FirstOutgoingMailbox == NULL)
+ BusLogic_CCB_T *CCB = (BusLogic_CCB_T *) BlockPointer;
+ memset(BlockPointer, 0, BlockSize);
+ CCB->AllocationGroupHead = true;
+ while ((BlockSize -= sizeof(BusLogic_CCB_T)) >= 0)
{
- BusLogic_Error("UNABLE TO ALLOCATE MAILBOXES - DETACHING\n",
- HostAdapter, HostAdapter->HostNumber);
- return false;
- }
- HostAdapter->LastOutgoingMailbox =
- HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1;
- HostAdapter->FirstIncomingMailbox =
- (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1);
- HostAdapter->LastIncomingMailbox =
- HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1;
- return true;
-}
-
-
-/*
- BusLogic_DestroyMailboxes deallocates the Outgoing and Incoming Mailboxes
- for Host Adapter.
-*/
-
-static void BusLogic_DestroyMailboxes(BusLogic_HostAdapter_T *HostAdapter)
-{
- if (HostAdapter->FirstOutgoingMailbox == NULL) return;
- scsi_init_free((char *) HostAdapter->FirstOutgoingMailbox,
- HostAdapter->MailboxCount
- * (sizeof(BusLogic_OutgoingMailbox_T)
- + sizeof(BusLogic_IncomingMailbox_T)));
-}
-
-
-/*
- BusLogic_CreateCCB allocates and initializes a single Command Control
- Block (CCB) for Host Adapter, and adds it to Host Adapter's free list.
-*/
-
-static boolean BusLogic_CreateCCB(BusLogic_HostAdapter_T *HostAdapter)
-{
- BusLogic_CCB_T *CCB = (BusLogic_CCB_T *)
- scsi_init_malloc(sizeof(BusLogic_CCB_T),
- (HostAdapter->BounceBuffersRequired
- ? GFP_ATOMIC | GFP_DMA
- : GFP_ATOMIC));
- if (CCB == NULL) return false;
- memset(CCB, 0, sizeof(BusLogic_CCB_T));
- CCB->HostAdapter = HostAdapter;
- CCB->Status = BusLogic_CCB_Free;
- if (BusLogic_FlashPointHostAdapterP(HostAdapter))
- {
- CCB->CallbackFunction = BusLogic_QueueCompletedCCB;
- CCB->BaseAddress = HostAdapter->IO_Address;
+ CCB->Status = BusLogic_CCB_Free;
+ CCB->HostAdapter = HostAdapter;
+ if (BusLogic_FlashPointHostAdapterP(HostAdapter))
+ {
+ CCB->CallbackFunction = BusLogic_QueueCompletedCCB;
+ CCB->BaseAddress = HostAdapter->FlashPointInfo.BaseAddress;
+ }
+ CCB->Next = HostAdapter->Free_CCBs;
+ CCB->NextAll = HostAdapter->All_CCBs;
+ HostAdapter->Free_CCBs = CCB;
+ HostAdapter->All_CCBs = CCB;
+ HostAdapter->AllocatedCCBs++;
+ CCB++;
}
- CCB->Next = HostAdapter->Free_CCBs;
- CCB->NextAll = HostAdapter->All_CCBs;
- HostAdapter->Free_CCBs = CCB;
- HostAdapter->All_CCBs = CCB;
- HostAdapter->AllocatedCCBs++;
- return true;
}
@@ -306,14 +306,21 @@ static boolean BusLogic_CreateCCB(BusLogic_HostAdapter_T *HostAdapter)
static boolean BusLogic_CreateInitialCCBs(BusLogic_HostAdapter_T *HostAdapter)
{
- int Allocated;
- for (Allocated = 0; Allocated < HostAdapter->InitialCCBs; Allocated++)
- if (!BusLogic_CreateCCB(HostAdapter))
- {
- BusLogic_Error("UNABLE TO ALLOCATE CCB %d - DETACHING\n",
- HostAdapter, Allocated);
- return false;
- }
+ int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T);
+ while (HostAdapter->AllocatedCCBs < HostAdapter->InitialCCBs)
+ {
+ void *BlockPointer = kmalloc(BlockSize,
+ (HostAdapter->BounceBuffersRequired
+ ? GFP_ATOMIC | GFP_DMA
+ : GFP_ATOMIC));
+ if (BlockPointer == NULL)
+ {
+ BusLogic_Error("UNABLE TO ALLOCATE CCB GROUP - DETACHING\n",
+ HostAdapter);
+ return false;
+ }
+ BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize);
+ }
return true;
}
@@ -330,7 +337,8 @@ static void BusLogic_DestroyCCBs(BusLogic_HostAdapter_T *HostAdapter)
while ((CCB = NextCCB) != NULL)
{
NextCCB = CCB->NextAll;
- scsi_init_free((char *) CCB, sizeof(BusLogic_CCB_T));
+ if (CCB->AllocationGroupHead)
+ kfree(CCB);
}
}
@@ -346,18 +354,35 @@ static void BusLogic_CreateAdditionalCCBs(BusLogic_HostAdapter_T *HostAdapter,
int AdditionalCCBs,
boolean SuccessMessageP)
{
- int Allocated;
+ int BlockSize = BusLogic_CCB_AllocationGroupSize * sizeof(BusLogic_CCB_T);
+ int PreviouslyAllocated = HostAdapter->AllocatedCCBs;
if (AdditionalCCBs <= 0) return;
- for (Allocated = 0; Allocated < AdditionalCCBs; Allocated++)
- if (!BusLogic_CreateCCB(HostAdapter)) break;
- if (Allocated > 0 && SuccessMessageP)
- BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n",
- HostAdapter, Allocated, HostAdapter->AllocatedCCBs);
- if (Allocated > 0) return;
+ while (HostAdapter->AllocatedCCBs - PreviouslyAllocated < AdditionalCCBs)
+ {
+ void *BlockPointer = kmalloc(BlockSize,
+ (HostAdapter->BounceBuffersRequired
+ ? GFP_ATOMIC | GFP_DMA
+ : GFP_ATOMIC));
+ if (BlockPointer == NULL) break;
+ BusLogic_InitializeCCBs(HostAdapter, BlockPointer, BlockSize);
+ }
+ if (HostAdapter->AllocatedCCBs > PreviouslyAllocated)
+ {
+ if (SuccessMessageP)
+ BusLogic_Notice("Allocated %d additional CCBs (total now %d)\n",
+ HostAdapter,
+ HostAdapter->AllocatedCCBs - PreviouslyAllocated,
+ HostAdapter->AllocatedCCBs);
+ return;
+ }
BusLogic_Notice("Failed to allocate additional CCBs\n", HostAdapter);
- HostAdapter->DriverQueueDepth =
- HostAdapter->AllocatedCCBs - (HostAdapter->MaxTargetDevices - 1);
- HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth;
+ if (HostAdapter->DriverQueueDepth >
+ HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount)
+ {
+ HostAdapter->DriverQueueDepth =
+ HostAdapter->AllocatedCCBs - HostAdapter->TargetDeviceCount;
+ HostAdapter->SCSI_Host->can_queue = HostAdapter->DriverQueueDepth;
+ }
}
@@ -413,47 +438,6 @@ static void BusLogic_DeallocateCCB(BusLogic_CCB_T *CCB)
/*
- BusLogic_CreateTargetDeviceStatistics creates the Target Device Statistics
- structure for Host Adapter.
-*/
-
-static boolean BusLogic_CreateTargetDeviceStatistics(BusLogic_HostAdapter_T
- *HostAdapter)
-{
- HostAdapter->TargetDeviceStatistics =
- (BusLogic_TargetDeviceStatistics_T *)
- scsi_init_malloc(HostAdapter->MaxTargetDevices
- * sizeof(BusLogic_TargetDeviceStatistics_T),
- GFP_ATOMIC);
- if (HostAdapter->TargetDeviceStatistics == NULL)
- {
- BusLogic_Error("UNABLE TO ALLOCATE TARGET DEVICE STATISTICS - "
- "DETACHING\n", HostAdapter, HostAdapter->HostNumber);
- return false;
- }
- memset(HostAdapter->TargetDeviceStatistics, 0,
- HostAdapter->MaxTargetDevices
- * sizeof(BusLogic_TargetDeviceStatistics_T));
- return true;
-}
-
-
-/*
- BusLogic_DestroyTargetDeviceStatistics destroys the Target Device Statistics
- structure for Host Adapter.
-*/
-
-static void BusLogic_DestroyTargetDeviceStatistics(BusLogic_HostAdapter_T
- *HostAdapter)
-{
- if (HostAdapter->TargetDeviceStatistics == NULL) return;
- scsi_init_free((char *) HostAdapter->TargetDeviceStatistics,
- HostAdapter->MaxTargetDevices
- * sizeof(BusLogic_TargetDeviceStatistics_T));
-}
-
-
-/*
BusLogic_Command sends the command OperationCode to HostAdapter, optionally
providing ParameterLength bytes of ParameterData and receiving at most
ReplyLength bytes of ReplyData; any excess reply data is received but
@@ -494,7 +478,7 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
If the IRQ Channel has not yet been acquired, then interrupts must be
disabled while issuing host adapter commands since a Command Complete
interrupt could occur if the IRQ Channel was previously enabled by another
- BusLogic Host Adapter or other driver sharing the same IRQ Channel.
+ BusLogic Host Adapter or another driver sharing the same IRQ Channel.
*/
if (!HostAdapter->IRQ_ChannelAcquired)
{
@@ -572,7 +556,7 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
Result = -1;
goto Done;
}
- if (BusLogic_GlobalOptions.Bits.TraceConfiguration)
+ if (BusLogic_GlobalOptions.TraceConfiguration)
BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: "
"(Modify I/O Address)\n", HostAdapter,
OperationCode, StatusRegister.All);
@@ -607,9 +591,11 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
if (InterruptRegister.Bits.CommandComplete) break;
if (HostAdapter->HostAdapterCommandCompleted) break;
if (StatusRegister.Bits.DataInRegisterReady)
- if (++ReplyBytes <= ReplyLength)
- *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter);
- else BusLogic_ReadDataInRegister(HostAdapter);
+ {
+ if (++ReplyBytes <= ReplyLength)
+ *ReplyPointer++ = BusLogic_ReadDataInRegister(HostAdapter);
+ else BusLogic_ReadDataInRegister(HostAdapter);
+ }
if (OperationCode == BusLogic_FetchHostAdapterLocalRAM &&
StatusRegister.Bits.HostAdapterReady) break;
udelay(100);
@@ -621,34 +607,24 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter,
goto Done;
}
/*
- If testing Command Complete Interrupts, wait a short while in case the
- loop immediately above terminated due to the Command Complete bit being
- set in the Interrupt Register, but the interrupt hasn't actually been
- processed yet. Otherwise, acknowledging the interrupt here could prevent
- the interrupt test from succeeding.
- */
- if (OperationCode == BusLogic_TestCommandCompleteInterrupt)
- udelay(10000);
- /*
Clear any pending Command Complete Interrupt.
*/
BusLogic_InterruptReset(HostAdapter);
/*
Provide tracing information if requested.
*/
- if (BusLogic_GlobalOptions.Bits.TraceConfiguration)
- if (OperationCode != BusLogic_TestCommandCompleteInterrupt)
- {
- int i;
- BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:",
- HostAdapter, OperationCode,
- StatusRegister.All, ReplyLength, ReplyBytes);
- if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes;
- for (i = 0; i < ReplyLength; i++)
- BusLogic_Notice(" %02X", HostAdapter,
- ((unsigned char *) ReplyData)[i]);
- BusLogic_Notice("\n", HostAdapter);
- }
+ if (BusLogic_GlobalOptions.TraceConfiguration)
+ {
+ int i;
+ BusLogic_Notice("BusLogic_Command(%02X) Status = %02X: %2d ==> %2d:",
+ HostAdapter, OperationCode,
+ StatusRegister.All, ReplyLength, ReplyBytes);
+ if (ReplyLength > ReplyBytes) ReplyLength = ReplyBytes;
+ for (i = 0; i < ReplyLength; i++)
+ BusLogic_Notice(" %02X", HostAdapter,
+ ((unsigned char *) ReplyData)[i]);
+ BusLogic_Notice("\n", HostAdapter);
+ }
/*
Process Command Invalid conditions.
*/
@@ -705,38 +681,63 @@ Done:
/*
+ BusLogic_AppendProbeAddressISA appends a single ISA I/O Address to the list
+ of I/O Address and Bus Probe Information to be checked for potential BusLogic
+ Host Adapters.
+*/
+
+static void BusLogic_AppendProbeAddressISA(BusLogic_IO_Address_T IO_Address)
+{
+ BusLogic_ProbeInfo_T *ProbeInfo;
+ if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return;
+ ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
+ ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+ ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
+ ProbeInfo->IO_Address = IO_Address;
+}
+
+
+/*
BusLogic_InitializeProbeInfoListISA initializes the list of I/O Address and
Bus Probe Information to be checked for potential BusLogic SCSI Host Adapters
only from the list of standard BusLogic MultiMaster ISA I/O Addresses.
*/
-static void BusLogic_InitializeProbeInfoListISA(void)
+static void BusLogic_InitializeProbeInfoListISA(BusLogic_HostAdapter_T
+ *PrototypeHostAdapter)
{
- int StandardAddressIndex;
- /*
- If BusLogic_Setup has provided an I/O Address probe list, do not override
- the Kernel Command Line specifications.
- */
- if (BusLogic_ProbeInfoCount > 0) return;
/*
- If a Kernel Command Line specification has requested that ISA Bus Probes
+ If BusLogic Driver Options specifications requested that ISA Bus Probes
be inhibited, do not proceed further.
*/
- if (BusLogic_ProbeOptions.Bits.NoProbeISA) return;
+ if (BusLogic_ProbeOptions.NoProbeISA) return;
/*
Append the list of standard BusLogic MultiMaster ISA I/O Addresses.
*/
- StandardAddressIndex = 0;
- while (BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters &&
- StandardAddressIndex < BusLogic_ISA_StandardAddressesCount)
- {
- BusLogic_ProbeInfo_T *ProbeInfo =
- &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
- ProbeInfo->IO_Address =
- BusLogic_ISA_StandardAddresses[StandardAddressIndex++];
- ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
- ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
- }
+ if (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe330
+ : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0)
+ BusLogic_AppendProbeAddressISA(0x330);
+ if (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe334
+ : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0)
+ BusLogic_AppendProbeAddressISA(0x334);
+ if (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe230
+ : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0)
+ BusLogic_AppendProbeAddressISA(0x230);
+ if (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe234
+ : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0)
+ BusLogic_AppendProbeAddressISA(0x234);
+ if (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe130
+ : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0)
+ BusLogic_AppendProbeAddressISA(0x130);
+ if (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe134
+ : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0)
+ BusLogic_AppendProbeAddressISA(0x134);
}
@@ -783,25 +784,26 @@ static void BusLogic_SortProbeInfo(BusLogic_ProbeInfo_T *ProbeInfoList,
I/O Addresses. It returns the number of PCI MultiMaster Host Adapters found.
*/
-static int BusLogic_InitializeMultiMasterProbeInfo(void)
+static int BusLogic_InitializeMultiMasterProbeInfo(BusLogic_HostAdapter_T
+ *PrototypeHostAdapter)
{
- boolean StandardAddressSeen[BusLogic_ISA_StandardAddressesCount];
BusLogic_ProbeInfo_T *PrimaryProbeInfo =
&BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount];
int NonPrimaryPCIMultiMasterIndex = BusLogic_ProbeInfoCount + 1;
int NonPrimaryPCIMultiMasterCount = 0, PCIMultiMasterCount = 0;
boolean ForceBusDeviceScanningOrder = false;
boolean ForceBusDeviceScanningOrderChecked = false;
- unsigned char Bus, DeviceFunction, IRQ_Channel;
+ boolean StandardAddressSeen[6];
+ unsigned char Bus, DeviceFunction;
unsigned int BaseAddress0, BaseAddress1;
+ unsigned char IRQ_Channel;
BusLogic_IO_Address_T IO_Address;
BusLogic_PCI_Address_T PCI_Address;
unsigned short Index = 0;
- int StandardAddressIndex, i;
- if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters)
- return 0;
+ int i;
+ if (BusLogic_ProbeInfoCount >= BusLogic_MaxHostAdapters) return 0;
BusLogic_ProbeInfoCount++;
- for (i = 0; i < BusLogic_ISA_StandardAddressesCount; i++)
+ for (i = 0; i < 6; i++)
StandardAddressSeen[i] = false;
/*
Iterate over the MultiMaster PCI Host Adapters. For each enumerated host
@@ -826,8 +828,7 @@ static int BusLogic_InitializeMultiMasterProbeInfo(void)
pcibios_read_config_byte(Bus, DeviceFunction,
PCI_INTERRUPT_LINE, &IRQ_Channel) == 0)
{
- BusLogic_HostAdapter_T HostAdapterPrototype;
- BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+ BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
BusLogic_PCIHostAdapterInformation_T PCIHostAdapterInformation;
BusLogic_ModifyIOAddressRequest_T ModifyIOAddressRequest;
unsigned char Device = DeviceFunction >> 3;
@@ -859,7 +860,7 @@ static int BusLogic_InitializeMultiMasterProbeInfo(void)
NULL, Bus, Device, IO_Address);
continue;
}
- if (BusLogic_GlobalOptions.Bits.TraceProbe)
+ if (BusLogic_GlobalOptions.TraceProbe)
{
BusLogic_Notice("BusLogic: PCI MultiMaster Host Adapter "
"detected at\n", NULL);
@@ -871,7 +872,7 @@ static int BusLogic_InitializeMultiMasterProbeInfo(void)
Issue the Inquire PCI Host Adapter Information command to determine
the ISA Compatible I/O Port. If the ISA Compatible I/O Port is
known and enabled, note that the particular Standard ISA I/O
- Address need not be probed.
+ Address should not be probed.
*/
HostAdapter->IO_Address = IO_Address;
if (BusLogic_Command(HostAdapter,
@@ -880,8 +881,7 @@ static int BusLogic_InitializeMultiMasterProbeInfo(void)
sizeof(PCIHostAdapterInformation))
== sizeof(PCIHostAdapterInformation))
{
- if (PCIHostAdapterInformation.ISACompatibleIOPort <
- BusLogic_ISA_StandardAddressesCount)
+ if (PCIHostAdapterInformation.ISACompatibleIOPort < 6)
StandardAddressSeen[PCIHostAdapterInformation
.ISACompatibleIOPort] = true;
}
@@ -933,10 +933,10 @@ static int BusLogic_InitializeMultiMasterProbeInfo(void)
*/
if (PCIHostAdapterInformation.ISACompatibleIOPort == BusLogic_IO_330)
{
- PrimaryProbeInfo->IO_Address = IO_Address;
- PrimaryProbeInfo->PCI_Address = PCI_Address;
PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
PrimaryProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+ PrimaryProbeInfo->IO_Address = IO_Address;
+ PrimaryProbeInfo->PCI_Address = PCI_Address;
PrimaryProbeInfo->Bus = Bus;
PrimaryProbeInfo->Device = Device;
PrimaryProbeInfo->IRQ_Channel = IRQ_Channel;
@@ -946,10 +946,10 @@ static int BusLogic_InitializeMultiMasterProbeInfo(void)
{
BusLogic_ProbeInfo_T *ProbeInfo =
&BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
- ProbeInfo->IO_Address = IO_Address;
- ProbeInfo->PCI_Address = PCI_Address;
ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+ ProbeInfo->IO_Address = IO_Address;
+ ProbeInfo->PCI_Address = PCI_Address;
ProbeInfo->Bus = Bus;
ProbeInfo->Device = Device;
ProbeInfo->IRQ_Channel = IRQ_Channel;
@@ -978,31 +978,48 @@ static int BusLogic_InitializeMultiMasterProbeInfo(void)
then the Primary I/O Address must be probed explicitly before any PCI
host adapters are probed.
*/
- if (PrimaryProbeInfo->IO_Address == 0 &&
- !BusLogic_ProbeOptions.Bits.NoProbeISA)
- {
- PrimaryProbeInfo->IO_Address = BusLogic_ISA_StandardAddresses[0];
- PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
- PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
- }
+ if (!BusLogic_ProbeOptions.NoProbeISA)
+ if (PrimaryProbeInfo->IO_Address == 0 &&
+ (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe330
+ : check_region(0x330, BusLogic_MultiMasterAddressCount) == 0))
+ {
+ PrimaryProbeInfo->HostAdapterType = BusLogic_MultiMaster;
+ PrimaryProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
+ PrimaryProbeInfo->IO_Address = 0x330;
+ }
/*
Append the list of standard BusLogic MultiMaster ISA I/O Addresses,
omitting the Primary I/O Address which has already been handled.
*/
- if (!BusLogic_ProbeOptions.Bits.NoProbeISA)
- for (StandardAddressIndex = 1;
- StandardAddressIndex < BusLogic_ISA_StandardAddressesCount;
- StandardAddressIndex++)
- if (!StandardAddressSeen[StandardAddressIndex] &&
- BusLogic_ProbeInfoCount < BusLogic_MaxHostAdapters)
- {
- BusLogic_ProbeInfo_T *ProbeInfo =
- &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
- ProbeInfo->IO_Address =
- BusLogic_ISA_StandardAddresses[StandardAddressIndex];
- ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
- ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
- }
+ if (!BusLogic_ProbeOptions.NoProbeISA)
+ {
+ if (!StandardAddressSeen[1] &&
+ (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe334
+ : check_region(0x334, BusLogic_MultiMasterAddressCount) == 0))
+ BusLogic_AppendProbeAddressISA(0x334);
+ if (!StandardAddressSeen[2] &&
+ (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe230
+ : check_region(0x230, BusLogic_MultiMasterAddressCount) == 0))
+ BusLogic_AppendProbeAddressISA(0x230);
+ if (!StandardAddressSeen[3] &&
+ (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe234
+ : check_region(0x234, BusLogic_MultiMasterAddressCount) == 0))
+ BusLogic_AppendProbeAddressISA(0x234);
+ if (!StandardAddressSeen[4] &&
+ (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe130
+ : check_region(0x130, BusLogic_MultiMasterAddressCount) == 0))
+ BusLogic_AppendProbeAddressISA(0x130);
+ if (!StandardAddressSeen[5] &&
+ (BusLogic_ProbeOptions.LimitedProbeISA
+ ? BusLogic_ProbeOptions.Probe134
+ : check_region(0x134, BusLogic_MultiMasterAddressCount) == 0))
+ BusLogic_AppendProbeAddressISA(0x134);
+ }
return PCIMultiMasterCount;
}
@@ -1014,11 +1031,13 @@ static int BusLogic_InitializeMultiMasterProbeInfo(void)
number of FlashPoint Host Adapters found.
*/
-static int BusLogic_InitializeFlashPointProbeInfo(void)
+static int BusLogic_InitializeFlashPointProbeInfo(BusLogic_HostAdapter_T
+ *PrototypeHostAdapter)
{
int FlashPointIndex = BusLogic_ProbeInfoCount, FlashPointCount = 0;
- unsigned char Bus, DeviceFunction, IRQ_Channel;
+ unsigned char Bus, DeviceFunction;
unsigned int BaseAddress0, BaseAddress1;
+ unsigned char IRQ_Channel;
BusLogic_IO_Address_T IO_Address;
BusLogic_PCI_Address_T PCI_Address;
unsigned short Index = 0;
@@ -1065,7 +1084,7 @@ static int BusLogic_InitializeFlashPointProbeInfo(void)
NULL, Bus, Device, IO_Address);
continue;
}
- if (BusLogic_GlobalOptions.Bits.TraceProbe)
+ if (BusLogic_GlobalOptions.TraceProbe)
{
BusLogic_Notice("BusLogic: FlashPoint Host Adapter "
"detected at\n", NULL);
@@ -1077,10 +1096,10 @@ static int BusLogic_InitializeFlashPointProbeInfo(void)
{
BusLogic_ProbeInfo_T *ProbeInfo =
&BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
- ProbeInfo->IO_Address = IO_Address;
- ProbeInfo->PCI_Address = PCI_Address;
ProbeInfo->HostAdapterType = BusLogic_FlashPoint;
ProbeInfo->HostAdapterBusType = BusLogic_PCI_Bus;
+ ProbeInfo->IO_Address = IO_Address;
+ ProbeInfo->PCI_Address = PCI_Address;
ProbeInfo->Bus = Bus;
ProbeInfo->Device = Device;
ProbeInfo->IRQ_Channel = IRQ_Channel;
@@ -1116,44 +1135,41 @@ static int BusLogic_InitializeFlashPointProbeInfo(void)
FlashPoint and PCI MultiMaster Host Adapters are present, this driver will
probe for FlashPoint Host Adapters first unless the BIOS primary disk is
controlled by the first PCI MultiMaster Host Adapter, in which case
- MultiMaster Host Adapters will be probed first. The Kernel Command Line
- options "MultiMasterFirst" and "FlashPointFirst" can be used to force a
- particular probe order.
+ MultiMaster Host Adapters will be probed first. The BusLogic Driver Options
+ specifications "MultiMasterFirst" and "FlashPointFirst" can be used to force
+ a particular probe order.
*/
-static void BusLogic_InitializeProbeInfoList(void)
+static void BusLogic_InitializeProbeInfoList(BusLogic_HostAdapter_T
+ *PrototypeHostAdapter)
{
/*
- If BusLogic_Setup has provided an I/O Address probe list, do not override
- the Kernel Command Line specifications.
- */
- if (BusLogic_ProbeInfoCount > 0) return;
- /*
If a PCI BIOS is present, interrogate it for MultiMaster and FlashPoint
Host Adapters; otherwise, default to the standard ISA MultiMaster probe.
*/
- if (!BusLogic_ProbeOptions.Bits.NoProbePCI && pcibios_present())
+ if (!BusLogic_ProbeOptions.NoProbePCI && pcibios_present())
{
- if (BusLogic_ProbeOptions.Bits.ProbeMultiMasterFirst)
+ if (BusLogic_ProbeOptions.MultiMasterFirst)
{
- BusLogic_InitializeMultiMasterProbeInfo();
- BusLogic_InitializeFlashPointProbeInfo();
+ BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
+ BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
}
- else if (BusLogic_ProbeOptions.Bits.ProbeFlashPointFirst)
+ else if (BusLogic_ProbeOptions.FlashPointFirst)
{
- BusLogic_InitializeFlashPointProbeInfo();
- BusLogic_InitializeMultiMasterProbeInfo();
+ BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
+ BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
}
else
{
- int FlashPointCount = BusLogic_InitializeFlashPointProbeInfo();
- int PCIMultiMasterCount = BusLogic_InitializeMultiMasterProbeInfo();
+ int FlashPointCount =
+ BusLogic_InitializeFlashPointProbeInfo(PrototypeHostAdapter);
+ int PCIMultiMasterCount =
+ BusLogic_InitializeMultiMasterProbeInfo(PrototypeHostAdapter);
if (FlashPointCount > 0 && PCIMultiMasterCount > 0)
{
BusLogic_ProbeInfo_T *ProbeInfo =
&BusLogic_ProbeInfoList[FlashPointCount];
- BusLogic_HostAdapter_T HostAdapterPrototype;
- BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+ BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
BusLogic_FetchHostAdapterLocalRAMRequest_T
FetchHostAdapterLocalRAMRequest;
BusLogic_BIOSDriveMapByte_T Drive0MapByte;
@@ -1195,7 +1211,7 @@ static void BusLogic_InitializeProbeInfoList(void)
}
}
}
- else BusLogic_InitializeProbeInfoListISA();
+ else BusLogic_InitializeProbeInfoListISA(PrototypeHostAdapter);
}
@@ -1240,20 +1256,14 @@ static boolean BusLogic_ProbeHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
*/
if (BusLogic_FlashPointHostAdapterP(HostAdapter))
{
- FlashPoint_Info_T *FlashPointInfo = (FlashPoint_Info_T *)
- scsi_init_malloc(sizeof(FlashPoint_Info_T), GFP_ATOMIC);
- int Retries = 10;
- if (FlashPointInfo == NULL)
- return BusLogic_Failure(HostAdapter, "ALLOCATING FLASHPOINT INFO");
- FlashPointInfo->BaseAddress = HostAdapter->IO_Address;
+ FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo;
+ FlashPointInfo->BaseAddress =
+ (BusLogic_Base_Address_T) HostAdapter->IO_Address;
FlashPointInfo->IRQ_Channel = HostAdapter->IRQ_Channel;
FlashPointInfo->Present = false;
- while (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 &&
- FlashPointInfo->Present) &&
- --Retries >= 0) ;
- if (!FlashPointInfo->Present)
+ if (!(FlashPoint_ProbeHostAdapter(FlashPointInfo) == 0 &&
+ FlashPointInfo->Present))
{
- scsi_init_free((char *) FlashPointInfo, sizeof(FlashPoint_Info_T));
BusLogic_Error("BusLogic: FlashPoint Host Adapter detected at "
"PCI Bus %d Device %d\n", HostAdapter,
HostAdapter->Bus, HostAdapter->Device);
@@ -1264,8 +1274,7 @@ static boolean BusLogic_ProbeHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
HostAdapter);
return false;
}
- HostAdapter->FlashPointInfo = FlashPointInfo;
- if (BusLogic_GlobalOptions.Bits.TraceProbe)
+ if (BusLogic_GlobalOptions.TraceProbe)
BusLogic_Notice("BusLogic_Probe(0x%X): FlashPoint Found\n",
HostAdapter, HostAdapter->IO_Address);
/*
@@ -1283,7 +1292,7 @@ static boolean BusLogic_ProbeHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
StatusRegister.All = BusLogic_ReadStatusRegister(HostAdapter);
InterruptRegister.All = BusLogic_ReadInterruptRegister(HostAdapter);
GeometryRegister.All = BusLogic_ReadGeometryRegister(HostAdapter);
- if (BusLogic_GlobalOptions.Bits.TraceProbe)
+ if (BusLogic_GlobalOptions.TraceProbe)
BusLogic_Notice("BusLogic_Probe(0x%X): Status 0x%02X, Interrupt 0x%02X, "
"Geometry 0x%02X\n", HostAdapter,
HostAdapter->IO_Address, StatusRegister.All,
@@ -1318,12 +1327,16 @@ static boolean BusLogic_ProbeHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
/*
- BusLogic_HardResetHostAdapter issues a Hard Reset to the Host Adapter,
- and waits for Host Adapter Diagnostics to complete.
+ BusLogic_HardwareResetHostAdapter issues a Hardware Reset to the Host Adapter
+ and waits for Host Adapter Diagnostics to complete. If HardReset is true, a
+ Hard Reset is performed which also initiates a SCSI Bus Reset. Otherwise, a
+ Soft Reset is performed which only resets the Host Adapter without forcing a
+ SCSI Bus Reset.
*/
-static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T
- *HostAdapter)
+static boolean BusLogic_HardwareResetHostAdapter(BusLogic_HostAdapter_T
+ *HostAdapter,
+ boolean HardReset)
{
BusLogic_StatusRegister_T StatusRegister;
int TimeoutCounter;
@@ -1332,9 +1345,11 @@ static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T
*/
if (BusLogic_FlashPointHostAdapterP(HostAdapter))
{
- HostAdapter->FlashPointInfo->ReportDataUnderrun = true;
+ FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo;
+ FlashPointInfo->HostSoftReset = !HardReset;
+ FlashPointInfo->ReportDataUnderrun = true;
HostAdapter->CardHandle =
- FlashPoint_HardResetHostAdapter(HostAdapter->FlashPointInfo);
+ FlashPoint_HardwareResetHostAdapter(FlashPointInfo);
if (HostAdapter->CardHandle == FlashPoint_BadCardHandle) return false;
/*
Indicate the Host Adapter Hard Reset completed successfully.
@@ -1342,10 +1357,12 @@ static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T
return true;
}
/*
- Issue a Hard Reset Command to the Host Adapter. The Host Adapter should
- respond by setting Diagnostic Active in the Status Register.
+ Issue a Hard Reset or Soft Reset Command to the Host Adapter. The Host
+ Adapter should respond by setting Diagnostic Active in the Status Register.
*/
- BusLogic_HardReset(HostAdapter);
+ if (HardReset)
+ BusLogic_HardReset(HostAdapter);
+ else BusLogic_SoftReset(HostAdapter);
/*
Wait until Diagnostic Active is set in the Status Register.
*/
@@ -1356,8 +1373,8 @@ static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T
if (StatusRegister.Bits.DiagnosticActive) break;
udelay(100);
}
- if (BusLogic_GlobalOptions.Bits.TraceHardReset)
- BusLogic_Notice("BusLogic_HardReset(0x%X): Diagnostic Active, "
+ if (BusLogic_GlobalOptions.TraceHardwareReset)
+ BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Active, "
"Status 0x%02X\n", HostAdapter,
HostAdapter->IO_Address, StatusRegister.All);
if (TimeoutCounter < 0) return false;
@@ -1377,8 +1394,8 @@ static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T
if (!StatusRegister.Bits.DiagnosticActive) break;
udelay(100);
}
- if (BusLogic_GlobalOptions.Bits.TraceHardReset)
- BusLogic_Notice("BusLogic_HardReset(0x%X): Diagnostic Completed, "
+ if (BusLogic_GlobalOptions.TraceHardwareReset)
+ BusLogic_Notice("BusLogic_HardwareReset(0x%X): Diagnostic Completed, "
"Status 0x%02X\n", HostAdapter,
HostAdapter->IO_Address, StatusRegister.All);
if (TimeoutCounter < 0) return false;
@@ -1396,8 +1413,8 @@ static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T
break;
udelay(100);
}
- if (BusLogic_GlobalOptions.Bits.TraceHardReset)
- BusLogic_Notice("BusLogic_HardReset(0x%X): Host Adapter Ready, "
+ if (BusLogic_GlobalOptions.TraceHardwareReset)
+ BusLogic_Notice("BusLogic_HardwareReset(0x%X): Host Adapter Ready, "
"Status 0x%02X\n", HostAdapter,
HostAdapter->IO_Address, StatusRegister.All);
if (TimeoutCounter < 0) return false;
@@ -1447,25 +1464,27 @@ static boolean BusLogic_CheckHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
Issue the Inquire Configuration command if the IRQ Channel is unknown.
*/
if (HostAdapter->IRQ_Channel == 0)
- if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration,
- NULL, 0, &Configuration, sizeof(Configuration))
- == sizeof(Configuration))
- {
- if (Configuration.IRQ_Channel9)
- HostAdapter->IRQ_Channel = 9;
- else if (Configuration.IRQ_Channel10)
- HostAdapter->IRQ_Channel = 10;
- else if (Configuration.IRQ_Channel11)
- HostAdapter->IRQ_Channel = 11;
- else if (Configuration.IRQ_Channel12)
- HostAdapter->IRQ_Channel = 12;
- else if (Configuration.IRQ_Channel14)
- HostAdapter->IRQ_Channel = 14;
- else if (Configuration.IRQ_Channel15)
- HostAdapter->IRQ_Channel = 15;
- else Result = false;
- }
- else Result = false;
+ {
+ if (BusLogic_Command(HostAdapter, BusLogic_InquireConfiguration,
+ NULL, 0, &Configuration, sizeof(Configuration))
+ == sizeof(Configuration))
+ {
+ if (Configuration.IRQ_Channel9)
+ HostAdapter->IRQ_Channel = 9;
+ else if (Configuration.IRQ_Channel10)
+ HostAdapter->IRQ_Channel = 10;
+ else if (Configuration.IRQ_Channel11)
+ HostAdapter->IRQ_Channel = 11;
+ else if (Configuration.IRQ_Channel12)
+ HostAdapter->IRQ_Channel = 12;
+ else if (Configuration.IRQ_Channel14)
+ HostAdapter->IRQ_Channel = 14;
+ else if (Configuration.IRQ_Channel15)
+ HostAdapter->IRQ_Channel = 15;
+ else Result = false;
+ }
+ else Result = false;
+ }
/*
Issue the Inquire Extended Setup Information command. Only genuine
BusLogic Host Adapters and true clones support this command. Adaptec 1542C
@@ -1484,7 +1503,7 @@ static boolean BusLogic_CheckHostAdapter(BusLogic_HostAdapter_T *HostAdapter)
/*
Provide tracing information if requested and return.
*/
- if (BusLogic_GlobalOptions.Bits.TraceProbe)
+ if (BusLogic_GlobalOptions.TraceProbe)
BusLogic_Notice("BusLogic_Check(0x%X): MultiMaster %s\n", HostAdapter,
HostAdapter->IO_Address, (Result ? "Found" : "Not Found"));
return Result;
@@ -1512,7 +1531,7 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
BusLogic_GeometryRegister_T GeometryRegister;
BusLogic_RequestedReplyLength_T RequestedReplyLength;
unsigned char *TargetPointer, Character;
- int i;
+ int TargetID, i;
/*
Configuration Information for FlashPoint Host Adapters is provided in the
FlashPoint_Info structure by the FlashPoint SCCB Manager's Probe Function.
@@ -1521,7 +1540,7 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
*/
if (BusLogic_FlashPointHostAdapterP(HostAdapter))
{
- FlashPoint_Info_T *FlashPointInfo = HostAdapter->FlashPointInfo;
+ FlashPoint_Info_T *FlashPointInfo = &HostAdapter->FlashPointInfo;
TargetPointer = HostAdapter->ModelName;
*TargetPointer++ = 'B';
*TargetPointer++ = 'T';
@@ -1550,8 +1569,8 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
HostAdapter->DriverScatterGatherLimit = BusLogic_ScatterGatherLimit;
HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
HostAdapter->MaxLogicalUnits = 32;
- HostAdapter->InitialCCBs = 64;
- HostAdapter->IncrementalCCBs = 16;
+ HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize;
+ HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize;
HostAdapter->DriverQueueDepth = 255;
HostAdapter->HostAdapterQueueDepth = HostAdapter->DriverQueueDepth;
HostAdapter->SynchronousPermitted = FlashPointInfo->SynchronousPermitted;
@@ -1698,12 +1717,14 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
HostAdapter->HostAdapterBusType =
BusLogic_HostAdapterBusTypes[HostAdapter->ModelName[3] - '4'];
if (HostAdapter->HostAdapterBusType == BusLogic_ISA_Bus)
- if (Configuration.DMA_Channel5)
- HostAdapter->DMA_Channel = 5;
- else if (Configuration.DMA_Channel6)
- HostAdapter->DMA_Channel = 6;
- else if (Configuration.DMA_Channel7)
- HostAdapter->DMA_Channel = 7;
+ {
+ if (Configuration.DMA_Channel5)
+ HostAdapter->DMA_Channel = 5;
+ else if (Configuration.DMA_Channel6)
+ HostAdapter->DMA_Channel = 6;
+ else if (Configuration.DMA_Channel7)
+ HostAdapter->DMA_Channel = 7;
+ }
/*
Determine whether Extended Translation is enabled and save it in
the Host Adapter structure.
@@ -1837,7 +1858,7 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
HostAdapter->MaxTargetDevices = (HostAdapter->HostWideSCSI ? 16 : 8);
HostAdapter->MaxLogicalUnits = (HostAdapter->ExtendedLUNSupport ? 32 : 8);
/*
- Select appropriate values for the Driver Queue Depth, Mailbox Count,
+ Select appropriate values for the Mailbox Count, Driver Queue Depth,
Initial CCBs, and Incremental CCBs variables based on whether or not Strict
Round Robin Mode is supported. If Strict Round Robin Mode is supported,
then there is no performance degradation in using the maximum possible
@@ -1868,18 +1889,16 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
if (strcmp(HostAdapter->FirmwareVersion, "3.31") >= 0)
{
HostAdapter->StrictRoundRobinModeSupport = true;
- HostAdapter->MailboxCount = 255;
- HostAdapter->InitialCCBs = 64;
- HostAdapter->IncrementalCCBs = 16;
+ HostAdapter->MailboxCount = BusLogic_MaxMailboxes;
}
else
{
HostAdapter->StrictRoundRobinModeSupport = false;
HostAdapter->MailboxCount = 32;
- HostAdapter->InitialCCBs = 32;
- HostAdapter->IncrementalCCBs = 8;
}
HostAdapter->DriverQueueDepth = HostAdapter->MailboxCount;
+ HostAdapter->InitialCCBs = 4 * BusLogic_CCB_AllocationGroupSize;
+ HostAdapter->IncrementalCCBs = BusLogic_CCB_AllocationGroupSize;
/*
Tagged Queuing support is available and operates properly on all "W" series
MultiMaster Host Adapters, on "C" series MultiMaster Host Adapters with
@@ -1931,57 +1950,32 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T
*/
Common:
/*
- Initialize the Host Adapter Name and Interrupt Label fields from the
- Model Name.
+ Initialize the Host Adapter Full Model Name and Interrupt Label fields
+ from the Model Name.
*/
strcpy(HostAdapter->FullModelName, "BusLogic ");
strcat(HostAdapter->FullModelName, HostAdapter->ModelName);
strcpy(HostAdapter->InterruptLabel, HostAdapter->FullModelName);
/*
Select an appropriate value for the Tagged Queue Depth either from a
- Command Line Entry, or based on whether this Host Adapter requires that ISA
- Bounce Buffers be used. The Tagged Queue Depth is left at 0 for automatic
- determination in BusLogic_SelectQueueDepths. Initialize the Untagged Queue
- Depth. Tagged Queuing is disabled by default when the Tagged Queue Depth
- is 1 since queuing multiple commands is not possible.
- */
- if (HostAdapter->CommandLineEntry != NULL &&
- HostAdapter->CommandLineEntry->TaggedQueueDepth > 0)
- HostAdapter->TaggedQueueDepth =
- HostAdapter->CommandLineEntry->TaggedQueueDepth;
- else if (HostAdapter->BounceBuffersRequired)
- HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepthBounceBuffers;
- else HostAdapter->TaggedQueueDepth = BusLogic_TaggedQueueDepthAutomatic;
- HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
- if (HostAdapter->UntaggedQueueDepth > HostAdapter->TaggedQueueDepth &&
- HostAdapter->TaggedQueueDepth > 0)
- HostAdapter->UntaggedQueueDepth = HostAdapter->TaggedQueueDepth;
- if (HostAdapter->TaggedQueueDepth == 1)
- HostAdapter->TaggedQueuingPermitted = 0;
- /*
- Select an appropriate value for Bus Settle Time either from a Command
- Line Entry, or from BusLogic_DefaultBusSettleTime.
- */
- if (HostAdapter->CommandLineEntry != NULL &&
- HostAdapter->CommandLineEntry->BusSettleTime > 0)
- HostAdapter->BusSettleTime = HostAdapter->CommandLineEntry->BusSettleTime;
- else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime;
- /*
- Select an appropriate value for Local Options from a Command Line Entry.
- */
- if (HostAdapter->CommandLineEntry != NULL)
- HostAdapter->LocalOptions = HostAdapter->CommandLineEntry->LocalOptions;
- /*
- Select appropriate values for the Error Recovery Strategy array either from
- a Command Line Entry, or using BusLogic_ErrorRecovery_Default.
+ BusLogic Driver Options specification, or based on whether this Host
+ Adapter requires that ISA Bounce Buffers be used. The Tagged Queue Depth
+ is left at 0 for automatic determination in BusLogic_SelectQueueDepths.
+ Initialize the Untagged Queue Depth.
*/
- if (HostAdapter->CommandLineEntry != NULL)
- memcpy(HostAdapter->ErrorRecoveryStrategy,
- HostAdapter->CommandLineEntry->ErrorRecoveryStrategy,
- sizeof(HostAdapter->ErrorRecoveryStrategy));
- else memset(HostAdapter->ErrorRecoveryStrategy,
- BusLogic_ErrorRecovery_Default,
- sizeof(HostAdapter->ErrorRecoveryStrategy));
+ for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+ {
+ unsigned char QueueDepth = 0;
+ if (HostAdapter->DriverOptions != NULL &&
+ HostAdapter->DriverOptions->QueueDepth[TargetID] > 0)
+ QueueDepth = HostAdapter->DriverOptions->QueueDepth[TargetID];
+ else if (HostAdapter->BounceBuffersRequired)
+ QueueDepth = BusLogic_TaggedQueueDepthBB;
+ HostAdapter->QueueDepth[TargetID] = QueueDepth;
+ }
+ if (HostAdapter->BounceBuffersRequired)
+ HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepthBB;
+ else HostAdapter->UntaggedQueueDepth = BusLogic_UntaggedQueueDepth;
/*
Tagged Queuing is only allowed if Disconnect/Reconnect is permitted.
Therefore, mask the Tagged Queuing Permitted Default bits with the
@@ -1989,15 +1983,34 @@ Common:
*/
HostAdapter->TaggedQueuingPermitted &= HostAdapter->DisconnectPermitted;
/*
- Combine the default Tagged Queuing Permitted bits with any Command
- Line Entry Tagged Queuing specification.
+ Combine the default Tagged Queuing Permitted bits with any BusLogic Driver
+ Options Tagged Queuing specification.
*/
- if (HostAdapter->CommandLineEntry != NULL)
+ if (HostAdapter->DriverOptions != NULL)
HostAdapter->TaggedQueuingPermitted =
- (HostAdapter->CommandLineEntry->TaggedQueuingPermitted &
- HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask) |
+ (HostAdapter->DriverOptions->TaggedQueuingPermitted &
+ HostAdapter->DriverOptions->TaggedQueuingPermittedMask) |
(HostAdapter->TaggedQueuingPermitted &
- ~HostAdapter->CommandLineEntry->TaggedQueuingPermittedMask);
+ ~HostAdapter->DriverOptions->TaggedQueuingPermittedMask);
+ /*
+ Select appropriate values for the Error Recovery Strategy array
+ either from a BusLogic Driver Options specification, or using
+ BusLogic_ErrorRecovery_Default.
+ */
+ for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+ if (HostAdapter->DriverOptions != NULL)
+ HostAdapter->ErrorRecoveryStrategy[TargetID] =
+ HostAdapter->DriverOptions->ErrorRecoveryStrategy[TargetID];
+ else HostAdapter->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_Default;
+ /*
+ Select an appropriate value for Bus Settle Time either from a BusLogic
+ Driver Options specification, or from BusLogic_DefaultBusSettleTime.
+ */
+ if (HostAdapter->DriverOptions != NULL &&
+ HostAdapter->DriverOptions->BusSettleTime > 0)
+ HostAdapter->BusSettleTime = HostAdapter->DriverOptions->BusSettleTime;
+ else HostAdapter->BusSettleTime = BusLogic_DefaultBusSettleTime;
/*
Indicate reading the Host Adapter Configuration completed successfully.
*/
@@ -2017,7 +2030,8 @@ static boolean BusLogic_ReportHostAdapterConfiguration(BusLogic_HostAdapter_T
unsigned short SynchronousPermitted, FastPermitted;
unsigned short UltraPermitted, WidePermitted;
unsigned short DisconnectPermitted, TaggedQueuingPermitted;
- boolean CommonSynchronousNegotiation, CommonErrorRecovery;
+ boolean CommonSynchronousNegotiation, CommonTaggedQueueDepth;
+ boolean CommonErrorRecovery;
char SynchronousString[BusLogic_MaxTargetDevices+1];
char WideString[BusLogic_MaxTargetDevices+1];
char DisconnectString[BusLogic_MaxTargetDevices+1];
@@ -2083,22 +2097,26 @@ static boolean BusLogic_ReportHostAdapterConfiguration(BusLogic_HostAdapter_T
CommonSynchronousNegotiation = true;
}
else if (SynchronousPermitted == AllTargetsMask)
- if (FastPermitted == 0)
- {
- SynchronousMessage = "Slow";
- CommonSynchronousNegotiation = true;
- }
- else if (FastPermitted == AllTargetsMask)
- if (UltraPermitted == 0)
+ {
+ if (FastPermitted == 0)
{
- SynchronousMessage = "Fast";
+ SynchronousMessage = "Slow";
CommonSynchronousNegotiation = true;
}
- else if (UltraPermitted == AllTargetsMask)
+ else if (FastPermitted == AllTargetsMask)
{
- SynchronousMessage = "Ultra";
- CommonSynchronousNegotiation = true;
+ if (UltraPermitted == 0)
+ {
+ SynchronousMessage = "Fast";
+ CommonSynchronousNegotiation = true;
+ }
+ else if (UltraPermitted == AllTargetsMask)
+ {
+ SynchronousMessage = "Ultra";
+ CommonSynchronousNegotiation = true;
+ }
}
+ }
if (!CommonSynchronousNegotiation)
{
for (TargetID = 0;
@@ -2175,9 +2193,20 @@ static boolean BusLogic_ReportHostAdapterConfiguration(BusLogic_HostAdapter_T
HostAdapter, HostAdapter->DriverQueueDepth,
HostAdapter->DriverScatterGatherLimit);
BusLogic_Info(" Tagged Queue Depth: ", HostAdapter);
- if (HostAdapter->TaggedQueueDepth > 0)
- BusLogic_Info("%d", HostAdapter, HostAdapter->TaggedQueueDepth);
- else BusLogic_Info("Automatic", HostAdapter);
+ CommonTaggedQueueDepth = true;
+ for (TargetID = 1; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ if (HostAdapter->QueueDepth[TargetID] != HostAdapter->QueueDepth[0])
+ {
+ CommonTaggedQueueDepth = false;
+ break;
+ }
+ if (CommonTaggedQueueDepth)
+ {
+ if (HostAdapter->QueueDepth[0] > 0)
+ BusLogic_Info("%d", HostAdapter, HostAdapter->QueueDepth[0]);
+ else BusLogic_Info("Automatic", HostAdapter);
+ }
+ else BusLogic_Info("Individual", HostAdapter);
BusLogic_Info(", Untagged Queue Depth: %d\n", HostAdapter,
HostAdapter->UntaggedQueueDepth);
CommonErrorRecovery = true;
@@ -2314,50 +2343,6 @@ static void BusLogic_ReleaseResources(BusLogic_HostAdapter_T *HostAdapter)
/*
- BusLogic_TestInterrupts tests for proper functioning of the Host Adapter
- Interrupt Register and that interrupts generated by the Host Adapter are
- getting through to the Interrupt Handler. A large proportion of initial
- problems with installing PCI Host Adapters are due to configuration problems
- where either the Host Adapter or Motherboard is configured incorrectly, and
- interrupts do not get through as a result.
-*/
-
-static boolean BusLogic_TestInterrupts(BusLogic_HostAdapter_T *HostAdapter)
-{
- unsigned int InitialInterruptCount, FinalInterruptCount;
- int TestCount = 5, i;
- /*
- FlashPoint Host Adapters do not provide for an interrupt test.
- */
- if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
- /*
- Inhibit the Interrupt Test if requested.
- */
- if (HostAdapter->LocalOptions.Bits.InhibitInterruptTest) return true;
- /*
- Issue the Test Command Complete Interrupt commands.
- */
- InitialInterruptCount = kstat.interrupts[HostAdapter->IRQ_Channel];
- for (i = 0; i < TestCount; i++)
- BusLogic_Command(HostAdapter, BusLogic_TestCommandCompleteInterrupt,
- NULL, 0, NULL, 0);
- FinalInterruptCount = kstat.interrupts[HostAdapter->IRQ_Channel];
- /*
- Verify that BusLogic_InterruptHandler was called at least TestCount
- times. Shared IRQ Channels could cause more than TestCount interrupts to
- occur, but there should never be fewer than TestCount, unless one or more
- interrupts were lost.
- */
- if (FinalInterruptCount < InitialInterruptCount + TestCount)
- return BusLogic_Failure(HostAdapter, "HOST ADAPTER INTERRUPT TEST");
- /*
- Indicate the Host Adapter Interrupt Test completed successfully.
- */
- return true;
-}
-
-
-/*
BusLogic_InitializeHostAdapter initializes Host Adapter. This is the only
function called during SCSI Host Adapter detection which modifies the state
of the Host Adapter from its initial power on or hard reset state.
@@ -2376,20 +2361,31 @@ static boolean BusLogic_InitializeHostAdapter(BusLogic_HostAdapter_T
for each Target Device.
*/
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
- HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
- memset(HostAdapter->TaggedQueuingActive, false,
- sizeof(HostAdapter->TaggedQueuingActive));
- memset(HostAdapter->CommandSuccessfulFlag, false,
- sizeof(HostAdapter->CommandSuccessfulFlag));
- memset(HostAdapter->ActiveCommands, 0,
- sizeof(HostAdapter->ActiveCommands));
- memset(HostAdapter->CommandsSinceReset, 0,
- sizeof(HostAdapter->CommandsSinceReset));
+ {
+ HostAdapter->BusDeviceResetPendingCCB[TargetID] = NULL;
+ HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
+ HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false;
+ HostAdapter->ActiveCommands[TargetID] = 0;
+ HostAdapter->CommandsSinceReset[TargetID] = 0;
+ }
/*
FlashPoint Host Adapters do not use Outgoing and Incoming Mailboxes.
*/
if (BusLogic_FlashPointHostAdapterP(HostAdapter)) goto Done;
/*
+ Initialize the Outgoing and Incoming Mailbox pointers.
+ */
+ HostAdapter->FirstOutgoingMailbox =
+ (BusLogic_OutgoingMailbox_T *) HostAdapter->MailboxSpace;
+ HostAdapter->LastOutgoingMailbox =
+ HostAdapter->FirstOutgoingMailbox + HostAdapter->MailboxCount - 1;
+ HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
+ HostAdapter->FirstIncomingMailbox =
+ (BusLogic_IncomingMailbox_T *) (HostAdapter->LastOutgoingMailbox + 1);
+ HostAdapter->LastIncomingMailbox =
+ HostAdapter->FirstIncomingMailbox + HostAdapter->MailboxCount - 1;
+ HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
+ /*
Initialize the Outgoing and Incoming Mailbox structures.
*/
memset(HostAdapter->FirstOutgoingMailbox, 0,
@@ -2397,11 +2393,6 @@ static boolean BusLogic_InitializeHostAdapter(BusLogic_HostAdapter_T
memset(HostAdapter->FirstIncomingMailbox, 0,
HostAdapter->MailboxCount * sizeof(BusLogic_IncomingMailbox_T));
/*
- Initialize the pointers to the Next Mailboxes.
- */
- HostAdapter->NextOutgoingMailbox = HostAdapter->FirstOutgoingMailbox;
- HostAdapter->NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
- /*
Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes.
*/
ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount;
@@ -2442,11 +2433,14 @@ static boolean BusLogic_InitializeHostAdapter(BusLogic_HostAdapter_T
Announce Successful Initialization.
*/
Done:
- if (HostAdapter->HostAdapterInitialized)
- BusLogic_Warning("*** %s Initialized Successfully ***\n",
- HostAdapter, HostAdapter->FullModelName);
- else BusLogic_Info("*** %s Initialized Successfully ***\n",
- HostAdapter, HostAdapter->FullModelName);
+ if (!HostAdapter->HostAdapterInitialized)
+ {
+ BusLogic_Info("*** %s Initialized Successfully ***\n",
+ HostAdapter, HostAdapter->FullModelName);
+ BusLogic_Info("\n", HostAdapter);
+ }
+ else BusLogic_Warning("*** %s Initialized Successfully ***\n",
+ HostAdapter, HostAdapter->FullModelName);
HostAdapter->HostAdapterInitialized = true;
/*
Indicate the Host Adapter Initialization completed successfully.
@@ -2457,7 +2451,7 @@ Done:
/*
BusLogic_TargetDeviceInquiry inquires about the Target Devices accessible
- through Host Adapter and reports on the results.
+ through Host Adapter.
*/
static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T
@@ -2468,7 +2462,7 @@ static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T
BusLogic_SetupInformation_T SetupInformation;
BusLogic_SynchronousPeriod_T SynchronousPeriod;
BusLogic_RequestedReplyLength_T RequestedReplyLength;
- int TargetDevicesFound = 0, TargetID;
+ int TargetID;
/*
Wait a few seconds between the Host Adapter Hard Reset which initiates
a SCSI Bus Reset and issuing any SCSI Commands. Some SCSI devices get
@@ -2480,13 +2474,11 @@ static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T
*/
if (BusLogic_FlashPointHostAdapterP(HostAdapter)) return true;
/*
- Inhibit the Target Devices Inquiry if requested.
+ Inhibit the Target Device Inquiry if requested.
*/
- if (HostAdapter->LocalOptions.Bits.InhibitTargetInquiry)
- {
- BusLogic_Info(" Target Device Inquiry Inhibited\n", HostAdapter);
- return true;
- }
+ if (HostAdapter->DriverOptions != NULL &&
+ HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry)
+ return true;
/*
Issue the Inquire Target Devices command for host adapters with firmware
version 4.25 or later, or the Inquire Installed Devices ID 0 to 7 command
@@ -2502,6 +2494,9 @@ static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T
&InstalledDevices, sizeof(InstalledDevices))
!= sizeof(InstalledDevices))
return BusLogic_Failure(HostAdapter, "INQUIRE TARGET DEVICES");
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ HostAdapter->TargetFlags[TargetID].TargetExists =
+ (InstalledDevices & (1 << TargetID) ? true : false);
}
else
{
@@ -2511,10 +2506,9 @@ static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T
!= sizeof(InstalledDevicesID0to7))
return BusLogic_Failure(HostAdapter,
"INQUIRE INSTALLED DEVICES ID 0 TO 7");
- InstalledDevices = 0;
for (TargetID = 0; TargetID < 8; TargetID++)
- if (InstalledDevicesID0to7[TargetID] != 0)
- InstalledDevices |= (1 << TargetID);
+ HostAdapter->TargetFlags[TargetID].TargetExists =
+ (InstalledDevicesID0to7[TargetID] != 0 ? true : false);
}
/*
Issue the Inquire Setup Information command.
@@ -2525,6 +2519,19 @@ static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T
&SetupInformation, sizeof(SetupInformation))
!= sizeof(SetupInformation))
return BusLogic_Failure(HostAdapter, "INQUIRE SETUP INFORMATION");
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ HostAdapter->SynchronousOffset[TargetID] =
+ (TargetID < 8
+ ? SetupInformation.SynchronousValuesID0to7[TargetID].Offset
+ : SetupInformation.SynchronousValuesID8to15[TargetID-8].Offset);
+ if (strcmp(HostAdapter->FirmwareVersion, "5.06L") >= 0)
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ HostAdapter->TargetFlags[TargetID].WideTransfersActive =
+ (TargetID < 8
+ ? (SetupInformation.WideTransfersActiveID0to7 & (1 << TargetID)
+ ? true : false)
+ : (SetupInformation.WideTransfersActiveID8to15 & (1 << (TargetID-8))
+ ? true : false));
/*
Issue the Inquire Synchronous Period command.
*/
@@ -2536,69 +2543,96 @@ static boolean BusLogic_TargetDeviceInquiry(BusLogic_HostAdapter_T
&SynchronousPeriod, sizeof(SynchronousPeriod))
!= sizeof(SynchronousPeriod))
return BusLogic_Failure(HostAdapter, "INQUIRE SYNCHRONOUS PERIOD");
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ HostAdapter->SynchronousPeriod[TargetID] = SynchronousPeriod[TargetID];
}
else
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
if (SetupInformation.SynchronousValuesID0to7[TargetID].Offset > 0)
- SynchronousPeriod[TargetID] =
+ HostAdapter->SynchronousPeriod[TargetID] =
20 + 5 * SetupInformation.SynchronousValuesID0to7[TargetID]
.TransferPeriod;
- else SynchronousPeriod[TargetID] = 0;
/*
- Save the Installed Devices, Synchronous Values, and Synchronous Period
- information in the Host Adapter structure.
+ Indicate the Target Device Inquiry completed successfully.
*/
- HostAdapter->InstalledDevices = InstalledDevices;
- memcpy(HostAdapter->SynchronousValues,
- SetupInformation.SynchronousValuesID0to7,
- sizeof(BusLogic_SynchronousValues8_T));
- if (HostAdapter->HostWideSCSI)
- memcpy(&HostAdapter->SynchronousValues[8],
- SetupInformation.SynchronousValuesID8to15,
- sizeof(BusLogic_SynchronousValues8_T));
- memcpy(HostAdapter->SynchronousPeriod, SynchronousPeriod,
- sizeof(BusLogic_SynchronousPeriod_T));
+ return true;
+}
+
+
+/*
+ BusLogic_ReportTargetDeviceInfo reports about the Target Devices accessible
+ through Host Adapter.
+*/
+
+static void BusLogic_ReportTargetDeviceInfo(BusLogic_HostAdapter_T
+ *HostAdapter)
+{
+ int TargetID;
/*
- Report on the Target Devices found.
+ Inhibit the Target Device Inquiry and Reporting if requested.
*/
- for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
- if (HostAdapter->InstalledDevices & (1 << TargetID))
- {
- int SynchronousPeriod = HostAdapter->SynchronousPeriod[TargetID];
- if (SynchronousPeriod > 10)
- {
- int SynchronousTransferRate = 100000000 / SynchronousPeriod;
- int RoundedSynchronousTransferRate =
- (SynchronousTransferRate + 5000) / 10000;
- BusLogic_Info(" Target %d: Synchronous at "
- "%d.%02d mega-transfers/second, offset %d\n",
- HostAdapter, TargetID,
- RoundedSynchronousTransferRate / 100,
- RoundedSynchronousTransferRate % 100,
- HostAdapter->SynchronousValues[TargetID].Offset);
- }
- else if (SynchronousPeriod > 0)
- {
- int SynchronousTransferRate = 100000000 / SynchronousPeriod;
- int RoundedSynchronousTransferRate =
- (SynchronousTransferRate + 50000) / 100000;
- BusLogic_Info(" Target %d: Synchronous at "
- "%d.%01d mega-transfers/second, offset %d\n",
- HostAdapter, TargetID,
- RoundedSynchronousTransferRate / 10,
- RoundedSynchronousTransferRate % 10,
- HostAdapter->SynchronousValues[TargetID].Offset);
- }
- else BusLogic_Info(" Target %d: Asynchronous\n",
- HostAdapter, TargetID);
- TargetDevicesFound++;
- }
- if (TargetDevicesFound == 0)
- BusLogic_Info(" No Target Devices Found\n", HostAdapter);
+ if (BusLogic_MultiMasterHostAdapterP(HostAdapter) &&
+ HostAdapter->DriverOptions != NULL &&
+ HostAdapter->DriverOptions->LocalOptions.InhibitTargetInquiry)
+ return;
/*
- Indicate the Target Device Inquiry completed successfully.
+ Report on the Target Devices found.
*/
- return true;
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ {
+ BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+ if (TargetFlags->TargetExists && !TargetFlags->TargetInfoReported)
+ {
+ int SynchronousTransferRate = 0;
+ if (BusLogic_FlashPointHostAdapterP(HostAdapter))
+ {
+ boolean WideTransfersActive;
+ FlashPoint_InquireTargetInfo(
+ HostAdapter->CardHandle, TargetID,
+ &HostAdapter->SynchronousPeriod[TargetID],
+ &HostAdapter->SynchronousOffset[TargetID],
+ &WideTransfersActive);
+ TargetFlags->WideTransfersActive = WideTransfersActive;
+ }
+ else if (TargetFlags->WideTransfersSupported &&
+ (HostAdapter->WidePermitted & (1 << TargetID)) &&
+ strcmp(HostAdapter->FirmwareVersion, "5.06L") < 0)
+ TargetFlags->WideTransfersActive = true;
+ if (HostAdapter->SynchronousPeriod[TargetID] > 0)
+ SynchronousTransferRate =
+ 100000 / HostAdapter->SynchronousPeriod[TargetID];
+ if (TargetFlags->WideTransfersActive)
+ SynchronousTransferRate <<= 1;
+ if (SynchronousTransferRate >= 9950)
+ {
+ SynchronousTransferRate = (SynchronousTransferRate + 50) / 100;
+ BusLogic_Info("Target %d: Queue Depth %d, %sSynchronous at "
+ "%d.%01d MB/sec, offset %d\n",
+ HostAdapter, TargetID,
+ HostAdapter->QueueDepth[TargetID],
+ (TargetFlags->WideTransfersActive ? "Wide " : ""),
+ SynchronousTransferRate / 10,
+ SynchronousTransferRate % 10,
+ HostAdapter->SynchronousOffset[TargetID]);
+ }
+ else if (SynchronousTransferRate > 0)
+ {
+ SynchronousTransferRate = (SynchronousTransferRate + 5) / 10;
+ BusLogic_Info("Target %d: Queue Depth %d, %sSynchronous at "
+ "%d.%02d MB/sec, offset %d\n",
+ HostAdapter, TargetID,
+ HostAdapter->QueueDepth[TargetID],
+ (TargetFlags->WideTransfersActive ? "Wide " : ""),
+ SynchronousTransferRate / 100,
+ SynchronousTransferRate % 100,
+ HostAdapter->SynchronousOffset[TargetID]);
+ }
+ else BusLogic_Info("Target %d: Queue Depth %d, Asynchronous\n",
+ HostAdapter, TargetID,
+ HostAdapter->QueueDepth[TargetID]);
+ TargetFlags->TargetInfoReported = true;
+ }
+ }
}
@@ -2628,9 +2662,11 @@ static void BusLogic_InitializeHostStructure(BusLogic_HostAdapter_T
/*
- BusLogic_SelectQueueDepths selects Queue Depths for each Target Device
- based on the Host Adapter's Total Queue Depth and the number, type, speed,
- and capabilities of the Target Devices.
+ BusLogic_SelectQueueDepths selects Queue Depths for each Target Device based
+ on the Host Adapter's Total Queue Depth and the number, type, speed, and
+ capabilities of the Target Devices. When called for the last Host Adapter,
+ it reports on the Target Device Information for all BusLogic Host Adapters
+ since all the Target Devices have now been probed.
*/
static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
@@ -2638,41 +2674,60 @@ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
{
BusLogic_HostAdapter_T *HostAdapter =
(BusLogic_HostAdapter_T *) Host->hostdata;
- int TaggedQueueDepth = HostAdapter->TaggedQueueDepth;
- int UntaggedQueueDepth = HostAdapter->UntaggedQueueDepth;
- int TaggedDeviceCount = 0, UntaggedDeviceCount = 0;
- int DesiredCCBs = HostAdapter->MaxTargetDevices - 1;
+ int TaggedDeviceCount = 0, AutomaticTaggedDeviceCount = 0;
+ int UntaggedDeviceCount = 0, AutomaticTaggedQueueDepth = 0;
+ int AllocatedQueueDepth = 0;
SCSI_Device_T *Device;
- for (Device = DeviceList; Device != NULL; Device = Device->next)
- if (Device->host == Host)
+ int TargetID;
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ if (HostAdapter->TargetFlags[TargetID].TargetExists)
{
- if (Device->tagged_supported &&
- (HostAdapter->TaggedQueuingPermitted & (1 << Device->id)))
- TaggedDeviceCount++;
+ int QueueDepth = HostAdapter->UntaggedQueueDepth;
+ if (HostAdapter->TargetFlags[TargetID].TaggedQueuingSupported &&
+ (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
+ {
+ QueueDepth = HostAdapter->QueueDepth[TargetID];
+ TaggedDeviceCount++;
+ if (QueueDepth == 0) AutomaticTaggedDeviceCount++;
+ }
else UntaggedDeviceCount++;
+ HostAdapter->QueueDepth[TargetID] = QueueDepth;
+ AllocatedQueueDepth += QueueDepth;
}
- if (TaggedQueueDepth == 0 && TaggedDeviceCount > 0)
+ HostAdapter->TargetDeviceCount = TaggedDeviceCount + UntaggedDeviceCount;
+ if (AutomaticTaggedDeviceCount > 0)
{
- TaggedQueueDepth =
- 1 + ((HostAdapter->HostAdapterQueueDepth
- - UntaggedDeviceCount * UntaggedQueueDepth)
- / TaggedDeviceCount);
- if (TaggedQueueDepth > BusLogic_PreferredTaggedQueueDepth)
- TaggedQueueDepth = BusLogic_PreferredTaggedQueueDepth;
+ AutomaticTaggedQueueDepth =
+ (HostAdapter->HostAdapterQueueDepth - AllocatedQueueDepth)
+ / AutomaticTaggedDeviceCount;
+ if (AutomaticTaggedQueueDepth > BusLogic_MaxAutomaticTaggedQueueDepth)
+ AutomaticTaggedQueueDepth = BusLogic_MaxAutomaticTaggedQueueDepth;
+ if (AutomaticTaggedQueueDepth < BusLogic_MinAutomaticTaggedQueueDepth)
+ AutomaticTaggedQueueDepth = BusLogic_MinAutomaticTaggedQueueDepth;
+ for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
+ if (HostAdapter->TargetFlags[TargetID].TargetExists &&
+ HostAdapter->QueueDepth[TargetID] == 0)
+ {
+ AllocatedQueueDepth += AutomaticTaggedQueueDepth;
+ HostAdapter->QueueDepth[TargetID] = AutomaticTaggedQueueDepth;
+ }
}
for (Device = DeviceList; Device != NULL; Device = Device->next)
if (Device->host == Host)
- {
- if (Device->tagged_supported &&
- (HostAdapter->TaggedQueuingPermitted & (1 << Device->id)))
- Device->queue_depth = TaggedQueueDepth;
- else Device->queue_depth = UntaggedQueueDepth;
- HostAdapter->QueueDepth[Device->id] = Device->queue_depth;
- DesiredCCBs += Device->queue_depth;
- }
+ Device->queue_depth = HostAdapter->QueueDepth[Device->id];
+ /* Allocate an extra CCB for each Target Device for a Bus Device Reset. */
+ AllocatedQueueDepth += HostAdapter->TargetDeviceCount;
+ if (AllocatedQueueDepth > HostAdapter->DriverQueueDepth)
+ AllocatedQueueDepth = HostAdapter->DriverQueueDepth;
BusLogic_CreateAdditionalCCBs(HostAdapter,
- DesiredCCBs - HostAdapter->AllocatedCCBs,
+ AllocatedQueueDepth
+ - HostAdapter->AllocatedCCBs,
false);
+ if (HostAdapter == BusLogic_LastRegisteredHostAdapter)
+ for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
+ HostAdapter != NULL;
+ HostAdapter = HostAdapter->NextAll)
+ BusLogic_ReportTargetDeviceInfo(HostAdapter);
}
@@ -2686,50 +2741,48 @@ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host,
int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
{
- int BusLogicHostAdapterCount = 0, CommandLineEntryIndex = 0, ProbeIndex;
- char *MessageBuffer = NULL;
- if (BusLogic_ProbeOptions.Bits.NoProbe) return 0;
- BusLogic_InitializeProbeInfoList();
+ int BusLogicHostAdapterCount = 0, DriverOptionsIndex = 0, ProbeIndex;
+ BusLogic_HostAdapter_T *PrototypeHostAdapter;
+ if (BusLogic_ProbeOptions.NoProbe) return 0;
+ BusLogic_ProbeInfoList = (BusLogic_ProbeInfo_T *)
+ kmalloc(BusLogic_MaxHostAdapters * sizeof(BusLogic_ProbeInfo_T),
+ GFP_ATOMIC);
+ if (BusLogic_ProbeInfoList == NULL)
+ {
+ BusLogic_Error("BusLogic: Unable to allocate Probe Info List\n", NULL);
+ return 0;
+ }
+ memset(BusLogic_ProbeInfoList, 0,
+ BusLogic_MaxHostAdapters * sizeof(BusLogic_ProbeInfo_T));
+ PrototypeHostAdapter = (BusLogic_HostAdapter_T *)
+ kmalloc(sizeof(BusLogic_HostAdapter_T), GFP_ATOMIC);
+ if (PrototypeHostAdapter == NULL)
+ {
+ kfree(BusLogic_ProbeInfoList);
+ BusLogic_Error("BusLogic: Unable to allocate Prototype "
+ "Host Adapter\n", NULL);
+ return 0;
+ }
+ memset(PrototypeHostAdapter, 0, sizeof(BusLogic_HostAdapter_T));
+ if (BusLogic_Options != NULL)
+ BusLogic_ParseDriverOptions(BusLogic_Options);
+ BusLogic_InitializeProbeInfoList(PrototypeHostAdapter);
for (ProbeIndex = 0; ProbeIndex < BusLogic_ProbeInfoCount; ProbeIndex++)
{
BusLogic_ProbeInfo_T *ProbeInfo = &BusLogic_ProbeInfoList[ProbeIndex];
- BusLogic_HostAdapter_T HostAdapterPrototype;
- BusLogic_HostAdapter_T *HostAdapter = &HostAdapterPrototype;
+ BusLogic_HostAdapter_T *HostAdapter = PrototypeHostAdapter;
SCSI_Host_T *Host;
if (ProbeInfo->IO_Address == 0) continue;
memset(HostAdapter, 0, sizeof(BusLogic_HostAdapter_T));
- HostAdapter->IO_Address = ProbeInfo->IO_Address;
- HostAdapter->PCI_Address = ProbeInfo->PCI_Address;
HostAdapter->HostAdapterType = ProbeInfo->HostAdapterType;
HostAdapter->HostAdapterBusType = ProbeInfo->HostAdapterBusType;
+ HostAdapter->IO_Address = ProbeInfo->IO_Address;
+ HostAdapter->PCI_Address = ProbeInfo->PCI_Address;
HostAdapter->Bus = ProbeInfo->Bus;
HostAdapter->Device = ProbeInfo->Device;
HostAdapter->IRQ_Channel = ProbeInfo->IRQ_Channel;
HostAdapter->AddressCount =
- BusLogic_HostAdapter_AddressCount[HostAdapter->HostAdapterType];
- if (MessageBuffer == NULL)
- MessageBuffer =
- scsi_init_malloc(BusLogic_MessageBufferSize, GFP_ATOMIC);
- if (MessageBuffer == NULL)
- {
- BusLogic_Error("BusLogic: Unable to allocate Message Buffer\n",
- HostAdapter);
- return BusLogicHostAdapterCount;
- }
- HostAdapter->MessageBuffer = MessageBuffer;
- /*
- If an explicit I/O Address was specified, Initialize the Command Line
- Entry field and inhibit the check for whether the I/O Address range is
- already in use.
- */
- if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount &&
- BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address ==
- HostAdapter->IO_Address)
- HostAdapter->CommandLineEntry =
- &BusLogic_CommandLineEntries[CommandLineEntryIndex++];
- else if (check_region(HostAdapter->IO_Address,
- HostAdapter->AddressCount) < 0)
- continue;
+ BusLogic_HostAdapterAddressCount[HostAdapter->HostAdapterType];
/*
Probe the Host Adapter. If unsuccessful, abort further initialization.
*/
@@ -2738,22 +2791,20 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
Hard Reset the Host Adapter. If unsuccessful, abort further
initialization.
*/
- if (!BusLogic_HardResetHostAdapter(HostAdapter)) continue;
+ if (!BusLogic_HardwareResetHostAdapter(HostAdapter, true)) continue;
/*
Check the Host Adapter. If unsuccessful, abort further initialization.
*/
if (!BusLogic_CheckHostAdapter(HostAdapter)) continue;
/*
- Initialize the Command Line Entry field if an explicit I/O Address
- was not specified.
+ Initialize the Driver Options field if provided.
*/
- if (CommandLineEntryIndex < BusLogic_CommandLineEntryCount &&
- BusLogic_CommandLineEntries[CommandLineEntryIndex].IO_Address == 0)
- HostAdapter->CommandLineEntry =
- &BusLogic_CommandLineEntries[CommandLineEntryIndex++];
+ if (DriverOptionsIndex < BusLogic_DriverOptionsCount)
+ HostAdapter->DriverOptions =
+ &BusLogic_DriverOptions[DriverOptionsIndex++];
/*
Announce the Driver Version and Date, Author's Name, Copyright Notice,
- and Contact Address.
+ and Electronic Mail Address.
*/
BusLogic_AnnounceDriver(HostAdapter);
/*
@@ -2771,8 +2822,7 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
*/
Host = scsi_register(HostTemplate, sizeof(BusLogic_HostAdapter_T));
HostAdapter = (BusLogic_HostAdapter_T *) Host->hostdata;
- memcpy(HostAdapter, &HostAdapterPrototype,
- sizeof(BusLogic_HostAdapter_T));
+ memcpy(HostAdapter, PrototypeHostAdapter, sizeof(BusLogic_HostAdapter_T));
HostAdapter->SCSI_Host = Host;
HostAdapter->HostNumber = Host->host_no;
Host->select_queue_depths = BusLogic_SelectQueueDepths;
@@ -2785,18 +2835,14 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
BusLogic_RegisterHostAdapter(HostAdapter);
/*
Read the Host Adapter Configuration, Configure the Host Adapter,
- Acquire the System Resources necessary to use the Host Adapter,
- then Test Interrupts, Create the Mailboxes, Initial CCBs, and
- Target Device Statistics, Initialize the Host Adapter, and
- finally perform Target Device Inquiry.
+ Acquire the System Resources necessary to use the Host Adapter, then
+ Create the Initial CCBs, Initialize the Host Adapter, and finally
+ perform Target Device Inquiry.
*/
if (BusLogic_ReadHostAdapterConfiguration(HostAdapter) &&
BusLogic_ReportHostAdapterConfiguration(HostAdapter) &&
BusLogic_AcquireResources(HostAdapter) &&
- BusLogic_TestInterrupts(HostAdapter) &&
- BusLogic_CreateMailboxes(HostAdapter) &&
BusLogic_CreateInitialCCBs(HostAdapter) &&
- BusLogic_CreateTargetDeviceStatistics(HostAdapter) &&
BusLogic_InitializeHostAdapter(HostAdapter) &&
BusLogic_TargetDeviceInquiry(HostAdapter))
{
@@ -2806,7 +2852,6 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
Name of the Host Adapter will appear, and initialize the SCSI
Host structure.
*/
- MessageBuffer = NULL;
release_region(HostAdapter->IO_Address,
HostAdapter->AddressCount);
request_region(HostAdapter->IO_Address,
@@ -2818,24 +2863,22 @@ int BusLogic_DetectHostAdapter(SCSI_Host_Template_T *HostTemplate)
else
{
/*
- An error occurred during Host Adapter Configuration Querying,
- Host Adapter Configuration, Resource Acquisition, Interrupt
- Testing, CCB Creation, Host Adapter Initialization, or Target
- Device Inquiry, so remove Host Adapter from the list of
- registered BusLogic Host Adapters, destroy the Target Device
- Statistics, CCBs, and Mailboxes, Release the System Resources,
- and Unregister the SCSI Host.
+ An error occurred during Host Adapter Configuration Querying, Host
+ Adapter Configuration, Resource Acquisition, CCB Creation, Host
+ Adapter Initialization, or Target Device Inquiry, so remove Host
+ Adapter from the list of registered BusLogic Host Adapters, destroy
+ the CCBs, Release the System Resources, and Unregister the SCSI
+ Host.
*/
- BusLogic_DestroyTargetDeviceStatistics(HostAdapter);
BusLogic_DestroyCCBs(HostAdapter);
- BusLogic_DestroyMailboxes(HostAdapter);
BusLogic_ReleaseResources(HostAdapter);
BusLogic_UnregisterHostAdapter(HostAdapter);
scsi_unregister(Host);
}
}
- if (MessageBuffer != NULL)
- scsi_init_free(MessageBuffer, BusLogic_MessageBufferSize);
+ kfree(PrototypeHostAdapter);
+ kfree(BusLogic_ProbeInfoList);
+ BusLogic_ProbeInfoList = NULL;
return BusLogicHostAdapterCount;
}
@@ -2851,21 +2894,16 @@ int BusLogic_ReleaseHostAdapter(SCSI_Host_T *Host)
BusLogic_HostAdapter_T *HostAdapter =
(BusLogic_HostAdapter_T *) Host->hostdata;
/*
- FlashPoint Host Adapters must also be released by the FlashPoint
+ FlashPoint Host Adapters must first be released by the FlashPoint
SCCB Manager.
*/
if (BusLogic_FlashPointHostAdapterP(HostAdapter))
- {
- FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle);
- scsi_init_free((char *) HostAdapter->FlashPointInfo,
- sizeof(FlashPoint_Info_T));
- }
+ FlashPoint_ReleaseHostAdapter(HostAdapter->CardHandle);
/*
- Destroy the CCBs and Mailboxes, and release any system resources acquired
- to support Host Adapter.
+ Destroy the CCBs and release any system resources acquired to
+ support Host Adapter.
*/
BusLogic_DestroyCCBs(HostAdapter);
- BusLogic_DestroyMailboxes(HostAdapter);
BusLogic_ReleaseResources(HostAdapter);
/*
Release usage of the I/O Address range.
@@ -2988,27 +3026,29 @@ static void BusLogic_ScanIncomingMailboxes(BusLogic_HostAdapter_T *HostAdapter)
BusLogic_CCB_T *CCB = (BusLogic_CCB_T *)
Bus_to_Virtual(NextIncomingMailbox->CCB);
if (CompletionCode != BusLogic_AbortedCommandNotFound)
- if (CCB->Status == BusLogic_CCB_Active ||
- CCB->Status == BusLogic_CCB_Reset)
- {
- /*
- Save the Completion Code for this CCB and queue the CCB
- for completion processing.
- */
- CCB->CompletionCode = CompletionCode;
- BusLogic_QueueCompletedCCB(CCB);
- }
- else
- {
- /*
- If a CCB ever appears in an Incoming Mailbox and is not marked as
- status Active or Reset, then there is most likely a bug in the
- Host Adapter firmware.
- */
- BusLogic_Warning("Illegal CCB #%ld status %d in "
- "Incoming Mailbox\n", HostAdapter,
- CCB->SerialNumber, CCB->Status);
- }
+ {
+ if (CCB->Status == BusLogic_CCB_Active ||
+ CCB->Status == BusLogic_CCB_Reset)
+ {
+ /*
+ Save the Completion Code for this CCB and queue the CCB
+ for completion processing.
+ */
+ CCB->CompletionCode = CompletionCode;
+ BusLogic_QueueCompletedCCB(CCB);
+ }
+ else
+ {
+ /*
+ If a CCB ever appears in an Incoming Mailbox and is not marked
+ as status Active or Reset, then there is most likely a bug in
+ the Host Adapter firmware.
+ */
+ BusLogic_Warning("Illegal CCB #%ld status %d in "
+ "Incoming Mailbox\n", HostAdapter,
+ CCB->SerialNumber, CCB->Status);
+ }
+ }
NextIncomingMailbox->CompletionCode = BusLogic_IncomingMailboxFree;
if (++NextIncomingMailbox > HostAdapter->LastIncomingMailbox)
NextIncomingMailbox = HostAdapter->FirstIncomingMailbox;
@@ -3047,10 +3087,9 @@ static void BusLogic_ProcessCompletedCCBs(void)
"%d Completed\n", HostAdapter,
CCB->SerialNumber, TargetID);
BusLogic_IncrementErrorCounter(
- &HostAdapter->TargetDeviceStatistics[TargetID]
- .BusDeviceResetsCompleted);
+ &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsCompleted);
+ HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
HostAdapter->CommandsSinceReset[TargetID] = 0;
- HostAdapter->TaggedQueuingActive[TargetID] = false;
HostAdapter->LastResetCompleted[TargetID] = jiffies;
/*
Place CCB back on the Host Adapter's free list.
@@ -3101,16 +3140,17 @@ static void BusLogic_ProcessCompletedCCBs(void)
HostAdapter, CCB->SerialNumber, CCB->TargetID);
break;
case BusLogic_CommandCompletedWithoutError:
- HostAdapter->TargetDeviceStatistics[CCB->TargetID]
+ HostAdapter->TargetStatistics[CCB->TargetID]
.CommandsCompleted++;
- HostAdapter->CommandSuccessfulFlag[CCB->TargetID] = true;
+ HostAdapter->TargetFlags[CCB->TargetID]
+ .CommandSuccessfulFlag = true;
Command->result = DID_OK << 16;
break;
case BusLogic_CommandAbortedAtHostRequest:
BusLogic_Warning("CCB #%ld to Target %d Aborted\n",
HostAdapter, CCB->SerialNumber, CCB->TargetID);
BusLogic_IncrementErrorCounter(
- &HostAdapter->TargetDeviceStatistics[CCB->TargetID]
+ &HostAdapter->TargetStatistics[CCB->TargetID]
.CommandAbortsCompleted);
Command->result = DID_ABORT << 16;
break;
@@ -3121,9 +3161,9 @@ static void BusLogic_ProcessCompletedCCBs(void)
CCB->TargetDeviceStatus);
if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout)
{
- HostAdapter->TargetDeviceStatistics[CCB->TargetID]
+ HostAdapter->TargetStatistics[CCB->TargetID]
.CommandsCompleted++;
- if (BusLogic_GlobalOptions.Bits.TraceErrors)
+ if (BusLogic_GlobalOptions.TraceErrors)
{
int i;
BusLogic_Notice("CCB #%ld Target %d: Result %X Host "
@@ -3147,6 +3187,22 @@ static void BusLogic_ProcessCompletedCCBs(void)
break;
}
/*
+ When an INQUIRY command completes normally, save the
+ CmdQue (Tagged Queuing Supported) and WBus16 (16 Bit
+ Wide Data Transfers Supported) bits.
+ */
+ if (CCB->CDB[0] == INQUIRY && CCB->CDB[1] == 0 &&
+ CCB->HostAdapterStatus == BusLogic_CommandCompletedNormally)
+ {
+ BusLogic_TargetFlags_T *TargetFlags =
+ &HostAdapter->TargetFlags[CCB->TargetID];
+ SCSI_Inquiry_T *InquiryResult =
+ (SCSI_Inquiry_T *) Command->request_buffer;
+ TargetFlags->TargetExists = true;
+ TargetFlags->TaggedQueuingSupported = InquiryResult->CmdQue;
+ TargetFlags->WideTransfersSupported = InquiryResult->WBus16;
+ }
+ /*
Place CCB back on the Host Adapter's free list.
*/
BusLogic_DeallocateCCB(CCB);
@@ -3171,7 +3227,7 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
{
BusLogic_HostAdapter_T *FirstHostAdapter =
BusLogic_RegisteredHostAdapters[IRQ_Channel];
- boolean HostAdapterResetRequested = false;
+ boolean HostAdapterResetRequired = false;
BusLogic_HostAdapter_T *HostAdapter;
BusLogic_Lock_T Lock;
/*
@@ -3213,8 +3269,8 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
*/
if (InterruptRegister.Bits.ExternalBusReset)
{
- HostAdapter->HostAdapterResetRequested = true;
- HostAdapterResetRequested = true;
+ HostAdapter->HostAdapterExternalReset = true;
+ HostAdapterResetRequired = true;
}
else if (InterruptRegister.Bits.IncomingMailboxLoaded)
BusLogic_ScanIncomingMailboxes(HostAdapter);
@@ -3228,11 +3284,20 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
Check if there is a pending interrupt for this Host Adapter.
*/
if (FlashPoint_InterruptPending(HostAdapter->CardHandle))
- if (FlashPoint_HandleInterrupt(HostAdapter->CardHandle)
- == FlashPoint_ExternalBusReset)
+ switch (FlashPoint_HandleInterrupt(HostAdapter->CardHandle))
{
- HostAdapter->HostAdapterResetRequested = true;
- HostAdapterResetRequested = true;
+ case FlashPoint_NormalInterrupt:
+ break;
+ case FlashPoint_ExternalBusReset:
+ HostAdapter->HostAdapterExternalReset = true;
+ HostAdapterResetRequired = true;
+ break;
+ case FlashPoint_InternalError:
+ BusLogic_Warning("Internal FlashPoint Error detected"
+ " - Resetting Host Adapter\n", HostAdapter);
+ HostAdapter->HostAdapterInternalError = true;
+ HostAdapterResetRequired = true;
+ break;
}
}
/*
@@ -3249,14 +3314,16 @@ static void BusLogic_InterruptHandler(int IRQ_Channel,
Iterate over the Host Adapters performing any requested
Host Adapter Resets.
*/
- if (HostAdapterResetRequested)
+ if (HostAdapterResetRequired)
for (HostAdapter = FirstHostAdapter;
HostAdapter != NULL;
HostAdapter = HostAdapter->Next)
- if (HostAdapter->HostAdapterResetRequested)
+ if (HostAdapter->HostAdapterExternalReset ||
+ HostAdapter->HostAdapterInternalError)
{
BusLogic_ResetHostAdapter(HostAdapter, NULL, 0);
- HostAdapter->HostAdapterResetRequested = false;
+ HostAdapter->HostAdapterExternalReset = false;
+ HostAdapter->HostAdapterInternalError = false;
scsi_mark_host_reset(HostAdapter->SCSI_Host);
}
}
@@ -3293,8 +3360,7 @@ static boolean BusLogic_WriteOutgoingMailbox(BusLogic_HostAdapter_T
{
HostAdapter->ActiveCommands[CCB->TargetID]++;
if (CCB->Opcode != BusLogic_BusDeviceReset)
- HostAdapter->TargetDeviceStatistics[CCB->TargetID]
- .CommandsAttempted++;
+ HostAdapter->TargetStatistics[CCB->TargetID].CommandsAttempted++;
}
return true;
}
@@ -3312,8 +3378,10 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
{
BusLogic_HostAdapter_T *HostAdapter =
(BusLogic_HostAdapter_T *) Command->host->hostdata;
- BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics =
- HostAdapter->TargetDeviceStatistics;
+ BusLogic_TargetFlags_T *TargetFlags =
+ &HostAdapter->TargetFlags[Command->target];
+ BusLogic_TargetStatistics_T *TargetStatistics =
+ HostAdapter->TargetStatistics;
unsigned char *CDB = Command->cmnd;
int CDB_Length = Command->cmd_len;
int TargetID = Command->target;
@@ -3371,13 +3439,9 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
int Segment;
CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather;
CCB->DataLength = SegmentCount * sizeof(BusLogic_ScatterGatherSegment_T);
-#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
if (BusLogic_MultiMasterHostAdapterP(HostAdapter))
CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList);
- else CCB->DataPointer = (BusLogic_BusAddress_T) CCB->ScatterGatherList;
-#else
- CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList);
-#endif
+ else CCB->DataPointer = Virtual_to_32Bit_Virtual(CCB->ScatterGatherList);
for (Segment = 0; Segment < SegmentCount; Segment++)
{
CCB->ScatterGatherList[Segment].SegmentByteCount =
@@ -3391,22 +3455,20 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
case READ_6:
case READ_10:
CCB->DataDirection = BusLogic_DataInLengthChecked;
- TargetDeviceStatistics[TargetID].ReadCommands++;
+ TargetStatistics[TargetID].ReadCommands++;
BusLogic_IncrementByteCounter(
- &TargetDeviceStatistics[TargetID].TotalBytesRead, BufferLength);
+ &TargetStatistics[TargetID].TotalBytesRead, BufferLength);
BusLogic_IncrementSizeBucket(
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets,
- BufferLength);
+ TargetStatistics[TargetID].ReadCommandSizeBuckets, BufferLength);
break;
case WRITE_6:
case WRITE_10:
CCB->DataDirection = BusLogic_DataOutLengthChecked;
- TargetDeviceStatistics[TargetID].WriteCommands++;
+ TargetStatistics[TargetID].WriteCommands++;
BusLogic_IncrementByteCounter(
- &TargetDeviceStatistics[TargetID].TotalBytesWritten, BufferLength);
+ &TargetStatistics[TargetID].TotalBytesWritten, BufferLength);
BusLogic_IncrementSizeBucket(
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets,
- BufferLength);
+ TargetStatistics[TargetID].WriteCommandSizeBuckets, BufferLength);
break;
default:
CCB->DataDirection = BusLogic_UncheckedDataTransfer;
@@ -3434,20 +3496,18 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
necessary to wait until there are no pending commands for a target device
before queuing tagged commands.
*/
- HostAdapter->TaggedQueuingSupported[TargetID] =
- Command->device->tagged_supported;
if (HostAdapter->CommandsSinceReset[TargetID]++ >=
BusLogic_MaxTaggedQueueDepth &&
- !HostAdapter->TaggedQueuingActive[TargetID] &&
+ !TargetFlags->TaggedQueuingActive &&
HostAdapter->ActiveCommands[TargetID] == 0 &&
- HostAdapter->TaggedQueuingSupported[TargetID] &&
+ TargetFlags->TaggedQueuingSupported &&
(HostAdapter->TaggedQueuingPermitted & (1 << TargetID)))
{
- HostAdapter->TaggedQueuingActive[TargetID] = true;
+ TargetFlags->TaggedQueuingActive = true;
BusLogic_Notice("Tagged Queuing now active for Target %d\n",
HostAdapter, TargetID);
}
- if (HostAdapter->TaggedQueuingActive[TargetID])
+ if (TargetFlags->TaggedQueuingActive)
{
BusLogic_QueueTag_T QueueTag = BusLogic_SimpleQueueTag;
/*
@@ -3457,7 +3517,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
write nearer the head position continue to arrive without interruption.
Therefore, for each Target Device this driver keeps track of the last
time either the queue was empty or an Ordered Queue Tag was issued. If
- more than 3 seconds (one fifth of the 15 second disk timeout) have
+ more than 4 seconds (one fifth of the 20 second disk timeout) have
elapsed since this last sequence point, this command will be issued
with an Ordered Queue Tag rather than a Simple Queue Tag, which forces
the Target Device to complete all previously queued commands before
@@ -3465,7 +3525,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
*/
if (HostAdapter->ActiveCommands[TargetID] == 0)
HostAdapter->LastSequencePoint[TargetID] = jiffies;
- else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 3*HZ)
+ else if (jiffies - HostAdapter->LastSequencePoint[TargetID] > 4*HZ)
{
HostAdapter->LastSequencePoint[TargetID] = jiffies;
QueueTag = BusLogic_OrderedQueueTag;
@@ -3519,7 +3579,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command,
*/
CCB->Status = BusLogic_CCB_Active;
HostAdapter->ActiveCommands[TargetID]++;
- TargetDeviceStatistics[TargetID].CommandsAttempted++;
+ TargetStatistics[TargetID].CommandsAttempted++;
FlashPoint_StartCCB(HostAdapter->CardHandle, CCB);
/*
The Command may have already completed and BusLogic_QueueCompletedCCB
@@ -3550,7 +3610,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
BusLogic_CCB_T *CCB;
int Result;
BusLogic_IncrementErrorCounter(
- &HostAdapter->TargetDeviceStatistics[TargetID].CommandAbortsRequested);
+ &HostAdapter->TargetStatistics[TargetID].CommandAbortsRequested);
/*
Acquire exclusive access to Host Adapter.
*/
@@ -3604,7 +3664,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
Firmware version 5.xx does generate Abort Tag messages, so it is
possible to abort commands when Tagged Queuing is active.
*/
- if (HostAdapter->TaggedQueuingActive[TargetID] &&
+ if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive &&
HostAdapter->FirmwareVersion[0] < '5')
{
BusLogic_Warning("Unable to Abort CCB #%ld to Target %d - "
@@ -3618,8 +3678,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
BusLogic_Warning("Aborting CCB #%ld to Target %d\n",
HostAdapter, CCB->SerialNumber, TargetID);
BusLogic_IncrementErrorCounter(
- &HostAdapter->TargetDeviceStatistics[TargetID]
- .CommandAbortsAttempted);
+ &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted);
Result = SCSI_ABORT_PENDING;
}
else
@@ -3638,7 +3697,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command)
BusLogic_Warning("Aborting CCB #%ld to Target %d\n",
HostAdapter, CCB->SerialNumber, TargetID);
BusLogic_IncrementErrorCounter(
- &HostAdapter->TargetDeviceStatistics[TargetID].CommandAbortsAttempted);
+ &HostAdapter->TargetStatistics[TargetID].CommandAbortsAttempted);
FlashPoint_AbortCCB(HostAdapter->CardHandle, CCB);
/*
The Abort may have already been completed and
@@ -3673,11 +3732,24 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
BusLogic_Lock_T Lock;
BusLogic_CCB_T *CCB;
int TargetID, Result;
- if (Command == NULL)
- BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets);
- else BusLogic_IncrementErrorCounter(
- &HostAdapter->TargetDeviceStatistics[Command->target]
- .HostAdapterResetsRequested);
+ boolean HardReset;
+ if (HostAdapter->HostAdapterExternalReset)
+ {
+ BusLogic_IncrementErrorCounter(&HostAdapter->ExternalHostAdapterResets);
+ HardReset = false;
+ }
+ else if (HostAdapter->HostAdapterInternalError)
+ {
+ BusLogic_IncrementErrorCounter(&HostAdapter->HostAdapterInternalErrors);
+ HardReset = true;
+ }
+ else
+ {
+ BusLogic_IncrementErrorCounter(
+ &HostAdapter->TargetStatistics[Command->target]
+ .HostAdapterResetsRequested);
+ HardReset = true;
+ }
/*
Acquire exclusive access to Host Adapter.
*/
@@ -3723,20 +3795,25 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
}
}
if (Command == NULL)
- BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n",
- HostAdapter, HostAdapter->FullModelName);
+ {
+ if (HostAdapter->HostAdapterInternalError)
+ BusLogic_Warning("Resetting %s due to Host Adapter Internal Error\n",
+ HostAdapter, HostAdapter->FullModelName);
+ else BusLogic_Warning("Resetting %s due to External SCSI Bus Reset\n",
+ HostAdapter, HostAdapter->FullModelName);
+ }
else
{
BusLogic_Warning("Resetting %s due to Target %d\n", HostAdapter,
HostAdapter->FullModelName, Command->target);
BusLogic_IncrementErrorCounter(
- &HostAdapter->TargetDeviceStatistics[Command->target]
+ &HostAdapter->TargetStatistics[Command->target]
.HostAdapterResetsAttempted);
}
/*
Attempt to Reset and Reinitialize the Host Adapter.
*/
- if (!(BusLogic_HardResetHostAdapter(HostAdapter) &&
+ if (!(BusLogic_HardwareResetHostAdapter(HostAdapter, HardReset) &&
BusLogic_InitializeHostAdapter(HostAdapter)))
{
BusLogic_Error("Resetting %s Failed\n", HostAdapter,
@@ -3746,7 +3823,7 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
}
if (Command != NULL)
BusLogic_IncrementErrorCounter(
- &HostAdapter->TargetDeviceStatistics[Command->target]
+ &HostAdapter->TargetStatistics[Command->target]
.HostAdapterResetsCompleted);
/*
Mark all currently executing CCBs as having been Reset.
@@ -3761,7 +3838,8 @@ static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter,
Note that a timer interrupt may occur here, but all active CCBs have
already been marked Reset and so a reentrant call will return Pending.
*/
- BusLogic_Delay(HostAdapter->BusSettleTime);
+ if (HardReset)
+ BusLogic_Delay(HostAdapter->BusSettleTime);
/*
If this is a Synchronous Reset, perform completion processing for
the Command being Reset.
@@ -3817,7 +3895,7 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
BusLogic_Lock_T Lock;
int Result = -1;
BusLogic_IncrementErrorCounter(
- &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsRequested);
+ &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsRequested);
/*
Acquire exclusive access to Host Adapter.
*/
@@ -3891,7 +3969,7 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
while there are tagged commands outstanding. Therefore, in that case a
full Host Adapter Hard Reset and SCSI Bus Reset must be done.
*/
- if (HostAdapter->TaggedQueuingActive[TargetID] &&
+ if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive &&
HostAdapter->ActiveCommands[TargetID] > 0 &&
HostAdapter->FirmwareVersion[0] < '5')
goto Done;
@@ -3958,7 +4036,7 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter,
processing performed.
*/
BusLogic_IncrementErrorCounter(
- &HostAdapter->TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted);
+ &HostAdapter->TargetStatistics[TargetID].BusDeviceResetsAttempted);
HostAdapter->BusDeviceResetPendingCCB[TargetID] = CCB;
HostAdapter->LastResetAttempted[TargetID] = jiffies;
for (XCCB = HostAdapter->All_CCBs; XCCB != NULL; XCCB = XCCB->NextAll)
@@ -4007,11 +4085,11 @@ int BusLogic_ResetCommand(SCSI_Command_T *Command, unsigned int ResetFlags)
it has been less than 10 minutes since the last reset occurred, or since
the system was initialized if no prior resets have occurred.
*/
- if (HostAdapter->TaggedQueuingActive[TargetID] &&
+ if (HostAdapter->TargetFlags[TargetID].TaggedQueuingActive &&
jiffies - HostAdapter->LastResetCompleted[TargetID] < 10*60*HZ)
{
HostAdapter->TaggedQueuingPermitted &= ~(1 << TargetID);
- HostAdapter->TaggedQueuingActive[TargetID] = false;
+ HostAdapter->TargetFlags[TargetID].TaggedQueuingActive = false;
BusLogic_Warning("Tagged Queuing now disabled for Target %d\n",
HostAdapter, TargetID);
}
@@ -4032,10 +4110,10 @@ int BusLogic_ResetCommand(SCSI_Command_T *Command, unsigned int ResetFlags)
forcing a Hard Reset before the Bus Device Reset has had a chance to
clear the error condition.
*/
- if (HostAdapter->CommandSuccessfulFlag[TargetID] ||
+ if (HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag ||
jiffies - HostAdapter->LastResetAttempted[TargetID] < HZ/10)
{
- HostAdapter->CommandSuccessfulFlag[TargetID] = false;
+ HostAdapter->TargetFlags[TargetID].CommandSuccessfulFlag = false;
return BusLogic_SendBusDeviceReset(HostAdapter, Command, ResetFlags);
}
/* Fall through to Hard Reset case. */
@@ -4076,16 +4154,18 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
struct buffer_head *BufferHead;
if (HostAdapter->ExtendedTranslationEnabled &&
Disk->capacity >= 2*1024*1024 /* 1 GB in 512 byte sectors */)
- if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */)
- {
- DiskParameters->Heads = 255;
- DiskParameters->Sectors = 63;
- }
- else
- {
- DiskParameters->Heads = 128;
- DiskParameters->Sectors = 32;
- }
+ {
+ if (Disk->capacity >= 4*1024*1024 /* 2 GB in 512 byte sectors */)
+ {
+ DiskParameters->Heads = 255;
+ DiskParameters->Sectors = 63;
+ }
+ else
+ {
+ DiskParameters->Heads = 128;
+ DiskParameters->Sectors = 32;
+ }
+ }
else
{
DiskParameters->Heads = 64;
@@ -4105,24 +4185,28 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
*/
if (*(unsigned short *) (BufferHead->b_data + 0x1FE) == 0xAA55)
{
- struct partition *PartitionEntry =
- (struct partition *) (BufferHead->b_data + 0x1BE);
+ PartitionTable_T *FirstPartitionEntry =
+ (PartitionTable_T *) (BufferHead->b_data + 0x1BE);
+ PartitionTable_T *PartitionEntry = FirstPartitionEntry;
int SavedCylinders = DiskParameters->Cylinders, PartitionNumber;
+ unsigned char PartitionEntryEndHead, PartitionEntryEndSector;
for (PartitionNumber = 0; PartitionNumber < 4; PartitionNumber++)
{
- if (PartitionEntry->end_head == 64-1)
+ PartitionEntryEndHead = PartitionEntry->end_head;
+ PartitionEntryEndSector = PartitionEntry->end_sector & 0x3F;
+ if (PartitionEntryEndHead == 64-1)
{
DiskParameters->Heads = 64;
DiskParameters->Sectors = 32;
break;
}
- else if (PartitionEntry->end_head == 128-1)
+ else if (PartitionEntryEndHead == 128-1)
{
DiskParameters->Heads = 128;
DiskParameters->Sectors = 32;
break;
}
- else if (PartitionEntry->end_head == 255-1)
+ else if (PartitionEntryEndHead == 255-1)
{
DiskParameters->Heads = 255;
DiskParameters->Sectors = 63;
@@ -4130,14 +4214,29 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *Disk, KernelDevice_T Device,
}
PartitionEntry++;
}
+ if (PartitionNumber == 4)
+ {
+ PartitionEntryEndHead = FirstPartitionEntry->end_head;
+ PartitionEntryEndSector = FirstPartitionEntry->end_sector & 0x3F;
+ }
DiskParameters->Cylinders =
Disk->capacity / (DiskParameters->Heads * DiskParameters->Sectors);
- if (SavedCylinders != DiskParameters->Cylinders)
+ if (PartitionNumber < 4 &&
+ PartitionEntryEndSector == DiskParameters->Sectors)
+ {
+ if (DiskParameters->Cylinders != SavedCylinders)
+ BusLogic_Warning("Adopting Geometry %d/%d from Partition Table\n",
+ HostAdapter,
+ DiskParameters->Heads, DiskParameters->Sectors);
+ }
+ else if (PartitionEntryEndHead > 0 || PartitionEntryEndSector > 0)
{
- BusLogic_Warning("Warning: Extended Translation Setting "
- "(> 1GB Switch) does not match\n", HostAdapter);
- BusLogic_Warning("Partition Table - Adopting %d/%d Geometry "
- "from Partition Table\n", HostAdapter,
+ BusLogic_Warning("Warning: Partition Table appears to "
+ "have Geometry %d/%d which is\n", HostAdapter,
+ PartitionEntryEndHead + 1,
+ PartitionEntryEndSector);
+ BusLogic_Warning("not compatible with current BusLogic "
+ "Host Adapter Geometry %d/%d\n", HostAdapter,
DiskParameters->Heads, DiskParameters->Sectors);
}
}
@@ -4155,22 +4254,21 @@ int BusLogic_ProcDirectoryInfo(char *ProcBuffer, char **StartPointer,
int HostNumber, int WriteFlag)
{
BusLogic_HostAdapter_T *HostAdapter;
- BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics;
- int IRQ_Channel, TargetID, Length;
+ BusLogic_TargetStatistics_T *TargetStatistics;
+ int TargetID, Length;
char *Buffer;
if (WriteFlag) return 0;
- for (IRQ_Channel = 0; IRQ_Channel < NR_IRQS; IRQ_Channel++)
+ for (HostAdapter = BusLogic_FirstRegisteredHostAdapter;
+ HostAdapter != NULL;
+ HostAdapter = HostAdapter->NextAll)
+ if (HostAdapter->HostNumber == HostNumber) break;
+ if (HostAdapter == NULL)
{
- HostAdapter = BusLogic_RegisteredHostAdapters[IRQ_Channel];
- while (HostAdapter != NULL)
- {
- if (HostAdapter->HostNumber == HostNumber) break;
- HostAdapter = HostAdapter->Next;
- }
- if (HostAdapter != NULL) break;
+ BusLogic_Error("Cannot find Host Adapter for SCSI Host %d\n",
+ NULL, HostNumber);
+ return 0;
}
- if (HostAdapter == NULL) return -1;
- TargetDeviceStatistics = HostAdapter->TargetDeviceStatistics;
+ TargetStatistics = HostAdapter->TargetStatistics;
Buffer = HostAdapter->MessageBuffer;
Length = HostAdapter->MessageBufferLength;
Length += sprintf(&Buffer[Length], "\n\
@@ -4181,100 +4279,105 @@ Currently Allocated CCBs: %d\n",
Length += sprintf(&Buffer[Length], "\n\n\
DATA TRANSFER STATISTICS\n\
\n\
-Target Tagged Queuing Queue Depth Commands Attempted Commands Completed\n\
-====== ============== =========== ================== ==================\n");
+Target Tagged Queuing Queue Depth Active Attempted Completed\n\
+====== ============== =========== ====== ========= =========\n");
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
- if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
- {
- Length +=
- sprintf(&Buffer[Length], " %2d %s", TargetID,
- (HostAdapter->TaggedQueuingSupported[TargetID]
- ? (HostAdapter->TaggedQueuingActive[TargetID]
- ? " Active"
- : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)
- ? " Permitted" : " Disabled"))
- : "Not Supported"));
- Length += sprintf(&Buffer[Length],
- " %3d %9u %9u\n",
- HostAdapter->QueueDepth[TargetID],
- TargetDeviceStatistics[TargetID].CommandsAttempted,
- TargetDeviceStatistics[TargetID].CommandsCompleted);
- }
+ {
+ BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+ if (!TargetFlags->TargetExists) continue;
+ Length +=
+ sprintf(&Buffer[Length], " %2d %s", TargetID,
+ (TargetFlags->TaggedQueuingSupported
+ ? (TargetFlags->TaggedQueuingActive
+ ? " Active"
+ : (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)
+ ? " Permitted" : " Disabled"))
+ : "Not Supported"));
+ Length += sprintf(&Buffer[Length],
+ " %3d %3u %9u %9u\n",
+ HostAdapter->QueueDepth[TargetID],
+ HostAdapter->ActiveCommands[TargetID],
+ TargetStatistics[TargetID].CommandsAttempted,
+ TargetStatistics[TargetID].CommandsCompleted);
+ }
Length += sprintf(&Buffer[Length], "\n\
Target Read Commands Write Commands Total Bytes Read Total Bytes Written\n\
====== ============= ============== =================== ===================\n");
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
- if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
- {
+ {
+ BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+ if (!TargetFlags->TargetExists) continue;
+ Length +=
+ sprintf(&Buffer[Length], " %2d %9u %9u", TargetID,
+ TargetStatistics[TargetID].ReadCommands,
+ TargetStatistics[TargetID].WriteCommands);
+ if (TargetStatistics[TargetID].TotalBytesRead.Billions > 0)
Length +=
- sprintf(&Buffer[Length], " %2d %9u %9u", TargetID,
- TargetDeviceStatistics[TargetID].ReadCommands,
- TargetDeviceStatistics[TargetID].WriteCommands);
- if (TargetDeviceStatistics[TargetID].TotalBytesRead.Billions > 0)
- Length +=
- sprintf(&Buffer[Length], " %9u%09u",
- TargetDeviceStatistics[TargetID].TotalBytesRead.Billions,
- TargetDeviceStatistics[TargetID].TotalBytesRead.Units);
- else
- Length +=
- sprintf(&Buffer[Length], " %9u",
- TargetDeviceStatistics[TargetID].TotalBytesRead.Units);
- if (TargetDeviceStatistics[TargetID].TotalBytesWritten.Billions > 0)
- Length +=
- sprintf(&Buffer[Length], " %9u%09u\n",
- TargetDeviceStatistics[TargetID].TotalBytesWritten.Billions,
- TargetDeviceStatistics[TargetID].TotalBytesWritten.Units);
- else
- Length +=
- sprintf(&Buffer[Length], " %9u\n",
- TargetDeviceStatistics[TargetID].TotalBytesWritten.Units);
- }
+ sprintf(&Buffer[Length], " %9u%09u",
+ TargetStatistics[TargetID].TotalBytesRead.Billions,
+ TargetStatistics[TargetID].TotalBytesRead.Units);
+ else
+ Length +=
+ sprintf(&Buffer[Length], " %9u",
+ TargetStatistics[TargetID].TotalBytesRead.Units);
+ if (TargetStatistics[TargetID].TotalBytesWritten.Billions > 0)
+ Length +=
+ sprintf(&Buffer[Length], " %9u%09u\n",
+ TargetStatistics[TargetID].TotalBytesWritten.Billions,
+ TargetStatistics[TargetID].TotalBytesWritten.Units);
+ else
+ Length +=
+ sprintf(&Buffer[Length], " %9u\n",
+ TargetStatistics[TargetID].TotalBytesWritten.Units);
+ }
Length += sprintf(&Buffer[Length], "\n\
Target Command 0-1KB 1-2KB 2-4KB 4-8KB 8-16KB\n\
====== ======= ========= ========= ========= ========= =========\n");
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
- if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
- {
- Length +=
- sprintf(&Buffer[Length],
- " %2d Read %9u %9u %9u %9u %9u\n", TargetID,
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[0],
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[1],
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[2],
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[3],
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[4]);
- Length +=
- sprintf(&Buffer[Length],
- " %2d Write %9u %9u %9u %9u %9u\n", TargetID,
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[0],
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[1],
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[2],
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[3],
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[4]);
- }
+ {
+ BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+ if (!TargetFlags->TargetExists) continue;
+ Length +=
+ sprintf(&Buffer[Length],
+ " %2d Read %9u %9u %9u %9u %9u\n", TargetID,
+ TargetStatistics[TargetID].ReadCommandSizeBuckets[0],
+ TargetStatistics[TargetID].ReadCommandSizeBuckets[1],
+ TargetStatistics[TargetID].ReadCommandSizeBuckets[2],
+ TargetStatistics[TargetID].ReadCommandSizeBuckets[3],
+ TargetStatistics[TargetID].ReadCommandSizeBuckets[4]);
+ Length +=
+ sprintf(&Buffer[Length],
+ " %2d Write %9u %9u %9u %9u %9u\n", TargetID,
+ TargetStatistics[TargetID].WriteCommandSizeBuckets[0],
+ TargetStatistics[TargetID].WriteCommandSizeBuckets[1],
+ TargetStatistics[TargetID].WriteCommandSizeBuckets[2],
+ TargetStatistics[TargetID].WriteCommandSizeBuckets[3],
+ TargetStatistics[TargetID].WriteCommandSizeBuckets[4]);
+ }
Length += sprintf(&Buffer[Length], "\n\
Target Command 16-32KB 32-64KB 64-128KB 128-256KB 256KB+\n\
====== ======= ========= ========= ========= ========= =========\n");
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
- if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
- {
- Length +=
- sprintf(&Buffer[Length],
- " %2d Read %9u %9u %9u %9u %9u\n", TargetID,
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[5],
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[6],
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[7],
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[8],
- TargetDeviceStatistics[TargetID].ReadCommandSizeBuckets[9]);
- Length +=
- sprintf(&Buffer[Length],
- " %2d Write %9u %9u %9u %9u %9u\n", TargetID,
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[5],
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[6],
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[7],
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[8],
- TargetDeviceStatistics[TargetID].WriteCommandSizeBuckets[9]);
- }
+ {
+ BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+ if (!TargetFlags->TargetExists) continue;
+ Length +=
+ sprintf(&Buffer[Length],
+ " %2d Read %9u %9u %9u %9u %9u\n", TargetID,
+ TargetStatistics[TargetID].ReadCommandSizeBuckets[5],
+ TargetStatistics[TargetID].ReadCommandSizeBuckets[6],
+ TargetStatistics[TargetID].ReadCommandSizeBuckets[7],
+ TargetStatistics[TargetID].ReadCommandSizeBuckets[8],
+ TargetStatistics[TargetID].ReadCommandSizeBuckets[9]);
+ Length +=
+ sprintf(&Buffer[Length],
+ " %2d Write %9u %9u %9u %9u %9u\n", TargetID,
+ TargetStatistics[TargetID].WriteCommandSizeBuckets[5],
+ TargetStatistics[TargetID].WriteCommandSizeBuckets[6],
+ TargetStatistics[TargetID].WriteCommandSizeBuckets[7],
+ TargetStatistics[TargetID].WriteCommandSizeBuckets[8],
+ TargetStatistics[TargetID].WriteCommandSizeBuckets[9]);
+ }
Length += sprintf(&Buffer[Length], "\n\n\
ERROR RECOVERY STATISTICS\n\
\n\
@@ -4283,21 +4386,26 @@ Target Requested Completed Requested Completed Requested Completed\n\
ID \\\\\\\\ Attempted //// \\\\\\\\ Attempted //// \\\\\\\\ Attempted ////\n\
====== ===== ===== ===== ===== ===== ===== ===== ===== =====\n");
for (TargetID = 0; TargetID < HostAdapter->MaxTargetDevices; TargetID++)
- if (TargetDeviceStatistics[TargetID].CommandsCompleted > 0)
+ {
+ BusLogic_TargetFlags_T *TargetFlags = &HostAdapter->TargetFlags[TargetID];
+ if (!TargetFlags->TargetExists) continue;
Length +=
sprintf(&Buffer[Length], "\
%2d %5d %5d %5d %5d %5d %5d %5d %5d %5d\n", TargetID,
- TargetDeviceStatistics[TargetID].CommandAbortsRequested,
- TargetDeviceStatistics[TargetID].CommandAbortsAttempted,
- TargetDeviceStatistics[TargetID].CommandAbortsCompleted,
- TargetDeviceStatistics[TargetID].BusDeviceResetsRequested,
- TargetDeviceStatistics[TargetID].BusDeviceResetsAttempted,
- TargetDeviceStatistics[TargetID].BusDeviceResetsCompleted,
- TargetDeviceStatistics[TargetID].HostAdapterResetsRequested,
- TargetDeviceStatistics[TargetID].HostAdapterResetsAttempted,
- TargetDeviceStatistics[TargetID].HostAdapterResetsCompleted);
+ TargetStatistics[TargetID].CommandAbortsRequested,
+ TargetStatistics[TargetID].CommandAbortsAttempted,
+ TargetStatistics[TargetID].CommandAbortsCompleted,
+ TargetStatistics[TargetID].BusDeviceResetsRequested,
+ TargetStatistics[TargetID].BusDeviceResetsAttempted,
+ TargetStatistics[TargetID].BusDeviceResetsCompleted,
+ TargetStatistics[TargetID].HostAdapterResetsRequested,
+ TargetStatistics[TargetID].HostAdapterResetsAttempted,
+ TargetStatistics[TargetID].HostAdapterResetsCompleted);
+ }
Length += sprintf(&Buffer[Length], "\nExternal Host Adapter Resets: %d\n",
HostAdapter->ExternalHostAdapterResets);
+ Length += sprintf(&Buffer[Length], "Host Adapter Internal Errors: %d\n",
+ HostAdapter->HostAdapterInternalErrors);
if (Length >= BusLogic_MessageBufferSize)
BusLogic_Error("Message Buffer length %d exceeds size %d\n",
HostAdapter, Length, BusLogic_MessageBufferSize);
@@ -4339,17 +4447,22 @@ static void BusLogic_Message(BusLogic_MessageLevel_T MessageLevel,
Buffer);
HostAdapter->MessageBufferLength += Length;
if (BeginningOfLine)
- printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
- HostAdapter->HostNumber, Buffer);
+ {
+ if (Buffer[0] != '\n' || Length > 1)
+ printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
+ HostAdapter->HostNumber, Buffer);
+ }
else printk("%s", Buffer);
}
else
{
if (BeginningOfLine)
- if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized)
- printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
- HostAdapter->HostNumber, Buffer);
- else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer);
+ {
+ if (HostAdapter != NULL && HostAdapter->HostAdapterInitialized)
+ printk("%sscsi%d: %s", BusLogic_MessageLevelMap[MessageLevel],
+ HostAdapter->HostNumber, Buffer);
+ else printk("%s%s", BusLogic_MessageLevelMap[MessageLevel], Buffer);
+ }
else printk("%s", Buffer);
}
BeginningOfLine = (Buffer[Length-1] == '\n');
@@ -4357,364 +4470,548 @@ static void BusLogic_Message(BusLogic_MessageLevel_T MessageLevel,
/*
- BusLogic_Setup handles processing of Kernel Command Line Arguments.
+ BusLogic_ParseKeyword parses an individual option keyword. It returns true
+ and updates the pointer if the keyword is recognized and false otherwise.
+*/
- For the BusLogic driver, a Kernel Command Line Entry comprises the driver
- identifier "BusLogic=" optionally followed by a comma-separated sequence of
- integers and then optionally followed by a comma-separated sequence of
- strings. Each command line entry applies to one BusLogic Host Adapter.
- Multiple command line entries may be used in systems which contain multiple
- BusLogic Host Adapters.
+static boolean BusLogic_ParseKeyword(char **StringPointer, char *Keyword)
+{
+ char *Pointer = *StringPointer;
+ while (*Keyword != '\0')
+ {
+ char StringChar = *Pointer++;
+ char KeywordChar = *Keyword++;
+ if (StringChar >= 'A' && StringChar <= 'Z')
+ StringChar += 'a' - 'Z';
+ if (KeywordChar >= 'A' && KeywordChar <= 'Z')
+ KeywordChar += 'a' - 'Z';
+ if (StringChar != KeywordChar) return false;
+ }
+ *StringPointer = Pointer;
+ return true;
+}
- The first integer specified is the I/O Address at which the Host Adapter is
- located. If unspecified, it defaults to 0 which means to apply this entry to
- the first BusLogic Host Adapter found during the default probe sequence. If
- any I/O Address parameters are provided on the command line, then the default
- probe sequence is omitted.
-
- The second integer specified is the Tagged Queue Depth to use for Target
- Devices that support Tagged Queuing. The Queue Depth is the number of SCSI
- commands that are allowed to be concurrently presented for execution. If
- unspecified, it defaults to 0 which means to use a value determined
- automatically based on the Host Adapter's Total Queue Depth and the number,
- type, speed, and capabilities of the detected Target Devices. For Host
- Adapters that require ISA Bounce Buffers, the Tagged Queue Depth is
- automatically set to BusLogic_TaggedQueueDepthBounceBuffers to avoid
- excessive preallocation of DMA Bounce Buffer memory. Target Devices that do
- not support Tagged Queuing use a Queue Depth of BusLogic_UntaggedQueueDepth.
-
- The third integer specified is the Bus Settle Time in seconds. This is
- the amount of time to wait between a Host Adapter Hard Reset which initiates
- a SCSI Bus Reset and issuing any SCSI Commands. If unspecified, it defaults
- to 0 which means to use the value of BusLogic_DefaultBusSettleTime.
-
- The fourth integer specified is the Local Options. If unspecified, it
- defaults to 0. Note that Local Options are only applied to a specific Host
- Adapter.
-
- The fifth integer specified is the Global Options. If unspecified, it
- defaults to 0. Note that Global Options are applied across all Host
- Adapters.
- The string options are used to provide control over Tagged Queuing, Error
- Recovery, and Host Adapter Probing.
-
- The Tagged Queuing specification begins with "TQ:" and allows for explicitly
- specifying whether Tagged Queuing is permitted on Target Devices that support
- it. The following specification options are available:
-
- TQ:Default Tagged Queuing will be permitted based on the firmware
- version of the BusLogic Host Adapter and based on
- whether the Tagged Queue Depth value allows queuing
- multiple commands.
-
- TQ:Enable Tagged Queuing will be enabled for all Target Devices
- on this Host Adapter overriding any limitation that
- would otherwise be imposed based on the Host Adapter
- firmware version.
-
- TQ:Disable Tagged Queuing will be disabled for all Target Devices
- on this Host Adapter.
-
- TQ:<Per-Target-Spec> Tagged Queuing will be controlled individually for each
- Target Device. <Per-Target-Spec> is a sequence of "Y",
- "N", and "X" characters. "Y" enabled Tagged Queuing,
- "N" disables Tagged Queuing, and "X" accepts the
- default based on the firmware version. The first
- character refers to Target Device 0, the second to
- Target Device 1, and so on; if the sequence of "Y",
- "N", and "X" characters does not cover all the Target
- Devices, unspecified characters are assumed to be "X".
-
- Note that explicitly requesting Tagged Queuing may lead to problems; this
- facility is provided primarily to allow disabling Tagged Queuing on Target
- Devices that do not implement it correctly.
-
- The Error Recovery Strategy specification begins with "ER:" and allows for
- explicitly specifying the Error Recovery action to be performed when
- ResetCommand is called due to a SCSI Command failing to complete
- successfully. The following specification options are available:
-
- ER:Default Error Recovery will select between the Hard Reset and
- Bus Device Reset options based on the recommendation
- of the SCSI Subsystem.
-
- ER:HardReset Error Recovery will initiate a Host Adapter Hard Reset
- which also causes a SCSI Bus Reset.
-
- ER:BusDeviceReset Error Recovery will send a Bus Device Reset message to
- the individual Target Device causing the error. If
- Error Recovery is again initiated for this Target
- Device and no SCSI Command to this Target Device has
- completed successfully since the Bus Device Reset
- message was sent, then a Hard Reset will be attempted.
-
- ER:None Error Recovery will be suppressed. This option should
- only be selected if a SCSI Bus Reset or Bus Device
- Reset will cause the Target Device to fail completely
- and unrecoverably.
-
- ER:<Per-Target-Spec> Error Recovery will be controlled individually for each
- Target Device. <Per-Target-Spec> is a sequence of "D",
- "H", "B", and "N" characters. "D" selects Default, "H"
- selects Hard Reset, "B" selects Bus Device Reset, and
- "N" selects None. The first character refers to Target
- Device 0, the second to Target Device 1, and so on; if
- the sequence of "D", "H", "B", and "N" characters does
- not cover all the possible Target Devices, unspecified
- characters are assumed to be "D".
-
- The Host Adapter Probing specification comprises the following strings:
-
- NoProbe No probing of any kind is to be performed, and hence
- no BusLogic Host Adapters will be detected.
-
- NoProbeISA No probing of the standard ISA I/O Addresses will
- be done, and hence only PCI MultiMaster and FlashPoint
- Host Adapters will be detected.
-
- NoProbePCI No interrogation of PCI Configuration Space will be
- made, and hence only ISA Multimaster Host Adapters
- will be detected, as well as PCI Multimaster Host
- Adapters that have their ISA Compatible I/O Port
- set to "Primary" or "Alternate".
-
- NoSortPCI PCI MultiMaster Host Adapters will be enumerated in
- the order provided by the PCI BIOS, ignoring any
- setting of the AutoSCSI "Use Bus And Device # For PCI
- Scanning Seq." option.
-
- MultiMasterFirst By default, if both FlashPoint and PCI MultiMaster
- Host Adapters are present, this driver will probe for
- FlashPoint Host Adapters first unless the BIOS primary
- disk is controlled by the first PCI MultiMaster Host
- Adapter, in which case MultiMaster Host Adapters will
- be probed first. This option forces MultiMaster Host
- Adapters to be probed first.
-
- FlashPointFirst By default, if both FlashPoint and PCI MultiMaster
- Host Adapters are present, this driver will probe for
- FlashPoint Host Adapters first unless the BIOS primary
- disk is controlled by the first PCI MultiMaster Host
- Adapter, in which case MultiMaster Host Adapters will
- be probed first. This option forces FlashPoint Host
- Adapters to be probed first.
-
- Debug Sets all the tracing bits in BusLogic_GlobalOptions.
+/*
+ BusLogic_ParseDriverOptions handles processing of BusLogic Driver Options
+ specifications.
+
+ BusLogic Driver Options may be specified either via the Linux Kernel Command
+ Line or via the Loadable Kernel Module Installation Facility. Driver Options
+ for multiple host adapters may be specified either by separating the option
+ strings by a semicolon, or by specifying multiple "BusLogic=" strings on the
+ command line. Individual option specifications for a single host adapter are
+ separated by commas. The Probing and Debugging Options apply to all host
+ adapters whereas the remaining options apply individually only to the
+ selected host adapter.
+
+ The BusLogic Driver Probing Options comprise the following:
+
+ IO:<integer>
+
+ The "IO:" option specifies an ISA I/O Address to be probed for a non-PCI
+ MultiMaster Host Adapter. If neither "IO:" nor "NoProbeISA" options are
+ specified, then the standard list of BusLogic MultiMaster ISA I/O Addresses
+ will be probed (0x330, 0x334, 0x230, 0x234, 0x130, and 0x134). Multiple
+ "IO:" options may be specified to precisely determine the I/O Addresses to
+ be probed, but the probe order will always follow the standard list.
+
+ NoProbe
+
+ The "NoProbe" option disables all probing and therefore no BusLogic Host
+ Adapters will be detected.
+
+ NoProbeISA
+
+ The "NoProbeISA" option disables probing of the standard BusLogic ISA I/O
+ Addresses and therefore only PCI MultiMaster and FlashPoint Host Adapters
+ will be detected.
+
+ NoProbePCI
+
+ The "NoProbePCI" options disables the interrogation of PCI Configuration
+ Space and therefore only ISA Multimaster Host Adapters will be detected, as
+ well as PCI Multimaster Host Adapters that have their ISA Compatible I/O
+ Port set to "Primary" or "Alternate".
+
+ NoSortPCI
+
+ The "NoSortPCI" option forces PCI MultiMaster Host Adapters to be
+ enumerated in the order provided by the PCI BIOS, ignoring any setting of
+ the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option.
+
+ MultiMasterFirst
+
+ The "MultiMasterFirst" option forces MultiMaster Host Adapters to be probed
+ before FlashPoint Host Adapters. By default, if both FlashPoint and PCI
+ MultiMaster Host Adapters are present, this driver will probe for
+ FlashPoint Host Adapters first unless the BIOS primary disk is controlled
+ by the first PCI MultiMaster Host Adapter, in which case MultiMaster Host
+ Adapters will be probed first.
+
+ FlashPointFirst
+
+ The "FlashPointFirst" option forces FlashPoint Host Adapters to be probed
+ before MultiMaster Host Adapters.
+
+ The BusLogic Driver Tagged Queuing Options allow for explicitly specifying
+ the Queue Depth and whether Tagged Queuing is permitted for each Target
+ Device (assuming that the Target Device supports Tagged Queuing). The Queue
+ Depth is the number of SCSI Commands that are allowed to be concurrently
+ presented for execution (either to the Host Adapter or Target Device). Note
+ that explicitly enabling Tagged Queuing may lead to problems; the option to
+ enable or disable Tagged Queuing is provided primarily to allow disabling
+ Tagged Queuing on Target Devices that do not implement it correctly. The
+ following options are available:
+
+ QueueDepth:<integer>
+
+ The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all
+ Target Devices that support Tagged Queuing. If no Queue Depth option is
+ provided, the Queue Depth will be determined automatically based on the
+ Host Adapter's Total Queue Depth and the number, type, speed, and
+ capabilities of the detected Target Devices. For Host Adapters that
+ require ISA Bounce Buffers, the Queue Depth is automatically set by default
+ to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA
+ Bounce Buffer memory. Target Devices that do not support Tagged Queuing
+ always use a Queue Depth of BusLogic_UntaggedQueueDepth.
+
+ QueueDepth:[<integer>,<integer>...]
+
+ The "QueueDepth:[...]" or "QD:[...]" option specifies the Queue Depth
+ individually for each Target Device. If an <integer> is omitted, the
+ associated Target Device will have its Queue Depth selected automatically.
+
+ TaggedQueuing:Default
+
+ The "TaggedQueuing:Default" or "TQ:Default" option permits Tagged Queuing
+ based on the firmware version of the BusLogic Host Adapter and based on
+ whether the Queue Depth allows queuing multiple commands.
+
+ TaggedQueuing:Enable
+
+ The "TaggedQueuing:Enable" or "TQ:Enable" option enables Tagged Queuing for
+ all Target Devices on this Host Adapter, overriding any limitation that
+ would otherwise be imposed based on the Host Adapter firmware version.
+
+ TaggedQueuing:Disable
+
+ The "TaggedQueuing:Disable" or "TQ:Disable" option disables Tagged Queuing
+ for all Target Devices on this Host Adapter.
+
+ TaggedQueuing:<Target-Spec>
+
+ The "TaggedQueuing:<Target-Spec>" or "TQ:<Target-Spec>" option controls
+ Tagged Queuing individually for each Target Device. <Target-Spec> is a
+ sequence of "Y", "N", and "X" characters. "Y" enables Tagged Queuing, "N"
+ disables Tagged Queuing, and "X" accepts the default based on the firmware
+ version. The first character refers to Target Device 0, the second to
+ Target Device 1, and so on; if the sequence of "Y", "N", and "X" characters
+ does not cover all the Target Devices, unspecified characters are assumed
+ to be "X".
+
+ The BusLogic Driver Error Recovery Option allows for explicitly specifying
+ the Error Recovery action to be performed when BusLogic_ResetCommand is
+ called due to a SCSI Command failing to complete successfully. The following
+ options are available:
+
+ ErrorRecovery:Default
+
+ The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard
+ Reset and Bus Device Reset options based on the recommendation of the SCSI
+ Subsystem.
+
+ ErrorRecovery:HardReset
+
+ The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host
+ Adapter Hard Reset which also causes a SCSI Bus Reset.
+
+ ErrorRecovery:BusDeviceReset
+
+ The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send
+ a Bus Device Reset message to the individual Target Device causing the
+ error. If Error Recovery is again initiated for this Target Device and no
+ SCSI Command to this Target Device has completed successfully since the Bus
+ Device Reset message was sent, then a Hard Reset will be attempted.
+
+ ErrorRecovery:None
+
+ The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery.
+ This option should only be selected if a SCSI Bus Reset or Bus Device Reset
+ will cause the Target Device or a critical operation to suffer a complete
+ and unrecoverable failure.
+
+ ErrorRecovery:<Target-Spec>
+
+ The "ErrorRecovery:<Target-Spec>" or "ER:<Target-Spec>" option controls
+ Error Recovery individually for each Target Device. <Target-Spec> is a
+ sequence of "D", "H", "B", and "N" characters. "D" selects Default, "H"
+ selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None.
+ The first character refers to Target Device 0, the second to Target Device
+ 1, and so on; if the sequence of "D", "H", "B", and "N" characters does not
+ cover all the possible Target Devices, unspecified characters are assumed
+ to be "D".
+
+ The BusLogic Driver Miscellaneous Options comprise the following:
+
+ BusSettleTime:<seconds>
+
+ The "BusSettleTime:" or "BST:" option specifies the Bus Settle Time in
+ seconds. The Bus Settle Time is the amount of time to wait between a Host
+ Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI
+ Commands. If unspecified, it defaults to BusLogic_DefaultBusSettleTime.
+
+ InhibitTargetInquiry
+
+ The "InhibitTargetInquiry" option inhibits the execution of an Inquire
+ Target Devices or Inquire Installed Devices command on MultiMaster Host
+ Adapters. This may be necessary with some older Target Devices that do not
+ respond correctly when Logical Units above 0 are addressed.
+
+ The BusLogic Driver Debugging Options comprise the following:
+
+ TraceProbe
+
+ The "TraceProbe" option enables tracing of Host Adapter Probing.
+
+ TraceHardwareReset
+
+ The "TraceHardwareReset" option enables tracing of Host Adapter Hardware
+ Reset.
+
+ TraceConfiguration
+
+ The "TraceConfiguration" option enables tracing of Host Adapter
+ Configuration.
+
+ TraceErrors
+
+ The "TraceErrors" option enables tracing of SCSI Commands that return an
+ error from the Target Device. The CDB and Sense Data will be printed for
+ each SCSI Command that fails.
+
+ Debug
+
+ The "Debug" option enables all debugging options.
+
+ The following examples demonstrate setting the Queue Depth for Target Devices
+ 1 and 2 on the first host adapter to 7 and 15, the Queue Depth for all Target
+ Devices on the second host adapter to 31, and the Bus Settle Time on the
+ second host adapter to 30 seconds.
+
+ Linux Kernel Command Line:
+
+ linux BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30
+
+ LILO Linux Boot Loader (in /etc/lilo.conf):
+
+ append = "BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"
+
+ INSMOD Loadable Kernel Module Installation Facility:
+
+ insmod BusLogic.o \
+ 'BusLogic_Options="QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"'
+
+ NOTE: Module Utilities 2.1.71 or later is required for correct parsing
+ of driver options containing commas.
*/
-void BusLogic_Setup(char *Strings, int *Integers)
+static void BusLogic_ParseDriverOptions(char *OptionsString)
{
- BusLogic_CommandLineEntry_T *CommandLineEntry =
- &BusLogic_CommandLineEntries[BusLogic_CommandLineEntryCount++];
- int IntegerCount = Integers[0];
- int TargetID, i;
- CommandLineEntry->IO_Address = 0;
- CommandLineEntry->TaggedQueueDepth = 0;
- CommandLineEntry->BusSettleTime = 0;
- CommandLineEntry->TaggedQueuingPermitted = 0;
- CommandLineEntry->TaggedQueuingPermittedMask = 0;
- CommandLineEntry->LocalOptions.All = 0;
- memset(CommandLineEntry->ErrorRecoveryStrategy,
- BusLogic_ErrorRecovery_Default,
- sizeof(CommandLineEntry->ErrorRecoveryStrategy));
- if (IntegerCount > 5)
- BusLogic_Error("BusLogic: Unexpected Command Line Integers "
- "ignored\n", NULL);
- if (IntegerCount >= 1)
+ while (true)
{
- BusLogic_IO_Address_T IO_Address = Integers[1];
- if (IO_Address > 0)
+ BusLogic_DriverOptions_T *DriverOptions =
+ &BusLogic_DriverOptions[BusLogic_DriverOptionsCount++];
+ int TargetID;
+ memset(DriverOptions, 0, sizeof(BusLogic_DriverOptions_T));
+ for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+ DriverOptions->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_Default;
+ while (*OptionsString != '\0' && *OptionsString != ';')
{
- BusLogic_ProbeInfo_T *ProbeInfo;
- for (i = 0; ; i++)
- if (BusLogic_ISA_StandardAddresses[i] == 0)
- {
- BusLogic_Error("BusLogic: Invalid Command Line Entry "
- "(illegal I/O Address 0x%X)\n",
- NULL, IO_Address);
- return;
- }
- else if (i < BusLogic_ProbeInfoCount &&
- IO_Address == BusLogic_ProbeInfoList[i].IO_Address)
- {
- BusLogic_Error("BusLogic: Invalid Command Line Entry "
- "(duplicate I/O Address 0x%X)\n",
- NULL, IO_Address);
- return;
- }
- else if (IO_Address >= 0x400 ||
- IO_Address == BusLogic_ISA_StandardAddresses[i]) break;
- ProbeInfo = &BusLogic_ProbeInfoList[BusLogic_ProbeInfoCount++];
- ProbeInfo->HostAdapterType = BusLogic_MultiMaster;
- ProbeInfo->HostAdapterBusType = BusLogic_ISA_Bus;
+ /* Probing Options. */
+ if (BusLogic_ParseKeyword(&OptionsString, "IO:"))
+ {
+ BusLogic_IO_Address_T IO_Address =
+ simple_strtoul(OptionsString, &OptionsString, 0);
+ BusLogic_ProbeOptions.LimitedProbeISA = true;
+ switch (IO_Address)
+ {
+ case 0x330:
+ BusLogic_ProbeOptions.Probe330 = true;
+ break;
+ case 0x334:
+ BusLogic_ProbeOptions.Probe334 = true;
+ break;
+ case 0x230:
+ BusLogic_ProbeOptions.Probe230 = true;
+ break;
+ case 0x234:
+ BusLogic_ProbeOptions.Probe234 = true;
+ break;
+ case 0x130:
+ BusLogic_ProbeOptions.Probe130 = true;
+ break;
+ case 0x134:
+ BusLogic_ProbeOptions.Probe134 = true;
+ break;
+ default:
+ BusLogic_Error("BusLogic: Invalid Driver Options "
+ "(illegal I/O Address 0x%X)\n",
+ NULL, IO_Address);
+ return;
+ }
+ }
+ else if (BusLogic_ParseKeyword(&OptionsString, "NoProbeISA"))
+ BusLogic_ProbeOptions.NoProbeISA = true;
+ else if (BusLogic_ParseKeyword(&OptionsString, "NoProbePCI"))
+ BusLogic_ProbeOptions.NoProbePCI = true;
+ else if (BusLogic_ParseKeyword(&OptionsString, "NoProbe"))
+ BusLogic_ProbeOptions.NoProbe = true;
+ else if (BusLogic_ParseKeyword(&OptionsString, "NoSortPCI"))
+ BusLogic_ProbeOptions.NoSortPCI = true;
+ else if (BusLogic_ParseKeyword(&OptionsString, "MultiMasterFirst"))
+ BusLogic_ProbeOptions.MultiMasterFirst = true;
+ else if (BusLogic_ParseKeyword(&OptionsString, "FlashPointFirst"))
+ BusLogic_ProbeOptions.FlashPointFirst = true;
+ /* Tagged Queuing Options. */
+ else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:[") ||
+ BusLogic_ParseKeyword(&OptionsString, "QD:["))
+ {
+ for (TargetID = 0;
+ TargetID < BusLogic_MaxTargetDevices;
+ TargetID++)
+ {
+ unsigned short QueueDepth =
+ simple_strtoul(OptionsString, &OptionsString, 0);
+ if (QueueDepth > BusLogic_MaxTaggedQueueDepth)
+ {
+ BusLogic_Error("BusLogic: Invalid Driver Options "
+ "(illegal Queue Depth %d)\n",
+ NULL, QueueDepth);
+ return;
+ }
+ DriverOptions->QueueDepth[TargetID] = QueueDepth;
+ if (*OptionsString == ',')
+ OptionsString++;
+ else if (*OptionsString == ']')
+ break;
+ else
+ {
+ BusLogic_Error("BusLogic: Invalid Driver Options "
+ "(',' or ']' expected at '%s')\n",
+ NULL, OptionsString);
+ return;
+ }
+ }
+ if (*OptionsString != ']')
+ {
+ BusLogic_Error("BusLogic: Invalid Driver Options "
+ "(']' expected at '%s')\n",
+ NULL, OptionsString);
+ return;
+ }
+ else OptionsString++;
+ }
+ else if (BusLogic_ParseKeyword(&OptionsString, "QueueDepth:") ||
+ BusLogic_ParseKeyword(&OptionsString, "QD:"))
+ {
+ unsigned short QueueDepth =
+ simple_strtoul(OptionsString, &OptionsString, 0);
+ if (QueueDepth == 0 || QueueDepth > BusLogic_MaxTaggedQueueDepth)
+ {
+ BusLogic_Error("BusLogic: Invalid Driver Options "
+ "(illegal Queue Depth %d)\n",
+ NULL, QueueDepth);
+ return;
+ }
+ for (TargetID = 0;
+ TargetID < BusLogic_MaxTargetDevices;
+ TargetID++)
+ DriverOptions->QueueDepth[TargetID] = QueueDepth;
+ }
+ else if (BusLogic_ParseKeyword(&OptionsString, "TaggedQueuing:") ||
+ BusLogic_ParseKeyword(&OptionsString, "TQ:"))
+ {
+ if (BusLogic_ParseKeyword(&OptionsString, "Default"))
+ {
+ DriverOptions->TaggedQueuingPermitted = 0x0000;
+ DriverOptions->TaggedQueuingPermittedMask = 0x0000;
+ }
+ else if (BusLogic_ParseKeyword(&OptionsString, "Enable"))
+ {
+ DriverOptions->TaggedQueuingPermitted = 0xFFFF;
+ DriverOptions->TaggedQueuingPermittedMask = 0xFFFF;
+ }
+ else if (BusLogic_ParseKeyword(&OptionsString, "Disable"))
+ {
+ DriverOptions->TaggedQueuingPermitted = 0x0000;
+ DriverOptions->TaggedQueuingPermittedMask = 0xFFFF;
+ }
+ else
+ {
+ unsigned short TargetBit;
+ for (TargetID = 0, TargetBit = 1;
+ TargetID < BusLogic_MaxTargetDevices;
+ TargetID++, TargetBit <<= 1)
+ switch (*OptionsString++)
+ {
+ case 'Y':
+ DriverOptions->TaggedQueuingPermitted |= TargetBit;
+ DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+ break;
+ case 'N':
+ DriverOptions->TaggedQueuingPermitted &= ~TargetBit;
+ DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+ break;
+ case 'X':
+ break;
+ default:
+ OptionsString--;
+ TargetID = BusLogic_MaxTargetDevices;
+ break;
+ }
+ }
+ }
+ /* Error Recovery Option. */
+ else if (BusLogic_ParseKeyword(&OptionsString, "ErrorRecovery:") ||
+ BusLogic_ParseKeyword(&OptionsString, "ER:"))
+ {
+ if (BusLogic_ParseKeyword(&OptionsString, "Default"))
+ for (TargetID = 0;
+ TargetID < BusLogic_MaxTargetDevices;
+ TargetID++)
+ DriverOptions->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_Default;
+ else if (BusLogic_ParseKeyword(&OptionsString, "HardReset"))
+ for (TargetID = 0;
+ TargetID < BusLogic_MaxTargetDevices;
+ TargetID++)
+ DriverOptions->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_HardReset;
+ else if (BusLogic_ParseKeyword(&OptionsString, "BusDeviceReset"))
+ for (TargetID = 0;
+ TargetID < BusLogic_MaxTargetDevices;
+ TargetID++)
+ DriverOptions->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_BusDeviceReset;
+ else if (BusLogic_ParseKeyword(&OptionsString, "None"))
+ for (TargetID = 0;
+ TargetID < BusLogic_MaxTargetDevices;
+ TargetID++)
+ DriverOptions->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_None;
+ else
+ for (TargetID = 0;
+ TargetID < BusLogic_MaxTargetDevices;
+ TargetID++)
+ switch (*OptionsString++)
+ {
+ case 'D':
+ DriverOptions->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_Default;
+ break;
+ case 'H':
+ DriverOptions->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_HardReset;
+ break;
+ case 'B':
+ DriverOptions->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_BusDeviceReset;
+ break;
+ case 'N':
+ DriverOptions->ErrorRecoveryStrategy[TargetID] =
+ BusLogic_ErrorRecovery_None;
+ break;
+ default:
+ OptionsString--;
+ TargetID = BusLogic_MaxTargetDevices;
+ break;
+ }
+ }
+ /* Miscellaneous Options. */
+ else if (BusLogic_ParseKeyword(&OptionsString, "BusSettleTime:") ||
+ BusLogic_ParseKeyword(&OptionsString, "BST:"))
+ {
+ unsigned short BusSettleTime =
+ simple_strtoul(OptionsString, &OptionsString, 0);
+ if (BusSettleTime > 5 * 60)
+ {
+ BusLogic_Error("BusLogic: Invalid Driver Options "
+ "(illegal Bus Settle Time %d)\n",
+ NULL, BusSettleTime);
+ return;
+ }
+ DriverOptions->BusSettleTime = BusSettleTime;
+ }
+ else if (BusLogic_ParseKeyword(&OptionsString,
+ "InhibitTargetInquiry"))
+ DriverOptions->LocalOptions.InhibitTargetInquiry = true;
+ /* Debugging Options. */
+ else if (BusLogic_ParseKeyword(&OptionsString, "TraceProbe"))
+ BusLogic_GlobalOptions.TraceProbe = true;
+ else if (BusLogic_ParseKeyword(&OptionsString, "TraceHardwareReset"))
+ BusLogic_GlobalOptions.TraceHardwareReset = true;
+ else if (BusLogic_ParseKeyword(&OptionsString, "TraceConfiguration"))
+ BusLogic_GlobalOptions.TraceConfiguration = true;
+ else if (BusLogic_ParseKeyword(&OptionsString, "TraceErrors"))
+ BusLogic_GlobalOptions.TraceErrors = true;
+ else if (BusLogic_ParseKeyword(&OptionsString, "Debug"))
+ {
+ BusLogic_GlobalOptions.TraceProbe = true;
+ BusLogic_GlobalOptions.TraceHardwareReset = true;
+ BusLogic_GlobalOptions.TraceConfiguration = true;
+ BusLogic_GlobalOptions.TraceErrors = true;
+ }
+ if (*OptionsString == ',')
+ OptionsString++;
+ else if (*OptionsString != ';' && *OptionsString != '\0')
+ {
+ BusLogic_Error("BusLogic: Unexpected Driver Option '%s' "
+ "ignored\n", NULL, OptionsString);
+ *OptionsString = '\0';
+ }
}
- CommandLineEntry->IO_Address = IO_Address;
- }
- if (IntegerCount >= 2)
- {
- unsigned short TaggedQueueDepth = Integers[2];
- if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth)
+ if (!(BusLogic_DriverOptionsCount == 0 ||
+ BusLogic_ProbeInfoCount == 0 ||
+ BusLogic_DriverOptionsCount == BusLogic_ProbeInfoCount))
{
- BusLogic_Error("BusLogic: Invalid Command Line Entry "
- "(illegal Tagged Queue Depth %d)\n",
- NULL, TaggedQueueDepth);
+ BusLogic_Error("BusLogic: Invalid Driver Options "
+ "(all or no I/O Addresses must be specified)\n", NULL);
return;
}
- CommandLineEntry->TaggedQueueDepth = TaggedQueueDepth;
+ /*
+ Tagged Queuing is disabled when the Queue Depth is 1 since queuing
+ multiple commands is not possible.
+ */
+ for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
+ if (DriverOptions->QueueDepth[TargetID] == 1)
+ {
+ unsigned short TargetBit = 1 << TargetID;
+ DriverOptions->TaggedQueuingPermitted &= ~TargetBit;
+ DriverOptions->TaggedQueuingPermittedMask |= TargetBit;
+ }
+ if (*OptionsString == ';') OptionsString++;
+ if (*OptionsString == '\0') return;
}
- if (IntegerCount >= 3)
- CommandLineEntry->BusSettleTime = Integers[3];
- if (IntegerCount >= 4)
- CommandLineEntry->LocalOptions.All = Integers[4];
- if (IntegerCount >= 5)
- BusLogic_GlobalOptions.All |= Integers[5];
- if (!(BusLogic_CommandLineEntryCount == 0 ||
- BusLogic_ProbeInfoCount == 0 ||
- BusLogic_CommandLineEntryCount == BusLogic_ProbeInfoCount))
+}
+
+
+/*
+ BusLogic_Setup handles processing of Kernel Command Line Arguments.
+*/
+
+void BusLogic_Setup(char *CommandLineString, int *CommandLineIntegers)
+{
+ if (CommandLineIntegers[0] != 0)
{
- BusLogic_Error("BusLogic: Invalid Command Line Entry "
- "(all or no I/O Addresses must be specified)\n", NULL);
+ BusLogic_Error("BusLogic: Obsolete Command Line Entry "
+ "Format Ignored\n", NULL);
return;
}
- if (Strings == NULL) return;
- while (*Strings != '\0')
- if (strncmp(Strings, "TQ:", 3) == 0)
- {
- Strings += 3;
- if (strncmp(Strings, "Default", 7) == 0)
- Strings += 7;
- else if (strncmp(Strings, "Enable", 6) == 0)
- {
- Strings += 6;
- CommandLineEntry->TaggedQueuingPermitted = 0xFFFF;
- CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
- }
- else if (strncmp(Strings, "Disable", 7) == 0)
- {
- Strings += 7;
- CommandLineEntry->TaggedQueuingPermitted = 0x0000;
- CommandLineEntry->TaggedQueuingPermittedMask = 0xFFFF;
- }
- else
- for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
- switch (*Strings++)
- {
- case 'Y':
- CommandLineEntry->TaggedQueuingPermitted |= 1 << TargetID;
- CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID;
- break;
- case 'N':
- CommandLineEntry->TaggedQueuingPermittedMask |= 1 << TargetID;
- break;
- case 'X':
- break;
- default:
- Strings--;
- TargetID = BusLogic_MaxTargetDevices;
- break;
- }
- }
- else if (strncmp(Strings, "ER:", 3) == 0)
- {
- Strings += 3;
- if (strncmp(Strings, "Default", 7) == 0)
- Strings += 7;
- else if (strncmp(Strings, "HardReset", 9) == 0)
- {
- Strings += 9;
- memset(CommandLineEntry->ErrorRecoveryStrategy,
- BusLogic_ErrorRecovery_HardReset,
- sizeof(CommandLineEntry->ErrorRecoveryStrategy));
- }
- else if (strncmp(Strings, "BusDeviceReset", 14) == 0)
- {
- Strings += 14;
- memset(CommandLineEntry->ErrorRecoveryStrategy,
- BusLogic_ErrorRecovery_BusDeviceReset,
- sizeof(CommandLineEntry->ErrorRecoveryStrategy));
- }
- else if (strncmp(Strings, "None", 4) == 0)
- {
- Strings += 4;
- memset(CommandLineEntry->ErrorRecoveryStrategy,
- BusLogic_ErrorRecovery_None,
- sizeof(CommandLineEntry->ErrorRecoveryStrategy));
- }
- else
- for (TargetID = 0; TargetID < BusLogic_MaxTargetDevices; TargetID++)
- switch (*Strings++)
- {
- case 'D':
- CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
- BusLogic_ErrorRecovery_Default;
- break;
- case 'H':
- CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
- BusLogic_ErrorRecovery_HardReset;
- break;
- case 'B':
- CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
- BusLogic_ErrorRecovery_BusDeviceReset;
- break;
- case 'N':
- CommandLineEntry->ErrorRecoveryStrategy[TargetID] =
- BusLogic_ErrorRecovery_None;
- break;
- default:
- Strings--;
- TargetID = BusLogic_MaxTargetDevices;
- break;
- }
- }
- else if (strcmp(Strings, "NoProbe") == 0 ||
- strcmp(Strings, "noprobe") == 0)
- {
- Strings += 7;
- BusLogic_ProbeOptions.Bits.NoProbe = true;
- }
- else if (strncmp(Strings, "NoProbeISA", 10) == 0)
- {
- Strings += 10;
- BusLogic_ProbeOptions.Bits.NoProbeISA = true;
- }
- else if (strncmp(Strings, "NoProbePCI", 10) == 0)
- {
- Strings += 10;
- BusLogic_ProbeOptions.Bits.NoProbePCI = true;
- }
- else if (strncmp(Strings, "NoSortPCI", 9) == 0)
- {
- Strings += 9;
- BusLogic_ProbeOptions.Bits.NoSortPCI = true;
- }
- else if (strncmp(Strings, "MultiMasterFirst", 16) == 0)
- {
- Strings += 16;
- BusLogic_ProbeOptions.Bits.ProbeMultiMasterFirst = true;
- }
- else if (strncmp(Strings, "FlashPointFirst", 15) == 0)
- {
- Strings += 15;
- BusLogic_ProbeOptions.Bits.ProbeFlashPointFirst = true;
- }
- else if (strncmp(Strings, "Debug", 5) == 0)
- {
- Strings += 5;
- BusLogic_GlobalOptions.Bits.TraceProbe = true;
- BusLogic_GlobalOptions.Bits.TraceHardReset = true;
- BusLogic_GlobalOptions.Bits.TraceConfiguration = true;
- BusLogic_GlobalOptions.Bits.TraceErrors = true;
- }
- else if (*Strings == ',')
- Strings++;
- else
- {
- BusLogic_Error("BusLogic: Unexpected Command Line String '%s' "
- "ignored\n", NULL, Strings);
- break;
- }
+ if (CommandLineString == NULL || *CommandLineString == '\0') return;
+ BusLogic_ParseDriverOptions(CommandLineString);
}
@@ -4724,6 +5021,8 @@ void BusLogic_Setup(char *Strings, int *Integers)
#ifdef MODULE
+MODULE_PARM(BusLogic_Options, "s");
+
SCSI_Host_Template_T driver_template = BUSLOGIC;
#include "scsi_module.c"
diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h
index 6f62e04b0..ef7a8dcca 100644
--- a/drivers/scsi/BusLogic.h
+++ b/drivers/scsi/BusLogic.h
@@ -6,8 +6,7 @@
This program is free software; you may redistribute and/or modify it under
the terms of the GNU General Public License Version 2 as published by the
- Free Software Foundation, provided that none of the source code or runtime
- copyright notices are removed or modified.
+ Free Software Foundation.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY, without even the implied warranty of MERCHANTABILITY
@@ -38,6 +37,7 @@
typedef kdev_t KernelDevice_T;
typedef struct proc_dir_entry PROC_DirectoryEntry_T;
typedef struct pt_regs Registers_T;
+typedef struct partition PartitionTable_T;
typedef Scsi_Host_Template SCSI_Host_Template_T;
typedef struct Scsi_Host SCSI_Host_T;
typedef struct scsi_device SCSI_Device_T;
@@ -66,28 +66,19 @@ extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
Define the BusLogic SCSI Host Template structure.
*/
-#define BUSLOGIC \
- { NULL, /* Next */ \
- NULL, /* Usage Count Pointer */ \
- &BusLogic_ProcDirectoryEntry, /* /proc Directory Entry */ \
- BusLogic_ProcDirectoryInfo, /* /proc Info Function */ \
- "BusLogic", /* Driver Name */ \
- BusLogic_DetectHostAdapter, /* Detect Host Adapter */ \
- BusLogic_ReleaseHostAdapter, /* Release Host Adapter */ \
- BusLogic_DriverInfo, /* Driver Info Function */ \
- NULL, /* Command Function */ \
- BusLogic_QueueCommand, /* Queue Command Function */ \
- BusLogic_AbortCommand, /* Abort Command Function */ \
- BusLogic_ResetCommand, /* Reset Command Function */ \
- NULL, /* Slave Attach Function */ \
- BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \
- 0, /* Can Queue */ \
- 0, /* This ID */ \
- 0, /* Scatter/Gather Table Size */ \
- 0, /* SCSI Commands per LUN */ \
- 0, /* Present */ \
- 1, /* Default Unchecked ISA DMA */ \
- ENABLE_CLUSTERING } /* Enable Clustering */
+#define BUSLOGIC \
+ { proc_dir: &BusLogic_ProcDirectoryEntry, /* ProcFS Directory Entry */ \
+ proc_info: BusLogic_ProcDirectoryInfo, /* ProcFS Info Function */ \
+ name: "BusLogic", /* Driver Name */ \
+ detect: BusLogic_DetectHostAdapter, /* Detect Host Adapter */ \
+ release: BusLogic_ReleaseHostAdapter, /* Release Host Adapter */ \
+ info: BusLogic_DriverInfo, /* Driver Info Function */ \
+ queuecommand: BusLogic_QueueCommand, /* Queue Command Function */ \
+ abort: BusLogic_AbortCommand, /* Abort Command Function */ \
+ reset: BusLogic_ResetCommand, /* Reset Command Function */ \
+ bios_param: BusLogic_BIOSDiskParameters, /* BIOS Disk Parameters */ \
+ unchecked_isa_dma: 1, /* Default Initial Value */ \
+ use_clustering: ENABLE_CLUSTERING } /* Enable Clustering */
/*
@@ -98,6 +89,24 @@ extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
/*
+ FlashPoint support is only available for the Intel x86 Architecture with
+ CONFIG_PCI set.
+*/
+
+#ifndef __i386__
+#undef CONFIG_SCSI_OMIT_FLASHPOINT
+#define CONFIG_SCSI_OMIT_FLASHPOINT
+#endif
+
+#ifndef CONFIG_PCI
+#undef CONFIG_SCSI_OMIT_FLASHPOINT
+#define CONFIG_SCSI_OMIT_FLASHPOINT
+#define BusLogic_InitializeProbeInfoListISA \
+ BusLogic_InitializeProbeInfoList
+#endif
+
+
+/*
Define the maximum number of BusLogic Host Adapters supported by this driver.
*/
@@ -121,16 +130,17 @@ extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
/*
- Define the maximum, preferred, and default Queue Depth to allow for Target
- Devices depending on whether or not they support Tagged Queuing and whether
- or not ISA Bounce Buffers are required.
+ Define the maximum, maximum automatic, minimum automatic, and default Queue
+ Depth to allow for Target Devices depending on whether or not they support
+ Tagged Queuing and whether or not ISA Bounce Buffers are required.
*/
-#define BusLogic_MaxTaggedQueueDepth 63
-#define BusLogic_PreferredTaggedQueueDepth 28
-#define BusLogic_TaggedQueueDepthBounceBuffers 2
-#define BusLogic_TaggedQueueDepthAutomatic 0
+#define BusLogic_MaxTaggedQueueDepth 64
+#define BusLogic_MaxAutomaticTaggedQueueDepth 28
+#define BusLogic_MinAutomaticTaggedQueueDepth 7
+#define BusLogic_TaggedQueueDepthBB 3
#define BusLogic_UntaggedQueueDepth 3
+#define BusLogic_UntaggedQueueDepthBB 2
/*
@@ -144,11 +154,29 @@ extern int BusLogic_ProcDirectoryInfo(char *, char **, off_t, int, int, int);
/*
+ Define the maximum number of Mailboxes that should be used for MultiMaster
+ Host Adapters. This number is chosen to be larger than the maximum Host
+ Adapter Queue Depth and small enough so that the Host Adapter structure
+ does not cross an allocation block size boundary.
+*/
+
+#define BusLogic_MaxMailboxes 211
+
+
+/*
+ Define the number of CCBs that should be allocated as a group to optimize
+ Kernel memory allocation.
+*/
+
+#define BusLogic_CCB_AllocationGroupSize 7
+
+
+/*
Define the Host Adapter Line and Message Buffer Sizes.
*/
#define BusLogic_LineBufferSize 100
-#define BusLogic_MessageBufferSize 9900
+#define BusLogic_MessageBufferSize 9700
/*
@@ -167,7 +195,27 @@ BusLogic_MessageLevel_T;
static char
*BusLogic_MessageLevelMap[] =
- { KERN_INFO, KERN_INFO, KERN_NOTICE, KERN_WARNING, KERN_ERR };
+ { KERN_NOTICE, KERN_NOTICE, KERN_NOTICE, KERN_WARNING, KERN_ERR };
+
+
+/*
+ Define Driver Message macros.
+*/
+
+#define BusLogic_Announce(Format, Arguments...) \
+ BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments)
+
+#define BusLogic_Info(Format, Arguments...) \
+ BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments)
+
+#define BusLogic_Notice(Format, Arguments...) \
+ BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments)
+
+#define BusLogic_Warning(Format, Arguments...) \
+ BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments)
+
+#define BusLogic_Error(Format, Arguments...) \
+ BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments)
/*
@@ -187,11 +235,34 @@ BusLogic_HostAdapterType_T;
#define BusLogic_FlashPointAddressCount 256
static int
- BusLogic_HostAdapter_AddressCount[3] =
+ BusLogic_HostAdapterAddressCount[3] =
{ 0, BusLogic_MultiMasterAddressCount, BusLogic_FlashPointAddressCount };
/*
+ Define macros for testing the Host Adapter Type.
+*/
+
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
+
+#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
+ (HostAdapter->HostAdapterType == BusLogic_MultiMaster)
+
+#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
+ (HostAdapter->HostAdapterType == BusLogic_FlashPoint)
+
+#else
+
+#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
+ (true)
+
+#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
+ (false)
+
+#endif
+
+
+/*
Define the possible Host Adapter Bus Types.
*/
@@ -204,6 +275,7 @@ typedef enum
BusLogic_VESA_Bus = 4,
BusLogic_MCA_Bus = 5
}
+__attribute__ ((packed))
BusLogic_HostAdapterBusType_T;
static char
@@ -257,6 +329,13 @@ typedef unsigned int BusLogic_PCI_Address_T;
/*
+ Define a 32 bit Base Address data type.
+*/
+
+typedef unsigned int BusLogic_Base_Address_T;
+
+
+/*
Define a 32 bit Bus Address data type.
*/
@@ -288,11 +367,10 @@ BusLogic_ByteCounter_T;
typedef struct BusLogic_ProbeInfo
{
+ BusLogic_HostAdapterType_T HostAdapterType;
+ BusLogic_HostAdapterBusType_T HostAdapterBusType;
BusLogic_IO_Address_T IO_Address;
BusLogic_PCI_Address_T PCI_Address;
- BusLogic_HostAdapterType_T HostAdapterType:2;
- BusLogic_HostAdapterBusType_T HostAdapterBusType:3;
- unsigned char :3;
unsigned char Bus;
unsigned char Device;
unsigned char IRQ_Channel;
@@ -301,35 +379,24 @@ BusLogic_ProbeInfo_T;
/*
- BusLogic_ISA_StandardAddresses is the list of standard ISA I/O Addresses at
- which BusLogic MultiMaster Host Adapters may potentially be found. The first
- I/O Address 0x330 is known as the "Primary" I/O Address. A Host Adapter
- configured to use the Primary I/O Address will always be the preferred boot
- device.
-*/
-
-#define BusLogic_ISA_StandardAddressesCount 6
-
-static BusLogic_IO_Address_T
- BusLogic_ISA_StandardAddresses[BusLogic_ISA_StandardAddressesCount] =
- { 0x330, 0x334, 0x230, 0x234, 0x130, 0x134 };
-
-
-/*
Define the Probe Options.
*/
-typedef union BusLogic_ProbeOptions
+typedef struct BusLogic_ProbeOptions
{
- unsigned short All;
- struct {
- boolean NoProbe:1; /* Bit 0 */
- boolean NoProbeISA:1; /* Bit 1 */
- boolean NoProbePCI:1; /* Bit 2 */
- boolean NoSortPCI:1; /* Bit 3 */
- boolean ProbeMultiMasterFirst:1; /* Bit 4 */
- boolean ProbeFlashPointFirst:1; /* Bit 5 */
- } Bits;
+ boolean NoProbe:1; /* Bit 0 */
+ boolean NoProbeISA:1; /* Bit 1 */
+ boolean NoProbePCI:1; /* Bit 2 */
+ boolean NoSortPCI:1; /* Bit 3 */
+ boolean MultiMasterFirst:1; /* Bit 4 */
+ boolean FlashPointFirst:1; /* Bit 5 */
+ boolean LimitedProbeISA:1; /* Bit 6 */
+ boolean Probe330:1; /* Bit 7 */
+ boolean Probe334:1; /* Bit 8 */
+ boolean Probe230:1; /* Bit 9 */
+ boolean Probe234:1; /* Bit 10 */
+ boolean Probe130:1; /* Bit 11 */
+ boolean Probe134:1; /* Bit 12 */
}
BusLogic_ProbeOptions_T;
@@ -338,15 +405,12 @@ BusLogic_ProbeOptions_T;
Define the Global Options.
*/
-typedef union BusLogic_GlobalOptions
+typedef struct BusLogic_GlobalOptions
{
- unsigned short All;
- struct {
- boolean TraceProbe:1; /* Bit 0 */
- boolean TraceHardReset:1; /* Bit 1 */
- boolean TraceConfiguration:1; /* Bit 2 */
- boolean TraceErrors:1; /* Bit 3 */
- } Bits;
+ boolean TraceProbe:1; /* Bit 0 */
+ boolean TraceHardwareReset:1; /* Bit 1 */
+ boolean TraceConfiguration:1; /* Bit 2 */
+ boolean TraceErrors:1; /* Bit 3 */
}
BusLogic_GlobalOptions_T;
@@ -355,13 +419,9 @@ BusLogic_GlobalOptions_T;
Define the Local Options.
*/
-typedef union BusLogic_LocalOptions
+typedef struct BusLogic_LocalOptions
{
- unsigned short All;
- struct {
- boolean InhibitTargetInquiry:1; /* Bit 0 */
- boolean InhibitInterruptTest:1; /* Bit 1 */
- } Bits;
+ boolean InhibitTargetInquiry:1; /* Bit 0 */
}
BusLogic_LocalOptions_T;
@@ -619,10 +679,13 @@ typedef struct BusLogic_SetupInformation
unsigned char Signature; /* Byte 17 */
unsigned char CharacterD; /* Byte 18 */
unsigned char HostBusType; /* Byte 19 */
- unsigned char :8; /* Byte 20 */
- unsigned char :8; /* Byte 21 */
+ unsigned char WideTransfersPermittedID0to7; /* Byte 20 */
+ unsigned char WideTransfersActiveID0to7; /* Byte 21 */
BusLogic_SynchronousValues8_T SynchronousValuesID8to15; /* Bytes 22-29 */
unsigned char DisconnectPermittedID8to15; /* Byte 30 */
+ unsigned char :8; /* Byte 31 */
+ unsigned char WideTransfersPermittedID8to15; /* Byte 32 */
+ unsigned char WideTransfersActiveID8to15; /* Byte 33 */
}
BusLogic_SetupInformation_T;
@@ -1064,6 +1127,21 @@ BusLogic_ScatterGatherSegment_T;
/*
+ Define the Driver CCB Status Codes.
+*/
+
+typedef enum
+{
+ BusLogic_CCB_Free = 0,
+ BusLogic_CCB_Active = 1,
+ BusLogic_CCB_Completed = 2,
+ BusLogic_CCB_Reset = 3
+}
+__attribute__ ((packed))
+BusLogic_CCB_Status_T;
+
+
+/*
Define the 32 Bit Mode Command Control Block (CCB) structure. The first 40
bytes are defined by and common to both the MultiMaster Firmware and the
FlashPoint SCCB Manager. The next 60 bytes are defined by the FlashPoint
@@ -1113,27 +1191,26 @@ typedef struct BusLogic_CCB
FlashPoint SCCB Manager Defined Portion.
*/
void (*CallbackFunction)(struct BusLogic_CCB *); /* Bytes 40-43 */
- BusLogic_IO_Address_T BaseAddress; /* Bytes 44-47 */
+ BusLogic_Base_Address_T BaseAddress; /* Bytes 44-47 */
BusLogic_CompletionCode_T CompletionCode; /* Byte 48 */
+#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
unsigned char :8; /* Byte 49 */
unsigned short OS_Flags; /* Bytes 50-51 */
unsigned char Private[48]; /* Bytes 52-99 */
+#endif
/*
BusLogic Linux Driver Defined Portion.
*/
- struct BusLogic_HostAdapter *HostAdapter;
- SCSI_Command_T *Command;
- enum { BusLogic_CCB_Free = 0,
- BusLogic_CCB_Active = 1,
- BusLogic_CCB_Completed = 2,
- BusLogic_CCB_Reset = 3 } Status;
+ boolean AllocationGroupHead;
+ BusLogic_CCB_Status_T Status;
unsigned long SerialNumber;
+ SCSI_Command_T *Command;
+ struct BusLogic_HostAdapter *HostAdapter;
struct BusLogic_CCB *Next;
struct BusLogic_CCB *NextAll;
BusLogic_ScatterGatherSegment_T
ScatterGatherList[BusLogic_ScatterGatherLimit];
}
-__attribute__ ((packed))
BusLogic_CCB_T;
@@ -1166,32 +1243,48 @@ BusLogic_IncomingMailbox_T;
/*
- Define the Linux BusLogic Driver Command Line Entry structure.
+ Define the BusLogic Driver Options structure.
*/
-typedef struct BusLogic_CommandLineEntry
+typedef struct BusLogic_DriverOptions
{
- BusLogic_IO_Address_T IO_Address;
- unsigned short TaggedQueueDepth;
- unsigned short BusSettleTime;
unsigned short TaggedQueuingPermitted;
unsigned short TaggedQueuingPermittedMask;
+ unsigned short BusSettleTime;
BusLogic_LocalOptions_T LocalOptions;
+ unsigned char QueueDepth[BusLogic_MaxTargetDevices];
BusLogic_ErrorRecoveryStrategy_T
ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
}
-BusLogic_CommandLineEntry_T;
+BusLogic_DriverOptions_T;
/*
- Define the Host Adapter Target Device Statistics structure.
+ Define the Host Adapter Target Flags structure.
+*/
+
+typedef struct BusLogic_TargetFlags
+{
+ boolean TargetExists:1;
+ boolean TaggedQueuingSupported:1;
+ boolean WideTransfersSupported:1;
+ boolean TaggedQueuingActive:1;
+ boolean WideTransfersActive:1;
+ boolean CommandSuccessfulFlag:1;
+ boolean TargetInfoReported:1;
+}
+BusLogic_TargetFlags_T;
+
+
+/*
+ Define the Host Adapter Target Statistics structure.
*/
#define BusLogic_SizeBuckets 10
typedef unsigned int BusLogic_CommandSizeBuckets_T[BusLogic_SizeBuckets];
-typedef struct BusLogic_TargetDeviceStatistics
+typedef struct BusLogic_TargetStatistics
{
unsigned int CommandsAttempted;
unsigned int CommandsCompleted;
@@ -1211,7 +1304,7 @@ typedef struct BusLogic_TargetDeviceStatistics
unsigned short HostAdapterResetsAttempted;
unsigned short HostAdapterResetsCompleted;
}
-BusLogic_TargetDeviceStatistics_T;
+BusLogic_TargetStatistics_T;
/*
@@ -1230,7 +1323,7 @@ typedef unsigned int FlashPoint_CardHandle_T;
typedef struct FlashPoint_Info
{
- BusLogic_IO_Address_T BaseAddress; /* Bytes 0-3 */
+ BusLogic_Base_Address_T BaseAddress; /* Bytes 0-3 */
boolean Present; /* Byte 4 */
unsigned char IRQ_Channel; /* Byte 5 */
unsigned char SCSI_ID; /* Byte 6 */
@@ -1265,12 +1358,14 @@ FlashPoint_Info_T;
/*
- Define the Linux BusLogic Driver Host Adapter structure.
+ Define the BusLogic Driver Host Adapter structure.
*/
typedef struct BusLogic_HostAdapter
{
SCSI_Host_T *SCSI_Host;
+ BusLogic_HostAdapterType_T HostAdapterType;
+ BusLogic_HostAdapterBusType_T HostAdapterBusType;
BusLogic_IO_Address_T IO_Address;
BusLogic_PCI_Address_T PCI_Address;
unsigned short AddressCount;
@@ -1279,18 +1374,16 @@ typedef struct BusLogic_HostAdapter
unsigned char FirmwareVersion[6];
unsigned char FullModelName[18];
unsigned char InterruptLabel[68];
+ unsigned char Bus;
+ unsigned char Device;
unsigned char IRQ_Channel;
unsigned char DMA_Channel;
unsigned char SCSI_ID;
- unsigned char Bus;
- unsigned char Device;
- BusLogic_HostAdapterType_T HostAdapterType;
- BusLogic_HostAdapterBusType_T HostAdapterBusType:3;
boolean IRQ_ChannelAcquired:1;
boolean DMA_ChannelAcquired:1;
boolean ExtendedTranslationEnabled:1;
boolean ParityCheckingEnabled:1;
- boolean BusResetEnabled;
+ boolean BusResetEnabled:1;
boolean LevelSensitiveInterrupt:1;
boolean HostWideSCSI:1;
boolean HostDifferentialSCSI:1;
@@ -1304,8 +1397,9 @@ typedef struct BusLogic_HostAdapter
boolean StrictRoundRobinModeSupport:1;
boolean SCAM_Enabled:1;
boolean SCAM_Level2:1;
- boolean HostAdapterInitialized;
- boolean HostAdapterResetRequested:1;
+ boolean HostAdapterInitialized:1;
+ boolean HostAdapterExternalReset:1;
+ boolean HostAdapterInternalError:1;
volatile boolean HostAdapterCommandCompleted:1;
unsigned short HostAdapterScatterGatherLimit;
unsigned short DriverScatterGatherLimit;
@@ -1317,7 +1411,6 @@ typedef struct BusLogic_HostAdapter
unsigned short AllocatedCCBs;
unsigned short DriverQueueDepth;
unsigned short HostAdapterQueueDepth;
- unsigned short TaggedQueueDepth;
unsigned short UntaggedQueueDepth;
unsigned short BusSettleTime;
unsigned short SynchronousPermitted;
@@ -1327,26 +1420,24 @@ typedef struct BusLogic_HostAdapter
unsigned short DisconnectPermitted;
unsigned short TaggedQueuingPermitted;
unsigned short ExternalHostAdapterResets;
- BusLogic_LocalOptions_T LocalOptions;
+ unsigned short HostAdapterInternalErrors;
+ unsigned short TargetDeviceCount;
+ unsigned short MessageBufferLength;
BusLogic_BusAddress_T BIOS_Address;
- BusLogic_InstalledDevices_T InstalledDevices;
- BusLogic_SynchronousValues_T SynchronousValues;
- BusLogic_SynchronousPeriod_T SynchronousPeriod;
- BusLogic_CommandLineEntry_T *CommandLineEntry;
- FlashPoint_Info_T *FlashPointInfo;
+ BusLogic_DriverOptions_T *DriverOptions;
+ FlashPoint_Info_T FlashPointInfo;
FlashPoint_CardHandle_T CardHandle;
struct BusLogic_HostAdapter *Next;
- char *MessageBuffer;
- int MessageBufferLength;
+ struct BusLogic_HostAdapter *NextAll;
BusLogic_CCB_T *All_CCBs;
BusLogic_CCB_T *Free_CCBs;
BusLogic_CCB_T *BusDeviceResetPendingCCB[BusLogic_MaxTargetDevices];
BusLogic_ErrorRecoveryStrategy_T
ErrorRecoveryStrategy[BusLogic_MaxTargetDevices];
- boolean TaggedQueuingSupported[BusLogic_MaxTargetDevices];
- boolean TaggedQueuingActive[BusLogic_MaxTargetDevices];
- boolean CommandSuccessfulFlag[BusLogic_MaxTargetDevices];
+ BusLogic_TargetFlags_T TargetFlags[BusLogic_MaxTargetDevices];
unsigned char QueueDepth[BusLogic_MaxTargetDevices];
+ unsigned char SynchronousPeriod[BusLogic_MaxTargetDevices];
+ unsigned char SynchronousOffset[BusLogic_MaxTargetDevices];
unsigned char ActiveCommands[BusLogic_MaxTargetDevices];
unsigned int CommandsSinceReset[BusLogic_MaxTargetDevices];
unsigned long LastSequencePoint[BusLogic_MaxTargetDevices];
@@ -1358,7 +1449,11 @@ typedef struct BusLogic_HostAdapter
BusLogic_IncomingMailbox_T *FirstIncomingMailbox;
BusLogic_IncomingMailbox_T *LastIncomingMailbox;
BusLogic_IncomingMailbox_T *NextIncomingMailbox;
- BusLogic_TargetDeviceStatistics_T *TargetDeviceStatistics;
+ BusLogic_TargetStatistics_T TargetStatistics[BusLogic_MaxTargetDevices];
+ unsigned char MailboxSpace[BusLogic_MaxMailboxes
+ * (sizeof(BusLogic_OutgoingMailbox_T)
+ + sizeof(BusLogic_IncomingMailbox_T))];
+ char MessageBuffer[BusLogic_MessageBufferSize];
}
BusLogic_HostAdapter_T;
@@ -1377,6 +1472,41 @@ BIOS_DiskParameters_T;
/*
+ Define a structure for the SCSI Inquiry command results.
+*/
+
+typedef struct SCSI_Inquiry
+{
+ unsigned char PeripheralDeviceType:5; /* Byte 0 Bits 0-4 */
+ unsigned char PeripheralQualifier:3; /* Byte 0 Bits 5-7 */
+ unsigned char DeviceTypeModifier:7; /* Byte 1 Bits 0-6 */
+ boolean RMB:1; /* Byte 1 Bit 7 */
+ unsigned char ANSI_ApprovedVersion:3; /* Byte 2 Bits 0-2 */
+ unsigned char ECMA_Version:3; /* Byte 2 Bits 3-5 */
+ unsigned char ISO_Version:2; /* Byte 2 Bits 6-7 */
+ unsigned char ResponseDataFormat:4; /* Byte 3 Bits 0-3 */
+ unsigned char :2; /* Byte 3 Bits 4-5 */
+ boolean TrmIOP:1; /* Byte 3 Bit 6 */
+ boolean AENC:1; /* Byte 3 Bit 7 */
+ unsigned char AdditionalLength; /* Byte 4 */
+ unsigned char :8; /* Byte 5 */
+ unsigned char :8; /* Byte 6 */
+ boolean SftRe:1; /* Byte 7 Bit 0 */
+ boolean CmdQue:1; /* Byte 7 Bit 1 */
+ boolean :1; /* Byte 7 Bit 2 */
+ boolean Linked:1; /* Byte 7 Bit 3 */
+ boolean Sync:1; /* Byte 7 Bit 4 */
+ boolean WBus16:1; /* Byte 7 Bit 5 */
+ boolean WBus32:1; /* Byte 7 Bit 6 */
+ boolean RelAdr:1; /* Byte 7 Bit 7 */
+ unsigned char VendorIdentification[8]; /* Bytes 8-15 */
+ unsigned char ProductIdentification[16]; /* Bytes 16-31 */
+ unsigned char ProductRevisionLevel[4]; /* Bytes 32-35 */
+}
+SCSI_Inquiry_T;
+
+
+/*
BusLogic_AcquireHostAdapterLock acquires exclusive access to Host Adapter.
*/
@@ -1552,6 +1682,19 @@ static inline void *Bus_to_Virtual(BusLogic_BusAddress_T BusAddress)
/*
+ Virtual_to_32Bit_Virtual maps between Kernel Virtual Addresses and
+ 32 Bit Kernel Virtual Addresses. This avoids compilation warnings
+ on 64 Bit architectures.
+*/
+
+static inline
+BusLogic_BusAddress_T Virtual_to_32Bit_Virtual(void *VirtualAddress)
+{
+ return (BusLogic_BusAddress_T) (unsigned long) VirtualAddress;
+}
+
+
+/*
BusLogic_IncrementErrorCounter increments Error Counter by 1, stopping at
65535 rather than wrapping around to 0.
*/
@@ -1589,93 +1732,38 @@ static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T
{
int Index = 0;
if (Amount < 8*1024)
- if (Amount < 2*1024)
- Index = (Amount < 1*1024 ? 0 : 1);
- else Index = (Amount < 4*1024 ? 2 : 3);
+ {
+ if (Amount < 2*1024)
+ Index = (Amount < 1*1024 ? 0 : 1);
+ else Index = (Amount < 4*1024 ? 2 : 3);
+ }
else if (Amount < 128*1024)
- if (Amount < 32*1024)
- Index = (Amount < 16*1024 ? 4 : 5);
- else Index = (Amount < 64*1024 ? 6 : 7);
+ {
+ if (Amount < 32*1024)
+ Index = (Amount < 16*1024 ? 4 : 5);
+ else Index = (Amount < 64*1024 ? 6 : 7);
+ }
else Index = (Amount < 256*1024 ? 8 : 9);
CommandSizeBuckets[Index]++;
}
/*
- If CONFIG_PCI is not set, force CONFIG_SCSI_OMIT_FLASHPOINT, and use the
- ISA only probe function as the general one.
+ Define compatibility macros between Linux 2.0 and Linux 2.1.
*/
-#ifndef CONFIG_PCI
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
+#if LINUX_VERSION_CODE < 0x20100
-#define BusLogic_InitializeProbeInfoListISA BusLogic_InitializeProbeInfoList
+#define MODULE_PARM(Variable, Type)
#endif
/*
- FlashPoint support is only available for the Intel x86 Architecture.
-*/
-
-#ifndef __i386__
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
-
-#endif
-
-
-/*
- Define macros for testing the Host Adapter Type.
-*/
-
-#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
-
-#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
- (HostAdapter->HostAdapterType == BusLogic_MultiMaster)
-
-#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
- (HostAdapter->HostAdapterType == BusLogic_FlashPoint)
-
-#else
-
-#define BusLogic_MultiMasterHostAdapterP(HostAdapter) \
- (true)
-
-#define BusLogic_FlashPointHostAdapterP(HostAdapter) \
- (false)
-
-#endif
-
-
-/*
- Define Driver Message Macros.
-*/
-
-#define BusLogic_Announce(Format, Arguments...) \
- BusLogic_Message(BusLogic_AnnounceLevel, Format, ##Arguments)
-
-#define BusLogic_Info(Format, Arguments...) \
- BusLogic_Message(BusLogic_InfoLevel, Format, ##Arguments)
-
-#define BusLogic_Notice(Format, Arguments...) \
- BusLogic_Message(BusLogic_NoticeLevel, Format, ##Arguments)
-
-#define BusLogic_Warning(Format, Arguments...) \
- BusLogic_Message(BusLogic_WarningLevel, Format, ##Arguments)
-
-#define BusLogic_Error(Format, Arguments...) \
- BusLogic_Message(BusLogic_ErrorLevel, Format, ##Arguments)
-
-
-/*
Define the version number of the FlashPoint Firmware (SCCB Manager).
*/
-#define FlashPoint_FirmwareVersion "5.01"
+#define FlashPoint_FirmwareVersion "5.02"
/*
@@ -1683,35 +1771,22 @@ static inline void BusLogic_IncrementSizeBucket(BusLogic_CommandSizeBuckets_T
*/
#define FlashPoint_NormalInterrupt 0x00
+#define FlashPoint_InternalError 0xFE
#define FlashPoint_ExternalBusReset 0xFF
/*
- Define prototypes for the FlashPoint SCCB Manager Functions.
-*/
-
-extern unsigned char FlashPoint_ProbeHostAdapter(FlashPoint_Info_T *);
-extern FlashPoint_CardHandle_T
- FlashPoint_HardResetHostAdapter(FlashPoint_Info_T *);
-extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
-extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
-extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T);
-extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T);
-extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T);
-
-
-/*
Define prototypes for the forward referenced BusLogic Driver
Internal Functions.
*/
-static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *CCB);
+static void BusLogic_QueueCompletedCCB(BusLogic_CCB_T *);
static void BusLogic_InterruptHandler(int, void *, Registers_T *);
static int BusLogic_ResetHostAdapter(BusLogic_HostAdapter_T *,
- SCSI_Command_T *,
- unsigned int);
-static void BusLogic_Message(BusLogic_MessageLevel_T, char *Format,
+ SCSI_Command_T *, unsigned int);
+static void BusLogic_Message(BusLogic_MessageLevel_T, char *,
BusLogic_HostAdapter_T *, ...);
+static void BusLogic_ParseDriverOptions(char *);
#endif /* BusLogic_DriverVersion */
diff --git a/drivers/scsi/ChangeLog.ncr53c8xx b/drivers/scsi/ChangeLog.ncr53c8xx
index 3a110ce40..e6adffd9f 100644
--- a/drivers/scsi/ChangeLog.ncr53c8xx
+++ b/drivers/scsi/ChangeLog.ncr53c8xx
@@ -1,3 +1,30 @@
+Fri Jan 2 18:00 1998 Gerard Roudier (groudier@club-internet.fr)
+ * Revision 2.5f
+ - Use FAST-5 instead of SLOW for slow scsi devices according to
+ new SPI-2 draft.
+ - Make some changes in order to accomodate with 875 rev <= 3
+ device errata listing 397. Minor consequences are:
+ . Leave use of PCI Write and Invalidate under user control.
+ Now, by default the driver does not enable PCI MWI and option
+ 'specf:y' is required in order to enable this feature.
+ . Memory Read Line is not enabled for 875 and 875-like chips.
+ . Programmed burst length set to 64 DWORDS (instead of 128).
+ (Note: SYMBIOS uses 32 DWORDS for the SDMS BIOS)
+
+Sun Oct 26 12:00 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.5e
+ - Add 'buschk' boot option.
+ This option enables checking of SCSI BUS data lines after SCSI
+ RESET (set by default). (Submitted by Richard Waltham).
+ - Update the README file.
+
+Sat Oct 4 18:00 1997 Gerard Roudier (groudier@club-internet.fr)
+ * revision 2.5d
+ - Dispatch CONDITION MET and RESERVATION CONFLICT scsi status
+ as OK driver status.
+ - Update the README file and the Symbios NVRAM format definition
+ with removable media flags values (available with SDMS 4.09).
+
Sat Sep 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr)
* revision 2.5c
- Several PCI configuration registers fix-ups for powerpc.
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index 969ef7831..96e04f796 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -4,7 +4,7 @@ dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI
dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI
dep_tristate 'SCSI CD-ROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI
if [ "$CONFIG_BLK_DEV_SR" != "n" ]; then
- bool ' Enable vendor-specific extentions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
+ bool ' Enable vendor-specific extensions (for SCSI CDROM)' CONFIG_BLK_DEV_SR_VENDOR
fi
dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI
@@ -13,6 +13,7 @@ comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs'
bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN
bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS
+bool 'SCSI logging facility' CONFIG_SCSI_LOGGING
mainmenu_option next_comment
comment 'SCSI low-level drivers'
@@ -24,7 +25,7 @@ dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
dep_tristate 'Adaptec AIC7xxx support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI
if [ "$CONFIG_SCSI_AIC7XXX" != "n" ]; then
bool ' Enable tagged command queueing' CONFIG_AIC7XXX_TAGGED_QUEUEING Y
- dep_tristate ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
+ bool ' Override driver defaults for commands per LUN' CONFIG_OVERRIDE_CMDS N
if [ "$CONFIG_OVERRIDE_CMDS" != "n" ]; then
int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
fi
@@ -83,10 +84,11 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then
fi
fi
if [ "$CONFIG_MCA" = "y" ]; then
- dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI
- if [ "$CONFIG_SCSI_IBMMCA" != "n" ]; then
- bool ' reset SCSI-devices while booting' CONFIG_SCSI_IBMMCA_DEV_RESET
- fi
+ dep_tristate 'IBMMCA SCSI support' CONFIG_SCSI_IBMMCA $CONFIG_SCSI
+ if [ "$CONFIG_SCSI_IBMMCA" != "n" ]; then
+ bool ' Standard SCSI-order' CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+ bool ' Reset SCSI-devices at boottime' CONFIG_IBMMCA_SCSI_DEV_RESET
+ fi
fi
if [ "$CONFIG_PARPORT" != "n" ]; then
dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
@@ -113,7 +115,17 @@ dep_tristate 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F $CONFIG_SCSI
int ' maximum number of queued commands' CONFIG_SCSI_U14_34F_MAX_TAGS 8
fi
dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
-#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+#
+# Note - this is a very special 'host' adapter that simulates the presence of some disks.
+# It can come in very handy for troubleshooting. Anyone else is welcome to use it - all
+# you do is hack it to simulate the condition you want to test for, and then use it.
+#
+# The actual configuration in any kernel release could change at any time as I hack it to
+# simulate various conditions that I am testing.
+#
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
+fi
if [ "$CONFIG_PPC" = "y" ]; then
dep_tristate 'MESH (Power Mac internal SCSI) support' CONFIG_SCSI_MESH $CONFIG_SCSI
if [ "$CONFIG_SCSI_MESH" != "n" ]; then
diff --git a/drivers/scsi/FlashPoint.c b/drivers/scsi/FlashPoint.c
index c4655ec25..d94631a41 100644
--- a/drivers/scsi/FlashPoint.c
+++ b/drivers/scsi/FlashPoint.c
@@ -19,40 +19,15 @@
#include <linux/config.h>
-/*
- If CONFIG_PCI is not set, force CONFIG_SCSI_OMIT_FLASHPOINT.
-*/
-
-#ifndef CONFIG_PCI
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
-
-#endif
-
-
-/*
- FlashPoint support is only available for the Intel x86 Architecture.
-*/
-
-#ifndef __i386__
-
-#undef CONFIG_SCSI_OMIT_FLASHPOINT
-#define CONFIG_SCSI_OMIT_FLASHPOINT
-
-#endif
-
-
#ifndef CONFIG_SCSI_OMIT_FLASHPOINT
#define UNIX
#define FW_TYPE _SCCB_MGR_
#define MAX_CARDS 8
+#undef BUSTYPE_PCI
-#include <asm/io.h>
-
#define OS_InPortByte(port) inb(port)
#define OS_InPortWord(port) inw(port)
#define OS_InPortLong(port) inl(port)
@@ -68,7 +43,7 @@
*/
#define SccbMgr_sense_adapter FlashPoint_ProbeHostAdapter
-#define SccbMgr_config_adapter FlashPoint_HardResetHostAdapter
+#define SccbMgr_config_adapter FlashPoint_HardwareResetHostAdapter
#define SccbMgr_unload_card FlashPoint_ReleaseHostAdapter
#define SccbMgr_start_sccb FlashPoint_StartCCB
#define SccbMgr_abort_sccb FlashPoint_AbortCCB
@@ -169,6 +144,7 @@
#define stwidn FPT_stwidn
#define sxfrp FPT_sxfrp
#define utilEERead FPT_utilEERead
+#define utilEEReadOrg FPT_utilEEReadOrg
#define utilEESendCmdAddr FPT_utilEESendCmdAddr
#define utilEEWrite FPT_utilEEWrite
#define utilEEWriteOnOff FPT_utilEEWriteOnOff
@@ -1317,9 +1293,9 @@ typedef struct SCCBscam_info {
*
* Description: Register definitions for HARPOON ASIC.
*
- * $Date: 1997/01/31 02:14:28 $
+ * $Date: 1997/07/09 21:44:36 $
*
- * $Revision: 1.6 $
+ * $Revision: 1.9 $
*
*----------------------------------------------------------------------*/
@@ -2070,9 +2046,14 @@ void schkdd(USHORT port, UCHAR p_card);
UCHAR RdStack(USHORT port, UCHAR index);
void WrStack(USHORT portBase, UCHAR index, UCHAR data);
UCHAR ChkIfChipInitialized(USHORT ioPort);
+
+#if defined(V302)
UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun);
+#endif
+
void SendMsg(USHORT port, UCHAR message);
void queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code);
+UCHAR scsellDOS(USHORT p_port, UCHAR targ_id);
#else
UCHAR sfm(ULONG port, PSCCB pcurrSCCB);
void scsiStartAuto(ULONG port);
@@ -2090,7 +2071,11 @@ void schkdd(ULONG port, UCHAR p_card);
UCHAR RdStack(ULONG port, UCHAR index);
void WrStack(ULONG portBase, UCHAR index, UCHAR data);
UCHAR ChkIfChipInitialized(ULONG ioPort);
+
+#if defined(V302)
UCHAR GetTarLun(ULONG port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tar, PUCHAR lun);
+#endif
+
void SendMsg(ULONG port, UCHAR message);
void queueFlushTargSccb(UCHAR p_card, UCHAR thisTarg, UCHAR error_code);
#endif
@@ -2130,6 +2115,7 @@ void Wait(USHORT p_port, UCHAR p_delay);
void utilEEWriteOnOff(USHORT p_port,UCHAR p_mode);
void utilEEWrite(USHORT p_port, USHORT ee_data, USHORT ee_addr);
USHORT utilEERead(USHORT p_port, USHORT ee_addr);
+USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr);
void utilEESendCmdAddr(USHORT p_port, UCHAR ee_cmd, USHORT ee_addr);
#else
void Wait1Second(ULONG p_port);
@@ -2137,6 +2123,7 @@ void Wait(ULONG p_port, UCHAR p_delay);
void utilEEWriteOnOff(ULONG p_port,UCHAR p_mode);
void utilEEWrite(ULONG p_port, USHORT ee_data, USHORT ee_addr);
USHORT utilEERead(ULONG p_port, USHORT ee_addr);
+USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr);
void utilEESendCmdAddr(ULONG p_port, UCHAR ee_cmd, USHORT ee_addr);
#endif
@@ -2339,7 +2326,7 @@ void Debug_Load(UCHAR p_card, UCHAR p_bug_data);
extern unsigned int SccbGlobalFlags;
-#ident "$Id: sccb.c 1.17 1997/02/11 21:06:41 mohan Exp $"
+#ident "$Id: sccb.c 1.18 1997/06/10 16:47:04 mohan Exp $"
/*----------------------------------------------------------------------
*
*
@@ -2353,9 +2340,9 @@ extern unsigned int SccbGlobalFlags;
* Description: Functions relating to handling of the SCCB interface
* between the device driver and the HARPOON.
*
- * $Date: 1997/02/11 21:06:41 $
+ * $Date: 1997/06/10 16:47:04 $
*
- * $Revision: 1.17 $
+ * $Revision: 1.18 $
*
*----------------------------------------------------------------------*/
@@ -2477,6 +2464,7 @@ int SccbMgr_sense_adapter(PSCCBMGR_INFO pCardInfo)
if(ChkIfChipInitialized(ioport) == FALSE)
{
pCurrNvRam = NULL;
+ WR_HARPOON(ioport+hp_semaphore, 0x00);
XbowInit(ioport, 0); /*Must Init the SCSI before attempting */
DiagEEPROM(ioport);
}
@@ -3036,6 +3024,7 @@ STATIC s32bits probe_adapter(PADAPTER_INFO pAdapterInfo)
if(ChkIfChipInitialized(ioport) == FALSE)
{
pCurrNvRam = NULL;
+ WR_HARPOON(ioport+hp_semaphore, 0x00);
XbowInit(ioport, 0); /*Must Init the SCSI before attempting */
DiagEEPROM(ioport);
}
@@ -4802,7 +4791,23 @@ int SccbMgr_isr(ULONG pCurrCard)
may not show up if another device reselects us in 1.5us or
less. SRR Wednesday, 3/8/1995.
*/
- while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL))) ;
+ while (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL)) &&
+ !((RDW_HARPOON((ioport+hp_intstat)) & PHASE) &&
+ RD_HARPOON((ioport+hp_scsisig)) ==
+ (SCSI_BSY | SCSI_REQ | SCSI_CD | SCSI_MSG | SCSI_IOBIT))) ;
+
+ /*
+ The additional loop exit condition above detects a timing problem
+ with the revision D/E harpoon chips. The caller should reset the
+ host adapter to recover when 0xFE is returned.
+ */
+ if (!(RDW_HARPOON((ioport+hp_intstat)) & (BUS_FREE | RSEL)))
+ {
+ mOS_Lock((PSCCBcard)pCurrCard);
+ MENABLE_INT(ioport);
+ mOS_UnLock((PSCCBcard)pCurrCard);
+ return 0xFE;
+ }
WRW_HARPOON((ioport+hp_intstat), (BUS_FREE | ITAR_DISC));
@@ -5347,7 +5352,7 @@ void Debug_Load(UCHAR p_card, UCHAR p_bug_data)
}
#endif
-#ident "$Id: sccb_dat.c 1.9 1997/01/31 02:12:58 mohan Exp $"
+#ident "$Id: sccb_dat.c 1.10 1997/02/22 03:16:02 awin Exp $"
/*----------------------------------------------------------------------
*
*
@@ -5361,9 +5366,9 @@ void Debug_Load(UCHAR p_card, UCHAR p_bug_data)
* Description: Functions relating to handling of the SCCB interface
* between the device driver and the HARPOON.
*
- * $Date: 1997/01/31 02:12:58 $
+ * $Date: 1997/02/22 03:16:02 $
*
- * $Revision: 1.9 $
+ * $Revision: 1.10 $
*
*----------------------------------------------------------------------*/
@@ -5378,18 +5383,19 @@ void Debug_Load(UCHAR p_card, UCHAR p_bug_data)
/*#include <target.h>*/
/*#include <harpoon.h>*/
+/*
+** IMPORTANT NOTE!!!
+**
+** You MUST preassign all data to a valid value or zero. This is
+** required due to the MS compiler bug under OS/2 and Solaris Real-Mode
+** driver environment.
+*/
+
-#if defined(OS2) || defined (SOLARIS_REAL_MODE)
-SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { 0 };
-SCCBCARD BL_Card[MAX_CARDS] = { 0 };
-SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { 0 };
-NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { 0 };
-#else
-SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR];
-SCCBCARD BL_Card[MAX_CARDS];
-SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR];
-NVRAMINFO nvRamInfo[MAX_MB_CARDS];
-#endif
+SCCBMGR_TAR_INFO sccbMgrTbl[MAX_CARDS][MAX_SCSI_TAR] = { { { 0 } } };
+SCCBCARD BL_Card[MAX_CARDS] = { { 0 } };
+SCCBSCAM_INFO scamInfo[MAX_SCSI_TAR] = { { { 0 } } };
+NVRAMINFO nvRamInfo[MAX_MB_CARDS] = { { 0 } };
#if defined(OS2)
@@ -5402,23 +5408,23 @@ void (*s_PhaseTbl[8]) ();
#endif
#if defined(DOS)
-UCHAR first_time;
+UCHAR first_time = 0;
#endif
-UCHAR mbCards;
+UCHAR mbCards = 0;
UCHAR scamHAString[] = {0x63, 0x07, 'B', 'U', 'S', 'L', 'O', 'G', 'I', 'C', \
' ', 'B', 'T', '-', '9', '3', '0', \
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, \
0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20};
-USHORT default_intena;
+USHORT default_intena = 0;
#if defined(BUGBUG)
-UCHAR debug_int[MAX_CARDS][debug_size];
-UCHAR debug_index[MAX_CARDS];
-UCHAR reserved_1[3];
+UCHAR debug_int[MAX_CARDS][debug_size] = { 0 };
+UCHAR debug_index[MAX_CARDS] = { 0 };
+UCHAR reserved_1[3] = { 0 };
#endif
-#ident "$Id: scsi.c 1.19 1997/01/31 02:08:14 mohan Exp $"
+#ident "$Id: scsi.c 1.23 1997/07/09 21:42:54 mohan Exp $"
/*----------------------------------------------------------------------
*
*
@@ -5433,9 +5439,9 @@ UCHAR reserved_1[3];
* selection/reselection, sync negotiation, message-in
* decoding.
*
- * $Date: 1997/01/31 02:08:14 $
+ * $Date: 1997/07/09 21:42:54 $
*
- * $Revision: 1.19 $
+ * $Revision: 1.23 $
*
*----------------------------------------------------------------------*/
@@ -5483,11 +5489,13 @@ UCHAR sfm(ULONG port, PSCCB pCurrSCCB)
while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) &&
(TimeOutLoop++ < 20000) ){}
+
WR_HARPOON(port+hp_portctrl_0, SCSI_PORT);
message = RD_HARPOON(port+hp_scsidata_0);
- WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+ WR_HARPOON(port+hp_scsisig, SCSI_ACK + S_MSGI_PH);
+
if (TimeOutLoop > 20000)
message = 0x00; /* force message byte = 0 if Time Out on Req */
@@ -5495,6 +5503,10 @@ UCHAR sfm(ULONG port, PSCCB pCurrSCCB)
if ((RDW_HARPOON((port+hp_intstat)) & PARITY) &&
(RD_HARPOON(port+hp_addstat) & SCSI_PAR_ERR))
{
+ WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+ WR_HARPOON(port+hp_xferstat, 0);
+ WR_HARPOON(port+hp_fiforead, 0);
+ WR_HARPOON(port+hp_fifowrite, 0);
if (pCurrSCCB != NULL)
{
pCurrSCCB->Sccb_scsimsg = SMPARITY;
@@ -5503,6 +5515,7 @@ UCHAR sfm(ULONG port, PSCCB pCurrSCCB)
do
{
ACCEPT_MSG_ATN(port);
+ TimeOutLoop = 0;
while( (!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ)) &&
(TimeOutLoop++ < 20000) ){}
if (TimeOutLoop > 20000)
@@ -5524,6 +5537,10 @@ UCHAR sfm(ULONG port, PSCCB pCurrSCCB)
}while(1);
}
+ WR_HARPOON(port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+ WR_HARPOON(port+hp_xferstat, 0);
+ WR_HARPOON(port+hp_fiforead, 0);
+ WR_HARPOON(port+hp_fifowrite, 0);
return(message);
}
@@ -5894,12 +5911,20 @@ void sres(USHORT port, UCHAR p_card, PSCCBcard pCurrCard)
void sres(ULONG port, UCHAR p_card, PSCCBcard pCurrCard)
#endif
{
+
+#if defined(V302)
#ifdef DOS
UCHAR our_target,message, msgRetryCount;
extern UCHAR lun, tag;
#else
UCHAR our_target,message,lun,tag, msgRetryCount;
#endif
+
+#else /* V302 */
+ UCHAR our_target, message, lun = 0, tag, msgRetryCount;
+#endif /* V302 */
+
+
PSCCBMgr_tar_info currTar_Info;
PSCCB currSCCB;
@@ -5972,7 +5997,103 @@ void sres(ULONG port, UCHAR p_card, PSCCBcard pCurrCard)
msgRetryCount = 0;
do
{
+
+#if defined(V302)
+
message = GetTarLun(port, p_card, our_target, pCurrCard, &tag, &lun);
+
+#else /* V302 */
+
+ currTar_Info = &sccbMgrTbl[p_card][our_target];
+ tag = 0;
+
+
+ while(!(RD_HARPOON(port+hp_scsisig) & SCSI_REQ))
+ {
+ if (! (RD_HARPOON(port+hp_scsisig) & SCSI_BSY))
+ {
+
+ WRW_HARPOON((port+hp_intstat), PHASE);
+ return;
+ }
+ }
+
+ WRW_HARPOON((port+hp_intstat), PHASE);
+ if ((RD_HARPOON(port+hp_scsisig) & S_SCSI_PHZ) == S_MSGI_PH)
+ {
+
+ message = sfm(port,pCurrCard->currentSCCB);
+ if (message)
+ {
+
+ if (message <= (0x80 | LUN_MASK))
+ {
+ lun = message & (UCHAR)LUN_MASK;
+
+#if !defined(DOS)
+ if ((currTar_Info->TarStatus & TAR_TAG_Q_MASK) == TAG_Q_TRYING)
+ {
+ if (currTar_Info->TarTagQ_Cnt != 0)
+ {
+
+ if (!(currTar_Info->TarLUN_CA))
+ {
+ ACCEPT_MSG(port); /*Release the ACK for ID msg. */
+
+
+ message = sfm(port,pCurrCard->currentSCCB);
+ if (message)
+ {
+ ACCEPT_MSG(port);
+ }
+
+ else
+ message = FALSE;
+
+ if(message != FALSE)
+ {
+ tag = sfm(port,pCurrCard->currentSCCB);
+
+ if (!(tag))
+ message = FALSE;
+ }
+
+ } /*C.A. exists! */
+
+ } /*End Q cnt != 0 */
+
+ } /*End Tag cmds supported! */
+#endif /* !DOS */
+
+ } /*End valid ID message. */
+
+ else
+ {
+
+ ACCEPT_MSG_ATN(port);
+ }
+
+ } /* End good id message. */
+
+ else
+ {
+
+ message = FALSE;
+ }
+ }
+ else
+ {
+ ACCEPT_MSG_ATN(port);
+
+ while (!(RDW_HARPOON((port+hp_intstat)) & (PHASE | RESET)) &&
+ !(RD_HARPOON(port+hp_scsisig) & SCSI_REQ) &&
+ (RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ;
+
+ return;
+ }
+
+#endif /* V302 */
+
if(message == FALSE)
{
msgRetryCount++;
@@ -6071,6 +6192,8 @@ void sres(ULONG port, UCHAR p_card, PSCCBcard pCurrCard)
(RD_HARPOON(port+hp_scsisig) & SCSI_BSY)) ;
}
+#if defined(V302)
+
#if defined(DOS)
UCHAR GetTarLun(USHORT port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard, PUCHAR tag, PUCHAR lun)
#else
@@ -6162,6 +6285,7 @@ UCHAR GetTarLun(ULONG port, UCHAR p_card, UCHAR our_target, PSCCBcard pCurrCard,
return(TRUE);
}
+#endif /* V302 */
#if defined(DOS)
void SendMsg(USHORT port, UCHAR message)
@@ -6469,6 +6593,10 @@ void shandem(ULONG port, UCHAR p_card, PSCCB pCurrSCCB)
ACCEPT_MSG(port);
WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
}
+ }else
+ {
+ if(pCurrSCCB->Sccb_scsimsg == SMPARITY)
+ WR_HARPOON(port+hp_autostart_1, (AUTO_IMMED+DISCONNECT_START));
}
}
@@ -7386,6 +7514,7 @@ void sinits(PSCCB p_sccb, UCHAR p_card)
p_sccb->Sccb_scsistat = BUS_FREE_ST;
p_sccb->SccbStatus = SCCB_IN_PROCESS;
p_sccb->Sccb_scsimsg = SMNO_OP;
+
}
@@ -9222,7 +9351,7 @@ void hostDataXferRestart(PSCCB currSCCB)
currSCCB->Sccb_XferCnt = currSCCB->DataLength - currSCCB->Sccb_ATC;
}
}
-#ident "$Id: scam.c 1.16 1997/01/31 02:11:12 mohan Exp $"
+#ident "$Id: scam.c 1.17 1997/03/20 23:49:37 mohan Exp $"
/*----------------------------------------------------------------------
*
*
@@ -9237,9 +9366,9 @@ void hostDataXferRestart(PSCCB currSCCB)
* and the determination of the SCSI IDs to be assigned
* to all perspective SCSI targets.
*
- * $Date: 1997/01/31 02:11:12 $
+ * $Date: 1997/03/20 23:49:37 $
*
- * $Revision: 1.16 $
+ * $Revision: 1.17 $
*
*----------------------------------------------------------------------*/
@@ -9468,7 +9597,7 @@ void scini(UCHAR p_card, UCHAR p_our_id, UCHAR p_power_up)
if (((ScamFlg & SCAM_ENABLED) && (scamInfo[i].state == LEGACY))
|| (i != p_our_id))
{
- scsell(p_port,i);
+ scsellDOS(p_port,i);
}
}
#endif
@@ -9885,6 +10014,7 @@ UCHAR sciso(ULONG p_port, UCHAR p_id_string[])
}
if ((ret_data & 0x1F) == 0)
+ {
/*
if(bit_cnt != 0 || bit_cnt != 8)
{
@@ -9899,6 +10029,7 @@ UCHAR sciso(ULONG p_port, UCHAR p_id_string[])
return(0x00);
else
return(0xFF);
+ }
} /*bit loop */
@@ -10090,6 +10221,90 @@ UCHAR scsell(ULONG p_port, UCHAR targ_id)
}
}
+#if defined(DOS)
+/*---------------------------------------------------------------------
+ *
+ * Function: scsell for DOS
+ *
+ * Description: Select the specified device ID using a selection timeout
+ * less than 2ms. This was specially required to solve
+ * the problem with Plextor 12X CD-ROM drive. This drive
+ * was responding the Selection at the end of 4ms and
+ * hanging the system.
+ *
+ *---------------------------------------------------------------------*/
+
+UCHAR scsellDOS(USHORT p_port, UCHAR targ_id)
+{
+ USHORT i;
+
+ WR_HARPOON(p_port+hp_page_ctrl,
+ (RD_HARPOON(p_port+hp_page_ctrl) | G_INT_DISABLE));
+
+ ARAM_ACCESS(p_port);
+
+ WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) | SCAM_TIMER));
+ WR_HARPOON(p_port+hp_seltimeout,TO_2ms);
+
+
+ for (i = p_port+CMD_STRT; i < p_port+CMD_STRT+12; i+=2) {
+ WRW_HARPOON(i, (MPM_OP+ACOMMAND));
+ }
+ WRW_HARPOON(i, (BRH_OP+ALWAYS+ NP));
+
+ WRW_HARPOON((p_port+hp_intstat),
+ (RESET | TIMEOUT | SEL | BUS_FREE | AUTO_INT));
+
+ WR_HARPOON(p_port+hp_select_id, targ_id);
+
+ WR_HARPOON(p_port+hp_portctrl_0, SCSI_PORT);
+ WR_HARPOON(p_port+hp_autostart_3, (SELECT | CMD_ONLY_STRT));
+ WR_HARPOON(p_port+hp_scsictrl_0, (SEL_TAR | ENA_RESEL));
+
+
+ while (!(RDW_HARPOON((p_port+hp_intstat)) &
+ (RESET | PROG_HLT | TIMEOUT | AUTO_INT))) {}
+
+ if (RDW_HARPOON((p_port+hp_intstat)) & RESET)
+ Wait(p_port, TO_250ms);
+
+ DISABLE_AUTO(p_port);
+
+ WR_HARPOON(p_port+hp_addstat,(RD_HARPOON(p_port+hp_addstat) & ~SCAM_TIMER));
+ WR_HARPOON(p_port+hp_seltimeout,TO_290ms);
+
+ SGRAM_ACCESS(p_port);
+
+ if (RDW_HARPOON((p_port+hp_intstat)) & (RESET | TIMEOUT) ) {
+
+ WRW_HARPOON((p_port+hp_intstat),
+ (RESET | TIMEOUT | SEL | BUS_FREE | PHASE));
+
+ WR_HARPOON(p_port+hp_page_ctrl,
+ (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+ return(FALSE); /*No legacy device */
+ }
+
+ else {
+
+ while(!(RDW_HARPOON((p_port+hp_intstat)) & BUS_FREE)) {
+ if (RD_HARPOON(p_port+hp_scsisig) & SCSI_REQ)
+ {
+ WR_HARPOON(p_port+hp_scsisig, (SCSI_ACK + S_ILL_PH));
+ ACCEPT_MSG(p_port);
+ }
+ }
+
+ WRW_HARPOON((p_port+hp_intstat), CLR_ALL_INT_1);
+
+ WR_HARPOON(p_port+hp_page_ctrl,
+ (RD_HARPOON(p_port+hp_page_ctrl) & ~G_INT_DISABLE));
+
+ return(TRUE); /*Found one of them oldies! */
+ }
+}
+#endif /* DOS */
/*---------------------------------------------------------------------
*
@@ -10252,10 +10467,12 @@ UCHAR scmachid(UCHAR p_card, UCHAR p_id_string[])
match--;
if (match == 0xFF)
+ {
if (p_id_string[0] & BIT(5))
match = 7;
else
match = MAX_SCSI_TAR-1;
+ }
}
@@ -10300,10 +10517,12 @@ UCHAR scmachid(UCHAR p_card, UCHAR p_id_string[])
match--;
if (match == 0xFF)
+ {
if (p_id_string[0] & BIT(5))
match = 7;
else
match = MAX_SCSI_TAR-1;
+ }
}
return(NO_ID_AVAIL);
@@ -10362,7 +10581,7 @@ void scsavdi(UCHAR p_card, ULONG p_port)
utilEEWrite(p_port, sum_data, EEPROM_CHECK_SUM/2);
utilEEWriteOnOff(p_port,0); /* Turn off write access */
}
-#ident "$Id: diagnose.c 1.9 1997/01/31 02:09:48 mohan Exp $"
+#ident "$Id: diagnose.c 1.10 1997/06/10 16:51:47 mohan Exp $"
/*----------------------------------------------------------------------
*
*
@@ -10376,9 +10595,9 @@ void scsavdi(UCHAR p_card, ULONG p_port)
* Description: Diagnostic funtions for testing the integrity of
* the HARPOON.
*
- * $Date: 1997/01/31 02:09:48 $
+ * $Date: 1997/06/10 16:51:47 $
*
- * $Revision: 1.9 $
+ * $Revision: 1.10 $
*
*----------------------------------------------------------------------*/
@@ -10419,7 +10638,7 @@ UCHAR i;
WR_HARPOON(port+hp_scsireset,(DMA_RESET | HPSCSI_RESET | PROG_RESET | \
FIFO_CLR));
- WR_HARPOON(port+hp_scsireset,0x00);
+ WR_HARPOON(port+hp_scsireset,SCSI_INI);
WR_HARPOON(port+hp_clkctrl_0,CLKCTRL_DEFAULT);
@@ -10703,8 +10922,8 @@ void DiagEEPROM(ULONG p_port)
temp += 0x70D3;
utilEEWrite(p_port, 0x0010, BIOS_CONFIG/2);
temp += 0x0010;
- utilEEWrite(p_port, 0x0007, SCAM_CONFIG/2);
- temp += 0x0007;
+ utilEEWrite(p_port, 0x0003, SCAM_CONFIG/2);
+ temp += 0x0003;
utilEEWrite(p_port, 0x0007, ADAPTER_SCSI_ID/2);
temp += 0x0007;
@@ -10807,7 +11026,7 @@ void DiagEEPROM(ULONG p_port)
}
-#ident "$Id: utility.c 1.22 1997/01/31 02:12:23 mohan Exp $"
+#ident "$Id: utility.c 1.23 1997/06/10 16:55:06 mohan Exp $"
/*----------------------------------------------------------------------
*
*
@@ -10821,9 +11040,9 @@ void DiagEEPROM(ULONG p_port)
* Description: Utility functions relating to queueing and EEPROM
* manipulation and any other garbage functions.
*
- * $Date: 1997/01/31 02:12:23 $
+ * $Date: 1997/06/10 16:55:06 $
*
- * $Revision: 1.22 $
+ * $Revision: 1.23 $
*
*----------------------------------------------------------------------*/
/*#include <globals.h>*/
@@ -11617,10 +11836,13 @@ void utilEEWrite(ULONG p_port, USHORT ee_data, USHORT ee_addr)
ee_value &= ~SEE_DO;
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
ee_value |= SEE_CLK; /* Clock data! */
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
ee_value &= ~SEE_CLK;
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
}
ee_value &= (EXT_ARB_ACK | SCSI_TERM_ENA_H);
WR_HARPOON(p_port+hp_ee_ctrl, (ee_value | SEE_MS));
@@ -11632,7 +11854,6 @@ void utilEEWrite(ULONG p_port, USHORT ee_data, USHORT ee_addr)
WR_HARPOON(p_port+hp_ee_ctrl, ee_value); /* Turn off Master Select */
}
-
/*---------------------------------------------------------------------
*
* Function: Read EEPROM
@@ -11648,6 +11869,40 @@ USHORT utilEERead(USHORT p_port, USHORT ee_addr)
USHORT utilEERead(ULONG p_port, USHORT ee_addr)
#endif
{
+ USHORT i, ee_data1, ee_data2;
+
+ i = 0;
+ ee_data1 = utilEEReadOrg(p_port, ee_addr);
+ do
+ {
+ ee_data2 = utilEEReadOrg(p_port, ee_addr);
+
+ if(ee_data1 == ee_data2)
+ return(ee_data1);
+
+ ee_data1 = ee_data2;
+ i++;
+
+ }while(i < 4);
+
+ return(ee_data1);
+}
+
+/*---------------------------------------------------------------------
+ *
+ * Function: Read EEPROM Original
+ *
+ * Description: Read a word from the EEPROM at the desired
+ * address.
+ *
+ *---------------------------------------------------------------------*/
+
+#if defined(DOS)
+USHORT utilEEReadOrg(USHORT p_port, USHORT ee_addr)
+#else
+USHORT utilEEReadOrg(ULONG p_port, USHORT ee_addr)
+#endif
+{
UCHAR ee_value;
USHORT i, ee_data;
@@ -11666,8 +11921,10 @@ USHORT utilEERead(ULONG p_port, USHORT ee_addr)
ee_value |= SEE_CLK; /* Clock data! */
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
ee_value &= ~SEE_CLK;
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
ee_data <<= 1;
@@ -11722,10 +11979,13 @@ void utilEESendCmdAddr(ULONG p_port, UCHAR ee_cmd, USHORT ee_addr)
ee_value &= ~SEE_DO;
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
ee_value |= SEE_CLK; /* Clock data! */
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
ee_value &= ~SEE_CLK;
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
}
@@ -11744,10 +12004,13 @@ void utilEESendCmdAddr(ULONG p_port, UCHAR ee_cmd, USHORT ee_addr)
ee_value &= ~SEE_DO;
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
ee_value |= SEE_CLK; /* Clock data! */
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
ee_value &= ~SEE_CLK;
WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
+ WR_HARPOON(p_port+hp_ee_ctrl, ee_value);
i >>= 1;
}
@@ -11785,4 +12048,112 @@ UCHAR CalcLrc(UCHAR buffer[])
+/*
+ The following inline definitions avoid type conflicts.
+*/
+
+static inline unsigned char
+FlashPoint__ProbeHostAdapter(FlashPoint_Info_T *FlashPointInfo)
+{
+ return FlashPoint_ProbeHostAdapter((PSCCBMGR_INFO) FlashPointInfo);
+}
+
+
+static inline FlashPoint_CardHandle_T
+FlashPoint__HardwareResetHostAdapter(FlashPoint_Info_T *FlashPointInfo)
+{
+ return FlashPoint_HardwareResetHostAdapter((PSCCBMGR_INFO) FlashPointInfo);
+}
+
+static inline void
+FlashPoint__ReleaseHostAdapter(FlashPoint_CardHandle_T CardHandle)
+{
+ FlashPoint_ReleaseHostAdapter(CardHandle);
+}
+
+
+static inline void
+FlashPoint__StartCCB(FlashPoint_CardHandle_T CardHandle, BusLogic_CCB_T *CCB)
+{
+ FlashPoint_StartCCB(CardHandle, (PSCCB) CCB);
+}
+
+
+static inline void
+FlashPoint__AbortCCB(FlashPoint_CardHandle_T CardHandle, BusLogic_CCB_T *CCB)
+{
+ FlashPoint_AbortCCB(CardHandle, (PSCCB) CCB);
+}
+
+
+static inline boolean
+FlashPoint__InterruptPending(FlashPoint_CardHandle_T CardHandle)
+{
+ return FlashPoint_InterruptPending(CardHandle);
+}
+
+
+static inline int
+FlashPoint__HandleInterrupt(FlashPoint_CardHandle_T CardHandle)
+{
+ return FlashPoint_HandleInterrupt(CardHandle);
+}
+
+
+#define FlashPoint_ProbeHostAdapter FlashPoint__ProbeHostAdapter
+#define FlashPoint_HardwareResetHostAdapter FlashPoint__HardwareResetHostAdapter
+#define FlashPoint_ReleaseHostAdapter FlashPoint__ReleaseHostAdapter
+#define FlashPoint_StartCCB FlashPoint__StartCCB
+#define FlashPoint_AbortCCB FlashPoint__AbortCCB
+#define FlashPoint_InterruptPending FlashPoint__InterruptPending
+#define FlashPoint_HandleInterrupt FlashPoint__HandleInterrupt
+
+
+/*
+ FlashPoint_InquireTargetInfo returns the Synchronous Period, Synchronous
+ Offset, and Wide Transfers Active information for TargetID on CardHandle.
+*/
+
+void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T CardHandle,
+ int TargetID,
+ unsigned char *SynchronousPeriod,
+ unsigned char *SynchronousOffset,
+ unsigned char *WideTransfersActive)
+{
+ SCCBMGR_TAR_INFO *TargetInfo =
+ &sccbMgrTbl[((SCCBCARD *)CardHandle)->cardIndex][TargetID];
+ if ((TargetInfo->TarSyncCtrl & SYNC_OFFSET) > 0)
+ {
+ *SynchronousPeriod = 5 * ((TargetInfo->TarSyncCtrl >> 5) + 1);
+ *SynchronousOffset = TargetInfo->TarSyncCtrl & SYNC_OFFSET;
+ }
+ else
+ {
+ *SynchronousPeriod = 0;
+ *SynchronousOffset = 0;
+ }
+ *WideTransfersActive = (TargetInfo->TarSyncCtrl & NARROW_SCSI ? 0 : 1);
+}
+
+
+#else /* CONFIG_SCSI_OMIT_FLASHPOINT */
+
+
+/*
+ Define prototypes for the FlashPoint SCCB Manager Functions.
+*/
+
+extern unsigned char FlashPoint_ProbeHostAdapter(FlashPoint_Info_T *);
+extern FlashPoint_CardHandle_T
+ FlashPoint_HardwareResetHostAdapter(FlashPoint_Info_T *);
+extern void FlashPoint_StartCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
+extern int FlashPoint_AbortCCB(FlashPoint_CardHandle_T, BusLogic_CCB_T *);
+extern boolean FlashPoint_InterruptPending(FlashPoint_CardHandle_T);
+extern int FlashPoint_HandleInterrupt(FlashPoint_CardHandle_T);
+extern void FlashPoint_ReleaseHostAdapter(FlashPoint_CardHandle_T);
+extern void FlashPoint_InquireTargetInfo(FlashPoint_CardHandle_T,
+ int, unsigned char *,
+ unsigned char *, unsigned char *);
+
+
#endif /* CONFIG_SCSI_OMIT_FLASHPOINT */
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index e79d4ee24..28ef6bbad 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -1,4 +1,3 @@
-
# Makefile for linux/drivers/scsi
#
# Note! Dependencies are done automagically by 'make dep', which also
@@ -14,8 +13,9 @@ MIX_OBJS :=
MOD_LIST_NAME := SCSI_MODULES
SCSI_SRCS = $(wildcard $(L_OBJS:%.o=%.c))
-AHA152X = -DDEBUG_AHA152X -DAUTOCONF
-GDTH = #-DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
+CFLAGS_aha152x.o = -DDEBUG_AHA152X -DAUTOCONF
+CFLAGS_gdth.o = # -DDEBUG_GDTH=2 -D__SERIAL__ -D__COM2__ -DGDTH_STATISTICS
+CFLAGS_seagate.o = -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -DPARITY
.SUFFIXES:
.SUFFIXES: .c .o .h .a
@@ -34,14 +34,13 @@ endif
ifeq ($(CONFIG_SCSI),y)
# We must attach scsi_syms.o to scsi.o, as otherwise there is nothing to
# pull the object file from the archive.
- SCSI=scsi.o
+ O_TARGET := scsi_n_syms.o
+ O_OBJS := scsi.o
ifeq ($(CONFIG_MODULES),y)
- O_TARGET := scsi_n_syms.o
- O_OBJS := scsi.o
OX_OBJS := scsi_syms.o
- SCSI := $(O_TARGET)
endif
- L_OBJS += $(SCSI) hosts.o scsi_ioctl.o constants.o scsicam.o
+ L_OBJS += scsi_n_syms.o hosts.o scsi_ioctl.o constants.o scsicam.o
+ L_OBJS += scsi_error.o scsi_obsolete.o scsi_queue.o
ifeq ($(CONFIG_PROC_FS),y)
L_OBJS += scsi_proc.o
endif
@@ -439,6 +438,14 @@ else
endif
endif
+ifeq ($(CONFIG_SCSI_PLUTO),y)
+L_OBJS += pluto.o
+else
+ ifeq ($(CONFIG_SCSI_PLUTO),m)
+ M_OBJS += pluto.o
+ endif
+endif
+
ifeq ($(CONFIG_SCSI_EATA),y)
L_OBJS += eata.o
else
@@ -469,24 +476,6 @@ endif
include $(TOPDIR)/Rules.make
-BusLogic.o: BusLogic.c FlashPoint.c
- $(CC) $(CFLAGS) -c BusLogic.c -o BusLogic.O
- $(CC) $(CFLAGS) -c FlashPoint.c -o FlashPoint.O
- $(LD) -r -o BusLogic.o BusLogic.O FlashPoint.O
- rm -f BusLogic.O FlashPoint.O
-
-aha152x.o: aha152x.c
- $(CC) $(CFLAGS) $(AHA152X) -c aha152x.c
-
-gdth.o: gdth.c gdth.h gdth_proc.c gdth_proc.h
- $(CC) $(CFLAGS) $(GDTH) -c gdth.c
-
-aic7xxx.o: aic7xxx.c aic7xxx_seq.h aic7xxx_reg.h
- $(CC) $(CFLAGS) -c -o $@ aic7xxx.c
-
-seagate.o: seagate.c
- $(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -DPARITY -c seagate.c
-
53c8xx_d.h 53c8xx_u.h : 53c7,8xx.scr script_asm.pl
ln -sf 53c7,8xx.scr fake.c
$(CPP) -traditional -DCHIP=810 fake.c | grep -v '^#' | perl script_asm.pl
@@ -502,8 +491,10 @@ seagate.o: seagate.c
rm fake.c
scsi_mod.o: $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o \
- scsicam.o scsi_proc.o
- $(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
+ scsicam.o scsi_proc.o scsi_error.o scsi_obsolete.o scsi_queue.o
+ $(LD) $(LD_RFLAG) -r -o $@ $(MIX_OBJS) hosts.o scsi.o scsi_ioctl.o \
+ constants.o scsicam.o scsi_proc.o \
+ scsi_error.o scsi_obsolete.o scsi_queue.o \
sr_mod.o: sr.o sr_ioctl.o sr_vendor.o
$(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o sr_vendor.o
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 6ecc0f1aa..ba1753147 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -625,7 +625,8 @@ static inline void NCR5380_all_init (void) {
*/
-static int probe_irq __initdata;
+static int probe_irq __initdata = 0;
+
__initfunc(static void probe_intr (int irq, void *dev_id, struct pt_regs * regs)) {
probe_irq = irq;
};
diff --git a/drivers/scsi/NCR53c406a.c b/drivers/scsi/NCR53c406a.c
index e29af7ad8..d2529b17e 100644
--- a/drivers/scsi/NCR53c406a.c
+++ b/drivers/scsi/NCR53c406a.c
@@ -1012,7 +1012,7 @@ static void chip_init()
outb(SYNC_MODE, SYNCOFF); /* synchronous mode */
}
-__initfunc(void calc_port_addr())
+__initfunc(void calc_port_addr(void))
{
/* Control Register Set 0 */
TC_LSB = (port_base+0x00);
diff --git a/drivers/scsi/NCR53c406a.h b/drivers/scsi/NCR53c406a.h
index 88e45e5e6..4ec3abbd5 100644
--- a/drivers/scsi/NCR53c406a.h
+++ b/drivers/scsi/NCR53c406a.h
@@ -26,27 +26,21 @@
* Use SG_NONE if DMA mode is enabled!
*/
#define NCR53c406a { \
- NULL /* next */, \
- NULL /* usage count */, \
- &proc_scsi_NCR53c406a /* proc_dir */, \
- NULL /* proc_info */, \
- "NCR53c406a" /* name */, \
- NCR53c406a_detect /* detect */, \
- NULL /* release */, \
- NCR53c406a_info /* info */, \
- NCR53c406a_command /* command */, \
- NCR53c406a_queue /* queuecommand */, \
- NCR53c406a_abort /* abort */, \
- NCR53c406a_reset /* reset */, \
- NULL /* slave_attach */, \
- NCR53c406a_biosparm /* biosparm */, \
- 1 /* can_queue */, \
- 7 /* SCSI ID of the chip */, \
- 32 /*SG_ALL*/ /*SG_NONE*/, \
- 1 /* commands per lun */, \
- 0 /* number of boards in system */, \
- 1 /* unchecked_isa_dma */, \
- ENABLE_CLUSTERING \
+ proc_dir: &proc_scsi_NCR53c406a /* proc_dir */, \
+ name: "NCR53c406a" /* name */, \
+ detect: NCR53c406a_detect /* detect */, \
+ info: NCR53c406a_info /* info */, \
+ command: NCR53c406a_command /* command */, \
+ queuecommand: NCR53c406a_queue /* queuecommand */, \
+ abort: NCR53c406a_abort /* abort */, \
+ reset: NCR53c406a_reset /* reset */, \
+ bios_param: NCR53c406a_biosparm /* biosparm */, \
+ can_queue: 1 /* can_queue */, \
+ this_id: 7 /* SCSI ID of the chip */, \
+ sg_tablesize: 32 /*SG_ALL*/ /*SG_NONE*/, \
+ cmd_per_lun: 1 /* commands per lun */, \
+ unchecked_isa_dma: 1 /* unchecked_isa_dma */, \
+ use_clustering: ENABLE_CLUSTERING \
}
extern struct proc_dir_entry proc_scsi_NCR53c406a;
diff --git a/drivers/scsi/README.BusLogic b/drivers/scsi/README.BusLogic
index a9962dbbc..60fa4011c 100644
--- a/drivers/scsi/README.BusLogic
+++ b/drivers/scsi/README.BusLogic
@@ -1,10 +1,10 @@
BusLogic MultiMaster and FlashPoint SCSI Driver for Linux
- Version 2.0.10 for Linux 2.0
+ Version 2.0.11 for Linux 2.0
PRODUCTION RELEASE
- 11 August 1997
+ 31 January 1998
Leonard N. Zubkoff
Dandelion Digital
@@ -15,27 +15,34 @@
INTRODUCTION
-BusLogic, Inc. designs and manufactures a variety of high performance SCSI host
-adapters which share a common programming interface across a diverse collection
-of bus architectures by virtue of their MultiMaster ASIC technology. This
-driver supports all present BusLogic MultiMaster Host Adapters, and should
+BusLogic, Inc. designed and manufactured a variety of high performance SCSI
+host adapters which share a common programming interface across a diverse
+collection of bus architectures by virtue of their MultiMaster ASIC technology.
+BusLogic was acquired by Mylex Corporation in February 1996, but the products
+supported by this driver originated under the BusLogic name and so that name is
+retained in the source code and documentation.
+
+This driver supports all present BusLogic MultiMaster Host Adapters, and should
support any future MultiMaster designs with little or no modification. More
-recently, BusLogic has introduced the FlashPoint Host Adapters, which are less
+recently, BusLogic introduced the FlashPoint Host Adapters, which are less
costly and rely on the host CPU, rather than including an onboard processor.
-Mylex/BusLogic has recently provided me with the FlashPoint Driver Developer's
-Kit, which comprises documentation and freely redistributable source code for
-the FlashPoint SCCB Manager. The SCCB Manager is the library of code that runs
-on the host CPU and performs functions analogous to the firmware on the
-MultiMaster Host Adapters. Thanks to their having provided the SCCB Manager,
-this driver now supports the FlashPoint Host Adapters as well.
+Despite not having an onboard CPU, the FlashPoint Host Adapters perform very
+well and have very low command latency. BusLogic has recently provided me with
+the FlashPoint Driver Developer's Kit, which comprises documentation and freely
+redistributable source code for the FlashPoint SCCB Manager. The SCCB Manager
+is the library of code that runs on the host CPU and performs functions
+analogous to the firmware on the MultiMaster Host Adapters. Thanks to their
+having provided the SCCB Manager, this driver now supports the FlashPoint Host
+Adapters as well.
My primary goals in writing this completely new BusLogic driver for Linux are
to achieve the full performance that BusLogic SCSI Host Adapters and modern
SCSI peripherals are capable of, and to provide a highly robust driver that can
be depended upon for high performance mission critical applications. All of
the major performance and error recovery features can be configured from the
-Linux kernel command line, allowing individual installations to tune driver
-performance and error recovery to their particular needs.
+Linux kernel command line or at module initialization time, allowing individual
+installations to tune driver performance and error recovery to their particular
+needs.
The latest information on Linux support for BusLogic SCSI Host Adapters, as
well as the most recent release of this driver and the latest firmware for the
@@ -48,33 +55,35 @@ driver and SCSI subsystem at startup, along with any subsequent system messages
relevant to SCSI operations, and a detailed description of your system's
hardware configuration.
-BusLogic has been an excellent company to work with and I highly recommend
-their products to the Linux community. In November 1995, I was offered the
+Mylex has been an excellent company to work with and I highly recommend their
+products to the Linux community. In November 1995, I was offered the
opportunity to become a beta test site for their latest MultiMaster product,
the BT-948 PCI Ultra SCSI Host Adapter, and then again for the BT-958 PCI Wide
Ultra SCSI Host Adapter in January 1996. This was mutually beneficial since
-BusLogic received a degree and kind of testing that their own testing group
-cannot readily achieve, and the Linux community has available high performance
-host adapters that have been well tested with Linux even before being brought
-to market. This relationship has also given me the opportunity to interact
+Mylex received a degree and kind of testing that their own testing group cannot
+readily achieve, and the Linux community has available high performance host
+adapters that have been well tested with Linux even before being brought to
+market. This relationship has also given me the opportunity to interact
directly with their technical staff, to understand more about the internal
workings of their products, and in turn to educate them about the needs and
-potential of the Linux community. Their interest and support is greatly
-appreciated.
+potential of the Linux community.
+
+More recently, Mylex has reaffirmed the company's interest in supporting the
+Linux community, and I am now working on a Linux driver for the DAC960 PCI RAID
+Controllers. Mylex's interest and support is greatly appreciated.
-Unlike some other vendors, if you contact BusLogic Technical Support with a
+Unlike some other vendors, if you contact Mylex Technical Support with a
problem and are running Linux, they will not tell you that your use of their
products is unsupported. Their latest product marketing literature even states
-"BusLogic SCSI host adapters are compatible with all major operating systems
+"Mylex SCSI host adapters are compatible with all major operating systems
including: ... Linux ...".
-BusLogic, Inc. is located at 4151 Burton Drive, Santa Clara, California, 95054,
-USA and can be reached by Voice at 408/492-9090 or by FAX at 408/492-1542.
-BusLogic maintains a World Wide Web site at http://www.buslogic.com, an
-anonymous FTP site at ftp.buslogic.com, and a BBS at 408/492-1984. BusLogic
-Technical Support can be reached by electronic mail at techsup@buslogic.com, by
-Voice at 408/654-0760, or by FAX at 408/492-1542. Contact information for
-offices in Europe and Japan is available on the Web site.
+Mylex Corporation is located at 34551 Ardenwood Blvd., Fremont, California
+94555, USA and can be reached at 510/796-6100 or on the World Wide Web at
+http://www.mylex.com. Mylex Technical Support can be reached by electronic
+mail at techsup@mylex.com, by Voice at 510/608-2400, or by FAX at 510/745-7715.
+Contact information for offices in Europe and Japan is available on the Web
+site.
DRIVER FEATURES
@@ -83,15 +92,46 @@ o Configuration Reporting and Testing
During system initialization, the driver reports extensively on the host
adapter hardware configuration, including the synchronous transfer parameters
- negotiated with each target device. In addition, the driver tests the
- hardware interrupt configuration to verify that interrupts are actually
- delivered correctly to the interrupt handler. This should catch a high
- percentage of PCI motherboard configuration errors early, because when the
- host adapter is probed successfully, most of the remaining problems appear to
- be related to interrupts. Most often, any remaining hardware problems are
- related to the specific configuration of devices on the SCSI bus, and the
- quality of cabling and termination used. Finally, this BusLogic driver
- should never incorrectly attempt to support an Adaptec 154x Host Adapter.
+ requested and negotiated with each target device. AutoSCSI settings for
+ Synchronous Negotiation, Wide Negotiation, and Disconnect/Reconnect are
+ reported for each target device, as well as the status of Tagged Queuing and
+ Error Recovery. If the same setting is in effect for all target devices,
+ then a single word or phrase is used; otherwise, a letter is provided for
+ each target device to indicate the individual status. The following examples
+ should clarify this reporting format:
+
+ Synchronous Negotiation: Ultra
+
+ Synchronous negotiation is enabled for all target devices and the host
+ adapter will attempt to negotiate for 20.0 mega-transfers/second.
+
+ Synchronous Negotiation: Fast
+
+ Synchronous negotiation is enabled for all target devices and the host
+ adapter will attempt to negotiate for 10.0 mega-transfers/second.
+
+ Synchronous Negotiation: Slow
+
+ Synchronous negotiation is enabled for all target devices and the host
+ adapter will attempt to negotiate for 5.0 mega-transfers/second.
+
+ Synchronous Negotiation: Disabled
+
+ Synchronous negotiation is disabled and all target devices are limited to
+ asynchronous operation.
+
+ Synchronous Negotiation: UFSNUUU#UUUUUUUU
+
+ Synchronous negotiation to Ultra speed is enabled for target devices 0
+ and 4 through 15, to Fast speed for target device 1, to Slow speed for
+ target device 2, and is not permitted to target device 3. The host
+ adapter's SCSI ID is represented by the "#".
+
+ The status of Wide Negotiation, Disconnect/Reconnect, and Tagged Queuing
+ are reported as "Enabled", Disabled", or a sequence of "Y" and "N" letters.
+
+ The Error Recovery option is reported as "Default", "Hard Reset",
+ "Bus Device Reset", "None" or a sequence of "D", "H", "B", and "N" letters.
o Performance Features
@@ -103,16 +143,15 @@ o Performance Features
addition, BusLogic's Strict Round Robin Mode is used to optimize host adapter
performance, and scatter/gather I/O can support as many segments as can be
effectively utilized by the Linux I/O subsystem. Control over the use of
- tagged queuing for each target device as well as selection of the tagged
- queue depth is available from the kernel command line. By default, the queue
- depth is automatically determined based on the number, type, speed, and
- capabilities of the target devices found. In addition, tagged queuing is
- automatically disabled whenever the host adapter firmware version is known
- not to implement it correctly, or whenever a tagged queue depth of 1 is
- selected. Tagged queuing is also disabled for individual target devices if
- disconnect/reconnect is disabled for that device. In performance testing,
- sustained disk writes of 7.3MB per second have been observed to a /dev/sd
- device.
+ tagged queuing for each target device as well as individual selection of the
+ tagged queue depth is available through driver options provided on the kernel
+ command line or at module initialization time. By default, the queue depth
+ is determined automatically based on the host adapter's total queue depth and
+ the number, type, speed, and capabilities of the target devices found. In
+ addition, tagged queuing is automatically disabled whenever the host adapter
+ firmware version is known not to implement it correctly, or whenever a tagged
+ queue depth of 1 is selected. Tagged queuing is also disabled for individual
+ target devices if disconnect/reconnect is disabled for that device.
o Robustness Features
@@ -121,15 +160,15 @@ o Robustness Features
a selection is made between a full host adapter hard reset and SCSI bus reset
versus sending a bus device reset message to the individual target device
based on the recommendation of the SCSI subsystem. Error recovery strategies
- are selectable from the kernel command line individually for each target
- device, and also include sending a bus device reset to the specific target
- device associated with the command being reset, as well as suppressing error
+ are selectable through driver options individually for each target device,
+ and also include sending a bus device reset to the specific target device
+ associated with the command being reset, as well as suppressing error
recovery entirely to avoid perturbing an improperly functioning device. If
the bus device reset error recovery strategy is selected and sending a bus
device reset does not restore correct operation, the next command that is
reset will force a full host adapter hard reset and SCSI bus reset. SCSI bus
resets caused by other devices and detected by the host adapter are also
- handled by issuing a hard reset to the host adapter and re-initialization.
+ handled by issuing a soft reset to the host adapter and re-initialization.
Finally, if tagged queuing is active and more than one command reset occurs
in a 10 minute interval, or if a command reset occurs within the first 10
minutes of operation, then tagged queuing will be disabled for that target
@@ -138,15 +177,6 @@ o Robustness Features
lock up or crash, and thereby allowing a clean shutdown and restart after the
offending component is removed.
-o Extensive Testing
-
- This driver has undergone extensive testing and improvement over a period of
- several months, and is routinely being used on heavily loaded systems. Over
- 300 people retrieved the driver during the beta test period. In addition to
- testing in normal system operation, error recovery tests have been performed
- to verify proper system recovery in the case of simulated dropped interrupts,
- external SCSI bus resets, and SCSI command errors due to bad CD-ROM media.
-
o PCI Configuration Support
On PCI systems running kernels compiled with PCI BIOS support enabled, this
@@ -159,8 +189,8 @@ o PCI Configuration Support
o /proc File System Support
- Copies of the host adapter configuration information together with data
- transfer and error recovery statistics are now available through the
+ Copies of the host adapter configuration information together with updated
+ data transfer and error recovery statistics are available through the
/proc/scsi/BusLogic/<N> interface.
o Shared Interrupts Support
@@ -168,16 +198,6 @@ o Shared Interrupts Support
On systems that support shared interrupts, any number of BusLogic Host
Adapters may share the same interrupt request channel.
-o Wide SCSI Support
-
- All BusLogic MultiMaster SCSI Host Adapters share a common programming
- interface, except for the inevitable improvements and extensions as new
- models are released, so support for Wide SCSI data transfer has automatically
- been available without explicit driver support. When used with Linux 2.0.x,
- this driver adds explicit support for up to 15 target devices and 64 logical
- units per target device, to fully exploit the capabilities of the newest
- BusLogic Wide SCSI Host Adapters.
-
SUPPORTED HOST ADAPTERS
@@ -188,16 +208,21 @@ that it is or will be supported.
FlashPoint Series PCI Host Adapters:
-FlashPoint LT (BT-930) Ultra SCSI-2
-FlashPoint DL (BT-932) Dual Channel Ultra SCSI-2
-FlashPoint LW (BT-950) Wide Ultra SCSI-2
-FlashPoint DW (BT-952) Dual Channel Wide Ultra SCSI-2
+FlashPoint LT (BT-930) Ultra SCSI-3
+FlashPoint LT (BT-930R) Ultra SCSI-3 with RAIDPlus
+FlashPoint LT (BT-920) Ultra SCSI-3 (BT-930 without BIOS)
+FlashPoint DL (BT-932) Dual Channel Ultra SCSI-3
+FlashPoint DL (BT-932R) Dual Channel Ultra SCSI-3 with RAIDPlus
+FlashPoint LW (BT-950) Wide Ultra SCSI-3
+FlashPoint LW (BT-950R) Wide Ultra SCSI-3 with RAIDPlus
+FlashPoint DW (BT-952) Dual Channel Wide Ultra SCSI-3
+FlashPoint DW (BT-952R) Dual Channel Wide Ultra SCSI-3 with RAIDPlus
MultiMaster "W" Series Host Adapters:
-BT-948 PCI Ultra SCSI-2
-BT-958 PCI Wide Ultra SCSI-2
-BT-958D PCI Wide Differential Ultra SCSI-2
+BT-948 PCI Ultra SCSI-3
+BT-958 PCI Wide Ultra SCSI-3
+BT-958D PCI Wide Differential Ultra SCSI-3
MultiMaster "C" Series Host Adapters:
@@ -231,6 +256,39 @@ BT-542B ISA SCSI-2 (542B revisions A - G)
AMI FastDisk Host Adapters that are true BusLogic MultiMaster clones are also
supported by this driver.
+BusLogic SCSI Host Adapters are available packaged both as bare boards and as
+retail kits. The BT- model numbers above refer to the bare board packaging.
+The retail kit model numbers are found by replacing BT- with KT- in the above
+list. The retail kit includes the bare board and manual as well as cabling and
+driver media and documentation that are not provided with bare boards.
+
+
+ FLASHPOINT INSTALLATION NOTES
+
+o RAIDPlus Support
+
+ FlashPoint Host Adapters now include RAIDPlus, Mylex's bootable software
+ RAID. RAIDPlus is not supported on Linux, and there are no plans to support
+ it. The MD driver in Linux 2.0 provides for concatenation (LINEAR) and
+ striping (RAID-0), and support for mirroring (RAID-1), fixed parity (RAID-4),
+ and distributed parity (RAID-5) is available separately. The built-in Linux
+ RAID support is generally more flexible and is expected to perform better
+ than RAIDPlus, so there is little impetus to include RAIDPlus support in the
+ BusLogic driver.
+
+o Enabling UltraSCSI Transfers
+
+ FlashPoint Host Adapters ship with their configuration set to "Factory
+ Default" settings that are conservative and do not allow for UltraSCSI speed
+ to be negotiated. This results in fewer problems when these host adapters
+ are installed in systems with cabling or termination that is not sufficient
+ for UltraSCSI operation, or where existing SCSI devices do not properly
+ respond to synchronous transfer negotiation for UltraSCSI speed. AutoSCSI
+ may be used to load "Optimum Performance" settings which allow UltraSCSI
+ speed to be negotiated with all devices, or UltraSCSI speed can be enabled on
+ an individual basis. It is recommended that SCAM be manually disabled after
+ the "Optimum Performance" settings are loaded.
+
BT-948/958/958D INSTALLATION NOTES
@@ -284,113 +342,254 @@ o PCI Slot Scanning Order
so as to recognize the host adapters in the same order as they are enumerated
by the host adapter's BIOS.
-o Mega-Transfers/Second
+o Enabling UltraSCSI Transfers
+
+ The BT-948/958/958D ship with their configuration set to "Factory Default"
+ settings that are conservative and do not allow for UltraSCSI speed to be
+ negotiated. This results in fewer problems when these host adapters are
+ installed in systems with cabling or termination that is not sufficient for
+ UltraSCSI operation, or where existing SCSI devices do not properly respond
+ to synchronous transfer negotiation for UltraSCSI speed. AutoSCSI may be
+ used to load "Optimum Performance" settings which allow UltraSCSI speed to be
+ negotiated with all devices, or UltraSCSI speed can be enabled on an
+ individual basis. It is recommended that SCAM be manually disabled after the
+ "Optimum Performance" settings are loaded.
+
+
+ DRIVER OPTIONS
+
+BusLogic Driver Options may be specified either via the Linux Kernel Command
+Line or via the Loadable Kernel Module Installation Facility. Driver Options
+for multiple host adapters may be specified either by separating the option
+strings by a semicolon, or by specifying multiple "BusLogic=" strings on the
+command line. Individual option specifications for a single host adapter are
+separated by commas. The Probing and Debugging Options apply to all host
+adapters whereas the remaining options apply individually only to the
+selected host adapter.
+
+The BusLogic Driver Probing Options comprise the following:
+
+IO:<integer>
+
+ The "IO:" option specifies an ISA I/O Address to be probed for a non-PCI
+ MultiMaster Host Adapter. If neither "IO:" nor "NoProbeISA" options are
+ specified, then the standard list of BusLogic MultiMaster ISA I/O Addresses
+ will be probed (0x330, 0x334, 0x230, 0x234, 0x130, and 0x134). Multiple
+ "IO:" options may be specified to precisely determine the I/O Addresses to
+ be probed, but the probe order will always follow the standard list.
+
+NoProbe
- The driver reports on the synchronous transfer parameters negotiated between
- the host adapter and target devices in units of "mega-transfers/second". For
- wide devices, the unit of transfer is 16 bits if wide negotiation has been
- successfully completed. Therefore, the total transfer rate to wide devices
- will generally be twice the synchronous tranfer rate reported by the driver.
+ The "NoProbe" option disables all probing and therefore no BusLogic Host
+ Adapters will be detected.
+NoProbeISA
- COMMAND LINE OPTIONS
+ The "NoProbeISA" option disables probing of the standard BusLogic ISA I/O
+ Addresses and therefore only PCI MultiMaster and FlashPoint Host Adapters
+ will be detected.
-Many features of this driver are configurable by specification of appropriate
-kernel command line options. A full description of the command line options
-may be found in the comments before BusLogic_Setup in the kernel source code
-file "BusLogic.c". The following examples may be useful as a starting point:
+NoProbePCI
- "BusLogic=NoProbe"
+ The "NoProbePCI" options disables the interrogation of PCI Configuration
+ Space and therefore only ISA Multimaster Host Adapters will be detected, as
+ well as PCI Multimaster Host Adapters that have their ISA Compatible I/O
+ Port set to "Primary" or "Alternate".
- No probing of any kind is to be performed, and hence no BusLogic Host
- Adapters will be detected.
+NoSortPCI
- "BusLogic=NoProbeISA"
+ The "NoSortPCI" option forces PCI MultiMaster Host Adapters to be
+ enumerated in the order provided by the PCI BIOS, ignoring any setting of
+ the AutoSCSI "Use Bus And Device # For PCI Scanning Seq." option.
- No probing of the standard ISA I/O Addresses will be done, and hence only
- PCI Host Adapters will be detected.
+MultiMasterFirst
- "BusLogic=NoProbePCI"
+ The "MultiMasterFirst" option forces MultiMaster Host Adapters to be probed
+ before FlashPoint Host Adapters. By default, if both FlashPoint and PCI
+ MultiMaster Host Adapters are present, this driver will probe for
+ FlashPoint Host Adapters first unless the BIOS primary disk is controlled
+ by the first PCI MultiMaster Host Adapter, in which case MultiMaster Host
+ Adapters will be probed first.
- No interrogation of PCI Configuration Space will be made, and hence only
- ISA Multimaster Host Adapters will be detected, as well as PCI Multimaster
- Host Adapters that have their ISA Compatible I/O Port set to "Primary" or
- "Alternate".
+FlashPointFirst
- "BusLogic=NoSortPCI"
+ The "FlashPointFirst" option forces FlashPoint Host Adapters to be probed
+ before MultiMaster Host Adapters.
- PCI MultiMaster Host Adapters will be enumerated in the order provided by
- the PCI BIOS, ignoring any setting of the AutoSCSI "Use Bus And Device #
- For PCI Scanning Seq." option.
+The BusLogic Driver Tagged Queuing Options allow for explicitly specifying
+the Queue Depth and whether Tagged Queuing is permitted for each Target
+Device (assuming that the Target Device supports Tagged Queuing). The Queue
+Depth is the number of SCSI Commands that are allowed to be concurrently
+presented for execution (either to the Host Adapter or Target Device). Note
+that explicitly enabling Tagged Queuing may lead to problems; the option to
+enable or disable Tagged Queuing is provided primarily to allow disabling
+Tagged Queuing on Target Devices that do not implement it correctly. The
+following options are available:
- "BusLogic=MultiMasterFirst"
+QueueDepth:<integer>
- By default, if both FlashPoint and PCI MultiMaster Host Adapters are
- present, this driver will probe for FlashPoint Host Adapters first unless
- the BIOS primary disk is controlled by the first PCI MultiMaster Host
- Adapter, in which case MultiMaster Host Adapters will be probed first.
- This option forces MultiMaster Host Adapters to be probed first.
+ The "QueueDepth:" or QD:" option specifies the Queue Depth to use for all
+ Target Devices that support Tagged Queuing. If no Queue Depth option is
+ provided, the Queue Depth will be determined automatically based on the
+ Host Adapter's Total Queue Depth and the number, type, speed, and
+ capabilities of the detected Target Devices. For Host Adapters that
+ require ISA Bounce Buffers, the Queue Depth is automatically set by default
+ to BusLogic_QueueDepthBounceBuffers to avoid excessive preallocation of DMA
+ Bounce Buffer memory. Target Devices that do not support Tagged Queuing
+ always use a Queue Depth of BusLogic_UntaggedQueueDepth.
- "BusLogic=FlashPointFirst"
+QueueDepth:[<integer>,<integer>...]
- By default, if both FlashPoint and PCI MultiMaster Host Adapters are
- present, this driver will probe for FlashPoint Host Adapters first unless
- the BIOS primary disk is controlled by the first PCI MultiMaster Host
- Adapter, in which case MultiMaster Host Adapters will be probed first.
- This option forces FlashPoint Host Adapters to be probed first.
+ The "QueueDepth:[...]" or "QD:[...]" option specifies the Queue Depth
+ individually for each Target Device. If an <integer> is omitted, the
+ associated Target Device will have its Queue Depth selected automatically.
- "BusLogic=0x330"
+TaggedQueuing:Default
- This command line limits probing to the single I/O port at 0x330.
+ The "TaggedQueuing:Default" or "TQ:Default" option permits Tagged Queuing
+ based on the firmware version of the BusLogic Host Adapter and based on
+ whether the Queue Depth allows queuing multiple commands.
- "BusLogic=0,1"
+TaggedQueuing:Enable
- This command line selects default probing and a tagged queue depth of 1
- which also disables tagged queuing. It may be useful if problems arise
- during installation on a system with a flaky SCSI configuration. In cases
- of a marginal SCSI configuration it may also be beneficial to disable fast
- transfers and/or synchronous negotiation using AutoSCSI on FlashPoint and
- "W" and "C" series MultiMaster host adapters. Disconnect/reconnect may
- also be disabled for fast devices such as disk drives, but should not be
- disabled for tape drives or other devices where a single command may take
- over a second to execute.
+ The "TaggedQueuing:Enable" or "TQ:Enable" option enables Tagged Queuing for
+ all Target Devices on this Host Adapter, overriding any limitation that
+ would otherwise be imposed based on the Host Adapter firmware version.
- "BusLogic=0,0,30"
+TaggedQueuing:Disable
- This command line selects default probing and automatic tagged queue depth
- selection, but changes the bus settle time to 30 seconds. It may be useful
- with SCSI devices that take an unusually long time to become ready to
- accept commands after a SCSI bus reset. Some tape drives will not respond
- properly immediately after a SCSI bus reset, especially if a tape is
- present in the drive.
+ The "TaggedQueuing:Disable" or "TQ:Disable" option disables Tagged Queuing
+ for all Target Devices on this Host Adapter.
- "BusLogic=TQ:Disable"
+TaggedQueuing:<Target-Spec>
- This command line selects default probing and disables tagged queuing.
+ The "TaggedQueuing:<Target-Spec>" or "TQ:<Target-Spec>" option controls
+ Tagged Queuing individually for each Target Device. <Target-Spec> is a
+ sequence of "Y", "N", and "X" characters. "Y" enables Tagged Queuing, "N"
+ disables Tagged Queuing, and "X" accepts the default based on the firmware
+ version. The first character refers to Target Device 0, the second to
+ Target Device 1, and so on; if the sequence of "Y", "N", and "X" characters
+ does not cover all the Target Devices, unspecified characters are assumed
+ to be "X".
- "BusLogic=0,15,TQ:N"
+The BusLogic Driver Error Recovery Option allows for explicitly specifying
+the Error Recovery action to be performed when BusLogic_ResetCommand is
+called due to a SCSI Command failing to complete successfully. The following
+options are available:
- This command line selects a tagged queue depth of 15 and disables tagged
- queuing for target 0, while allowing tagged queuing for all other target
- devices.
+ErrorRecovery:Default
-Note that limiting the tagged queue depth or disabling tagged queuing can
-substantially impact performance.
+ The "ErrorRecovery:Default" or "ER:Default" option selects between the Hard
+ Reset and Bus Device Reset options based on the recommendation of the SCSI
+ Subsystem.
+ErrorRecovery:HardReset
- INSTALLATION
+ The "ErrorRecovery:HardReset" or "ER:HardReset" option will initiate a Host
+ Adapter Hard Reset which also causes a SCSI Bus Reset.
-This distribution was prepared for Linux kernel version 2.0.30, but should be
-compatible with 2.0.4 or any later 2.0 series kernel if BusLogic.patch is also
-applied.
+ErrorRecovery:BusDeviceReset
+
+ The "ErrorRecovery:BusDeviceReset" or "ER:BusDeviceReset" option will send
+ a Bus Device Reset message to the individual Target Device causing the
+ error. If Error Recovery is again initiated for this Target Device and no
+ SCSI Command to this Target Device has completed successfully since the Bus
+ Device Reset message was sent, then a Hard Reset will be attempted.
+
+ErrorRecovery:None
+
+ The "ErrorRecovery:None" or "ER:None" option suppresses Error Recovery.
+ This option should only be selected if a SCSI Bus Reset or Bus Device Reset
+ will cause the Target Device or a critical operation to suffer a complete
+ and unrecoverable failure.
+
+ErrorRecovery:<Target-Spec>
+
+ The "ErrorRecovery:<Target-Spec>" or "ER:<Target-Spec>" option controls
+ Error Recovery individually for each Target Device. <Target-Spec> is a
+ sequence of "D", "H", "B", and "N" characters. "D" selects Default, "H"
+ selects Hard Reset, "B" selects Bus Device Reset, and "N" selects None.
+ The first character refers to Target Device 0, the second to Target Device
+ 1, and so on; if the sequence of "D", "H", "B", and "N" characters does not
+ cover all the possible Target Devices, unspecified characters are assumed
+ to be "D".
+
+The BusLogic Driver Miscellaneous Options comprise the following:
+
+BusSettleTime:<seconds>
+
+ The "BusSettleTime:" or "BST:" option specifies the Bus Settle Time in
+ seconds. The Bus Settle Time is the amount of time to wait between a Host
+ Adapter Hard Reset which initiates a SCSI Bus Reset and issuing any SCSI
+ Commands. If unspecified, it defaults to BusLogic_DefaultBusSettleTime.
+
+InhibitTargetInquiry
+
+ The "InhibitTargetInquiry" option inhibits the execution of an Inquire
+ Target Devices or Inquire Installed Devices command on MultiMaster Host
+ Adapters. This may be necessary with some older Target Devices that do not
+ respond correctly when Logical Units above 0 are addressed.
+
+The BusLogic Driver Debugging Options comprise the following:
+
+TraceProbe
+
+ The "TraceProbe" option enables tracing of Host Adapter Probing.
+
+TraceHardwareReset
+
+ The "TraceHardwareReset" option enables tracing of Host Adapter Hardware
+ Reset.
+
+TraceConfiguration
+
+ The "TraceConfiguration" option enables tracing of Host Adapter
+ Configuration.
+
+TraceErrors
+
+ The "TraceErrors" option enables tracing of SCSI Commands that return an
+ error from the Target Device. The CDB and Sense Data will be printed for
+ each SCSI Command that fails.
+
+Debug
+
+ The "Debug" option enables all debugging options.
+
+The following examples demonstrate setting the Queue Depth for Target Devices
+1 and 2 on the first host adapter to 7 and 15, the Queue Depth for all Target
+Devices on the second host adapter to 31, and the Bus Settle Time on the
+second host adapter to 30 seconds.
+
+Linux Kernel Command Line:
+
+ linux BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30
+
+LILO Linux Boot Loader (in /etc/lilo.conf):
+
+ append = "BusLogic=QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"
+
+INSMOD Loadable Kernel Module Installation Facility:
+
+ insmod BusLogic.o \
+ 'BusLogic_Options="QueueDepth:[,7,15];QueueDepth:31,BusSettleTime:30"'
+
+NOTE: Module Utilities 2.1.71 or later is required for correct parsing
+ of driver options containing commas.
+
+
+ DRIVER INSTALLATION
+
+This distribution was prepared for Linux kernel version 2.0.33, but should be
+compatible with 2.0.4 or any later 2.0 series kernel.
To install the new BusLogic SCSI driver, you may use the following commands,
replacing "/usr/src" with wherever you keep your Linux kernel source tree:
cd /usr/src
- tar -xvzf BusLogic-2.0.10.tar.gz
+ tar -xvzf BusLogic-2.0.11.tar.gz
mv README.* LICENSE.* BusLogic.[ch] FlashPoint.c linux/drivers/scsi
- patch -p < BusLogic.patch # Only for kernels prior to 2.0.30
+ patch -p < BusLogic.patch
cd linux
make config
make depend
@@ -399,11 +598,6 @@ replacing "/usr/src" with wherever you keep your Linux kernel source tree:
Then install "arch/i386/boot/zImage" as your standard kernel, run lilo if
appropriate, and reboot.
-Be sure to answer "y" to the "BusLogic SCSI support" query during the "make
-config" step. If your system was already configured for the old BusLogic
-driver or for an older version of this driver, you may omit the "make config"
-step above.
-
BUSLOGIC ANNOUNCEMENTS MAILING LIST
diff --git a/drivers/scsi/README.Mylex b/drivers/scsi/README.Mylex
new file mode 100644
index 000000000..a786fabc6
--- /dev/null
+++ b/drivers/scsi/README.Mylex
@@ -0,0 +1,6 @@
+Please see the file README.BusLogic for information about Linux support for
+Mylex (formerly BusLogic) MultiMaster and FlashPoint SCSI Host Adapters.
+
+The Mylex DAC960 PCI RAID Controllers are not supported at the present time,
+but work on a Linux driver for the DAC960 is in progress. Please consult
+http://www.dandelion.com/Linux/ for further information on the DAC960 driver.
diff --git a/drivers/scsi/README.ncr53c8xx b/drivers/scsi/README.ncr53c8xx
index ab12ed995..4b179a318 100644
--- a/drivers/scsi/README.ncr53c8xx
+++ b/drivers/scsi/README.ncr53c8xx
@@ -4,7 +4,7 @@ Written by Gerard Roudier <groudier@club-internet.fr>
21 Rue Carnot
95170 DEUIL LA BARRE - FRANCE
-23 August 1997
+2 January 1998
===============================================================================
1. Introduction
@@ -30,6 +30,7 @@ Written by Gerard Roudier <groudier@club-internet.fr>
10.3 Advised boot setup commands
10.4 PCI configuration fix-up boot option
10.5 Serial NVRAM support boot option
+ 10.6 SCSI BUS checking boot option
11. Some constants and flags of the ncr53c8xx.h header file
12. Installation
12.1 Provided files
@@ -38,6 +39,8 @@ Written by Gerard Roudier <groudier@club-internet.fr>
14. Known problems
14.1 Tagged commands with Iomega Jaz device
14.2 Device names change when another controller is added
+ 14.3 Using only 8 bit devices with a WIDE SCSI controller.
+ 14.4 Possible data corruption during a Memory Write and Invalidate
15. SCSI problem troubleshooting
16. Synchonous transfer negotiation tables
16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers
@@ -490,7 +493,9 @@ CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT
10.1 Syntax
-Setup commands can be passed to the driver at boot time.
+Setup commands can be passed to the driver either at boot time or as a
+string variable using 'insmod'.
+
A boot setup command for the ncr53c8xx driver begins with the driver name
"ncr53c8xx=". The kernel syntax parser then expects an optionnal list of
integers separated with comma followed by an optionnal list of comma-
@@ -502,7 +507,14 @@ lilo: linux root=/dev/hda2 ncr53c8xx=tags:4,sync:10,debug:0x200
- set synchronous negotiation speed to 10 Mega-transfers / second.
- set DEBUG_NEGO flag.
-For the moment, the integer list of arguments is disgarded by the driver.
+Since comma seems not to be allowed when defining a string variable using
+'insmod', the driver also accepts <space> as option separator.
+The following command will install driver module with the same options as
+above.
+
+insmod ncr53c8xx.o ncr53c8xx="tags:4 sync:10 debug:0x200"
+
+For the moment, the integer list of arguments is discarded by the driver.
It will be used in the future in order to allow a per controller setup.
Each string argument must be specified as "keyword:value". Only lower-case
@@ -525,8 +537,12 @@ Scsi disconnections
Special features
Only apply to 810A, 825A, 860 and 875 controllers.
Have no effect with normal 810 and 825.
- specf:y enabled
- specf:n disabled
+ specf:y (or 1) enabled
+ specf:n (or 0) disabled
+ specf:3 enabled except Memory Write And Invalidate
+ The default driver setup is 'specf:3'. As a consequence, option 'specf:y'
+ must be specified in the boot setup command to enable Memory Write And
+ Invalidate.
Ultra SCSI support
Only apply to 860 and 875 controllers.
@@ -628,6 +644,7 @@ Fix up PCI configuration space
pcifix:<option bits>
Available option bits:
+ 0x0: No attempt to fix PCI configuration space registers values.
0x1: Set PCI cache-line size register if not set.
0x2: Set write and invalidate bit in PCI command register.
0x4: Increase if necessary PCI latency timer according to burst max.
@@ -638,6 +655,14 @@ Serial NVRAM
nvram:n do not look for serial NVRAM
nvram:y test controllers for onboard serial NVRAM
+Check SCSI BUS
+ buschk:<option bits>
+
+ Available option bits:
+ 0x0: No check.
+ 0x1: Check and donnot attach the controller on error.
+ 0x2: Check and just warn on error.
+
Boot fail safe
safe:y load the following assumed fail safe initial setup
@@ -660,13 +685,14 @@ Boot fail safe
settle time 10 seconds settle:10
differential support from BIOS settings diff:1
irq mode from BIOS settings irqm:1
+ SCSI BUS check donnot attach on error buschk:1
10.3 Advised boot setup commands
If the driver has been configured with default options, the equivalent
boot setup is:
- ncr53c8xx=mpar:y,spar:y,disc:y,specf:y,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\
+ ncr53c8xx=mpar:y,spar:y,disc:y,specf:3,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\
tags:0,sync:50,debug:0,burst:7,led:0,wide:1,settle:2,diff:0,irqm:0
For an installation diskette or a safe but not fast system,
@@ -679,7 +705,7 @@ boot setup can be:
My personnal system works flawlessly with the following equivalent setup:
- ncr53c8xx=mpar:y,spar:y,disc:y,specf:y,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\
+ ncr53c8xx=mpar:y,spar:y,disc:y,specf:1,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\
tags:8,sync:12,debug:0,burst:7,led:1,wide:1,settle:2,diff:0,irqm:0
The driver prints its actual setup when verbosity level is 2. You can try
@@ -765,6 +791,21 @@ Using "nvram=0x7" allows me to boot in 8 bits/async and to let the driver
use its setup for synchronous and wide negotiations.
+10.6 SCSI BUS checking boot option.
+
+When this option is set to a non-zero value, the driver checks SCSI lines
+logic state, 100 micro-seconds after having asserted the SCSI RESET line.
+The driver just reads SCSI lines and checks all lines read FALSE except RESET.
+Since SCSI devices shall release the BUS at most 800 nano-seconds after SCSI
+RESET has been asserted, any signal to TRUE may indicate a SCSI BUS problem.
+Unfortunately, the following common SCSI BUS problems are not detected:
+- Only 1 terminator installed.
+- Misplaced terminators.
+- Bad quality terminators.
+On the other hand, either bad cabling, broken devices, not conformant
+devices, ... may cause a SCSI signal to be wrong when te driver reads it.
+
+
11. Some constants and flags of the ncr53c8xx.h header file
Some of these are defined from the configuration parameters. To
@@ -900,7 +941,7 @@ applies a patch to some files of the kernel tree.
Change to linux source directory
Configure with NCR53C7,8XX support = N
Configure with NCR53C8XX support = Y (or m)
- Make dependancies
+ Make dependencies
Make the kernel (use make zdisk first)
Make and install modules if you have configured with 'm'
@@ -952,6 +993,50 @@ If your controllers do not have NvRAM, you can:
- Make appropriate changes in the fstab.
- Use the 'scsidev' tool from Eric Youngdale.
+14.3 Using only 8 bit devices with a WIDE SCSI controller.
+
+When only 8 bit NARROW devices are connected to a 16 bit WIDE SCSI controller,
+you must ensure that lines of the wide part of the SCSI BUS are pulled-up.
+This can be achieved by ENABLING the WIDE TERMINATOR portion of the SCSI
+controller card.
+The TYAN 1365 documentation revision 1.2 is not correct about such settings.
+(page 10, figure 3.3).
+
+14.4 Possible data corruption during a Memory Write and Invalidate
+
+This problem is described in SYMBIOS DEL 397, Part Number 69-039241, ITEM 4.
+
+In some complex situations, 53C875 chips revision <= 3 may start a PCI
+Write and Invalidate Command at a not cache-line-aligned 4 DWORDS boundary.
+This is only possible when Cache Line Size is 8 DWORDS or greater.
+Pentium systems use a 8 DWORDS cache line size and so are concerned by
+this chip bug, unlike i486 systems that use a 4 DWORDS cache line size.
+
+When this situation occurs, the chip may complete the Write and Invalidate
+command after having only filled part of the last cache line involved in
+the transfer, leaving to data corruption the remainder of this cache line.
+
+Not using Write And Invalidate obviously gets rid of this chip bug, and so
+it is now the default setting of the driver.
+However, for people like me who want to enable this feature, I have added
+part of a work-around suggested by SYMBIOS. This work-around resets the
+addressing logic when the DATA IN phase is entered and so prevents the bug
+from being triggered for the first SCSI MOVE of the phase. This work-around
+should be enough according to the following:
+
+The only driver internal data structure that is greater than 8 DWORDS and
+that is moved by the SCRIPTS processor is the 'CCB header' that contains
+the context of the SCSI transfer. This data structure is aligned on 8 DWORDS
+boundary (Pentium Cache Line Size), and so is immune to this chip bug, at
+least on Pentium systems.
+But the conditions of this bug can be met when a SCSI read command is
+performed using a buffer that is 4 DWORDS but not cache-line aligned.
+This cannot happen under Linux when scatter/gather lists are used since
+they only refer to system buffers that are well aligned. So, a work around
+may only be needed under Linux when a scatter/gather list is not used and
+when the SCSI DATA IN phase is reentered after a phase mismatch.
+
+
15. SCSI problem troubleshooting
Most SCSI problems are due to a non conformant SCSI bus or to buggy
@@ -1216,8 +1301,14 @@ header
controller set up
00 30 00 00 00 00 07 00 00 00 00 00 00 00 07 04 10 04 00 00
- | | |
- | | -- host ID
+ | | | |
+ | | | -- host ID
+ | | |
+ | | --Removable Media Support
+ | | 0x00 = none
+ | | 0x01 = Bootable Device
+ | | 0x02 = All with Media
+ | |
| --flag bits 2
| 0x00000001= scan order hi->low
| (default 0x00 - scan low->hi)
@@ -1230,6 +1321,7 @@ remaining bytes unknown - they do not appear to change in my
current set up for any of the controllers.
default set up is identical for 53c810a and 53c875 NVRAM
+(Removable Media added Symbios BIOS version 4.09)
-----------------------------------------------------------
boot configuration
diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h
index 268908358..b04ef6c25 100644
--- a/drivers/scsi/a2091.h
+++ b/drivers/scsi/a2091.h
@@ -33,27 +33,18 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
extern struct proc_dir_entry proc_scsi_a2091;
-#define A2091_SCSI { /* next */ NULL, \
- /* module */ NULL, \
- /* proc_dir_entry */ &proc_scsi_a2091, \
- /* proc_info */ NULL, \
- /* name */ "Commodore A2091/A590 SCSI", \
- /* detect */ a2091_detect, \
- /* release */ a2091_release, \
- /* info */ NULL, \
- /* command */ NULL, \
- /* queuecommand */ wd33c93_queuecommand, \
- /* abort */ wd33c93_abort, \
- /* reset */ wd33c93_reset, \
- /* slave_attach */ NULL, \
- /* bios_param */ NULL, \
- /* can_queue */ CAN_QUEUE, \
- /* this_id */ 7, \
- /* sg_tablesize */ SG_ALL, \
- /* cmd_per_lun */ CMD_PER_LUN, \
- /* present */ 0, \
- /* unchecked_isa_dma */ 0, \
- /* use_clustering */ DISABLE_CLUSTERING }
+#define A2091_SCSI { proc_dir: &proc_scsi_a2091, \
+ name: "Commodore A2091/A590 SCSI", \
+ detect: a2091_detect, \
+ release: a2091_release, \
+ queuecommand: wd33c93_queuecommand, \
+ abort: wd33c93_abort, \
+ reset: wd33c93_reset, \
+ can_queue: CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: CMD_PER_LUN, \
+ use_clustering: DISABLE_CLUSTERING }
#else
/*
diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h
index 1b13557b9..c088f1d98 100644
--- a/drivers/scsi/a3000.h
+++ b/drivers/scsi/a3000.h
@@ -33,27 +33,19 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
extern struct proc_dir_entry proc_scsi_a3000;
-#define A3000_SCSI { /* next */ NULL, \
- /* module */ NULL, \
- /* proc_dir_entry */ &proc_scsi_a3000, \
- /* proc_info */ NULL, \
- /* name */ "Amiga 3000 built-in SCSI", \
- /* detect */ a3000_detect, \
- /* release */ a3000_release, \
- /* info */ NULL, \
- /* command */ NULL, \
- /* queuecommand */ wd33c93_queuecommand, \
- /* abort */ wd33c93_abort, \
- /* reset */ wd33c93_reset, \
- /* slave_attach */ NULL, \
- /* bios_param */ NULL, \
- /* can_queue */ CAN_QUEUE, \
- /* this_id */ 7, \
- /* sg_tablesize */ SG_ALL, \
- /* cmd_per_lun */ CMD_PER_LUN, \
- /* present */ 0, \
- /* unchecked_isa_dma */ 0, \
- /* use_clustering */ ENABLE_CLUSTERING }
+#define A3000_SCSI { proc_dir: &proc_scsi_a3000, \
+ proc_info: NULL, \
+ name: "Amiga 3000 built-in SCSI", \
+ detect: a3000_detect, \
+ release: a3000_release, \
+ queuecommand: wd33c93_queuecommand, \
+ abort: wd33c93_abort, \
+ reset: wd33c93_reset, \
+ can_queue: CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: CMD_PER_LUN, \
+ use_clustering: ENABLE_CLUSTERING }
#else
/*
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 737793e29..315de3935 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -1,10 +1,10 @@
-/* $Id: advansys.c,v 1997/05/28 00:06:55 bobf Exp bobf $ */
-#define ASC_VERSION "2.8" /* AdvanSys Driver Version */
+/* $Id: advansys.c,v 1.49 1998/01/22 20:19:25 bobf Exp bobf $ */
+#define ASC_VERSION "3.1D" /* AdvanSys Driver Version */
/*
* advansys.c - Linux Host Driver for AdvanSys SCSI Adapters
*
- * Copyright (c) 1995-1997 Advanced System Products, Inc.
+ * Copyright (c) 1995-1998 Advanced System Products, Inc.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -16,13 +16,12 @@
* http://www.advansys.com/linux.html
*
* The latest version of the AdvanSys driver is available at:
- * ftp://ftp.advansys.com/pub/linux
+ * ftp://ftp.advansys.com/pub/linux/linux.tgz
*
* Please send questions, comments, bug reports to:
- * bobf@advansys.com (Bob Frey)
+ * bobf@advansys.com (Bob Frey)
*/
-
/*
Documentation for the AdvanSys Driver
@@ -43,7 +42,7 @@
A. Linux Kernel Testing
This driver has been tested in the following Linux kernels: v1.2.13,
- v1.3.57, v2.0.30, v2.1.40. These kernel versions are major releases
+ v1.3.57, v2.0.33, v2.1.77. These kernel versions are major releases
of Linux or the latest Linux kernel versions available when this version
of the driver was released. The driver should also work in earlier
versions of the Linux kernel. Beginning with v1.3.58 the AdvanSys driver
@@ -53,8 +52,10 @@
B. Adapters Supported by this Driver
AdvanSys (Advanced System Products, Inc.) manufactures the following
- Bus-Mastering SCSI-2 Host Adapters for the ISA, EISA, VL, and PCI
- buses. This Linux driver supports all of these adapters.
+ RISC-based, Bus-Mastering, Fast (10 Mhz) and Ultra (20 Mhz) Narrow
+ (8-bit transfer) SCSI Host Adapters for the ISA, EISA, VL, and PCI
+ buses and RISC-based, Bus-Mastering, Ultra (20 Mhz) Wide (16-bit
+ transfer) SCSI Host Adapters for the PCI bus.
The CDB counts below indicate the number of SCSI CDB (Command
Descriptor Block) requests that can be stored in the RISC chip
@@ -72,7 +73,7 @@
ABP930U - Bus-Master PCI Ultra (16 CDB)
ABP930UA - Bus-Master PCI Ultra (16 CDB)
ABP960 - Bus-Master PCI MAC/PC (16 CDB) (Footnote 2)
- ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB)
+ ABP960U - Bus-Master PCI MAC/PC Ultra (16 CDB) (Footnote 2)
Single Channel Products:
ABP542 - Bus-Master ISA with floppy (240 CDB)
@@ -82,11 +83,14 @@
ABP940U - Bus-Master PCI Ultra (240 CDB)
ABP970 - Bus-Master PCI MAC/PC (240 CDB)
ABP970U - Bus-Master PCI MAC/PC Ultra (240 CDB)
+ ABP940UW - Bus-Master PCI Ultra-Wide (240 CDB)
- Dual Channel Products:
+ Multi Channel Products:
ABP752 - Dual Channel Bus-Master EISA (240 CDB Per Channel)
ABP852 - Dual Channel Bus-Master VL (240 CDB Per Channel)
ABP950 - Dual Channel Bus-Master PCI (240 CDB Per Channel)
+ ABP980 - Four Channel Bus-Master PCI (240 CDB Per Channel)
+ ABP980U - Four Channel Bus-Master PCI Ultra (240 CDB Per Channel)
Footnotes:
1. This board has been shipped by HP with the 4020i CD-R drive.
@@ -264,6 +268,7 @@
--- Driver Options
--- Debugging Header
--- Asc Library Constants and Macros
+ --- Adv Library Constants and Macros
--- Driver Constants and Macros
--- Driver Structures
--- Driver Data
@@ -272,20 +277,24 @@
--- Loadable Driver Support
--- Miscellaneous Driver Functions
--- Functions Required by the Asc Library
+ --- Functions Required by the Adv Library
--- Tracing and Debugging Functions
--- Asc Library Functions
+ --- Adv Library Functions
3. The string 'XXX' is used to flag code that needs to be re-written
or that contains a problem that needs to be addressed.
4. I have stripped comments from and reformatted the source for the
- Asc Library which is included in this file. I haven't done this
- to obfuscate the code. Actually I have done this to deobfuscate
- the code. The Asc Library source can be found under the following
- headings.
+ Asc Library and Adv Library to reduce the size of this file. This
+ source can be found under the following headings. The Asc Library
+ is used to support Narrow Boards. The Adv Library is used to
+ support Wide Boards.
--- Asc Library Constants and Macros
+ --- Adv Library Constants and Macros
--- Asc Library Functions
+ --- Adv Library Functions
G. Driver Compile Time Options and Debugging
@@ -308,7 +317,7 @@
Enabling this option adds tracing functions to the driver and
the ability to set a driver tracing level at boot time. This
- option will also symbols not required outside the driver to
+ option will also export symbols not required outside the driver to
the kernel name space. This option is very useful for debugging
the driver, but it will add to the size of the driver execution
image and add overhead to the execution of the driver.
@@ -319,7 +328,7 @@
If the driver is loaded at boot time and the LILO Driver Option
is included in the system, the debug level can be changed by
- specifying a 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port. The
+ specifying a 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port. The
first three hex digits of the pseudo I/O Port must be set to
'deb' and the fourth hex digit specifies the debug level: 0 - F.
The following command line will look for an adapter at 0x330
@@ -350,11 +359,6 @@
I found that increasing LOG_BUF_LEN to 40960 in kernel/printk.c
prevents most level 1 debug messages from being lost.
- this constant for debugging purposes, but for normal use of
- the driver the constant should not be defined. This option
- does not add overhead to the driver, but it does add unnecessary
- symbols to the kernel name space.
-
3. ADVANSYS_STATS - Enable statistics (Def: Enabled >= v1.3.0)
Enabling this option adds statistics collection and display
@@ -379,7 +383,6 @@
When ADVANSYS_STATS is not defined the AdvanSys /proc files only
contain adapter and device configuration information.
-
H. Driver LILO Option
If init/main.c is modified as described in the 'Directions for Adding
@@ -406,7 +409,7 @@
insmod advansys.o asc_iopflag=1 asc_ioport=0x110,0x330
- If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_BOARD_SUPPORTED + 1)
+ If ADVANSYS_DEBUG is defined a 5th (ASC_NUM_IOPORT_PROBE + 1)
I/O Port may be added to specify the driver debug level. Refer to
the 'Driver Compile Time Options and Debugging' section above for
more information.
@@ -505,7 +508,7 @@
repeat busy or QUEUE FULL status returned by a device.
2. Incorporate miscellaneous Asc Library bug fixes.
3. To allow the driver to work in kernels with broken module
- support set 'cmd_per_lun' if the driver is compile as a
+ support set 'cmd_per_lun' if the driver is compiled as a
module. This change affects kernels v1.3.89 to present.
4. Remove PCI BIOS address from the driver banner. The PCI BIOS
is relocated by the motherboard BIOS and its new address can
@@ -541,13 +544,42 @@
option is enabled by default.
2.8 (5/26/97):
- 1. Change version number to 2.8, skipping 2.3 through 2.7, in
- order to synchronize the Linux driver version numbering with
- other AdvanSys drivers.
- 2. Reformat source files without tabs to give everyone everyone
- the same view of the file regardless of the tab setting used.
+ 1. Change version number to 2.8 to synchronize the Linux driver
+ version numbering with other AdvanSys drivers.
+ 2. Reformat source files without tabs to present the same view
+ of the file to everyone regardless of the editor tab setting
+ being used.
3. Add Asc Library bug fixes.
+ 3.1A (1/8/98):
+ 1. Change version number to 3.1 to indicate that support for
+ Ultra-Wide adapters (ABP-940UW) is included in this release.
+ 2. Add Asc Library (Narrow Board) bug fixes.
+ 3. Report an underrun condition with the host status byte set
+ to DID_UNDERRUN. Currently DID_UNDERRUN is defined to 0 which
+ causes the underrun condition to be ignored. When Linux defines
+ its own DID_UNDERRUN the constant defined in this file can be
+ removed.
+ 4. Add patch to AscWaitTixISRDone().
+ 5. Add support for up to 16 different AdvanSys host adapter SCSI
+ channels in one system. This allows four cards with four channels
+ to be used in one system.
+
+ 3.1B (1/9/98):
+ 1. Handle that PCI register base addresses are not always page
+ aligned even though ioremap() requires that the address argument
+ be page aligned.
+
+ 3.1C (1/10/98):
+ 1. Update latest BIOS version to 3.1E.
+ 2. Don't set microcode SDTR variable at initialization. Instead
+ wait until device capabilities have been detected from an Inquiry
+ command.
+
+ 3.1D (1/21/98):
+ 1. Improve performance when the driver is compiled as module by
+ allowing up to 64 scatter-gather elements instead of 8.
+
J. Known Problems or Issues
1. Remove conditional constants (ASC_QUEUE_FLOW_CONTROL) around
@@ -563,8 +595,15 @@
Thomas E Zerucha <zerucha@shell.portal.com> pointed out a bug
in advansys_biosparam() which was fixed in the 1.3 release.
- Erik Ratcliffe <erik@caldera.com> has done a lot of testing of
- the AdvanSys driver in the Caldera releases.
+ Erik Ratcliffe <erik@caldera.com> has done testing of the
+ AdvanSys driver in the Caldera releases.
+
+ Rik van Riel <H.H.vanRiel@fys.ruu.nl> provided a patch to
+ AscWaitTixISRDone() which he found necessary to make the
+ driver work with a SCSI-1 disk.
+
+ Mark Moran <mmoran@mmoran.com> has helped test Ultra-Wide
+ support in the 3.1A driver.
L. AdvanSys Contact Information
@@ -576,7 +615,7 @@
Tech Support: 1-800-525-7440/1-408-467-2930
BBS: 1-408-383-9540 (14400,N,8,1)
Interactive FAX: 1-408-383-9753
- Customer Direct Sales: 1-800-883-1099/1-408-383-5777
+ Customer Direct Sales: 1-800-525-7443/1-408-383-5777
Tech Support E-Mail: support@advansys.com
FTP Site: ftp.advansys.com (login: anonymous)
Web Site: http://www.advansys.com
@@ -613,6 +652,7 @@
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/malloc.h>
+#include <linux/mm.h>
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
#include <linux/proc_fs.h>
#endif /* version >= v1.3.0 */
@@ -633,6 +673,15 @@
#include "sd.h"
#include "advansys.h"
+#include <linux/bios32.h>
+
+/*
+ * If Linux eventually defines a DID_UNDERRUN, the constant here can be
+ * removed. The current value of zero for DID_UNDERRUN results in underrun
+ * conditions being ignored.
+ */
+#define DID_UNDERRUN 0
+
/*
* --- Driver Options
@@ -646,7 +695,7 @@
/*
* Because of no /proc to display them, statistics are disabled
- * for version prior to v1.3.0.
+ * for versions prior to v1.3.0.
*/
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
#undef ADVANSYS_STATS /* Disable statistics */
@@ -672,7 +721,7 @@
#define ASC_LIB_VERSION_MAJOR 1
#define ASC_LIB_VERSION_MINOR 22
-#define ASC_LIB_SERIAL_NUMBER 105
+#define ASC_LIB_SERIAL_NUMBER 111
typedef unsigned char uchar;
@@ -769,27 +818,6 @@ typedef unsigned char uchar;
#define ASC_MAX_SG_QUEUE 7
#define ASC_MAX_SG_LIST SG_ALL
-#define CC_CLEAR_LRAM_SRB_PTR FALSE
-#define CC_VERIFY_LRAM_COPY FALSE
-#define CC_DEBUG_SG_LIST FALSE
-#define CC_FAST_STRING_IO FALSE
-#define CC_WRITE_IO_COUNT FALSE
-#define CC_CLEAR_DMA_REMAIN FALSE
-#define CC_DISABLE_PCI_PARITY_INT TRUE
-#define CC_LITTLE_ENDIAN_HOST TRUE
-#define CC_STRUCT_ALIGNED TRUE
-#define CC_MEMORY_MAPPED_IO FALSE
-#define CC_INCLUDE_EEP_CONFIG TRUE
-#define CC_PCI_ULTRA TRUE
-#define CC_ASC_SCSI_Q_USRDEF FALSE
-#define CC_ASC_SCSI_REQ_Q_USRDEF FALSE
-#define CC_ASCISR_CHECK_INT_PENDING TRUE
-#define CC_CHK_FIX_EEP_CONTENT TRUE
-#define CC_INCLUDE_EEP_CONFIG TRUE
-#define CC_PLEXTOR_VL FALSE
-#define CC_TMP_USE_EEP_SDTR FALSE
-#define CC_CHK_COND_REDO_SDTR TRUE
-
#define ASC_CS_TYPE unsigned short
#ifndef asc_ptr_type
#define asc_ptr_type
@@ -840,27 +868,6 @@ typedef unsigned char uchar;
#define ASC_MAX_ISA_DMA_COUNT (0x00FFFFFFL)
#define ASC_MAX_EISA_DMA_ADDR (0x07FFFFFFL)
#define ASC_MAX_EISA_DMA_COUNT (0x07FFFFFFL)
-#if !CC_STRUCT_ALIGNED
-#define DvcGetQinfo(iop_base, s_addr, outbuf, words) \
-AscMemWordCopyFromLram(iop_base, s_addr, outbuf, words)
-#define DvcPutScsiQ(iop_base, s_addr, outbuf, words) \
-AscMemWordCopyToLram(iop_base, s_addr, outbuf, words)
-#endif
-#ifdef ASC_CHIP_VERSION
-#endif
-#if CC_MEMORY_MAPPED_IO
-#define inp(port) *((uchar *)(port))
-#define outp(port, data) *((uchar *)(port)) = (uchar)(data)
-#if CC_LITTLE_ENDIAN_HOST
-#define inpw(port) *((ushort *)(port))
-#define outpw(port, data) *((ushort *)(port)) = (ushort)(data)
-#else
-#define inpw(port) EndianSwap16Bit((*((ushort *)(port))))
-#define outpw(port, data) *((ushort *)(port)) = EndianSwap16Bit((ushort)(data))
-#define inpw_noswap(port) *((ushort *)(port))
-#define outpw_noswap(port, data) *((ushort *)(port)) = (ushort)(data)
-#endif
-#endif
#ifndef inpw_noswap
#define inpw_noswap(port) inpw(port)
#endif
@@ -901,6 +908,7 @@ AscMemWordCopyToLram(iop_base, s_addr, outbuf, words)
#define ASC_MAX_SENSE_LEN 32
#define ASC_MIN_SENSE_LEN 14
#define ASC_MAX_CDB_LEN 12
+#define ASC_SCSI_RESET_HOLD_TIME_US 60
#define SCSICMD_TestUnitReady 0x00
#define SCSICMD_Rewind 0x01
#define SCSICMD_Rezero 0x01
@@ -963,6 +971,7 @@ AscMemWordCopyToLram(iop_base, s_addr, outbuf, words)
#define SCSI_SENKEY_VOL_OVERFLOW 0x0D
#define SCSI_SENKEY_MISCOMP 0x0E
#define SCSI_SENKEY_RESERVED 0x0F
+#define SCSI_ASC_NOMEDIA 0x3A
#define ASC_SRB_HOST(x) ((uchar)((uchar)(x) >> 4))
#define ASC_SRB_TID(x) ((uchar)((uchar)(x) & (uchar)0x0F))
#define ASC_SRB_LUN(x) ((uchar)((uint)(x) >> 13))
@@ -1005,48 +1014,22 @@ AscMemWordCopyToLram(iop_base, s_addr, outbuf, words)
#define M2_QTAG_MSG_ORDERED 0x22
#define M2_IGNORE_WIDE_RESIDUE 0x23
-#if CC_LITTLE_ENDIAN_HOST
typedef struct {
uchar peri_dvc_type:5;
uchar peri_qualifier:3;
} ASC_SCSI_INQ0;
-#else
-typedef struct {
- uchar peri_qualifier:3;
- uchar peri_dvc_type:5;
-} ASC_SCSI_INQ0;
-
-#endif
-#if CC_LITTLE_ENDIAN_HOST
typedef struct {
uchar dvc_type_modifier:7;
uchar rmb:1;
} ASC_SCSI_INQ1;
-#else
-typedef struct {
- uchar rmb:1;
- uchar dvc_type_modifier:7;
-} ASC_SCSI_INQ1;
-
-#endif
-#if CC_LITTLE_ENDIAN_HOST
typedef struct {
uchar ansi_apr_ver:3;
uchar ecma_ver:3;
uchar iso_ver:2;
} ASC_SCSI_INQ2;
-#else
-typedef struct {
- uchar iso_ver:2;
- uchar ecma_ver:3;
- uchar ansi_apr_ver:3;
-} ASC_SCSI_INQ2;
-
-#endif
-#if CC_LITTLE_ENDIAN_HOST
typedef struct {
uchar rsp_data_fmt:4;
uchar res:2;
@@ -1054,16 +1037,6 @@ typedef struct {
uchar aenc:1;
} ASC_SCSI_INQ3;
-#else
-typedef struct {
- uchar aenc:1;
- uchar TemIOP:1;
- uchar res:2;
- uchar rsp_data_fmt:4;
-} ASC_SCSI_INQ3;
-
-#endif
-#if CC_LITTLE_ENDIAN_HOST
typedef struct {
uchar StfRe:1;
uchar CmdQue:1;
@@ -1075,19 +1048,6 @@ typedef struct {
uchar RelAdr:1;
} ASC_SCSI_INQ7;
-#else
-typedef struct {
- uchar RelAdr:1;
- uchar WBus32:1;
- uchar WBus16:1;
- uchar Sync:1;
- uchar Linked:1;
- uchar Reserved:1;
- uchar CmdQue:1;
- uchar StfRe:1;
-} ASC_SCSI_INQ7;
-
-#endif
typedef struct {
ASC_SCSI_INQ0 byte0;
ASC_SCSI_INQ1 byte1;
@@ -1102,7 +1062,6 @@ typedef struct {
uchar product_rev_level[4];
} ASC_SCSI_INQUIRY;
-#if CC_LITTLE_ENDIAN_HOST
typedef struct asc_req_sense {
uchar err_code:7;
uchar info_valid:1;
@@ -1126,31 +1085,6 @@ typedef struct asc_req_sense {
uchar info2[4];
} ASC_REQ_SENSE;
-#else
-typedef struct asc_req_sense {
- uchar info_valid:1;
- uchar err_code:7;
- uchar segment_no;
- uchar file_mark:1;
- uchar sense_EOM:1;
- uchar sense_ILI:1;
- uchar reserved_bit:1;
- uchar sense_key:4;
- uchar info1[4];
- uchar add_sense_len;
- uchar cmd_sp_info[4];
- uchar asc;
- uchar ascq;
- uchar fruc;
- uchar sks_valid:1;
- uchar sks_byte0:7;
- uchar sks_bytes[2];
- uchar notused[2];
- uchar ex_sense_code;
- uchar info2[4];
-} ASC_REQ_SENSE;
-
-#endif
#define ASC_SG_LIST_PER_Q 7
#define QS_FREE 0x00
#define QS_READY 0x01
@@ -1348,9 +1282,6 @@ typedef struct asc_scsi_q {
ASC_SCSIQ_2 q2;
uchar *cdbptr;
ASC_SG_HEAD *sg_head;
-#if CC_ASC_SCSI_Q_USRDEF
- ASC_SCSI_Q_USR usr;
-#endif
} ASC_SCSI_Q;
typedef struct asc_scsi_req_q {
@@ -1362,9 +1293,6 @@ typedef struct asc_scsi_req_q {
ASC_SCSIQ_3 r3;
uchar cdb[ASC_MAX_CDB_LEN];
uchar sense[ASC_MIN_SENSE_LEN];
-#if CC_ASC_SCSI_REQ_Q_USRDEF
- ASC_SCSI_REQ_Q_USR usr;
-#endif
} ASC_SCSI_REQ_Q;
typedef struct asc_scsi_bios_req_q {
@@ -1569,9 +1497,10 @@ typedef struct asc_dvc_cfg {
ushort mcode_date;
ushort mcode_version;
uchar max_tag_qng[ASC_MAX_TID + 1];
- uchar *overrun_buf;
+ uchar *overrun_buf;
uchar sdtr_period_offset[ASC_MAX_TID + 1];
ushort pci_slot_info;
+ uchar adapter_info[6];
} ASC_DVC_CFG;
#define ASC_DEF_DVC_CNTL 0xFFFF
@@ -1856,7 +1785,7 @@ typedef struct asceep_config {
#define ASC_CFG0_SCSI_PARITY_ON 0x0800
#define ASC_CFG1_SCSI_TARGET_ON 0x0080
#define ASC_CFG1_LRAM_8BITS_ON 0x0800
-#define ASC_CFG_MSW_CLR_MASK 0x30C0
+#define ASC_CFG_MSW_CLR_MASK 0x3080
#define CSW_TEST1 (ASC_CS_TYPE)0x8000
#define CSW_AUTO_CONFIG (ASC_CS_TYPE)0x4000
#define CSW_RESERVED1 (ASC_CS_TYPE)0x2000
@@ -2000,7 +1929,7 @@ STATIC void AscAckInterrupt(PortAddr);
STATIC void AscDisableInterrupt(PortAddr);
STATIC void AscEnableInterrupt(PortAddr);
STATIC void AscSetBank(PortAddr, uchar);
-STATIC int AscResetChipAndScsiBus(PortAddr);
+STATIC int AscResetChipAndScsiBus(ASC_DVC_VAR *);
STATIC ushort AscGetIsaDmaChannel(PortAddr);
STATIC ushort AscSetIsaDmaChannel(PortAddr, ushort);
STATIC uchar AscSetIsaDmaSpeed(PortAddr, uchar);
@@ -2143,10 +2072,1120 @@ STATIC ulong AscGetMaxDmaCount(ushort);
/*
+ * --- Adv Library Constants and Macros
+ */
+
+#define ADV_LIB_VERSION_MAJOR 3
+#define ADV_LIB_VERSION_MINOR 34
+
+/* d_os_dep.h */
+#define ADV_OS_LINUX
+
+/*
+ * Define Adv Library required special types.
+ */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+#define AdvPortAddr unsigned short /* I/O Port address size */
+#else /* version >= v1,3,0 */
+#define AdvPortAddr unsigned long /* Virtual memory address size */
+#endif /* version >= v1,3,0 */
+
+/*
+ * Define Adv Library required memory access macros.
+ */
+#define ADV_MEM_READB(addr) readb(addr)
+#define ADV_MEM_READW(addr) readw(addr)
+#define ADV_MEM_WRITEB(addr, byte) writeb(byte, addr)
+#define ADV_MEM_WRITEW(addr, word) writew(word, addr)
+
+/*
+ * The I/O memory mapping function names changed in 2.1.X.
+ */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,0)
+#define ioremap vremap
+#define iounmap vfree
+#endif /* version < v2.1.0 */
+
+/*
+ * Define total number of simultaneous maximum element scatter-gather
+ * requests, i.e. ADV_TOT_SG_LIST * ADV_MAX_SG_LIST is the total number
+ * of simultaneous scatter-gather elements supported per wide adapter.
+ */
+#define ADV_TOT_SG_LIST 64
+
+/*
+ * Define Adv Library required per request scatter-gather element limit.
+ */
+#define ADV_MAX_SG_LIST 64
+
+/*
+ * Scatter-Gather Definitions per request.
+ *
+ * Because SG block memory is allocated in virtual memory but is
+ * referenced by the microcode as physical memory, we need to do
+ * calculations to insure there will be enough physically contiguous
+ * memory to support ADV_MAX_SG_LIST SG entries.
+ */
+
+/* Number of SG blocks needed. */
+#define ADV_NUM_SG_BLOCK \
+ ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK)
+
+/* Total contiguous memory needed for SG blocks. */
+#define ADV_SG_TOTAL_MEM_SIZE \
+ (sizeof(ADV_SG_BLOCK) * ADV_NUM_SG_BLOCK)
+
+#define ASC_PAGE_SIZE PAGE_SIZE
+
+/*
+ * Number of page crossings possible for the total contiguous virtual memory
+ * needed for SG blocks.
+ *
+ * We need to allocate this many additional SG blocks in virtual memory to
+ * insure there will be space for ADV_NUM_SG_BLOCK physically contiguous
+ * scatter-gather blocks.
+ */
+#define ADV_NUM_PAGE_CROSSING \
+ ((ADV_SG_TOTAL_MEM_SIZE + (ASC_PAGE_SIZE - 1))/ASC_PAGE_SIZE)
+
+/*
+ * Define Adv Library Assertion Macro.
+ */
+
+#define ADV_ASSERT(a) ASC_ASSERT(a)
+
+/* a_condor.h */
+#define ADV_PCI_VENDOR_ID 0x10CD
+#define ADV_PCI_DEVICE_ID_REV_A 0x2300
+
+#define ASC_EEP_DVC_CFG_BEGIN (0x00)
+#define ASC_EEP_DVC_CFG_END (0x15)
+#define ASC_EEP_DVC_CTL_BEGIN (0x16) /* location of OEM name */
+#define ASC_EEP_MAX_WORD_ADDR (0x1E)
+
+#define ASC_EEP_DELAY_MS 100
+
+/*
+ * EEPROM bits reference by the RISC after initialization.
+ */
+#define ADV_EEPROM_BIG_ENDIAN 0x8000 /* EEPROM Bit 15 */
+#define ADV_EEPROM_BIOS_ENABLE 0x4000 /* EEPROM Bit 14 */
+#define ADV_EEPROM_TERM_POL 0x2000 /* EEPROM Bit 13 */
+
+/*
+ * EEPROM configuration format
+ *
+ * Field naming convention:
+ *
+ * *_enable indicates the field enables or disables the feature. The
+ * value is never reset.
+ *
+ * *_able indicates both whether a feature should be enabled or disabled
+ * and whether a device isi capable of the feature. At initialization
+ * this field may be set, but later if a device is found to be incapable
+ * of the feature, the field is cleared.
+ *
+ * Default values are maintained in a_init.c in the structure
+ * Default_EEPROM_Config.
+ */
+typedef struct adveep_config
+{
+ /* Word Offset, Description */
+
+ ushort cfg_lsw; /* 00 power up initialization */
+ /* bit 13 set - Term Polarity Control */
+ /* bit 14 set - BIOS Enable */
+ /* bit 15 set - Big Endian Mode */
+ ushort cfg_msw; /* 01 unused */
+ ushort disc_enable; /* 02 disconnect enable */
+ ushort wdtr_able; /* 03 Wide DTR able */
+ ushort sdtr_able; /* 04 Synchronous DTR able */
+ ushort start_motor; /* 05 send start up motor */
+ ushort tagqng_able; /* 06 tag queuing able */
+ ushort bios_scan; /* 07 BIOS device control */
+ ushort scam_tolerant; /* 08 no scam */
+
+ uchar adapter_scsi_id; /* 09 Host Adapter ID */
+ uchar bios_boot_delay; /* power up wait */
+
+ uchar scsi_reset_delay; /* 10 reset delay */
+ uchar bios_id_lun; /* first boot device scsi id & lun */
+ /* high nibble is lun */
+ /* low nibble is scsi id */
+
+ uchar termination; /* 11 0 - automatic */
+ /* 1 - low off / high off */
+ /* 2 - low off / high on */
+ /* 3 - low on / high on */
+ /* There is no low on / high off */
+
+ uchar reserved1; /* reserved byte (not used) */
+
+ ushort bios_ctrl; /* 12 BIOS control bits */
+ /* bit 0 set: BIOS don't act as initiator. */
+ /* bit 1 set: BIOS > 1 GB support */
+ /* bit 2 set: BIOS > 2 Disk Support */
+ /* bit 3 set: BIOS don't support removables */
+ /* bit 4 set: BIOS support bootable CD */
+ /* bit 5 set: */
+ /* bit 6 set: BIOS support multiple LUNs */
+ /* bit 7 set: BIOS display of message */
+ /* bit 8 set: */
+ /* bit 9 set: Reset SCSI bus during init. */
+ /* bit 10 set: */
+ /* bit 11 set: No verbose initialization. */
+ /* bit 12 set: SCSI parity enabled */
+ /* bit 13 set: */
+ /* bit 14 set: */
+ /* bit 15 set: */
+ ushort ultra_able; /* 13 ULTRA speed able */
+ ushort reserved2; /* 14 reserved */
+ uchar max_host_qng; /* 15 maximum host queuing */
+ uchar max_dvc_qng; /* maximum per device queuing */
+ ushort dvc_cntl; /* 16 control bit for driver */
+ ushort bug_fix; /* 17 control bit for bug fix */
+ ushort serial_number_word1; /* 18 Board serial number word 1 */
+ ushort serial_number_word2; /* 19 Board serial number word 2 */
+ ushort serial_number_word3; /* 20 Board serial number word 3 */
+ ushort check_sum; /* 21 EEP check sum */
+ uchar oem_name[16]; /* 22 OEM name */
+ ushort dvc_err_code; /* 30 last device driver error code */
+ ushort adv_err_code; /* 31 last uc and Adv Lib error code */
+ ushort adv_err_addr; /* 32 last uc error address */
+ ushort saved_dvc_err_code; /* 33 saved last dev. driver error code */
+ ushort saved_adv_err_code; /* 34 saved last uc and Adv Lib error code */
+ ushort saved_adv_err_addr; /* 35 saved last uc error address */
+ ushort num_of_err; /* 36 number of error */
+} ADVEEP_CONFIG;
+
+/*
+ * EEPROM Commands
+ */
+#define ASC_EEP_CMD_DONE 0x0200
+#define ASC_EEP_CMD_DONE_ERR 0x0001
+
+/* cfg_word */
+#define EEP_CFG_WORD_BIG_ENDIAN 0x8000
+
+/* bios_ctrl */
+#define BIOS_CTRL_BIOS 0x0001
+#define BIOS_CTRL_EXTENDED_XLAT 0x0002
+#define BIOS_CTRL_GT_2_DISK 0x0004
+#define BIOS_CTRL_BIOS_REMOVABLE 0x0008
+#define BIOS_CTRL_BOOTABLE_CD 0x0010
+#define BIOS_CTRL_MULTIPLE_LUN 0x0040
+#define BIOS_CTRL_DISPLAY_MSG 0x0080
+#define BIOS_CTRL_NO_SCAM 0x0100
+#define BIOS_CTRL_RESET_SCSI_BUS 0x0200
+#define BIOS_CTRL_INIT_VERBOSE 0x0800
+#define BIOS_CTRL_SCSI_PARITY 0x1000
+
+/*
+ * ASC 3550 Internal Memory Size - 8KB
+ */
+#define ADV_CONDOR_MEMSIZE 0x2000 /* 8 KB Internal Memory */
+
+/*
+ * ASC 3550 I/O Length - 64 bytes
+ */
+#define ADV_CONDOR_IOLEN 0x40 /* I/O Port Range in bytes */
+
+/*
+ * Byte I/O register address from base of 'iop_base'.
+ */
+#define IOPB_INTR_STATUS_REG 0x00
+#define IOPB_CHIP_ID_1 0x01
+#define IOPB_INTR_ENABLES 0x02
+#define IOPB_CHIP_TYPE_REV 0x03
+#define IOPB_RES_ADDR_4 0x04
+#define IOPB_RES_ADDR_5 0x05
+#define IOPB_RAM_DATA 0x06
+#define IOPB_RES_ADDR_7 0x07
+#define IOPB_FLAG_REG 0x08
+#define IOPB_RES_ADDR_9 0x09
+#define IOPB_RISC_CSR 0x0A
+#define IOPB_RES_ADDR_B 0x0B
+#define IOPB_RES_ADDR_C 0x0C
+#define IOPB_RES_ADDR_D 0x0D
+#define IOPB_RES_ADDR_E 0x0E
+#define IOPB_RES_ADDR_F 0x0F
+#define IOPB_MEM_CFG 0x10
+#define IOPB_RES_ADDR_11 0x11
+#define IOPB_RES_ADDR_12 0x12
+#define IOPB_RES_ADDR_13 0x13
+#define IOPB_FLASH_PAGE 0x14
+#define IOPB_RES_ADDR_15 0x15
+#define IOPB_RES_ADDR_16 0x16
+#define IOPB_RES_ADDR_17 0x17
+#define IOPB_FLASH_DATA 0x18
+#define IOPB_RES_ADDR_19 0x19
+#define IOPB_RES_ADDR_1A 0x1A
+#define IOPB_RES_ADDR_1B 0x1B
+#define IOPB_RES_ADDR_1C 0x1C
+#define IOPB_RES_ADDR_1D 0x1D
+#define IOPB_RES_ADDR_1E 0x1E
+#define IOPB_RES_ADDR_1F 0x1F
+#define IOPB_DMA_CFG0 0x20
+#define IOPB_DMA_CFG1 0x21
+#define IOPB_TICKLE 0x22
+#define IOPB_DMA_REG_WR 0x23
+#define IOPB_SDMA_STATUS 0x24
+#define IOPB_SCSI_BYTE_CNT 0x25
+#define IOPB_HOST_BYTE_CNT 0x26
+#define IOPB_BYTE_LEFT_TO_XFER 0x27
+#define IOPB_BYTE_TO_XFER_0 0x28
+#define IOPB_BYTE_TO_XFER_1 0x29
+#define IOPB_BYTE_TO_XFER_2 0x2A
+#define IOPB_BYTE_TO_XFER_3 0x2B
+#define IOPB_ACC_GRP 0x2C
+#define IOPB_RES_ADDR_2D 0x2D
+#define IOPB_DEV_ID 0x2E
+#define IOPB_RES_ADDR_2F 0x2F
+#define IOPB_SCSI_DATA 0x30
+#define IOPB_RES_ADDR_31 0x31
+#define IOPB_RES_ADDR_32 0x32
+#define IOPB_SCSI_DATA_HSHK 0x33
+#define IOPB_SCSI_CTRL 0x34
+#define IOPB_RES_ADDR_35 0x35
+#define IOPB_RES_ADDR_36 0x36
+#define IOPB_RES_ADDR_37 0x37
+#define IOPB_RES_ADDR_38 0x38
+#define IOPB_RES_ADDR_39 0x39
+#define IOPB_RES_ADDR_3A 0x3A
+#define IOPB_RES_ADDR_3B 0x3B
+#define IOPB_RFIFO_CNT 0x3C
+#define IOPB_RES_ADDR_3D 0x3D
+#define IOPB_RES_ADDR_3E 0x3E
+#define IOPB_RES_ADDR_3F 0x3F
+
+/*
+ * Word I/O register address from base of 'iop_base'.
+ */
+#define IOPW_CHIP_ID_0 0x00 /* CID0 */
+#define IOPW_CTRL_REG 0x02 /* CC */
+#define IOPW_RAM_ADDR 0x04 /* LA */
+#define IOPW_RAM_DATA 0x06 /* LD */
+#define IOPW_RES_ADDR_08 0x08
+#define IOPW_RISC_CSR 0x0A /* CSR */
+#define IOPW_SCSI_CFG0 0x0C /* CFG0 */
+#define IOPW_SCSI_CFG1 0x0E /* CFG1 */
+#define IOPW_RES_ADDR_10 0x10
+#define IOPW_SEL_MASK 0x12 /* SM */
+#define IOPW_RES_ADDR_14 0x14
+#define IOPW_FLASH_ADDR 0x16 /* FA */
+#define IOPW_RES_ADDR_18 0x18
+#define IOPW_EE_CMD 0x1A /* EC */
+#define IOPW_EE_DATA 0x1C /* ED */
+#define IOPW_SFIFO_CNT 0x1E /* SFC */
+#define IOPW_RES_ADDR_20 0x20
+#define IOPW_Q_BASE 0x22 /* QB */
+#define IOPW_QP 0x24 /* QP */
+#define IOPW_IX 0x26 /* IX */
+#define IOPW_SP 0x28 /* SP */
+#define IOPW_PC 0x2A /* PC */
+#define IOPW_RES_ADDR_2C 0x2C
+#define IOPW_RES_ADDR_2E 0x2E
+#define IOPW_SCSI_DATA 0x30 /* SD */
+#define IOPW_SCSI_DATA_HSHK 0x32 /* SDH */
+#define IOPW_SCSI_CTRL 0x34 /* SC */
+#define IOPW_HSHK_CFG 0x36 /* HCFG */
+#define IOPW_SXFR_STATUS 0x36 /* SXS */
+#define IOPW_SXFR_CNTL 0x38 /* SXL */
+#define IOPW_SXFR_CNTH 0x3A /* SXH */
+#define IOPW_RES_ADDR_3C 0x3C
+#define IOPW_RFIFO_DATA 0x3E /* RFD */
+
+/*
+ * Doubleword I/O register address from base of 'iop_base'.
+ */
+#define IOPDW_RES_ADDR_0 0x00
+#define IOPDW_RAM_DATA 0x04
+#define IOPDW_RES_ADDR_8 0x08
+#define IOPDW_RES_ADDR_C 0x0C
+#define IOPDW_RES_ADDR_10 0x10
+#define IOPDW_RES_ADDR_14 0x14
+#define IOPDW_RES_ADDR_18 0x18
+#define IOPDW_RES_ADDR_1C 0x1C
+#define IOPDW_SDMA_ADDR0 0x20
+#define IOPDW_SDMA_ADDR1 0x24
+#define IOPDW_SDMA_COUNT 0x28
+#define IOPDW_SDMA_ERROR 0x2C
+#define IOPDW_RDMA_ADDR0 0x30
+#define IOPDW_RDMA_ADDR1 0x34
+#define IOPDW_RDMA_COUNT 0x38
+#define IOPDW_RDMA_ERROR 0x3C
+
+#define ADV_CHIP_ID_BYTE 0x25
+#define ADV_CHIP_ID_WORD 0x04C1
+
+#define ADV_SC_SCSI_BUS_RESET 0x2000
+
+#define ADV_INTR_ENABLE_HOST_INTR 0x01
+#define ADV_INTR_ENABLE_SEL_INTR 0x02
+#define ADV_INTR_ENABLE_DPR_INTR 0x04
+#define ADV_INTR_ENABLE_RTA_INTR 0x08
+#define ADV_INTR_ENABLE_RMA_INTR 0x10
+#define ADV_INTR_ENABLE_RST_INTR 0x20
+#define ADV_INTR_ENABLE_DPE_INTR 0x40
+#define ADV_INTR_ENABLE_GLOBAL_INTR 0x80
+
+#define ADV_INTR_STATUS_INTRA 0x01
+#define ADV_INTR_STATUS_INTRB 0x02
+#define ADV_INTR_STATUS_INTRC 0x04
+
+#define ADV_RISC_CSR_STOP (0x0000)
+#define ADV_RISC_TEST_COND (0x2000)
+#define ADV_RISC_CSR_RUN (0x4000)
+#define ADV_RISC_CSR_SINGLE_STEP (0x8000)
+
+#define ADV_CTRL_REG_HOST_INTR 0x0100
+#define ADV_CTRL_REG_SEL_INTR 0x0200
+#define ADV_CTRL_REG_DPR_INTR 0x0400
+#define ADV_CTRL_REG_RTA_INTR 0x0800
+#define ADV_CTRL_REG_RMA_INTR 0x1000
+#define ADV_CTRL_REG_RES_BIT14 0x2000
+#define ADV_CTRL_REG_DPE_INTR 0x4000
+#define ADV_CTRL_REG_POWER_DONE 0x8000
+#define ADV_CTRL_REG_ANY_INTR 0xFF00
+
+#define ADV_CTRL_REG_CMD_RESET 0x00C6
+#define ADV_CTRL_REG_CMD_WR_IO_REG 0x00C5
+#define ADV_CTRL_REG_CMD_RD_IO_REG 0x00C4
+#define ADV_CTRL_REG_CMD_WR_PCI_CFG_SPACE 0x00C3
+#define ADV_CTRL_REG_CMD_RD_PCI_CFG_SPACE 0x00C2
+
+#define ADV_SCSI_CTRL_RSTOUT 0x2000
+
+#define AdvIsIntPending(port) \
+ (AdvReadWordRegister(port, IOPW_CTRL_REG) & ADV_CTRL_REG_HOST_INTR)
+
+/*
+ * SCSI_CFG0 Register bit definitions
+ */
+#define TIMER_MODEAB 0xC000 /* Watchdog, Second, and Select. Timer Ctrl. */
+#define PARITY_EN 0x2000 /* Enable SCSI Parity Error detection */
+#define EVEN_PARITY 0x1000 /* Select Even Parity */
+#define WD_LONG 0x0800 /* Watchdog Interval, 1: 57 min, 0: 13 sec */
+#define QUEUE_128 0x0400 /* Queue Size, 1: 128 byte, 0: 64 byte */
+#define PRIM_MODE 0x0100 /* Primitive SCSI mode */
+#define SCAM_EN 0x0080 /* Enable SCAM selection */
+#define SEL_TMO_LONG 0x0040 /* Sel/Resel Timeout, 1: 400 ms, 0: 1.6 ms */
+#define CFRM_ID 0x0020 /* SCAM id sel. confirm., 1: fast, 0: 6.4 ms */
+#define OUR_ID_EN 0x0010 /* Enable OUR_ID bits */
+#define OUR_ID 0x000F /* SCSI ID */
+
+/*
+ * SCSI_CFG1 Register bit definitions
+ */
+#define BIG_ENDIAN 0x8000 /* Enable Big Endian Mode MIO:15, EEP:15 */
+#define TERM_POL 0x2000 /* Terminator Polarity Ctrl. MIO:13, EEP:13 */
+#define SLEW_RATE 0x1000 /* SCSI output buffer slew rate */
+#define FILTER_SEL 0x0C00 /* Filter Period Selection */
+#define FLTR_DISABLE 0x0000 /* Input Filtering Disabled */
+#define FLTR_11_TO_20NS 0x0800 /* Input Filtering 11ns to 20ns */
+#define FLTR_21_TO_39NS 0x0C00 /* Input Filtering 21ns to 39ns */
+#define ACTIVE_DBL 0x0200 /* Disable Active Negation */
+#define DIFF_MODE 0x0100 /* SCSI differential Mode (Read-Only) */
+#define DIFF_SENSE 0x0080 /* 1: No SE cables, 0: SE cable (Read-Only) */
+#define TERM_CTL_SEL 0x0040 /* Enable TERM_CTL_H and TERM_CTL_L */
+#define TERM_CTL 0x0030 /* External SCSI Termination Bits */
+#define TERM_CTL_H 0x0020 /* Enable External SCSI Upper Termination */
+#define TERM_CTL_L 0x0010 /* Enable External SCSI Lower Termination */
+#define CABLE_DETECT 0x000F /* External SCSI Cable Connection Status */
+
+#define CABLE_ILLEGAL_A 0x7
+ /* x 0 0 0 | on on | Illegal (all 3 connectors are used) */
+
+#define CABLE_ILLEGAL_B 0xB
+ /* 0 x 0 0 | on on | Illegal (all 3 connectors are used) */
+
+/*
+ The following table details the SCSI_CFG1 Termination Polarity,
+ Termination Control and Cable Detect bits.
+
+ Cable Detect | Termination
+ Bit 3 2 1 0 | 5 4 | Notes
+ _____________|________|____________________
+ 1 1 1 0 | on on | Internal wide only
+ 1 1 0 1 | on on | Internal narrow only
+ 1 0 1 1 | on on | External narrow only
+ 0 x 1 1 | on on | External wide only
+ 1 1 0 0 | on off| Internal wide and internal narrow
+ 1 0 1 0 | on off| Internal wide and external narrow
+ 0 x 1 0 | off off| Internal wide and external wide
+ 1 0 0 1 | on off| Internal narrow and external narrow
+ 0 x 0 1 | on off| Internal narrow and external wide
+ 1 1 1 1 | on on | No devices are attached
+ x 0 0 0 | on on | Illegal (all 3 connectors are used)
+ 0 x 0 0 | on on | Illegal (all 3 connectors are used)
+
+ x means don't-care (either '0' or '1')
+
+ If term_pol (bit 13) is '0' (active-low terminator enable), then:
+ 'on' is '0' and 'off' is '1'.
+
+ If term_pol bit is '1' (meaning active-hi terminator enable), then:
+ 'on' is '1' and 'off' is '0'.
+ */
+
+/*
+ * MEM_CFG Register bit definitions
+ */
+#define BIOS_EN 0x40 /* BIOS Enable MIO:14,EEP:14 */
+#define FAST_EE_CLK 0x20 /* Diagnostic Bit */
+#define RAM_SZ 0x1C /* Specify size of RAM to RISC */
+#define RAM_SZ_2KB 0x00 /* 2 KB */
+#define RAM_SZ_4KB 0x04 /* 4 KB */
+#define RAM_SZ_8KB 0x08 /* 8 KB */
+#define RAM_SZ_16KB 0x0C /* 16 KB */
+#define RAM_SZ_32KB 0x10 /* 32 KB */
+#define RAM_SZ_64KB 0x14 /* 64 KB */
+
+/*
+ * DMA_CFG0 Register bit definitions
+ *
+ * This register is only accessible to the host.
+ */
+#define BC_THRESH_ENB 0x80 /* PCI DMA Start Conditions */
+#define FIFO_THRESH 0x70 /* PCI DMA FIFO Threshold */
+#define FIFO_THRESH_16B 0x00 /* 16 bytes */
+#define FIFO_THRESH_32B 0x20 /* 32 bytes */
+#define FIFO_THRESH_48B 0x30 /* 48 bytes */
+#define FIFO_THRESH_64B 0x40 /* 64 bytes */
+#define FIFO_THRESH_80B 0x50 /* 80 bytes (default) */
+#define FIFO_THRESH_96B 0x60 /* 96 bytes */
+#define FIFO_THRESH_112B 0x70 /* 112 bytes */
+#define START_CTL 0x0C /* DMA start conditions */
+#define START_CTL_TH 0x00 /* Wait threshold level (default) */
+#define START_CTL_ID 0x04 /* Wait SDMA/SBUS idle */
+#define START_CTL_THID 0x08 /* Wait threshold and SDMA/SBUS idle */
+#define START_CTL_EMFU 0x0C /* Wait SDMA FIFO empty/full */
+#define READ_CMD 0x03 /* Memory Read Method */
+#define READ_CMD_MR 0x00 /* Memory Read */
+#define READ_CMD_MRL 0x02 /* Memory Read Long */
+#define READ_CMD_MRM 0x03 /* Memory Read Multiple (default) */
+
+/* a_advlib.h */
+
+/*
+ * Adv Library Status Definitions
+ */
+#define ADV_TRUE 1
+#define ADV_FALSE 0
+#define ADV_NOERROR 1
+#define ADV_SUCCESS 1
+#define ADV_BUSY 0
+#define ADV_ERROR (-1)
+
+
+/*
+ * ASC_DVC_VAR 'warn_code' values
+ */
+#define ASC_WARN_EEPROM_CHKSUM 0x0002 /* EEP check sum error */
+#define ASC_WARN_EEPROM_TERMINATION 0x0004 /* EEP termination bad field */
+#define ASC_WARN_SET_PCI_CONFIG_SPACE 0x0080 /* PCI config space set error */
+#define ASC_WARN_ERROR 0xFFFF /* ADV_ERROR return */
+
+#define ADV_MAX_TID 15 /* max. target identifier */
+#define ADV_MAX_LUN 7 /* max. logical unit number */
+
+
+/*
+ * AscInitGetConfig() and AscInitAsc1000Driver() Definitions
+ *
+ * Error code values are set in ASC_DVC_VAR 'err_code'.
+ */
+#define ASC_IERR_WRITE_EEPROM 0x0001 /* write EEPROM error */
+#define ASC_IERR_MCODE_CHKSUM 0x0002 /* micro code check sum error */
+#define ASC_IERR_START_STOP_CHIP 0x0008 /* start/stop chip failed */
+#define ASC_IERR_CHIP_VERSION 0x0040 /* wrong chip version */
+#define ASC_IERR_SET_SCSI_ID 0x0080 /* set SCSI ID failed */
+#define ASC_IERR_BAD_SIGNATURE 0x0200 /* signature not found */
+#define ASC_IERR_ILLEGAL_CONNECTION 0x0400 /* Illegal cable connection */
+#define ASC_IERR_SINGLE_END_DEVICE 0x0800 /* Single-end used w/differential */
+#define ASC_IERR_REVERSED_CABLE 0x1000 /* Narrow flat cable reversed */
+#define ASC_IERR_RW_LRAM 0x8000 /* read/write local RAM error */
+
+/*
+ * Fixed locations of microcode operating variables.
+ */
+#define ASC_MC_CODE_BEGIN_ADDR 0x0028 /* microcode start address */
+#define ASC_MC_CODE_END_ADDR 0x002A /* microcode end address */
+#define ASC_MC_CODE_CHK_SUM 0x002C /* microcode code checksum */
+#define ASC_MC_STACK_BEGIN 0x002E /* microcode stack begin */
+#define ASC_MC_STACK_END 0x0030 /* microcode stack end */
+#define ASC_MC_VERSION_DATE 0x0038 /* microcode version */
+#define ASC_MC_VERSION_NUM 0x003A /* microcode number */
+#define ASCV_VER_SERIAL_W 0x003C /* used in dos_init */
+#define ASC_MC_BIOSMEM 0x0040 /* BIOS RISC Memory Start */
+#define ASC_MC_BIOSLEN 0x0050 /* BIOS RISC Memory Length */
+#define ASC_MC_HALTCODE 0x0094 /* microcode halt code */
+#define ASC_MC_CALLERPC 0x0096 /* microcode halt caller PC */
+#define ASC_MC_ADAPTER_SCSI_ID 0x0098 /* one ID byte + reserved */
+#define ASC_MC_ULTRA_ABLE 0x009C
+#define ASC_MC_SDTR_ABLE 0x009E
+#define ASC_MC_TAGQNG_ABLE 0x00A0
+#define ASC_MC_DISC_ENABLE 0x00A2
+#define ASC_MC_IDLE_CMD 0x00A6
+#define ASC_MC_IDLE_PARA_STAT 0x00A8
+#define ASC_MC_DEFAULT_SCSI_CFG0 0x00AC
+#define ASC_MC_DEFAULT_SCSI_CFG1 0x00AE
+#define ASC_MC_DEFAULT_MEM_CFG 0x00B0
+#define ASC_MC_DEFAULT_SEL_MASK 0x00B2
+#define ASC_MC_RISC_NEXT_READY 0x00B4
+#define ASC_MC_RISC_NEXT_DONE 0x00B5
+#define ASC_MC_SDTR_DONE 0x00B6
+#define ASC_MC_NUMBER_OF_QUEUED_CMD 0x00C0
+#define ASC_MC_NUMBER_OF_MAX_CMD 0x00D0
+#define ASC_MC_DEVICE_HSHK_CFG_TABLE 0x0100
+#define ASC_MC_WDTR_ABLE 0x0120 /* Wide Transfer TID bitmask. */
+#define ASC_MC_CONTROL_FLAG 0x0122 /* Microcode control flag. */
+#define ASC_MC_WDTR_DONE 0x0124
+#define ASC_MC_HOST_NEXT_READY 0x0128 /* Host Next Ready RQL Entry. */
+#define ASC_MC_HOST_NEXT_DONE 0x0129 /* Host Next Done RQL Entry. */
+
+/*
+ * BIOS LRAM variable absolute offsets.
+ */
+#define BIOS_CODESEG 0x54
+#define BIOS_CODELEN 0x56
+#define BIOS_SIGNATURE 0x58
+#define BIOS_VERSION 0x5A
+#define BIOS_SIGNATURE 0x58
+
+/*
+ * Microcode Control Flags
+ *
+ * Flags set by the Adv Library in RISC variable 'control_flag' (0x122)
+ * and handled by the microcode.
+ */
+#define CONTROL_FLAG_IGNORE_PERR 0x0001 /* Ignore DMA Parity Errors */
+
+/*
+ * ASC_MC_DEVICE_HSHK_CFG_TABLE microcode table or HSHK_CFG register format
+ */
+#define HSHK_CFG_WIDE_XFR 0x8000
+#define HSHK_CFG_RATE 0x0F00
+#define HSHK_CFG_OFFSET 0x001F
+
+/*
+ * LRAM RISC Queue Lists (LRAM addresses 0x1200 - 0x19FF)
+ *
+ * Each of the 255 Adv Library/Microcode RISC queue lists or mailboxes
+ * starting at LRAM address 0x1200 is 8 bytes and has the following
+ * structure. Only 253 of these are actually used for command queues.
+ */
+
+#define ASC_MC_RISC_Q_LIST_BASE 0x1200
+#define ASC_MC_RISC_Q_LIST_SIZE 0x0008
+#define ASC_MC_RISC_Q_TOTAL_CNT 0x00FF /* Num. queue slots in LRAM. */
+#define ASC_MC_RISC_Q_FIRST 0x0001
+#define ASC_MC_RISC_Q_LAST 0x00FF
+
+#define ASC_DEF_MAX_HOST_QNG 0xFD /* Max. number of host commands (253) */
+#define ASC_DEF_MIN_HOST_QNG 0x10 /* Min. number of host commands (16) */
+#define ASC_DEF_MAX_DVC_QNG 0x3F /* Max. number commands per device (63) */
+#define ASC_DEF_MIN_DVC_QNG 0x04 /* Min. number commands per device (4) */
+
+/* RISC Queue List structure - 8 bytes */
+#define RQL_FWD 0 /* forward pointer (1 byte) */
+#define RQL_BWD 1 /* backward pointer (1 byte) */
+#define RQL_STATE 2 /* state byte - free, ready, done, aborted (1 byte) */
+#define RQL_TID 3 /* request target id (1 byte) */
+#define RQL_PHYADDR 4 /* request physical pointer (4 bytes) */
+
+/* RISC Queue List state values */
+#define ASC_MC_QS_FREE 0x00
+#define ASC_MC_QS_READY 0x01
+#define ASC_MC_QS_DONE 0x40
+#define ASC_MC_QS_ABORTED 0x80
+
+/* RISC Queue List pointer values */
+#define ASC_MC_NULL_Q 0x00 /* NULL_Q == 0 */
+#define ASC_MC_BIOS_Q 0xFF /* BIOS_Q = 255 */
+
+/* ASC_SCSI_REQ_Q 'cntl' field values */
+#define ASC_MC_QC_START_MOTOR 0x02 /* Issue start motor. */
+#define ASC_MC_QC_NO_OVERRUN 0x04 /* Don't report overrun. */
+#define ASC_MC_QC_FIRST_DMA 0x08 /* Internal microcode flag. */
+#define ASC_MC_QC_ABORTED 0x10 /* Request aborted by host. */
+#define ASC_MC_QC_REQ_SENSE 0x20 /* Auto-Request Sense. */
+#define ASC_MC_QC_DOS_REQ 0x80 /* Request issued by DOS. */
+
+
+/*
+ * ASC_SCSI_REQ_Q 'a_flag' definitions
+ *
+ * The Adv Library should limit use to the lower nibble (4 bits) of
+ * a_flag. Drivers are free to use the upper nibble (4 bits) of a_flag.
+ */
+#define ADV_POLL_REQUEST 0x01 /* poll for request completion */
+#define ADV_SCSIQ_DONE 0x02 /* request done */
+
+/*
+ * Adapter temporary configuration structure
+ *
+ * This structure can be discarded after initialization. Don't add
+ * fields here needed after initialization.
+ *
+ * Field naming convention:
+ *
+ * *_enable indicates the field enables or disables a feature. The
+ * value of the field is never reset.
+ */
+typedef struct adv_dvc_cfg {
+ ushort disc_enable; /* enable disconnection */
+ uchar chip_version; /* chip version */
+ uchar termination; /* Term. Ctrl. bits 6-5 of SCSI_CFG1 register */
+ ushort pci_device_id; /* PCI device code number */
+ ushort lib_version; /* Adv Library version number */
+ ushort control_flag; /* Microcode Control Flag */
+ ushort mcode_date; /* Microcode date */
+ ushort mcode_version; /* Microcode version */
+ ushort pci_slot_info; /* high byte device/function number */
+ /* bits 7-3 device num., bits 2-0 function num. */
+ /* low byte bus num. */
+ ushort bios_boot_wait; /* BIOS boot time delay */
+ ushort serial1; /* EEPROM serial number word 1 */
+ ushort serial2; /* EEPROM serial number word 2 */
+ ushort serial3; /* EEPROM serial number word 3 */
+} ADV_DVC_CFG;
+
+/*
+ * Adapter operation variable structure.
+ *
+ * One structure is required per host adapter.
+ *
+ * Field naming convention:
+ *
+ * *_able indicates both whether a feature should be enabled or disabled
+ * and whether a device isi capable of the feature. At initialization
+ * this field may be set, but later if a device is found to be incapable
+ * of the feature, the field is cleared.
+ */
+typedef struct adv_dvc_var {
+ AdvPortAddr iop_base; /* I/O port address */
+ ushort err_code; /* fatal error code */
+ ushort bios_ctrl; /* BIOS control word, EEPROM word 12 */
+ Ptr2Func isr_callback; /* pointer to function, called in AdvISR() */
+ Ptr2Func sbreset_callback; /* pointer to function, called in AdvISR() */
+ ushort wdtr_able; /* try WDTR for a device */
+ ushort sdtr_able; /* try SDTR for a device */
+ ushort ultra_able; /* try SDTR Ultra speed for a device */
+ ushort tagqng_able; /* try tagged queuing with a device */
+ uchar max_dvc_qng; /* maximum number of tagged commands per device */
+ ushort start_motor; /* start motor command allowed */
+ uchar scsi_reset_wait; /* delay in seconds after scsi bus reset */
+ uchar chip_no; /* should be assigned by caller */
+ uchar max_host_qng; /* maximum number of Q'ed command allowed */
+ uchar cur_host_qng; /* total number of queue command */
+ uchar irq_no; /* IRQ number */
+ ushort no_scam; /* scam_tolerant of EEPROM */
+ ushort idle_cmd_done; /* microcode idle command done set by AdvISR() */
+ ulong drv_ptr; /* driver pointer to private structure */
+ uchar chip_scsi_id; /* chip SCSI target ID */
+ /*
+ * Note: The following fields will not be used after initialization. The
+ * driver may discard the buffer after initialization is done.
+ */
+ ADV_DVC_CFG *cfg; /* temporary configuration structure */
+} ADV_DVC_VAR;
+
+#define NO_OF_SG_PER_BLOCK 15
+
+typedef struct asc_sg_block {
+ uchar reserved1;
+ uchar reserved2;
+ uchar first_entry_no; /* starting entry number */
+ uchar last_entry_no; /* last entry number */
+ struct asc_sg_block *sg_ptr; /* links to the next sg block */
+ struct {
+ ulong sg_addr; /* SG element address */
+ ulong sg_count; /* SG element count */
+ } sg_list[NO_OF_SG_PER_BLOCK];
+} ADV_SG_BLOCK;
+
+/*
+ * ASC_SCSI_REQ_Q - microcode request structure
+ *
+ * All fields in this structure up to byte 60 are used by the microcode.
+ * The microcode makes assumptions about the size and ordering of fields
+ * in this structure. Do not change the structure definition here without
+ * coordinating the change with the microcode.
+ */
+typedef struct adv_scsi_req_q {
+ uchar cntl; /* Ucode flags and state (ASC_MC_QC_*). */
+ uchar sg_entry_cnt; /* SG element count. Zero for no SG. */
+ uchar target_id; /* Device target identifier. */
+ uchar target_lun; /* Device target logical unit number. */
+ ulong data_addr; /* Data buffer physical address. */
+ ulong data_cnt; /* Data count. Ucode sets to residual. */
+ ulong sense_addr; /* Sense buffer physical address. */
+ ulong srb_ptr; /* Driver request pointer. */
+ uchar a_flag; /* Adv Library flag field. */
+ uchar sense_len; /* Auto-sense length. Ucode sets to residual. */
+ uchar cdb_len; /* SCSI CDB length. */
+ uchar tag_code; /* SCSI-2 Tag Queue Code: 00, 20-22. */
+ uchar done_status; /* Completion status. */
+ uchar scsi_status; /* SCSI status byte. */
+ uchar host_status; /* Ucode host status. */
+ uchar ux_sg_ix; /* Ucode working SG variable. */
+ uchar cdb[12]; /* SCSI command block. */
+ ulong sg_real_addr; /* SG list physical address. */
+ struct adv_scsi_req_q *free_scsiq_link;
+ ulong ux_wk_data_cnt; /* Saved data count at disconnection. */
+ struct adv_scsi_req_q *scsiq_ptr;
+ ADV_SG_BLOCK *sg_list_ptr; /* SG list virtual address. */
+ /*
+ * End of microcode structure - 60 bytes. The rest of the structure
+ * is used by the Adv Library and ignored by the microcode.
+ */
+ ulong vsense_addr; /* Sense buffer virtual address. */
+ ulong vdata_addr; /* Data buffer virtual address. */
+ uchar orig_sense_len; /* Original length of sense buffer. */
+} ADV_SCSI_REQ_Q; /* BIOS - 70 bytes, DOS - 76 bytes, W95, WNT - 69 bytes */
+
+/*
+ * Microcode idle loop commands
+ */
+#define IDLE_CMD_COMPLETED 0
+#define IDLE_CMD_STOP_CHIP 0x0001
+#define IDLE_CMD_STOP_CHIP_SEND_INT 0x0002
+#define IDLE_CMD_SEND_INT 0x0004
+#define IDLE_CMD_ABORT 0x0008
+#define IDLE_CMD_DEVICE_RESET 0x0010
+#define IDLE_CMD_SCSI_RESET 0x0020
+
+/*
+ * AdvSendIdleCmd() flag definitions.
+ */
+#define ADV_NOWAIT 0x01
+
+/*
+ * Wait loop time out values.
+ */
+#define SCSI_WAIT_10_SEC 10 /* 10 seconds */
+#define SCSI_MS_PER_SEC 1000 /* milliseconds per second */
+
+/*
+ * Device drivers must define the following functions.
+ */
+STATIC int DvcEnterCritical(void);
+STATIC void DvcLeaveCritical(int);
+STATIC void DvcSleepMilliSecond(ulong);
+STATIC uchar DvcAdvReadPCIConfigByte(ADV_DVC_VAR *, ushort);
+STATIC void DvcAdvWritePCIConfigByte(ADV_DVC_VAR *, ushort, uchar);
+STATIC ulong DvcGetPhyAddr(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *,
+ uchar *, long *, int);
+STATIC void DvcDelayMicroSecond(ADV_DVC_VAR *, ushort);
+
+/*
+ * Adv Library functions available to drivers.
+ */
+STATIC int AdvExeScsiQueue(ADV_DVC_VAR *,
+ ADV_SCSI_REQ_Q *);
+STATIC int AdvISR(ADV_DVC_VAR *);
+STATIC int AdvInitGetConfig(ADV_DVC_VAR *);
+STATIC int AdvInitAsc3550Driver(ADV_DVC_VAR *);
+STATIC int AdvResetSB(ADV_DVC_VAR *);
+
+/*
+ * Internal Adv Library functions.
+ */
+STATIC int AdvSendIdleCmd(ADV_DVC_VAR *, ushort, ulong, int);
+STATIC void AdvResetChip(ADV_DVC_VAR *);
+STATIC int AdvSendScsiCmd(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC void AdvInquiryHandling(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC int AdvInitFromEEP(ADV_DVC_VAR *);
+STATIC ushort AdvGetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *);
+STATIC void AdvSetEEPConfig(AdvPortAddr, ADVEEP_CONFIG *);
+STATIC void AdvWaitEEPCmd(AdvPortAddr);
+STATIC ushort AdvReadEEPWord(AdvPortAddr, int);
+STATIC void AdvResetSCSIBus(ADV_DVC_VAR *);
+
+/*
+ * PCI Bus Definitions
+ */
+#define AscPCICmdRegBits_BusMastering 0x0007
+#define AscPCICmdRegBits_ParErrRespCtrl 0x0040
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+
+/* Read byte from a register. */
+#define AdvReadByteRegister(iop_base, reg_off) \
+ (inp((iop_base) + (reg_off)))
+
+/* Write byte to a register. */
+#define AdvWriteByteRegister(iop_base, reg_off, byte) \
+ (outp((iop_base) + (reg_off), (byte)))
+
+/* Read word (2 bytes) from a register. */
+#define AdvReadWordRegister(iop_base, reg_off) \
+ (inpw((iop_base) + (reg_off)))
+
+/* Write word (2 bytes) to a register. */
+#define AdvWriteWordRegister(iop_base, reg_off, word) \
+ (outpw((iop_base) + (reg_off), (word)))
+
+/* Read byte from LRAM. */
+#define AdvReadByteLram(iop_base, addr, byte) \
+do { \
+ outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \
+ (byte) = inp((iop_base) + IOPB_RAM_DATA); \
+} while (0)
+
+/* Write byte to LRAM. */
+#define AdvWriteByteLram(iop_base, addr, byte) \
+ (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
+ outp((iop_base) + IOPB_RAM_DATA, (byte)))
+
+/* Read word (2 bytes) from LRAM. */
+#define AdvReadWordLram(iop_base, addr, word) \
+do { \
+ outpw((iop_base) + IOPW_RAM_ADDR, (addr)); \
+ (word) = inpw((iop_base) + IOPW_RAM_DATA); \
+} while (0)
+
+/* Write word (2 bytes) to LRAM. */
+#define AdvWriteWordLram(iop_base, addr, word) \
+ (outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
+ outpw((iop_base) + IOPW_RAM_DATA, (word)))
+
+/* Write double word (4 bytes) to LRAM */
+/* Because of unspecified C language ordering don't use auto-increment. */
+#define AdvWriteDWordLram(iop_base, addr, dword) \
+ ((outpw((iop_base) + IOPW_RAM_ADDR, (addr)), \
+ outpw((iop_base) + IOPW_RAM_DATA, (ushort) ((dword) & 0xFFFF))), \
+ (outpw((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
+ outpw((iop_base) + IOPW_RAM_DATA, (ushort) ((dword >> 16) & 0xFFFF))))
+
+/* Read word (2 bytes) from LRAM assuming that the address is already set. */
+#define AdvReadWordAutoIncLram(iop_base) \
+ (inpw((iop_base) + IOPW_RAM_DATA))
+
+/* Write word (2 bytes) to LRAM assuming that the address is already set. */
+#define AdvWriteWordAutoIncLram(iop_base, word) \
+ (outpw((iop_base) + IOPW_RAM_DATA, (word)))
+
+#else /* version >= v1,3,0 */
+
+/* Read byte from a register. */
+#define AdvReadByteRegister(iop_base, reg_off) \
+ (ADV_MEM_READB((iop_base) + (reg_off)))
+
+/* Write byte to a register. */
+#define AdvWriteByteRegister(iop_base, reg_off, byte) \
+ (ADV_MEM_WRITEB((iop_base) + (reg_off), (byte)))
+
+/* Read word (2 bytes) from a register. */
+#define AdvReadWordRegister(iop_base, reg_off) \
+ (ADV_MEM_READW((iop_base) + (reg_off)))
+
+/* Write word (2 bytes) to a register. */
+#define AdvWriteWordRegister(iop_base, reg_off, word) \
+ (ADV_MEM_WRITEW((iop_base) + (reg_off), (word)))
+
+/* Read byte from LRAM. */
+#define AdvReadByteLram(iop_base, addr, byte) \
+do { \
+ ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
+ (byte) = ADV_MEM_READB((iop_base) + IOPB_RAM_DATA); \
+} while (0)
+
+/* Write byte to LRAM. */
+#define AdvWriteByteLram(iop_base, addr, byte) \
+ (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
+ ADV_MEM_WRITEB((iop_base) + IOPB_RAM_DATA, (byte)))
+
+/* Read word (2 bytes) from LRAM. */
+#define AdvReadWordLram(iop_base, addr, word) \
+do { \
+ ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)); \
+ (word) = ADV_MEM_READW((iop_base) + IOPW_RAM_DATA); \
+} while (0)
+
+/* Write word (2 bytes) to LRAM. */
+#define AdvWriteWordLram(iop_base, addr, word) \
+ (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
+ ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
+
+/* Write double word (4 bytes) to LRAM */
+/* Because of unspecified C language ordering don't use auto-increment. */
+#define AdvWriteDWordLram(iop_base, addr, dword) \
+ ((ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr)), \
+ ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
+ (ushort) ((dword) & 0xFFFF))), \
+ (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_ADDR, (addr) + 2), \
+ ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, \
+ (ushort) ((dword >> 16) & 0xFFFF))))
+
+/* Read word (2 bytes) from LRAM assuming that the address is already set. */
+#define AdvReadWordAutoIncLram(iop_base) \
+ (ADV_MEM_READW((iop_base) + IOPW_RAM_DATA))
+
+/* Write word (2 bytes) to LRAM assuming that the address is already set. */
+#define AdvWriteWordAutoIncLram(iop_base, word) \
+ (ADV_MEM_WRITEW((iop_base) + IOPW_RAM_DATA, (word)))
+
+#endif /* version >= v1,3,0 */
+
+/*
+ * Define macro to check for Condor signature.
+ *
+ * Evaluate to ADV_TRUE if a Condor chip is found the specified port
+ * address 'iop_base'. Otherwise evalue to ADV_FALSE.
+ */
+#define AdvFindSignature(iop_base) \
+ (((AdvReadByteRegister((iop_base), IOPB_CHIP_ID_1) == \
+ ADV_CHIP_ID_BYTE) && \
+ (AdvReadWordRegister((iop_base), IOPW_CHIP_ID_0) == \
+ ADV_CHIP_ID_WORD)) ? ADV_TRUE : ADV_FALSE)
+
+/*
+ * Define macro to Return the version number of the chip at 'iop_base'.
+ *
+ * The second parameter 'bus_type' is currently unused.
+ */
+#define AdvGetChipVersion(iop_base, bus_type) \
+ AdvReadByteRegister((iop_base), IOPB_CHIP_TYPE_REV)
+
+/*
+ * Abort an SRB in the chip's RISC Memory. The 'srb_ptr' argument must
+ * match the ASC_SCSI_REQ_Q 'srb_ptr' field.
+ *
+ * If the request has not yet been sent to the device it will simply be
+ * aborted from RISC memory. If the request is disconnected it will be
+ * aborted on reselection by sending an Abort Message to the target ID.
+ *
+ * Return value:
+ * ADV_TRUE(1) - Queue was successfully aborted.
+ * ADV_FALSE(0) - Queue was not found on the active queue list.
+ */
+#define AdvAbortSRB(asc_dvc, srb_ptr) \
+ AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_ABORT, \
+ (ulong) (srb_ptr), 0)
+
+/*
+ * Send a Bus Device Reset Message to the specified target ID.
+ *
+ * All outstanding commands will be purged if sending the
+ * Bus Device Reset Message is successful.
+ *
+ * Return Value:
+ * ADV_TRUE(1) - All requests on the target are purged.
+ * ADV_FALSE(0) - Couldn't issue Bus Device Reset Message; Requests
+ * are not purged.
+ */
+#define AdvResetDevice(asc_dvc, target_id) \
+ AdvSendIdleCmd((asc_dvc), (ushort) IDLE_CMD_DEVICE_RESET, \
+ (ulong) (target_id), 0)
+
+/*
+ * SCSI Wide Type definition.
+ */
+#define ADV_SCSI_BIT_ID_TYPE ushort
+
+/*
+ * AdvInitScsiTarget() 'cntl_flag' options.
+ */
+#define ADV_SCAN_LUN 0x01
+#define ADV_CAPINFO_NOLUN 0x02
+
+/*
+ * Convert target id to target id bit mask.
+ */
+#define ADV_TID_TO_TIDMASK(tid) (0x01 << ((tid) & ADV_MAX_TID))
+
+/*
+ * ASC_SCSI_REQ_Q 'done_status' and 'host_status' return values.
+ */
+
+#define QD_NO_STATUS 0x00 /* Request not completed yet. */
+#define QD_NO_ERROR 0x01
+#define QD_ABORTED_BY_HOST 0x02
+#define QD_WITH_ERROR 0x04
+
+#define QHSTA_NO_ERROR 0x00
+#define QHSTA_M_SEL_TIMEOUT 0x11
+#define QHSTA_M_DATA_OVER_RUN 0x12
+#define QHSTA_M_UNEXPECTED_BUS_FREE 0x13
+#define QHSTA_M_QUEUE_ABORTED 0x15
+#define QHSTA_M_SXFR_SDMA_ERR 0x16 /* SXFR_STATUS SCSI DMA Error */
+#define QHSTA_M_SXFR_SXFR_PERR 0x17 /* SXFR_STATUS SCSI Bus Parity Error */
+#define QHSTA_M_RDMA_PERR 0x18 /* RISC PCI DMA parity error */
+#define QHSTA_M_SXFR_OFF_UFLW 0x19 /* SXFR_STATUS Offset Underflow */
+#define QHSTA_M_SXFR_OFF_OFLW 0x20 /* SXFR_STATUS Offset Overflow */
+#define QHSTA_M_SXFR_WD_TMO 0x21 /* SXFR_STATUS Watchdog Timeout */
+#define QHSTA_M_SXFR_DESELECTED 0x22 /* SXFR_STATUS Deselected */
+/* Note: QHSTA_M_SXFR_XFR_OFLW is identical to QHSTA_M_DATA_OVER_RUN. */
+#define QHSTA_M_SXFR_XFR_OFLW 0x12 /* SXFR_STATUS Transfer Overflow */
+#define QHSTA_M_SXFR_XFR_PH_ERR 0x24 /* SXFR_STATUS Transfer Phase Error */
+#define QHSTA_M_SXFR_UNKNOWN_ERROR 0x25 /* SXFR_STATUS Unknown Error */
+#define QHSTA_M_WTM_TIMEOUT 0x41
+#define QHSTA_M_BAD_CMPL_STATUS_IN 0x42
+#define QHSTA_M_NO_AUTO_REQ_SENSE 0x43
+#define QHSTA_M_AUTO_REQ_SENSE_FAIL 0x44
+#define QHSTA_M_INVALID_DEVICE 0x45 /* Bad target ID */
+
+typedef int (* ADV_ISR_CALLBACK)
+ (ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+
+typedef int (* ADV_SBRESET_CALLBACK)
+ (ADV_DVC_VAR *);
+
+/*
+ * Default EEPROM Configuration structure defined in a_init.c.
+ */
+extern ADVEEP_CONFIG Default_EEPROM_Config;
+
+/*
+ * DvcGetPhyAddr() flag arguments
+ */
+#define ADV_IS_SCSIQ_FLAG 0x01 /* 'addr' is ASC_SCSI_REQ_Q pointer */
+#define ADV_ASCGETSGLIST_VADDR 0x02 /* 'addr' is AscGetSGList() virtual addr */
+#define ADV_IS_SENSE_FLAG 0x04 /* 'addr' is sense virtual pointer */
+#define ADV_IS_DATA_FLAG 0x08 /* 'addr' is data virtual pointer */
+#define ADV_IS_SGLIST_FLAG 0x10 /* 'addr' is sglist virtual pointer */
+
+/* 'IS_SCSIQ_FLAG is now obsolete; Instead use ADV_IS_SCSIQ_FLAG. */
+#define IS_SCSIQ_FLAG ADV_IS_SCSIQ_FLAQ
+
+
+/* Return the address that is aligned at the next doubleword >= to 'addr'. */
+#define ADV_DWALIGN(addr) (((ulong) (addr) + 0x3) & ~0x3)
+
+/*
+ * Total contiguous memory needed for driver SG blocks.
+ *
+ * ADV_MAX_SG_LIST must be defined by a driver. It is the maximum
+ * number of scatter-gather elements the driver supports in a
+ * single request.
+ */
+
+#ifndef ADV_MAX_SG_LIST
+Forced Error: Driver must define ADV_MAX_SG_LIST.
+#endif /* ADV_MAX_SG_LIST */
+
+#define ADV_SG_LIST_MAX_BYTE_SIZE \
+ (sizeof(ADV_SG_BLOCK) * \
+ ((ADV_MAX_SG_LIST + (NO_OF_SG_PER_BLOCK - 1))/NO_OF_SG_PER_BLOCK))
+
+/*
+ * A driver may optionally define the assertion macro ADV_ASSERT() in
+ * its d_os_dep.h file. If the macro has not already been defined,
+ * then define the macro to a no-op.
+ */
+#ifndef ADV_ASSERT
+#define ADV_ASSERT(a)
+#endif /* ADV_ASSERT */
+
+
+/*
* --- Driver Constants and Macros
*/
-#define ASC_NUM_BOARD_SUPPORTED 4
+#define ASC_NUM_BOARD_SUPPORTED 16
+#define ASC_NUM_IOPORT_PROBE 4
#define ASC_NUM_BUS 4
/* Reference Scsi_Host hostdata */
@@ -2155,22 +3194,27 @@ STATIC ulong AscGetMaxDmaCount(ushort);
/* asc_board_t flags */
#define ASC_HOST_IN_RESET 0x01
#define ASC_HOST_IN_ABORT 0x02
+#define ASC_IS_WIDE_BOARD 0x04 /* AdvanSys Wide Board */
+#define ASC_SELECT_QUEUE_DEPTHS 0x08
+
+#define ASC_NARROW_BOARD(boardp) (((boardp)->flags & ASC_IS_WIDE_BOARD) == 0)
+#define ASC_WIDE_BOARD(boardp) ((boardp)->flags & ASC_IS_WIDE_BOARD)
#define NO_ISA_DMA 0xff /* No ISA DMA Channel Used */
/*
- * If the Linux kernel version supports throwing away initialization code
+ * If the Linux kernel version supports freeing initialization code
* and data after loading, define macros for this purpose. These macros
* are not used when the driver is built as a module, cf. linux/init.h.
*/
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,23)
-#define ASC_INITFUNC(func) __initfunc(func)
-#define ASC_INITDATA __initdata
-#define ASC_INIT __init
-#else /* version >= v2.1.23 */
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,23)
#define ASC_INITFUNC(func) func
#define ASC_INITDATA
#define ASC_INIT
+#else /* version >= v2.1.23 */
+#define ASC_INITFUNC(func) __initfunc(func)
+#define ASC_INITDATA __initdata
+#define ASC_INIT __init
#endif /* version >= v2.1.23 */
#define ASC_INFO_SIZE 128 /* advansys_info() line size */
@@ -2216,11 +3260,11 @@ STATIC ulong AscGetMaxDmaCount(ushort);
* REQTIMESTAMP() - system time stamp value
*/
typedef Scsi_Cmnd REQ, *REQP;
-#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
-#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
+#define REQPNEXT(reqp) ((REQP) ((reqp)->host_scribble))
+#define REQPNEXTP(reqp) ((REQP *) &((reqp)->host_scribble))
#define REQPTID(reqp) ((reqp)->target)
-#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
-#define REQTIMESTAMP() (jiffies)
+#define REQPTIME(reqp) ((reqp)->SCp.this_residual)
+#define REQTIMESTAMP() (jiffies)
#define REQTIMESTAT(function, ascq, reqp, tid) \
{ \
@@ -2253,7 +3297,7 @@ typedef Scsi_Cmnd REQ, *REQP;
}
/* asc_enqueue() flags */
-#define ASC_FRONT 1
+#define ASC_FRONT 1
#define ASC_BACK 2
/* asc_dequeue_list() argument */
@@ -2316,6 +3360,7 @@ typedef Scsi_Cmnd REQ, *REQP;
#define ASC_PCI_DEVICE_ID_1100 0x1100
#define ASC_PCI_DEVICE_ID_1200 0x1200
#define ASC_PCI_DEVICE_ID_1300 0x1300
+#define ASC_PCI_DEVICE_ID_2300 0x2300
/* PCI IO Port Addresses to generate special cycle */
@@ -2397,8 +3442,10 @@ typedef Scsi_Cmnd REQ, *REQP;
#define ASC_DBG4(lvl, s, a1, a2, a3, a4)
#define ASC_DBG_PRT_SCSI_HOST(lvl, s)
#define ASC_DBG_PRT_SCSI_CMND(lvl, s)
-#define ASC_DBG_PRT_SCSI_Q(lvl, scsiqp)
-#define ASC_DBG_PRT_QDONE_INFO(lvl, qdone)
+#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp)
+#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
+#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone)
+#define ADV_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp)
#define ASC_DBG_PRT_HEX(lvl, name, start, length)
#define ASC_DBG_PRT_CDB(lvl, cdb, len)
#define ASC_DBG_PRT_SENSE(lvl, sense, len)
@@ -2462,17 +3509,24 @@ typedef Scsi_Cmnd REQ, *REQP;
} \
}
-#define ASC_DBG_PRT_SCSI_Q(lvl, scsiqp) \
+#define ASC_DBG_PRT_ASC_SCSI_Q(lvl, scsiqp) \
+ { \
+ if (asc_dbglvl >= (lvl)) { \
+ asc_prt_asc_scsi_q(scsiqp); \
+ } \
+ }
+
+#define ASC_DBG_PRT_ASC_QDONE_INFO(lvl, qdone) \
{ \
if (asc_dbglvl >= (lvl)) { \
- asc_prt_scsi_q(scsiqp); \
+ asc_prt_asc_qdone_info(qdone); \
} \
}
-#define ASC_DBG_PRT_QDONE_INFO(lvl, qdone) \
+#define ASC_DBG_PRT_ADV_SCSI_REQ_Q(lvl, scsiqp) \
{ \
if (asc_dbglvl >= (lvl)) { \
- asc_prt_qdone_info(qdone); \
+ asc_prt_adv_scsi_req_q(scsiqp); \
} \
}
@@ -2522,15 +3576,17 @@ struct asc_stats {
ulong abort; /* # calls to advansys_abort() */
ulong reset; /* # calls to advansys_reset() */
ulong biosparam; /* # calls to advansys_biosparam() */
- ulong check_interrupt; /* # advansys_interrupt() check pending calls */
- ulong interrupt; /* # advansys_interrupt() interrupts */
- ulong callback; /* # calls asc_isr_callback() */
- ulong done; /* # calls request scsi_done */
- /* AscExeScsiQueue() Statistics */
- ulong asc_noerror; /* # AscExeScsiQueue() ASC_NOERROR returns. */
- ulong asc_busy; /* # AscExeScsiQueue() ASC_BUSY returns. */
- ulong asc_error; /* # AscExeScsiQueue() ASC_ERROR returns. */
- ulong asc_unknown; /* # AscExeScsiQueue() unknown returns. */
+ ulong interrupt; /* # advansys_interrupt() calls */
+ ulong callback; /* # calls to asc/adv_isr_callback() */
+ ulong done; /* # calls to request's scsi_done function */
+ ulong build_error; /* # asc/adv_build_req() ASC_ERROR returns. */
+ ulong adv_build_noreq; /* # adv_build_req() adv_req_t alloc. fail. */
+ ulong adv_build_nosg; /* # adv_build_req() adv_sgblk_t alloc. fail. */
+ /* AscExeScsiQueue()/AdvExeScsiQueue() Statistics */
+ ulong exe_noerror; /* # ASC_NOERROR returns. */
+ ulong exe_busy; /* # ASC_BUSY returns. */
+ ulong exe_error; /* # ASC_ERROR returns. */
+ ulong exe_unknown; /* # unknown returns. */
/* Data Transfer Statistics */
ulong cont_cnt; /* # non-scatter-gather I/O requests received */
ulong cont_xfer; /* # contiguous transfer 512-bytes */
@@ -2544,20 +3600,49 @@ struct asc_stats {
* Request queuing structure
*/
typedef struct asc_queue {
- ASC_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
- REQP q_first[ASC_MAX_TID+1]; /* first queued request */
- REQP q_last[ASC_MAX_TID+1]; /* last queued request */
+ ADV_SCSI_BIT_ID_TYPE q_tidmask; /* queue mask */
+ REQP q_first[ADV_MAX_TID+1]; /* first queued request */
+ REQP q_last[ADV_MAX_TID+1]; /* last queued request */
#ifdef ADVANSYS_STATS
- short q_cur_cnt[ASC_MAX_TID+1]; /* current queue count */
- short q_max_cnt[ASC_MAX_TID+1]; /* maximum queue count */
- ulong q_tot_cnt[ASC_MAX_TID+1]; /* total enqueue count */
- ulong q_tot_tim[ASC_MAX_TID+1]; /* total time queued */
- ushort q_max_tim[ASC_MAX_TID+1]; /* maximum time queued */
- ushort q_min_tim[ASC_MAX_TID+1]; /* minimum time queued */
+ short q_cur_cnt[ADV_MAX_TID+1]; /* current queue count */
+ short q_max_cnt[ADV_MAX_TID+1]; /* maximum queue count */
+ ulong q_tot_cnt[ADV_MAX_TID+1]; /* total enqueue count */
+ ulong q_tot_tim[ADV_MAX_TID+1]; /* total time queued */
+ ushort q_max_tim[ADV_MAX_TID+1]; /* maximum time queued */
+ ushort q_min_tim[ADV_MAX_TID+1]; /* minimum time queued */
#endif /* ADVANSYS_STATS */
} asc_queue_t;
/*
+ * Adv Library Request Structures
+ *
+ * The following two se structures are used to process Wide Board requests.
+ * One structure is needed for each command received from the Mid-Level SCSI
+ * driver.
+ *
+ * The ADV_SCSI_REQ_Q structure in adv_req_t is passed to the Adv Library
+ * and microcode with the ADV_SCSI_REQ_Q field 'srb_ptr' pointing to the
+ * adv_req_t. The adv_req_t structure 'cmndp' field in turn points to the
+ * Mid-Level SCSI request structure.
+ *
+ * The adv_sgblk_t structure is used to handle requests that include
+ * scatter-gather elements.
+ */
+typedef struct adv_sgblk {
+ ADV_SG_BLOCK sg_block[ADV_NUM_SG_BLOCK + ADV_NUM_PAGE_CROSSING];
+ uchar align2[4]; /* Sgblock structure padding. */
+ struct adv_sgblk *next_sgblkp; /* Next scatter-gather structure. */
+} adv_sgblk_t;
+
+typedef struct adv_req {
+ ADV_SCSI_REQ_Q scsi_req_q; /* Adv Library request structure. */
+ uchar align1[4]; /* Request structure padding. */
+ Scsi_Cmnd *cmndp; /* Mid-Level SCSI command pointer. */
+ adv_sgblk_t *sgblkp; /* Adv Library scatter-gather pointer. */
+ struct adv_req *next_reqp; /* Next Request Structure. */
+} adv_req_t;
+
+/*
* Structure allocated for each board.
*
* This structure is allocated by scsi_register() at the end
@@ -2565,35 +3650,60 @@ typedef struct asc_queue {
* field. It is guaranteed to be allocated from DMA-able memory.
*/
typedef struct asc_board {
- int id; /* Board Id */
- uint flags; /* Board flags */
- ASC_DVC_VAR asc_dvc_var; /* Board configuration */
- ASC_DVC_CFG asc_dvc_cfg; /* Device configuration */
- asc_queue_t active; /* Active command queue */
- asc_queue_t waiting; /* Waiting command queue */
- asc_queue_t done; /* Done command queue */
- ASC_SCSI_BIT_ID_TYPE init_tidmask; /* Target initialized mask */
- /* The following three structures must be in DMA-able memory. */
- ASC_SCSI_REQ_Q scsireqq;
- ASC_CAP_INFO cap_info;
- ASC_SCSI_INQUIRY inquiry;
- Scsi_Device *device[ASC_MAX_TID+1]; /* Mid-Level Scsi Device */
- ushort reqcnt[ASC_MAX_TID+1]; /* Starvation request count */
- uchar sdtr_data[ASC_MAX_TID+1]; /* SDTR information */
+ int id; /* Board Id */
+ uint flags; /* Board flags */
+ union {
+ ASC_DVC_VAR asc_dvc_var; /* Narrow board */
+ ADV_DVC_VAR adv_dvc_var; /* Wide board */
+ } dvc_var;
+ union {
+ ASC_DVC_CFG asc_dvc_cfg; /* Narrow board */
+ ADV_DVC_CFG adv_dvc_cfg; /* Wide board */
+ } dvc_cfg;
+ asc_queue_t active; /* Active command queue */
+ asc_queue_t waiting; /* Waiting command queue */
+ asc_queue_t done; /* Done command queue */
+ ADV_SCSI_BIT_ID_TYPE init_tidmask; /* Target init./valid mask */
+ Scsi_Device *device[ADV_MAX_TID+1]; /* Mid-Level Scsi Device */
+ ushort reqcnt[ADV_MAX_TID+1]; /* Starvation request count */
#if ASC_QUEUE_FLOW_CONTROL
- ushort nerrcnt[ASC_MAX_TID+1]; /* No error request count */
+ ushort nerrcnt[ADV_MAX_TID+1]; /* No error request count */
#endif /* ASC_QUEUE_FLOW_CONTROL */
- ASC_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
- ushort queue_full_cnt[ASC_MAX_TID+1]; /* Queue full count */
- ASCEEP_CONFIG eep_config; /* EEPROM configuration */
- ulong last_reset; /* Saved last reset time */
+ ADV_SCSI_BIT_ID_TYPE queue_full; /* Queue full mask */
+ ushort queue_full_cnt[ADV_MAX_TID+1]; /* Queue full count */
+ union {
+ ASCEEP_CONFIG asc_eep; /* Narrow EEPROM config. */
+ ADVEEP_CONFIG adv_eep; /* Wide EEPROM config. */
+ } eep_config;
+ ulong last_reset; /* Saved last reset time */
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
/* /proc/scsi/advansys/[0...] */
- char *prtbuf; /* Statistics Print Buffer */
+ char *prtbuf; /* Statistics Print Buffer */
#endif /* version >= v1.3.0 */
#ifdef ADVANSYS_STATS
- struct asc_stats asc_stats; /* Board statistics */
+ struct asc_stats asc_stats; /* Board statistics */
#endif /* ADVANSYS_STATS */
+ /*
+ * The following fields are used only for Narrow Boards.
+ */
+ /* The following three structures must be in DMA-able memory. */
+ ASC_SCSI_REQ_Q scsireqq;
+ ASC_CAP_INFO cap_info;
+ ASC_SCSI_INQUIRY inquiry;
+ uchar sdtr_data[ASC_MAX_TID+1]; /* SDTR information */
+ /*
+ * The following fields are used only for Wide Boards.
+ */
+ void *ioremap_addr; /* I/O Memory remap address. */
+ ushort ioport; /* I/O Port address. */
+ adv_req_t *orig_reqp; /* adv_req_t memory block. */
+ adv_req_t *adv_reqp; /* Request structures. */
+ adv_sgblk_t *orig_sgblkp; /* adv_sgblk_t memory block. */
+ adv_sgblk_t *adv_sgblkp; /* Scatter-gather structures. */
+ ushort bios_signature; /* BIOS Signature. */
+ ushort bios_version; /* BIOS Version. */
+ ushort bios_codeseg; /* BIOS Code Segment. */
+ ushort bios_codelen; /* BIOS Code Segment Length. */
} asc_board_t;
/*
@@ -2655,10 +3765,10 @@ typedef struct _PCI_CONFIG_SPACE_
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
struct proc_dir_entry proc_scsi_advansys =
{
- PROC_SCSI_ADVANSYS, /* unsigned short low_ino */
- 8, /* unsigned short namelen */
- "advansys", /* const char *name */
- S_IFDIR | S_IRUGO | S_IXUGO, /* mode_t mode */
+ PROC_SCSI_ADVANSYS, /* unsigned short low_ino */
+ 8, /* unsigned short namelen */
+ "advansys", /* const char *name */
+ S_IFDIR | S_IRUGO | S_IXUGO, /* mode_t mode */
2 /* nlink_t nlink */
};
#endif /* version >= v1.3.0 */
@@ -2691,7 +3801,18 @@ STATIC int pci_scan_method ASC_INITDATA = -1;
* limit I/O port probing at boot time, cf. advansys_setup().
*/
STATIC int asc_iopflag = ASC_FALSE;
-STATIC int asc_ioport[ASC_NUM_BOARD_SUPPORTED] = { 0, 0, 0, 0 };
+STATIC int asc_ioport[ASC_NUM_IOPORT_PROBE] = { 0, 0, 0, 0 };
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+/*
+ * In kernels earlier than v1.3.0, kmalloc() does not work
+ * during driver initialization. Therefore statically declare
+ * 16 elements of each structure. v1.3.0 kernels will probably
+ * not need any more than this number.
+ */
+uchar adv_req_buf[16 * sizeof(adv_req_t)] = { 0 };
+uchar adv_sgblk_buf[16 * sizeof(adv_sgblk_t)] = { 0 };
+#endif /* version >= v1,3,0 */
#ifdef ADVANSYS_DEBUG
STATIC char *
@@ -2727,47 +3848,59 @@ STATIC void advansys_interrupt(int, void *, struct pt_regs *);
STATIC void advansys_select_queue_depths(struct Scsi_Host *,
Scsi_Device *);
#endif /* version >= v1.3.89 */
-STATIC void advansys_command_done(Scsi_Cmnd *);
-STATIC void asc_scsi_done_list(Scsi_Cmnd *);
-STATIC int asc_execute_scsi_cmnd(Scsi_Cmnd *);
-STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
-STATIC int asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *);
-STATIC int asc_srch_pci_dev(PCI_DEVICE *);
-STATIC uchar asc_scan_method(void);
-STATIC int asc_pci_find_dev(PCI_DEVICE *);
-STATIC void asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *);
-STATIC ushort asc_get_cfg_word(PCI_DATA *);
-STATIC uchar asc_get_cfg_byte(PCI_DATA *);
-STATIC void asc_put_cfg_byte(PCI_DATA *, uchar);
-STATIC void asc_enqueue(asc_queue_t *, REQP, int);
-STATIC REQP asc_dequeue(asc_queue_t *, int);
-STATIC REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
-STATIC int asc_rmqueue(asc_queue_t *, REQP);
-STATIC int asc_isqueued(asc_queue_t *, REQP);
-STATIC void asc_execute_queue(asc_queue_t *);
+STATIC void advansys_command_done(Scsi_Cmnd *);
+STATIC void asc_scsi_done_list(Scsi_Cmnd *);
+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 **);
+STATIC int adv_get_sglist(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *, Scsi_Cmnd *);
+STATIC void asc_isr_callback(ASC_DVC_VAR *, ASC_QDONE_INFO *);
+STATIC void adv_isr_callback(ADV_DVC_VAR *, ADV_SCSI_REQ_Q *);
+STATIC int asc_init_dev(ASC_DVC_VAR *, Scsi_Cmnd *);
+STATIC int asc_srch_pci_dev(PCI_DEVICE *);
+STATIC uchar asc_scan_method(void);
+STATIC int asc_pci_find_dev(PCI_DEVICE *);
+STATIC void asc_get_pci_cfg(PCI_DEVICE *, PCI_CONFIG_SPACE *);
+STATIC ushort asc_get_cfg_word(PCI_DATA *);
+STATIC uchar asc_get_cfg_byte(PCI_DATA *);
+STATIC void asc_put_cfg_byte(PCI_DATA *, uchar);
+STATIC void asc_enqueue(asc_queue_t *, REQP, int);
+STATIC REQP asc_dequeue(asc_queue_t *, int);
+STATIC REQP asc_dequeue_list(asc_queue_t *, REQP *, int);
+STATIC int asc_rmqueue(asc_queue_t *, REQP);
+STATIC int asc_isqueued(asc_queue_t *, REQP);
+STATIC void asc_execute_queue(asc_queue_t *);
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
-STATIC int asc_prt_board_devices(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_board_eeprom(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_board_info(struct Scsi_Host *, char *, int);
-STATIC int asc_prt_line(char *, int, char *fmt, ...);
+STATIC int asc_prt_board_devices(struct Scsi_Host *, char *, int);
+STATIC int asc_prt_adv_bios(struct Scsi_Host *, char *, int);
+STATIC int asc_get_eeprom_string(ushort *serialnum, uchar *cp);
+STATIC int asc_prt_asc_board_eeprom(struct Scsi_Host *, char *, int);
+STATIC int asc_prt_adv_board_eeprom(struct Scsi_Host *, char *, int);
+STATIC int asc_prt_driver_conf(struct Scsi_Host *, char *, int);
+STATIC int asc_prt_asc_board_info(struct Scsi_Host *, char *, int);
+STATIC int asc_prt_adv_board_info(struct Scsi_Host *, char *, int);
+STATIC int asc_prt_line(char *, int, char *fmt, ...);
#endif /* version >= v1.3.0 */
/* Declaration for Asc Library internal functions reference by driver. */
-STATIC int AscFindSignature(PortAddr);
-STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
+STATIC int AscFindSignature(PortAddr);
+STATIC ushort AscGetEEPConfig(PortAddr, ASCEEP_CONFIG *, ushort);
#ifdef ADVANSYS_STATS
-STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int);
+STATIC int asc_prt_board_stats(struct Scsi_Host *, char *, int);
#endif /* ADVANSYS_STATS */
#ifdef ADVANSYS_DEBUG
STATIC void asc_prt_scsi_host(struct Scsi_Host *);
STATIC void asc_prt_scsi_cmnd(Scsi_Cmnd *);
-STATIC void asc_prt_dvc_cfg(ASC_DVC_CFG *);
-STATIC void asc_prt_dvc_var(ASC_DVC_VAR *);
-STATIC void asc_prt_scsi_q(ASC_SCSI_Q *);
-STATIC void asc_prt_qdone_info(ASC_QDONE_INFO *);
+STATIC void asc_prt_asc_dvc_cfg(ASC_DVC_CFG *);
+STATIC void asc_prt_asc_dvc_var(ASC_DVC_VAR *);
+STATIC void asc_prt_asc_scsi_q(ASC_SCSI_Q *);
+STATIC void asc_prt_asc_qdone_info(ASC_QDONE_INFO *);
+STATIC void asc_prt_adv_dvc_cfg(ADV_DVC_CFG *);
+STATIC void asc_prt_adv_dvc_var(ADV_DVC_VAR *);
+STATIC void asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *);
+STATIC void asc_prt_adv_sgblock(int, ADV_SG_BLOCK *);
STATIC void asc_prt_hex(char *f, uchar *, int);
#endif /* ADVANSYS_DEBUG */
@@ -2870,6 +4003,24 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
curbuf += cnt;
/*
+ * Display Wide Board BIOS Information.
+ */
+ if (ASC_WIDE_BOARD(boardp)) {
+ cp = boardp->prtbuf;
+ cplen = asc_prt_adv_bios(shp, cp, ASC_PRTBUF_SIZE);
+ ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
+ cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
+ totcnt += cnt;
+ leftlen -= cnt;
+ if (leftlen == 0) {
+ ASC_DBG1(1, "advansys_proc_info: totcnt %d\n", totcnt);
+ return totcnt;
+ }
+ advoffset += cplen;
+ curbuf += cnt;
+ }
+
+ /*
* Display driver information for each device attached to the board.
*/
cp = boardp->prtbuf;
@@ -2889,7 +4040,12 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
* Display target driver information for each device attached
* to the board.
*/
- for (scd = scsi_devices; scd; scd = scd->next) {
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75)
+ for (scd = scsi_devices; scd; scd = scd->next)
+#else /* version >= v2.1.75 */
+ for (scd = shp->host_queue; scd; scd = scd->next)
+#endif /* version >= v2.1.75 */
+ {
if (scd->host == shp) {
cp = boardp->prtbuf;
/*
@@ -2914,7 +4070,11 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
* Display EEPROM configuration for the board.
*/
cp = boardp->prtbuf;
- cplen = asc_prt_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+ if (ASC_NARROW_BOARD(boardp)) {
+ cplen = asc_prt_asc_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+ } else {
+ cplen = asc_prt_adv_board_eeprom(shp, cp, ASC_PRTBUF_SIZE);
+ }
ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
totcnt += cnt;
@@ -2965,7 +4125,11 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
* for the board.
*/
cp = boardp->prtbuf;
- cplen = asc_prt_board_info(shp, cp, ASC_PRTBUF_SIZE);
+ if (ASC_NARROW_BOARD(boardp)) {
+ cplen = asc_prt_asc_board_info(shp, cp, ASC_PRTBUF_SIZE);
+ } else {
+ cplen = asc_prt_adv_board_info(shp, cp, ASC_PRTBUF_SIZE);
+ }
ASC_ASSERT(cplen < ASC_PRTBUF_SIZE);
cnt = asc_proc_copy(advoffset, offset, curbuf, leftlen, cp, cplen);
totcnt += cnt;
@@ -2983,7 +4147,6 @@ advansys_proc_info(char *buffer, char **start, off_t offset, int length,
}
#endif /* version >= v1.3.0 */
-
/*
* advansys_detect()
*
@@ -3007,17 +4170,19 @@ advansys_detect(Scsi_Host_Template *tpnt)
int bus;
struct Scsi_Host *shp;
asc_board_t *boardp;
- ASC_DVC_VAR *asc_dvc_varp;
+ ASC_DVC_VAR *asc_dvc_varp = NULL;
+ ADV_DVC_VAR *adv_dvc_varp = NULL;
int ioport = 0;
int share_irq = FALSE;
PCI_DEVICE pciDevice;
PCI_CONFIG_SPACE pciConfig;
+ int warn_code, err_code;
int ret;
if (detect_called == ASC_FALSE) {
detect_called = ASC_TRUE;
} else {
- printk("AdvanSys SCSI: advansys_detect() mulitple calls ignored\n");
+ printk("AdvanSys SCSI: advansys_detect() multiple calls ignored\n");
return 0;
}
@@ -3034,7 +4199,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
* clean-up the 'asc_ioport' list.
*/
if (asc_iopflag == ASC_TRUE) {
- for (ioport = 0; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) {
+ for (ioport = 0; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
ASC_DBG2(1, "advansys_detect: asc_ioport[%d] %x\n",
ioport, asc_ioport[ioport]);
if (asc_ioport[ioport] != 0) {
@@ -3044,7 +4209,8 @@ advansys_detect(Scsi_Host_Template *tpnt)
}
}
if (iop == ASC_IOADR_TABLE_MAX_IX) {
- printk("AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
+ printk(
+"AdvanSys SCSI: specified I/O Port 0x%X is invalid\n",
asc_ioport[ioport]);
asc_ioport[ioport] = 0;
}
@@ -3084,7 +4250,7 @@ advansys_detect(Scsi_Host_Template *tpnt)
ASC_DBG(1, "advansys_detect: I/O port scanning modified\n");
ioport_try_again:
iop = 0;
- for (; ioport < ASC_NUM_BOARD_SUPPORTED; ioport++) {
+ for (; ioport < ASC_NUM_IOPORT_PROBE; ioport++) {
if ((iop = asc_ioport[ioport]) != 0) {
break;
}
@@ -3093,12 +4259,14 @@ advansys_detect(Scsi_Host_Template *tpnt)
ASC_DBG1(1, "advansys_detect: probing I/O port %x...\n",
iop);
if (check_region(iop, ASC_IOADR_GAP) != 0) {
- printk("AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop);
+ printk(
+"AdvanSys SCSI: specified I/O Port 0x%X is busy\n", iop);
/* Don't try this I/O port twice. */
asc_ioport[ioport] = 0;
goto ioport_try_again;
} else if (AscFindSignature(iop) == ASC_FALSE) {
- printk("AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop);
+ printk(
+"AdvanSys SCSI: specified I/O Port 0x%X has no adapter\n", iop);
/* Don't try this I/O port twice. */
asc_ioport[ioport] = 0;
goto ioport_try_again;
@@ -3144,7 +4312,10 @@ advansys_detect(Scsi_Host_Template *tpnt)
pciDevice.slotFound, pciDevice.busNumber);
asc_get_pci_cfg(&pciDevice, &pciConfig);
iop = pciConfig.baseAddress[0] & PCI_IOADDRESS_MASK;
- ASC_DBG2(2, "advansys_detect: iop %x, irqLine %d\n",
+ ASC_DBG2(1,
+ "advansys_detect: vendorID %X, deviceID %X\n",
+ pciConfig.vendorID, pciConfig.deviceID);
+ ASC_DBG2(2, "advansys_detect: iop %X, irqLine %d\n",
iop, pciConfig.irqLine);
}
break;
@@ -3179,13 +4350,76 @@ advansys_detect(Scsi_Host_Template *tpnt)
boardp = ASC_BOARDP(shp);
memset(boardp, 0, sizeof(asc_board_t));
boardp->id = asc_board_count - 1;
- asc_dvc_varp = &boardp->asc_dvc_var;
- asc_dvc_varp->drv_ptr = (ulong) boardp;
- asc_dvc_varp->cfg = &boardp->asc_dvc_cfg;
- asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
- asc_dvc_varp->iop_base = iop;
+
+ /*
+ * Handle both narrow and wide PCI boards.
+ *
+ * If a Wide board was detected, set the board structure
+ * wide board flag. Set-up the board structure based on
+ * the board type.
+ */
+ if ((asc_bus[bus] == ASC_IS_PCI &&
+ pciConfig.deviceID == ASC_PCI_DEVICE_ID_2300) == 0) {
+ ASC_DBG(1, "advansys_detect: narrow board\n");
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ asc_dvc_varp->bus_type = asc_bus[bus];
+ asc_dvc_varp->drv_ptr = (ulong) boardp;
+ asc_dvc_varp->cfg = &boardp->dvc_cfg.asc_dvc_cfg;
+ asc_dvc_varp->cfg->overrun_buf = &overrun_buf[0];
+ asc_dvc_varp->iop_base = iop;
+ asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback;
+ } else {
+ ASC_DBG(1, "advansys_detect: wide board\n");
+ boardp->flags |= ASC_IS_WIDE_BOARD;
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+ adv_dvc_varp->drv_ptr = (ulong) boardp;
+ adv_dvc_varp->cfg = &boardp->dvc_cfg.adv_dvc_cfg;
+ adv_dvc_varp->isr_callback = (Ptr2Func) adv_isr_callback;
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+ adv_dvc_varp->iop_base = iop;
+#else /* version >= v1,3,0 */
+ /*
+ * Map the board's registers into virtual memory for
+ * PCI slave access. Only memory accesses are used to
+ * access the board's registers.
+ *
+ * Note: The PCI register base address is not always
+ * page aligned, but the address passed to ioremap()
+ * must be page aligned. It is guaranteed that the
+ * PCI register base address will not cross a page
+ * boundary.
+ */
+ if ((boardp->ioremap_addr =
+ ioremap(pciConfig.baseAddress[1] & PAGE_MASK,
+ PAGE_SIZE)) == 0) {
+ ASC_PRINT3(
+"advansys_detect: board %d: ioremap(%lx, %d) returned NULL\n",
+ boardp->id, pciConfig.baseAddress[1], ADV_CONDOR_IOLEN);
+ scsi_unregister(shp);
+ asc_board_count--;
+ continue;
+ }
+ adv_dvc_varp->iop_base = (AdvPortAddr)
+ (boardp->ioremap_addr +
+ (pciConfig.baseAddress[1] -
+ (pciConfig.baseAddress[1] & PAGE_MASK)));
+#endif /* version >= v1,3,0 */
+
+ /*
+ * Even though it isn't used to access the board in
+ * kernels greater than or equal to v1.3.0, save
+ * the I/O Port address so that it can be reported and
+ * displayed.
+ */
+ boardp->ioport = iop;
+ }
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+ /*
+ * Allocate buffer for printing information from
+ * /proc/scsi/advansys/[0...].
+ */
if ((boardp->prtbuf =
kmalloc(ASC_PRTBUF_SIZE, GFP_ATOMIC)) == NULL) {
ASC_PRINT3(
@@ -3197,90 +4431,122 @@ advansys_detect(Scsi_Host_Template *tpnt)
}
#endif /* version >= v1.3.0 */
- /*
- * Set the board bus type and PCI IRQ for AscInitGetConfig().
- */
- asc_dvc_varp->bus_type = asc_bus[bus];
- switch (asc_dvc_varp->bus_type) {
- case ASC_IS_ISA:
- shp->unchecked_isa_dma = TRUE;
- share_irq = FALSE;
- break;
- case ASC_IS_VL:
- shp->unchecked_isa_dma = FALSE;
- share_irq = FALSE;
- break;
- case ASC_IS_EISA:
- shp->unchecked_isa_dma = FALSE;
- share_irq = TRUE;
- break;
- case ASC_IS_PCI:
- shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine;
- asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
- asc_dvc_varp->cfg->pci_slot_info =
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * Set the board bus type and PCI IRQ before
+ * calling AscInitGetConfig().
+ */
+ switch (asc_dvc_varp->bus_type) {
+ case ASC_IS_ISA:
+ shp->unchecked_isa_dma = TRUE;
+ share_irq = FALSE;
+ break;
+ case ASC_IS_VL:
+ shp->unchecked_isa_dma = FALSE;
+ share_irq = FALSE;
+ break;
+ case ASC_IS_EISA:
+ shp->unchecked_isa_dma = FALSE;
+ share_irq = TRUE;
+ break;
+ case ASC_IS_PCI:
+ shp->irq = asc_dvc_varp->irq_no = pciConfig.irqLine;
+ shp->unchecked_isa_dma = FALSE;
+ share_irq = TRUE;
+ asc_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
+ asc_dvc_varp->cfg->pci_slot_info =
ASC_PCI_MKID(pciDevice.busNumber,
- pciDevice.slotFound,
- pciDevice.devFunc);
+ pciDevice.slotFound,
+ pciDevice.devFunc);
+ break;
+ default:
+ ASC_PRINT2(
+"advansys_detect: board %d: unknown adapter type: %d\n",
+ boardp->id, asc_dvc_varp->bus_type);
+ shp->unchecked_isa_dma = TRUE;
+ share_irq = FALSE;
+ break;
+ }
+ } else {
+ /*
+ * For Wide boards set PCI information before calling
+ * AdvInitGetConfig().
+ */
+ shp->irq = adv_dvc_varp->irq_no = pciConfig.irqLine;
shp->unchecked_isa_dma = FALSE;
share_irq = TRUE;
- break;
- default:
- ASC_PRINT2(
-"advansys_detect: board %d: unknown adapter type: %d",
- boardp->id, asc_dvc_varp->bus_type);
- shp->unchecked_isa_dma = TRUE;
- share_irq = FALSE;
- break;
+ adv_dvc_varp->cfg->pci_device_id = pciConfig.deviceID;
+ adv_dvc_varp->cfg->pci_slot_info =
+ ASC_PCI_MKID(pciDevice.busNumber,
+ pciDevice.slotFound,
+ pciDevice.devFunc);
}
/*
- * Get the board configuration.
- *
- * NOTE: AscInitGetConfig() may change the board's bus_type
- * value. The asc_bus[bus] value should no longer be used. If
- * the bus_type field must be referenced only use the bit-wise
- * AND operator "&".
+ * Read the board configuration.
*/
- ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
- switch(ret = AscInitGetConfig(asc_dvc_varp)) {
- case 0: /* No error */
- break;
- case ASC_WARN_IO_PORT_ROTATE:
- ASC_PRINT1(
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * NOTE: AscInitGetConfig() may change the board's
+ * bus_type value. The asc_bus[bus] value should no
+ * longer be used. If the bus_type field must be
+ * referenced only use the bit-wise AND operator "&".
+ */
+ ASC_DBG(2, "advansys_detect: AscInitGetConfig()\n");
+ switch(ret = AscInitGetConfig(asc_dvc_varp)) {
+ case 0: /* No error */
+ break;
+ case ASC_WARN_IO_PORT_ROTATE:
+ ASC_PRINT1(
"AscInitGetConfig: board %d: I/O port address modified\n",
- boardp->id);
- break;
- case ASC_WARN_AUTO_CONFIG:
- ASC_PRINT1(
+ boardp->id);
+ break;
+ case ASC_WARN_AUTO_CONFIG:
+ ASC_PRINT1(
"AscInitGetConfig: board %d: I/O port increment switch enabled\n",
- boardp->id);
- break;
- case ASC_WARN_EEPROM_CHKSUM:
- ASC_PRINT1(
+ boardp->id);
+ break;
+ case ASC_WARN_EEPROM_CHKSUM:
+ ASC_PRINT1(
"AscInitGetConfig: board %d: EEPROM checksum error\n",
- boardp->id);
- break;
- case ASC_WARN_IRQ_MODIFIED:
- ASC_PRINT1(
+ boardp->id);
+ break;
+ case ASC_WARN_IRQ_MODIFIED:
+ ASC_PRINT1(
"AscInitGetConfig: board %d: IRQ modified\n",
- boardp->id);
- break;
- case ASC_WARN_CMD_QNG_CONFLICT:
- ASC_PRINT1(
+ boardp->id);
+ break;
+ case ASC_WARN_CMD_QNG_CONFLICT:
+ ASC_PRINT1(
"AscInitGetConfig: board %d: tag queuing enabled w/o disconnects\n",
- boardp->id);
- break;
- default:
- ASC_PRINT2(
+ boardp->id);
+ break;
+ default:
+ ASC_PRINT2(
"AscInitGetConfig: board %d: unknown warning: %x\n",
- boardp->id, ret);
- break;
- }
- if (asc_dvc_varp->err_code != 0) {
- ASC_PRINT3(
+ boardp->id, ret);
+ break;
+ }
+ if ((err_code = asc_dvc_varp->err_code) != 0) {
+ ASC_PRINT3(
"AscInitGetConfig: board %d error: init_state %x, err_code %x\n",
- boardp->id, asc_dvc_varp->init_state,
- asc_dvc_varp->err_code);
+ boardp->id, asc_dvc_varp->init_state,
+ asc_dvc_varp->err_code);
+ }
+ } else {
+ ASC_DBG(2, "advansys_detect: AdvInitGetConfig()\n");
+ if ((ret = AdvInitGetConfig(adv_dvc_varp)) != 0) {
+ ASC_PRINT2("AdvInitGetConfig: board %d: warning: %x\n",
+ boardp->id, ret);
+ }
+ if ((err_code = adv_dvc_varp->err_code) != 0) {
+ ASC_PRINT2(
+"AdvInitGetConfig: board %d error: err_code %x\n",
+ boardp->id, adv_dvc_varp->err_code);
+ }
+ }
+
+ if (err_code != 0) {
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
kfree(boardp->prtbuf);
#endif /* version >= v1.3.0 */
@@ -3290,110 +4556,180 @@ advansys_detect(Scsi_Host_Template *tpnt)
}
/*
- * Set the adapter's target id bit in the init_tidmask field.
+ * Save the EEPROM configuration so that it can be displayed
+ * from /proc/scsi/advansys/[0...].
*/
- boardp->init_tidmask |=
- ASC_TIX_TO_TARGET_ID(asc_dvc_varp->cfg->chip_scsi_id);
+ if (ASC_NARROW_BOARD(boardp)) {
- /*
- * Save EEPROM settings for the board.
- */
- boardp->eep_config.init_sdtr = asc_dvc_varp->init_sdtr;
- boardp->eep_config.disc_enable = asc_dvc_varp->cfg->disc_enable;
- boardp->eep_config.use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
- boardp->eep_config.isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed;
- boardp->eep_config.start_motor = asc_dvc_varp->start_motor;
- boardp->eep_config.cntl = asc_dvc_varp->dvc_cntl;
- boardp->eep_config.no_scam = asc_dvc_varp->no_scam;
- boardp->eep_config.max_total_qng = asc_dvc_varp->max_total_qng;
- boardp->eep_config.chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id;
- /* 'max_tag_qng' is set to the same value for every device. */
- boardp->eep_config.max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
+ ASCEEP_CONFIG *ep;
- /*
- * Modify board configuration.
- */
- asc_dvc_varp->isr_callback = (Ptr2Func) asc_isr_callback;
- asc_dvc_varp->exe_callback = (Ptr2Func) NULL;
+ /*
+ * Set the adapter's target id bit in the 'init_tidmask' field.
+ */
+ boardp->init_tidmask |=
+ ADV_TID_TO_TIDMASK(asc_dvc_varp->cfg->chip_scsi_id);
- ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n");
- switch (ret = AscInitSetConfig(asc_dvc_varp)) {
- case 0: /* No error. */
- break;
- case ASC_WARN_IO_PORT_ROTATE:
- ASC_PRINT1(
+ /*
+ * Save EEPROM settings for the board.
+ */
+ ep = &boardp->eep_config.asc_eep;
+
+ ep->init_sdtr = asc_dvc_varp->init_sdtr;
+ ep->disc_enable = asc_dvc_varp->cfg->disc_enable;
+ ep->use_cmd_qng = asc_dvc_varp->cfg->cmd_qng_enabled;
+ ep->isa_dma_speed = asc_dvc_varp->cfg->isa_dma_speed;
+ ep->start_motor = asc_dvc_varp->start_motor;
+ ep->cntl = asc_dvc_varp->dvc_cntl;
+ ep->no_scam = asc_dvc_varp->no_scam;
+ ep->max_total_qng = asc_dvc_varp->max_total_qng;
+ ep->chip_scsi_id = asc_dvc_varp->cfg->chip_scsi_id;
+ /* 'max_tag_qng' is set to the same value for every device. */
+ ep->max_tag_qng = asc_dvc_varp->cfg->max_tag_qng[0];
+ ep->adapter_info[0] = asc_dvc_varp->cfg->adapter_info[0];
+ ep->adapter_info[1] = asc_dvc_varp->cfg->adapter_info[1];
+ ep->adapter_info[2] = asc_dvc_varp->cfg->adapter_info[2];
+ ep->adapter_info[3] = asc_dvc_varp->cfg->adapter_info[3];
+ ep->adapter_info[4] = asc_dvc_varp->cfg->adapter_info[4];
+ ep->adapter_info[5] = asc_dvc_varp->cfg->adapter_info[5];
+ ep->adapter_info[6] = asc_dvc_varp->cfg->adapter_info[6];
+
+ /*
+ * Modify board configuration.
+ */
+ ASC_DBG(2, "advansys_detect: AscInitSetConfig()\n");
+ switch (ret = AscInitSetConfig(asc_dvc_varp)) {
+ case 0: /* No error. */
+ break;
+ case ASC_WARN_IO_PORT_ROTATE:
+ ASC_PRINT1(
"AscInitSetConfig: board %d: I/O port address modified\n",
- boardp->id);
- break;
- case ASC_WARN_AUTO_CONFIG:
- ASC_PRINT1(
+ boardp->id);
+ break;
+ case ASC_WARN_AUTO_CONFIG:
+ ASC_PRINT1(
"AscInitSetConfig: board %d: I/O port increment switch enabled\n",
- boardp->id);
- break;
- case ASC_WARN_EEPROM_CHKSUM:
- ASC_PRINT1(
+ boardp->id);
+ break;
+ case ASC_WARN_EEPROM_CHKSUM:
+ ASC_PRINT1(
"AscInitSetConfig: board %d: EEPROM checksum error\n",
- boardp->id);
- break;
- case ASC_WARN_IRQ_MODIFIED:
- ASC_PRINT1(
+ boardp->id);
+ break;
+ case ASC_WARN_IRQ_MODIFIED:
+ ASC_PRINT1(
"AscInitSetConfig: board %d: IRQ modified\n",
- boardp->id);
- break;
- case ASC_WARN_CMD_QNG_CONFLICT:
- ASC_PRINT1(
+ boardp->id);
+ break;
+ case ASC_WARN_CMD_QNG_CONFLICT:
+ ASC_PRINT1(
"AscInitSetConfig: board %d: tag queuing w/o disconnects\n",
- boardp->id);
- break;
- default:
- ASC_PRINT2(
+ boardp->id);
+ break;
+ default:
+ ASC_PRINT2(
"AscInitSetConfig: board %d: unknown warning: %x\n",
- boardp->id, ret);
- break;
- }
- if (asc_dvc_varp->err_code != 0) {
- ASC_PRINT3(
+ boardp->id, ret);
+ break;
+ }
+ if (asc_dvc_varp->err_code != 0) {
+ ASC_PRINT3(
"AscInitSetConfig: board %d error: init_state %x, err_code %x\n",
- boardp->id, asc_dvc_varp->init_state,
- asc_dvc_varp->err_code);
+ boardp->id, asc_dvc_varp->init_state,
+ asc_dvc_varp->err_code);
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
- kfree(boardp->prtbuf);
+ kfree(boardp->prtbuf);
#endif /* version >= v1.3.0 */
- scsi_unregister(shp);
- asc_board_count--;
- continue;
- }
+ scsi_unregister(shp);
+ asc_board_count--;
+ continue;
+ }
- /*
- * Finish initializing the 'Scsi_Host' structure.
- */
+ /*
+ * Finish initializing the 'Scsi_Host' structure.
+ */
+ /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
+ if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
+ shp->irq = asc_dvc_varp->irq_no;
+ }
+ } else {
+
+ ADVEEP_CONFIG *ep;
+
+ /*
+ * Save Wide EEP Configuration Information.
+ */
+ ep = &boardp->eep_config.adv_eep;
+
+ ep->adapter_scsi_id = adv_dvc_varp->chip_scsi_id;
+ ep->max_host_qng = adv_dvc_varp->max_host_qng;
+ ep->max_dvc_qng = adv_dvc_varp->max_dvc_qng;
+ ep->termination = adv_dvc_varp->cfg->termination;
+ ep->disc_enable = adv_dvc_varp->cfg->disc_enable;
+ ep->bios_ctrl = adv_dvc_varp->bios_ctrl;
+ ep->wdtr_able = adv_dvc_varp->wdtr_able;
+ ep->sdtr_able = adv_dvc_varp->sdtr_able;
+ ep->ultra_able = adv_dvc_varp->ultra_able;
+ ep->tagqng_able = adv_dvc_varp->tagqng_able;
+ ep->start_motor = adv_dvc_varp->start_motor;
+ ep->scsi_reset_delay = adv_dvc_varp->scsi_reset_wait;
+ ep->bios_boot_delay = adv_dvc_varp->cfg->bios_boot_wait;
+ ep->serial_number_word1 = adv_dvc_varp->cfg->serial1;
+ ep->serial_number_word2 = adv_dvc_varp->cfg->serial2;
+ ep->serial_number_word3 = adv_dvc_varp->cfg->serial3;
- /* AscInitSetConfig() will set the IRQ for non-PCI boards. */
- if ((asc_dvc_varp->bus_type & ASC_IS_PCI) == 0) {
- shp->irq = asc_dvc_varp->irq_no;
+ /*
+ * Set the adapter's target id bit in the 'init_tidmask' field.
+ */
+ boardp->init_tidmask |=
+ ADV_TID_TO_TIDMASK(adv_dvc_varp->chip_scsi_id);
+
+ /*
+ * Finish initializing the 'Scsi_Host' structure.
+ */
+ shp->irq = adv_dvc_varp->irq_no;
}
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
/*
- * One host supports one channel. There are two different
- * hosts for each channel of a dual channel board.
+ * Channels are numbered beginning with 0. For AdvanSys One host
+ * structure supports one channel. Multi-channel boards have a
+ * separate host structure for each channel.
*/
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
shp->max_channel = 0;
#endif /* version >= v1.3.89 */
- shp->max_id = ASC_MAX_TID + 1;
- shp->max_lun = ASC_MAX_LUN + 1;
+ if (ASC_NARROW_BOARD(boardp)) {
+ shp->max_id = ASC_MAX_TID + 1;
+ shp->max_lun = ASC_MAX_LUN + 1;
+
+ shp->io_port = asc_dvc_varp->iop_base;
+ shp->n_io_port = ASC_IOADR_GAP;
+ shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
+
+ /* Set maximum number of queues the adapter can handle. */
+ shp->can_queue = asc_dvc_varp->max_total_qng;
+ } else {
+ shp->max_id = ADV_MAX_TID + 1;
+ shp->max_lun = ADV_MAX_LUN + 1;
- shp->io_port = asc_dvc_varp->iop_base;
- shp->n_io_port = ASC_IOADR_GAP;
- shp->this_id = asc_dvc_varp->cfg->chip_scsi_id;
+ /*
+ * Save the I/O Port address and length even though the
+ * in v1.3.0 and greater kernels the region is not used
+ * by a Wide board. Instead the board is accessed with
+ * Memory Mapped I/O.
+ */
+ shp->io_port = iop;
+ shp->n_io_port = ADV_CONDOR_IOLEN;
- /* Maximum number of queues this adapter can handle. */
- shp->can_queue = asc_dvc_varp->max_total_qng;
+ shp->this_id = adv_dvc_varp->chip_scsi_id;
+
+ /* Set maximum number of queues the adapter can handle. */
+ shp->can_queue = adv_dvc_varp->max_host_qng;
+ }
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,89)
/*
- * Set a conservative 'cmd_per_lun' value to prevent memory
- * allocation failures.
+ * In old kernels without tag queuing support and with memory
+ * allocation problems set a conservative 'cmd_per_lun' value.
*/
#ifdef MODULE
shp->cmd_per_lun = 1;
@@ -3403,49 +4739,54 @@ advansys_detect(Scsi_Host_Template *tpnt)
ASC_DBG1(1, "advansys_detect: cmd_per_lun: %d\n", shp->cmd_per_lun);
#else /* version >= v1.3.89 */
/*
- * Use the host 'select_queue_depths' function to determine
- * the number of commands to queue per device.
- */
- shp->select_queue_depths = advansys_select_queue_depths;
-
-#ifdef MODULE
- /*
* Following v1.3.89, 'cmd_per_lun' is no longer needed
- * and should be set to zero. But because of a bug introduced
- * in v1.3.89 if the driver is compiled as a module and
- * 'cmd_per_lun' is zero, the Mid-Level SCSI function
- * 'allocate_device' will panic. To allow the driver to
- * work as a module in these kernels set 'cmd_per_lun' to 1.
+ * and should be set to zero.
+ *
+ * But because of a bug introduced in v1.3.89 if the driver is
+ * compiled as a module and 'cmd_per_lun' is zero, the Mid-Level
+ * SCSI function 'allocate_device' will panic. To allow the driver
+ * to work as a module in these kernels set 'cmd_per_lun' to 1.
*/
+#ifdef MODULE
shp->cmd_per_lun = 1;
#else /* MODULE */
shp->cmd_per_lun = 0;
#endif /* MODULE */
+ /*
+ * Use the host 'select_queue_depths' function to determine
+ * the number of commands to queue per device.
+ */
+ shp->select_queue_depths = advansys_select_queue_depths;
#endif /* version >= v1.3.89 */
/*
- * Set the maximum number of scatter-gather elements adapter
- * can handle.
+ * Set the maximum number of scatter-gather elements the
+ * adapter can handle.
*/
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * Allow two commands with 'sg_tablesize' scatter-gather
+ * elements to be executed simultaneously. This value is
+ * the theoretical hardware limit. It may be decreased
+ * below.
+ */
+ shp->sg_tablesize =
+ (((asc_dvc_varp->max_total_qng - 2) / 2) *
+ ASC_SG_LIST_PER_Q) + 1;
+ } else {
+ shp->sg_tablesize = ADV_MAX_SG_LIST;
+ }
#ifdef MODULE
/*
- * If the driver is compiled as a module, set a conservative
+ * If the driver is compiled as a module, set a limit on the
* 'sg_tablesize' value to prevent memory allocation failures.
* Memory allocation errors are more likely to occur at module
* load time, then at driver initialization time.
*/
- shp->sg_tablesize = 8;
-#else /* MODULE */
- /*
- * Allow two commands with 'sg_tablesize' scatter-gather
- * elements to be executed simultaneously. This value is
- * the theoretical hardware limit. It may be decreased
- * below.
- */
- shp->sg_tablesize =
- (((asc_dvc_varp->max_total_qng - 2) / 2) *
- ASC_SG_LIST_PER_Q) + 1;
+ if (shp->sg_tablesize > 64) {
+ shp->sg_tablesize = 64;
+ }
#endif /* MODULE */
/*
@@ -3462,52 +4803,96 @@ advansys_detect(Scsi_Host_Template *tpnt)
shp->sg_tablesize);
/* BIOS start address. */
- shp->base = (char *) ((ulong) AscGetChipBiosAddress(
+ if (ASC_NARROW_BOARD(boardp)) {
+ shp->base = (char *) ((ulong) AscGetChipBiosAddress(
asc_dvc_varp->iop_base,
asc_dvc_varp->bus_type));
+ } else {
+ /*
+ * Fill-in BIOS board variables. The Wide BIOS saves
+ * information in LRAM that is used by the driver.
+ */
+ AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_SIGNATURE,
+ boardp->bios_signature);
+ AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_VERSION,
+ boardp->bios_version);
+ AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODESEG,
+ boardp->bios_codeseg);
+ AdvReadWordLram(adv_dvc_varp->iop_base, BIOS_CODELEN,
+ boardp->bios_codelen);
+
+ ASC_DBG2(1,
+ "advansys_detect: bios_signature %x, bios_version %x\n",
+ boardp->bios_signature, boardp->bios_version);
+
+ ASC_DBG2(1,
+ "advansys_detect: bios_codeseg %x, bios_codelen %x\n",
+ boardp->bios_codeseg, boardp->bios_codelen);
+
+ /*
+ * If the BIOS saved a valid signature, then fill in
+ * the BIOS code segment base address.
+ */
+ if (boardp->bios_signature == 0x55AA) {
+ /*
+ * Convert x86 realmode code segment to a linear
+ * address by shifting left 4.
+ */
+ shp->base = (uchar *) (boardp->bios_codeseg << 4);
+ } else {
+ shp->base = 0;
+ }
+ }
/*
* Register Board Resources - I/O Port, DMA, IRQ
*/
- /* Register I/O port range */
+ /* Register I/O port range. */
ASC_DBG(2, "advansys_detect: request_region()\n");
request_region(shp->io_port, shp->n_io_port, "advansys");
- /* Register DMA channel for ISA bus. */
- if ((asc_dvc_varp->bus_type & ASC_IS_ISA) == 0) {
- shp->dma_channel = NO_ISA_DMA;
- } else {
- shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
- if ((ret = request_dma(shp->dma_channel, "advansys")) != 0) {
- ASC_PRINT3(
+ /* Register DMA Channel for Narrow boards. */
+ shp->dma_channel = NO_ISA_DMA; /* Default to no ISA DMA. */
+ if (ASC_NARROW_BOARD(boardp)) {
+ /* Register DMA channel for ISA bus. */
+ if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+ shp->dma_channel = asc_dvc_varp->cfg->isa_dma_channel;
+ if ((ret =
+ request_dma(shp->dma_channel, "advansys")) != 0) {
+ ASC_PRINT3(
"advansys_detect: board %d: request_dma() %d failed %d\n",
- boardp->id, shp->dma_channel, ret);
- release_region(shp->io_port, shp->n_io_port);
+ boardp->id, shp->dma_channel, ret);
+ release_region(shp->io_port, shp->n_io_port);
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
- kfree(boardp->prtbuf);
+ kfree(boardp->prtbuf);
#endif /* version >= v1.3.0 */
- scsi_unregister(shp);
- asc_board_count--;
- continue;
+ scsi_unregister(shp);
+ asc_board_count--;
+ continue;
+ }
+ AscEnableIsaDma(shp->dma_channel);
}
- AscEnableIsaDma(shp->dma_channel);
}
/* Register IRQ Number. */
ASC_DBG1(2, "advansys_detect: request_irq() %d\n", shp->irq);
#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,70)
if ((ret = request_irq(shp->irq, advansys_interrupt,
- SA_INTERRUPT, "advansys")) != 0) {
+ SA_INTERRUPT, "advansys")) != 0)
#else /* version >= v1.3.70 */
if ((ret = request_irq(shp->irq, advansys_interrupt,
SA_INTERRUPT | (share_irq == TRUE ? SA_SHIRQ : 0),
- "advansys", boardp)) != 0) {
+ "advansys", boardp)) != 0)
#endif /* version >= v1.3.70 */
+ {
ASC_PRINT2(
"advansys_detect: board %d: request_irq() failed %d\n",
boardp->id, ret);
release_region(shp->io_port, shp->n_io_port);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+ iounmap(boardp->ioremap_addr);
+#endif /* version >= v1,3,0 */
if (shp->dma_channel != NO_ISA_DMA) {
free_dma(shp->dma_channel);
}
@@ -3522,13 +4907,146 @@ advansys_detect(Scsi_Host_Template *tpnt)
/*
* Initialize board RISC chip and enable interrupts.
*/
- ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
- if (AscInitAsc1000Driver(asc_dvc_varp)) {
- ASC_PRINT3(
-"AscInitAsc1000Driver: board %d: error: init_state %x, err_code %x\n",
- boardp->id, asc_dvc_varp->init_state,
- asc_dvc_varp->err_code);
+ if (ASC_NARROW_BOARD(boardp)) {
+ ASC_DBG(2, "advansys_detect: AscInitAsc1000Driver()\n");
+ warn_code = AscInitAsc1000Driver(asc_dvc_varp);
+ err_code = asc_dvc_varp->err_code;
+
+ if (warn_code || err_code) {
+ ASC_PRINT4(
+"AscInitAsc1000Driver: board %d: error: init_state %x, warn %x error %x\n",
+ boardp->id, asc_dvc_varp->init_state,
+ warn_code, err_code);
+ }
+ } else {
+ int req_cnt;
+ adv_req_t *reqp = NULL;
+ int sg_cnt;
+ adv_sgblk_t *sgp = NULL;
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,0)
+ req_cnt = sizeof(adv_req_buf)/sizeof(adv_req_t);
+ sg_cnt = sizeof(adv_sgblk_buf)/sizeof(adv_sgblk_t);
+ reqp = (adv_req_t *) &adv_req_buf[0];
+ sgp = (adv_sgblk_t *) &adv_sgblk_buf[0];
+#else /* version >= v1.3.0 */
+ /*
+ * Allocate up to 'max_host_qng' request structures for
+ * the Wide board.
+ */
+ for (req_cnt = adv_dvc_varp->max_host_qng;
+ req_cnt > 0; req_cnt--) {
+
+ reqp = (adv_req_t *)
+ kmalloc(sizeof(adv_req_t) * req_cnt, GFP_ATOMIC);
+
+ ASC_DBG3(1,
+ "advansys_detect: reqp %x, req_cnt %d, bytes %d\n",
+ (unsigned) reqp, req_cnt, sizeof(adv_req_t) * req_cnt);
+
+ if (reqp != NULL) {
+ break;
+ }
+ }
+
+ /*
+ * Allocate up to ADV_TOT_SG_LIST request structures for
+ * the Wide board.
+ */
+ for (sg_cnt = ADV_TOT_SG_LIST; sg_cnt > 0; sg_cnt--) {
+
+ sgp = (adv_sgblk_t *)
+ kmalloc(sizeof(adv_sgblk_t) * sg_cnt, GFP_ATOMIC);
+
+ ASC_DBG3(1,
+ "advansys_detect: sgp %x, sg_cnt %d, bytes %d\n",
+ (unsigned) sgp, sg_cnt, sizeof(adv_sgblk_t) * sg_cnt);
+
+ if (sgp != NULL) {
+ break;
+ }
+ }
+#endif /* version >= v1.3.0 */
+
+ /*
+ * If no request structures or scatter-gather structures could
+ * be allocated, then return an error. Otherwise continue with
+ * initialization.
+ */
+ if (reqp == NULL) {
+ ASC_PRINT1(
+"advansys_detect: board %d: error: failed to kmalloc() adv_req_t buffer.\n",
+ boardp->id);
+ err_code = ADV_ERROR;
+ } else if (sgp == NULL) {
+ kfree(reqp);
+ ASC_PRINT1(
+"advansys_detect: board %d: error: failed to kmalloc() adv_sgblk_t buffer.\n",
+ boardp->id);
+ err_code = ADV_ERROR;
+ } else {
+
+ /*
+ * Save original pointer for kfree() in case the
+ * driver is built as a module and can be unloaded.
+ */
+ boardp->orig_reqp = reqp;
+
+ /*
+ * Point 'adv_reqp' to the request structures and
+ * link them together.
+ */
+ req_cnt--;
+ reqp[req_cnt].next_reqp = NULL;
+ for (; req_cnt > 0; req_cnt--) {
+ reqp[req_cnt - 1].next_reqp = &reqp[req_cnt];
+ }
+ boardp->adv_reqp = &reqp[0];
+
+ /*
+ * Save original pointer for kfree() in case the
+ * driver is built as a module and can be unloaded.
+ */
+ boardp->orig_sgblkp = sgp;
+
+ /*
+ * Point 'adv_sgblkp' to the request structures and
+ * link them together.
+ */
+ sg_cnt--;
+ sgp[sg_cnt].next_sgblkp = NULL;
+ for (; sg_cnt > 0; sg_cnt--) {
+ sgp[sg_cnt - 1].next_sgblkp = &sgp[sg_cnt];
+ }
+ boardp->adv_sgblkp = &sgp[0];
+
+ ASC_DBG(2, "advansys_detect: AdvInitAsc3550Driver()\n");
+ warn_code = AdvInitAsc3550Driver(adv_dvc_varp);
+ err_code = adv_dvc_varp->err_code;
+
+ if (warn_code || err_code) {
+ ASC_PRINT3(
+"AdvInitAsc3550Driver: board %d: error: warn %x, error %x\n",
+ boardp->id, warn_code, adv_dvc_varp->err_code);
+ }
+ }
+ }
+
+ if (err_code != 0) {
release_region(shp->io_port, shp->n_io_port);
+ if (ASC_WIDE_BOARD(boardp)) {
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+ iounmap(boardp->ioremap_addr);
+#endif /* version >= v1,3,0 */
+ if (boardp->orig_reqp) {
+ kfree(boardp->orig_reqp);
+ boardp->orig_reqp = boardp->adv_reqp = NULL;
+ }
+ if (boardp->orig_sgblkp) {
+ kfree(boardp->orig_sgblkp);
+ boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
+ }
+ }
if (shp->dma_channel != NO_ISA_DMA) {
free_dma(shp->dma_channel);
}
@@ -3573,6 +5091,19 @@ advansys_release(struct Scsi_Host *shp)
free_dma(shp->dma_channel);
}
release_region(shp->io_port, shp->n_io_port);
+ if (ASC_WIDE_BOARD(boardp)) {
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
+ iounmap(boardp->ioremap_addr);
+#endif /* version >= v1,3,0 */
+ if (boardp->orig_reqp) {
+ kfree(boardp->orig_reqp);
+ boardp->orig_reqp = boardp->adv_reqp = NULL;
+ }
+ if (boardp->orig_sgblkp) {
+ kfree(boardp->orig_sgblkp);
+ boardp->orig_sgblkp = boardp->adv_sgblkp = NULL;
+ }
+ }
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,0)
ASC_ASSERT(boardp->prtbuf != NULL);
kfree(boardp->prtbuf);
@@ -3597,49 +5128,79 @@ advansys_info(struct Scsi_Host *shp)
static char info[ASC_INFO_SIZE];
asc_board_t *boardp;
ASC_DVC_VAR *asc_dvc_varp;
+ ADV_DVC_VAR *adv_dvc_varp;
char *busname;
boardp = ASC_BOARDP(shp);
- asc_dvc_varp = &boardp->asc_dvc_var;
- ASC_DBG(1, "advansys_info: begin\n");
- if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
- if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) {
- busname = "ISA PnP";
- } else {
- busname = "ISA";
- }
- sprintf(info,
- "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u, DMA %u",
- ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
- (unsigned) shp->base, shp->io_port,
- shp->io_port + (shp->n_io_port - 1), shp->irq, shp->dma_channel);
- } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
- if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
- == ASC_IS_PCI_ULTRA) {
- busname = "PCI Ultra";
+ if (ASC_NARROW_BOARD(boardp)) {
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ ASC_DBG(1, "advansys_info: begin\n");
+ if (asc_dvc_varp->bus_type & ASC_IS_ISA) {
+ if ((asc_dvc_varp->bus_type & ASC_IS_ISAPNP) == ASC_IS_ISAPNP) {
+ busname = "ISA PnP";
+ } else {
+ busname = "ISA";
+ }
+ sprintf(info,
+"AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X/%X, IRQ %u, DMA %u",
+ ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
+ (unsigned) shp->base,
+ shp->io_port, shp->n_io_port - 1,
+ shp->irq, shp->dma_channel);
+ } else if (asc_dvc_varp->bus_type & ASC_IS_PCI) {
+ if ((asc_dvc_varp->bus_type & ASC_IS_PCI_ULTRA)
+ == ASC_IS_PCI_ULTRA) {
+ busname = "PCI Ultra";
+ } else {
+ busname = "PCI";
+ }
+ sprintf(info,
+ "AdvanSys SCSI %s: %s %u CDB: IO %X/%X, IRQ %u",
+ ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
+ shp->io_port, shp->n_io_port - 1, shp->irq);
} else {
- busname = "PCI";
+ if (asc_dvc_varp->bus_type & ASC_IS_VL) {
+ busname = "VL";
+ } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
+ busname = "EISA";
+ } else {
+ busname = "?";
+ ASC_PRINT2(
+ "advansys_info: board %d: unknown bus type %d\n",
+ boardp->id, asc_dvc_varp->bus_type);
+ }
+ sprintf(info,
+ "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X/%X, IRQ %u",
+ ASC_VERSION, busname, asc_dvc_varp->max_total_qng,
+ (unsigned) shp->base, shp->io_port - 1,
+ shp->n_io_port, shp->irq);
}
- sprintf(info,
- "AdvanSys SCSI %s: %s %u CDB: IO %X-%X, IRQ %u",
- ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
- shp->io_port, shp->io_port + (shp->n_io_port - 1), shp->irq);
} else {
- if (asc_dvc_varp->bus_type & ASC_IS_VL) {
- busname = "VL";
- } else if (asc_dvc_varp->bus_type & ASC_IS_EISA) {
- busname = "EISA";
+ /*
+ * Wide Adapter Information
+ *
+ * Memory-mapped I/O is used instead of I/O space to access
+ * the adapter, but display the I/O Port range. The Memory
+ * I/O address is displayed through the driver /proc file.
+ */
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+ if (boardp->bios_signature == 0x55AA) {
+ sprintf(info,
+"AdvanSys SCSI %s: PCI Ultra-Wide: BIOS %X/%X, IO %X/%X, IRQ %u",
+ ASC_VERSION,
+ boardp->bios_codeseg << 4,
+ boardp->bios_codelen > 0 ?
+ (boardp->bios_codelen << 9) - 1 : 0,
+ (unsigned) boardp->ioport, ADV_CONDOR_IOLEN - 1,
+ shp->irq);
} else {
- busname = "?";
- ASC_PRINT2(
-"advansys_info: board %d: unknown bus type %d\n",
- boardp->id, asc_dvc_varp->bus_type);
+ sprintf(info,
+"AdvanSys SCSI %s: PCI Ultra-Wide: IO %X/%X, IRQ %u",
+ ASC_VERSION,
+ (unsigned) boardp->ioport,
+ (ADV_CONDOR_IOLEN - 1),
+ shp->irq);
}
- sprintf(info,
- "AdvanSys SCSI %s: %s %u CDB: BIOS %X, IO %X-%X, IRQ %u",
- ASC_VERSION, busname, boardp->asc_dvc_var.max_total_qng,
- (unsigned) shp->base, shp->io_port,
- shp->io_port + (shp->n_io_port - 1), shp->irq);
}
ASC_ASSERT(strlen(info) < ASC_INFO_SIZE);
ASC_DBG(1, "advansys_info: end\n");
@@ -3647,10 +5208,10 @@ advansys_info(struct Scsi_Host *shp)
}
/*
- * advansys_command()
+ * advansys_command() - polled I/O entrypoint.
*
- * Polled-I/O. Apparently host drivers shouldn't return until
- * command is finished.
+ * Apparently host drivers shouldn't return until the command
+ * is finished.
*
* Note: This is an old interface that is no longer used by the SCSI
* mid-level driver. The new interface, advansys_queuecommand(),
@@ -3663,10 +5224,6 @@ advansys_command(Scsi_Cmnd *scp)
ASC_STATS(scp->host, command);
scp->SCp.Status = 0; /* Set to a known state */
advansys_queuecommand(scp, advansys_command_done);
- /*
- * XXX - Can host drivers block here instead of spinning on
- * command status?
- */
while (scp->SCp.Status == 0) {
continue;
}
@@ -3675,7 +5232,7 @@ advansys_command(Scsi_Cmnd *scp)
}
/*
- * advansys_queuecommand()
+ * advansys_queuecommand() - interrupt-driven I/O entrypoint.
*
* This function always returns 0. Command return status is saved
* in the 'scp' result field.
@@ -3779,6 +5336,7 @@ advansys_abort(Scsi_Cmnd *scp)
struct Scsi_Host *shp;
asc_board_t *boardp;
ASC_DVC_VAR *asc_dvc_varp;
+ ADV_DVC_VAR *adv_dvc_varp;
int flags;
int do_scsi_done;
int scp_found;
@@ -3839,10 +5397,10 @@ advansys_abort(Scsi_Cmnd *scp)
do_scsi_done = ASC_TRUE;
if (asc_rmqueue(&boardp->waiting, scp) == ASC_TRUE) {
/*
- * If asc_rmqueue() found the command on the waiting
+ * If asc_rmqueue() found the command on the waiting
* queue, it had not been sent to the device. After
* the queue is removed, no other handling is required.
- */
+ */
ASC_DBG1(1, "advansys_abort: scp %x found on waiting queue\n",
(unsigned) scp);
scp_found = ASC_TRUE;
@@ -3850,35 +5408,72 @@ advansys_abort(Scsi_Cmnd *scp)
ret = SCSI_ABORT_SUCCESS;
} else if (asc_isqueued(&boardp->active, scp) == ASC_TRUE) {
/*
- * If asc_isqueued() found the command on the active
+ * If asc_isqueued() found the command on the active
* queue, it has been sent to the device. The command
- * should be returned through the interrupt handler after
- * calling AscAbortSRB().
- */
- asc_dvc_varp = &boardp->asc_dvc_var;
- scp->result = HOST_BYTE(DID_ABORT);
+ * will be returned through the interrupt handler after
+ * it has been aborted.
+ */
- sti(); /* Enable interrupts for AscAbortSRB(). */
- ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
- (unsigned) scp);
- switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
- case ASC_TRUE:
- /* asc_isr_callback() will be called */
- ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
- ret = SCSI_ABORT_PENDING;
- break;
- case ASC_FALSE:
- /* Request has apparently already completed. */
- ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n");
- ret = SCSI_ABORT_NOT_RUNNING;
- break;
- case ASC_ERROR:
- default:
- ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n");
- ret = SCSI_ABORT_ERROR;
- break;
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * Narrow Board
+ */
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ scp->result = HOST_BYTE(DID_ABORT);
+
+ sti(); /* Enable interrupts for AscAbortSRB(). */
+ ASC_DBG1(1, "advansys_abort: before AscAbortSRB(), scp %x\n",
+ (unsigned) scp);
+ switch (AscAbortSRB(asc_dvc_varp, (ulong) scp)) {
+ case ASC_TRUE:
+ /* asc_isr_callback() will be called */
+ ASC_DBG(1, "advansys_abort: AscAbortSRB() TRUE\n");
+ ret = SCSI_ABORT_PENDING;
+ break;
+ case ASC_FALSE:
+ /* Request has apparently already completed. */
+ ASC_DBG(1, "advansys_abort: AscAbortSRB() FALSE\n");
+ ret = SCSI_ABORT_NOT_RUNNING;
+ break;
+ case ASC_ERROR:
+ default:
+ ASC_DBG(1, "advansys_abort: AscAbortSRB() ERROR\n");
+ ret = SCSI_ABORT_ERROR;
+ break;
+ }
+ cli();
+ } else {
+ /*
+ * Wide Board
+ */
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+ scp->result = HOST_BYTE(DID_ABORT);
+
+ ASC_DBG1(1, "advansys_abort: before AdvAbortSRB(), scp %x\n",
+ (unsigned) scp);
+ switch (AdvAbortSRB(adv_dvc_varp, (ulong) scp)) {
+ case ASC_TRUE:
+ /* asc_isr_callback() will be called */
+ ASC_DBG(1, "advansys_abort: AdvAbortSRB() TRUE\n");
+ ret = SCSI_ABORT_PENDING;
+ break;
+ case ASC_FALSE:
+ /* Request has apparently already completed. */
+ ASC_DBG(1, "advansys_abort: AdvAbortSRB() FALSE\n");
+ ret = SCSI_ABORT_NOT_RUNNING;
+ break;
+ case ASC_ERROR:
+ default:
+ ASC_DBG(1, "advansys_abort: AdvAbortSRB() ERROR\n");
+ ret = SCSI_ABORT_ERROR;
+ break;
+ }
+ /*
+ * Ensure all requests completed by the microcode have
+ * been processed by calling AdvISR().
+ */
+ (void) AdvISR(adv_dvc_varp);
}
- cli();
/*
* The request will either still be on the active queue
@@ -3980,6 +5575,7 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
struct Scsi_Host *shp;
asc_board_t *boardp;
ASC_DVC_VAR *asc_dvc_varp;
+ ADV_DVC_VAR *adv_dvc_varp;
int flags;
Scsi_Cmnd *done_scp = NULL, *last_scp = NULL;
Scsi_Cmnd *tscp, *new_last_scp;
@@ -3988,6 +5584,7 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
int status;
int target;
int ret;
+ int device_reset = ASC_FALSE;
/* Save current flags and disable interrupts. */
save_flags(flags);
@@ -4053,8 +5650,6 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
scp->result = HOST_BYTE(DID_ERROR);
ret = SCSI_RESET_ERROR;
} else {
- int device_reset = ASC_FALSE;
-
do_scsi_done = ASC_TRUE;
/* Set reset flag to avoid nested reset or abort requests. */
@@ -4077,83 +5672,166 @@ advansys_reset(Scsi_Cmnd *scp, unsigned int reset_flags)
scp_found = ASC_FALSE;
}
- /*
- * If the suggest reset bus flags are set, reset the bus.
- * Otherwise only reset the device.
- */
- asc_dvc_varp = &boardp->asc_dvc_var;
-#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
- if (reset_flags &
- (SCSI_RESET_SUGGEST_BUS_RESET | SCSI_RESET_SUGGEST_HOST_RESET)) {
-#endif /* version >= v1.3.89 */
+ if (ASC_NARROW_BOARD(boardp)) {
/*
- * Reset the target's SCSI bus.
+ * Narrow Board
+ *
+ * If the suggest reset bus flags are set, then reset the bus.
+ * Otherwise only reset the device.
*/
- ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
- sti(); /* Enable interrupts for AscResetSB(). */
- status = AscResetSB(asc_dvc_varp);
- cli();
- switch (status) {
- case ASC_TRUE:
- ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
- ret = SCSI_RESET_SUCCESS;
- break;
- case ASC_ERROR:
- default:
- ASC_DBG(1, "advansys_reset: AscResetSB() failed\n");
- ret = SCSI_RESET_ERROR;
- break;
- }
-
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
- } else {
- /*
- * Reset the specified device. If the device reset fails,
- * then reset the SCSI bus.
- */
-
- ASC_DBG1(1, "advansys_reset: before AscResetDevice(), target %d\n",
- scp->target);
- sti(); /* Enable interrupts for AscResetDevice(). */
- status = AscResetDevice(asc_dvc_varp, scp->target);
- cli();
-
- /*
- * If the device has been reset, try to initialize it.
- */
- if (status == ASC_TRUE) {
- status = asc_init_dev(asc_dvc_varp, scp);
- }
+ if (reset_flags &
+ (SCSI_RESET_SUGGEST_BUS_RESET |
+ SCSI_RESET_SUGGEST_HOST_RESET)) {
+#endif /* version >= v1.3.89 */
- switch (status) {
- case ASC_TRUE:
- ASC_DBG(1, "advansys_reset: AscResetDevice() success\n");
- device_reset = ASC_TRUE;
- ret = SCSI_RESET_SUCCESS;
- break;
- case ASC_ERROR:
- default:
- ASC_DBG(1,
-"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n");
+ /*
+ * Reset the target's SCSI bus.
+ */
+ ASC_DBG(1, "advansys_reset: before AscResetSB()\n");
sti(); /* Enable interrupts for AscResetSB(). */
status = AscResetSB(asc_dvc_varp);
cli();
switch (status) {
case ASC_TRUE:
- ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
+ ASC_DBG(1, "advansys_reset: AscResetSB() success\n");
ret = SCSI_RESET_SUCCESS;
break;
case ASC_ERROR:
default:
- ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
+ ASC_DBG(1, "advansys_reset: AscResetSB() failed\n");
ret = SCSI_RESET_ERROR;
break;
}
- break;
+
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+ } else {
+ /*
+ * Reset the specified device. If the device reset fails,
+ * then reset the SCSI bus.
+ */
+
+ ASC_DBG1(1,
+ "advansys_reset: before AscResetDevice(), target %d\n",
+ scp->target);
+ sti(); /* Enable interrupts for AscResetDevice(). */
+ status = AscResetDevice(asc_dvc_varp, scp->target);
+ cli();
+
+ /*
+ * If the device has been reset, try to initialize it.
+ */
+ if (status == ASC_TRUE) {
+ status = asc_init_dev(asc_dvc_varp, scp);
+ }
+
+ switch (status) {
+ case ASC_TRUE:
+ ASC_DBG(1, "advansys_reset: AscResetDevice() success\n");
+ device_reset = ASC_TRUE;
+ ret = SCSI_RESET_SUCCESS;
+ break;
+ case ASC_ERROR:
+ default:
+ ASC_DBG(1,
+"advansys_reset: AscResetDevice() failed; Calling AscResetSB()\n");
+ sti(); /* Enable interrupts for AscResetSB(). */
+ status = AscResetSB(asc_dvc_varp);
+ cli();
+ switch (status) {
+ case ASC_TRUE:
+ ASC_DBG(1, "advansys_reset: AscResetSB() TRUE\n");
+ ret = SCSI_RESET_SUCCESS;
+ break;
+ case ASC_ERROR:
+ default:
+ ASC_DBG(1, "advansys_reset: AscResetSB() ERROR\n");
+ ret = SCSI_RESET_ERROR;
+ break;
+ }
+ break;
+ }
+ }
+#endif /* version >= v1.3.89 */
+ } else {
+ /*
+ * Wide Board
+ *
+ * If the suggest reset bus flags are set, then reset the bus.
+ * Otherwise only reset the device.
+ */
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+ if (reset_flags &
+ (SCSI_RESET_SUGGEST_BUS_RESET |
+ SCSI_RESET_SUGGEST_HOST_RESET)) {
+#endif /* version >= v1.3.89 */
+
+ /*
+ * Reset the target's SCSI bus.
+ */
+ ASC_DBG(1, "advansys_reset: before AdvResetSB()\n");
+ switch (AdvResetSB(adv_dvc_varp)) {
+ case ASC_TRUE:
+ ASC_DBG(1, "advansys_reset: AdvResetSB() success\n");
+ ret = SCSI_RESET_SUCCESS;
+ break;
+ case ASC_FALSE:
+ default:
+ ASC_DBG(1, "advansys_reset: AdvResetSB() failed\n");
+ ret = SCSI_RESET_ERROR;
+ break;
+ }
+ /*
+ * Ensure all requests completed by the microcode have
+ * been processed by calling AdvISR().
+ */
+ (void) AdvISR(adv_dvc_varp);
+#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
+ } else {
+ /*
+ * Reset the specified device. If the device reset fails,
+ * then reset the SCSI bus.
+ */
+
+ ASC_DBG1(1,
+ "advansys_reset: before AdvResetDevice(), target %d\n",
+ scp->target);
+
+ switch (AdvResetDevice(adv_dvc_varp, scp->target)) {
+ case ASC_TRUE:
+ ASC_DBG(1, "advansys_reset: AdvResetDevice() success\n");
+ device_reset = ASC_TRUE;
+ ret = SCSI_RESET_SUCCESS;
+ break;
+ case ASC_FALSE:
+ default:
+ ASC_DBG(1,
+"advansys_reset: AdvResetDevice() failed; Calling AdvResetSB()\n");
+
+ switch (AdvResetSB(adv_dvc_varp)) {
+ case ASC_TRUE:
+ ASC_DBG(1, "advansys_reset: AdvResetSB() TRUE\n");
+ ret = SCSI_RESET_SUCCESS;
+ break;
+ case ASC_FALSE:
+ default:
+ ASC_DBG(1, "advansys_reset: AdvResetSB() ERROR\n");
+ ret = SCSI_RESET_ERROR;
+ break;
+ }
+ break;
+ }
+ /*
+ * Ensure all requests completed by the microcode have
+ * been processed by calling AdvISR().
+ */
+ (void) AdvISR(adv_dvc_varp);
}
- }
#endif /* version >= v1.3.89 */
+ }
/*
* Because the ASC_HOST_IN_RESET flag causes both
@@ -4296,15 +5974,29 @@ advansys_biosparam(Disk *dp, int dep, int ip[])
advansys_biosparam(Disk *dp, kdev_t dep, int ip[])
#endif /* version >= v1.3.0 */
{
+ asc_board_t *boardp;
+
ASC_DBG(1, "advansys_biosparam: begin\n");
ASC_STATS(dp->device->host, biosparam);
- if ((ASC_BOARDP(dp->device->host)->asc_dvc_var.dvc_cntl &
- ASC_CNTL_BIOS_GT_1GB) && dp->capacity > 0x200000) {
- ip[0] = 255;
- ip[1] = 63;
+ boardp = ASC_BOARDP(dp->device->host);
+ if (ASC_NARROW_BOARD(boardp)) {
+ if ((boardp->dvc_var.asc_dvc_var.dvc_cntl &
+ ASC_CNTL_BIOS_GT_1GB) && dp->capacity > 0x200000) {
+ ip[0] = 255;
+ ip[1] = 63;
+ } else {
+ ip[0] = 64;
+ ip[1] = 32;
+ }
} else {
- ip[0] = 64;
- ip[1] = 32;
+ if ((boardp->dvc_var.adv_dvc_var.bios_ctrl &
+ BIOS_CTRL_EXTENDED_XLAT) && dp->capacity > 0x200000) {
+ ip[0] = 255;
+ ip[1] = 63;
+ } else {
+ ip[0] = 64;
+ ip[1] = 32;
+ }
}
ip[2] = dp->capacity / (ip[0] * ip[1]);
ASC_DBG(1, "advansys_biosparam: end\n");
@@ -4325,7 +6017,7 @@ advansys_biosparam(Disk *dp, kdev_t dep, int ip[])
* only affects searching for ISA and VL boards.
*
* If ADVANSYS_DEBUG is defined the driver debug level may
- * be set using the 5th (ASC_NUM_BOARD_SUPPORTED + 1) I/O Port.
+ * be set using the 5th (ASC_NUM_IOPORT_PROBE + 1) I/O Port.
*
* Examples:
* 1. Eliminate I/O port scanning:
@@ -4359,15 +6051,15 @@ advansys_setup(char *str, int *ints)
asc_iopflag = ASC_TRUE;
- if (ints[0] > ASC_NUM_BOARD_SUPPORTED) {
+ if (ints[0] > ASC_NUM_IOPORT_PROBE) {
#ifdef ADVANSYS_DEBUG
- if ((ints[0] == ASC_NUM_BOARD_SUPPORTED + 1) &&
- (ints[ASC_NUM_BOARD_SUPPORTED + 1] >> 4 == 0xdeb)) {
- asc_dbglvl = ints[ASC_NUM_BOARD_SUPPORTED + 1] & 0xf;
+ if ((ints[0] == ASC_NUM_IOPORT_PROBE + 1) &&
+ (ints[ASC_NUM_IOPORT_PROBE + 1] >> 4 == 0xdeb)) {
+ asc_dbglvl = ints[ASC_NUM_IOPORT_PROBE + 1] & 0xf;
} else {
#endif /* ADVANSYS_DEBUG */
printk("AdvanSys SCSI: only %d I/O ports accepted\n",
- ASC_NUM_BOARD_SUPPORTED);
+ ASC_NUM_IOPORT_PROBE);
#ifdef ADVANSYS_DEBUG
}
#endif /* ADVANSYS_DEBUG */
@@ -4381,7 +6073,7 @@ advansys_setup(char *str, int *ints)
ASC_DBG(1, "\n");
#endif /* ADVANSYS_DEBUG */
- for (i = 1; i <= ints[0] && i <= ASC_NUM_BOARD_SUPPORTED; i++) {
+ for (i = 1; i <= ints[0] && i <= ASC_NUM_IOPORT_PROBE; i++) {
asc_ioport[i-1] = ints[i];
ASC_DBG2(1, "advansys_setup: asc_ioport[%d] %x\n",
i - 1, asc_ioport[i-1]);
@@ -4430,17 +6122,32 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
cli();
ASC_DBG(1, "advansys_interrupt: begin\n");
+
/*
* Check for interrupts on all boards.
* AscISR() will call asc_isr_callback().
*/
for (i = 0; i < asc_board_count; i++) {
- ASC_STATS(asc_host[i], check_interrupt);
boardp = ASC_BOARDP(asc_host[i]);
- while (AscIsIntPending(asc_host[i]->io_port)) {
- ASC_STATS(asc_host[i], interrupt);
- ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
- AscISR(&boardp->asc_dvc_var);
+ ASC_DBG2(2, "advansys_interrupt: i %d, boardp %lx\n",
+ i, (ulong) boardp)
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * Narrow Board
+ */
+ if (AscIsIntPending(asc_host[i]->io_port)) {
+ ASC_STATS(asc_host[i], interrupt);
+ ASC_DBG(1, "advansys_interrupt: before AscISR()\n");
+ AscISR(&boardp->dvc_var.asc_dvc_var);
+ }
+ } else {
+ /*
+ * Wide Board
+ */
+ ASC_DBG(1, "advansys_interrupt: before AdvISR()\n");
+ if (AdvISR(&boardp->dvc_var.adv_dvc_var)) {
+ ASC_STATS(asc_host[i], interrupt);
+ }
}
/*
@@ -4451,6 +6158,9 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
* it has completed.
*/
if ((boardp->flags & (ASC_HOST_IN_RESET | ASC_HOST_IN_ABORT)) == 0) {
+ ASC_DBG2(1, "advansys_interrupt: done_scp %lx, last_scp %lx\n",
+ (ulong) done_scp, (ulong) last_scp);
+
/* Start any waiting commands for the board. */
if (!ASC_QUEUE_EMPTY(&boardp->waiting)) {
ASC_DBG(1, "advansys_interrupt: before asc_execute_queue()\n");
@@ -4458,8 +6168,12 @@ advansys_interrupt(int irq, void *dev_id, struct pt_regs *regs)
}
/*
- * Add to the list of requests that must be completed.
- */
+ * Add to the list of requests that must be completed.
+ *
+ * 'done_scp' will always be NULL on the first iteration
+ * of this loop. 'last_scp' is set at the same time as
+ * 'done_scp'.
+ */
if (done_scp == NULL) {
done_scp = asc_dequeue_list(&boardp->done, &last_scp,
ASC_TID_ALL);
@@ -4503,6 +6217,7 @@ advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
asc_board_t *boardp;
boardp = ASC_BOARDP(shp);
+ boardp->flags |= ASC_SELECT_QUEUE_DEPTHS;
for (device = devicelist; device != NULL; device = device->next) {
if (device->host != shp) {
continue;
@@ -4512,7 +6227,13 @@ advansys_select_queue_depths(struct Scsi_Host *shp, Scsi_Device *devicelist)
* queue depth.
*/
boardp->device[device->id] = device;
- device->queue_depth = boardp->asc_dvc_var.max_dvc_qng[device->id];
+ if (ASC_NARROW_BOARD(boardp)) {
+ device->queue_depth =
+ boardp->dvc_var.asc_dvc_var.max_dvc_qng[device->id];
+ } else {
+ device->queue_depth =
+ boardp->dvc_var.adv_dvc_var.max_dvc_qng;
+ }
ASC_DBG3(1, "advansys_select_queue_depths: shp %x, id %d, depth %d\n",
(unsigned) shp, device->id, device->queue_depth);
}
@@ -4541,7 +6262,9 @@ asc_scsi_done_list(Scsi_Cmnd *scp)
{
Scsi_Cmnd *tscp;
+ ASC_DBG(2, "asc_scsi_done_list: begin\n");
while (scp != NULL) {
+ ASC_DBG1(3, "asc_scsi_done_list: scp %x\n", (unsigned) scp);
tscp = REQPNEXT(scp);
REQPNEXT(scp) = NULL;
ASC_STATS(scp->host, done);
@@ -4549,6 +6272,7 @@ asc_scsi_done_list(Scsi_Cmnd *scp)
scp->scsi_done(scp);
scp = tscp;
}
+ ASC_DBG(2, "asc_scsi_done_list: done\n");
return;
}
@@ -4564,28 +6288,29 @@ asc_scsi_done_list(Scsi_Cmnd *scp)
* target - target of device
* lun - lun of device
* cmd_len - length of SCSI CDB
- * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
+ * cmnd - buffer for SCSI 8, 10, or 12 byte CDB
* use_sg - if non-zero indicates scatter-gather request with use_sg elements
*
- * if (use_sg == 0)
- * request_buffer - buffer address for request
- * request_bufflen - length of request buffer
- * else
- * request_buffer - pointer to scatterlist structure
+ * if (use_sg == 0) {
+ * request_buffer - buffer address for request
+ * request_bufflen - length of request buffer
+ * } else {
+ * request_buffer - pointer to scatterlist structure
+ * }
*
* sense_buffer - sense command buffer
*
* result (4 bytes of an int):
- * Byte Meaning
- * 0 SCSI Status Byte Code
- * 1 SCSI One Byte Message Code
- * 2 Host Error Code
- * 3 Mid-Level Error Code
+ * Byte Meaning
+ * 0 SCSI Status Byte Code
+ * 1 SCSI One Byte Message Code
+ * 2 Host Error Code
+ * 3 Mid-Level Error Code
*
* host driver fields:
- * SCp - Scsi_Pointer used for command processing status
- * scsi_done - used to save caller's done function
- * host_scribble - used for pointer to another Scsi_Cmnd
+ * SCp - Scsi_Pointer used for command processing status
+ * scsi_done - used to save caller's done function
+ * host_scribble - used for pointer to another Scsi_Cmnd
*
* If this function returns ASC_NOERROR or ASC_ERROR the request
* has been enqueued on the board's 'done' queue and must be
@@ -4599,6 +6324,8 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
{
asc_board_t *boardp;
ASC_DVC_VAR *asc_dvc_varp;
+ ADV_DVC_VAR *adv_dvc_varp;
+ ADV_SCSI_REQ_Q *adv_scsiqp;
Scsi_Device *device;
int ret;
@@ -4607,22 +6334,199 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
(unsigned) scp, (unsigned) scp->scsi_done);
boardp = ASC_BOARDP(scp->host);
- asc_dvc_varp = &boardp->asc_dvc_var;
device = boardp->device[scp->target];
- /*
- * If this is the first command, then initialize the device. If
- * no device is found set 'DID_BAD_TARGET' and return.
- */
- if ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(scp->target)) == 0) {
- if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) {
- scp->result = HOST_BYTE(DID_BAD_TARGET);
+ if (ASC_NARROW_BOARD(boardp)) {
+ /*
+ * Build and execute Narrow Board request.
+ */
+
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+
+ /*
+ * Narrow Board - Asc Library requires special device initialization.
+ *
+ * If this is the first command, then initialize the device. If
+ * no device is found set 'DID_BAD_TARGET' and return.
+ */
+ if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->target)) == 0) {
+ if (asc_init_dev(asc_dvc_varp, scp) == ASC_FALSE) {
+ scp->result = HOST_BYTE(DID_BAD_TARGET);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ return ASC_ERROR;
+ }
+ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target);
+ }
+
+ /*
+ * Build Asc Library request structure using the
+ * global structures 'asc_scsi_req' and 'asc_sg_head'.
+ *
+ * asc_build_req() can not return ASC_BUSY.
+ */
+ if (asc_build_req(boardp, scp) == ASC_ERROR) {
+ ASC_STATS(scp->host, build_error);
+ return ASC_ERROR;
+ }
+
+ /*
+ * Execute the command. If there is no error, add the command
+ * to the active queue.
+ */
+ switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
+ case ASC_NOERROR:
+ ASC_STATS(scp->host, exe_noerror);
+ /*
+ * Increment monotonically increasing per device successful
+ * request counter. Wrapping doesn't matter.
+ */
+ boardp->reqcnt[scp->target]++;
+
+#if ASC_QUEUE_FLOW_CONTROL
+ /*
+ * Conditionally increment the device queue depth.
+ *
+ * If no error occurred and there have been 100 consecutive
+ * successful requests and the current queue depth is less
+ * than the maximum queue depth, then increment the current
+ * queue depth.
+ */
+ if (boardp->nerrcnt[scp->target]++ > 100) {
+ boardp->nerrcnt[scp->target] = 0;
+ if (device != NULL &&
+ (device->queue_curr_depth < device->queue_depth) &&
+ (!(boardp->queue_full &
+ ADV_TID_TO_TIDMASK(scp->target)) ||
+ (boardp->queue_full_cnt[scp->target] >
+ device->queue_curr_depth))) {
+ device->queue_curr_depth++;
+ }
+ }
+#endif /* ASC_QUEUE_FLOW_CONTROL */
+ asc_enqueue(&boardp->active, scp, ASC_BACK);
+ ASC_DBG(1,
+ "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
+ break;
+ case ASC_BUSY:
+ /* Caller must enqueue request and retry later. */
+ ASC_STATS(scp->host, exe_busy);
+#if ASC_QUEUE_FLOW_CONTROL
+ /*
+ * Clear consecutive no error counter and if possible decrement
+ * queue depth.
+ */
+ boardp->nerrcnt[scp->target] = 0;
+ if (device != NULL && device->queue_curr_depth > 1) {
+ device->queue_curr_depth--;
+ }
+#endif /* ASC_QUEUE_FLOW_CONTROL */
+ break;
+ case ASC_ERROR:
+ ASC_PRINT2(
+"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
+ boardp->id, asc_dvc_varp->err_code);
+ ASC_STATS(scp->host, exe_error);
+#if ASC_QUEUE_FLOW_CONTROL
+ /* Clear consecutive no error counter. */
+ boardp->nerrcnt[scp->target] = 0;
+#endif /* ASC_QUEUE_FLOW_CONTROL */
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ break;
+ default:
+ ASC_PRINT2(
+"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
+ boardp->id, asc_dvc_varp->err_code);
+ ASC_STATS(scp->host, exe_unknown);
+#if ASC_QUEUE_FLOW_CONTROL
+ /* Clear consecutive no error counter. */
+ boardp->nerrcnt[scp->target] = 0;
+#endif /* ASC_QUEUE_FLOW_CONTROL */
+ scp->result = HOST_BYTE(DID_ERROR);
asc_enqueue(&boardp->done, scp, ASC_BACK);
+ break;
+ }
+ } else {
+ /*
+ * Build and execute Wide Board request.
+ */
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+
+ /*
+ * Build and get a pointer to an Adv Library request structure.
+ *
+ * If the request is successfully built then send it below,
+ * otherwise return with an error.
+ */
+ switch (adv_build_req(boardp, scp, &adv_scsiqp)) {
+ case ASC_NOERROR:
+ ASC_DBG(3, "asc_execute_scsi_cmnd: adv_build_req ASC_NOERROR\n");
+ break;
+ case ASC_BUSY:
+ ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_BUSY\n");
+ return ASC_BUSY;
+ case ASC_ERROR:
+ default:
+ ASC_DBG(1, "asc_execute_scsi_cmnd: adv_build_req ASC_ERROR\n");
+ ASC_STATS(scp->host, build_error);
return ASC_ERROR;
}
- boardp->init_tidmask |= ASC_TIX_TO_TARGET_ID(scp->target);
+
+ /*
+ * Execute the command. If there is no error, add the command
+ * to the active queue.
+ */
+ switch (ret = AdvExeScsiQueue(adv_dvc_varp, adv_scsiqp)) {
+ case ASC_NOERROR:
+ ASC_STATS(scp->host, exe_noerror);
+ /*
+ * Increment monotonically increasing per device successful
+ * request counter. Wrapping doesn't matter.
+ */
+ boardp->reqcnt[scp->target]++;
+ asc_enqueue(&boardp->active, scp, ASC_BACK);
+ ASC_DBG(1,
+ "asc_execute_scsi_cmnd: AdvExeScsiQueue(), ASC_NOERROR\n");
+ break;
+ case ASC_BUSY:
+ /* Caller must enqueue request and retry later. */
+ ASC_STATS(scp->host, exe_busy);
+ break;
+ case ASC_ERROR:
+ ASC_PRINT2(
+"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() ASC_ERROR, err_code %x\n",
+ boardp->id, adv_dvc_varp->err_code);
+ ASC_STATS(scp->host, exe_error);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ break;
+ default:
+ ASC_PRINT2(
+"asc_execute_scsi_cmnd: board %d: AdvExeScsiQueue() unknown, err_code %x\n",
+ boardp->id, adv_dvc_varp->err_code);
+ ASC_STATS(scp->host, exe_unknown);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+ break;
+ }
}
+ ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
+ ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ return ret;
+}
+
+/*
+ * Build a request structure for the Asc Library (Narrow Board).
+ *
+ * The global structures 'asc_scsi_q' and 'asc_sg_head' are
+ * used to build the request.
+ *
+ * If an error occurs, then return ASC_ERROR.
+ */
+STATIC int
+asc_build_req(asc_board_t *boardp, Scsi_Cmnd *scp)
+{
/*
* Mutually exclusive access is required to 'asc_scsi_q' and
* 'asc_sg_head' until after the request is started.
@@ -4637,6 +6541,10 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
/*
* Build the ASC_SCSI_Q request.
*/
+ ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN);
+ if (scp->cmd_len > ASC_MAX_CDB_LEN) {
+ scp->cmd_len = ASC_MAX_CDB_LEN;
+ }
asc_scsi_q.cdbptr = &scp->cmnd[0];
asc_scsi_q.q2.cdb_len = scp->cmd_len;
asc_scsi_q.q1.target_id = ASC_TID_TO_TARGET_ID(scp->target);
@@ -4660,7 +6568,7 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
* started request.
*
*/
- if ((asc_dvc_varp->cur_dvc_qng[scp->target] > 0) &&
+ if ((boardp->dvc_var.asc_dvc_var.cur_dvc_qng[scp->target] > 0) &&
(boardp->reqcnt[scp->target] % 255) == 0) {
asc_scsi_q.q2.tag_code = M2_QTAG_MSG_ORDERED;
} else {
@@ -4690,12 +6598,12 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
/*
* CDB scatter-gather request list.
*/
- int sgcnt;
- struct scatterlist *slp;
+ int sgcnt;
+ struct scatterlist *slp;
if (scp->use_sg > scp->host->sg_tablesize) {
ASC_PRINT3(
-"asc_execute_scsi_cmnd: board %d: use_sg %d > sg_tablesize %d\n",
+"asc_build_req: board %d: use_sg %d > sg_tablesize %d\n",
boardp->id, scp->use_sg, scp->host->sg_tablesize);
scp->result = HOST_BYTE(DID_ERROR);
asc_enqueue(&boardp->done, scp, ASC_BACK);
@@ -4705,8 +6613,8 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
ASC_STATS(scp->host, sg_cnt);
/*
- * Allocate a ASC_SG_HEAD structure and set the ASC_SCSI_Q
- * to point to it.
+ * Use global ASC_SG_HEAD structure and set the ASC_SCSI_Q
+ * structure to point to it.
*/
memset(&asc_sg_head, 0, sizeof(ASC_SG_HEAD));
@@ -4732,91 +6640,262 @@ asc_execute_scsi_cmnd(Scsi_Cmnd *scp)
}
}
- ASC_DBG_PRT_SCSI_Q(2, &asc_scsi_q);
+ ASC_DBG_PRT_ASC_SCSI_Q(2, &asc_scsi_q);
ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+ return ASC_NOERROR;
+}
+
+/*
+ * Build a request structure for the Adv Library (Wide Board).
+ *
+ * If an adv_req_t can not be allocated to issue the request,
+ * then return ASC_BUSY. If an error occurs, then return ASC_ERROR.
+ */
+STATIC int
+adv_build_req(asc_board_t *boardp, Scsi_Cmnd *scp,
+ ADV_SCSI_REQ_Q **adv_scsiqpp)
+{
+ adv_req_t *reqp;
+ ADV_SCSI_REQ_Q *scsiqp;
+ int i;
+
/*
- * Execute the command. If there is no error, add the command
- * to the active queue.
+ * Allocate an adv_req_t structure from the board to execute
+ * the command.
*/
- switch (ret = AscExeScsiQueue(asc_dvc_varp, &asc_scsi_q)) {
- case ASC_NOERROR:
- ASC_STATS(scp->host, asc_noerror);
+ if (boardp->adv_reqp == NULL) {
+ ASC_DBG(1, "adv_build_req: no free adv_req_t\n");
+ ASC_STATS(scp->host, adv_build_noreq);
+ return ASC_BUSY;
+ } else {
+ reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp->next_reqp;
+ reqp->next_reqp = NULL;
+ }
+
+ /*
+ * Get 4-byte aligned ADV_SCSI_REQ_Q and ADV_SG_BLOCK pointers.
+ */
+ scsiqp = (ADV_SCSI_REQ_Q *) ADV_DWALIGN(&reqp->scsi_req_q);
+ memset(scsiqp, 0, sizeof(ADV_SCSI_REQ_Q));
+
+ /*
+ * Set the ADV_SCSI_REQ_Q 'srb_ptr' to point to the adv_req_t structure.
+ */
+ scsiqp->srb_ptr = (ulong) reqp;
+
+ /*
+ * Set the adv_req_t 'cmndp' to point to the Scsi_Cmnd structure.
+ */
+ reqp->cmndp = scp;
+
+ /*
+ * Build the ADV_SCSI_REQ_Q request.
+ */
+
+ /*
+ * Set CDB length and copy it to the request structure.
+ */
+ ASC_ASSERT(scp->cmd_len <= ASC_MAX_CDB_LEN);
+ if (scp->cmd_len > ASC_MAX_CDB_LEN) {
+ scp->cmd_len = ASC_MAX_CDB_LEN;
+ }
+ scsiqp->cdb_len = scp->cmd_len;
+ for (i = 0; i < scp->cmd_len; i++) {
+ scsiqp->cdb[i] = scp->cmnd[i];
+ }
+
+ scsiqp->target_id = scp->target;
+ scsiqp->target_lun = scp->lun;
+
+ scsiqp->vsense_addr = (ulong) &scp->sense_buffer[0];
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+ scsiqp->sense_addr = (ulong) &scp->sense_buffer[0];
+#else /* version >= v2.0.0 */
+ scsiqp->sense_addr = virt_to_bus(&scp->sense_buffer[0]);
+#endif /* version >= v2.0.0 */
+ scsiqp->sense_len = sizeof(scp->sense_buffer);
+
+ /*
+ * Build ADV_SCSI_REQ_Q for a contiguous buffer or a scatter-gather
+ * buffer command.
+ */
+ scsiqp->data_cnt = scp->request_bufflen;
+ scsiqp->vdata_addr = (ulong) scp->request_buffer;
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+ scsiqp->data_addr = (ulong) scp->request_buffer;
+#else /* version >= v2.0.0 */
+ scsiqp->data_addr = virt_to_bus(scp->request_buffer);
+#endif /* version >= v2.0.0 */
+
+ if (scp->use_sg == 0) {
/*
- * Increment monotonically increasing per device successful
- * request counter. Wrapping doesn't matter.
+ * CDB request of single contiguous buffer.
*/
- boardp->reqcnt[scp->target]++;
+ reqp->sgblkp = NULL;
+ scsiqp->sg_list_ptr = NULL;
+ ASC_STATS(scp->host, cont_cnt);
+ ASC_STATS_ADD(scp->host, cont_xfer,
+ ASC_CEILING(scp->request_bufflen, 512));
+ } else {
+ /*
+ * CDB scatter-gather request list.
+ */
+ if (scp->use_sg > ADV_MAX_SG_LIST) {
+ ASC_PRINT3(
+"adv_build_req: board %d: use_sg %d > ADV_MAX_SG_LIST %d\n",
+ boardp->id, scp->use_sg, scp->host->sg_tablesize);
+ scp->result = HOST_BYTE(DID_ERROR);
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+ /*
+ * Free the 'adv_req_t' structure by adding it back to the
+ * board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ return ASC_ERROR;
+ }
-#if ASC_QUEUE_FLOW_CONTROL
/*
- * Conditionally increment the device queue depth.
- *
- * If no error occurred and there have been 100 consecutive
- * successfull requests and the current queue depth is less
- * than the maximum queue depth, then increment the current
- * queue depth.
+ * Allocate an 'adv_sgblk_t' structure from the board to
+ * execute the command.
*/
- if (boardp->nerrcnt[scp->target]++ > 100) {
- boardp->nerrcnt[scp->target] = 0;
- if ((device->queue_curr_depth < device->queue_depth) &&
- (!(boardp->queue_full & ASC_TIX_TO_TARGET_ID(scp->target)) ||
- (boardp->queue_full_cnt[scp->target] >
- device->queue_curr_depth))) {
- device->queue_curr_depth++;
- }
+ if (boardp->adv_sgblkp == NULL) {
+ ASC_DBG(1, "adv_build_req: no free adv_sgblk_t\n");
+ ASC_STATS(scp->host, adv_build_nosg);
+ /*
+ * Free the 'adv_req_t' structure by adding it back to the
+ * board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+ return ASC_BUSY;
+ } else {
+ reqp->sgblkp = boardp->adv_sgblkp;
+ boardp->adv_sgblkp = reqp->sgblkp->next_sgblkp;
+ reqp->sgblkp->next_sgblkp = NULL;
}
-#endif /* ASC_QUEUE_FLOW_CONTROL */
- asc_enqueue(&boardp->active, scp, ASC_BACK);
- ASC_DBG(1, "asc_execute_scsi_cmnd: AscExeScsiQueue(), ASC_NOERROR\n");
- break;
- case ASC_BUSY:
- /* Caller must enqueue request and retry later. */
- ASC_STATS(scp->host, asc_busy);
-#if ASC_QUEUE_FLOW_CONTROL
+
/*
- * Clear consecutive no error counter and if possbile decrement
- * queue depth.
+ * Build scatter-gather list.
*/
- boardp->nerrcnt[scp->target] = 0;
- if (device->queue_curr_depth > 1) {
- device->queue_curr_depth--;
+ scsiqp->sg_list_ptr = (ADV_SG_BLOCK *)
+ ADV_DWALIGN(&reqp->sgblkp->sg_block[0]);
+
+ memset(scsiqp->sg_list_ptr, 0, sizeof(ADV_SG_BLOCK) *
+ (ADV_NUM_SG_BLOCK + ADV_NUM_PAGE_CROSSING));
+
+ if (adv_get_sglist(&boardp->dvc_var.adv_dvc_var, scsiqp, scp) ==
+ ADV_ERROR) {
+
+ /*
+ * Free the adv_sgblk_t structure, if any, by adding it back
+ * to the board free list.
+ */
+ ASC_ASSERT(reqp->sgblkp != NULL);
+ reqp->sgblkp->next_sgblkp = boardp->adv_sgblkp;
+ boardp->adv_sgblkp = reqp->sgblkp;
+
+ /*
+ * Free the adv_req_t structure by adding it back to the
+ * board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ return ADV_ERROR;
}
-#endif /* ASC_QUEUE_FLOW_CONTROL */
- break;
- case ASC_ERROR:
- ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() ASC_ERROR, err_code %x\n",
- boardp->id, asc_dvc_varp->err_code);
- ASC_STATS(scp->host, asc_error);
-#if ASC_QUEUE_FLOW_CONTROL
- /* Clear consecutive no error counter. */
- boardp->nerrcnt[scp->target] = 0;
-#endif /* ASC_QUEUE_FLOW_CONTROL */
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
- default:
- ASC_PRINT2(
-"asc_execute_scsi_cmnd: board %d: AscExeScsiQueue() unknown, err_code %x\n",
- boardp->id, asc_dvc_varp->err_code);
- ASC_STATS(scp->host, asc_unknown);
-#if ASC_QUEUE_FLOW_CONTROL
- /* Clear consecutive no error counter. */
- boardp->nerrcnt[scp->target] = 0;
-#endif /* ASC_QUEUE_FLOW_CONTROL */
- scp->result = HOST_BYTE(DID_ERROR);
- asc_enqueue(&boardp->done, scp, ASC_BACK);
- break;
+
+ ASC_STATS(scp->host, sg_cnt);
+ ASC_STATS_ADD(scp->host, sg_elem, scp->use_sg);
}
- ASC_DBG(1, "asc_execute_scsi_cmnd: end\n");
- ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
- return ret;
+ ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+ ASC_DBG_PRT_CDB(1, scp->cmnd, scp->cmd_len);
+
+ *adv_scsiqpp = scsiqp;
+
+ return ASC_NOERROR;
+}
+
+/*
+ * Build scatter-gather list for Adv Library (Wide Board).
+ *
+ * Return:
+ * ADV_SUCCESS(1) - SG List successfully created
+ * ADV_ERROR(-1) - SG List creation failed
+ */
+STATIC int
+adv_get_sglist(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp,
+ Scsi_Cmnd *scp)
+{
+ ADV_SG_BLOCK *sg_block; /* virtual address of a SG */
+ ulong sg_block_next_addr; /* block and its next */
+ ulong sg_block_physical_addr;
+ int sg_block_index, i; /* how many SG entries */
+ struct scatterlist *slp;
+ int sg_elem_cnt;
+
+ slp = (struct scatterlist *) scp->request_buffer;
+ sg_elem_cnt = scp->use_sg;
+
+ sg_block = scsiqp->sg_list_ptr;
+ sg_block_next_addr = (ulong) sg_block; /* allow math operation */
+ sg_block_physical_addr =
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+ (ulong) scsiqp->sg_list_ptr;
+#else /* version >= v2.0.0 */
+ virt_to_bus(scsiqp->sg_list_ptr);
+#endif /* version >= v2.0.0 */
+ ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) ==
+ sg_block_physical_addr);
+ scsiqp->sg_real_addr = sg_block_physical_addr;
+
+ sg_block_index = 0;
+ do
+ {
+ sg_block->first_entry_no = sg_block_index;
+ for (i = 0; i < NO_OF_SG_PER_BLOCK; i++)
+ {
+ sg_block->sg_list[i].sg_addr =
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+ (ulong) slp->address;
+#else /* version >= v2.0.0 */
+ virt_to_bus(slp->address);
+#endif /* version >= v2.0.0 */
+ sg_block->sg_list[i].sg_count = slp->length;
+ ASC_STATS_ADD(scp->host, sg_xfer, ASC_CEILING(slp->length, 512));
+
+ if (--sg_elem_cnt == 0)
+ { /* last entry, get out */
+ scsiqp->sg_entry_cnt = sg_block_index + i + 1;
+ sg_block->last_entry_no = sg_block_index + i;
+ sg_block->sg_ptr = 0L; /* next link = NULL */
+ return ADV_SUCCESS;
+ }
+ slp++;
+ }
+ sg_block_next_addr += sizeof(ADV_SG_BLOCK);
+ sg_block_physical_addr += sizeof(ADV_SG_BLOCK);
+ ADV_ASSERT(ADV_DWALIGN(sg_block_physical_addr) ==
+ sg_block_physical_addr);
+
+ sg_block_index += NO_OF_SG_PER_BLOCK;
+ sg_block->sg_ptr = (ADV_SG_BLOCK *) sg_block_physical_addr;
+ sg_block->last_entry_no = sg_block_index - 1;
+ sg_block = (ADV_SG_BLOCK *) sg_block_next_addr; /* virtual addr */
+ }
+ while (1);
+ /* NOTREACHED */
}
/*
* asc_isr_callback() - Second Level Interrupt Handler called by AscISR().
+ *
+ * Interrupt callback function for the Narrow SCSI Asc Library.
*/
STATIC void
asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
@@ -4824,12 +6903,13 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
asc_board_t *boardp;
Scsi_Cmnd *scp;
struct Scsi_Host *shp;
+ int underrun = ASC_FALSE;
int i;
ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
ASC_DBG2(1, "asc_isr_callback: asc_dvc_varp %x, qdonep %x\n",
(unsigned) asc_dvc_varp, (unsigned) qdonep);
- ASC_DBG_PRT_QDONE_INFO(2, qdonep);
+ ASC_DBG_PRT_ASC_QDONE_INFO(2, qdonep);
/*
* Get the Scsi_Cmnd structure and Scsi_Host structure for the
@@ -4837,12 +6917,12 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
*/
scp = (Scsi_Cmnd *) qdonep->d2.srb_ptr;
ASC_DBG1(1, "asc_isr_callback: scp %x\n", (unsigned) scp);
- ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
if (scp == NULL) {
ASC_PRINT("asc_isr_callback: scp is NULL\n");
return;
}
+ ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
/*
* If the request's host pointer is not valid, display a
@@ -4876,6 +6956,16 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
}
/*
+ * Check for an underrun condition.
+ */
+ if (scp->request_bufflen != 0 && qdonep->remain_bytes != 0 &&
+ qdonep->remain_bytes <= scp->request_bufflen != 0) {
+ ASC_DBG1(1, "asc_isr_callback: underrun condition %u bytes\n",
+ (unsigned) qdonep->remain_bytes);
+ underrun = ASC_TRUE;
+ }
+
+ /*
* 'qdonep' contains the command's ending status.
*/
switch (qdonep->d3.done_stat) {
@@ -4890,6 +6980,13 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
scp->result = HOST_BYTE(DID_ERROR);
break;
}
+ /*
+ * If there was an underrun without any other error,
+ * set DID_ERROR to indicate the underrun error.
+ */
+ if (scp->result == 0 && underrun == ASC_TRUE) {
+ scp->result = HOST_BYTE(DID_UNDERRUN);
+ }
break;
case QD_WITH_ERROR:
@@ -4952,9 +7049,215 @@ asc_isr_callback(ASC_DVC_VAR *asc_dvc_varp, ASC_QDONE_INFO *qdonep)
}
/*
- * asc_init_dev()
+ * adv_isr_callback() - Second Level Interrupt Handler called by AdvISR().
*
- * Perform one-time initialization of a device.
+ * Callback function for the Wide SCSI Adv Library.
+ */
+STATIC void
+adv_isr_callback(ADV_DVC_VAR *adv_dvc_varp, ADV_SCSI_REQ_Q *scsiqp)
+{
+ asc_board_t *boardp;
+ adv_req_t *reqp;
+ Scsi_Cmnd *scp;
+ struct Scsi_Host *shp;
+ int underrun = ASC_FALSE;
+ int i;
+
+ ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
+ ASC_DBG2(1, "adv_isr_callback: adv_dvc_varp %x, scsiqp %x\n",
+ (unsigned) adv_dvc_varp, (unsigned) scsiqp);
+ ASC_DBG_PRT_ADV_SCSI_REQ_Q(2, scsiqp);
+
+ /*
+ * Get the adv_req_t structure for the command that has been
+ * completed. The adv_req_t structure actually contains the
+ * completed ADV_SCSI_REQ_Q structure.
+ */
+ reqp = (adv_req_t *) scsiqp->srb_ptr;
+ ASC_DBG1(1, "adv_isr_callback: reqp %x\n", (unsigned) reqp);
+ if (reqp == NULL) {
+ ASC_PRINT("adv_isr_callback: reqp is NULL\n");
+ return;
+ }
+
+ /*
+ * Get the Scsi_Cmnd structure and Scsi_Host structure for the
+ * command that has been completed.
+ *
+ * Note: The adv_req_t request structure and adv_sgblk_t structure,
+ * if any, * dropped, because a board structure pointer can not be
+ * determined.
+ */
+ scp = reqp->cmndp;
+ ASC_DBG1(1, "adv_isr_callback: scp %x\n", (unsigned) scp);
+ if (scp == NULL) {
+ ASC_PRINT("adv_isr_callback: scp is NULL; adv_req_t dropped.\n");
+ return;
+ }
+ ASC_DBG_PRT_CDB(2, scp->cmnd, scp->cmd_len);
+
+ /*
+ * If the request's host pointer is not valid, display a message
+ * and return.
+ */
+ shp = scp->host;
+ for (i = 0; i < asc_board_count; i++) {
+ if (asc_host[i] == shp) {
+ break;
+ }
+ }
+ /*
+ * Note: If the host structure is not found, the adv_req_t request
+ * structure and adv_sgblk_t structure, if any, is dropped.
+ */
+ if (i == asc_board_count) {
+ ASC_PRINT2("adv_isr_callback: scp %x has bad host pointer, host %x\n",
+ (unsigned) scp, (unsigned) shp);
+ return;
+ }
+
+ ASC_STATS(shp, callback);
+ ASC_DBG1(1, "adv_isr_callback: shp %x\n", (unsigned) shp);
+
+ /*
+ * If the request isn't found on the active queue, it may have been
+ * removed to handle a reset or abort request. Display a message and
+ * return.
+ *
+ * Note: Because the structure may still be in use don't attempt
+ * to free the adv_req_t and adv_sgblk_t, if any, structures.
+ */
+ boardp = ASC_BOARDP(shp);
+ if (asc_rmqueue(&boardp->active, scp) == ASC_FALSE) {
+ ASC_PRINT2("adv_isr_callback: board %d: scp %x not on active queue\n",
+ boardp->id, (unsigned) scp);
+ return;
+ }
+
+ /*
+ * Check for an underrun condition.
+ */
+ if (scp->request_bufflen != 0 && scsiqp->data_cnt != 0) {
+ ASC_DBG1(1, "adv_isr_callback: underrun condition %lu bytes\n",
+ scsiqp->data_cnt);
+ underrun = ASC_TRUE;
+ }
+
+ /*
+ * 'done_status' contains the command's ending status.
+ */
+ switch (scsiqp->done_status) {
+ case QD_NO_ERROR:
+ ASC_DBG(2, "adv_isr_callback: QD_NO_ERROR\n");
+ switch (scsiqp->host_status) {
+ case QHSTA_NO_ERROR:
+ scp->result = 0;
+ break;
+ default:
+ /* QHSTA error occurred. */
+ ASC_DBG1(2, "adv_isr_callback: host_status %x\n",
+ scsiqp->host_status);
+ scp->result = HOST_BYTE(DID_ERROR);
+ break;
+ }
+ /*
+ * If there was an underrun without any other error,
+ * set DID_ERROR to indicate the underrun error.
+ */
+ if (scp->result == 0 && underrun == ASC_TRUE) {
+ scp->result = HOST_BYTE(DID_UNDERRUN);
+ }
+ break;
+
+ case QD_WITH_ERROR:
+ ASC_DBG(2, "adv_isr_callback: QD_WITH_ERROR\n");
+ switch (scsiqp->host_status) {
+ case QHSTA_NO_ERROR:
+ if (scsiqp->scsi_status == SS_CHK_CONDITION) {
+ ASC_DBG(2, "adv_isr_callback: SS_CHK_CONDITION\n");
+ ASC_DBG_PRT_SENSE(2, scp->sense_buffer,
+ sizeof(scp->sense_buffer));
+ /*
+ * Note: The 'status_byte()' macro used by target drivers
+ * defined in scsi.h shifts the status byte returned by
+ * host drivers right by 1 bit. This is why target drivers
+ * also use right shifted status byte definitions. For
+ * instance target drivers use CHECK_CONDITION, defined to
+ * 0x1, instead of the SCSI defined check condition value
+ * of 0x2. Host drivers are supposed to return the status
+ * byte as it is defined by SCSI.
+ */
+ scp->result = DRIVER_BYTE(DRIVER_SENSE) |
+ STATUS_BYTE(scsiqp->scsi_status);
+ } else {
+ scp->result = STATUS_BYTE(scsiqp->scsi_status);
+ }
+ break;
+
+ default:
+ /* Some other QHSTA error occurred. */
+ ASC_DBG1(2, "adv_isr_callback: host_status %x\n",
+ scsiqp->host_status);
+ scp->result = HOST_BYTE(DID_BAD_TARGET);
+ break;
+ }
+ break;
+
+ case QD_ABORTED_BY_HOST:
+ ASC_DBG(1, "adv_isr_callback: QD_ABORTED_BY_HOST\n");
+ scp->result = HOST_BYTE(DID_ABORT) | STATUS_BYTE(scsiqp->scsi_status);
+ break;
+
+ default:
+ ASC_PRINT1("adv_isr_callback: done_status %x\n", scsiqp->done_status);
+ scp->result = HOST_BYTE(DID_ERROR) | STATUS_BYTE(scsiqp->scsi_status);
+ break;
+ }
+
+ /*
+ * If the 'init_tidmask' bit isn't already set for the target and the
+ * current request did not finish with a Selection Timeout, then set
+ * the bit for the target to indicate that a device is present.
+ */
+ if ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(scp->target)) == 0 &&
+ scsiqp->done_status == QD_NO_ERROR &&
+ scsiqp->host_status == QHSTA_NO_ERROR) {
+ boardp->init_tidmask |= ADV_TID_TO_TIDMASK(scp->target);
+ }
+
+ /*
+ * Because interrupts may be enabled by the 'Scsi_Cmnd' done
+ * function, add the command to the end of the board's done queue.
+ * The done function for the command will be called from
+ * advansys_interrupt().
+ */
+ asc_enqueue(&boardp->done, scp, ASC_BACK);
+
+ /*
+ * Free the adv_sgblk_t structure, if any, by adding it back
+ * to the board free list.
+ */
+ if (reqp->sgblkp != NULL) {
+ reqp->sgblkp->next_sgblkp = boardp->adv_sgblkp;
+ boardp->adv_sgblkp = reqp->sgblkp;
+ }
+
+ /*
+ * Free the adv_req_t structure used with the command by adding
+ * it back to the board free list.
+ */
+ reqp->next_reqp = boardp->adv_reqp;
+ boardp->adv_reqp = reqp;
+
+ ASC_DBG(1, "adv_isr_callback: done\n");
+
+ return;
+}
+
+/*
+ * asc_init_dev() - Narrow Board initialization function.
+ *
+ * Perform one-time initialization of a device for Asc Library
*/
STATIC int
asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
@@ -4987,10 +7290,9 @@ asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
memset(inquiry, 0, sizeof(ASC_SCSI_INQUIRY));
/*
- * XXX - AscInitPollBegin() re-initializes these fields to
- * zero. 'Or' in the new values and restore them before calling
- * AscInitPollEnd(). Normally all targets are initialized within
- * a call to AscInitPollBegin() and AscInitPollEnd().
+ * AscInitPollBegin() re-initializes these bitmask fields to zero.
+ * Save the current bitmask value and 'or' them back in after calling
+ * AscInitPollEnd() below..
*/
save_use_tagged_qng = asc_dvc_varp->use_tagged_qng;
save_can_tagged_qng = asc_dvc_varp->cfg->can_tagged_qng;
@@ -5015,7 +7317,7 @@ asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
case ASC_TRUE:
found = ASC_TRUE;
#ifdef ADVANSYS_DEBUG
- tidmask = ASC_TIX_TO_TARGET_ID(scp->target);
+ tidmask = ADV_TID_TO_TIDMASK(scp->target);
ASC_DBG2(1, "asc_init_dev: lba %lu, blk_size %lu\n",
cap_info->lba, cap_info->blk_size);
ASC_DBG1(1, "asc_init_dev: peri_dvc_type %x\n",
@@ -5053,7 +7355,7 @@ asc_init_dev(ASC_DVC_VAR *asc_dvc_varp, Scsi_Cmnd *scp)
break;
}
- /* XXX - 'Or' in original tag bits. */
+ /* Restore previously set bits in the bitmask fields. */
asc_dvc_varp->use_tagged_qng |= save_use_tagged_qng;
asc_dvc_varp->cfg->can_tagged_qng |= save_can_tagged_qng;
@@ -5166,7 +7468,8 @@ asc_pci_find_dev(PCI_DEVICE *pciDevice)
if ((vendorid == ASC_PCI_VENDORID) &&
((deviceid == ASC_PCI_DEVICE_ID_1100) ||
(deviceid == ASC_PCI_DEVICE_ID_1200) ||
- (deviceid == ASC_PCI_DEVICE_ID_1300))) {
+ (deviceid == ASC_PCI_DEVICE_ID_1300) ||
+ (deviceid == ASC_PCI_DEVICE_ID_2300))) {
pciDevice->slotFound = lslot;
ASC_DBG(3, "asc_pci_find_dev: PCI_DEVICE_FOUND\n");
return PCI_DEVICE_FOUND;
@@ -5311,74 +7614,8 @@ asc_get_cfg_byte(PCI_DATA *pciData)
)
{
uchar tmp;
- ulong address;
- ulong lbus = pciData->bus, lslot = pciData->slot, lfunc = pciData->func;
- uchar t2CFA, t2CF8;
- ulong t1CF8, t1CFC;
-
- ASC_DBG1(4, "asc_get_cfg_byte: type: %d\n", pciData->type);
-
- /*
- * Check type of configuration mechanism.
- */
- if (pciData->type == 2) {
- /*
- * Save registers to be restored later.
- */
- t2CFA = inp(0xCFA); /* save PCI bus register */
- t2CF8 = inp(0xCF8); /* save config space enable register */
-
- /*
- * Write the bus and enable registers.
- */
- /* set for type 1 cycle, if needed */
- outp(0xCFA, pciData->bus);
- /* set the function number */
- outp(0xCF8, 0x10 | (pciData->func << 1));
-
- /*
- * Read configuration space type 2 locations.
- */
- tmp = inp(0xC000 | ((pciData->slot << 8) + pciData->offset));
-
- /*
- * Restore registers.
- */
- outp(0xCF8, t2CF8); /* restore the enable register */
- outp(0xCFA, t2CFA); /* restore PCI bus register */
- } else {
- /*
- * Type 1 or 3 configuration mechanism.
- *
- * Save CONFIG_ADDRESS and CONFIG_DATA register values.
- */
- t1CF8 = inpl(0xCF8);
- t1CFC = inpl(0xCFC);
-
- /*
- * enable <31>, bus = <23:16>, slot = <15:11>, func = <10:8>,
- * reg = <7:2>
- */
- address = (ulong) ((lbus << 16) | (lslot << 11) |
- (lfunc << 8) | (pciData->offset & 0xFC) | 0x80000000L);
- /*
- * Write out address to CONFIG_ADDRESS.
- */
- outpl(0xCF8, address);
-
- /*
- * Read in word from CONFIG_DATA.
- */
- tmp = (uchar) ((inpl(0xCFC) >> ((pciData->offset & 3) * 8)) & 0xFF);
-
- /*
- * Restore registers.
- */
- outpl(0xCF8, t1CF8);
- outpl(0xCFC, t1CFC);
- }
- ASC_DBG1(4, "asc_get_cfg_byte: config data: %x\n", tmp);
+ pcibios_read_config_byte(pciData->bus, pciData->slot * 8 + pciData->func, pciData->offset, &tmp);
return tmp;
}
@@ -5480,13 +7717,13 @@ asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
{
int tid;
- ASC_DBG3(2, "asc_enqueue: ascq %x, reqp %x, flag %d\n",
+ ASC_DBG3(3, "asc_enqueue: ascq %x, reqp %x, flag %d\n",
(unsigned) ascq, (unsigned) reqp, flag);
ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(reqp != NULL);
ASC_ASSERT(flag == ASC_FRONT || flag == ASC_BACK);
tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+ ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
if (flag == ASC_FRONT) {
REQPNEXT(reqp) = ascq->q_first[tid];
ascq->q_first[tid] = reqp;
@@ -5506,19 +7743,19 @@ asc_enqueue(asc_queue_t *ascq, REQP reqp, int flag)
}
}
/* The queue has at least one entry, set its bit. */
- ascq->q_tidmask |= ASC_TIX_TO_TARGET_ID(tid);
+ ascq->q_tidmask |= ADV_TID_TO_TIDMASK(tid);
#ifdef ADVANSYS_STATS
/* Maintain request queue statistics. */
ascq->q_tot_cnt[tid]++;
ascq->q_cur_cnt[tid]++;
if (ascq->q_cur_cnt[tid] > ascq->q_max_cnt[tid]) {
ascq->q_max_cnt[tid] = ascq->q_cur_cnt[tid];
- ASC_DBG2(1, "asc_enqueue: new q_max_cnt[%d] %d\n",
+ ASC_DBG2(2, "asc_enqueue: new q_max_cnt[%d] %d\n",
tid, ascq->q_max_cnt[tid]);
}
REQPTIME(reqp) = REQTIMESTAMP();
#endif /* ADVANSYS_STATS */
- ASC_DBG1(1, "asc_enqueue: reqp %x\n", (unsigned) reqp);
+ ASC_DBG1(3, "asc_enqueue: reqp %x\n", (unsigned) reqp);
return;
}
@@ -5534,15 +7771,15 @@ asc_dequeue(asc_queue_t *ascq, int tid)
{
REQP reqp;
- ASC_DBG2(1, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid);
+ ASC_DBG2(3, "asc_dequeue: ascq %x, tid %d\n", (unsigned) ascq, tid);
ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
- ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+ ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
if ((reqp = ascq->q_first[tid]) != NULL) {
- ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid));
+ ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
ascq->q_first[tid] = REQPNEXT(reqp);
/* If the queue is empty, clear its bit and the last pointer. */
if (ascq->q_first[tid] == NULL) {
- ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+ ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
ASC_ASSERT(ascq->q_last[tid] == reqp);
ascq->q_last[tid] = NULL;
}
@@ -5553,7 +7790,7 @@ asc_dequeue(asc_queue_t *ascq, int tid)
REQTIMESTAT("asc_dequeue", ascq, reqp, tid);
#endif /* ADVANSYS_STATS */
}
- ASC_DBG1(1, "asc_dequeue: reqp %x\n", (unsigned) reqp);
+ ASC_DBG1(3, "asc_dequeue: reqp %x\n", (unsigned) reqp);
return reqp;
}
@@ -5583,9 +7820,9 @@ asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
REQP firstp, lastp;
int i;
- ASC_DBG2(1, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid);
+ ASC_DBG2(3, "asc_dequeue_list: ascq %x, tid %d\n", (unsigned) ascq, tid);
ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
- ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ASC_MAX_TID));
+ ASC_ASSERT((tid == ASC_TID_ALL) || (tid >= 0 && tid <= ADV_MAX_TID));
/*
* If 'tid' is not ASC_TID_ALL, return requests only for
@@ -5594,14 +7831,14 @@ asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
*/
if (tid != ASC_TID_ALL) {
/* Return all requests for the specified 'tid'. */
- if ((ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid)) == 0) {
+ if ((ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid)) == 0) {
/* List is empty; Set first and last return pointers to NULL. */
firstp = lastp = NULL;
} else {
firstp = ascq->q_first[tid];
lastp = ascq->q_last[tid];
ascq->q_first[tid] = ascq->q_last[tid] = NULL;
- ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+ ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
#ifdef ADVANSYS_STATS
{
REQP reqp;
@@ -5615,8 +7852,8 @@ asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
} else {
/* Return all requests for all tids. */
firstp = lastp = NULL;
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if (ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if (ascq->q_tidmask & ADV_TID_TO_TIDMASK(i)) {
if (firstp == NULL) {
firstp = ascq->q_first[i];
lastp = ascq->q_last[i];
@@ -5626,7 +7863,7 @@ asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
lastp = ascq->q_last[i];
}
ascq->q_first[i] = ascq->q_last[i] = NULL;
- ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
+ ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(i);
#ifdef ADVANSYS_STATS
ascq->q_cur_cnt[i] = 0;
#endif /* ADVANSYS_STATS */
@@ -5644,7 +7881,7 @@ asc_dequeue_list(asc_queue_t *ascq, REQP *lastpp, int tid)
if (lastpp) {
*lastpp = lastp;
}
- ASC_DBG1(1, "asc_dequeue_list: firstp %x\n", (unsigned) firstp);
+ ASC_DBG1(3, "asc_dequeue_list: firstp %x\n", (unsigned) firstp);
return firstp;
}
@@ -5665,13 +7902,13 @@ asc_rmqueue(asc_queue_t *ascq, REQP reqp)
int tid;
int ret = ASC_FALSE;
- ASC_DBG2(1, "asc_rmqueue: ascq %x, reqp %x\n",
+ ASC_DBG2(3, "asc_rmqueue: ascq %x, reqp %x\n",
(unsigned) ascq, (unsigned) reqp);
ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(reqp != NULL);
tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+ ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
/*
* Handle the common case of 'reqp' being the first
@@ -5682,7 +7919,7 @@ asc_rmqueue(asc_queue_t *ascq, REQP reqp)
ascq->q_first[tid] = REQPNEXT(reqp);
/* If the queue is now empty, clear its bit and the last pointer. */
if (ascq->q_first[tid] == NULL) {
- ascq->q_tidmask &= ~ASC_TIX_TO_TARGET_ID(tid);
+ ascq->q_tidmask &= ~ADV_TID_TO_TIDMASK(tid);
ASC_ASSERT(ascq->q_last[tid] == reqp);
ascq->q_last[tid] = NULL;
}
@@ -5718,7 +7955,7 @@ asc_rmqueue(asc_queue_t *ascq, REQP reqp)
}
ASC_ASSERT(ascq->q_cur_cnt[tid] >= 0);
#endif /* ADVANSYS_STATS */
- ASC_DBG2(1, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret);
+ ASC_DBG2(3, "asc_rmqueue: reqp %x, ret %d\n", (unsigned) reqp, ret);
return ret;
}
@@ -5733,22 +7970,22 @@ asc_isqueued(asc_queue_t *ascq, REQP reqp)
int tid;
int ret = ASC_FALSE;
- ASC_DBG2(1, "asc_isqueued: ascq %x, reqp %x\n",
+ ASC_DBG2(3, "asc_isqueued: ascq %x, reqp %x\n",
(unsigned) ascq, (unsigned) reqp);
ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
ASC_ASSERT(reqp != NULL);
tid = REQPTID(reqp);
- ASC_ASSERT(tid >= 0 && tid <= ASC_MAX_TID);
+ ASC_ASSERT(tid >= 0 && tid <= ADV_MAX_TID);
for (treqp = ascq->q_first[tid]; treqp; treqp = REQPNEXT(treqp)) {
- ASC_ASSERT(ascq->q_tidmask & ASC_TIX_TO_TARGET_ID(tid));
+ ASC_ASSERT(ascq->q_tidmask & ADV_TID_TO_TIDMASK(tid));
if (treqp == reqp) {
ret = ASC_TRUE;
break;
}
}
- ASC_DBG1(1, "asc_isqueued: ret %x\n", ret);
+ ASC_DBG1(3, "asc_isqueued: ret %x\n", ret);
return ret;
}
@@ -5760,9 +7997,9 @@ asc_isqueued(asc_queue_t *ascq, REQP reqp)
STATIC void
asc_execute_queue(asc_queue_t *ascq)
{
- ASC_SCSI_BIT_ID_TYPE scan_tidmask;
+ ADV_SCSI_BIT_ID_TYPE scan_tidmask;
REQP reqp;
- int i;
+ int i;
ASC_DBG1(1, "asc_execute_queue: ascq %x\n", (unsigned) ascq);
ASC_ASSERT(interrupts_enabled() == ASC_FALSE);
@@ -5772,13 +8009,13 @@ asc_execute_queue(asc_queue_t *ascq)
*/
scan_tidmask = ascq->q_tidmask;
do {
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if (scan_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if (scan_tidmask & ADV_TID_TO_TIDMASK(i)) {
if ((reqp = asc_dequeue(ascq, i)) == NULL) {
- scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
+ scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
} else if (asc_execute_scsi_cmnd((Scsi_Cmnd *) reqp)
== ASC_BUSY) {
- scan_tidmask &= ~ASC_TIX_TO_TARGET_ID(i);
+ scan_tidmask &= ~ADV_TID_TO_TIDMASK(i);
/* Put the request back at front of the list. */
asc_enqueue(ascq, reqp, ASC_FRONT);
}
@@ -5807,6 +8044,7 @@ asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
int leftlen;
int totlen;
int len;
+ int chip_scsi_id;
int i;
boardp = ASC_BOARDP(shp);
@@ -5817,25 +8055,166 @@ asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
"\nDevice Information for AdvanSys SCSI Host %d:\n", shp->host_no);
ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen, "Target Ids Detected:");
+ if (ASC_NARROW_BOARD(boardp)) {
+ chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+ } else {
+ chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+ }
+
+ len = asc_prt_line(cp, leftlen, "Target IDs Detected:");
ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if (boardp->asc_dvc_cfg.chip_scsi_id == i) {
- continue;
- } else if (boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) {
- len = asc_prt_line(cp, leftlen, " %d,", i);
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if (boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) {
+ len = asc_prt_line(cp, leftlen, " %X,", i);
ASC_PRT_NEXT();
}
}
- len = asc_prt_line(cp, leftlen, " (%d=Host Adapter)\n",
- boardp->asc_dvc_cfg.chip_scsi_id);
+ len = asc_prt_line(cp, leftlen, " (%X=Host Adapter)\n", chip_scsi_id);
ASC_PRT_NEXT();
- return totlen;
+ return totlen;
+}
+
+/*
+ * Display Wide Board BIOS Information.
+ */
+STATIC int
+asc_prt_adv_bios(struct Scsi_Host *shp, char *cp, int cplen)
+{
+ asc_board_t *boardp;
+ int leftlen;
+ int totlen;
+ int len;
+ int upgrade = ASC_FALSE;
+ ushort major, minor, letter;
+
+ boardp = ASC_BOARDP(shp);
+ leftlen = cplen;
+ totlen = len = 0;
+
+ len = asc_prt_line(cp, leftlen, "\nROM BIOS Version: ");
+ ASC_PRT_NEXT();
+
+ /*
+ * If the BIOS saved a valid signature, then fill in
+ * the BIOS code segment base address.
+ */
+ if (boardp->bios_signature != 0x55AA) {
+ len = asc_prt_line(cp, leftlen, "Pre-3.1\n");
+ ASC_PRT_NEXT();
+ upgrade = ASC_TRUE;
+ } else {
+ major = (boardp->bios_version >> 12) & 0xF;
+ minor = (boardp->bios_version >> 8) & 0xF;
+ letter = (boardp->bios_version & 0xFF);
+
+ len = asc_prt_line(cp, leftlen, "%d.%d%c\n",
+ major, minor, letter >= 26 ? '?' : letter + 'A');
+ ASC_PRT_NEXT();
+
+ /* Current available ROM BIOS release is 3.1E. */
+ if (major < 3 || (major <= 3 && minor < 1) ||
+ (major <= 3 && minor <= 1 && letter < ('E'- 'A'))) {
+ upgrade = ASC_TRUE;
+ }
+ }
+ if (upgrade == ASC_TRUE) {
+ len = asc_prt_line(cp, leftlen,
+"Newer version of ROM BIOS available: ftp://ftp.advansys.com/pub\n");
+ ASC_PRT_NEXT();
+ }
+
+ return totlen;
}
/*
- * asc_prt_board_eeprom()
+ * Add serial number to information bar if signature AAh
+ * is found in at bit 15-9 (7 bits) of word 1.
+ *
+ * Serial Number consists 12 alpha-numeric digits.
+ *
+ * 1 - Product type (A,B,C,D..) Word0: 15-13 (3 bits)
+ * 2 - MFG Location (A,B,C,D..) Word0: 12-10 (3 bits)
+ * 3-4 - Product ID (0-99) Word0: 10-0 (11 bits)
+ * 5 - Product revision Word0: " "
+ *
+ * Signature Word1: 15-9 (7 bits)
+ * 6 - Year (4-9) Word1: 8-6 (3 bits)
+ * 7-8 - Week of the year Word1: 5-0 (6 bits)
+ *
+ * 9-12 - Serial Number Word2: 15-0 (16 bits)
+ *
+ * Note 1: Only production cards will have a serial number.
+ *
+ * Note 2: Signature is most significant 7 bits (0xFE).
+ *
+ * Returns ASC_TRUE if serial number found, otherwise returns ASC_FALSE.
+ */
+STATIC int
+asc_get_eeprom_string(ushort *serialnum, uchar *cp)
+{
+ ushort w, num;
+
+ if ((serialnum[1] & 0xFE00) != ((ushort) 0xAA << 8)) {
+ return ASC_FALSE;
+ } else {
+ /*
+ * First word - 6 digits.
+ */
+ w = serialnum[0];
+
+ /* Product type - 1st digit. */
+ *cp++ = 'A' + ((w & 0xE000) >> 13);
+
+ /* Manufacturing location - 2nd digit. */
+ *cp++ = 'A' + ((w & 0x1C00) >> 10);
+
+ /* Product ID - 3rd, 4th digits. */
+ num = w & 0x3FF;
+ *cp++ = '0' + (num / 100);
+ num %= 100;
+ *cp++ = '0' + (num / 10);
+
+ /* Product revision - 5th digit. */
+ *cp++ = 'A' + (num % 10);
+
+ /*
+ * Second word
+ */
+ w = serialnum[1];
+
+ /* Year - 6th digit. */
+ *cp++ = '0' + ((w & 0x1C0) >> 6);
+
+ /* Week of year - 7th, 8th digits. */
+ num = w & 0x003F;
+ *cp++ = '0' + num / 10;
+ num %= 10;
+ *cp++ = '0' + num;
+
+ /*
+ * Third word
+ */
+ w = serialnum[2];
+
+ /* Serial number - 9th digit. */
+ *cp++ = 'A' + (w / 1000);
+
+ /* 10th, 11th, 12th digits. */
+ num = w % 1000;
+ *cp++ = '0' + num / 100;
+ num %= 100;
+ *cp++ = '0' + num / 10;
+ num %= 10;
+ *cp++ = '0' + num;
+
+ *cp = '\0'; /* Null Terminate the string. */
+ return ASC_TRUE;
+ }
+}
+
+/*
+ * asc_prt_asc_board_eeprom()
*
* Print board EEPROM configuration.
*
@@ -5846,7 +8225,7 @@ asc_prt_board_devices(struct Scsi_Host *shp, char *cp, int cplen)
* 'cplen' characters will be copied to 'cp'.
*/
STATIC int
-asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
+asc_prt_asc_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
{
asc_board_t *boardp;
ASC_DVC_VAR *asc_dvc_varp;
@@ -5856,10 +8235,11 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
ASCEEP_CONFIG *ep;
int i;
int isa_dma_speed[] = { 10, 8, 7, 6, 5, 4, 3, 2 };
+ uchar serialstr[13];
boardp = ASC_BOARDP(shp);
- asc_dvc_varp = &boardp->asc_dvc_var;
- ep = &boardp->eep_config;
+ asc_dvc_varp = &boardp->dvc_var.asc_dvc_var;
+ ep = &boardp->eep_config.asc_eep;
leftlen = cplen;
totlen = len = 0;
@@ -5868,17 +8248,48 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
ASC_PRT_NEXT();
+ if (asc_get_eeprom_string((ushort *) &ep->adapter_info[0], serialstr) ==
+ ASC_TRUE) {
+ len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
+ ASC_PRT_NEXT();
+ } else {
+ if (ep->adapter_info[5] == 0xBB) {
+ len = asc_prt_line(cp, leftlen,
+ " Default Settings Used for EEPROM-less Adapter.\n");
+ ASC_PRT_NEXT();
+ } else {
+ len = asc_prt_line(cp, leftlen,
+ " Serial Number Signature Not Present.\n");
+ ASC_PRT_NEXT();
+ }
+ }
+
len = asc_prt_line(cp, leftlen,
" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
ep->chip_scsi_id, ep->max_total_qng, ep->max_tag_qng);
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
+" cntl %x, no_scam %x\n",
+ ep->cntl, ep->no_scam);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Target ID: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %d", i);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
" Disconnects: ");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %d:%c",
- i, (ep->disc_enable & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
@@ -5888,8 +8299,8 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
" Command Queuing: ");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %d:%c",
- i, (ep->use_cmd_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->use_cmd_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
@@ -5899,8 +8310,8 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
" Start Motor: ");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %d:%c",
- i, (ep->start_motor & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
@@ -5910,8 +8321,8 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
" Synchronous Transfer:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- len = asc_prt_line(cp, leftlen, " %d:%c",
- i, (ep->init_sdtr & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->init_sdtr & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
@@ -5928,6 +8339,156 @@ asc_prt_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
}
/*
+ * asc_prt_adv_board_eeprom()
+ *
+ * Print board EEPROM configuration.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_adv_board_eeprom(struct Scsi_Host *shp, char *cp, int cplen)
+{
+ asc_board_t *boardp;
+ ADV_DVC_VAR *adv_dvc_varp;
+ int leftlen;
+ int totlen;
+ int len;
+ int i;
+ char *termstr;
+ uchar serialstr[13];
+ ADVEEP_CONFIG *ep;
+
+ boardp = ASC_BOARDP(shp);
+ adv_dvc_varp = &boardp->dvc_var.adv_dvc_var;
+ ep = &boardp->eep_config.adv_eep;
+
+ leftlen = cplen;
+ totlen = len = 0;
+
+ len = asc_prt_line(cp, leftlen,
+"\nEEPROM Settings for AdvanSys SCSI Host %d:\n", shp->host_no);
+ ASC_PRT_NEXT();
+
+ if (asc_get_eeprom_string(&ep->serial_number_word1, serialstr) ==
+ ASC_TRUE) {
+ len = asc_prt_line(cp, leftlen, " Serial Number: %s\n", serialstr);
+ ASC_PRT_NEXT();
+ } else {
+ len = asc_prt_line(cp, leftlen,
+ " Serial Number Signature Not Present.\n");
+ ASC_PRT_NEXT();
+ }
+
+ len = asc_prt_line(cp, leftlen,
+" Host SCSI ID: %u, Host Queue Size: %u, Device Queue Size: %u\n",
+ ep->adapter_scsi_id, ep->max_host_qng, ep->max_dvc_qng);
+ ASC_PRT_NEXT();
+
+ switch (ep->termination) {
+ case 1:
+ termstr = "Low Off/High Off";
+ break;
+ case 2:
+ termstr = "Low Off/High On";
+ break;
+ case 3:
+ termstr = "Low On/High On";
+ break;
+ default:
+ case 0:
+ termstr = "Automatic";
+ break;
+ }
+
+ len = asc_prt_line(cp, leftlen,
+" termination: %u (%s), bios_ctrl: %x\n",
+ ep->termination, termstr, ep->bios_ctrl);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Target ID: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %X", i);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Disconnects: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->disc_enable & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Command Queuing: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->tagqng_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Start Motor: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->start_motor & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Synchronous Transfer:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Ultra Transfer: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->ultra_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Wide Transfer: ");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ len = asc_prt_line(cp, leftlen, " %c",
+ (ep->wdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ return totlen;
+}
+
+/*
* asc_prt_driver_conf()
*
* Note: no single line should be greater than ASC_PRTLINE_SIZE,
@@ -5943,6 +8504,7 @@ asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
int leftlen;
int totlen;
int len;
+ int chip_scsi_id;
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
int i;
#endif /* version >= v1.3.89 */
@@ -5989,65 +8551,82 @@ asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
#endif /* version >= v1.3.57 */
ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
-" flags %x, last_reset %x, jiffies %x\n",
- ASC_BOARDP(shp)->flags, ASC_BOARDP(shp)->last_reset, jiffies);
+ len = asc_prt_line(cp, leftlen, " flags %x, last_reset %x, jiffies %x\n",
+ boardp->flags, boardp->last_reset, jiffies);
ASC_PRT_NEXT();
+ if (ASC_NARROW_BOARD(boardp)) {
+ chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+ } else {
+ chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+ }
+
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(1,3,89)
- len = asc_prt_line(cp, leftlen,
-" queue_depth: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
- continue;
+ if (boardp->flags & ASC_SELECT_QUEUE_DEPTHS) {
+ len = asc_prt_line(cp, leftlen, " queue_depth:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+ if (boardp->device[i] == NULL) {
+ continue;
+ }
+ len = asc_prt_line(cp, leftlen, " %X:%d",
+ i, boardp->device[i]->queue_depth);
+ ASC_PRT_NEXT();
}
- len = asc_prt_line(cp, leftlen, " %d:%d",
- i, boardp->device[i]->queue_depth);
+ len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
#endif /* version >= v1.3.89 */
#if ASC_QUEUE_FLOW_CONTROL
- len = asc_prt_line(cp, leftlen,
-" queue_curr_depth:");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
- continue;
+ if (ASC_NARROW_BOARD(boardp)) {
+ len = asc_prt_line(cp, leftlen, " queue_curr_depth:");
+ ASC_PRT_NEXT();
+ /* Use ASC_MAX_TID for Narrow Board. */
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+ if (boardp->device[i] == NULL) {
+ continue;
+ }
+ len = asc_prt_line(cp, leftlen, " %d:%d",
+ i, boardp->device[i]->queue_curr_depth);
+ ASC_PRT_NEXT();
}
- len = asc_prt_line(cp, leftlen, " %d:%d",
- i, boardp->device[i]->queue_curr_depth);
+ len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
- }
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
- len = asc_prt_line(cp, leftlen,
-" queue_count: ");
- ASC_PRT_NEXT();
- for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
- continue;
+ len = asc_prt_line(cp, leftlen, " queue_count:");
+ ASC_PRT_NEXT();
+ /* Use ASC_MAX_TID for Narrow Board. */
+ for (i = 0; i <= ASC_MAX_TID; i++) {
+ if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+ if (boardp->device[i] == NULL) {
+ continue;
+ }
+ len = asc_prt_line(cp, leftlen, " %d:%d",
+ i, boardp->device[i]->queue_count);
+ ASC_PRT_NEXT();
}
- len = asc_prt_line(cp, leftlen, " %d:%d",
- i, boardp->device[i]->queue_count);
+ len = asc_prt_line(cp, leftlen, "\n");
ASC_PRT_NEXT();
}
- len = asc_prt_line(cp, leftlen, "\n");
- ASC_PRT_NEXT();
#endif /* ASC_QUEUE_FLOW_CONTROL */
- return totlen;
+ return totlen;
}
/*
- * asc_prt_board_info()
+ * asc_prt_asc_board_info()
*
* Print dynamic board configuration information.
*
@@ -6058,7 +8637,7 @@ asc_prt_driver_conf(struct Scsi_Host *shp, char *cp, int cplen)
* 'cplen' characters will be copied to 'cp'.
*/
STATIC int
-asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
+asc_prt_asc_board_info(struct Scsi_Host *shp, char *cp, int cplen)
{
asc_board_t *boardp;
int leftlen;
@@ -6069,8 +8648,8 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
int i;
boardp = ASC_BOARDP(shp);
- v = &boardp->asc_dvc_var;
- c = &boardp->asc_dvc_cfg;
+ v = &boardp->dvc_var.asc_dvc_var;
+ c = &boardp->dvc_cfg.asc_dvc_cfg;
leftlen = cplen;
totlen = len = 0;
@@ -6081,30 +8660,30 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
-" chip_version %u, lib_version %u, lib_serial_no %u, mcode_date %u\n",
+" chip_version %u, lib_version %x, lib_serial_no %u, mcode_date %x\n",
c->chip_version, c->lib_version, c->lib_serial_no, c->mcode_date);
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
-" mcode_version %u, err_code %u\n",
+" mcode_version %x, err_code %u\n",
c->mcode_version, v->err_code);
ASC_PRT_NEXT();
/* Current number of commands waiting for the host. */
len = asc_prt_line(cp, leftlen,
-" Total Command Pending: %d\n", v->cur_total_qng);
+" Total Command Pending: %d\n", v->cur_total_qng);
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
-" Command Queuing: ");
+" Command Queuing:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+ if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
len = asc_prt_line(cp, leftlen, " %d:%c",
- i, (v->use_tagged_qng & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
+ i, (v->use_tagged_qng & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
@@ -6112,11 +8691,11 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
/* Current number of commands waiting for a device. */
len = asc_prt_line(cp, leftlen,
-" Command Queue Pending: ");
+" Command Queue Pending:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+ if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
len = asc_prt_line(cp, leftlen, " %d:%u", i, v->cur_dvc_qng[i]);
@@ -6127,11 +8706,11 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
/* Current limit on number of commands that can be sent to a device. */
len = asc_prt_line(cp, leftlen,
-" Command Queue Limit: ");
+" Command Queue Limit:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+ if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
len = asc_prt_line(cp, leftlen, " %d:%u", i, v->max_dvc_qng[i]);
@@ -6142,14 +8721,14 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
/* Indicate whether the device has returned queue full status. */
len = asc_prt_line(cp, leftlen,
-" Command Queue Full: ");
+" Command Queue Full:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+ if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- if (boardp->queue_full & ASC_TIX_TO_TARGET_ID(i)) {
+ if (boardp->queue_full & ADV_TID_TO_TIDMASK(i)) {
len = asc_prt_line(cp, leftlen, " %d:Y-%d",
i, boardp->queue_full_cnt[i]);
} else {
@@ -6161,15 +8740,15 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
-" Synchronous Transfer: ");
+" Synchronous Transfer:");
ASC_PRT_NEXT();
for (i = 0; i <= ASC_MAX_TID; i++) {
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+ if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
len = asc_prt_line(cp, leftlen, " %d:%c",
- i, (v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) ? 'Y' : 'N');
+ i, (v->sdtr_done & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
ASC_PRT_NEXT();
}
len = asc_prt_line(cp, leftlen, "\n");
@@ -6178,15 +8757,15 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
for (i = 0; i <= ASC_MAX_TID; i++) {
uchar syn_period_ix;
- if ((boardp->asc_dvc_cfg.chip_scsi_id == i) ||
- ((boardp->init_tidmask & ASC_TIX_TO_TARGET_ID(i)) == 0)) {
+ if ((boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
continue;
}
- if ((v->sdtr_done & ASC_TIX_TO_TARGET_ID(i)) == 0) {
+ if ((v->sdtr_done & ADV_TID_TO_TIDMASK(i)) == 0) {
continue;
}
syn_period_ix = (boardp->sdtr_data[i] >> 4) & (v->max_sdtr_index - 1);
- len = asc_prt_line(cp, leftlen, " %d:", i);
+ len = asc_prt_line(cp, leftlen, " %d:", i);
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
@@ -6201,7 +8780,194 @@ asc_prt_board_info(struct Scsi_Host *shp, char *cp, int cplen)
ASC_PRT_NEXT();
}
- return totlen;
+ return totlen;
+}
+
+/*
+ * asc_prt_adv_board_info()
+ *
+ * Print dynamic board configuration information.
+ *
+ * Note: no single line should be greater than ASC_PRTLINE_SIZE,
+ * cf. asc_prt_line().
+ *
+ * Return the number of characters copied into 'cp'. No more than
+ * 'cplen' characters will be copied to 'cp'.
+ */
+STATIC int
+asc_prt_adv_board_info(struct Scsi_Host *shp, char *cp, int cplen)
+{
+ asc_board_t *boardp;
+ int leftlen;
+ int totlen;
+ int len;
+ int i;
+ ADV_DVC_VAR *v;
+ ADV_DVC_CFG *c;
+ AdvPortAddr iop_base;
+ ushort chip_scsi_id;
+ ushort lramword;
+ uchar lrambyte;
+ ushort sdtr_able;
+ ushort period;
+
+ boardp = ASC_BOARDP(shp);
+ v = &boardp->dvc_var.adv_dvc_var;
+ c = &boardp->dvc_cfg.adv_dvc_cfg;
+ iop_base = v->iop_base;
+ chip_scsi_id = v->chip_scsi_id;
+
+ leftlen = cplen;
+ totlen = len = 0;
+
+ len = asc_prt_line(cp, leftlen,
+"\nAdv Library Configuration and Statistics for AdvanSys SCSI Host %d:\n",
+ shp->host_no);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" iop_base %lx, cable_detect: %X, err_code %u, idle_cmd_done %u\n",
+ v->iop_base,
+ AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1) & CABLE_DETECT,
+ v->err_code, v->idle_cmd_done);
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" chip_version %u, lib_version %x, mcode_date %x, mcode_version %x\n",
+ c->chip_version, c->lib_version, c->mcode_date, c->mcode_version);
+ ASC_PRT_NEXT();
+
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, lramword);
+ len = asc_prt_line(cp, leftlen,
+" Queuing Enabled:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ len = asc_prt_line(cp, leftlen, " %X:%c",
+ i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Queue Limit:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + i, lrambyte);
+
+ len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Command Pending:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ AdvReadByteLram(iop_base, ASC_MC_NUMBER_OF_QUEUED_CMD + i, lrambyte);
+
+ len = asc_prt_line(cp, leftlen, " %X:%d", i, lrambyte);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, lramword);
+ len = asc_prt_line(cp, leftlen,
+" Wide Enabled:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ len = asc_prt_line(cp, leftlen, " %X:%c",
+ i, (lramword & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen,
+" Transfer Bit Width:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+ lramword);
+ len = asc_prt_line(cp, leftlen, " %X:%d",
+ i, (lramword & 0x8000) ? 16 : 8);
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, sdtr_able);
+ len = asc_prt_line(cp, leftlen,
+" Synchronous Enabled:");
+ ASC_PRT_NEXT();
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
+ len = asc_prt_line(cp, leftlen, " %X:%c",
+ i, (sdtr_able & ADV_TID_TO_TIDMASK(i)) ? 'Y' : 'N');
+ ASC_PRT_NEXT();
+ }
+ len = asc_prt_line(cp, leftlen, "\n");
+ ASC_PRT_NEXT();
+
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+
+ AdvReadWordLram(iop_base, ASC_MC_DEVICE_HSHK_CFG_TABLE + (2 * i),
+ lramword);
+ lramword &= ~0x8000;
+
+ if ((chip_scsi_id == i) ||
+ ((sdtr_able & ADV_TID_TO_TIDMASK(i)) == 0) ||
+ (lramword == 0)) {
+ continue;
+ }
+
+ len = asc_prt_line(cp, leftlen, " %X:", i);
+ ASC_PRT_NEXT();
+
+ period = (((lramword >> 8) * 25) + 50)/4;
+
+ len = asc_prt_line(cp, leftlen,
+ " Transfer Period Factor: %d (%d.%d Mhz),",
+ period, 250/period, ASC_TENTHS(250, period));
+ ASC_PRT_NEXT();
+
+ len = asc_prt_line(cp, leftlen, " REQ/ACK Offset: %d\n",
+ lramword & 0x1F);
+ ASC_PRT_NEXT();
+ }
+
+ return totlen;
}
/*
@@ -6410,7 +9176,6 @@ DvcInPortWords(ushort iop_base, ushort *inbuf, int words)
*inbuf = inpw(iop_base);
}
-
/*
* void DvcOutPortDWords(PortAddr port, ulong *pdw, int dwords)
*
@@ -6528,6 +9293,81 @@ AscGetChipBiosAddress(
/*
+ * --- Functions Required by the Adv Library
+ */
+
+/*
+ * DvcGetPhyAddr()
+ *
+ * Return the physical address of 'vaddr' and set '*lenp' to the
+ * number of physically contiguous bytes that follow 'vaddr'.
+ * 'flag' indicates the type of structure whose physical address
+ * is being translated.
+ *
+ * Note: Because Linux currently doesn't page the kernel and all
+ * kernel buffers are physically contiguous, leave '*lenp' unchanged.
+ */
+ulong
+DvcGetPhyAddr(ADV_DVC_VAR *asc_dvc, ADV_SCSI_REQ_Q *scsiq,
+ uchar *vaddr, long *lenp, int flag)
+{
+ ulong paddr;
+
+#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,0,0)
+ paddr = (ulong) vaddr;
+#else /* version >= v2.0.0 */
+ paddr = virt_to_bus(vaddr);
+#endif /* version >= v2.0.0 */
+
+ ASC_DBG4(4,
+ "DvcGetPhyAddr: vaddr 0x%lx, lenp 0x%lx *lenp %lu, paddr 0x%lx\n",
+ (ulong) vaddr, (ulong) lenp, (ulong) *((ulong *) lenp), paddr);
+
+ return paddr;
+}
+
+/*
+ * Read a PCI configuration byte.
+ */
+ASC_INITFUNC(
+STATIC uchar
+DvcAdvReadPCIConfigByte(
+ ADV_DVC_VAR *asc_dvc,
+ ushort offset)
+)
+{
+ PCI_DATA pciData;
+
+ pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info);
+ pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info);
+ pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info);
+ pciData.offset = offset;
+ pciData.type = pci_scan_method;
+ return asc_get_cfg_byte(&pciData);
+}
+
+/*
+ * Write a PCI configuration byte.
+ */
+ASC_INITFUNC(
+STATIC void
+DvcAdvWritePCIConfigByte(
+ ADV_DVC_VAR *asc_dvc,
+ ushort offset,
+ uchar byte_data)
+)
+{
+ PCI_DATA pciData;
+
+ pciData.bus = ASC_PCI_ID2BUS(asc_dvc->cfg->pci_slot_info);
+ pciData.slot = ASC_PCI_ID2DEV(asc_dvc->cfg->pci_slot_info);
+ pciData.func = ASC_PCI_ID2FUNC(asc_dvc->cfg->pci_slot_info);
+ pciData.offset = offset;
+ pciData.type = pci_scan_method;
+ asc_put_cfg_byte(&pciData, byte_data);
+}
+
+/*
* --- Tracing and Debugging Functions
*/
@@ -6547,15 +9387,19 @@ asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
int leftlen;
int totlen;
int len;
- struct asc_stats *s;
+ struct asc_stats *s;
int i;
+ ushort chip_scsi_id;
+ asc_board_t *boardp;
asc_queue_t *active;
asc_queue_t *waiting;
leftlen = cplen;
totlen = len = 0;
- s = &ASC_BOARDP(shp)->asc_stats;
+ boardp = ASC_BOARDP(shp);
+ s = &boardp->asc_stats;
+
len = asc_prt_line(cp, leftlen,
"\nLinux Driver Statistics for AdvanSys SCSI Host %d:\n", shp->host_no);
ASC_PRT_NEXT();
@@ -6566,13 +9410,24 @@ asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
-" check_interrupt %lu, interrupt %lu, callback %lu, done %lu\n",
- s->check_interrupt, s->interrupt, s->callback, s->done);
+" interrupt %lu, callback %lu, done %lu\n",
+ s->interrupt, s->callback, s->done);
ASC_PRT_NEXT();
len = asc_prt_line(cp, leftlen,
-" asc_noerror %lu, asc_busy %lu, asc_error %lu, asc_unknown %lu\n",
- s->asc_noerror, s->asc_busy, s->asc_error, s->asc_unknown);
+" exe_noerror %lu, exe_busy %lu, exe_error %lu, exe_unknown %lu\n",
+ s->exe_noerror, s->exe_busy, s->exe_error, s->exe_unknown);
+ ASC_PRT_NEXT();
+
+ if (ASC_NARROW_BOARD(boardp)) {
+ len = asc_prt_line(cp, leftlen,
+" build_error %lu\n",
+ s->build_error);
+ } else {
+ len = asc_prt_line(cp, leftlen,
+" build_error %lu, build_noreq %lu, build_nosg %lu\n",
+ s->build_error, s->adv_build_noreq, s->adv_build_nosg);
+ }
ASC_PRT_NEXT();
/*
@@ -6626,12 +9481,25 @@ asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
* Display request queuing statistics.
*/
len = asc_prt_line(cp, leftlen,
-" Active and Waiting Request Queues (time unit: %d HZ):\n", HZ);
+" Active and Waiting Request Queues (Time Unit: %d HZ):\n", HZ);
ASC_PRT_NEXT();
active = &ASC_BOARDP(shp)->active;
waiting = &ASC_BOARDP(shp)->waiting;
- for (i = 0; i < ASC_MAX_TID + 1; i++) {
+
+ if (ASC_NARROW_BOARD(boardp)) {
+ chip_scsi_id = boardp->dvc_cfg.asc_dvc_cfg.chip_scsi_id;
+ } else {
+ chip_scsi_id = boardp->dvc_var.adv_dvc_var.chip_scsi_id;
+ }
+
+ for (i = 0; i <= ADV_MAX_TID; i++) {
+
+ if ((chip_scsi_id == i) ||
+ ((boardp->init_tidmask & ADV_TID_TO_TIDMASK(i)) == 0)) {
+ continue;
+ }
+
if (active->q_tot_cnt[i] > 0 || waiting->q_tot_cnt[i] > 0) {
len = asc_prt_line(cp, leftlen, " target %d\n", i);
ASC_PRT_NEXT();
@@ -6671,6 +9539,10 @@ asc_prt_board_stats(struct Scsi_Host *shp, char *cp, int cplen)
STATIC void
asc_prt_scsi_host(struct Scsi_Host *s)
{
+ asc_board_t *boardp;
+
+ boardp = ASC_BOARDP(s);
+
printk("Scsi_Host at addr %x\n", (unsigned) s);
printk(
" next %x, extra_bytes %u, host_busy %u, host_no %d, last_reset %d,\n",
@@ -6695,8 +9567,13 @@ asc_prt_scsi_host(struct Scsi_Host *s)
s->cmd_per_lun, s->sg_tablesize, s->unchecked_isa_dma,
s->loaded_as_module);
- asc_prt_dvc_var(&ASC_BOARDP(s)->asc_dvc_var);
- asc_prt_dvc_cfg(&ASC_BOARDP(s)->asc_dvc_cfg);
+ if (ASC_NARROW_BOARD(boardp)) {
+ asc_prt_asc_dvc_var(&ASC_BOARDP(s)->dvc_var.asc_dvc_var);
+ asc_prt_asc_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.asc_dvc_cfg);
+ } else {
+ asc_prt_adv_dvc_var(&ASC_BOARDP(s)->dvc_var.adv_dvc_var);
+ asc_prt_adv_dvc_cfg(&ASC_BOARDP(s)->dvc_cfg.adv_dvc_cfg);
+ }
}
/*
@@ -6754,10 +9631,10 @@ asc_prt_scsi_cmnd(Scsi_Cmnd *s)
}
/*
- * asc_prt_dvc_var()
+ * asc_prt_asc_dvc_var()
*/
STATIC void
-asc_prt_dvc_var(ASC_DVC_VAR *h)
+asc_prt_asc_dvc_var(ASC_DVC_VAR *h)
{
printk("ASC_DVC_VAR at addr %x\n", (unsigned) h);
@@ -6796,10 +9673,10 @@ asc_prt_dvc_var(ASC_DVC_VAR *h)
}
/*
- * asc_prt_dvc_cfg()
+ * asc_prt_asc_dvc_cfg()
*/
STATIC void
-asc_prt_dvc_cfg(ASC_DVC_CFG *h)
+asc_prt_asc_dvc_cfg(ASC_DVC_CFG *h)
{
printk("ASC_DVC_CFG at addr %x\n", (unsigned) h);
@@ -6813,7 +9690,7 @@ asc_prt_dvc_cfg(ASC_DVC_CFG *h)
h->chip_version);
printk(
-" pci_device_id %d, lib_serial_no %d, lib_version %d, mcode_date %d,\n",
+" pci_device_id %d, lib_serial_no %x, lib_version %x, mcode_date %x,\n",
h->pci_device_id, h->lib_serial_no, h->lib_version, h->mcode_date);
printk(
@@ -6822,10 +9699,10 @@ asc_prt_dvc_cfg(ASC_DVC_CFG *h)
}
/*
- * asc_prt_scsi_q()
+ * asc_prt_asc_scsi_q()
*/
STATIC void
-asc_prt_scsi_q(ASC_SCSI_Q *q)
+asc_prt_asc_scsi_q(ASC_SCSI_Q *q)
{
ASC_SG_HEAD *sgp;
int i;
@@ -6860,10 +9737,10 @@ asc_prt_scsi_q(ASC_SCSI_Q *q)
}
/*
- * asc_prt_qdone_info()
+ * asc_prt_asc_qdone_info()
*/
STATIC void
-asc_prt_qdone_info(ASC_QDONE_INFO *q)
+asc_prt_asc_qdone_info(ASC_QDONE_INFO *q)
{
printk("ASC_QDONE_INFO at addr %x\n", (unsigned) q);
printk(
@@ -6876,6 +9753,158 @@ asc_prt_qdone_info(ASC_QDONE_INFO *q)
}
/*
+ * asc_prt_adv_dvc_var()
+ *
+ * Display an ADV_DVC_VAR structure.
+ */
+STATIC void
+asc_prt_adv_dvc_var(ADV_DVC_VAR *h)
+{
+ printk(" ADV_DVC_VAR at addr 0x%lx\n", (ulong) h);
+
+ printk(
+" iop_base 0x%lx, err_code 0x%x, ultra_able 0x%x\n",
+ (ulong) h->iop_base, h->err_code, (unsigned) h->ultra_able);
+
+ printk(
+" isr_callback 0x%x, sdtr_able 0x%x, wdtr_able 0x%x\n",
+ (unsigned) h->isr_callback, (unsigned) h->wdtr_able,
+ (unsigned) h->sdtr_able);
+
+ printk(
+" start_motor 0x%x, scsi_reset_wait 0x%x, irq_no 0x%x,\n",
+ (unsigned) h->start_motor,
+ (unsigned) h->scsi_reset_wait, (unsigned) h->irq_no);
+
+ printk(
+" max_host_qng 0x%x, cur_host_qng 0x%x, max_dvc_qng 0x%x\n",
+ (unsigned) h->max_host_qng, (unsigned) h->cur_host_qng,
+ (unsigned) h->max_dvc_qng);
+
+ printk(
+" no_scam 0x%x, tagqng_able 0x%x, chip_scsi_id 0x%x, cfg 0x%lx\n",
+ (unsigned) h->no_scam, (unsigned) h->tagqng_able,
+ (unsigned) h->chip_scsi_id, (ulong) h->cfg);
+
+}
+
+/*
+ * asc_prt_adv_dvc_cfg()
+ *
+ * Display an ADV_DVC_CFG structure.
+ */
+STATIC void
+asc_prt_adv_dvc_cfg(ADV_DVC_CFG *h)
+{
+ printk(" ADV_DVC_CFG at addr 0x%lx\n", (ulong) h);
+
+ printk(
+" disc_enable 0x%x, termination 0x%x\n",
+ h->disc_enable, h->termination);
+
+ printk(
+" chip_version 0x%x, mcode_date 0x%x\n",
+ h->chip_version, h->mcode_date);
+
+ printk(
+" mcode_version 0x%x, pci_device_id 0x%x, lib_version 0x%x\n",
+ h->mcode_version, h->pci_device_id, h->lib_version);
+
+ printk(
+" control_flag 0x%x, pci_slot_info 0x%x\n",
+ h->control_flag, h->pci_slot_info);
+}
+
+/*
+ * asc_prt_adv_scsi_req_q()
+ *
+ * Display an ADV_SCSI_REQ_Q structure.
+ */
+STATIC void
+asc_prt_adv_scsi_req_q(ADV_SCSI_REQ_Q *q)
+{
+ int i;
+ struct asc_sg_block *sg_ptr;
+
+ printk("ADV_SCSI_REQ_Q at addr %x\n", (unsigned) q);
+
+ printk(
+" target_id %u, target_lun %u, srb_ptr 0x%lx, a_flag 0x%x\n",
+ q->target_id, q->target_lun, q->srb_ptr, q->a_flag);
+
+ printk(" cntl 0x%x, data_addr 0x%lx, vdata_addr 0x%lx\n",
+ q->cntl, q->data_addr, q->vdata_addr);
+
+ printk(
+" data_cnt %lu, sense_addr 0x%lx, sense_len %u,\n",
+ q->data_cnt, q->sense_addr, q->sense_len);
+
+ printk(
+" cdb_len %u, done_status 0x%x, host_status 0x%x, scsi_status 0x%x\n",
+ q->cdb_len, q->done_status, q->host_status, q->scsi_status);
+
+ printk(
+" vsense_addr 0x%lx, scsiq_ptr 0x%lx, ux_wk_data_cnt %lu\n",
+ (ulong) q->vsense_addr, (ulong) q->scsiq_ptr,
+ (ulong) q->ux_wk_data_cnt);
+
+ printk(
+" sg_list_ptr 0x%lx, sg_real_addr 0x%lx, sg_entry_cnt %u\n",
+ (ulong) q->sg_list_ptr, (ulong) q->sg_real_addr, q->sg_entry_cnt);
+
+ printk(
+" ux_sg_ix %u, orig_sense_len %u\n",
+ q->ux_sg_ix, q->orig_sense_len);
+
+ /* Display the request's ADV_SG_BLOCK structures. */
+ for (sg_ptr = q->sg_list_ptr, i = 0; sg_ptr != NULL;
+ sg_ptr = sg_ptr->sg_ptr, i++) {
+ /*
+ * 'sg_ptr' is a physical address. Convert it to a virtual
+ * address by indexing 'i' into the virtual address array
+ * 'sg_list_ptr'.
+ *
+ * At the end of the each iteration of the loop 'sg_ptr' is
+ * converted back into a physical address by setting 'sg_ptr'
+ * to the next pointer 'sg_ptr->sg_ptr'.
+ */
+ sg_ptr = &(((ADV_SG_BLOCK *) (q->sg_list_ptr))[i]);
+ asc_prt_adv_sgblock(i, sg_ptr);
+ }
+}
+
+/*
+ * asc_prt_adv_sgblock()
+ *
+ * Display an ADV_SG_BLOCK structure.
+ */
+STATIC void
+asc_prt_adv_sgblock(int sgblockno, ADV_SG_BLOCK *b)
+{
+ int i, s;
+
+ /* Calculate starting entry number for the current block. */
+ s = sgblockno * NO_OF_SG_PER_BLOCK;
+
+ printk(" ADV_SG_BLOCK at addr 0x%lx (sgblockno %lu)\n",
+ (ulong) b, (ulong) sgblockno);
+ printk(
+" first_entry_no %lu, last_entry_no %lu, sg_ptr 0x%lx\n",
+ (ulong) b->first_entry_no, (ulong) b->last_entry_no, (ulong) b->sg_ptr);
+ ASC_ASSERT(b->first_entry_no - s >= 0);
+ ASC_ASSERT(b->last_entry_no - s >= 0);
+ ASC_ASSERT(b->last_entry_no - s <= NO_OF_SG_PER_BLOCK);
+ ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK);
+ ASC_ASSERT(b->first_entry_no - s <= NO_OF_SG_PER_BLOCK);
+ ASC_ASSERT(b->first_entry_no - s <= b->last_entry_no - s);
+ for (i = b->first_entry_no - s; i <= b->last_entry_no - s; i++) {
+ printk(" [%lu]: sg_addr 0x%lx, sg_count 0x%lx\n",
+ (ulong) i, (ulong) b->sg_list[i].sg_addr,
+ (ulong) b->sg_list[i].sg_count);
+ }
+}
+
+/*
* asc_prt_hex()
*
* Print hexadecimal output in 4 byte groupings 32 bytes
@@ -6966,6 +9995,7 @@ AscGetEisaChipCfg(
)
{
PortAddr eisa_cfg_iop;
+
eisa_cfg_iop = (PortAddr) ASC_GET_EISA_SLOT(iop_base) |
(PortAddr) (ASC_EISA_CFG_IOP_MASK);
return (inpw(eisa_cfg_iop));
@@ -6980,6 +10010,7 @@ AscSetChipScsiID(
)
{
ushort cfg_lsw;
+
if (AscGetChipScsiID(iop_base) == new_host_id) {
return (new_host_id);
}
@@ -6998,6 +10029,7 @@ AscGetChipScsiCtrl(
)
{
uchar sc;
+
AscSetBank(iop_base, 1);
sc = inp(iop_base + IOP_REG_SC);
AscSetBank(iop_base, 0);
@@ -7031,6 +10063,7 @@ AscGetChipBusType(
)
{
ushort chip_ver;
+
chip_ver = AscGetChipVerNo(iop_base);
if (
(chip_ver >= ASC_CHIP_MIN_VER_VL)
@@ -7070,6 +10103,7 @@ AscLoadMicroCode(
ulong chksum;
ushort mcode_word_size;
ushort mcode_chksum;
+
mcode_word_size = (ushort) (mcode_size >> 1);
AscMemWordSetLram(iop_base, s_addr, 0, mcode_word_size);
AscMemWordCopyToLram(iop_base, s_addr, mcode_buf, mcode_word_size);
@@ -7090,6 +10124,7 @@ AscFindSignature(
)
{
ushort sig_word;
+
if (AscGetChipSignatureByte(iop_base) == (uchar) ASC_1000_ID1B) {
sig_word = AscGetChipSignatureWord(iop_base);
if ((sig_word == (ushort) ASC_1000_ID0W) ||
@@ -7153,6 +10188,7 @@ AscSearchIOPortAddr11(
{
int i;
PortAddr iop_base;
+
for (i = 0; i < ASC_IOADR_TABLE_MAX_IX; i++) {
if (_asc_def_iop_base[i] > s_addr) {
break;
@@ -7207,6 +10243,7 @@ AscGetChipIRQ(
{
ushort cfg_lsw;
uchar chip_irq;
+
if ((bus_type & ASC_IS_EISA) != 0) {
cfg_lsw = AscGetEisaChipCfg(iop_base);
chip_irq = (uchar) (((cfg_lsw >> 8) & 0x07) + 10);
@@ -7223,11 +10260,6 @@ AscGetChipIRQ(
(chip_irq == 7)) {
return (0);
}
-#if CC_PLEXTOR_VL
- if (chip_irq == 5) {
- return (9);
- }
-#endif
return ((uchar) (chip_irq + (ASC_MIN_IRQ_NO - 1)));
}
cfg_lsw = AscGetChipCfgLsw(iop_base);
@@ -7247,13 +10279,9 @@ AscSetChipIRQ(
)
{
ushort cfg_lsw;
+
if ((bus_type & ASC_IS_VL) != 0) {
if (irq_no != 0) {
-#if CC_PLEXTOR_VL
- if (irq_no == 9) {
- irq_no = 14;
- }
-#endif
if ((irq_no < ASC_MIN_IRQ_NO) || (irq_no > ASC_MAX_IRQ_NO)) {
irq_no = 0;
} else {
@@ -7464,7 +10492,6 @@ AscIsrChipHalted(
q_cntl |= QC_REQ_SENSE;
-#if CC_CHK_COND_REDO_SDTR
if ((asc_dvc->init_sdtr & target_id) != 0) {
asc_dvc->sdtr_done &= ~target_id;
@@ -7476,7 +10503,6 @@ AscIsrChipHalted(
(uchar) (asc_dvc->max_sdtr_index - 1)],
(uchar) (sdtr_data & (uchar) ASC_SYN_MAX_OFFSET));
}
-#endif
AscWriteLramByte(iop_base,
(ushort) (halt_q_addr + (ushort) ASC_SCSIQ_B_CNTL),
@@ -7568,7 +10594,8 @@ AscIsrChipHalted(
boardp->queue_full |= target_id;
boardp->queue_full_cnt[tid_no] = cur_dvc_qng;
#if ASC_QUEUE_FLOW_CONTROL
- if (boardp->device[tid_no]->queue_curr_depth >
+ if (boardp->device[tid_no] != NULL &&
+ boardp->device[tid_no]->queue_curr_depth >
cur_dvc_qng) {
boardp->device[tid_no]->queue_curr_depth =
cur_dvc_qng;
@@ -7593,13 +10620,11 @@ _AscCopyLramScsiDoneQ(
{
ushort _val;
uchar sg_queue_cnt;
+
DvcGetQinfo(iop_base,
(ushort) (q_addr + (ushort) ASC_SCSIQ_DONE_INFO_BEG),
(ushort *) scsiq,
(ushort) ((sizeof (ASC_SCSIQ_2) + sizeof (ASC_SCSIQ_3)) / 2));
-#if !CC_LITTLE_ENDIAN_HOST
- AscAdjEndianQDoneInfo(scsiq);
-#endif
_val = AscReadLramWord(iop_base,
(ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS));
scsiq->q_status = (uchar) _val;
@@ -7640,6 +10665,7 @@ AscIsrQDone(
REG ASC_QDONE_INFO *scsiq;
int false_overrun;
ASC_ISR_CALLBACK asc_isr_callback;
+
iop_base = asc_dvc->iop_base;
asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
n_q_used = 1;
@@ -7722,18 +10748,13 @@ AscIsrQDone(
AscStopChip(iop_base);
AscSetChipControl(iop_base,
(uchar) (CC_SCSI_RESET | CC_HALT));
- DvcDelayNanoSecond(asc_dvc, 30000);
+ DvcDelayNanoSecond(asc_dvc, 60000);
AscSetChipControl(iop_base, CC_HALT);
AscSetChipStatus(iop_base, CIW_CLR_SCSI_RESET_INT);
AscSetChipStatus(iop_base, 0);
AscSetChipControl(iop_base, 0);
}
}
-#if CC_CLEAR_LRAM_SRB_PTR
- AscWriteLramDWord(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_D_SRBPTR),
- asc_dvc->int_count);
-#endif
if ((scsiq->cntl & QC_NO_CALLBACK) == 0) {
(*asc_isr_callback) (asc_dvc, scsiq);
} else {
@@ -7772,6 +10793,7 @@ AscISR(
int int_pending;
int status;
uchar host_flag;
+
iop_base = asc_dvc->iop_base;
int_pending = FALSE;
if (((asc_dvc->init_state & ASC_INIT_STATE_END_LOAD_MC) == 0)
@@ -7810,12 +10832,10 @@ AscISR(
ASCV_HOST_FLAG_B) & (uchar) (~ASC_HOST_FLAG_IN_ISR);
AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B,
(uchar) (host_flag | (uchar) ASC_HOST_FLAG_IN_ISR));
-#if CC_ASCISR_CHECK_INT_PENDING
if ((chipstat & CSW_INT_PENDING)
|| (int_pending)
) {
AscAckInterrupt(iop_base);
-#endif
int_pending = TRUE;
if ((chipstat & CSW_HALTED) &&
(ctrl_reg & CC_SINGLE_STEP)) {
@@ -7839,9 +10859,7 @@ AscISR(
if ((status & 0x80) != 0)
int_pending = ERR;
}
-#if CC_ASCISR_CHECK_INT_PENDING
}
-#endif
AscWriteLramByte(iop_base, ASCV_HOST_FLAG_B, host_flag);
AscSetChipLramAddr(iop_base, saved_ram_addr);
AscSetChipControl(iop_base, saved_ctrl_reg);
@@ -7858,6 +10876,7 @@ AscScsiSetupCmdQ(
)
{
ulong phy_addr;
+
scsiq->r1.cntl = 0;
scsiq->r1.sg_queue_cnt = 0;
scsiq->r1.q_no = 0;
@@ -7892,155 +10911,156 @@ AscScsiSetupCmdQ(
return (0);
}
-STATIC uchar _mcode_buf[] ASC_INITDATA =
-{
- 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x79, 0x0D, 0x09, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x23, 0x00, 0x22, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
- 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xCC, 0x88, 0x00, 0x00, 0x00, 0x00,
- 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
- 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC2, 0x00, 0x92, 0x80,
- 0x08, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x32, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80,
- 0x4F, 0x00, 0xF5, 0x00, 0x32, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
- 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00,
- 0x00, 0xA3, 0xD6, 0x00, 0x90, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, 0xD8, 0x84, 0xD2, 0xC1,
- 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE2, 0x01, 0x90, 0x97, 0xCE, 0x81, 0x00, 0x33,
- 0x02, 0x00, 0xAA, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0x02, 0x01, 0x4F, 0x00,
- 0x6E, 0x97, 0x07, 0xA6, 0x0C, 0x01, 0x00, 0x33, 0x03, 0x00, 0xAA, 0x88, 0x03, 0x03, 0x03, 0xDE,
- 0x00, 0x33, 0x05, 0x00, 0xAA, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60,
- 0x00, 0xA2, 0x80, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x2C, 0x01, 0x80, 0x81, 0x03, 0x03, 0x80, 0x63,
- 0xE2, 0x00, 0x07, 0xA6, 0x3C, 0x01, 0x00, 0x33, 0x04, 0x00, 0xAA, 0x88, 0x03, 0x07, 0x02, 0x01,
- 0x04, 0xCA, 0x0D, 0x23, 0x52, 0x98, 0x4D, 0x04, 0xF6, 0x84, 0x05, 0xD8, 0x0D, 0x23, 0x52, 0x98,
- 0xCD, 0x04, 0x15, 0x23, 0xE0, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03,
- 0x06, 0xA3, 0x6A, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xAA, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x76, 0x01,
- 0x00, 0x33, 0x0B, 0x00, 0xAA, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xAA, 0x88,
- 0x50, 0x04, 0x90, 0x81, 0x06, 0xAB, 0x8A, 0x01, 0x90, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x9A, 0x01,
- 0x50, 0x00, 0x00, 0xA3, 0x44, 0x01, 0x00, 0x05, 0x84, 0x81, 0x30, 0x97, 0x02, 0x01, 0x05, 0xC6,
- 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xC6, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01,
- 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xBC, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D,
- 0x00, 0x33, 0x1B, 0x00, 0xAA, 0x88, 0x06, 0x23, 0x52, 0x98, 0xCD, 0x04, 0xD8, 0x84, 0x06, 0x01,
- 0x00, 0xA2, 0xDC, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE2, 0x01, 0xD8, 0x84, 0x80, 0x23, 0xA0, 0x01,
- 0xD8, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x08, 0x02, 0x04, 0x01, 0x0C, 0xDE,
- 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x6E, 0x97, 0x04, 0x82, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
- 0x4F, 0x00, 0x4C, 0x97, 0x48, 0x04, 0x84, 0x80, 0xDA, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0,
- 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x67, 0xEB,
- 0x11, 0x23, 0xE0, 0x88, 0xEE, 0x97, 0xF4, 0x80, 0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x36, 0x02,
- 0x00, 0x33, 0x31, 0x00, 0xAA, 0x88, 0x04, 0x01, 0x03, 0xD8, 0x9C, 0x98, 0x44, 0x96, 0x48, 0x82,
- 0xD4, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x72, 0x02, 0x07, 0xA6,
- 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6, 0x68, 0x02, 0x00, 0x33, 0x10, 0x00, 0xAA, 0x88,
- 0x6E, 0x95, 0x4A, 0x82, 0x3A, 0x96, 0x4A, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01,
- 0x2E, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04,
- 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B,
- 0x1C, 0x01, 0x02, 0xA6, 0xB0, 0x02, 0x07, 0xA6, 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6,
- 0x12, 0x04, 0x01, 0xA6, 0xBA, 0x02, 0x00, 0xA6, 0xBA, 0x02, 0x00, 0x33, 0x12, 0x00, 0xAA, 0x88,
- 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x92, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC,
- 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38,
- 0x00, 0x3F, 0x00, 0x00, 0xF0, 0x82, 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE8, 0x02, 0x04, 0x01,
- 0x98, 0xC8, 0x00, 0x33, 0x1F, 0x00, 0xAA, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D,
- 0x68, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x1A, 0x03, 0x00, 0xA6, 0x1A, 0x03, 0x07, 0xA6, 0x12, 0x03,
- 0x06, 0xA6, 0x16, 0x03, 0x03, 0xA6, 0x12, 0x04, 0x02, 0xA6, 0x72, 0x02, 0x00, 0x33, 0x33, 0x00,
- 0xAA, 0x88, 0x6E, 0x95, 0xF4, 0x82, 0x3A, 0x96, 0xF4, 0x82, 0x6C, 0x98, 0x80, 0x42, 0x68, 0x98,
- 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x5A, 0x03, 0x00, 0x43,
- 0x87, 0x01, 0x05, 0x05, 0x70, 0x98, 0x68, 0x98, 0x00, 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x52, 0x03,
- 0x03, 0xA6, 0x2E, 0x04, 0x06, 0xA6, 0x56, 0x03, 0x01, 0xA6, 0x1C, 0x03, 0x00, 0x33, 0x25, 0x00,
- 0xAA, 0x88, 0x6E, 0x95, 0x38, 0x83, 0x3A, 0x96, 0x38, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8,
- 0x00, 0x33, 0x42, 0x00, 0xAA, 0x88, 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x78, 0x03, 0xB1, 0x01,
- 0x08, 0x23, 0xB2, 0x01, 0x34, 0x83, 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x98, 0x03, 0xEC, 0x00,
- 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x94, 0x03, 0x00, 0xA6,
- 0x94, 0x03, 0x08, 0x84, 0x80, 0x42, 0x68, 0x98, 0x01, 0xA6, 0xA2, 0x03, 0x00, 0xA6, 0xBA, 0x03,
- 0x08, 0x84, 0x90, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA2, 0x03, 0x07, 0xA6, 0xB0, 0x03, 0xD2, 0x83,
- 0x6E, 0x95, 0xA6, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xAA, 0x88, 0x90, 0x98, 0x80, 0x42, 0x00, 0xA6,
- 0xBA, 0x03, 0x07, 0xA6, 0xC8, 0x03, 0xD2, 0x83, 0x6E, 0x95, 0xBE, 0x83, 0x00, 0x33, 0x26, 0x00,
- 0xAA, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01,
- 0x08, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00, 0xAA, 0x88, 0x03, 0xA6, 0x06, 0x04,
- 0x07, 0xA6, 0xFE, 0x03, 0x06, 0xA6, 0x02, 0x04, 0x00, 0x33, 0x17, 0x00, 0xAA, 0x88, 0x6E, 0x95,
- 0xEC, 0x83, 0x3A, 0x96, 0xEC, 0x83, 0x12, 0x84, 0x04, 0xF0, 0x80, 0x6B, 0x00, 0x33, 0x20, 0x00,
- 0xAA, 0x88, 0xB6, 0x2D, 0x03, 0xA6, 0x2E, 0x04, 0x07, 0xA6, 0x26, 0x04, 0x06, 0xA6, 0x2A, 0x04,
- 0x00, 0x33, 0x30, 0x00, 0xAA, 0x88, 0x6E, 0x95, 0x12, 0x84, 0x3A, 0x96, 0x12, 0x84, 0x1D, 0x01,
- 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20, 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D,
- 0x80, 0x63, 0x07, 0xA6, 0x4C, 0x04, 0x00, 0x33, 0x18, 0x00, 0xAA, 0x88, 0x03, 0x03, 0x80, 0x63,
- 0xA3, 0x01, 0x07, 0xA4, 0x56, 0x04, 0x23, 0x01, 0x00, 0xA2, 0x78, 0x04, 0x0A, 0xA0, 0x68, 0x04,
- 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0xAA, 0x88, 0x0B, 0xA0, 0x74, 0x04, 0xE0, 0x00, 0x00, 0x33,
- 0x1E, 0x00, 0xAA, 0x88, 0x42, 0x23, 0xE0, 0x88, 0x00, 0x23, 0x22, 0xA3, 0xD8, 0x04, 0x08, 0x23,
- 0x22, 0xA3, 0x94, 0x04, 0x28, 0x23, 0x22, 0xA3, 0xA0, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xB6, 0x04,
- 0x42, 0x23, 0xE0, 0x88, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xA0, 0x04, 0x45, 0x23, 0xE0, 0x88,
- 0xEE, 0x97, 0x00, 0xA2, 0xB2, 0x04, 0x9C, 0x98, 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62,
- 0xF0, 0x81, 0x47, 0x23, 0xE0, 0x88, 0x04, 0x01, 0x0B, 0xDE, 0xEE, 0x97, 0x9C, 0x98, 0x00, 0x33,
- 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01, 0x00, 0xA0, 0x08, 0x02, 0x43, 0x23, 0xE0, 0x88,
- 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01, 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xE6, 0x04,
- 0x00, 0x33, 0x27, 0x00, 0xAA, 0x88, 0x04, 0x01, 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23,
- 0xA0, 0x01, 0xEE, 0x97, 0x18, 0x95, 0x4B, 0x00, 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3,
- 0x14, 0x05, 0x00, 0x05, 0x76, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x0E, 0x05, 0xFC, 0x84, 0x30, 0x97,
- 0xCD, 0x04, 0x16, 0x85, 0x48, 0x04, 0x84, 0x80, 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01,
- 0x26, 0x85, 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x32, 0x05, 0x1D, 0x01,
- 0x04, 0xD6, 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60, 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00,
- 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01, 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04,
- 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01, 0xFF, 0xA0, 0x52, 0x05, 0x77, 0x04, 0x01, 0x23,
- 0xEA, 0x00, 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62, 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4,
- 0xD2, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x80, 0x05, 0xCE, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xAA, 0x88,
- 0x04, 0xA0, 0xA6, 0x05, 0x80, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x92, 0x05, 0x1D, 0x01,
- 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01, 0x50, 0x00, 0x4C, 0x97, 0xF6, 0x84, 0x04, 0x23,
- 0x02, 0x41, 0x82, 0x01, 0xF6, 0x84, 0x08, 0xA0, 0xAC, 0x05, 0xCE, 0x85, 0x03, 0xA0, 0xB2, 0x05,
- 0xCE, 0x85, 0x01, 0xA0, 0xBC, 0x05, 0x88, 0x00, 0x80, 0x63, 0xAA, 0x86, 0x07, 0xA0, 0xC8, 0x05,
- 0x06, 0x23, 0x52, 0x98, 0x48, 0x23, 0xE0, 0x88, 0x07, 0x23, 0x80, 0x00, 0xF0, 0x86, 0x80, 0x63,
- 0x6E, 0x85, 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x10, 0x06, 0x1D, 0x01, 0x18, 0xD4,
- 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0xF2, 0x05, 0x00, 0x33, 0x37, 0x00,
- 0xAA, 0x88, 0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23, 0xE0, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63,
- 0x06, 0xA6, 0x0A, 0x06, 0x00, 0x33, 0x38, 0x00, 0xAA, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63,
- 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x28, 0x06, 0x1D, 0x01,
- 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63, 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83,
- 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41, 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03,
- 0x80, 0x63, 0x00, 0x63, 0x06, 0xA6, 0x56, 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x02, 0xA6, 0xE4, 0x06,
- 0x00, 0x33, 0x39, 0x00, 0xAA, 0x88, 0x00, 0x00, 0x01, 0xA0, 0xFE, 0x06, 0xD4, 0x95, 0x83, 0x03,
- 0x80, 0x63, 0x06, 0xA6, 0x6A, 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x00, 0x01, 0xA0, 0xFE, 0x06,
- 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00, 0x06, 0xA6, 0x86, 0x06, 0x07, 0xA6, 0x6E, 0x05,
- 0x00, 0x33, 0x3A, 0x00, 0xAA, 0x88, 0x40, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x78, 0x06,
- 0x06, 0xA6, 0x9E, 0x06, 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x33, 0x3B, 0x00, 0xAA, 0x88, 0x80, 0x67,
- 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, 0x6E, 0x05, 0x00, 0x63, 0x07, 0xA6, 0xB4, 0x06, 0x00, 0x33,
- 0x2A, 0x00, 0xAA, 0x88, 0x03, 0x03, 0x80, 0x63, 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xC6, 0x06,
- 0x00, 0x33, 0x29, 0x00, 0xAA, 0x88, 0x00, 0x43, 0x00, 0xA2, 0xD2, 0x06, 0xC0, 0x0E, 0x80, 0x63,
- 0xBC, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80, 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA,
- 0x80, 0x63, 0x6E, 0x85, 0x80, 0x67, 0x00, 0x33, 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63,
- 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x62, 0x06, 0x00, 0x33, 0x2C, 0x00, 0xAA, 0x88, 0x0C, 0xA2,
- 0x18, 0x07, 0xD4, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x16, 0x07, 0x07, 0xA6, 0x6E, 0x05,
- 0x00, 0x33, 0x3D, 0x00, 0xAA, 0x88, 0x00, 0x00, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0,
- 0x2E, 0x07, 0x07, 0xA6, 0x6E, 0x05, 0xBF, 0x23, 0x04, 0x61, 0x84, 0x01, 0xD8, 0x84, 0x00, 0x63,
- 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01, 0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04,
- 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05, 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00,
- 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x71, 0x00, 0x81, 0x01,
- 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04,
- 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00, 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00,
- 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04, 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63,
- 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01, 0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01,
- 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xAE, 0x07, 0x00, 0x33, 0x07, 0x00, 0xAA, 0x88, 0x80, 0x05,
- 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00, 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01,
- 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2, 0xCE, 0x07, 0x00, 0x05, 0xC4, 0x87, 0x00, 0x01,
- 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08,
- 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04,
- 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x00, 0xA0, 0xFE, 0x07, 0x00, 0x88, 0x00, 0x43,
- 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00,
- 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2, 0x2E, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9,
- 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x0E, 0x08, 0xEE, 0x97, 0x18, 0x95, 0x0E, 0x88, 0x73, 0x04,
- 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x44, 0x88, 0x02, 0x01, 0x04, 0xD8, 0x30, 0x97, 0xEE, 0x97,
- 0x18, 0x95, 0x34, 0x88, 0x75, 0x00, 0x00, 0xA3, 0x4E, 0x08, 0x00, 0x05, 0x38, 0x88, 0x73, 0x04,
- 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x60, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xAA, 0x88,
- 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x38, 0x2B, 0x86, 0x88, 0x38, 0x2B, 0x7C, 0x88,
- 0x32, 0x09, 0x31, 0x05, 0x7C, 0x98, 0x05, 0x05, 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36,
- 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32, 0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63,
- 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A, 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40,
- 0x00, 0xA0, 0x9C, 0x08, 0x5D, 0x00, 0xFE, 0xC3, 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23,
- 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73, 0x13, 0x23, 0xE0, 0x88, 0x66, 0x20, 0xC0, 0x20,
- 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01, 0x81, 0x62, 0xCA, 0x88, 0x80, 0x73, 0x80, 0x77,
- 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2, 0xF1, 0xC7, 0x41, 0x23, 0xE0, 0x88, 0x11, 0x23,
- 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xD8, 0x84,
+STATIC uchar _asc_mcode_buf[] ASC_INITDATA =
+{
+ 0x01, 0x03, 0x01, 0x19, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xDB, 0x0C, 0x0A, 0x05, 0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0xFF, 0x80, 0xFF, 0xFF, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x23, 0x00, 0x23, 0x00, 0x00, 0x00, 0x07, 0x00, 0xFF, 0x00, 0x00, 0x00, 0x00,
+ 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD4, 0x88, 0x00, 0x00, 0x00, 0x00,
+ 0x80, 0x73, 0x48, 0x04, 0x36, 0x00, 0x00, 0xA2, 0xC2, 0x00, 0x80, 0x73, 0x03, 0x23, 0x36, 0x40,
+ 0xB6, 0x00, 0x36, 0x00, 0x05, 0xD6, 0x0C, 0xD2, 0x12, 0xDA, 0x00, 0xA2, 0xC2, 0x00, 0x92, 0x80,
+ 0x10, 0x98, 0x50, 0x00, 0xF5, 0x00, 0x3A, 0x98, 0xDF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80,
+ 0x4F, 0x00, 0xF5, 0x00, 0x3A, 0x98, 0xEF, 0x23, 0x36, 0x60, 0xB6, 0x00, 0x92, 0x80, 0x80, 0x62,
+ 0x92, 0x80, 0x00, 0x46, 0x17, 0xEE, 0x13, 0xEA, 0x02, 0x01, 0x09, 0xD8, 0xCD, 0x04, 0x4D, 0x00,
+ 0x00, 0xA3, 0xD6, 0x00, 0x98, 0x97, 0x7F, 0x23, 0x04, 0x61, 0x84, 0x01, 0xE0, 0x84, 0xD2, 0xC1,
+ 0x80, 0x73, 0xCD, 0x04, 0x4D, 0x00, 0x00, 0xA3, 0xE2, 0x01, 0x98, 0x97, 0xCE, 0x81, 0x00, 0x33,
+ 0x02, 0x00, 0xB2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x00, 0x01, 0x01, 0xA1, 0x02, 0x01, 0x4F, 0x00,
+ 0x76, 0x97, 0x07, 0xA6, 0x0C, 0x01, 0x00, 0x33, 0x03, 0x00, 0xB2, 0x88, 0x03, 0x03, 0x03, 0xDE,
+ 0x00, 0x33, 0x05, 0x00, 0xB2, 0x88, 0xCE, 0x00, 0x69, 0x60, 0xCE, 0x00, 0x02, 0x03, 0x4A, 0x60,
+ 0x00, 0xA2, 0x80, 0x01, 0x80, 0x63, 0x07, 0xA6, 0x2C, 0x01, 0x80, 0x81, 0x03, 0x03, 0x80, 0x63,
+ 0xE2, 0x00, 0x07, 0xA6, 0x3C, 0x01, 0x00, 0x33, 0x04, 0x00, 0xB2, 0x88, 0x03, 0x07, 0x02, 0x01,
+ 0x04, 0xCA, 0x0D, 0x23, 0x5A, 0x98, 0x4D, 0x04, 0xFE, 0x84, 0x05, 0xD8, 0x0D, 0x23, 0x5A, 0x98,
+ 0xCD, 0x04, 0x15, 0x23, 0xE8, 0x88, 0xFB, 0x23, 0x02, 0x61, 0x82, 0x01, 0x80, 0x63, 0x02, 0x03,
+ 0x06, 0xA3, 0x6A, 0x01, 0x00, 0x33, 0x0A, 0x00, 0xB2, 0x88, 0x4E, 0x00, 0x07, 0xA3, 0x76, 0x01,
+ 0x00, 0x33, 0x0B, 0x00, 0xB2, 0x88, 0xCD, 0x04, 0x36, 0x2D, 0x00, 0x33, 0x1A, 0x00, 0xB2, 0x88,
+ 0x50, 0x04, 0x90, 0x81, 0x06, 0xAB, 0x8A, 0x01, 0x90, 0x81, 0x4E, 0x00, 0x07, 0xA3, 0x9A, 0x01,
+ 0x50, 0x00, 0x00, 0xA3, 0x44, 0x01, 0x00, 0x05, 0x84, 0x81, 0x38, 0x97, 0x02, 0x01, 0x05, 0xC6,
+ 0x04, 0x23, 0xA0, 0x01, 0x15, 0x23, 0xA1, 0x01, 0xC6, 0x81, 0xFD, 0x23, 0x02, 0x61, 0x82, 0x01,
+ 0x0A, 0xDA, 0x4A, 0x00, 0x06, 0x61, 0x00, 0xA0, 0xBC, 0x01, 0x80, 0x63, 0xCD, 0x04, 0x36, 0x2D,
+ 0x00, 0x33, 0x1B, 0x00, 0xB2, 0x88, 0x06, 0x23, 0x5A, 0x98, 0xCD, 0x04, 0xE0, 0x84, 0x06, 0x01,
+ 0x00, 0xA2, 0xDC, 0x01, 0x57, 0x60, 0x00, 0xA0, 0xE2, 0x01, 0xE0, 0x84, 0x80, 0x23, 0xA0, 0x01,
+ 0xE0, 0x84, 0x80, 0x73, 0x4B, 0x00, 0x06, 0x61, 0x00, 0xA2, 0x08, 0x02, 0x04, 0x01, 0x0C, 0xDE,
+ 0x02, 0x01, 0x03, 0xCC, 0x4F, 0x00, 0x76, 0x97, 0x04, 0x82, 0x08, 0x23, 0x02, 0x41, 0x82, 0x01,
+ 0x4F, 0x00, 0x54, 0x97, 0x48, 0x04, 0x84, 0x80, 0xE2, 0x97, 0x00, 0x46, 0x56, 0x00, 0x03, 0xC0,
+ 0x01, 0x23, 0xE8, 0x00, 0x81, 0x73, 0x06, 0x29, 0x03, 0x42, 0x06, 0xE2, 0x03, 0xEE, 0x67, 0xEB,
+ 0x11, 0x23, 0xE8, 0x88, 0xF6, 0x97, 0xF4, 0x80, 0x80, 0x73, 0x80, 0x77, 0x06, 0xA6, 0x36, 0x02,
+ 0x00, 0x33, 0x31, 0x00, 0xB2, 0x88, 0x04, 0x01, 0x03, 0xD8, 0xA4, 0x98, 0x4C, 0x96, 0x48, 0x82,
+ 0xDC, 0x95, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x02, 0xA6, 0x72, 0x02, 0x07, 0xA6,
+ 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6, 0x68, 0x02, 0x00, 0x33, 0x10, 0x00, 0xB2, 0x88,
+ 0x76, 0x95, 0x4A, 0x82, 0x42, 0x96, 0x4A, 0x82, 0x04, 0x23, 0xA0, 0x01, 0x14, 0x23, 0xA1, 0x01,
+ 0x36, 0x84, 0x04, 0x01, 0x0C, 0xDC, 0xE0, 0x23, 0x25, 0x61, 0xEF, 0x00, 0x14, 0x01, 0x4F, 0x04,
+ 0xA8, 0x01, 0x6F, 0x00, 0xA5, 0x01, 0x03, 0x23, 0xA4, 0x01, 0x06, 0x23, 0x9C, 0x01, 0x24, 0x2B,
+ 0x1C, 0x01, 0x02, 0xA6, 0xB0, 0x02, 0x07, 0xA6, 0x60, 0x02, 0x06, 0xA6, 0x64, 0x02, 0x03, 0xA6,
+ 0x1A, 0x04, 0x01, 0xA6, 0xBA, 0x02, 0x00, 0xA6, 0xBA, 0x02, 0x00, 0x33, 0x12, 0x00, 0xB2, 0x88,
+ 0x00, 0x0E, 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x92, 0x02, 0x4D, 0x04, 0x04, 0x01, 0x0B, 0xDC,
+ 0xE7, 0x23, 0x04, 0x61, 0x84, 0x01, 0x10, 0x31, 0x12, 0x35, 0x14, 0x01, 0xEC, 0x00, 0x6C, 0x38,
+ 0x00, 0x3F, 0x00, 0x00, 0xF0, 0x82, 0x18, 0x23, 0x04, 0x61, 0x18, 0xA0, 0xE8, 0x02, 0x04, 0x01,
+ 0x9C, 0xC8, 0x00, 0x33, 0x1F, 0x00, 0xB2, 0x88, 0x08, 0x31, 0x0A, 0x35, 0x0C, 0x39, 0x0E, 0x3D,
+ 0x70, 0x98, 0xB6, 0x2D, 0x01, 0xA6, 0x1A, 0x03, 0x00, 0xA6, 0x1A, 0x03, 0x07, 0xA6, 0x12, 0x03,
+ 0x06, 0xA6, 0x16, 0x03, 0x03, 0xA6, 0x1A, 0x04, 0x02, 0xA6, 0x72, 0x02, 0x00, 0x33, 0x33, 0x00,
+ 0xB2, 0x88, 0x76, 0x95, 0xF4, 0x82, 0x42, 0x96, 0xF4, 0x82, 0x74, 0x98, 0x80, 0x42, 0x70, 0x98,
+ 0x60, 0xE4, 0x04, 0x01, 0x29, 0xC8, 0x31, 0x05, 0x07, 0x01, 0x00, 0xA2, 0x5A, 0x03, 0x00, 0x43,
+ 0x87, 0x01, 0x05, 0x05, 0x78, 0x98, 0x70, 0x98, 0x00, 0xA6, 0x1C, 0x03, 0x07, 0xA6, 0x52, 0x03,
+ 0x03, 0xA6, 0x36, 0x04, 0x06, 0xA6, 0x56, 0x03, 0x01, 0xA6, 0x1C, 0x03, 0x00, 0x33, 0x25, 0x00,
+ 0xB2, 0x88, 0x76, 0x95, 0x38, 0x83, 0x42, 0x96, 0x38, 0x83, 0x04, 0x01, 0x0C, 0xCE, 0x03, 0xC8,
+ 0x00, 0x33, 0x42, 0x00, 0xB2, 0x88, 0x00, 0x01, 0x05, 0x05, 0xFF, 0xA2, 0x78, 0x03, 0xB1, 0x01,
+ 0x08, 0x23, 0xB2, 0x01, 0x34, 0x83, 0x05, 0x05, 0x15, 0x01, 0x00, 0xA2, 0x98, 0x03, 0xEC, 0x00,
+ 0x6E, 0x00, 0x95, 0x01, 0x6C, 0x38, 0x00, 0x3F, 0x00, 0x00, 0x01, 0xA6, 0x94, 0x03, 0x00, 0xA6,
+ 0x94, 0x03, 0x0C, 0x84, 0x80, 0x42, 0x70, 0x98, 0x01, 0xA6, 0xA2, 0x03, 0x00, 0xA6, 0xBA, 0x03,
+ 0x0C, 0x84, 0x98, 0x98, 0x80, 0x42, 0x01, 0xA6, 0xA2, 0x03, 0x07, 0xA6, 0xB0, 0x03, 0xD2, 0x83,
+ 0x76, 0x95, 0xA6, 0x83, 0x00, 0x33, 0x2F, 0x00, 0xB2, 0x88, 0x98, 0x98, 0x80, 0x42, 0x00, 0xA6,
+ 0xBA, 0x03, 0x07, 0xA6, 0xC8, 0x03, 0xD2, 0x83, 0x76, 0x95, 0xBE, 0x83, 0x00, 0x33, 0x26, 0x00,
+ 0xB2, 0x88, 0x38, 0x2B, 0x80, 0x32, 0x80, 0x36, 0x04, 0x23, 0xA0, 0x01, 0x12, 0x23, 0xA1, 0x01,
+ 0x0C, 0x84, 0x06, 0xF0, 0x06, 0xA4, 0xF0, 0x03, 0x80, 0x6B, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63,
+ 0x03, 0xA6, 0x0A, 0x04, 0x07, 0xA6, 0x02, 0x04, 0x06, 0xA6, 0x06, 0x04, 0x00, 0x33, 0x17, 0x00,
+ 0xB2, 0x88, 0x76, 0x95, 0xF0, 0x83, 0x42, 0x96, 0xF0, 0x83, 0x1A, 0x84, 0x06, 0xF0, 0x06, 0xA4,
+ 0x1A, 0x04, 0x80, 0x6B, 0x05, 0x23, 0x83, 0x03, 0x80, 0x63, 0xB6, 0x2D, 0x03, 0xA6, 0x36, 0x04,
+ 0x07, 0xA6, 0x2E, 0x04, 0x06, 0xA6, 0x32, 0x04, 0x00, 0x33, 0x30, 0x00, 0xB2, 0x88, 0x76, 0x95,
+ 0x1A, 0x84, 0x42, 0x96, 0x1A, 0x84, 0x1D, 0x01, 0x06, 0xCC, 0x00, 0x33, 0x00, 0x84, 0xC0, 0x20,
+ 0x00, 0x23, 0xEA, 0x00, 0x81, 0x62, 0xA2, 0x0D, 0x80, 0x63, 0x07, 0xA6, 0x54, 0x04, 0x00, 0x33,
+ 0x18, 0x00, 0xB2, 0x88, 0x03, 0x03, 0x80, 0x63, 0xA3, 0x01, 0x07, 0xA4, 0x5E, 0x04, 0x23, 0x01,
+ 0x00, 0xA2, 0x80, 0x04, 0x0A, 0xA0, 0x70, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1D, 0x00, 0xB2, 0x88,
+ 0x0B, 0xA0, 0x7C, 0x04, 0xE0, 0x00, 0x00, 0x33, 0x1E, 0x00, 0xB2, 0x88, 0x42, 0x23, 0xE8, 0x88,
+ 0x00, 0x23, 0x22, 0xA3, 0xE0, 0x04, 0x08, 0x23, 0x22, 0xA3, 0x9C, 0x04, 0x28, 0x23, 0x22, 0xA3,
+ 0xA8, 0x04, 0x02, 0x23, 0x22, 0xA3, 0xBE, 0x04, 0x42, 0x23, 0xE8, 0x88, 0x4A, 0x00, 0x06, 0x61,
+ 0x00, 0xA0, 0xA8, 0x04, 0x45, 0x23, 0xE8, 0x88, 0xF6, 0x97, 0x00, 0xA2, 0xBA, 0x04, 0xA4, 0x98,
+ 0x00, 0x33, 0x00, 0x82, 0xC0, 0x20, 0x81, 0x62, 0xF0, 0x81, 0x47, 0x23, 0xE8, 0x88, 0x04, 0x01,
+ 0x0B, 0xDE, 0xF6, 0x97, 0xA4, 0x98, 0x00, 0x33, 0x00, 0x81, 0xC0, 0x20, 0x81, 0x62, 0x14, 0x01,
+ 0x00, 0xA0, 0x08, 0x02, 0x43, 0x23, 0xE8, 0x88, 0x04, 0x23, 0xA0, 0x01, 0x44, 0x23, 0xA1, 0x01,
+ 0x80, 0x73, 0x4D, 0x00, 0x03, 0xA3, 0xEE, 0x04, 0x00, 0x33, 0x27, 0x00, 0xB2, 0x88, 0x04, 0x01,
+ 0x04, 0xDC, 0x02, 0x23, 0xA2, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xF6, 0x97, 0x20, 0x95, 0x4B, 0x00,
+ 0xF6, 0x00, 0x4F, 0x04, 0x4F, 0x00, 0x00, 0xA3, 0x1C, 0x05, 0x00, 0x05, 0x76, 0x00, 0x06, 0x61,
+ 0x00, 0xA2, 0x16, 0x05, 0x04, 0x85, 0x38, 0x97, 0xCD, 0x04, 0x1E, 0x85, 0x48, 0x04, 0x84, 0x80,
+ 0x02, 0x01, 0x03, 0xDA, 0x80, 0x23, 0x82, 0x01, 0x2E, 0x85, 0x02, 0x23, 0xA0, 0x01, 0x4A, 0x00,
+ 0x06, 0x61, 0x00, 0xA2, 0x3A, 0x05, 0x1D, 0x01, 0x04, 0xD6, 0xFF, 0x23, 0x86, 0x41, 0x4B, 0x60,
+ 0xCB, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x49, 0x00, 0x81, 0x01, 0x04, 0x01, 0x02, 0xC8, 0x30, 0x01,
+ 0x80, 0x01, 0xF7, 0x04, 0x03, 0x01, 0x49, 0x04, 0x80, 0x01, 0xC9, 0x00, 0x00, 0x05, 0x00, 0x01,
+ 0xFF, 0xA0, 0x5A, 0x05, 0x77, 0x04, 0x01, 0x23, 0xEA, 0x00, 0x5D, 0x00, 0xFE, 0xC7, 0x00, 0x62,
+ 0x00, 0x23, 0xEA, 0x00, 0x00, 0x63, 0x07, 0xA4, 0xDA, 0x05, 0x03, 0x03, 0x02, 0xA0, 0x88, 0x05,
+ 0xD6, 0x85, 0x00, 0x33, 0x2D, 0x00, 0xB2, 0x88, 0x04, 0xA0, 0xAE, 0x05, 0x80, 0x63, 0x4A, 0x00,
+ 0x06, 0x61, 0x00, 0xA2, 0x9A, 0x05, 0x1D, 0x01, 0x06, 0xD6, 0x02, 0x23, 0x02, 0x41, 0x82, 0x01,
+ 0x50, 0x00, 0x54, 0x97, 0xFE, 0x84, 0x04, 0x23, 0x02, 0x41, 0x82, 0x01, 0xFE, 0x84, 0x08, 0xA0,
+ 0xB4, 0x05, 0xD6, 0x85, 0x03, 0xA0, 0xBA, 0x05, 0xD6, 0x85, 0x01, 0xA0, 0xC4, 0x05, 0x88, 0x00,
+ 0x80, 0x63, 0xB2, 0x86, 0x07, 0xA0, 0xD0, 0x05, 0x06, 0x23, 0x5A, 0x98, 0x48, 0x23, 0xE8, 0x88,
+ 0x07, 0x23, 0x80, 0x00, 0xF8, 0x86, 0x80, 0x63, 0x76, 0x85, 0x00, 0x63, 0x4A, 0x00, 0x06, 0x61,
+ 0x00, 0xA2, 0x18, 0x06, 0x1D, 0x01, 0x18, 0xD4, 0xC0, 0x23, 0x07, 0x41, 0x83, 0x03, 0x80, 0x63,
+ 0x06, 0xA6, 0xFA, 0x05, 0x00, 0x33, 0x37, 0x00, 0xB2, 0x88, 0x1D, 0x01, 0x02, 0xD6, 0x46, 0x23,
+ 0xE8, 0x88, 0x63, 0x60, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x12, 0x06, 0x00, 0x33, 0x38, 0x00,
+ 0xB2, 0x88, 0xEF, 0x04, 0x6F, 0x00, 0x00, 0x63, 0x4B, 0x00, 0x06, 0x41, 0xCB, 0x00, 0x52, 0x00,
+ 0x06, 0x61, 0x00, 0xA2, 0x30, 0x06, 0x1D, 0x01, 0x03, 0xCA, 0xC0, 0x23, 0x07, 0x41, 0x00, 0x63,
+ 0x1D, 0x01, 0x04, 0xCC, 0x00, 0x33, 0x00, 0x83, 0xC0, 0x20, 0x81, 0x62, 0x80, 0x23, 0x07, 0x41,
+ 0x00, 0x63, 0x80, 0x67, 0x08, 0x23, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63, 0x06, 0xA6, 0x5E, 0x06,
+ 0x07, 0xA6, 0x76, 0x05, 0x02, 0xA6, 0xEC, 0x06, 0x00, 0x33, 0x39, 0x00, 0xB2, 0x88, 0x00, 0x00,
+ 0x01, 0xA0, 0x06, 0x07, 0xDC, 0x95, 0x83, 0x03, 0x80, 0x63, 0x06, 0xA6, 0x72, 0x06, 0x07, 0xA6,
+ 0x76, 0x05, 0x00, 0x00, 0x01, 0xA0, 0x06, 0x07, 0x00, 0x2B, 0x40, 0x0E, 0x80, 0x63, 0x01, 0x00,
+ 0x06, 0xA6, 0x8E, 0x06, 0x07, 0xA6, 0x76, 0x05, 0x00, 0x33, 0x3A, 0x00, 0xB2, 0x88, 0x40, 0x0E,
+ 0x80, 0x63, 0x00, 0x43, 0x00, 0xA0, 0x80, 0x06, 0x06, 0xA6, 0xA6, 0x06, 0x07, 0xA6, 0x76, 0x05,
+ 0x00, 0x33, 0x3B, 0x00, 0xB2, 0x88, 0x80, 0x67, 0x40, 0x0E, 0x80, 0x63, 0x07, 0xA6, 0x76, 0x05,
+ 0x00, 0x63, 0x07, 0xA6, 0xBC, 0x06, 0x00, 0x33, 0x2A, 0x00, 0xB2, 0x88, 0x03, 0x03, 0x80, 0x63,
+ 0x89, 0x00, 0x0A, 0x2B, 0x07, 0xA6, 0xCE, 0x06, 0x00, 0x33, 0x29, 0x00, 0xB2, 0x88, 0x00, 0x43,
+ 0x00, 0xA2, 0xDA, 0x06, 0xC0, 0x0E, 0x80, 0x63, 0xC4, 0x86, 0xC0, 0x0E, 0x00, 0x33, 0x00, 0x80,
+ 0xC0, 0x20, 0x81, 0x62, 0x04, 0x01, 0x08, 0xDA, 0x80, 0x63, 0x76, 0x85, 0x80, 0x67, 0x00, 0x33,
+ 0x00, 0x40, 0xC0, 0x20, 0x81, 0x62, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6, 0x6A, 0x06,
+ 0x00, 0x33, 0x2C, 0x00, 0xB2, 0x88, 0x0C, 0xA2, 0x20, 0x07, 0xDC, 0x95, 0x83, 0x03, 0x80, 0x63,
+ 0x06, 0xA6, 0x1E, 0x07, 0x07, 0xA6, 0x76, 0x05, 0x00, 0x33, 0x3D, 0x00, 0xB2, 0x88, 0x00, 0x00,
+ 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x0C, 0xA0, 0x36, 0x07, 0x07, 0xA6, 0x76, 0x05, 0xBF, 0x23,
+ 0x04, 0x61, 0x84, 0x01, 0xE0, 0x84, 0x00, 0x63, 0xF0, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x00, 0x01,
+ 0xF2, 0x00, 0x01, 0x05, 0x80, 0x01, 0x72, 0x04, 0x71, 0x00, 0x81, 0x01, 0x70, 0x04, 0x80, 0x05,
+ 0x81, 0x05, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x01, 0x01, 0xF1, 0x00, 0x70, 0x00,
+ 0x81, 0x01, 0x70, 0x04, 0x71, 0x00, 0x81, 0x01, 0x72, 0x00, 0x80, 0x01, 0x71, 0x04, 0x70, 0x00,
+ 0x80, 0x01, 0x70, 0x04, 0x00, 0x63, 0xF0, 0x04, 0xF2, 0x00, 0x72, 0x04, 0x00, 0x01, 0xF1, 0x00,
+ 0x70, 0x00, 0x80, 0x01, 0x70, 0x04, 0x71, 0x00, 0x80, 0x01, 0x72, 0x00, 0x81, 0x01, 0x71, 0x04,
+ 0x70, 0x00, 0x81, 0x01, 0x70, 0x04, 0x00, 0x63, 0x00, 0x23, 0xB3, 0x01, 0x83, 0x05, 0xA3, 0x01,
+ 0xA2, 0x01, 0xA1, 0x01, 0x01, 0x23, 0xA0, 0x01, 0x00, 0x01, 0xC8, 0x00, 0x03, 0xA1, 0xB6, 0x07,
+ 0x00, 0x33, 0x07, 0x00, 0xB2, 0x88, 0x80, 0x05, 0x81, 0x05, 0x04, 0x01, 0x11, 0xC8, 0x48, 0x00,
+ 0xB0, 0x01, 0xB1, 0x01, 0x08, 0x23, 0xB2, 0x01, 0x05, 0x01, 0x48, 0x04, 0x00, 0x43, 0x00, 0xA2,
+ 0xD6, 0x07, 0x00, 0x05, 0xCC, 0x87, 0x00, 0x01, 0xC8, 0x00, 0xFF, 0x23, 0x80, 0x01, 0x05, 0x05,
+ 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02, 0x80, 0x43, 0x76, 0x08,
+ 0x80, 0x02, 0x77, 0x04, 0x00, 0x63, 0xF7, 0x04, 0x1A, 0x09, 0xF6, 0x08, 0x6E, 0x04, 0x00, 0x02,
+ 0x00, 0xA0, 0x06, 0x08, 0x08, 0x88, 0x00, 0x43, 0x76, 0x08, 0x80, 0x02, 0x77, 0x04, 0x00, 0x63,
+ 0xF3, 0x04, 0x00, 0x23, 0xF4, 0x00, 0x74, 0x00, 0x80, 0x43, 0xF4, 0x00, 0xCF, 0x40, 0x00, 0xA2,
+ 0x36, 0x08, 0x74, 0x04, 0x02, 0x01, 0xF7, 0xC9, 0xF6, 0xD9, 0x00, 0x01, 0x01, 0xA1, 0x16, 0x08,
+ 0xF6, 0x97, 0x20, 0x95, 0x16, 0x88, 0x73, 0x04, 0x00, 0x63, 0xF3, 0x04, 0x75, 0x04, 0x4C, 0x88,
+ 0x02, 0x01, 0x04, 0xD8, 0x38, 0x97, 0xF6, 0x97, 0x20, 0x95, 0x3C, 0x88, 0x75, 0x00, 0x00, 0xA3,
+ 0x56, 0x08, 0x00, 0x05, 0x40, 0x88, 0x73, 0x04, 0x00, 0x63, 0x80, 0x7B, 0x80, 0x63, 0x06, 0xA6,
+ 0x68, 0x08, 0x00, 0x33, 0x3E, 0x00, 0xB2, 0x88, 0x80, 0x67, 0x83, 0x03, 0x80, 0x63, 0x00, 0x63,
+ 0x38, 0x2B, 0x8E, 0x88, 0x38, 0x2B, 0x84, 0x88, 0x32, 0x09, 0x31, 0x05, 0x84, 0x98, 0x05, 0x05,
+ 0xB2, 0x09, 0x00, 0x63, 0x00, 0x32, 0x00, 0x36, 0x00, 0x3A, 0x00, 0x3E, 0x00, 0x63, 0x80, 0x32,
+ 0x80, 0x36, 0x80, 0x3A, 0x80, 0x3E, 0x00, 0x63, 0x38, 0x2B, 0x40, 0x32, 0x40, 0x36, 0x40, 0x3A,
+ 0x40, 0x3E, 0x00, 0x63, 0x5A, 0x20, 0xC9, 0x40, 0x00, 0xA0, 0xA4, 0x08, 0x5D, 0x00, 0xFE, 0xC3,
+ 0x00, 0x63, 0x80, 0x73, 0xE6, 0x20, 0x02, 0x23, 0xE8, 0x00, 0x82, 0x73, 0xFF, 0xFD, 0x80, 0x73,
+ 0x13, 0x23, 0xE8, 0x88, 0x66, 0x20, 0xC0, 0x20, 0x04, 0x23, 0xA0, 0x01, 0xA1, 0x23, 0xA1, 0x01,
+ 0x81, 0x62, 0xD2, 0x88, 0x80, 0x73, 0x80, 0x77, 0x68, 0x00, 0x00, 0xA2, 0x80, 0x00, 0x03, 0xC2,
+ 0xF1, 0xC7, 0x41, 0x23, 0xE8, 0x88, 0x11, 0x23, 0xA1, 0x01, 0x04, 0x23, 0xA0, 0x01, 0xE0, 0x84,
+
};
-STATIC ushort _mcode_size ASC_INITDATA = sizeof(_mcode_buf);
-STATIC ulong _mcode_chksum ASC_INITDATA = 0x01297F32UL;
+STATIC ushort _asc_mcode_size ASC_INITDATA = sizeof(_asc_mcode_buf);
+STATIC ulong _asc_mcode_chksum ASC_INITDATA = 0x012A727FUL ;
#define ASC_SYN_OFFSET_ONE_DISABLE_LIST 16
STATIC uchar _syn_offset_one_disable_cmd[ASC_SYN_OFFSET_ONE_DISABLE_LIST] =
@@ -8087,6 +11107,7 @@ AscExeScsiQueue(
uchar disable_cmd;
ASC_SG_HEAD *sg_head;
ulong data_cnt;
+
iop_base = asc_dvc->iop_base;
sg_head = scsiq->sg_head;
asc_exe_callback = (ASC_EXE_CALLBACK) asc_dvc->exe_callback;
@@ -8137,19 +11158,6 @@ AscExeScsiQueue(
scsiq->q1.cntl &= ~(QC_SG_HEAD | QC_SG_SWAP_QUEUE);
}
sg_entry_cnt_minus_one = sg_entry_cnt - 1;
-#if CC_DEBUG_SG_LIST
- if (asc_dvc->bus_type & (ASC_IS_ISA | ASC_IS_VL | ASC_IS_EISA)) {
- for (i = 0; i < sg_entry_cnt_minus_one; i++) {
- addr = sg_head->sg_list[i].addr + sg_head->sg_list[i].bytes;
- if (((ushort) addr & 0x0003) != 0) {
- asc_dvc->in_critical_cnt--;
- DvcLeaveCritical(last_int_level);
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_SG_LIST_ODD_ADDRESS);
- return (ERR);
- }
- }
- }
-#endif
}
scsi_cmd = scsiq->cdbptr[0];
disable_syn_offset_one_fix = FALSE;
@@ -8271,6 +11279,7 @@ AscSendScsiQueue(
uchar tid_no;
uchar target_ix;
int sta;
+
iop_base = asc_dvc->iop_base;
target_ix = scsiq->q2.target_ix;
tid_no = ASC_TIX_TO_TID(target_ix);
@@ -8285,9 +11294,6 @@ AscSendScsiQueue(
scsiq->q1.q_no = free_q_head;
if ((sta = AscPutReadySgListQueue(asc_dvc, scsiq,
free_q_head)) == 1) {
-#if CC_WRITE_IO_COUNT
- asc_dvc->req_count++;
-#endif
AscPutVarFreeQHead(iop_base, next_qp);
asc_dvc->cur_total_qng += (uchar) (n_q_required);
asc_dvc->cur_dvc_qng[tid_no]++;
@@ -8300,9 +11306,6 @@ AscSendScsiQueue(
scsiq->q1.q_no = free_q_head;
if ((sta = AscPutReadyQueue(asc_dvc, scsiq,
free_q_head)) == 1) {
-#if CC_WRITE_IO_COUNT
- asc_dvc->req_count++;
-#endif
AscPutVarFreeQHead(iop_base, next_qp);
asc_dvc->cur_total_qng++;
asc_dvc->cur_dvc_qng[tid_no]++;
@@ -8319,6 +11322,7 @@ AscSgListToQueue(
)
{
int n_sg_list_qs;
+
n_sg_list_qs = ((sg_list - 1) / ASC_SG_LIST_PER_Q);
if (((sg_list - 1) % ASC_SG_LIST_PER_Q) != 0)
n_sg_list_qs++;
@@ -8337,6 +11341,7 @@ AscGetNumOfFreeQueue(
uint cur_free_qs;
ASC_SCSI_BIT_ID_TYPE target_id;
uchar tid_no;
+
target_id = ASC_TIX_TO_TARGET_ID(target_ix);
tid_no = ASC_TIX_TO_TID(target_ix);
if ((asc_dvc->unit_not_ready & target_id) ||
@@ -8380,6 +11385,7 @@ AscPutReadyQueue(
uchar syn_period_ix;
uchar syn_offset;
PortAddr iop_base;
+
iop_base = asc_dvc->iop_base;
if (((asc_dvc->init_sdtr & scsiq->q1.target_id) != 0) &&
((asc_dvc->sdtr_done & scsiq->q1.target_id) == 0)) {
@@ -8401,43 +11407,10 @@ AscPutReadyQueue(
(ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG),
(ushort *) scsiq->cdbptr,
(ushort) ((ushort) scsiq->q2.cdb_len >> 1));
-#if !CC_LITTLE_ENDIAN_HOST
- AscAdjEndianScsiQ(scsiq);
-#endif
DvcPutScsiQ(iop_base,
(ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG),
(ushort *) & scsiq->q1.cntl,
(ushort) ((((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1)));
-#if CC_WRITE_IO_COUNT
- AscWriteLramWord(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_W_REQ_COUNT),
- (ushort) asc_dvc->req_count);
-#endif
-#if CC_VERIFY_LRAM_COPY
- if ((asc_dvc->dvc_cntl & ASC_CNTL_NO_VERIFY_COPY) == 0) {
- if (AscMemWordCmpToLram(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_CDB_BEG),
- (ushort *) scsiq->cdbptr,
- (ushort) (scsiq->q2.cdb_len >> 1)) != 0) {
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM);
- return (ERR);
- }
- if (AscMemWordCmpToLram(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_CPY_BEG),
- (ushort *) & scsiq->q1.cntl,
- (ushort) (((sizeof (ASC_SCSIQ_1) + sizeof (ASC_SCSIQ_2)) / 2) - 1))
- != 0) {
- AscSetLibErrorCode(asc_dvc, ASCQ_ERR_LOCAL_MEM);
- return (ERR);
- }
- }
-#endif
-#if CC_CLEAR_DMA_REMAIN
- AscWriteLramDWord(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_ADDR), 0UL);
- AscWriteLramDWord(iop_base,
- (ushort) (q_addr + (ushort) ASC_SCSIQ_DW_REMAIN_XFER_CNT), 0UL);
-#endif
AscWriteLramWord(iop_base,
(ushort) (q_addr + (ushort) ASC_SCSIQ_B_STATUS),
(ushort) (((ushort) scsiq->q1.q_no << 8) | (ushort) QS_READY));
@@ -8463,6 +11436,7 @@ AscPutReadySgListQueue(
ushort sg_entry_cnt;
ushort q_addr;
uchar next_qp;
+
iop_base = asc_dvc->iop_base;
sg_head = scsiq->sg_head;
saved_data_addr = scsiq->q1.data_addr;
@@ -8533,6 +11507,7 @@ AscAbortSRB(
int sta;
ASC_SCSI_BIT_ID_TYPE saved_unit_not_ready;
PortAddr iop_base;
+
iop_base = asc_dvc->iop_base;
sta = ERR;
saved_unit_not_ready = asc_dvc->unit_not_ready;
@@ -8562,6 +11537,7 @@ AscResetDevice(
PortAddr iop_base;
int sta;
uchar tid_no;
+
ASC_SCSI_BIT_ID_TYPE target_id;
int i;
ASC_SCSI_REQ_Q scsiq_buf;
@@ -8633,13 +11609,14 @@ AscResetSB(
int sta;
int i;
PortAddr iop_base;
+
iop_base = asc_dvc->iop_base;
asc_dvc->unit_not_ready = 0xFF;
sta = TRUE;
AscWaitISRDone(asc_dvc);
AscStopQueueExe(iop_base);
asc_dvc->sdtr_done = 0;
- AscResetChipAndScsiBus(iop_base);
+ AscResetChipAndScsiBus(asc_dvc);
DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
AscReInitLram(asc_dvc);
for (i = 0; i <= ASC_MAX_TID; i++) {
@@ -8670,6 +11647,7 @@ AscSetRunChipSynRegAtID(
)
{
int sta = FALSE;
+
if (AscHostReqRiscHalt(iop_base)) {
sta = AscSetChipSynRegAtID(iop_base, tid_no, sdtr_data);
AscStartChip(iop_base);
@@ -8687,8 +11665,8 @@ AscSetChipSynRegAtID(
{
ASC_SCSI_BIT_ID_TYPE org_id;
int i;
- int sta;
- sta = TRUE;
+ int sta = TRUE;
+
AscSetBank(iop_base, 1);
org_id = AscReadChipDvcID(iop_base);
for (i = 0; i <= ASC_MAX_TID; i++) {
@@ -8731,6 +11709,7 @@ AscInitLram(
ushort s_addr;
PortAddr iop_base;
ushort warn_code;
+
iop_base = asc_dvc->iop_base;
warn_code = 0;
AscMemWordSetLram(iop_base, ASC_QADR_BEG, 0,
@@ -8782,6 +11761,7 @@ AscInitQLinkVar(
PortAddr iop_base;
int i;
ushort lram_addr;
+
iop_base = asc_dvc->iop_base;
AscPutRiscVarFreeQHead(iop_base, 1);
AscPutRiscVarDoneQTail(iop_base, asc_dvc->max_total_qng);
@@ -8831,6 +11811,7 @@ _AscWaitQDone(
ushort q_addr;
uchar q_status;
int count = 0;
+
while (scsiq->q1.q_no == 0) ;
q_addr = ASC_QNO_TO_QADDR(scsiq->q1.q_no);
do {
@@ -8890,6 +11871,7 @@ AscCalSDTRData(
{
uchar byte;
uchar sdtr_period_ix;
+
sdtr_period_ix = AscGetSynPeriodIndex(asc_dvc, sdtr_period);
if (
(sdtr_period_ix > asc_dvc->max_sdtr_index)
@@ -8922,6 +11904,7 @@ AscGetSynPeriodIndex(
int max_index;
int min_index;
int i;
+
period_table = asc_dvc->sdtr_period_tbl;
max_index = (int) asc_dvc->max_sdtr_index;
min_index = (int)asc_dvc->host_init_sdtr_index ;
@@ -8946,6 +11929,7 @@ AscAllocFreeQueue(
ushort q_addr;
uchar next_qp;
uchar q_status;
+
q_addr = ASC_QNO_TO_QADDR(free_q_head);
q_status = (uchar) AscReadLramByte(iop_base,
(ushort) (q_addr + ASC_SCSIQ_B_STATUS));
@@ -8965,6 +11949,7 @@ AscAllocMultipleFreeQueue(
)
{
uchar i;
+
for (i = 0; i < n_free_q; i++) {
if ((free_q_head = AscAllocFreeQueue(iop_base, free_q_head))
== ASC_QLINK_END) {
@@ -8987,6 +11972,7 @@ AscRiscHaltedAbortSRB(
ASC_QDONE_INFO *scsiq;
ASC_ISR_CALLBACK asc_isr_callback;
int last_int_level;
+
iop_base = asc_dvc->iop_base;
asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
last_int_level = DvcEnterCritical();
@@ -9032,6 +12018,7 @@ AscRiscHaltedAbortTIX(
ASC_QDONE_INFO *scsiq;
ASC_ISR_CALLBACK asc_isr_callback;
int last_int_level;
+
iop_base = asc_dvc->iop_base;
asc_isr_callback = (ASC_ISR_CALLBACK) asc_dvc->isr_callback;
last_int_level = DvcEnterCritical();
@@ -9069,6 +12056,7 @@ AscHostReqRiscHalt(
int count = 0;
int sta = 0;
uchar saved_stop_code;
+
if (AscIsChipHalted(iop_base))
return (1);
saved_stop_code = AscReadLramByte(iop_base, ASCV_STOP_CODE_B);
@@ -9091,8 +12079,8 @@ AscStopQueueExe(
PortAddr iop_base
)
{
- int count;
- count = 0;
+ int count = 0;
+
if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) == 0) {
AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
ASC_STOP_REQ_RISC_STOP);
@@ -9126,6 +12114,7 @@ AscCleanUpBusyQueue(
{
int count;
uchar stop_code;
+
count = 0;
if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
@@ -9148,6 +12137,7 @@ AscCleanUpDiscQueue(
{
int count;
uchar stop_code;
+
count = 0;
if (AscReadLramByte(iop_base, ASCV_STOP_CODE_B) != 0) {
AscWriteLramByte(iop_base, ASCV_STOP_CODE_B,
@@ -9171,12 +12161,14 @@ AscWaitTixISRDone(
{
uchar cur_req;
uchar tid_no;
+ int i = 0;
+
tid_no = ASC_TIX_TO_TID(target_ix);
- while (TRUE) {
+ while (i++ < 10) {
if ((cur_req = asc_dvc->cur_dvc_qng[tid_no]) == 0) {
break;
}
- DvcSleepMilliSecond(1000L);
+ DvcSleepMilliSecond(100L);
if (asc_dvc->cur_dvc_qng[tid_no] == cur_req) {
break;
}
@@ -9190,6 +12182,7 @@ AscWaitISRDone(
)
{
int tid;
+
for (tid = 0; tid <= ASC_MAX_TID; tid++) {
AscWaitTixISRDone(asc_dvc, ASC_TID_TO_TIX(tid));
}
@@ -9204,6 +12197,7 @@ AscGetOnePhyAddr(
)
{
ASC_MIN_SG_HEAD sg_head;
+
sg_head.entry_cnt = ASC_MIN_SG_LIST;
if (DvcGetSGList(asc_dvc, (uchar *) buf_addr,
buf_size, (ASC_SG_HEAD *) & sg_head) != buf_size) {
@@ -9216,20 +12210,15 @@ AscGetOnePhyAddr(
}
STATIC void
-DvcDelayNanoSecond(
- ASC_DVC_VAR asc_ptr_type * asc_dvc,
- ulong nano_sec
-)
+DvcDelayMicroSecond(ADV_DVC_VAR *asc_dvc, ushort micro_sec)
{
- ulong loop;
- PortAddr iop_base;
- iop_base = asc_dvc->iop_base;
- loop = nano_sec / 90;
- loop++;
- while (loop-- != 0) {
- inp(iop_base);
- }
- return;
+ udelay(micro_sec);
+}
+
+STATIC void
+DvcDelayNanoSecond(ASC_DVC_VAR asc_ptr_type * asc_dvc, ulong nano_sec)
+{
+ udelay((nano_sec + 999)/1000);
}
ASC_INITFUNC(
@@ -9242,6 +12231,7 @@ AscGetEisaProductID(
PortAddr eisa_iop;
ushort product_id_high, product_id_low;
ulong product_id;
+
eisa_iop = ASC_GET_EISA_SLOT(iop_base) | ASC_EISA_PID_IOP_MASK;
product_id_low = inpw(eisa_iop);
product_id_high = inpw(eisa_iop + 2);
@@ -9257,6 +12247,7 @@ AscSearchIOPortAddrEISA(
)
{
ulong eisa_product_id;
+
if (iop_base == 0) {
iop_base = ASC_EISA_MIN_IOP_ADDR;
} else {
@@ -9306,6 +12297,7 @@ AscStopChip(
)
{
uchar cc_val;
+
cc_val = AscGetChipControl(iop_base) & (~(CC_SINGLE_STEP | CC_TEST | CC_DIAG));
AscSetChipControl(iop_base, (uchar) (cc_val | CC_HALT));
AscSetChipIH(iop_base, INS_HALT);
@@ -9349,6 +12341,7 @@ AscAckInterrupt(
uchar host_flag;
uchar risc_flag;
ushort loop;
+
loop = 0;
do {
risc_flag = AscReadLramByte(iop_base, ASCV_RISC_FLAG_B);
@@ -9377,6 +12370,7 @@ AscDisableInterrupt(
)
{
ushort cfg;
+
cfg = AscGetChipCfgLsw(iop_base);
AscSetChipCfgLsw(iop_base, cfg & (~ASC_CFG0_HOST_INT_ON));
return;
@@ -9388,6 +12382,7 @@ AscEnableInterrupt(
)
{
ushort cfg;
+
cfg = AscGetChipCfgLsw(iop_base);
AscSetChipCfgLsw(iop_base, cfg | ASC_CFG0_HOST_INT_ON);
return;
@@ -9402,6 +12397,7 @@ AscSetBank(
)
{
uchar val;
+
val = AscGetChipControl(iop_base) &
(~(CC_SINGLE_STEP | CC_TEST | CC_DIAG | CC_SCSI_RESET | CC_CHIP_RESET));
if (bank == 1) {
@@ -9415,17 +12411,18 @@ AscSetBank(
return;
}
-
-
STATIC int
AscResetChipAndScsiBus(
- PortAddr iop_base
+ ASC_DVC_VAR *asc_dvc
)
{
+ PortAddr iop_base;
+
+ iop_base = asc_dvc->iop_base;
while (AscGetChipStatus(iop_base) & CSW_SCSI_RESET_ACTIVE) ;
AscStopChip(iop_base);
AscSetChipControl(iop_base, CC_CHIP_RESET | CC_SCSI_RESET | CC_HALT);
- DvcSleepMilliSecond(200);
+ DvcDelayNanoSecond(asc_dvc, 60000);
AscSetChipIH(iop_base, INS_RFLAG_WTM);
AscSetChipIH(iop_base, INS_HALT);
AscSetChipControl(iop_base, CC_CHIP_RESET | CC_HALT);
@@ -9458,6 +12455,7 @@ AscGetIsaDmaChannel(
)
{
ushort channel;
+
channel = AscGetChipCfgLsw(iop_base) & 0x0003;
if (channel == 0x03)
return (0);
@@ -9476,6 +12474,7 @@ AscSetIsaDmaChannel(
{
ushort cfg_lsw;
uchar value;
+
if ((dma_channel >= 5) && (dma_channel <= 7)) {
if (dma_channel == 7)
value = 0x00;
@@ -9512,6 +12511,7 @@ AscGetIsaDmaSpeed(
)
{
uchar speed_value;
+
AscSetBank(iop_base, 1);
speed_value = AscReadChipDmaSpeed(iop_base);
speed_value &= 0x07;
@@ -9625,8 +12625,8 @@ AscInitSetConfig(
)
)
{
- ushort warn_code;
- warn_code = 0;
+ ushort warn_code = 0;
+
asc_dvc->init_state |= ASC_INIT_STATE_BEG_SET_CFG;
if (asc_dvc->err_code != 0)
return (UW_ERR);
@@ -9650,6 +12650,7 @@ AscInitFromAscDvcVar(
ushort cfg_msw;
ushort warn_code;
ushort pci_device_id;
+
iop_base = asc_dvc->iop_base;
pci_device_id = asc_dvc->cfg->pci_device_id;
warn_code = 0;
@@ -9674,10 +12675,8 @@ AscInitFromAscDvcVar(
}
}
if (asc_dvc->bus_type & ASC_IS_PCI) {
-#if CC_DISABLE_PCI_PARITY_INT
cfg_msw &= 0xFFC0;
AscSetChipCfgMsw(iop_base, cfg_msw);
-#endif
if ((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA) {
} else {
if ((pci_device_id == ASC_PCI_DEVICE_ID_REV_A) ||
@@ -9712,14 +12711,15 @@ AscInitAsc1000Driver(
{
ushort warn_code;
PortAddr iop_base;
- extern ushort _mcode_size;
- extern ulong _mcode_chksum;
- extern uchar _mcode_buf[];
+ extern ushort _asc_mcode_size;
+ extern ulong _asc_mcode_chksum;
+ extern uchar _asc_mcode_buf[];
+
iop_base = asc_dvc->iop_base;
warn_code = 0;
if ((asc_dvc->dvc_cntl & ASC_CNTL_RESET_SCSI) &&
!(asc_dvc->init_state & ASC_INIT_RESET_SCSI_DONE)) {
- AscResetChipAndScsiBus(iop_base);
+ AscResetChipAndScsiBus(asc_dvc);
DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
}
asc_dvc->init_state |= ASC_INIT_STATE_BEG_LOAD_MC;
@@ -9733,8 +12733,8 @@ AscInitAsc1000Driver(
warn_code |= AscInitLram(asc_dvc);
if (asc_dvc->err_code != 0)
return (UW_ERR);
- if (AscLoadMicroCode(iop_base, 0, (ushort *) _mcode_buf,
- _mcode_size) != _mcode_chksum) {
+ if (AscLoadMicroCode(iop_base, 0, (ushort *) _asc_mcode_buf,
+ _asc_mcode_size) != _asc_mcode_chksum) {
asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
return (warn_code);
}
@@ -9755,6 +12755,7 @@ AscInitAscDvcVar(
PortAddr iop_base;
ushort warn_code;
uchar chip_version;
+
iop_base = asc_dvc->iop_base;
warn_code = 0;
asc_dvc->err_code = 0;
@@ -9857,7 +12858,6 @@ AscInitAscDvcVar(
return (warn_code);
}
-#if CC_INCLUDE_EEP_CONFIG
ASC_INITFUNC(
STATIC ushort
AscInitFromEEP(
@@ -9866,12 +12866,14 @@ AscInitFromEEP(
)
{
ASCEEP_CONFIG eep_config_buf;
- ASCEEP_CONFIG *eep_config;
+ ASCEEP_CONFIG *eep_config;
PortAddr iop_base;
ushort chksum;
ushort warn_code;
ushort cfg_msw, cfg_lsw;
int i;
+ int write_eep = 0;
+
iop_base = asc_dvc->iop_base;
warn_code = 0;
AscWriteLramWord(iop_base, ASCV_HALTCODE_W, 0x00FE);
@@ -9879,7 +12881,7 @@ AscInitFromEEP(
if ((AscStopChip(iop_base) == FALSE) ||
(AscGetChipScsiCtrl(iop_base) != 0)) {
asc_dvc->init_state |= ASC_INIT_RESET_SCSI_DONE;
- AscResetChipAndScsiBus(iop_base);
+ AscResetChipAndScsiBus(asc_dvc);
DvcSleepMilliSecond((ulong) ((ushort) asc_dvc->scsi_reset_wait * 1000));
}
if (AscIsChipHalted(iop_base) == FALSE) {
@@ -9900,7 +12902,9 @@ AscInitFromEEP(
AscSetChipCfgMsw(iop_base, cfg_msw);
}
chksum = AscGetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
- eep_config->cfg_msw &= (~(ASC_CFG_MSW_CLR_MASK));
+ if (chksum == 0) {
+ chksum = 0xaa55;
+ }
if (AscGetChipStatus(iop_base) & CSW_AUTO_CONFIG) {
warn_code |= ASC_WARN_AUTO_CONFIG;
if (asc_dvc->cfg->chip_version == 3) {
@@ -9914,9 +12918,32 @@ AscInitFromEEP(
}
}
}
+ eep_config->cfg_msw &= ~ASC_CFG_MSW_CLR_MASK;
eep_config->cfg_lsw |= ASC_CFG0_HOST_INT_ON;
if (chksum != eep_config->chksum) {
- warn_code |= ASC_WARN_EEPROM_CHKSUM;
+ if (AscGetChipVersion(iop_base, asc_dvc->bus_type) ==
+ ASC_CHIP_VER_PCI_ULTRA_3050 )
+ {
+ eep_config->init_sdtr = 0xFF;
+ eep_config->disc_enable = 0xFF;
+ eep_config->start_motor = 0xFF;
+ eep_config->use_cmd_qng = 0;
+ eep_config->max_total_qng = 0xF0;
+ eep_config->max_tag_qng = 0x20;
+ eep_config->cntl = 0xBFFF;
+ eep_config->chip_scsi_id = 7;
+ eep_config->no_scam = 0;
+ eep_config->adapter_info[0] = 0;
+ eep_config->adapter_info[1] = 0;
+ eep_config->adapter_info[2] = 0;
+ eep_config->adapter_info[3] = 0;
+ eep_config->adapter_info[4] = 0;
+ /* Indicate EEPROM-less board. */
+ eep_config->adapter_info[5] = 0xBB;
+ } else {
+ write_eep = 1 ;
+ warn_code |= ASC_WARN_EEPROM_CHKSUM ;
+ }
}
asc_dvc->init_sdtr = eep_config->init_sdtr;
asc_dvc->cfg->disc_enable = eep_config->disc_enable;
@@ -9925,6 +12952,12 @@ AscInitFromEEP(
asc_dvc->start_motor = eep_config->start_motor;
asc_dvc->dvc_cntl = eep_config->cntl;
asc_dvc->no_scam = eep_config->no_scam;
+ asc_dvc->cfg->adapter_info[0] = eep_config->adapter_info[0];
+ asc_dvc->cfg->adapter_info[1] = eep_config->adapter_info[1];
+ asc_dvc->cfg->adapter_info[2] = eep_config->adapter_info[2];
+ asc_dvc->cfg->adapter_info[3] = eep_config->adapter_info[3];
+ asc_dvc->cfg->adapter_info[4] = eep_config->adapter_info[4];
+ asc_dvc->cfg->adapter_info[5] = eep_config->adapter_info[5];
if (!AscTestExternalLram(asc_dvc)) {
if (((asc_dvc->bus_type & ASC_IS_PCI_ULTRA) == ASC_IS_PCI_ULTRA)) {
eep_config->max_total_qng = ASC_MAX_PCI_ULTRA_INRAM_TOTAL_QNG;
@@ -9967,9 +13000,6 @@ AscInitFromEEP(
}
for (i = 0; i <= ASC_MAX_TID; i++) {
-#if CC_TMP_USE_EEP_SDTR
- asc_dvc->cfg->sdtr_period_offset[i] = eep_config->dos_int13_table[i];
-#endif
asc_dvc->dos_int13_table[i] = eep_config->dos_int13_table[i];
asc_dvc->cfg->max_tag_qng[i] = eep_config->max_tag_qng;
asc_dvc->cfg->sdtr_period_offset[i] =
@@ -9977,14 +13007,11 @@ AscInitFromEEP(
(asc_dvc->host_init_sdtr_index << 4));
}
eep_config->cfg_msw = AscGetChipCfgMsw(iop_base);
-#if CC_CHK_FIX_EEP_CONTENT
- if (AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type) != 0) {
- asc_dvc->err_code |= ASC_IERR_WRITE_EEPROM;
+ if (write_eep) {
+ (void) AscSetEEPConfig(iop_base, eep_config, asc_dvc->bus_type);
}
-#endif
return (warn_code);
}
-#endif
ASC_INITFUNC(
STATIC ushort
@@ -9997,6 +13024,7 @@ AscInitMicroCodeVar(
ushort warn_code;
PortAddr iop_base;
ulong phy_addr;
+
iop_base = asc_dvc->iop_base;
warn_code = 0;
for (i = 0; i <= ASC_MAX_TID; i++) {
@@ -10045,6 +13073,7 @@ AscInitPollIsrCallBack(
ASC_ISR_CALLBACK asc_isr_callback;
uchar cp_sen_len;
uchar i;
+
ASC_DBG(1, "AscInitPollIsrCallBack: begin\n");
if ((scsi_done_q->d2.flag & ASC_FLAG_SCSIQ_REQ) != 0) {
scsiq_req = (ASC_SCSI_REQ_Q *) scsi_done_q->d2.srb_ptr;
@@ -10086,6 +13115,7 @@ AscTestExternalLram(
ushort q_addr;
ushort saved_word;
int sta;
+
iop_base = asc_dvc->iop_base;
sta = 0;
q_addr = ASC_QNO_TO_QADDR(241);
@@ -10101,7 +13131,6 @@ AscTestExternalLram(
return (sta);
}
-#if CC_INCLUDE_EEP_CONFIG
ASC_INITFUNC(
STATIC int
AscWriteEEPCmdReg(
@@ -10112,6 +13141,7 @@ AscWriteEEPCmdReg(
{
uchar read_back;
int retry;
+
retry = 0;
while (TRUE) {
AscSetChipEEPCmd(iop_base, cmd_reg);
@@ -10136,6 +13166,7 @@ AscWriteEEPDataReg(
{
ushort read_back;
int retry;
+
retry = 0;
while (TRUE) {
AscSetChipEEPData(iop_base, data_reg);
@@ -10182,6 +13213,7 @@ AscReadEEPWord(
{
ushort read_wval;
uchar cmd_reg;
+
AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_DISABLE);
AscWaitEEPRead();
cmd_reg = addr | ASC_EEP_CMD_READ;
@@ -10202,6 +13234,7 @@ AscWriteEEPWord(
)
{
ushort read_wval;
+
read_wval = AscReadEEPWord(iop_base, addr);
if (read_wval != word_val) {
AscWriteEEPCmdReg(iop_base, ASC_EEP_CMD_WRITE_ABLE);
@@ -10233,6 +13266,7 @@ AscGetEEPConfig(
int cfg_end;
int s_addr;
int isa_pnp_wsize;
+
wbuf = (ushort *) cfg_buf;
sum = 0;
isa_pnp_wsize = 0;
@@ -10258,7 +13292,6 @@ AscGetEEPConfig(
return (sum);
}
-#if CC_CHK_FIX_EEP_CONTENT
ASC_INITFUNC(
STATIC int
AscSetEEPConfigOnce(
@@ -10273,6 +13306,7 @@ AscSetEEPConfigOnce(
int s_addr;
int cfg_beg;
int cfg_end;
+
wbuf = (ushort *) cfg_buf;
n_error = 0;
sum = 0;
@@ -10338,8 +13372,6 @@ AscSetEEPConfig(
}
return (n_error);
}
-#endif
-#endif
STATIC int
AscInitPollBegin(
@@ -10347,6 +13379,7 @@ AscInitPollBegin(
)
{
PortAddr iop_base;
+
iop_base = asc_dvc->iop_base;
AscDisableInterrupt(iop_base);
asc_dvc->init_state |= ASC_INIT_STATE_BEG_INQUIRY;
@@ -10365,6 +13398,7 @@ AscInitPollEnd(
{
PortAddr iop_base;
rint i;
+
iop_base = asc_dvc->iop_base;
asc_dvc->isr_callback = (Ptr2Func) asc_dvc->saved_ptr2func;
AscWriteLramByte(iop_base, ASCV_DISC_ENABLE_B,
@@ -10384,8 +13418,6 @@ AscInitPollEnd(
return (0);
}
-STATIC int _asc_wait_slow_device_ = FALSE;
-
STATIC int
AscInitPollTarget(
REG ASC_DVC_VAR asc_ptr_type * asc_dvc,
@@ -10416,9 +13448,9 @@ AscInitPollTarget(
if (PollScsiInquiry(asc_dvc, scsiq, (uchar *) inq,
sizeof (ASC_SCSI_INQUIRY)) == 1) {
dvc_found = 1;
- support_read_cap = TRUE;
dvc_type = inq->byte0.peri_dvc_type;
if (dvc_type != SCSI_TYPE_UNKNOWN) {
+ support_read_cap = TRUE;
if ((dvc_type != SCSI_TYPE_DASD)
&& (dvc_type != SCSI_TYPE_WORM)
&& (dvc_type != SCSI_TYPE_CDROM)
@@ -10426,12 +13458,6 @@ AscInitPollTarget(
asc_dvc->start_motor &= ~tid_bits;
support_read_cap = FALSE;
}
- if ((dvc_type != SCSI_TYPE_DASD) || inq->byte1.rmb) {
- if (!_asc_wait_slow_device_) {
- DvcSleepMilliSecond(3000 - ((int) tid_no * 250));
- _asc_wait_slow_device_ = TRUE;
- }
- }
if (lun == 0) {
if ((inq->byte3.rsp_data_fmt >= 2) ||
(inq->byte2.ansi_apr_ver >= 2)) {
@@ -10485,6 +13511,14 @@ AscInitPollTarget(
(uchar *)"CD-ROM DRIVE ", 16) == 0)) {
asc_dvc->pci_fix_asyn_xfer &= ~tid_bits ;
}
+ if ((dvc_type == SCSI_TYPE_CDROM) &&
+ (AscCompareString((uchar *) inq->vendor_id,
+ (uchar *) "YAMAHA", 6) == 0) &&
+ (AscCompareString((uchar *) inq->product_id,
+ (uchar *) "CDR400", 6) == 0))
+ {
+ asc_dvc->pci_fix_asyn_xfer &= ~tid_bits ;
+ }
if (asc_dvc->pci_fix_asyn_xfer & tid_bits) {
AscSetRunChipSynRegAtID(asc_dvc->iop_base, tid_no,
@@ -10544,7 +13578,7 @@ PollQueueDone(
scsiq->r3.host_stat = 0;
scsiq->r3.scsi_stat = 0;
scsiq->r3.scsi_msg = 0;
- DvcSleepMilliSecond(2000);
+ DvcSleepMilliSecond(1000);
continue;
}
scsiq->r3.done_stat = 0;
@@ -10602,19 +13636,15 @@ PollScsiReadCapacity(
{
ASC_CAP_INFO scsi_cap_info;
int status;
+
if (AscScsiReadCapacity(asc_dvc, scsiq,
(uchar *) & scsi_cap_info) == ERR) {
return (scsiq->r3.done_stat = QD_WITH_ERROR);
}
status = PollQueueDone(asc_dvc, (ASC_SCSI_REQ_Q *) scsiq, 8);
if (status == 1) {
-#if CC_LITTLE_ENDIAN_HOST
cap_info->lba = (ulong) * swapfarbuf4((uchar *) & scsi_cap_info.lba);
cap_info->blk_size = (ulong) * swapfarbuf4((uchar *) & scsi_cap_info.blk_size);
-#else
- cap_info->lba = scsi_cap_info.lba;
- cap_info->blk_size = scsi_cap_info.blk_size;
-#endif
return (scsiq->r3.done_stat);
}
return (scsiq->r3.done_stat = QD_WITH_ERROR);
@@ -10659,6 +13689,7 @@ InitTestUnitReady(
ASC_SCSI_BIT_ID_TYPE tid_bits;
int retry;
ASC_REQ_SENSE *sen;
+
retry = 0;
tid_bits = scsiq->r1.target_id;
while (retry++ < 4) {
@@ -10666,26 +13697,28 @@ InitTestUnitReady(
if (scsiq->r3.done_stat == 0x01) {
return (1);
} else if (scsiq->r3.done_stat == QD_WITH_ERROR) {
- DvcSleepMilliSecond(200);
sen = (ASC_REQ_SENSE *) scsiq->sense_ptr;
if ((scsiq->r3.scsi_stat == SS_CHK_CONDITION) &&
((sen->err_code & 0x70) != 0)) {
if (sen->sense_key == SCSI_SENKEY_NOT_READY) {
+ if (sen->asc == SCSI_ASC_NOMEDIA)
+ {
+ break;
+ }
if (asc_dvc->start_motor & tid_bits) {
if (PollScsiStartUnit(asc_dvc, scsiq) == 1) {
- retry = 0;
+ DvcSleepMilliSecond(250);
continue;
} else {
asc_dvc->start_motor &= ~tid_bits;
break;
}
} else {
- DvcSleepMilliSecond(5000);
+ DvcSleepMilliSecond(250);
}
} else if (sen->sense_key == SCSI_SENKEY_ATTENTION) {
- DvcSleepMilliSecond((ulong)(500L*retry)) ;
+ DvcSleepMilliSecond(250);
} else {
- DvcSleepMilliSecond(500) ;
break;
}
} else {
@@ -10710,6 +13743,7 @@ AscPollQDone(
int loop, loop_end;
int sta;
PortAddr iop_base;
+
iop_base = asc_dvc->iop_base;
loop = 0;
loop_end = timeout_sec * 100;
@@ -10736,17 +13770,11 @@ AscPollQDone(
}
if (AscIsChipHalted(iop_base)) {
ASC_DBG(1, "AscPollQDone: AscIsChipHalted()\n");
-#if !CC_ASCISR_CHECK_INT_PENDING
- AscAckInterrupt(iop_base);
-#endif
AscISR(asc_dvc);
loop = 0;
} else {
if (AscIsIntPending(iop_base)) {
ASC_DBG(1, "AscPollQDone: AscIsIntPending()\n");
-#if !CC_ASCISR_CHECK_INT_PENDING
- AscAckInterrupt(iop_base);
-#endif
AscISR(asc_dvc);
}
}
@@ -10763,6 +13791,7 @@ AscCompareString(
{
int i;
int diff;
+
for (i = 0; i < len; i++) {
diff = (int) (str1[i] - str2[i]);
if (diff != 0)
@@ -10779,6 +13808,7 @@ AscReadLramByte(
{
uchar byte_data;
ushort word_data;
+
if (isodd_word(addr)) {
AscSetChipLramAddr(iop_base, addr - 1);
word_data = AscGetChipLramData(iop_base);
@@ -10798,6 +13828,7 @@ AscReadLramWord(
)
{
ushort word_data;
+
AscSetChipLramAddr(iop_base, addr);
word_data = AscGetChipLramData(iop_base);
return (word_data);
@@ -10811,6 +13842,7 @@ AscReadLramDWord(
{
ushort val_low, val_high;
ulong dword_data;
+
AscSetChipLramAddr(iop_base, addr);
val_low = AscGetChipLramData(iop_base);
val_high = AscGetChipLramData(iop_base);
@@ -10838,6 +13870,7 @@ AscWriteLramDWord(
)
{
ushort word_val;
+
AscSetChipLramAddr(iop_base, addr);
word_val = (ushort) dword_val;
AscSetChipLramData(iop_base, word_val);
@@ -10854,6 +13887,7 @@ AscWriteLramByte(
)
{
ushort word_data;
+
if (isodd_word(addr)) {
addr--;
word_data = AscReadLramWord(iop_base, addr);
@@ -10916,6 +13950,7 @@ AscMemSumLramWord(
{
ulong sum;
int i;
+
sum = 0L;
for (i = 0; i < words; i++, s_addr += 2) {
sum += AscReadLramWord(iop_base, s_addr);
@@ -10932,6 +13967,7 @@ AscMemWordSetLram(
)
{
rint i;
+
AscSetChipLramAddr(iop_base, s_addr);
for (i = 0; i < words; i++) {
AscSetChipLramData(iop_base, set_wval);
@@ -11027,3 +14063,1727 @@ AscScsiStartStopUnit(
scsiq->r2.cdb_len = 6;
return (0);
}
+
+
+/*
+ * --- Adv Library Functions
+ */
+
+/* a_qswap.h */
+STATIC unsigned char _adv_mcode_buf[] ASC_INITDATA = {
+ 0x9C, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0x40, 0x0A, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x72, 0x01, 0xD2, 0x11, 0x00, 0x00, 0x70, 0x01,
+ 0x30, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x88, 0x0F, 0x22, 0x03, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x04, 0xF7, 0x70, 0x01, 0x0C, 0x1C, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF2, 0xD2, 0x0A,
+ 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x3E, 0x57, 0x3C, 0x56, 0x0C, 0x1C, 0x00, 0xFC,
+ 0xA6, 0x00, 0x01, 0x58, 0xAA, 0x13, 0x20, 0xF0, 0x9A, 0x03, 0x06, 0xEC, 0xB9, 0x00, 0x0E, 0x47,
+ 0x03, 0xE6, 0x10, 0x00, 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0x06, 0xEA, 0xB9, 0x00, 0x47, 0x4B,
+ 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x4E, 0x12, 0x03, 0xF6, 0xC0, 0x00,
+ 0x00, 0xF2, 0x64, 0x0A, 0x41, 0x58, 0x03, 0xF6, 0xD0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x49, 0x44,
+ 0x59, 0xF0, 0x0A, 0x02, 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x44, 0x58, 0x00, 0xF2,
+ 0xDE, 0x0D, 0x02, 0xCC, 0x4A, 0xE4, 0x01, 0x00, 0x55, 0xF0, 0x08, 0x03, 0x45, 0xF4, 0x02, 0x00,
+ 0x83, 0x5A, 0x04, 0xCC, 0x01, 0x4A, 0x12, 0x12, 0x00, 0xF2, 0xDE, 0x0D, 0x00, 0xCD, 0x48, 0xE4,
+ 0x01, 0x00, 0xE9, 0x13, 0x00, 0xF2, 0xC2, 0x0F, 0xFA, 0x10, 0x0E, 0x47, 0x03, 0xE6, 0x10, 0x00,
+ 0xCE, 0x45, 0x02, 0x13, 0x3E, 0x57, 0xCE, 0x47, 0x97, 0x13, 0x04, 0xEC, 0xB4, 0x00, 0x00, 0xF2,
+ 0xDE, 0x0D, 0x00, 0xCD, 0x48, 0xE4, 0x00, 0x00, 0x12, 0x12, 0x3E, 0x57, 0x06, 0xCC, 0x45, 0xF4,
+ 0x02, 0x00, 0x83, 0x5A, 0x00, 0xCC, 0x00, 0xEA, 0xB4, 0x00, 0x92, 0x10, 0x00, 0xF0, 0x8C, 0x01,
+ 0x43, 0xF0, 0x5C, 0x02, 0x44, 0xF0, 0x60, 0x02, 0x45, 0xF0, 0x64, 0x02, 0x46, 0xF0, 0x68, 0x02,
+ 0x47, 0xF0, 0x6E, 0x02, 0x48, 0xF0, 0x9E, 0x02, 0xB9, 0x54, 0x62, 0x10, 0x00, 0x1C, 0x5A, 0x10,
+ 0x02, 0x1C, 0x56, 0x10, 0x1E, 0x1C, 0x52, 0x10, 0x00, 0xF2, 0x1A, 0x11, 0x50, 0x10, 0x06, 0xFC,
+ 0xA8, 0x00, 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x4A, 0x0A, 0x8C, 0x10, 0x01, 0xF6, 0x01, 0x00,
+ 0x01, 0xFA, 0xA8, 0x00, 0x00, 0xF2, 0x28, 0x0B, 0x06, 0x10, 0xB9, 0x54, 0x01, 0xFA, 0xA8, 0x00,
+ 0x03, 0xF6, 0xBE, 0x00, 0x00, 0xF2, 0x54, 0x0A, 0x01, 0xFC, 0xA8, 0x00, 0x20, 0x10, 0x58, 0x1C,
+ 0x00, 0xF2, 0x18, 0x0B, 0x5A, 0x1C, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54, 0x00, 0xFA, 0xA6, 0x00,
+ 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x72, 0x01, 0x01, 0xF6, 0x01, 0x00, 0x38, 0x54,
+ 0x00, 0xFA, 0xA6, 0x00, 0x01, 0xFA, 0xA8, 0x00, 0x20, 0x1C, 0x00, 0xF0, 0x80, 0x01, 0x03, 0xF6,
+ 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x0A, 0x13, 0x00, 0xF2, 0x34, 0x10, 0x00, 0xF2,
+ 0x50, 0x0F, 0x24, 0x10, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x02, 0xF6, 0xD0, 0x00,
+ 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x49, 0x44, 0x5B, 0xF0, 0x04, 0x03, 0x00, 0xF2, 0x98, 0x0F,
+ 0x00, 0xF0, 0x80, 0x01, 0x00, 0xF2, 0x10, 0x10, 0x0C, 0x1C, 0x02, 0x4B, 0xBF, 0x57, 0x9E, 0x43,
+ 0x77, 0x57, 0x07, 0x4B, 0x20, 0xF0, 0x9A, 0x03, 0x40, 0x1C, 0x1E, 0xF0, 0x30, 0x03, 0x26, 0xF0,
+ 0x2C, 0x03, 0xA0, 0xF0, 0x1A, 0x03, 0x11, 0xF0, 0x9A, 0x03, 0x12, 0x10, 0x9F, 0xF0, 0x3E, 0x03,
+ 0x46, 0x1C, 0x82, 0xE7, 0x05, 0x00, 0x9E, 0xE7, 0x11, 0x00, 0x00, 0xF0, 0x02, 0x0A, 0x0C, 0x1C,
+ 0x48, 0x1C, 0x46, 0x1C, 0x38, 0x54, 0x00, 0xEC, 0xBA, 0x00, 0x08, 0x44, 0x00, 0xEA, 0xBA, 0x00,
+ 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x08, 0x44, 0x00, 0x4C, 0x82, 0xE7, 0x02, 0x00,
+ 0x00, 0xF2, 0x0E, 0x11, 0x00, 0xF2, 0x0E, 0x11, 0x06, 0xF0, 0x74, 0x03, 0x1E, 0xF0, 0xF8, 0x09,
+ 0x00, 0xF0, 0xFE, 0x09, 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0x55, 0xF0, 0xA0, 0x04, 0x01, 0xE6,
+ 0x0C, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2,
+ 0xC4, 0x11, 0x01, 0xF0, 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x46, 0x1C, 0x0C, 0x1C, 0x67, 0x1B,
+ 0xBF, 0x57, 0x77, 0x57, 0x02, 0x4B, 0x48, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x8E, 0x0D, 0x30, 0x1C,
+ 0x96, 0xF0, 0xB0, 0x03, 0xB1, 0xF0, 0xB4, 0x03, 0x1E, 0xF0, 0xF8, 0x09, 0x85, 0xF0, 0xFE, 0x09,
+ 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0x14, 0x12, 0x01, 0xE6, 0x0C, 0x00, 0x00, 0xF2, 0x4A, 0x0D,
+ 0x00, 0xF2, 0x0E, 0x11, 0x01, 0xF0, 0x7C, 0x02, 0x00, 0xF0, 0x8A, 0x02, 0x03, 0xF6, 0xE0, 0x00,
+ 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x55, 0xF0, 0x8C, 0x04, 0x03, 0x82, 0x03, 0xFC, 0xA0, 0x00,
+ 0x9B, 0x57, 0x40, 0x12, 0x69, 0x18, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0x36, 0x04, 0x69, 0x08,
+ 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0xFE, 0x09, 0x68, 0x08, 0x4C, 0x44, 0x28, 0x12, 0x44, 0x48,
+ 0x03, 0xF6, 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x45, 0x58, 0x00, 0xF2, 0xF2, 0x0D, 0x00, 0xCC,
+ 0x01, 0x48, 0x55, 0xF0, 0x8C, 0x04, 0x4C, 0x44, 0xEF, 0x13, 0x00, 0xF2, 0xC2, 0x0F, 0x00, 0xF2,
+ 0x10, 0x10, 0x08, 0x10, 0x68, 0x18, 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, 0x04, 0x80, 0x18, 0xE4,
+ 0x10, 0x00, 0x28, 0x12, 0x01, 0xE6, 0x06, 0x00, 0x04, 0x80, 0x18, 0xE4, 0x01, 0x00, 0x04, 0x12,
+ 0x01, 0xE6, 0x0D, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x04, 0xE6, 0x02, 0x00,
+ 0x9E, 0xE7, 0x15, 0x00, 0x01, 0xF0, 0x18, 0x0A, 0x00, 0xF0, 0xFE, 0x09, 0x69, 0x08, 0x05, 0x80,
+ 0x48, 0xE4, 0x00, 0x00, 0x0C, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA, 0xB8, 0x00, 0x00, 0xF2,
+ 0xB2, 0x10, 0x82, 0xE7, 0x02, 0x00, 0x1C, 0x90, 0x40, 0x5C, 0x00, 0x16, 0x01, 0xE6, 0x06, 0x00,
+ 0x00, 0xF2, 0x4A, 0x0D, 0x01, 0xF0, 0x80, 0x01, 0x1E, 0xF0, 0x80, 0x01, 0x00, 0xF0, 0x94, 0x04,
+ 0x42, 0x5B, 0x06, 0xF7, 0x03, 0x00, 0x46, 0x59, 0xBF, 0x57, 0x77, 0x57, 0x01, 0xE6, 0x80, 0x00,
+ 0x07, 0x80, 0x31, 0x44, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x5E, 0x13, 0x20, 0x80, 0x48, 0xE4,
+ 0x03, 0x00, 0x56, 0x12, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x4C, 0x13, 0x00, 0xFC, 0xA2, 0x00,
+ 0x98, 0x57, 0x55, 0xF0, 0x18, 0x05, 0x31, 0xE4, 0x40, 0x00, 0x00, 0xFC, 0xA0, 0x00, 0x98, 0x57,
+ 0x36, 0x12, 0x4C, 0x1C, 0x00, 0xF2, 0x0E, 0x11, 0x89, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0,
+ 0x2A, 0x05, 0x82, 0xE7, 0x06, 0x00, 0x1B, 0x80, 0x48, 0xE4, 0x22, 0x00, 0x5B, 0xF0, 0x08, 0x05,
+ 0x48, 0xE4, 0x20, 0x00, 0x59, 0xF0, 0x0C, 0x05, 0x00, 0xE6, 0x20, 0x00, 0x09, 0x48, 0x00, 0xF2,
+ 0x0E, 0x11, 0x86, 0xF0, 0x2A, 0x05, 0x83, 0x80, 0x04, 0x10, 0x00, 0xF2, 0x9E, 0x0D, 0x00, 0xE6,
+ 0x01, 0x00, 0x00, 0xEA, 0x26, 0x01, 0x01, 0xEA, 0x27, 0x01, 0x04, 0x80, 0x18, 0xE4, 0x10, 0x00,
+ 0x36, 0x12, 0xB9, 0x54, 0x00, 0xF2, 0xF2, 0x0E, 0x01, 0xE6, 0x06, 0x00, 0x04, 0x80, 0x18, 0xE4,
+ 0x01, 0x00, 0x04, 0x12, 0x01, 0xE6, 0x0D, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11,
+ 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00,
+ 0x01, 0xF0, 0x18, 0x0A, 0x00, 0xF0, 0xFE, 0x09, 0x00, 0xFC, 0x20, 0x01, 0x98, 0x57, 0x34, 0x12,
+ 0x00, 0xFC, 0x24, 0x01, 0x98, 0x57, 0x2C, 0x13, 0xB9, 0x54, 0x00, 0xF2, 0xF2, 0x0E, 0x86, 0xF0,
+ 0xA4, 0x05, 0x03, 0xF6, 0x01, 0x00, 0x00, 0xF2, 0x88, 0x0E, 0x85, 0xF0, 0x9A, 0x05, 0x82, 0xE7,
+ 0x03, 0x00, 0x00, 0xF2, 0x5C, 0x0B, 0x82, 0xE7, 0x02, 0x00, 0x00, 0xFC, 0x24, 0x01, 0xB0, 0x57,
+ 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFC, 0x9E, 0x00, 0x98, 0x57, 0x5A, 0x12, 0x00, 0xFC, 0xB6, 0x00,
+ 0x98, 0x57, 0x52, 0x13, 0x03, 0xE6, 0x0C, 0x00, 0x00, 0xFC, 0x9C, 0x00, 0x98, 0x57, 0x04, 0x13,
+ 0x03, 0xE6, 0x19, 0x00, 0x05, 0xE6, 0x08, 0x00, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57,
+ 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x04, 0x13, 0x05, 0xE6, 0x0F, 0x00, 0xB9, 0x54,
+ 0x00, 0xF2, 0xF2, 0x0E, 0x86, 0xF0, 0x06, 0x06, 0x00, 0xF2, 0xB6, 0x0E, 0x85, 0xF0, 0xFC, 0x05,
+ 0x82, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x5C, 0x0B, 0x82, 0xE7, 0x02, 0x00, 0x00, 0xFC, 0xB6, 0x00,
+ 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0xF2, 0xF2, 0x0E, 0x9C, 0x32,
+ 0x4E, 0x1C, 0x32, 0x1C, 0x00, 0xF2, 0x8E, 0x0D, 0x30, 0x1C, 0x82, 0xE7, 0x04, 0x00, 0xB1, 0xF0,
+ 0x1E, 0x06, 0x0A, 0xF0, 0x3A, 0x06, 0x05, 0xF0, 0xD2, 0x06, 0x06, 0xF0, 0xD8, 0x06, 0x09, 0xF0,
+ 0x20, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0x00, 0xF0, 0xFE, 0x09, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00,
+ 0x30, 0x12, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x21, 0x80, 0x18, 0xE4, 0xE0, 0x00,
+ 0x09, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7,
+ 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x99, 0xA4, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00,
+ 0x9A, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x34, 0x12, 0x09, 0xE7, 0x1B, 0x00, 0x00, 0xF2,
+ 0x0E, 0x11, 0x21, 0x80, 0x18, 0xE4, 0xE0, 0x00, 0x09, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7,
+ 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7,
+ 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x09, 0xE7, 0x00, 0x00, 0x00, 0xF0, 0x08, 0x09, 0xBB, 0x55,
+ 0x9A, 0x81, 0x03, 0xF7, 0x20, 0x00, 0x09, 0x6F, 0x93, 0x45, 0x55, 0xF0, 0xDE, 0x06, 0xB1, 0xF0,
+ 0xBE, 0x06, 0x0A, 0xF0, 0xB6, 0x06, 0x09, 0xF0, 0x20, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0x00, 0xF0,
+ 0xFE, 0x09, 0x00, 0xF2, 0x5C, 0x0B, 0x47, 0x10, 0x09, 0xE7, 0x08, 0x00, 0x41, 0x10, 0x05, 0x80,
+ 0x48, 0xE4, 0x00, 0x00, 0x1E, 0x12, 0x00, 0xE6, 0x11, 0x00, 0x00, 0xEA, 0xB8, 0x00, 0x00, 0xF2,
+ 0xB2, 0x10, 0x2C, 0x90, 0xAE, 0x90, 0x08, 0x50, 0x8A, 0x50, 0x38, 0x54, 0x1F, 0x40, 0x00, 0xF2,
+ 0xB0, 0x0D, 0x08, 0x10, 0x08, 0x90, 0x8A, 0x90, 0x30, 0x50, 0xB2, 0x50, 0x9C, 0x32, 0x0C, 0x92,
+ 0x8E, 0x92, 0x38, 0x54, 0x04, 0x80, 0x30, 0xE4, 0x08, 0x00, 0x04, 0x40, 0x0C, 0x1C, 0x00, 0xF6,
+ 0x03, 0x00, 0xB1, 0xF0, 0x22, 0x07, 0x9E, 0xF0, 0x36, 0x07, 0x01, 0x48, 0x55, 0xF0, 0xF8, 0x09,
+ 0x0C, 0x1C, 0x10, 0x44, 0xED, 0x10, 0x0B, 0xF0, 0x5A, 0x07, 0x0C, 0xF0, 0x5E, 0x07, 0x05, 0xF0,
+ 0x4E, 0x07, 0x06, 0xF0, 0x54, 0x07, 0x09, 0xF0, 0x20, 0x09, 0x00, 0xF0, 0xFE, 0x09, 0x00, 0xF2,
+ 0x5C, 0x0B, 0xCF, 0x10, 0x09, 0xE7, 0x08, 0x00, 0xC9, 0x10, 0x2E, 0x1C, 0x02, 0x10, 0x2C, 0x1C,
+ 0xAA, 0xF0, 0x60, 0x07, 0xAC, 0xF0, 0x6E, 0x07, 0x40, 0x10, 0x34, 0x1C, 0xF3, 0x10, 0xAD, 0xF0,
+ 0x78, 0x07, 0xC8, 0x10, 0x36, 0x1C, 0xE9, 0x10, 0x2B, 0xF0, 0x7E, 0x08, 0x6B, 0x18, 0x18, 0xF4,
+ 0x00, 0xFE, 0x20, 0x12, 0x01, 0x58, 0xD2, 0xF0, 0x7E, 0x08, 0x76, 0x18, 0x18, 0xF4, 0x03, 0x00,
+ 0xEC, 0x12, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xE2, 0x12, 0x0B, 0xF0, 0x60, 0x07,
+ 0x0C, 0xF0, 0x60, 0x07, 0x36, 0x1C, 0x34, 0x1C, 0xB7, 0x10, 0x38, 0x54, 0xB9, 0x54, 0x84, 0x80,
+ 0x19, 0xE4, 0x20, 0x00, 0xB2, 0x13, 0x85, 0x80, 0x81, 0x48, 0x66, 0x12, 0x04, 0x80, 0x18, 0xE4,
+ 0x08, 0x00, 0x58, 0x13, 0x1F, 0x80, 0x08, 0x44, 0xC8, 0x44, 0x9F, 0x12, 0x1F, 0x40, 0x34, 0x91,
+ 0xB6, 0x91, 0x44, 0x55, 0xE5, 0x55, 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49, 0xBB, 0x55, 0x82, 0x81,
+ 0xC0, 0x55, 0x48, 0xF4, 0x0F, 0x00, 0x5A, 0xF0, 0x16, 0x08, 0x4A, 0xE4, 0x17, 0x00, 0xD5, 0xF0,
+ 0xF6, 0x07, 0x02, 0xF6, 0x0F, 0x00, 0x02, 0xF4, 0x02, 0x00, 0x02, 0xEA, 0xB8, 0x00, 0x04, 0x91,
+ 0x86, 0x91, 0x02, 0x4B, 0x2C, 0x90, 0x08, 0x50, 0x2E, 0x90, 0x0A, 0x50, 0x2C, 0x51, 0xAE, 0x51,
+ 0x00, 0xF2, 0xB2, 0x10, 0x38, 0x54, 0x00, 0xF2, 0xB0, 0x0D, 0x56, 0x10, 0x34, 0x91, 0xB6, 0x91,
+ 0x0C, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x08, 0x00, 0x41, 0x12, 0x0C, 0x91, 0x8E, 0x91, 0x04, 0x80,
+ 0x18, 0xE4, 0xF7, 0x00, 0x04, 0x40, 0x30, 0x90, 0xB2, 0x90, 0x36, 0x10, 0x02, 0x80, 0x48, 0xE4,
+ 0x10, 0x00, 0x31, 0x12, 0x82, 0xE7, 0x10, 0x00, 0x84, 0x80, 0x19, 0xE4, 0x20, 0x00, 0x10, 0x13,
+ 0x0C, 0x90, 0x8E, 0x90, 0x5D, 0xF0, 0x74, 0x07, 0x0C, 0x58, 0x8D, 0x58, 0x00, 0xF0, 0x60, 0x07,
+ 0x38, 0x54, 0xB9, 0x54, 0x19, 0x80, 0xF1, 0x10, 0x3A, 0x55, 0x19, 0x81, 0xBB, 0x55, 0x10, 0x90,
+ 0x92, 0x90, 0x10, 0x58, 0x91, 0x58, 0x14, 0x59, 0x95, 0x59, 0x00, 0xF0, 0x60, 0x07, 0x04, 0x80,
+ 0x18, 0xE4, 0x20, 0x00, 0x06, 0x12, 0x6C, 0x19, 0x19, 0x41, 0x7C, 0x10, 0x6C, 0x19, 0x0C, 0x51,
+ 0xED, 0x19, 0x8E, 0x51, 0x6B, 0x18, 0x18, 0xF4, 0x00, 0xFF, 0x02, 0x13, 0x6A, 0x10, 0x01, 0x58,
+ 0xD2, 0xF0, 0xBC, 0x08, 0x76, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x0A, 0x12, 0x00, 0xFC, 0x22, 0x01,
+ 0x18, 0xF4, 0x01, 0x00, 0x06, 0x13, 0x9E, 0xE7, 0x16, 0x00, 0x4C, 0x10, 0xD1, 0xF0, 0xC6, 0x08,
+ 0x9E, 0xE7, 0x17, 0x00, 0x42, 0x10, 0xD0, 0xF0, 0xD0, 0x08, 0x9E, 0xE7, 0x19, 0x00, 0x38, 0x10,
+ 0xCF, 0xF0, 0xDA, 0x08, 0x9E, 0xE7, 0x20, 0x00, 0x2E, 0x10, 0xCE, 0xF0, 0xE4, 0x08, 0x9E, 0xE7,
+ 0x21, 0x00, 0x24, 0x10, 0xCD, 0xF0, 0xEE, 0x08, 0x9E, 0xE7, 0x22, 0x00, 0x1A, 0x10, 0xCC, 0xF0,
+ 0x00, 0x09, 0x84, 0x80, 0x19, 0xE4, 0x04, 0x00, 0x06, 0x12, 0x9E, 0xE7, 0x12, 0x00, 0x08, 0x10,
+ 0xCB, 0xF0, 0x08, 0x09, 0x9E, 0xE7, 0x24, 0x00, 0xB1, 0xF0, 0x08, 0x09, 0x05, 0xF0, 0x1A, 0x09,
+ 0x09, 0xF0, 0x20, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0xE4, 0x10, 0x00, 0xF2, 0x5C, 0x0B, 0xE9, 0x10,
+ 0x9C, 0x32, 0x82, 0xE7, 0x20, 0x00, 0x32, 0x1C, 0xE9, 0x09, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0,
+ 0xFE, 0x09, 0x69, 0x08, 0x01, 0xF0, 0x40, 0x09, 0x1E, 0xF0, 0xF8, 0x09, 0x00, 0xF0, 0x34, 0x09,
+ 0x30, 0x44, 0x06, 0x12, 0x9E, 0xE7, 0x42, 0x00, 0xB8, 0x10, 0x04, 0xF6, 0x01, 0x00, 0xB3, 0x45,
+ 0x74, 0x12, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x22, 0x13, 0x4B, 0xE4, 0x02, 0x00, 0x36, 0x12,
+ 0x4B, 0xE4, 0x28, 0x00, 0xAC, 0x13, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0x03, 0xF6,
+ 0xD0, 0x00, 0xFA, 0x14, 0x82, 0xE7, 0x01, 0x00, 0x00, 0xF0, 0x80, 0x01, 0x9E, 0xE7, 0x44, 0x00,
+ 0x4B, 0xE4, 0x02, 0x00, 0x06, 0x12, 0x03, 0xE6, 0x02, 0x00, 0x76, 0x10, 0x00, 0xF2, 0x9E, 0x0D,
+ 0x03, 0xE6, 0x02, 0x00, 0x6C, 0x10, 0x00, 0xF2, 0x9E, 0x0D, 0x19, 0x82, 0x34, 0x46, 0x0A, 0x13,
+ 0x03, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x43, 0x00, 0x68, 0x10, 0x04, 0x80, 0x30, 0xE4, 0x20, 0x00,
+ 0x04, 0x40, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0x82, 0xE7, 0x01, 0x00, 0x06, 0xF7,
+ 0x02, 0x00, 0x00, 0xF0, 0x08, 0x03, 0x04, 0x80, 0x18, 0xE4, 0x20, 0x00, 0x06, 0x12, 0x03, 0xE6,
+ 0x02, 0x00, 0x3E, 0x10, 0x04, 0x80, 0x18, 0xE4, 0x02, 0x00, 0x3A, 0x12, 0x04, 0x80, 0x18, 0xE4,
+ 0xFD, 0x00, 0x04, 0x40, 0x1C, 0x1C, 0x9D, 0xF0, 0xE6, 0x09, 0x1C, 0x1C, 0x9D, 0xF0, 0xEC, 0x09,
+ 0xC1, 0x10, 0x9E, 0xE7, 0x13, 0x00, 0x0A, 0x10, 0x9E, 0xE7, 0x41, 0x00, 0x04, 0x10, 0x9E, 0xE7,
+ 0x24, 0x00, 0x00, 0xFC, 0xBE, 0x00, 0x98, 0x57, 0xD5, 0xF0, 0x8A, 0x02, 0x04, 0xE6, 0x04, 0x00,
+ 0x06, 0x10, 0x04, 0xE6, 0x04, 0x00, 0x9D, 0x41, 0x1C, 0x42, 0x9F, 0xE7, 0x00, 0x00, 0x06, 0xF7,
+ 0x02, 0x00, 0x03, 0xF6, 0xE0, 0x00, 0x3C, 0x14, 0x44, 0x58, 0x45, 0x58, 0x00, 0xF2, 0xF2, 0x0D,
+ 0x00, 0xF2, 0x7A, 0x10, 0x00, 0xF2, 0xC2, 0x0F, 0x3C, 0x14, 0x1E, 0x1C, 0x00, 0xF0, 0x80, 0x01,
+ 0x12, 0x1C, 0x22, 0x1C, 0xD2, 0x14, 0x00, 0xF0, 0x72, 0x01, 0x83, 0x59, 0x03, 0xDC, 0x73, 0x57,
+ 0x80, 0x5D, 0x00, 0x16, 0x83, 0x59, 0x03, 0xDC, 0x38, 0x54, 0x70, 0x57, 0x33, 0x54, 0x3B, 0x54,
+ 0x80, 0x5D, 0x00, 0x16, 0x03, 0x57, 0x83, 0x59, 0x38, 0x54, 0x00, 0xCC, 0x00, 0x16, 0x03, 0x57,
+ 0x83, 0x59, 0x00, 0x4C, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4, 0x01, 0x00, 0x0E, 0x12, 0x48, 0xE4,
+ 0x05, 0x00, 0x08, 0x12, 0x00, 0xF2, 0xB8, 0x11, 0x00, 0xF2, 0xC4, 0x11, 0xC1, 0x5A, 0x3A, 0x55,
+ 0x02, 0xEC, 0xB5, 0x00, 0x45, 0x59, 0x00, 0xF2, 0xF2, 0x0D, 0x83, 0x58, 0x30, 0xE7, 0x00, 0x00,
+ 0x10, 0x4D, 0x30, 0xE7, 0x40, 0x00, 0x10, 0x4F, 0x38, 0x90, 0xBA, 0x90, 0x10, 0x5C, 0x80, 0x5C,
+ 0x83, 0x5A, 0x10, 0x4E, 0x04, 0xEA, 0xB5, 0x00, 0x43, 0x5B, 0x03, 0xF4, 0xE0, 0x00, 0x83, 0x59,
+ 0x04, 0xCC, 0x01, 0x4A, 0x0A, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, 0x00, 0xF2, 0x34, 0x10,
+ 0x00, 0x16, 0x08, 0x1C, 0x00, 0xFC, 0xAC, 0x00, 0x06, 0x58, 0x67, 0x18, 0x18, 0xF4, 0x8F, 0xE1,
+ 0x01, 0xFC, 0xAE, 0x00, 0x19, 0xF4, 0x70, 0x1E, 0xB0, 0x54, 0x07, 0x58, 0x00, 0xFC, 0xB0, 0x00,
+ 0x08, 0x58, 0x00, 0xFC, 0xB2, 0x00, 0x09, 0x58, 0x0A, 0x1C, 0x00, 0xE6, 0x0F, 0x00, 0x00, 0xEA,
+ 0xB9, 0x00, 0x38, 0x54, 0x00, 0xFA, 0x24, 0x01, 0x00, 0xFA, 0xB6, 0x00, 0x18, 0x1C, 0x14, 0x1C,
+ 0x10, 0x1C, 0x32, 0x1C, 0x12, 0x1C, 0x00, 0x16, 0x3E, 0x57, 0x0C, 0x14, 0x0E, 0x47, 0x07, 0xE6,
+ 0x10, 0x00, 0xCE, 0x47, 0xF5, 0x13, 0x00, 0x16, 0x00, 0xF2, 0x9E, 0x0D, 0x02, 0x4B, 0x03, 0xF6,
+ 0xE0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x01, 0x48, 0x20, 0x12, 0x44, 0x58, 0x45, 0x58, 0x9E, 0xE7,
+ 0x15, 0x00, 0x9C, 0xE7, 0x04, 0x00, 0x00, 0xF2, 0xF2, 0x0D, 0x00, 0xF2, 0x7A, 0x10, 0x00, 0xF2,
+ 0xC2, 0x0F, 0x00, 0xF2, 0x76, 0x0A, 0x1E, 0x1C, 0xD5, 0x10, 0x00, 0x16, 0x69, 0x08, 0x48, 0xE4,
+ 0x04, 0x00, 0x64, 0x12, 0x48, 0xE4, 0x02, 0x00, 0x20, 0x12, 0x48, 0xE4, 0x03, 0x00, 0x1A, 0x12,
+ 0x48, 0xE4, 0x08, 0x00, 0x14, 0x12, 0x48, 0xE4, 0x01, 0x00, 0xF0, 0x12, 0x48, 0xE4, 0x07, 0x00,
+ 0x12, 0x12, 0x01, 0xE6, 0x07, 0x00, 0x00, 0xF2, 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x05, 0xF0,
+ 0x5C, 0x0B, 0x00, 0x16, 0x00, 0xE6, 0x01, 0x00, 0x00, 0xEA, 0x99, 0x00, 0x02, 0x80, 0x48, 0xE4,
+ 0x03, 0x00, 0xB9, 0x12, 0x48, 0xE4, 0x06, 0x00, 0xB3, 0x12, 0x01, 0xE6, 0x06, 0x00, 0x00, 0xF2,
+ 0x4A, 0x0D, 0x00, 0xF2, 0x0E, 0x11, 0x04, 0xE6, 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, 0x01, 0xF0,
+ 0x18, 0x0A, 0x00, 0xF0, 0xFE, 0x09, 0x00, 0x16, 0x02, 0x80, 0x48, 0xE4, 0x10, 0x00, 0x1C, 0x12,
+ 0x82, 0xE7, 0x08, 0x00, 0x3C, 0x56, 0x03, 0x82, 0x00, 0xF2, 0xDE, 0x0D, 0x30, 0xE7, 0x08, 0x00,
+ 0x04, 0xF7, 0x70, 0x01, 0x06, 0xF7, 0x02, 0x00, 0x00, 0xF0, 0x80, 0x01, 0x6C, 0x19, 0xED, 0x19,
+ 0x5D, 0xF0, 0xD0, 0x0B, 0x44, 0x55, 0xE5, 0x55, 0x59, 0xF0, 0x4E, 0x0C, 0x04, 0x55, 0xA5, 0x55,
+ 0x1F, 0x80, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80, 0x49, 0x44, 0x2E, 0x13, 0x01, 0xEC,
+ 0xB8, 0x00, 0x41, 0xE4, 0x02, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x49, 0xE4, 0x11, 0x00, 0x59, 0xF0,
+ 0x2A, 0x0C, 0x01, 0xE6, 0x17, 0x00, 0x01, 0xEA, 0xB8, 0x00, 0x02, 0x4B, 0x88, 0x90, 0xAC, 0x50,
+ 0x8A, 0x90, 0xAE, 0x50, 0x01, 0xEC, 0xB8, 0x00, 0x82, 0x48, 0x82, 0x80, 0x10, 0x44, 0x02, 0x4B,
+ 0x1F, 0x40, 0xC0, 0x44, 0x00, 0xF2, 0xB0, 0x0D, 0x04, 0x55, 0xA5, 0x55, 0x9F, 0x10, 0x0C, 0x51,
+ 0x8E, 0x51, 0x30, 0x90, 0xB2, 0x90, 0x00, 0x56, 0xA1, 0x56, 0x30, 0x50, 0xB2, 0x50, 0x34, 0x90,
+ 0xB6, 0x90, 0x40, 0x56, 0xE1, 0x56, 0x34, 0x50, 0xB6, 0x50, 0x65, 0x10, 0xB1, 0xF0, 0x6C, 0x0C,
+ 0x85, 0xF0, 0xC6, 0x0B, 0xE9, 0x09, 0x4B, 0xE4, 0x03, 0x00, 0x78, 0x12, 0x4B, 0xE4, 0x02, 0x00,
+ 0x01, 0x13, 0xB1, 0xF0, 0x82, 0x0C, 0x85, 0xF0, 0xC6, 0x0B, 0x69, 0x08, 0x48, 0xE4, 0x03, 0x00,
+ 0xD5, 0xF0, 0x82, 0x0B, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0xC6, 0x0B, 0xE8, 0x09, 0x3C, 0x56,
+ 0x00, 0xFC, 0x20, 0x01, 0x98, 0x57, 0x02, 0x13, 0xBB, 0x45, 0x4B, 0xE4, 0x00, 0x00, 0x08, 0x12,
+ 0x03, 0xE6, 0x01, 0x00, 0x04, 0xF6, 0x00, 0x80, 0xA8, 0x14, 0xD2, 0x14, 0x30, 0x1C, 0x02, 0x80,
+ 0x48, 0xE4, 0x03, 0x00, 0x10, 0x13, 0x00, 0xFC, 0xB6, 0x00, 0x98, 0x57, 0x02, 0x13, 0x4C, 0x1C,
+ 0x3E, 0x1C, 0x00, 0xF0, 0x8A, 0x0B, 0x00, 0xFC, 0x24, 0x01, 0xB0, 0x57, 0x00, 0xFA, 0x24, 0x01,
+ 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0x8A, 0x0B, 0x00, 0xF2, 0x88, 0x0E,
+ 0x00, 0xF0, 0x8A, 0x0B, 0xB1, 0xF0, 0xF4, 0x0C, 0x85, 0xF0, 0x82, 0x0B, 0x69, 0x08, 0x48, 0xE4,
+ 0x01, 0x00, 0xD5, 0xF0, 0x82, 0x0B, 0xFC, 0x14, 0x42, 0x58, 0x6C, 0x14, 0x80, 0x14, 0x30, 0x1C,
+ 0x4A, 0xF4, 0x02, 0x00, 0x55, 0xF0, 0x82, 0x0B, 0x4A, 0xF4, 0x01, 0x00, 0x0E, 0x12, 0x02, 0x80,
+ 0x48, 0xE4, 0x03, 0x00, 0x06, 0x13, 0x3E, 0x1C, 0x00, 0xF0, 0x8A, 0x0B, 0x00, 0xFC, 0xB6, 0x00,
+ 0xB0, 0x57, 0x00, 0xFA, 0xB6, 0x00, 0x4C, 0x1C, 0x3E, 0x1C, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0,
+ 0x8A, 0x0B, 0x00, 0xF2, 0xB6, 0x0E, 0x00, 0xF0, 0x8A, 0x0B, 0x4C, 0x1C, 0xB1, 0xF0, 0x4C, 0x0D,
+ 0x85, 0xF0, 0x58, 0x0D, 0x69, 0x08, 0xF3, 0x10, 0x86, 0xF0, 0x60, 0x0D, 0x4E, 0x1C, 0x89, 0x48,
+ 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4,
+ 0xFF, 0x7F, 0x30, 0x56, 0x00, 0x5C, 0x00, 0x16, 0x00, 0xF6, 0x00, 0x01, 0x00, 0x57, 0x00, 0x57,
+ 0x03, 0x58, 0x00, 0xDC, 0x18, 0xF4, 0x00, 0x80, 0x30, 0x56, 0x00, 0x5C, 0x00, 0x16, 0x00, 0xF6,
+ 0x00, 0x01, 0x00, 0x57, 0x00, 0x57, 0x03, 0x58, 0x00, 0xDC, 0x0B, 0x58, 0x00, 0x16, 0x03, 0xF6,
+ 0x24, 0x01, 0x00, 0xF2, 0x54, 0x0A, 0x03, 0xF6, 0xB6, 0x00, 0x00, 0xF2, 0x54, 0x0A, 0x00, 0x16,
+ 0x02, 0xEC, 0xB8, 0x00, 0x02, 0x49, 0x18, 0xF4, 0xFF, 0x00, 0x00, 0x54, 0x00, 0x54, 0x00, 0x54,
+ 0x00, 0xF4, 0x08, 0x00, 0xE1, 0x18, 0x80, 0x54, 0x03, 0x58, 0x00, 0xDD, 0x01, 0xDD, 0x02, 0xDD,
+ 0x03, 0xDC, 0x02, 0x4B, 0x30, 0x50, 0xB2, 0x50, 0x34, 0x51, 0xB6, 0x51, 0x00, 0x16, 0x45, 0x5A,
+ 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56, 0x05, 0xF4, 0x02, 0x12, 0x83, 0x5A,
+ 0x00, 0x16, 0x1D, 0xF4, 0xFF, 0x00, 0x85, 0x56, 0x85, 0x56, 0x85, 0x56, 0x05, 0xF4, 0x00, 0x12,
+ 0x83, 0x5A, 0x00, 0x16, 0x38, 0x54, 0xBB, 0x55, 0x3C, 0x56, 0xBD, 0x56, 0x00, 0xF2, 0x0E, 0x11,
+ 0x85, 0xF0, 0x7E, 0x0E, 0xE9, 0x09, 0xC1, 0x59, 0x00, 0xF2, 0x0E, 0x11, 0x85, 0xF0, 0x7E, 0x0E,
+ 0xE8, 0x0A, 0x83, 0x55, 0x83, 0x55, 0x4B, 0xF4, 0x90, 0x01, 0x5C, 0xF0, 0x32, 0x0E, 0xBD, 0x56,
+ 0x40, 0x10, 0x4B, 0xF4, 0x30, 0x00, 0x59, 0xF0, 0x44, 0x0E, 0x01, 0xF6, 0x0C, 0x00, 0x00, 0xF6,
+ 0x01, 0x00, 0x2E, 0x10, 0x02, 0xFC, 0x9C, 0x00, 0x9A, 0x57, 0x14, 0x13, 0x4B, 0xF4, 0x64, 0x00,
+ 0x59, 0xF0, 0x60, 0x0E, 0x03, 0xF6, 0x64, 0x00, 0x01, 0xF6, 0x19, 0x00, 0x00, 0xF6, 0x01, 0x00,
+ 0x43, 0xF4, 0x33, 0x00, 0x56, 0xF0, 0x72, 0x0E, 0x04, 0xF4, 0x00, 0x01, 0x43, 0xF4, 0x19, 0x00,
+ 0xF3, 0x10, 0xB4, 0x56, 0xC3, 0x58, 0x02, 0xFC, 0x9E, 0x00, 0x9A, 0x57, 0x08, 0x13, 0x3C, 0x56,
+ 0x00, 0xF6, 0x02, 0x00, 0x00, 0x16, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11,
+ 0x86, 0xF0, 0xB4, 0x0E, 0x09, 0xE7, 0x02, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xB4, 0x0E,
+ 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xB4, 0x0E, 0x4E, 0x1C, 0x89, 0x49,
+ 0x00, 0xF2, 0x0E, 0x11, 0x00, 0x16, 0x09, 0xE7, 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0,
+ 0xEE, 0x0E, 0x09, 0xE7, 0x03, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xEE, 0x0E, 0x09, 0xE7,
+ 0x01, 0x00, 0x00, 0xF2, 0x0E, 0x11, 0x86, 0xF0, 0xEE, 0x0E, 0x89, 0x49, 0x00, 0xF2, 0x0E, 0x11,
+ 0x86, 0xF0, 0xEE, 0x0E, 0x4E, 0x1C, 0x89, 0x4A, 0x00, 0xF2, 0x0E, 0x11, 0x00, 0x16, 0x3C, 0x56,
+ 0x00, 0x16, 0x00, 0xEC, 0x26, 0x01, 0x48, 0xE4, 0x01, 0x00, 0x1E, 0x13, 0x38, 0x44, 0x00, 0xEA,
+ 0x26, 0x01, 0x49, 0xF4, 0x00, 0x00, 0x04, 0x12, 0x4E, 0x1C, 0x02, 0x10, 0x4C, 0x1C, 0x01, 0xEC,
+ 0x27, 0x01, 0x89, 0x48, 0x00, 0xF2, 0x0E, 0x11, 0x02, 0x14, 0x00, 0x16, 0x85, 0xF0, 0x4E, 0x0F,
+ 0x38, 0x54, 0x00, 0xEA, 0x99, 0x00, 0x00, 0xF2, 0x5C, 0x0B, 0x02, 0x80, 0x48, 0xE4, 0x06, 0x00,
+ 0x1C, 0x13, 0x00, 0xEC, 0x99, 0x00, 0x48, 0xE4, 0x01, 0x00, 0x0A, 0x12, 0x04, 0x80, 0x30, 0xE4,
+ 0x01, 0x00, 0x04, 0x40, 0x08, 0x10, 0x04, 0x80, 0x18, 0xE4, 0xFE, 0x00, 0x04, 0x40, 0x00, 0x16,
+ 0x02, 0xF6, 0xE0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x01, 0xCC, 0x81, 0x48, 0x22, 0x12, 0x00, 0x4E,
+ 0x83, 0x5A, 0x90, 0x4C, 0x20, 0xE7, 0x00, 0x00, 0xC3, 0x58, 0x1B, 0xF4, 0xFF, 0x00, 0x83, 0x55,
+ 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12, 0x8B, 0x55, 0x83, 0x59, 0x00, 0x4E, 0x00, 0x16,
+ 0x00, 0x4E, 0x02, 0xF6, 0xF0, 0x00, 0x02, 0x57, 0x03, 0x59, 0x00, 0x4E, 0x83, 0x5A, 0x30, 0xE7,
+ 0x00, 0x00, 0x20, 0xE7, 0x00, 0x00, 0x00, 0x16, 0x02, 0xF6, 0xF0, 0x00, 0x02, 0x57, 0x03, 0x59,
+ 0x01, 0xCC, 0x00, 0x4E, 0x83, 0x5A, 0x30, 0xE7, 0x00, 0x00, 0x80, 0x4C, 0xC3, 0x58, 0x1B, 0xF4,
+ 0xFF, 0x00, 0x83, 0x55, 0x83, 0x55, 0x83, 0x55, 0x03, 0xF4, 0x00, 0x12, 0x83, 0x59, 0x00, 0x4E,
+ 0x00, 0x16, 0x03, 0xF6, 0xE0, 0x00, 0x03, 0x57, 0x83, 0x59, 0x3A, 0x55, 0x02, 0xCC, 0x45, 0x5A,
+ 0x00, 0xF2, 0xF2, 0x0D, 0xC0, 0x5A, 0x40, 0x5C, 0x38, 0x54, 0x00, 0xCD, 0x01, 0xCC, 0x4A, 0x46,
+ 0x0A, 0x13, 0x83, 0x59, 0x00, 0x4C, 0x01, 0x48, 0x16, 0x13, 0x0C, 0x10, 0xC5, 0x58, 0x00, 0xF2,
+ 0xF2, 0x0D, 0x00, 0x4C, 0x01, 0x48, 0x08, 0x13, 0x05, 0xF6, 0xF0, 0x00, 0x05, 0x57, 0x08, 0x10,
+ 0x45, 0x58, 0x00, 0xF2, 0xF2, 0x0D, 0x8D, 0x56, 0x83, 0x5A, 0x80, 0x4C, 0x05, 0x17, 0x00, 0x16,
+ 0x02, 0x4B, 0x06, 0xF7, 0x04, 0x00, 0x62, 0x0B, 0x03, 0x82, 0x00, 0xF2, 0xDE, 0x0D, 0x02, 0x80,
+ 0x00, 0x4C, 0x45, 0xF4, 0x02, 0x00, 0x52, 0x14, 0x06, 0xF7, 0x02, 0x00, 0x06, 0x14, 0x00, 0xF2,
+ 0x50, 0x0F, 0x00, 0x16, 0x02, 0x4B, 0x01, 0xF6, 0xFF, 0x00, 0x38, 0x1C, 0x05, 0xF4, 0x04, 0x00,
+ 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x1D, 0xF7, 0x3C, 0x00, 0xB8, 0xF0, 0x4A, 0x10, 0x9C, 0x14,
+ 0x01, 0x48, 0x1C, 0x13, 0x0E, 0xF7, 0x3C, 0x00, 0x03, 0xF7, 0x04, 0x00, 0xAF, 0x19, 0x03, 0x42,
+ 0x45, 0xF4, 0x02, 0x00, 0x83, 0x5A, 0x02, 0xCC, 0x02, 0x41, 0x45, 0xF4, 0x02, 0x00, 0x00, 0x16,
+ 0x91, 0x44, 0xD5, 0xF0, 0x3A, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x01, 0xF6, 0xFF, 0x00, 0x38, 0x1C,
+ 0x05, 0xF4, 0x04, 0x00, 0x83, 0x5A, 0x18, 0xDF, 0x19, 0xDF, 0x0E, 0xF7, 0x3C, 0x00, 0x03, 0xF7,
+ 0x04, 0x00, 0x0F, 0x79, 0x1C, 0xF7, 0x3C, 0x00, 0xB8, 0xF0, 0x98, 0x10, 0x4E, 0x14, 0x01, 0x48,
+ 0x06, 0x13, 0x45, 0xF4, 0x04, 0x00, 0x00, 0x16, 0x91, 0x44, 0xD5, 0xF0, 0x7E, 0x10, 0x00, 0xF0,
+ 0x9E, 0x02, 0x02, 0xF6, 0xFF, 0x00, 0x38, 0x1C, 0x2C, 0xBC, 0xAE, 0xBC, 0xE2, 0x08, 0x00, 0xEC,
+ 0xB8, 0x00, 0x02, 0x48, 0x1D, 0xF7, 0x80, 0x00, 0xB8, 0xF0, 0xC8, 0x10, 0x1E, 0x14, 0x01, 0x48,
+ 0x0E, 0x13, 0x0E, 0xF7, 0x80, 0x00, 0x38, 0x54, 0x03, 0x58, 0xAF, 0x19, 0x82, 0x48, 0x00, 0x16,
+ 0x82, 0x48, 0x12, 0x45, 0xD5, 0xF0, 0xB6, 0x10, 0x00, 0xF0, 0x9E, 0x02, 0x39, 0xF0, 0xF4, 0x10,
+ 0x38, 0x44, 0x00, 0x16, 0x7E, 0x18, 0x18, 0xF4, 0x03, 0x00, 0x04, 0x13, 0x61, 0x18, 0x00, 0x16,
+ 0x38, 0x1C, 0x00, 0xFC, 0x22, 0x01, 0x18, 0xF4, 0x01, 0x00, 0xF1, 0x12, 0xE3, 0x10, 0x30, 0x44,
+ 0x30, 0x44, 0x30, 0x44, 0xB1, 0xF0, 0x14, 0x11, 0x00, 0x16, 0x3E, 0x57, 0x03, 0xF6, 0xE0, 0x00,
+ 0x03, 0x57, 0x83, 0x59, 0x04, 0xCC, 0x01, 0x4A, 0x6A, 0x12, 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D,
+ 0x02, 0x4B, 0x70, 0x14, 0x34, 0x13, 0x02, 0x80, 0x48, 0xE4, 0x08, 0x00, 0x18, 0x12, 0x9C, 0xE7,
+ 0x02, 0x00, 0x9E, 0xE7, 0x15, 0x00, 0x00, 0xF2, 0xC2, 0x0F, 0x00, 0xF2, 0x76, 0x0A, 0x1E, 0x1C,
+ 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x30, 0xE4, 0x10, 0x00, 0x04, 0x40, 0x00, 0xF2, 0xDE, 0x0D,
+ 0x20, 0xE7, 0x01, 0x00, 0x01, 0xF6, 0x01, 0x00, 0x00, 0x16, 0x04, 0xDC, 0x01, 0x4A, 0x24, 0x12,
+ 0x45, 0x5A, 0x00, 0xF2, 0xF2, 0x0D, 0x43, 0x5B, 0x06, 0xEC, 0x98, 0x00, 0x00, 0xF2, 0x34, 0x10,
+ 0xC6, 0x59, 0x20, 0x14, 0x0A, 0x13, 0x00, 0xF2, 0xC2, 0x0F, 0x00, 0xF2, 0x10, 0x10, 0xA7, 0x10,
+ 0x83, 0x5A, 0xD7, 0x10, 0x0E, 0x47, 0x07, 0xE6, 0x10, 0x00, 0xCE, 0x47, 0x5A, 0xF0, 0x1C, 0x11,
+ 0xB9, 0x54, 0x00, 0x16, 0x14, 0x90, 0x96, 0x90, 0x02, 0xFC, 0xA8, 0x00, 0x03, 0xFC, 0xAA, 0x00,
+ 0x48, 0x55, 0x02, 0x13, 0xC9, 0x55, 0x00, 0x16, 0x00, 0xEC, 0xBA, 0x00, 0x10, 0x44, 0x00, 0xEA,
+ 0xBA, 0x00, 0x00, 0x16, 0x03, 0xF6, 0xC0, 0x00, 0x00, 0xF2, 0x64, 0x0A, 0x10, 0x44, 0x00, 0x4C,
+ 0x00, 0x16 };
+
+unsigned short _adv_mcode_size ASC_INITDATA =
+ sizeof(_adv_mcode_buf); /* 0x11D2 */
+unsigned long _adv_mcode_chksum ASC_INITDATA = 0x0347D07AUL;
+
+/* a_init.c */
+/*
+ * EEPROM Configuration.
+ *
+ * All drivers should use this structure to set the default EEPROM
+ * configuration. The BIOS now uses this structure when it is built.
+ * Additional structure information can be found in a_condor.h where
+ * the structure is defined.
+ */
+STATIC ADVEEP_CONFIG
+Default_EEPROM_Config ASC_INITDATA = {
+ ADV_EEPROM_BIOS_ENABLE, /* cfg_msw */
+ 0x0000, /* cfg_lsw */
+ 0xFFFF, /* disc_enable */
+ 0xFFFF, /* wdtr_able */
+ 0xFFFF, /* sdtr_able */
+ 0xFFFF, /* start_motor */
+ 0xFFFF, /* tagqng_able */
+ 0xFFFF, /* bios_scan */
+ 0, /* scam_tolerant */
+ 7, /* adapter_scsi_id */
+ 0, /* bios_boot_delay */
+ 3, /* scsi_reset_delay */
+ 0, /* bios_id_lun */
+ 0, /* termination */
+ 0, /* reserved1 */
+ 0xFFEF, /* bios_ctrl */
+ 0xFFFF, /* ultra_able */
+ 0, /* reserved2 */
+ ASC_DEF_MAX_HOST_QNG, /* max_host_qng */
+ ASC_DEF_MAX_DVC_QNG, /* max_dvc_qng */
+ 0, /* dvc_cntl */
+ 0, /* bug_fix */
+ 0, /* serial_number_word1 */
+ 0, /* serial_number_word2 */
+ 0, /* serial_number_word3 */
+ 0, /* check_sum */
+ { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 }, /* oem_name[16] */
+ 0, /* dvc_err_code */
+ 0, /* adv_err_code */
+ 0, /* adv_err_addr */
+ 0, /* saved_dvc_err_code */
+ 0, /* saved_adv_err_code */
+ 0, /* saved_adv_err_addr */
+ 0 /* num_of_err */
+};
+
+/*
+ * Initialize the ADV_DVC_VAR structure.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ */
+ASC_INITFUNC(
+int
+AdvInitGetConfig(ADV_DVC_VAR *asc_dvc)
+)
+{
+ ushort warn_code;
+ AdvPortAddr iop_base;
+ uchar pci_cmd_reg;
+ int status;
+
+ warn_code = 0;
+ asc_dvc->err_code = 0;
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * PCI Command Register
+ */
+
+ if (((pci_cmd_reg = DvcAdvReadPCIConfigByte(asc_dvc,
+ AscPCIConfigCommandRegister))
+ & AscPCICmdRegBits_BusMastering)
+ != AscPCICmdRegBits_BusMastering)
+ {
+ pci_cmd_reg |= AscPCICmdRegBits_BusMastering;
+
+ DvcAdvWritePCIConfigByte(asc_dvc,
+ AscPCIConfigCommandRegister, pci_cmd_reg);
+
+ if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister))
+ & AscPCICmdRegBits_BusMastering)
+ != AscPCICmdRegBits_BusMastering)
+ {
+ warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+ }
+
+ /*
+ * PCI Latency Timer
+ *
+ * If the "latency timer" register is 0x20 or above, then we don't need
+ * to change it. Otherwise, set it to 0x20 (i.e. set it to 0x20 if it
+ * comes up less than 0x20).
+ */
+ if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20) {
+ DvcAdvWritePCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer, 0x20);
+ if (DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigLatencyTimer) < 0x20)
+ {
+ warn_code |= ASC_WARN_SET_PCI_CONFIG_SPACE;
+ }
+ }
+
+ /*
+ * Save the state of the PCI Configuration Command Register
+ * "Parity Error Response Control" Bit. If the bit is clear (0),
+ * in AdvInitAsc3550Driver() tell the microcode to ignore DMA
+ * parity errors.
+ */
+ asc_dvc->cfg->control_flag = 0;
+ if (((DvcAdvReadPCIConfigByte(asc_dvc, AscPCIConfigCommandRegister)
+ & AscPCICmdRegBits_ParErrRespCtrl)) == 0)
+ {
+ asc_dvc->cfg->control_flag |= CONTROL_FLAG_IGNORE_PERR;
+ }
+
+ asc_dvc->cur_host_qng = 0;
+
+ asc_dvc->cfg->lib_version = (ADV_LIB_VERSION_MAJOR << 8) |
+ ADV_LIB_VERSION_MINOR;
+ asc_dvc->cfg->chip_version =
+ AdvGetChipVersion(iop_base, asc_dvc->bus_type);
+
+ /*
+ * Reset the chip to start and allow register writes.
+ */
+ if (AdvFindSignature(iop_base) == 0)
+ {
+ asc_dvc->err_code = ASC_IERR_BAD_SIGNATURE;
+ return ADV_ERROR;
+ }
+ else {
+
+ AdvResetChip(asc_dvc);
+
+ if ((status = AdvInitFromEEP(asc_dvc)) == ADV_ERROR)
+ {
+ return ADV_ERROR;
+ }
+ warn_code |= status;
+
+ /*
+ * Reset the SCSI Bus if the EEPROM indicates that SCSI Bus
+ * Resets should be performed.
+ */
+ if (asc_dvc->bios_ctrl & BIOS_CTRL_RESET_SCSI_BUS)
+ {
+ AdvResetSCSIBus(asc_dvc);
+ }
+ }
+
+ return warn_code;
+}
+
+/*
+ * Initialize the ASC3550.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ */
+ASC_INITFUNC(
+int
+AdvInitAsc3550Driver(ADV_DVC_VAR *asc_dvc)
+)
+{
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ ulong sum;
+ int begin_addr;
+ int end_addr;
+ int code_sum;
+ int word;
+ int rql_addr; /* RISC Queue List address */
+ int i;
+ ushort scsi_cfg1;
+ uchar biosmem[ASC_MC_BIOSLEN]; /* BIOS RISC Memory 0x40-0x8F. */
+
+ /* If there is already an error, don't continue. */
+ if (asc_dvc->err_code != 0)
+ {
+ return ADV_ERROR;
+ }
+
+ warn_code = 0;
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Save the RISC memory BIOS region before writing the microcode.
+ * The BIOS may already be loaded and using its RISC LRAM region
+ * so its region must be saved and restored.
+ *
+ * Note: This code makes the assumption, which is currently true,
+ * that a chip reset does not clear RISC LRAM.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN; i++)
+ {
+ AdvReadByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]);
+ }
+
+ /*
+ * Load the Microcode
+ *
+ * Write the microcode image to RISC memory starting at address 0.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+ for (word = 0; word < _adv_mcode_size; word += 2)
+ {
+ AdvWriteWordAutoIncLram(iop_base,
+ *((ushort *) (&_adv_mcode_buf[word])));
+ }
+
+ /*
+ * Clear the rest of Condor's Internal RAM (8KB).
+ */
+ for (; word < ADV_CONDOR_MEMSIZE; word += 2)
+ {
+ AdvWriteWordAutoIncLram(iop_base, 0);
+ }
+
+ /*
+ * Verify the microcode checksum.
+ */
+ sum = 0;
+ AdvWriteWordRegister(iop_base, IOPW_RAM_ADDR, 0);
+ for (word = 0; word < _adv_mcode_size; word += 2)
+ {
+ sum += AdvReadWordAutoIncLram(iop_base);
+ }
+
+ if (sum != _adv_mcode_chksum)
+ {
+ asc_dvc->err_code |= ASC_IERR_MCODE_CHKSUM;
+ return ADV_ERROR;
+ }
+
+ /*
+ * Restore the RISC memory BIOS region.
+ */
+ for (i = 0; i < ASC_MC_BIOSLEN; i++)
+ {
+ AdvWriteByteLram(iop_base, ASC_MC_BIOSMEM + i, biosmem[i]);
+ }
+
+ /*
+ * Calculate and write the microcode code checksum to the microcode
+ * code checksum location ASC_MC_CODE_CHK_SUM (0x2C).
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, begin_addr);
+ AdvReadWordLram(iop_base, ASC_MC_CODE_END_ADDR, end_addr);
+ code_sum = 0;
+ for (word = begin_addr; word < end_addr; word += 2)
+ {
+ code_sum += *((ushort *) (&_adv_mcode_buf[word]));
+ }
+ AdvWriteWordLram(iop_base, ASC_MC_CODE_CHK_SUM, code_sum);
+
+ /*
+ * Read microcode version and date.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_DATE, asc_dvc->cfg->mcode_date);
+ AdvReadWordLram(iop_base, ASC_MC_VERSION_NUM, asc_dvc->cfg->mcode_version);
+
+ /*
+ * Initialize microcode operating variables
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_ADAPTER_SCSI_ID,
+ asc_dvc->chip_scsi_id);
+
+ /*
+ * If the PCI Configuration Command Register "Parity Error Response
+ * Control" Bit was clear (0), then set the microcode variable
+ * 'control_flag' CONTROL_FLAG_IGNORE_PERR flag to tell the microcode
+ * to ignore DMA parity errors.
+ */
+ if (asc_dvc->cfg->control_flag & CONTROL_FLAG_IGNORE_PERR)
+ {
+ /*
+ * Note: Don't remove the use of a temporary variable in
+ * the following code, otherwise the Microsoft C compiler
+ * will turn the following lines into a no-op.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ word |= CONTROL_FLAG_IGNORE_PERR;
+ AdvWriteWordLram(iop_base, ASC_MC_CONTROL_FLAG, word);
+ }
+
+ /*
+ * Set default microcode operating variables for WDTR, SDTR, and
+ * command tag queuing based on the EEPROM configuration values.
+ *
+ * These ADV_DVC_VAR fields and the microcode variables will be
+ * changed in AdvInquiryHandling() if it is found a device is
+ * incapable of a particular feature.
+ */
+
+ /*
+ * Set the microcode ULTRA target mask from EEPROM value. The
+ * SDTR target mask overrides the ULTRA target mask in the
+ * microcode so it is safe to set this value without determining
+ * whether the device supports SDTR.
+ *
+ * Note: There is no way to know whether a device supports ULTRA
+ * speed without attempting a SDTR ULTRA speed negotiation with
+ * the device. The device will reject the speed if it does not
+ * support it by responding with an SDTR message containing a
+ * slower speed.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_ULTRA_ABLE, asc_dvc->ultra_able);
+ AdvWriteWordLram(iop_base, ASC_MC_DISC_ENABLE, asc_dvc->cfg->disc_enable);
+
+
+ /*
+ * Set SCSI_CFG0 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG0 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG0,
+ PARITY_EN | SEL_TMO_LONG | OUR_ID_EN | asc_dvc->chip_scsi_id);
+
+ /*
+ * Determine SCSI_CFG1 Microcode Default Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+
+ /* Read current SCSI_CFG1 Register value. */
+ scsi_cfg1 = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+
+ /*
+ * If all three connectors are in use, return an error.
+ */
+ if ((scsi_cfg1 & CABLE_ILLEGAL_A) == 0 ||
+ (scsi_cfg1 & CABLE_ILLEGAL_B) == 0)
+ {
+ asc_dvc->err_code |= ASC_IERR_ILLEGAL_CONNECTION;
+ return ADV_ERROR;
+ }
+
+ /*
+ * If the internal narrow cable is reversed all of the SCSI_CTRL
+ * register signals will be set. Check for and return an error if
+ * this condition is found.
+ */
+ if ((AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL) & 0x3F07) == 0x3F07)
+ {
+ asc_dvc->err_code |= ASC_IERR_REVERSED_CABLE;
+ return ADV_ERROR;
+ }
+
+ /*
+ * If this is a differential board and a single-ended device
+ * is attached to one of the connectors, return an error.
+ */
+ if ((scsi_cfg1 & DIFF_MODE) && (scsi_cfg1 & DIFF_SENSE) == 0)
+ {
+ asc_dvc->err_code |= ASC_IERR_SINGLE_END_DEVICE;
+ return ADV_ERROR;
+ }
+
+ /*
+ * If automatic termination control is enabled, then set the
+ * termination value based on a table listed in a_condor.h.
+ *
+ * If manual termination was specified with an EEPROM setting
+ * then 'termination' was set-up in AdvInitFromEEP() and
+ * is ready to be 'ored' into SCSI_CFG1.
+ */
+ if (asc_dvc->cfg->termination == 0)
+ {
+ /*
+ * The software always controls termination by setting TERM_CTL_SEL.
+ * If TERM_CTL_SEL were set to 0, the hardware would set termination.
+ */
+ asc_dvc->cfg->termination |= TERM_CTL_SEL;
+
+ switch(scsi_cfg1 & CABLE_DETECT)
+ {
+ /* TERM_CTL_H: on, TERM_CTL_L: on */
+ case 0x3: case 0x7: case 0xB: case 0xD: case 0xE: case 0xF:
+ asc_dvc->cfg->termination |= (TERM_CTL_H | TERM_CTL_L);
+ break;
+
+ /* TERM_CTL_H: on, TERM_CTL_L: off */
+ case 0x1: case 0x5: case 0x9: case 0xA: case 0xC:
+ asc_dvc->cfg->termination |= TERM_CTL_H;
+ break;
+
+ /* TERM_CTL_H: off, TERM_CTL_L: off */
+ case 0x2: case 0x6:
+ break;
+ }
+ }
+
+ /*
+ * Clear any set TERM_CTL_H and TERM_CTL_L bits.
+ */
+ scsi_cfg1 &= ~TERM_CTL;
+
+ /*
+ * Invert the TERM_CTL_H and TERM_CTL_L bits and then
+ * set 'scsi_cfg1'. The TERM_POL bit does not need to be
+ * referenced, because the hardware internally inverts
+ * the Termination High and Low bits if TERM_POL is set.
+ */
+ scsi_cfg1 |= (TERM_CTL_SEL | (~asc_dvc->cfg->termination & TERM_CTL));
+
+ /*
+ * Set SCSI_CFG1 Microcode Default Value
+ *
+ * Set filter value and possibly modified termination control
+ * bits in the Microcode SCSI_CFG1 Register Value.
+ *
+ * The microcode will set the SCSI_CFG1 register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SCSI_CFG1,
+ FLTR_11_TO_20NS | scsi_cfg1);
+
+ /*
+ * Set SEL_MASK Microcode Default Value
+ *
+ * The microcode will set the SEL_MASK register using this value
+ * after it is started below.
+ */
+ AdvWriteWordLram(iop_base, ASC_MC_DEFAULT_SEL_MASK,
+ ADV_TID_TO_TIDMASK(asc_dvc->chip_scsi_id));
+
+ /*
+ * Link all the RISC Queue Lists together in a doubly-linked
+ * NULL terminated list.
+ *
+ * Skip the NULL (0) queue which is not used.
+ */
+ for (i = 1, rql_addr = ASC_MC_RISC_Q_LIST_BASE + ASC_MC_RISC_Q_LIST_SIZE;
+ i < ASC_MC_RISC_Q_TOTAL_CNT;
+ i++, rql_addr += ASC_MC_RISC_Q_LIST_SIZE)
+ {
+ /*
+ * Set the current RISC Queue List's RQL_FWD and RQL_BWD pointers
+ * in a one word write and set the state (RQL_STATE) to free.
+ */
+ AdvWriteWordLram(iop_base, rql_addr, ((i + 1) + ((i - 1) << 8)));
+ AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+ }
+
+ /*
+ * Set the Host and RISC Queue List pointers.
+ *
+ * Both sets of pointers are initialized with the same values:
+ * ASC_MC_RISC_Q_FIRST(0x01) and ASC_MC_RISC_Q_LAST (0xFF).
+ */
+ AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, ASC_MC_RISC_Q_FIRST);
+ AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, ASC_MC_RISC_Q_LAST);
+
+ AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_READY, ASC_MC_RISC_Q_FIRST);
+ AdvWriteByteLram(iop_base, ASC_MC_RISC_NEXT_DONE, ASC_MC_RISC_Q_LAST);
+
+ /*
+ * Finally, set up the last RISC Queue List (255) with
+ * a NULL forward pointer.
+ */
+ AdvWriteWordLram(iop_base, rql_addr, (ASC_MC_NULL_Q + ((i - 1) << 8)));
+ AdvWriteByteLram(iop_base, rql_addr + RQL_STATE, ASC_MC_QS_FREE);
+
+ AdvWriteByteRegister(iop_base, IOPB_INTR_ENABLES,
+ (ADV_INTR_ENABLE_HOST_INTR | ADV_INTR_ENABLE_GLOBAL_INTR));
+
+ /*
+ * Note: Don't remove the use of a temporary variable in
+ * the following code, otherwise the Microsoft C compiler
+ * will turn the following lines into a no-op.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_CODE_BEGIN_ADDR, word);
+ AdvWriteWordRegister(iop_base, IOPW_PC, word);
+
+ /* finally, finally, gentlemen, start your engine */
+ AdvWriteWordRegister(iop_base, IOPW_RISC_CSR, ADV_RISC_CSR_RUN);
+
+ return warn_code;
+}
+
+/*
+ * Read the board's EEPROM configuration. Set fields in ADV_DVC_VAR and
+ * ADV_DVC_CFG based on the EEPROM settings. The chip is stopped while
+ * all of this is done.
+ *
+ * On failure set the ADV_DVC_VAR field 'err_code' and return ADV_ERROR.
+ *
+ * For a non-fatal error return a warning code. If there are no warnings
+ * then 0 is returned.
+ *
+ * Note: Chip is stopped on entry.
+ */
+ASC_INITFUNC(
+STATIC int
+AdvInitFromEEP(ADV_DVC_VAR *asc_dvc)
+)
+{
+ AdvPortAddr iop_base;
+ ushort warn_code;
+ ADVEEP_CONFIG eep_config;
+ int i;
+
+ iop_base = asc_dvc->iop_base;
+
+ warn_code = 0;
+
+ /*
+ * Read the board's EEPROM configuration.
+ *
+ * Set default values if a bad checksum is found.
+ */
+ if (AdvGetEEPConfig(iop_base, &eep_config) != eep_config.check_sum)
+ {
+ warn_code |= ASC_WARN_EEPROM_CHKSUM;
+
+ /*
+ * Set EEPROM default values.
+ */
+ for (i = 0; i < sizeof(ADVEEP_CONFIG); i++)
+ {
+ *((uchar *) &eep_config + i) =
+ *((uchar *) &Default_EEPROM_Config + i);
+ }
+
+ /*
+ * Assume the 6 byte board serial number that was read
+ * from EEPROM is correct even if the EEPROM checksum
+ * failed.
+ */
+ eep_config.serial_number_word3 =
+ AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 1);
+ eep_config.serial_number_word2 =
+ AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 2);
+ eep_config.serial_number_word1 =
+ AdvReadEEPWord(iop_base, ASC_EEP_DVC_CFG_END - 3);
+ AdvSetEEPConfig(iop_base, &eep_config);
+ }
+
+ /*
+ * Set ADV_DVC_VAR and ADV_DVC_CFG variables from the
+ * EEPROM configuration that was read.
+ *
+ * This is the mapping of EEPROM fields to Adv Library fields.
+ */
+ asc_dvc->wdtr_able = eep_config.wdtr_able;
+ asc_dvc->sdtr_able = eep_config.sdtr_able;
+ asc_dvc->ultra_able = eep_config.ultra_able;
+ asc_dvc->tagqng_able = eep_config.tagqng_able;
+ asc_dvc->cfg->disc_enable = eep_config.disc_enable;
+ asc_dvc->max_host_qng = eep_config.max_host_qng;
+ asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+ asc_dvc->chip_scsi_id = (eep_config.adapter_scsi_id & ADV_MAX_TID);
+ asc_dvc->start_motor = eep_config.start_motor;
+ asc_dvc->scsi_reset_wait = eep_config.scsi_reset_delay;
+ asc_dvc->cfg->bios_boot_wait = eep_config.bios_boot_delay;
+ asc_dvc->bios_ctrl = eep_config.bios_ctrl;
+ asc_dvc->no_scam = eep_config.scam_tolerant;
+ asc_dvc->cfg->serial1 = eep_config.serial_number_word1;
+ asc_dvc->cfg->serial2 = eep_config.serial_number_word2;
+ asc_dvc->cfg->serial3 = eep_config.serial_number_word3;
+
+ /*
+ * Set the host maximum queuing (max. 253, min. 16) and the per device
+ * maximum queuing (max. 63, min. 4).
+ */
+ if (eep_config.max_host_qng > ASC_DEF_MAX_HOST_QNG)
+ {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else if (eep_config.max_host_qng < ASC_DEF_MIN_HOST_QNG)
+ {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_host_qng == 0)
+ {
+ eep_config.max_host_qng = ASC_DEF_MAX_HOST_QNG;
+ } else
+ {
+ eep_config.max_host_qng = ASC_DEF_MIN_HOST_QNG;
+ }
+ }
+
+ if (eep_config.max_dvc_qng > ASC_DEF_MAX_DVC_QNG)
+ {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else if (eep_config.max_dvc_qng < ASC_DEF_MIN_DVC_QNG)
+ {
+ /* If the value is zero, assume it is uninitialized. */
+ if (eep_config.max_dvc_qng == 0)
+ {
+ eep_config.max_dvc_qng = ASC_DEF_MAX_DVC_QNG;
+ } else
+ {
+ eep_config.max_dvc_qng = ASC_DEF_MIN_DVC_QNG;
+ }
+ }
+
+ /*
+ * If 'max_dvc_qng' is greater than 'max_host_qng', then
+ * set 'max_dvc_qng' to 'max_host_qng'.
+ */
+ if (eep_config.max_dvc_qng > eep_config.max_host_qng)
+ {
+ eep_config.max_dvc_qng = eep_config.max_host_qng;
+ }
+
+ /*
+ * Set ADV_DVC_VAR 'max_host_qng' and ADV_DVC_CFG 'max_dvc_qng'
+ * values based on possibly adjusted EEPROM values.
+ */
+ asc_dvc->max_host_qng = eep_config.max_host_qng;
+ asc_dvc->max_dvc_qng = eep_config.max_dvc_qng;
+
+
+ /*
+ * If the EEPROM 'termination' field is set to automatic (0), then set
+ * the ADV_DVC_CFG 'termination' field to automatic also.
+ *
+ * If the termination is specified with a non-zero 'termination'
+ * value check that a legal value is set and set the ADV_DVC_CFG
+ * 'termination' field appropriately.
+ */
+ if (eep_config.termination == 0)
+ {
+ asc_dvc->cfg->termination = 0; /* auto termination */
+ } else
+ {
+ /* Enable manual control with low off / high off. */
+ if (eep_config.termination == 1)
+ {
+ asc_dvc->cfg->termination = TERM_CTL_SEL;
+
+ /* Enable manual control with low off / high on. */
+ } else if (eep_config.termination == 2)
+ {
+ asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H;
+
+ /* Enable manual control with low on / high on. */
+ } else if (eep_config.termination == 3)
+ {
+ asc_dvc->cfg->termination = TERM_CTL_SEL | TERM_CTL_H | TERM_CTL_L;
+ } else
+ {
+ /*
+ * The EEPROM 'termination' field contains a bad value. Use
+ * automatic termination instead.
+ */
+ asc_dvc->cfg->termination = 0;
+ warn_code |= ASC_WARN_EEPROM_TERMINATION;
+ }
+ }
+
+ return warn_code;
+}
+
+/*
+ * Read EEPROM configuration into the specified buffer.
+ *
+ * Return a checksum based on the EEPROM configuration read.
+ */
+ASC_INITFUNC(
+STATIC ushort
+AdvGetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
+)
+{
+ ushort wval, chksum;
+ ushort *wbuf;
+ int eep_addr;
+
+ wbuf = (ushort *) cfg_buf;
+ chksum = 0;
+
+ for (eep_addr = ASC_EEP_DVC_CFG_BEGIN;
+ eep_addr < ASC_EEP_DVC_CFG_END;
+ eep_addr++, wbuf++)
+ {
+ wval = AdvReadEEPWord(iop_base, eep_addr);
+ chksum += wval;
+ *wbuf = wval;
+ }
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ wbuf++;
+ for (eep_addr = ASC_EEP_DVC_CTL_BEGIN;
+ eep_addr < ASC_EEP_MAX_WORD_ADDR;
+ eep_addr++, wbuf++)
+ {
+ *wbuf = AdvReadEEPWord(iop_base, eep_addr);
+ }
+ return chksum;
+}
+
+/*
+ * Read the EEPROM from specified location
+ */
+ASC_INITFUNC(
+STATIC ushort
+AdvReadEEPWord(AdvPortAddr iop_base, int eep_word_addr)
+)
+{
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD,
+ ASC_EEP_CMD_READ | eep_word_addr);
+ AdvWaitEEPCmd(iop_base);
+ return AdvReadWordRegister(iop_base, IOPW_EE_DATA);
+}
+
+/*
+ * Wait for EEPROM command to complete
+ */
+ASC_INITFUNC(
+STATIC void
+AdvWaitEEPCmd(AdvPortAddr iop_base)
+)
+{
+ int eep_delay_ms;
+
+ for (eep_delay_ms = 0; eep_delay_ms < ASC_EEP_DELAY_MS; eep_delay_ms++)
+ {
+ if (AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE)
+ {
+ break;
+ }
+ DvcSleepMilliSecond(1);
+ }
+ if ((AdvReadWordRegister(iop_base, IOPW_EE_CMD) & ASC_EEP_CMD_DONE) == 0)
+ {
+ ADV_ASSERT(0);
+ }
+ return;
+}
+
+/*
+ * Write the EEPROM from 'cfg_buf'.
+ */
+ASC_INITFUNC(
+STATIC void
+AdvSetEEPConfig(AdvPortAddr iop_base, ADVEEP_CONFIG *cfg_buf)
+)
+{
+ ushort *wbuf;
+ ushort addr, chksum;
+
+ wbuf = (ushort *) cfg_buf;
+ chksum = 0;
+
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_ABLE);
+ AdvWaitEEPCmd(iop_base);
+
+ /*
+ * Write EEPROM from word 0 to word 15
+ */
+ for (addr = ASC_EEP_DVC_CFG_BEGIN;
+ addr < ASC_EEP_DVC_CFG_END; addr++, wbuf++)
+ {
+ chksum += *wbuf;
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ DvcSleepMilliSecond(ASC_EEP_DELAY_MS);
+ }
+
+ /*
+ * Write EEPROM checksum at word 18
+ */
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, chksum);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ wbuf++; /* skip over check_sum */
+
+ /*
+ * Write EEPROM OEM name at words 19 to 26
+ */
+ for (addr = ASC_EEP_DVC_CTL_BEGIN;
+ addr < ASC_EEP_MAX_WORD_ADDR; addr++, wbuf++)
+ {
+ AdvWriteWordRegister(iop_base, IOPW_EE_DATA, *wbuf);
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE | addr);
+ AdvWaitEEPCmd(iop_base);
+ }
+ AdvWriteWordRegister(iop_base, IOPW_EE_CMD, ASC_EEP_CMD_WRITE_DISABLE);
+ AdvWaitEEPCmd(iop_base);
+ return;
+}
+
+/*
+ * This function resets the chip and SCSI bus
+ *
+ * It is up to the caller to add a delay to let the bus settle after
+ * calling this function.
+ *
+ * The SCSI_CFG0, SCSI_CFG1, and MEM_CFG registers are set-up in
+ * AdvInitAsc3550Driver(). Here when doing a write to one of these
+ * registers read first and then write.
+ *
+ * Note: A SCSI Bus Reset can not be done until after the EEPROM
+ * configuration is read to determine whether SCSI Bus Resets
+ * should be performed.
+ */
+ASC_INITFUNC(
+STATIC void
+AdvResetChip(ADV_DVC_VAR *asc_dvc)
+)
+{
+ AdvPortAddr iop_base;
+ ushort word;
+ uchar byte;
+
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Reset Chip.
+ */
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_RESET);
+ DvcSleepMilliSecond(100);
+ AdvWriteWordRegister(iop_base, IOPW_CTRL_REG, ADV_CTRL_REG_CMD_WR_IO_REG);
+
+ /*
+ * Initialize Chip registers.
+ *
+ * Note: Don't remove the use of a temporary variable in the following
+ * code, otherwise the Microsoft C compiler will turn the following lines
+ * into a no-op.
+ */
+ byte = AdvReadByteRegister(iop_base, IOPB_MEM_CFG);
+ byte |= RAM_SZ_8KB;
+ AdvWriteByteRegister(iop_base, IOPB_MEM_CFG, byte);
+
+ word = AdvReadWordRegister(iop_base, IOPW_SCSI_CFG1);
+ word &= ~BIG_ENDIAN;
+ AdvWriteWordRegister(iop_base, IOPW_SCSI_CFG1, word);
+
+ /*
+ * Setting the START_CTL_EMFU 3:2 bits sets a FIFO threshold
+ * of 128 bytes. This register is only accessible to the host.
+ */
+ AdvWriteByteRegister(iop_base, IOPB_DMA_CFG0,
+ START_CTL_EMFU | READ_CMD_MRM);
+}
+
+/* a_advlib.c */
+/*
+ * Description:
+ * Send a SCSI request to the ASC3550 chip
+ *
+ * If there is no SG list for the request, set 'sg_entry_cnt' to 0.
+ *
+ * If 'sg_real_addr' is non-zero on entry, AscGetSGList() will not be
+ * called. It is assumed the caller has already initialized 'sg_real_addr'.
+ *
+ * Return:
+ * ADV_SUCCESS(1) - the request is in the mailbox
+ * ADV_BUSY(0) - total request count > 253, try later
+ * ADV_ERROR(-1) - invalid scsi request Q
+ */
+STATIC int
+AdvExeScsiQueue(ADV_DVC_VAR *asc_dvc,
+ ADV_SCSI_REQ_Q *scsiq)
+{
+ if (scsiq == (ADV_SCSI_REQ_Q *) 0L)
+ {
+ /* 'scsiq' should never be NULL. */
+ ADV_ASSERT(0);
+ return ADV_ERROR;
+ }
+
+ return AdvSendScsiCmd(asc_dvc, scsiq);
+}
+
+/*
+ * Reset SCSI Bus and purge all outstanding requests.
+ *
+ * Return Value:
+ * ADV_TRUE(1) - All requests are purged and SCSI Bus is reset.
+ *
+ * Note: Should always return ADV_TRUE.
+ */
+STATIC int
+AdvResetSB(ADV_DVC_VAR *asc_dvc)
+{
+ int status;
+
+ status = AdvSendIdleCmd(asc_dvc, (ushort) IDLE_CMD_SCSI_RESET, 0L, 0);
+
+ AdvResetSCSIBus(asc_dvc);
+
+ return status;
+}
+
+/*
+ * Reset SCSI Bus and delay.
+ */
+STATIC void
+AdvResetSCSIBus(ADV_DVC_VAR *asc_dvc)
+{
+ AdvPortAddr iop_base;
+ ushort scsi_ctrl;
+
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * The microcode currently sets the SCSI Bus Reset signal while
+ * handling the AscSendIdleCmd() IDLE_CMD_SCSI_RESET command above.
+ * But the SCSI Bus Reset Hold Time in the microcode is not deterministic
+ * (it may in fact be for less than the SCSI Spec. minimum of 25 us).
+ * Therefore on return the Adv Library sets the SCSI Bus Reset signal
+ * for ASC_SCSI_RESET_HOLD_TIME_US, which is defined to be greater
+ * than 25 us.
+ */
+ scsi_ctrl = AdvReadWordRegister(iop_base, IOPW_SCSI_CTRL);
+ AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL,
+ scsi_ctrl | ADV_SCSI_CTRL_RSTOUT);
+ DvcDelayMicroSecond(asc_dvc, (ushort) ASC_SCSI_RESET_HOLD_TIME_US);
+ AdvWriteWordRegister(iop_base, IOPW_SCSI_CTRL,
+ scsi_ctrl & ~ADV_SCSI_CTRL_RSTOUT);
+
+ DvcSleepMilliSecond((ulong) asc_dvc->scsi_reset_wait * 1000);
+}
+
+
+/*
+ * Adv Library Interrupt Service Routine
+ *
+ * This function is called by a driver's interrupt service routine.
+ * The function disables and re-enables interrupts.
+ *
+ * When a microcode idle command is completed, the ADV_DVC_VAR
+ * 'idle_cmd_done' field is set to ADV_TRUE.
+ *
+ * Note: AdvISR() can be called when interrupts are disabled or even
+ * when there is no hardware interrupt condition present. It will
+ * always check for completed idle commands and microcode requests.
+ * This is an important feature that shouldn't be changed because it
+ * allows commands to be completed from polling mode loops.
+ *
+ * Return:
+ * ADV_TRUE(1) - interrupt was pending
+ * ADV_FALSE(0) - no interrupt was pending
+ */
+STATIC int
+AdvISR(ADV_DVC_VAR *asc_dvc)
+{
+ AdvPortAddr iop_base;
+ uchar int_stat;
+ ushort next_done_loc, target_bit;
+ int completed_q;
+ int flags;
+ ADV_SCSI_REQ_Q *scsiq;
+ ASC_REQ_SENSE *sense_data;
+ int ret;
+
+ flags = DvcEnterCritical();
+ iop_base = asc_dvc->iop_base;
+
+ if (AdvIsIntPending(iop_base))
+ {
+ ret = ADV_TRUE;
+ } else
+ {
+ ret = ADV_FALSE;
+ }
+
+ /* Reading the register clears the interrupt. */
+ int_stat = AdvReadByteRegister(iop_base, IOPB_INTR_STATUS_REG);
+
+ if (int_stat & ADV_INTR_STATUS_INTRB)
+ {
+ asc_dvc->idle_cmd_done = ADV_TRUE;
+ }
+
+ /*
+ * Notify the driver of a hardware detected SCSI Bus Reset.
+ */
+ if (int_stat & ADV_INTR_STATUS_INTRC)
+ {
+ if (asc_dvc->sbreset_callback != 0)
+ {
+ (*(ADV_SBRESET_CALLBACK) asc_dvc->sbreset_callback)(asc_dvc);
+ }
+ }
+
+ /*
+ * ASC_MC_HOST_NEXT_DONE (0x129) is actually the last completed RISC
+ * Queue List request. Its forward pointer (RQL_FWD) points to the
+ * current completed RISC Queue List request.
+ */
+ AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, next_done_loc);
+ next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
+ (next_done_loc * ASC_MC_RISC_Q_LIST_SIZE) + RQL_FWD;
+
+ AdvReadByteLram(iop_base, next_done_loc, completed_q);
+
+ /* Loop until all completed Q's are processed. */
+ while (completed_q != ASC_MC_NULL_Q)
+ {
+ AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_DONE, completed_q);
+
+ next_done_loc = ASC_MC_RISC_Q_LIST_BASE +
+ (completed_q * ASC_MC_RISC_Q_LIST_SIZE);
+
+ /*
+ * Read the ADV_SCSI_REQ_Q virtual address pointer from
+ * the RISC list entry. The microcode has changed the
+ * ADV_SCSI_REQ_Q physical address to its virtual address.
+ *
+ * Refer to comments at the end of AdvSendScsiCmd() for
+ * more information on the RISC list structure.
+ */
+ {
+ ushort lsw, msw;
+ AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR, lsw);
+ AdvReadWordLram(iop_base, next_done_loc + RQL_PHYADDR + 2, msw);
+
+ scsiq = (ADV_SCSI_REQ_Q *) (((ulong) msw << 16) | lsw);
+ }
+ ADV_ASSERT(scsiq != NULL);
+
+ target_bit = ADV_TID_TO_TIDMASK(scsiq->target_id);
+
+ /*
+ * Clear request microcode control flag.
+ */
+ scsiq->cntl = 0;
+
+ /*
+ * Check Condition handling
+ */
+ if ((scsiq->done_status == QD_WITH_ERROR) &&
+ (scsiq->scsi_status == SS_CHK_CONDITION) &&
+ (sense_data = (ASC_REQ_SENSE *) scsiq->vsense_addr) != 0 &&
+ (scsiq->orig_sense_len - scsiq->sense_len) >= ASC_MIN_SENSE_LEN)
+ {
+ /*
+ * Command returned with a check condition and valid
+ * sense data.
+ */
+ }
+ /*
+ * If the command that completed was a SCSI INQUIRY and
+ * LUN 0 was sent the command, then process the INQUIRY
+ * command information for the device.
+ */
+ else if (scsiq->done_status == QD_NO_ERROR &&
+ scsiq->cdb[0] == SCSICMD_Inquiry &&
+ scsiq->target_lun == 0)
+ {
+ AdvInquiryHandling(asc_dvc, scsiq);
+ }
+
+
+ /* Change the RISC Queue List state to free. */
+ AdvWriteByteLram(iop_base, next_done_loc + RQL_STATE, ASC_MC_QS_FREE);
+
+ /* Get the RISC Queue List forward pointer. */
+ AdvReadByteLram(iop_base, next_done_loc + RQL_FWD, completed_q);
+
+ /*
+ * Notify the driver of the completed request by passing
+ * the ADV_SCSI_REQ_Q pointer to its callback function.
+ */
+ ADV_ASSERT(asc_dvc->cur_host_qng > 0);
+ asc_dvc->cur_host_qng--;
+ scsiq->a_flag |= ADV_SCSIQ_DONE;
+ (*(ADV_ISR_CALLBACK) asc_dvc->isr_callback)(asc_dvc, scsiq);
+ /*
+ * Note: After the driver callback function is called, 'scsiq'
+ * can no longer be referenced.
+ *
+ * Fall through and continue processing other completed
+ * requests...
+ */
+
+ /*
+ * Disable interrupts again in case the driver inadvertently
+ * enabled interrupts in its callback function.
+ *
+ * The DvcEnterCritical() return value is ignored, because
+ * the 'flags' saved when AdvISR() was first entered will be
+ * used to restore the interrupt flag on exit.
+ */
+ (void) DvcEnterCritical();
+ }
+ DvcLeaveCritical(flags);
+ return ret;
+}
+
+/*
+ * Send an idle command to the chip and wait for completion.
+ *
+ * Interrupts do not have to be enabled on entry.
+ *
+ * Return Values:
+ * ADV_TRUE - command completed successfully
+ * ADV_FALSE - command failed
+ */
+STATIC int
+AdvSendIdleCmd(ADV_DVC_VAR *asc_dvc,
+ ushort idle_cmd,
+ ulong idle_cmd_parameter,
+ int flags)
+{
+ int last_int_level;
+ ulong i;
+ AdvPortAddr iop_base;
+ int ret;
+
+ asc_dvc->idle_cmd_done = 0;
+
+ last_int_level = DvcEnterCritical();
+ iop_base = asc_dvc->iop_base;
+
+ /*
+ * Write the idle command value after the idle command parameter
+ * has been written to avoid a race condition. If the order is not
+ * followed, the microcode may process the idle command before the
+ * parameters have been written to LRAM.
+ */
+ AdvWriteDWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, idle_cmd_parameter);
+ AdvWriteWordLram(iop_base, ASC_MC_IDLE_CMD, idle_cmd);
+ DvcLeaveCritical(last_int_level);
+
+ /*
+ * If the 'flags' argument contains the ADV_NOWAIT flag, then
+ * return with success.
+ */
+ if (flags & ADV_NOWAIT)
+ {
+ return ADV_TRUE;
+ }
+
+ for (i = 0; i < SCSI_WAIT_10_SEC * SCSI_MS_PER_SEC; i++)
+ {
+ /*
+ * 'idle_cmd_done' is set by AdvISR().
+ */
+ if (asc_dvc->idle_cmd_done)
+ {
+ break;
+ }
+ DvcSleepMilliSecond(1);
+
+ /*
+ * If interrupts were disabled on entry to AdvSendIdleCmd(),
+ * then they will still be disabled here. Call AdvISR() to
+ * check for the idle command completion.
+ */
+ (void) AdvISR(asc_dvc);
+ }
+
+ last_int_level = DvcEnterCritical();
+
+ if (asc_dvc->idle_cmd_done == ADV_FALSE)
+ {
+ ADV_ASSERT(0); /* The idle command should never timeout. */
+ return ADV_FALSE;
+ } else
+ {
+ AdvReadWordLram(iop_base, ASC_MC_IDLE_PARA_STAT, ret);
+ return ret;
+ }
+}
+
+/*
+ * Send the SCSI request block to the adapter
+ *
+ * Each of the 255 Adv Library/Microcode RISC Lists or mailboxes has the
+ * following structure:
+ *
+ * 0: RQL_FWD - RISC list forward pointer (1 byte)
+ * 1: RQL_BWD - RISC list backward pointer (1 byte)
+ * 2: RQL_STATE - RISC list state byte - free, ready, done, aborted (1 byte)
+ * 3: RQL_TID - request target id (1 byte)
+ * 4: RQL_PHYADDR - ADV_SCSI_REQ_Q physical pointer (4 bytes)
+ *
+ * Return:
+ * ADV_SUCCESS(1) - the request is in the mailbox
+ * ADV_BUSY(0) - total request count > 253, try later
+ */
+STATIC int
+AdvSendScsiCmd(
+ ADV_DVC_VAR *asc_dvc,
+ ADV_SCSI_REQ_Q *scsiq)
+{
+ ushort next_ready_loc;
+ uchar next_ready_loc_fwd;
+ int last_int_level;
+ AdvPortAddr iop_base;
+ long req_size;
+ ulong q_phy_addr;
+
+ /*
+ * The ADV_SCSI_REQ_Q 'target_id' field should never be equal
+ * to the host adapter ID or exceed ADV_MAX_TID.
+ */
+ if (scsiq->target_id == asc_dvc->chip_scsi_id ||
+ scsiq->target_id > ADV_MAX_TID)
+ {
+ scsiq->host_status = QHSTA_M_INVALID_DEVICE;
+ scsiq->done_status = QD_WITH_ERROR;
+ return ADV_ERROR;
+ }
+
+ iop_base = asc_dvc->iop_base;
+
+ last_int_level = DvcEnterCritical();
+
+ if (asc_dvc->cur_host_qng >= asc_dvc->max_host_qng)
+ {
+ DvcLeaveCritical(last_int_level);
+ return ADV_BUSY;
+ } else
+ {
+ ADV_ASSERT(asc_dvc->cur_host_qng < ASC_MC_RISC_Q_TOTAL_CNT);
+ asc_dvc->cur_host_qng++;
+ }
+
+ /*
+ * Clear the ADV_SCSI_REQ_Q done flag.
+ */
+ scsiq->a_flag &= ~ADV_SCSIQ_DONE;
+
+ /*
+ * Save the original sense buffer length.
+ *
+ * After the request completes 'sense_len' will be set to the residual
+ * byte count of the Auto-Request Sense if a command returns CHECK
+ * CONDITION and the Sense Data is valid indicated by 'host_status' not
+ * being set to QHSTA_M_AUTO_REQ_SENSE_FAIL. To determine the valid
+ * Sense Data Length subtract 'sense_len' from 'orig_sense_len'.
+ */
+ scsiq->orig_sense_len = scsiq->sense_len;
+
+ AdvReadByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc);
+ next_ready_loc = ASC_MC_RISC_Q_LIST_BASE +
+ (next_ready_loc * ASC_MC_RISC_Q_LIST_SIZE);
+
+ /*
+ * Write the physical address of the Q to the mailbox.
+ * We need to skip the first four bytes, because the microcode
+ * uses them internally for linking Q's together.
+ */
+ req_size = sizeof(ADV_SCSI_REQ_Q);
+ q_phy_addr = DvcGetPhyAddr(asc_dvc, scsiq,
+ (uchar *) scsiq, &req_size,
+ ADV_IS_SCSIQ_FLAG);
+ ADV_ASSERT(ADV_DWALIGN(q_phy_addr) == q_phy_addr);
+ ADV_ASSERT(req_size >= sizeof(ADV_SCSI_REQ_Q));
+
+ scsiq->scsiq_ptr = (ADV_SCSI_REQ_Q *) scsiq;
+
+ /*
+ * The RISC list structure, which 'next_ready_loc' is a pointer
+ * to in microcode LRAM, has the format detailed in the comment
+ * header for this function.
+ *
+ * Write the ADV_SCSI_REQ_Q physical pointer to 'next_ready_loc' request.
+ */
+ AdvWriteDWordLram(iop_base, next_ready_loc + RQL_PHYADDR, q_phy_addr);
+
+ /* Write target_id to 'next_ready_loc' request. */
+ AdvWriteByteLram(iop_base, next_ready_loc + RQL_TID, scsiq->target_id);
+
+ /*
+ * Set the ASC_MC_HOST_NEXT_READY (0x128) microcode variable to
+ * the 'next_ready_loc' request forward pointer.
+ *
+ * Do this *before* changing the 'next_ready_loc' queue to QS_READY.
+ * After the state is changed to QS_READY 'RQL_FWD' will be changed
+ * by the microcode.
+ *
+ * NOTE: The temporary variable 'next_ready_loc_fwd' is required to
+ * prevent some compilers from optimizing out 'AdvReadByteLram()' if
+ * it were used as the 3rd argument to 'AdvWriteByteLram()'.
+ */
+ AdvReadByteLram(iop_base, next_ready_loc + RQL_FWD, next_ready_loc_fwd);
+ AdvWriteByteLram(iop_base, ASC_MC_HOST_NEXT_READY, next_ready_loc_fwd);
+
+ /*
+ * Change the state of 'next_ready_loc' request from QS_FREE to
+ * QS_READY which will cause the microcode to pick it up and
+ * execute it.
+ *
+ * Can't reference 'next_ready_loc' after changing the request
+ * state to QS_READY. The microcode now owns the request.
+ */
+ AdvWriteByteLram(iop_base, next_ready_loc + RQL_STATE, ASC_MC_QS_READY);
+
+ DvcLeaveCritical(last_int_level);
+ return ADV_SUCCESS;
+}
+
+/*
+ * Inquiry Information Byte 7 Handling
+ *
+ * Handle SCSI Inquiry Command information for a device by setting
+ * microcode operating variables that affect WDTR, SDTR, and Tag
+ * Queuing.
+ */
+STATIC void
+AdvInquiryHandling(
+ ADV_DVC_VAR *asc_dvc,
+ ADV_SCSI_REQ_Q *scsiq)
+{
+ AdvPortAddr iop_base;
+ uchar tid;
+ ASC_SCSI_INQUIRY *inq;
+ ushort tidmask;
+ ushort cfg_word;
+
+ /*
+ * AdvInquiryHandling() requires up to INQUIRY information Byte 7
+ * to be available.
+ *
+ * If less than 8 bytes of INQUIRY information were requested or less
+ * than 8 bytes were transferred, then return. cdb[4] is the request
+ * length and the ADV_SCSI_REQ_Q 'data_cnt' field is set by the
+ * microcode to the transfer residual count.
+ */
+ if (scsiq->cdb[4] < 8 || (scsiq->cdb[4] - scsiq->data_cnt) < 8)
+ {
+ return;
+ }
+
+ iop_base = asc_dvc->iop_base;
+ tid = scsiq->target_id;
+ inq = (ASC_SCSI_INQUIRY *) scsiq->vdata_addr;
+
+ /*
+ * WDTR, SDTR, and Tag Queuing cannot be enabled for old devices.
+ */
+ if (inq->byte3.rsp_data_fmt < 2 && inq->byte2.ansi_apr_ver < 2)
+ {
+ return;
+ } else
+ {
+ /*
+ * INQUIRY Byte 7 Handling
+ *
+ * Use a device's INQUIRY byte 7 to determine whether it
+ * supports WDTR, SDTR, and Tag Queuing. If the feature
+ * is enabled in the EEPROM and the device supports the
+ * feature, then enable it in the microcode.
+ */
+
+ tidmask = ADV_TID_TO_TIDMASK(tid);
+
+ /*
+ * Wide Transfers
+ *
+ * If the EEPROM enabled WDTR for the device and the device
+ * supports wide bus (16 bit) transfers, then turn on the
+ * device's 'wdtr_able' bit and write the new value to the
+ * microcode.
+ */
+ if ((asc_dvc->wdtr_able & tidmask) && inq->byte7.WBus16)
+ {
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+ if ((cfg_word & tidmask) == 0)
+ {
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_ABLE, cfg_word);
+
+ /*
+ * Clear the microcode "WDTR negotiation" done indicator
+ * for the target to cause it to negotiate with the new
+ * setting set above.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_WDTR_DONE, cfg_word);
+ }
+ }
+
+ /*
+ * Synchronous Transfers
+ *
+ * If the EEPROM enabled SDTR for the device and the device
+ * supports synchronous transfers, then turn on the device's
+ * 'sdtr_able' bit. Write the new value to the microcode.
+ */
+ if ((asc_dvc->sdtr_able & tidmask) && inq->byte7.Sync)
+ {
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+ if ((cfg_word & tidmask) == 0)
+ {
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_ABLE, cfg_word);
+
+ /*
+ * Clear the microcode "SDTR negotiation" done indicator
+ * for the target to cause it to negotiate with the new
+ * setting set above.
+ */
+ AdvReadWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+ cfg_word &= ~tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_SDTR_DONE, cfg_word);
+ }
+ }
+
+ /*
+ * If the EEPROM enabled Tag Queuing for device and the
+ * device supports Tag Queuing, then turn on the device's
+ * 'tagqng_enable' bit in the microcode and set the microcode
+ * maximum command count to the ADV_DVC_VAR 'max_dvc_qng'
+ * value.
+ *
+ * Tag Queuing is disabled for the BIOS which runs in polled
+ * mode and would see no benefit from Tag Queuing. Also by
+ * disabling Tag Queuing in the BIOS devices with Tag Queuing
+ * bugs will at least work with the BIOS.
+ */
+ if ((asc_dvc->tagqng_able & tidmask) && inq->byte7.CmdQue)
+ {
+ AdvReadWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+ cfg_word |= tidmask;
+ AdvWriteWordLram(iop_base, ASC_MC_TAGQNG_ABLE, cfg_word);
+ AdvWriteByteLram(iop_base, ASC_MC_NUMBER_OF_MAX_CMD + tid,
+ asc_dvc->max_dvc_qng);
+ }
+ }
+}
diff --git a/drivers/scsi/advansys.h b/drivers/scsi/advansys.h
index eb3d65e65..010cd6153 100644
--- a/drivers/scsi/advansys.h
+++ b/drivers/scsi/advansys.h
@@ -1,9 +1,9 @@
-/* $Id: advansys.h,v 1.6 1997/05/30 19:25:12 davem Exp $ */
+/* $Id: advansys.h,v 1.17 1998/01/08 21:23:49 bobf Exp bobf $ */
/*
* advansys.h - Linux Host Driver for AdvanSys SCSI Adapters
*
- * Copyright (c) 1995-1997 Advanced System Products, Inc.
+ * Copyright (c) 1995-1998 Advanced System Products, Inc.
* All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -18,7 +18,7 @@
* ftp://ftp.advansys.com/pub/linux
*
* Please send questions, comments, bug reports to:
- * bobf@advansys.com (Bob Frey)
+ * bobf@advansys.com (Bob Frey)
*/
#ifndef _ADVANSYS_H
@@ -97,7 +97,7 @@ void advansys_setup(char *, int *);
*/ \
ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \
}
-#else /* version >= v1.3.0 */
+#elif LINUX_VERSION_CODE < ASC_LINUX_VERSION(2,1,75)
#define ADVANSYS { \
NULL, /* struct SHT *next */ \
NULL, \
@@ -142,5 +142,33 @@ void advansys_setup(char *, int *);
*/ \
ENABLE_CLUSTERING, /* unsigned use_clustering:1 */ \
}
-#endif /* version >= v1.3.0 */
+#else /* version >= v2.1.75 */
+#define ADVANSYS { \
+ proc_dir: &proc_scsi_advansys, \
+ proc_info: advansys_proc_info, \
+ name: "advansys", \
+ detect: advansys_detect, \
+ release: advansys_release, \
+ info: advansys_info, \
+ command: advansys_command, \
+ queuecommand: advansys_queuecommand, \
+ abort: advansys_abort, \
+ reset: advansys_reset, \
+ bios_param: advansys_biosparam, \
+ /* \
+ * Because the driver may control an ISA adapter 'unchecked_isa_dma' \
+ * must be set. The flag will be cleared in advansys_detect for non-ISA \
+ * adapters. Refer to the comment in scsi_module.c for more information. \
+ */ \
+ unchecked_isa_dma: 1, \
+ /* \
+ * All adapters controlled by this driver are capable of large \
+ * scatter-gather lists. According to the mid-level SCSI documentation \
+ * this obviates any performance gain provided by setting \
+ * 'use_clustering'. But empirically while CPU utilization is increased \
+ * by enabling clustering, I/O throughput increases as well. \
+ */ \
+ use_clustering: ENABLE_CLUSTERING, \
+}
+#endif /* version >= v2.1.75 */
#endif /* _ADVANSYS_H */
diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h
index 56c56e52b..dba7eba93 100644
--- a/drivers/scsi/aha152x.h
+++ b/drivers/scsi/aha152x.h
@@ -28,27 +28,23 @@ int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int
extern struct proc_dir_entry proc_scsi_aha152x;
/* Initial value of Scsi_Host entry */
-#define AHA152X { /* next */ 0, \
- /* module */ 0, \
- /* proc_dir */ &proc_scsi_aha152x, \
- /* proc_info */ aha152x_proc_info, \
- /* name */ AHA152X_REVID, \
- /* detect */ aha152x_detect, \
- /* release */ 0, \
- /* info */ 0, \
- /* command */ aha152x_command, \
- /* queuecommand */ aha152x_queue, \
- /* abort */ aha152x_abort, \
- /* reset */ aha152x_reset, \
- /* slave_attach */ 0, \
- /* bios_param */ aha152x_biosparam, \
- /* can_queue */ 1, \
- /* this_id */ 7, \
- /* sg_tablesize */ SG_ALL, \
- /* cmd_per_lun */ 1, \
- /* present */ 0, \
- /* unchecked_isa_dma */ 0, \
- /* use_clustering */ DISABLE_CLUSTERING }
+#define AHA152X { proc_dir: &proc_scsi_aha152x, \
+ proc_info: aha152x_proc_info, \
+ name: AHA152X_REVID, \
+ detect: aha152x_detect, \
+ command: aha152x_command, \
+ queuecommand: aha152x_queue, \
+ abort: aha152x_abort, \
+ reset: aha152x_reset, \
+ slave_attach: 0, \
+ bios_param: aha152x_biosparam, \
+ can_queue: 1, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ present: 0, \
+ unchecked_isa_dma: 0, \
+ use_clustering: DISABLE_CLUSTERING }
#endif
diff --git a/drivers/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 29f31e170..c291a95e6 100644
--- a/drivers/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -133,8 +133,8 @@ static int aha1542_restart(struct Scsi_Host * shost);
#define aha1542_intr_reset(base) outb(IRST, CONTROL(base))
#define WAIT(port, mask, allof, noneof) \
- { register WAITbits; \
- register WAITtimeout = WAITnexttimeout; \
+ { register int WAITbits; \
+ register int WAITtimeout = WAITnexttimeout; \
while (1) { \
WAITbits = inb(port) & (mask); \
if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
@@ -146,8 +146,8 @@ static int aha1542_restart(struct Scsi_Host * shost);
/* Similar to WAIT, except we use the udelay call to regulate the
amount of time we wait. */
#define WAITd(port, mask, allof, noneof, timeout) \
- { register WAITbits; \
- register WAITtimeout = timeout; \
+ { register int WAITbits; \
+ register int WAITtimeout = timeout; \
while (1) { \
WAITbits = inb(port) & (mask); \
if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \
@@ -1117,12 +1117,264 @@ static int aha1542_restart(struct Scsi_Host * shost)
return 0;
}
-/* The abort command does not leave the device in a clean state where
- it is available to be used again. Until this gets worked out, we will
- leave it commented out. */
-
int aha1542_abort(Scsi_Cmnd * SCpnt)
{
+
+ /*
+ * The abort command does not leave the device in a clean state where
+ * it is available to be used again. Until this gets worked out, we
+ * will leave it commented out.
+ */
+
+ printk("aha1542.c: Unable to abort command for target %d\n",
+ SCpnt->target);
+ return FAILED;
+}
+
+/*
+ * This is a device reset. This is handled by sending a special command
+ * to the device.
+ */
+int aha1542_dev_reset(Scsi_Cmnd * SCpnt)
+{
+ unsigned long flags;
+ struct mailbox * mb;
+ unchar target = SCpnt->target;
+ unchar lun = SCpnt->lun;
+ int mbo;
+ struct ccb *ccb;
+ unchar ahacmd = CMD_START_SCSI;
+
+ ccb = HOSTDATA(SCpnt->host)->ccb;
+ mb = HOSTDATA(SCpnt->host)->mb;
+
+ save_flags(flags);
+ cli();
+ mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
+ if (mbo >= AHA1542_MAILBOXES) mbo = 0;
+
+ do{
+ if(mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
+ break;
+ mbo++;
+ if (mbo >= AHA1542_MAILBOXES) mbo = 0;
+ } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
+
+ if(mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
+ panic("Unable to find empty mailbox for aha1542.\n");
+
+ HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt; /* This will effectively
+ prevent someone else from
+ screwing with this cdb. */
+
+ HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;
+ restore_flags(flags);
+
+ any2scsi(mb[mbo].ccbptr, SCSI_PA(&ccb[mbo])); /* This gets trashed for some reason*/
+
+ memset(&ccb[mbo], 0, sizeof(struct ccb));
+
+ ccb[mbo].op = 0x81; /* BUS DEVICE RESET */
+
+ ccb[mbo].idlun = (target&7)<<5 | (lun & 7); /*SCSI Target Id*/
+
+ ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0;
+ ccb[mbo].commlinkid = 0;
+
+ /*
+ * Now tell the 1542 to flush all pending commands for this
+ * target
+ */
+ aha1542_out(SCpnt->host->io_port, &ahacmd, 1);
+
+ printk("aha1542.c: Trying device reset for target %d\n", SCpnt->target);
+
+ return SUCCESS;
+
+
+#ifdef ERIC_neverdef
+ /*
+ * With the 1542 we apparently never get an interrupt to
+ * acknowledge a device reset being sent. Then again, Leonard
+ * says we are doing this wrong in the first place...
+ *
+ * Take a wait and see attitude. If we get spurious interrupts,
+ * then the device reset is doing something sane and useful, and
+ * we will wait for the interrupt to post completion.
+ */
+ printk("Sent BUS DEVICE RESET to target %d\n", SCpnt->target);
+
+ /*
+ * Free the command block for all commands running on this
+ * target...
+ */
+ for(i=0; i< AHA1542_MAILBOXES; i++)
+ {
+ if(HOSTDATA(SCpnt->host)->SCint[i] &&
+ HOSTDATA(SCpnt->host)->SCint[i]->target == SCpnt->target)
+ {
+ Scsi_Cmnd * SCtmp;
+ SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+ if (SCtmp->host_scribble)
+ {
+ scsi_free(SCtmp->host_scribble, 512);
+ }
+
+ HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ }
+ }
+ return SUCCESS;
+
+ return FAILED;
+#endif /* ERIC_neverdef */
+}
+
+int aha1542_bus_reset(Scsi_Cmnd * SCpnt)
+{
+ int i;
+
+ /*
+ * This does a scsi reset for all devices on the bus.
+ * In principle, we could also reset the 1542 - should
+ * we do this? Try this first, and we can add that later
+ * if it turns out to be useful.
+ */
+ outb(SCRST, CONTROL(SCpnt->host->io_port));
+
+ /*
+ * Wait for the thing to settle down a bit. Unfortunately
+ * this is going to basically lock up the machine while we
+ * wait for this to complete. To be 100% correct, we need to
+ * check for timeout, and if we are doing something like this
+ * we are pretty desperate anyways.
+ */
+ scsi_sleep(4*HZ);
+
+ WAIT(STATUS(SCpnt->host->io_port),
+ STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+
+ /*
+ * Now try to pick up the pieces. For all pending commands,
+ * free any internal data structures, and basically clear things
+ * out. We do not try and restart any commands or anything -
+ * the strategy handler takes care of that crap.
+ */
+ printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+ for(i=0; i< AHA1542_MAILBOXES; i++)
+ {
+ if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
+ {
+ Scsi_Cmnd * SCtmp;
+ SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+
+
+ if( SCtmp->device->soft_reset )
+ {
+ /*
+ * If this device implements the soft reset option,
+ * then it is still holding onto the command, and
+ * may yet complete it. In this case, we don't
+ * flush the data.
+ */
+ continue;
+ }
+
+ if (SCtmp->host_scribble)
+ {
+ scsi_free(SCtmp->host_scribble, 512);
+ }
+
+ HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ }
+ }
+
+ return SUCCESS;
+
+fail:
+ return FAILED;
+}
+
+int aha1542_host_reset(Scsi_Cmnd * SCpnt)
+{
+ int i;
+
+ /*
+ * This does a scsi reset for all devices on the bus.
+ * In principle, we could also reset the 1542 - should
+ * we do this? Try this first, and we can add that later
+ * if it turns out to be useful.
+ */
+ outb(HRST | SCRST, CONTROL(SCpnt->host->io_port));
+
+ /*
+ * Wait for the thing to settle down a bit. Unfortunately
+ * this is going to basically lock up the machine while we
+ * wait for this to complete. To be 100% correct, we need to
+ * check for timeout, and if we are doing something like this
+ * we are pretty desperate anyways.
+ */
+ scsi_sleep(4*HZ);
+
+ WAIT(STATUS(SCpnt->host->io_port),
+ STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+
+ /*
+ * We need to do this too before the 1542 can interact with
+ * us again.
+ */
+ setup_mailboxes(SCpnt->host->io_port, SCpnt->host);
+
+ /*
+ * Now try to pick up the pieces. For all pending commands,
+ * free any internal data structures, and basically clear things
+ * out. We do not try and restart any commands or anything -
+ * the strategy handler takes care of that crap.
+ */
+ printk("Sent BUS RESET to scsi host %d\n", SCpnt->host->host_no);
+
+ for(i=0; i< AHA1542_MAILBOXES; i++)
+ {
+ if(HOSTDATA(SCpnt->host)->SCint[i] != NULL)
+ {
+ Scsi_Cmnd * SCtmp;
+ SCtmp = HOSTDATA(SCpnt->host)->SCint[i];
+
+ if( SCtmp->device->soft_reset )
+ {
+ /*
+ * If this device implements the soft reset option,
+ * then it is still holding onto the command, and
+ * may yet complete it. In this case, we don't
+ * flush the data.
+ */
+ continue;
+ }
+
+ if (SCtmp->host_scribble)
+ {
+ scsi_free(SCtmp->host_scribble, 512);
+ }
+
+ HOSTDATA(SCpnt->host)->SCint[i] = NULL;
+ HOSTDATA(SCpnt->host)->mb[i].status = 0;
+ }
+ }
+
+ return SUCCESS;
+
+fail:
+ return FAILED;
+}
+
+/*
+ * These are the old error handling routines. They are only temporarily
+ * here while we play with the new error handling code.
+ */
+int aha1542_old_abort(Scsi_Cmnd * SCpnt)
+{
#if 0
unchar ahacmd = CMD_START_SCSI;
unsigned long flags;
@@ -1194,7 +1446,7 @@ int aha1542_abort(Scsi_Cmnd * SCpnt)
For a first go, we assume that the 1542 notifies us with all of the
pending commands (it does implement soft reset, after all). */
-int aha1542_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+int aha1542_old_reset(Scsi_Cmnd * SCpnt, unsigned int reset_flags)
{
unchar ahacmd = CMD_START_SCSI;
int i;
diff --git a/drivers/scsi/aha1542.h b/drivers/scsi/aha1542.h
index 6c250d5a5..820cc4b1c 100644
--- a/drivers/scsi/aha1542.h
+++ b/drivers/scsi/aha1542.h
@@ -133,8 +133,12 @@ struct ccb { /* Command Control Block 5.3 */
int aha1542_detect(Scsi_Host_Template *);
int aha1542_command(Scsi_Cmnd *);
int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int aha1542_abort(Scsi_Cmnd *);
-int aha1542_reset(Scsi_Cmnd *, unsigned int);
+int aha1542_abort(Scsi_Cmnd * SCpnt);
+int aha1542_bus_reset(Scsi_Cmnd * SCpnt);
+int aha1542_dev_reset(Scsi_Cmnd * SCpnt);
+int aha1542_host_reset(Scsi_Cmnd * SCpnt);
+extern int aha1542_old_abort(Scsi_Cmnd * SCpnt);
+int aha1542_old_reset(Scsi_Cmnd *, unsigned int);
int aha1542_biosparam(Disk *, kdev_t, int*);
#define AHA1542_MAILBOXES 8
@@ -147,25 +151,24 @@ int aha1542_biosparam(Disk *, kdev_t, int*);
extern struct proc_dir_entry proc_scsi_aha1542;
-#define AHA1542 { NULL, NULL, \
- &proc_scsi_aha1542,/* proc_dir_entry */ \
- NULL, \
- "Adaptec 1542", \
- aha1542_detect, \
- NULL, \
- NULL, \
- aha1542_command, \
- aha1542_queuecommand, \
- aha1542_abort, \
- aha1542_reset, \
- NULL, \
- aha1542_biosparam, \
- AHA1542_MAILBOXES, \
- 7, \
- AHA1542_SCATTER, \
- AHA1542_CMDLUN, \
- 0, \
- 1, \
- ENABLE_CLUSTERING}
+#define AHA1542 { proc_dir: &proc_scsi_aha1542, \
+ name: "Adaptec 1542", \
+ detect: aha1542_detect, \
+ command: aha1542_command, \
+ queuecommand: aha1542_queuecommand, \
+ abort: aha1542_old_abort, \
+ reset: aha1542_old_reset, \
+ eh_abort_handler: aha1542_abort, \
+ eh_device_reset_handler: aha1542_dev_reset, \
+ eh_bus_reset_handler: aha1542_bus_reset, \
+ eh_host_reset_handler: aha1542_host_reset, \
+ bios_param: aha1542_biosparam, \
+ can_queue: AHA1542_MAILBOXES, \
+ this_id: 7, \
+ sg_tablesize: AHA1542_SCATTER, \
+ cmd_per_lun: AHA1542_CMDLUN, \
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 1}
#endif
diff --git a/drivers/scsi/aha1740.h b/drivers/scsi/aha1740.h
index cd38a894b..597ec8be3 100644
--- a/drivers/scsi/aha1740.h
+++ b/drivers/scsi/aha1740.h
@@ -172,25 +172,19 @@ int aha1740_proc_info(char *buffer, char **start, off_t offset,
extern struct proc_dir_entry proc_scsi_aha1740;
-#define AHA1740 {NULL, NULL, \
- &proc_scsi_aha1740, \
- aha1740_proc_info, \
- "Adaptec 174x (EISA)", \
- aha1740_detect, \
- NULL, \
- NULL, \
- aha1740_command, \
- aha1740_queuecommand, \
- aha1740_abort, \
- aha1740_reset, \
- NULL, \
- aha1740_biosparam, \
- AHA1740_ECBS, \
- 7, \
- AHA1740_SCATTER, \
- AHA1740_CMDLUN, \
- 0, \
- 0, \
- ENABLE_CLUSTERING}
+#define AHA1740 { proc_dir: &proc_scsi_aha1740, \
+ proc_info: aha1740_proc_info, \
+ name: "Adaptec 174x (EISA)", \
+ detect: aha1740_detect, \
+ command: aha1740_command, \
+ queuecommand: aha1740_queuecommand, \
+ abort: aha1740_abort, \
+ reset: aha1740_reset, \
+ bios_param: aha1740_biosparam, \
+ can_queue: AHA1740_ECBS, \
+ this_id: 7, \
+ sg_tablesize: AHA1740_SCATTER, \
+ cmd_per_lun: AHA1740_CMDLUN, \
+ use_clustering: ENABLE_CLUSTERING}
#endif
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index 051dedaac..7839a2399 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -6953,7 +6953,7 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
channel = cmd->channel ? 'B': 'A';
tindex = TARGET_INDEX(cmd);
-#ifdef 0 /* AIC7XXX_DEBUG_ABORT */
+#if 0 /* AIC7XXX_DEBUG_ABORT */
if (scb != NULL)
{
printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n",
diff --git a/drivers/scsi/aic7xxx.h b/drivers/scsi/aic7xxx.h
index 5ba54acfa..fd40554f3 100644
--- a/drivers/scsi/aic7xxx.h
+++ b/drivers/scsi/aic7xxx.h
@@ -30,33 +30,26 @@
* to do with card config are filled in after the card is detected.
*/
#define AIC7XXX { \
- NULL, \
- NULL, \
- NULL, \
- aic7xxx_proc_info, \
- NULL, \
- aic7xxx_detect, \
- NULL, \
- aic7xxx_info, \
- NULL, \
- aic7xxx_queue, \
- NULL, \
- aic7xxx_reset, \
- NULL, \
- aic7xxx_biosparam, \
- -1, /* max simultaneous cmds */\
- -1, /* scsi id of host adapter */\
- 0, /* max scatter-gather cmds */\
- 2, /* cmds per lun (linked cmds) */\
- 0, /* number of 7xxx's present */\
- 0, /* no memory DMA restrictions */\
- ENABLE_CLUSTERING \
+ proc_info: aic7xxx_proc_info, \
+ detect: aic7xxx_detect, \
+ info: aic7xxx_info, \
+ queuecommand: aic7xxx_queue, \
+ abort: aic7xxx_abort, \
+ reset: aic7xxx_reset, \
+ bios_param: aic7xxx_biosparam, \
+ can_queue: -1, /* max simultaneous cmds */\
+ this_id: -1, /* scsi id of host adapter */\
+ sg_tablesize: SG_ALL, /* max scatter-gather cmds */\
+ cmd_per_lun: 2, /* cmds per lun (linked cmds) */\
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 0 /* Enable new error code */ \
}
extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
extern int aic7xxx_biosparam(Disk *, kdev_t, int[]);
extern int aic7xxx_detect(Scsi_Host_Template *);
extern int aic7xxx_command(Scsi_Cmnd *);
+extern int aic7xxx_abort(Scsi_Cmnd *);
extern int aic7xxx_reset(Scsi_Cmnd *, unsigned int);
extern const char *aic7xxx_info(struct Scsi_Host *);
diff --git a/drivers/scsi/amiga7xx.h b/drivers/scsi/amiga7xx.h
index ca85dca7b..09317d376 100644
--- a/drivers/scsi/amiga7xx.h
+++ b/drivers/scsi/amiga7xx.h
@@ -27,26 +27,16 @@ void NCR53c7x0_intr(int irq, void *dev_id, struct pt_regs * regs);
extern struct proc_dir_entry proc_scsi_amiga7xx;
-#define AMIGA7XX_SCSI {/* next */ NULL, \
- /* usage_count */ NULL, \
- /* proc_dir_entry */ NULL, \
- /* proc_info */ NULL, \
- /* name */ "Amiga NCR53c710 SCSI", \
- /* detect */ amiga7xx_detect, \
- /* release */ NULL, \
- /* info */ NULL, \
- /* command */ NULL, \
- /* queuecommand */ NCR53c7xx_queue_command, \
- /* abort */ NCR53c7xx_abort, \
- /* reset */ NCR53c7xx_reset, \
- /* slave_attach */ NULL, \
- /* bios_param */ scsicam_bios_param, \
- /* can_queue */ 24, \
- /* this_id */ 7, \
- /* sg_tablesize */ 127, \
- /* cmd_per_lun */ 3, \
- /* present */ 0, \
- /* unchecked_isa_dma */ 0, \
- /* use_clustering */ DISABLE_CLUSTERING }
+#define AMIGA7XX_SCSI {name: "Amiga NCR53c710 SCSI", \
+ detect: amiga7xx_detect, \
+ queuecommand: NCR53c7xx_queue_command, \
+ abort: NCR53c7xx_abort, \
+ reset: NCR53c7xx_reset, \
+ bios_param: scsicam_bios_param, \
+ can_queue: 24, \
+ this_id: 7, \
+ sg_tablesize: 127, \
+ cmd_per_lun: 3, \
+ use_clustering: DISABLE_CLUSTERING }
#endif
#endif /* AMIGA7XX_H */
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
index 79a1a9580..15280b82c 100644
--- a/drivers/scsi/atari_scsi.h
+++ b/drivers/scsi/atari_scsi.h
@@ -53,25 +53,19 @@ int atari_scsi_release (struct Scsi_Host *);
#if defined (HOSTS_C) || defined (MODULE)
-#define ATARI_SCSI { NULL, NULL, NULL, \
- atari_scsi_proc_info, \
- "Atari native SCSI", \
- atari_scsi_detect, \
- atari_scsi_release, \
- atari_scsi_info, \
- /* command */ NULL, \
- atari_scsi_queue_command, \
- atari_scsi_abort, \
- atari_scsi_reset, \
- /* slave_attach */ NULL, \
- /* bios_param */ NULL, \
- /* can queue */ 0, /* initialized at run-time */ \
- /* host_id */ 0, /* initialized at run-time */ \
- /* scatter gather */ 0, /* initialized at run-time */ \
- /* cmd per lun */ 0, /* initialized at run-time */ \
- /* present */ 0, \
- /* unchecked ISA DMA */ 0, \
- /* use_clustering */ DISABLE_CLUSTERING }
+#define ATARI_SCSI { proc_info: atari_scsi_proc_info, \
+ name: "Atari native SCSI", \
+ detect: atari_scsi_detect, \
+ release: atari_scsi_release, \
+ info: atari_scsi_info, \
+ queuecommand: atari_scsi_queue_command, \
+ abort: atari_scsi_abort, \
+ reset: atari_scsi_reset, \
+ can_queue: 0, /* initialized at run-time */ \
+ this_id: 0, /* initialized at run-time */ \
+ sg_tablesize: 0, /* initialized at run-time */ \
+ cmd_per_lun: 0, /* initialized at run-time */ \
+ use_clustering: DISABLE_CLUSTERING }
#endif
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index 1495a5d81..d6c766635 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -3,11 +3,6 @@
* etc.
*/
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
#define __NO_VERSION__
#include <linux/module.h>
diff --git a/drivers/scsi/dc390.h b/drivers/scsi/dc390.h
index bfe20c96b..88ae90f28 100644
--- a/drivers/scsi/dc390.h
+++ b/drivers/scsi/dc390.h
@@ -5,19 +5,7 @@
* Bus Master Host Adapter *
***********************************************************************/
-/* Kernel version autodetection */
-
#include <linux/version.h>
-/* Convert Linux Version, Patch-level, Sub-level to LINUX_VERSION_CODE. */
-#define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
-
-#if LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,50)
-#define VERSION_ELF_1_2_13
-#elseif LINUX_VERSION_CODE < ASC_LINUX_VERSION(1,3,95)
-#define VERSION_1_3_85
-#else
-#define VERSION_2_0_0
-#endif
/*
* AMD 53C974 driver, header file
@@ -28,119 +16,39 @@
#if defined(HOSTS_C) || defined(MODULE)
-#ifdef VERSION_2_0_0
#include <scsi/scsicam.h>
-#else
-#include <linux/scsicam.h>
-#endif
extern int DC390_detect(Scsi_Host_Template *psht);
extern int DC390_queue_command(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
extern int DC390_abort(Scsi_Cmnd *cmd);
-
-#ifdef VERSION_2_0_0
extern int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags);
-#else
-extern int DC390_reset(Scsi_Cmnd *cmd);
-#endif
-
-#ifdef VERSION_ELF_1_2_13
-extern int DC390_bios_param(Disk *disk, int devno, int geom[]);
-#else
extern int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]);
-#endif
#ifdef MODULE
static int DC390_release(struct Scsi_Host *);
#else
-#define DC390_release NULL
+# define DC390_release NULL
#endif
-#ifndef VERSION_ELF_1_2_13
extern struct proc_dir_entry proc_scsi_tmscsim;
extern int tmscsim_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout);
-#endif
-
-#ifdef VERSION_2_0_0
-
-#define DC390_T { \
- NULL, /* *next */ \
- NULL, /* *usage_count */ \
- &proc_scsi_tmscsim, /* *proc_dir */ \
- tmscsim_proc_info, /* (*proc_info)() */ \
- "Tekram DC390(T) V1.10 Dec-05-1996", /* *name */ \
- DC390_detect, \
- DC390_release, /* (*release)() */ \
- NULL, /* *(*info)() */ \
- NULL, /* (*command)() */ \
- DC390_queue_command, \
- DC390_abort, \
- DC390_reset, \
- NULL, /* slave attach */\
- DC390_bios_param, \
- 10,/* can queue(-1) */ \
- 7, /* id(-1) */ \
- SG_ALL, \
- 2, /* cmd per lun(2) */ \
- 0, /* present */ \
- 0, /* unchecked isa dma */ \
- DISABLE_CLUSTERING \
- }
-#endif
-
-
-#ifdef VERSION_1_3_85
-#define DC390_T { \
- NULL, /* *next */ \
- NULL, /* *usage_count */ \
- &proc_scsi_tmscsim, /* *proc_dir */ \
- tmscsim_proc_info, /* (*proc_info)() */ \
- "Tekram DC390(T) V1.10 Dec-05-1996", /* *name */ \
- DC390_detect, \
- DC390_release, /* (*release)() */ \
- NULL, /* *(*info)() */ \
- NULL, /* (*command)() */ \
- DC390_queue_command, \
- DC390_abort, \
- DC390_reset, \
- NULL, /* slave attach */\
- DC390_bios_param, \
- 10,/* can queue(-1) */ \
- 7, /* id(-1) */ \
- SG_ALL, \
- 2, /* cmd per lun(2) */ \
- 0, /* present */ \
- 0, /* unchecked isa dma */ \
- DISABLE_CLUSTERING \
- }
-#endif
-
-
-#ifdef VERSION_ELF_1_2_13
-
-#define DC390_T { \
- NULL, \
- NULL, \
- "Tekram DC390(T) V1.10 Dec-05-1996",\
- DC390_detect, \
- DC390_release, \
- NULL, /* info */ \
- NULL, /* command, deprecated */ \
- DC390_queue_command, \
- DC390_abort, \
- DC390_reset, \
- NULL, /* slave attach */\
- DC390_bios_param, \
- 10,/* can queue(-1) */ \
- 7, /* id(-1) */ \
- 16,/* old (SG_ALL) */ \
- 2, /* cmd per lun(2) */ \
- 0, /* present */ \
- 0, /* unchecked isa dma */ \
- DISABLE_CLUSTERING \
- }
-#endif
+#define DC390_T { \
+ proc_dir: &proc_scsi_tmscsim, \
+ proc_info: tmscsim_proc_info, \
+ name: "Tekram DC390(T) V1.12 Feb-25-1998",\
+ detect: DC390_detect, \
+ release: DC390_release, \
+ queuecommand: DC390_queue_command, \
+ abort: DC390_abort, \
+ reset: DC390_reset, \
+ bios_param: DC390_bios_param, \
+ can_queue: 10, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 2, \
+ use_clustering: DISABLE_CLUSTERING \
+ }
#endif /* defined(HOSTS_C) || defined(MODULE) */
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
index 9216ac1d2..c0e15f6ea 100644
--- a/drivers/scsi/dtc.h
+++ b/drivers/scsi/dtc.h
@@ -57,13 +57,18 @@ int dtc_proc_info (char *buffer, char **start, off_t offset,
#if defined(HOSTS_C) || defined(MODULE)
-#define DTC3x80 {NULL, NULL, NULL, NULL, \
- "DTC 3180/3280 ", dtc_detect, NULL, \
- NULL, \
- NULL, dtc_queue_command, dtc_abort, dtc_reset, NULL, \
- dtc_biosparam, \
- /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
- /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
+#define DTC3x80 { \
+ name: "DTC 3180/3280 ", \
+ detect: dtc_detect, \
+ queuecommand: dtc_queue_command, \
+ abort: dtc_abort, \
+ reset: dtc_reset, \
+ bios_param: dtc_biosparam, \
+ can_queue: CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: CMD_PER_LUN , \
+ use_clustering: DISABLE_CLUSTERING}
#endif
diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h
index 8292ef514..0a01d00b0 100644
--- a/drivers/scsi/eata.h
+++ b/drivers/scsi/eata.h
@@ -15,27 +15,16 @@ int eata2x_reset(Scsi_Cmnd *, unsigned int);
#define EATA_VERSION "3.11.00"
-#define EATA { \
- NULL, /* Ptr for modules */ \
- NULL, /* usage count for modules */ \
- NULL, \
- NULL, \
- "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
- eata2x_detect, \
- eata2x_release, \
- NULL, \
- NULL, \
- eata2x_queuecommand, \
- eata2x_abort, \
- eata2x_reset, \
- NULL, \
- scsicam_bios_param, \
- 0, /* can_queue, reset by detect */ \
- 7, /* this_id, reset by detect */ \
- 0, /* sg_tablesize, reset by detect */ \
- 0, /* cmd_per_lun, reset by detect */ \
- 0, /* number of boards present */ \
- 1, /* unchecked isa dma, reset by detect */ \
- ENABLE_CLUSTERING \
+#define EATA { \
+ name: "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
+ detect: eata2x_detect, \
+ release: eata2x_release, \
+ queuecommand: eata2x_queuecommand, \
+ abort: eata2x_abort, \
+ reset: eata2x_reset, \
+ bios_param: scsicam_bios_param, \
+ this_id: 7, /* this_id, reset by detect */ \
+ unchecked_isa_dma: 1, /* unchecked isa dma, reset by detect */\
+ use_clustering: ENABLE_CLUSTERING \
}
#endif
diff --git a/drivers/scsi/eata_dma.h b/drivers/scsi/eata_dma.h
index a23931bf9..616744efe 100644
--- a/drivers/scsi/eata_dma.h
+++ b/drivers/scsi/eata_dma.h
@@ -84,26 +84,17 @@ int eata_release(struct Scsi_Host *);
#include <scsi/scsicam.h>
-#define EATA_DMA { \
- NULL, NULL, \
- NULL, /* proc_dir_entry */ \
- eata_proc_info, /* procinfo */ \
- "EATA (Extended Attachment) HBA driver", \
- eata_detect, \
- eata_release, \
- NULL, NULL, \
- eata_queue, \
- eata_abort, \
- eata_reset, \
- NULL, /* Slave attach */ \
- scsicam_bios_param, \
- 0, /* Canqueue */ \
- 0, /* this_id */ \
- 0, /* sg_tablesize */ \
- 0, /* cmd_per_lun */ \
- 0, /* present */ \
- 1, /* True if ISA */ \
- ENABLE_CLUSTERING }
+#define EATA_DMA { \
+ proc_info: eata_proc_info, /* procinfo */ \
+ name: "EATA (Extended Attachment) HBA driver", \
+ detect: eata_detect, \
+ release: eata_release, \
+ queuecommand: eata_queue, \
+ abort: eata_abort, \
+ reset: eata_reset, \
+ bios_param: scsicam_bios_param, \
+ unchecked_isa_dma: 1, /* True if ISA */ \
+ use_clustering: ENABLE_CLUSTERING }
#endif /* _EATA_DMA_H */
diff --git a/drivers/scsi/eata_dma_proc.c b/drivers/scsi/eata_dma_proc.c
index 3a3a19aa5..267d8bf82 100644
--- a/drivers/scsi/eata_dma_proc.c
+++ b/drivers/scsi/eata_dma_proc.c
@@ -439,15 +439,12 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
goto stop_output;
}
-#if 0
- scd = scsi_devices;
-
- size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+ size = sprintf(buffer+len,"Attached devices: %s\n",
+ (HBA_ptr->host_queue)?"":"none");
len += size;
pos = begin + len;
- while (scd) {
- if (scd->host == HBA_ptr) {
+ for(scd = HBA_ptr->host_queue; scd; scd = scd->next) {
proc_print_scsidevice(scd, buffer, &size, len);
len += size;
pos = begin + len;
@@ -458,10 +455,7 @@ int eata_proc_info(char *buffer, char **start, off_t offset, int length,
}
if (pos > offset + length)
goto stop_output;
- }
- scd = scd->next;
}
-#endif
stop_output:
DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
diff --git a/drivers/scsi/eata_pio.h b/drivers/scsi/eata_pio.h
index 333f7c4a7..7531e78a4 100644
--- a/drivers/scsi/eata_pio.h
+++ b/drivers/scsi/eata_pio.h
@@ -74,26 +74,17 @@ int eata_pio_release(struct Scsi_Host *);
#endif
-#define EATA_PIO { \
- NULL, NULL, \
- NULL, /* proc_dir_entry */ \
- eata_pio_proc_info, /* procinfo */ \
- "EATA (Extended Attachment) PIO driver", \
- eata_pio_detect, \
- eata_pio_release, \
- NULL, NULL, \
- eata_pio_queue, \
- eata_pio_abort, \
- eata_pio_reset, \
- NULL, /* Slave attach */ \
- scsicam_bios_param, \
- 0, /* Canqueue */ \
- 0, /* this_id */ \
- 0, /* sg_tablesize */ \
- 0, /* cmd_per_lun */ \
- 0, /* present */ \
- 1, /* True if ISA */ \
- ENABLE_CLUSTERING }
+#define EATA_PIO { \
+ proc_info: eata_pio_proc_info, /* procinfo */ \
+ name: "EATA (Extended Attachment) PIO driver", \
+ detect: eata_pio_detect, \
+ release: eata_pio_release, \
+ queuecommand: eata_pio_queue, \
+ abort: eata_pio_abort, \
+ reset: eata_pio_reset, \
+ bios_param: scsicam_bios_param, \
+ unchecked_isa_dma: 1, /* True if ISA */ \
+ use_clustering: ENABLE_CLUSTERING }
#endif /* _EATA_PIO_H */
diff --git a/drivers/scsi/eata_pio_proc.c b/drivers/scsi/eata_pio_proc.c
index d98958703..829053315 100644
--- a/drivers/scsi/eata_pio_proc.c
+++ b/drivers/scsi/eata_pio_proc.c
@@ -81,14 +81,12 @@ int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length,
if (pos > offset + length)
goto stop_output;
- scd = scsi_devices;
-
- size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+ size = sprintf(buffer+len,"Attached devices: %s\n",
+ (HBA_ptr->host_queue)?"":"none");
len += size;
pos = begin + len;
- while (scd) {
- if (scd->host == HBA_ptr) {
+ for(scd = HBA_ptr->host_queue; scd; scd = scd->next) {
proc_print_scsidevice(scd, buffer, &size, len);
len += size;
pos = begin + len;
@@ -99,8 +97,6 @@ int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length,
}
if (pos > offset + length)
goto stop_output;
- }
- scd = scd->next;
}
stop_output:
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 811522465..596e7b33f 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -844,7 +844,7 @@ static int esp_host_info(struct Sparc_ESP *esp, char *ptr, off_t offset, int len
copy_info(&info, "Target #\tconfig3\t\tSync Capabilities\tDisconnect\tWide\n");
for(i = 0; i < 15; i++) {
if(esp->targets_present & (1 << i)) {
- Scsi_Device *SDptr = scsi_devices;
+ Scsi_Device *SDptr = esp->ehost->host_queue;
while((SDptr->host != esp->ehost) &&
(SDptr->id != i) &&
diff --git a/drivers/scsi/fdomain.h b/drivers/scsi/fdomain.h
index c15255819..0983e5383 100644
--- a/drivers/scsi/fdomain.h
+++ b/drivers/scsi/fdomain.h
@@ -37,25 +37,17 @@ int fdomain_16x0_proc_info( char *buffer, char **start, off_t offset,
extern struct proc_dir_entry proc_scsi_fdomain;
-#define FDOMAIN_16X0 { NULL, \
- NULL, \
- NULL, \
- fdomain_16x0_proc_info, \
- NULL, \
- fdomain_16x0_detect, \
- NULL, \
- fdomain_16x0_info, \
- fdomain_16x0_command, \
- fdomain_16x0_queue, \
- fdomain_16x0_abort, \
- fdomain_16x0_reset, \
- NULL, \
- fdomain_16x0_biosparam, \
- 1, \
- 6, \
- 64, \
- 1, \
- 0, \
- 0, \
- DISABLE_CLUSTERING }
+#define FDOMAIN_16X0 { proc_info: fdomain_16x0_proc_info, \
+ detect: fdomain_16x0_detect, \
+ info: fdomain_16x0_info, \
+ command: fdomain_16x0_command, \
+ queuecommand: fdomain_16x0_queue, \
+ abort: fdomain_16x0_abort, \
+ reset: fdomain_16x0_reset, \
+ bios_param: fdomain_16x0_biosparam, \
+ can_queue: 1, \
+ this_id: 6, \
+ sg_tablesize: 64, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING }
#endif
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index 0d65f36a9..006c98d8f 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -658,8 +658,7 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
PRINTP(" %d pending writes" ANDP hostdata->pendingw);
if (hostdata->pendingr || hostdata->pendingw)
PRINTP("\n");
- for (dev = scsi_devices; dev; dev=dev->next) {
- if (dev->host == scsi_ptr) {
+ for (dev = scsi_ptr->host_queue; dev; dev=dev->next) {
unsigned long br = hostdata->bytes_read[dev->id];
unsigned long bw = hostdata->bytes_write[dev->id];
long tr = hostdata->time_read[dev->id] / HZ;
@@ -687,7 +686,6 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
if (tw)
PRINTP(" @ %5ld bps" ANDP bw / tw);
PRINTP("\n");
- }
}
#endif
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index 2730723eb..000449277 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -72,16 +72,21 @@ int generic_NCR5380_proc_info(char* buffer, char** start, off_t offset, int leng
#if defined(HOSTS_C) || defined(MODULE)
-#define GENERIC_NCR5380 {NULL, NULL, NULL, \
- generic_NCR5380_proc_info, \
- "Generic NCR5380/NCR53C400 Scsi Driver", \
- generic_NCR5380_detect, generic_NCR5380_release_resources, \
- (void *)generic_NCR5380_info, NULL, \
- generic_NCR5380_queue_command, generic_NCR5380_abort, \
- generic_NCR5380_reset, NULL, \
- NCR5380_BIOSPARAM, \
- /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
- /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
+#define GENERIC_NCR5380 { \
+ proc_info: generic_NCR5380_proc_info, \
+ name: "Generic NCR5380/NCR53C400 Scsi Driver", \
+ detect: generic_NCR5380_detect, \
+ release: generic_NCR5380_release_resources, \
+ info: (void *)generic_NCR5380_info, \
+ queuecommand: generic_NCR5380_queue_command, \
+ abort: generic_NCR5380_abort, \
+ reset: generic_NCR5380_reset, \
+ bios_param: NCR5380_BIOSPARAM, \
+ can_queue: CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: CMD_PER_LUN , \
+ use_clustering: DISABLE_CLUSTERING}
#endif
diff --git a/drivers/scsi/gdth.h b/drivers/scsi/gdth.h
index 4e2c47742..ad2c3eed0 100644
--- a/drivers/scsi/gdth.h
+++ b/drivers/scsi/gdth.h
@@ -670,51 +670,26 @@ int gdth_reset(Scsi_Cmnd *);
const char *gdth_info(struct Scsi_Host *);
-#if LINUX_VERSION_CODE >= 0x010300
int gdth_bios_param(Disk *,kdev_t,int *);
extern struct proc_dir_entry proc_scsi_gdth;
int gdth_proc_info(char *,char **,off_t,int,int,int);
-#define GDTH { NULL, NULL, \
- &proc_scsi_gdth, \
- gdth_proc_info, \
- "GDT SCSI Disk Array Controller", \
- gdth_detect, \
- gdth_release, \
- gdth_info, \
- gdth_command, \
- gdth_queuecommand, \
- gdth_abort, \
- gdth_reset, \
- NULL, \
- gdth_bios_param, \
- GDTH_MAXCMDS, \
- -1, \
- GDTH_MAXSG, \
- GDTH_MAXC_P_L, \
- 0, \
- 1, \
- ENABLE_CLUSTERING}
-#else
-int gdth_bios_param(Disk *,int,int *);
-#define GDTH { NULL, NULL, \
- "GDT SCSI Disk Array Controller", \
- gdth_detect, \
- gdth_release, \
- gdth_info, \
- gdth_command, \
- gdth_queuecommand, \
- gdth_abort, \
- gdth_reset, \
- NULL, \
- gdth_bios_param, \
- GDTH_MAXCMDS, \
- -1, \
- GDTH_MAXSG, \
- GDTH_MAXC_P_L, \
- 0, \
- 1, \
- ENABLE_CLUSTERING}
-#endif
+#define GDTH { proc_dir: &proc_scsi_gdth, \
+ proc_info: gdth_proc_info, \
+ name: "GDT SCSI Disk Array Controller", \
+ detect: gdth_detect, \
+ release: gdth_release, \
+ info: gdth_info, \
+ command: gdth_command, \
+ queuecommand: gdth_queuecommand, \
+ abort: gdth_abort, \
+ reset: gdth_reset, \
+ bios_param: gdth_bios_param, \
+ can_queue: GDTH_MAXCMDS, \
+ this_id: -1, \
+ sg_tablesize: GDTH_MAXSG, \
+ cmd_per_lun: GDTH_MAXC_P_L, \
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING}
#endif
diff --git a/drivers/scsi/gdth_proc.c b/drivers/scsi/gdth_proc.c
index 1a34996a1..3fd6968b3 100644
--- a/drivers/scsi/gdth_proc.c
+++ b/drivers/scsi/gdth_proc.c
@@ -620,12 +620,12 @@ static int gdth_update_timeout(Scsi_Cmnd *scp, int timeout)
oldto = scp->timeout;
scp->timeout = timeout;
if (timeout > 0) {
- if (timer_table[SCSI_TIMER].expires == 0) {
- timer_table[SCSI_TIMER].expires = jiffies + timeout;
- timer_active |= 1 << SCSI_TIMER;
+ if (timer_table[GDTH_TIMER].expires == 0) {
+ timer_table[GDTH_TIMER].expires = jiffies + timeout;
+ timer_active |= 1 << GDTH_TIMER;
} else {
- if (jiffies + timeout < timer_table[SCSI_TIMER].expires)
- timer_table[SCSI_TIMER].expires = jiffies + timeout;
+ if (jiffies + timeout < timer_table[GDTH_TIMER].expires)
+ timer_table[GDTH_TIMER].expires = jiffies + timeout;
}
}
diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h
index 77004d0d3..d03886baa 100644
--- a/drivers/scsi/gvp11.h
+++ b/drivers/scsi/gvp11.h
@@ -34,27 +34,18 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
extern struct proc_dir_entry proc_scsi_gvp11;
-#define GVP11_SCSI { /* next */ NULL, \
- /* module */ NULL, \
- /* proc_dir_entry */ &proc_scsi_gvp11, \
- /* proc_info */ NULL, \
- /* name */ "GVP Series II SCSI", \
- /* detect */ gvp11_detect, \
- /* release */ gvp11_release, \
- /* info */ NULL, \
- /* command */ NULL, \
- /* queuecommand */ wd33c93_queuecommand, \
- /* abort */ wd33c93_abort, \
- /* reset */ wd33c93_reset, \
- /* slave_attach */ NULL, \
- /* bios_param */ NULL, \
- /* can_queue */ CAN_QUEUE, \
- /* this_id */ 7, \
- /* sg_tablesize */ SG_ALL, \
- /* cmd_per_lun */ CMD_PER_LUN, \
- /* present */ 0, \
- /* unchecked_isa_dma */ 0, \
- /* use_clustering */ DISABLE_CLUSTERING }
+#define GVP11_SCSI { proc_dir: &proc_scsi_gvp11, \
+ name: "GVP Series II SCSI", \
+ detect: gvp11_detect, \
+ release: gvp11_release, \
+ queuecommand: wd33c93_queuecommand, \
+ abort: wd33c93_abort, \
+ reset: wd33c93_reset, \
+ can_queue: CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: CMD_PER_LUN, \
+ use_clustering: DISABLE_CLUSTERING }
#else
/*
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 4c62c2df4..e9ea1be59 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -16,11 +16,6 @@
* hosts currently present in the system.
*/
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
#define __NO_VERSION__
#include <linux/module.h>
@@ -32,6 +27,10 @@
#include <linux/proc_fs.h>
#include <linux/init.h>
+#define __KERNEL_SYSCALLS__
+
+#include <linux/unistd.h>
+
#include "scsi.h"
#ifndef NULL
@@ -447,7 +446,9 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
struct Scsi_Host * retval, *shpnt;
retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j,
(tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
+ atomic_set(&retval->host_active,0);
retval->host_busy = 0;
+ retval->host_failed = 0;
retval->block = NULL;
retval->wish_block = 0;
if(j > 0xffff) panic("Too many extra bytes requested\n");
@@ -470,6 +471,16 @@ struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
retval->io_port = 0;
retval->hostt = tpnt;
retval->next = NULL;
+ retval->in_recovery = 0;
+ retval->ehandler = NULL; /* Initial value until the thing starts up. */
+ retval->eh_notify = NULL; /* Who we notify when we exit. */
+
+ /*
+ * Initialize the fields used for mid-level queueing.
+ */
+ retval->pending_commands = NULL;
+ retval->host_busy = FALSE;
+
#ifdef DEBUG
printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
#endif
@@ -506,6 +517,32 @@ scsi_register_device(struct Scsi_Device_Template * sdpnt)
return 0;
}
+/*
+ * Why is this a seperate function? Because the kernel_thread code
+ * effectively does a fork, and there is a builtin exit() call when
+ * the child returns. The difficulty is that scsi_init() is
+ * marked __initfunc(), which means the memory is unmapped after bootup
+ * is complete, which means that the thread's exit() call gets wiped.
+ *
+ * The lesson is to *NEVER*, *NEVER* call kernel_thread() from an
+ * __initfunc() function, if that function could ever return.
+ */
+static void launch_error_handler_thread(struct Scsi_Host * shpnt)
+{
+ struct semaphore sem = MUTEX_LOCKED;
+
+ shpnt->eh_notify = &sem;
+
+ kernel_thread((int (*)(void *))scsi_error_handler,
+ (void *) shpnt, 0);
+ /*
+ * Now wait for the kernel error thread to initialize itself
+ * as it might be needed when we scan the bus.
+ */
+ down (&sem);
+ shpnt->eh_notify = NULL;
+}
+
__initfunc(unsigned int scsi_init(void))
{
static int called = 0;
@@ -556,6 +593,14 @@ __initfunc(unsigned int scsi_init(void))
name = shpnt->hostt->name;
printk ("scsi%d : %s\n", /* And print a little message */
shpnt->host_no, name);
+
+ /*
+ * Now start the error recovery thread for the host.
+ */
+ if( shpnt->hostt->use_new_eh_code )
+ {
+ launch_error_handler_thread(shpnt);
+ }
}
printk ("scsi : %d host%s.\n", next_scsi_host,
diff --git a/drivers/scsi/hosts.h b/drivers/scsi/hosts.h
index d7e366350..f41438eea 100644
--- a/drivers/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -127,10 +127,34 @@ typedef struct SHT
* # and exit result when the command is complete.
* Host number is the POSITION IN THE hosts array of THIS
* host adapter.
+ *
+ * The done() function must only be called after QueueCommand()
+ * has returned.
*/
int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
/*
+ * This is an error handling strategy routine. You don't need to
+ * define one of these if you don't want to - there is a default
+ * routine that is present that should work in most cases. For those
+ * driver authors that have the inclination and ability to write their
+ * own strategy routine, this is where it is specified. Note - the
+ * strategy routine is *ALWAYS* run in the context of the kernel eh
+ * thread. Thus you are guaranteed to *NOT* be in an interrupt handler
+ * when you execute this, and you are also guaranteed to *NOT* have any
+ * other commands being queued while you are in the strategy routine.
+ * When you return from this function, operations return to normal.
+ *
+ * See scsi_error.c scsi_unjam_host for additional comments about what
+ * this function should and should not be attempting to do.
+ */
+ int (*eh_strategy_handler)(struct Scsi_Host *);
+ int (*eh_abort_handler)(Scsi_Cmnd *);
+ int (*eh_device_reset_handler)(Scsi_Cmnd *);
+ int (*eh_bus_reset_handler)(Scsi_Cmnd *);
+ int (*eh_host_reset_handler)(Scsi_Cmnd *);
+
+ /*
* Since the mid level driver handles time outs, etc, we want to
* be able to abort the current command. Abort returns 0 if the
* abortion was successful. The field SCpnt->abort reason
@@ -143,6 +167,9 @@ typedef struct SHT
*
* Note that the scsi driver should "clean up" after itself,
* resetting the bus, etc. if necessary.
+ *
+ * NOTE - this interface is depreciated, and will go away. Use
+ * the eh_ routines instead.
*/
int (* abort)(Scsi_Cmnd *);
@@ -155,6 +182,9 @@ typedef struct SHT
* the first place. Some hosts do not implement a reset function,
* and these hosts must call scsi_request_sense(SCpnt) to keep
* the command alive.
+ *
+ * NOTE - this interface is depreciated, and will go away. Use
+ * the eh_ routines instead.
*/
int (* reset)(Scsi_Cmnd *, unsigned int);
@@ -227,6 +257,13 @@ typedef struct SHT
*/
unsigned use_clustering:1;
+ /*
+ * True if this driver uses the new error handling code. This flag is
+ * really only temporary until all of the other drivers get converted
+ * to use the new error handling code.
+ */
+ unsigned use_new_eh_code:1;
+
} Scsi_Host_Template;
/*
@@ -240,14 +277,40 @@ typedef struct SHT
struct Scsi_Host
{
- struct Scsi_Host * next;
+/* private: */
+ /*
+ * This information is private to the scsi mid-layer. Wrapping it in a
+ * struct private is a way of marking it in a sort of C++ type of way.
+ */
+ struct Scsi_Host * next;
+ Scsi_Device * host_queue;
+ /*
+ * List of commands that have been rejected because either the host
+ * or the device was busy. These need to be retried relatively quickly,
+ * but we need to hold onto it for a short period until the host/device
+ * is available.
+ */
+ Scsi_Cmnd * pending_commands;
+
+ struct task_struct * ehandler; /* Error recovery thread. */
+ struct semaphore * eh_wait; /* The error recovery thread waits on
+ this. */
+ struct semaphore * eh_notify; /* wait for eh to begin */
+ struct semaphore * eh_action; /* Wait for specific actions on the
+ host. */
+ unsigned int eh_active:1; /* Indicates the eh thread is awake and active if
+ this is true. */
+ struct wait_queue * host_wait;
+ Scsi_Host_Template * hostt;
+ atomic_t host_active; /* commands checked out */
+ volatile unsigned short host_busy; /* commands actually active on low-level */
+ volatile unsigned short host_failed; /* commands that failed. */
+
+/* public: */
unsigned short extra_bytes;
- volatile unsigned char host_busy;
- char host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
+ unsigned short host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
unsigned long last_reset;
- struct wait_queue *host_wait;
- Scsi_Cmnd *host_queue;
- Scsi_Host_Template * hostt;
+
/*
* These three parameters can be used to allow for wide scsi,
@@ -292,6 +355,8 @@ struct Scsi_Host
int can_queue;
short cmd_per_lun;
short unsigned int sg_tablesize;
+
+ unsigned in_recovery:1;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
/*
@@ -299,9 +364,20 @@ struct Scsi_Host
*/
unsigned loaded_as_module:1;
+ /*
+ * Host has rejected a command because it was busy.
+ */
+ unsigned host_blocked:1;
+
void (*select_queue_depths)(struct Scsi_Host *, Scsi_Device *);
- unsigned long hostdata[0]; /* Used for storage of host specific stuff */
+ /*
+ * We should ensure that this is aligned, both for better performance
+ * and also because some compilers (m68k) don't automatically force
+ * alignment to a 4-byte boundary.
+ */
+ unsigned long hostdata[0] /* Used for storage of host specific stuff */
+ __attribute__ ((aligned (sizeof(unsigned long))));
};
extern struct Scsi_Host * scsi_hostlist;
@@ -333,6 +409,8 @@ unsigned int scsi_init(void);
extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j);
extern void scsi_unregister(struct Scsi_Host * i);
+extern void scsi_mark_host_reset(struct Scsi_Host *Host);
+
#define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
struct Scsi_Device_Template
diff --git a/drivers/scsi/ibmmca.c b/drivers/scsi/ibmmca.c
index 2600f7397..60be3c619 100644
--- a/drivers/scsi/ibmmca.c
+++ b/drivers/scsi/ibmmca.c
@@ -199,10 +199,11 @@
5) Magneto-Optical drives and medium-changers are also recognized, now.
Therefore, we have a completely gapfree recognition of all SCSI-
device-types, that are known by Linux up to kernel 2.1.31.
- 6) The flag CONFIG_SCSI_IBMMCA_DEV_RESET has been inserted. If it is set
- within the configuration, each connected SCSI-device will get a reset
- command during boottime. This can be necessary for some special
- SCSI-devices. (See also the new Config.in file.)
+ 6) The flag SCSI_IBMMCA_DEV_RESET has been inserted. If it is set within
+ the configuration, each connected SCSI-device will get a reset command
+ during boottime. This can be necessary for some special SCSI-devices.
+ This flag should be included in Config.in.
+ (See also the new Config.in file.)
Probable next improvement: bad disk handler.
- Michael Lang
@@ -210,8 +211,64 @@
1) Some debugging and speed optimization applied.
- Michael Lang
+ Dec 15, 1997
+ - chrisb@truespectra.com
+ - made the front panel display thingy optional, specified from the
+ command-line via ibmmcascsi=display. Along the lines of the /LED
+ option for the OS/2 driver.
+ - fixed small bug in the LED display that would hang some machines.
+ - reversed ordering of the drives (using the
+ IBMMCA_SCSI_ORDER_STANDARD define). This is necessary for two main
+ reasons:
+ - users who've already installed Linux won't be screwed. Keep
+ in mind that not everyone is a kernel hacker.
+ - be consistent with the BIOS ordering of the drives. In the
+ BIOS, id 6 is C:, id 0 might be D:. With this scheme, they'd be
+ backwards. This confuses the crap out of those heathens who've
+ got a impure Linux installation (which, <wince>, I'm one of).
+ This whole problem arises because IBM is actually non-standard with
+ the id to BIOS mappings. You'll find, in fdomain.c, a similar
+ comment about a few FD BIOS revisions. The Linux (and apparently
+ industry) standard is that C: maps to scsi id (0,0). Let's stick
+ with that standard.
+ - Since this is technically a branch of my own, I changed the
+ version number to 3.0e-cpb.
+
+ Jan 17, 1998: (v3.0f)
+ 1) Addition of some statistical info for /proc in proc_info.
+ 2) Taking care of the SCSI-assignment problem, dealed by Chris at Dec 15
+ 1997. In fact, IBM is right, concerning the assignment of SCSI-devices
+ to driveletters. It is conform to the ANSI-definition of the SCSI-
+ standard to assign drive C: to SCSI-id 6, because it is the highest
+ hardware priority after the hostadapter (that has still today by
+ default everywhere id 7). Also realtime-operating systems that I use,
+ like LynxOS and OS9, which are quite industrial systems use top-down
+ numbering of the harddisks, that is also starting at id 6. Now, one
+ sits a bit between two chairs. On one hand side, using the define
+ IBMMCA_SCSI_ORDER_STANDARD makes Linux assigning disks conform to
+ the IBM- and ANSI-SCSI-standard and keeps this driver downward
+ compatible to older releases, on the other hand side, people is quite
+ habituated in believing that C: is assigned to (0,0) and much other
+ SCSI-BIOS do so. Therefore, I moved the IBMMCA_SCSI_ORDER_STANDARD
+ define out of the driver and put it into Config.in as subitem of
+ 'IBM SCSI support'. A help, added to Documentation/Configure.help
+ explains the differences between saying 'y' or 'n' to the user, when
+ IBMMCA_SCSI_ORDER_STANDARD prompts, so the ordinary user is enabled to
+ choose the way of assignment, depending on his own situation and gusto.
+ 3) Adapted SCSI_IBMMCA_DEV_RESET to the local naming convention, so it is
+ now called IBMMCA_SCSI_DEV_RESET.
+ 4) Optimization of proc_info and its subroutines.
+ 5) Added more in-source-comments and extended the driver description by
+ some explanation about the SCSI-device-assignment problem.
+ - Michael Lang
+
+ Jan 18, 1998: (v3.0g)
+ 1) Correcting names to be absolutely conform to the later 2.1.x releases.
+ This is necessary for
+ IBMMCA_SCSI_DEV_RESET -> CONFIG_IBMMCA_SCSI_DEV_RESET
+ IBMMCA_SCSI_ORDER_STANDARD -> CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+ - Michael Lang
-
TODO:
- It seems that the handling of bad disks is really bad -
@@ -252,7 +309,12 @@
/*--------------------------------------------------------------------*/
/* current version of this driver-source: */
-#define IBMMCA_SCSI_DRIVER_VERSION "3.0d"
+#define IBMMCA_SCSI_DRIVER_VERSION "3.0f"
+
+/* use standard Linux ordering, where C: maps to (0,0), unlike the IBM
+standard which seems to like C: => (6,0) */
+/* #define IBMMCA_SCSI_ORDER_STANDARD is defined/undefined in Config.in
+ * now, while configuring the kernel. */
/*
Driver Description
@@ -341,8 +403,23 @@
If your boot-partition is not coming up, also edit the /etc/lilo.conf-file
in a Linux session booted on old kernel and run lilo before reboot. Check
lilo.conf anyway to get boot on other partitions with foreign OSes right
- again.
-
+ again.
+
+ The problem is, that Linux does not assign the SCSI-devices in the
+ way as described in the ANSI-SCSI-standard. Linux assigns /dev/sda to
+ the device with at minimum id 0. But the first drive should be at id 6,
+ because for historical reasons, drive at id 6 has, by hardware, the highest
+ priority and a drive at id 0 the lowest. IBM was one of the rare producers,
+ where the BIOS assigns drives belonging to the ANSI-SCSI-standard. Most
+ other producers' BIOS does not (I think even Adaptec-BIOS). The
+ IBMMCA_SCSI_ORDER_STANDARD flag helps to be able to choose the preferred
+ way of SCSI-device-assignment. Defining this flag would result in Linux
+ determining the devices in the same order as DOS and OS/2 does on your
+ MCA-machine. This is also standard on most industrial computers. Leaving
+ this flag undefined will get your devices ordered in the default way of
+ Linux. See also the remarks of Chris Beauregard from Dec 15, 1997 and
+ the followups.
+
(C) Regular Processing
Only three functions get involved: ibmmca_queuecommand(), issue_cmd(),
and interrupt_handler().
@@ -443,7 +520,7 @@
/* basic I/O-port of first adapter */
#define IM_IO_PORT 0x3540
-/* maximum number of hosts that can be find */
+/* maximum number of hosts that can be found */
#define IM_N_IO_PORT 8
/*requests going into the upper nibble of the Attention register */
@@ -589,16 +666,19 @@ struct im_tsb
interest, debugging or just for having fun. The left number gives the
host-adapter number and the right shows the accessed SCSI-ID. */
+/* use_display is set by the ibmmcascsi=display command line arg */
+static int use_display = 0;
#define PS2_DISK_LED_ON(ad,id) {\
- if( machine_id == 0xf8 ) { outb((char)(id+48), MOD95_LED_PORT ); \
+ if( use_display ) { outb((char)(id+48), MOD95_LED_PORT ); \
outb((char)(ad+48), MOD95_LED_PORT+1); } \
else outb(inb(PS2_SYS_CTR) | 0xc0, PS2_SYS_CTR); \
}
+/* bug fixed, Dec 15, 1997, where | was replaced by & here */
#define PS2_DISK_LED_OFF() {\
- if( machine_id == 0xf8 ) { outb( ' ', MOD95_LED_PORT ); \
+ if( use_display ) { outb( ' ', MOD95_LED_PORT ); \
outb(' ', MOD95_LED_PORT+1); } \
- else outb(inb(PS2_SYS_CTR) | 0x3f, PS2_SYS_CTR); \
+ else outb(inb(PS2_SYS_CTR) & 0x3f, PS2_SYS_CTR); \
}
/*--------------------------------------------------------------------*/
@@ -609,6 +689,8 @@ struct subsys_list_struct
unsigned short mca_id;
char *description;
};
+
+/* List of possible IBM-SCSI-adapters */
struct subsys_list_struct subsys_list[] =
{
{0x8efc, "IBM Fast SCSI-2 Adapter"},
@@ -632,14 +714,14 @@ of the adapter itself. */
/*local data for a logical device */
struct logical_device
{
- struct im_scb scb;
+ struct im_scb scb; /* SCSI-subsystem-control-block structure */
struct im_tsb tsb;
struct im_sge sge[16];
Scsi_Cmnd *cmd; /* SCSI-command that is currently in progress */
int device_type; /* type of the SCSI-device. See include/scsi/scsi.h
- for interpreation of the possible values */
- int block_length;
+ for interpretation of the possible values */
+ int block_length;/* blocksize of a particular logical SCSI-device */
};
/* statistics of the driver during operations (for proc_info) */
@@ -649,6 +731,8 @@ struct Driver_Statistics
int ldn_access[MAX_LOG_DEV+1]; /* total accesses on a ldn */
int ldn_read_access[MAX_LOG_DEV+1]; /* total read-access on a ldn */
int ldn_write_access[MAX_LOG_DEV+1]; /* total write-access on a ldn */
+ int ldn_inquiry_access[MAX_LOG_DEV+1]; /* total inquiries on a ldn */
+ int ldn_modeselect_access[MAX_LOG_DEV+1]; /* total mode selects on ldn */
int total_accesses; /* total accesses on all ldns */
int total_interrupts; /* total interrupts (should be
same as total_accesses) */
@@ -663,26 +747,28 @@ struct Driver_Statistics
/* data structure for each host adapter */
struct ibmmca_hostdata
{
- /* array of logical devices */
- struct logical_device _ld[MAX_LOG_DEV];
- /* array to convert (pun, lun) into logical device number */
+ /* array of logical devices: */
+ struct logical_device _ld[MAX_LOG_DEV];
+ /* array to convert (pun, lun) into logical device number: */
unsigned char _get_ldn[8][8];
/*array that contains the information about the physical SCSI-devices
- attached to this host adapter */
+ attached to this host adapter: */
unsigned char _get_scsi[8][8];
- /* used only when checking logical devices */
+ /* used only when checking logical devices: */
int _local_checking_phase_flag;
+ /* report received interrupt: */
int _got_interrupt;
+ /* report termination-status of SCSI-command: */
int _stat_result;
- /* reset status (used only when doing reset) */
+ /* reset status (used only when doing reset): */
int _reset_status;
- /* code of the last SCSI command (needed for panic info) */
+ /* code of the last SCSI command (needed for panic info): */
int _last_scsi_command;
- /* counter that points on next reassignable ldn for dynamical remapping */
- /* The default value is 7, that is the first reassignable number in
- the list on startup. */
+ /* Counter that points on the next reassignable ldn for dynamical
+ remapping. The default value is 7, that is the first reassignable
+ number in the list at boottime: */
int _next_ldn;
- /* Statistics for this IBM-SCSI-host */
+ /* Statistics-structure for this IBM-SCSI-host: */
struct Driver_Statistics _IBM_DS;
};
@@ -701,21 +787,21 @@ struct ibmmca_hostdata
#define IBM_DS (HOSTDATA(shpnt)->_IBM_DS)
/* Define a arbitrary number as subsystem-marker-type. This number is, as
- described in the SCSI-Standard, not occupied by other device-types. */
+ described in the ANSI-SCSI-standard, not occupied by other device-types. */
#define TYPE_IBM_SCSI_ADAPTER 0x2F
/* Define 0xFF for no device type, because this type is not defined within
- the SCSI-standard, therefore, it can be used and should not cause any
+ the ANSI-SCSI-standard, therefore, it can be used and should not cause any
harm. */
#define TYPE_NO_DEVICE 0xFF
-/* define medium-changer. If this is not defined previously, define
- this type here. */
+/* define medium-changer. If this is not defined previously, e.g. Linux
+ 2.0.x, define this type here. */
#ifndef TYPE_MEDIUM_CHANGER
#define TYPE_MEDIUM_CHANGER 0x08
#endif
-/* define operations for immediate_assign */
+/* define possible operations for the immediate_assign command */
#define SET_LDN 0
#define REMOVE_LDN 1
@@ -732,7 +818,7 @@ static int io_port[IM_MAX_HOSTS] = { 0, 0, 0, 0, 0, 0, 0, 0 };
static int scsi_id[IM_MAX_HOSTS] = { 7, 7, 7, 7, 7, 7, 7, 7 };
/* fill module-parameters only, when this define is present.
- (that is kernel >=2.1.0) */
+ (that is kernel version 2.1.x) */
#ifdef MODULE_PARM
MODULE_PARM(io_port, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");
MODULE_PARM(scsi_id, "1-" __MODULE_STRING(IM_MAX_HOSTS) "i");
@@ -1036,24 +1122,19 @@ static char *ti_p(int value)
return("-");
}
-/* type-interpreter for logical devices
- (A bit stupid, but it was necessary to get the '-' and the Hex-codes
- into one type.) */
+/* interpreter for logical device numbers (ldn) */
static char *ti_l(int value)
{
- switch (value)
- {
- case 0: return("0"); break; case 1: return("1"); break;
- case 2: return("2"); break; case 3: return("3"); break;
- case 4: return("4"); break; case 5: return("5"); break;
- case 6: return("6"); break; case 7: return("7"); break;
- case 8: return("8"); break; case 9: return("9"); break;
- case 10: return("a"); break; case 11: return("b"); break;
- case 12: return("c"); break; case 13: return("d"); break;
- case 14: return("e"); break; case 15: return("f"); break;
- default: return("-"); break;
- }
- return("-");
+ const char hex[16] = ("0123456789abcdef");
+ static char answer[2];
+
+ answer[1] = (char)(0x0);
+ if (value<=MAX_LOG_DEV)
+ answer[0] = hex[value];
+ else
+ answer[0] = '-';
+
+ return (char *)&answer;
}
/*
@@ -1093,7 +1174,7 @@ static void check_devices (struct Scsi_Host *shpnt)
memset (get_ldn, TYPE_NO_DEVICE, sizeof get_ldn); /* this is essential ! */
memset (get_scsi, TYPE_NO_DEVICE, sizeof get_scsi); /* this is essential ! */
- for (lun=0; lun<=7; lun++) /* mark the adapter at its pun on all luns*/
+ for (lun=0; lun<8; lun++) /* mark the adapter at its pun on all luns*/
{
get_scsi[subsystem_pun][lun] = TYPE_IBM_SCSI_ADAPTER;
get_ldn[subsystem_pun][lun] = MAX_LOG_DEV; /* make sure, the subsystem
@@ -1111,13 +1192,13 @@ static void check_devices (struct Scsi_Host *shpnt)
immediate_assign(shpnt,0,0,ldn,REMOVE_LDN); /* remove ldn (wherever)*/
}
- lun = 0;
+ lun = 0; /* default lun is 0 */
/* STEP 2: */
printk("\nIBM MCA SCSI: Probing SCSI-devices.");
- for (id=0; id<=7; id++)
+ for (id=0; id<8; id++)
#ifdef CONFIG_SCSI_MULTI_LUN
- for (lun=0; lun<=7; lun++)
+ for (lun=0; lun<8; lun++)
#endif
{
#ifdef IM_DEBUG_PROBE
@@ -1137,16 +1218,16 @@ static void check_devices (struct Scsi_Host *shpnt)
}
}
- /* STEP 3: */
+ /* STEP 3: */
printk("\nIBM MCA SCSI: Mapping SCSI-devices.");
ldn = 0;
lun = 0;
#ifdef CONFIG_SCSI_MULTI_LUN
- for (lun=0; lun<=7 && ldn<MAX_LOG_DEV; lun++)
+ for (lun=0; lun<8 && ldn<MAX_LOG_DEV; lun++)
#endif
- for (id=0; id<=7 && ldn<MAX_LOG_DEV; id++)
+ for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
{
#ifdef IM_DEBUG_PROBE
printk(".");
@@ -1163,7 +1244,7 @@ static void check_devices (struct Scsi_Host *shpnt)
if (device_exists (shpnt, ldn, &ld[ldn].block_length,
&ld[ldn].device_type))
{
-#ifdef CONFIG_SCSI_IBMMCA_DEV_RESET
+#ifdef CONFIG_IBMMCA_SCSI_DEV_RESET
int ticks;
printk("(resetting)");
ticks = IM_RESET_DELAY*HZ;
@@ -1211,8 +1292,8 @@ static void check_devices (struct Scsi_Host *shpnt)
/* STEP 4: */
/* map remaining ldns to non-existing devices */
- for (lun=1; lun<=7 && ldn<MAX_LOG_DEV; lun++)
- for (id=0; id<=7 && ldn<MAX_LOG_DEV; id++)
+ for (lun=1; lun<8 && ldn<MAX_LOG_DEV; lun++)
+ for (id=0; id<8 && ldn<MAX_LOG_DEV; id++)
{
if (get_scsi[id][lun] == TYPE_NO_LUN ||
get_scsi[id][lun] == TYPE_NO_DEVICE)
@@ -1228,24 +1309,29 @@ static void check_devices (struct Scsi_Host *shpnt)
}
printk("\n");
-
+#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+ printk("IBM MCA SCSI: SCSI-access-order: IBM/ANSI.\n");
+#else
+ printk("IBM MCA SCSI: SCSI-access-order: Linux.\n");
+#endif
+
#ifdef IM_DEBUG_PROBE
/* Show the physical and logical mapping during boot. */
printk("IBM MCA SCSI: Determined SCSI-device-mapping:\n");
printk(" Physical SCSI-Device Map Logical SCSI-Device Map\n");
printk("ID\\LUN 0 1 2 3 4 5 6 7 ID\\LUN 0 1 2 3 4 5 6 7\n");
- for (id=0; id<=7; id++)
+ for (id=0; id<8; id++)
{
- printk("%2d %2s %2s %2s %2s %2s %2s %2s %2s",
- id, ti_p(get_scsi[id][0]), ti_p(get_scsi[id][1]),
- ti_p(get_scsi[id][2]), ti_p(get_scsi[id][3]),
- ti_p(get_scsi[id][4]), ti_p(get_scsi[id][5]),
- ti_p(get_scsi[id][6]), ti_p(get_scsi[id][7]));
- printk(" %2d %2s %2s %2s %2s %2s %2s %2s %2s\n",
- id, ti_l(get_ldn[id][0]), ti_l(get_ldn[id][1]),
- ti_l(get_ldn[id][2]), ti_l(get_ldn[id][3]),
- ti_l(get_ldn[id][4]), ti_l(get_ldn[id][5]),
- ti_l(get_ldn[id][6]), ti_l(get_ldn[id][7]));
+ printk("%2d %2s %2s %2s %2s %2s %2s %2s %2s",
+ id, ti_p(get_scsi[id][0]), ti_p(get_scsi[id][1]),
+ ti_p(get_scsi[id][2]), ti_p(get_scsi[id][3]),
+ ti_p(get_scsi[id][4]), ti_p(get_scsi[id][5]),
+ ti_p(get_scsi[id][6]), ti_p(get_scsi[id][7]));
+
+ printk(" %2d ",id);
+ for (lun=0; lun<8; lun++)
+ printk("%2s ",ti_l(get_ldn[id][lun]));
+ printk("\n");
}
#endif
@@ -1270,6 +1356,8 @@ static void check_devices (struct Scsi_Host *shpnt)
memset (IBM_DS.ldn_access, 0x0, sizeof (IBM_DS.ldn_access));
memset (IBM_DS.ldn_read_access, 0x0, sizeof (IBM_DS.ldn_read_access));
memset (IBM_DS.ldn_write_access, 0x0, sizeof (IBM_DS.ldn_write_access));
+ memset (IBM_DS.ldn_inquiry_access, 0x0, sizeof (IBM_DS.ldn_inquiry_access));
+ memset (IBM_DS.ldn_modeselect_access, 0x0, sizeof (IBM_DS.ldn_modeselect_access));
memset (IBM_DS.ldn_assignments, 0x0, sizeof (IBM_DS.ldn_assignments));
return;
@@ -1412,10 +1500,14 @@ device_exists (struct Scsi_Host *shpnt, int ldn, int *block_length,
void
ibmmca_scsi_setup (char *str, int *ints)
{
- int i;
-
- for (i = 0; i < IM_MAX_HOSTS && i < ints[0]; i++)
- io_port[i] = ints[i+1];
+ if( str && !strcmp( str, "display" ) ) {
+ use_display = 1;
+ } else if( ints ) {
+ int i;
+ for (i = 0; i < IM_MAX_HOSTS && i < ints[0]; i++) {
+ io_port[i] = ints[i+1];
+ }
+ }
}
#endif
@@ -1597,9 +1689,16 @@ int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
int current_ldn;
int id,lun;
+ /* use industry standard ordering of the IDs */
+#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+ int target = 6 - cmd->target;
+#else
+ int target = cmd->target;
+#endif
+
/*if (target,lun) is NO LUN or not existing at all, return error */
- if ((get_scsi[cmd->target][cmd->lun] == TYPE_NO_LUN)||
- (get_scsi[cmd->target][cmd->lun] == TYPE_NO_DEVICE))
+ if ((get_scsi[target][cmd->lun] == TYPE_NO_LUN)||
+ (get_scsi[target][cmd->lun] == TYPE_NO_DEVICE))
{
cmd->result = DID_NO_CONNECT << 16;
done (cmd);
@@ -1607,7 +1706,7 @@ int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
}
/*if (target,lun) unassigned, do further checks... */
- ldn = get_ldn[cmd->target][cmd->lun];
+ ldn = get_ldn[target][cmd->lun];
if (ldn >= MAX_LOG_DEV) /* on invalid ldn do special stuff */
{
if (ldn > MAX_LOG_DEV) /* dynamical remapping if ldn unassigned */
@@ -1623,7 +1722,7 @@ int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
printk("IBM MCA SCSI: Cannot assign SCSI-device dynamically!\n");
printk(" On ldn 7-14 SCSI-commands everywhere in progress.\n");
printk(" Reporting DID_NO_CONNECT for device (%d,%d).\n",
- cmd->target, cmd->lun);
+ target, cmd->lun);
cmd->result = DID_NO_CONNECT << 16;/* return no connect*/
done (cmd);
return 0;
@@ -1631,8 +1730,8 @@ int ibmmca_queuecommand (Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
}
/* unmap non-processing ldn */
- for (id=0; id<=7; id ++)
- for (lun=0; lun<=7; lun++)
+ for (id=0; id<8; id ++)
+ for (lun=0; lun<8; lun++)
{
if (get_ldn[id][lun] == next_ldn)
{
@@ -1645,9 +1744,9 @@ DYN_ASSIGN:
/* unassign found ldn (pun,lun does not matter for remove) */
immediate_assign(shpnt,0,0,next_ldn,REMOVE_LDN);
/* assign found ldn to aimed pun,lun */
- immediate_assign(shpnt,cmd->target,cmd->lun,next_ldn,SET_LDN);
+ immediate_assign(shpnt,target,cmd->lun,next_ldn,SET_LDN);
/* map found ldn to pun,lun */
- get_ldn[cmd->target][cmd->lun] = next_ldn;
+ get_ldn[target][cmd->lun] = next_ldn;
/* change ldn to the right value, that is now next_ldn */
ldn = next_ldn;
/* set reduced interrupt_handler-mode for checking */
@@ -1668,19 +1767,19 @@ DYN_ASSIGN:
/* panic here, because a device, found at boottime has
vanished */
panic("IBM MCA SCSI: ldn=0x%x, SCSI-device on (%d,%d) vanished!\n",
- ldn, cmd->target, cmd->lun);
+ ldn, target, cmd->lun);
/* set back to normal interrupt_handling */
local_checking_phase_flag = 0;
/* Information on syslog terminal */
printk("IBM MCA SCSI: ldn=0x%x dynamically reassigned to (%d,%d).\n",
- ldn, cmd->target, cmd->lun);
+ ldn, target, cmd->lun);
/* increase next_ldn for next dynamical assignment */
next_ldn ++;
if (next_ldn>=MAX_LOG_DEV) next_ldn = 7;
- }
+ }
else
{ /* wall against Linux accesses to the subsystem adapter */
cmd->result = DID_NO_CONNECT << 16;
@@ -1729,7 +1828,7 @@ DYN_ASSIGN:
printk("issue scsi cmd=%02x to ldn=%d\n", scsi_cmd, ldn);
#endif
- /* for specific device debugging: */
+ /* for specific device-type debugging: */
#ifdef IM_DEBUG_CMD_SPEC_DEV
if (ld[ldn].device_type==IM_DEBUG_CMD_DEVICE)
printk("(SCSI-device-type=0x%x) issue scsi cmd=%02x to ldn=%d\n",
@@ -1794,7 +1893,7 @@ DYN_ASSIGN:
}
scb->u2.blk.length = ld[ldn].block_length;
if (++disk_rw_in_progress == 1)
- PS2_DISK_LED_ON (shpnt->host_no, cmd->target);
+ PS2_DISK_LED_ON (shpnt->host_no, target);
break;
/* for other devices, enter here. Other types are not known by
@@ -1830,11 +1929,12 @@ DYN_ASSIGN:
/* Read/write on this non-disk devices is also displayworthy,
so flash-up the LED/display. */
if (++disk_rw_in_progress == 1)
- PS2_DISK_LED_ON (shpnt->host_no, cmd->target);
+ PS2_DISK_LED_ON (shpnt->host_no, target);
break;
}
break;
case INQUIRY:
+ IBM_DS.ldn_inquiry_access[ldn]++;
scb->command = IM_DEVICE_INQUIRY_CMD;
scb->enable |= IM_READ_CONTROL | IM_SUPRESS_EXCEPTION_SHORT;
break;
@@ -1856,6 +1956,7 @@ DYN_ASSIGN:
/* Commands that need write-only-mode (system -> device): */
case MODE_SELECT:
case MODE_SELECT_10:
+ IBM_DS.ldn_modeselect_access[ldn]++;
scb->command = IM_OTHER_SCSI_CMD_CMD;
scb->enable |= IM_SUPRESS_EXCEPTION_SHORT; /*Select needs WRITE-enabled*/
scb->u1.scsi_cmd_length = cmd->cmd_len;
@@ -1892,10 +1993,16 @@ ibmmca_abort (Scsi_Cmnd * cmd)
unsigned int ldn;
void (*saved_done) (Scsi_Cmnd *);
+#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+ int target = 6 - cmd->target;
+#else
+ int target = cmd->target;
+#endif
+
/*get logical device number, and disable system interrupts */
printk ("IBM MCA SCSI: sending abort to device id=%d lun=%d.\n",
- cmd->target, cmd->lun);
- ldn = get_ldn[cmd->target][cmd->lun];
+ target, cmd->lun);
+ ldn = get_ldn[target][cmd->lun];
cli ();
/*if cmd for this ldn has already finished, no need to abort */
@@ -2027,12 +2134,32 @@ static int ldn_access_total_read_write(struct Scsi_Host *shpnt)
return(a);
}
+static int ldn_access_total_inquiry(struct Scsi_Host *shpnt)
+{
+ int a = 0;
+ int i;
+
+ for (i=0; i<=MAX_LOG_DEV; i++)
+ a+=IBM_DS.ldn_inquiry_access[i];
+ return(a);
+}
+
+static int ldn_access_total_modeselect(struct Scsi_Host *shpnt)
+{
+ int a = 0;
+ int i;
+
+ for (i=0; i<=MAX_LOG_DEV; i++)
+ a+=IBM_DS.ldn_modeselect_access[i];
+ return(a);
+}
+
/* routine to display info in the proc-fs-structure (a deluxe feature) */
int ibmmca_proc_info (char *buffer, char **start, off_t offset, int length,
int hostno, int inout)
{
int len=0;
- int i,id;
+ int i,id,lun;
struct Scsi_Host *shpnt;
for (i = 0; hosts[i] && hosts[i]->host_no != hostno; i++);
@@ -2047,6 +2174,11 @@ int ibmmca_proc_info (char *buffer, char **start, off_t offset, int length,
len += sprintf(buffer+len, "\n IBM-SCSI-Subsystem-Linux-Driver, Version %s\n\n\n",
IBMMCA_SCSI_DRIVER_VERSION);
len += sprintf(buffer+len, " SCSI Access-Statistics:\n");
+#ifdef CONFIG_IBMMCA_SCSI_ORDER_STANDARD
+ len += sprintf(buffer+len, " ANSI-SCSI-standard order.: Yes\n");
+#else
+ len += sprintf(buffer+len, " ANSI-SCSI-standard order.: No\n");
+#endif
#ifdef CONFIG_SCSI_MULTI_LUN
len += sprintf(buffer+len, " Multiple LUN probing.....: Yes\n");
#else
@@ -2064,8 +2196,14 @@ int ibmmca_proc_info (char *buffer, char **start, off_t offset, int length,
IBM_DS.total_accesses);
len += sprintf(buffer+len, " Total SCSI READ/WRITE..: %d\n",
ldn_access_total_read_write(shpnt));
+ len += sprintf(buffer+len, " Total SCSI Inquiries...: %d\n",
+ ldn_access_total_inquiry(shpnt));
+ len += sprintf(buffer+len, " Total SCSI Modeselects.: %d\n",
+ ldn_access_total_modeselect(shpnt));
len += sprintf(buffer+len, " Total SCSI other cmds..: %d\n\n",
- IBM_DS.total_accesses - ldn_access_total_read_write(shpnt));
+ IBM_DS.total_accesses - ldn_access_total_read_write(shpnt)
+ - ldn_access_total_modeselect(shpnt)
+ - ldn_access_total_inquiry(shpnt));
len += sprintf(buffer+len, " Logical-Device-Number (LDN) Access-Statistics:\n");
len += sprintf(buffer+len, " LDN | Accesses [%%] | READ | WRITE | ASSIGNMENTS\n");
@@ -2096,11 +2234,11 @@ int ibmmca_proc_info (char *buffer, char **start, off_t offset, int length,
ti_p(get_scsi[id][2]), ti_p(get_scsi[id][3]),
ti_p(get_scsi[id][4]), ti_p(get_scsi[id][5]),
ti_p(get_scsi[id][6]), ti_p(get_scsi[id][7]));
- len += sprintf(buffer+len, " %2d %2s %2s %2s %2s %2s %2s %2s %2s\n",
- id, ti_l(get_ldn[id][0]), ti_l(get_ldn[id][1]),
- ti_l(get_ldn[id][2]), ti_l(get_ldn[id][3]),
- ti_l(get_ldn[id][4]), ti_l(get_ldn[id][5]),
- ti_l(get_ldn[id][6]), ti_l(get_ldn[id][7]));
+
+ len += sprintf(buffer+len, " %2d ",id);
+ for (lun=0; lun<8; lun++)
+ len += sprintf(buffer+len,"%2s ",ti_l(get_ldn[id][lun]));
+ len += sprintf(buffer+len,"\n");
}
len += sprintf(buffer+len, "(A = IBM-Subsystem, D = Harddisk, T = Tapedrive, P = Processor, W = WORM,\n");
@@ -2125,3 +2263,6 @@ Scsi_Host_Template driver_template = IBMMCA;
#endif
/*--------------------------------------------------------------------*/
+
+
+
diff --git a/drivers/scsi/ibmmca.h b/drivers/scsi/ibmmca.h
index 4306f52ac..0bf4b3517 100644
--- a/drivers/scsi/ibmmca.h
+++ b/drivers/scsi/ibmmca.h
@@ -19,28 +19,30 @@ int ibmmca_biosparam (Disk *, kdev_t, int *);
extern struct proc_dir_entry proc_scsi_ibmmca;
/*initialization for Scsi_host_template type */
-#define IBMMCA { \
- NULL, /*next*/ \
- NULL, /*usage_count*/ \
- &proc_scsi_ibmmca, /*proc_dir*/ \
- ibmmca_proc_info, /*proc info fn*/ \
- "IBMMCA", /*name*/ \
- ibmmca_detect, /*detect fn*/ \
- ibmmca_release, /*release fn*/ \
- NULL, /*info fn*/ \
- ibmmca_command, /*command fn*/ \
- ibmmca_queuecommand, /*queuecommand fn*/ \
- ibmmca_abort, /*abort fn*/ \
- ibmmca_reset, /*reset fn*/ \
- NULL, /*slave_attach fn*/ \
- ibmmca_biosparam, /*bios fn*/ \
- 16, /*can_queue*/ \
- 7, /*set by detect*/ \
- 16, /*sg_tablesize*/ \
- 1, /*cmd_per_lun*/ \
- 0, /*present*/ \
- 0, /*unchecked_isa_dma*/ \
- ENABLE_CLUSTERING /*use_clustering*/ \
- }
+/*
+ * 2/8/98
+ * Note to maintainer of IBMMCA. Do not change this initializer back to
+ * the old format. Please ask eric@andante.jic.com if you have any questions
+ * about this, but it will break things in the future.
+ */
+#define IBMMCA { \
+ proc_dir: &proc_scsi_ibmmca, /*proc_dir*/ \
+ proc_info: ibmmca_proc_info, /*proc info fn*/ \
+ name: "IBMMCA", /*name*/ \
+ detect: ibmmca_detect, /*detect fn*/ \
+ release: ibmmca_release, /*release fn*/ \
+ command: ibmmca_command, /*command fn*/ \
+ queuecommand: ibmmca_queuecommand, /*queuecommand fn*/ \
+ abort: ibmmca_abort, /*abort fn*/ \
+ reset: ibmmca_reset, /*reset fn*/ \
+ bios_param: ibmmca_biosparam, /*bios fn*/ \
+ can_queue: 16, /*can_queue*/ \
+ this_id: 7, /*set by detect*/ \
+ sg_tablesize: 16, /*sg_tablesize*/ \
+ cmd_per_lun: 1, /*cmd_per_lun*/ \
+ use_clustering: ENABLE_CLUSTERING /*use_clustering*/ \
+ }
#endif /* _IBMMCA_H */
+
+
diff --git a/drivers/scsi/ide-scsi.c b/drivers/scsi/ide-scsi.c
index ff3264da3..0bfa8d876 100644
--- a/drivers/scsi/ide-scsi.c
+++ b/drivers/scsi/ide-scsi.c
@@ -1,7 +1,7 @@
/*
- * linux/drivers/scsi/ide-scsi.c Version 0.4 Dec 7, 1997
+ * linux/drivers/scsi/ide-scsi.c Version 0.5 Jan 2, 1998
*
- * Copyright (C) 1996, 1997 Gadi Oxman <gadio@netvision.net.il>
+ * Copyright (C) 1996 - 1998 Gadi Oxman <gadio@netvision.net.il>
*/
/*
@@ -18,9 +18,11 @@
* Added Scatter/Gather and DMA support.
* Ver 0.4 Dec 7 97 Add support for ATAPI PD/CD drives.
* Use variable timeout for each command.
+ * Ver 0.5 Jan 2 98 Fix previous PD/CD support.
+ * Allow disabling of SCSI-6 to SCSI-10 transformation.
*/
-#define IDESCSI_VERSION "0.4"
+#define IDESCSI_VERSION "0.5"
#include <linux/module.h>
#include <linux/types.h>
@@ -71,6 +73,7 @@ typedef struct {
ide_drive_t *drive;
idescsi_pc_t *pc; /* Current packet command */
unsigned int flags; /* Status/Action flags */
+ int transform; /* Transform SCSI-6 commands */
} idescsi_scsi_t;
/*
@@ -102,7 +105,7 @@ static void idescsi_output_zeros (ide_drive_t *drive, unsigned int bcount)
}
/*
- * PIO data transfer routines using the scather gather table.
+ * PIO data transfer routines using the scatter gather table.
*/
static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigned int bcount)
{
@@ -110,7 +113,7 @@ static void idescsi_input_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsigne
while (bcount) {
if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
- printk (KERN_ERR "ide-scsi: scather gather table too small, discarding data\n");
+ printk (KERN_ERR "ide-scsi: scatter gather table too small, discarding data\n");
idescsi_discard_data (drive, bcount);
return;
}
@@ -130,7 +133,7 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign
while (bcount) {
if (pc->sg - (struct scatterlist *) pc->scsi_cmd->request_buffer > pc->scsi_cmd->use_sg) {
- printk (KERN_ERR "ide-scsi: scather gather table too small, padding with zeros\n");
+ printk (KERN_ERR "ide-scsi: scatter gather table too small, padding with zeros\n");
idescsi_output_zeros (drive, bcount);
return;
}
@@ -150,14 +153,17 @@ static void idescsi_output_buffers (ide_drive_t *drive, idescsi_pc_t *pc, unsign
*/
static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
{
+ idescsi_scsi_t *scsi = drive->driver_data;
u8 *c = pc->c, *buf = pc->buffer, *sc = pc->scsi_cmd->cmnd;
int i;
+ if (!scsi->transform)
+ return;
if (drive->media == ide_cdrom) {
if (c[0] == READ_6 || c[0] == WRITE_6) {
c[8] = c[4]; c[5] = c[3]; c[4] = c[2];
c[3] = c[1] & 0x1f; c[2] = 0; c[1] &= 0xe0;
- c[0] = READ_10;
+ c[0] += (READ_10 - READ_6);
}
if (c[0] == MODE_SENSE || (c[0] == MODE_SELECT && buf[3] == 8)) {
pc->request_transfer -= 4;
@@ -172,9 +178,12 @@ static inline void idescsi_transform_pc1 (ide_drive_t *drive, idescsi_pc_t *pc)
static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
{
+ idescsi_scsi_t *scsi = drive->driver_data;
u8 *buf = pc->buffer;
int i;
+ if (!scsi->transform)
+ return;
if (drive->media == ide_cdrom) {
if (pc->c[0] == MODE_SENSE_10 && pc->scsi_cmd->cmnd[0] == MODE_SENSE) {
buf[0] = buf[1]; buf[1] = buf[2];
@@ -182,6 +191,8 @@ static inline void idescsi_transform_pc2 (ide_drive_t *drive, idescsi_pc_t *pc)
for (i = pc->buffer_size - 1; i >= 12; i--) buf[i] = buf[i - 4];
for (i = 11; i >= 4; i--) buf[i] = 0;
}
+ if (pc->c[0] == INQUIRY)
+ buf[2] |= 2;
}
}
@@ -400,6 +411,19 @@ static void idescsi_ide_release (struct inode *inode, struct file *filp, ide_dri
static ide_drive_t *idescsi_drives[MAX_HWIFS * MAX_DRIVES];
static int idescsi_initialized = 0;
+static void idescsi_add_settings(ide_drive_t *drive)
+{
+ idescsi_scsi_t *scsi = drive->driver_data;
+
+/*
+ * drive setting name read/write ioctl ioctl data type min max mul_factor div_factor data pointer set function
+ */
+ ide_add_setting(drive, "bios_cyl", SETTING_RW, -1, -1, TYPE_SHORT, 0, 1023, 1, 1, &drive->bios_cyl, NULL);
+ ide_add_setting(drive, "bios_head", SETTING_RW, -1, -1, TYPE_BYTE, 0, 255, 1, 1, &drive->bios_head, NULL);
+ ide_add_setting(drive, "bios_sect", SETTING_RW, -1, -1, TYPE_BYTE, 0, 63, 1, 1, &drive->bios_sect, NULL);
+ ide_add_setting(drive, "transform", SETTING_RW, -1, -1, TYPE_INT, 0, 1, 1, 1, &scsi->transform, NULL);
+}
+
/*
* Driver initialization.
*/
@@ -413,6 +437,8 @@ static void idescsi_setup (ide_drive_t *drive, idescsi_scsi_t *scsi, int id)
scsi->drive = drive;
if (drive->id && (drive->id->config & 0x0060) == 0x20)
set_bit (IDESCSI_DRQ_INTERRUPT, &scsi->flags);
+ scsi->transform = 1;
+ idescsi_add_settings(drive);
}
static int idescsi_cleanup (ide_drive_t *drive)
@@ -426,13 +452,6 @@ static int idescsi_cleanup (ide_drive_t *drive)
return 0;
}
-int idescsi_init (void);
-static ide_module_t idescsi_module = {
- IDE_DRIVER_MODULE,
- idescsi_init,
- NULL
-};
-
/*
* IDE subdriver functions, registered with ide.c
*/
@@ -456,6 +475,14 @@ static ide_driver_t idescsi_driver = {
NULL /* proc */
};
+int idescsi_init (void);
+static ide_module_t idescsi_module = {
+ IDE_DRIVER_MODULE,
+ idescsi_init,
+ &idescsi_driver,
+ NULL
+};
+
static struct proc_dir_entry idescsi_proc_dir = {PROC_SCSI_IDESCSI, 8, "ide-scsi", S_IFDIR | S_IRUGO | S_IXUGO, 2};
/*
@@ -476,7 +503,7 @@ int idescsi_init (void)
MOD_INC_USE_COUNT;
for (i = 0; media[i] != 255; i++) {
failed = 0;
- while ((drive = ide_scan_devices (media[i], NULL, failed++)) != NULL) {
+ while ((drive = ide_scan_devices (media[i], idescsi_driver.name, NULL, failed++)) != NULL) {
if ((scsi = (idescsi_scsi_t *) kmalloc (sizeof (idescsi_scsi_t), GFP_KERNEL)) == NULL) {
printk (KERN_ERR "ide-scsi: %s: Can't allocate a scsi structure\n", drive->name);
continue;
@@ -664,10 +691,10 @@ int idescsi_bios (Disk *disk, kdev_t dev, int *parm)
{
ide_drive_t *drive = idescsi_drives[disk->device->id];
- if (drive->cyl && drive->head && drive->sect) {
- parm[0] = drive->head;
- parm[1] = drive->sect;
- parm[2] = drive->cyl;
+ if (drive->bios_cyl && drive->bios_head && drive->bios_sect) {
+ parm[0] = drive->bios_head;
+ parm[1] = drive->bios_sect;
+ parm[2] = drive->bios_cyl;
}
return 0;
}
@@ -692,7 +719,7 @@ void cleanup_module (void)
scsi_unregister_module (MODULE_SCSI_HA, &idescsi_template);
for (i = 0; media[i] != 255; i++) {
failed = 0;
- while ((drive = ide_scan_devices (media[i], &idescsi_driver, failed)) != NULL)
+ while ((drive = ide_scan_devices (media[i], idescsi_driver.name, &idescsi_driver, failed)) != NULL)
if (idescsi_cleanup (drive)) {
printk ("%s: cleanup_module() called while still busy\n", drive->name);
failed++;
diff --git a/drivers/scsi/ide-scsi.h b/drivers/scsi/ide-scsi.h
index 2ccbc3c03..360850d75 100644
--- a/drivers/scsi/ide-scsi.h
+++ b/drivers/scsi/ide-scsi.h
@@ -15,28 +15,20 @@ extern int idescsi_abort (Scsi_Cmnd *cmd);
extern int idescsi_reset (Scsi_Cmnd *cmd, unsigned int resetflags);
extern int idescsi_bios (Disk *disk, kdev_t dev, int *parm);
-#define IDESCSI \
-{ NULL, /* next */ \
- NULL, /* module */ \
- NULL, /* proc_dir */ \
- NULL, /* proc_info */ \
- "idescsi", /* name */ \
- idescsi_detect, /* detect */ \
- idescsi_release, /* release */ \
- idescsi_info, /* info */ \
- NULL, /* command */ \
- idescsi_queue, /* queuecommand */ \
- idescsi_abort, /* abort */ \
- idescsi_reset, /* reset */ \
- NULL, /* slave_attach */ \
- idescsi_bios, /* bios_param */ \
- 10, /* can_queue */ \
- -1, /* this_id */ \
- 256, /* sg_tablesize */ \
- 5, /* cmd_per_lun */ \
- 0, /* present */ \
- 0, /* isa_dma */ \
- DISABLE_CLUSTERING /* clustering */ \
+#define IDESCSI { \
+ name: "idescsi", /* name */ \
+ detect: idescsi_detect, /* detect */ \
+ release: idescsi_release, /* release */ \
+ info: idescsi_info, /* info */ \
+ queuecommand: idescsi_queue, /* queuecommand */ \
+ abort: idescsi_abort, /* abort */ \
+ reset: idescsi_reset, /* reset */ \
+ bios_param: idescsi_bios, /* bios_param */ \
+ can_queue: 10, /* can_queue */ \
+ this_id: -1, /* this_id */ \
+ sg_tablesize: 256, /* sg_tablesize */ \
+ cmd_per_lun: 5, /* cmd_per_lun */ \
+ use_clustering: DISABLE_CLUSTERING /* clustering */ \
}
#endif /* IDESCSI_H */
diff --git a/drivers/scsi/in2000.h b/drivers/scsi/in2000.h
index bb75a08c5..557ca60e8 100644
--- a/drivers/scsi/in2000.h
+++ b/drivers/scsi/in2000.h
@@ -392,28 +392,21 @@ int in2000_reset(Scsi_Cmnd *, unsigned int);
#define IN2000_CPL 2
#define IN2000_HOST_ID 7
-#define IN2000 { NULL, /* link pointer for modules */ \
- NULL, /* usage_count for modules */ \
- &proc_scsi_in2000, /* pointer to /proc/scsi directory entry */ \
- in2000_proc_info, /* pointer to proc info function */ \
- "Always IN2000", /* device name */ \
- in2000_detect, /* returns number of in2000's found */ \
- NULL, /* optional unload function for modules */ \
- NULL, /* optional misc info function */ \
- NULL, /* send scsi command, wait for completion */ \
- in2000_queuecommand, /* queue scsi command, don't wait */ \
- in2000_abort, /* abort current command */ \
- in2000_reset, /* reset scsi bus */ \
- NULL, /* slave_attach - unused */ \
- in2000_biosparam, /* figures out BIOS parameters for lilo, etc */ \
- IN2000_CAN_Q, /* max commands we can queue up */ \
- IN2000_HOST_ID, /* host-adapter scsi id */ \
- IN2000_SG, /* scatter-gather table size */ \
- IN2000_CPL, /* commands per lun */ \
- 0, /* board counter */ \
- 0, /* unchecked dma */ \
- DISABLE_CLUSTERING \
- }
+#define IN2000 { proc_dir: &proc_scsi_in2000, /* pointer to /proc/scsi directory entry */ \
+ proc_info: in2000_proc_info, /* pointer to proc info function */ \
+ name: "Always IN2000", /* device name */ \
+ detect: in2000_detect, /* returns number of in2000's found */ \
+ queuecommand: in2000_queuecommand, /* queue scsi command, don't wait */ \
+ abort: in2000_abort, /* abort current command */ \
+ reset: in2000_reset, /* reset scsi bus */ \
+ bios_param: in2000_biosparam, /* figures out BIOS parameters for lilo, etc */ \
+ can_queue: IN2000_CAN_Q, /* max commands we can queue up */ \
+ this_id: IN2000_HOST_ID, /* host-adapter scsi id */ \
+ sg_tablesize: IN2000_SG, /* scatter-gather table size */ \
+ cmd_per_lun: IN2000_CPL, /* commands per lun */ \
+ use_clustering: DISABLE_CLUSTERING, \
+ use_new_eh_code: 0 /* Enable new error code */ \
+ }
#endif /* IN2000_H */
diff --git a/drivers/scsi/jazz_esp.h b/drivers/scsi/jazz_esp.h
index 9a7886f26..4de4797c1 100644
--- a/drivers/scsi/jazz_esp.h
+++ b/drivers/scsi/jazz_esp.h
@@ -20,29 +20,21 @@ extern int esp_reset(Scsi_Cmnd *, unsigned int);
extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
int hostno, int inout);
-
-#define SCSI_JAZZ_ESP { \
-/* struct SHT *next */ NULL, \
-/* long *usage_count */ NULL, \
-/* struct proc_dir_entry *proc_dir */ &proc_scsi_esp, \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */ &esp_proc_info, \
-/* const char *name */ "JAZZ SCSI", \
-/* int detect(struct SHT *) */ jazz_esp_detect, \
-/* int release(struct Scsi_Host *) */ NULL, \
-/* const char *info(struct Scsi_Host *) */ esp_info, \
-/* int command(Scsi_Cmnd *) */ esp_command, \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue, \
-/* int abort(Scsi_Cmnd *) */ esp_abort, \
-/* int reset(Scsi_Cmnd *) */ esp_reset, \
-/* int slave_attach(int, int) */ NULL, \
-/* int bios_param(Disk *, kdev_t, int[]) */ NULL, \
-/* int can_queue */ 7, \
-/* int this_id */ 7, \
-/* short unsigned int sg_tablesize */ SG_ALL, \
-/* short cmd_per_lun */ 1, \
-/* unsigned char present */ 0, \
-/* unsigned unchecked_isa_dma:1 */ 0, \
-/* unsigned use_clustering:1 */ DISABLE_CLUSTERING, }
+#define SCSI_JAZZ_ESP { \
+ proc_dir: &proc_scsi_esp, \
+ proc_info: &esp_proc_info, \
+ name: "Sun ESP 100/100a/200", \
+ detect: jazz_esp_detect, \
+ info: esp_info, \
+ command: esp_command, \
+ queuecommand: esp_queue, \
+ abort: esp_abort, \
+ reset: esp_reset, \
+ can_queue: 7, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING, }
#endif /* JAZZ_ESP_H */
diff --git a/drivers/scsi/mac53c94.h b/drivers/scsi/mac53c94.h
index b423b0c9f..914e89cf9 100644
--- a/drivers/scsi/mac53c94.h
+++ b/drivers/scsi/mac53c94.h
@@ -16,27 +16,18 @@ int mac53c94_abort(Scsi_Cmnd *);
int mac53c94_reset(Scsi_Cmnd *, unsigned int);
#define SCSI_MAC53C94 { \
- NULL, /* next */ \
- NULL, /* usage_count */ \
- &proc_scsi_mac53c94, /* proc_dir */ \
- NULL, /* proc_info */ \
- "53C94", /* name */ \
- mac53c94_detect, /* detect */ \
- NULL, /* release */ \
- NULL, /* info */ \
- mac53c94_command, /* command */ \
- mac53c94_queue, /* queuecommand */ \
- mac53c94_abort, /* abort */ \
- mac53c94_reset, /* reset */ \
- NULL, /* slave_attach */ \
- NULL, /* bios_param */ \
- 1, /* can_queue */ \
- 7, /* this_id */ \
- SG_ALL, /* sg_tablesize */ \
- 1, /* cmd_per_lun */ \
- 0, /* present */ \
- 0, /* unchecked_isa_dma */ \
- DISABLE_CLUSTERING, /* use_clustering */ \
+ proc_dir: &proc_scsi_mac53c94, \
+ name: "53C94", \
+ detect: mac53c94_detect, \
+ command: mac53c94_command, \
+ queuecommand: mac53c94_queue, \
+ abort: mac53c94_abort, \
+ reset: mac53c94_reset, \
+ can_queue: 1, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING, \
}
/*
diff --git a/drivers/scsi/mesh.h b/drivers/scsi/mesh.h
index c808cc58a..6627de4bd 100644
--- a/drivers/scsi/mesh.h
+++ b/drivers/scsi/mesh.h
@@ -16,27 +16,18 @@ int mesh_abort(Scsi_Cmnd *);
int mesh_reset(Scsi_Cmnd *, unsigned int);
#define SCSI_MESH { \
- NULL, /* next */ \
- NULL, /* usage_count */ \
- &proc_scsi_mesh, /* proc_dir */ \
- NULL, /* proc_info */ \
- "MESH", /* name */ \
- mesh_detect, /* detect */ \
- NULL, /* release */ \
- NULL, /* info */ \
- mesh_command, /* command */ \
- mesh_queue, /* queuecommand */ \
- mesh_abort, /* abort */ \
- mesh_reset, /* reset */ \
- NULL, /* slave_attach */ \
- NULL, /* bios_param */ \
- 20, /* can_queue */ \
- 7, /* this_id */ \
- SG_ALL, /* sg_tablesize */ \
- 2, /* cmd_per_lun */ \
- 0, /* present */ \
- 0, /* unchecked_isa_dma */ \
- DISABLE_CLUSTERING, /* use_clustering */ \
+ proc_dir: &proc_scsi_mesh, \
+ name: "MESH", \
+ detect: mesh_detect, \
+ command: mesh_command, \
+ queuecommand: mesh_queue, \
+ abort: mesh_abort, \
+ reset: mesh_reset, \
+ can_queue: 20, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 2, \
+ use_clustering: DISABLE_CLUSTERING, \
}
/*
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index 2595f77f2..2dc9c8a66 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -67,7 +67,7 @@
*/
/*
-** 20 September 1997, version 2.5c
+** 2 January 1998, version 2.5f
**
** Supported SCSI-II features:
** Synchronous negotiation
@@ -511,7 +511,7 @@ struct ncr_driver_setup {
unsigned master_parity : 1;
unsigned scsi_parity : 1;
unsigned disconnection : 1;
- unsigned special_features : 1;
+ unsigned special_features : 2;
unsigned ultra_scsi : 2;
unsigned force_sync_nego: 1;
unsigned reverse_probe: 1;
@@ -527,6 +527,7 @@ struct ncr_driver_setup {
u_char settle_delay;
u_char diff_support;
u_char irqm;
+ u_char bus_check;
};
static struct ncr_driver_setup
@@ -586,7 +587,8 @@ struct Symbios_nvram {
u_short flags1;
#define SYMBIOS_SCAN_HI_LO (1)
u_short word10; /* 0x00 */
- u_short word12; /* 0x00 */
+ u_short flags3; /* 0x00 */
+#define SYMBIOS_REMOVABLE_FLAGS (3) /* 0=none, 1=bootable, 2=all */
u_char host_id;
u_char byte15; /* 0x04 */
u_short word16; /* 0x0410 */
@@ -701,7 +703,7 @@ typedef struct {
ncr_slot slot;
ncr_chip chip;
ncr_nvram *nvram;
- int attached;
+ int attach_done;
} ncr_device;
/*==========================================================
@@ -1894,7 +1896,7 @@ struct script {
ncrcmd prepare2 [ 24];
ncrcmd setmsg [ 5];
ncrcmd clrack [ 2];
- ncrcmd dispatch [ 33];
+ ncrcmd dispatch [ 38];
ncrcmd no_data [ 17];
ncrcmd checkatn [ 10];
ncrcmd command [ 15];
@@ -1996,6 +1998,7 @@ static int ncr_snooptest (ncb_p np);
static void ncr_timeout (ncb_p np);
static void ncr_wakeup (ncb_p np, u_long code);
static void ncr_start_reset (ncb_p np, int settle_delay);
+static int ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay);
#ifdef SCSI_NCR_USER_COMMAND_SUPPORT
static void ncr_usercmd (ncb_p np);
@@ -2391,8 +2394,21 @@ static struct script script0 __initdata = {
0,
SCR_RETURN ^ IFTRUE (WHEN (SCR_DATA_OUT)),
0,
- SCR_RETURN ^ IFTRUE (IF (SCR_DATA_IN)),
+ /*
+ ** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 4.
+ ** Possible data corruption during Memory Write and Invalidate.
+ ** This work-around resets the addressing logic prior to the
+ ** start of the first MOVE of a DATA IN phase.
+ ** (See README.ncr53c8xx for more information)
+ */
+ SCR_JUMPR ^ IFFALSE (IF (SCR_DATA_IN)),
+ 20,
+ SCR_COPY (4),
+ RADDR (scratcha),
+ RADDR (scratcha),
+ SCR_RETURN,
0,
+
SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)),
PADDR (msg_out),
SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN)),
@@ -4613,7 +4629,11 @@ printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%x, io_port=0x%x, irq=%d\n",
** Then enable disconnects.
*/
save_flags(flags); cli();
- ncr_start_reset(np, driver_setup.settle_delay);
+ if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) {
+ printf("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np));
+ restore_flags(flags);
+ goto attach_error;
+ }
ncr_exception (np);
restore_flags(flags);
@@ -4681,6 +4701,16 @@ attach_error:
#endif
release_region(np->port, 128);
}
+ if (np->irq) {
+#ifdef DEBUG_NCR53C8XX
+ printf("%s: freeing irq %d\n", ncr_name(np), np->irq);
+#endif
+#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70)
+ free_irq(np->irq, np);
+#else
+ free_irq(np->irq);
+#endif
+ }
scsi_unregister(instance);
return -1;
@@ -5202,21 +5232,64 @@ static void ncr_start_reset(ncb_p np, int settle_delay)
save_flags(flags); cli();
if (!np->settle_time) {
- if (bootverbose > 1)
- printf("%s: resetting, command processing suspended for %d seconds\n",
- ncr_name(np), settle_delay);
- np->settle_time = jiffies + settle_delay * HZ;
- OUTB (nc_istat, SRST);
- DELAY (1000);
- OUTB (nc_istat, 0);
- OUTW (nc_sien, RST);
- OUTB (nc_scntl1, CRST);
- DELAY (100);
+ (void) ncr_reset_scsi_bus(np, 1, settle_delay);
}
-
restore_flags(flags);
}
+static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay)
+{
+ u_int32 term;
+ int retv = 0;
+
+ np->settle_time = jiffies + settle_delay * HZ;
+
+ if (bootverbose > 1)
+ printf("%s: resetting, "
+ "command processing suspended for %d seconds\n",
+ ncr_name(np), settle_delay);
+
+ OUTB (nc_istat, SRST);
+ DELAY (1000);
+ OUTB (nc_istat, 0);
+ if (enab_int)
+ OUTW (nc_sien, RST);
+ OUTB (nc_scntl1, CRST);
+ DELAY (100);
+
+ if (!driver_setup.bus_check)
+ goto out;
+ /*
+ ** Check for no terminators or SCSI bus shorts to ground.
+ ** Read SCSI data bus, data parity bits and control signals.
+ ** We are expecting RESET to be TRUE and other signals to be
+ ** FALSE.
+ */
+ term = INB(nc_sstat0); /* rst, sdp0 */
+ term = ((term & 2) << 7) + ((term & 1) << 16);
+ term |= ((INB(nc_sstat2) & 0x01) << 25) | /* sdp1 */
+ (INW(nc_sbdl) << 9) | /* d15-0 */
+ INB(nc_sbcl); /* req, ack, bsy, sel, atn, msg, cd, io */
+
+ if (!(np->features & FE_WIDE))
+ term &= 0x3ffff;
+
+ if (term != (2<<7)) {
+ printf("%s: suspicious SCSI data while resetting the BUS.\n",
+ ncr_name(np));
+ printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = "
+ "0x%lx, expecting 0x%lx\n",
+ ncr_name(np),
+ (np->features & FE_WIDE) ? "dp1,d15-8," : "",
+ (u_long)term, (u_long)(2<<7));
+ if (driver_setup.bus_check == 1)
+ retv = 1;
+ }
+out:
+ OUTB (nc_scntl1, 0);
+ return retv;
+}
+
/*==========================================================
**
**
@@ -5629,10 +5702,12 @@ void ncr_complete (ncb_p np, ccb_p cp)
** Check the status.
*/
if ( (cp->host_status == HS_COMPLETE)
- && (cp->scsi_status == S_GOOD)) {
-
+ && (cp->scsi_status == S_GOOD ||
+ cp->scsi_status == S_COND_MET)) {
/*
- ** All went well.
+ ** All went well (GOOD status).
+ ** CONDITION MET status is returned on
+ ** `Pre-Fetch' or `Search data' success.
*/
cmd->result = ScsiResult(DID_OK, cp->scsi_status);
@@ -5727,7 +5802,8 @@ void ncr_complete (ncb_p np, ccb_p cp)
}
} else if ((cp->host_status == HS_COMPLETE)
- && (cp->scsi_status == S_BUSY)) {
+ && (cp->scsi_status == S_BUSY ||
+ cp->scsi_status == S_CONFLICT)) {
/*
** Target is busy.
@@ -6261,7 +6337,7 @@ static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer)
if (tp->period < 500) scsi = "FAST-40";
else if (tp->period < 1000) scsi = "FAST-20";
else if (tp->period < 2000) scsi = "FAST-10";
- else scsi = "SLOW";
+ else scsi = "FAST-5";
printf ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi,
tp->widedone > 1 ? "WIDE " : "",
@@ -6940,9 +7016,16 @@ void ncr_exception (ncb_p np)
ncr_int_sir (np);
return;
}
- if (!(sist & (SBMC|PAR)) && !(dstat & SSI))
- printf("%s: unknown interrupt(s) ignored sist=%x dstat=%x\n",
- ncr_name(np), sist, dstat);
+ /*
+ ** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 2.
+ */
+ if (!(sist & (SBMC|PAR)) && !(dstat & SSI)) {
+ printf( "%s: unknown interrupt(s) ignored, "
+ "ISTAT=%x DSTAT=%x SIST=%x\n",
+ ncr_name(np), istat, dstat, sist);
+ return;
+ }
+
OUTONB (nc_dcntl, (STD|NOCOM));
return;
};
@@ -6969,6 +7052,11 @@ void ncr_exception (ncb_p np)
if ((sist & STO) &&
!(dstat & (MDPE|BF|ABRT))) {
+ /*
+ ** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 1.
+ */
+ OUTONB (nc_ctest3, CLF);
+
ncr_int_sto (np);
return;
};
@@ -8927,6 +9015,8 @@ void ncr53c8xx_setup(char *str, int *ints)
driver_setup.irqm = val;
else if (!strncmp(cur, "pcifix:", 7))
driver_setup.pci_fix_up = val;
+ else if (!strncmp(cur, "buschk:", 7))
+ driver_setup.bus_check = val;
#ifdef SCSI_NCR_NVRAM_SUPPORT
else if (!strncmp(cur, "nvram:", 6))
driver_setup.use_nvram = val;
@@ -8970,9 +9060,9 @@ static void ncr_print_driver_setup(void)
)
{
#define YesNo(y) y ? 'y' : 'n'
- printk("ncr53c8xx: setup=disc:%c,specf:%c,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
+ printk("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n",
YesNo(driver_setup.disconnection),
- YesNo(driver_setup.special_features),
+ driver_setup.special_features,
YesNo(driver_setup.ultra_scsi),
driver_setup.default_tags,
driver_setup.default_sync,
@@ -9071,10 +9161,10 @@ ncr_attach_using_nvram(Scsi_Host_Template *tpnt, int nvram_index, int count, ncr
h->device_id == devp->chip.device_id)
break;
}
- if (j < count && !devp->attached &&
- !ncr_attach (tpnt, attach_count, devp)) {
- attach_count++;
- devp->attached = 1;
+ if (j < count && !devp->attach_done) {
+ if (!ncr_attach (tpnt, attach_count, devp))
+ attach_count++;
+ devp->attach_done = 1;
}
}
@@ -9183,8 +9273,6 @@ if (ncr53c8xx)
#endif
printf(KERN_INFO "ncr53c8xx: 53c%s detected %s\n",
device[count].chip.name, msg);
-
- device[count].attached = 0;
++count;
}
}
@@ -9197,9 +9285,9 @@ if (ncr53c8xx)
** so try to attach them here.
*/
for (i= 0; i < count; i++) {
- if ((!device[i].attached) && (!ncr_attach (tpnt, attach_count, &device[i]))) {
+ if (!device[i].attach_done &&
+ !ncr_attach (tpnt, attach_count, &device[i])) {
attach_count++;
- device[i].attached = 1;
}
}
@@ -9303,10 +9391,10 @@ printk("ncr53c8xx_pci_init() #1: bus == %d, device_fn == %d\n", bus, device_fn);
command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO|PCI_COMMAND_MEMORY;
pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
}
- if (io_port >= 0x10000000) {
+ if (io_port >= 0x10000000) {
io_port = (io_port & 0x00FFFFFF) | 0x01000000;
pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
- }
+ }
if (base >= 0x10000000) {
base = (base & 0x00FFFFFF) | 0x01000000;
pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_1, base);
@@ -9361,8 +9449,12 @@ printk("ncr53c8xx_pci_init() #1: bus == %d, device_fn == %d\n", bus, device_fn);
/*
* Fix some features according to driver setup.
*/
- if (!driver_setup.special_features)
+ if (!(driver_setup.special_features & 1))
chip->features &= ~FE_SPECIAL_SET;
+ else {
+ if (driver_setup.special_features & 2)
+ chip->features &= ~FE_WRIE;
+ }
if (driver_setup.ultra_scsi < 2 && (chip->features & FE_ULTRA2)) {
chip->features |= FE_ULTRA;
chip->features &= ~FE_ULTRA2;
@@ -9381,8 +9473,12 @@ printk("ncr53c8xx_pci_init() #1: bus == %d, device_fn == %d\n", bus, device_fn);
#if defined(__i386) && !defined(MODULE)
if ((driver_setup.pci_fix_up & 1) &&
(chip->features & FE_CLSE) && cache_line_size == 0) {
+#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,75)
extern char x86;
switch(x86) {
+#else
+ switch(boot_cpu_data.x86) {
+#endif
case 4: cache_line_size = 4; break;
case 5: cache_line_size = 8; break;
}
@@ -9469,7 +9565,7 @@ printk("ncr53c8xx_pci_init() #1: bus == %d, device_fn == %d\n", bus, device_fn);
device->slot.base_2 = base_2;
device->slot.io_port = io_port;
device->slot.irq = irq;
- device->attached = 0;
+ device->attach_done = 0;
#ifdef SCSI_NCR_NVRAM_SUPPORT
if (!nvram)
goto out;
diff --git a/drivers/scsi/ncr53c8xx.h b/drivers/scsi/ncr53c8xx.h
index 0f8cb7876..9b54fc3b2 100644
--- a/drivers/scsi/ncr53c8xx.h
+++ b/drivers/scsi/ncr53c8xx.h
@@ -45,7 +45,7 @@
/*
** Name and revision of the driver
*/
-#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 2.5c"
+#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 2.5f"
/*
** Check supported Linux versions
@@ -125,7 +125,7 @@
* For Ultra2 SCSI support option, use special features and allow 40Mhz
* synchronous data transfers.
*/
-#define SCSI_NCR_SETUP_SPECIAL_FEATURES (1)
+#define SCSI_NCR_SETUP_SPECIAL_FEATURES (3)
#define SCSI_NCR_SETUP_ULTRA_SCSI (2)
#define SCSI_NCR_MAX_SYNC (40)
@@ -290,27 +290,44 @@ int ncr53c8xx_release(struct Scsi_Host *);
#define ncr53c8xx_release NULL
#endif
-#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
-
-#define NCR53C8XX {NULL,NULL,NULL,NULL,SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect,\
- ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL, \
- ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset, \
- NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\
- /* id */ 7, SCSI_NCR_SG_TABLESIZE /* SG */, /* cmd per lun */ SCSI_NCR_CMD_PER_LUN, \
- /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING}
+#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,75)
+
+#define NCR53C8XX { name: SCSI_NCR_DRIVER_NAME, \
+ detect: ncr53c8xx_detect, \
+ release: ncr53c8xx_release, \
+ queuecommand: ncr53c8xx_queue_command,\
+ abort: ncr53c8xx_abort, \
+ reset: ncr53c8xx_reset, \
+ bios_param: scsicam_bios_param, \
+ can_queue: SCSI_NCR_CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: SCSI_NCR_SG_TABLESIZE, \
+ cmd_per_lun: SCSI_NCR_CMD_PER_LUN, \
+ use_clustering: DISABLE_CLUSTERING}
+
+#elif LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0)
+#define NCR53C8XX { NULL, NULL, NULL, NULL, \
+ SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect, \
+ ncr53c8xx_release, NULL, NULL, \
+ ncr53c8xx_queue_command,ncr53c8xx_abort, \
+ ncr53c8xx_reset, NULL, scsicam_bios_param, \
+ SCSI_NCR_CAN_QUEUE, 7, \
+ SCSI_NCR_SG_TABLESIZE, SCSI_NCR_CMD_PER_LUN, \
+ 0, 0, DISABLE_CLUSTERING}
#else
+#define NCR53C8XX { NULL, NULL, \
+ SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect, \
+ ncr53c8xx_release, NULL, NULL, \
+ ncr53c8xx_queue_command,ncr53c8xx_abort, \
+ ncr53c8xx_reset, NULL, scsicam_bios_param, \
+ SCSI_NCR_CAN_QUEUE, 7, \
+ SCSI_NCR_SG_TABLESIZE, SCSI_NCR_CMD_PER_LUN, \
+ 0, 0, DISABLE_CLUSTERING}
-#define NCR53C8XX {NULL, NULL, SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect,\
- ncr53c8xx_release, /* info */ NULL, /* command, deprecated */ NULL, \
- ncr53c8xx_queue_command, ncr53c8xx_abort, ncr53c8xx_reset, \
- NULL /* slave attach */, scsicam_bios_param, /* can queue */ SCSI_NCR_CAN_QUEUE,\
- /* id */ 7, SCSI_NCR_SG_TABLESIZE /* SG */, /* cmd per lun */ SCSI_NCR_CMD_PER_LUN, \
- /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING}
-
-#endif /* LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) */
+#endif /* LINUX_VERSION_CODE */
#endif /* defined(HOSTS_C) || defined(MODULE) */
@@ -436,6 +453,19 @@ typedef struct {
#define FE_SPECIAL_SET (FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM)
} ncr_chip;
+/*
+** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 3.
+** Memory Read transaction terminated by a retry followed by
+** Memory Read Line command.
+*/
+#define FE_CACHE0_SET (FE_CACHE_SET & ~FE_ERL)
+
+/*
+** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 5.
+** On paper, this errata is harmless. But it is a good reason for
+** using a shorter programmed burst length (64 DWORDS instead of 128).
+*/
+
#define SCSI_NCR_CHIP_TABLE \
{ \
{PCI_DEVICE_ID_NCR_53C810, 0x0f, "810", 4, 8, 4, \
@@ -453,23 +483,23 @@ typedef struct {
{PCI_DEVICE_ID_NCR_53C825, 0x0f, "825", 4, 8, 4, \
FE_WIDE|FE_ERL|FE_BOF} \
, \
- {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 7, 8, 4, \
- FE_WIDE|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM} \
+ {PCI_DEVICE_ID_NCR_53C825, 0xff, "825a", 6, 8, 4, \
+ FE_WIDE|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM} \
, \
{PCI_DEVICE_ID_NCR_53C860, 0xff, "860", 4, 8, 5, \
FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_LDSTR|FE_PFEN} \
, \
- {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 7, 16, 5, \
- FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ {PCI_DEVICE_ID_NCR_53C875, 0x01, "875", 6, 16, 5, \
+ FE_WIDE|FE_ULTRA|FE_CLK80|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
, \
- {PCI_DEVICE_ID_NCR_53C875, 0xff, "875", 7, 16, 5, \
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ {PCI_DEVICE_ID_NCR_53C875, 0xff, "875", 6, 16, 5, \
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
, \
- {PCI_DEVICE_ID_NCR_53C875J, 0xff, "875J", 7, 16, 5, \
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ {PCI_DEVICE_ID_NCR_53C875J,0xff, "875J", 6, 16, 5, \
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
, \
- {PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 7, 16, 5, \
- FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
+ {PCI_DEVICE_ID_NCR_53C885, 0xff, "885", 6, 16, 5, \
+ FE_WIDE|FE_ULTRA|FE_DBLR|FE_CACHE0_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
, \
{PCI_DEVICE_ID_NCR_53C895, 0xff, "895", 7, 31, 7, \
FE_WIDE|FE_ULTRA2|FE_QUAD|FE_CACHE_SET|FE_BOF|FE_DFS|FE_LDSTR|FE_PFEN|FE_RAM}\
@@ -519,7 +549,8 @@ typedef struct {
1, \
SCSI_NCR_SETUP_SETTLE_TIME, \
SCSI_NCR_SETUP_DIFF_SUPPORT, \
- 0 \
+ 0, \
+ 1 \
}
/*
@@ -547,6 +578,7 @@ typedef struct {
0, \
10, \
1, \
+ 1, \
1 \
}
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 507080dd0..c126030d9 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -516,7 +516,7 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
register unsigned char *d = dst;
register unsigned short reg = (unsigned short) (instance->io_port +
P_DATA_REG_OFFSET);
- register i = len;
+ register int i = len;
int ii = 0;
while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) )
@@ -552,7 +552,7 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src
int len) {
register unsigned char *s = src;
register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
- register i = len;
+ register int i = len;
int ii = 0;
while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) )
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
index a1bda1fa6..308f26473 100644
--- a/drivers/scsi/pas16.h
+++ b/drivers/scsi/pas16.h
@@ -142,13 +142,18 @@ int pas16_proc_info (char *buffer ,char **start, off_t offset,
#if defined(HOSTS_C) || defined(MODULE)
-#define MV_PAS16 {NULL, NULL, NULL, NULL, \
- "Pro Audio Spectrum-16 SCSI", \
- pas16_detect, NULL, NULL, \
- NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL, \
- pas16_biosparam, \
- /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
- /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
+#define MV_PAS16 { \
+ name: "Pro Audio Spectrum-16 SCSI", \
+ detect: pas16_detect, \
+ queuecommand: pas16_queue_command, \
+ abort: pas16_abort, \
+ reset: pas16_reset, \
+ bios_param: pas16_biosparam, \
+ can_queue: CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: CMD_PER_LUN , \
+ use_clustering: DISABLE_CLUSTERING}
#endif
#ifndef HOSTS_C
diff --git a/drivers/scsi/pci2000.c b/drivers/scsi/pci2000.c
index 0a27c904a..89ef9beb0 100644
--- a/drivers/scsi/pci2000.c
+++ b/drivers/scsi/pci2000.c
@@ -653,7 +653,7 @@ int Pci2000_BiosParam (Scsi_Disk *disk, kdev_t dev, int geom[])
#ifdef MODULE
/* Eventually this will go into an include file, but this will be later */
-Scsi_Host_Template driver_template = PCI2220I;
+Scsi_Host_Template driver_template = PCI2000;
#include "scsi_module.c"
#endif
diff --git a/drivers/scsi/pci2000.h b/drivers/scsi/pci2000.h
index ded993958..ab8458d1d 100644
--- a/drivers/scsi/pci2000.h
+++ b/drivers/scsi/pci2000.h
@@ -202,25 +202,18 @@ int Pci2000_BiosParam (Disk *disk, kdev_t dev, int geom[]);
extern struct proc_dir_entry Proc_Scsi_Pci2000;
-#define PCI2000 { NULL, NULL, \
- &Proc_Scsi_Pci2000,/* proc_dir_entry */ \
- NULL, \
- "PCI-2000 SCSI Intelligent Disk Controller",\
- Pci2000_Detect, \
- NULL, \
- NULL, \
- Pci2000_Command, \
- Pci2000_QueueCommand, \
- Pci2000_Abort, \
- Pci2000_Reset, \
- NULL, \
- Pci2000_BiosParam, \
- 16, \
- -1, \
- 16, \
- 1, \
- 0, \
- 0, \
- DISABLE_CLUSTERING }
+#define PCI2000 { proc_dir: &Proc_Scsi_Pci2000,/* proc_dir_entry */ \
+ name: "PCI-2000 SCSI Intelligent Disk Controller",\
+ detect: Pci2000_Detect, \
+ command: Pci2000_Command, \
+ queuecommand: Pci2000_QueueCommand, \
+ abort: Pci2000_Abort, \
+ reset: Pci2000_Reset, \
+ bios_param: Pci2000_BiosParam, \
+ can_queue: 16, \
+ this_id: -1, \
+ sg_tablesize: 16, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING }
#endif
diff --git a/drivers/scsi/pci2220i.h b/drivers/scsi/pci2220i.h
index 0fafc2648..1a9bd6cad 100644
--- a/drivers/scsi/pci2220i.h
+++ b/drivers/scsi/pci2220i.h
@@ -321,25 +321,18 @@ int Pci2220i_BiosParam (Disk *disk, kdev_t dev, int geom[]);
extern struct proc_dir_entry Proc_Scsi_Pci2220i;
-#define PCI2220I { NULL, NULL, \
- &Proc_Scsi_Pci2220i,/* proc_dir_entry */ \
- NULL, \
- "PCI-2220I EIDE Disk Controller", \
- Pci2220i_Detect, \
- NULL, \
- NULL, \
- Pci2220i_Command, \
- Pci2220i_QueueCommand, \
- Pci2220i_Abort, \
- Pci2220i_Reset, \
- NULL, \
- Pci2220i_BiosParam, \
- 1, \
- -1, \
- SG_NONE, \
- 1, \
- 0, \
- 0, \
- DISABLE_CLUSTERING }
+#define PCI2220I { proc_dir: &Proc_Scsi_Pci2220i,/* proc_dir_entry */ \
+ name: "PCI-2220I EIDE Disk Controller",\
+ detect: Pci2220i_Detect, \
+ command: Pci2220i_Command, \
+ queuecommand: Pci2220i_QueueCommand, \
+ abort: Pci2220i_Abort, \
+ reset: Pci2220i_Reset, \
+ bios_param: Pci2220i_BiosParam, \
+ can_queue: 1, \
+ this_id: -1, \
+ sg_tablesize: SG_NONE, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING }
#endif
diff --git a/drivers/scsi/pluto.c b/drivers/scsi/pluto.c
new file mode 100644
index 000000000..3b4598a3f
--- /dev/null
+++ b/drivers/scsi/pluto.c
@@ -0,0 +1,313 @@
+/* pluto.c: SparcSTORAGE Array SCSI host adapter driver.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/blk.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/init.h>
+
+#include <asm/irq.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "../fc4/fcp_scsi.h"
+#include "pluto.h"
+
+#include <linux/module.h>
+
+/* #define PLUTO_DEBUG */
+
+#define pluto_printk printk ("PLUTO %s: ", fc->name); printk
+
+#ifdef PLUTO_DEBUG
+#define PLD(x) pluto_printk x;
+#define PLND(x) printk ("PLUTO: "); printk x;
+#else
+#define PLD(x)
+#define PLND(x)
+#endif
+
+struct proc_dir_entry proc_scsi_pluto = {
+ PROC_SCSI_PLUTO, 5, "pluto",
+ S_IFDIR | S_IRUGO | S_IXUGO, 2
+};
+
+static struct ctrl_inquiry {
+ struct Scsi_Host host;
+ struct pluto pluto;
+ Scsi_Cmnd cmd;
+ char inquiry[256];
+ fc_channel *fc;
+} *fcs __initdata;
+static int fcscount __initdata;
+static atomic_t fcss __initdata;
+static struct timer_list fc_timer __initdata = { 0 };
+struct semaphore fc_sem __initdata = MUTEX_LOCKED;
+
+static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr);
+
+__initfunc(static void pluto_detect_timeout(unsigned long data))
+{
+ PLND(("Timeout\n"))
+ up(&fc_sem);
+}
+
+__initfunc(static void pluto_detect_done(Scsi_Cmnd *SCpnt))
+{
+ /* Do nothing */
+}
+
+__initfunc(static void pluto_detect_scsi_done(Scsi_Cmnd *SCpnt))
+{
+ SCpnt->request.rq_status = RQ_SCSI_DONE;
+ PLND(("Detect done %08lx\n", (long)SCpnt))
+ if (atomic_dec_and_test (&fcss))
+ up(&fc_sem);
+}
+
+static void pluto_select_queue_depths(struct Scsi_Host *host, Scsi_Device *devlist)
+{
+ Scsi_Device *device;
+
+ for (device = devlist; device; device = device->next) {
+ if (device->host != host) continue;
+ if (device->tagged_supported)
+ device->queue_depth = /* 254 */ 8;
+ else
+ device->queue_depth = 2;
+ }
+}
+
+/* Detect all SSAs attached to the machine.
+ To be fast, do it on all online FC channels at the same time. */
+__initfunc(int pluto_detect(Scsi_Host_Template *tpnt))
+{
+ int i, retry, nplutos;
+ fc_channel *fc;
+ Scsi_Device dev;
+
+ tpnt->proc_dir = &proc_scsi_pluto;
+ fcscount = 0;
+ for_each_online_fc_channel(fc)
+ fcscount++;
+ PLND(("%d channels online\n", fcscount))
+ if (!fcscount)
+ return 0;
+ fcs = (struct ctrl_inquiry *) scsi_init_malloc (sizeof (struct ctrl_inquiry) * fcscount, GFP_DMA);
+ if (!fcs) {
+ printk ("PLUTO: Not enough memory to probe\n");
+ return 0;
+ }
+
+ memset (fcs, 0, sizeof (struct ctrl_inquiry) * fcscount);
+ memset (&dev, 0, sizeof(dev));
+ atomic_set (&fcss, fcscount);
+ fc_timer.function = pluto_detect_timeout;
+
+ i = 0;
+ for_each_online_fc_channel(fc) {
+ Scsi_Cmnd *SCpnt;
+ struct Scsi_Host *host;
+ struct pluto *pluto;
+
+ if (i == fcscount) break;
+
+ PLD(("trying to find SSA\n"))
+
+ /* If this is already registered to some other SCSI host, then it cannot be pluto */
+ if (fc->scsi_name[0]) continue;
+ memcpy (fc->scsi_name, "SSA", 4);
+
+ fcs[i].fc = fc;
+
+ fc->can_queue = PLUTO_CAN_QUEUE;
+ fc->rsp_size = 64;
+ fc->encode_addr = pluto_encode_addr;
+
+ fc->fcp_register(fc, TYPE_SCSI_FCP, 0);
+
+ SCpnt = &(fcs[i].cmd);
+ host = &(fcs[i].host);
+ pluto = (struct pluto *)host->hostdata;
+
+ pluto->fc = fc;
+
+ SCpnt->host = host;
+ SCpnt->cmnd[0] = INQUIRY;
+ SCpnt->cmnd[4] = 255;
+
+ /* FC layer requires this, so that SCpnt->device->tagged_supported is initially 0 */
+ SCpnt->device = &dev;
+
+ SCpnt->cmd_len = COMMAND_SIZE(INQUIRY);
+
+ SCpnt->request.rq_status = RQ_SCSI_BUSY;
+
+ SCpnt->done = pluto_detect_done;
+ SCpnt->bufflen = 256;
+ SCpnt->buffer = fcs[i].inquiry;
+ SCpnt->request_bufflen = 256;
+ SCpnt->request_buffer = fcs[i].inquiry;
+ PLD(("set up %d %08lx\n", i, (long)SCpnt))
+ i++;
+ }
+
+ for (retry = 0; retry < 5; retry++) {
+ for (i = 0; i < fcscount; i++) {
+ if (!fcs[i].fc) break;
+ if (fcs[i].cmd.request.rq_status != RQ_SCSI_DONE) {
+ disable_irq(fcs[i].fc->irq);
+ PLND(("queuecommand %d %d\n", retry, i))
+ fcp_scsi_queuecommand (&(fcs[i].cmd),
+ pluto_detect_scsi_done);
+ enable_irq(fcs[i].fc->irq);
+ }
+ }
+
+ fc_timer.expires = jiffies + 10 * HZ;
+ add_timer(&fc_timer);
+
+ down(&fc_sem);
+ PLND(("Woken up\n"))
+ if (!atomic_read(&fcss))
+ break; /* All fc channels have answered us */
+ }
+ del_timer(&fc_timer);
+
+ PLND(("Finished search\n"))
+ for (i = 0, nplutos = 0; i < fcscount; i++) {
+ Scsi_Cmnd *SCpnt;
+
+ if (!(fc = fcs[i].fc)) break;
+
+ SCpnt = &(fcs[i].cmd);
+
+ /* Let FC mid-level free allocated resources */
+ SCpnt->done (SCpnt);
+
+ if (!SCpnt->result) {
+ struct pluto_inquiry *inq;
+ struct pluto *pluto;
+ struct Scsi_Host *host;
+
+ inq = (struct pluto_inquiry *)fcs[i].inquiry;
+
+ if ((inq->dtype & 0x1f) == TYPE_PROCESSOR &&
+ !strncmp (inq->vendor_id, "SUN", 3) &&
+ !strncmp (inq->product_id, "SSA", 3)) {
+ char *p;
+ long *ages;
+
+ ages = kmalloc (((inq->channels + 1) * inq->targets) * sizeof(long), GFP_KERNEL);
+ if (!ages) continue;
+
+ host = scsi_register (tpnt, sizeof (struct pluto));
+ if (!host) panic ("Cannot register PLUTO host\n");
+
+ nplutos++;
+
+ pluto = (struct pluto *)host->hostdata;
+
+ host->max_id = inq->targets;
+ host->max_channel = inq->channels;
+ host->irq = fc->irq;
+
+ host->select_queue_depths = pluto_select_queue_depths;
+
+ fc->channels = inq->channels + 1;
+ fc->targets = inq->targets;
+ fc->ages = ages;
+ memset (ages, 0, ((inq->channels + 1) * inq->targets) * sizeof(long));
+
+ pluto->fc = fc;
+ memcpy (pluto->rev_str, inq->revision, 4);
+ pluto->rev_str[4] = 0;
+ p = strchr (pluto->rev_str, ' ');
+ if (p) *p = 0;
+ memcpy (pluto->fw_rev_str, inq->fw_revision, 4);
+ pluto->fw_rev_str[4] = 0;
+ p = strchr (pluto->fw_rev_str, ' ');
+ if (p) *p = 0;
+ memcpy (pluto->serial_str, inq->serial, 12);
+ pluto->serial_str[12] = 0;
+ p = strchr (pluto->serial_str, ' ');
+ if (p) *p = 0;
+
+ PLD(("Found SSA rev %s fw rev %s serial %s %dx%d\n", pluto->rev_str, pluto->fw_rev_str, pluto->serial_str, host->max_channel, host->max_id))
+ } else
+ fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
+ } else
+ fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
+ }
+ scsi_init_free((char *)fcs, sizeof (struct ctrl_inquiry) * fcscount);
+ if (nplutos)
+ printk ("PLUTO: Total of %d SparcSTORAGE Arrays found\n", nplutos);
+ return nplutos;
+}
+
+int pluto_release(struct Scsi_Host *host)
+{
+ struct pluto *pluto = (struct pluto *)host->hostdata;
+ fc_channel *fc = pluto->fc;
+
+ fc->fcp_register(fc, TYPE_SCSI_FCP, 1);
+ kfree (fc->ages);
+ return 0;
+}
+
+const char *pluto_info(struct Scsi_Host *host)
+{
+ static char buf[80];
+ struct pluto *pluto = (struct pluto *) host->hostdata;
+
+ sprintf(buf, "SUN SparcSTORAGE Array %s fw %s serial %s %dx%d on %s",
+ pluto->rev_str, pluto->fw_rev_str, pluto->serial_str,
+ host->max_channel, host->max_id, pluto->fc->name);
+ return buf;
+}
+
+/* SSA uses this FC4S addressing:
+ switch (addr[0])
+ {
+ case 0: CONTROLLER - All of addr[1]..addr[3] has to be 0
+ case 1: SINGLE DISK - addr[1] channel, addr[2] id, addr[3] 0
+ case 2: DISK GROUP - ???
+ }
+
+ So that SCSI mid-layer can access to these, we reserve
+ channel 0 id 0 lun 0 for CONTROLLER
+ and channels 1 .. max_channel are normal single disks.
+ */
+static int pluto_encode_addr(Scsi_Cmnd *SCpnt, u16 *addr)
+{
+ PLND(("encode addr %d %d %d\n", SCpnt->channel, SCpnt->target, SCpnt->cmnd[1] & 0xe0))
+ /* We don't support LUNs */
+ if (SCpnt->cmnd[1] & 0xe0) return -EINVAL;
+ if (!SCpnt->channel) {
+ if (SCpnt->target) return -EINVAL;
+ memset (addr, 0, 4 * sizeof(u16));
+ } else {
+ addr[0] = 1;
+ addr[1] = SCpnt->channel - 1;
+ addr[2] = SCpnt->target;
+ addr[3] = 0;
+ }
+ PLND(("trying %04x%04x%04x%04x\n", addr[0], addr[1], addr[2], addr[3]))
+ return 0;
+}
+
+#ifdef MODULE
+
+Scsi_Host_Template driver_template = PLUTO;
+
+#include "scsi_module.c"
+
+EXPORT_NO_SYMBOLS;
+#endif /* MODULE */
diff --git a/drivers/scsi/pluto.h b/drivers/scsi/pluto.h
new file mode 100644
index 000000000..6dbda6a57
--- /dev/null
+++ b/drivers/scsi/pluto.h
@@ -0,0 +1,59 @@
+/* pluto.h: SparcSTORAGE Array SCSI host adapter driver definitions.
+ *
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
+ */
+
+#ifndef _PLUTO_H
+#define _PLUTO_H
+
+#include "../fc4/fcp_scsi.h"
+
+struct pluto {
+ /* This must be first */
+ fc_channel *fc;
+ char rev_str[5];
+ char fw_rev_str[5];
+ char serial_str[13];
+};
+
+struct pluto_inquiry {
+ u8 dtype;
+ u8 removable:1, qualifier:7;
+ u8 iso:2, ecma:3, ansi:3;
+ u8 aenc:1, trmiop:1, :2, rdf:4;
+ u8 len;
+ u8 xxx1;
+ u8 xxx2;
+ u8 reladdr:1, wbus32:1, wbus16:1, sync:1, linked:1, :1, cmdque:1, softreset:1;
+ u8 vendor_id[8];
+ u8 product_id[16];
+ u8 revision[4];
+ u8 fw_revision[4];
+ u8 serial[12];
+ u8 xxx3[2];
+ u8 channels;
+ u8 targets;
+};
+
+/* This is the max number of outstanding SCSI commands per pluto */
+#define PLUTO_CAN_QUEUE 254
+
+int pluto_detect(Scsi_Host_Template *);
+int pluto_release(struct Scsi_Host *);
+const char * pluto_info(struct Scsi_Host *);
+
+#define PLUTO { \
+ detect: pluto_detect, \
+ release: pluto_release, \
+ info: pluto_info, \
+ queuecommand: fcp_scsi_queuecommand, \
+ abort: fcp_scsi_abort, \
+ reset: fcp_scsi_reset, \
+ can_queue: PLUTO_CAN_QUEUE, \
+ this_id: -1, \
+ sg_tablesize: 1, \
+ cmd_per_lun: 1, \
+ use_clustering: ENABLE_CLUSTERING \
+}
+
+#endif /* !(_PLUTO_H) */
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
index ea86dd17e..8c825112c 100644
--- a/drivers/scsi/ppa.h
+++ b/drivers/scsi/ppa.h
@@ -15,6 +15,7 @@
/* Use the following to enable certain chipset support
* Default is PEDANTIC = 3
*/
+#include <linux/config.h> /* for CONFIG_SCSI_PPA_HAVE_PEDANTIC */
#ifndef CONFIG_SCSI_PPA_HAVE_PEDANTIC
#define CONFIG_SCSI_PPA_HAVE_PEDANTIC 3
#endif
@@ -152,26 +153,19 @@ int ppa_reset(Scsi_Cmnd *, unsigned int);
int ppa_proc_info(char *, char **, off_t, int, int, int);
int ppa_biosparam(Disk *, kdev_t, int *);
-#define PPA { /* next */ 0, \
- /* usage_count */ 0, \
- /* proc_dir */ &proc_scsi_ppa, \
- /* proc_info */ ppa_proc_info, \
- /* name */ "Iomega parport ZIP drive", \
- /* detect */ ppa_detect, \
- /* release */ ppa_release, \
- /* info */ 0, \
- /* command */ ppa_command, \
- /* queuecommand */ ppa_queuecommand, \
- /* abort */ ppa_abort, \
- /* reset */ ppa_reset, \
- /* slave_attach */ 0, \
- /* bios_param */ ppa_biosparam, \
- /* can_queue */ 0, \
- /* this_id */ -1, \
- /* sg_tablesize */ SG_ALL, \
- /* cmd_per_lun */ 1, \
- /* present */ 0, \
- /* unchecked_isa_dma */ 0, \
- /* use_clustering */ ENABLE_CLUSTERING \
+#define PPA { proc_dir: &proc_scsi_ppa, \
+ proc_info: ppa_proc_info, \
+ name: "Iomega parport ZIP drive", \
+ detect: ppa_detect, \
+ release: ppa_release, \
+ command: ppa_command, \
+ queuecommand: ppa_queuecommand, \
+ abort: ppa_abort, \
+ reset: ppa_reset, \
+ bios_param: ppa_biosparam, \
+ this_id: -1, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: ENABLE_CLUSTERING \
}
#endif /* _PPA_H */
diff --git a/drivers/scsi/psi240i.h b/drivers/scsi/psi240i.h
index 282ee1bb0..1aed96ec7 100644
--- a/drivers/scsi/psi240i.h
+++ b/drivers/scsi/psi240i.h
@@ -320,25 +320,18 @@ int Psi240i_BiosParam (Disk *disk, kdev_t dev, int geom[]);
extern struct proc_dir_entry Proc_Scsi_Psi240i;
-#define PSI240I { NULL, NULL, \
- &Proc_Scsi_Psi240i,/* proc_dir_entry */ \
- NULL, \
- "PSI-240I EIDE Disk Controller", \
- Psi240i_Detect, \
- NULL, \
- NULL, \
- Psi240i_Command, \
- Psi240i_QueueCommand, \
- Psi240i_Abort, \
- Psi240i_Reset, \
- NULL, \
- Psi240i_BiosParam, \
- 1, \
- -1, \
- SG_NONE, \
- 1, \
- 0, \
- 0, \
- DISABLE_CLUSTERING }
+#define PSI240I { proc_dir: &Proc_Scsi_Psi240i,/* proc_dir_entry */ \
+ name: "PSI-240I EIDE Disk Controller",\
+ detect: Psi240i_Detect, \
+ command: Psi240i_Command, \
+ queuecommand: Psi240i_QueueCommand, \
+ abort: Psi240i_Abort, \
+ reset: Psi240i_Reset, \
+ bios_param: Psi240i_BiosParam, \
+ can_queue: 1, \
+ this_id: -1, \
+ sg_tablesize: SG_NONE, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING }
#endif
diff --git a/drivers/scsi/qlogicfas.h b/drivers/scsi/qlogicfas.h
index 4dc16df09..233408c24 100644
--- a/drivers/scsi/qlogicfas.h
+++ b/drivers/scsi/qlogicfas.h
@@ -14,27 +14,18 @@ int qlogicfas_biosparam(Disk *, kdev_t, int[]);
#endif
#define QLOGICFAS { \
- NULL, \
- NULL, \
- NULL, \
- NULL, \
- NULL, \
- qlogicfas_detect, \
- NULL, \
- qlogicfas_info, \
- qlogicfas_command, \
- qlogicfas_queuecommand, \
- qlogicfas_abort, \
- qlogicfas_reset, \
- NULL, \
- qlogicfas_biosparam, \
- 0, \
- -1, \
- SG_ALL, \
- 1, \
- 0, \
- 0, \
- DISABLE_CLUSTERING \
+ detect: qlogicfas_detect, \
+ info: qlogicfas_info, \
+ command: qlogicfas_command, \
+ queuecommand: qlogicfas_queuecommand, \
+ abort: qlogicfas_abort, \
+ reset: qlogicfas_reset, \
+ bios_param: qlogicfas_biosparam, \
+ can_queue: 0, \
+ this_id: -1, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING \
}
#endif /* _QLOGICFAS_H */
diff --git a/drivers/scsi/qlogicisp.h b/drivers/scsi/qlogicisp.h
index 7bc9ef26b..aaba51fe0 100644
--- a/drivers/scsi/qlogicisp.h
+++ b/drivers/scsi/qlogicisp.h
@@ -73,27 +73,20 @@ int isp1020_biosparam(Disk *, kdev_t, int[]);
extern struct proc_dir_entry proc_scsi_isp1020;
#define QLOGICISP { \
- /* next */ NULL, \
- /* module */ NULL, \
- /* proc dir */ NULL, \
- /* procfs info */ NULL, \
- /* name */ NULL, \
- /* detect */ isp1020_detect, \
- /* release */ isp1020_release, \
- /* info */ isp1020_info, \
- /* command */ NULL, \
- /* queuecommand */ isp1020_queuecommand, \
- /* abort */ isp1020_abort, \
- /* reset */ isp1020_reset, \
- /* slave_attach */ NULL, \
- /* bios_param */ isp1020_biosparam, \
- /* can_queue */ QLOGICISP_REQ_QUEUE_LEN, \
- /* this_id */ -1, \
- /* sg_tablesize */ QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
- /* cmd_per_lun */ 1, \
- /* present */ 0, \
- /* unchecked_isa_dma */ 0, \
- /* use_clustering */ DISABLE_CLUSTERING \
+ detect: isp1020_detect, \
+ release: isp1020_release, \
+ info: isp1020_info, \
+ queuecommand: isp1020_queuecommand, \
+ abort: isp1020_abort, \
+ reset: isp1020_reset, \
+ bios_param: isp1020_biosparam, \
+ can_queue: QLOGICISP_REQ_QUEUE_LEN, \
+ this_id: -1, \
+ sg_tablesize: QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
+ cmd_per_lun: 1, \
+ present: 0, \
+ unchecked_isa_dma: 0, \
+ use_clustering: DISABLE_CLUSTERING \
}
#endif /* _QLOGICISP_H */
diff --git a/drivers/scsi/qlogicpti.h b/drivers/scsi/qlogicpti.h
index dc60c4be4..d35f4edb0 100644
--- a/drivers/scsi/qlogicpti.h
+++ b/drivers/scsi/qlogicpti.h
@@ -718,28 +718,18 @@ struct qlogicpti {
#define HCCTRL_B1ENAB 0x0008 /* Breakpoint 1 enable */
#define HCCTRL_B0ENAB 0x0004 /* Breakpoint 0 enable */
-#define QLOGICPTI { \
- /* next */ NULL, \
- /* module */ NULL, \
- /* proc dir */ NULL, \
- /* procfs info */ NULL, \
- /* name */ NULL, \
- /* detect */ qlogicpti_detect, \
- /* release */ qlogicpti_release, \
- /* info */ qlogicpti_info, \
- /* command */ NULL, \
- /* queuecommand */ qlogicpti_queuecommand, \
- /* abort */ qlogicpti_abort, \
- /* reset */ qlogicpti_reset, \
- /* slave_attach */ NULL, \
- /* bios_param */ NULL, \
- /* can_queue */ QLOGICISP_REQ_QUEUE_LEN, \
- /* this_id */ 7, \
- /* sg_tablesize */ QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
- /* cmd_per_lun */ 1, \
- /* present */ 0, \
- /* unchecked_isa_dma */ 0, \
- /* use_clustering */ DISABLE_CLUSTERING \
+#define QLOGICPTI { \
+ detect: qlogicpti_detect, \
+ release: qlogicpti_release, \
+ info: qlogicpti_info, \
+ queuecommand: qlogicpti_queuecommand, \
+ abort: qlogicpti_abort, \
+ reset: qlogicpti_reset, \
+ can_queue: QLOGICISP_REQ_QUEUE_LEN, \
+ this_id: 7, \
+ sg_tablesize: QLOGICISP_MAX_SG(QLOGICISP_REQ_QUEUE_LEN), \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING \
}
/* For our interrupt engine. */
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 9f20c373c..4876ad297 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -12,9 +12,8 @@
* Rik Faith <faith@cs.unc.edu>
* Tommy Thorn <tthorn>
* Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
- * Andrea Arcangeli <arcangeli@mbox.queen.it>
*
- * Modified by Eric Youngdale eric@aib.com to
+ * Modified by Eric Youngdale eric@andante.jic.com or ericy@gnu.ai.mit.edu to
* add scatter-gather, multiple outstanding request, and other
* enhancements.
*
@@ -30,12 +29,6 @@
* Leonard N. Zubkoff <lnz@dandelion.com>
*/
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
-
#include <linux/config.h>
#include <linux/module.h>
@@ -51,9 +44,14 @@
#include <linux/delay.h>
#include <linux/init.h>
+#define __KERNEL_SYSCALLS__
+
+#include <linux/unistd.h>
+
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/dma.h>
+#include <asm/spinlock.h>
#include "scsi.h"
#include "hosts.h"
@@ -69,10 +67,9 @@
static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1.38 1997/01/19 23:07:18 davem Exp $";
*/
-
-/* Command groups 3 and 4 are reserved and should never be used. */
-const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };
-
+/*
+ * Definitions and constants.
+ */
#define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
/*
@@ -90,27 +87,73 @@ const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };
# error You lose.
#endif
-static void scsi_done (Scsi_Cmnd *SCpnt);
-int update_timeout (Scsi_Cmnd *, int);
-static void print_inquiry(unsigned char *data);
-static void scsi_times_out (Scsi_Cmnd * SCpnt);
-static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
- int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
- struct Scsi_Host *shpnt, char * scsi_result);
-void scsi_build_commandblocks(Scsi_Device * SDpnt);
+#define MAX_SCSI_DEVICE_CODE 10
+
+#ifdef DEBUG
+ #define SCSI_TIMEOUT (5*HZ)
+#else
+ #define SCSI_TIMEOUT (2*HZ)
+#endif
+
+#define MIN_RESET_DELAY (2*HZ)
+
+/* Do not call reset on error if we just did a reset within 15 sec. */
+#define MIN_RESET_PERIOD (15*HZ)
+
+/* The following devices are known not to tolerate a lun != 0 scan for
+ * one reason or another. Some will respond to all luns, others will
+ * lock up.
+ */
+
+#define BLIST_NOLUN 0x01
+#define BLIST_FORCELUN 0x02
+#define BLIST_BORKEN 0x04
+#define BLIST_KEY 0x08
+#define BLIST_SINGLELUN 0x10
+#define BLIST_NOTQ 0x20
+#define BLIST_SPARSELUN 0x40
+/*
+ * Data declarations.
+ */
+unsigned long scsi_pid = 0;
+Scsi_Cmnd * last_cmnd = NULL;
+/* Command groups 3 and 4 are reserved and should never be used. */
+const unsigned char scsi_command_size[8] = { 6, 10, 10, 12,
+ 12, 12, 10, 10 };
+static unsigned long serial_number = 0;
+static Scsi_Cmnd * scsi_bh_queue_head = NULL;
+static Scsi_Cmnd * scsi_bh_queue_tail = NULL;
+static spinlock_t scsi_bh_queue_spin = SPIN_LOCK_UNLOCKED;
static FreeSectorBitmap * dma_malloc_freelist = NULL;
-static int scsi_need_isa_bounce_buffers;
-static unsigned int dma_sectors = 0;
-unsigned int dma_free_sectors = 0;
-unsigned int need_isa_buffer = 0;
-static unsigned char ** dma_malloc_pages = NULL;
-
-static int time_start;
-static int time_elapsed;
+static int need_isa_bounce_buffers;
+static unsigned int dma_sectors = 0;
+unsigned int scsi_dma_free_sectors = 0;
+unsigned int scsi_need_isa_buffer = 0;
+static unsigned char ** dma_malloc_pages = NULL;
+
+/*
+ * Note - the initial logging level can be set here to log events at boot time.
+ * After the system is up, you may enable logging via the /proc interface.
+ */
+unsigned int scsi_logging_level = 0;
+
static volatile struct Scsi_Host * host_active = NULL;
-#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
- || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
+
+#if CONFIG_PROC_FS
+/*
+ * This is the pointer to the /proc/scsi code.
+ * It is only initialized to !=0 if the scsi code is present
+ */
+struct proc_dir_entry proc_scsi_scsi = {
+ PROC_SCSI_SCSI, 4, "scsi",
+ S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
+ NULL,
+ NULL, NULL,
+ NULL, NULL, NULL
+};
+#endif
+
const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
{
@@ -126,93 +169,40 @@ const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
"Communications "
};
-
-/*
- * global variables :
- * scsi_devices an array of these specifying the address for each
- * (host, id, LUN)
+/*
+ * Function prototypes.
*/
-
-Scsi_Device * scsi_devices = NULL;
-
-/* Process ID of SCSI commands */
-unsigned long scsi_pid = 0;
-
-static unsigned long serial_number = 0;
-
-static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
static void resize_dma_pool(void);
+static void print_inquiry(unsigned char *data);
+extern void scsi_times_out (Scsi_Cmnd * SCpnt);
+static int scan_scsis_single (int channel,int dev,int lun,int * max_scsi_dev ,
+ int * sparse_lun, Scsi_Device ** SDpnt, Scsi_Cmnd * SCpnt,
+ struct Scsi_Host *shpnt, char * scsi_result);
+void scsi_build_commandblocks(Scsi_Device * SDpnt);
-/* This variable is merely a hook so that we can debug the kernel with gdb. */
-Scsi_Cmnd * last_cmnd = NULL;
-
-/* This is the pointer to the /proc/scsi code.
- * It is only initialized to !=0 if the scsi code is present
+/*
+ * These are the interface to the old error handling code. It should go away
+ * someday soon.
*/
+extern void scsi_old_done (Scsi_Cmnd *SCpnt);
+extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
+
#if CONFIG_PROC_FS
extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start,
off_t offset, int length, int inout);
extern int dispatch_scsi_info(int ino, char *buffer, char **start,
off_t offset, int length, int inout);
-
-struct proc_dir_entry proc_scsi_scsi = {
- PROC_SCSI_SCSI, 4, "scsi",
- S_IFREG | S_IRUGO | S_IWUSR, 1, 0, 0, 0,
- NULL,
- NULL, NULL,
- NULL, NULL, NULL
-};
#endif
-/*
- * This is the number of clock ticks we should wait before we time out
- * and abort the command. This is for where the scsi.c module generates
- * the command, not where it originates from a higher level, in which
- * case the timeout is specified there.
- *
- * ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
- * respectively.
- */
+#define SCSI_BLOCK(DEVICE, HOST) \
+ ((HOST->block && host_active && HOST != host_active) \
+ || ((HOST)->can_queue && HOST->host_busy >= HOST->can_queue) \
+ || ((HOST)->host_blocked) \
+ || ((DEVICE) != NULL && (DEVICE)->device_blocked) )
-#ifdef DEBUG_TIMEOUT
-static void scsi_dump_status(void);
-#endif
+static void scsi_dump_status(int level);
-#ifdef DEBUG
- #define SCSI_TIMEOUT (5*HZ)
-#else
- #define SCSI_TIMEOUT (2*HZ)
-#endif
-
-#ifdef DEBUG
- #define SENSE_TIMEOUT SCSI_TIMEOUT
- #define ABORT_TIMEOUT SCSI_TIMEOUT
- #define RESET_TIMEOUT SCSI_TIMEOUT
-#else
- #define SENSE_TIMEOUT (5*HZ/10)
- #define RESET_TIMEOUT (5*HZ/10)
- #define ABORT_TIMEOUT (5*HZ/10)
-#endif
-
-#define MIN_RESET_DELAY (2*HZ)
-
-/* Do not call reset on error if we just did a reset within 15 sec. */
-#define MIN_RESET_PERIOD (15*HZ)
-
-/* The following devices are known not to tolerate a lun != 0 scan for
- * one reason or another. Some will respond to all luns, others will
- * lock up.
- */
-
-#define BLIST_NOLUN 0x01
-#define BLIST_FORCELUN 0x02
-#define BLIST_BORKEN 0x04
-#define BLIST_KEY 0x08
-#define BLIST_SINGLELUN 0x10
-#define BLIST_NOTQ 0x20
-#define BLIST_SPARSELUN 0x40
-
struct dev_info{
const char * vendor;
const char * model;
@@ -227,6 +217,7 @@ struct dev_info{
*/
static struct dev_info device_list[] =
{
+{"Aashima","IMAGERY 2400SP","1.03",BLIST_NOLUN},/* Locks up if polled for lun != 0 */
{"CHINON","CD-ROM CDS-431","H42", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
{"CHINON","CD-ROM CDS-535","Q14", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
{"DENON","DRD-25X","V", BLIST_NOLUN}, /* Locks up if probed for lun != 0 */
@@ -284,6 +275,7 @@ static struct dev_info device_list[] =
{"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN},
{"EMULEX","MD21/S2 ESDI","*", BLIST_SINGLELUN},
{"CANON","IPUBJD","*", BLIST_SPARSELUN},
+{"nCipher","Fastness Crypto","*", BLIST_FORCELUN},
{"MATSHITA","PD","*", BLIST_FORCELUN | BLIST_SINGLELUN},
{"YAMAHA","CDR100","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
{"YAMAHA","CDR102","1.00", BLIST_NOLUN}, /* Locks up if polled for lun != 0 */
@@ -311,7 +303,31 @@ static int get_device_flags(unsigned char * response_data){
return 0;
}
-void scsi_make_blocked_list(void) {
+/*
+ * Function: scsi_make_blocked_list
+ *
+ * Purpose: Build linked list of hosts that require blocking.
+ *
+ * Arguments: None.
+ *
+ * Returns: Nothing
+ *
+ * Notes: Blocking is sort of a hack that is used to prevent more than one
+ * host adapter from being active at one time. This is used in cases
+ * where the ISA bus becomes unreliable if you have more than one
+ * host adapter really pumping data through.
+ *
+ * We spent a lot of time examining the problem, and I *believe* that
+ * the problem is bus related as opposed to being a driver bug.
+ *
+ * The blocked list is used as part of the synchronization object
+ * that we use to ensure that only one host is active at one time.
+ * I (ERY) would like to make this go away someday, but this would
+ * require that we have a recursive mutex object.
+ */
+void
+scsi_make_blocked_list(void)
+{
int block_count = 0, index;
unsigned long flags;
struct Scsi_Host * sh[128], * shpnt;
@@ -373,22 +389,31 @@ void scsi_make_blocked_list(void) {
static void scan_scsis_done (Scsi_Cmnd * SCpnt)
{
-#ifdef DEBUG
- printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);
-#endif
+ SCSI_LOG_MLCOMPLETE(1,printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result));
SCpnt->request.rq_status = RQ_SCSI_DONE;
if (SCpnt->request.sem != NULL)
up(SCpnt->request.sem);
}
+void scsi_logging_setup(char *str, int *ints)
+{
+ if (ints[0] != 1) {
+ printk("scsi_logging_setup : usage scsi_logging_level=n "
+ "(n should be 0 or non-zero)\n");
+ } else {
+ scsi_logging_level = (ints[1])? ~0 : 0;
+ }
+}
+
#ifdef CONFIG_SCSI_MULTI_LUN
static int max_scsi_luns = 8;
#else
static int max_scsi_luns = 1;
#endif
-void scsi_luns_setup(char *str, int *ints) {
+void scsi_luns_setup(char *str, int *ints)
+{
if (ints[0] != 1)
printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
else
@@ -402,20 +427,29 @@ void scsi_luns_setup(char *str, int *ints) {
* lun address of all sequential devices to the tape driver, all random
* devices to the disk driver.
*/
-static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
- unchar hchannel, unchar hid, unchar hlun)
+static void scan_scsis (struct Scsi_Host *shpnt,
+ unchar hardcoded,
+ unchar hchannel,
+ unchar hid,
+ unchar hlun)
{
- int dev, lun, channel;
- unsigned char scsi_result0[256];
- unsigned char *scsi_result;
- Scsi_Device *SDpnt;
- int max_dev_lun, sparse_lun;
- Scsi_Cmnd *SCpnt;
+ int channel;
+ int dev;
+ int lun;
+ int max_dev_lun;
+ Scsi_Cmnd * SCpnt;
+ unsigned char * scsi_result;
+ unsigned char scsi_result0[256];
+ Scsi_Device * SDpnt;
+ Scsi_Device * SDtail;
+ int sparse_lun;
SCpnt = (Scsi_Cmnd *) scsi_init_malloc (sizeof (Scsi_Cmnd), GFP_ATOMIC | GFP_DMA);
- SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
memset (SCpnt, 0, sizeof (Scsi_Cmnd));
+ SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
+ memset (SDpnt, 0, sizeof (Scsi_Device));
+
/* Make sure we have something that is valid for DMA purposes */
#ifndef CONFIG_SGI
@@ -425,18 +459,44 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
scsi_result = (scsi_init_malloc (512, GFP_DMA));
#endif
- if (scsi_result == NULL) {
- printk ("Unable to obtain scsi_result buffer\n");
- goto leave;
+ if (scsi_result == NULL)
+ {
+ printk ("Unable to obtain scsi_result buffer\n");
+ goto leave;
}
- /* We must chain ourself in the host_queue, so commands can time out */
- if(shpnt->host_queue)
- shpnt->host_queue->prev = SCpnt;
- SCpnt->next = shpnt->host_queue;
- SCpnt->prev = NULL;
- shpnt->host_queue = SCpnt;
+ /*
+ * We must chain ourself in the host_queue, so commands can time out
+ */
+ SCpnt->next = NULL;
+ SDpnt->device_queue = SCpnt;
+ SDpnt->host = shpnt;
+ SDpnt->online = TRUE;
+ /*
+ * Next, hook the device to the host in question.
+ */
+ SDpnt->prev = NULL;
+ SDpnt->next = NULL;
+ if( shpnt->host_queue != NULL )
+ {
+ SDtail = shpnt->host_queue;
+ while( SDtail->next != NULL )
+ SDtail = SDtail->next;
+
+ SDtail->next = SDpnt;
+ SDpnt->prev = SDtail;
+ }
+ else
+ {
+ shpnt->host_queue = SDpnt;
+ }
+
+ /*
+ * We need to increment the counter for this one device so we can track when
+ * things are quiet.
+ */
+ atomic_inc(&shpnt->host_active);
if (hardcoded == 1) {
Scsi_Device *oldSDpnt=SDpnt;
@@ -494,20 +554,30 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
} /* for channel ends */
} /* if/else hardcoded */
+ /*
+ * We need to decrement the counter for this one device
+ * so we know when everything is quiet.
+ */
+ atomic_dec(&shpnt->host_active);
+
leave:
{/* Unchain SCpnt from host_queue */
- Scsi_Cmnd *prev, *next, *hqptr;
- for(hqptr = shpnt->host_queue; hqptr != SCpnt; hqptr = hqptr->next) ;
- if(hqptr) {
- prev = hqptr->prev;
- next = hqptr->next;
- if(prev)
- prev->next = next;
- else
- shpnt->host_queue = next;
- if(next) next->prev = prev;
- }
+ Scsi_Device *prev, *next;
+ Scsi_Device * dqptr;
+
+ for(dqptr = shpnt->host_queue; dqptr != SDpnt; dqptr = dqptr->next)
+ continue;
+ if(dqptr)
+ {
+ prev = dqptr->prev;
+ next = dqptr->next;
+ if(prev)
+ prev->next = next;
+ else
+ shpnt->host_queue = next;
+ if(next) next->prev = prev;
+ }
}
/* Last device block does not exist. Free memory. */
@@ -519,8 +589,25 @@ static void scan_scsis (struct Scsi_Host *shpnt, unchar hardcoded,
/* If we allocated a buffer so we could do DMA, free it now */
if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
- scsi_init_free (scsi_result, 512);
+ {
+ scsi_init_free (scsi_result, 512);
+ }
+ {
+ Scsi_Device * sdev;
+ Scsi_Cmnd * scmd;
+
+ SCSI_LOG_SCAN_BUS(4,printk("Host status for host %p:\n", shpnt));
+ for(sdev = shpnt->host_queue; sdev; sdev = sdev->next)
+ {
+ SCSI_LOG_SCAN_BUS(4,printk("Device %d %p: ", sdev->id, sdev));
+ for(scmd=sdev->device_queue; scmd; scmd = scmd->next)
+ {
+ SCSI_LOG_SCAN_BUS(4,printk("%p ", scmd));
+ }
+ SCSI_LOG_SCAN_BUS(4,printk("\n"));
+ }
+ }
}
/*
@@ -537,16 +624,11 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
Scsi_Device * SDtail, *SDpnt=*SDpnt2;
int bflags, type=-1;
- SDtail = scsi_devices;
- if (scsi_devices)
- while (SDtail->next)
- SDtail = SDtail->next;
-
- memset (SDpnt, 0, sizeof (Scsi_Device));
SDpnt->host = shpnt;
SDpnt->id = dev;
SDpnt->lun = lun;
SDpnt->channel = channel;
+ SDpnt->online = TRUE;
/* Some low level driver could use device->type (DB) */
SDpnt->type = -1;
@@ -576,14 +658,14 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
(void *) scsi_result,
256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
down (&sem);
+ SCpnt->request.sem = NULL;
}
-#if defined(DEBUG) || defined(DEBUG_INIT)
- printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
- dev, lun, SCpnt->result);
- print_driverbyte(SCpnt->result); print_hostbyte(SCpnt->result);
- printk("\n");
-#endif
+ SCSI_LOG_SCAN_BUS(3, printk ("scsi: scan_scsis_single id %d lun %d. Return code 0x%08x\n",
+ dev, lun, SCpnt->result));
+ SCSI_LOG_SCAN_BUS(3,print_driverbyte(SCpnt->result));
+ SCSI_LOG_SCAN_BUS(3,print_hostbyte(SCpnt->result));
+ SCSI_LOG_SCAN_BUS(3,printk("\n"));
if (SCpnt->result) {
if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
@@ -598,9 +680,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
return 0;
}
-#if defined (DEBUG) || defined(DEBUG_INIT)
- printk ("scsi: performing INQUIRY\n");
-#endif
+ SCSI_LOG_SCAN_BUS(3,printk ("scsi: performing INQUIRY\n"));
/*
* Build an INQUIRY command block.
*/
@@ -619,12 +699,11 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
(void *) scsi_result,
256, scan_scsis_done, SCSI_TIMEOUT, 3);
down (&sem);
+ SCpnt->request.sem = NULL;
}
-#if defined(DEBUG) || defined(DEBUG_INIT)
- printk ("scsi: INQUIRY %s with code 0x%x\n",
- SCpnt->result ? "failed" : "successful", SCpnt->result);
-#endif
+ SCSI_LOG_SCAN_BUS(3,printk ("scsi: INQUIRY %s with code 0x%x\n",
+ SCpnt->result ? "failed" : "successful", SCpnt->result));
if (SCpnt->result)
return 0; /* assume no peripheral if any sort of error */
@@ -653,6 +732,7 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
memcpy (SDpnt->rev, scsi_result + 32, 4);
SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
+ SDpnt->online = TRUE;
SDpnt->lockable = SDpnt->removable;
SDpnt->changed = 0;
SDpnt->access_count = 0;
@@ -679,6 +759,8 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
printk ("scsi: unknown type %d\n", type);
}
+ SDpnt->device_blocked = FALSE;
+ SDpnt->device_busy = 0;
SDpnt->single_lun = 0;
SDpnt->soft_reset =
(scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
@@ -732,6 +814,13 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
SDpnt->borken = 0;
/*
+ * If we want to only allow I/O to one of the luns attached to this device
+ * at a time, then we set this flag.
+ */
+ if (bflags & BLIST_SINGLELUN)
+ SDpnt->single_lun = 1;
+
+ /*
* These devices need this "key" to unlock the devices so we can use it
*/
if ((bflags & BLIST_KEY) != 0) {
@@ -752,33 +841,61 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
(void *) scsi_result, 0x2a,
scan_scsis_done, SCSI_TIMEOUT, 3);
down (&sem);
+ SCpnt->request.sem = NULL;
}
}
- /* Add this device to the linked list at the end */
- if (SDtail)
- SDtail->next = SDpnt;
- else
- scsi_devices = SDpnt;
- SDtail = SDpnt;
+ /*
+ * Detach the command from the device. It was just a temporary to be used while
+ * scanning the bus - the real ones will be allocated later.
+ */
+ SDpnt->device_queue = NULL;
+
+ /*
+ * This device was already hooked up to the host in question,
+ * so at this point we just let go of it and it should be fine. We do need to
+ * allocate a new one and attach it to the host so that we can further scan the bus.
+ */
SDpnt = (Scsi_Device *) scsi_init_malloc (sizeof (Scsi_Device), GFP_ATOMIC);
*SDpnt2=SDpnt;
if (!SDpnt)
- printk ("scsi: scan_scsis_single: Cannot malloc\n");
+ {
+ printk ("scsi: scan_scsis_single: Cannot malloc\n");
+ return 0;
+ }
+ memset (SDpnt, 0, sizeof (Scsi_Device));
/*
- * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
+ * And hook up our command block to the new device we will be testing
+ * for.
*/
- if (bflags & BLIST_NOLUN)
- return 0; /* break; */
+ SDpnt->device_queue = SCpnt;
+ SDpnt->online = TRUE;
/*
- * If we want to only allow I/O to one of the luns attached to this device
- * at a time, then we set this flag.
+ * Since we just found one device, there had damn well better be one in the list
+ * already.
*/
- if (bflags & BLIST_SINGLELUN)
- SDpnt->single_lun = 1;
+ if( shpnt->host_queue == NULL )
+ panic("scan_scsis_single: Host queue == NULL\n");
+
+ SDtail = shpnt->host_queue;
+ while (SDtail->next)
+ {
+ SDtail = SDtail->next;
+ }
+
+ /* Add this device to the linked list at the end */
+ SDtail->next = SDpnt;
+ SDpnt->prev = SDtail;
+ SDpnt->next = NULL;
+
+ /*
+ * Some scsi devices cannot be polled for lun != 0 due to firmware bugs
+ */
+ if (bflags & BLIST_NOLUN)
+ return 0; /* break; */
/*
* If this device is known to support sparse multiple units, override the
@@ -820,68 +937,6 @@ int scan_scsis_single (int channel, int dev, int lun, int *max_dev_lun,
#define IN_RESET2 4
#define IN_RESET3 8
-/*
- * This is our time out function, called when the timer expires for a
- * given host adapter. It will attempt to abort the currently executing
- * command, that failing perform a kernel panic.
- */
-
-static void scsi_times_out (Scsi_Cmnd * SCpnt)
-{
-
- switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
- {
- case NORMAL_TIMEOUT:
- {
-#ifdef DEBUG_TIMEOUT
- scsi_dump_status();
-#endif
- }
-
- if (!scsi_abort (SCpnt, DID_TIME_OUT))
- return;
- case IN_ABORT:
- printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
- SCpnt->host->host_no, SCpnt->pid);
- if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
- return;
- case IN_RESET:
- case (IN_ABORT | IN_RESET):
- /* This might be controversial, but if there is a bus hang,
- * you might conceivably want the machine up and running
- * esp if you have an ide disk.
- */
- printk("SCSI host %d channel %d reset (pid %ld) timed out - "
- "trying harder\n",
- SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);
- SCpnt->internal_timeout &= ~IN_RESET;
- SCpnt->internal_timeout |= IN_RESET2;
- scsi_reset (SCpnt,
- SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
- return;
- case (IN_ABORT | IN_RESET | IN_RESET2):
- /* Obviously the bus reset didn't work.
- * Let's try even harder and call for an HBA reset.
- * Maybe the HBA itself crashed and this will shake it loose.
- */
- printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",
- SCpnt->host->host_no, SCpnt->pid);
- SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);
- SCpnt->internal_timeout |= IN_RESET3;
- scsi_reset (SCpnt,
- SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
- return;
-
- default:
- printk("SCSI host %d reset (pid %ld) timed out again -\n",
- SCpnt->host->host_no, SCpnt->pid);
- printk("probably an unrecoverable SCSI bus or device hang.\n");
- return;
-
- }
-
-}
-
/* This function takes a quick look at a request, and decides if it
* can be queued now, or if there would be a stall while waiting for
@@ -890,7 +945,7 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt)
* of the calling code to ensure that this is the case.
*/
-Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
+Scsi_Cmnd * scsi_request_queueable (struct request * req, Scsi_Device * device)
{
Scsi_Cmnd * SCpnt = NULL;
int tablesize;
@@ -898,10 +953,10 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
struct buffer_head * bh, *bhp;
if (!device)
- panic ("No device passed to request_queueable().\n");
+ panic ("No device passed to scsi_request_queueable().\n");
if (req && req->rq_status == RQ_INACTIVE)
- panic("Inactive in request_queueable");
+ panic("Inactive in scsi_request_queueable");
/*
* Look for a free command block. If we have been instructed not to queue
@@ -913,10 +968,10 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
SCpnt = device->device_queue;
while(SCpnt){
if(SCpnt->request.rq_status == RQ_INACTIVE) break;
- SCpnt = SCpnt->device_next;
+ SCpnt = SCpnt->next;
}
} else {
- SCpnt = device->host->host_queue;
+ SCpnt = device->device_queue;
while(SCpnt){
if(SCpnt->channel == device->channel
&& SCpnt->target == device->id) {
@@ -943,7 +998,7 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
if (!SCpnt) return NULL;
- if (SCSI_BLOCK(device->host)) return NULL;
+ if (SCSI_BLOCK(device, device->host)) return NULL;
if (req) {
memcpy(&SCpnt->request, req, sizeof(struct request));
@@ -983,6 +1038,9 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
* either */
}
+ atomic_inc(&SCpnt->host->host_active);
+ SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n", SCpnt->target,
+ atomic_read(&SCpnt->host->host_active)));
SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
SCpnt->old_use_sg = 0;
SCpnt->transfersize = 0;
@@ -995,6 +1053,8 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
SCpnt->channel = device->channel;
SCpnt->lun = device->lun;
SCpnt->target = device->id;
+ SCpnt->state = SCSI_STATE_INITIALIZING;
+ SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
return SCpnt;
}
@@ -1005,11 +1065,11 @@ Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
* not to return a descriptor if the host is unable to accept any more
* commands for the time being. We need to keep in mind that there is no
* guarantee that the host remain not busy. Keep in mind the
- * request_queueable function also knows the internal allocation scheme
+ * scsi_request_queueable function also knows the internal allocation scheme
* of the packets for each device
*/
-Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
+Scsi_Cmnd * scsi_allocate_device (struct request ** reqp, Scsi_Device * device,
int wait)
{
kdev_t dev;
@@ -1023,7 +1083,7 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
Scsi_Cmnd * found = NULL;
if (!device)
- panic ("No device passed to allocate_device().\n");
+ panic ("No device passed to scsi_allocate_device().\n");
if (reqp) req = *reqp;
@@ -1036,7 +1096,7 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
host = device->host;
- if (in_interrupt() && SCSI_BLOCK(host)) return NULL;
+ if (in_interrupt() && SCSI_BLOCK(device, host)) return NULL;
while (1==1){
if (!device->single_lun) {
@@ -1044,10 +1104,10 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
while(SCpnt){
SCwait = SCpnt;
if(SCpnt->request.rq_status == RQ_INACTIVE) break;
- SCpnt = SCpnt->device_next;
+ SCpnt = SCpnt->next;
}
} else {
- SCpnt = device->host->host_queue;
+ SCpnt = device->device_queue;
while(SCpnt){
if(SCpnt->channel == device->channel
&& SCpnt->target == device->id) {
@@ -1084,7 +1144,6 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
}
if (!SCpnt || SCpnt->request.rq_status != RQ_INACTIVE) /* Might have changed */
{
-#if 1 /* NEW CODE */
if (wait && SCwait && SCwait->request.rq_status != RQ_INACTIVE){
sleep_on(&device->device_wait);
restore_flags(flags);
@@ -1095,21 +1154,9 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
printk("Attempt to allocate device channel %d,"
" target %d, lun %d\n", device->channel,
device->id, device->lun);
- panic("No device found in allocate_device\n");
+ panic("No device found in scsi_allocate_device\n");
}
}
-#else /* ORIGINAL CODE */
- restore_flags(flags);
- if(!wait) return NULL;
- if (!SCwait) {
- printk("Attempt to allocate device channel %d, target"
- " %d, lun %d\n", device->channel, device->id,
- device->lun);
- panic("No device found in allocate_device\n");
- }
- SCSI_SLEEP(&device->device_wait,
- (SCwait->request.rq_status != RQ_INACTIVE));
-#endif
} else {
if (req) {
memcpy(&SCpnt->request, req, sizeof(struct request));
@@ -1150,7 +1197,11 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
SCpnt->request.sem = NULL; /* And no one is waiting for this
* to complete */
}
+ atomic_inc(&SCpnt->host->host_active);
restore_flags(flags);
+ SCSI_LOG_MLQUEUE(5, printk("Activating command for device %d (%d)\n",
+ SCpnt->target,
+ atomic_read(&SCpnt->host->host_active)));
break;
}
}
@@ -1164,25 +1215,74 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
/* Since not everyone seems to set the device info correctly
* before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+ * FIXME(eric) This doesn't make any sense.
*/
SCpnt->channel = device->channel;
SCpnt->lun = device->lun;
SCpnt->target = device->id;
+ SCpnt->state = SCSI_STATE_INITIALIZING;
+ SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
return SCpnt;
}
/*
+ * Function: scsi_release_command
+ *
+ * Purpose: Release a command block.
+ *
+ * Arguments: SCpnt - command block we are releasing.
+ *
+ * Notes: The command block can no longer be used by the caller once
+ * this funciton is called. This is in effect the inverse
+ * of scsi_allocate_device/scsi_request_queueable.
+ */
+void
+scsi_release_command(Scsi_Cmnd * SCpnt)
+{
+ SCpnt->request.rq_status = RQ_INACTIVE;
+ SCpnt->state = SCSI_STATE_UNUSED;
+ SCpnt->owner = SCSI_OWNER_NOBODY;
+ atomic_dec(&SCpnt->host->host_active);
+
+ SCSI_LOG_MLQUEUE(5, printk("Deactivating command for device %d (active=%d, failed=%d)\n",
+ SCpnt->target,
+ atomic_read(&SCpnt->host->host_active),
+ SCpnt->host->host_failed));
+ if( SCpnt->host->host_failed != 0 )
+ {
+ SCSI_LOG_ERROR_RECOVERY(5, printk("Error handler thread %d %d\n",
+ SCpnt->host->in_recovery,
+ SCpnt->host->eh_active));
+ }
+
+ /*
+ * If the host is having troubles, then look to see if this was the last
+ * command that might have failed. If so, wake up the error handler.
+ */
+ if( SCpnt->host->in_recovery
+ && !SCpnt->host->eh_active
+ && atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+ {
+ SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
+ atomic_read(&SCpnt->host->eh_wait->count)));
+ up(SCpnt->host->eh_wait);
+ }
+}
+
+/*
* This is inline because we have stack problemes if we recurse to deeply.
*/
-inline void internal_cmnd (Scsi_Cmnd * SCpnt)
+inline int internal_cmnd (Scsi_Cmnd * SCpnt)
{
- unsigned long flags, timeout;
- struct Scsi_Host * host;
#ifdef DEBUG_DELAY
unsigned long clock;
#endif
+ unsigned long flags;
+ struct Scsi_Host * host;
+ int rtn = 0;
+ unsigned long timeout;
#if DEBUG
unsigned long *ret = 0;
@@ -1223,25 +1323,31 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
}
restore_flags(flags);
- update_timeout(SCpnt, SCpnt->timeout_per_command);
+ if( host->hostt->use_new_eh_code )
+ {
+ scsi_add_timer(SCpnt, SCpnt->timeout_per_command, scsi_times_out);
+ }
+ else
+ {
+ scsi_add_timer(SCpnt, SCpnt->timeout_per_command,
+ scsi_old_times_out);
+ }
/*
* We will use a queued command if possible, otherwise we will emulate the
* queuing and calling of completion function ourselves.
*/
-#ifdef DEBUG
- printk("internal_cmnd (host = %d, channel = %d, target = %d, "
+ SCSI_LOG_MLQUEUE(3,printk("internal_cmnd (host = %d, channel = %d, target = %d, "
"command = %p, buffer = %p, \nbufflen = %d, done = %p)\n",
SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd,
- SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
-#endif
+ SCpnt->buffer, SCpnt->bufflen, SCpnt->done));
+ SCpnt->state = SCSI_STATE_QUEUED;
+ SCpnt->owner = SCSI_OWNER_LOWLEVEL;
if (host->can_queue)
{
-#ifdef DEBUG
- printk("queuecommand : routine at %p\n",
- host->hostt->queuecommand);
-#endif
+ SCSI_LOG_MLQUEUE(3,printk("queuecommand : routine at %p\n",
+ host->hostt->queuecommand));
/* This locking tries to prevent all sorts of races between
* queuecommand and the interrupt code. In effect,
* we are only allowed to be in queuecommand once at
@@ -1254,7 +1360,23 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
if(!in_interrupt() && SCpnt->host->irq)
disable_irq(SCpnt->host->irq);
- host->hostt->queuecommand (SCpnt, scsi_done);
+ /*
+ * Use the old error handling code if we haven't converted the driver
+ * to use the new one yet. Note - only the new queuecommand variant
+ * passes a meaningful return value.
+ */
+ if( host->hostt->use_new_eh_code )
+ {
+ rtn = host->hostt->queuecommand (SCpnt, scsi_done);
+ if( rtn != 0 )
+ {
+ scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_HOST_BUSY);
+ }
+ }
+ else
+ {
+ host->hostt->queuecommand (SCpnt, scsi_old_done);
+ }
if(!in_interrupt() && SCpnt->host->irq)
enable_irq(SCpnt->host->irq);
@@ -1263,9 +1385,7 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
{
int temp;
-#ifdef DEBUG
- printk("command() : routine at %p\n", host->hostt->command);
-#endif
+ SCSI_LOG_MLQUEUE(3,printk("command() : routine at %p\n", host->hostt->command));
temp = host->hostt->command (SCpnt);
SCpnt->result = temp;
#ifdef DEBUG_DELAY
@@ -1274,39 +1394,19 @@ inline void internal_cmnd (Scsi_Cmnd * SCpnt)
printk("done(host = %d, result = %04x) : routine at %p\n",
host->host_no, temp, host->hostt->command);
#endif
- scsi_done(SCpnt);
+ if( host->hostt->use_new_eh_code )
+ {
+ scsi_done(SCpnt);
+ }
+ else
+ {
+ scsi_old_done(SCpnt);
+ }
}
-#ifdef DEBUG
- printk("leaving internal_cmnd()\n");
-#endif
+ SCSI_LOG_MLQUEUE(3,printk("leaving internal_cmnd()\n"));
+ return rtn;
}
-static void scsi_request_sense (Scsi_Cmnd * SCpnt)
-{
- unsigned long flags;
-
- save_flags(flags);
- cli();
- SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
- update_timeout(SCpnt, SENSE_TIMEOUT);
- restore_flags(flags);
-
-
- memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
- sizeof(generic_sense));
-
- SCpnt->cmnd[1] = SCpnt->lun << 5;
- SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
-
- SCpnt->request_buffer = &SCpnt->sense_buffer;
- SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
- SCpnt->use_sg = 0;
- SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
- internal_cmnd (SCpnt);
-}
-
-
-
/*
* scsi_do_cmd sends all the commands out to the low-level driver. It
* handles the specifics required for each low level driver - ie queued
@@ -1320,8 +1420,11 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
{
unsigned long flags;
struct Scsi_Host * host = SCpnt->host;
+ Scsi_Device * device = SCpnt->device;
-#ifdef DEBUG
+ SCpnt->owner = SCSI_OWNER_MIDLEVEL;
+
+SCSI_LOG_MLQUEUE(4,
{
int i;
int target = SCpnt->target;
@@ -1333,8 +1436,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
for (i = 0; i < 10; ++i)
printk ("%02x ", ((unsigned char *) cmnd)[i]);
printk("\n");
- }
-#endif
+ });
if (!host)
{
@@ -1354,15 +1456,16 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
cli();
SCpnt->pid = scsi_pid++;
- while (SCSI_BLOCK(host)) {
+ while (SCSI_BLOCK((Scsi_Device *) NULL, host)) {
restore_flags(flags);
- SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
+ SCSI_SLEEP(&host->host_wait, SCSI_BLOCK((Scsi_Device *) NULL, host));
cli();
}
if (host->block) host_active = host;
host->host_busy++;
+ device->device_busy++;
restore_flags(flags);
/*
@@ -1373,12 +1476,6 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
*/
memcpy ((void *) SCpnt->data_cmnd , (const void *) cmnd, 12);
-#if 0
- SCpnt->host = host;
- SCpnt->channel = channel;
- SCpnt->target = target;
- SCpnt->lun = (SCpnt->data_cmnd[1] >> 5);
-#endif
SCpnt->reset_chain = NULL;
SCpnt->serial_number = 0;
SCpnt->bufflen = bufflen;
@@ -1407,967 +1504,307 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
SCpnt->abort_reason = 0;
internal_cmnd (SCpnt);
-#ifdef DEBUG
- printk ("Leaving scsi_do_cmd()\n");
-#endif
-}
-
-static int check_sense (Scsi_Cmnd * SCpnt)
-{
- /* If there is no sense information, request it. If we have already
- * requested it, there is no point in asking again - the firmware must
- * be confused.
- */
- if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
- if(!(SCpnt->flags & ASKED_FOR_SENSE))
- return SUGGEST_SENSE;
- else
- return SUGGEST_RETRY;
- }
-
- SCpnt->flags &= ~ASKED_FOR_SENSE;
-
-#ifdef DEBUG_INIT
- printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
- print_sense("", SCpnt);
- printk("\n");
-#endif
- if (SCpnt->sense_buffer[2] & 0xe0)
- return SUGGEST_ABORT;
-
- switch (SCpnt->sense_buffer[2] & 0xf)
- {
- case NO_SENSE:
- return 0;
- case RECOVERED_ERROR:
- return SUGGEST_IS_OK;
-
- case ABORTED_COMMAND:
- return SUGGEST_RETRY;
- case NOT_READY:
- case UNIT_ATTENTION:
- /*
- * If we are expecting a CC/UA because of a bus reset that we
- * performed, treat this just as a retry. Otherwise this is
- * information that we should pass up to the upper-level driver
- * so that we can deal with it there.
- */
- if( SCpnt->device->expecting_cc_ua )
- {
- SCpnt->device->expecting_cc_ua = 0;
- return SUGGEST_RETRY;
- }
- return SUGGEST_ABORT;
-
- /* these three are not supported */
- case COPY_ABORTED:
- case VOLUME_OVERFLOW:
- case MISCOMPARE:
-
- case MEDIUM_ERROR:
- return SUGGEST_REMAP;
- case BLANK_CHECK:
- case DATA_PROTECT:
- case HARDWARE_ERROR:
- case ILLEGAL_REQUEST:
- default:
- return SUGGEST_ABORT;
- }
+ SCSI_LOG_MLQUEUE(3,printk ("Leaving scsi_do_cmd()\n"));
}
/* This function is the mid-level interrupt routine, which decides how
* to handle error conditions. Each invocation of this function must
* do one and *only* one of the following:
*
- * (1) Call last_cmnd[host].done. This is done for fatal errors and
- * normal completion, and indicates that the handling for this
- * request is complete.
- * (2) Call internal_cmnd to requeue the command. This will result in
- * scsi_done being called again when the retry is complete.
- * (3) Call scsi_request_sense. This asks the host adapter/drive for
- * more information about the error condition. When the information
- * is available, scsi_done will be called again.
- * (4) Call reset(). This is sort of a last resort, and the idea is that
- * this may kick things loose and get the drive working again. reset()
- * automatically calls scsi_request_sense, and thus scsi_done will be
- * called again once the reset is complete.
+ * 1) Insert command in BH queue.
+ * 2) Activate error handler for host.
*
- * If none of the above actions are taken, the drive in question
- * will hang. If more than one of the above actions are taken by
- * scsi_done, then unpredictable behavior will result.
+ * FIXME(eric) - I am concerned about stack overflow (still). An interrupt could
+ * come while we are processing the bottom queue, which would cause another command
+ * to be stuffed onto the bottom queue, and it would in turn be processed as that
+ * interrupt handler is returning. Given a sufficiently steady rate of returning
+ * commands, this could cause the stack to overflow. I am not sure what is the most
+ * appropriate solution here - we should probably keep a depth count, and not process
+ * any commands while we still have a bottom handler active higher in the stack.
+ *
+ * There is currently code in the bottom half handler to monitor recursion in the bottom
+ * handler and report if it ever happens. If this becomes a problem, it won't be hard to
+ * engineer something to deal with it so that only the outer layer ever does any real
+ * processing.
*/
-static void scsi_done (Scsi_Cmnd * SCpnt)
+void
+scsi_done (Scsi_Cmnd * SCpnt)
{
- int status=0;
- int exit=0;
- int checked;
- int oldto;
- struct Scsi_Host * host = SCpnt->host;
- int result = SCpnt->result;
- SCpnt->serial_number = 0;
- oldto = update_timeout(SCpnt, 0);
-
-#ifdef DEBUG_TIMEOUT
- if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
- result, SCpnt->target, SCpnt->lun);
-#endif
-
- /* If we requested an abort, (and we got it) then fix up the return
- * status to say why
- */
- if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
- SCpnt->result = result = (result & 0xff00ffff) |
- (SCpnt->abort_reason << 16);
-
-
-#define FINISHED 0
-#define MAYREDO 1
-#define REDO 3
-#define PENDING 4
-
-#ifdef DEBUG
- printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
-#endif
-
- if(SCpnt->flags & WAS_SENSE)
- {
- SCpnt->use_sg = SCpnt->old_use_sg;
- SCpnt->cmd_len = SCpnt->old_cmd_len;
- }
-
- switch (host_byte(result))
- {
- case DID_OK:
- if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
- /* Failed to obtain sense information */
- {
- SCpnt->flags &= ~WAS_SENSE;
-#if 0 /* This cannot possibly be correct. */
- SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-#endif
-
- if (!(SCpnt->flags & WAS_RESET))
- {
- printk("scsi%d : channel %d target %d lun %d request sense"
- " failed, performing reset.\n",
- SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
- SCpnt->lun);
- scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
- return;
- }
- else
- {
- exit = (DRIVER_HARD | SUGGEST_ABORT);
- status = FINISHED;
- }
- }
- else switch(msg_byte(result))
- {
- case COMMAND_COMPLETE:
- switch (status_byte(result))
- {
- case GOOD:
- if (SCpnt->flags & WAS_SENSE)
- {
-#ifdef DEBUG
- printk ("In scsi_done, GOOD status, COMMAND COMPLETE, "
- "parsing sense information.\n");
-#endif
- SCpnt->flags &= ~WAS_SENSE;
-#if 0 /* This cannot possibly be correct. */
- SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-#endif
+ unsigned long flags;
- switch (checked = check_sense(SCpnt))
- {
- case SUGGEST_SENSE:
- case 0:
-#ifdef DEBUG
- printk("NO SENSE. status = REDO\n");
-#endif
- update_timeout(SCpnt, oldto);
- status = REDO;
- break;
- case SUGGEST_IS_OK:
- break;
- case SUGGEST_REMAP:
-#ifdef DEBUG
- printk("SENSE SUGGEST REMAP - status = FINISHED\n");
-#endif
- status = FINISHED;
- exit = DRIVER_SENSE | SUGGEST_ABORT;
- break;
- case SUGGEST_RETRY:
-#ifdef DEBUG
- printk("SENSE SUGGEST RETRY - status = MAYREDO\n");
-#endif
- status = MAYREDO;
- exit = DRIVER_SENSE | SUGGEST_RETRY;
- break;
- case SUGGEST_ABORT:
-#ifdef DEBUG
- printk("SENSE SUGGEST ABORT - status = FINISHED");
-#endif
- status = FINISHED;
- exit = DRIVER_SENSE | SUGGEST_ABORT;
- break;
- default:
- printk ("Internal error %s %d \n", __FILE__,
- __LINE__);
- }
- } /* end WAS_SENSE */
- else
- {
-#ifdef DEBUG
- printk("COMMAND COMPLETE message returned, "
- "status = FINISHED. \n");
-#endif
- exit = DRIVER_OK;
- status = FINISHED;
- }
- break;
-
- case CHECK_CONDITION:
- case COMMAND_TERMINATED:
- switch (check_sense(SCpnt))
- {
- case 0:
- update_timeout(SCpnt, oldto);
- status = REDO;
- break;
- case SUGGEST_REMAP:
- status = FINISHED;
- exit = DRIVER_SENSE | SUGGEST_ABORT;
- break;
- case SUGGEST_RETRY:
- status = MAYREDO;
- exit = DRIVER_SENSE | SUGGEST_RETRY;
- break;
- case SUGGEST_ABORT:
- status = FINISHED;
- exit = DRIVER_SENSE | SUGGEST_ABORT;
- break;
- case SUGGEST_SENSE:
- scsi_request_sense (SCpnt);
- status = PENDING;
- break;
- }
- break;
-
- case CONDITION_GOOD:
- case INTERMEDIATE_GOOD:
- case INTERMEDIATE_C_GOOD:
- break;
-
- case BUSY:
- case QUEUE_FULL:
- update_timeout(SCpnt, oldto);
- status = REDO;
- break;
-
- case RESERVATION_CONFLICT:
- printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
- " reset.\n", SCpnt->host->host_no, SCpnt->channel);
- scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
- return;
-#if 0
- exit = DRIVER_SOFT | SUGGEST_ABORT;
- status = MAYREDO;
- break;
-#endif
- default:
- printk ("Internal error %s %d \n"
- "status byte = %d \n", __FILE__,
- __LINE__, status_byte(result));
-
- }
- break;
- default:
- panic("scsi: unsupported message byte %d received\n",
- msg_byte(result));
- }
- break;
- case DID_TIME_OUT:
-#ifdef DEBUG
- printk("Host returned DID_TIME_OUT - ");
-#endif
-
- if (SCpnt->flags & WAS_TIMEDOUT)
- {
-#ifdef DEBUG
- printk("Aborting\n");
-#endif
- /*
- Allow TEST_UNIT_READY and INQUIRY commands to timeout early
- without causing resets. All other commands should be retried.
- */
- if (SCpnt->cmnd[0] != TEST_UNIT_READY &&
- SCpnt->cmnd[0] != INQUIRY)
- status = MAYREDO;
- exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
- }
- else
- {
-#ifdef DEBUG
- printk ("Retrying.\n");
-#endif
- SCpnt->flags |= WAS_TIMEDOUT;
- SCpnt->internal_timeout &= ~IN_ABORT;
- status = REDO;
- }
- break;
- case DID_BUS_BUSY:
- case DID_PARITY:
- status = REDO;
- break;
- case DID_NO_CONNECT:
-#ifdef DEBUG
- printk("Couldn't connect.\n");
-#endif
- exit = (DRIVER_HARD | SUGGEST_ABORT);
- break;
- case DID_ERROR:
- status = MAYREDO;
- exit = (DRIVER_HARD | SUGGEST_ABORT);
- break;
- case DID_BAD_TARGET:
- case DID_ABORT:
- exit = (DRIVER_INVALID | SUGGEST_ABORT);
- break;
- case DID_RESET:
- if (SCpnt->flags & IS_RESETTING)
- {
- SCpnt->flags &= ~IS_RESETTING;
- status = REDO;
- break;
- }
-
- if(msg_byte(result) == GOOD &&
- status_byte(result) == CHECK_CONDITION) {
- switch (check_sense(SCpnt)) {
- case 0:
- update_timeout(SCpnt, oldto);
- status = REDO;
- break;
- case SUGGEST_REMAP:
- case SUGGEST_RETRY:
- status = MAYREDO;
- exit = DRIVER_SENSE | SUGGEST_RETRY;
- break;
- case SUGGEST_ABORT:
- status = FINISHED;
- exit = DRIVER_SENSE | SUGGEST_ABORT;
- break;
- case SUGGEST_SENSE:
- scsi_request_sense (SCpnt);
- status = PENDING;
- break;
- }
- } else {
- status=REDO;
- exit = SUGGEST_RETRY;
- }
- break;
- default :
- exit = (DRIVER_ERROR | SUGGEST_DIE);
- }
+ /*
+ * We don't have to worry about this one timing out any more.
+ */
+ scsi_delete_timer(SCpnt);
- switch (status)
+ /*
+ * First, see whether this command already timed out. If so, we ignore
+ * the response. We treat it as if the command never finished.
+ */
+ if( SCpnt->state == SCSI_STATE_TIMEOUT )
{
- case FINISHED:
- case PENDING:
- break;
- case MAYREDO:
-#ifdef DEBUG
- printk("In MAYREDO, allowing %d retries, have %d\n",
- SCpnt->allowed, SCpnt->retries);
-#endif
- if ((++SCpnt->retries) < SCpnt->allowed)
- {
- if ((SCpnt->retries >= (SCpnt->allowed >> 1))
- && !(SCpnt->host->last_reset > 0 &&
- jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
- && !(SCpnt->flags & WAS_RESET))
- {
- printk("scsi%d channel %d : resetting for second half of retries.\n",
- SCpnt->host->host_no, SCpnt->channel);
- scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
- break;
- }
-
- }
- else
- {
- status = FINISHED;
- break;
- }
- /* fall through to REDO */
-
- case REDO:
-
- if (SCpnt->flags & WAS_SENSE)
- scsi_request_sense(SCpnt);
- else
- {
- memcpy ((void *) SCpnt->cmnd,
- (void*) SCpnt->data_cmnd,
- sizeof(SCpnt->data_cmnd));
- SCpnt->request_buffer = SCpnt->buffer;
- SCpnt->request_bufflen = SCpnt->bufflen;
- SCpnt->use_sg = SCpnt->old_use_sg;
- SCpnt->cmd_len = SCpnt->old_cmd_len;
- internal_cmnd (SCpnt);
- }
- break;
- default:
- INTERNAL_ERROR;
+ SCSI_LOG_MLCOMPLETE(1,printk("Ignoring completion of %p due to timeout status", SCpnt));
+ return;
}
- if (status == FINISHED) {
-#ifdef DEBUG
- printk("Calling done function - at address %p\n", SCpnt->done);
-#endif
- host->host_busy--; /* Indicate that we are free */
+ SCpnt->state = SCSI_STATE_BHQUEUE;
+ SCpnt->owner = SCSI_OWNER_BH_HANDLER;
+ SCpnt->bh_next = NULL;
- if (host->block && host->host_busy == 0) {
- host_active = NULL;
-
- /* For block devices "wake_up" is done in end_scsi_request */
- if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
- MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
- struct Scsi_Host * next;
-
- for (next = host->block; next != host; next = next->block)
- wake_up(&next->host_wait);
- }
-
- }
+ /*
+ * Next, put this command in the BH queue. All processing of the command
+ * past this point will take place with interrupts turned on.
+ * We start by atomicly swapping the pointer into the queue head slot.
+ * If it was NULL before, then everything is fine, and we are done
+ * (this is the normal case). If it was not NULL, then we block interrupts,
+ * and link them together.
+ * We need a spinlock here, or compare and exchange if we can reorder incoming
+ * Scsi_Cmnds, as it happens pretty often scsi_done is called multiple times
+ * before bh is serviced. -jj
+ */
- wake_up(&host->host_wait);
- SCpnt->result = result | ((exit & 0xff) << 24);
- SCpnt->use_sg = SCpnt->old_use_sg;
- SCpnt->cmd_len = SCpnt->old_cmd_len;
- SCpnt->done (SCpnt);
- }
+ spin_lock_irqsave(&scsi_bh_queue_spin, flags);
+ if (!scsi_bh_queue_head) {
+ scsi_bh_queue_head = SCpnt;
+ scsi_bh_queue_tail = SCpnt;
+ } else {
+ scsi_bh_queue_tail->bh_next = SCpnt;
+ scsi_bh_queue_tail = SCpnt;
+ }
+ spin_unlock_irqrestore(&scsi_bh_queue_spin, flags);
-#undef FINISHED
-#undef REDO
-#undef MAYREDO
-#undef PENDING
+ /*
+ * Mark the bottom half handler to be run.
+ */
+ mark_bh(SCSI_BH);
}
/*
- * The scsi_abort function interfaces with the abort() function of the host
- * we are aborting, and causes the current command to not complete. The
- * caller should deal with any error messages or status returned on the
- * next call.
+ * Procedure: scsi_bottom_half_handler
*
- * This will not be called reentrantly for a given host.
- */
-
-/*
- * Since we're nice guys and specified that abort() and reset()
- * can be non-reentrant. The internal_timeout flags are used for
- * this.
+ * Purpose: Called after we have finished processing interrupts, it
+ * performs post-interrupt handling for commands that may
+ * have completed.
+ *
+ * Notes: This is called with all interrupts enabled. This should reduce
+ * interrupt latency, stack depth, and reentrancy of the low-level
+ * drivers.
*/
-
-
-int scsi_abort (Scsi_Cmnd * SCpnt, int why)
-{
- int oldto;
- unsigned long flags;
- struct Scsi_Host * host = SCpnt->host;
-
- while(1)
- {
- save_flags(flags);
- cli();
-
- /*
- * Protect against races here. If the command is done, or we are
- * on a different command forget it.
- */
- if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
- restore_flags(flags);
- return 0;
- }
-
- if (SCpnt->internal_timeout & IN_ABORT)
- {
- restore_flags(flags);
- while (SCpnt->internal_timeout & IN_ABORT)
- barrier();
- }
- else
- {
- SCpnt->internal_timeout |= IN_ABORT;
- oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
-
- if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
- /* OK, this command must have died when we did the
- * reset. The device itself must have lied.
- */
- printk("Stale command on %d %d:%d appears to have died when"
- " the bus was reset\n",
- SCpnt->channel, SCpnt->target, SCpnt->lun);
- }
-
- restore_flags(flags);
- if (!host->host_busy) {
- SCpnt->internal_timeout &= ~IN_ABORT;
- update_timeout(SCpnt, oldto);
- return 0;
- }
- printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
- " channel %d, id %d, lun %d ",
- SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
- (int) SCpnt->target, (int) SCpnt->lun);
- print_command (SCpnt->cmnd);
- if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
- return 0;
- SCpnt->abort_reason = why;
- switch(host->hostt->abort(SCpnt)) {
- /* We do not know how to abort. Try waiting another
- * time increment and see if this helps. Set the
- * WAS_TIMEDOUT flag set so we do not try this twice
- */
- case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
- * this is too severe
- */
- case SCSI_ABORT_SNOOZE:
- if(why == DID_TIME_OUT) {
- save_flags(flags);
- cli();
- SCpnt->internal_timeout &= ~IN_ABORT;
- if(SCpnt->flags & WAS_TIMEDOUT) {
- restore_flags(flags);
- return 1; /* Indicate we cannot handle this.
- * We drop down into the reset handler
- * and try again
- */
- } else {
- SCpnt->flags |= WAS_TIMEDOUT;
- oldto = SCpnt->timeout_per_command;
- update_timeout(SCpnt, oldto);
- }
- restore_flags(flags);
- }
- return 0;
- case SCSI_ABORT_PENDING:
- if(why != DID_TIME_OUT) {
- save_flags(flags);
- cli();
- update_timeout(SCpnt, oldto);
- restore_flags(flags);
- }
- return 0;
- case SCSI_ABORT_SUCCESS:
- /* We should have already aborted this one. No
- * need to adjust timeout
- */
- SCpnt->internal_timeout &= ~IN_ABORT;
- return 0;
- case SCSI_ABORT_NOT_RUNNING:
- SCpnt->internal_timeout &= ~IN_ABORT;
- update_timeout(SCpnt, 0);
- return 0;
- case SCSI_ABORT_ERROR:
- default:
- SCpnt->internal_timeout &= ~IN_ABORT;
- return 1;
- }
- }
- }
-}
-
-
-/* Mark a single SCSI Device as having been reset. */
-
-static inline void scsi_mark_device_reset(Scsi_Device *Device)
-{
- Device->was_reset = 1;
- Device->expecting_cc_ua = 1;
-}
-
-
-/* Mark all SCSI Devices on a specific Host as having been reset. */
-
-void scsi_mark_host_reset(struct Scsi_Host *Host)
-{
- Scsi_Cmnd *SCpnt;
- for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
- scsi_mark_device_reset(SCpnt->device);
-}
-
-
-/* Mark all SCSI Devices on a specific Host Bus as having been reset. */
-
-void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel)
-{
- Scsi_Cmnd *SCpnt;
- for (SCpnt = Host->host_queue; SCpnt; SCpnt = SCpnt->next)
- if (SCpnt->channel == channel)
- scsi_mark_device_reset(SCpnt->device);
-}
-
-
-int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+void scsi_bottom_half_handler(void)
{
- int temp;
- unsigned long flags;
- Scsi_Cmnd * SCpnt1;
- struct Scsi_Host * host = SCpnt->host;
-
- printk("SCSI bus is being reset for host %d channel %d.\n",
- host->host_no, SCpnt->channel);
-
-#if 0
- /*
- * First of all, we need to make a recommendation to the low-level
- * driver as to whether a BUS_DEVICE_RESET should be performed,
- * or whether we should do a full BUS_RESET. There is no simple
- * algorithm here - we basically use a series of heuristics
- * to determine what we should do.
- */
- SCpnt->host->suggest_bus_reset = FALSE;
-
- /*
- * First see if all of the active devices on the bus have
- * been jammed up so that we are attempting resets. If so,
- * then suggest a bus reset. Forcing a bus reset could
- * result in some race conditions, but no more than
- * you would usually get with timeouts. We will cross
- * that bridge when we come to it.
- *
- * This is actually a pretty bad idea, since a sequence of
- * commands will often timeout together and this will cause a
- * Bus Device Reset followed immediately by a SCSI Bus Reset.
- * If all of the active devices really are jammed up, the
- * Bus Device Reset will quickly timeout and scsi_times_out
- * will follow up with a SCSI Bus Reset anyway.
- */
- SCpnt1 = host->host_queue;
- while(SCpnt1) {
- if( SCpnt1->request.rq_status != RQ_INACTIVE
- && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
- break;
- SCpnt1 = SCpnt1->next;
- }
- if( SCpnt1 == NULL ) {
- reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
- }
-
- /*
- * If the code that called us is suggesting a hard reset, then
- * definitely request it. This usually occurs because a
- * BUS_DEVICE_RESET times out.
- *
- * Passing reset_flags along takes care of this automatically.
- */
- if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) {
- SCpnt->host->suggest_bus_reset = TRUE;
- }
-#endif
-
- while (1) {
- save_flags(flags);
- cli();
-
- /*
- * Protect against races here. If the command is done, or we are
- * on a different command forget it.
- */
- if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
- if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
- restore_flags(flags);
- return 0;
- }
-
- if (SCpnt->internal_timeout & IN_RESET)
- {
- restore_flags(flags);
- while (SCpnt->internal_timeout & IN_RESET)
- barrier();
- }
- else
- {
- SCpnt->internal_timeout |= IN_RESET;
- update_timeout(SCpnt, RESET_TIMEOUT);
-
- if (host->host_busy)
- {
- restore_flags(flags);
- SCpnt1 = host->host_queue;
- while(SCpnt1) {
- if (SCpnt1->request.rq_status != RQ_INACTIVE) {
-#if 0
- if (!(SCpnt1->flags & IS_RESETTING) &&
- !(SCpnt1->internal_timeout & IN_ABORT))
- scsi_abort(SCpnt1, DID_RESET);
-#endif
- SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
- }
- SCpnt1 = SCpnt1->next;
- }
-
- host->last_reset = jiffies;
- temp = host->hostt->reset(SCpnt, reset_flags);
- /*
- This test allows the driver to introduce an additional bus
- settle time delay by setting last_reset up to 20 seconds in
- the future. In the normal case where the driver does not
- modify last_reset, it must be assumed that the actual bus
- reset occurred immediately prior to the return to this code,
- and so last_reset must be updated to the current time, so
- that the delay in internal_cmnd will guarantee at least a
- MIN_RESET_DELAY bus settle time.
- */
- if (host->last_reset - jiffies > 20UL * HZ)
- host->last_reset = jiffies;
- }
- else
- {
- if (!host->block) host->host_busy++;
- restore_flags(flags);
- host->last_reset = jiffies;
- SCpnt->flags |= (WAS_RESET | IS_RESETTING);
- temp = host->hostt->reset(SCpnt, reset_flags);
- if ((host->last_reset < jiffies) ||
- (host->last_reset > (jiffies + 20 * HZ)))
- host->last_reset = jiffies;
- if (!host->block) host->host_busy--;
- }
-
-#ifdef DEBUG
- printk("scsi reset function returned %d\n", temp);
-#endif
-
- /*
- * Now figure out what we need to do, based upon
- * what the low level driver said that it did.
- * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
- * or SCSI_RESET_WAKEUP, then the low level driver did a
- * bus device reset or bus reset, so we should go through
- * and mark one or all of the devices on that bus
- * as having been reset.
- */
- switch(temp & SCSI_RESET_ACTION) {
- case SCSI_RESET_SUCCESS:
- if (temp & SCSI_RESET_HOST_RESET)
- scsi_mark_host_reset(host);
- else if (temp & SCSI_RESET_BUS_RESET)
- scsi_mark_bus_reset(host, SCpnt->channel);
- else scsi_mark_device_reset(SCpnt->device);
- save_flags(flags);
- cli();
- SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
- restore_flags(flags);
- return 0;
- case SCSI_RESET_PENDING:
- if (temp & SCSI_RESET_HOST_RESET)
- scsi_mark_host_reset(host);
- else if (temp & SCSI_RESET_BUS_RESET)
- scsi_mark_bus_reset(host, SCpnt->channel);
- else scsi_mark_device_reset(SCpnt->device);
- case SCSI_RESET_NOT_RUNNING:
- return 0;
- case SCSI_RESET_PUNT:
- SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
- scsi_request_sense (SCpnt);
- return 0;
- case SCSI_RESET_WAKEUP:
- if (temp & SCSI_RESET_HOST_RESET)
- scsi_mark_host_reset(host);
- else if (temp & SCSI_RESET_BUS_RESET)
- scsi_mark_bus_reset(host, SCpnt->channel);
- else scsi_mark_device_reset(SCpnt->device);
- SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
- scsi_request_sense (SCpnt);
- /*
- * If a bus reset was performed, we
- * need to wake up each and every command
- * that was active on the bus or if it was a HBA
- * reset all active commands on all channels
- */
- if( temp & SCSI_RESET_HOST_RESET )
- {
- SCpnt1 = host->host_queue;
- while(SCpnt1) {
- if (SCpnt1->request.rq_status != RQ_INACTIVE
- && SCpnt1 != SCpnt)
- scsi_request_sense (SCpnt1);
- SCpnt1 = SCpnt1->next;
- }
- } else if( temp & SCSI_RESET_BUS_RESET ) {
- SCpnt1 = host->host_queue;
- while(SCpnt1) {
- if(SCpnt1->request.rq_status != RQ_INACTIVE
- && SCpnt1 != SCpnt
- && SCpnt1->channel == SCpnt->channel)
- scsi_request_sense (SCpnt);
- SCpnt1 = SCpnt1->next;
- }
- }
- return 0;
- case SCSI_RESET_SNOOZE:
- /* In this case, we set the timeout field to 0
- * so that this command does not time out any more,
- * and we return 1 so that we get a message on the
- * screen.
- */
- save_flags(flags);
- cli();
- SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
- update_timeout(SCpnt, 0);
- restore_flags(flags);
- /* If you snooze, you lose... */
- case SCSI_RESET_ERROR:
- default:
- return 1;
- }
+ Scsi_Cmnd * SCpnt;
+ Scsi_Cmnd * SCnext;
+ static atomic_t recursion_depth;
+ unsigned long flags;
+
+ while(1==1)
+ {
+ /*
+ * If the counter is > 0, that means that there is another interrupt handler
+ * out there somewhere processing commands. We don't want to get these guys
+ * nested as this can lead to stack overflow problems, and there isn't any
+ * real sense in it anyways.
+ */
+ if( atomic_read(&recursion_depth) > 0 )
+ {
+ printk("SCSI bottom half recursion depth = %d \n", atomic_read(&recursion_depth));
+ SCSI_LOG_MLCOMPLETE(1,printk("SCSI bottom half recursion depth = %d \n",
+ atomic_read(&recursion_depth)));
+ break;
+ }
+
+ /*
+ * We need to hold the spinlock, so that nobody is tampering with the queue. -jj
+ * We will process everything we find in the list here.
+ */
+
+ spin_lock_irqsave(&scsi_bh_queue_spin, flags);
+ SCpnt = scsi_bh_queue_head;
+ scsi_bh_queue_head = NULL;
+ spin_unlock_irqrestore(&scsi_bh_queue_spin, flags);
+
+ if( SCpnt == NULL )
+ return;
+
+ atomic_inc(&recursion_depth);
+
+ SCnext = SCpnt->bh_next;
+
+ for(; SCpnt; SCpnt = SCnext)
+ {
+ SCnext = SCpnt->bh_next;
+
+ switch( scsi_decide_disposition(SCpnt) )
+ {
+ case SUCCESS:
+ /*
+ * Add to BH queue.
+ */
+ SCSI_LOG_MLCOMPLETE(3,printk("Command finished %d %d 0x%x\n", SCpnt->host->host_busy,
+ SCpnt->host->host_failed,
+ SCpnt->result));
+
+ scsi_finish_command(SCpnt);
+ break;
+ case NEEDS_RETRY:
+ /*
+ * We only come in here if we want to retry a command. The
+ * test to see whether the command should be retried should be
+ * keeping track of the number of tries, so we don't end up looping,
+ * of course.
+ */
+ SCSI_LOG_MLCOMPLETE(3,printk("Command needs retry %d %d 0x%x\n", SCpnt->host->host_busy,
+ SCpnt->host->host_failed, SCpnt->result));
+
+ scsi_retry_command(SCpnt);
+ break;
+ case ADD_TO_MLQUEUE:
+ /*
+ * This typically happens for a QUEUE_FULL message -
+ * typically only when the queue depth is only
+ * approximate for a given device. Adding a command
+ * to the queue for the device will prevent further commands
+ * from being sent to the device, so we shouldn't end up
+ * with tons of things being sent down that shouldn't be.
+ */
+ scsi_mlqueue_insert(SCpnt, SCSI_MLQUEUE_DEVICE_BUSY);
+ break;
+ default:
+ /*
+ * Here we have a fatal error of some sort. Turn it over to
+ * the error handler.
+ */
+ SCSI_LOG_MLCOMPLETE(3,printk("Command failed %p %x active=%d busy=%d failed=%d\n",
+ SCpnt, SCpnt->result,
+ atomic_read(&SCpnt->host->host_active),
+ SCpnt->host->host_busy,
+ SCpnt->host->host_failed));
+
+ /*
+ * Dump the sense information too.
+ */
+ if ((status_byte (SCpnt->result) & CHECK_CONDITION) != 0)
+ {
+ SCSI_LOG_MLCOMPLETE(3,print_sense("bh",SCpnt));
+ }
+
+
+ if( SCpnt->host->eh_wait != NULL )
+ {
+ SCpnt->host->host_failed++;
+ SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+ SCpnt->state = SCSI_STATE_FAILED;
+ SCpnt->host->in_recovery = 1;
+ /*
+ * If the host is having troubles, then look to see if this was the last
+ * command that might have failed. If so, wake up the error handler.
+ */
+ if( atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+ {
+ SCSI_LOG_ERROR_RECOVERY(5, printk("Waking error handler thread (%d)\n",
+ atomic_read(&SCpnt->host->eh_wait->count)));
+ up(SCpnt->host->eh_wait);
+ }
+ }
+ else
+ {
+ /*
+ * We only get here if the error recovery thread has died.
+ */
+ scsi_finish_command(SCpnt);
+ }
+ }
+ } /* for(; SCpnt...) */
+
+ atomic_dec(&recursion_depth);
+
+ } /* while(1==1) */
- return temp;
- }
- }
}
-
-static void scsi_main_timeout(void)
+/*
+ * Function: scsi_retry_command
+ *
+ * Purpose: Send a command back to the low level to be retried.
+ *
+ * Notes: This command is always executed in the context of the
+ * bottom half handler, or the error handler thread. Low
+ * level drivers should not become re-entrant as a result of
+ * this.
+ */
+int
+scsi_retry_command(Scsi_Cmnd * SCpnt)
{
- /*
- * We must not enter update_timeout with a timeout condition still pending.
- */
-
- int timed_out;
- unsigned long flags;
- struct Scsi_Host * host;
- Scsi_Cmnd * SCpnt = NULL;
-
- save_flags(flags);
- cli();
-
- update_timeout(NULL, 0);
-
- /*
- * Find all timers such that they have 0 or negative (shouldn't happen)
- * time remaining on them.
- */
- timed_out = 0;
- for (host = scsi_hostlist; host; host = host->next) {
- for (SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
- if (SCpnt->timeout == -1)
- {
- SCpnt->timeout = 0;
- SCpnt->serial_number_at_timeout = SCpnt->serial_number;
- ++timed_out;
- }
- }
- if (timed_out > 0) {
- for (host = scsi_hostlist; host; host = host->next) {
- for (SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
- if (SCpnt->serial_number_at_timeout > 0 &&
- SCpnt->serial_number_at_timeout == SCpnt->serial_number)
- {
- restore_flags(flags);
- scsi_times_out(SCpnt);
- SCpnt->serial_number_at_timeout = 0;
- cli();
- }
- }
- }
- restore_flags(flags);
+ memcpy ((void *) SCpnt->cmnd, (void*) SCpnt->data_cmnd,
+ sizeof(SCpnt->data_cmnd));
+ SCpnt->request_buffer = SCpnt->buffer;
+ SCpnt->request_bufflen = SCpnt->bufflen;
+ SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
+ return internal_cmnd (SCpnt);
}
/*
- * The strategy is to cause the timer code to call scsi_times_out()
- * when the soonest timeout is pending.
- * The arguments are used when we are queueing a new command, because
- * we do not want to subtract the time used from this time, but when we
- * set the timer, we want to take this value into account.
+ * Function: scsi_finish_command
+ *
+ * Purpose: Pass command off to upper layer for finishing of I/O
+ * request, waking processes that are waiting on results,
+ * etc.
*/
-
-int update_timeout(Scsi_Cmnd * SCset, int timeout)
+void
+scsi_finish_command(Scsi_Cmnd * SCpnt)
{
- unsigned int least, used;
- unsigned int oldto;
- unsigned long flags;
struct Scsi_Host * host;
- Scsi_Cmnd * SCpnt = NULL;
-
- save_flags(flags);
- cli();
+ Scsi_Device * device;
- oldto = 0;
-
- /*
- * This routine can be a performance bottleneck under high loads, since
- * it is called twice per SCSI operation: once when internal_cmnd is
- * called, and again when scsi_done completes the command. To limit
- * the load this routine can cause, we shortcut processing if no clock
- * ticks have occurred since the last time it was called.
- */
+ host = SCpnt->host;
+ device = SCpnt->device;
- if (jiffies == time_start && timer_table[SCSI_TIMER].expires > 0) {
- if(SCset){
- oldto = SCset->timeout;
- SCset->timeout = timeout;
- if (timeout > 0 &&
- jiffies + timeout < timer_table[SCSI_TIMER].expires)
- timer_table[SCSI_TIMER].expires = jiffies + timeout;
- }
- restore_flags(flags);
- return oldto;
+ host->host_busy--; /* Indicate that we are free */
+ device->device_busy--; /* Decrement device usage counter. */
+
+ if (host->block && host->host_busy == 0)
+ {
+ host_active = NULL;
+
+ /* For block devices "wake_up" is done in end_scsi_request */
+ if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
+ MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
+ struct Scsi_Host * next;
+
+ for (next = host->block; next != host; next = next->block)
+ wake_up(&next->host_wait);
+ }
+
}
-
- /*
- * Figure out how much time has passed since the last time the timeouts
- * were updated
- */
- used = (time_start) ? (jiffies - time_start) : 0;
-
+
/*
- * Find out what is due to timeout soonest, and adjust all timeouts for
- * the amount of time that has passed since the last time we called
- * update_timeout.
+ * Now try and drain the mid-level queue if any commands have been
+ * inserted. Check to see whether the queue even has anything in
+ * it first, as otherwise this is useless overhead.
*/
-
- oldto = 0;
-
- if(SCset){
- oldto = SCset->timeout - used;
- SCset->timeout = timeout;
+ if( SCpnt->host->pending_commands != NULL )
+ {
+ scsi_mlqueue_finish(SCpnt->host, SCpnt->device);
}
- least = 0xffffffff;
-
- for(host = scsi_hostlist; host; host = host->next)
- for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
- if (SCpnt->timeout > 0) {
- if (SCpnt != SCset)
- SCpnt->timeout -= used;
- if(SCpnt->timeout <= 0) SCpnt->timeout = -1;
- if(SCpnt->timeout > 0 && SCpnt->timeout < least)
- least = SCpnt->timeout;
- }
-
+ wake_up(&host->host_wait);
+
/*
- * If something is due to timeout again, then we will set the next timeout
- * interrupt to occur. Otherwise, timeouts are disabled.
+ * If we have valid sense information, then some kind of recovery
+ * must have taken place. Make a note of this.
*/
-
- if (least != 0xffffffff)
+ if( scsi_sense_valid(SCpnt) )
{
- time_start = jiffies;
- timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
- timer_active |= 1 << SCSI_TIMER;
+ SCpnt->result |= (DRIVER_SENSE << 24);
}
- else
- {
- timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
- timer_active &= ~(1 << SCSI_TIMER);
- }
- restore_flags(flags);
- return oldto;
+
+ SCSI_LOG_MLCOMPLETE(3,printk("Notifying upper driver of completion for device %d %x\n",
+ SCpnt->device->id, SCpnt->result));
+
+ SCpnt->owner = SCSI_OWNER_HIGHLEVEL;
+ SCpnt->state = SCSI_STATE_FINISHED;
+ SCpnt->done (SCpnt);
}
#ifdef CONFIG_MODULES
@@ -2393,9 +1830,10 @@ void *scsi_malloc(unsigned int len)
if ((dma_malloc_freelist[i] & (mask << j)) == 0){
dma_malloc_freelist[i] |= (mask << j);
restore_flags(flags);
- dma_free_sectors -= nbits;
+ scsi_dma_free_sectors -= nbits;
#ifdef DEBUG
- printk("SMalloc: %d %p\n",len, dma_malloc_pages[i] + (j << 9));
+ SCSI_LOG_MLQUEUE(3,printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9)));
+ printk("SMalloc: %d %p [From:%p]\n",len, dma_malloc_pages[i] + (j << 9));
#endif
return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
}
@@ -2418,6 +1856,7 @@ int scsi_free(void *obj, unsigned int len)
ret = __builtin_return_address(0);
#endif
printk("scsi_free %p %d\n",obj, len);
+ SCSI_LOG_MLQUEUE(3,printk("SFree: %p %d\n",obj, len));
#endif
for (page = 0; page < dma_sectors / SECTORS_PER_PAGE; page++) {
@@ -2443,7 +1882,7 @@ int scsi_free(void *obj, unsigned int len)
#endif
panic("scsi_free:Trying to free unused memory");
}
- dma_free_sectors += nbits;
+ scsi_dma_free_sectors += nbits;
dma_malloc_freelist[page] &= ~(mask << sector);
restore_flags(flags);
return 0;
@@ -2455,7 +1894,7 @@ int scsi_free(void *obj, unsigned int len)
int scsi_loadable_module_flag; /* Set after we scan builtin drivers */
-void * scsi_init_malloc(unsigned int size, int priority)
+void * scsi_init_malloc(unsigned int size, int gfp_mask)
{
void * retval;
@@ -2468,10 +1907,9 @@ void * scsi_init_malloc(unsigned int size, int priority)
for (order = 0, a_size = PAGE_SIZE;
a_size < size; order++, a_size <<= 1)
;
- retval = (void *) __get_dma_pages(priority & GFP_LEVEL_MASK,
- order);
+ retval = (void *) __get_free_pages(gfp_mask | GFP_DMA, order);
} else
- retval = kmalloc(size, priority);
+ retval = kmalloc(size, gfp_mask);
if (retval)
memset(retval, 0, size);
@@ -2512,37 +1950,37 @@ void scsi_build_commandblocks(Scsi_Device * SDpnt)
scsi_init_malloc(sizeof(Scsi_Cmnd),
GFP_ATOMIC |
(host->unchecked_isa_dma ? GFP_DMA : 0));
- SCpnt->host = host;
- SCpnt->device = SDpnt;
- SCpnt->target = SDpnt->id;
- SCpnt->lun = SDpnt->lun;
- SCpnt->channel = SDpnt->channel;
- SCpnt->request.rq_status = RQ_INACTIVE;
- SCpnt->use_sg = 0;
- SCpnt->old_use_sg = 0;
- SCpnt->old_cmd_len = 0;
- SCpnt->timeout = 0;
- SCpnt->underflow = 0;
- SCpnt->transfersize = 0;
- SCpnt->serial_number = 0;
- SCpnt->serial_number_at_timeout = 0;
- SCpnt->host_scribble = NULL;
- if(host->host_queue)
- host->host_queue->prev = SCpnt;
- SCpnt->next = host->host_queue;
- SCpnt->prev = NULL;
- host->host_queue = SCpnt;
- SCpnt->device_next = SDpnt->device_queue;
- SDpnt->device_queue = SCpnt;
+ memset(&SCpnt->eh_timeout, 0, sizeof(SCpnt->eh_timeout));
+ SCpnt->host = host;
+ SCpnt->device = SDpnt;
+ SCpnt->target = SDpnt->id;
+ SCpnt->lun = SDpnt->lun;
+ SCpnt->channel = SDpnt->channel;
+ SCpnt->request.rq_status = RQ_INACTIVE;
+ SCpnt->host_wait = FALSE;
+ SCpnt->device_wait = FALSE;
+ SCpnt->use_sg = 0;
+ SCpnt->old_use_sg = 0;
+ SCpnt->old_cmd_len = 0;
+ SCpnt->underflow = 0;
+ SCpnt->transfersize = 0;
+ SCpnt->serial_number = 0;
+ SCpnt->serial_number_at_timeout = 0;
+ SCpnt->host_scribble = NULL;
+ SCpnt->next = SDpnt->device_queue;
+ SDpnt->device_queue = SCpnt;
+ SCpnt->state = SCSI_STATE_UNUSED;
+ SCpnt->owner = SCSI_OWNER_NOBODY;
}
SDpnt->has_cmdblocks = 1;
}
+#ifndef MODULE /* { */
/*
* scsi_dev_init() is our initialization routine, which in turn calls host
* initialization, bus scanning, and sd/st initialization routines.
+ * This is only used at boot time.
*/
-
__initfunc(int scsi_dev_init(void))
{
Scsi_Device * SDpnt;
@@ -2560,9 +1998,6 @@ __initfunc(int scsi_dev_init(void))
/* Init a few things so we can "malloc" memory. */
scsi_loadable_module_flag = 0;
- timer_table[SCSI_TIMER].fn = scsi_main_timeout;
- timer_table[SCSI_TIMER].expires = 0;
-
/* Register the /proc/scsi/scsi entry */
#if CONFIG_PROC_FS
proc_scsi_register(0, &proc_scsi_scsi);
@@ -2571,12 +2006,17 @@ __initfunc(int scsi_dev_init(void))
/* initialize all hosts */
scsi_init();
- scsi_devices = (Scsi_Device *) NULL;
+ /*
+ * This is where the processing takes place for most everything
+ * when commands are completed. Until we do this, we will not be able
+ * to queue any commands.
+ */
+ init_bh(SCSI_BH, scsi_bottom_half_handler);
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) {
scan_scsis(shpnt,0,0,0,0); /* scan for scsi devices */
if (shpnt->select_queue_depths != NULL)
- (shpnt->select_queue_depths)(shpnt, scsi_devices);
+ (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
}
printk("scsi : detected ");
@@ -2589,14 +2029,17 @@ __initfunc(int scsi_dev_init(void))
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
- for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
- SDpnt->scsi_request_fn = NULL;
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
- if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ for(SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ /* SDpnt->scsi_request_fn = NULL; */
+ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
+ if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+ }
}
-
-
+
/*
* This should build the DMA pool.
*/
@@ -2614,6 +2057,7 @@ __initfunc(int scsi_dev_init(void))
return 0;
}
+#endif /* MODULE */ /* } */
static void print_inquiry(unsigned char *data)
{
@@ -2666,7 +2110,7 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
{
Scsi_Cmnd *SCpnt;
struct Scsi_Device_Template *SDTpnt;
- Scsi_Device *scd, *scd_h = NULL;
+ Scsi_Device *scd;
struct Scsi_Host *HBA_ptr;
char *p;
int host, channel, id, lun;
@@ -2674,37 +2118,41 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
off_t begin = 0;
off_t pos = 0;
- scd = scsi_devices;
- HBA_ptr = scsi_hostlist;
-
if(inout == 0) {
- size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+ /*
+ * First, see if there are any attached devices or not.
+ */
+ for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
+ {
+ if( HBA_ptr->host_queue != NULL )
+ {
+ break;
+ }
+ }
+ size = sprintf(buffer+len,"Attached devices: %s\n", (HBA_ptr)?"":"none");
len += size;
pos = begin + len;
- while (HBA_ptr) {
+ for (HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
+ {
#if 0
size += sprintf(buffer+len,"scsi%2d: %s\n", (int) HBA_ptr->host_no,
HBA_ptr->hostt->procname);
len += size;
pos = begin + len;
#endif
- scd = scsi_devices;
- while (scd) {
- if (scd->host == HBA_ptr) {
- proc_print_scsidevice(scd, buffer, &size, len);
- len += size;
- pos = begin + len;
-
- if (pos < offset) {
- len = 0;
- begin = pos;
- }
- if (pos > offset + length)
- goto stop_output;
- }
- scd = scd->next;
+ for(scd = HBA_ptr->host_queue; scd; scd = scd->next)
+ {
+ proc_print_scsidevice(scd, buffer, &size, len);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
}
- HBA_ptr = HBA_ptr->next;
}
stop_output:
@@ -2715,10 +2163,126 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
return (len);
}
- if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
+ if(!buffer || length < 11 || strncmp("scsi", buffer, 4))
return(-EINVAL);
/*
+ * Usage: echo "scsi dump #N" > /proc/scsi/scsi
+ * to dump status of all scsi commands. The number is used to specify the level
+ * of detail in the dump.
+ */
+ if(!strncmp("dump", buffer + 5, 4))
+ {
+ unsigned int level;
+
+ p = buffer + 10;
+
+ if( *p == '\0' )
+ return (-EINVAL);
+
+ level = simple_strtoul(p, NULL, 0);
+ scsi_dump_status(level);
+ }
+ /*
+ * Usage: echo "scsi log token #N" > /proc/scsi/scsi
+ * where token is one of [error,scan,mlqueue,mlcomplete,llqueue,
+ * llcomplete,hlqueue,hlcomplete]
+ */
+#if CONFIG_SCSI_LOGGING /* { */
+
+ if(!strncmp("log", buffer + 5, 3))
+ {
+ char * token;
+ unsigned int level;
+
+ p = buffer + 9;
+ token = p;
+ while(*p != ' ' && *p != '\t' && *p != '\0')
+ {
+ p++;
+ }
+
+ if( *p == '\0' )
+ {
+ if( strncmp(token, "all", 3) == 0 )
+ {
+ /*
+ * Turn on absolutely everything.
+ */
+ scsi_logging_level = ~0;
+ }
+ else if( strncmp(token, "none", 4) == 0 )
+ {
+ /*
+ * Turn off absolutely everything.
+ */
+ scsi_logging_level = 0;
+ }
+ else
+ {
+ return (-EINVAL);
+ }
+ }
+ else
+ {
+ *p++ = '\0';
+
+ level = simple_strtoul(p, NULL, 0);
+
+ /*
+ * Now figure out what to do with it.
+ */
+ if( strcmp(token, "error") == 0 )
+ {
+ SCSI_SET_ERROR_RECOVERY_LOGGING(level);
+ }
+ else if( strcmp(token, "timeout") == 0 )
+ {
+ SCSI_SET_TIMEOUT_LOGGING(level);
+ }
+ else if( strcmp(token, "scan") == 0 )
+ {
+ SCSI_SET_SCAN_BUS_LOGGING(level);
+ }
+ else if( strcmp(token, "mlqueue") == 0 )
+ {
+ SCSI_SET_MLQUEUE_LOGGING(level);
+ }
+ else if( strcmp(token, "mlcomplete") == 0 )
+ {
+ SCSI_SET_MLCOMPLETE_LOGGING(level);
+ }
+ else if( strcmp(token, "llqueue") == 0 )
+ {
+ SCSI_SET_LLQUEUE_LOGGING(level);
+ }
+ else if( strcmp(token, "llcomplete") == 0 )
+ {
+ SCSI_SET_LLCOMPLETE_LOGGING(level);
+ }
+ else if( strcmp(token, "hlqueue") == 0 )
+ {
+ SCSI_SET_HLQUEUE_LOGGING(level);
+ }
+ else if( strcmp(token, "hlcomplete") == 0 )
+ {
+ SCSI_SET_HLCOMPLETE_LOGGING(level);
+ }
+ else if( strcmp(token, "ioctl") == 0 )
+ {
+ SCSI_SET_IOCTL_LOGGING(level);
+ }
+ else
+ {
+ return (-EINVAL);
+ }
+ }
+
+ printk("scsi logging level set to 0x%8.8x\n", scsi_logging_level);
+ }
+#endif /* CONFIG_SCSI_LOGGING */ /* } */
+
+ /*
* Usage: echo "scsi add-single-device 0 1 2 3" >/proc/scsi/scsi
* with "0 1 2 3" replaced by your "Host Channel Id Lun".
* Consider this feature BETA.
@@ -2740,20 +2304,29 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
printk("scsi singledevice %d %d %d %d\n", host, channel,
id, lun);
- while(scd && (scd->host->host_no != host
- || scd->channel != channel
- || scd->id != id
- || scd->lun != lun)) {
- scd = scd->next;
- }
- if(scd)
- return(-ENOSYS); /* We do not yet support unplugging */
- while(HBA_ptr && HBA_ptr->host_no != host)
- HBA_ptr = HBA_ptr->next;
-
+ for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
+ {
+ if( HBA_ptr->host_no == host )
+ {
+ break;
+ }
+ }
if(!HBA_ptr)
return(-ENXIO);
+ for(scd = HBA_ptr->host_queue; scd; scd = scd->next)
+ {
+ if((scd->channel == channel
+ && scd->id == id
+ && scd->lun == lun))
+ {
+ break;
+ }
+ }
+
+ if(scd)
+ return(-ENOSYS); /* We do not yet support unplugging */
+
scan_scsis (HBA_ptr, 1, channel, id, lun);
return(length);
@@ -2778,15 +2351,25 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
id = simple_strtoul(p+1, &p, 0);
lun = simple_strtoul(p+1, &p, 0);
- while(scd != NULL) {
- if(scd->host->host_no == host
- && scd->channel == channel
- && scd->id == id
- && scd->lun == lun){
+
+ for(HBA_ptr = scsi_hostlist; HBA_ptr; HBA_ptr = HBA_ptr->next)
+ {
+ if( HBA_ptr->host_no == host )
+ {
+ break;
+ }
+ }
+ if(!HBA_ptr)
+ return(-ENODEV);
+
+ for(scd = HBA_ptr->host_queue; scd; scd = scd->next)
+ {
+ if((scd->channel == channel
+ && scd->id == id
+ && scd->lun == lun))
+ {
break;
}
- scd_h = scd;
- scd = scd->next;
}
if(scd == NULL)
@@ -2806,24 +2389,23 @@ int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
* Nobody is using this device any more.
* Free all of the command structures.
*/
- for(SCpnt=scd->host->host_queue; SCpnt; SCpnt = SCpnt->next){
- if(SCpnt->device == scd) {
- if(SCpnt->prev != NULL)
- SCpnt->prev->next = SCpnt->next;
- if(SCpnt->next != NULL)
- SCpnt->next->prev = SCpnt->prev;
- if(SCpnt == scd->host->host_queue)
- scd->host->host_queue = SCpnt->next;
- scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
- }
+ for(SCpnt=scd->device_queue; SCpnt; SCpnt = SCpnt->next)
+ {
+ scd->device_queue = SCpnt->next;
+ scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
}
/* Now we can remove the device structure */
- if(scd_h != NULL) {
- scd_h->next = scd->next;
- } else if (scsi_devices == scd) {
- /* We had a hit on the first entry of the device list */
- scsi_devices = scd->next;
+ if( scd->next != NULL )
+ scd->next->prev = scd->prev;
+
+ if( scd->prev != NULL )
+ scd->prev->next = scd->next;
+
+ if( HBA_ptr->host_queue == scd )
+ {
+ HBA_ptr->host_queue = scd->next;
}
+
scsi_init_free((char *) scd, sizeof(Scsi_Device));
} else {
return(-EBUSY);
@@ -2851,13 +2433,13 @@ static void resize_dma_pool(void)
unsigned int new_need_isa_buffer = 0;
unsigned char ** new_dma_malloc_pages = NULL;
- if( !scsi_devices )
+ if( !scsi_hostlist )
{
/*
* Free up the DMA pool.
*/
- if( dma_free_sectors != dma_sectors )
- panic("SCSI DMA pool memory leak %d %d\n",dma_free_sectors,dma_sectors);
+ if( scsi_dma_free_sectors != dma_sectors )
+ panic("SCSI DMA pool memory leak %d %d\n",scsi_dma_free_sectors,dma_sectors);
for(i=0; i < dma_sectors / SECTORS_PER_PAGE; i++)
scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
@@ -2870,7 +2452,7 @@ static void resize_dma_pool(void)
(dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_freelist));
dma_malloc_freelist = NULL;
dma_sectors = 0;
- dma_free_sectors = 0;
+ scsi_dma_free_sectors = 0;
return;
}
/* Next, check to see if we need to extend the DMA buffer pool */
@@ -2878,52 +2460,54 @@ static void resize_dma_pool(void)
new_dma_sectors = 2*SECTORS_PER_PAGE; /* Base value we use */
if (__pa(high_memory)-1 > ISA_DMA_THRESHOLD)
- scsi_need_isa_bounce_buffers = 1;
+ need_isa_bounce_buffers = 1;
else
- scsi_need_isa_bounce_buffers = 0;
+ need_isa_bounce_buffers = 0;
if (scsi_devicelist)
for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
new_dma_sectors += SECTORS_PER_PAGE; /* Increment for each host */
- for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
- host = SDpnt->host;
-
- /*
- * sd and sr drivers allocate scatterlists.
- * sr drivers may allocate for each command 1x2048 or 2x1024 extra
- * buffers for 2k sector size and 1k fs.
- * sg driver allocates buffers < 4k.
- * st driver does not need buffers from the dma pool.
- * estimate 4k buffer/command for devices of unknown type (should panic).
- */
- if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
- SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
- new_dma_sectors += ((host->sg_tablesize *
- sizeof(struct scatterlist) + 511) >> 9) *
- SDpnt->queue_depth;
- if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
- new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
- }
- else if (SDpnt->type == TYPE_SCANNER ||
- SDpnt->type == TYPE_PROCESSOR ||
- SDpnt->type == TYPE_MEDIUM_CHANGER) {
- new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
- }
- else {
- if (SDpnt->type != TYPE_TAPE) {
- printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
- new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
- }
+ for (host = scsi_hostlist; host; host = host->next)
+ {
+ for (SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ /*
+ * sd and sr drivers allocate scatterlists.
+ * sr drivers may allocate for each command 1x2048 or 2x1024 extra
+ * buffers for 2k sector size and 1k fs.
+ * sg driver allocates buffers < 4k.
+ * st driver does not need buffers from the dma pool.
+ * estimate 4k buffer/command for devices of unknown type (should panic).
+ */
+ if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM ||
+ SDpnt->type == TYPE_DISK || SDpnt->type == TYPE_MOD) {
+ new_dma_sectors += ((host->sg_tablesize *
+ sizeof(struct scatterlist) + 511) >> 9) *
+ SDpnt->queue_depth;
+ if (SDpnt->type == TYPE_WORM || SDpnt->type == TYPE_ROM)
+ new_dma_sectors += (2048 >> 9) * SDpnt->queue_depth;
+ }
+ else if (SDpnt->type == TYPE_SCANNER ||
+ SDpnt->type == TYPE_PROCESSOR ||
+ SDpnt->type == TYPE_MEDIUM_CHANGER) {
+ new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
+ }
+ else {
+ if (SDpnt->type != TYPE_TAPE) {
+ printk("resize_dma_pool: unknown device type %d\n", SDpnt->type);
+ new_dma_sectors += (4096 >> 9) * SDpnt->queue_depth;
+ }
+ }
+
+ if(host->unchecked_isa_dma &&
+ need_isa_bounce_buffers &&
+ SDpnt->type != TYPE_TAPE) {
+ new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
+ SDpnt->queue_depth;
+ new_need_isa_buffer++;
+ }
}
-
- if(host->unchecked_isa_dma &&
- scsi_need_isa_bounce_buffers &&
- SDpnt->type != TYPE_TAPE) {
- new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
- SDpnt->queue_depth;
- new_need_isa_buffer++;
- }
}
#ifdef DEBUG_INIT
@@ -2981,16 +2565,16 @@ static void resize_dma_pool(void)
scsi_init_free((char *) dma_malloc_pages, size);
}
- dma_free_sectors += new_dma_sectors - dma_sectors;
+ scsi_dma_free_sectors += new_dma_sectors - dma_sectors;
dma_malloc_pages = new_dma_malloc_pages;
dma_sectors = new_dma_sectors;
- need_isa_buffer = new_need_isa_buffer;
+ scsi_need_isa_buffer = new_need_isa_buffer;
restore_flags(flags);
#ifdef DEBUG_INIT
- printk("resize_dma_pool: dma free sectors = %d\n", dma_free_sectors);
+ printk("resize_dma_pool: dma free sectors = %d\n", scsi_dma_free_sectors);
printk("resize_dma_pool: dma sectors = %d\n", dma_sectors);
- printk("resize_dma_pool: need isa buffers = %d\n", need_isa_buffer);
+ printk("resize_dma_pool: need isa buffers = %d\n", scsi_need_isa_buffer);
#endif
}
@@ -3014,13 +2598,16 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
pcount = next_scsi_host;
if ((tpnt->present = tpnt->detect(tpnt)))
{
- if(pcount == next_scsi_host) {
- if(tpnt->present > 1) {
+ if(pcount == next_scsi_host)
+ {
+ if(tpnt->present > 1)
+ {
printk("Failure to register low-level scsi driver");
scsi_unregister_host(tpnt);
return 1;
}
- /* The low-level driver failed to register a driver. We
+ /*
+ * The low-level driver failed to register a driver. We
* can do this now.
*/
scsi_register(tpnt,0);
@@ -3033,16 +2620,46 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
build_proc_dir_entries(tpnt);
#endif
+
+ /*
+ * Add the kernel threads for each host adapter that will
+ * handle error correction.
+ */
+ for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ if( shpnt->hostt == tpnt && shpnt->hostt->use_new_eh_code )
+ {
+ struct semaphore sem = MUTEX_LOCKED;
+
+ shpnt->eh_notify = &sem;
+ kernel_thread((int (*)(void *))scsi_error_handler,
+ (void *) shpnt, 0);
+
+ /*
+ * Now wait for the kernel error thread to initialize itself
+ * as it might be needed when we scan the bus.
+ */
+ down (&sem);
+ shpnt->eh_notify = NULL;
+ }
+ }
+
for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
if(shpnt->hostt == tpnt)
{
if(tpnt->info)
+ {
name = tpnt->info(shpnt);
+ }
else
+ {
name = tpnt->name;
+ }
printk ("scsi%d : %s\n", /* And print a little message */
shpnt->host_no, name);
}
+ }
printk ("scsi : %d host%s.\n", next_scsi_host,
(next_scsi_host == 1) ? "" : "s");
@@ -3052,26 +2669,36 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
/* The next step is to call scan_scsis here. This generates the
* Scsi_Devices entries
*/
-
for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
- if(shpnt->hostt == tpnt) {
- scan_scsis(shpnt,0,0,0,0);
- if (shpnt->select_queue_depths != NULL)
- (shpnt->select_queue_depths)(shpnt, scsi_devices);
+ {
+ if(shpnt->hostt == tpnt)
+ {
+ scan_scsis(shpnt,0,0,0,0);
+ if (shpnt->select_queue_depths != NULL)
+ {
+ (shpnt->select_queue_depths)(shpnt, shpnt->host_queue);
+ }
}
+ }
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ {
if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
+ }
- /* Next we create the Scsi_Cmnd structures for this host */
-
- for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
- if(SDpnt->host->hostt == tpnt)
- {
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
- if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
- }
+ /*
+ * Next we create the Scsi_Cmnd structures for this host
+ */
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ for(SDpnt = shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
+ if(SDpnt->host->hostt == tpnt)
+ {
+ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
+ if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+ }
+ }
/*
* Now that we have all of the devices, resize the DMA pool,
@@ -3081,8 +2708,12 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
/* This does any final handling that is required. */
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ {
if(sdtpnt->finish && sdtpnt->nr_dev)
+ {
(*sdtpnt->finish)();
+ }
+ }
}
#if defined(USE_STATIC_SCSI_MEMORY)
@@ -3099,90 +2730,187 @@ static int scsi_register_host(Scsi_Host_Template * tpnt)
/*
* Similarly, this entry point should be called by a loadable module if it
* is trying to remove a low level scsi driver from the system.
+ *
+ * Note - there is a fatal flaw in the deregister module function.
+ * There is no way to return a code that says 'I cannot be unloaded now'.
+ * The system relies entirely upon usage counts that are maintained,
+ * and the assumption is that if the usage count is 0, then the module
+ * can be unloaded.
*/
static void scsi_unregister_host(Scsi_Host_Template * tpnt)
{
- Scsi_Host_Template * SHT, *SHTp;
- Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
- Scsi_Cmnd * SCpnt;
- unsigned long flags;
+ unsigned long flags;
+ int online_status;
+ int pcount;
+ Scsi_Cmnd * SCpnt;
+ Scsi_Device * SDpnt;
+ Scsi_Device * SDpnt1;
struct Scsi_Device_Template * sdtpnt;
- struct Scsi_Host * shpnt, *sh1;
- int pcount;
+ struct Scsi_Host * sh1;
+ struct Scsi_Host * shpnt;
+ Scsi_Host_Template * SHT;
+ Scsi_Host_Template * SHTp;
- /* First verify that this host adapter is completely free with no pending
- * commands */
+ /*
+ * First verify that this host adapter is completely free with no pending
+ * commands
+ */
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ for(SDpnt = shpnt->host_queue; SDpnt;
+ SDpnt = SDpnt->next)
+ {
+ if(SDpnt->host->hostt == tpnt
+ && SDpnt->host->hostt->module
+ && SDpnt->host->hostt->module->usecount) return;
+ /*
+ * FIXME(eric) - We need to find a way to notify the
+ * low level driver that we are shutting down - via the
+ * special device entry that still needs to get added.
+ *
+ * Is detach interface below good enough for this?
+ */
+ }
+ }
- for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
- if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->module
- && sdpnt->host->hostt->module->usecount) return;
+ /*
+ * FIXME(eric) put a spinlock on this. We force all of the devices offline
+ * to help prevent race conditions where other hosts/processors could try and
+ * get in and queue a command.
+ */
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ for(SDpnt = shpnt->host_queue; SDpnt;
+ SDpnt = SDpnt->next)
+ {
+ if(SDpnt->host->hostt == tpnt )
+ SDpnt->online = FALSE;
+
+ }
+ }
for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
{
- if (shpnt->hostt != tpnt) continue;
- for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
- {
- save_flags(flags);
- cli();
- if(SCpnt->request.rq_status != RQ_INACTIVE) {
- restore_flags(flags);
- for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
- if(SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING)
- SCpnt->request.rq_status = RQ_INACTIVE;
- printk("Device busy???\n");
- return;
+ if (shpnt->hostt != tpnt)
+ {
+ continue;
+ }
+
+ for(SDpnt = shpnt->host_queue; SDpnt;
+ SDpnt = SDpnt->next)
+ {
+ /*
+ * Loop over all of the commands associated with the device. If any of
+ * them are busy, then set the state back to inactive and bail.
+ */
+ for(SCpnt = SDpnt->device_queue; SCpnt;
+ SCpnt = SCpnt->next)
+ {
+ online_status = SDpnt->online;
+ SDpnt->online = FALSE;
+ save_flags(flags);
+ cli();
+ if(SCpnt->request.rq_status != RQ_INACTIVE)
+ {
+ restore_flags(flags);
+ printk("SCSI device not inactive - state=%d, id=%d\n",
+ SCpnt->request.rq_status, SCpnt->target);
+ for(SDpnt1 = shpnt->host_queue; SDpnt1;
+ SDpnt1 = SDpnt1->next)
+ {
+ for(SCpnt = SDpnt1->device_queue; SCpnt;
+ SCpnt = SCpnt->next)
+ if(SCpnt->request.rq_status == RQ_SCSI_DISCONNECTING)
+ SCpnt->request.rq_status = RQ_INACTIVE;
+ }
+ SDpnt->online = online_status;
+ printk("Device busy???\n");
+ return;
+ }
+ /*
+ * No, this device is really free. Mark it as such, and
+ * continue on.
+ */
+ SCpnt->state = SCSI_STATE_DISCONNECTING;
+ SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */
+ restore_flags(flags);
}
- SCpnt->request.rq_status = RQ_SCSI_DISCONNECTING; /* Mark as busy */
- restore_flags(flags);
- }
+ }
}
/* Next we detach the high level drivers from the Scsi_Device structures */
- for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
- if(sdpnt->host->hostt == tpnt)
- {
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ if(shpnt->hostt != tpnt)
+ {
+ continue;
+ }
+
+ for(SDpnt = shpnt->host_queue; SDpnt;
+ SDpnt = SDpnt->next)
+ {
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->detach) (*sdtpnt->detach)(sdpnt);
- /* If something still attached, punt */
- if (sdpnt->attached) {
- printk("Attached usage count = %d\n", sdpnt->attached);
- return;
- }
+ if(sdtpnt->detach) (*sdtpnt->detach)(SDpnt);
+
+ /* If something still attached, punt */
+ if (SDpnt->attached)
+ {
+ printk("Attached usage count = %d\n", SDpnt->attached);
+ return;
+ }
}
+ }
+
+ /*
+ * Next, kill the kernel error recovery thread for this host.
+ */
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ if( shpnt->hostt == tpnt
+ && shpnt->hostt->use_new_eh_code
+ && shpnt->ehandler != NULL )
+ {
+ struct semaphore sem = MUTEX_LOCKED;
+
+ shpnt->eh_notify = &sem;
+ send_sig(SIGKILL, shpnt->ehandler, 1);
+ down(&sem);
+ shpnt->eh_notify = NULL;
+ }
+ }
/* Next we free up the Scsi_Cmnd structures for this host */
- for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
- if(sdpnt->host->hostt == tpnt)
- while (sdpnt->host->host_queue) {
- SCpnt = sdpnt->host->host_queue->next;
- scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
- sdpnt->host->host_queue = SCpnt;
- if (SCpnt) SCpnt->prev = NULL;
- sdpnt->has_cmdblocks = 0;
- }
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ if(shpnt->hostt != tpnt)
+ {
+ continue;
+ }
- /* Next free up the Scsi_Device structures for this host */
+ for(SDpnt = shpnt->host_queue; SDpnt;
+ SDpnt = shpnt->host_queue)
+ {
+ while (SDpnt->device_queue)
+ {
+ SCpnt = SDpnt->device_queue->next;
+ scsi_init_free((char *) SDpnt->device_queue, sizeof(Scsi_Cmnd));
+ SDpnt->device_queue = SCpnt;
+ }
+ SDpnt->has_cmdblocks = 0;
- sdppnt = NULL;
- for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1)
- {
- sdpnt1 = sdpnt->next;
- if (sdpnt->host->hostt == tpnt) {
- if (sdppnt)
- sdppnt->next = sdpnt->next;
- else
- scsi_devices = sdpnt->next;
- scsi_init_free((char *) sdpnt, sizeof (Scsi_Device));
- } else
- sdppnt = sdpnt;
+ /* Next free up the Scsi_Device structures for this host */
+ shpnt->host_queue = SDpnt->next;
+ scsi_init_free((char *) SDpnt, sizeof (Scsi_Device));
+
+ }
}
/* Next we go through and remove the instances of the individual hosts
* that were detected */
- shpnt = scsi_hostlist;
- while(shpnt) {
+ for(shpnt = scsi_hostlist; shpnt; shpnt = sh1)
+ {
sh1 = shpnt->next;
if(shpnt->hostt == tpnt) {
if(shpnt->loaded_as_module) {
@@ -3208,7 +2936,6 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
tpnt->present--;
}
}
- shpnt = sh1;
}
/*
@@ -3216,7 +2943,7 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
* to completely nuke the DMA pool. The resize operation will
* do the right thing and free everything.
*/
- if( !scsi_devices )
+ if( !scsi_hosts )
resize_dma_pool();
printk ("scsi : %d host%s.\n", next_scsi_host,
@@ -3260,7 +2987,8 @@ static void scsi_unregister_host(Scsi_Host_Template * tpnt)
*/
static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
{
- Scsi_Device * SDpnt;
+ Scsi_Device * SDpnt;
+ struct Scsi_Host * shpnt;
if (tpnt->next) return 1;
@@ -3269,8 +2997,14 @@ static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
* First scan the devices that we know about, and see if we notice them.
*/
- for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
- if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ for(SDpnt = shpnt->host_queue; SDpnt;
+ SDpnt = SDpnt->next)
+ {
+ if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
+ }
+ }
/*
* If any of the devices would match this driver, then perform the
@@ -3282,15 +3016,22 @@ static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
/*
* Now actually connect the devices to the new driver.
*/
- for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
{
- if(tpnt->attach) (*tpnt->attach)(SDpnt);
- /*
- * If this driver attached to the device, and we no longer
- * have anything attached, release the scsi command blocks.
- */
- if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
- scsi_build_commandblocks(SDpnt);
+ for(SDpnt = shpnt->host_queue; SDpnt;
+ SDpnt = SDpnt->next)
+ {
+ if(tpnt->attach) (*tpnt->attach)(SDpnt);
+ /*
+ * If this driver attached to the device, and don't have any
+ * command blocks for this device, allocate some.
+ */
+ if(SDpnt->attached && SDpnt->has_cmdblocks == 0)
+ {
+ SDpnt->online = TRUE;
+ scsi_build_commandblocks(SDpnt);
+ }
+ }
}
/*
@@ -3306,6 +3047,7 @@ static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
{
Scsi_Device * SDpnt;
Scsi_Cmnd * SCpnt;
+ struct Scsi_Host * shpnt;
struct Scsi_Device_Template * spnt;
struct Scsi_Device_Template * prev_spnt;
@@ -3318,30 +3060,30 @@ static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
* Next, detach the devices from the driver.
*/
- for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
{
- if(tpnt->detach) (*tpnt->detach)(SDpnt);
- if(SDpnt->attached == 0)
- {
- /*
- * Nobody is using this device any more. Free all of the
- * command structures.
- */
- for(SCpnt = SDpnt->host->host_queue; SCpnt; SCpnt = SCpnt->next)
+ for(SDpnt = shpnt->host_queue; SDpnt;
+ SDpnt = SDpnt->next)
+ {
+ if(tpnt->detach) (*tpnt->detach)(SDpnt);
+ if(SDpnt->attached == 0)
{
- if(SCpnt->device == SDpnt)
- {
- if(SCpnt->prev != NULL)
- SCpnt->prev->next = SCpnt->next;
- if(SCpnt->next != NULL)
- SCpnt->next->prev = SCpnt->prev;
- if(SCpnt == SDpnt->host->host_queue)
- SDpnt->host->host_queue = SCpnt->next;
+ SDpnt->online = FALSE;
+
+ /*
+ * Nobody is using this device any more. Free all of the
+ * command structures.
+ */
+ for(SCpnt = SDpnt->device_queue; SCpnt;
+ SCpnt = SCpnt->next)
+ {
+ if(SCpnt == SDpnt->device_queue)
+ SDpnt->device_queue = SCpnt->next;
scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
- }
+ }
+ SDpnt->has_cmdblocks = 0;
}
- SDpnt->has_cmdblocks = 0;
- }
+ }
}
/*
* Extract the template from the linked list.
@@ -3369,26 +3111,27 @@ static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
int scsi_register_module(int module_type, void * ptr)
{
- switch(module_type){
+ switch(module_type)
+ {
case MODULE_SCSI_HA:
return scsi_register_host((Scsi_Host_Template *) ptr);
-
+
/* Load upper level device handler of some kind */
case MODULE_SCSI_DEV:
#ifdef CONFIG_KERNELD
if (scsi_hosts == NULL)
- request_module("scsi_hostadapter");
+ request_module("scsi_hostadapter");
#endif
return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
/* The rest of these are not yet implemented */
-
+
/* Load constants.o */
case MODULE_SCSI_CONST:
-
+
/* Load specialized ioctl handler for some device. Intended for
* cdroms that have non-SCSI2 audio command sets. */
case MODULE_SCSI_IOCTL:
-
+
default:
return 1;
}
@@ -3396,7 +3139,8 @@ int scsi_register_module(int module_type, void * ptr)
void scsi_unregister_module(int module_type, void * ptr)
{
- switch(module_type) {
+ switch(module_type)
+ {
case MODULE_SCSI_HA:
scsi_unregister_host((Scsi_Host_Template *) ptr);
break;
@@ -3414,65 +3158,123 @@ void scsi_unregister_module(int module_type, void * ptr)
#endif /* CONFIG_MODULES */
-#ifdef DEBUG_TIMEOUT
+/*
+ * Function: scsi_dump_status
+ *
+ * Purpose: Brain dump of scsi system, used for problem solving.
+ *
+ * Arguments: level - used to indicate level of detail.
+ *
+ * Notes: The level isn't used at all yet, but we need to find some way
+ * of sensibly logging varying degrees of information. A quick one-line
+ * display of each command, plus the status would be most useful.
+ *
+ * This does depend upon CONFIG_SCSI_LOGGING - I do want some way of turning
+ * it all off if the user wants a lean and mean kernel. It would probably
+ * also be useful to allow the user to specify one single host to be dumped.
+ * A second argument to the function would be useful for that purpose.
+ *
+ * FIXME - some formatting of the output into tables would be very handy.
+ */
static void
-scsi_dump_status(void)
+scsi_dump_status(int level)
{
+#if CONFIG_PROC_FS
+#if CONFIG_SCSI_LOGGING /* { */
int i;
struct Scsi_Host * shpnt;
Scsi_Cmnd * SCpnt;
- printk("Dump of scsi parameters:\n");
+ Scsi_Device * SDpnt;
+ printk("Dump of scsi host parameters:\n");
i = 0;
for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
- for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
+ {
+ printk(" %d %d %d : %d %p\n",
+ shpnt->host_failed,
+ shpnt->host_busy,
+ atomic_read(&shpnt->host_active),
+ shpnt->host_blocked,
+ shpnt->pending_commands);
+
+ }
+
+ printk("\n\n");
+ printk("Dump of scsi command parameters:\n");
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ printk("h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result\n");
+ for(SDpnt=shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
{
- /* (0) 0:0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x */
- printk("(%d) %d:%d:%d:%d (%s %ld %ld %ld %d) (%d %d %x) (%d %d %d) %x %x %x\n",
- i++, SCpnt->host->host_no,
- SCpnt->channel,
- SCpnt->target,
- SCpnt->lun,
- kdevname(SCpnt->request.rq_dev),
- SCpnt->request.sector,
- SCpnt->request.nr_sectors,
- SCpnt->request.current_nr_sectors,
- SCpnt->use_sg,
- SCpnt->retries,
- SCpnt->allowed,
- SCpnt->flags,
- SCpnt->timeout_per_command,
- SCpnt->timeout,
- SCpnt->internal_timeout,
- SCpnt->cmnd[0],
- SCpnt->sense_buffer[2],
- SCpnt->result);
- }
- printk("wait_for_request = %p\n", wait_for_request);
- /* Now dump the request lists for each block device */
- printk("Dump of pending block device requests\n");
- for(i=0; i<MAX_BLKDEV; i++)
- if(blk_dev[i].current_request)
+ for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+ {
+ /* (0) h:c:t:l (dev sect nsect cnumsec sg) (ret all flg) (to/cmd to ito) cmd snse result %d %x */
+ printk("(%3d) %2d:%1d:%2d:%2d (%6s %4ld %4ld %4ld %4x %1d) (%1d %1d 0x%2x) (%4d %4d %4d) 0x%2.2x 0x%2.2x 0x%8.8x\n",
+ i++,
+
+ SCpnt->host->host_no,
+ SCpnt->channel,
+ SCpnt->target,
+ SCpnt->lun,
+
+ kdevname(SCpnt->request.rq_dev),
+ SCpnt->request.sector,
+ SCpnt->request.nr_sectors,
+ SCpnt->request.current_nr_sectors,
+ SCpnt->request.rq_status,
+ SCpnt->use_sg,
+
+ SCpnt->retries,
+ SCpnt->allowed,
+ SCpnt->flags,
+
+ SCpnt->timeout_per_command,
+ SCpnt->timeout,
+ SCpnt->internal_timeout,
+
+ SCpnt->cmnd[0],
+ SCpnt->sense_buffer[2],
+ SCpnt->result);
+ }
+ }
+ }
+
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ for(SDpnt=shpnt->host_queue; SDpnt; SDpnt = SDpnt->next)
{
- struct request * req;
- printk("%d: ", i);
- req = blk_dev[i].current_request;
- while(req) {
- printk("(%s %d %ld %ld %ld) ",
- kdevname(req->rq_dev),
- req->cmd,
- req->sector,
- req->nr_sectors,
- req->current_nr_sectors);
- req = req->next;
- }
- printk("\n");
- }
+ /* Now dump the request lists for each block device */
+ printk("Dump of pending block device requests\n");
+ for(i=0; i<MAX_BLKDEV; i++)
+ {
+ if(blk_dev[i].current_request)
+ {
+ struct request * req;
+ printk("%d: ", i);
+ req = blk_dev[i].current_request;
+ while(req)
+ {
+ printk("(%s %d %ld %ld %ld) ",
+ kdevname(req->rq_dev),
+ req->cmd,
+ req->sector,
+ req->nr_sectors,
+ req->current_nr_sectors);
+ req = req->next;
+ }
+ printk("\n");
+ }
+ }
+ }
+ }
+ printk("wait_for_request = %p\n", wait_for_request);
+#endif /* CONFIG_SCSI_LOGGING */ /* } */
+#endif /* CONFIG_PROC_FS */
}
-#endif
#ifdef MODULE
-int init_module(void) {
+int init_module(void)
+{
unsigned long size;
/*
@@ -3482,8 +3284,6 @@ int init_module(void) {
dispatch_scsi_info_ptr = dispatch_scsi_info;
#endif
- timer_table[SCSI_TIMER].fn = scsi_main_timeout;
- timer_table[SCSI_TIMER].expires = 0;
scsi_loadable_module_flag = 1;
/* Register the /proc/scsi/scsi entry */
@@ -3493,7 +3293,7 @@ int init_module(void) {
dma_sectors = PAGE_SIZE / SECTOR_SIZE;
- dma_free_sectors= dma_sectors;
+ scsi_dma_free_sectors= dma_sectors;
/*
* Set up a minimal DMA buffer list - this will be used during scan_scsis
* in some cases.
@@ -3509,12 +3309,20 @@ int init_module(void) {
scsi_init_malloc((dma_sectors / SECTORS_PER_PAGE)*sizeof(*dma_malloc_pages), GFP_ATOMIC);
dma_malloc_pages[0] = (unsigned char *)
scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+
+ /*
+ * This is where the processing takes place for most everything
+ * when commands are completed.
+ */
+ init_bh(SCSI_BH, scsi_bottom_half_handler);
+
return 0;
}
void cleanup_module( void)
{
- timer_active &= ~(1 << SCSI_TIMER);
+ remove_bh(SCSI_BH);
+
#if CONFIG_PROC_FS
proc_scsi_unregister(0, PROC_SCSI_SCSI);
@@ -3527,8 +3335,6 @@ void cleanup_module( void)
*/
resize_dma_pool();
- timer_table[SCSI_TIMER].fn = NULL;
- timer_table[SCSI_TIMER].expires = 0;
}
#endif /* MODULE */
diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h
index dd0f18fa1..fa0dc8f06 100644
--- a/drivers/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -15,6 +15,8 @@
#ifndef _SCSI_H
#define _SCSI_H
+#include <linux/config.h> /* for CONFIG_SCSI_LOGGING */
+
/*
* Some of the public constants are being moved to this file.
* We include it here so that what came from where is transparent.
@@ -24,6 +26,7 @@
#include <linux/random.h>
#include <asm/hardirq.h>
+#include <asm/scatterlist.h>
#include <asm/io.h>
/*
@@ -39,9 +42,57 @@
#define MAX_SCSI_DEVICE_CODE 10
extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
-extern void scsi_make_blocked_list(void);
-extern volatile int in_scan_scsis;
-extern const unsigned char scsi_command_size[8];
+/*
+ * Use these to separate status msg and our bytes
+ *
+ * These are set by:
+ *
+ * status byte = set from target device
+ * msg_byte = return status from host adapter itself.
+ * host_byte = set by low-level driver to indicate status.
+ * driver_byte = set by mid-level.
+ */
+#define status_byte(result) (((result) >> 1) & 0x1f)
+#define msg_byte(result) (((result) >> 8) & 0xff)
+#define host_byte(result) (((result) >> 16) & 0xff)
+#define driver_byte(result) (((result) >> 24) & 0xff)
+#define suggestion(result) (driver_byte(result) & SUGGEST_MASK)
+
+#define sense_class(sense) (((sense) >> 4) & 0x7)
+#define sense_error(sense) ((sense) & 0xf)
+#define sense_valid(sense) ((sense) & 0x80);
+
+#define NEEDS_RETRY 0x2001
+#define SUCCESS 0x2002
+#define FAILED 0x2003
+#define QUEUED 0x2004
+#define SOFT_ERROR 0x2005
+#define ADD_TO_MLQUEUE 0x2006
+
+/*
+ * These are the values that scsi_cmd->state can take.
+ */
+#define SCSI_STATE_TIMEOUT 0x1000
+#define SCSI_STATE_FINISHED 0x1001
+#define SCSI_STATE_FAILED 0x1002
+#define SCSI_STATE_QUEUED 0x1003
+#define SCSI_STATE_UNUSED 0x1006
+#define SCSI_STATE_DISCONNECTING 0x1008
+#define SCSI_STATE_INITIALIZING 0x1009
+#define SCSI_STATE_BHQUEUE 0x100a
+#define SCSI_STATE_MLQUEUE 0x100b
+
+/*
+ * These are the values that the owner field can take.
+ * They are used as an indication of who the command belongs to.
+ */
+#define SCSI_OWNER_HIGHLEVEL 0x100
+#define SCSI_OWNER_MIDLEVEL 0x101
+#define SCSI_OWNER_LOWLEVEL 0x102
+#define SCSI_OWNER_ERROR_HANDLER 0x103
+#define SCSI_OWNER_BH_HANDLER 0x104
+#define SCSI_OWNER_NOBODY 0x105
+
#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
#define IDENTIFY_BASE 0x80
@@ -50,6 +101,126 @@ extern const unsigned char scsi_command_size[8];
((lun) & 0x07))
+/*
+ * This defines the scsi logging feature. It is a means by which the
+ * user can select how much information they get about various goings on,
+ * and it can be really useful for fault tracing. The logging word is divided
+ * into 8 nibbles, each of which describes a loglevel. The division of things
+ * is somewhat arbitrary, and the division of the word could be changed if it
+ * were really needed for any reason. The numbers below are the only place where these
+ * are specified. For a first go-around, 3 bits is more than enough, since this
+ * gives 8 levels of logging (really 7, since 0 is always off). Cutting to 2 bits
+ * might be wise at some point.
+ */
+
+#define SCSI_LOG_ERROR_SHIFT 0
+#define SCSI_LOG_TIMEOUT_SHIFT 3
+#define SCSI_LOG_SCAN_SHIFT 6
+#define SCSI_LOG_MLQUEUE_SHIFT 9
+#define SCSI_LOG_MLCOMPLETE_SHIFT 12
+#define SCSI_LOG_LLQUEUE_SHIFT 15
+#define SCSI_LOG_LLCOMPLETE_SHIFT 18
+#define SCSI_LOG_HLQUEUE_SHIFT 21
+#define SCSI_LOG_HLCOMPLETE_SHIFT 24
+#define SCSI_LOG_IOCTL_SHIFT 27
+
+#define SCSI_LOG_ERROR_BITS 3
+#define SCSI_LOG_TIMEOUT_BITS 3
+#define SCSI_LOG_SCAN_BITS 3
+#define SCSI_LOG_MLQUEUE_BITS 3
+#define SCSI_LOG_MLCOMPLETE_BITS 3
+#define SCSI_LOG_LLQUEUE_BITS 3
+#define SCSI_LOG_LLCOMPLETE_BITS 3
+#define SCSI_LOG_HLQUEUE_BITS 3
+#define SCSI_LOG_HLCOMPLETE_BITS 3
+#define SCSI_LOG_IOCTL_BITS 3
+
+#if CONFIG_SCSI_LOGGING
+
+#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD) \
+{ \
+ unsigned int mask; \
+ \
+ mask = (1 << (BITS)) - 1; \
+ if( ((scsi_logging_level >> (SHIFT)) & mask) > (LEVEL) ) \
+ { \
+ (CMD); \
+ } \
+}
+
+#define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL) \
+{ \
+ unsigned int mask; \
+ \
+ mask = ((1 << (BITS)) - 1) << SHIFT; \
+ scsi_logging_level = ((scsi_logging_level & ~mask) \
+ | ((LEVEL << SHIFT) & mask)); \
+}
+
+
+
+#else
+
+/*
+ * With no logging enabled, stub these out so they don't do anything.
+ */
+#define SCSI_SET_LOGGING(SHIFT, BITS, LEVEL)
+
+#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)
+#endif
+
+/*
+ * These are the macros that are actually used throughout the code to
+ * log events. If logging isn't enabled, they are no-ops and will be
+ * completely absent from the user's code.
+ *
+ * The 'set' versions of the macros are really intended to only be called
+ * from the /proc filesystem, and in production kernels this will be about
+ * all that is ever used. It could be useful in a debugging environment to
+ * bump the logging level when certain strange events are detected, however.
+ */
+#define SCSI_LOG_ERROR_RECOVERY(LEVEL,CMD) \
+ SCSI_CHECK_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL,CMD);
+#define SCSI_LOG_TIMEOUT(LEVEL,CMD) \
+ SCSI_CHECK_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL,CMD);
+#define SCSI_LOG_SCAN_BUS(LEVEL,CMD) \
+ SCSI_CHECK_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL,CMD);
+#define SCSI_LOG_MLQUEUE(LEVEL,CMD) \
+ SCSI_CHECK_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_MLCOMPLETE(LEVEL,CMD) \
+ SCSI_CHECK_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_LLQUEUE(LEVEL,CMD) \
+ SCSI_CHECK_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_LLCOMPLETE(LEVEL,CMD) \
+ SCSI_CHECK_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_HLQUEUE(LEVEL,CMD) \
+ SCSI_CHECK_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL,CMD);
+#define SCSI_LOG_HLCOMPLETE(LEVEL,CMD) \
+ SCSI_CHECK_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL,CMD);
+#define SCSI_LOG_IOCTL(LEVEL,CMD) \
+ SCSI_CHECK_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL,CMD);
+
+
+#define SCSI_SET_ERROR_RECOVERY_LOGGING(LEVEL) \
+ SCSI_SET_LOGGING(SCSI_LOG_ERROR_SHIFT, SCSI_LOG_ERROR_BITS, LEVEL);
+#define SCSI_SET_TIMEOUT_LOGGING(LEVEL) \
+ SCSI_SET_LOGGING(SCSI_LOG_TIMEOUT_SHIFT, SCSI_LOG_TIMEOUT_BITS, LEVEL);
+#define SCSI_SET_SCAN_BUS_LOGGING(LEVEL) \
+ SCSI_SET_LOGGING(SCSI_LOG_SCAN_SHIFT, SCSI_LOG_SCAN_BITS, LEVEL);
+#define SCSI_SET_MLQUEUE_LOGGING(LEVEL) \
+ SCSI_SET_LOGGING(SCSI_LOG_MLQUEUE_SHIFT, SCSI_LOG_MLQUEUE_BITS, LEVEL);
+#define SCSI_SET_MLCOMPLETE_LOGGING(LEVEL) \
+ SCSI_SET_LOGGING(SCSI_LOG_MLCOMPLETE_SHIFT, SCSI_LOG_MLCOMPLETE_BITS, LEVEL);
+#define SCSI_SET_LLQUEUE_LOGGING(LEVEL) \
+ SCSI_SET_LOGGING(SCSI_LOG_LLQUEUE_SHIFT, SCSI_LOG_LLQUEUE_BITS, LEVEL);
+#define SCSI_SET_LLCOMPLETE_LOGGING(LEVEL) \
+ SCSI_SET_LOGGING(SCSI_LOG_LLCOMPLETE_SHIFT, SCSI_LOG_LLCOMPLETE_BITS, LEVEL);
+#define SCSI_SET_HLQUEUE_LOGGING(LEVEL) \
+ SCSI_SET_LOGGING(SCSI_LOG_HLQUEUE_SHIFT, SCSI_LOG_HLQUEUE_BITS, LEVEL);
+#define SCSI_SET_HLCOMPLETE_LOGGING(LEVEL) \
+ SCSI_SET_LOGGING(SCSI_LOG_HLCOMPLETE_SHIFT, SCSI_LOG_HLCOMPLETE_BITS, LEVEL);
+#define SCSI_SET_IOCTL_LOGGING(LEVEL) \
+ SCSI_SET_LOGGING(SCSI_LOG_IOCTL_SHIFT, SCSI_LOG_IOCTL_BITS, LEVEL);
/*
* the return of the status word will be in the following format :
@@ -81,6 +252,7 @@ extern const unsigned char scsi_command_size[8];
#define DID_ERROR 0x07 /* Internal error */
#define DID_RESET 0x08 /* Reset by somebody. */
#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */
+#define DID_PASSTHROUGH 0x0a /* Force command past mid-layer */
#define DRIVER_OK 0x00 /* Driver status */
/*
@@ -139,14 +311,107 @@ extern const unsigned char scsi_command_size[8];
#define IS_ABORTING 0x10
#define ASKED_FOR_SENSE 0x20
+
+#define CONTIGUOUS_BUFFERS(X,Y) ((X->b_data+X->b_size) == Y->b_data)
+
+/*
+ * This is the crap from the old error handling code. We have it in a special
+ * place so that we can more easily delete it later on.
+ */
+#include "scsi_obsolete.h"
+
+/*
+ * Add some typedefs so that we can prototyope a bunch of the functions.
+ */
+typedef struct scsi_device Scsi_Device;
+typedef struct scsi_cmnd Scsi_Cmnd;
+
+/*
+ * Here is where we prototype most of the mid-layer.
+ */
+
+/*
+ * Initializes all SCSI devices. This scans all scsi busses.
+ */
+
+extern int scsi_dev_init (void);
+
+
+
+void * scsi_malloc(unsigned int);
+int scsi_free(void *, unsigned int);
+extern unsigned int scsi_logging_level; /* What do we log? */
+extern unsigned int scsi_dma_free_sectors; /* How much room do we have left */
+extern unsigned int scsi_need_isa_buffer; /* True if some devices need indirection
+ * buffers */
+extern void scsi_make_blocked_list(void);
+extern volatile int in_scan_scsis;
+extern const unsigned char scsi_command_size[8];
+
+/*
+ * These are the error handling functions defined in scsi_error.c
+ */
+extern void scsi_add_timer(Scsi_Cmnd * SCset, int timeout,
+ void (*complete)(Scsi_Cmnd *));
+extern void scsi_done (Scsi_Cmnd *SCpnt);
+extern int scsi_delete_timer(Scsi_Cmnd * SCset);
+extern void scsi_error_handler(void * host);
+extern int scsi_retry_command(Scsi_Cmnd *);
+extern void scsi_finish_command(Scsi_Cmnd *);
+extern int scsi_sense_valid(Scsi_Cmnd *);
+extern int scsi_decide_disposition (Scsi_Cmnd * SCpnt);
+extern int scsi_block_when_processing_errors(Scsi_Device *);
+extern void scsi_sleep(int);
+
+/*
+ * scsi_abort aborts the current command that is executing on host host.
+ * The error code, if non zero is returned in the host byte, otherwise
+ * DID_ABORT is returned in the hostbyte.
+ */
+
+extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
+ void *buffer, unsigned bufflen,
+ void (*done)(struct scsi_cmnd *),
+ int timeout, int retries);
+
+
+extern Scsi_Cmnd * scsi_allocate_device(struct request **, Scsi_Device *, int);
+
+extern Scsi_Cmnd * scsi_request_queueable(struct request *, Scsi_Device *);
+
+extern void scsi_release_command(Scsi_Cmnd *);
+
+extern int max_scsi_hosts;
+
+extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
+
+extern void print_command(unsigned char *);
+extern void print_sense(const char *, Scsi_Cmnd *);
+extern void print_driverbyte(int scsiresult);
+extern void print_hostbyte(int scsiresult);
+
/*
* The scsi_device struct contains what we know about each given scsi
* device.
*/
-typedef struct scsi_device {
+struct scsi_device {
+/* private: */
+ /*
+ * This information is private to the scsi mid-layer. Wrapping it in a
+ * struct private is a way of marking it in a sort of C++ type of way.
+ */
struct scsi_device * next; /* Used for linked list */
-
+ struct scsi_device * prev; /* Used for linked list */
+ struct wait_queue * device_wait;/* Used to wait if
+ device is busy */
+ struct Scsi_Host * host;
+ volatile unsigned short device_busy; /* commands actually active on low-level */
+ void (* scsi_request_fn)(void); /* Used to jumpstart things after an
+ * ioctl */
+ Scsi_Cmnd * device_queue; /* queue of SCSI Command structures */
+
+/* public: */
unsigned char id, lun, channel;
unsigned int manufacturer; /* Manufacturer of device, for using
@@ -154,11 +419,7 @@ typedef struct scsi_device {
int attached; /* # of high level drivers attached to
* this */
int access_count; /* Count of open channels/mounts */
- struct wait_queue * device_wait;/* Used to wait if device is busy */
- struct Scsi_Host * host;
- void (*scsi_request_fn)(void); /* Used to jumpstart things after an
- * ioctl */
- struct scsi_cmnd *device_queue; /* queue of SCSI Command structures */
+
void *hostdata; /* available to low-level driver */
char type;
char scsi_level;
@@ -168,6 +429,7 @@ typedef struct scsi_device {
unsigned char sync_max_offset; /* Not greater than this offset */
unsigned char queue_depth; /* How deep a queue to use */
+ unsigned online:1;
unsigned writeable:1;
unsigned removable:1;
unsigned random:1;
@@ -190,35 +452,8 @@ typedef struct scsi_device {
* this device */
unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN
* because we did a bus reset. */
-} Scsi_Device;
-
-/*
- * Use these to separate status msg and our bytes
- */
-
-#define status_byte(result) (((result) >> 1) & 0x1f)
-#define msg_byte(result) (((result) >> 8) & 0xff)
-#define host_byte(result) (((result) >> 16) & 0xff)
-#define driver_byte(result) (((result) >> 24) & 0xff)
-#define suggestion(result) (driver_byte(result) & SUGGEST_MASK)
-
-#define sense_class(sense) (((sense) >> 4) & 0x7)
-#define sense_error(sense) ((sense) & 0xf)
-#define sense_valid(sense) ((sense) & 0x80);
-
-/*
- * These are the SCSI devices available on the system.
- */
-
-extern Scsi_Device * scsi_devices;
-
-/*
- * Initializes all SCSI devices. This scans all scsi busses.
- */
-
-extern int scsi_dev_init (void);
-
-#include <asm/scatterlist.h>
+ unsigned device_blocked:1; /* Device returned QUEUE_FULL. */
+};
#ifdef __mc68000__
#include <asm/pgtable.h>
@@ -230,109 +465,6 @@ extern int scsi_dev_init (void);
/*
- * These are the return codes for the abort and reset functions. The mid-level
- * code uses these to decide what to do next. Each of the low level abort
- * and reset functions must correctly indicate what it has done.
- * The descriptions are written from the point of view of the mid-level code,
- * so that the return code is telling the mid-level drivers exactly what
- * the low level driver has already done, and what remains to be done.
- */
-
-/* We did not do anything.
- * Wait some more for this command to complete, and if this does not work,
- * try something more serious. */
-#define SCSI_ABORT_SNOOZE 0
-
-/* This means that we were able to abort the command. We have already
- * called the mid-level done function, and do not expect an interrupt that
- * will lead to another call to the mid-level done function for this command */
-#define SCSI_ABORT_SUCCESS 1
-
-/* We called for an abort of this command, and we should get an interrupt
- * when this succeeds. Thus we should not restore the timer for this
- * command in the mid-level abort function. */
-#define SCSI_ABORT_PENDING 2
-
-/* Unable to abort - command is currently on the bus. Grin and bear it. */
-#define SCSI_ABORT_BUSY 3
-
-/* The command is not active in the low level code. Command probably
- * finished. */
-#define SCSI_ABORT_NOT_RUNNING 4
-
-/* Something went wrong. The low level driver will indicate the correct
- * error condition when it calls scsi_done, so the mid-level abort function
- * can simply wait until this comes through */
-#define SCSI_ABORT_ERROR 5
-
-/* We do not know how to reset the bus, or we do not want to. Bummer.
- * Anyway, just wait a little more for the command in question, and hope that
- * it eventually finishes. If it never finishes, the SCSI device could
- * hang, so use this with caution. */
-#define SCSI_RESET_SNOOZE 0
-
-/* We do not know how to reset the bus, or we do not want to. Bummer.
- * We have given up on this ever completing. The mid-level code will
- * request sense information to decide how to proceed from here. */
-#define SCSI_RESET_PUNT 1
-
-/* This means that we were able to reset the bus. We have restarted all of
- * the commands that should be restarted, and we should be able to continue
- * on normally from here. We do not expect any interrupts that will return
- * DID_RESET to any of the other commands in the host_queue, and the mid-level
- * code does not need to do anything special to keep the commands alive.
- * If a hard reset was performed then all outstanding commands on the
- * bus have been restarted. */
-#define SCSI_RESET_SUCCESS 2
-
-/* We called for a reset of this bus, and we should get an interrupt
- * when this succeeds. Each command should get its own status
- * passed up to scsi_done, but this has not happened yet.
- * If a hard reset was performed, then we expect an interrupt
- * for *each* of the outstanding commands that will have the
- * effect of restarting the commands.
- */
-#define SCSI_RESET_PENDING 3
-
-/* We did a reset, but do not expect an interrupt to signal DID_RESET.
- * This tells the upper level code to request the sense info, and this
- * should keep the command alive. */
-#define SCSI_RESET_WAKEUP 4
-
-/* The command is not active in the low level code. Command probably
- finished. */
-#define SCSI_RESET_NOT_RUNNING 5
-
-/* Something went wrong, and we do not know how to fix it. */
-#define SCSI_RESET_ERROR 6
-
-#define SCSI_RESET_SYNCHRONOUS 0x01
-#define SCSI_RESET_ASYNCHRONOUS 0x02
-#define SCSI_RESET_SUGGEST_BUS_RESET 0x04
-#define SCSI_RESET_SUGGEST_HOST_RESET 0x08
-/*
- * This is a bitmask that is ored with one of the above codes.
- * It tells the mid-level code that we did a hard reset.
- */
-#define SCSI_RESET_BUS_RESET 0x100
-/*
- * This is a bitmask that is ored with one of the above codes.
- * It tells the mid-level code that we did a host adapter reset.
- */
-#define SCSI_RESET_HOST_RESET 0x200
-/*
- * Used to mask off bits and to obtain the basic action that was
- * performed.
- */
-#define SCSI_RESET_ACTION 0xff
-
-void * scsi_malloc(unsigned int);
-int scsi_free(void *, unsigned int);
-extern unsigned int dma_free_sectors; /* How much room do we have left */
-extern unsigned int need_isa_buffer; /* True if some devices need indirection
- * buffers */
-
-/*
* The Scsi_Cmnd structure is used by scsi.c internally, and for communication
* with low level drivers that support multiple outstanding commands.
*/
@@ -349,43 +481,22 @@ typedef struct scsi_pointer {
volatile int phase;
} Scsi_Pointer;
-typedef struct scsi_cmnd {
+
+struct scsi_cmnd {
+/* private: */
+ /*
+ * This information is private to the scsi mid-layer. Wrapping it in a
+ * struct private is a way of marking it in a sort of C++ type of way.
+ */
struct Scsi_Host * host;
- Scsi_Device * device;
- unsigned char target, lun, channel;
- unsigned char cmd_len;
- unsigned char old_cmd_len;
- struct scsi_cmnd *next, *prev, *device_next, *reset_chain;
+ unsigned short state;
+ unsigned short owner;
+ Scsi_Device * device;
+ struct scsi_cmnd * next;
+ struct scsi_cmnd * reset_chain;
- /* These elements define the operation we are about to perform */
- unsigned char cmnd[12];
- unsigned request_bufflen; /* Actual request size */
-
- void * request_buffer; /* Actual requested buffer */
-
- /* These elements define the operation we ultimately want to perform */
- unsigned char data_cmnd[12];
- unsigned short old_use_sg; /* We save use_sg here when requesting
- * sense info */
- unsigned short use_sg; /* Number of pieces of scatter-gather */
- unsigned short sglist_len; /* size of malloc'd scatter-gather list */
- unsigned short abort_reason;/* If the mid-level code requests an
- * abort, this is the reason. */
- unsigned bufflen; /* Size of data buffer */
- void *buffer; /* Data buffer */
-
- unsigned underflow; /* Return error if less than this amount is
- * transfered */
-
- unsigned transfersize; /* How much we are guaranteed to transfer with
- * each SCSI transfer (ie, between disconnect /
- * reconnects. Probably == sector size */
-
-
- struct request request; /* A copy of the command we are working on */
-
- unsigned char sense_buffer[16]; /* Sense for this command, if needed */
-
+ int eh_state; /* Used for state tracking in error handlr */
+ void (*done)(struct scsi_cmnd *); /* Mid-level done function */
/*
A SCSI Command is assigned a nonzero serial_number when internal_cmnd
passes it to the driver's queue command function. The serial_number
@@ -398,41 +509,96 @@ typedef struct scsi_cmnd {
completed and the SCSI Command structure has already being reused
for another command, so that we can avoid incorrectly aborting or
resetting the new command.
- */
-
- unsigned long serial_number;
- unsigned long serial_number_at_timeout;
-
- int retries;
- int allowed;
- int timeout_per_command, timeout_total, timeout;
-
+ */
+
+ unsigned long serial_number;
+ unsigned long serial_number_at_timeout;
+
+ int retries;
+ int allowed;
+ int timeout_per_command;
+ int timeout_total;
+ int timeout;
+
/*
- * We handle the timeout differently if it happens when a reset,
- * abort, etc are in process.
+ * We handle the timeout differently if it happens when a reset,
+ * abort, etc are in process.
*/
unsigned volatile char internal_timeout;
+ struct scsi_cmnd * bh_next; /* To enumerate the commands waiting
+ to be processed. */
+
+/* public: */
+
+ unsigned char target;
+ unsigned char lun;
+ unsigned char channel;
+ unsigned char cmd_len;
+ unsigned char old_cmd_len;
+
+ /* These elements define the operation we are about to perform */
+ unsigned char cmnd[12];
+ unsigned request_bufflen; /* Actual request size */
+
+ struct timer_list eh_timeout; /* Used to time out the command. */
+ void * request_buffer; /* Actual requested buffer */
- unsigned flags;
+ /* These elements define the operation we ultimately want to perform */
+ unsigned char data_cmnd[12];
+ unsigned short old_use_sg; /* We save use_sg here when requesting
+ * sense info */
+ unsigned short use_sg; /* Number of pieces of scatter-gather */
+ unsigned short sglist_len; /* size of malloc'd scatter-gather list */
+ unsigned short abort_reason; /* If the mid-level code requests an
+ * abort, this is the reason. */
+ unsigned bufflen; /* Size of data buffer */
+ void * buffer; /* Data buffer */
+
+ unsigned underflow; /* Return error if less than
+ this amount is transfered */
+
+ unsigned transfersize; /* How much we are guaranteed to
+ transfer with each SCSI transfer
+ (ie, between disconnect /
+ reconnects. Probably == sector
+ size */
+
+
+ struct request request; /* A copy of the command we are
+ working on */
+
+ unsigned char sense_buffer[16]; /* Sense for this command,
+ needed */
+ unsigned flags;
+
+ /*
+ * These two flags are used to track commands that are in the
+ * mid-level queue. The idea is that a command can be there for
+ * one of two reasons - either the host is busy or the device is
+ * busy. Thus when a command on the host finishes, we only try
+ * and requeue commands that we might expect to be queueable.
+ */
+ unsigned host_wait:1;
+ unsigned device_wait:1;
+
/* These variables are for the cdrom only. Once we have variable size
* buffers in the buffer cache, they will go away. */
- int this_count;
+ int this_count;
/* End of special cdrom variables */
/* Low-level done function - can be used by low-level driver to point
* to completion function. Not used by mid/upper level code. */
- void (*scsi_done)(struct scsi_cmnd *);
- void (*done)(struct scsi_cmnd *); /* Mid-level done function */
+ void (*scsi_done)(struct scsi_cmnd *);
/*
* The following fields can be written to by the host specific code.
* Everything else should be left alone.
*/
- Scsi_Pointer SCp; /* Scratchpad used by some host adapters */
+ Scsi_Pointer SCp; /* Scratchpad used by some host adapters */
- unsigned char * host_scribble; /* The host adapter is allowed to
+ unsigned char * host_scribble; /* The host adapter is allowed to
* call scsi_malloc and get some memory
* and hang it here. The host adapter
* is also expected to call scsi_free
@@ -440,42 +606,22 @@ typedef struct scsi_cmnd {
* obtained by scsi_malloc is guaranteed
* to be at an address < 16Mb). */
- int result; /* Status code from lower level driver */
+ int result; /* Status code from lower level driver */
- unsigned char tag; /* SCSI-II queued command tag */
- unsigned long pid; /* Process ID, starts at 0 */
-} Scsi_Cmnd;
+ unsigned char tag; /* SCSI-II queued command tag */
+ unsigned long pid; /* Process ID, starts at 0 */
+};
+
/*
- * scsi_abort aborts the current command that is executing on host host.
- * The error code, if non zero is returned in the host byte, otherwise
- * DID_ABORT is returned in the hostbyte.
+ * Definitions and prototypes used for scsi mid-level queue.
*/
+#define SCSI_MLQUEUE_HOST_BUSY 0x1055
+#define SCSI_MLQUEUE_DEVICE_BUSY 0x1056
-extern int scsi_abort (Scsi_Cmnd *, int code);
-
-extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
- void *buffer, unsigned bufflen,
- void (*done)(struct scsi_cmnd *),
- int timeout, int retries);
-
-
-extern Scsi_Cmnd * allocate_device(struct request **, Scsi_Device *, int);
-
-extern Scsi_Cmnd * request_queueable(struct request *, Scsi_Device *);
-extern int scsi_reset (Scsi_Cmnd *, unsigned int);
-
-extern int max_scsi_hosts;
-
-extern void proc_print_scsidevice(Scsi_Device *, char *, int *, int);
-
-extern void print_command(unsigned char *);
-extern void print_sense(const char *, Scsi_Cmnd *);
-extern void print_driverbyte(int scsiresult);
-extern void print_hostbyte(int scsiresult);
+extern int scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason);
+extern int scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device);
-extern void scsi_mark_host_reset(struct Scsi_Host *Host);
-extern void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel);
#if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
#include "hosts.h"
@@ -527,9 +673,9 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors
wake_up(&next->host_wait);
}
- req->rq_status = RQ_INACTIVE;
wake_up(&wait_for_request);
wake_up(&SCpnt->device->device_wait);
+ scsi_release_command(SCpnt);
return NULL;
}
@@ -541,7 +687,7 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors
#define INIT_SCSI_REQUEST \
if (!CURRENT) { \
CLEAR_INTR; \
- restore_flags(flags); \
+ spin_unlock_irqrestore(&io_request_lock,flags); \
return; \
} \
if (MAJOR(CURRENT->rq_dev) != MAJOR_NR) \
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index b623ae124..58b19f722 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -43,9 +43,16 @@ struct proc_dir_entry proc_scsi_scsi_debug = {
/* A few options that we want selected */
+#define NR_HOSTS_PRESENT 1
+#define NR_FAKE_DISKS 3
+#define N_HEAD 32
+#define N_SECTOR 64
+#define DISK_READONLY(TGT) (1)
+#define DISK_REMOVEABLE(TGT) (1)
+
/* Do not attempt to use a timer to simulate a real disk with latency */
/* Only use this in the actual kernel, not in the simulator. */
-#define IMMEDIATE
+/* #define IMMEDIATE */
/* Skip some consistency checking. Good for benchmarking */
#define SPEEDY
@@ -58,12 +65,12 @@ static int NR_REAL=-1;
#define MAJOR_NR 8
#endif
#define START_PARTITION 4
-#define SCSI_DEBUG_TIMER 20
+
/* Number of jiffies to wait before completing a command */
#define DISK_SPEED 10
#define CAPACITY (0x80000)
-static int starts[] = {4, 1000, 50000, CAPACITY, 0};
+static int starts[] = {N_HEAD, N_HEAD * N_SECTOR, 50000, CAPACITY, 0};
static int npart = 0;
#include "scsi_debug.h"
@@ -74,8 +81,8 @@ static int npart = 0;
#endif
#ifdef SPEEDY
-#define VERIFY1_DEBUG(RW) 1
-#define VERIFY_DEBUG(RW) 1
+#define VERIFY1_DEBUG(RW)
+#define VERIFY_DEBUG(RW)
#else
#define VERIFY1_DEBUG(RW) \
@@ -111,12 +118,16 @@ static int npart = 0;
};
#endif
-static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, };
-extern void scsi_debug_interrupt();
+typedef void (*done_fct_t)(Scsi_Cmnd *);
+
+static volatile done_fct_t do_done[SCSI_DEBUG_MAILBOXES] = {NULL, };
+
+static void scsi_debug_intr_handle(unsigned long);
-volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
+static struct timer_list timeout[SCSI_DEBUG_MAILBOXES];
+
+Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,};
static char SCrst[SCSI_DEBUG_MAILBOXES] = {0,};
-static volatile unsigned int timeout[8] ={0,};
/*
* Semaphore used to simulate bus lockups.
@@ -137,11 +148,11 @@ static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
sgpnt = (struct scatterlist *) SCpnt->buffer;
for(i=0; i<SCpnt->use_sg; i++) {
lpnt = (int *) sgpnt[i].alt_address;
- printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+ printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
if (lpnt) printk(" (Alt %x) ",lpnt[15]);
};
} else {
- printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+ printk("nosg: %p %p %d\n",SCpnt->request.buffer, SCpnt->buffer,
SCpnt->bufflen);
lpnt = (int *) SCpnt->request.buffer;
if (lpnt) printk(" (Alt %x) ",lpnt[15]);
@@ -167,14 +178,14 @@ static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
};
printk("\n");
#endif
- printk("DMA free %d sectors.\n", dma_free_sectors);
+ printk("DMA free %d sectors.\n", scsi_dma_free_sectors);
}
int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
{
unchar *cmd = (unchar *) SCpnt->cmnd;
struct partition * p;
- int block, start;
+ int block;
struct buffer_head * bh = NULL;
unsigned char * buff;
int nbytes, sgcount;
@@ -187,15 +198,28 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
sgcount = 0;
sgpnt = NULL;
- DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;});
+ /*
+ * If we are being notified of the mid-level reposessing a command due to timeout,
+ * just return.
+ */
+ if( done == NULL )
+ {
+ return 0;
+ }
+
+ DEB(if (target >= NR_FAKE_DISKS)
+ {
+ SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;
+ });
buff = (unsigned char *) SCpnt->request_buffer;
- if(target>=1 || SCpnt->lun != 0) {
+ if(target>=NR_FAKE_DISKS || SCpnt->lun != 0)
+ {
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
- };
+ }
if( SCrst[target] != 0 && !scsi_debug_lockup )
{
@@ -208,11 +232,11 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
}
switch(*cmd){
case REQUEST_SENSE:
- printk("Request sense...\n");
+ SCSI_LOG_LLQUEUE(3,printk("Request sense...\n"));
#ifndef DEBUG
{
int i;
- printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);
+ printk("scsi_debug: Requesting sense buffer (%p %p %p %d):", SCpnt, buff, done, bufflen);
for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
printk("\n");
};
@@ -224,15 +248,21 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
done(SCpnt);
return 0;
case ALLOW_MEDIUM_REMOVAL:
- if(cmd[4]) printk("Medium removal inhibited...");
- else printk("Medium removal enabled...");
+ if(cmd[4])
+ {
+ SCSI_LOG_LLQUEUE(2,printk("Medium removal inhibited..."));
+ }
+ else
+ {
+ SCSI_LOG_LLQUEUE(2,printk("Medium removal enabled..."));
+ }
scsi_debug_errsts = 0;
break;
case INQUIRY:
- printk("Inquiry...(%x %d)\n", buff, bufflen);
+ SCSI_LOG_LLQUEUE(3,printk("Inquiry...(%p %d)\n", buff, bufflen));
memset(buff, 0, bufflen);
buff[0] = TYPE_DISK;
- buff[1] = 0x80; /* Removable disk */
+ buff[1] = DISK_REMOVEABLE(target) ? 0x80 : 0; /* Removable disk */
buff[2] = 1;
buff[4] = 33 - 5;
memcpy(&buff[8],"Foo Inc",7);
@@ -241,13 +271,13 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
scsi_debug_errsts = 0;
break;
case TEST_UNIT_READY:
- printk("Test unit ready(%x %d)\n", buff, bufflen);
+ SCSI_LOG_LLQUEUE(3,printk("Test unit ready(%p %d)\n", buff, bufflen));
if (buff)
memset(buff, 0, bufflen);
scsi_debug_errsts = 0;
break;
case READ_CAPACITY:
- printk("Read Capacity\n");
+ SCSI_LOG_LLQUEUE(3,printk("Read Capacity\n"));
if(NR_REAL < 0) NR_REAL = (MINOR(SCpnt->request.rq_dev) >> 4) & 0x0f;
memset(buff, 0, bufflen);
buff[0] = (CAPACITY >> 24);
@@ -308,6 +338,12 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
p->start_sect = starts[npart];
p->nr_sects = starts[npart+1] - starts [npart];
p->sys_ind = 0x81; /* Linux partition */
+ p->head = (npart == 0 ? 1 : 0);
+ p->sector = 1;
+ p->cyl = starts[npart] / N_HEAD / N_SECTOR;
+ p->end_head = N_HEAD - 1;
+ p->end_sector = N_SECTOR;
+ p->end_cyl = starts[npart + 1] / N_HEAD / N_SECTOR;
p++;
npart++;
};
@@ -365,7 +401,7 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
SCpnt->result = 0;
(done)(SCpnt);
- return;
+ return 0;
if (SCpnt->use_sg && !scsi_debug_errsts)
if(bh) scsi_dump(SCpnt, 0);
@@ -396,8 +432,15 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
#endif
scsi_debug_errsts = 0;
break;
+ case MODE_SENSE:
+ /*
+ * Used to detect write protected status.
+ */
+ scsi_debug_errsts = 0;
+ memset(buff, 0, 6);
+ break;
default:
- printk("Unknown command %d\n",*cmd);
+ SCSI_LOG_LLQUEUE(3,printk("Unknown command %d\n",*cmd));
SCpnt->result = DID_NO_CONNECT << 16;
done(SCpnt);
return 0;
@@ -406,45 +449,45 @@ int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
save_flags(flags);
cli();
for(i=0;i<SCSI_DEBUG_MAILBOXES; i++){
- if (SCint[i] == 0) break;
+ if( timeout[i].function == NULL ) break;
};
- if (i >= SCSI_DEBUG_MAILBOXES || SCint[i] != 0)
- panic("Unable to find empty SCSI_DEBUG command slot.\n");
-
- SCint[i] = SCpnt;
-
- if (done) {
- DEB(printk("scsi_debug_queuecommand: now waiting for interrupt "););
- if (do_done[i])
- printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n");
- else
- do_done[i] = done;
+ /*
+ * If all of the slots are full, just return 1. The new error handling scheme
+ * allows this, and the mid-level should queue things.
+ */
+ if (i >= SCSI_DEBUG_MAILBOXES || timeout[i].function != 0)
+ {
+ SCSI_LOG_LLQUEUE(1,printk("Command rejected - host busy\n"));
+ restore_flags(flags);
+ return 1;
}
- else
- printk("scsi_debug_queuecommand: done can't be NULL\n");
+
+ SCSI_LOG_LLQUEUE(1,printk("Command accepted - slot %d\n", i));
#ifdef IMMEDIATE
if( !scsi_debug_lockup )
{
SCpnt->result = scsi_debug_errsts;
- scsi_debug_intr_handle(); /* No timer - do this one right away */
+ scsi_debug_intr_handle(i); /* No timer - do this one right away */
}
restore_flags(flags);
#else
- timeout[i] = jiffies+DISK_SPEED;
-
- /* If no timers active, then set this one */
- if ((timer_active & (1 << SCSI_DEBUG_TIMER)) == 0) {
- timer_table[SCSI_DEBUG_TIMER].expires = timeout[i];
- timer_active |= 1 << SCSI_DEBUG_TIMER;
- };
-
+
SCpnt->result = scsi_debug_errsts;
+ timeout[i].function = scsi_debug_intr_handle;
+ timeout[i].data = i;
+ timeout[i].expires = jiffies + DISK_SPEED;
+ SCint[i] = SCpnt;
+ do_done[i] = done;
+
restore_flags(flags);
+ add_timer(&timeout[i]);
+ if (!done)
+ panic("scsi_debug_queuecommand: done can't be NULL\n");
#if 0
- printk("Sending command (%d %x %d %d)...", i, done, timeout[i],jiffies);
+ printk("Sending command (%d %x %d %d)...", i, done, timeout[i].expires,jiffies);
#endif
#endif
@@ -472,92 +515,52 @@ int scsi_debug_command(Scsi_Cmnd * SCpnt)
/* A "high" level interrupt handler. This should be called once per jiffy
* to simulate a regular scsi disk. We use a timer to do this. */
-static void scsi_debug_intr_handle(void)
+static void scsi_debug_intr_handle(unsigned long indx)
{
Scsi_Cmnd * SCtmp;
- int i, pending;
+ int pending;
void (*my_done)(Scsi_Cmnd *);
unsigned long flags;
int to;
-#ifndef IMMEDIATE
- timer_table[SCSI_DEBUG_TIMER].expires = 0;
- timer_active &= ~(1 << SCSI_DEBUG_TIMER);
+#if 0
+ del_timer(&timeout[indx]);
#endif
- repeat:
- save_flags(flags);
- cli();
- for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
- if (SCint[i] == 0) continue;
-#ifndef IMMEDIATE
- if (timeout[i] == 0) continue;
- if (timeout[i] <= jiffies) break;
-#else
- break;
-#endif
- };
+ SCtmp = (Scsi_Cmnd *) SCint[indx];
+ my_done = do_done[indx];
+ do_done[indx] = NULL;
+ timeout[indx].function = NULL;
+ SCint[indx] = NULL;
- if(i == SCSI_DEBUG_MAILBOXES){
-#ifndef IMMEDIATE
- pending = INT_MAX;
- for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
- if (SCint[i] == 0) continue;
- if (timeout[i] == 0) continue;
- if (timeout[i] <= jiffies) {restore_flags(flags); goto repeat;};
- if (timeout[i] > jiffies) {
- if (pending > timeout[i]) pending = timeout[i];
- continue;
- };
- };
- if (pending && pending != INT_MAX) {
- timer_table[SCSI_DEBUG_TIMER].expires =
- (pending <= jiffies ? jiffies+1 : pending);
- timer_active |= 1 << SCSI_DEBUG_TIMER;
- };
- restore_flags(flags);
-#endif
- return;
- };
+ if (!my_done) {
+ printk("scsi_debug_intr_handle: Unexpected interrupt\n");
+ return;
+ }
- if(i < SCSI_DEBUG_MAILBOXES){
- timeout[i] = 0;
- my_done = do_done[i];
- do_done[i] = NULL;
- to = timeout[i];
- timeout[i] = 0;
- SCtmp = (Scsi_Cmnd *) SCint[i];
- SCint[i] = NULL;
- restore_flags(flags);
-
- if (!my_done) {
- printk("scsi_debug_intr_handle: Unexpected interrupt\n");
- return;
- }
-
#ifdef DEBUG
- printk("In intr_handle...");
- printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
- printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
+ printk("In intr_handle...");
+ printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
+ printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
#endif
-
- my_done(SCtmp);
+
+ my_done(SCtmp);
#ifdef DEBUG
- printk("Called done.\n");
+ printk("Called done.\n");
#endif
- };
- goto repeat;
}
int scsi_debug_detect(Scsi_Host_Template * tpnt)
{
- tpnt->proc_dir = &proc_scsi_scsi_debug;
-#ifndef IMMEDIATE
- timer_table[SCSI_DEBUG_TIMER].fn = scsi_debug_intr_handle;
- timer_table[SCSI_DEBUG_TIMER].expires = 0;
-#endif
- return 1;
+ int i;
+
+ for(i=0; i < NR_HOSTS_PRESENT; i++)
+ {
+ tpnt->proc_dir = &proc_scsi_scsi_debug;
+ scsi_register(tpnt,0);
+ }
+ return NR_HOSTS_PRESENT;
}
int scsi_debug_abort(Scsi_Cmnd * SCpnt)
@@ -587,20 +590,20 @@ int scsi_debug_abort(Scsi_Cmnd * SCpnt)
int scsi_debug_biosparam(Disk * disk, kdev_t dev, int* info){
int size = disk->capacity;
- info[0] = 32;
- info[1] = 64;
+ info[0] = N_HEAD;
+ info[1] = N_SECTOR;
info[2] = (size + 2047) >> 11;
if (info[2] >= 1024) info[2] = 1024;
return 0;
}
-int scsi_debug_reset(Scsi_Cmnd * SCpnt)
+int scsi_debug_reset(Scsi_Cmnd * SCpnt, unsigned int why)
{
int i;
unsigned long flags;
void (*my_done)(Scsi_Cmnd *);
- printk("Bus unlocked by reset(%d)\n", SCpnt->host->suggest_bus_reset);
+ printk("Bus unlocked by reset - %d\n", why);
scsi_debug_lockup = 0;
DEB(printk("scsi_debug_reset called\n"));
for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
@@ -610,9 +613,9 @@ int scsi_debug_reset(Scsi_Cmnd * SCpnt)
my_done(SCint[i]);
save_flags(flags);
cli();
- SCint[i] = NULL;
- do_done[i] = NULL;
- timeout[i] = 0;
+ SCint[i] = NULL;
+ do_done[i] = NULL;
+ timeout[i].function = NULL;
restore_flags(flags);
}
return SCSI_RESET_SUCCESS;
@@ -633,12 +636,21 @@ int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
int len, pos, begin;
int orig_length;
+ orig_length = length;
+
if(inout == 1)
{
/* First check for the Signature */
if (length >= 10 && strncmp(buffer, "scsi_debug", 10) == 0) {
buffer += 11;
length -= 11;
+
+ if( buffer[length - 1] == '\n' )
+ {
+ buffer[length-1] = '\0';
+ length--;
+ }
+
/*
* OK, we are getting some kind of command. Figure out
* what we are supposed to do here. Simulate bus lockups
@@ -647,18 +659,18 @@ int scsi_debug_proc_info(char *buffer, char **start, off_t offset,
if( length == 6 && strncmp(buffer, "lockup", length) == 0 )
{
scsi_debug_lockup = 1;
- return length;
+ return orig_length;
}
if( length == 6 && strncmp(buffer, "unlock", length) == 0 )
{
scsi_debug_lockup = 0;
- return length;
+ return orig_length;
}
- printk("Unknown command:%s\n", buffer);
+ printk("Unknown command:%s (%d)\n", buffer, length);
} else
- printk("Wrong Signature:%10s\n", (char *) ((ulong)buffer-11));
+ printk("Wrong Signature:%10s\n", (char *) buffer);
return -EINVAL;
diff --git a/drivers/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
index 87ae155f6..43c11af57 100644
--- a/drivers/scsi/scsi_debug.h
+++ b/drivers/scsi/scsi_debug.h
@@ -8,7 +8,7 @@ int scsi_debug_command(Scsi_Cmnd *);
int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int scsi_debug_abort(Scsi_Cmnd *);
int scsi_debug_biosparam(Disk *, kdev_t, int[]);
-int scsi_debug_reset(Scsi_Cmnd *);
+int scsi_debug_reset(Scsi_Cmnd *, unsigned int);
int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
#ifndef NULL
@@ -16,15 +16,28 @@ int scsi_debug_proc_info(char *, char **, off_t, int, int, int);
#endif
-#define SCSI_DEBUG_MAILBOXES 8
+#define SCSI_DEBUG_MAILBOXES 1
-#define SCSI_DEBUG {NULL, NULL, NULL, scsi_debug_proc_info, \
- "SCSI DEBUG", scsi_debug_detect, NULL, \
- NULL, scsi_debug_command, \
- scsi_debug_queuecommand, \
- scsi_debug_abort, \
- scsi_debug_reset, \
- NULL, \
- scsi_debug_biosparam, \
- SCSI_DEBUG_MAILBOXES, 7, SG_ALL, 1, 0, 1, ENABLE_CLUSTERING}
+/*
+ * Allow the driver to reject commands. Thus we accept only one, but
+ * and the mid-level will queue the remainder.
+ */
+#define SCSI_DEBUG_CANQUEUE 255
+
+#define SCSI_DEBUG {proc_info: scsi_debug_proc_info, \
+ name: "SCSI DEBUG", \
+ detect: scsi_debug_detect, \
+ command: scsi_debug_command, \
+ queuecommand: scsi_debug_queuecommand, \
+ abort: scsi_debug_abort, \
+ reset: scsi_debug_reset, \
+ bios_param: scsi_debug_biosparam, \
+ can_queue: SCSI_DEBUG_CANQUEUE, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 3, \
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING, \
+ use_new_eh_code: 1, \
+}
#endif
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
new file mode 100644
index 000000000..f5e19c547
--- /dev/null
+++ b/drivers/scsi/scsi_error.c
@@ -0,0 +1,1897 @@
+/*
+ * scsi_error.c Copyright (C) 1997 Eric Youngdale
+ *
+ * SCSI error/timeout handling
+ * Initial versions: Eric Youngdale. Based upon conversations with
+ * Leonard Zubkoff and David Miller at Linux Expo,
+ * ideas originating from all over the place.
+ *
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/blk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/smp_lock.h>
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/unistd.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#define SHUTDOWN_SIGS (sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM))
+
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
+#ifdef DEBUG
+ #define SENSE_TIMEOUT SCSI_TIMEOUT
+ #define ABORT_TIMEOUT SCSI_TIMEOUT
+ #define RESET_TIMEOUT SCSI_TIMEOUT
+#else
+ #define SENSE_TIMEOUT (10*HZ)
+ #define RESET_TIMEOUT (2*HZ)
+ #define ABORT_TIMEOUT (15*HZ)
+#endif
+
+#define STATIC
+
+/*
+ * These should *probably* be handled by the host itself.
+ * Since it is allowed to sleep, it probably should.
+ */
+#define BUS_RESET_SETTLE_TIME 5*HZ
+#define HOST_RESET_SETTLE_TIME 10*HZ
+
+
+static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_error.c,v 1.10 1997/12/08 04:50:35 eric Exp $";
+
+STATIC int scsi_check_sense (Scsi_Cmnd * SCpnt);
+STATIC int scsi_request_sense(Scsi_Cmnd *);
+STATIC void scsi_send_eh_cmnd (Scsi_Cmnd * SCpnt, int timeout);
+STATIC int scsi_try_to_abort_command(Scsi_Cmnd *, int);
+STATIC int scsi_test_unit_ready(Scsi_Cmnd *);
+STATIC int scsi_try_bus_device_reset(Scsi_Cmnd *, int timeout);
+STATIC int scsi_try_bus_reset(Scsi_Cmnd *);
+STATIC int scsi_try_host_reset(Scsi_Cmnd *);
+STATIC int scsi_unit_is_ready(Scsi_Cmnd *);
+STATIC void scsi_eh_action_done(Scsi_Cmnd *, int);
+STATIC int scsi_eh_retry_command(Scsi_Cmnd *);
+STATIC int scsi_eh_completed_normally(Scsi_Cmnd * SCpnt);
+STATIC void scsi_restart_operations(struct Scsi_Host *);
+STATIC void scsi_eh_finish_command(Scsi_Cmnd ** SClist, Scsi_Cmnd * SCpnt);
+
+
+/*
+ * Function: scsi_add_timer()
+ *
+ * Purpose: Start timeout timer for a single scsi command.
+ *
+ * Arguments: SCset - command that is about to start running.
+ * timeout - amount of time to allow this command to run.
+ * complete - timeout function to call if timer isn't
+ * canceled.
+ *
+ * Returns: Nothing
+ *
+ * Notes: This should be turned into an inline function.
+ *
+ * More Notes: Each scsi command has it's own timer, and as it is added to
+ * the queue, we set up the timer. When the command completes,
+ * we cancel the timer. Pretty simple, really, especially
+ * compared to the old way of handling this crap.
+ */
+void
+scsi_add_timer(Scsi_Cmnd * SCset,
+ int timeout,
+ void (*complete)(Scsi_Cmnd *))
+{
+
+ /*
+ * If the clock was already running for this command, then
+ * first delete the timer. The timer handling code gets rather
+ * confused if we don't do this.
+ */
+ if( SCset->eh_timeout.function != NULL )
+ {
+ del_timer(&SCset->eh_timeout);
+ }
+
+ SCset->eh_timeout.data = (unsigned long) SCset;
+ SCset->eh_timeout.expires = jiffies + timeout;
+ SCset->eh_timeout.function = (void (*)(unsigned long))complete;
+
+ SCSI_LOG_ERROR_RECOVERY(5,printk("Adding timer for command %p at %d (%p)\n", SCset, timeout, complete));
+
+ add_timer(&SCset->eh_timeout);
+
+}
+
+/*
+ * Function: scsi_delete_timer()
+ *
+ * Purpose: Delete/cancel timer for a given function.
+ *
+ * Arguments: SCset - command that we are canceling timer for.
+ *
+ * Returns: Amount of time remaining before command would have timed out.
+ *
+ * Notes: This should be turned into an inline function.
+ */
+int
+scsi_delete_timer(Scsi_Cmnd * SCset)
+{
+ int rtn;
+
+ rtn = jiffies - SCset->eh_timeout.expires;
+ del_timer(&SCset->eh_timeout);
+
+ SCSI_LOG_ERROR_RECOVERY(5,printk("Clearing timer for command %p\n", SCset));
+
+ SCset->eh_timeout.data = (unsigned long) NULL;
+ SCset->eh_timeout.expires = 0;
+ SCset->eh_timeout.function = NULL;
+
+ return rtn;
+}
+
+/*
+ * Function: scsi_times_out()
+ *
+ * Purpose: Timeout function for normal scsi commands..
+ *
+ * Arguments: SCpnt - command that is timing out.
+ *
+ * Returns: Nothing.
+ *
+ * Notes:
+ */
+void scsi_times_out (Scsi_Cmnd * SCpnt)
+{
+
+ /*
+ * Notify the low-level code that this operation failed and we are
+ * reposessing the command.
+ */
+#ifdef ERIC_neverdef
+ /*
+ * FIXME(eric)
+ * Allow the host adapter to push a queue ordering tag
+ * out to the bus to force the command in question to complete.
+ * If the host wants to do this, then we just restart the timer
+ * for the command. Before we really do this, some real thought
+ * as to the optimum way to handle this should be done. We *do*
+ * need to force ordering every so often to ensure that all requests
+ * do eventually complete, but I am not sure if this is the best way
+ * to actually go about it.
+ *
+ * Better yet, force a sync here, but don't block since we are in an
+ * interrupt.
+ */
+ if( SCpnt->host->hostt->eh_ordered_queue_tag )
+ {
+ if( (*SCpnt->host->hostt->eh_ordered_queue_tag)(SCpnt))
+ {
+ scsi_add_timer(SCpnt, SCpnt->internal_timeout,
+ scsi_times_out);
+ return;
+ }
+ }
+ /*
+ * FIXME(eric) - add a second special interface to handle this
+ * case. Ideally that interface can also be used to request
+ * a queu
+ */
+ if (SCpnt->host->can_queue)
+ {
+ SCpnt->host->hostt->queuecommand (SCpnt, NULL);
+ }
+#endif
+
+ SCpnt->state = SCSI_STATE_TIMEOUT;
+ SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+
+ SCpnt->host->in_recovery = 1;
+ SCpnt->host->host_failed++;
+
+ SCSI_LOG_TIMEOUT(3,printk("Command timed out active=%d busy=%d failed=%d\n",
+ atomic_read(&SCpnt->host->host_active),
+ SCpnt->host->host_busy,
+ SCpnt->host->host_failed));
+
+ /*
+ * If the host is having troubles, then look to see if this was the last
+ * command that might have failed. If so, wake up the error handler.
+ */
+ if( atomic_read(&SCpnt->host->host_active) == SCpnt->host->host_failed )
+ {
+ up(SCpnt->host->eh_wait);
+ }
+}
+
+/*
+ * Function scsi_block_when_processing_errors
+ *
+ * Purpose: Prevent more commands from being queued while error recovery
+ * is taking place.
+ *
+ * Arguments: SDpnt - device on which we are performing recovery.
+ *
+ * Returns: FALSE The device was taken offline by error recovery.
+ * TRUE OK to proceed.
+ *
+ * Notes: We block until the host is out of error recovery, and then
+ * check to see whether the host or the device is offline.
+ */
+int
+scsi_block_when_processing_errors(Scsi_Device * SDpnt)
+{
+
+ SCSI_SLEEP( &SDpnt->host->host_wait, SDpnt->host->in_recovery);
+
+ SCSI_LOG_ERROR_RECOVERY(5,printk("Open returning %d\n", SDpnt->online));
+
+ return SDpnt->online;
+}
+
+/*
+ * Function: scsi_eh_times_out()
+ *
+ * Purpose: Timeout function for error handling.
+ *
+ * Arguments: SCpnt - command that is timing out.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: During error handling, the kernel thread will be sleeping
+ * waiting for some action to complete on the device. Our only
+ * job is to record that it timed out, and to wake up the
+ * thread.
+ */
+STATIC
+void scsi_eh_times_out (Scsi_Cmnd * SCpnt)
+{
+ SCpnt->request.rq_status = RQ_SCSI_DONE;
+ SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+ SCpnt->eh_state = SCSI_STATE_TIMEOUT;
+
+ SCSI_LOG_ERROR_RECOVERY(5,printk("In scsi_eh_times_out %p\n", SCpnt));
+
+ if (SCpnt->host->eh_action != NULL)
+ up(SCpnt->host->eh_action);
+ else
+ panic("Missing scsi error handler thread");
+}
+
+
+/*
+ * Function: scsi_eh_done()
+ *
+ * Purpose: Completion function for error handling.
+ *
+ * Arguments: SCpnt - command that is timing out.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: During error handling, the kernel thread will be sleeping
+ * waiting for some action to complete on the device. Our only
+ * job is to record that the action completed, and to wake up the
+ * thread.
+ */
+STATIC
+void scsi_eh_done (Scsi_Cmnd * SCpnt)
+{
+ SCpnt->request.rq_status = RQ_SCSI_DONE;
+
+ SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+ SCpnt->eh_state = SUCCESS;
+
+ SCSI_LOG_ERROR_RECOVERY(5,printk("In eh_done %p result:%x\n", SCpnt,
+ SCpnt->result));
+
+ if (SCpnt->host->eh_action != NULL)
+ up(SCpnt->host->eh_action);
+}
+
+/*
+ * Function: scsi_eh_action_done()
+ *
+ * Purpose: Completion function for error handling.
+ *
+ * Arguments: SCpnt - command that is timing out.
+ * answer - boolean that indicates whether operation succeeded.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: This callback is only used for abort and reset operations.
+ */
+STATIC
+void scsi_eh_action_done (Scsi_Cmnd * SCpnt, int answer)
+{
+ SCpnt->request.rq_status = RQ_SCSI_DONE;
+
+ SCpnt->owner = SCSI_OWNER_ERROR_HANDLER;
+ SCpnt->eh_state = (answer ? SUCCESS : FAILED);
+
+ if (SCpnt->host->eh_action != NULL)
+ up(SCpnt->host->eh_action);
+}
+
+/*
+ * Function: scsi_sense_valid()
+ *
+ * Purpose: Determine whether a host has automatically obtained sense
+ * information or not. If we have it, then give a recommendation
+ * as to what we should do next.
+ */
+int
+scsi_sense_valid(Scsi_Cmnd * SCpnt)
+{
+ if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7)
+ {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/*
+ * Function: scsi_eh_retry_command()
+ *
+ * Purpose: Retry the original command
+ *
+ * Returns: SUCCESS - we were able to get the sense data.
+ * FAILED - we were not able to get the sense data.
+ *
+ * Notes: This function will *NOT* return until the command either
+ * times out, or it completes.
+ */
+STATIC int
+scsi_eh_retry_command(Scsi_Cmnd * SCpnt)
+{
+ memcpy ((void *) SCpnt->cmnd, (void*) SCpnt->data_cmnd,
+ sizeof(SCpnt->data_cmnd));
+ SCpnt->request_buffer = SCpnt->buffer;
+ SCpnt->request_bufflen = SCpnt->bufflen;
+ SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
+
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+
+ scsi_send_eh_cmnd (SCpnt, SCpnt->timeout_per_command);
+
+ /*
+ * Hey, we are done. Let's look to see what happened.
+ */
+ return SCpnt->eh_state;
+}
+
+/*
+ * Function: scsi_request_sense()
+ *
+ * Purpose: Request sense data from a particular target.
+ *
+ * Returns: SUCCESS - we were able to get the sense data.
+ * FAILED - we were not able to get the sense data.
+ *
+ * Notes: Some hosts automatically obtain this information, others
+ * require that we obtain it on our own.
+ *
+ * This function will *NOT* return until the command either
+ * times out, or it completes.
+ */
+STATIC int
+scsi_request_sense(Scsi_Cmnd * SCpnt)
+{
+ static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
+
+ memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
+ sizeof(generic_sense));
+
+ SCpnt->cmnd[1] = SCpnt->lun << 5;
+ SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+
+ SCpnt->request_buffer = &SCpnt->sense_buffer;
+ SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+ SCpnt->use_sg = 0;
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+
+ scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT);
+
+ /*
+ * Hey, we are done. Let's look to see what happened.
+ */
+ return SCpnt->eh_state;
+}
+
+/*
+ * Function: scsi_test_unit_ready()
+ *
+ * Purpose: Run test unit ready command to see if the device is talking to us or not.
+ *
+ */
+STATIC int
+scsi_test_unit_ready(Scsi_Cmnd * SCpnt)
+{
+ static unsigned char tur_command[6] = {TEST_UNIT_READY, 0,0,0,0,0};
+
+ memcpy ((void *) SCpnt->cmnd , (void *) tur_command,
+ sizeof(tur_command));
+
+ SCpnt->cmnd[1] = SCpnt->lun << 5;
+ SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+
+ SCpnt->request_buffer = &SCpnt->sense_buffer;
+ SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+ SCpnt->use_sg = 0;
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+
+ scsi_send_eh_cmnd (SCpnt, SENSE_TIMEOUT);
+
+ /*
+ * Hey, we are done. Let's look to see what happened.
+ */
+ return SCpnt->eh_state;
+}
+
+STATIC
+void scsi_sleep_done (struct semaphore * sem)
+{
+ if( sem != NULL )
+ {
+ up(sem);
+ }
+}
+
+
+void scsi_sleep (int timeout)
+{
+ struct semaphore sem = MUTEX_LOCKED;
+ struct timer_list timer;
+
+ timer.data = (unsigned long) &sem;
+ timer.expires = jiffies + timeout;
+ timer.function = (void (*)(unsigned long))scsi_sleep_done;
+
+ SCSI_LOG_ERROR_RECOVERY(5,printk("Sleeping for timer tics %d\n", timeout));
+
+ add_timer(&timer);
+
+ down(&sem);
+
+ del_timer(&timer);
+}
+
+/*
+ * Function: scsi_send_eh_cmnd
+ *
+ * Purpose: Send a command out to a device as part of error recovery.
+ *
+ * Notes: The initialization of the structures is quite a bit different
+ * in this case, and furthermore, there is a different completion
+ * handler.
+ */
+STATIC void scsi_send_eh_cmnd (Scsi_Cmnd * SCpnt, int timeout)
+{
+ struct Scsi_Host * host;
+
+ host = SCpnt->host;
+
+retry:
+ /*
+ * We will use a queued command if possible, otherwise we will emulate the
+ * queuing and calling of completion function ourselves.
+ */
+ SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+
+ if (host->can_queue)
+ {
+ struct semaphore sem = MUTEX_LOCKED;
+
+ SCpnt->eh_state = SCSI_STATE_QUEUED;
+
+ scsi_add_timer(SCpnt, timeout, scsi_eh_times_out);
+
+ /*
+ * Set up the semaphore so we wait for the command to complete.
+ */
+ SCpnt->host->eh_action = &sem;
+ SCpnt->request.rq_status = RQ_SCSI_BUSY;
+
+ host->hostt->queuecommand (SCpnt, scsi_eh_done);
+ down(&sem);
+ SCpnt->host->eh_action = NULL;
+
+ del_timer(&SCpnt->eh_timeout);
+
+ /*
+ * See if timeout. If so, tell the host to forget about it.
+ * In other words, we don't want a callback any more.
+ */
+ if( SCpnt->eh_state == SCSI_STATE_TIMEOUT )
+ {
+ SCpnt->eh_state = FAILED;
+ }
+
+ SCSI_LOG_ERROR_RECOVERY(5,printk("send_eh_cmnd: %p eh_state:%x\n",
+ SCpnt, SCpnt->eh_state));
+ }
+ else
+ {
+ int temp;
+
+ /*
+ * We damn well had better never use this code. There is no timeout
+ * protection here, since we would end up waiting in the actual low
+ * level driver, we don't know how to wake it up.
+ */
+ temp = host->hostt->command (SCpnt);
+ SCpnt->result = temp;
+ if( scsi_eh_completed_normally(SCpnt) )
+ {
+ SCpnt->eh_state = SUCCESS;
+ }
+ else
+ {
+ SCpnt->eh_state = FAILED;
+ }
+ }
+
+ /*
+ * Now examine the actual status codes to see whether the command actually
+ * did complete normally.
+ */
+ if( SCpnt->eh_state == SUCCESS )
+ {
+ switch( scsi_eh_completed_normally(SCpnt) )
+ {
+ case SUCCESS:
+ SCpnt->eh_state = SUCCESS;
+ break;
+ case NEEDS_RETRY:
+ goto retry;
+ case FAILED:
+ default:
+ SCpnt->eh_state = FAILED;
+ break;
+ }
+ }
+ else
+ {
+ SCpnt->eh_state = FAILED;
+ }
+}
+
+/*
+ * Function: scsi_unit_is_ready()
+ *
+ * Purpose: Called after TEST_UNIT_READY is run, to test to see if
+ * the unit responded in a way that indicates it is ready.
+ */
+STATIC int
+scsi_unit_is_ready(Scsi_Cmnd * SCpnt)
+{
+ if (SCpnt->result)
+ {
+ if (((driver_byte (SCpnt->result) & DRIVER_SENSE) ||
+ (status_byte (SCpnt->result) & CHECK_CONDITION)) &&
+ ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7)
+ {
+ if (((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
+ ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION) &&
+ ((SCpnt->sense_buffer[2] & 0xf) != ILLEGAL_REQUEST))
+ {
+ return 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+/*
+ * Function: scsi_eh_finish_command
+ *
+ * Purpose: Handle a command that we are finished with WRT error handling.
+ *
+ * Arguments: SClist - pointer to list into which we are putting completed commands.
+ * SCpnt - command that is completing
+ *
+ * Notes: We don't want to use the normal command completion while we are
+ * are still handling errors - it may cause other commands to be queued,
+ * and that would disturb what we are doing. Thus we really want to keep
+ * a list of pending commands for final completion, and once we
+ * are ready to leave error handling we handle completion for real.
+ */
+STATIC void
+scsi_eh_finish_command(Scsi_Cmnd **SClist, Scsi_Cmnd * SCpnt)
+{
+ SCpnt->state = SCSI_STATE_BHQUEUE;
+ SCpnt->bh_next = *SClist;
+ /*
+ * Set this back so that the upper level can correctly free up
+ * things.
+ */
+ SCpnt->use_sg = SCpnt->old_use_sg;
+ *SClist = SCpnt;
+}
+
+/*
+ * Function: scsi_try_to_abort_command
+ *
+ * Purpose: Ask host adapter to abort a running command.
+ *
+ * Returns: FAILED Operation failed or not supported.
+ * SUCCESS Succeeded.
+ *
+ * Notes: This function will not return until the user's completion
+ * function has been called. There is no timeout on this
+ * operation. If the author of the low-level driver wishes
+ * this operation to be timed, they can provide this facility
+ * themselves. Helper functions in scsi_error.c can be supplied
+ * to make this easier to do.
+ *
+ * Notes: It may be possible to combine this with all of the reset
+ * handling to eliminate a lot of code duplication. I don't
+ * know what makes more sense at the moment - this is just a
+ * prototype.
+ */
+STATIC int
+scsi_try_to_abort_command(Scsi_Cmnd * SCpnt, int timeout)
+{
+ SCpnt->eh_state = FAILED; /* Until we come up with something better */
+
+ if( SCpnt->host->hostt->eh_abort_handler == NULL )
+ {
+ return FAILED;
+ }
+
+ SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+
+ return SCpnt->host->hostt->eh_abort_handler(SCpnt);
+}
+
+/*
+ * Function: scsi_try_bus_device_reset
+ *
+ * Purpose: Ask host adapter to perform a bus device reset for a given
+ * device.
+ *
+ * Returns: FAILED Operation failed or not supported.
+ * SUCCESS Succeeded.
+ *
+ * Notes: There is no timeout for this operation. If this operation is
+ * unreliable for a given host, then the host itself needs to put a
+ * timer on it, and set the host back to a consistent state prior
+ * to returning.
+ */
+STATIC int
+scsi_try_bus_device_reset(Scsi_Cmnd * SCpnt, int timeout)
+{
+ SCpnt->eh_state = FAILED; /* Until we come up with something better */
+
+ if( SCpnt->host->hostt->eh_device_reset_handler == NULL )
+ {
+ return FAILED;
+ }
+
+ SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+
+ return SCpnt->host->hostt->eh_device_reset_handler(SCpnt);
+}
+
+/*
+ * Function: scsi_try_bus_reset
+ *
+ * Purpose: Ask host adapter to perform a bus reset for a host.
+ *
+ * Returns: FAILED Operation failed or not supported.
+ * SUCCESS Succeeded.
+ *
+ * Notes:
+ */
+STATIC int
+scsi_try_bus_reset(Scsi_Cmnd * SCpnt)
+{
+ int rtn;
+
+ SCpnt->eh_state = FAILED; /* Until we come up with something better */
+ SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+
+ if( SCpnt->host->hostt->eh_bus_reset_handler == NULL )
+ {
+ return FAILED;
+ }
+
+ rtn = SCpnt->host->hostt->eh_bus_reset_handler(SCpnt);
+
+ /*
+ * If we had a successful bus reset, mark the command blocks to expect
+ * a condition code of unit attention.
+ */
+ scsi_sleep(BUS_RESET_SETTLE_TIME);
+ if( SCpnt->eh_state == SUCCESS )
+ {
+ Scsi_Device * SDloop;
+ for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next)
+ {
+ if( SCpnt->channel == SDloop->channel )
+ {
+ SDloop->was_reset = 1;
+ SDloop->expecting_cc_ua = 1;
+ }
+ }
+ }
+
+ return SCpnt->eh_state;
+}
+
+/*
+ * Function: scsi_try_host_reset
+ *
+ * Purpose: Ask host adapter to reset itself, and the bus.
+ *
+ * Returns: FAILED Operation failed or not supported.
+ * SUCCESS Succeeded.
+ *
+ * Notes:
+ */
+STATIC int
+scsi_try_host_reset(Scsi_Cmnd * SCpnt)
+{
+ int rtn;
+
+ SCpnt->eh_state = FAILED; /* Until we come up with something better */
+ SCpnt->owner = SCSI_OWNER_LOWLEVEL;
+
+ if( SCpnt->host->hostt->eh_host_reset_handler == NULL )
+ {
+ return FAILED;
+ }
+
+ rtn = SCpnt->host->hostt->eh_host_reset_handler(SCpnt);
+
+ /*
+ * If we had a successful host reset, mark the command blocks to expect
+ * a condition code of unit attention.
+ */
+ scsi_sleep(HOST_RESET_SETTLE_TIME);
+ if( SCpnt->eh_state == SUCCESS )
+ {
+ Scsi_Device * SDloop;
+ for (SDloop = SCpnt->host->host_queue; SDloop; SDloop = SDloop->next)
+ {
+ SDloop->was_reset = 1;
+ SDloop->expecting_cc_ua = 1;
+ }
+ }
+
+ return SCpnt->eh_state;
+}
+
+/*
+ * Function: scsi_decide_disposition
+ *
+ * Purpose: Examine a command block that has come back from the low-level
+ * and figure out what to do next.
+ *
+ * Returns: SUCCESS - pass on to upper level.
+ * FAILED - pass on to error handler thread.
+ * RETRY - command should be retried.
+ * SOFTERR - command succeeded, but we need to log
+ * a soft error.
+ *
+ * Notes: This is *ONLY* called when we are examining the status
+ * after sending out the actual data command. Any commands
+ * that are queued for error recovery (i.e. TEST_UNIT_READY)
+ * do *NOT* come through here.
+ *
+ * NOTE - When this routine returns FAILED, it means the error
+ * handler thread is woken. In cases where the error code
+ * indicates an error that doesn't require the error handler
+ * thread (i.e. we don't need to abort/reset), then this function
+ * should return SUCCESS.
+ */
+int scsi_decide_disposition (Scsi_Cmnd * SCpnt)
+{
+ int rtn;
+
+ /*
+ * If the device is offline, then we clearly just pass the result back
+ * up to the top level.
+ */
+ if( SCpnt->device->online == FALSE )
+ {
+ SCSI_LOG_ERROR_RECOVERY(5,printk("scsi_error.c: device offline - report as SUCCESS\n"));
+ return SUCCESS;
+ }
+
+ /*
+ * First check the host byte, to see if there is anything in there
+ * that would indicate what we need to do.
+ */
+
+ switch(host_byte(SCpnt->result))
+ {
+ case DID_PASSTHROUGH:
+ /*
+ * No matter what, pass this through to the upper layer.
+ * Nuke this special code so that it looks like we are saying
+ * DID_OK.
+ */
+ SCpnt->result &= 0xff00ffff;
+ return SUCCESS;
+ case DID_OK:
+ /*
+ * Looks good. Drop through, and check the next byte.
+ */
+ break;
+ case DID_NO_CONNECT:
+ case DID_BAD_TARGET:
+ case DID_ABORT:
+ /*
+ * Note - this means that we just report the status back to the
+ * top level driver, not that we actually think that it indicates
+ * sucess.
+ */
+ return SUCCESS;
+ case DID_PARITY:
+ case DID_BUS_BUSY:
+ case DID_ERROR:
+ goto maybe_retry;
+ case DID_TIME_OUT:
+ /*
+ * When we scan the bus, we get timeout messages for
+ * these commands if there is no device available.
+ * Other hosts report DID_NO_CONNECT for the same thing.
+ */
+ if( (SCpnt->cmnd[0] == TEST_UNIT_READY ||
+ SCpnt->cmnd[0] == INQUIRY) )
+ {
+ return SUCCESS;
+ }
+ else
+ {
+ return FAILED;
+ }
+ case DID_RESET:
+ /*
+ * In the normal case where we haven't initiated a reset, this is
+ * a failure.
+ */
+ if( SCpnt->flags & IS_RESETTING )
+ {
+ SCpnt->flags &= ~IS_RESETTING;
+ goto maybe_retry;
+ }
+
+ /*
+ * Examine the sense data to figure out how to proceed from here.
+ * If there is no sense data, we will be forced into the error
+ * handler thread, where we get to examine the thing in a lot more
+ * detail.
+ */
+ return scsi_check_sense (SCpnt);
+ default:
+ return FAILED;
+ }
+
+ /*
+ * Next, check the message byte.
+ */
+ if( msg_byte(SCpnt->result) != COMMAND_COMPLETE )
+ {
+ return FAILED;
+ }
+
+ /*
+ * Now, check the status byte to see if this indicates anything special.
+ */
+ switch (status_byte(SCpnt->result))
+ {
+ case QUEUE_FULL:
+ /*
+ * The case of trying to send too many commands to a tagged queueing
+ * device.
+ */
+ return ADD_TO_MLQUEUE;
+ case GOOD:
+ case COMMAND_TERMINATED:
+ return SUCCESS;
+ case CHECK_CONDITION:
+ rtn = scsi_check_sense(SCpnt);
+ if( rtn == NEEDS_RETRY )
+ {
+ goto maybe_retry;
+ }
+ return rtn;
+ case CONDITION_GOOD:
+ case INTERMEDIATE_GOOD:
+ case INTERMEDIATE_C_GOOD:
+ /*
+ * Who knows? FIXME(eric)
+ */
+ return SUCCESS;
+ case BUSY:
+ case RESERVATION_CONFLICT:
+ goto maybe_retry;
+ default:
+ return FAILED;
+ }
+ return FAILED;
+
+maybe_retry:
+
+ if ((++SCpnt->retries) < SCpnt->allowed)
+ {
+ return NEEDS_RETRY;
+ }
+ else
+ {
+ return FAILED;
+ }
+}
+
+/*
+ * Function: scsi_eh_completed_normally
+ *
+ * Purpose: Examine a command block that has come back from the low-level
+ * and figure out what to do next.
+ *
+ * Returns: SUCCESS - pass on to upper level.
+ * FAILED - pass on to error handler thread.
+ * RETRY - command should be retried.
+ * SOFTERR - command succeeded, but we need to log
+ * a soft error.
+ *
+ * Notes: This is *ONLY* called when we are examining the status
+ * of commands queued during error recovery. The main
+ * difference here is that we don't allow for the possibility
+ * of retries here, and we are a lot more restrictive about what
+ * we consider acceptable.
+ */
+STATIC int scsi_eh_completed_normally (Scsi_Cmnd * SCpnt)
+{
+ int rtn;
+ /*
+ * First check the host byte, to see if there is anything in there
+ * that would indicate what we need to do.
+ */
+ if( host_byte(SCpnt->result) == DID_RESET )
+ {
+ if (SCpnt->flags & IS_RESETTING )
+ {
+ /*
+ * OK, this is normal. We don't know whether in fact the
+ * command in question really needs to be rerun or not -
+ * if this was the original data command then the answer is yes,
+ * otherwise we just flag it as success.
+ */
+ SCpnt->flags &= ~IS_RESETTING;
+ return NEEDS_RETRY;
+ }
+
+ /*
+ * Rats. We are already in the error handler, so we now get to try
+ * and figure out what to do next. If the sense is valid, we have
+ * a pretty good idea of what to do. If not, we mark it as failed.
+ */
+ return scsi_check_sense (SCpnt);
+ }
+
+ if(host_byte(SCpnt->result) != DID_OK )
+ {
+ return FAILED;
+ }
+
+ /*
+ * Next, check the message byte.
+ */
+ if( msg_byte(SCpnt->result) != COMMAND_COMPLETE )
+ {
+ return FAILED;
+ }
+
+ /*
+ * Now, check the status byte to see if this indicates anything special.
+ */
+ switch (status_byte(SCpnt->result))
+ {
+ case GOOD:
+ case COMMAND_TERMINATED:
+ return SUCCESS;
+ case CHECK_CONDITION:
+ rtn = scsi_check_sense(SCpnt);
+ if( rtn == NEEDS_RETRY )
+ {
+ return FAILED;
+ }
+ return rtn;
+ case CONDITION_GOOD:
+ case INTERMEDIATE_GOOD:
+ case INTERMEDIATE_C_GOOD:
+ /*
+ * Who knows? FIXME(eric)
+ */
+ return SUCCESS;
+ case BUSY:
+ case QUEUE_FULL:
+ case RESERVATION_CONFLICT:
+ default:
+ return FAILED;
+ }
+ return FAILED;
+}
+
+/*
+ * Function: scsi_check_sense
+ *
+ * Purpose: Examine sense information - give suggestion as to what
+ * we should do with it.
+ */
+STATIC int scsi_check_sense (Scsi_Cmnd * SCpnt)
+{
+ if ( !scsi_sense_valid(SCpnt) )
+ {
+ return FAILED;
+ }
+
+ if (SCpnt->sense_buffer[2] & 0xe0)
+ return FAILED;
+
+ switch (SCpnt->sense_buffer[2] & 0xf)
+ {
+ case NO_SENSE:
+ return SUCCESS;
+ case RECOVERED_ERROR:
+ return SOFT_ERROR;
+
+ case ABORTED_COMMAND:
+ return NEEDS_RETRY;
+ case NOT_READY:
+ case UNIT_ATTENTION:
+ /*
+ * If we are expecting a CC/UA because of a bus reset that we
+ * performed, treat this just as a retry. Otherwise this is
+ * information that we should pass up to the upper-level driver
+ * so that we can deal with it there.
+ */
+ if( SCpnt->device->expecting_cc_ua )
+ {
+ SCpnt->device->expecting_cc_ua = 0;
+ return NEEDS_RETRY;
+ }
+ return SUCCESS;
+
+ /* these three are not supported */
+ case COPY_ABORTED:
+ case VOLUME_OVERFLOW:
+ case MISCOMPARE:
+
+ case MEDIUM_ERROR:
+ return FAILED;
+
+ case ILLEGAL_REQUEST:
+ return SUCCESS;
+
+ case BLANK_CHECK:
+ case DATA_PROTECT:
+ case HARDWARE_ERROR:
+ default:
+ return FAILED;
+ }
+}
+
+
+/*
+ * Function: scsi_restart_operations
+ *
+ * Purpose: Restart IO operations to the specified host.
+ *
+ * Arguments: host - host that we are restarting
+ *
+ * Returns: Nothing
+ *
+ * Notes: When we entered the error handler, we blocked all further
+ * I/O to this device. We need to 'reverse' this process.
+ */
+STATIC void
+scsi_restart_operations(struct Scsi_Host * host)
+{
+ Scsi_Device * SDpnt;
+
+ /*
+ * Next free up anything directly waiting upon the host. This will be
+ * requests for character device operations, and also for ioctls to queued
+ * block devices.
+ */
+ SCSI_LOG_ERROR_RECOVERY(5,printk("scsi_error.c: Waking up host to restart\n"));
+
+ wake_up(&host->host_wait);
+
+ /*
+ * Finally, block devices need an extra kick in the pants. This is because
+ * the request queueing mechanism may have queued lots of pending requests
+ * and there won't be a process waiting in a place where we can simply wake
+ * it up. Thus we simply go through and call the request function to goose
+ * the various top level drivers and get things moving again.
+ */
+ for( SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next )
+ {
+ SCSI_LOG_ERROR_RECOVERY(5,printk("Calling request function to restart things...\n"));
+
+ if( SDpnt->scsi_request_fn != NULL )
+ (*SDpnt->scsi_request_fn)();
+ }
+}
+
+/*
+ * Function: scsi_unjam_host
+ *
+ * Purpose: Attempt to fix a host which has a command that failed for
+ * some reason.
+ *
+ * Arguments: host - host that needs unjamming.
+ *
+ * Returns: Nothing
+ *
+ * Notes: When we come in here, we *know* that all commands on the
+ * bus have either completed, failed or timed out. We also
+ * know that no further commands are being sent to the host,
+ * so things are relatively quiet and we have freedom to
+ * fiddle with things as we wish.
+ *
+ * Additional note: This is only the *default* implementation. It is possible
+ * for individual drivers to supply their own version of this
+ * function, and if the maintainer wishes to do this, it is
+ * strongly suggested that this function be taken as a template
+ * and modified. This function was designed to correctly handle
+ * problems for about 95% of the different cases out there, and
+ * it should always provide at least a reasonable amount of error
+ * recovery.
+ *
+ * Note3: Any command marked 'FAILED' or 'TIMEOUT' must eventually
+ * have scsi_finish_command() called for it. We do all of
+ * the retry stuff here, so when we restart the host after we
+ * return it should have an empty queue.
+ */
+STATIC int
+scsi_unjam_host(struct Scsi_Host * host)
+{
+ int devices_failed;
+ int numfailed;
+ int ourrtn;
+ int rtn = FALSE;
+ int result;
+ Scsi_Cmnd * SCloop;
+ Scsi_Cmnd * SCpnt;
+ Scsi_Device * SDpnt;
+ Scsi_Device * SDloop;
+ Scsi_Cmnd * SCdone;
+ int timed_out;
+
+ SCdone = NULL;
+
+ /*
+ * First, protect against any sort of race condition. If any of the outstanding
+ * commands are in states that indicate that we are not yet blocked (i.e. we are
+ * not in a quiet state) then we got woken up in error. If we ever end up here,
+ * we need to re-examine some of the assumptions.
+ */
+ for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+ {
+ if( SCpnt->state == SCSI_STATE_FAILED
+ || SCpnt->state == SCSI_STATE_TIMEOUT
+ || SCpnt->state == SCSI_STATE_UNUSED)
+ {
+ continue;
+ }
+
+ /*
+ * Rats. Something is still floating around out there. This could
+ * be the result of the fact that the upper level drivers are still frobbing
+ * commands that might have succeeded. There are two outcomes. One is that
+ * the command block will eventually be freed, and the other one is that
+ * the command will be queued and will be finished along the way.
+ */
+ SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler prematurely woken - commands still active (%p %x %d)\n", SCpnt, SCpnt->state, SCpnt->target));
+ panic("SCSI Error handler woken too early\n");
+ }
+ }
+
+ /*
+ * Next, see if we need to request sense information. if so,
+ * then get it now, so we have a better idea of what to do.
+ * FIXME(eric) this has the unfortunate side effect that if a host
+ * adapter does not automatically request sense information, that we end
+ * up shutting it down before we request it. All hosts should be doing this
+ * anyways, so for now all I have to say is tough noogies if you end up in here.
+ * On second thought, this is probably a good idea. We *really* want to give
+ * authors an incentive to automatically request this.
+ */
+ SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we need to request sense\n"));
+
+ for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+ {
+ if( SCpnt->state != SCSI_STATE_FAILED || scsi_sense_valid(SCpnt) )
+ {
+ continue;
+ }
+
+ SCSI_LOG_ERROR_RECOVERY(2,printk("scsi_unjam_host: Requesting sense for %d\n",
+ SCpnt->target));
+ rtn = scsi_request_sense(SCpnt);
+ if( rtn != SUCCESS )
+ {
+ continue;
+ }
+
+ SCSI_LOG_ERROR_RECOVERY(3,printk("Sense requested for %p - result %x\n",
+ SCpnt, SCpnt->result));
+ SCSI_LOG_ERROR_RECOVERY(3,print_sense("bh",SCpnt));
+
+ result = scsi_decide_disposition(SCpnt);
+
+ /*
+ * If the result was normal, then just pass it along to the
+ * upper level.
+ */
+ if( result == SUCCESS )
+ {
+ SCpnt->host->host_failed--;
+ scsi_eh_finish_command(&SCdone, SCpnt);
+ }
+
+ if( result != NEEDS_RETRY )
+ {
+ continue;
+ }
+
+ /*
+ * We only come in here if we want to retry a
+ * command. The test to see whether the command
+ * should be retried should be keeping track of the
+ * number of tries, so we don't end up looping, of
+ * course.
+ */
+ SCpnt->state = NEEDS_RETRY;
+ rtn = scsi_eh_retry_command(SCpnt);
+ if( rtn != SUCCESS )
+ {
+ continue;
+ }
+
+ /*
+ * We eventually hand this one back to the top level.
+ */
+ SCpnt->host->host_failed--;
+ scsi_eh_finish_command(&SCdone, SCpnt);
+ }
+ }
+
+ /*
+ * Go through the list of commands and figure out where we stand and how bad things
+ * really are.
+ */
+ numfailed = 0;
+ timed_out = 0;
+ devices_failed = 0;
+ for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ unsigned int device_error = 0;
+
+ for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+ {
+ if( SCpnt->state == SCSI_STATE_FAILED )
+ {
+ SCSI_LOG_ERROR_RECOVERY(5,printk("Command to ID %d failed\n",
+ SCpnt->target));
+ numfailed++;
+ device_error++;
+ }
+ if( SCpnt->state == SCSI_STATE_TIMEOUT )
+ {
+ SCSI_LOG_ERROR_RECOVERY(5,printk("Command to ID %d timedout\n",
+ SCpnt->target));
+ timed_out++;
+ device_error++;
+ }
+ }
+ if( device_error > 0 )
+ {
+ devices_failed++;
+ }
+ }
+
+ SCSI_LOG_ERROR_RECOVERY(2,printk("Total of %d+%d commands on %d devices require eh work\n",
+ numfailed, timed_out, devices_failed));
+
+ if( host->host_failed == 0 )
+ {
+ ourrtn = TRUE;
+ goto leave;
+ }
+
+
+ /*
+ * Next, try and see whether or not it makes sense to try and abort
+ * the running command. This only works out to be the case if we have
+ * one command that has timed out. If the command simply failed, it
+ * makes no sense to try and abort the command, since as far as the
+ * host adapter is concerned, it isn't running.
+ */
+
+ SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we want to try abort\n"));
+
+ for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
+ {
+ if( SCloop->state != SCSI_STATE_TIMEOUT )
+ {
+ continue;
+ }
+
+ rtn = scsi_try_to_abort_command(SCloop, ABORT_TIMEOUT);
+
+ if( rtn == SUCCESS )
+ {
+ rtn = scsi_test_unit_ready(SCloop);
+
+ if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+ {
+ rtn = scsi_eh_retry_command(SCloop);
+
+ if( rtn == SUCCESS )
+ {
+ SCloop->host->host_failed--;
+ scsi_eh_finish_command(&SCdone,SCloop);
+ }
+ }
+ }
+ }
+ }
+
+ /*
+ * If we have corrected all of the problems, then we are done.
+ */
+ if( host->host_failed == 0 )
+ {
+ ourrtn = TRUE;
+ goto leave;
+ }
+
+ /*
+ * Either the abort wasn't appropriate, or it didn't succeed.
+ * Now try a bus device reset. Still, look to see whether we have
+ * multiple devices that are jammed or not - if we have multiple devices,
+ * it makes no sense to try BUS_DEVICE_RESET - we really would need
+ * to try a BUS_RESET instead.
+ *
+ * Does this make sense - should we try BDR on each device individually?
+ * Yes, definitely.
+ */
+ SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Checking to see if we want to try BDR\n"));
+
+ for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
+ {
+ if( SCloop->state == SCSI_STATE_FAILED
+ || SCloop->state == SCSI_STATE_TIMEOUT )
+ {
+ break;
+ }
+ }
+
+ if( SCloop == NULL )
+ {
+ continue;
+ }
+
+ /*
+ * OK, we have a device that is having problems. Try and send
+ * a bus device reset to it.
+ *
+ * FIXME(eric) - make sure we handle the case where multiple
+ * commands to the same device have failed. They all must
+ * get properly restarted.
+ */
+ rtn = scsi_try_bus_device_reset(SCloop, RESET_TIMEOUT);
+
+ if( rtn == SUCCESS )
+ {
+ rtn = scsi_test_unit_ready(SCloop);
+
+ if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+ {
+ rtn = scsi_eh_retry_command(SCloop);
+
+ if( rtn == SUCCESS )
+ {
+ SCloop->host->host_failed--;
+ scsi_eh_finish_command(&SCdone,SCloop);
+ }
+ }
+ }
+
+ }
+
+ if( host->host_failed == 0 )
+ {
+ ourrtn = TRUE;
+ goto leave;
+ }
+
+ /*
+ * If we ended up here, we have serious problems. The only thing left
+ * to try is a full bus reset. If someone has grabbed the bus and isn't
+ * letting go, then perhaps this will help.
+ */
+ SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Try hard bus reset\n"));
+
+ /*
+ * We really want to loop over the various channels, and do this on
+ * a channel by channel basis. We should also check to see if any
+ * of the failed commands are on soft_reset devices, and if so, skip
+ * the reset.
+ */
+ for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+next_device:
+ for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+ {
+ if( SCpnt->state != SCSI_STATE_FAILED
+ && SCpnt->state != SCSI_STATE_TIMEOUT )
+ {
+ continue;
+ }
+ /*
+ * We have a failed command. Make sure there are no other failed
+ * commands on the same channel that are timed out and implement a
+ * soft reset.
+ */
+ for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
+ {
+ for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
+ {
+ if( SCloop->channel != SCpnt->channel )
+ {
+ continue;
+ }
+
+ if( SCloop->state != SCSI_STATE_FAILED
+ && SCloop->state != SCSI_STATE_TIMEOUT )
+ {
+ continue;
+ }
+
+ if( SDloop->soft_reset && SCloop->state == SCSI_STATE_TIMEOUT )
+ {
+ /*
+ * If this device uses the soft reset option, and this
+ * is one of the devices acting up, then our only
+ * option is to wait a bit, since the command is
+ * supposedly still running.
+ *
+ * FIXME(eric) - right now we will just end up falling
+ * through to the 'take device offline' case.
+ *
+ * FIXME(eric) - It is possible that the command completed
+ * *after* the error recovery procedure started, and if this
+ * is the case, we are worrying about nothing here.
+ */
+ goto next_device;
+ }
+ }
+ }
+
+ /*
+ * We now know that we are able to perform a reset for the
+ * bus that SCpnt points to. There are no soft-reset devices
+ * with outstanding timed out commands.
+ */
+ rtn = scsi_try_bus_reset(SCpnt);
+ if( rtn == SUCCESS )
+ {
+ for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
+ {
+ for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
+ {
+ if( SCloop->channel != SCpnt->channel )
+ {
+ continue;
+ }
+
+ if( SCloop->state != SCSI_STATE_FAILED
+ && SCloop->state != SCSI_STATE_TIMEOUT )
+ {
+ continue;
+ }
+
+ rtn = scsi_test_unit_ready(SCloop);
+
+ if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+ {
+ rtn = scsi_eh_retry_command(SCloop);
+
+ if( rtn == SUCCESS )
+ {
+ SCpnt->host->host_failed--;
+ scsi_eh_finish_command(&SCdone,SCloop);
+ }
+ }
+
+ /*
+ * If the bus reset worked, but we are still unable to
+ * talk to the device, take it offline.
+ * FIXME(eric) - is this really the correct thing to do?
+ */
+ if( rtn != SUCCESS )
+ {
+ SCloop->device->online = FALSE;
+ SCloop->host->host_failed--;
+ scsi_eh_finish_command(&SCdone,SCloop);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if( host->host_failed == 0 )
+ {
+ ourrtn = TRUE;
+ goto leave;
+ }
+ /*
+ * If we ended up here, we have serious problems. The only thing left
+ * to try is a full host reset - perhaps the firmware on the device
+ * crashed, or something like that.
+ *
+ * It is assumed that a succesful host reset will cause *all* information
+ * about the command to be flushed from both the host adapter *and* the
+ * device.
+ *
+ * FIXME(eric) - it isn't clear that devices that implement the soft reset
+ * option can ever be cleared except via cycling the power. The problem is
+ * that sending the host reset command will cause the host to forget
+ * about the pending command, but the device won't forget. For now, we
+ * skip the host reset option if any of the failed devices are configured
+ * to use the soft reset option.
+ */
+ for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+next_device2:
+ for(SCpnt=SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+ {
+ if( SCpnt->state != SCSI_STATE_FAILED
+ && SCpnt->state != SCSI_STATE_TIMEOUT )
+ {
+ continue;
+ }
+ if( SDpnt->soft_reset && SCpnt->state == SCSI_STATE_TIMEOUT )
+ {
+ /*
+ * If this device uses the soft reset option, and this
+ * is one of the devices acting up, then our only
+ * option is to wait a bit, since the command is
+ * supposedly still running.
+ *
+ * FIXME(eric) - right now we will just end up falling
+ * through to the 'take device offline' case.
+ */
+ SCSI_LOG_ERROR_RECOVERY(3,
+ printk("scsi_unjam_host: Unable to try hard host reset\n"));
+ goto next_device2;
+ }
+
+ SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Try hard host reset\n"));
+
+ /*
+ * FIXME(eric) - we need to obtain a valid SCpnt to perform this call.
+ */
+ rtn = scsi_try_host_reset(SCpnt);
+ if( rtn == SUCCESS )
+ {
+ /*
+ * FIXME(eric) we assume that all commands are flushed from the
+ * controller. We should get a DID_RESET for all of the commands
+ * that were pending. We should ignore these so that we can
+ * guarantee that we are in a consistent state.
+ *
+ * I believe this to be the case right now, but this needs to be
+ * tested.
+ */
+ for(SDloop=host->host_queue; SDloop; SDloop = SDloop->next)
+ {
+ for(SCloop=SDloop->device_queue; SCloop; SCloop = SCloop->next)
+ {
+ if( SCloop->state != SCSI_STATE_FAILED
+ && SCloop->state != SCSI_STATE_TIMEOUT )
+ {
+ continue;
+ }
+
+ rtn = scsi_test_unit_ready(SCloop);
+
+ if( rtn == SUCCESS && scsi_unit_is_ready(SCloop) )
+ {
+ rtn = scsi_eh_retry_command(SCloop);
+
+ if( rtn == SUCCESS )
+ {
+ SCpnt->host->host_failed--;
+ scsi_eh_finish_command(&SCdone,SCloop);
+ }
+ }
+ if( rtn != SUCCESS )
+ {
+ SCloop->device->online = FALSE;
+ SCloop->host->host_failed--;
+ scsi_eh_finish_command(&SCdone,SCloop);
+ }
+ }
+ }
+ }
+ }
+ }
+
+
+ /*
+ * If we solved all of the problems, then let's rev up the engines again.
+ */
+ if( host->host_failed == 0 )
+ {
+ ourrtn = TRUE;
+ goto leave;
+ }
+
+ /*
+ * If the HOST RESET failed, then for now we assume that the entire host
+ * adapter is too hosed to be of any use. For our purposes, however, it is
+ * easier to simply take the devices offline that correspond to commands
+ * that failed.
+ */
+ SCSI_LOG_ERROR_RECOVERY(1,printk("scsi_unjam_host: Take device offline\n"));
+
+ for(SDpnt=host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ for(SCloop=SDpnt->device_queue; SCloop; SCloop = SCloop->next)
+ {
+ if( SCloop->state == SCSI_STATE_FAILED || SCloop->state == SCSI_STATE_TIMEOUT )
+ {
+ SCloop->device->online = FALSE;
+
+ /*
+ * This should pass the failure up to the top level driver, and
+ * it will have to try and do something intelligent with it.
+ */
+ SCloop->host->host_failed--;
+
+ if( SCloop->state == SCSI_STATE_TIMEOUT )
+ {
+ SCloop->result |= (DRIVER_TIMEOUT << 24);
+ }
+
+ SCSI_LOG_ERROR_RECOVERY(3,printk("Finishing command for device %d %x\n",
+ SCloop->device->id, SCloop->result));
+
+ scsi_eh_finish_command(&SCdone,SCloop);
+ }
+ }
+ }
+
+ if( host->host_failed != 0 )
+ {
+ panic("scsi_unjam_host: Miscount of number of failed commands.\n");
+ }
+
+ SCSI_LOG_ERROR_RECOVERY(3,printk("scsi_unjam_host: Returning\n"));
+
+ ourrtn = FALSE;
+
+leave:
+
+ /*
+ * We should have a list of commands that we 'finished' during the course of
+ * error recovery. This should be the same as the list of commands that timed out
+ * or failed. We are currently holding these things in a linked list - we didn't
+ * put them in the bottom half queue because we wanted to keep things quiet while
+ * we were working on recovery, and passing them up to the top level could easily
+ * cause the top level to try and queue something else again.
+ *
+ * Start by marking that the host is no longer in error recovery.
+ */
+ host->in_recovery = 0;
+
+ /*
+ * Take the list of commands, and stick them in the bottom half queue.
+ * The current implementation of scsi_done will do this for us - if need
+ * be we can create a special version of this function to do the
+ * same job for us.
+ */
+ for(SCpnt = SCdone; SCpnt != NULL; SCpnt = SCdone)
+ {
+ SCdone = SCpnt->bh_next;
+ SCpnt->bh_next = NULL;
+ scsi_done(SCpnt);
+ }
+
+ return (ourrtn);
+}
+
+
+/*
+ * Function: scsi_error_handler
+ *
+ * Purpose: Handle errors/timeouts of scsi commands, try and clean up
+ * and unjam the bus, and restart things.
+ *
+ * Arguments: host - host for which we are running.
+ *
+ * Returns: Never returns.
+ *
+ * Notes: This is always run in the context of a kernel thread. The
+ * idea is that we start this thing up when the kernel starts
+ * up (one per host that we detect), and it immediately goes to
+ * sleep and waits for some event (i.e. failure). When this
+ * takes place, we have the job of trying to unjam the bus
+ * and restarting things.
+ *
+ */
+void
+scsi_error_handler(void * data)
+{
+ struct Scsi_Host * host = (struct Scsi_Host *) data;
+ int rtn;
+ struct semaphore sem = MUTEX_LOCKED;
+
+ lock_kernel();
+
+ /*
+ * If we were started as result of loading a module, close all of the
+ * user space pages. We don't need them, and if we didn't close them
+ * they would be locked into memory.
+ */
+ exit_mm(current);
+
+
+ current->session = 1;
+ current->pgrp = 1;
+ /*
+ * FIXME(eric) this is still a child process of the one that did the insmod.
+ * This needs to be attached to task[0] instead.
+ */
+
+ siginitsetinv(&current->blocked, SHUTDOWN_SIGS);
+ current->fs->umask = 0;
+
+ /*
+ * Set the name of this process.
+ */
+ sprintf(current->comm, "scsi_eh_%d", host->host_no);
+
+ host->eh_wait = &sem;
+ host->ehandler = current;
+
+ unlock_kernel();
+
+ /*
+ * Wake up the thread that created us.
+ */
+ SCSI_LOG_ERROR_RECOVERY(3,printk("Wake up parent %d\n", host->eh_notify->count.counter));
+
+ up(host->eh_notify);
+
+ while(1)
+ {
+ /*
+ * If we get a signal, it means we are supposed to go
+ * away and die. This typically happens if the user is
+ * trying to unload a module.
+ */
+ SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler sleeping\n"));
+ down_interruptible (&sem);
+
+ if (signal_pending(current) )
+ break;
+
+ SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler waking up\n"));
+
+ host->eh_active = 1;
+
+ /*
+ * We have a host that is failing for some reason. Figure out
+ * what we need to do to get it up and online again (if we can).
+ * If we fail, we end up taking the thing offline.
+ */
+ if( host->hostt->eh_strategy_handler != NULL )
+ {
+ rtn = host->hostt->eh_strategy_handler(host);
+ }
+ else
+ {
+ rtn = scsi_unjam_host(host);
+ }
+
+ host->eh_active = 0;
+
+ /*
+ * Note - if the above fails completely, the action is to take
+ * individual devices offline and flush the queue of any
+ * outstanding requests that may have been pending. When we
+ * restart, we restart any I/O to any other devices on the bus
+ * which are still online.
+ */
+ scsi_restart_operations(host);
+ }
+
+ SCSI_LOG_ERROR_RECOVERY(1,printk("Error handler exiting\n"));
+
+ /*
+ * Make sure that nobody tries to wake us up again.
+ */
+ host->eh_wait = NULL;
+
+ /*
+ * Knock this down too. From this point on, the host is flying
+ * without a pilot. If this is because the module is being unloaded,
+ * that's fine. If the user sent a signal to this thing, we are
+ * potentially in real danger.
+ */
+ host->in_recovery = 0;
+ host->eh_active = 0;
+ host->ehandler = NULL;
+
+ /*
+ * If anyone is waiting for us to exit (i.e. someone trying to unload
+ * a driver), then wake up that process to let them know we are on
+ * the way out the door. This may be overkill - I *think* that we
+ * could probably just unload the driver and send the signal, and when
+ * the error handling thread wakes up that it would just exit without
+ * needing to touch any memory associated with the driver itself.
+ */
+ if( host->eh_notify != NULL )
+ up(host->eh_notify);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 93711a0d2..eafaf6a00 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -1,8 +1,3 @@
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
#define __NO_VERSION__
#include <linux/module.h>
@@ -103,8 +98,10 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
{
int result;
Scsi_Cmnd * SCpnt;
-
- SCpnt = allocate_device(NULL, dev, 1);
+ Scsi_Device * SDpnt;
+
+ SCSI_LOG_IOCTL(1, printk("Trying ioctl with scsi command %d\n", cmd[0]));
+ SCpnt = scsi_allocate_device(NULL, dev, 1);
{
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
@@ -112,8 +109,11 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
scsi_ioctl_done, MAX_TIMEOUT,
MAX_RETRIES);
down(&sem);
+ SCpnt->request.sem = NULL;
}
+ SCSI_LOG_IOCTL(2, printk("Ioctl returned 0x%x\n", SCpnt->result));
+
if(driver_byte(SCpnt->result) != 0)
switch(SCpnt->sense_buffer[2] & 0xf) {
case ILLEGAL_REQUEST:
@@ -146,12 +146,16 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
};
result = SCpnt->result;
- SCpnt->request.rq_status = RQ_INACTIVE;
- if (!SCpnt->device->was_reset && SCpnt->device->scsi_request_fn)
- (*SCpnt->device->scsi_request_fn)();
+ SCSI_LOG_IOCTL(2, printk("IOCTL Releasing command\n"));
+ SDpnt = SCpnt->device;
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
- wake_up(&SCpnt->device->device_wait);
+ if (!SDpnt->was_reset && SDpnt->scsi_request_fn)
+ (*SDpnt->scsi_request_fn)();
+
+ wake_up(&SDpnt->device_wait);
return result;
}
@@ -166,6 +170,7 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
unsigned char cmd[12];
char * cmd_in;
Scsi_Cmnd * SCpnt;
+ Scsi_Device * SDpnt;
unsigned char opcode;
int inlen, outlen, cmdlen;
int needed, buf_needed;
@@ -221,7 +226,7 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
cmdlen = COMMAND_SIZE(opcode);
result = verify_area(VERIFY_READ, cmd_in,
- cmdlen + inlen > MAX_BUF ? MAX_BUF : inlen);
+ cmdlen + inlen > MAX_BUF ? MAX_BUF : cmdlen + inlen);
if (result) return result;
copy_from_user ((void *) cmd, cmd_in, cmdlen);
@@ -261,7 +266,7 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
#ifndef DEBUG_NO_CMD
- SCpnt = allocate_device(NULL, dev, 1);
+ SCpnt = scsi_allocate_device(NULL, dev, 1);
{
struct semaphore sem = MUTEX_LOCKED;
@@ -269,6 +274,7 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done,
timeout, retries);
down(&sem);
+ SCpnt->request.sem = NULL;
}
/*
@@ -289,14 +295,16 @@ static int ioctl_command(Scsi_Device *dev, Scsi_Ioctl_Command *sic)
}
result = SCpnt->result;
- SCpnt->request.rq_status = RQ_INACTIVE;
+ wake_up(&SCpnt->device->device_wait);
+ SDpnt = SCpnt->device;
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
if (buf) scsi_free(buf, buf_needed);
- if(SCpnt->device->scsi_request_fn)
- (*SCpnt->device->scsi_request_fn)();
+ if(SDpnt->scsi_request_fn)
+ (*SDpnt->scsi_request_fn)();
- wake_up(&SCpnt->device->device_wait);
return result;
#else
{
@@ -329,6 +337,17 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
/* No idea how this happens.... */
if (!dev) return -ENXIO;
+ /*
+ * If we are in the middle of error recovery, don't let anyone
+ * else try and use this device. Also, if error recovery fails, it
+ * may try and take the device offline, in which case all further
+ * access to the device is prohibited.
+ */
+ if( !scsi_block_when_processing_errors(dev) )
+ {
+ return -ENODEV;
+ }
+
switch (cmd) {
case SCSI_IOCTL_GET_IDLUN:
result = verify_area(VERIFY_WRITE, arg, sizeof (Scsi_Idlun));
diff --git a/drivers/scsi/scsi_obsolete.c b/drivers/scsi/scsi_obsolete.c
new file mode 100644
index 000000000..077b73063
--- /dev/null
+++ b/drivers/scsi/scsi_obsolete.c
@@ -0,0 +1,1132 @@
+/*
+ * scsi.c Copyright (C) 1992 Drew Eckhardt
+ * Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ *
+ * generic mid-level SCSI driver
+ * Initial versions: Drew Eckhardt
+ * Subsequent revisions: Eric Youngdale
+ *
+ * <drew@colorado.edu>
+ *
+ * Bug correction thanks go to :
+ * Rik Faith <faith@cs.unc.edu>
+ * Tommy Thorn <tthorn>
+ * Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
+ *
+ * Modified by Eric Youngdale eric@aib.com to
+ * add scatter-gather, multiple outstanding request, and other
+ * enhancements.
+ *
+ * Native multichannel, wide scsi, /proc/scsi and hot plugging
+ * support added by Michael Neuffer <mike@i-connect.net>
+ *
+ * Added request_module("scsi_hostadapter") for kerneld:
+ * (Put an "alias scsi_hostadapter your_hostadapter" in /etc/conf.modules)
+ * Bjorn Ekwall <bj0rn@blox.se>
+ *
+ * Major improvements to the timeout, abort, and reset processing,
+ * as well as performance modifications for large queue depths by
+ * Leonard N. Zubkoff <lnz@dandelion.com>
+ */
+
+/*
+ *#########################################################################
+ *#########################################################################
+ *#########################################################################
+ *#########################################################################
+ * NOTE - NOTE - NOTE - NOTE - NOTE - NOTE - NOTE
+ *
+ *#########################################################################
+ *#########################################################################
+ *#########################################################################
+ *#########################################################################
+ *
+ * This file contains the 'old' scsi error handling. It is only present
+ * while the new error handling code is being debugged, and while the low
+ * level drivers are being converted to use the new code. Once the last
+ * driver uses the new code this *ENTIRE* file will be nuked.
+ */
+
+#include <linux/config.h> /* for CONFIG_KERNELD */
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/blk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
+#undef USE_STATIC_SCSI_MEMORY
+
+/*
+static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_obsolete.c,v 1.1 1997/05/18 23:27:21 eric Exp $";
+*/
+
+
+#define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
+
+
+static int scsi_abort (Scsi_Cmnd *, int code);
+static int scsi_reset (Scsi_Cmnd *, unsigned int);
+
+extern void scsi_old_done (Scsi_Cmnd *SCpnt);
+static int update_timeout (Scsi_Cmnd *, int);
+extern void scsi_old_times_out (Scsi_Cmnd * SCpnt);
+extern void internal_cmnd (Scsi_Cmnd * SCpnt);
+
+static volatile struct Scsi_Host * host_active = NULL;
+#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
+ || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
+
+static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
+
+/*
+ * This is the number of clock ticks we should wait before we time out
+ * and abort the command. This is for where the scsi.c module generates
+ * the command, not where it originates from a higher level, in which
+ * case the timeout is specified there.
+ *
+ * ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
+ * respectively.
+ */
+
+#ifdef DEBUG_TIMEOUT
+static void scsi_dump_status(void);
+#endif
+
+
+#ifdef DEBUG
+ #define SCSI_TIMEOUT (5*HZ)
+#else
+ #define SCSI_TIMEOUT (2*HZ)
+#endif
+
+#ifdef DEBUG
+ #define SENSE_TIMEOUT SCSI_TIMEOUT
+ #define ABORT_TIMEOUT SCSI_TIMEOUT
+ #define RESET_TIMEOUT SCSI_TIMEOUT
+#else
+ #define SENSE_TIMEOUT (5*HZ/10)
+ #define RESET_TIMEOUT (5*HZ/10)
+ #define ABORT_TIMEOUT (5*HZ/10)
+#endif
+
+
+/* Do not call reset on error if we just did a reset within 15 sec. */
+#define MIN_RESET_PERIOD (15*HZ)
+
+
+
+/*
+ * Flag bits for the internal_timeout array
+ */
+#define NORMAL_TIMEOUT 0
+#define IN_ABORT 1
+#define IN_RESET 2
+#define IN_RESET2 4
+#define IN_RESET3 8
+
+/*
+ * This is our time out function, called when the timer expires for a
+ * given host adapter. It will attempt to abort the currently executing
+ * command, that failing perform a kernel panic.
+ */
+
+void scsi_old_times_out (Scsi_Cmnd * SCpnt)
+{
+
+ switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET | IN_RESET2 | IN_RESET3))
+ {
+ case NORMAL_TIMEOUT:
+ {
+#ifdef DEBUG_TIMEOUT
+ scsi_dump_status();
+#endif
+ }
+
+ if (!scsi_abort (SCpnt, DID_TIME_OUT))
+ return;
+ case IN_ABORT:
+ printk("SCSI host %d abort (pid %ld) timed out - resetting\n",
+ SCpnt->host->host_no, SCpnt->pid);
+ if (!scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS))
+ return;
+ case IN_RESET:
+ case (IN_ABORT | IN_RESET):
+ /* This might be controversial, but if there is a bus hang,
+ * you might conceivably want the machine up and running
+ * esp if you have an ide disk.
+ */
+ printk("SCSI host %d channel %d reset (pid %ld) timed out - "
+ "trying harder\n",
+ SCpnt->host->host_no, SCpnt->channel, SCpnt->pid);
+ SCpnt->internal_timeout &= ~IN_RESET;
+ SCpnt->internal_timeout |= IN_RESET2;
+ scsi_reset (SCpnt,
+ SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET);
+ return;
+ case (IN_ABORT | IN_RESET | IN_RESET2):
+ /* Obviously the bus reset didn't work.
+ * Let's try even harder and call for an HBA reset.
+ * Maybe the HBA itself crashed and this will shake it loose.
+ */
+ printk("SCSI host %d reset (pid %ld) timed out - trying to shake it loose\n",
+ SCpnt->host->host_no, SCpnt->pid);
+ SCpnt->internal_timeout &= ~(IN_RESET | IN_RESET2);
+ SCpnt->internal_timeout |= IN_RESET3;
+ scsi_reset (SCpnt,
+ SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_HOST_RESET);
+ return;
+
+ default:
+ printk("SCSI host %d reset (pid %ld) timed out again -\n",
+ SCpnt->host->host_no, SCpnt->pid);
+ printk("probably an unrecoverable SCSI bus or device hang.\n");
+ return;
+
+ }
+
+}
+
+
+static void scsi_request_sense (Scsi_Cmnd * SCpnt)
+{
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
+ update_timeout(SCpnt, SENSE_TIMEOUT);
+ restore_flags(flags);
+
+
+ memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
+ sizeof(generic_sense));
+
+ SCpnt->cmnd[1] = SCpnt->lun << 5;
+ SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+
+ SCpnt->request_buffer = &SCpnt->sense_buffer;
+ SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+ SCpnt->use_sg = 0;
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ internal_cmnd (SCpnt);
+}
+
+
+
+
+static int check_sense (Scsi_Cmnd * SCpnt)
+{
+ /* If there is no sense information, request it. If we have already
+ * requested it, there is no point in asking again - the firmware must
+ * be confused.
+ */
+ if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
+ if(!(SCpnt->flags & ASKED_FOR_SENSE))
+ return SUGGEST_SENSE;
+ else
+ return SUGGEST_RETRY;
+ }
+
+ SCpnt->flags &= ~ASKED_FOR_SENSE;
+
+#ifdef DEBUG_INIT
+ printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
+ print_sense("", SCpnt);
+ printk("\n");
+#endif
+ if (SCpnt->sense_buffer[2] & 0xe0)
+ return SUGGEST_ABORT;
+
+ switch (SCpnt->sense_buffer[2] & 0xf)
+ {
+ case NO_SENSE:
+ return 0;
+ case RECOVERED_ERROR:
+ return SUGGEST_IS_OK;
+
+ case ABORTED_COMMAND:
+ return SUGGEST_RETRY;
+ case NOT_READY:
+ case UNIT_ATTENTION:
+ /*
+ * If we are expecting a CC/UA because of a bus reset that we
+ * performed, treat this just as a retry. Otherwise this is
+ * information that we should pass up to the upper-level driver
+ * so that we can deal with it there.
+ */
+ if( SCpnt->device->expecting_cc_ua )
+ {
+ SCpnt->device->expecting_cc_ua = 0;
+ return SUGGEST_RETRY;
+ }
+ return SUGGEST_ABORT;
+
+ /* these three are not supported */
+ case COPY_ABORTED:
+ case VOLUME_OVERFLOW:
+ case MISCOMPARE:
+
+ case MEDIUM_ERROR:
+ return SUGGEST_REMAP;
+ case BLANK_CHECK:
+ case DATA_PROTECT:
+ case HARDWARE_ERROR:
+ case ILLEGAL_REQUEST:
+ default:
+ return SUGGEST_ABORT;
+ }
+}
+
+/* This function is the mid-level interrupt routine, which decides how
+ * to handle error conditions. Each invocation of this function must
+ * do one and *only* one of the following:
+ *
+ * (1) Call last_cmnd[host].done. This is done for fatal errors and
+ * normal completion, and indicates that the handling for this
+ * request is complete.
+ * (2) Call internal_cmnd to requeue the command. This will result in
+ * scsi_done being called again when the retry is complete.
+ * (3) Call scsi_request_sense. This asks the host adapter/drive for
+ * more information about the error condition. When the information
+ * is available, scsi_done will be called again.
+ * (4) Call reset(). This is sort of a last resort, and the idea is that
+ * this may kick things loose and get the drive working again. reset()
+ * automatically calls scsi_request_sense, and thus scsi_done will be
+ * called again once the reset is complete.
+ *
+ * If none of the above actions are taken, the drive in question
+ * will hang. If more than one of the above actions are taken by
+ * scsi_done, then unpredictable behavior will result.
+ */
+void scsi_old_done (Scsi_Cmnd * SCpnt)
+{
+ int status=0;
+ int exit=0;
+ int checked;
+ int oldto;
+ struct Scsi_Host * host = SCpnt->host;
+ int result = SCpnt->result;
+ SCpnt->serial_number = 0;
+ oldto = update_timeout(SCpnt, 0);
+
+#ifdef DEBUG_TIMEOUT
+ if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
+ result, SCpnt->target, SCpnt->lun);
+#endif
+
+ /* If we requested an abort, (and we got it) then fix up the return
+ * status to say why
+ */
+ if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
+ SCpnt->result = result = (result & 0xff00ffff) |
+ (SCpnt->abort_reason << 16);
+
+
+#define CMD_FINISHED 0
+#define MAYREDO 1
+#define REDO 3
+#define PENDING 4
+
+#ifdef DEBUG
+ printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
+#endif
+
+ if(SCpnt->flags & WAS_SENSE)
+ {
+ SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
+ }
+
+ switch (host_byte(result))
+ {
+ case DID_OK:
+ if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
+ /* Failed to obtain sense information */
+ {
+ SCpnt->flags &= ~WAS_SENSE;
+#if 0 /* This cannot possibly be correct. */
+ SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+#endif
+
+ if (!(SCpnt->flags & WAS_RESET))
+ {
+ printk("scsi%d : channel %d target %d lun %d request sense"
+ " failed, performing reset.\n",
+ SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
+ SCpnt->lun);
+ scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+ return;
+ }
+ else
+ {
+ exit = (DRIVER_HARD | SUGGEST_ABORT);
+ status = CMD_FINISHED;
+ }
+ }
+ else switch(msg_byte(result))
+ {
+ case COMMAND_COMPLETE:
+ switch (status_byte(result))
+ {
+ case GOOD:
+ if (SCpnt->flags & WAS_SENSE)
+ {
+#ifdef DEBUG
+ printk ("In scsi_done, GOOD status, COMMAND COMPLETE, "
+ "parsing sense information.\n");
+#endif
+ SCpnt->flags &= ~WAS_SENSE;
+#if 0 /* This cannot possibly be correct. */
+ SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+#endif
+
+ switch (checked = check_sense(SCpnt))
+ {
+ case SUGGEST_SENSE:
+ case 0:
+#ifdef DEBUG
+ printk("NO SENSE. status = REDO\n");
+#endif
+ update_timeout(SCpnt, oldto);
+ status = REDO;
+ break;
+ case SUGGEST_IS_OK:
+ break;
+ case SUGGEST_REMAP:
+#ifdef DEBUG
+ printk("SENSE SUGGEST REMAP - status = CMD_FINISHED\n");
+#endif
+ status = CMD_FINISHED;
+ exit = DRIVER_SENSE | SUGGEST_ABORT;
+ break;
+ case SUGGEST_RETRY:
+#ifdef DEBUG
+ printk("SENSE SUGGEST RETRY - status = MAYREDO\n");
+#endif
+ status = MAYREDO;
+ exit = DRIVER_SENSE | SUGGEST_RETRY;
+ break;
+ case SUGGEST_ABORT:
+#ifdef DEBUG
+ printk("SENSE SUGGEST ABORT - status = CMD_FINISHED");
+#endif
+ status = CMD_FINISHED;
+ exit = DRIVER_SENSE | SUGGEST_ABORT;
+ break;
+ default:
+ printk ("Internal error %s %d \n", __FILE__,
+ __LINE__);
+ }
+ } /* end WAS_SENSE */
+ else
+ {
+#ifdef DEBUG
+ printk("COMMAND COMPLETE message returned, "
+ "status = CMD_FINISHED. \n");
+#endif
+ exit = DRIVER_OK;
+ status = CMD_FINISHED;
+ }
+ break;
+
+ case CHECK_CONDITION:
+ case COMMAND_TERMINATED:
+ switch (check_sense(SCpnt))
+ {
+ case 0:
+ update_timeout(SCpnt, oldto);
+ status = REDO;
+ break;
+ case SUGGEST_REMAP:
+ status = CMD_FINISHED;
+ exit = DRIVER_SENSE | SUGGEST_ABORT;
+ break;
+ case SUGGEST_RETRY:
+ status = MAYREDO;
+ exit = DRIVER_SENSE | SUGGEST_RETRY;
+ break;
+ case SUGGEST_ABORT:
+ status = CMD_FINISHED;
+ exit = DRIVER_SENSE | SUGGEST_ABORT;
+ break;
+ case SUGGEST_SENSE:
+ scsi_request_sense (SCpnt);
+ status = PENDING;
+ break;
+ }
+ break;
+
+ case CONDITION_GOOD:
+ case INTERMEDIATE_GOOD:
+ case INTERMEDIATE_C_GOOD:
+ break;
+
+ case BUSY:
+ case QUEUE_FULL:
+ update_timeout(SCpnt, oldto);
+ status = REDO;
+ break;
+
+ case RESERVATION_CONFLICT:
+ printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
+ " reset.\n", SCpnt->host->host_no, SCpnt->channel);
+ scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+ return;
+#if 0
+ exit = DRIVER_SOFT | SUGGEST_ABORT;
+ status = MAYREDO;
+ break;
+#endif
+ default:
+ printk ("Internal error %s %d \n"
+ "status byte = %d \n", __FILE__,
+ __LINE__, status_byte(result));
+
+ }
+ break;
+ default:
+ panic("scsi: unsupported message byte %d received\n",
+ msg_byte(result));
+ }
+ break;
+ case DID_TIME_OUT:
+#ifdef DEBUG
+ printk("Host returned DID_TIME_OUT - ");
+#endif
+
+ if (SCpnt->flags & WAS_TIMEDOUT)
+ {
+#ifdef DEBUG
+ printk("Aborting\n");
+#endif
+ /*
+ Allow TEST_UNIT_READY and INQUIRY commands to timeout early
+ without causing resets. All other commands should be retried.
+ */
+ if (SCpnt->cmnd[0] != TEST_UNIT_READY &&
+ SCpnt->cmnd[0] != INQUIRY)
+ status = MAYREDO;
+ exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
+ }
+ else
+ {
+#ifdef DEBUG
+ printk ("Retrying.\n");
+#endif
+ SCpnt->flags |= WAS_TIMEDOUT;
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ status = REDO;
+ }
+ break;
+ case DID_BUS_BUSY:
+ case DID_PARITY:
+ status = REDO;
+ break;
+ case DID_NO_CONNECT:
+#ifdef DEBUG
+ printk("Couldn't connect.\n");
+#endif
+ exit = (DRIVER_HARD | SUGGEST_ABORT);
+ break;
+ case DID_ERROR:
+ status = MAYREDO;
+ exit = (DRIVER_HARD | SUGGEST_ABORT);
+ break;
+ case DID_BAD_TARGET:
+ case DID_ABORT:
+ exit = (DRIVER_INVALID | SUGGEST_ABORT);
+ break;
+ case DID_RESET:
+ if (SCpnt->flags & IS_RESETTING)
+ {
+ SCpnt->flags &= ~IS_RESETTING;
+ status = REDO;
+ break;
+ }
+
+ if(msg_byte(result) == GOOD &&
+ status_byte(result) == CHECK_CONDITION) {
+ switch (check_sense(SCpnt)) {
+ case 0:
+ update_timeout(SCpnt, oldto);
+ status = REDO;
+ break;
+ case SUGGEST_REMAP:
+ case SUGGEST_RETRY:
+ status = MAYREDO;
+ exit = DRIVER_SENSE | SUGGEST_RETRY;
+ break;
+ case SUGGEST_ABORT:
+ status = CMD_FINISHED;
+ exit = DRIVER_SENSE | SUGGEST_ABORT;
+ break;
+ case SUGGEST_SENSE:
+ scsi_request_sense (SCpnt);
+ status = PENDING;
+ break;
+ }
+ } else {
+ status=REDO;
+ exit = SUGGEST_RETRY;
+ }
+ break;
+ default :
+ exit = (DRIVER_ERROR | SUGGEST_DIE);
+ }
+
+ switch (status)
+ {
+ case CMD_FINISHED:
+ case PENDING:
+ break;
+ case MAYREDO:
+#ifdef DEBUG
+ printk("In MAYREDO, allowing %d retries, have %d\n",
+ SCpnt->allowed, SCpnt->retries);
+#endif
+ if ((++SCpnt->retries) < SCpnt->allowed)
+ {
+ if ((SCpnt->retries >= (SCpnt->allowed >> 1))
+ && !(SCpnt->host->last_reset > 0 &&
+ jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
+ && !(SCpnt->flags & WAS_RESET))
+ {
+ printk("scsi%d channel %d : resetting for second half of retries.\n",
+ SCpnt->host->host_no, SCpnt->channel);
+ scsi_reset(SCpnt, SCSI_RESET_SYNCHRONOUS);
+ break;
+ }
+
+ }
+ else
+ {
+ status = CMD_FINISHED;
+ break;
+ }
+ /* fall through to REDO */
+
+ case REDO:
+
+ if (SCpnt->flags & WAS_SENSE)
+ scsi_request_sense(SCpnt);
+ else
+ {
+ memcpy ((void *) SCpnt->cmnd,
+ (void*) SCpnt->data_cmnd,
+ sizeof(SCpnt->data_cmnd));
+ SCpnt->request_buffer = SCpnt->buffer;
+ SCpnt->request_bufflen = SCpnt->bufflen;
+ SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
+ internal_cmnd (SCpnt);
+ }
+ break;
+ default:
+ INTERNAL_ERROR;
+ }
+
+ if (status == CMD_FINISHED) {
+#ifdef DEBUG
+ printk("Calling done function - at address %p\n", SCpnt->done);
+#endif
+ host->host_busy--; /* Indicate that we are free */
+
+ if (host->block && host->host_busy == 0) {
+ host_active = NULL;
+
+ /* For block devices "wake_up" is done in end_scsi_request */
+ if (MAJOR(SCpnt->request.rq_dev) != SCSI_DISK_MAJOR &&
+ MAJOR(SCpnt->request.rq_dev) != SCSI_CDROM_MAJOR) {
+ struct Scsi_Host * next;
+
+ for (next = host->block; next != host; next = next->block)
+ wake_up(&next->host_wait);
+ }
+
+ }
+
+ wake_up(&host->host_wait);
+ SCpnt->result = result | ((exit & 0xff) << 24);
+ SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->done (SCpnt);
+ }
+
+#undef CMD_FINISHED
+#undef REDO
+#undef MAYREDO
+#undef PENDING
+}
+
+/*
+ * The scsi_abort function interfaces with the abort() function of the host
+ * we are aborting, and causes the current command to not complete. The
+ * caller should deal with any error messages or status returned on the
+ * next call.
+ *
+ * This will not be called reentrantly for a given host.
+ */
+
+/*
+ * Since we're nice guys and specified that abort() and reset()
+ * can be non-reentrant. The internal_timeout flags are used for
+ * this.
+ */
+
+
+static int scsi_abort (Scsi_Cmnd * SCpnt, int why)
+{
+ int oldto;
+ unsigned long flags;
+ struct Scsi_Host * host = SCpnt->host;
+
+ while(1)
+ {
+ save_flags(flags);
+ cli();
+
+ /*
+ * Protect against races here. If the command is done, or we are
+ * on a different command forget it.
+ */
+ if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
+ restore_flags(flags);
+ return 0;
+ }
+
+ if (SCpnt->internal_timeout & IN_ABORT)
+ {
+ restore_flags(flags);
+ while (SCpnt->internal_timeout & IN_ABORT)
+ barrier();
+ }
+ else
+ {
+ SCpnt->internal_timeout |= IN_ABORT;
+ oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
+
+ if ((SCpnt->flags & IS_RESETTING) && SCpnt->device->soft_reset) {
+ /* OK, this command must have died when we did the
+ * reset. The device itself must have lied.
+ */
+ printk("Stale command on %d %d:%d appears to have died when"
+ " the bus was reset\n",
+ SCpnt->channel, SCpnt->target, SCpnt->lun);
+ }
+
+ restore_flags(flags);
+ if (!host->host_busy) {
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ update_timeout(SCpnt, oldto);
+ return 0;
+ }
+ printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
+ " channel %d, id %d, lun %d ",
+ SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
+ (int) SCpnt->target, (int) SCpnt->lun);
+ print_command (SCpnt->cmnd);
+ if (SCpnt->serial_number != SCpnt->serial_number_at_timeout)
+ return 0;
+ SCpnt->abort_reason = why;
+ switch(host->hostt->abort(SCpnt)) {
+ /* We do not know how to abort. Try waiting another
+ * time increment and see if this helps. Set the
+ * WAS_TIMEDOUT flag set so we do not try this twice
+ */
+ case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
+ * this is too severe
+ */
+ case SCSI_ABORT_SNOOZE:
+ if(why == DID_TIME_OUT) {
+ save_flags(flags);
+ cli();
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ if(SCpnt->flags & WAS_TIMEDOUT) {
+ restore_flags(flags);
+ return 1; /* Indicate we cannot handle this.
+ * We drop down into the reset handler
+ * and try again
+ */
+ } else {
+ SCpnt->flags |= WAS_TIMEDOUT;
+ oldto = SCpnt->timeout_per_command;
+ update_timeout(SCpnt, oldto);
+ }
+ restore_flags(flags);
+ }
+ return 0;
+ case SCSI_ABORT_PENDING:
+ if(why != DID_TIME_OUT) {
+ save_flags(flags);
+ cli();
+ update_timeout(SCpnt, oldto);
+ restore_flags(flags);
+ }
+ return 0;
+ case SCSI_ABORT_SUCCESS:
+ /* We should have already aborted this one. No
+ * need to adjust timeout
+ */
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ return 0;
+ case SCSI_ABORT_NOT_RUNNING:
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ update_timeout(SCpnt, 0);
+ return 0;
+ case SCSI_ABORT_ERROR:
+ default:
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ return 1;
+ }
+ }
+ }
+}
+
+
+/* Mark a single SCSI Device as having been reset. */
+
+static inline void scsi_mark_device_reset(Scsi_Device *Device)
+{
+ Device->was_reset = 1;
+ Device->expecting_cc_ua = 1;
+}
+
+
+/* Mark all SCSI Devices on a specific Host as having been reset. */
+
+void scsi_mark_host_reset(struct Scsi_Host *Host)
+{
+ Scsi_Cmnd * SCpnt;
+ Scsi_Device * SDpnt;
+
+ for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+ scsi_mark_device_reset(SCpnt->device);
+ }
+}
+
+
+/* Mark all SCSI Devices on a specific Host Bus as having been reset. */
+
+static void scsi_mark_bus_reset(struct Scsi_Host *Host, int channel)
+{
+ Scsi_Cmnd *SCpnt;
+ Scsi_Device * SDpnt;
+
+ for (SDpnt = Host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ for (SCpnt = SDpnt->device_queue; SCpnt; SCpnt = SCpnt->next)
+ if (SCpnt->channel == channel)
+ scsi_mark_device_reset(SCpnt->device);
+ }
+}
+
+
+static int scsi_reset (Scsi_Cmnd * SCpnt, unsigned int reset_flags)
+{
+ int temp;
+ unsigned long flags;
+ Scsi_Cmnd * SCpnt1;
+ Scsi_Device * SDpnt;
+ struct Scsi_Host * host = SCpnt->host;
+
+ printk("SCSI bus is being reset for host %d channel %d.\n",
+ host->host_no, SCpnt->channel);
+
+#if 0
+ /*
+ * First of all, we need to make a recommendation to the low-level
+ * driver as to whether a BUS_DEVICE_RESET should be performed,
+ * or whether we should do a full BUS_RESET. There is no simple
+ * algorithm here - we basically use a series of heuristics
+ * to determine what we should do.
+ */
+ SCpnt->host->suggest_bus_reset = FALSE;
+
+ /*
+ * First see if all of the active devices on the bus have
+ * been jammed up so that we are attempting resets. If so,
+ * then suggest a bus reset. Forcing a bus reset could
+ * result in some race conditions, but no more than
+ * you would usually get with timeouts. We will cross
+ * that bridge when we come to it.
+ *
+ * This is actually a pretty bad idea, since a sequence of
+ * commands will often timeout together and this will cause a
+ * Bus Device Reset followed immediately by a SCSI Bus Reset.
+ * If all of the active devices really are jammed up, the
+ * Bus Device Reset will quickly timeout and scsi_times_out
+ * will follow up with a SCSI Bus Reset anyway.
+ */
+ SCpnt1 = host->host_queue;
+ while(SCpnt1) {
+ if( SCpnt1->request.rq_status != RQ_INACTIVE
+ && (SCpnt1->flags & (WAS_RESET | IS_RESETTING)) == 0 )
+ break;
+ SCpnt1 = SCpnt1->next;
+ }
+ if( SCpnt1 == NULL ) {
+ reset_flags |= SCSI_RESET_SUGGEST_BUS_RESET;
+ }
+
+ /*
+ * If the code that called us is suggesting a hard reset, then
+ * definitely request it. This usually occurs because a
+ * BUS_DEVICE_RESET times out.
+ *
+ * Passing reset_flags along takes care of this automatically.
+ */
+ if( reset_flags & SCSI_RESET_SUGGEST_BUS_RESET ) {
+ SCpnt->host->suggest_bus_reset = TRUE;
+ }
+#endif
+
+ while (1) {
+ save_flags(flags);
+ cli();
+
+ /*
+ * Protect against races here. If the command is done, or we are
+ * on a different command forget it.
+ */
+ if (reset_flags & SCSI_RESET_ASYNCHRONOUS)
+ if (SCpnt->serial_number != SCpnt->serial_number_at_timeout) {
+ restore_flags(flags);
+ return 0;
+ }
+
+ if (SCpnt->internal_timeout & IN_RESET)
+ {
+ restore_flags(flags);
+ while (SCpnt->internal_timeout & IN_RESET)
+ barrier();
+ }
+ else
+ {
+ SCpnt->internal_timeout |= IN_RESET;
+ update_timeout(SCpnt, RESET_TIMEOUT);
+
+ if (host->host_busy)
+ {
+ restore_flags(flags);
+ for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ SCpnt1 = SDpnt->device_queue;
+ while(SCpnt1) {
+ if (SCpnt1->request.rq_status != RQ_INACTIVE) {
+#if 0
+ if (!(SCpnt1->flags & IS_RESETTING) &&
+ !(SCpnt1->internal_timeout & IN_ABORT))
+ scsi_abort(SCpnt1, DID_RESET);
+#endif
+ SCpnt1->flags |= (WAS_RESET | IS_RESETTING);
+ }
+ SCpnt1 = SCpnt1->next;
+ }
+ }
+
+ host->last_reset = jiffies;
+ temp = host->hostt->reset(SCpnt, reset_flags);
+ /*
+ This test allows the driver to introduce an additional bus
+ settle time delay by setting last_reset up to 20 seconds in
+ the future. In the normal case where the driver does not
+ modify last_reset, it must be assumed that the actual bus
+ reset occurred immediately prior to the return to this code,
+ and so last_reset must be updated to the current time, so
+ that the delay in internal_cmnd will guarantee at least a
+ MIN_RESET_DELAY bus settle time.
+ */
+ if (host->last_reset - jiffies > 20UL * HZ)
+ host->last_reset = jiffies;
+ }
+ else
+ {
+ if (!host->block) host->host_busy++;
+ restore_flags(flags);
+ host->last_reset = jiffies;
+ SCpnt->flags |= (WAS_RESET | IS_RESETTING);
+ temp = host->hostt->reset(SCpnt, reset_flags);
+ if ((host->last_reset < jiffies) ||
+ (host->last_reset > (jiffies + 20 * HZ)))
+ host->last_reset = jiffies;
+ if (!host->block) host->host_busy--;
+ }
+
+#ifdef DEBUG
+ printk("scsi reset function returned %d\n", temp);
+#endif
+
+ /*
+ * Now figure out what we need to do, based upon
+ * what the low level driver said that it did.
+ * If the result is SCSI_RESET_SUCCESS, SCSI_RESET_PENDING,
+ * or SCSI_RESET_WAKEUP, then the low level driver did a
+ * bus device reset or bus reset, so we should go through
+ * and mark one or all of the devices on that bus
+ * as having been reset.
+ */
+ switch(temp & SCSI_RESET_ACTION) {
+ case SCSI_RESET_SUCCESS:
+ if (temp & SCSI_RESET_HOST_RESET)
+ scsi_mark_host_reset(host);
+ else if (temp & SCSI_RESET_BUS_RESET)
+ scsi_mark_bus_reset(host, SCpnt->channel);
+ else scsi_mark_device_reset(SCpnt->device);
+ save_flags(flags);
+ cli();
+ SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+ restore_flags(flags);
+ return 0;
+ case SCSI_RESET_PENDING:
+ if (temp & SCSI_RESET_HOST_RESET)
+ scsi_mark_host_reset(host);
+ else if (temp & SCSI_RESET_BUS_RESET)
+ scsi_mark_bus_reset(host, SCpnt->channel);
+ else scsi_mark_device_reset(SCpnt->device);
+ case SCSI_RESET_NOT_RUNNING:
+ return 0;
+ case SCSI_RESET_PUNT:
+ SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+ scsi_request_sense (SCpnt);
+ return 0;
+ case SCSI_RESET_WAKEUP:
+ if (temp & SCSI_RESET_HOST_RESET)
+ scsi_mark_host_reset(host);
+ else if (temp & SCSI_RESET_BUS_RESET)
+ scsi_mark_bus_reset(host, SCpnt->channel);
+ else scsi_mark_device_reset(SCpnt->device);
+ SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+ scsi_request_sense (SCpnt);
+ /*
+ * If a bus reset was performed, we
+ * need to wake up each and every command
+ * that was active on the bus or if it was a HBA
+ * reset all active commands on all channels
+ */
+ if( temp & SCSI_RESET_HOST_RESET )
+ {
+ for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ SCpnt1 = SDpnt->device_queue;
+ while(SCpnt1) {
+ if (SCpnt1->request.rq_status != RQ_INACTIVE
+ && SCpnt1 != SCpnt)
+ scsi_request_sense (SCpnt1);
+ SCpnt1 = SCpnt1->next;
+ }
+ }
+ } else if( temp & SCSI_RESET_BUS_RESET ) {
+ for(SDpnt = host->host_queue; SDpnt; SDpnt = SDpnt->next)
+ {
+ SCpnt1 = SDpnt->device_queue;
+ while(SCpnt1) {
+ if(SCpnt1->request.rq_status != RQ_INACTIVE
+ && SCpnt1 != SCpnt
+ && SCpnt1->channel == SCpnt->channel)
+ scsi_request_sense (SCpnt);
+ SCpnt1 = SCpnt1->next;
+ }
+ }
+ }
+ return 0;
+ case SCSI_RESET_SNOOZE:
+ /* In this case, we set the timeout field to 0
+ * so that this command does not time out any more,
+ * and we return 1 so that we get a message on the
+ * screen.
+ */
+ save_flags(flags);
+ cli();
+ SCpnt->internal_timeout &= ~(IN_RESET|IN_RESET2|IN_RESET3);
+ update_timeout(SCpnt, 0);
+ restore_flags(flags);
+ /* If you snooze, you lose... */
+ case SCSI_RESET_ERROR:
+ default:
+ return 1;
+ }
+
+ return temp;
+ }
+ }
+}
+
+/*
+ * The strategy is to cause the timer code to call scsi_times_out()
+ * when the soonest timeout is pending.
+ * The arguments are used when we are queueing a new command, because
+ * we do not want to subtract the time used from this time, but when we
+ * set the timer, we want to take this value into account.
+ */
+
+static int update_timeout(Scsi_Cmnd * SCset, int timeout)
+{
+ int rtn;
+
+ /*
+ * We are using the new error handling code to actually register/deregister
+ * timers for timeout.
+ */
+
+ if( SCset->eh_timeout.expires == 0 )
+ {
+ rtn = 0;
+ }
+ else
+ {
+ rtn = SCset->eh_timeout.expires - jiffies;
+ }
+
+ if( timeout == 0 )
+ {
+ scsi_delete_timer(SCset);
+ }
+ else
+ {
+ scsi_add_timer(SCset, timeout, scsi_old_times_out);
+ }
+
+ return rtn;
+}
+
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
diff --git a/drivers/scsi/scsi_obsolete.h b/drivers/scsi/scsi_obsolete.h
new file mode 100644
index 000000000..a923e8e8b
--- /dev/null
+++ b/drivers/scsi/scsi_obsolete.h
@@ -0,0 +1,106 @@
+/*
+ * scsi_obsolete.h Copyright (C) 1997 Eric Youngdale
+ *
+ */
+
+#ifndef _SCSI_OBSOLETE_H
+#define _SCSI_OBSOLETE_H
+
+/*
+ * These are the return codes for the abort and reset functions. The mid-level
+ * code uses these to decide what to do next. Each of the low level abort
+ * and reset functions must correctly indicate what it has done.
+ * The descriptions are written from the point of view of the mid-level code,
+ * so that the return code is telling the mid-level drivers exactly what
+ * the low level driver has already done, and what remains to be done.
+ */
+
+/* We did not do anything.
+ * Wait some more for this command to complete, and if this does not work,
+ * try something more serious. */
+#define SCSI_ABORT_SNOOZE 0
+
+/* This means that we were able to abort the command. We have already
+ * called the mid-level done function, and do not expect an interrupt that
+ * will lead to another call to the mid-level done function for this command */
+#define SCSI_ABORT_SUCCESS 1
+
+/* We called for an abort of this command, and we should get an interrupt
+ * when this succeeds. Thus we should not restore the timer for this
+ * command in the mid-level abort function. */
+#define SCSI_ABORT_PENDING 2
+
+/* Unable to abort - command is currently on the bus. Grin and bear it. */
+#define SCSI_ABORT_BUSY 3
+
+/* The command is not active in the low level code. Command probably
+ * finished. */
+#define SCSI_ABORT_NOT_RUNNING 4
+
+/* Something went wrong. The low level driver will indicate the correct
+ * error condition when it calls scsi_done, so the mid-level abort function
+ * can simply wait until this comes through */
+#define SCSI_ABORT_ERROR 5
+
+/* We do not know how to reset the bus, or we do not want to. Bummer.
+ * Anyway, just wait a little more for the command in question, and hope that
+ * it eventually finishes. If it never finishes, the SCSI device could
+ * hang, so use this with caution. */
+#define SCSI_RESET_SNOOZE 0
+
+/* We do not know how to reset the bus, or we do not want to. Bummer.
+ * We have given up on this ever completing. The mid-level code will
+ * request sense information to decide how to proceed from here. */
+#define SCSI_RESET_PUNT 1
+
+/* This means that we were able to reset the bus. We have restarted all of
+ * the commands that should be restarted, and we should be able to continue
+ * on normally from here. We do not expect any interrupts that will return
+ * DID_RESET to any of the other commands in the host_queue, and the mid-level
+ * code does not need to do anything special to keep the commands alive.
+ * If a hard reset was performed then all outstanding commands on the
+ * bus have been restarted. */
+#define SCSI_RESET_SUCCESS 2
+
+/* We called for a reset of this bus, and we should get an interrupt
+ * when this succeeds. Each command should get its own status
+ * passed up to scsi_done, but this has not happened yet.
+ * If a hard reset was performed, then we expect an interrupt
+ * for *each* of the outstanding commands that will have the
+ * effect of restarting the commands.
+ */
+#define SCSI_RESET_PENDING 3
+
+/* We did a reset, but do not expect an interrupt to signal DID_RESET.
+ * This tells the upper level code to request the sense info, and this
+ * should keep the command alive. */
+#define SCSI_RESET_WAKEUP 4
+
+/* The command is not active in the low level code. Command probably
+ finished. */
+#define SCSI_RESET_NOT_RUNNING 5
+
+/* Something went wrong, and we do not know how to fix it. */
+#define SCSI_RESET_ERROR 6
+
+#define SCSI_RESET_SYNCHRONOUS 0x01
+#define SCSI_RESET_ASYNCHRONOUS 0x02
+#define SCSI_RESET_SUGGEST_BUS_RESET 0x04
+#define SCSI_RESET_SUGGEST_HOST_RESET 0x08
+/*
+ * This is a bitmask that is ored with one of the above codes.
+ * It tells the mid-level code that we did a hard reset.
+ */
+#define SCSI_RESET_BUS_RESET 0x100
+/*
+ * This is a bitmask that is ored with one of the above codes.
+ * It tells the mid-level code that we did a host adapter reset.
+ */
+#define SCSI_RESET_HOST_RESET 0x200
+/*
+ * Used to mask off bits and to obtain the basic action that was
+ * performed.
+ */
+#define SCSI_RESET_ACTION 0xff
+
+#endif /* SCSI_OBSOLETE_H */
diff --git a/drivers/scsi/scsi_proc.c b/drivers/scsi/scsi_proc.c
index 83c21c20b..7c8b95138 100644
--- a/drivers/scsi/scsi_proc.c
+++ b/drivers/scsi/scsi_proc.c
@@ -16,11 +16,7 @@
* Michael A. Griffith <grif@acm.org>
*/
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
+#include <linux/config.h> /* for CONFIG_PROC_FS */
#define __NO_VERSION__
#include <linux/module.h>
@@ -39,6 +35,7 @@
#define FALSE 0
#endif
+#ifdef CONFIG_PROC_FS
extern int scsi_proc_info(char *, char **, off_t, int, int, int);
struct scsi_dir {
@@ -295,6 +292,7 @@ void proc_print_scsidevice(Scsi_Device *scd, char *buffer, int *size, int len)
*size = y;
return;
}
+#endif /* CONFIG_PROC_FS */
/*
* Overrides for Emacs so that we get a uniform tabbing style.
diff --git a/drivers/scsi/scsi_queue.c b/drivers/scsi/scsi_queue.c
new file mode 100644
index 000000000..b9e2a4feb
--- /dev/null
+++ b/drivers/scsi/scsi_queue.c
@@ -0,0 +1,321 @@
+/*
+ * scsi_queue.c Copyright (C) 1997 Eric Youngdale
+ *
+ * generic mid-level SCSI queueing.
+ *
+ * The point of this is that we need to track when hosts are unable to
+ * accept a command because they are busy. In addition, we track devices
+ * that cannot accept a command because of a QUEUE_FULL condition. In both
+ * of these cases, we enter the command in the queue. At some later point,
+ * we attempt to remove commands from the queue and retry them.
+ */
+
+#include <linux/config.h>
+#define __NO_VERSION__
+#include <linux/module.h>
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <linux/kernel.h>
+#include <linux/stat.h>
+#include <linux/blk.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <asm/smp_lock.h>
+
+#define __KERNEL_SYSCALLS__
+
+#include <linux/unistd.h>
+
+#include <asm/system.h>
+#include <asm/irq.h>
+#include <asm/dma.h>
+
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+
+#ifdef CONFIG_KERNELD
+#include <linux/kerneld.h>
+#endif
+
+/*
+ * TODO:
+ * 1) Prevent multiple traversals of list to look for commands to
+ * queue.
+ * 2) Protect against multiple insertions of list at the same time.
+ * DONE:
+ * 1) Set state of scsi command to a new state value for ml queue.
+ * 2) Insert into queue when host rejects command.
+ * 3) Make sure status code is properly passed from low-level queue func
+ * so that internal_cmnd properly returns the right value.
+ * 4) Insert into queue when QUEUE_FULL.
+ * 5) Cull queue in bottom half handler.
+ * 6) Check usage count prior to queue insertion. Requeue if usage
+ * count is 0.
+ * 7) Don't send down any more commands if the host/device is busy.
+ */
+
+static const char RCSid[] = "$Header: /mnt/ide/home/eric/CVSROOT/linux/drivers/scsi/scsi_queue.c,v 1.1 1997/10/21 11:16:38 eric Exp $";
+
+/*
+ * Lock used to prevent more than one process from frobbing the list at the
+ * same time. FIXME(eric) - there should be seperate spinlocks for each host.
+ * This will reduce contention.
+ */
+spinlock_t scsi_mlqueue_lock = SPIN_LOCK_UNLOCKED;
+spinlock_t scsi_mlqueue_remove_lock = SPIN_LOCK_UNLOCKED;
+
+/*
+ * Function: scsi_mlqueue_insert()
+ *
+ * Purpose: Insert a command in the midlevel queue.
+ *
+ * Arguments: cmd - command that we are adding to queue.
+ * reason - why we are inserting command to queue.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: We do this for one of two cases. Either the host is busy
+ * and it cannot accept any more commands for the time being,
+ * or the device returned QUEUE_FULL and can accept no more
+ * commands.
+ * Notes: This could be called either from an interrupt context or a
+ * normal process context.
+ */
+int
+scsi_mlqueue_insert(Scsi_Cmnd * cmd, int reason)
+{
+ Scsi_Cmnd * cpnt;
+ unsigned long flags;
+ struct Scsi_Host * host;
+
+ SCSI_LOG_MLQUEUE(1,printk("Inserting command %p into mlqueue\n", cmd));
+
+ /*
+ * We are inserting the command into the ml queue. First, we
+ * cancel the timer, so it doesn't time out.
+ */
+ scsi_delete_timer(cmd);
+
+ host = cmd->host;
+
+ /*
+ * Next, set the appropriate busy bit for the device/host.
+ */
+ if( reason == SCSI_MLQUEUE_HOST_BUSY )
+ {
+ /*
+ * Protect against race conditions. If the host isn't busy,
+ * assume that something actually completed, and that we should
+ * be able to queue a command now. Note that there is an implicit
+ * assumption that every host can always queue at least one command.
+ * If a host is inactive and cannot queue any commands, I don't see
+ * how things could possibly work anyways.
+ */
+ if( host->host_busy == 0 )
+ {
+ if( scsi_retry_command(cmd) == 0 )
+ {
+ return 0;
+ }
+ }
+
+ host->host_blocked = TRUE;
+ cmd->host_wait = TRUE;
+ }
+ else
+ {
+ /*
+ * Protect against race conditions. If the device isn't busy,
+ * assume that something actually completed, and that we should
+ * be able to queue a command now. Note that there is an implicit
+ * assumption that every host can always queue at least one command.
+ * If a host is inactive and cannot queue any commands, I don't see
+ * how things could possibly work anyways.
+ */
+ if( cmd->device->device_busy == 0 )
+ {
+ if( scsi_retry_command(cmd) == 0 )
+ {
+ return 0;
+ }
+ }
+
+ cmd->device->device_busy = TRUE;
+ cmd->device_wait = TRUE;
+ }
+
+ /*
+ * Register the fact that we own the thing for now.
+ */
+ cmd->state = SCSI_STATE_MLQUEUE;
+ cmd->owner = SCSI_OWNER_MIDLEVEL;
+ cmd->bh_next = NULL;
+
+ /*
+ * As a performance enhancement, look to see whether the list is
+ * empty. If it is, then we can just atomicly insert the command
+ * in the list and return without locking.
+ */
+ if( host->pending_commands == NULL )
+ {
+ cpnt = xchg(&host->pending_commands, cmd);
+ if( cpnt == NULL )
+ {
+ return 0;
+ }
+ /*
+ * Rats. Something slipped in while we were exchanging.
+ * Swap it back and fall through to do it the hard way.
+ */
+ cmd = xchg(&host->pending_commands, cpnt);
+
+ }
+
+ /*
+ * Next append the command to the list of pending commands.
+ */
+ spin_lock_irqsave(&scsi_mlqueue_lock, flags);
+ for(cpnt = host->pending_commands; cpnt && cpnt->bh_next;
+ cpnt = cpnt->bh_next)
+ {
+ continue;
+ }
+ if( cpnt != NULL )
+ {
+ cpnt->bh_next = cmd;
+ }
+ else
+ {
+ host->pending_commands = cmd;
+ }
+
+ spin_unlock_irqrestore(&scsi_mlqueue_lock, flags);
+ return 0;
+}
+
+/*
+ * Function: scsi_mlqueue_finish()
+ *
+ * Purpose: Try and queue commands from the midlevel queue.
+ *
+ * Arguments: host - host that just finished a command.
+ * device - device that just finished a command.
+ *
+ * Returns: Nothing.
+ *
+ * Notes: This could be called either from an interrupt context or a
+ * normal process context.
+ */
+int
+scsi_mlqueue_finish(struct Scsi_Host * host, Scsi_Device * device)
+{
+ Scsi_Cmnd * cpnt;
+ unsigned long flags;
+ Scsi_Cmnd * next;
+ Scsi_Cmnd * prev;
+ int reason = 0;
+ int rtn;
+
+ SCSI_LOG_MLQUEUE(2,printk("scsi_mlqueue_finish starting\n"));
+ /*
+ * First, clear the flag for the host/device. We will then start
+ * pushing commands through until either something else blocks, or
+ * the queue is empty.
+ */
+ if( host->host_blocked )
+ {
+ reason = SCSI_MLQUEUE_HOST_BUSY;
+ host->host_blocked = FALSE;
+ }
+
+ if( device->device_busy )
+ {
+ reason = SCSI_MLQUEUE_DEVICE_BUSY;
+ device->device_busy = FALSE;
+ }
+
+ /*
+ * Walk the list of commands to see if there is anything we can
+ * queue. This probably needs to be optimized for performance at
+ * some point.
+ */
+ prev = NULL;
+ spin_lock_irqsave(&scsi_mlqueue_remove_lock, flags);
+ for(cpnt = host->pending_commands; cpnt; cpnt = next)
+ {
+ next = cpnt->bh_next;
+ /*
+ * First, see if this command is suitable for being retried now.
+ */
+ if( reason == SCSI_MLQUEUE_HOST_BUSY )
+ {
+ /*
+ * The host was busy, but isn't any more. Thus we may be
+ * able to queue the command now, but we were waiting for
+ * the device, then we should keep waiting. Similarily, if
+ * the device is now busy, we should also keep waiting.
+ */
+ if( (cpnt->host_wait == FALSE)
+ || (device->device_busy == TRUE) )
+ {
+ prev = cpnt;
+ continue;
+ }
+ }
+
+ if( reason == SCSI_MLQUEUE_DEVICE_BUSY )
+ {
+ /*
+ * The device was busy, but isn't any more. Thus we may be
+ * able to queue the command now, but we were waiting for
+ * the host, then we should keep waiting. Similarily, if
+ * the host is now busy, we should also keep waiting.
+ */
+ if( (cpnt->device_wait == FALSE)
+ || (host->host_blocked == TRUE) )
+ {
+ prev = cpnt;
+ continue;
+ }
+ }
+
+ /*
+ * First, remove the command from the list.
+ */
+ if( prev == NULL )
+ {
+ host->pending_commands = next;
+ }
+ else
+ {
+ prev->bh_next = next;
+ }
+ cpnt->bh_next = NULL;
+
+ rtn = scsi_retry_command(cpnt);
+
+ /*
+ * If we got a non-zero return value, it means that the host rejected
+ * the command. The internal_cmnd function will have added the
+ * command back to the end of the list, so we don't have anything
+ * more to do here except return.
+ */
+ if( rtn )
+ {
+ spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags);
+ SCSI_LOG_MLQUEUE(1,printk("Unable to remove command %p from mlqueue\n", cpnt));
+ goto finish;
+ }
+ SCSI_LOG_MLQUEUE(1,printk("Removed command %p from mlqueue\n", cpnt));
+ }
+
+ spin_unlock_irqrestore(&scsi_mlqueue_remove_lock, flags);
+finish:
+ SCSI_LOG_MLQUEUE(2,printk("scsi_mlqueue_finish returning\n"));
+ return 0;
+}
diff --git a/drivers/scsi/scsi_syms.c b/drivers/scsi/scsi_syms.c
index bf82a51cb..924ec8e0c 100644
--- a/drivers/scsi/scsi_syms.c
+++ b/drivers/scsi/scsi_syms.c
@@ -38,6 +38,8 @@ extern int scsicam_bios_param (Disk * disk,
extern void print_command (unsigned char *command);
extern void print_sense(const char * devclass, Scsi_Cmnd * SCpnt);
+extern const char *const scsi_device_types[];
+
EXPORT_SYMBOL(scsi_register_module);
EXPORT_SYMBOL(scsi_unregister_module);
EXPORT_SYMBOL(scsi_free);
@@ -45,7 +47,7 @@ EXPORT_SYMBOL(scsi_malloc);
EXPORT_SYMBOL(scsi_register);
EXPORT_SYMBOL(scsi_unregister);
EXPORT_SYMBOL(scsicam_bios_param);
-EXPORT_SYMBOL(allocate_device);
+EXPORT_SYMBOL(scsi_allocate_device);
EXPORT_SYMBOL(scsi_do_cmd);
EXPORT_SYMBOL(scsi_command_size);
EXPORT_SYMBOL(scsi_init_malloc);
@@ -55,13 +57,20 @@ EXPORT_SYMBOL(print_command);
EXPORT_SYMBOL(print_sense);
EXPORT_SYMBOL(print_msg);
EXPORT_SYMBOL(print_status);
-EXPORT_SYMBOL(dma_free_sectors);
+EXPORT_SYMBOL(scsi_dma_free_sectors);
EXPORT_SYMBOL(kernel_scsi_ioctl);
-EXPORT_SYMBOL(need_isa_buffer);
-EXPORT_SYMBOL(request_queueable);
+EXPORT_SYMBOL(scsi_need_isa_buffer);
+EXPORT_SYMBOL(scsi_request_queueable);
+EXPORT_SYMBOL(scsi_release_command);
EXPORT_SYMBOL(print_Scsi_Cmnd);
+EXPORT_SYMBOL(scsi_block_when_processing_errors);
EXPORT_SYMBOL(scsi_mark_host_reset);
-EXPORT_SYMBOL(scsi_mark_bus_reset);
+#if defined(CONFIG_SCSI_LOGGING) /* { */
+EXPORT_SYMBOL(scsi_logging_level);
+#endif
+
+EXPORT_SYMBOL(scsi_sleep);
+
#if defined(CONFIG_PROC_FS)
EXPORT_SYMBOL(proc_print_scsidevice);
#endif
@@ -71,7 +80,6 @@ EXPORT_SYMBOL(proc_print_scsidevice);
EXPORT_SYMBOL(scsi_hostlist);
EXPORT_SYMBOL(scsi_hosts);
EXPORT_SYMBOL(scsi_devicelist);
-EXPORT_SYMBOL(scsi_devices);
EXPORT_SYMBOL(scsi_device_types);
diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
index e45d80f4e..3d434d2f6 100644
--- a/drivers/scsi/scsicam.c
+++ b/drivers/scsi/scsicam.c
@@ -10,11 +10,6 @@
* For more information, please consult the SCSI-CAM draft.
*/
-/*
- * Don't import our own symbols, as this would severely mess up our
- * symbol tables.
- */
-#define _SCSI_SYMS_VER_
#define __NO_VERSION__
#include <linux/module.h>
diff --git a/drivers/scsi/scsiiom.c b/drivers/scsi/scsiiom.c
index 97801d755..e0838ba17 100644
--- a/drivers/scsi/scsiiom.c
+++ b/drivers/scsi/scsiiom.c
@@ -175,13 +175,8 @@ DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB )
}
-#ifndef VERSION_ELF_1_2_13
static void
DC390_Interrupt( int irq, void *dev_id, struct pt_regs *regs)
-#else
-static void
-DC390_Interrupt( int irq, struct pt_regs *regs)
-#endif
{
PACB pACB;
PDCB pDCB;
@@ -303,11 +298,7 @@ DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
pSRB->pSegmentList++;
psgl = pSRB->pSegmentList;
-#ifndef VERSION_ELF_1_2_13
pSRB->SGPhysAddr = virt_to_phys( psgl->address );
-#else
- pSRB->SGPhysAddr = (ULONG) psgl->address;
-#endif
pSRB->SGToBeXferLen = (ULONG) psgl->length;
}
else
@@ -368,11 +359,7 @@ DC390_DataIn_0( PACB pACB, PSRB pSRB, PUCHAR psstatus)
pSRB->pSegmentList++;
psgl = pSRB->pSegmentList;
-#ifndef VERSION_ELF_1_2_13
pSRB->SGPhysAddr = virt_to_phys( psgl->address );
-#else
- pSRB->SGPhysAddr = (ULONG) psgl->address;
-#endif
pSRB->SGToBeXferLen = (ULONG) psgl->length;
}
else
@@ -427,11 +414,7 @@ din_1:
if( residual )
{
bval = inb(ioport+ScsiFifo); /* get residual byte */
-#ifndef VERSION_ELF_1_2_13
ptr = (PUCHAR) phys_to_virt( pSRB->SGPhysAddr );
-#else
- ptr = (PUCHAR) pSRB->SGPhysAddr;
-#endif
*ptr = bval;
pSRB->SGPhysAddr++;
pSRB->TotalXferredLen++;
@@ -643,11 +626,7 @@ DataIO_Comm( PACB pACB, PSRB pSRB, UCHAR ioDir)
if( !pSRB->SGToBeXferLen )
{
psgl = pSRB->pSegmentList;
-#ifndef VERSION_ELF_1_2_13
pSRB->SGPhysAddr = virt_to_phys( psgl->address );
-#else
- pSRB->SGPhysAddr = (ULONG) psgl->address;
-#endif
pSRB->SGToBeXferLen = (ULONG) psgl->length;
}
lval = pSRB->SGToBeXferLen;
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index 4ec0a82fa..c29194b70 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -87,6 +87,26 @@ static int sd_attach(Scsi_Device *);
static int sd_detect(Scsi_Device *);
static void sd_detach(Scsi_Device *);
+static void sd_devname(unsigned int disknum, char * buffer)
+{
+ if( disknum <= 26 )
+ {
+ sprintf(buffer, "sd%c", 'a' + disknum);
+ }
+ else
+ {
+ unsigned int min1;
+ unsigned int min2;
+ /*
+ * For larger numbers of disks, we need to go to a new
+ * naming scheme.
+ */
+ min1 = disknum / 26;
+ min2 = disknum % 26;
+ sprintf(buffer, "sd%c%c", 'a' + min1, 'a' + min2);
+ }
+}
+
struct Scsi_Device_Template sd_template =
{ NULL, "disk", "sd", NULL, TYPE_DISK,
SCSI_DISK_MAJOR, 0, 0, 0, 1,
@@ -99,10 +119,21 @@ static int sd_open(struct inode * inode, struct file * filp)
int target;
target = DEVICE_NR(inode->i_rdev);
+ SCSI_LOG_HLQUEUE(1,printk("target=%d, max=%d\n", target, sd_template.dev_max));
+
if(target >= sd_template.dev_max || !rscsi_disks[target].device)
return -ENXIO; /* No such device */
/*
+ * If the device is in error recovery, wait until it is done.
+ * If the device is offline, then disallow any access to it.
+ */
+ if( !scsi_block_when_processing_errors(rscsi_disks[target].device) )
+ {
+ return -ENXIO;
+ }
+
+ /*
* Make sure that only one process can do a check_change_disk at one time.
* This is also used to lock out further access when the partition table
* is being re-read.
@@ -129,6 +160,16 @@ static int sd_open(struct inode * inode, struct file * filp)
}
/*
+ * It is possible that the disk changing stuff resulted in the device being taken
+ * offline. If this is the case, report this to the user, and don't pretend that
+ * the open actually succeeded.
+ */
+ if( !rscsi_disks[target].device->online )
+ {
+ return -ENXIO;
+ }
+
+ /*
* See if we are requesting a non-existent partition. Do this
* after checking for disk change.
*/
@@ -222,14 +263,18 @@ static void sd_geninit (struct gendisk *ignored)
static void rw_intr (Scsi_Cmnd *SCpnt)
{
int result = SCpnt->result;
+ char nbuff[6];
int this_count = SCpnt->bufflen >> 9;
int good_sectors = (result == 0 ? this_count : 0);
int block_sectors = 1;
-#ifdef DEBUG
- printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.rq_dev),
- SCpnt->host->host_no, result);
-#endif
+ sd_devname(MINOR(SCpnt->request.rq_dev) >> 4, nbuff);
+
+ SCSI_LOG_HLCOMPLETE(1,printk("%s : rw_intr(%d, %x [%x %x])\n", nbuff,
+ SCpnt->host->host_no,
+ result,
+ SCpnt->sense_buffer[0],
+ SCpnt->sense_buffer[2]));
/*
Handle MEDIUM ERRORs that indicate partial success. Since this is a
@@ -276,20 +321,21 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
if (good_sectors > 0) {
-#ifdef DEBUG
- printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.rq_dev),
- SCpnt->request.nr_sectors);
- printk("use_sg is %d\n ",SCpnt->use_sg);
-#endif
+ SCSI_LOG_HLCOMPLETE(1,printk("%s : %ld sectors remain.\n", nbuff,
+ SCpnt->request.nr_sectors));
+ SCSI_LOG_HLCOMPLETE(1,printk("use_sg is %d\n ",SCpnt->use_sg));
+
if (SCpnt->use_sg) {
struct scatterlist * sgpnt;
int i;
sgpnt = (struct scatterlist *) SCpnt->buffer;
for(i=0; i<SCpnt->use_sg; i++) {
-#ifdef DEBUG
- printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address,
- sgpnt[i].length);
+
+#if 0
+ SCSI_LOG_HLCOMPLETE(3,printk(":%p %p %d\n",sgpnt[i].alt_address, sgpnt[i].address,
+ sgpnt[i].length));
#endif
+
if (sgpnt[i].alt_address) {
if (SCpnt->request.cmd == READ)
memcpy(sgpnt[i].alt_address, sgpnt[i].address,
@@ -302,10 +348,10 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
scsi_free(SCpnt->buffer, SCpnt->sglist_len);
} else {
if (SCpnt->buffer != SCpnt->request.buffer) {
-#ifdef DEBUG
- printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
- SCpnt->bufflen);
-#endif
+ SCSI_LOG_HLCOMPLETE(3,printk("nosg: %p %p %d\n",
+ SCpnt->request.buffer, SCpnt->buffer,
+ SCpnt->bufflen));
+
if (SCpnt->request.cmd == READ)
memcpy(SCpnt->request.buffer, SCpnt->buffer,
SCpnt->bufflen);
@@ -323,10 +369,9 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
if (!SCpnt->request.bh)
{
-#ifdef DEBUG
- printk("sd%c : handling page request, no buffer\n",
- 'a' + MINOR(SCpnt->request.rq_dev));
-#endif
+ SCSI_LOG_HLCOMPLETE(2,printk("%s : handling page request, no buffer\n",
+ nbuff));
+
/*
* The SCpnt->request.nr_sectors field is always done in
* 512 byte sectors, even if this really isn't the case.
@@ -351,20 +396,18 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
int i;
sgpnt = (struct scatterlist *) SCpnt->buffer;
for(i=0; i<SCpnt->use_sg; i++) {
-#ifdef DEBUG
- printk("err: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
- SCpnt->bufflen);
-#endif
+ SCSI_LOG_HLCOMPLETE(3,printk("err: %p %p %d\n",
+ SCpnt->request.buffer, SCpnt->buffer,
+ SCpnt->bufflen));
if (sgpnt[i].alt_address) {
scsi_free(sgpnt[i].address, sgpnt[i].length);
}
}
scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */
} else {
-#ifdef DEBUG
- printk("nosgerr: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
- SCpnt->bufflen);
-#endif
+ SCSI_LOG_HLCOMPLETE(2,printk("nosgerr: %p %p %d\n",
+ SCpnt->request.buffer, SCpnt->buffer,
+ SCpnt->bufflen));
if (SCpnt->buffer != SCpnt->request.buffer)
scsi_free(SCpnt->buffer, SCpnt->bufflen);
}
@@ -473,11 +516,11 @@ static void do_sd_request (void)
unsigned long flags;
int flag = 0;
- save_flags(flags);
while (1==1){
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
+
if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
return;
}
@@ -485,6 +528,18 @@ static void do_sd_request (void)
SDev = rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device;
/*
+ * If the host for this device is in error recovery mode, don't
+ * do anything at all here. When the host leaves error recovery
+ * mode, it will automatically restart things and start queueing
+ * commands again.
+ */
+ if( SDev->host->in_recovery )
+ {
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+
+ /*
* I am not sure where the best place to do this is. We need
* to hook in a place where we are likely to come if in user
* space.
@@ -495,10 +550,12 @@ static void do_sd_request (void)
* We need to relock the door, but we might
* be in an interrupt handler. Only do this
* from user space, since we do not want to
- * sleep from an interrupt.
+ * sleep from an interrupt. FIXME(eric) - do this
+ * from the kernel error handling thred.
*/
if( SDev->removable && !in_interrupt() )
{
+ spin_unlock_irqrestore(&io_request_lock, flags);
scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
/* scsi_ioctl may allow CURRENT to change, so start over. */
SDev->was_reset = 0;
@@ -507,21 +564,21 @@ static void do_sd_request (void)
SDev->was_reset = 0;
}
- /* We have to be careful here. allocate_device will get a free pointer,
+ /* We have to be careful here. scsi_allocate_device will get a free pointer,
* but there is no guarantee that it is queueable. In normal usage,
* we want to call this, because other types of devices may have the
* host all tied up, and we want to make sure that we have at least
* one request pending for this type of device. We can also come
* through here while servicing an interrupt, because of the need to
- * start another command. If we call allocate_device more than once,
+ * start another command. If we call scsi_allocate_device more than once,
* then the system can wedge if the command is not queueable. The
- * request_queueable function is safe because it checks to make sure
+ * scsi_request_queueable function is safe because it checks to make sure
* that the host is able to take another command before it returns
* a pointer.
*/
if (flag++ == 0)
- SCpnt = allocate_device(&CURRENT,
+ SCpnt = scsi_allocate_device(&CURRENT,
rscsi_disks[DEVICE_NR(CURRENT->rq_dev)].device, 0);
else SCpnt = NULL;
@@ -530,7 +587,7 @@ static void do_sd_request (void)
* Using a "sti()" gets rid of the latency problems but causes
* race conditions and crashes.
*/
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
/* This is a performance enhancement. We dig down into the request
* list and try to find a queueable request (i.e. device not busy,
@@ -539,15 +596,19 @@ static void do_sd_request (void)
* one disk drive. We want to have the interrupts off when monkeying
* with the request list, because otherwise the kernel might try to
* slip in a request in between somewhere.
+ *
+ * FIXME(eric) - this doesn't belong at this level. The device code in
+ * ll_rw_blk.c should know how to dig down into the device queue to
+ * figure out what it can deal with, and what it can't. Consider
+ * possibility of pulling entire queue down into scsi layer.
*/
-
if (!SCpnt && sd_template.nr_dev > 1){
struct request *req1;
req1 = NULL;
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
req = CURRENT;
while(req){
- SCpnt = request_queueable(req,
+ SCpnt = scsi_request_queueable(req,
rscsi_disks[DEVICE_NR(req->rq_dev)].device);
if(SCpnt) break;
req1 = req;
@@ -559,7 +620,7 @@ static void do_sd_request (void)
else
req1->next = req->next;
}
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
}
if (!SCpnt) return; /* Could not find anything to do */
@@ -573,6 +634,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
{
int dev, devm, block, this_count;
unsigned char cmd[10];
+ char nbuff[6];
int bounce_size, contiguous;
int max_sg;
struct buffer_head * bh, *bhp;
@@ -591,15 +653,16 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
block = SCpnt->request.sector;
this_count = 0;
-#ifdef DEBUG
- printk("Doing sd request, dev = %d, block = %d\n", devm, block);
-#endif
+ SCSI_LOG_HLQUEUE(1,printk("Doing sd request, dev = %d, block = %d\n", devm, block));
if (devm >= (sd_template.dev_max << 4) ||
!rscsi_disks[dev].device ||
+ !rscsi_disks[dev].device->online ||
block + SCpnt->request.nr_sectors > sd[devm].nr_sects)
{
+ SCSI_LOG_HLQUEUE(2,printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));
SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+ SCSI_LOG_HLQUEUE(2,printk("Retry with 0x%p\n", SCpnt));
goto repeat;
}
@@ -616,10 +679,9 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
goto repeat;
}
-#ifdef DEBUG
- printk("sd%c : real dev = /dev/sd%c, block = %d\n",
- 'a' + devm, dev, block);
-#endif
+ sd_devname(devm, nbuff);
+ SCSI_LOG_HLQUEUE(2,printk("%s : real dev = /dev/%d, block = %d\n",
+ nbuff, dev, block));
/*
* If we have a 1K hardware sectorsize, prevent access to single
@@ -702,7 +764,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
SCpnt->use_sg = 0;
} else if (SCpnt->host->sg_tablesize == 0 ||
- (need_isa_buffer && dma_free_sectors <= 10)) {
+ (scsi_need_isa_buffer && scsi_dma_free_sectors <= 10)) {
/* Case of host adapter that cannot scatter-gather. We also
* come here if we are running low on DMA buffer memory. We set
@@ -712,8 +774,8 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
* we have no choice but to panic.
*/
if (SCpnt->host->sg_tablesize != 0 &&
- need_isa_buffer &&
- dma_free_sectors <= 10)
+ scsi_need_isa_buffer &&
+ scsi_dma_free_sectors <= 10)
printk("Warning: SCSI DMA buffer space running low. Using non scatter-gather I/O.\n");
this_count = SCpnt->request.current_nr_sectors;
@@ -787,7 +849,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
* easier to control usage here. In other places we might
* have a more pressing need, and we would be screwed if
* we ran out */
- if(dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
+ if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
sgpnt[count].address = NULL;
} else {
sgpnt[count].address =
@@ -832,7 +894,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
!sgpnt[count].alt_address) continue;
if(!sgpnt[count].alt_address) {count--; continue; }
- if(dma_free_sectors > 10)
+ if(scsi_dma_free_sectors > 10)
tmp = (char *) scsi_malloc(sgpnt[count].length
+ bhp->b_size);
else {
@@ -861,7 +923,7 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
> SCpnt->host->sg_tablesize){
bh = SCpnt->request.bh;
printk("Use sg, count %d %x %d\n",
- SCpnt->use_sg, count, dma_free_sectors);
+ SCpnt->use_sg, count, scsi_dma_free_sectors);
printk("maxsg = %x, counted = %d this_count = %d\n",
max_sg, counted, this_count);
while(bh){
@@ -903,12 +965,10 @@ static void requeue_sd_request (Scsi_Cmnd * SCpnt)
memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
}
}
-#ifdef DEBUG
- printk("sd%c : %s %d/%d 512 byte blocks.\n",
- 'a' + devm,
- (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
- this_count, SCpnt->request.nr_sectors);
-#endif
+ SCSI_LOG_HLQUEUE(2,printk("%s : %s %d/%ld 512 byte blocks.\n",
+ nbuff,
+ (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+ this_count, SCpnt->request.nr_sectors));
cmd[1] = (SCpnt->lun << 5) & 0xe0;
@@ -989,6 +1049,20 @@ static int check_scsidisk_media_change(kdev_t full_dev){
if(!rscsi_disks[target].device->removable) return 0;
+ /*
+ * If the device is offline, don't send any commands - just pretend as if
+ * the command failed. If the device ever comes back online, we can deal with
+ * it then. It is only because of unrecoverable errors that we would ever
+ * take a device offline in the first place.
+ */
+ if( rscsi_disks[target].device->online == FALSE )
+ {
+ rscsi_disks[target].ready = 0;
+ rscsi_disks[target].device->changed = 1;
+ return 1; /* This will force a flush, if called from
+ * check_disk_change */
+ }
+
inode.i_rdev = full_dev; /* This is all we really need here */
retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
@@ -1031,17 +1105,32 @@ static void sd_init_done (Scsi_Cmnd * SCpnt)
static int sd_init_onedisk(int i)
{
unsigned char cmd[10];
+ char nbuff[6];
unsigned char *buffer;
unsigned long spintime;
int the_result, retries;
Scsi_Cmnd * SCpnt;
+ /*
+ * Get the name of the disk, in case we need to log it somewhere.
+ */
+ sd_devname(i, nbuff);
+
+ /*
+ * If the device is offline, don't try and read capacity or any of the other
+ * nicities.
+ */
+ if( rscsi_disks[i].device->online == FALSE )
+ {
+ return i;
+ }
+
/* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
* considered a fatal error, and many devices report such an error
* just after a scsi bus reset.
*/
- SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1);
+ SCpnt = scsi_allocate_device(NULL, rscsi_disks[i].device, 1);
buffer = (unsigned char *) scsi_malloc(512);
spintime = 0;
@@ -1069,6 +1158,7 @@ static int sd_init_onedisk(int i)
512, sd_init_done, SD_TIMEOUT,
MAX_RETRIES);
down(&sem);
+ SCpnt->request.sem = NULL;
}
the_result = SCpnt->result;
@@ -1084,7 +1174,7 @@ static int sd_init_onedisk(int i)
SCpnt->sense_buffer[2] == NOT_READY) {
unsigned long time1;
if(!spintime){
- printk( "sd%c: Spinning up disk...", 'a' + i );
+ printk( "%s: Spinning up disk...", nbuff );
cmd[0] = START_STOP;
cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
cmd[1] |= 1; /* Return immediately */
@@ -1104,6 +1194,7 @@ static int sd_init_onedisk(int i)
512, sd_init_done, SD_TIMEOUT,
MAX_RETRIES);
down(&sem);
+ SCpnt->request.sem = NULL;
}
spintime = jiffies;
@@ -1141,6 +1232,7 @@ static int sd_init_onedisk(int i)
8, sd_init_done, SD_TIMEOUT,
MAX_RETRIES);
down(&sem); /* sleep until it is ready */
+ SCpnt->request.sem = NULL;
}
the_result = SCpnt->result;
@@ -1148,12 +1240,6 @@ static int sd_init_onedisk(int i)
} while(the_result && retries);
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
-
- wake_up(&SCpnt->device->device_wait);
-
- /* Wake up a process waiting for device */
-
/*
* The SCSI standard says:
* "READ CAPACITY is necessary for self configuring software"
@@ -1170,22 +1256,22 @@ static int sd_init_onedisk(int i)
if (the_result)
{
- printk ("sd%c : READ CAPACITY failed.\n"
- "sd%c : status = %x, message = %02x, host = %d, driver = %02x \n",
- 'a' + i, 'a' + i,
+ printk ("%s : READ CAPACITY failed.\n"
+ "%s : status = %x, message = %02x, host = %d, driver = %02x \n",
+ nbuff, nbuff,
status_byte(the_result),
msg_byte(the_result),
host_byte(the_result),
driver_byte(the_result)
);
if (driver_byte(the_result) & DRIVER_SENSE)
- printk("sd%c : extended sense code = %1x \n",
- 'a' + i, SCpnt->sense_buffer[2] & 0xf);
+ printk("%s : extended sense code = %1x \n",
+ nbuff, SCpnt->sense_buffer[2] & 0xf);
else
- printk("sd%c : sense not available. \n", 'a' + i);
+ printk("%s : sense not available. \n", nbuff);
- printk("sd%c : block size assumed to be 512 bytes, disk size 1GB. \n",
- 'a' + i);
+ printk("%s : block size assumed to be 512 bytes, disk size 1GB. \n",
+ nbuff);
rscsi_disks[i].capacity = 0x1fffff;
rscsi_disks[i].sector_size = 512;
@@ -1213,7 +1299,7 @@ static int sd_init_onedisk(int i)
if (rscsi_disks[i].sector_size == 0) {
rscsi_disks[i].sector_size = 512;
- printk("sd%c : sector size 0 reported, assuming 512.\n", 'a' + i);
+ printk("%s : sector size 0 reported, assuming 512.\n", nbuff);
}
@@ -1222,8 +1308,8 @@ static int sd_init_onedisk(int i)
rscsi_disks[i].sector_size != 2048 &&
rscsi_disks[i].sector_size != 256)
{
- printk ("sd%c : unsupported sector size %d.\n",
- 'a' + i, rscsi_disks[i].sector_size);
+ printk ("%s : unsupported sector size %d.\n",
+ nbuff, rscsi_disks[i].sector_size);
if(rscsi_disks[i].device->removable){
rscsi_disks[i].capacity = 0;
} else {
@@ -1231,6 +1317,12 @@ static int sd_init_onedisk(int i)
rscsi_disks[i].device = NULL;
sd_template.nr_dev--;
sd_gendisk.nr_real--;
+
+ /* Wake up a process waiting for device */
+ wake_up(&SCpnt->device->device_wait);
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
+
return i;
}
}
@@ -1268,9 +1360,9 @@ static int sd_init_onedisk(int i)
m = (mb + 50) / 100;
sz_quot = m / 10;
sz_rem = m - (10 * sz_quot);
- printk ("SCSI device sd%c: hdwr sector= %d bytes."
+ printk ("SCSI device %s: hdwr sector= %d bytes."
" Sectors= %d [%d MB] [%d.%1d GB]\n",
- i+'a', hard_sector, rscsi_disks[i].capacity,
+ nbuff, hard_sector, rscsi_disks[i].capacity,
mb, sz_quot, sz_rem);
}
if(rscsi_disks[i].sector_size == 2048)
@@ -1315,23 +1407,27 @@ static int sd_init_onedisk(int i)
512, sd_init_done, SD_TIMEOUT,
MAX_RETRIES);
down(&sem);
+ SCpnt->request.sem = NULL;
}
the_result = SCpnt->result;
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
- wake_up(&SCpnt->device->device_wait);
if ( the_result ) {
- printk ("sd%c: test WP failed, assume Write Protected\n",i+'a');
+ printk ("%s: test WP failed, assume Write Protected\n",nbuff);
rscsi_disks[i].write_prot = 1;
} else {
rscsi_disks[i].write_prot = ((buffer[2] & 0x80) != 0);
- printk ("sd%c: Write Protect is %s\n",i+'a',
+ printk ("%s: Write Protect is %s\n",nbuff,
rscsi_disks[i].write_prot ? "on" : "off");
}
} /* check for write protect */
+ /* Wake up a process waiting for device */
+ wake_up(&SCpnt->device->device_wait);
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
+
rscsi_disks[i].ten = 1;
rscsi_disks[i].remap = 1;
scsi_free(buffer, 512);
@@ -1400,12 +1496,19 @@ static int sd_init()
static void sd_finish()
{
+ struct gendisk *gendisk;
int i;
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
- sd_gendisk.next = gendisk_head;
- gendisk_head = &sd_gendisk;
+ for (gendisk = gendisk_head; gendisk != NULL; gendisk = gendisk->next)
+ if (gendisk == &sd_gendisk)
+ break;
+ if (gendisk == NULL)
+ {
+ sd_gendisk.next = gendisk_head;
+ gendisk_head = &sd_gendisk;
+ }
for (i = 0; i < sd_template.dev_max; ++i)
if (!rscsi_disks[i].capacity &&
@@ -1435,11 +1538,13 @@ static void sd_finish()
}
static int sd_detect(Scsi_Device * SDp){
+ char nbuff[6];
if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
- printk("Detected scsi %sdisk sd%c at scsi%d, channel %d, id %d, lun %d\n",
+ sd_devname(sd_template.dev_noticed++, nbuff);
+ printk("Detected scsi %sdisk %s at scsi%d, channel %d, id %d, lun %d\n",
SDp->removable ? "removable " : "",
- 'a'+ (sd_template.dev_noticed++),
+ nbuff,
SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
return 1;
@@ -1509,7 +1614,7 @@ int revalidate_scsidisk(kdev_t dev, int maxusage){
for (i=max_p - 1; i >=0 ; i--) {
int minor = start+i;
kdev_t devi = MKDEV(MAJOR_NR, minor);
- struct super_block *sb = get_super(devi);
+ struct super_block *sb = get_super(devi);
sync_dev(devi);
if (sb) invalidate_inodes(sb);
invalidate_buffers(devi);
@@ -1562,7 +1667,7 @@ static void sd_detach(Scsi_Device * SDp)
for (i=max_p - 1; i >=0 ; i--) {
int minor = start+i;
kdev_t devi = MKDEV(MAJOR_NR, minor);
- struct super_block *sb = get_super(devi);
+ struct super_block *sb = get_super(devi);
sync_dev(devi);
if (sb) invalidate_inodes(sb);
invalidate_buffers(devi);
diff --git a/drivers/scsi/sd_ioctl.c b/drivers/scsi/sd_ioctl.c
index 070e6423e..2f771552a 100644
--- a/drivers/scsi/sd_ioctl.c
+++ b/drivers/scsi/sd_ioctl.c
@@ -25,9 +25,22 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
kdev_t dev = inode->i_rdev;
int error;
struct Scsi_Host * host;
+ Scsi_Device * SDev;
int diskinfo[4];
struct hd_geometry *loc = (struct hd_geometry *) arg;
+ SDev = rscsi_disks[MINOR(dev) >> 4].device;
+ /*
+ * If we are in the middle of error recovery, don't let anyone
+ * else try and use this device. Also, if error recovery fails, it
+ * may try and take the device offline, in which case all further
+ * access to the device is prohibited.
+ */
+ if( !scsi_block_when_processing_errors(SDev) )
+ {
+ return -ENODEV;
+ }
+
switch (cmd) {
case HDIO_GETGEO: /* Return BIOS disk parameters */
if (!loc) return -EINVAL;
@@ -91,6 +104,9 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
case BLKRRPART: /* Re-read partition tables */
return revalidate_scsidisk(dev, 1);
+
+ RO_IOCTLS(dev, arg);
+
default:
return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg);
}
diff --git a/drivers/scsi/seagate.h b/drivers/scsi/seagate.h
index f339ea612..2d07fd9a7 100644
--- a/drivers/scsi/seagate.h
+++ b/drivers/scsi/seagate.h
@@ -27,13 +27,18 @@ int seagate_st0x_reset(Scsi_Cmnd *, unsigned int);
#include <linux/kdev_t.h>
int seagate_st0x_biosparam(Disk *, kdev_t, int*);
-#define SEAGATE_ST0X { NULL, NULL, NULL, NULL, \
- NULL, seagate_st0x_detect, \
- NULL, \
- seagate_st0x_info, seagate_st0x_command, \
- seagate_st0x_queue_command, seagate_st0x_abort, \
- seagate_st0x_reset, NULL, seagate_st0x_biosparam, \
- 1, 7, SG_ALL, 1, 0, 0, DISABLE_CLUSTERING}
+#define SEAGATE_ST0X { detect: seagate_st0x_detect, \
+ info: seagate_st0x_info, \
+ command: seagate_st0x_command, \
+ queuecommand: seagate_st0x_queue_command, \
+ abort: seagate_st0x_abort, \
+ reset: seagate_st0x_reset, \
+ bios_param: seagate_st0x_biosparam, \
+ can_queue: 1, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING}
#endif /* ASM */
#endif /* _SEAGATE_H */
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index a94fb569c..1d14136fb 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -67,10 +67,22 @@ static void sg_free(char *buff,int size);
static int sg_ioctl(struct inode * inode,struct file * file,
unsigned int cmd_in, unsigned long arg)
{
- int result;
- int dev = MINOR(inode->i_rdev);
+ int dev = MINOR(inode->i_rdev);
+ int result;
+
if ((dev<0) || (dev>=sg_template.dev_max))
return -ENXIO;
+
+ /*
+ * If we are in the middle of error recovery, then don't allow any
+ * access to this device. Also, error recovery *may* have taken the
+ * device offline, in which case all further access is prohibited.
+ */
+ if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+ {
+ return -ENXIO;
+ }
+
switch(cmd_in)
{
case SG_SET_TIMEOUT:
@@ -92,6 +104,12 @@ static int sg_open(struct inode * inode, struct file * filp)
int flags=filp->f_flags;
if (dev>=sg_template.dev_max || !scsi_generics[dev].device)
return -ENXIO;
+
+ if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+ {
+ return -ENXIO;
+ }
+
if (O_RDWR!=(flags & O_ACCMODE))
return -EACCES;
@@ -209,6 +227,17 @@ static ssize_t sg_read(struct file *filp, char *buf,
unsigned long flags;
struct scsi_generic *device=&scsi_generics[dev];
+ /*
+ * If we are in the middle of error recovery, don't let anyone
+ * else try and use this device. Also, if error recovery fails, it
+ * may try and take the device offline, in which case all further
+ * access to the device is prohibited.
+ */
+ if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+ {
+ return -ENXIO;
+ }
+
if (ppos != &filp->f_pos) {
/* FIXME: Hmm. Seek to the right place, or fail? */
}
@@ -278,7 +307,8 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
if (!device->pending)
{
printk("unexpected done for sg %d\n",dev);
- SCpnt->request.rq_status = RQ_INACTIVE;
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
return;
}
@@ -325,7 +355,8 @@ static void sg_command_done(Scsi_Cmnd * SCpnt)
* result.
*/
device->complete=1;
- SCpnt->request.rq_status = RQ_INACTIVE;
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
wake_up(&scsi_generics[dev].read_wait);
}
@@ -342,6 +373,17 @@ static ssize_t sg_write(struct file *filp, const char *buf,
unsigned char opcode;
Scsi_Cmnd * SCpnt;
+ /*
+ * If we are in the middle of error recovery, don't let anyone
+ * else try and use this device. Also, if error recovery fails, it
+ * may try and take the device offline, in which case all further
+ * access to the device is prohibited.
+ */
+ if( !scsi_block_when_processing_errors(scsi_generics[dev].device) )
+ {
+ return -ENXIO;
+ }
+
if (ppos != &filp->f_pos) {
/* FIXME: Hmm. Seek to the right place, or fail? */
}
@@ -444,7 +486,7 @@ static ssize_t sg_write(struct file *filp, const char *buf,
* Grab a device pointer for the device we want to talk to. If we
* don't want to block, just return with the appropriate message.
*/
- if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
+ if (!(SCpnt=scsi_allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
{
device->pending=0;
wake_up(&device->write_wait);
@@ -505,8 +547,8 @@ static unsigned int sg_poll(struct file *file, poll_table * wait)
struct scsi_generic *device = &scsi_generics[dev];
unsigned int mask = 0;
- poll_wait(&scsi_generics[dev].read_wait, wait);
- poll_wait(&scsi_generics[dev].write_wait, wait);
+ poll_wait(file, &scsi_generics[dev].read_wait, wait);
+ poll_wait(file, &scsi_generics[dev].write_wait, wait);
if(device->pending && device->complete)
mask |= POLLIN | POLLRDNORM;
if(!device->pending)
diff --git a/drivers/scsi/sgiwd93.c b/drivers/scsi/sgiwd93.c
index 599f981b4..ce448de91 100644
--- a/drivers/scsi/sgiwd93.c
+++ b/drivers/scsi/sgiwd93.c
@@ -1,4 +1,4 @@
-/* $Id: sgiwd93.c,v 1.7 1996/07/23 09:00:16 dm Exp $
+/* $Id: sgiwd93.c,v 1.4 1998/03/04 10:49:47 ralf Exp $
* sgiwd93.c: SGI WD93 scsi driver.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -258,3 +258,13 @@ Scsi_Host_Template driver_template = SGIWD93_SCSI;
#include "scsi_module.c"
#endif
+
+int sgiwd93_release(struct Scsi_Host *instance)
+{
+#ifdef MODULE
+ free_irq(1, sgiwd93_intr);
+ free_page(KSEG0ADDR(hdata->dma_bounce_buffer));
+ wd33c93_release();
+#endif
+ return 1;
+}
diff --git a/drivers/scsi/sgiwd93.h b/drivers/scsi/sgiwd93.h
index 83b5a29c6..badcebb7e 100644
--- a/drivers/scsi/sgiwd93.h
+++ b/drivers/scsi/sgiwd93.h
@@ -1,4 +1,4 @@
-/* $Id: sgiwd93.h,v 1.4 1996/07/14 06:43:13 dm Exp $
+/* $Id: sgiwd93.h,v 1.2 1997/12/01 18:00:19 ralf Exp $
* sgiwd93.h: SGI WD93 scsi definitions.
*
* Copyright (C) 1996 David S. Miller (dm@engr.sgi.com)
@@ -19,6 +19,7 @@
#endif
int sgiwd93_detect(Scsi_Host_Template *);
+int sgiwd93_release(struct Scsi_Host *instance);
const char *wd33c93_info(void);
int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int wd33c93_abort(Scsi_Cmnd *);
@@ -26,27 +27,17 @@ int wd33c93_reset(Scsi_Cmnd *, unsigned int);
extern struct proc_dir_entry proc_scsi_sgiwd93;
-#define SGIWD93_SCSI {/* next */ NULL, \
- /* usage_count */ NULL, \
- /* proc_dir_entry */ &proc_scsi_sgiwd93, \
- /* proc_info */ NULL, \
- /* name */ "SGI WD93", \
- /* detect */ sgiwd93_detect, \
- /* release */ NULL, \
- /* info */ NULL, \
- /* command */ NULL, \
- /* queuecommand */ wd33c93_queuecommand, \
- /* abort */ wd33c93_abort, \
- /* reset */ wd33c93_reset, \
- /* slave_attach */ NULL, \
- /* bios_param */ NULL, \
- /* can_queue */ CAN_QUEUE, \
- /* this_id */ 7, \
- /* sg_tablesize */ SG_ALL, \
- /* cmd_per_lun */ CMD_PER_LUN, \
- /* present */ 0, \
- /* unchecked_isa_dma */ 0, \
- /* use_clustering */ DISABLE_CLUSTERING \
-}
+#define SGIWD93_SCSI {proc_dir: &proc_scsi_sgiwd93, \
+ name: "GVP Series II SCSI", \
+ detect: sgiwd93_detect, \
+ release: sgiwd93_release, \
+ queuecommand: wd33c93_queuecommand, \
+ abort: wd33c93_abort, \
+ reset: wd33c93_reset, \
+ can_queue: CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: CMD_PER_LUN, \
+ use_clustering: DISABLE_CLUSTERING }
#endif /* !(_SGIWD93_H) */
diff --git a/drivers/scsi/sparc_esp.h b/drivers/scsi/sparc_esp.h
index 6fd09b2e9..4cb20d27e 100644
--- a/drivers/scsi/sparc_esp.h
+++ b/drivers/scsi/sparc_esp.h
@@ -21,33 +21,22 @@ extern int esp_proc_info(char *buffer, char **start, off_t offset, int length,
extern struct proc_dir_entry proc_scsi_esp;
-
#define DMA_PORTS_P (dregs->cond_reg & DMA_INT_ENAB)
-
-
-#define SCSI_SPARC_ESP { \
-/* struct SHT *next */ NULL, \
-/* long *usage_count */ NULL, \
-/* struct proc_dir_entry *proc_dir */ &proc_scsi_esp, \
-/* int (*proc_info)(char *, char **, off_t, int, int, int) */ &esp_proc_info, \
-/* const char *name */ "Sun ESP 100/100a/200", \
-/* int detect(struct SHT *) */ esp_detect, \
-/* int release(struct Scsi_Host *) */ NULL, \
-/* const char *info(struct Scsi_Host *) */ esp_info, \
-/* int command(Scsi_Cmnd *) */ esp_command, \
-/* int queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)) */ esp_queue, \
-/* int abort(Scsi_Cmnd *) */ esp_abort, \
-/* int reset(Scsi_Cmnd *, int) */ esp_reset, \
-/* int slave_attach(int, int) */ NULL, \
-/* int bios_param(Disk *, kdev_t, int[]) */ NULL, \
-/* int can_queue */ 7, \
-/* int this_id */ 7, \
-/* short unsigned int sg_tablesize */ SG_ALL, \
-/* short cmd_per_lun */ 1, \
-/* unsigned char present */ 0, \
-/* unsigned unchecked_isa_dma:1 */ 0, \
-/* unsigned use_clustering:1 */ DISABLE_CLUSTERING, }
+#define SCSI_JAZZ_ESP { \
+ proc_dir: &proc_scsi_esp, \
+ proc_info: &esp_proc_info, \
+ name: "Sun ESP 100/100a/200", \
+ detect: jazz_esp_detect, \
+ info: esp_info, \
+ command: esp_command, \
+ queuecommand: esp_queue, \
+ abort: esp_abort, \
+ reset: esp_reset, \
+ can_queue: 7, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: 1, \
+ use_clustering: DISABLE_CLUSTERING, }
#endif /* !(_SPARC_ESP_H) */
-
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 2504b30a5..e5d3e830a 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -32,7 +32,6 @@
#include <linux/errno.h>
#include <linux/cdrom.h>
#include <linux/interrupt.h>
-#include <linux/config.h>
#include <asm/system.h>
#include <asm/io.h>
@@ -385,6 +384,21 @@ static int sr_open(struct cdrom_device_info *cdi, int purpose)
{
check_disk_change(cdi->dev);
+ if( MINOR(cdi->dev) >= sr_template.dev_max
+ || !scsi_CDs[MINOR(cdi->dev)].device)
+ {
+ return -ENXIO; /* No such device */
+ }
+
+ /*
+ * If the device is in error recovery, wait until it is done.
+ * If the device is offline, then disallow any access to it.
+ */
+ if( !scsi_block_when_processing_errors(scsi_CDs[MINOR(cdi->dev)].device) )
+ {
+ return -ENXIO;
+ }
+
scsi_CDs[MINOR(cdi->dev)].device->access_count++;
if (scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module)
__MOD_INC_USE_COUNT(scsi_CDs[MINOR(cdi->dev)].device->host->hostt->module);
@@ -417,10 +431,10 @@ static void do_sr_request (void)
int flag = 0;
while (1==1){
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
+
if (CURRENT != NULL && CURRENT->rq_status == RQ_INACTIVE) {
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
return;
};
@@ -428,6 +442,18 @@ static void do_sr_request (void)
SDev = scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device;
+ /*
+ * If the host for this device is in error recovery mode, don't
+ * do anything at all here. When the host leaves error recovery
+ * mode, it will automatically restart things and start queueing
+ * commands again.
+ */
+ if( SDev->host->in_recovery )
+ {
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ return;
+ }
+
/*
* I am not sure where the best place to do this is. We need
* to hook in a place where we are likely to come if in user
@@ -443,7 +469,11 @@ static void do_sr_request (void)
*/
if( SDev->removable && !in_interrupt() )
{
+ spin_unlock_irqrestore(&io_request_lock, flags);
scsi_ioctl(SDev, SCSI_IOCTL_DOORLOCK, 0);
+ /* scsi_ioctl may allow CURRENT to change, so start over. */
+ SDev->was_reset = 0;
+ continue;
}
SDev->was_reset = 0;
}
@@ -460,10 +490,10 @@ static void do_sr_request (void)
}
if (flag++ == 0)
- SCpnt = allocate_device(&CURRENT,
+ SCpnt = scsi_allocate_device(&CURRENT,
scsi_CDs[DEVICE_NR(CURRENT->rq_dev)].device, 0);
else SCpnt = NULL;
- restore_flags(flags);
+ spin_unlock_irqrestore(&io_request_lock, flags);
/* This is a performance enhancement. We dig down into the request list and
* try to find a queueable request (i.e. device not busy, and host able to
@@ -475,24 +505,23 @@ static void do_sr_request (void)
if (!SCpnt && sr_template.nr_dev > 1){
struct request *req1;
req1 = NULL;
- save_flags(flags);
- cli();
+ spin_lock_irqsave(&io_request_lock, flags);
req = CURRENT;
while(req){
- SCpnt = request_queueable(req,
+ SCpnt = scsi_request_queueable(req,
scsi_CDs[DEVICE_NR(req->rq_dev)].device);
if(SCpnt) break;
req1 = req;
req = req->next;
- };
+ }
if (SCpnt && req->rq_status == RQ_INACTIVE) {
if (req == CURRENT)
CURRENT = CURRENT->next;
else
req1->next = req->next;
- };
- restore_flags(flags);
- };
+ }
+ spin_unlock_irqrestore(&io_request_lock, flags);
+ }
if (!SCpnt)
return; /* Could not find anything to do */
@@ -501,7 +530,7 @@ static void do_sr_request (void)
/* Queue command */
requeue_sr_request(SCpnt);
- }; /* While */
+ } /* While */
}
void requeue_sr_request (Scsi_Cmnd * SCpnt)
@@ -537,6 +566,13 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
goto repeat;
}
+ if( !scsi_CDs[dev].device->online )
+ {
+ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+ tries = 2;
+ goto repeat;
+ }
+
if (scsi_CDs[dev].device->changed) {
/*
* quietly refuse to do anything to a changed disc
@@ -583,8 +619,8 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
SCpnt->use_sg = 0;
if (SCpnt->host->sg_tablesize > 0 &&
- (!need_isa_buffer ||
- dma_free_sectors >= 10)) {
+ (!scsi_need_isa_buffer ||
+ scsi_dma_free_sectors >= 10)) {
struct buffer_head * bh;
struct scatterlist * sgpnt;
int count, this_count_max;
@@ -655,7 +691,7 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
/* We try to avoid exhausting the DMA pool, since it is easier
* to control usage here. In other places we might have a more
* pressing need, and we would be screwed if we ran out */
- if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
+ if(scsi_dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
sgpnt[count].address = NULL;
} else {
sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
@@ -728,7 +764,13 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2;
- if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten)
+ /*
+ * Note: The scsi standard says that READ_6 is *optional*, while
+ * READ_10 is mandatory. Thus there is no point in using
+ * READ_6.
+ */
+ if (scsi_CDs[dev].ten)
+
{
if (realcount > 0xffff)
{
@@ -821,8 +863,6 @@ static int sr_attach(Scsi_Device * SDp){
SDp->scsi_request_fn = do_sr_request;
scsi_CDs[i].device = SDp;
- sr_vendor_init(i);
-
sr_template.nr_dev++;
if(sr_template.nr_dev > sr_template.dev_max)
panic ("scsi_devices corrupt (sr)");
@@ -849,7 +889,7 @@ void get_sectorsize(int i){
Scsi_Cmnd * SCpnt;
buffer = (unsigned char *) scsi_malloc(512);
- SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1);
+ SCpnt = scsi_allocate_device(NULL, scsi_CDs[i].device, 1);
retries = 3;
do {
@@ -877,9 +917,10 @@ void get_sectorsize(int i){
} while(the_result && retries);
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
wake_up(&SCpnt->device->device_wait);
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
if (the_result) {
scsi_CDs[i].capacity = 0x1fffff;
@@ -952,13 +993,11 @@ void get_capabilities(int i){
if (-EINVAL == rc) {
/* failed, drive has'nt this mode page */
scsi_CDs[i].cdi.speed = 1;
- scsi_CDs[i].cdi.capacity = 1;
/* disable speed select, drive probably can't do this either */
scsi_CDs[i].cdi.mask |= CDC_SELECT_SPEED;
} else {
n = buffer[3]+4;
scsi_CDs[i].cdi.speed = ((buffer[n+8] << 8) + buffer[n+9])/176;
- scsi_CDs[i].cdi.capacity = 1;
scsi_CDs[i].readcd_known = 1;
scsi_CDs[i].readcd_cdda = buffer[n+5] & 0x01;
/* print some capability bits */
@@ -1051,7 +1090,9 @@ void sr_finish()
scsi_CDs[i].cdi.handle = &scsi_CDs[i];
scsi_CDs[i].cdi.dev = MKDEV(MAJOR_NR,i);
scsi_CDs[i].cdi.mask = 0;
+ scsi_CDs[i].cdi.capacity = 1;
get_capabilities(i);
+ sr_vendor_init(i);
sprintf(name, "sr%d", i);
strcpy(scsi_CDs[i].cdi.name, name);
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 265c7d04f..e864582b3 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -30,7 +30,7 @@ extern void get_sectorsize(int);
#define IOCTL_RETRIES 3
/* The CDROM is fairly slow, so we need a little extra time */
/* In fact, it is very slow if it has to spin up first */
-#define IOCTL_TIMEOUT 3000
+#define IOCTL_TIMEOUT 30*HZ
static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
{
@@ -51,11 +51,15 @@ static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
int sr_do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength, int quiet)
{
Scsi_Cmnd * SCpnt;
+ Scsi_Device * SDev;
int result, err = 0, retries = 0;
- SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
+ SDev = scsi_CDs[target].device;
+ SCpnt = scsi_allocate_device(NULL, scsi_CDs[target].device, 1);
retry:
+ if( !scsi_block_when_processing_errors(SDev) )
+ return -ENODEV;
{
struct semaphore sem = MUTEX_LOCKED;
SCpnt->request.sem = &sem;
@@ -63,12 +67,13 @@ retry:
(void *) sr_cmd, buffer, buflength, sr_ioctl_done,
IOCTL_TIMEOUT, IOCTL_RETRIES);
down(&sem);
+ SCpnt->request.sem = NULL;
}
result = SCpnt->result;
/* Minimal error checking. Ignore cases we know about, and report the rest. */
- if(driver_byte(result) != 0)
+ if(driver_byte(result) != 0) {
switch(SCpnt->sense_buffer[2] & 0xf) {
case UNIT_ATTENTION:
scsi_CDs[target].device->changed = 1;
@@ -85,9 +90,7 @@ retry:
printk(KERN_INFO "sr%d: CDROM not ready yet.\n", target);
if (retries++ < 10) {
/* sleep 2 sec and try again */
- current->state = TASK_INTERRUPTIBLE;
- current->timeout = jiffies + 200;
- schedule ();
+ scsi_sleep(2*HZ);
goto retry;
} else {
/* 20 secs are enouth? */
@@ -122,13 +125,14 @@ retry:
print_command(sr_cmd);
print_sense("sr", SCpnt);
err = -EIO;
- };
+ }
+ }
result = SCpnt->result;
- SCpnt->request.rq_status = RQ_INACTIVE; /* Deallocate */
- /* Wake up a process waiting for device */
+ /* Wake up a process waiting for device*/
wake_up(&SCpnt->device->device_wait);
-
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
return err;
}
@@ -186,7 +190,7 @@ int sr_disk_status(struct cdrom_device_info *cdi)
/* look for data tracks */
if (0 != (rc = sr_audio_ioctl(cdi, CDROMREADTOCHDR, &toc_h)))
return (rc == -ENOMEDIUM) ? CDS_NO_DISC : CDS_NO_INFO;
-
+
for (i = toc_h.cdth_trk0; i <= toc_h.cdth_trk1; i++) {
toc_e.cdte_track = i;
toc_e.cdte_format = CDROM_LBA;
@@ -799,6 +803,15 @@ int sr_dev_ioctl(struct cdrom_device_info *cdi,
RO_IOCTLS(cdi->dev,arg);
+ case BLKFLSBUF:
+ if(!suser())
+ return -EACCES;
+ if(!(cdi->dev))
+ return -EINVAL;
+ fsync_dev(cdi->dev);
+ invalidate_buffers(cdi->dev);
+ return 0;
+
default:
return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
}
diff --git a/drivers/scsi/sr_vendor.c b/drivers/scsi/sr_vendor.c
index 7fec8fea1..34220ca4d 100644
--- a/drivers/scsi/sr_vendor.c
+++ b/drivers/scsi/sr_vendor.c
@@ -3,7 +3,7 @@
* vendor-specific code for SCSI CD-ROM's goes here.
*
* This is needed becauce most of the new features (multisession and
- * the like) are to new to be included into the SCSI-II standard (to
+ * the like) are too new to be included into the SCSI-II standard (to
* be exact: there is'nt anything in my draft copy).
*
* Aug 1997: Ha! Got a SCSI-3 cdrom spec across my fingers. SCSI-3 does
@@ -56,8 +56,7 @@
#define VENDOR_NEC 2
#define VENDOR_TOSHIBA 3
-#define VENDOR_HP_4020 4 /* HP 4xxx writers, others too ?? */
-#define VENDOR_HP_6020 5 /* HP 6020 writers */
+#define VENDOR_WRITER 4 /* pre-scsi3 writers */
#define VENDOR_ID (scsi_CDs[minor].vendor)
@@ -72,20 +71,25 @@ sr_vendor_init(int minor)
/* default */
VENDOR_ID = VENDOR_SCSI3;
+ if (scsi_CDs[minor].readcd_known)
+ /* this is true for scsi3/mmc drives - no more checks */
+ return;
- if ((!strncmp(vendor,"HP",2) || !strncmp(vendor,"PHILIPS",7)) &&
- scsi_CDs[minor].device->type == TYPE_WORM) {
- if (!strncmp(model,"CD-Writer 6020",14))
- VENDOR_ID = VENDOR_HP_6020;
- else
- VENDOR_ID = VENDOR_HP_4020;
+ if (scsi_CDs[minor].device->type == TYPE_WORM) {
+ VENDOR_ID = VENDOR_WRITER;
} else if (!strncmp (vendor, "NEC", 3)) {
VENDOR_ID = VENDOR_NEC;
if (!strncmp (model,"CD-ROM DRIVE:25", 15) ||
!strncmp (model,"CD-ROM DRIVE:36", 15) ||
!strncmp (model,"CD-ROM DRIVE:83", 15) ||
- !strncmp (model,"CD-ROM DRIVE:84 ",16))
+ !strncmp (model,"CD-ROM DRIVE:84 ",16)
+#if 0
+ /* my NEC 3x returns the read-raw data if a read-raw
+ is followed by a read for the same sector - aeb */
+ || !strncmp (model,"CD-ROM DRIVE:500",16)
+#endif
+ )
/* these can't handle multisession, may hang */
scsi_CDs[minor].cdi.mask |= CDC_MULTI_SESSION;
@@ -147,10 +151,10 @@ sr_set_blocklength(int minor, int blocklength)
int sr_cd_check(struct cdrom_device_info *cdi)
{
- unsigned long sector,min,sec,frame;
+ unsigned long sector;
unsigned char *buffer; /* the buffer for the ioctl */
unsigned char cmd[12]; /* the scsi-command */
- int rc,is_xa,no_multi,minor;
+ int rc,no_multi,minor;
minor = MINOR(cdi->dev);
if (scsi_CDs[minor].cdi.mask & CDC_MULTI_SESSION)
@@ -160,7 +164,6 @@ int sr_cd_check(struct cdrom_device_info *cdi)
if(!buffer) return -ENOMEM;
sector = 0; /* the multisession sector offset goes here */
- is_xa = 0; /* flag: the CD uses XA-Sectors */
no_multi = 0; /* flag: the drive can't handle multisession */
rc = 0;
@@ -190,7 +193,8 @@ int sr_cd_check(struct cdrom_device_info *cdi)
break;
#ifdef CONFIG_BLK_DEV_SR_VENDOR
- case VENDOR_NEC:
+ case VENDOR_NEC: {
+ unsigned long min,sec,frame;
memset(cmd,0,12);
cmd[0] = 0xde;
cmd[1] = (scsi_CDs[minor].device->lun << 5) | 0x03;
@@ -209,8 +213,11 @@ int sr_cd_check(struct cdrom_device_info *cdi)
frame = BCD_TO_BIN(buffer[17]);
sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
break;
+ }
+
+ case VENDOR_TOSHIBA: {
+ unsigned long min,sec,frame;
- case VENDOR_TOSHIBA:
/* we request some disc information (is it a XA-CD ?,
* where starts the last session ?) */
memset(cmd,0,12);
@@ -232,17 +239,15 @@ int sr_cd_check(struct cdrom_device_info *cdi)
if (sector)
sector -= CD_MSF_OFFSET;
break;
+ }
- case VENDOR_HP_4020:
- /* Fallthrough */
- case VENDOR_HP_6020:
+ case VENDOR_WRITER:
+ memset(cmd,0,12);
cmd[0] = READ_TOC;
cmd[1] = (scsi_CDs[minor].device->lun << 5);
- cmd[8] = (VENDOR_ID == VENDOR_HP_4020) ?
- 0x04 : 0x0c;
+ cmd[8] = 0x04;
cmd[9] = 0x40;
- rc = sr_do_ioctl(minor, cmd, buffer,
- (VENDOR_ID == VENDOR_HP_4020) ? 0x04 : 0x0c, 0);
+ rc = sr_do_ioctl(minor, cmd, buffer, 0x04, 0);
if (rc != 0) {
break;
}
@@ -252,16 +257,14 @@ int sr_cd_check(struct cdrom_device_info *cdi)
break;
}
- if (VENDOR_ID == VENDOR_HP_4020) {
- cmd[0] = READ_TOC; /* Read TOC */
- cmd[1] = (scsi_CDs[minor].device->lun << 5);
- cmd[6] = rc & 0x7f; /* number of last session */
- cmd[8] = 0x0c;
- cmd[9] = 0x40;
- rc = sr_do_ioctl(minor, cmd, buffer, 12, 0);
- if (rc != 0) {
- break;
- }
+ cmd[0] = READ_TOC; /* Read TOC */
+ cmd[1] = (scsi_CDs[minor].device->lun << 5);
+ cmd[6] = rc & 0x7f; /* number of last session */
+ cmd[8] = 0x0c;
+ cmd[9] = 0x40;
+ rc = sr_do_ioctl(minor, cmd, buffer, 12, 0);
+ if (rc != 0) {
+ break;
}
sector = buffer[11] + (buffer[10] << 8) +
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 1d7ed45b4..809dc93a6 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -230,7 +230,6 @@ st_sleep_done (Scsi_Cmnd * SCpnt)
}
else
(STp->buffer)->last_result = SCpnt->result;
-
SCpnt->request.rq_status = RQ_SCSI_DONE;
(STp->buffer)->last_SCpnt = SCpnt;
@@ -252,7 +251,7 @@ st_do_scsi(Scsi_Cmnd *SCpnt, Scsi_Tape *STp, unsigned char *cmd, int bytes,
int timeout, int retries)
{
if (SCpnt == NULL)
- if ((SCpnt = allocate_device(NULL, STp->device, 1)) == NULL) {
+ if ((SCpnt = scsi_allocate_device(NULL, STp->device, 1)) == NULL) {
printk(KERN_ERR "st%d: Can't get SCSI request.\n", TAPE_NR(STp->devt));
return NULL;
}
@@ -293,7 +292,7 @@ write_behind_check(Scsi_Tape *STp)
down(&(STp->sem));
(STp->buffer)->last_result_fatal = st_chk_result((STp->buffer)->last_SCpnt);
- ((STp->buffer)->last_SCpnt)->request.rq_status = RQ_INACTIVE;
+ scsi_release_command((STp->buffer)->last_SCpnt);
if (STbuffer->writing < STbuffer->buffer_bytes)
memcpy(STbuffer->b_data,
@@ -340,7 +339,9 @@ cross_eof(Scsi_Tape *STp, int forward)
if (!SCpnt)
return (-EBUSY);
- SCpnt->request.rq_status = RQ_INACTIVE;
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
+
if ((STp->buffer)->last_result != 0)
printk(KERN_ERR "st%d: Stepping over filemark %s failed.\n",
TAPE_NR(STp->devt), forward ? "forward" : "backward");
@@ -421,7 +422,8 @@ flush_write_buffer(Scsi_Tape *STp)
STp->dirty = 0;
(STp->buffer)->buffer_bytes = 0;
}
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
}
return result;
}
@@ -543,6 +545,12 @@ scsi_tape_open(struct inode * inode, struct file * filp)
if (dev >= st_template.dev_max || !scsi_tapes[dev].device)
return (-ENXIO);
+
+ if( !scsi_block_when_processing_errors(scsi_tapes[dev].device) )
+ {
+ return -ENXIO;
+ }
+
STp = &(scsi_tapes[dev]);
if (STp->in_use) {
#if DEBUG
@@ -644,7 +652,8 @@ scsi_tape_open(struct inode * inode, struct file * filp)
STp->ready = ST_NO_TAPE;
} else
STp->ready = ST_NOT_READY;
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
STp->density = 0; /* Clear the erroneous "residue" */
STp->write_prot = 0;
STp->block_size = 0;
@@ -736,7 +745,8 @@ scsi_tape_open(struct inode * inode, struct file * filp)
}
STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0;
}
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
if (STp->block_size > 0)
(STp->buffer)->buffer_blocks = st_buffer_size / STp->block_size;
@@ -874,13 +884,15 @@ scsi_tape_close(struct inode * inode, struct file * filp)
SCpnt->sense_buffer[5] |
SCpnt->sense_buffer[6]) == 0))) {
/* Filter out successful write at EOM */
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
printk(KERN_ERR "st%d: Error on write filemark.\n", dev);
if (result == 0)
result = (-EIO);
}
else {
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
if (STps->drv_file >= 0)
STps->drv_file++ ;
STps->drv_block = 0;
@@ -965,12 +977,24 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
ST_partstat * STps;
int dev = TAPE_NR(inode->i_rdev);
+ STp = &(scsi_tapes[dev]);
+
+ /*
+ * If we are in the middle of error recovery, don't let anyone
+ * else try and use this device. Also, if error recovery fails, it
+ * may try and take the device offline, in which case all further
+ * access to the device is prohibited.
+ */
+ if( !scsi_block_when_processing_errors(STp->device) )
+ {
+ return -ENXIO;
+ }
+
if (ppos != &filp->f_pos) {
/* "A request was outside the capabilities of the device." */
return -ENXIO;
}
- STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY) {
if (STp->ready == ST_NO_TAPE)
return (-ENOMEDIUM);
@@ -1098,7 +1122,10 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
(STp->buffer)->buffer_bytes, b_point, do_count);
if (i) {
if (SCpnt != NULL)
- SCpnt->request.rq_status = RQ_INACTIVE;
+ {
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
+ }
return (-EFAULT);
}
@@ -1167,7 +1194,8 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
retval = (-EIO);
}
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
(STp->buffer)->buffer_bytes = 0;
STp->dirty = 0;
if (count < total)
@@ -1193,7 +1221,10 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
(STp->buffer)->buffer_bytes, b_point, count);
if (i) {
if (SCpnt != NULL)
- SCpnt->request.rq_status = RQ_INACTIVE;
+ {
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
+ }
return (-EFAULT);
}
filp->f_pos += count;
@@ -1202,7 +1233,8 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
}
if (doing_write && (STp->buffer)->last_result_fatal != 0) {
- SCpnt->request.rq_status = RQ_INACTIVE;
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
return (STp->buffer)->last_result_fatal;
}
@@ -1212,7 +1244,7 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
STp->block_size == 0) ) {
/* Schedule an asynchronous write */
if (!SCpnt) {
- SCpnt = allocate_device(NULL, STp->device, 1);
+ SCpnt = scsi_allocate_device(NULL, STp->device, 1);
if (!SCpnt)
return (-EBUSY);
}
@@ -1245,8 +1277,10 @@ st_write(struct file * filp, const char * buf, size_t count, loff_t *ppos)
st_sleep_done, STp->timeout, MAX_WRITE_RETRIES);
}
else if (SCpnt != NULL)
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
-
+ {
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
+ }
STps->at_sm &= (total == 0);
if (total > 0)
STps->eof = ST_NOEOF;
@@ -1346,7 +1380,7 @@ read_tape(struct inode *inode, long count, Scsi_Cmnd **aSCpnt)
(STp->buffer)->buffer_bytes = bytes - transfer;
}
else {
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
SCpnt = *aSCpnt = NULL;
if (transfer == blks) { /* We did not get anything, error */
printk(KERN_NOTICE "st%d: Incorrect block size.\n", dev);
@@ -1457,12 +1491,24 @@ st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
ST_partstat * STps;
int dev = TAPE_NR(inode->i_rdev);
+ STp = &(scsi_tapes[dev]);
+
+ /*
+ * If we are in the middle of error recovery, don't let anyone
+ * else try and use this device. Also, if error recovery fails, it
+ * may try and take the device offline, in which case all further
+ * access to the device is prohibited.
+ */
+ if( !scsi_block_when_processing_errors(STp->device) )
+ {
+ return -ENXIO;
+ }
+
if (ppos != &filp->f_pos) {
/* "A request was outside the capabilities of the device." */
return -ENXIO;
}
- STp = &(scsi_tapes[dev]);
if (STp->ready != ST_READY) {
if (STp->ready == ST_NO_TAPE)
return (-ENOMEDIUM);
@@ -1537,7 +1583,9 @@ st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
special = read_tape(inode, count - total, &SCpnt);
if (special < 0) { /* No need to continue read */
if (SCpnt != NULL)
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ {
+ scsi_release_command(SCpnt);
+ }
return special;
}
}
@@ -1555,7 +1603,10 @@ st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
(STp->buffer)->read_pointer, transfer);
if (i) {
if (SCpnt != NULL)
- SCpnt->request.rq_status = RQ_INACTIVE;
+ {
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
+ }
return (-EFAULT);
}
filp->f_pos += transfer;
@@ -1571,7 +1622,10 @@ st_read(struct file * filp, char * buf, size_t count, loff_t *ppos)
} /* for (total = 0, special = 0; total < count && !special; ) */
if (SCpnt != NULL)
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ {
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
+ }
/* Change the eof state if no data from tape or buffer */
if (total == 0) {
@@ -1815,7 +1869,8 @@ st_compression(Scsi_Tape * STp, int state)
if (debugging)
printk(ST_DEB_MSG "st%d: Compression mode page not supported.\n", dev);
#endif
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
return (-EIO);
}
#if DEBUG
@@ -1830,7 +1885,8 @@ st_compression(Scsi_Tape * STp, int state)
if (debugging)
printk(ST_DEB_MSG "st%d: Compression not supported.\n", dev);
#endif
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
return (-EIO);
}
@@ -1855,7 +1911,8 @@ st_compression(Scsi_Tape * STp, int state)
if (debugging)
printk(ST_DEB_MSG "st%d: Compression change failed.\n", dev);
#endif
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
return (-EIO);
}
@@ -1865,7 +1922,8 @@ st_compression(Scsi_Tape * STp, int state)
dev, state);
#endif
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
STp->compression_changed = TRUE;
return 0;
}
@@ -2238,9 +2296,9 @@ st_int_ioctl(struct inode * inode,
ioctl_result = (STp->buffer)->last_result_fatal;
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
-
if (!ioctl_result) { /* SCSI command successful */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
STps->drv_block = blkno;
STps->drv_file = fileno;
STps->at_sm = at_sm;
@@ -2288,7 +2346,8 @@ st_int_ioctl(struct inode * inode,
STp->partition = 0;
}
- } else { /* SCSI command was not completely successful */
+ } else { /* SCSI command was not completely successful. Don't return
+ from this block without releasing the SCSI command block! */
if (SCpnt->sense_buffer[2] & 0x40) {
if (cmd_in != MTBSF && cmd_in != MTBSFM &&
@@ -2369,6 +2428,9 @@ st_int_ioctl(struct inode * inode,
if (cmd_in == MTLOCK)
STp->door_locked = ST_LOCK_FAILS;
+
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
}
return ioctl_result;
@@ -2441,7 +2503,8 @@ get_location(struct inode * inode, unsigned int *block, int *partition,
#endif
}
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
return result;
}
@@ -2529,7 +2592,6 @@ set_location(struct inode * inode, unsigned int block, int partition,
if (!SCpnt)
return (-EBUSY);
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
STps->drv_block = STps->drv_file = (-1);
STps->eof = ST_NOEOF;
if ((STp->buffer)->last_result_fatal != 0) {
@@ -2556,6 +2618,9 @@ set_location(struct inode * inode, unsigned int block, int partition,
result = 0;
}
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
+
return result;
}
@@ -2622,7 +2687,8 @@ nbr_partitions(struct inode * inode)
SCpnt = st_do_scsi(SCpnt, STp, cmd, 200, STp->timeout, MAX_READY_RETRIES);
if (SCpnt == NULL)
return (-EBUSY);
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
if ((STp->buffer)->last_result_fatal != 0) {
#if DEBUG
@@ -2696,7 +2762,8 @@ partition_tape(struct inode * inode, int size)
SCpnt = st_do_scsi(SCpnt, STp, cmd, cmd[4], STp->long_timeout, MAX_READY_RETRIES);
if (SCpnt == NULL)
return (-EBUSY);
- SCpnt->request.rq_status = RQ_INACTIVE; /* Mark as not busy */
+ scsi_release_command(SCpnt);
+ SCpnt = NULL;
if ((STp->buffer)->last_result_fatal != 0) {
printk(KERN_INFO "st%d: Partitioning of tape failed.\n", dev);
@@ -2734,6 +2801,17 @@ st_ioctl(struct inode * inode,struct file * file,
STm = &(STp->modes[STp->current_mode]);
STps = &(STp->ps[STp->partition]);
+ /*
+ * If we are in the middle of error recovery, don't let anyone
+ * else try and use this device. Also, if error recovery fails, it
+ * may try and take the device offline, in which case all further
+ * access to the device is prohibited.
+ */
+ if( !scsi_block_when_processing_errors(STp->device) )
+ {
+ return -ENXIO;
+ }
+
cmd_type = _IOC_TYPE(cmd_in);
cmd_nr = _IOC_NR(cmd_in);
@@ -2768,11 +2846,18 @@ st_ioctl(struct inode * inode,struct file * file,
}
}
- i = flush_buffer(inode, file, /* mtc.mt_op == MTSEEK || */
- mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
- mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
- mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
- mtc.mt_op == MTCOMPRESSION);
+ if (mtc.mt_op == MTSEEK) {
+ /* Old position must be restored if partition will be changed */
+ i = !STp->can_partitions ||
+ (STp->new_partition != STp->partition);
+ }
+ else {
+ i = mtc.mt_op == MTREW || mtc.mt_op == MTOFFL ||
+ mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM ||
+ mtc.mt_op == MTLOCK || mtc.mt_op == MTLOAD ||
+ mtc.mt_op == MTCOMPRESSION;
+ }
+ i = flush_buffer(inode, file, i);
if (i < 0)
return i;
}
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index a8a4a8934..48036ed33 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -141,11 +141,11 @@ static struct override {
#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
static struct base {
- unsigned char *address;
+ unsigned int address;
int noauto;
} bases[] __initdata = {
- {(unsigned char *) 0xcc000, 0}, {(unsigned char *) 0xc8000, 0},
- {(unsigned char *) 0xdc000, 0}, {(unsigned char *) 0xd8000, 0}};
+ { 0xcc000, 0}, { 0xc8000, 0}, { 0xdc000, 0}, { 0xd8000, 0}
+};
#define NO_BASES (sizeof (bases) / sizeof (struct base))
@@ -178,7 +178,7 @@ __initfunc(void t128_setup(char *str, int *ints)) {
overrides[commandline_current].address = (unsigned char *) ints[1];
overrides[commandline_current].irq = ints[2];
for (i = 0; i < NO_BASES; ++i)
- if (bases[i].address == (unsigned char *) ints[1]) {
+ if (bases[i].address == ints[1]) {
bases[i].noauto = 1;
break;
}
@@ -216,7 +216,7 @@ __initfunc(int t128_detect(Scsi_Host_Template * tpnt)) {
else
for (; !base && (current_base < NO_BASES); ++current_base) {
#if (TDEBUG & TDEBUG_INIT)
- printk("scsi-t128 : probing address %08x\n", (unsigned int) bases[current_base].address);
+ printk("scsi-t128 : probing address %08x\n", bases[current_base].address);
#endif
for (sig = 0; sig < NO_SIGNATURES; ++sig)
if (!bases[current_base].noauto &&
@@ -224,7 +224,7 @@ __initfunc(int t128_detect(Scsi_Host_Template * tpnt)) {
signatures[sig].offset,
signatures[sig].string,
strlen(signatures[sig].string))) {
- base = bases[current_base].address;
+ base = (unsigned char *) bases[current_base].address;
#if (TDEBUG & TDEBUG_INIT)
printk("scsi-t128 : detected board.\n");
#endif
@@ -328,7 +328,7 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
int len) {
register unsigned char *reg = (unsigned char *) (instance->base +
T_DATA_REG_OFFSET), *d = dst;
- register i = len;
+ register int i = len;
#if 0
@@ -372,7 +372,7 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src
int len) {
register unsigned char *reg = (unsigned char *) (instance->base +
T_DATA_REG_OFFSET), *s = src;
- register i = len;
+ register int i = len;
#if 0
for (; i; --i) {
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index 43a898200..8f4f27f85 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -119,13 +119,18 @@ int t128_proc_info (char *buffer, char **start, off_t offset,
#if defined(HOSTS_C) || defined(MODULE)
-#define TRANTOR_T128 {NULL, NULL, NULL, NULL, \
- "Trantor T128/T128F/T228", t128_detect, NULL, \
- NULL, \
- NULL, t128_queue_command, t128_abort, t128_reset, NULL, \
- t128_biosparam, \
- /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
- /* cmd per lun */ CMD_PER_LUN , 0, 0, DISABLE_CLUSTERING}
+#define TRANTOR_T128 { \
+ name: "Trantor T128/T128F/T228", \
+ detect: t128_detect, \
+ queuecommand: t128_queue_command, \
+ abort: t128_abort, \
+ reset: t128_reset, \
+ bios_param: t128_biosparam, \
+ can_queue: CAN_QUEUE, \
+ this_id: 7, \
+ sg_tablesize: SG_ALL, \
+ cmd_per_lun: CMD_PER_LUN, \
+ use_clustering: DISABLE_CLUSTERING}
#endif
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
index 3008f1b21..980aadccc 100644
--- a/drivers/scsi/tmscsim.c
+++ b/drivers/scsi/tmscsim.c
@@ -24,6 +24,9 @@
* 1.09 11/30/96 KG Added register the allocated IO space *
* 1.10 12/05/96 CLH Modified tmscsim_proc_info(), and reset *
* pending interrupt in DC390_detect() *
+ * 1.11 02/05/97 KG/CLH Fixeds problem with partitions greater *
+ * than 1GB *
+ * 1.12 25/02/98 KG Cleaned up ifdefs for 2.1 kernel *
***********************************************************************/
@@ -32,7 +35,7 @@
#define SCSI_MALLOC
#ifdef MODULE
-#include <linux/module.h>
+# include <linux/module.h>
#endif
#include <asm/dma.h>
@@ -677,11 +680,11 @@ int DC390_bios_param(Disk *disk, kdev_t devno, int geom[])
sectors = 32;
cylinders = disk->capacity / (heads * sectors);
- if ( cylinders > 1024)
+ if ( (pACB->Gmode2 & GREATER_1G) && (cylinders > 1024) )
{
heads = 255;
sectors = 63;
- cylinders = disk->capacity / (255 * 63);
+ cylinders = disk->capacity / (heads * sectors);
}
geom[0] = heads;
@@ -898,11 +901,7 @@ RecoverSRB( PACB pACB )
* Returns : 0 on success.
***********************************************************************/
-#ifdef VERSION_2_0_0
int DC390_reset(Scsi_Cmnd *cmd, unsigned int resetFlags)
-#else
-int DC390_reset (Scsi_Cmnd *cmd)
-#endif
{
USHORT ioport;
unsigned long flags;
@@ -1161,7 +1160,7 @@ __initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT inde
if( !used_irq )
{
- if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim", NULL))
+ if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT | SA_SHIRQ, "tmscsim", NULL))
{
printk("DC390: register IRQ error!\n");
return( -1 );
@@ -1763,11 +1762,11 @@ int tmscsim_proc_info(char *buffer, char **start,
if (acbpnt == (PACB)-1) return(-ESRCH);
if(!shpnt) return(-ESRCH);
- if(inout) // Has data been written to the file ?
+ if(inout) /* Has data been written to the file ? */
return(tmscsim_set_info(buffer, length, shpnt));
SPRINTF("Tekram DC390(T) PCI SCSI Host Adadpter, ");
- SPRINTF("Driver Version 1.10, 1996/12/05\n");
+ SPRINTF("Driver Version 1.12, 1998/02/25\n");
save_flags(flags);
cli();
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
index 361c488ac..ed22865fd 100644
--- a/drivers/scsi/tmscsim.h
+++ b/drivers/scsi/tmscsim.h
@@ -4,8 +4,8 @@
;* Device Driver *
;***********************************************************************/
-#ifndef TMSCSIM_H
-#define TMSCSIM_H
+#ifndef _TMSCSIM_H
+#define _TMSCSIM_H
#define IRQ_NONE 255
@@ -677,4 +677,4 @@ UCHAR xx2;
(PCI_CFG2_ENABLE | (((function) << 1) & 0xe))
-#endif /* TMSCSIM_H */
+#endif /* _TMSCSIM_H */
diff --git a/drivers/scsi/u14-34f.h b/drivers/scsi/u14-34f.h
index 004936393..244bc811d 100644
--- a/drivers/scsi/u14-34f.h
+++ b/drivers/scsi/u14-34f.h
@@ -13,27 +13,16 @@ int u14_34f_biosparam(Disk *, kdev_t, int *);
#define U14_34F_VERSION "3.11.00"
-#define ULTRASTOR_14_34F { \
- NULL, /* Ptr for modules */ \
- NULL, /* usage count for modules */ \
- NULL, \
- NULL, \
- "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
- u14_34f_detect, \
- u14_34f_release, \
- NULL, \
- NULL, \
- u14_34f_queuecommand, \
- u14_34f_abort, \
- u14_34f_reset, \
- NULL, \
- u14_34f_biosparam, \
- 0, /* can_queue, reset by detect */ \
- 7, /* this_id, reset by detect */ \
- 0, /* sg_tablesize, reset by detect */ \
- 0, /* cmd_per_lun, reset by detect */ \
- 0, /* number of boards present */ \
- 1, /* unchecked isa dma, reset by detect */ \
- ENABLE_CLUSTERING \
+#define ULTRASTOR_14_34F { \
+ name: "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
+ detect: u14_34f_detect, \
+ release: u14_34f_release, \
+ queuecommand: u14_34f_queuecommand, \
+ abort: u14_34f_abort, \
+ reset: u14_34f_reset, \
+ bios_param: u14_34f_biosparam, \
+ this_id: 7, /* this_id, reset by detect */ \
+ unchecked_isa_dma: 1, /* unchecked isa dma, reset by detect */ \
+ use_clustering: ENABLE_CLUSTERING \
}
#endif
diff --git a/drivers/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
index 7a40acc58..ffe57ec18 100644
--- a/drivers/scsi/ultrastor.h
+++ b/drivers/scsi/ultrastor.h
@@ -31,26 +31,19 @@ int ultrastor_biosparam(Disk *, kdev_t, int *);
#define ULTRASTOR_24F_PORT 0xC80
-#define ULTRASTOR_14F { NULL, NULL, /* Ptr for modules*/ \
- NULL, \
- NULL, \
- "UltraStor 14F/24F/34F", \
- ultrastor_detect, \
- NULL, /* Release */ \
- ultrastor_info, \
- 0, \
- ultrastor_queuecommand, \
- ultrastor_abort, \
- ultrastor_reset, \
- 0, \
- ultrastor_biosparam, \
- ULTRASTOR_MAX_CMDS, \
- 0, \
- ULTRASTOR_14F_MAX_SG, \
- ULTRASTOR_MAX_CMDS_PER_LUN, \
- 0, \
- 1, \
- ENABLE_CLUSTERING }
+#define ULTRASTOR_14F { name: "UltraStor 14F/24F/34F", \
+ detect: ultrastor_detect, \
+ info: ultrastor_info, \
+ queuecommand: ultrastor_queuecommand, \
+ abort: ultrastor_abort, \
+ reset: ultrastor_reset, \
+ bios_param: ultrastor_biosparam, \
+ can_queue: ULTRASTOR_MAX_CMDS, \
+ this_id: 0, \
+ sg_tablesize: ULTRASTOR_14F_MAX_SG, \
+ cmd_per_lun: ULTRASTOR_MAX_CMDS_PER_LUN,\
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING }
#ifdef ULTRASTOR_PRIVATE
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 94c5e594c..f8c899535 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -473,7 +473,7 @@ typedef struct icbRevLvl {
typedef struct icbUnsMask { /* I'm totally guessing here */
unchar op;
volatile unchar mask[14]; /* mask bits */
-#ifdef 0
+#if 0
unchar rsvd[12]; /* reserved */
#endif
volatile unchar vue; /* vendor-unique error code */
diff --git a/drivers/scsi/wd7000.h b/drivers/scsi/wd7000.h
index 705f92958..8835e5f50 100644
--- a/drivers/scsi/wd7000.h
+++ b/drivers/scsi/wd7000.h
@@ -38,18 +38,18 @@ int wd7000_biosparam(Disk *, kdev_t, int *);
#define WD7000_Q 16
#define WD7000_SG 16
-#define WD7000 { NULL, NULL, \
- NULL, \
- NULL, \
- "Western Digital WD-7000", \
- wd7000_detect, \
- NULL, \
- NULL, \
- wd7000_command, \
- wd7000_queuecommand, \
- wd7000_abort, \
- wd7000_reset, \
- NULL, \
- wd7000_biosparam, \
- WD7000_Q, 7, WD7000_SG, 1, 0, 1, ENABLE_CLUSTERING}
+#define WD7000 { \
+ name: "Western Digital WD-7000", \
+ detect: wd7000_detect, \
+ command: wd7000_command, \
+ queuecommand: wd7000_queuecommand, \
+ abort: wd7000_abort, \
+ reset: wd7000_reset, \
+ bios_param: wd7000_biosparam, \
+ can_queue: WD7000_Q, \
+ this_id: 7, \
+ sg_tablesize: WD7000_SG, \
+ cmd_per_lun: 1, \
+ unchecked_isa_dma: 1, \
+ use_clustering: ENABLE_CLUSTERING}
#endif