summaryrefslogtreecommitdiffstats
path: root/drivers
diff options
context:
space:
mode:
authorMiguel de Icaza <miguel@nuclecu.unam.mx>1997-08-06 19:14:48 +0000
committerMiguel de Icaza <miguel@nuclecu.unam.mx>1997-08-06 19:14:48 +0000
commite2819e52a162873ff5061de81bb749831bdb5de9 (patch)
tree6067ea700202750ba335a423696f2972700e5f76 /drivers
parent17a005074429bbf143e40401f405ae4363e56828 (diff)
Merge to 2.1.38.
IMPORTANT NOTE: I could not figure out what information is the one that should be used for the following files (ie, those that were in our tree, or those that came from Linus' patch), please, check these: include/asm-mips/jazz.h include/asm-mips/jazzdma.h include/asm-mips/ioctls.h
Diffstat (limited to 'drivers')
-rw-r--r--drivers/Makefile2
-rw-r--r--drivers/block/acsi.c7
-rw-r--r--drivers/block/acsi_slm.c13
-rw-r--r--drivers/block/genhd.c8
-rw-r--r--drivers/char/Config.in1
-rw-r--r--drivers/char/Makefile10
-rw-r--r--drivers/char/fbmem.c3
-rw-r--r--drivers/char/keyboard.c5
-rw-r--r--drivers/char/lp.c11
-rw-r--r--drivers/char/mem.c4
-rw-r--r--drivers/char/misc.c4
-rw-r--r--drivers/char/pc110pad.c4
-rw-r--r--drivers/char/pc110pad.h2
-rw-r--r--drivers/char/pc_keyb.c74
-rw-r--r--drivers/char/pc_keyb.h6
-rw-r--r--drivers/char/psaux.c114
-rw-r--r--drivers/char/sysrq.c48
-rw-r--r--drivers/char/tty_io.c4
-rw-r--r--drivers/char/vga.c22
-rw-r--r--drivers/misc/parport_arc.c3
-rw-r--r--drivers/misc/parport_init.c9
-rw-r--r--drivers/misc/parport_pc.c20
-rw-r--r--drivers/misc/parport_procfs.c9
-rw-r--r--drivers/misc/parport_share.c35
-rw-r--r--drivers/net/myri_sbus.c10
-rw-r--r--drivers/net/plip.c18
-rw-r--r--drivers/net/soundmodem/sm_sbc.c5
-rw-r--r--drivers/net/soundmodem/sm_wss.c5
-rw-r--r--drivers/pnp/parport_probe.c8
-rw-r--r--drivers/sbus/char/Makefile2
-rw-r--r--drivers/sbus/char/creator.c6
-rw-r--r--drivers/sbus/char/suncons.c4
-rw-r--r--drivers/sbus/char/tcx.c8
-rw-r--r--drivers/sbus/char/weitek.c4
-rw-r--r--drivers/sbus/sbus.c7
-rw-r--r--drivers/scsi/53c7,8xx.c364
-rw-r--r--drivers/scsi/53c7,8xx.h2
-rw-r--r--drivers/scsi/Config.in9
-rw-r--r--drivers/scsi/Makefile8
-rw-r--r--drivers/scsi/README.aic7xxx44
-rw-r--r--drivers/scsi/aic7xxx.c7361
-rw-r--r--drivers/scsi/aic7xxx.h9
-rw-r--r--drivers/scsi/aic7xxx.seq1127
-rw-r--r--drivers/scsi/aic7xxx_asm.c734
-rw-r--r--drivers/scsi/aic7xxx_proc.c42
-rw-r--r--drivers/scsi/aic7xxx_reg.h1154
-rw-r--r--drivers/scsi/atari_scsi.c32
-rw-r--r--drivers/scsi/eata.h41
-rw-r--r--drivers/scsi/esp.c20
-rw-r--r--drivers/scsi/ppa.c26
-rw-r--r--drivers/scsi/ppa.h2
-rw-r--r--drivers/sgi/char/sgicons.c3
52 files changed, 5404 insertions, 6069 deletions
diff --git a/drivers/Makefile b/drivers/Makefile
index df324c4bb..c152af2eb 100644
--- a/drivers/Makefile
+++ b/drivers/Makefile
@@ -9,7 +9,7 @@
SUB_DIRS := block char net misc #streams
MOD_SUB_DIRS := $(SUB_DIRS) sbus
-ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sound cdrom isdn misc pnp
+ALL_SUB_DIRS := $(SUB_DIRS) pci sgi scsi sound cdrom isdn pnp
ifdef CONFIG_PCI
SUB_DIRS += pci
diff --git a/drivers/block/acsi.c b/drivers/block/acsi.c
index 740a3780a..e14cf09c7 100644
--- a/drivers/block/acsi.c
+++ b/drivers/block/acsi.c
@@ -370,7 +370,7 @@ static void redo_acsi_request( void );
static int acsi_ioctl( struct inode *inode, struct file *file, unsigned int
cmd, unsigned long arg );
static int acsi_open( struct inode * inode, struct file * filp );
-static void acsi_release( struct inode * inode, struct file * file );
+static int acsi_release( struct inode * inode, struct file * file );
static void acsi_prevent_removal( int target, int flag );
static int acsi_change_blk_size( int target, int lun);
static int acsi_mode_sense( int target, int lun, SENSE_DATA *sd );
@@ -1200,7 +1200,7 @@ static int acsi_open( struct inode * inode, struct file * filp )
* be forgotten about...
*/
-static void acsi_release( struct inode * inode, struct file * file )
+static int acsi_release( struct inode * inode, struct file * file )
{
int device;
@@ -1210,6 +1210,7 @@ static void acsi_release( struct inode * inode, struct file * file )
if (--access_count[device] == 0 && acsi_info[device].removable)
acsi_prevent_removal(device, 0);
MOD_DEC_USE_COUNT;
+ return( 0 );
}
/*
@@ -1821,7 +1822,7 @@ void cleanup_module(void)
{
del_timer( &acsi_timer );
blk_dev[MAJOR_NR].request_fn = 0;
- free_pages( acsi_buffer, ACSI_BUFFER_ORDER );
+ free_pages( (unsigned long)acsi_buffer, ACSI_BUFFER_ORDER );
if (unregister_blkdev( MAJOR_NR, "ad" ) != 0)
printk( KERN_ERR "acsi: cleanup_module failed\n");
diff --git a/drivers/block/acsi_slm.c b/drivers/block/acsi_slm.c
index da9af49b0..97957c0ea 100644
--- a/drivers/block/acsi_slm.c
+++ b/drivers/block/acsi_slm.c
@@ -117,7 +117,9 @@ static char slmreqsense_cmd[6] = { 0x03, 0, 0, 0, 0, 0 };
static char slmprint_cmd[6] = { 0x0a, 0, 0, 0, 0, 0 };
static char slminquiry_cmd[6] = { 0x12, 0, 0, 0, 0, 0x80 };
static char slmmsense_cmd[6] = { 0x1a, 0, 0, 0, 255, 0 };
+#if 0
static char slmmselect_cmd[6] = { 0x15, 0, 0, 0, 0, 0 };
+#endif
#define MAX_SLM 2
@@ -262,11 +264,13 @@ static long slm_write( struct inode *node, struct file *file, const char *buf,
static int slm_ioctl( struct inode *inode, struct file *file, unsigned int
cmd, unsigned long arg );
static int slm_open( struct inode *inode, struct file *file );
-static void slm_release( struct inode *inode, struct file *file );
+static int slm_release( struct inode *inode, struct file *file );
static int slm_req_sense( int device );
static int slm_mode_sense( int device, char *buffer, int abs_flag );
+#if 0
static int slm_mode_select( int device, char *buffer, int len, int
default_flag );
+#endif
static int slm_get_pagesize( int device, int *w, int *h );
/************************* End of Prototypes **************************/
@@ -794,7 +798,7 @@ static int slm_open( struct inode *inode, struct file *file )
}
-static void slm_release( struct inode *inode, struct file *file )
+static int slm_release( struct inode *inode, struct file *file )
{ int device;
struct slm *sip;
@@ -806,6 +810,8 @@ static void slm_release( struct inode *inode, struct file *file )
sip->wbusy = 0;
if (file->f_mode & 1)
sip->rbusy = 0;
+
+ return( 0 );
}
@@ -876,6 +882,8 @@ static int slm_mode_sense( int device, char *buffer, int abs_flag )
}
+#if 0
+/* currently unused */
static int slm_mode_select( int device, char *buffer, int len,
int default_flag )
@@ -911,6 +919,7 @@ static int slm_mode_select( int device, char *buffer, int len,
stdma_release();
return( rv );
}
+#endif
static int slm_get_pagesize( int device, int *w, int *h )
diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c
index 0217dcb52..1ee709737 100644
--- a/drivers/block/genhd.c
+++ b/drivers/block/genhd.c
@@ -979,14 +979,14 @@ static inline void setup_dev(struct gendisk *dev)
__initfunc(void device_setup(void))
{
extern void console_map_init(void);
-#ifdef CONFIG_PNP_PARPORT
- extern int pnp_parport_init(void);
+#ifdef CONFIG_PARPORT
+ extern int parport_init(void);
#endif
struct gendisk *p;
int nr=0;
-#ifdef CONFIG_PNP_PARPORT
- pnp_parport_init();
+#ifdef CONFIG_PARPORT
+ parport_init();
#endif
chr_dev_init();
blk_dev_init();
diff --git a/drivers/char/Config.in b/drivers/char/Config.in
index 0ef43d101..65407caf6 100644
--- a/drivers/char/Config.in
+++ b/drivers/char/Config.in
@@ -99,5 +99,6 @@ if [ "$CONFIG_WATCHDOG" != "n" ]; then
tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG
fi
bool 'Enhanced Real Time Clock Support' CONFIG_RTC
+tristate '/dev/nvram support' CONFIG_NVRAM
tristate 'PC joystick support' CONFIG_JOYSTICK
endmenu
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
index 18d50bf74..ad3664204 100644
--- a/drivers/char/Makefile
+++ b/drivers/char/Makefile
@@ -267,6 +267,16 @@ M = y
L_OBJS += rtc.o
endif
+ifeq ($(CONFIG_NVRAM),y)
+M = y
+L_OBJS += nvram.o
+else
+ ifeq ($(CONFIG_NVRAM),m)
+ MM = m
+ M_OBJS += nvram.o
+ endif
+endif
+
ifeq ($(CONFIG_QIC02_TAPE),y)
L_OBJS += tpqic02.o
else
diff --git a/drivers/char/fbmem.c b/drivers/char/fbmem.c
index 7db3b5dba..4a5bea195 100644
--- a/drivers/char/fbmem.c
+++ b/drivers/char/fbmem.c
@@ -221,8 +221,7 @@ fb_mmap(struct inode *inode, struct file *file, struct vm_area_struct * vma)
if (remap_page_range(vma->vm_start, vma->vm_offset,
vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
- vma->vm_inode = inode;
- atomic_inc(&inode->i_count);
+ vma->vm_dentry = dget(file->f_dentry);
return 0;
}
diff --git a/drivers/char/keyboard.c b/drivers/char/keyboard.c
index d29653c8a..932578806 100644
--- a/drivers/char/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -37,6 +37,7 @@
#include <linux/kbd_diacr.h>
#include <linux/vt_kern.h>
#include <linux/kbd_ll.h>
+#include <linux/sysrq.h>
#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
@@ -148,8 +149,6 @@ static unsigned char handle_diacr(unsigned char);
struct pt_regs * kbd_pt_regs;
#ifdef CONFIG_MAGIC_SYSRQ
-#define SYSRQ_KEY 0x54
-extern void handle_sysrq(int, struct pt_regs *, struct kbd_struct *, struct tty_struct *);
static int sysrq_pressed;
#endif
@@ -239,7 +238,7 @@ void handle_scancode(unsigned char scancode)
return;
} else if (sysrq_pressed) {
if (!up_flag)
- handle_sysrq(keycode, kbd_pt_regs, kbd, tty);
+ handle_sysrq(kbd_sysrq_xlate[keycode], kbd_pt_regs, kbd, tty);
return;
}
#endif
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index caf5b5ccf..59bb0a0a2 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -500,7 +500,7 @@ static int lp_release(struct inode * inode, struct file * file)
unsigned int minor = MINOR(inode->i_rdev);
unsigned int irq;
- if ((irq = LP_IRQ(minor))) {
+ if ((irq = LP_IRQ(minor)) != PARPORT_IRQ_NONE) {
kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE);
lp_table[minor].lp_buffer = NULL;
}
@@ -642,7 +642,7 @@ void lp_setup(char *str, int *ints)
parport[0] = -3;
} else {
if (ints[0] == 0 || ints[1] == 0) {
- /* disable driver on "parport=" or "parport=0" */
+ /* disable driver on "lp=" or "lp=0" */
parport[0] = -2;
} else {
printk(KERN_WARNING "warning: 'lp=0x%x' is deprecated, ignored\n", ints[1]);
@@ -652,19 +652,18 @@ void lp_setup(char *str, int *ints)
#endif
-int lp_wakeup(void *ref)
+void lp_wakeup(void *ref)
{
struct lp_struct *lp_dev = (struct lp_struct *) ref;
if (!lp_dev->lp_wait_q)
- return 1; /* Wake up whom? */
+ return; /* Wake up whom? */
/* Claim the Parport */
if (parport_claim(lp_dev->dev))
- return 1; /* Shouldn't happen */
+ return; /* Shouldn't happen */
wake_up(&lp_dev->lp_wait_q);
- return 0;
}
static int inline lp_searchfor(int list[], int a)
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 063503595..6e9eb5766 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -133,6 +133,10 @@ static int mmap_mem(struct inode * inode, struct file * file, struct vm_area_str
if (x86 > 3 && offset >= __pa(high_memory))
pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
#endif
+#ifdef __powerpc__
+ if (offset >= __pa(high_memory))
+ pgprot_val(vma->vm_page_prot) |= _PAGE_NO_CACHE | _PAGE_GUARDED;
+#endif
if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot))
return -EAGAIN;
vma->vm_dentry = dget(file->f_dentry);
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index 6262792b6..4495f881d 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -76,6 +76,7 @@ extern void wdt_init(void);
extern void pcwatchdog_init(void);
extern int rtc_init(void);
extern int dsp56k_init(void);
+extern int nvram_init(void);
#ifdef CONFIG_PROC_FS
static int misc_read_proc(char *buf, char **start, off_t offset,
@@ -244,6 +245,9 @@ __initfunc(int misc_init(void))
#ifdef CONFIG_ATARI_DSP56K
dsp56k_init();
#endif
+#ifdef CONFIG_NVRAM
+ nvram_init();
+#endif
#ifdef CONFIG_SGI_GRAPHICS
gfx_register ();
streamable_init ();
diff --git a/drivers/char/pc110pad.c b/drivers/char/pc110pad.c
index 7a6b8cde0..d9c5ac453 100644
--- a/drivers/char/pc110pad.c
+++ b/drivers/char/pc110pad.c
@@ -492,7 +492,7 @@ static int close_pad(struct inode * inode, struct file * file)
{
fasync_pad(inode, file, 0);
if (--active)
- return;
+ return 0;
outb(0x30, current_params.io+2); /* switch off digitiser */
MOD_DEC_USE_COUNT;
return 0;
@@ -640,7 +640,7 @@ static struct miscdevice pc110_pad = {
};
-static int pc110pad_init(void)
+int pc110pad_init(void)
{
current_params = default_params;
diff --git a/drivers/char/pc110pad.h b/drivers/char/pc110pad.h
index 56d8d82e0..d0ea0b0d3 100644
--- a/drivers/char/pc110pad.h
+++ b/drivers/char/pc110pad.h
@@ -26,6 +26,6 @@ struct pc110pad_params {
#define PC110PAD_IOCTL_TYPE 0x9a
#define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params)
-#define PC110PADIOCSETP _IOR(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
+#define PC110PADIOCSETP _IOW(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params)
#endif /* _PC110PAD_H */
diff --git a/drivers/char/pc_keyb.c b/drivers/char/pc_keyb.c
index fd1c8e862..866a4170f 100644
--- a/drivers/char/pc_keyb.c
+++ b/drivers/char/pc_keyb.c
@@ -7,6 +7,8 @@
* Major cleanup by Martin Mares, May 1997
*/
+#include <linux/config.h>
+
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/tty.h>
@@ -25,21 +27,38 @@
#include "pc_keyb.h"
+/* Simple translation table for the SysRq keys */
+
+#ifdef CONFIG_MAGIC_SYSRQ
+unsigned char pckbd_sysrq_xlate[128] =
+ "\000\0331234567890-=\177\t" /* 0x00 - 0x0f */
+ "qwertyuiop[]\r\000as" /* 0x10 - 0x1f */
+ "dfghjkl;'`\000\\zxcv" /* 0x20 - 0x2f */
+ "bnm,./\000*\000 \000\201\202\203\204\205" /* 0x30 - 0x3f */
+ "\206\207\210\211\212\000\000789-456+1" /* 0x40 - 0x4f */
+ "230\177\000\000\213\214\000\000\000\000\000\000\000\000\000\000" /* 0x50 - 0x5f */
+ "\r\000/"; /* 0x60 - 0x6f */
+#endif
+
/*
* In case we run on a non-x86 hardware we need to initialize both the keyboard
* controller and the keyboard. On a x86, the BIOS will already have initialized
* them.
*/
+#ifndef __i386__
+#define INIT_KBD
+#endif
+
#ifdef INIT_KBD
__initfunc(static int kbd_wait_for_input(void))
{
- int n;
- int status, data;
+ int n;
+ int status, data;
+ unsigned long start = jiffies;
- n = KBD_TIMEOUT;
- do {
+ do {
status = kbd_read_status();
/*
* Wait for input data to become available. This bit will
@@ -62,7 +81,7 @@ __initfunc(static int kbd_wait_for_input(void))
continue;
}
return (data & 0xff);
- } while (--n);
+ } while (jiffies - start < KBD_INIT_TIMEOUT);
return -1; /* timed-out if fell through to here... */
}
@@ -165,12 +184,11 @@ __initfunc(static char *initialize_kbd2(void))
__initfunc(void initialize_kbd(void))
{
- unsigned long flags;
char *msg;
- save_flags(flags); cli();
+ disable_irq(KEYBOARD_IRQ);
msg = initialize_kbd2();
- restore_flags(flags);
+ enable_irq(KEYBOARD_IRQ);
if (msg)
printk(KERN_WARNING "initialize_kbd: %s\n", msg);
@@ -191,12 +209,15 @@ static volatile unsigned char resend = 0;
static inline void kb_wait(void)
{
- int i;
+ unsigned long start = jiffies;
- for (i=0; i<KBD_TIMEOUT; i++)
+ do {
if (! (kbd_read_status() & KBD_STAT_IBF))
return;
+ } while (jiffies - start < KBC_TIMEOUT);
+#ifdef KBD_REPORT_TIMEOUTS
printk(KERN_WARNING "Keyboard timed out\n");
+#endif
}
/*
@@ -374,7 +395,7 @@ static int do_acknowledge(unsigned char scancode)
}
if (scancode == 0) {
#ifdef KBD_REPORT_ERR
- printk(KERN_INFO "keyboard buffer overflow\n");
+ printk(KERN_INFO "Keyboard buffer overflow\n");
#endif
prev_scancode = 0;
return 0;
@@ -390,7 +411,7 @@ int pckbd_pretranslate(unsigned char scancode, char raw_mode)
#ifndef KBD_IS_FOCUS_9000
#ifdef KBD_REPORT_ERR
if (!raw_mode)
- printk(KERN_DEBUG "keyboard error\n");
+ printk(KERN_DEBUG "Keyboard error\n");
#endif
#endif
prev_scancode = 0;
@@ -505,15 +526,17 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
unsigned char scancode;
/* mouse data? */
- if (status & kbd_read_mask & KBD_STAT_MOUSE_OBF)
+ if (status & kbd_read_mask & KBD_STAT_MOUSE_OBF){
+ printk ("MOUSE!\n");
break;
+ }
scancode = kbd_read_input();
if ((status & KBD_STAT_OBF) && do_acknowledge(scancode))
handle_scancode(scancode);
status = kbd_read_status();
- } while (status & (KBD_STAT_OBF | KBD_STAT_MOUSE_OBF));
+ } while (status & KBD_STAT_OBF);
mark_bh(KEYBOARD_BH);
enable_keyboard();
@@ -527,7 +550,7 @@ static void keyboard_interrupt(int irq, void *dev_id, struct pt_regs *regs)
static int send_data(unsigned char data)
{
int retries = 3;
- int i;
+ unsigned long start;
do {
kb_wait();
@@ -536,16 +559,21 @@ static int send_data(unsigned char data)
reply_expected = 1;
kbd_write_output(data);
kbd_pause();
- for(i=0; i<0x200000; i++) {
- kbd_read_status(); /* just as a delay */
+ start = jiffies;
+ do {
if (acknowledge)
return 1;
- if (resend)
- break;
- }
- if (!resend)
- return 0;
+ if (jiffies - start >= KBD_TIMEOUT) {
+#ifdef KBD_REPORT_TIMEOUTS
+ printk(KERN_WARNING "Keyboard timeout\n");
+#endif
+ return 0;
+ }
+ } while (!resend);
} while (retries-- > 0);
+#ifdef KBD_REPORT_TIMEOUTS
+ printk(KERN_WARNING "keyboard: Too many NACKs -- noisy kbd cable?\n");
+#endif
return 0;
}
@@ -557,7 +585,7 @@ void pckbd_leds(unsigned char leds)
__initfunc(void pckbd_init_hw(void))
{
- request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard", NULL);
+ request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard-aaa", NULL);
keyboard_setup();
#ifdef INIT_KBD
initialize_kbd();
diff --git a/drivers/char/pc_keyb.h b/drivers/char/pc_keyb.h
index f12ddab08..ffbfc49e2 100644
--- a/drivers/char/pc_keyb.h
+++ b/drivers/char/pc_keyb.h
@@ -12,8 +12,12 @@
#define KBD_REPORT_ERR /* Report keyboard errors */
#define KBD_REPORT_UNKN /* Report unknown scan codes */
+#define KBD_REPORT_TIMEOUTS /* Report keyboard timeouts */
#undef KBD_IS_FOCUS_9000 /* We have the brain-damaged FOCUS-9000 keyboard */
-#define KBD_TIMEOUT 0x100000 /* Timeout for sending of commands */
+
+#define KBD_INIT_TIMEOUT HZ /* Timeout for initializing the keyboard */
+#define KBC_TIMEOUT (HZ/4) /* Timeout for sending to keyboard controller */
+#define KBD_TIMEOUT (HZ/4) /* Timeout for keyboard command acknowledge */
/*
* Internal variables of the driver
diff --git a/drivers/char/psaux.c b/drivers/char/psaux.c
index d329a6883..78089e833 100644
--- a/drivers/char/psaux.c
+++ b/drivers/char/psaux.c
@@ -53,6 +53,7 @@
#include <asm/io.h>
#include <asm/uaccess.h>
#include <asm/system.h>
+#include <asm/semaphore.h>
#include <linux/config.h>
@@ -143,25 +144,7 @@ static int poll_aux_status(void)
schedule();
retries++;
}
- return !(retries==MAX_RETRIES);
-}
-
-static int poll_aux_status_nosleep(void)
-{
- int retries = 0;
- unsigned char status;
-
- while ((kbd_read_status() & (KBD_STAT_IBF | KBD_STAT_OBF))
- && retries < 1000000) {
- status = kbd_read_status();
- kbd_pause();
- if ((status & AUX_STAT_OBF) == AUX_STAT_OBF) {
- kbd_read_input();
- kbd_pause();
- }
- retries++;
- }
- return !(retries == 1000000);
+ return (retries < MAX_RETRIES);
}
/*
@@ -181,18 +164,10 @@ static void aux_write_dev(int val)
*/
#ifdef INITIALIZE_DEVICE
-__initfunc(static void aux_write_dev_nosleep(int val))
-{
- poll_aux_status_nosleep();
- kbd_write_command(KBD_CCMD_WRITE_MOUSE);
- poll_aux_status_nosleep();
- kbd_write_output(val);
-}
-
__initfunc(static int aux_write_ack(int val))
{
- aux_write_dev_nosleep(val);
- poll_aux_status_nosleep();
+ aux_write_dev(val);
+ poll_aux_status();
if ((kbd_read_status() & AUX_STAT_OBF) == AUX_STAT_OBF)
{
@@ -215,6 +190,31 @@ static void aux_write_cmd(int val)
}
/*
+ * AUX handler critical section start and end.
+ *
+ * Only one process can be in the critical section and all keyboard sends are
+ * deferred as long as we're inside. This is necessary as we may sleep when
+ * waiting for the keyboard controller and other processes / BH's can
+ * preempt us. Please note that the input buffer must be flushed when
+ * aux_end_atomic() is called and the interrupt is no longer enabled as not
+ * doing so might cause the keyboard driver to ignore all incoming keystrokes.
+ */
+
+static struct semaphore aux_sema4 = MUTEX;
+
+static inline void aux_start_atomic(void)
+{
+ down(&aux_sema4);
+ disable_bh(KEYBOARD_BH);
+}
+
+static inline void aux_end_atomic(void)
+{
+ enable_bh(KEYBOARD_BH);
+ up(&aux_sema4);
+}
+
+/*
* Interrupt from the auxiliary device: a character
* is waiting in the keyboard/aux controller.
*/
@@ -273,14 +273,12 @@ static int release_aux(struct inode * inode, struct file * file)
fasync_aux(inode, file, 0);
if (--aux_count)
return 0;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
+ aux_start_atomic();
aux_write_cmd(AUX_INTS_OFF); /* Disable controller ints */
poll_aux_status();
kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable Aux device */
poll_aux_status();
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
ps2_free_irq(inode);
MOD_DEC_USE_COUNT;
return 0;
@@ -291,27 +289,31 @@ static int open_aux(struct inode * inode, struct file * file)
{
if (!aux_present)
return -ENODEV;
- if (aux_count++)
+ aux_start_atomic();
+ if (aux_count++) {
+ aux_end_atomic();
return 0;
- if (!poll_aux_status()) {
+ }
+ if (!poll_aux_status()) { /* FIXME: Race condition */
aux_count--;
+ aux_end_atomic();
return -EBUSY;
}
queue->head = queue->tail = 0; /* Flush input queue */
if(ps2_request_irq()) {
aux_count--;
+ aux_end_atomic();
return -EBUSY;
}
MOD_INC_USE_COUNT;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
+
+
poll_aux_status();
kbd_write_command(KBD_CCMD_MOUSE_ENABLE); /* Enable Aux */
aux_write_dev(AUX_ENABLE_DEV); /* Enable aux device */
aux_write_cmd(AUX_INTS_ON); /* Enable controller ints */
poll_aux_status();
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
aux_ready = 0;
return 0;
@@ -329,9 +331,7 @@ static long write_aux(struct inode * inode, struct file * file,
if (count) {
int written = 0;
- /* disable kbd bh to avoid mixing of cmd bytes */
- disable_bh(KEYBOARD_BH);
-
+ aux_start_atomic();
do {
char c;
if (!poll_aux_status())
@@ -343,8 +343,7 @@ static long write_aux(struct inode * inode, struct file * file,
kbd_write_output(c);
written++;
} while (--count);
- /* reenable kbd bh */
- enable_bh(KEYBOARD_BH);
+ aux_end_atomic();
retval = -EIO;
if (written) {
retval = written;
@@ -628,11 +627,7 @@ __initfunc(int psaux_init(void))
psaux_fops.release = release_qp;
} else
#endif
-#if defined(CONFIG_SGI) && defined(CONFIG_PSMOUSE)
- if (1) {
-#else
if (aux_device_present == 0xaa) {
-#endif
printk(KERN_INFO "PS/2 auxiliary pointing device detected -- driver installed.\n");
aux_present = 1;
#ifdef CONFIG_VT
@@ -647,20 +642,33 @@ __initfunc(int psaux_init(void))
queue->head = queue->tail = 0;
queue->proc_list = NULL;
if (!qp_found) {
+ printk ("AUX--1\n");
+ aux_start_atomic();
#ifdef INITIALIZE_DEVICE
+ printk ("AUX--2\n");
kbd_write_command(AUX_ENABLE); /* Enable Aux */
aux_write_ack(AUX_SET_SAMPLE);
+ printk ("AUX--3\n");
aux_write_ack(100); /* 100 samples/sec */
aux_write_ack(AUX_SET_RES);
aux_write_ack(3); /* 8 counts per mm */
+ printk ("AUX--4\n");
aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */
- poll_aux_status_nosleep();
+ poll_aux_status();
+ printk ("AUX--5\n");
#endif /* INITIALIZE_DEVICE */
+ printk ("AUX--6\n");
kbd_write_command(KBD_CCMD_MOUSE_DISABLE); /* Disable Aux device */
- poll_aux_status_nosleep();
- kbd_write_command(KBD_CCMD_WRITE_MODE);
- poll_aux_status_nosleep(); /* Disable interrupts */
- kbd_write_output(AUX_INTS_OFF); /* on the controller */
+ poll_aux_status();
+ printk ("AUX--7\n");
+ kbd_write_command(KBD_CCMD_WRITE_MODE); /* Disable controller interrupts */
+ kbd_pause ();
+ poll_aux_status();
+ printk ("AUX--8\n");
+ kbd_write_output (AUX_INTS_OFF);
+ kbd_pause ();
+ poll_aux_status();
+ aux_end_atomic();
}
return 0;
}
diff --git a/drivers/char/sysrq.c b/drivers/char/sysrq.c
index 1e0e1a2a0..25396c3c1 100644
--- a/drivers/char/sysrq.c
+++ b/drivers/char/sysrq.c
@@ -1,6 +1,6 @@
/* -*- linux-c -*-
*
- * $Id: sysrq.c,v 1.1 1997/06/17 13:24:07 ralf Exp $
+ * $Id: sysrq.c,v 1.4 1997/07/17 11:54:15 mj Exp $
*
* Linux Magic System Request Key Hacks
*
@@ -63,72 +63,72 @@ void handle_sysrq(int key, struct pt_regs *pt_regs,
console_loglevel = 7;
printk(KERN_INFO "SysRq: ");
switch (key) {
- case 19: /* R -- Reset raw mode */
- kbd->kbdmode = VC_XLATE;
- printk("Keyboard mode set to XLATE\n");
+ case 'r': /* R -- Reset raw mode */
+ if (kbd) {
+ kbd->kbdmode = VC_XLATE;
+ printk("Keyboard mode set to XLATE\n");
+ }
break;
- case 30: /* A -- SAK */
+ case 'a': /* A -- SAK */
printk("SAK\n");
- do_SAK(tty);
+ if (tty)
+ do_SAK(tty);
reset_vc(fg_console);
break;
- case 48: /* B -- boot immediately */
+ case 'b': /* B -- boot immediately */
printk("Resetting\n");
machine_restart(NULL);
break;
#ifdef __sparc__
- case 35: /* H -- halt immediately */
+ case 'h': /* H -- halt immediately */
printk("Halting\n");
halt_now();
break;
#endif
#ifdef CONFIG_APM
- case 24: /* O -- power off */
+ case 'o': /* O -- power off */
printk("Power off\n");
apm_set_power_state(APM_STATE_OFF);
break;
#endif
- case 31: /* S -- emergency sync */
+ case 's': /* S -- emergency sync */
printk("Emergency Sync\n");
emergency_sync_scheduled = EMERG_SYNC;
wakeup_bdflush(0);
break;
- case 22: /* U -- emergency remount R/O */
+ case 'u': /* U -- emergency remount R/O */
printk("Emergency Remount R/O\n");
emergency_sync_scheduled = EMERG_REMOUNT;
wakeup_bdflush(0);
break;
- case 25: /* P -- show PC */
+ case 'p': /* P -- show PC */
printk("Show Regs\n");
if (pt_regs)
show_regs(pt_regs);
break;
- case 20: /* T -- show task info */
+ case 't': /* T -- show task info */
printk("Show State\n");
show_state();
break;
- case 50: /* M -- show memory info */
+ case 'm': /* M -- show memory info */
printk("Show Memory\n");
show_mem();
break;
- case 2 ... 11: /* 0-9 -- set console logging level */
- key--;
- if (key == 10)
- key = 0;
- orig_log_level = key;
- printk("Log level set to %d\n", key);
+ case '0' ... '9': /* 0-9 -- set console logging level */
+ orig_log_level = key - '0';
+ printk("Log level set to %d\n", orig_log_level);
break;
- case 18: /* E -- terminate all user processes */
+ case 'e': /* E -- terminate all user processes */
printk("Terminate All Tasks\n");
send_sig_all(SIGTERM, 0);
orig_log_level = 8; /* We probably have killed syslogd */
break;
- case 37: /* K -- kill all user processes */
+ case 'k': /* K -- kill all user processes */
printk("Kill All Tasks\n");
send_sig_all(SIGKILL, 0);
orig_log_level = 8;
break;
- case 38: /* L -- kill all processes including init */
+ case 'l': /* L -- kill all processes including init */
printk("Kill ALL Tasks (even init)\n");
send_sig_all(SIGKILL, 1);
orig_log_level = 8;
@@ -154,7 +154,7 @@ static void all_files_read_only(void) /* Kill write permissions of all files
struct file *file;
for (file = inuse_filps; file; file = file->f_next)
- if (file->f_inode && file->f_count && S_ISREG(file->f_inode->i_mode))
+ if (file->f_dentry && file->f_count && S_ISREG(file->f_dentry->d_inode->i_mode))
file->f_mode &= ~2;
}
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index d63578c55..4c6ecae22 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -688,7 +688,6 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty)
return -ENODEV;
idx = MINOR(device) - driver->minor_start;
- tty = driver->table[idx];
/*
* Check whether we need to acquire the tty semaphore to avoid
@@ -697,7 +696,8 @@ static int init_dev(kdev_t device, struct tty_struct **ret_tty)
down_tty_sem(idx);
/* check whether we're reopening an existing tty */
- if(tty) goto fast_track;
+ tty = driver->table[idx];
+ if (tty) goto fast_track;
/*
* First time open is complex, especially for PTY devices.
diff --git a/drivers/char/vga.c b/drivers/char/vga.c
index afce24c98..c3fee1ae7 100644
--- a/drivers/char/vga.c
+++ b/drivers/char/vga.c
@@ -84,6 +84,12 @@ unsigned long video_port_base;
#define dac_reg (0x3c8)
#define dac_val (0x3c9)
+#ifdef __powerpc__
+#define VGA_OFFSET 0xC0000000;
+#else
+#define VGA_OFFSET 0x0
+#endif
+
/*
* By replacing the four outb_p with two back to back outw, we can reduce
* the window of opportunity to see text mislocated to the RHS of the
@@ -241,20 +247,20 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
#endif
if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
{
- video_mem_base = 0xb0000;
+ video_mem_base = 0xb0000 + VGA_OFFSET;
video_port_reg = 0x3b4;
video_port_val = 0x3b5;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
{
video_type = VIDEO_TYPE_EGAM;
- video_mem_term = 0xb8000;
+ video_mem_term = 0xb8000 + VGA_OFFSET;
*display_desc = "EGA+";
request_region(0x3b0,16,"ega");
}
else
{
video_type = VIDEO_TYPE_MDA;
- video_mem_term = 0xb2000;
+ video_mem_term = 0xb2000 + VGA_OFFSET;
*display_desc = "*MDA";
request_region(0x3b0,12,"mda");
request_region(0x3bf, 1,"mda");
@@ -263,14 +269,14 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
else /* If not, it is color. */
{
can_do_color = 1;
- video_mem_term = 0xb8000;
+ video_mem_term = 0xb8000 + VGA_OFFSET;
video_port_reg = 0x3d4;
video_port_val = 0x3d5;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
{
int i ;
- video_mem_term = 0xc0000;
+ video_mem_term = 0xc0000 + VGA_OFFSET;
if (!ORIG_VIDEO_ISVGA) {
video_type = VIDEO_TYPE_EGAC;
@@ -288,8 +294,8 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
* controllers (it seems like setting MM=01
* and COE=1 isn't necessarily a good idea)
*/
- video_mem_base = 0xa0000;
- video_mem_term = 0xb0000;
+ video_mem_base = 0xa0000 + VGA_OFFSET;
+ video_mem_term = 0xb0000 + VGA_OFFSET;
outb_p (6, 0x3ce) ;
outb_p (6, 0x3cf) ;
#endif
@@ -321,7 +327,7 @@ con_type_init(unsigned long kmem_start, const char **display_desc))
else
{
video_type = VIDEO_TYPE_CGA;
- video_mem_term = 0xba000;
+ video_mem_term = 0xba000 + VGA_OFFSET;
*display_desc = "*CGA";
request_region(0x3d4,2,"cga");
}
diff --git a/drivers/misc/parport_arc.c b/drivers/misc/parport_arc.c
index 8ceaee794..932ecab8c 100644
--- a/drivers/misc/parport_arc.c
+++ b/drivers/misc/parport_arc.c
@@ -1,4 +1,4 @@
-/* $Id: parport_arc.c,v 1.1 1997/07/25 01:53:12 ralf Exp $
+/* $Id: parport_arc.c,v 1.1 1997/07/29 03:59:12 ralf Exp $
* Parallel-port routines for ARC onboard hardware.
*
* Author: Phil Blundell <pjb27@cam.ac.uk>
@@ -10,7 +10,6 @@
#include <asm/io.h>
#include <asm/dma.h>
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
diff --git a/drivers/misc/parport_init.c b/drivers/misc/parport_init.c
index 52f3c6e33..a0f280b2f 100644
--- a/drivers/misc/parport_init.c
+++ b/drivers/misc/parport_init.c
@@ -1,4 +1,4 @@
-/* $Id: parport_init.c,v 1.1 1997/07/25 01:53:14 ralf Exp $
+/* $Id: parport_init.c,v 1.1 1997/07/29 03:59:13 ralf Exp $
* Parallel-port initialisation code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -56,6 +56,7 @@ __initfunc(void parport_setup(char *str, int *ints))
#ifdef MODULE
int init_module(void)
{
+ parport_proc_init();
return 0;
}
@@ -79,7 +80,8 @@ __initfunc(int parport_init(void))
{
struct parport *pb;
- if (io[0] == PARPORT_DISABLE) return 1;
+ if (io[0] == PARPORT_DISABLE) return 1;
+ parport_proc_init();
#ifdef CONFIG_PARPORT_PC
parport_pc_init(io, irq, dma);
#endif
@@ -92,12 +94,15 @@ __initfunc(int parport_init(void))
EXPORT_SYMBOL(parport_claim);
EXPORT_SYMBOL(parport_release);
EXPORT_SYMBOL(parport_register_port);
+EXPORT_SYMBOL(parport_unregister_port);
EXPORT_SYMBOL(parport_quiesce);
EXPORT_SYMBOL(parport_register_device);
EXPORT_SYMBOL(parport_unregister_device);
EXPORT_SYMBOL(parport_enumerate);
EXPORT_SYMBOL(parport_ieee1284_nibble_mode_ok);
EXPORT_SYMBOL(parport_wait_peripheral);
+EXPORT_SYMBOL(parport_proc_register);
+EXPORT_SYMBOL(parport_proc_unregister);
void inc_parport_count(void)
{
diff --git a/drivers/misc/parport_pc.c b/drivers/misc/parport_pc.c
index 925f697f6..6c6dbd033 100644
--- a/drivers/misc/parport_pc.c
+++ b/drivers/misc/parport_pc.c
@@ -1,4 +1,4 @@
-/* $Id: parport_pc.c,v 1.1 1997/07/25 01:53:16 ralf Exp $
+/* $Id: parport_pc.c,v 1.1 1997/07/29 03:59:13 ralf Exp $
* Parallel-port routines for PC architecture
*
* Authors: Phil Blundell <pjb27@cam.ac.uk>
@@ -10,6 +10,7 @@
* and Philip Blundell <Philip.Blundell@pobox.com>
*/
+#include <linux/stddef.h>
#include <linux/tasks.h>
#include <asm/ptrace.h>
@@ -140,7 +141,7 @@ static void pc_enable_irq(struct parport *p)
static void pc_release_resources(struct parport *p)
{
if (p->irq != PARPORT_IRQ_NONE)
- free_irq(p->irq, NULL);
+ free_irq(p->irq, p);
release_region(p->base, p->size);
if (p->modes & PARPORT_MODE_PCECR)
release_region(p->base+0x400, 3);
@@ -439,9 +440,10 @@ static int parport_SPP_supported(struct parport *pb)
*/
static int parport_ECR_present(struct parport *pb)
{
- int r, octr = pc_read_control(pb), oecr = pc_read_econtrol(pb);
+ unsigned int r, octr = pc_read_control(pb),
+ oecr = pc_read_econtrol(pb);
- r= pc_read_control(pb);
+ r = pc_read_control(pb);
if ((pc_read_econtrol(pb) & 0x03) == (r & 0x03)) {
pc_write_control(pb, r ^ 0x03 ); /* Toggle bits 0-1 */
@@ -820,7 +822,10 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
}
if (p->irq != PARPORT_IRQ_NONE)
printk(", irq %d", p->irq);
- if (p->irq != PARPORT_DMA_NONE)
+ if (p->dma == PARPORT_DMA_AUTO)
+ p->dma = (p->modes & PARPORT_MODE_PCECP)?
+ parport_dma_probe(p):PARPORT_DMA_NONE;
+ if (p->dma != PARPORT_DMA_NONE)
printk(", dma %d", p->dma);
printk(" [");
#define printmode(x) {if(p->modes&PARPORT_MODE_PC##x){printk("%s%s",f?",":"",#x);f++;}}
@@ -835,6 +840,7 @@ static int probe_one_port(unsigned long int base, int irq, int dma)
}
#undef printmode
printk("]\n");
+ parport_proc_register(p);
return 1;
}
@@ -868,7 +874,7 @@ MODULE_PARM(dma, "1-" __MODULE_STRING(PC_MAX_PORTS) "i");
static int init_module(void)
{
- return (parport_pc_init(NULL, NULL, NULL)?0:1);
+ return (parport_pc_init(io, irq, dma)?0:1);
}
static void cleanup_module(void)
@@ -878,6 +884,8 @@ static void cleanup_module(void)
if (p->modes & PARPORT_MODE_PCSPP) {
if (!(p->flags & PARPORT_FLAG_COMA))
parport_quiesce(p);
+ parport_proc_unregister(p);
+ parport_unregister_port(p);
}
p = p->next;
}
diff --git a/drivers/misc/parport_procfs.c b/drivers/misc/parport_procfs.c
index 5365c0df7..0fd03fddf 100644
--- a/drivers/misc/parport_procfs.c
+++ b/drivers/misc/parport_procfs.c
@@ -1,4 +1,4 @@
-/* $Id: parport_procfs.c,v 1.1 1997/07/25 01:53:18 ralf Exp $
+/* $Id: parport_procfs.c,v 1.1 1997/07/29 03:59:13 ralf Exp $
* Parallel port /proc interface code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -8,12 +8,12 @@
* and Philip Blundell <Philip.Blundell@pobox.com>
*/
+#include <linux/stddef.h>
#include <linux/tasks.h>
#include <asm/ptrace.h>
#include <asm/io.h>
#include <asm/dma.h>
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/interrupt.h>
@@ -131,7 +131,10 @@ static int hardware_read_proc(char *page, char **start, off_t off,
len += sprintf(page+len, "irq:\tnone\n");
else
len += sprintf(page+len, "irq:\t%d\n",pp->irq);
- len += sprintf(page+len, "dma:\t%d\n",pp->dma);
+ if (pp->dma == PARPORT_DMA_NONE)
+ len += sprintf(page+len, "dma:\tnone\n");
+ else
+ len += sprintf(page+len, "dma:\t%d\n",pp->dma);
#if 0
diff --git a/drivers/misc/parport_share.c b/drivers/misc/parport_share.c
index 55b64e856..256cbcee6 100644
--- a/drivers/misc/parport_share.c
+++ b/drivers/misc/parport_share.c
@@ -1,4 +1,4 @@
-/* $Id: parport_share.c,v 1.1 1997/07/25 01:53:19 ralf Exp $
+/* $Id: parport_share.c,v 1.1 1997/07/29 03:59:13 ralf Exp $
* Parallel-port resource manager code.
*
* Authors: David Campbell <campbell@tirian.che.curtin.edu.au>
@@ -88,6 +88,23 @@ struct parport *parport_register_port(unsigned long base, int irq, int dma,
return tmp;
}
+void parport_unregister_port(struct parport *port)
+{
+ struct parport *p;
+ kfree(port->name);
+ if (portlist == port) {
+ portlist = port->next;
+ } else {
+ for (p = portlist; (p != NULL) && (p->next != port);
+ p=p->next);
+ if (p) {
+ if ((p->next = port->next) == NULL)
+ portlist_tail = p;
+ }
+ }
+ kfree(port);
+}
+
void parport_quiesce(struct parport *port)
{
if (port->devices) {
@@ -106,7 +123,7 @@ void parport_quiesce(struct parport *port)
}
struct pardevice *parport_register_device(struct parport *port, const char *name,
- int (*pf)(void *), int (*kf)(void *),
+ int (*pf)(void *), void (*kf)(void *),
void (*irq_func)(int, void *, struct pt_regs *),
int flags, void *handle)
{
@@ -223,7 +240,6 @@ int parport_claim(struct pardevice *dev)
pd1 = dev->port->cad;
if (dev->port->cad) {
if (dev->port->cad->preempt) {
- /* Now try to preempt */
if (dev->port->cad->preempt(dev->port->cad->private))
return -EAGAIN;
dev->port->ops->save_state(dev->port, dev->state);
@@ -301,19 +317,10 @@ void parport_release(struct pardevice *dev)
}
/* Now give the lurker a chance.
- * There should be a wakeup callback because we checked for it
+ * There must be a wakeup callback because we checked for it
* at registration.
*/
if (dev->port->lurker && (dev->port->lurker != dev)) {
- if (dev->port->lurker->wakeup) {
- dev->port->lurker->wakeup(dev->port->lurker->private);
- }
-#ifdef PARPORT_PARANOID
- else { /* can't happen */
- printk(KERN_DEBUG
- "%s (%s): lurker's wakeup callback went away!\n",
- dev->port->name, dev->name);
- }
-#endif
+ dev->port->lurker->wakeup(dev->port->lurker->private);
}
}
diff --git a/drivers/net/myri_sbus.c b/drivers/net/myri_sbus.c
index 4ae7aa069..4647f0fea 100644
--- a/drivers/net/myri_sbus.c
+++ b/drivers/net/myri_sbus.c
@@ -275,7 +275,7 @@ static void myri_init_rings(struct myri_eth *mp, int from_irq)
mp->rx_skbs[i] = skb;
skb->dev = dev;
skb_put(skb, RX_ALLOC_SIZE);
- rxd[i].myri_scatters[0].addr = (unsigned int) skb->data;
+ rxd[i].myri_scatters[0].addr = (unsigned long) skb->data;
rxd[i].myri_scatters[0].len = RX_ALLOC_SIZE;
rxd[i].ctx = i;
rxd[i].num_sg = 1;
@@ -429,7 +429,7 @@ static inline void myri_rx(struct myri_eth *mp, struct device *dev)
drops++;
DRX(("DROP "));
mp->enet_stats.rx_dropped++;
- rxd->myri_scatters[0].addr = (unsigned int) skb->data;
+ rxd->myri_scatters[0].addr = (unsigned long) skb->data;
rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
rxd->ctx = index;
rxd->num_sg = 1;
@@ -450,7 +450,7 @@ static inline void myri_rx(struct myri_eth *mp, struct device *dev)
mp->rx_skbs[index] = new_skb;
new_skb->dev = dev;
skb_put(new_skb, RX_ALLOC_SIZE);
- rxd->myri_scatters[0].addr = (unsigned int) new_skb->data;
+ rxd->myri_scatters[0].addr = (unsigned long) new_skb->data;
rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
rxd->ctx = index;
rxd->num_sg = 1;
@@ -474,7 +474,7 @@ static inline void myri_rx(struct myri_eth *mp, struct device *dev)
/* Reuse original ring buffer. */
DRX(("reuse "));
- rxd->myri_scatters[0].addr = (unsigned int) skb->data;
+ rxd->myri_scatters[0].addr = (unsigned long) skb->data;
rxd->myri_scatters[0].len = RX_ALLOC_SIZE;
rxd->ctx = index;
rxd->num_sg = 1;
@@ -618,7 +618,7 @@ static int myri_start_xmit(struct sk_buff *skb, struct device *dev)
txd = &sq->myri_txd[entry];
mp->tx_skbs[entry] = skb;
- txd->myri_gathers[0].addr = (unsigned int) skb->data;
+ txd->myri_gathers[0].addr = (unsigned long) skb->data;
txd->myri_gathers[0].len = len;
txd->num_sg = 1;
txd->chan = KERNEL_CHANNEL;
diff --git a/drivers/net/plip.c b/drivers/net/plip.c
index f06a66afc..2e2f3f3e2 100644
--- a/drivers/net/plip.c
+++ b/drivers/net/plip.c
@@ -1,4 +1,4 @@
-/* $Id: plip.c,v 1.3.6.2 1997/04/16 15:07:56 phil Exp $ */
+/* $Id: plip.c,v 1.1.1.1 1997/06/01 03:17:24 ralf Exp $ */
/* PLIP: A parallel port "network" driver for Linux. */
/* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */
/*
@@ -204,7 +204,7 @@ struct net_local {
struct tq_struct deferred;
struct plip_local snd_data;
struct plip_local rcv_data;
- struct ppd *pardev;
+ struct pardevice *pardev;
unsigned long trigger;
unsigned long nibble;
enum plip_connection_state connection;
@@ -228,7 +228,7 @@ __initfunc(int
plip_init_dev(struct device *dev, struct parport *pb))
{
struct net_local *nl;
- struct ppd *pardev;
+ struct pardevice *pardev;
dev->irq = pb->irq;
dev->base_addr = pb->base;
@@ -239,8 +239,8 @@ plip_init_dev(struct device *dev, struct parport *pb))
}
pardev = parport_register_device(pb, dev->name, plip_preempt,
- plip_wakeup,
- plip_interrupt, PARPORT_DEV_LURK, dev);
+ plip_wakeup, plip_interrupt,
+ PARPORT_DEV_LURK, dev);
printk(version);
printk("%s: Parallel port at %#3lx, using IRQ %d\n", dev->name,
@@ -1045,7 +1045,7 @@ plip_preempt(void *handle)
return 0;
}
-static int
+static void
plip_wakeup(void *handle)
{
struct device *dev = (struct device *)handle;
@@ -1058,12 +1058,12 @@ plip_wakeup(void *handle)
/* bus_owner is already set (but why?) */
printk(KERN_DEBUG "%s: I'm broken.\n", dev->name);
else
- return 1;
+ return;
}
if (!(dev->flags & IFF_UP))
/* Don't need the port when the interface is down */
- return 1;
+ return;
if (!parport_claim(nl->pardev)) {
nl->port_owner = 1;
@@ -1072,7 +1072,7 @@ plip_wakeup(void *handle)
outb (0x00, PAR_DATA(dev));
}
- return 0;
+ return;
}
static struct net_device_stats *
diff --git a/drivers/net/soundmodem/sm_sbc.c b/drivers/net/soundmodem/sm_sbc.c
index 2a2f874aa..fc26b57bf 100644
--- a/drivers/net/soundmodem/sm_sbc.c
+++ b/drivers/net/soundmodem/sm_sbc.c
@@ -339,6 +339,7 @@ static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
sti();
if (sm->dma.ptt_cnt <= 0) {
dma_receive(sm, curfrag);
+ hdlcdrv_arbitrate(dev, &sm->hdrv);
if (hdlcdrv_ptt(&sm->hdrv)) {
/* starting to transmit */
disable_dma(dev->dma);
@@ -352,10 +353,8 @@ static void sbc_interrupt(int irq, void *dev_id, struct pt_regs *regs)
sti();
dma_init_receive(sm);
setup_dma_dsp(dev, sm, 0);
- } else {
+ } else
dma_transmit(sm);
- hdlcdrv_arbitrate(dev, &sm->hdrv);
- }
sm_output_status(sm);
hdlcdrv_transmitter(dev, &sm->hdrv);
hdlcdrv_receiver(dev, &sm->hdrv);
diff --git a/drivers/net/soundmodem/sm_wss.c b/drivers/net/soundmodem/sm_wss.c
index 021ecc165..ef129930a 100644
--- a/drivers/net/soundmodem/sm_wss.c
+++ b/drivers/net/soundmodem/sm_wss.c
@@ -402,6 +402,7 @@ static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs)
sti();
if (sm->dma.ptt_cnt <= 0) {
dma_receive(sm, curfrag);
+ hdlcdrv_arbitrate(dev, &sm->hdrv);
if (hdlcdrv_ptt(&sm->hdrv)) {
/* starting to transmit */
disable_dma(dev->dma);
@@ -415,10 +416,8 @@ static void wss_interrupt(int irq, void *dev_id, struct pt_regs *regs)
sti();
dma_init_receive(sm);
setup_dma_wss(dev, sm, 0);
- } else {
+ } else
dma_transmit(sm);
- hdlcdrv_arbitrate(dev, &sm->hdrv);
- }
sm_output_status(sm);
hdlcdrv_transmitter(dev, &sm->hdrv);
hdlcdrv_receiver(dev, &sm->hdrv);
diff --git a/drivers/pnp/parport_probe.c b/drivers/pnp/parport_probe.c
index 0e7b56294..7ffde6f53 100644
--- a/drivers/pnp/parport_probe.c
+++ b/drivers/pnp/parport_probe.c
@@ -1,4 +1,4 @@
-/* $Id: parport_probe.c,v 1.1.1.1 1997/06/01 03:17:25 ralf Exp $
+/* $Id: parport_probe.c,v 1.2 1997/07/29 03:59:29 ralf Exp $
* Parallel port device probing code
*
* Authors: Carsten Gross, carsten@sol.wohnheim.uni-ulm.de
@@ -86,15 +86,15 @@ static long read_polled(struct parport *port, char *buf,
static struct wait_queue *wait_q = NULL;
-static int wakeup(void *ref)
+static void wakeup(void *ref)
{
struct pardevice **dev = (struct pardevice **)ref;
if (!wait_q || parport_claim(*dev))
- return 1;
+ return;
wake_up(&wait_q);
- return 0;
+ return;
}
int parport_probe(struct parport *port, char *buffer, int len)
diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile
index 4ce803b34..a5d2b3016 100644
--- a/drivers/sbus/char/Makefile
+++ b/drivers/sbus/char/Makefile
@@ -32,7 +32,9 @@ ifdef TADPOLE_FB_WEITEK
FB_OBJS += weitek.o
endif
ifdef SUN_FB_CREATOR
+ ifeq ($(ARCH),sparc64)
FB_OBJS += creator.o
+ endif
endif
#ifdef SUN_FB_FAST_ONE
# FB_OBJS += sun_8bit_fast1.o
diff --git a/drivers/sbus/char/creator.c b/drivers/sbus/char/creator.c
index 086f9b40e..3ce90092a 100644
--- a/drivers/sbus/char/creator.c
+++ b/drivers/sbus/char/creator.c
@@ -1,4 +1,4 @@
-/* $Id: creator.c,v 1.7 1997/07/17 02:21:47 davem Exp $
+/* $Id: creator.c,v 1.8 1997/07/22 06:14:12 davem Exp $
* creator.c: Creator/Creator3D frame buffer driver
*
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -235,7 +235,6 @@ ffb_wid_get (fbinfo_t *fb, struct fb_wid_list *wl)
struct fb_wid_item wit[30];
char *km = NULL;
int i, j;
- u32 l;
int err;
#ifdef CONFIG_SPARC32_COMPAT
@@ -287,7 +286,6 @@ ffb_wid_put (fbinfo_t *fb, struct fb_wid_list *wl)
struct fb_wid_item wit[30];
char *km = NULL;
int i, j;
- u32 l;
#ifdef CONFIG_SPARC32_COMPAT
if (current->tss.flags & SPARC_FLAG_32BIT) {
@@ -464,8 +462,6 @@ ffb_loadcmap (fbinfo_t *fb, int index, int count)
static int
ffb_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb)
{
- int i;
-
switch (cmd) {
case FBIO_WID_GET:
return ffb_wid_get (fb, (struct fb_wid_list *)arg);
diff --git a/drivers/sbus/char/suncons.c b/drivers/sbus/char/suncons.c
index cad446904..111f65f97 100644
--- a/drivers/sbus/char/suncons.c
+++ b/drivers/sbus/char/suncons.c
@@ -1,4 +1,4 @@
-/* $Id: suncons.c,v 1.66 1997/07/15 09:48:47 jj Exp $
+/* $Id: suncons.c,v 1.67 1997/07/20 05:59:42 davem Exp $
*
* suncons.c: Sun SparcStation console support.
*
@@ -931,7 +931,7 @@ __initfunc(static void
leo_setup (&fbinfo [n], n, base, io);
break;
#endif
-#ifdef SUN_FB_CREATOR
+#if defined(SUN_FB_CREATOR) && defined(__sparc_v9__)
case FBTYPE_CREATOR:
creator_setup (&fbinfo [n], n, con_node, base, io);
break;
diff --git a/drivers/sbus/char/tcx.c b/drivers/sbus/char/tcx.c
index 20c14a687..9eaad5bc7 100644
--- a/drivers/sbus/char/tcx.c
+++ b/drivers/sbus/char/tcx.c
@@ -1,4 +1,4 @@
-/* $Id: tcx.c,v 1.17 1997/07/17 02:21:50 davem Exp $
+/* $Id: tcx.c,v 1.18 1997/07/22 06:14:09 davem Exp $
* tcx.c: SUNW,tcx 24/8bit frame buffer driver
*
* Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
@@ -309,9 +309,9 @@ __initfunc(void tcx_setup (fbinfo_t *fb, int slot, int node, u32 tcx, struct lin
tcxinfo->tec = sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_TEC_OFFSET], 0,
sizeof (struct tcx_tec), "tcx_tec", fb->space, 0);
if (!fb->base){
- fb->base = (uint)
- sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET], 0,
- fb->type.fb_size, "tcx_ram", fb->space, 0);
+ fb->base = (unsigned long)
+ sparc_alloc_io((u32)tcxinfo->tcx_offsets [TCX_RAM8BIT_OFFSET],
+ 0, fb->type.fb_size, "tcx_ram", fb->space, 0);
}
if (prom_getbool (node, "hw-cursor")) {
diff --git a/drivers/sbus/char/weitek.c b/drivers/sbus/char/weitek.c
index 7b7b1bd72..7de26c2f7 100644
--- a/drivers/sbus/char/weitek.c
+++ b/drivers/sbus/char/weitek.c
@@ -1,4 +1,4 @@
-/* $Id: weitek.c,v 1.14 1997/07/17 02:21:53 davem Exp $
+/* $Id: weitek.c,v 1.15 1997/07/22 06:14:11 davem Exp $
* weitek.c: Tadpole P9100/P9000 console driver
*
* Copyright (C) 1996 David Redman (djhr@tadpole.co.uk)
@@ -99,8 +99,6 @@ weitek_loadcmap (void *fbinfo, int index, int count)
__initfunc(void weitek_setup(fbinfo_t *fb, int slot, u32 addr, int io))
{
- extern struct screen_info screen_info;
-
printk ("weitek%d at 0x%8.8x\n", slot, addr);
/* Fill in parameters we left out */
diff --git a/drivers/sbus/sbus.c b/drivers/sbus/sbus.c
index 4d59647cc..cf06585ff 100644
--- a/drivers/sbus/sbus.c
+++ b/drivers/sbus/sbus.c
@@ -385,5 +385,12 @@ sbus_init(unsigned long memory_start, unsigned long memory_end))
if (sparc_cpu_model == sun4u)
auxio_probe ();
#endif
+#ifdef __sparc_v9__
+ if (sparc_cpu_model == sun4u) {
+ extern void sun4u_start_timers(void);
+
+ sun4u_start_timers();
+ }
+#endif
return memory_start;
}
diff --git a/drivers/scsi/53c7,8xx.c b/drivers/scsi/53c7,8xx.c
index 44a78b12c..3d28dae2f 100644
--- a/drivers/scsi/53c7,8xx.c
+++ b/drivers/scsi/53c7,8xx.c
@@ -560,7 +560,7 @@ issue_to_cmd (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
* sure what the relationship between the NCR structures
* and host structures were going to be.
*/
- (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (issue[1]) -
+ (struct NCR53c7x0_cmd *) ((char *) bus_to_virt (le32_to_cpu(issue[1])) -
(hostdata->E_dsa_code_begin - hostdata->E_dsa_code_template) -
offsetof(struct NCR53c7x0_cmd, dsa))
/* If the IF TRUE bit is not set, it's a NOP */
@@ -795,18 +795,18 @@ NCR53c7x0_driver_init (struct Scsi_Host *host) {
for (i = 0, curr = (u32 *) hostdata->schedule;
i < host->can_queue; ++i, curr += 2) {
curr[0] = hostdata->NOP_insn;
- curr[1] = 0xdeadbeef;
+ curr[1] = le32_to_cpu(0xdeadbeef);
}
- curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE;
- curr[1] = (u32) virt_to_bus (hostdata->script) +
- hostdata->E_wait_reselect;
+ curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) | DBC_TCI_TRUE);
+ curr[1] = (u32) le32_to_cpu(virt_to_bus (hostdata->script) +
+ hostdata->E_wait_reselect);
hostdata->reconnect_dsa_head = 0;
hostdata->addr_reconnect_dsa_head = (u32)
- virt_to_bus((void *) &(hostdata->reconnect_dsa_head));
+ le32_to_cpu(virt_to_bus((void *) &(hostdata->reconnect_dsa_head)));
hostdata->expecting_iid = 0;
hostdata->expecting_sto = 0;
if (hostdata->options & OPTION_ALWAYS_SYNCHRONOUS)
- hostdata->initiate_sdtr = 0xffff;
+ hostdata->initiate_sdtr = le32_to_cpu(0xffff);
else
hostdata->initiate_sdtr = 0;
hostdata->talked_to = 0;
@@ -877,7 +877,7 @@ clock_to_ccf (int clock) {
* Returns : 0 on success, -1 on failure.
*/
-static inline int
+static int
NCR53c7x0_init (struct Scsi_Host *host) {
NCR53c7x0_local_declare();
int i, ccf, expected_ccf;
@@ -899,6 +899,7 @@ NCR53c7x0_init (struct Scsi_Host *host) {
* will differ.
*/
int expected_mapping = OPTION_IO_MAPPED;
+
NCR53c7x0_local_setup(host);
switch (hostdata->chip) {
@@ -929,10 +930,10 @@ NCR53c7x0_init (struct Scsi_Host *host) {
/* Assign constants accessed by NCR */
hostdata->NCR53c7xx_zero = 0;
- hostdata->NCR53c7xx_msg_reject = MESSAGE_REJECT;
- hostdata->NCR53c7xx_msg_abort = ABORT;
- hostdata->NCR53c7xx_msg_nop = NOP;
- hostdata->NOP_insn = (DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24;
+ hostdata->NCR53c7xx_msg_reject = le32_to_cpu(MESSAGE_REJECT);
+ hostdata->NCR53c7xx_msg_abort = le32_to_cpu(ABORT);
+ hostdata->NCR53c7xx_msg_nop = le32_to_cpu(NOP);
+ hostdata->NOP_insn = le32_to_cpu((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24);
if (expected_mapping == -1 ||
(hostdata->options & (OPTION_MEMORY_MAPPED)) !=
@@ -1131,7 +1132,14 @@ NCR53c7x0_init (struct Scsi_Host *host) {
search->irq == host->irq && search != host); search=search->next);
if (!search) {
- if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL)) {
+#ifdef __powerpc__
+ if (request_irq(host->irq, NCR53c7x0_intr, SA_SHIRQ, "53c7,8xx", NULL))
+#else
+ if (request_irq(host->irq, NCR53c7x0_intr, SA_INTERRUPT, "53c7,8xx", NULL))
+#endif
+ {
+
+
printk("scsi%d : IRQ%d not free, detaching\n"
" You have either a configuration problem, or a\n"
" broken BIOS. You may wish to manually assign\n"
@@ -1453,6 +1461,21 @@ ncr_pci_init (Scsi_Host_Template *tpnt, int board, int chip,
return -1;
}
+#ifdef __powerpc__
+ if ( ! (command & PCI_COMMAND_MASTER)) {
+ printk("SCSI: PCI Master Bit has not been set. Setting...\n");
+ command |= PCI_COMMAND_MASTER|PCI_COMMAND_IO;
+ pcibios_write_config_word(bus, device_fn, PCI_COMMAND, command);
+ if (io_port >= 0x10000000) {
+ /* Mapping on PowerPC can't handle this! */
+ unsigned long new_io_port;
+ new_io_port = (io_port & 0x00FFFFFF) | 0x01000000;
+ printk("SCSI: I/O moved from %08X to %08x\n", io_port, new_io_port);
+ io_port = new_io_port;
+ pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_0, io_port);
+ }
+ }
+#endif
/*
* Bit 0 is the address space indicator and must be one for I/O
@@ -1613,6 +1636,9 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
unsigned char tmp;
int i, ncr_to_memory, memory_to_ncr;
u32 base;
+#ifdef __powerpc__
+ unsigned long *script_ptr;
+#endif
NCR53c7x0_local_setup(host);
@@ -1801,6 +1827,14 @@ NCR53c8x0_init_fixup (struct Scsi_Host *host) {
printk("scsi%d : NCR dsa_fields start is %d not %d\n",
host->host_no, A_dsa_fields_start, Ent_dsa_code_template_end -
Ent_dsa_zero);
+#ifdef __powerpc__
+/* The PowerPC is Big Endian - adjust script appropriately */
+ script_ptr = hostdata->script;
+ for (i = 0; i < sizeof(SCRIPT); i += sizeof(long))
+ {
+ *script_ptr++ = le32_to_cpu(*script_ptr);
+ }
+#endif
printk("scsi%d : NCR code relocated to 0x%lx (virt 0x%p)\n", host->host_no,
virt_to_bus(hostdata->script), hostdata->script);
@@ -1884,7 +1918,7 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
" also verify that the board is jumpered to use PCI INTA, since\n"
" most PCI motherboards lack support for INTB, INTC, and INTD.\n"
: "");
- else if (hostdata->test_completed != 1)
+ else if (hostdata->test_completed != 1)
printk ("scsi%d : test 1 bad interrupt value (%d)\n",
host->host_no, hostdata->test_completed);
else
@@ -1922,16 +1956,17 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
cmd[1] = cmd[2] = cmd[3] = cmd[5] = 0;
cmd[4] = sizeof(data);
- dsa[2] = 1;
- dsa[3] = virt_to_bus(&identify);
- dsa[4] = 6;
- dsa[5] = virt_to_bus(&cmd);
- dsa[6] = sizeof(data);
- dsa[7] = virt_to_bus(&data);
- dsa[8] = 1;
- dsa[9] = virt_to_bus(&status);
- dsa[10] = 1;
- dsa[11] = virt_to_bus(&msg);
+/* Need to adjust for endian-ness */
+ dsa[2] = le32_to_cpu(1);
+ dsa[3] = le32_to_cpu(virt_to_bus(&identify));
+ dsa[4] = le32_to_cpu(6);
+ dsa[5] = le32_to_cpu(virt_to_bus(&cmd));
+ dsa[6] = le32_to_cpu(sizeof(data));
+ dsa[7] = le32_to_cpu(virt_to_bus(&data));
+ dsa[8] = le32_to_cpu(1);
+ dsa[9] = le32_to_cpu(virt_to_bus(&status));
+ dsa[10] = le32_to_cpu(1);
+ dsa[11] = le32_to_cpu(virt_to_bus(&msg));
for (i = 0; i < 3; ++i) {
cli();
@@ -1942,7 +1977,7 @@ NCR53c8xx_run_tests (struct Scsi_Host *host) {
}
/* SCNTL3 SDID */
- dsa[0] = (0x33 << 24) | (i << 16) ;
+ dsa[0] = le32_to_cpu((0x33 << 24) | (i << 16)) ;
hostdata->idle = 0;
hostdata->test_running = 2;
hostdata->test_completed = -1;
@@ -2004,9 +2039,22 @@ NCR53c8xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
host->hostdata;
int i;
+#ifdef __powerpc__
+ int len;
+ unsigned long *dsa_ptr;
+#endif
memcpy (cmd->dsa, hostdata->script + (hostdata->E_dsa_code_template / 4),
hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template);
+#ifdef __powerpc__
+ /* Note: the script has already been 'endianized' */
+ dsa_ptr = cmd->dsa;
+ len = hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template;
+ for (i = 0; i < len; i += sizeof(long))
+ {
+ *dsa_ptr++ = le32_to_cpu(*dsa_ptr);
+ }
+#endif
/*
* Note : within the NCR 'C' code, dsa points to the _start_
@@ -2046,6 +2094,14 @@ NCR53c8xx_dsa_fixup (struct NCR53c7x0_cmd *cmd) {
/* XXX - new start stuff */
patch_abs_32 (cmd->dsa, Ent_dsa_code_template / sizeof(u32),
dsa_temp_addr_dsa_value, virt_to_bus(&cmd->dsa_addr));
+#ifdef __powerpc__
+ dsa_ptr = cmd->dsa;
+ len = hostdata->E_dsa_code_template_end - hostdata->E_dsa_code_template;
+ for (i = 0; i < len; i += sizeof(long))
+ {
+ *dsa_ptr++ = le32_to_cpu(*dsa_ptr);
+ }
+#endif
}
@@ -2125,7 +2181,7 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
if (issue_to_cmd (host, hostdata, (u32 *) curr) == cmd)
{
curr[0] = hostdata->NOP_insn;
- curr[1] = 0xdeadbeef;
+ curr[1] = le32_to_cpu(0xdeadbeef);
++found;
break;
}
@@ -2140,13 +2196,13 @@ abnormal_finished (struct NCR53c7x0_cmd *cmd, int result) {
*/
for (left = host->can_queue,
- ncr_search = hostdata->reconnect_dsa_head,
+ ncr_search = le32_to_cpu(hostdata->reconnect_dsa_head),
ncr_prev = &hostdata->reconnect_dsa_head;
left >= 0 && ncr_search &&
((char*)bus_to_virt(ncr_search) + hostdata->dsa_start)
!= (char *) cmd->dsa;
ncr_prev = (u32*) ((char*)bus_to_virt(ncr_search) +
- hostdata->dsa_next), ncr_search = *ncr_prev, --left);
+ hostdata->dsa_next), ncr_search = le32_to_cpu(*ncr_prev), --left);
if (left < 0)
printk("scsi%d: loop detected in ncr reconnect list\n",
@@ -2491,7 +2547,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
dsps = NCR53c7x0_read32(DSPS_REG);
dsp = (u32 *) bus_to_virt(NCR53c7x0_read32(DSP_REG));
- if (hostdata->options & OPTION_DEBUG_INTR)
+ if (hostdata->options & OPTION_DEBUG_INTR)
printk ("scsi%d : DSPS = 0x%x\n", host->host_no, dsps);
switch (dsps) {
@@ -2584,9 +2640,9 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
hostdata->msg_buf[4] = 0; /* 0 offset = async */
asynchronous (host, c->target);
}
- patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, 5);
+ patch_dsa_32 (cmd->dsa, dsa_msgout_other, 0, le32_to_cpu(5));
patch_dsa_32 (cmd->dsa, dsa_msgout_other, 1, (u32)
- virt_to_bus ((void *)&hostdata->msg_buf));
+ le32_to_cpu(virt_to_bus ((void *)&hostdata->msg_buf)));
hostdata->dsp = hostdata->script +
hostdata->E_respond_message / sizeof(u32);
hostdata->dsp_changed = 1;
@@ -2649,14 +2705,14 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
* agrees with this being an untagged queue'd command.
*/
- patch_dsa_32 (cmd->dsa, dsa_msgout, 0, 1);
+ patch_dsa_32 (cmd->dsa, dsa_msgout, 0, le32_to_cpu(1));
/*
* Modify the table indirect for COMMAND OUT phase, since
* Request Sense is a six byte command.
*/
- patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, 6);
+ patch_dsa_32 (cmd->dsa, dsa_cmdout, 0, le32_to_cpu(6));
c->cmnd[0] = REQUEST_SENSE;
c->cmnd[1] &= 0xe0; /* Zero all but LUN */
@@ -2672,17 +2728,17 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
*/
patch_dsa_32 (cmd->dsa, dsa_dataout, 0,
- virt_to_bus(hostdata->script) + hostdata->E_other_transfer);
+ le32_to_cpu(virt_to_bus(hostdata->script) + hostdata->E_other_transfer));
patch_dsa_32 (cmd->dsa, dsa_datain, 0,
- virt_to_bus(cmd->data_transfer_start));
- cmd->data_transfer_start[0] = (((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I |
- DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer);
- cmd->data_transfer_start[1] = (u32) virt_to_bus(c->sense_buffer);
+ le32_to_cpu(virt_to_bus(cmd->data_transfer_start)));
+ cmd->data_transfer_start[0] = le32_to_cpu((((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I |
+ DCMD_BMI_IO)) << 24) | sizeof(c->sense_buffer));
+ cmd->data_transfer_start[1] = (u32) le32_to_cpu(virt_to_bus(c->sense_buffer));
- cmd->data_transfer_start[2] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP)
- << 24) | DBC_TCI_TRUE;
- cmd->data_transfer_start[3] = (u32) virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
+ cmd->data_transfer_start[2] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP)
+ << 24) | DBC_TCI_TRUE);
+ cmd->data_transfer_start[3] = (u32) le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer);
/*
* Currently, this command is flagged as completed, ie
@@ -2691,7 +2747,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
* status, etc are used.
*/
- cmd->cmd->result = 0xffff;
+ cmd->cmd->result = le32_to_cpu(0xffff);
/*
* Restart command as a REQUEST SENSE.
@@ -2732,7 +2788,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
host->host_no, NCR53c7x0_read32(DSA_REG), dsa);
printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt(cmd->saved_data_pointer));
+ bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)));
print_insn (host, hostdata->script + Ent_reselected_ok /
sizeof(u32), "", 1);
printk ("scsi%d : sxfer=0x%x, scntl3=0x%x\n",
@@ -2765,7 +2821,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
if (dsa) {
printk("scsi%d : resume address is 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer));
+ bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)));
#if 0
printk("scsi%d : template code :\n", host->host_no);
for (code = dsa + (Ent_dsa_code_check_reselect - Ent_dsa_zero)
@@ -2794,7 +2850,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
printk("scsi%d : resume address is 0x%x (virt 0x%p)\n"
" (temp was 0x%x (virt 0x%p))\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer),
+ bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)),
NCR53c7x0_read32 (TEMP_REG),
bus_to_virt (NCR53c7x0_read32(TEMP_REG)));
}
@@ -2888,7 +2944,7 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
OPTION_DEBUG_DISCONNECT)) {
printk ("scsi%d : saved data pointer 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer,
- bus_to_virt (cmd->saved_data_pointer));
+ bus_to_virt (le32_to_cpu(cmd->saved_data_pointer)));
print_progress (c);
}
return SPECIFIC_INT_RESTART;
@@ -2901,11 +2957,11 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
int size;
printk ("scsi%d : restored data pointer 0x%x (virt 0x%p)\n",
host->host_no, cmd->saved_data_pointer, bus_to_virt (
- cmd->saved_data_pointer));
+ le32_to_cpu(cmd->saved_data_pointer)));
size = print_insn (host, (u32 *)
- bus_to_virt(cmd->saved_data_pointer), "", 1);
+ bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)), "", 1);
size = print_insn (host, (u32 *)
- bus_to_virt(cmd->saved_data_pointer) + size, "", 1);
+ bus_to_virt(le32_to_cpu(cmd->saved_data_pointer)) + size, "", 1);
print_progress (c);
}
#if 0
@@ -2947,8 +3003,8 @@ NCR53c8x0_dstat_sir_intr (struct Scsi_Host *host, struct
(int) NCR53c7x0_read8(SCNTL3_REG_800),
datapath_residual (host)) ;
print_insn (host, dsp, "", 1);
- size = print_insn (host, (u32 *) bus_to_virt(dsp[1]), "", 1);
- print_insn (host, (u32 *) bus_to_virt(dsp[1]) + size, "", 1);
+ size = print_insn (host, (u32 *) bus_to_virt(le32_to_cpu(dsp[1])), "", 1);
+ print_insn (host, (u32 *) bus_to_virt(le32_to_cpu(dsp[1])) + size, "", 1);
}
return SPECIFIC_INT_RESTART;
#endif
@@ -3543,7 +3599,6 @@ create_cmd (Scsi_Cmnd *cmd) {
case MODE_SELECT:
case WRITE_6:
case WRITE_10:
- case START_STOP: /* also SCAN, which may do DATA OUT */
#if 0
printk("scsi%d : command is ", host->host_no);
print_command(cmd->cmnd);
@@ -3562,6 +3617,7 @@ create_cmd (Scsi_Cmnd *cmd) {
* These commands do no data transfer, we should force an
* interrupt if a data phase is attempted on them.
*/
+ case START_STOP: /* also SCAN, which may do DATA OUT */
case TEST_UNIT_READY:
datain = dataout = 0;
break;
@@ -3612,8 +3668,8 @@ create_cmd (Scsi_Cmnd *cmd) {
* will start the data transfer over at the beginning.
*/
- tmp->saved_data_pointer = virt_to_bus (hostdata->script) +
- hostdata->E_data_transfer;
+ tmp->saved_data_pointer = le32_to_cpu(virt_to_bus (hostdata->script) +
+ hostdata->E_data_transfer);
/*
* Initialize Linux specific fields.
@@ -3622,9 +3678,9 @@ create_cmd (Scsi_Cmnd *cmd) {
tmp->cmd = cmd;
tmp->next = NULL;
tmp->flags = 0;
- tmp->dsa_next_addr = virt_to_bus(tmp->dsa) + hostdata->dsa_next -
- hostdata->dsa_start;
- tmp->dsa_addr = virt_to_bus(tmp->dsa) - hostdata->dsa_start;
+ tmp->dsa_next_addr = le32_to_cpu(virt_to_bus(tmp->dsa) + hostdata->dsa_next -
+ hostdata->dsa_start);
+ tmp->dsa_addr = le32_to_cpu(virt_to_bus(tmp->dsa) - hostdata->dsa_start);
/*
* Calculate addresses of dynamic code to fill in DSA
@@ -3650,8 +3706,8 @@ create_cmd (Scsi_Cmnd *cmd) {
if (hostdata->dsa_fixup)
hostdata->dsa_fixup(tmp);
- patch_dsa_32(tmp->dsa, dsa_next, 0, 0);
- patch_dsa_32(tmp->dsa, dsa_cmnd, 0, virt_to_bus(cmd));
+ patch_dsa_32(tmp->dsa, dsa_next, 0, le32_to_cpu(0));
+ patch_dsa_32(tmp->dsa, dsa_cmnd, 0, le32_to_cpu(virt_to_bus(cmd)));
if (hostdata->options & OPTION_DEBUG_SYNCHRONOUS)
if (hostdata->sync[cmd->target].select_indirect !=
@@ -3664,8 +3720,8 @@ create_cmd (Scsi_Cmnd *cmd) {
}
- patch_dsa_32(tmp->dsa, dsa_select, 0, hostdata->sync[cmd->target].
- select_indirect);
+ patch_dsa_32(tmp->dsa, dsa_select, 0, le32_to_cpu(hostdata->sync[cmd->target].
+ select_indirect));
/*
* Right now, we'll do the WIDE and SYNCHRONOUS negotiations on
* different commands; although it should be trivial to do them
@@ -3674,7 +3730,7 @@ create_cmd (Scsi_Cmnd *cmd) {
if (hostdata->initiate_wdtr & (1 << cmd->target)) {
memcpy ((void *) (tmp->select + 1), (void *) wdtr_message,
sizeof(wdtr_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(wdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(wdtr_message)));
save_flags(flags);
cli();
hostdata->initiate_wdtr &= ~(1 << cmd->target);
@@ -3682,7 +3738,7 @@ create_cmd (Scsi_Cmnd *cmd) {
} else if (hostdata->initiate_sdtr & (1 << cmd->target)) {
memcpy ((void *) (tmp->select + 1), (void *) sdtr_message,
sizeof(sdtr_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(sdtr_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(sdtr_message)));
tmp->flags |= CMD_FLAG_SDTR;
save_flags(flags);
cli();
@@ -3695,40 +3751,40 @@ create_cmd (Scsi_Cmnd *cmd) {
!(hostdata->options & OPTION_NO_ASYNC)) {
memcpy ((void *) (tmp->select + 1), (void *) async_message,
sizeof(async_message));
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1 + sizeof(async_message));
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1 + sizeof(async_message)));
tmp->flags |= CMD_FLAG_SDTR;
}
#endif
else
- patch_dsa_32(tmp->dsa, dsa_msgout, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_msgout, 0, le32_to_cpu(1));
hostdata->talked_to |= (1 << cmd->target);
tmp->select[0] = (hostdata->options & OPTION_DISCONNECT) ?
IDENTIFY (1, cmd->lun) : IDENTIFY (0, cmd->lun);
- patch_dsa_32(tmp->dsa, dsa_msgout, 1, virt_to_bus(tmp->select));
- patch_dsa_32(tmp->dsa, dsa_cmdout, 0, cmd->cmd_len);
- patch_dsa_32(tmp->dsa, dsa_cmdout, 1, virt_to_bus(cmd->cmnd));
- patch_dsa_32(tmp->dsa, dsa_dataout, 0, cmd_dataout ?
+ patch_dsa_32(tmp->dsa, dsa_msgout, 1, le32_to_cpu(virt_to_bus(tmp->select)));
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 0, le32_to_cpu(cmd->cmd_len));
+ patch_dsa_32(tmp->dsa, dsa_cmdout, 1, le32_to_cpu(virt_to_bus(cmd->cmnd)));
+ patch_dsa_32(tmp->dsa, dsa_dataout, 0, le32_to_cpu(cmd_dataout ?
virt_to_bus (cmd_dataout)
- : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
- patch_dsa_32(tmp->dsa, dsa_datain, 0, cmd_datain ?
+ : virt_to_bus (hostdata->script) + hostdata->E_other_transfer));
+ patch_dsa_32(tmp->dsa, dsa_datain, 0, le32_to_cpu(cmd_datain ?
virt_to_bus (cmd_datain)
- : virt_to_bus (hostdata->script) + hostdata->E_other_transfer);
+ : virt_to_bus (hostdata->script) + hostdata->E_other_transfer));
/*
* XXX - need to make endian aware, should use separate variables
* for both status and message bytes.
*/
- patch_dsa_32(tmp->dsa, dsa_msgin, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_msgin, 0, le32_to_cpu(1));
/*
* FIXME : these only works for little endian. We probably want to
* provide message and status fields in the NCR53c7x0_cmd
* structure, and assign them to cmd->result when we're done.
*/
- patch_dsa_32(tmp->dsa, dsa_msgin, 1, virt_to_bus(&cmd->result) + 1);
- patch_dsa_32(tmp->dsa, dsa_status, 0, 1);
- patch_dsa_32(tmp->dsa, dsa_status, 1, virt_to_bus(&cmd->result));
- patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, 1);
+ patch_dsa_32(tmp->dsa, dsa_msgin, 1, le32_to_cpu(virt_to_bus(&cmd->result) + 1));
+ patch_dsa_32(tmp->dsa, dsa_status, 0, le32_to_cpu(1));
+ patch_dsa_32(tmp->dsa, dsa_status, 1, le32_to_cpu(virt_to_bus(&cmd->result)));
+ patch_dsa_32(tmp->dsa, dsa_msgout_other, 0, le32_to_cpu(1));
patch_dsa_32(tmp->dsa, dsa_msgout_other, 1,
- virt_to_bus(&(hostdata->NCR53c7xx_msg_nop)));
+ le32_to_cpu(virt_to_bus(&(hostdata->NCR53c7xx_msg_nop))));
/*
* Generate code for zero or more of the DATA IN, DATA OUT phases
@@ -3779,15 +3835,15 @@ create_cmd (Scsi_Cmnd *cmd) {
if (datain) {
/* CALL other_in, WHEN NOT DATA_IN */
- cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+ cmd_datain[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
DCMD_TCI_IO) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd_datain[1] = virt_to_bus (hostdata->script) +
- hostdata->E_other_in;
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+ cmd_datain[1] = le32_to_cpu(virt_to_bus (hostdata->script) +
+ hostdata->E_other_in);
/* MOVE count, buf, WHEN DATA_IN */
- cmd_datain[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO)
- << 24) | count;
- cmd_datain[3] = buf;
+ cmd_datain[2] = le32_to_cpu(((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I | DCMD_BMI_IO)
+ << 24) | count);
+ cmd_datain[3] = le32_to_cpu(buf);
#if 0
print_insn (host, cmd_datain, "dynamic ", 1);
print_insn (host, cmd_datain + 2, "dynamic ", 1);
@@ -3795,14 +3851,14 @@ create_cmd (Scsi_Cmnd *cmd) {
}
if (dataout) {
/* CALL other_out, WHEN NOT DATA_OUT */
- cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd_dataout[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_out;
+ cmd_dataout[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL) << 24) |
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+ cmd_dataout[1] = le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_out);
/* MOVE count, buf, WHEN DATA+OUT */
- cmd_dataout[2] = ((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24)
- | count;
- cmd_dataout[3] = buf;
+ cmd_dataout[2] = le32_to_cpu(((DCMD_TYPE_BMI | DCMD_BMI_OP_MOVE_I) << 24)
+ | count);
+ cmd_dataout[3] = le32_to_cpu(buf);
#if 0
print_insn (host, cmd_dataout, "dynamic ", 1);
print_insn (host, cmd_dataout + 2, "dynamic ", 1);
@@ -3817,10 +3873,10 @@ create_cmd (Scsi_Cmnd *cmd) {
if (datain) {
- cmd_datain[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- cmd_datain[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
+ cmd_datain[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE);
+ cmd_datain[1] = le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer);
#if 0
print_insn (host, cmd_datain, "dynamic jump ", 1);
#endif
@@ -3834,10 +3890,10 @@ create_cmd (Scsi_Cmnd *cmd) {
}
#endif
if (dataout) {
- cmd_dataout[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
- cmd_dataout[1] = virt_to_bus(hostdata->script) +
- hostdata->E_other_transfer;
+ cmd_dataout[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE);
+ cmd_dataout[1] = le32_to_cpu(virt_to_bus(hostdata->script) +
+ hostdata->E_other_transfer);
#if 0
print_insn (host, cmd_dataout, "dynamic jump ", 1);
#endif
@@ -3894,26 +3950,25 @@ NCR53c7xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) {
|| hostdata->state == STATE_DISABLED) {
printk("scsi%d : disabled or bad target %d lun %d\n", host->host_no,
cmd->target, cmd->lun);
- cmd->result = (DID_BAD_TARGET << 16);
+ cmd->result = DID_BAD_TARGET << 16;
} else if ((hostdata->options & OPTION_DEBUG_NCOMMANDS_LIMIT) &&
(hostdata->debug_count_limit == 0)) {
printk("scsi%d : maximum commands exceeded\n", host->host_no);
- cmd->result = (DID_BAD_TARGET << 16);
- cmd->result = (DID_BAD_TARGET << 16);
+ cmd->result = DID_BAD_TARGET << 16;
} else if (hostdata->options & OPTION_DEBUG_READ_ONLY) {
switch (cmd->cmnd[0]) {
case WRITE_6:
case WRITE_10:
printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
host->host_no);
- cmd->result = (DID_BAD_TARGET << 16);
+ cmd->result = DID_BAD_TARGET << 16;
}
} else {
if ((hostdata->options & OPTION_DEBUG_TARGET_LIMIT) &&
hostdata->debug_count_limit != -1)
--hostdata->debug_count_limit;
restore_flags (flags);
- cmd->result = 0xffff; /* The NCR will overwrite message
+ cmd->result = le32_to_cpu(0xffff); /* The NCR will overwrite message
and status with valid data */
cmd->host_scribble = (unsigned char *) tmp = create_cmd (cmd);
}
@@ -3967,7 +4022,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
int i;
NCR53c7x0_local_setup(host);
-#if 0
+#if 0
printk("scsi%d : new dsa is 0x%lx (virt 0x%p)\n", host->host_no,
virt_to_bus(dsa), dsa);
#endif
@@ -3982,7 +4037,7 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
if (hostdata->state == STATE_DISABLED) {
printk("scsi%d : driver disabled\n", host->host_no);
- tmp->result = (DID_BAD_TARGET << 16);
+ tmp->result = DID_BAD_TARGET << 16;
cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
hostdata->free = cmd;
tmp->scsi_done(tmp);
@@ -4001,18 +4056,18 @@ to_schedule_list (struct Scsi_Host *host, struct NCR53c7x0_hostdata *hostdata,
/* Restore this instruction to a NOP once the command starts */
cmd->dsa [(hostdata->dsa_jump_dest - hostdata->dsa_start) /
- sizeof(u32)] = (u32) virt_to_bus ((void *)curr);
+ sizeof(u32)] = (u32) le32_to_cpu(virt_to_bus ((void *)curr));
/* Replace the current jump operand. */
curr[1] =
- virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
- hostdata->E_dsa_code_template;
+ le32_to_cpu(virt_to_bus ((void *) cmd->dsa) + hostdata->E_dsa_code_begin -
+ hostdata->E_dsa_code_template);
/* Replace the NOP instruction with a JUMP */
- curr[0] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
- DBC_TCI_TRUE;
+ curr[0] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP) << 24) |
+ DBC_TCI_TRUE);
} else {
printk ("scsi%d: no free slot\n", host->host_no);
disable(host);
- tmp->result = (DID_ERROR << 16);
+ tmp->result = DID_ERROR << 16;
cmd->next = (struct NCR53c7x0_cmd *) hostdata->free;
hostdata->free = cmd;
tmp->scsi_done(tmp);
@@ -4101,7 +4156,7 @@ process_issue_queue (unsigned long flags) {
if (hostdata->state == STATE_DISABLED) {
tmp = (Scsi_Cmnd *) hostdata->issue_queue;
hostdata->issue_queue = (Scsi_Cmnd *) tmp->SCp.ptr;
- tmp->result = (DID_BAD_TARGET << 16);
+ tmp->result = DID_BAD_TARGET << 16;
if (tmp->host_scribble) {
((struct NCR53c7x0_cmd *)tmp->host_scribble)->next =
hostdata->free;
@@ -4133,6 +4188,7 @@ process_issue_queue (unsigned long flags) {
(struct NCR53c7x0_cmd *)
tmp->host_scribble);
} else {
+ tmp->result = le32_to_cpu(tmp->result);
if (((tmp->result & 0xff) == 0xff) ||
((tmp->result & 0xff00) == 0xff00)) {
printk ("scsi%d : danger Will Robinson!\n",
@@ -4370,7 +4426,6 @@ NCR53c7x0_intr (int irq, void *dev_id, struct pt_regs * regs) {
char buf[80]; /* Debugging sprintf buffer */
size_t buflen; /* Length of same */
#endif
-
do {
done = 1;
for (host = first_host; host; host = host->next)
@@ -4449,10 +4504,16 @@ restart:
printk ("scsi%d : looking at result of 0x%x\n",
host->host_no, cmd->cmd->result);
#endif
-
+
+#ifdef __powerpc__
+ if (tmp->result == le32_to_cpu(0xffff))
+ continue;
+ tmp->result = le32_to_cpu(tmp->result);
+#else
if (((tmp->result & 0xff) == 0xff) ||
((tmp->result & 0xff00) == 0xff00))
continue;
+#endif
search_found = 1;
@@ -4537,7 +4598,6 @@ restart:
printk("scsi%d : no active command\n", host->host_no);
}
}
-
if (istat & ISTAT_SIP) {
if (hostdata->options & OPTION_DEBUG_INTR)
printk ("scsi%d : ISTAT_SIP\n", host->host_no);
@@ -4872,12 +4932,12 @@ intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
* from normal dynamic code.
*/
if (dsp != cmd->residual + 2) {
- cmd->residual[0] = ((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
+ cmd->residual[0] = le32_to_cpu(((DCMD_TYPE_TCI | DCMD_TCI_OP_CALL |
((dcmd & DCMD_BMI_IO) ? DCMD_TCI_IO : 0)) << 24) |
- DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE;
- cmd->residual[1] = virt_to_bus(hostdata->script)
+ DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE);
+ cmd->residual[1] = le32_to_cpu(virt_to_bus(hostdata->script)
+ ((dcmd & DCMD_BMI_IO)
- ? hostdata->E_other_in : hostdata->E_other_out);
+ ? hostdata->E_other_in : hostdata->E_other_out));
}
/*
@@ -4885,17 +4945,17 @@ intr_phase_mismatch (struct Scsi_Host *host, struct NCR53c7x0_cmd *cmd) {
* move instruction, reflecting the pointer and count at the
* time of the phase mismatch.
*/
- cmd->residual[2] = dbc_dcmd + residual;
- cmd->residual[3] = NCR53c7x0_read32(DNAD_REG) - residual;
+ cmd->residual[2] = le32_to_cpu(dbc_dcmd + residual);
+ cmd->residual[3] = le32_to_cpu(NCR53c7x0_read32(DNAD_REG) - residual);
/*
* The third and final instruction is a jump to the instruction
* which follows the instruction which had to be 'split'
*/
if (dsp != cmd->residual + 2) {
- cmd->residual[4] = ((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP)
- << 24) | DBC_TCI_TRUE;
- cmd->residual[5] = virt_to_bus(dsp_next);
+ cmd->residual[4] = le32_to_cpu(((DCMD_TYPE_TCI|DCMD_TCI_OP_JUMP)
+ << 24) | DBC_TCI_TRUE);
+ cmd->residual[5] = le32_to_cpu(virt_to_bus(dsp_next));
}
/*
@@ -5375,11 +5435,11 @@ print_insn (struct Scsi_Host *host, const u32 *insn,
*/
sprintf(buf, "%s0x%lx (virt 0x%p) : 0x%08x 0x%08x (virt 0x%p)",
(prefix ? prefix : ""), virt_to_bus((void *) insn), insn,
- insn[0], insn[1], bus_to_virt (insn[1]));
+ insn[0], insn[1], bus_to_virt (le32_to_cpu(insn[1])));
tmp = buf + strlen(buf);
if ((dcmd & DCMD_TYPE_MASK) == DCMD_TYPE_MMI) {
sprintf (tmp, " 0x%08x (virt 0x%p)\n", insn[2],
- bus_to_virt(insn[2]));
+ bus_to_virt(le32_to_cpu(insn[2])));
size = 3;
} else {
sprintf (tmp, "\n");
@@ -5439,6 +5499,7 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
struct NCR53c7x0_hostdata *hostdata = host ? (struct NCR53c7x0_hostdata *)
host->hostdata : NULL;
unsigned long flags;
+ unsigned long result;
struct NCR53c7x0_cmd *curr, **prev;
Scsi_Cmnd *me, **last;
#if 0
@@ -5530,7 +5591,8 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
&(curr->next), curr = (struct NCR53c7x0_cmd *) curr->next);
if (curr) {
- if ((cmd->result & 0xff) != 0xff && (cmd->result & 0xff00) != 0xff00) {
+ result = le32_to_cpu(cmd->result);
+ if ((result & 0xff) != 0xff && (result & 0xff00) != 0xff00) {
if (prev)
*prev = (struct NCR53c7x0_cmd *) curr->next;
curr->next = (struct NCR53c7x0_cmd *) hostdata->free;
@@ -5561,8 +5623,9 @@ NCR53c7xx_abort (Scsi_Cmnd *cmd) {
cmd->host_scribble = NULL;
}
- if (((cmd->result & 0xff00) == 0xff00) ||
- ((cmd->result & 0xff) == 0xff)) {
+ result = le32_to_cpu(cmd->result);
+ if (((result & 0xff00) == 0xff00) ||
+ ((result & 0xff) == 0xff)) {
printk ("scsi%d : did this command ever run?\n", host->host_no);
cmd->result = DID_ABORT << 16;
} else {
@@ -5709,7 +5772,7 @@ insn_to_offset (Scsi_Cmnd *cmd, u32 *insn) {
(insn >= ncmd->residual &&
insn < (ncmd->residual +
sizeof(ncmd->residual))))) {
- ptr = bus_to_virt(insn[3]);
+ ptr = bus_to_virt(le32_to_cpu(insn[3]));
if ((buffers = cmd->use_sg)) {
for (offset = 0,
@@ -5764,7 +5827,7 @@ print_progress (Scsi_Cmnd *cmd) {
continue;
if (!i) {
where = "saved";
- ptr = bus_to_virt(ncmd->saved_data_pointer);
+ ptr = bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer));
} else {
where = "active";
ptr = bus_to_virt (NCR53c7x0_read32 (DSP_REG) -
@@ -5782,9 +5845,9 @@ print_progress (Scsi_Cmnd *cmd) {
cmd->host->host_no, where);
if (ncmd) {
size = print_insn (cmd->host,
- bus_to_virt(ncmd->saved_data_pointer), "", 1);
+ bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer)), "", 1);
print_insn (cmd->host,
- bus_to_virt(ncmd->saved_data_pointer) + size * sizeof(u32),
+ bus_to_virt(le32_to_cpu(ncmd->saved_data_pointer)) + size * sizeof(u32),
"", 1);
}
}
@@ -5809,9 +5872,9 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
" + %d : dsa_msgout length = %u, data = 0x%x (virt 0x%p)\n" ,
prefix ? prefix : "",
host->host_no, virt_to_bus (dsa), dsa, hostdata->dsa_msgout,
- dsa[hostdata->dsa_msgout / sizeof(u32)],
- dsa[hostdata->dsa_msgout / sizeof(u32) + 1],
- bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
+ le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]),
+ le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1]),
+ bus_to_virt (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1])));
/*
* Only print messages if they're sane in length so we don't
@@ -5819,10 +5882,10 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
* anything.
*/
- if (dsa[hostdata->dsa_msgout / sizeof(u32)] <
+ if (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]) <
sizeof (hostdata->free->select))
- for (i = dsa[hostdata->dsa_msgout / sizeof(u32)],
- ptr = bus_to_virt (dsa[hostdata->dsa_msgout / sizeof(u32) + 1]);
+ for (i = le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32)]),
+ ptr = bus_to_virt (le32_to_cpu(dsa[hostdata->dsa_msgout / sizeof(u32) + 1]));
i > 0 && !check_address ((unsigned long) ptr, 1);
ptr += len, i -= len) {
printk(" ");
@@ -5833,8 +5896,8 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
}
printk(" + %d : select_indirect = 0x%x\n",
- hostdata->dsa_select, dsa[hostdata->dsa_select / sizeof(u32)]);
- cmd = (Scsi_Cmnd *) bus_to_virt(dsa[hostdata->dsa_cmnd / sizeof(u32)]);
+ hostdata->dsa_select, le32_to_cpu(dsa[hostdata->dsa_select / sizeof(u32)]));
+ cmd = (Scsi_Cmnd *) bus_to_virt(le32_to_cpu(dsa[hostdata->dsa_cmnd / sizeof(u32)]));
printk(" + %d : dsa_cmnd = 0x%x ", hostdata->dsa_cmnd,
(u32) virt_to_bus(cmd));
if (cmd) {
@@ -5844,7 +5907,7 @@ print_dsa (struct Scsi_Host *host, u32 *dsa, const char *prefix) {
} else
printk("\n");
printk(" + %d : dsa_next = 0x%x\n", hostdata->dsa_next,
- dsa[hostdata->dsa_next / sizeof(u32)]);
+ le32_to_cpu(dsa[hostdata->dsa_next / sizeof(u32)]));
if (cmd) {
printk("scsi%d target %d : sxfer_sanity = 0x%x, scntl3_sanity = 0x%x\n"
" script : ",
@@ -5891,8 +5954,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, ((struct NCR53c7x0_cmd *) cmd->host_scribble)
- -> dsa, "");
+ print_dsa (host, 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);
@@ -5917,7 +5979,7 @@ print_queues (struct Scsi_Host *host) {
left > 0; curr += 2, --left)
if (curr[0] != hostdata->NOP_insn)
/* FIXME : convert pointer to dsa_begin to pointer to dsa. */
- print_dsa (host, bus_to_virt (curr[1] -
+ print_dsa (host, bus_to_virt (le32_to_cpu(curr[1]) -
(hostdata->E_dsa_code_begin -
hostdata->E_dsa_code_template)), "");
printk ("scsi%d : end schedule dsa array\n", host->host_no);
@@ -5925,7 +5987,7 @@ print_queues (struct Scsi_Host *host) {
printk ("scsi%d : reconnect_dsa_head :\n", host->host_no);
for (left = host->can_queue,
- dsa = bus_to_virt (hostdata->reconnect_dsa_head);
+ dsa = bus_to_virt (le32_to_cpu(hostdata->reconnect_dsa_head));
left >= 0 && dsa;
dsa = next_dsa) {
save_flags (flags);
@@ -5937,7 +5999,7 @@ print_queues (struct Scsi_Host *host) {
}
else
{
- next_dsa = bus_to_virt(dsa[hostdata->dsa_next / sizeof(u32)]);
+ next_dsa = bus_to_virt(le32_to_cpu(dsa[hostdata->dsa_next / sizeof(u32)]));
print_dsa (host, dsa, "");
}
restore_flags(flags);
@@ -6131,7 +6193,7 @@ return_outstanding_commands (struct Scsi_Host *host, int free, int issue) {
for (i = 0, curr = (u32 *) hostdata->schedule;
i < host->can_queue; ++i, curr += 2) {
curr[0] = hostdata->NOP_insn;
- curr[1] = 0xdeadbeef;
+ curr[1] = le32_to_cpu(0xdeadbeef);
}
hostdata->curr = NULL;
}
diff --git a/drivers/scsi/53c7,8xx.h b/drivers/scsi/53c7,8xx.h
index cfddfa681..cb0071e9d 100644
--- a/drivers/scsi/53c7,8xx.h
+++ b/drivers/scsi/53c7,8xx.h
@@ -1574,7 +1574,7 @@ struct NCR53c7x0_hostdata {
if (hostdata->options & OPTION_DEBUG_DSA) \
printk("scsi : dsa %s symbol %s(%d) word %d now 0x%x\n", \
#dsa, #symbol, hostdata->##symbol, \
- (word), (u32) (value)); \
+ (word), (u32) le32_to_cpu(value)); \
}
/* Paranoid people could use panic() here. */
diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in
index ce08d4873..3f24e681f 100644
--- a/drivers/scsi/Config.in
+++ b/drivers/scsi/Config.in
@@ -21,7 +21,14 @@ dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI
dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI
dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI
-dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $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
+ int ' Maximum number of commands per LUN' CONFIG_AIC7XXX_CMDS_PER_LUN 8
+ bool ' Enable SCB paging' CONFIG_AIC7XXX_PAGE_ENABLE N
+ bool ' Collect statistics to report in /proc' CONFIG_AIC7XXX_PROC_STATS N
+ int ' delay in seconds after SCSI bus reset' CONFIG_AIC7XXX_RESET_DELAY 15
+fi
dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI
dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI
dep_tristate 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 $CONFIG_SCSI
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 02c066202..dcb47e47e 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -429,12 +429,8 @@ BusLogic.o: BusLogic.c FlashPoint.c
aha152x.o: aha152x.c
$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c
-aic7xxx_asm: aic7xxx_asm.c
- $(HOSTCC) -o $@ aic7xxx_asm.c
-
-aic7xxx.c: aic7xxx_seq.h
-aic7xxx_seq.h: aic7xxx_asm aic7xxx.seq
- ./aic7xxx_asm -o $@ aic7xxx.seq
+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
diff --git a/drivers/scsi/README.aic7xxx b/drivers/scsi/README.aic7xxx
index ccbf4a6e2..5ec8a51d2 100644
--- a/drivers/scsi/README.aic7xxx
+++ b/drivers/scsi/README.aic7xxx
@@ -1,5 +1,5 @@
AIC7xxx Driver for Linux
- April 15, 1996
+ July 20, 1997
Introduction
------------------------
@@ -31,6 +31,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
-----------------------
AIC-777x
AIC-785x
+ AIC-786x
AIC-787x
AIC-788x
@@ -58,6 +59,7 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
Dan Eischen deischen@iworks.InterWorks.org (Linux Driver Co-maintainer)
Dean Gehnert deang@teleport.com (Linux FTP/patch maintainer)
Jess Johnson jester@frenzy.com (AIC7xxx FAQ author)
+ Doug Ledford dledford@dialnet.net (Stress tester/bug squasher)
Special thanks go to John Aycock (aycock@cpsc.ucalgary.ca), the original
author of the driver. John has since retired from the project. Thanks
@@ -82,10 +84,17 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
Send regular messages and replies to: AIC7xxx@FreeBSD.ORG
- Command line options
- ------------------------
+ Command line options ("aic7xxx=option[,option...]")
+ ---------------------------------------------------
"aic7xxx=no_reset" - Eliminate the SCSI reset delay during startup.
Some SCSI devices need some extra time to reset.
+ "aic7xxx=extended" - Force extended translation.
+ "aic7xxx=ultra" - Force Ultra mode
+ "aic7xxx=irq_trigger:[0,1]" - Edge (0) or Level (1) triggered
+ interrupts. AFAIK, the driver only works with level triggered
+ interrupts. This only applies to EISA adapters.
+ "aic7xxx=verbose" - Enable more bootup messages. PLEASE use this
+ if you have problems with the driver.
/proc support
------------------------
@@ -106,10 +115,37 @@ linux-1.1.x and fairly stable since linux-1.2.x, and are also in FreeBSD
- US Linux mirror of Teleport site
ftp://ekf2.vsb.cz/pub/linux/kernel/aic7xxx/ftp.teleport.com/
- European Linux mirror of Teleport site
+ ftp://ftp.pcnet.com/users/eischen/Linux/
+ - Daniel Eischens experimental/development ftp site that is
+ also home of the Linux aic7xxx sequencer assembler source.
+
+ Sequencer assembler
+ ------------------------
+ The sequencer assembler is no longer being distributed with the
+ Linux kernel. The sequencer assembler (aic7xxx_asm) is now being
+ maintained by Justin Gibbs under a BSD copyright (which pretty
+ much lets you do anything you want with it). I keep a Linux
+ version of the assembler at my ftp site should you wish to hack
+ the sequencer code (ftp://ftp.pcnet.com/users/eischen/Linux/).
+ Please note that you do NOT need the assembler to build a kernel
+ with aic7xxx support. The assembler generates the code that is
+ downloaded to the aic7xxx controllers; this code IS part of the
+ Linux kernel (aic7xxx_seq.h and aic7xxx_reg.h).
+
+ Problems compiling the kernel with aic7xxx support
+ --------------------------------------------------
+ This is probably due to having modified the sequencer files in
+ some way. If you are not modifying the sequencer source (in
+ drivers/scsi/aic7xxx/aic7xxx.seq), then you can just re-extract
+ the necessary files from your kernel tarball. Otherwise, visit
+ my anonymous ftp site (ftp.pcnet.com) and grab the sequencer
+ assembler source.
Dean W. Gehnert
deang@teleport.com
-$Revision: 3.0 $
+(Modified by D. Eischen, 7/20/97)
+
+$Revision: 3.1a $
diff --git a/drivers/scsi/aic7xxx.c b/drivers/scsi/aic7xxx.c
index 96e66defd..005c889d7 100644
--- a/drivers/scsi/aic7xxx.c
+++ b/drivers/scsi/aic7xxx.c
@@ -1,5 +1,3 @@
-#define EXPERIMENTAL_FLAGS 0
-
/*+M*************************************************************************
* Adaptec AIC7xxx device driver for Linux.
*
@@ -29,21 +27,73 @@
* the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
* ANSI SCSI-2 specification (draft 10c), ...
*
- * ----------------------------------------------------------------
- * Modified to include support for wide and twin bus adapters,
- * DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ * --------------------------------------------------------------------------
+ *
+ * Modifications by Daniel M. Eischen (deischen@iworks.InterWorks.org):
+ *
+ * Substantially modified to include support for wide and twin bus
+ * adapters, DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
* SCB paging, and other rework of the code.
*
- * Parts of this driver are based on the FreeBSD driver by Justin
- * T. Gibbs.
+ * Parts of this driver were also based on the FreeBSD driver by
+ * Justin T. Gibbs. His copyright follows:
+ *
+ * --------------------------------------------------------------------------
+ * Copyright (c) 1994-1997 Justin Gibbs.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions, and the following disclaimer,
+ * without modification, immediately at the beginning of the file.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * Where this Software is combined with software released under the terms of
+ * the GNU Public License ("GPL") and the terms of the GPL would require the
+ * combined work to also be released under the terms of the GPL, the terms
+ * and conditions of this License will apply in addition to those of the
+ * GPL with the exception of any terms or conditions of this License that
+ * conflict with, or are expressly prohibited by, the GPL.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * $Id: aic7xxx.c,v 1.119 1997/06/27 19:39:18 gibbs Exp $
+ *---------------------------------------------------------------------------
+ *
+ * Thanks also go to (in alphabetical order) the following:
+ *
+ * Rory Bolt - Sequencer bug fixes
+ * Jay Estabrook - Initial DEC Alpha support
+ * Doug Ledford - Much needed abort/reset bug fixes
+ * Kai Makisara - DMAing of SCBs
*
* A Boot time option was also added for not resetting the scsi bus.
*
- * Form: aic7xxx=extended,no_reset
+ * Form: aic7xxx=extended
+ * aic7xxx=no_reset
+ * aic7xxx=ultra
+ * aic7xxx=irq_trigger:[0,1] # 0 edge, 1 level
+ * aic7xxx=verbose
*
- * -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 07/07/96
+ * Daniel M. Eischen, deischen@iworks.InterWorks.org, 1/23/97
*
- * $Id: aic7xxx.c,v 4.0 1996/10/13 08:23:42 deang Exp $
+ * $Id: aic7xxx.c,v 4.1 1997/06/12 08:23:42 deang Exp $
*-M*************************************************************************/
#ifdef MODULE
@@ -67,7 +117,11 @@
#include "scsi.h"
#include "hosts.h"
#include "aic7xxx.h"
+
+#include "aic7xxx/sequencer.h"
+#include "aic7xxx/scsi_message.h"
#include "aic7xxx_reg.h"
+#include "aic7xxx_seq.h"
#include <linux/stat.h>
#include <linux/malloc.h> /* for kmalloc() */
@@ -79,16 +133,20 @@
*/
#define VIRT_TO_BUS(a) (unsigned int)virt_to_bus((void *)(a))
-static struct proc_dir_entry proc_scsi_aic7xxx = {
+struct proc_dir_entry proc_scsi_aic7xxx = {
PROC_SCSI_AIC7XXX, 7, "aic7xxx",
- S_IFDIR | S_IRUGO | S_IXUGO, 2
+ S_IFDIR | S_IRUGO | S_IXUGO, 2,
+ 0, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL
};
-#define AIC7XXX_C_VERSION "$Revision: 4.0 $"
+#define AIC7XXX_C_VERSION "$Revision: 4.1 $"
#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
-#define MIN(a,b) ((a < b) ? a : b)
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#define ALL_TARGETS -1
+#define ALL_CHANNELS '\0'
+#define ALL_LUNS -1
#ifndef TRUE
# define TRUE 1
#endif
@@ -107,11 +165,8 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
* support because all PCI dependent code is bracketed with
* "#ifdef CONFIG_PCI ... #endif CONFIG_PCI".
*
- * o Twin bus support - this has been tested and does work.
- *
- * o DMAing of SCBs - thanks to Kai Makisara, this now works.
- * This define is now taken out and DMAing of SCBs is always
- * performed (8/12/95 - DE).
+ * o Twin bus support - this has been tested and does work. It is
+ * not an option anymore.
*
* o Tagged queueing - this driver is capable of tagged queueing
* but I am unsure as to how well the higher level driver implements
@@ -140,16 +195,16 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
* LUN using its own heuristic based on the number of available
* SCBs.
*
- * o 3985 support - The 3985 adapter is much like the 3940, but
- * has three 7870 controllers as opposed to two for the 3940.
- * It will get probed and recognized as three different adapters,
- * but all three controllers can share the same external bank of
- * 255 SCBs. If you enable AIC7XXX_SHARE_SCBS, then the driver
- * will attempt to share the common bank of SCBs between the three
- * controllers of the 3985. This is experimental and hasn't
- * been tested. By default, we do not share the bank of SCBs,
- * and force the controllers to use their own internal bank of
- * 16 SCBs. Please let us know if sharing the SCB array works.
+ * o 3985 support - The 3985 adapter is much like the 3940, but has
+ * three 7870 controllers as opposed to two for the 3940. It will
+ * be probed and recognized as three different adapters, but all
+ * three controllers can share the same external bank of 255 SCBs.
+ * If you enable AIC7XXX_USE_EXT_SCBRAM, then the driver will attempt
+ * to use and share the common bank of SCBs between the three
+ * controllers of the 3985. This is experimental and hasn't been
+ * been tested. By default, we do not use external SCB RAM, and
+ * force the controllers to use their own internal bank of 16 SCBs.
+ * Please let us know if using the external SCB array works.
*
* o SCB paging support - SCB paging is enabled by defining
* AIC7XXX_PAGE_ENABLE. Support for this was taken from the
@@ -162,43 +217,54 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
* Note that sharing of IRQs is not an option any longer. Linux supports
* it so we support it.
*
- * Daniel M. Eischen, deischen@iworks.InterWorks.org, 06/30/96
+ * Daniel M. Eischen, deischen@iworks.InterWorks.org, 01/26/96
*/
-/* Uncomment this for testing twin bus support. */
-#define AIC7XXX_TWIN_SUPPORT
-
/* Uncomment this for tagged queueing. */
-/* #define AIC7XXX_TAGGED_QUEUEING */
+#ifdef CONFIG_AIC7XXX_TAGGED_QUEUEING
+#define AIC7XXX_TAGGED_QUEUEING
+#endif
/*
* You can try raising me if tagged queueing is enabled, or lowering
* me if you only have 4 SCBs.
*/
-/* #define AIC7XXX_CMDS_PER_LUN 8 */
+#ifdef CONFIG_AIC7XXX_CMDS_PER_LUN
+#define AIC7XXX_CMDS_PER_LUN CONFIG_AIC7XXX_CMDS_PER_LUN
+#endif
/* Set this to the delay in seconds after SCSI bus reset. */
+#ifdef CONFIG_AIC7XXX_RESET_DELAY
+#define AIC7XXX_RESET_DELAY CONFIG_AIC7XXX_RESET_DELAY
+#else
#define AIC7XXX_RESET_DELAY 15
+#endif
/*
- * Uncomment the following define for collection of SCSI transfer statistics
- * for the /proc filesystem.
+ * Control collection of SCSI transfer statistics for the /proc filesystem.
*
* NOTE: Do NOT enable this when running on kernels version 1.2.x and below.
* NOTE: This does affect performance since it has to maintain statistics.
*/
-/* #define AIC7XXX_PROC_STATS */
+#ifdef CONFIG_AIC7XXX_PROC_STATS
+#define AIC7XXX_PROC_STATS
+#endif
/*
- * Uncomment the following to enable SCB paging.
+ * Enable SCB paging.
*/
-/* #define AIC7XXX_PAGE_ENABLE */
+#ifdef CONFIG_AIC7XXX_PAGE_ENABLE
+#define AIC7XXX_PAGE_ENABLE
+#endif
/*
- * Uncomment the following to enable sharing of the external bank
- * of 255 SCBs for the 3985.
+ * Uncomment the following to enable use of the external bank
+ * of 255 SCBs. For 3985 adapters, this will also enable sharing
+ * of the SCB array across all three controllers.
*/
-#define AIC7XXX_SHARE_SCBS
+#ifdef CONFIG_AIC7XXX_USE_EXT_SCBRAM
+#define AIC7XXX_USE_EXT_SCBRAM
+#endif
/*
* For debugging the abort/reset code.
@@ -211,6 +277,87 @@ static struct proc_dir_entry proc_scsi_aic7xxx = {
#define AIC7XXX_DEBUG
/*
+ * Set this for defining the number of tagged commands on a device
+ * by device, and controller by controller basis. The first set
+ * of tagged commands will be used for the first detected aic7xxx
+ * controller, the second set will be used for the second detected
+ * aic7xxx controller, and so on. These values will *only* be used
+ * for targets that are tagged queueing capable; these values will
+ * be ignored in all other cases. The tag_commands is an array of
+ * 16 to allow for wide and twin adapters. Twin adapters will use
+ * indexes 0-7 for channel 0, and indexes 8-15 for channel 1.
+ *
+ * *** Determining commands per LUN ***
+ *
+ * When AIC7XXX_CMDS_PER_LUN is not defined, the driver will use its
+ * own algorithm to determine the commands/LUN. If SCB paging is
+ * enabled, the commands/LUN is 8. When SCB paging is not enabled,
+ * then commands/LUN is 8 for adapters with 16 or more hardware SCBs
+ * and 4 commands/LUN for adapters with 3 or 4 SCBs.
+ *
+ */
+/* #define AIC7XXX_TAGGED_QUEUEING_BY_DEVICE */
+
+#ifdef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
+typedef struct
+{
+ char tag_commands[16]; /* Allow for wide/twin channel adapters. */
+} adapter_tag_info_t;
+
+/*
+ * Make a define that will tell the driver to use it's own algorithm
+ * for determining commands/LUN (see Determining commands per LUN
+ * above).
+ */
+#define DEFAULT_TAG_COMMANDS {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
+
+/*
+ * Modify this as you see fit for your system. By setting tag_commands
+ * to 0, the driver will use it's own algorithm for determining the
+ * number of commands to use (see above). When -1, the driver will
+ * not enable tagged queueing for that particular device. When positive
+ * (> 0) the values in the array are used for the queue_depth. Note
+ * that the maximum value for an entry is 127.
+ *
+ * In this example, the first line will enable tagged queueing for all
+ * the devices on the first probed aic7xxx adapter and tells the driver
+ * to use it's own algorithm for determining commands/LUN.
+ *
+ * The second line enables tagged queueing with 4 commands/LUN for IDs
+ * (1, 2-11, 13-15), disables tagged queueing for ID 12, and tells the
+ * driver to use its own algorithm for ID 1.
+ *
+ * The third line is the same as the first line.
+ *
+ * The fourth line disables tagged queueing for devices 0 and 3. It
+ * enables tagged queueing for the other IDs, with 16 commands/LUN
+ * for IDs 1 and 4, 127 commands/LUN for ID 8, and 4 commands/LUN for
+ * IDs 2, 5-7, and 9-15.
+ */
+adapter_tag_info_t aic7xxx_tag_info[] =
+{
+ {DEFAULT_TAG_COMMANDS},
+ {{4, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, -1, 4, 4, 4}},
+ {DEFAULT_TAG_COMMANDS},
+ {{-1, 16, 4, -1, 16, 4, 4, 4, 127, 4, 4, 4, 4, 4, 4, 4}}
+};
+#endif
+
+/*
+ * Don't define this unless you have problems with the driver
+ * interrupt handler. The old method would register the drivers
+ * interrupt handler as a "fast" type interrupt handler that would
+ * lock out other interrupts. Since this driver can spend a lot
+ * of time in the interrupt handler, this is _not_ a good idea.
+ * It also conflicts with some of the more common ethernet drivers
+ * that don't use fast interrupts. Currently, Linux does not allow
+ * IRQ sharing unless both drivers can agree on the type of interrupt
+ * handler.
+ */
+/* #define AIC7XXX_OLD_ISR_TYPE */
+
+
+/*
* Controller type and options
*/
typedef enum {
@@ -232,14 +379,15 @@ typedef enum {
AIC_7882, /* PCI aic7882 on 3940 Ultra */
AIC_7883, /* PCI aic7883 on 3985 Ultra */
AIC_7884 /* PCI aic7884 on 294x Ultra Differential */
-} aha_type;
+} aha_chip_type;
typedef enum {
AIC_777x, /* AIC-7770 based */
- AIC_785x, /* AIC-7850 based */
+ AIC_785x, /* AIC-7850 based (3 SCBs)*/
+ AIC_786x, /* AIC-7860 based (7850 ultra) */
AIC_787x, /* AIC-7870 based */
- AIC_788x /* AIC-7880 based */
-} aha_chip_type;
+ AIC_788x /* AIC-7880 based (ultra) */
+} aha_chip_class_type;
typedef enum {
AIC_SINGLE, /* Single Channel */
@@ -269,24 +417,24 @@ typedef enum {
* Don't forget to change this when changing the types!
*/
static const char *board_names[] = {
- "<AIC-7xxx Unknown>", /* AIC_NONE */
- "AIC-7770", /* AIC_7770 */
- "AHA-2740", /* AIC_7771 */
- "AHA-2840", /* AIC_284x */
- "AIC-7850", /* AIC_7850 */
- "AIC-7855", /* AIC_7855 */
- "AIC-7850 Ultra", /* AIC_7860 */
- "AHA-2940A Ultra", /* AIC_7861 */
- "AIC-7870", /* AIC_7870 */
- "AHA-2940", /* AIC_7871 */
- "AHA-3940", /* AIC_7872 */
- "AHA-3985", /* AIC_7873 */
- "AHA-2940 Differential", /* AIC_7874 */
- "AIC-7880 Ultra", /* AIC_7880 */
- "AHA-2940 Ultra", /* AIC_7881 */
- "AHA-3940 Ultra", /* AIC_7882 */
- "AHA-3985 Ultra", /* AIC_7883 */
- "AHA-2940 Ultra Differential" /* AIC_7884 */
+ "AIC-7xxx Unknown", /* AIC_NONE */
+ "Adaptec AIC-7770 SCSI host adapter", /* AIC_7770 */
+ "Adaptec AHA-274X SCSI host adapter", /* AIC_7771 */
+ "Adaptec AHA-284X SCSI host adapter", /* AIC_284x */
+ "Adaptec AIC-7850 SCSI host adapter", /* AIC_7850 */
+ "Adaptec AIC-7855 SCSI host adapter", /* AIC_7855 */
+ "Adaptec AIC-7860 Ultra SCSI host adapter", /* AIC_7860 */
+ "Adaptec AHA-2940A Ultra SCSI host adapter", /* AIC_7861 */
+ "Adaptec AIC-7870 SCSI host adapter", /* AIC_7870 */
+ "Adaptec AHA-294X SCSI host adapter", /* AIC_7871 */
+ "Adaptec AHA-394X SCSI host adapter", /* AIC_7872 */
+ "Adaptec AHA-398X SCSI host adapter", /* AIC_7873 */
+ "Adaptec AHA-2944 SCSI host adapter", /* AIC_7874 */
+ "Adaptec AIC-7880 Ultra SCSI host adapter", /* AIC_7880 */
+ "Adaptec AHA-294X Ultra SCSI host adapter", /* AIC_7881 */
+ "Adaptec AHA-394X Ultra SCSI host adapter", /* AIC_7882 */
+ "Adaptec AHA-398X Ultra SCSI host adapter", /* AIC_7883 */
+ "Adaptec AHA-2944 Ultra SCSI host adapter" /* AIC_7884 */
};
/*
@@ -310,12 +458,17 @@ static const char *board_names[] = {
*/
#define DID_RETRY_COMMAND DID_ERROR
+#define HSCSIID 0x07
+#define HWSCSIID 0x0F
+#define SCSI_RESET 0x040
+
/*
* EISA/VL-bus stuff
*/
#define MINSLOT 1
#define MAXSLOT 15
#define SLOTBASE(x) ((x) << 12)
+#define BASE_TO_SLOT(x) ((x) >> 12)
/*
* Standard EISA Host ID regs (Offset from slot base)
@@ -334,14 +487,6 @@ static const char *board_names[] = {
#define INTDEF 0x5C /* Interrupt Definition Register */
/*
- * Some defines for the HCNTRL register.
- */
-#define REQ_PAUSE IRQMS | INTEN | PAUSE
-#define UNPAUSE_274X IRQMS | INTEN
-#define UNPAUSE_284X INTEN
-#define UNPAUSE_294X IRQMS | INTEN
-
-/*
* AIC-78X0 PCI registers
*/
#define CLASS_PROGIF_REVID 0x08
@@ -377,7 +522,7 @@ static const char *board_names[] = {
* each word, while the C56 and C66 (4096 bits) use 8 bits to
* address each word.
*/
-typedef enum {c46 = 6, c56_66 = 8} seeprom_chip_type;
+typedef enum {C46 = 6, C56_66 = 8} seeprom_chip_type;
/*
*
@@ -417,15 +562,15 @@ struct seeprom_config {
/*
* Host Adapter Control Bits
*/
-/* UNUSED 0x0001 */
+#define CFAUTOTERM 0x0001 /* Perform Auto termination */
#define CFULTRAEN 0x0002 /* Ultra SCSI speed enable (Ultra cards) */
#define CF284XSELTO 0x0003 /* Selection timeout (284x cards) */
#define CF284XFIFO 0x000C /* FIFO Threshold (284x cards) */
-#define CFSTERM 0x0004 /* SCSI low byte termination (non-wide cards) */
+#define CFSTERM 0x0004 /* SCSI low byte termination */
#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
#define CFSPARITY 0x0010 /* SCSI parity */
#define CF284XSTERM 0x0020 /* SCSI low byte termination (284x cards) */
-#define CFRESETB 0x0040 /* reset SCSI bus at IC initialization */
+#define CFRESETB 0x0040 /* reset SCSI bus at boot */
/* UNUSED 0xFF80 */
unsigned short adapter_control; /* word 17 */
@@ -448,36 +593,17 @@ struct seeprom_config {
unsigned short checksum; /* word 31 */
};
+#define SELBUS_MASK 0x0a
+#define SELNARROW 0x00
+#define SELBUSB 0x08
+#define SINGLE_BUS 0x00
-#define SCSI_RESET 0x040
-
-/*
- * Pause the sequencer and wait for it to actually stop - this
- * is important since the sequencer can disable pausing for critical
- * sections.
- */
-#define PAUSE_SEQUENCER(p) \
- synchronize_irq(); \
- outb(p->pause, HCNTRL + p->base); \
- while ((inb(HCNTRL + p->base) & PAUSE) == 0) \
- ; \
-
-/*
- * Unpause the sequencer. Unremarkable, yet done often enough to
- * warrant an easy way to do it.
- */
-#define UNPAUSE_SEQUENCER(p) \
- outb(p->unpause, HCNTRL + p->base)
-
-/*
- * Restart the sequencer program from address zero
- */
-#define RESTART_SEQUENCER(p) \
- do { \
- outb(SEQRESET | FASTMODE, SEQCTL + p->base); \
- } while (inb(SEQADDR0 + p->base) != 0 && \
- inb(SEQADDR1 + p->base) != 0); \
- UNPAUSE_SEQUENCER(p);
+#define SCB_TARGET(scb) \
+ (((scb)->hscb->target_channel_lun & TID) >> 4)
+#define SCB_LUN(scb) \
+ ((scb)->hscb->target_channel_lun & LID)
+#define SCB_IS_SCSIBUS_B(scb) \
+ (((scb)->hscb->target_channel_lun & SELBUSB) != 0)
/*
* If an error occurs during a data transfer phase, run the command
@@ -541,12 +667,6 @@ static struct Scsi_Host *aic7xxx_boards[NR_IRQS + 1];
static int aic7xxx_spurious_count;
/*
- * The driver keeps up to four scb structures per card in memory. Only the
- * first 25 bytes of the structure are valid for the hardware, the rest used
- * for driver level bookkeeping.
- */
-
-/*
* As of Linux 2.1, the mid-level SCSI code uses virtual addresses
* in the scatter-gather lists. We need to convert the virtual
* addresses to physical addresses.
@@ -559,20 +679,28 @@ struct hw_scatterlist {
/*
* Maximum number of SG segments these cards can support.
*/
-#define MAX_SG 256
+#define AIC7XXX_MAX_SG 27
-struct aic7xxx_scb {
+/*
+ * The maximum number of SCBs we could have for ANY type
+ * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
+ * SEQUENCER CODE IF THIS IS MODIFIED!
+ */
+#define AIC7XXX_MAXSCB 255
+
+
+struct aic7xxx_hwscb {
/* ------------ Begin hardware supported fields ---------------- */
/* 0*/ unsigned char control;
/* 1*/ unsigned char target_channel_lun; /* 4/1/3 bits */
/* 2*/ unsigned char target_status;
/* 3*/ unsigned char SG_segment_count;
-/* 4*/ unsigned char SG_list_pointer[4] __attribute__ ((packed));
+/* 4*/ unsigned int SG_list_pointer;
/* 8*/ unsigned char residual_SG_segment_count;
-/* 9*/ unsigned char residual_data_count[3] __attribute__ ((packed));
-/*12*/ unsigned char data_pointer[4] __attribute__ ((packed));
-/*16*/ unsigned int data_count __attribute__ ((packed)); /* must be 32 bits */
-/*20*/ unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
+/* 9*/ unsigned char residual_data_count[3];
+/*12*/ unsigned int data_pointer;
+/*16*/ unsigned int data_count;
+/*20*/ unsigned int SCSI_cmd_pointer;
/*24*/ unsigned char SCSI_cmd_length;
/*25*/ u_char tag; /* Index into our kernel SCB array.
* Also used as the tag for tagged I/O
@@ -580,29 +708,47 @@ struct aic7xxx_scb {
#define SCB_PIO_TRANSFER_SIZE 26 /* amount we need to upload/download
* via PIO to initialize a transaction.
*/
-/*26*/ u_char next; /* Used to thread SCBs awaiting selection
+/*26*/ unsigned char next; /* Used to thread SCBs awaiting selection
* or disconnected down in the sequencer.
*/
- /*-----------------end of hardware supported fields----------------*/
- Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
- struct aic7xxx_scb *q_next; /* next scb in queue */
-#define SCB_FREE 0x00
-#define SCB_ACTIVE 0x01
-#define SCB_ABORTED 0x02
-#define SCB_DEVICE_RESET 0x04
-#define SCB_IMMED 0x08
-#define SCB_SENSE 0x10
-#define SCB_QUEUED_FOR_DONE 0x40
-#define SCB_PAGED_OUT 0x80
-#define SCB_WAITINGQ 0x100
-#define SCB_ASSIGNEDQ 0x200
-#define SCB_SENTORDEREDTAG 0x400
-#define SCB_IN_PROGRESS (SCB_ACTIVE | SCB_PAGED_OUT | \
- SCB_WAITINGQ | SCB_ASSIGNEDQ)
- int state; /* current state of scb */
- unsigned int position; /* Position in scb array */
- struct hw_scatterlist sg_list[MAX_SG]; /* SG list in adapter format */
- unsigned char sense_cmd[6]; /* Allocate 6 characters for sense command */
+/*27*/ unsigned char prev;
+/*28*/ unsigned int pad; /*
+ * Unused by the kernel, but we require
+ * the padding so that the array of
+ * hardware SCBs is alligned on 32 byte
+ * boundaries so the sequencer can index
+ */
+};
+
+typedef enum {
+ SCB_FREE = 0x0000,
+ SCB_ACTIVE = 0x0001,
+ SCB_ABORTED = 0x0002,
+ SCB_DEVICE_RESET = 0x0004,
+ SCB_SENSE = 0x0008,
+ SCB_TIMEDOUT = 0x0010,
+ SCB_QUEUED_FOR_DONE = 0x0020,
+ SCB_RECOVERY_SCB = 0x0040,
+ SCB_WAITINGQ = 0x0080,
+ SCB_ASSIGNEDQ = 0x0100,
+ SCB_SENTORDEREDTAG = 0x0200,
+ SCB_MSGOUT_SDTR = 0x0400,
+ SCB_MSGOUT_WDTR = 0x0800,
+ SCB_ABORT = 0x1000,
+ SCB_QUEUED_ABORT = 0x2000
+} scb_flag_type;
+
+struct aic7xxx_scb {
+ struct aic7xxx_hwscb *hscb; /* corresponding hardware scb */
+ Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
+ struct aic7xxx_scb *q_next; /* next scb in queue */
+ scb_flag_type flags; /* current state of scb */
+ struct hw_scatterlist *sg_list; /* SG list in adapter format */
+ unsigned char sg_count;
+ unsigned char sense_cmd[6]; /*
+ * Allocate 6 characters for
+ * sense command.
+ */
};
/*
@@ -627,20 +773,17 @@ static unsigned char
generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
typedef struct {
+ struct aic7xxx_hwscb *hscbs;
scb_queue_type free_scbs; /*
* SCBs assigned to free slot on
* card (no paging required)
*/
- int numscbs; /* current number of scbs */
- int activescbs; /* active scbs */
-} scb_usage_type;
-
-/*
- * The maximum number of SCBs we could have for ANY type
- * of card. DON'T FORGET TO CHANGE THE SCB MASK IN THE
- * SEQUENCER CODE IF THIS IS MODIFIED!
- */
-#define AIC7XXX_MAXSCB 255
+ unsigned char numscbs; /* current number of scbs */
+ unsigned char maxhscbs; /* hardware scbs */
+ unsigned char maxscbs; /* max scbs including pageable scbs */
+ struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB];
+ unsigned int reserve[100];
+} scb_data_type;
/*
* Define a structure used for each host adapter, only one per IRQ.
@@ -648,17 +791,26 @@ typedef struct {
struct aic7xxx_host {
struct Scsi_Host *host; /* pointer to scsi host */
int host_no; /* SCSI host number */
+ int instance; /* aic7xxx instance number */
+ int scsi_id; /* host adapter SCSI ID */
+ int scsi_id_b; /* channel B for twin adapters */
+ int irq; /* IRQ for this adapter */
int base; /* card base address */
- int maxhscbs; /* hardware SCBs */
- int maxscbs; /* max SCBs (including pageable) */
-#define A_SCANNED 0x0001
-#define B_SCANNED 0x0002
-#define EXTENDED_TRANSLATION 0x0004
-#define HAVE_SEEPROM 0x0008
-#define ULTRA_ENABLED 0x0010
-#define PAGE_ENABLED 0x0020
-#define IN_ISR 0x0040
-#define USE_DEFAULTS 0x0080
+ unsigned int mbase; /* I/O memory address */
+ volatile unsigned char *maddr; /* memory mapped address */
+#define A_SCANNED 0x0001
+#define B_SCANNED 0x0002
+#define EXTENDED_TRANSLATION 0x0004
+#define FLAGS_CHANNEL_B_PRIMARY 0x0008
+#define MULTI_CHANNEL 0x0010
+#define ULTRA_ENABLED 0x0020
+#define PAGE_ENABLED 0x0040
+#define USE_DEFAULTS 0x0080
+#define BIOS_ENABLED 0x0100
+#define IN_ISR 0x0200
+#define IN_TIMEOUT 0x0400
+#define SHARED_SCBDATA 0x0800
+#define HAVE_SEEPROM 0x1000
unsigned int flags;
unsigned int isr_count; /* Interrupt count */
unsigned short needsdtr_copy; /* default config */
@@ -669,36 +821,22 @@ struct aic7xxx_host {
unsigned short wdtr_pending;
unsigned short orderedtag;
unsigned short discenable; /* Targets allowed to disconnect */
- aha_type type; /* card type */
- aha_chip_type chip_type; /* chip base type */
+ aha_chip_type chip_type; /* card type */
+ aha_chip_class_type chip_class;
aha_bus_type bus_type; /* normal/twin/wide bus */
- char * mbase; /* I/O memory address */
- unsigned char chan_num; /* for 3940/3985, channel number */
+ unsigned char chan_num; /* for 39xx, channel number */
unsigned char unpause; /* unpause value for HCNTRL */
unsigned char pause; /* pause value for HCNTRL */
unsigned char qcntmask;
- struct seeprom_config seeprom;
+ unsigned char qfullcount;
+ unsigned char curqincnt;
struct Scsi_Host *next; /* allow for multiple IRQs */
- struct aic7xxx_scb *scb_array[AIC7XXX_MAXSCB]; /* active commands */
- struct aic7xxx_scb *pagedout_ntscbs[16]; /*
- * paged-out, non-tagged scbs
- * indexed by target.
- */
- scb_queue_type page_scbs; /*
- * SCBs that will require paging
- * before use (no assigned slot)
- */
+ unsigned char activescbs; /* active scbs */
scb_queue_type waiting_scbs; /*
- * SCBs waiting to be paged and
- * started.
+ * SCBs waiting for space in
+ * the QINFIFO.
*/
- scb_queue_type assigned_scbs; /*
- * SCBs that were waiting but have
- * have now been assigned a slot
- * by aic7xxx_free_scb
- */
- scb_usage_type scb_usage;
- scb_usage_type *scb_link;
+ scb_data_type *scb_data;
struct aic7xxx_cmd_queue {
Scsi_Cmnd *head;
@@ -710,6 +848,7 @@ struct aic7xxx_host {
#define BUS_DEVICE_RESET_PENDING 0x02
int flags;
int commands_sent;
+ int active_cmds;
} device_status[16];
#ifdef AIC7XXX_PROC_STATS
/*
@@ -735,34 +874,10 @@ struct aic7xxx_host {
#endif /* AIC7XXX_PROC_STATS */
};
-struct aic7xxx_host_config {
- int irq; /* IRQ number */
- int mbase; /* memory base address*/
- int base; /* I/O base address*/
- int maxhscbs; /* hardware SCBs */
- int maxscbs; /* max SCBs (including pageable) */
- int unpause; /* unpause value for HCNTRL */
- int pause; /* pause value for HCNTRL */
- int scsi_id; /* host SCSI ID */
- int scsi_id_b; /* host SCSI ID B channel for twin cards */
- unsigned int flags; /* used the same as struct aic7xxx_host flags */
- int chan_num; /* for 3940/3985, channel number */
- unsigned char busrtime; /* bus release time */
- unsigned char bus_speed; /* bus speed */
- unsigned char qcntmask;
- aha_type type; /* card type */
- aha_chip_type chip_type; /* chip base type */
- aha_bus_type bus_type; /* normal/twin/wide bus */
- aha_status_type bios; /* BIOS is enabled/disabled */
- aha_status_type parity; /* bus parity enabled/disabled */
- aha_status_type low_term; /* bus termination low byte */
- aha_status_type high_term; /* bus termination high byte (wide cards only) */
-};
-
/*
* Valid SCSIRATE values. (p. 3-17)
- * Provides a mapping of transfer periods in ns to the proper value to
- * stick in the scsiscfr reg to use that transfer rate.
+ * Provides a mapping of transfer periods in ns/4 to the proper value to
+ * stick in the SCSIRATE reg to use that transfer rate.
*/
static struct {
short period;
@@ -771,17 +886,17 @@ static struct {
short rate;
const char *english;
} aic7xxx_syncrates[] = {
- { 50, 0x100, "20.0" },
- { 62, 0x110, "16.0" },
- { 75, 0x120, "13.4" },
- { 100, 0x000, "10.0" },
- { 125, 0x010, "8.0" },
- { 150, 0x020, "6.67" },
- { 175, 0x030, "5.7" },
- { 200, 0x040, "5.0" },
- { 225, 0x050, "4.4" },
- { 250, 0x060, "4.0" },
- { 275, 0x070, "3.6" }
+ { 12, 0x100, "20.0" },
+ { 15, 0x110, "16.0" },
+ { 18, 0x120, "13.4" },
+ { 25, 0x000, "10.0" },
+ { 31, 0x010, "8.0" },
+ { 37, 0x020, "6.67" },
+ { 43, 0x030, "5.7" },
+ { 50, 0x040, "5.0" },
+ { 56, 0x050, "4.4" },
+ { 62, 0x060, "4.0" },
+ { 68, 0x070, "3.6" }
};
static int num_aic7xxx_syncrates =
@@ -790,166 +905,51 @@ static int num_aic7xxx_syncrates =
#ifdef CONFIG_PCI
static int number_of_3940s = 0;
static int number_of_3985s = 0;
-#ifdef AIC7XXX_SHARE_SCBS
-static scb_usage_type *shared_3985_scbs = NULL;
-#endif
-#endif CONFIG_PCI
+#endif /* CONFIG_PCI */
#ifdef AIC7XXX_DEBUG
-static void
-debug_config(struct aic7xxx_host_config *p)
-{
- int scsi_conf;
- unsigned char brelease;
- unsigned char dfthresh;
-
- static int DFT[] = { 0, 50, 75, 100 };
- static int SST[] = { 256, 128, 64, 32 };
- static const char *BUSW[] = { "", "-TWIN", "-WIDE" };
-
- scsi_conf = inb(SCSICONF + p->base);
-
- /*
- * Scale the Data FIFO Threshhold and the Bus Release Time; they are
- * stored in formats compatible for writing to sequencer registers.
- */
- dfthresh = p->bus_speed >> 6;
-
- if (p->chip_type == AIC_777x)
- {
- brelease = p->busrtime >> 2;
- }
- else
- {
- brelease = p->busrtime;
- }
- if (brelease == 0)
- {
- brelease = 2;
- }
-
- switch (p->type)
- {
- case AIC_7770:
- case AIC_7771:
- printk("%s%s AT EISA SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
- p->base >> 12);
- break;
-
- case AIC_284x:
- printk("%s%s AT VLB SLOT %d:\n", board_names[p->type], BUSW[p->bus_type],
- p->base >> 12);
- break;
-
- case AIC_7850:
- case AIC_7855:
- case AIC_7860:
- case AIC_7861:
- case AIC_7870:
- case AIC_7871:
- case AIC_7872:
- case AIC_7873:
- case AIC_7874:
- case AIC_7880:
- case AIC_7881:
- case AIC_7882:
- case AIC_7883:
- case AIC_7884:
- printk("%s%s (PCI-bus), I/O 0x%x, Mem 0x%x:\n", board_names[p->type],
- BUSW[p->bus_type], p->base, p->mbase);
- break;
-
- default:
- panic("aic7xxx: (debug_config) internal error.\n");
- }
-
- printk(" irq %d\n"
- " bus release time %d bclks\n"
- " data fifo threshold %d%%\n",
- p->irq,
- brelease,
- DFT[dfthresh]);
-
- printk(" SCSI CHANNEL A:\n"
- " scsi id %d\n"
- " scsi selection timeout %d ms\n"
- " scsi bus reset at power-on %sabled\n",
- scsi_conf & 0x07,
- SST[(scsi_conf >> 3) & 0x03],
- (scsi_conf & 0x40) ? "en" : "dis");
-
- if ((p->chip_type == AIC_777x) && (p->parity == AIC_UNKNOWN))
- {
- /*
- * Set the parity for 7770 based cards.
- */
- p->parity = (scsi_conf & 0x20) ? AIC_ENABLED : AIC_DISABLED;
- }
- if (p->parity != AIC_UNKNOWN)
- {
- printk(" scsi bus parity %sabled\n",
- (p->parity == AIC_ENABLED) ? "en" : "dis");
- }
-
- if ((p->type == AIC_7770) || (p->type == AIC_7771))
- {
- p->low_term = (scsi_conf & 0x80) ? AIC_ENABLED : AIC_DISABLED;
- }
- if (p->low_term != AIC_UNKNOWN)
- {
- printk(" scsi bus termination (low byte) %sabled\n",
- (p->low_term == AIC_ENABLED) ? "en" : "dis");
- }
- if ((p->bus_type == AIC_WIDE) && (p->high_term != AIC_UNKNOWN))
- {
- printk(" scsi bus termination (high byte) %sabled\n",
- (p->high_term == AIC_ENABLED) ? "en" : "dis");
- }
-}
-
#if 0
static void
debug_scb(struct aic7xxx_scb *scb)
{
- printk("control 0x%x, tcl 0x%x, sg_count %d, sg_ptr 0x%x, cmdp 0x%x, cmdlen %d\n",
- scb->control, scb->target_channel_lun, scb->SG_segment_count,
- (scb->SG_list_pointer[3] << 24) | (scb->SG_list_pointer[2] << 16) |
- (scb->SG_list_pointer[1] << 8) | scb->SG_list_pointer[0],
- (scb->SCSI_cmd_pointer[3] << 24) | (scb->SCSI_cmd_pointer[2] << 16) |
- (scb->SCSI_cmd_pointer[1] << 8) | scb->SCSI_cmd_pointer[0],
- scb->SCSI_cmd_length);
- printk("reserved 0x%x, target status 0x%x, resid SG count %d, resid data count %d\n",
- (scb->RESERVED[1] << 8) | scb->RESERVED[0], scb->target_status,
- scb->residual_SG_segment_count,
- ((scb->residual_data_count[2] << 16) |
- (scb->residual_data_count[1] << 8) |
- (scb->residual_data_count[0]));
- printk("data ptr 0x%x, data count %d, next waiting %d\n",
- (scb->data_pointer[3] << 24) | (scb->data_pointer[2] << 16) |
- (scb->data_pointer[1] << 8) | scb->data_pointer[0],
- scb->data_count, scb->next_waiting);
- printk("next ptr 0x%lx, Scsi Cmnd 0x%lx, state 0x%x, position %d\n",
- (unsigned long) scb->next, (unsigned long) scb->cmd, scb->state,
- scb->position);
+ struct aic7xxx_hwscb *hscb = scb->hscb;
+
+ printk("scb:%p control:0x%x tcl:0x%x cmdlen:%d cmdpointer:0x%lx\n",
+ scb,
+ hscb->control,
+ hscb->target_channel_lun,
+ hscb->SCSI_cmd_length,
+ hscb->SCSI_cmd_pointer );
+ printk(" datlen:%d data:0x%lx segs:0x%x segp:0x%lx\n",
+ hscb->data_count,
+ hscb->data_pointer,
+ hscb->SG_segment_count,
+ hscb->SG_list_pointer);
+ printk(" sg_addr:%lx sg_len:%ld\n",
+ hscb->sg_list[0].address,
+ hscb->sg_list[0].length);
}
#endif
#else
-# define debug_config(x)
# define debug_scb(x)
#endif AIC7XXX_DEBUG
-#define TCL_OF_SCB(x) (((x)->target_channel_lun >> 4) & 0xf), \
- (((x)->target_channel_lun >> 3) & 0x01), \
- ((x)->target_channel_lun & 0x07)
+#define TCL_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
+ (((scb->hscb)->target_channel_lun >> 3) & 0x01), \
+ ((scb->hscb)->target_channel_lun & 0x07)
+
+#define TC_OF_SCB(scb) (((scb->hscb)->target_channel_lun >> 4) & 0xf), \
+ (((scb->hscb)->target_channel_lun >> 3) & 0x01)
-#define TARGET_INDEX(x) ((x)->target | ((x)->channel << 3))
+#define CHAN_TO_INT(chan) ((chan) == 'A' ? 0 : 1)
+
+#define TARGET_INDEX(cmd) ((cmd)->target | ((cmd)->channel << 3))
/*
* XXX - these options apply unilaterally to _all_ 274x/284x/294x
- * cards in the system. This should be fixed, but then,
- * does anyone really have more than one in a machine?
+ * cards in the system. This should be fixed.
*/
static unsigned int aic7xxx_extended = 0; /* extended translation on? */
static unsigned int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */
@@ -959,6 +959,53 @@ static int aic7xxx_irq_trigger = -1; /*
* 1 use level triggered
*/
static int aic7xxx_enable_ultra = 0; /* enable ultra SCSI speeds */
+static int aic7xxx_verbose = 0; /* verbose messages */
+
+
+/****************************************************************************
+ *
+ * These functions are not used yet, but when we do memory mapped
+ * IO, we'll use them then.
+ *
+ ***************************************************************************/
+static inline unsigned char
+aic_inb(struct aic7xxx_host *p, long port)
+{
+ if (p->maddr != NULL)
+ return (p->maddr[port]);
+ else
+ return (inb(p->base + port));
+}
+
+static inline void
+aic_outb(struct aic7xxx_host *p, unsigned char val, long port)
+{
+ if (p->maddr != NULL)
+ p->maddr[port] = val;
+ else
+ outb(val, p->base + port);
+}
+
+static inline void
+aic_outsb(struct aic7xxx_host *p, long port, unsigned char *valp, size_t size)
+{
+ if (p->maddr != NULL)
+ {
+ __asm __volatile("
+ cld;
+ 1: lodsb;
+ movb %%al,(%0);
+ loop 1b" :
+ :
+ "r" ((p)->maddr + (port)),
+ "S" ((valp)), "c" ((size)) :
+ "%esi", "%ecx", "%eax");
+ }
+ else
+ {
+ outsb(p->base + port, valp, size);
+ }
+}
/*+F*************************************************************************
* Function:
@@ -983,6 +1030,7 @@ aic7xxx_setup(char *s, int *dummy)
{ "no_reset", &aic7xxx_no_reset },
{ "irq_trigger", &aic7xxx_irq_trigger },
{ "ultra", &aic7xxx_enable_ultra },
+ { "verbose", &aic7xxx_verbose },
{ NULL, NULL }
};
@@ -1008,58 +1056,230 @@ aic7xxx_setup(char *s, int *dummy)
/*+F*************************************************************************
* Function:
+ * pause_sequencer
+ *
+ * Description:
+ * Pause the sequencer and wait for it to actually stop - this
+ * is important since the sequencer can disable pausing for critical
+ * sections.
+ *-F*************************************************************************/
+static inline void
+pause_sequencer(struct aic7xxx_host *p)
+{
+ outb(p->pause, p->base + HCNTRL);
+ while ((inb(p->base + HCNTRL) & PAUSE) == 0)
+ {
+ ;
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
+ * unpause_sequencer
+ *
+ * Description:
+ * Unpause the sequencer. Unremarkable, yet done often enough to
+ * warrant an easy way to do it.
+ *-F*************************************************************************/
+static inline void
+unpause_sequencer(struct aic7xxx_host *p, int unpause_always)
+{
+ if (unpause_always ||
+ ((inb(p->base + INTSTAT) & (SCSIINT | SEQINT | BRKADRINT)) == 0))
+ {
+ outb(p->unpause, p->base + HCNTRL);
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
+ * restart_sequencer
+ *
+ * Description:
+ * Restart the sequencer program from address zero. This assumes
+ * that the sequencer is already paused.
+ *-F*************************************************************************/
+static inline void
+restart_sequencer(struct aic7xxx_host *p)
+{
+ /* Set the sequencer address to 0. */
+ outb(0, p->base + SEQADDR0);
+ outb(0, p->base + SEQADDR1);
+
+ /*
+ * Reset and unpause the sequencer. The reset is suppose to
+ * start the sequencer running, but we do an unpause to make
+ * sure.
+ */
+ outb(SEQRESET | FASTMODE, p->base + SEQCTL);
+
+ unpause_sequencer(p, /*unpause_always*/ TRUE);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_next_patch
+ *
+ * Description:
+ * Find the next patch to download.
+ *-F*************************************************************************/
+static struct patch *
+aic7xxx_next_patch(struct patch *cur_patch, int options, int instrptr)
+{
+ while (cur_patch != NULL)
+ {
+ if ((((cur_patch->options & options) != 0) && (cur_patch->negative == FALSE))
+ || (((cur_patch->options & options) == 0) && (cur_patch->negative == TRUE))
+ || (instrptr >= cur_patch->end))
+ {
+ /*
+ * Either we want to keep this section of code, or we have consumed
+ * this patch. Skip to the next patch.
+ */
+ cur_patch++;
+ if (cur_patch->options == 0)
+ {
+ /* Out of patches. */
+ cur_patch = NULL;
+ }
+ }
+ else
+ {
+ /* Found an OK patch. */
+ break;
+ }
+ }
+ return (cur_patch);
+}
+
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_download_instr
+ *
+ * Description:
+ * Find the next patch to download.
+ *-F*************************************************************************/
+static void
+aic7xxx_download_instr(struct aic7xxx_host *p, int options, int instrptr)
+{
+ unsigned char opcode;
+ struct ins_format3 *instr;
+
+ instr = (struct ins_format3 *) &seqprog[instrptr * 4];
+ /* Pull the opcode */
+ opcode = instr->opcode_addr >> 1;
+ switch (opcode)
+ {
+ case AIC_OP_JMP:
+ case AIC_OP_JC:
+ case AIC_OP_JNC:
+ case AIC_OP_CALL:
+ case AIC_OP_JNE:
+ case AIC_OP_JNZ:
+ case AIC_OP_JE:
+ case AIC_OP_JZ:
+ {
+ int address_offset;
+ struct ins_format3 new_instr;
+ unsigned int address;
+ struct patch *patch;
+ int i;
+
+ address_offset = 0;
+ new_instr = *instr; /* Strucure copy */
+ address = new_instr.address;
+ address |= (new_instr.opcode_addr & ADDR_HIGH_BIT) << 8;
+ for (i = 0; i < NUMBER(patches); i++)
+ {
+ patch = &patches[i];
+ if ((((patch->options & options) == 0) && (patch->negative == FALSE)) ||
+ (((patch->options & options) != 0) && (patch->negative == TRUE)))
+ {
+ if (address >= patch->end)
+ {
+ address_offset += patch->end - patch->begin;
+ }
+ }
+ }
+ address -= address_offset;
+ new_instr.address = address &0xFF;
+ new_instr.opcode_addr &= ~ADDR_HIGH_BIT;
+ new_instr.opcode_addr |= (address >> 8) & ADDR_HIGH_BIT;
+ outsb(p->base + SEQRAM, &new_instr.immediate, 4);
+ break;
+ }
+
+ case AIC_OP_OR:
+ case AIC_OP_AND:
+ case AIC_OP_XOR:
+ case AIC_OP_ADD:
+ case AIC_OP_ADC:
+ case AIC_OP_ROL:
+ outsb(p->base + SEQRAM, &instr->immediate, 4);
+ break;
+
+ default:
+ panic("aic7xxx: Unknown opcode encountered in sequencer program.");
+ break;
+ }
+}
+
+
+/*+F*************************************************************************
+ * Function:
* aic7xxx_loadseq
*
* Description:
* Load the sequencer code into the controller memory.
*-F*************************************************************************/
static void
-aic7xxx_loadseq(int base)
+aic7xxx_loadseq(struct aic7xxx_host *p)
{
- static unsigned char seqprog[] = {
- /*
- * Each sequencer instruction is 29 bits
- * long (fill in the excess with zeroes)
- * and has to be loaded from least -> most
- * significant byte, so this table has the
- * byte ordering reversed.
- */
-# include "aic7xxx_seq.h"
- };
+ int options;
+ struct patch *cur_patch;
+ int i;
+ int downloaded;
- /*
- * When the AIC-7770 is paused (as on chip reset), the
- * sequencer address can be altered and a sequencer
- * program can be loaded by writing it, byte by byte, to
- * the sequencer RAM port - the Adaptec documentation
- * recommends using REP OUTSB to do this, hence the inline
- * assembly. Since the address autoincrements as we load
- * the program, reset it back to zero afterward. Disable
- * sequencer RAM parity error detection while loading, and
- * make sure the LOADRAM bit is enabled for loading.
- */
- outb(PERRORDIS | SEQRESET | LOADRAM, SEQCTL + base);
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
+ }
+ options = 1; /* Code for all options. */
+ downloaded = 0;
+ if ((p->flags & ULTRA_ENABLED) != 0)
+ options |= ULTRA;
+ if (p->bus_type == AIC_TWIN)
+ options |= TWIN_CHANNEL;
+ if (p->scb_data->maxscbs > p->scb_data->maxhscbs)
+ options |= SCB_PAGING;
- outsb(SEQRAM + base, seqprog, sizeof(seqprog));
+ cur_patch = patches;
+ outb(PERRORDIS | LOADRAM, p->base + SEQCTL);
+ outb(0, p->base + SEQADDR0);
+ outb(0, p->base + SEQADDR1);
- /*
- * WARNING! This is a magic sequence! After extensive
- * experimentation, it seems that you MUST turn off the
- * LOADRAM bit before you play with SEQADDR again, else
- * you will end up with parity errors being flagged on
- * your sequencer program. (You would also think that
- * turning off LOADRAM and setting SEQRESET to reset the
- * address to zero would work, but you need to do it twice
- * for it to take effect on the address. Timing problem?)
- */
- do {
- /*
- * Actually, reset it until
- * the address shows up as
- * zero just to be safe..
- */
- outb(SEQRESET | FASTMODE, SEQCTL + base);
- } while ((inb(SEQADDR0 + base) != 0) && (inb(SEQADDR1 + base) != 0));
+ for (i = 0; i < sizeof(seqprog) / 4; i++)
+ {
+ cur_patch = aic7xxx_next_patch(cur_patch, options, i);
+ if (cur_patch && (cur_patch->begin <= i) && (cur_patch->end > i))
+ {
+ /* Skip this instruction for this configuration. */
+ continue;
+ }
+ aic7xxx_download_instr(p, options, i);
+ downloaded++;
+ }
+
+ outb(FASTMODE, p->base + SEQCTL);
+ outb(0, p->base + SEQADDR0);
+ outb(0, p->base + SEQADDR1);
+
+ if (aic7xxx_verbose)
+ {
+ printk(" %d instructions downloaded\n", downloaded);
+ }
}
/*+F*************************************************************************
@@ -1067,18 +1287,22 @@ aic7xxx_loadseq(int base)
* aic7xxx_delay
*
* Description:
- * Delay for specified amount of time.
+ * Delay for specified amount of time. We use udelay because the timer
+ * interrupt is not guaranteed to be enabled. This will cause an
+ * infinite loop since jiffies (clock ticks) is not updated.
*-F*************************************************************************/
static void
aic7xxx_delay(int seconds)
{
- unsigned long i;
-
- i = jiffies + (seconds * HZ); /* compute time to stop */
+ int i;
- while (jiffies < i)
+ /*
+ * Call udelay() for 1 millisecond inside a loop for
+ * the requested amount of seconds.
+ */
+ for (i=0; i < seconds*1000; i++)
{
- ; /* Do nothing! */
+ udelay(1000); /* Delay for 1 millisecond. */
}
}
@@ -1090,7 +1314,7 @@ aic7xxx_delay(int seconds)
* Return a string containing just the RCS version number from either
* an Id or Revision RCS clause.
*-F*************************************************************************/
-static const char *
+const char *
rcs_version(const char *version_info)
{
static char buf[10];
@@ -1150,8 +1374,10 @@ aic7xxx_info(struct Scsi_Host *notused)
strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
strcat(buffer, "/");
strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
+#if 0
strcat(buffer, "/");
strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
+#endif
return buffer;
}
@@ -1161,9 +1387,12 @@ aic7xxx_info(struct Scsi_Host *notused)
* aic7xxx_length
*
* Description:
- * How much data should be transferred for this SCSI command? Stop
- * at segment sg_last if it's a scatter-gather command so we can
- * compute underflow easily.
+ * How much data should be transferred for this SCSI command? Assume
+ * all segments are to be transferred except for the last sg_last
+ * segments. This will allow us to compute underflow easily. To
+ * calculate the total length of the command, use sg_last = 0. To
+ * calculate the length of all but the last 2 SG segments, use
+ * sg_last = 2.
*-F*************************************************************************/
static unsigned
aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
@@ -1177,7 +1406,7 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
if (cmd->use_sg)
{
- for (i = length = 0; (i < cmd->use_sg) && (i < segments); i++)
+ for (i = length = 0; i < segments; i++)
{
length += sg[i].length;
}
@@ -1199,9 +1428,9 @@ aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
*-F*************************************************************************/
static void
aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
- short period, unsigned char offset, int target, char channel)
+ unsigned char *period, unsigned char *offset, int target, char channel)
{
- int i;
+ int i = num_aic7xxx_syncrates;
unsigned long ultra_enb_addr;
unsigned char ultra_enb, sxfrctl0;
@@ -1209,11 +1438,11 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
* If the offset is 0, then the device is requesting asynchronous
* transfers.
*/
- if (offset != 0)
+ if ((*period >= aic7xxx_syncrates[i].period) && *offset != 0)
{
for (i = 0; i < num_aic7xxx_syncrates; i++)
{
- if ((aic7xxx_syncrates[i].period - period) >= 0)
+ if (*period <= aic7xxx_syncrates[i].period)
{
/*
* Watch out for Ultra speeds when ultra is not enabled and
@@ -1229,99 +1458,57 @@ aic7xxx_scsirate(struct aic7xxx_host *p, unsigned char *scsirate,
*/
continue;
}
- *scsirate = (aic7xxx_syncrates[i].rate) | (offset & 0x0F);
+ *scsirate = (aic7xxx_syncrates[i].rate & 0xF0) | (*offset & 0x0F);
+ *period = aic7xxx_syncrates[i].period;
- /*
- * Ensure Ultra mode is set properly for this target.
- */
- ultra_enb_addr = ULTRA_ENB;
- if ((channel == 'B') || (target > 7))
- {
- ultra_enb_addr++;
- }
- ultra_enb = inb(p->base + ultra_enb_addr);
- sxfrctl0 = inb(p->base + SXFRCTL0);
- if (aic7xxx_syncrates[i].rate & ULTRA_SXFR)
+ if (aic7xxx_verbose)
{
- ultra_enb |= 0x01 << (target & 0x07);
- sxfrctl0 |= ULTRAEN;
+ printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
+ "offset %d.\n", p->host_no, target, channel,
+ aic7xxx_syncrates[i].english, *offset);
}
- else
- {
- ultra_enb &= ~(0x01 << (target & 0x07));
- sxfrctl0 &= ~ULTRAEN;
- }
- outb(ultra_enb, p->base + ultra_enb_addr);
- outb(sxfrctl0, p->base + SXFRCTL0);
-
- printk("scsi%d: Target %d, channel %c, now synchronous at %sMHz, "
- "offset %d.\n", p->host_no, target, channel,
- aic7xxx_syncrates[i].english, offset);
- return;
+ break;
}
}
}
- /*
- * Default to asynchronous transfer
- */
- *scsirate = 0;
- printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
- p->host_no, target, channel);
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_putscb
- *
- * Description:
- * Transfer a SCB to the controller.
- *-F*************************************************************************/
-static inline void
-aic7xxx_putscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
- int base = p->base;
-
- outb(SCBAUTO, SCBCNT + base);
+ if (i >= num_aic7xxx_syncrates)
+ {
+ /*
+ * Use asynchronous transfers.
+ */
+ *scsirate = 0;
+ *period = 0;
+ *offset = 0;
+ if (aic7xxx_verbose)
+ {
+ printk("scsi%d: Target %d, channel %c, using asynchronous transfers.\n",
+ p->host_no, target, channel);
+ }
+ }
/*
- * By turning on the SCB auto increment, any reference
- * to the SCB I/O space postincrements the SCB address
- * we're looking at. So turn this on and dump the relevant
- * portion of the SCB to the card.
- *
- * We can do 16bit transfers on all but 284x.
+ * Ensure Ultra mode is set properly for this target.
*/
- if (p->type == AIC_284x)
+ ultra_enb_addr = ULTRA_ENB;
+ if ((channel == 'B') || (target > 7))
+ {
+ ultra_enb_addr++;
+ }
+ ultra_enb = inb(p->base + ultra_enb_addr);
+ sxfrctl0 = inb(p->base + SXFRCTL0);
+ if ((*scsirate != 0) && (aic7xxx_syncrates[i].rate & ULTRA_SXFR))
{
- outsb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
+ ultra_enb |= 0x01 << (target & 0x07);
+ sxfrctl0 |= FAST20;
}
else
{
- outsl(SCBARRAY + base, scb, (SCB_PIO_TRANSFER_SIZE + 3) / 4);
+ ultra_enb &= ~(0x01 << (target & 0x07));
+ sxfrctl0 &= ~FAST20;
}
-
- outb(0, SCBCNT + base);
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_getscb
- *
- * Description:
- * Get a SCB from the controller.
- *-F*************************************************************************/
-static inline void
-aic7xxx_getscb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
-{
- int base = p->base;
-
- /*
- * This is almost identical to aic7xxx_putscb().
- */
- outb(SCBAUTO, SCBCNT + base);
- insb(SCBARRAY + base, scb, SCB_PIO_TRANSFER_SIZE);
- outb(0, SCBCNT + base);
+ outb(ultra_enb, p->base + ultra_enb_addr);
+ outb(sxfrctl0, p->base + SXFRCTL0);
}
/*+F*************************************************************************
@@ -1375,6 +1562,47 @@ scbq_remove_head(scb_queue_type *queue)
/*+F*************************************************************************
* Function:
+ * scbq_remove
+ *
+ * Description:
+ * Removes an SCB from the list.
+ *
+ *-F*************************************************************************/
+static inline void
+scbq_remove(scb_queue_type *queue, struct aic7xxx_scb *scb)
+{
+ if (queue->head == scb)
+ {
+ /* At beginning of queue, remove from head. */
+ scbq_remove_head(queue);
+ }
+ else
+ {
+ struct aic7xxx_scb *curscb = queue->head;
+
+ /*
+ * Search until the next scb is the one we're looking for, or
+ * we run out of queue.
+ */
+ while ((curscb != NULL) && (curscb->q_next != scb))
+ {
+ curscb = curscb->q_next;
+ }
+ if (curscb != NULL)
+ {
+ /* Found it. */
+ curscb->q_next = scb->q_next;
+ if (scb->q_next == NULL)
+ {
+ /* Update the tail when removing the tail. */
+ queue->tail = curscb;
+ }
+ }
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
* scbq_insert_tail
*
* Description:
@@ -1404,23 +1632,87 @@ scbq_insert_tail(scb_queue_type *queue, struct aic7xxx_scb *scb)
* to be reset and all devices on that channel must be aborted.
*-F*************************************************************************/
static int
-aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel)
+aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel,
+ int lun, unsigned char tag)
{
- int targ = (scb->target_channel_lun >> 4) & 0x0F;
- char chan = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+ int targ = (scb->hscb->target_channel_lun >> 4) & 0x0F;
+ char chan = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+ int slun = scb->hscb->target_channel_lun & 0x07;
+ int match;
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (match_scb) comparing target/channel %d/%c to scb %d/%c\n",
- target, channel, targ, chan);
+ printk("scsi%d: (targ %d/chan %c) matching scb to (targ %d/chan %c)\n",
+ scb->cmd->device->host->host_no, target, channel, targ, chan);
#endif
- if (target == ALL_TARGETS)
+ match = ((chan == channel) || (channel == ALL_CHANNELS));
+ if (match != 0)
+ match = ((targ == target) || (target == ALL_TARGETS));
+ if (match != 0)
+ match = ((lun == slun) || (lun == ALL_LUNS));
+ if (match != 0)
+ match = ((tag == scb->hscb->tag) || (tag == SCB_LIST_NULL));
+
+ return (match);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_add_curscb_to_free_list
+ *
+ * Description:
+ * Adds the current scb (in SCBPTR) to the list of free SCBs.
+ *-F*************************************************************************/
+static void
+aic7xxx_add_curscb_to_free_list(struct aic7xxx_host *p)
+{
+ /*
+ * Invalidate the tag so that aic7xxx_find_scb doesn't think
+ * it's active
+ */
+ outb(SCB_LIST_NULL, p->base + SCB_TAG);
+
+ outb(inb(p->base + FREE_SCBH), p->base + SCB_NEXT);
+ outb(inb(p->base + SCBPTR), p->base + FREE_SCBH);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_rem_scb_from_disc_list
+ *
+ * Description:
+ * Removes the current SCB from the disconnected list and adds it
+ * to the free list.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_rem_scb_from_disc_list(struct aic7xxx_host *p, unsigned char scbptr)
+{
+ unsigned char next;
+ unsigned char prev;
+
+ outb(scbptr, p->base + SCBPTR);
+ next = inb(p->base + SCB_NEXT);
+ prev = inb(p->base + SCB_PREV);
+
+ outb(0, p->base + SCB_CONTROL);
+
+ aic7xxx_add_curscb_to_free_list(p);
+
+ if (prev != SCB_LIST_NULL)
{
- return (chan == channel);
+ outb(prev, p->base + SCBPTR);
+ outb(next, p->base + SCB_NEXT);
}
else
{
- return ((chan == channel) && (targ == target));
+ outb(next, p->base + DISCONNECTED_SCBH);
}
+
+ if (next != SCB_LIST_NULL)
+ {
+ outb(next, p->base + SCBPTR);
+ outb(prev, p->base + SCB_PREV);
+ }
+ return next;
}
/*+F*************************************************************************
@@ -1428,51 +1720,93 @@ aic7xxx_match_scb(struct aic7xxx_scb *scb, int target, char channel)
* aic7xxx_busy_target
*
* Description:
- * Set the specified target active.
+ * Set the specified target busy.
*-F*************************************************************************/
static void
-aic7xxx_busy_target(unsigned char target, char channel, int base)
+aic7xxx_busy_target(struct aic7xxx_host *p, unsigned char target,
+ char channel, unsigned char scbid)
{
- unsigned char active;
- unsigned long active_port = ACTIVE_A + base;
+ unsigned char active_scb;
+ unsigned char info_scb;
+ unsigned int scb_offset;
+
+ info_scb = target / 4;
+ if (channel == 'B')
+ info_scb = info_scb + 2;
+
+ active_scb = inb(p->base + SCBPTR);
+ outb(info_scb, p->base + SCBPTR);
+ scb_offset = SCB_BUSYTARGETS + (target & 0x03);
+ outb(scbid, p->base + scb_offset);
+ outb(active_scb, p->base + SCBPTR);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_index_busy_target
+ *
+ * Description:
+ * Returns the index of the busy target, and optionally sets the
+ * target inactive.
+ *-F*************************************************************************/
+static unsigned char
+aic7xxx_index_busy_target(struct aic7xxx_host *p, unsigned char target,
+ char channel, int unbusy)
+{
+ unsigned char active_scb;
+ unsigned char info_scb;
+ unsigned char busy_scbid;
+ unsigned int scb_offset;
+
+ info_scb = target / 4;
+ if (channel == 'B')
+ info_scb = info_scb + 2;
- if ((target > 0x07) || (channel == 'B'))
+ active_scb = inb(p->base + SCBPTR);
+ outb(info_scb, p->base + SCBPTR);
+ scb_offset = SCB_BUSYTARGETS + (target & 0x03);
+ busy_scbid = inb(p->base + scb_offset);
+ if (unbusy)
{
- /*
- * targets on the Second channel or above id 7 store info in byte two
- * of ACTIVE
- */
- active_port++;
+ outb(SCB_LIST_NULL, p->base + scb_offset);
}
- active = inb(active_port);
- active |= (0x01 << (target & 0x07));
- outb(active, active_port);
+ outb(active_scb, p->base + SCBPTR);
+ return (busy_scbid);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_unbusy_target
+ * aic7xxx_find_scb
*
* Description:
- * Set the specified target inactive.
+ * Look through the SCB array of the card and attempt to find the
+ * hardware SCB that corresponds to the passed in SCB. Return
+ * SCB_LIST_NULL if unsuccessful. This routine assumes that the
+ * card is already paused.
*-F*************************************************************************/
-static void
-aic7xxx_unbusy_target(unsigned char target, char channel, int base)
+static unsigned char
+aic7xxx_find_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- unsigned char active;
- unsigned long active_port = ACTIVE_A + base;
+ unsigned char saved_scbptr;
+ unsigned char curindex;
- if ((target > 0x07) || (channel == 'B'))
+ saved_scbptr = inb(p->base + SCBPTR);
+ curindex = 0;
+ for (curindex = 0; curindex < p->scb_data->maxhscbs; curindex++)
{
- /*
- * targets on the Second channel or above id 7 store info in byte two
- * of ACTIVE
- */
- active_port++;
+ outb(curindex, p->base + SCBPTR);
+ if (inb(p->base + SCB_TAG) == scb->hscb->tag)
+ {
+ break;
+ }
}
- active = inb(active_port);
- active &= ~(0x01 << (target & 0x07));
- outb(active, active_port);
+ outb(saved_scbptr, p->base + SCBPTR);
+ if (curindex >= p->scb_data->maxhscbs)
+ {
+ curindex = SCB_LIST_NULL;
+ }
+
+ return (curindex);
}
/*+F*************************************************************************
@@ -1480,68 +1814,60 @@ aic7xxx_unbusy_target(unsigned char target, char channel, int base)
* aic7xxx_allocate_scb
*
* Description:
- * Get a free SCB either from one already assigned to a hardware
- * slot, or one that will require an SCB to be paged out before
- * use. If there are none, attempt to allocate a new one.
+ * Get an SCB from the free list or by allocating a new one.
*-F*************************************************************************/
static struct aic7xxx_scb *
aic7xxx_allocate_scb(struct aic7xxx_host *p)
{
- struct aic7xxx_scb *scbp = NULL;
- int maxscbs;
+ struct aic7xxx_scb *scbp = NULL;
+ struct aic7xxx_hwscb *hscbp = NULL;
+#ifdef AGRESSIVE
+ long processor_flags;
- scbp = p->scb_link->free_scbs.head;
+ save_flags(processor_flags);
+ cli();
+#endif
+
+ scbp = p->scb_data->free_scbs.head;
if (scbp != NULL)
{
- scbq_remove_head(&p->scb_link->free_scbs);
+ scbq_remove_head(&p->scb_data->free_scbs);
}
else
{
- /*
- * This should always be NULL if paging is not enabled.
- */
- scbp = p->page_scbs.head;
- if (scbp != NULL)
+ if (p->scb_data->numscbs < p->scb_data->maxscbs)
{
- scbq_remove_head(&p->page_scbs);
- }
- else
- {
- /*
- * Set limit the SCB allocation to the maximum number of
- * hardware SCBs if paging is not enabled; otherwise use
- * the maximum (255).
- */
- if (p->flags & PAGE_ENABLED)
- maxscbs = p->maxscbs;
- else
- maxscbs = p->maxhscbs;
- if (p->scb_link->numscbs < maxscbs)
- {
- int scb_index = p->scb_link->numscbs;
- int scb_size = sizeof(struct aic7xxx_scb);
+ int scb_index = p->scb_data->numscbs;
+ int scb_size = sizeof(struct aic7xxx_scb) +
+ sizeof (struct hw_scatterlist) * AIC7XXX_MAX_SG;
- p->scb_array[scb_index] = kmalloc(scb_size, GFP_ATOMIC | GFP_DMA);
- scbp = (p->scb_array[scb_index]);
- if (scbp != NULL)
- {
- memset(scbp, 0, sizeof(*scbp));
- scbp->tag = scb_index;
- if (scb_index < p->maxhscbs)
- scbp->position = scb_index;
- else
- scbp->position = SCB_LIST_NULL;
- p->scb_link->numscbs++;
- }
+ scbp = kmalloc(scb_size, GFP_ATOMIC);
+ if (scbp != NULL)
+ {
+ memset(scbp, 0, sizeof(struct aic7xxx_scb));
+ hscbp = &p->scb_data->hscbs[scb_index];
+ scbp->hscb = hscbp;
+ scbp->sg_list = (struct hw_scatterlist *) &scbp[1];
+ memset(hscbp, 0, sizeof(struct aic7xxx_hwscb));
+ hscbp->tag = scb_index;
+ p->scb_data->numscbs++;
+ /*
+ * Place in the scb array; never is removed
+ */
+ p->scb_data->scb_array[scb_index] = scbp;
}
}
}
+#ifdef AIC7XXX_DEBUG
if (scbp != NULL)
{
-#ifdef AIC7XXX_DEBUG
- p->scb_link->activescbs++;
-#endif
+ p->activescbs++;
}
+#endif
+
+#ifdef AGRESSIVE
+ restore_flags(processor_flags);
+#endif
return (scbp);
}
@@ -1581,6 +1907,7 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
cmd = p->completeq.head;
p->completeq.head = (Scsi_Cmnd *)cmd->host_scribble;
cmd->host_scribble = NULL;
+ p->device_status[TARGET_INDEX(cmd)].active_cmds--;
cmd->scsi_done(cmd);
}
p->completeq.tail = NULL;
@@ -1591,53 +1918,29 @@ aic7xxx_done_cmds_complete(struct aic7xxx_host *p)
* aic7xxx_free_scb
*
* Description:
- * Free the scb and update the page, waiting, free scb lists.
+ * Free the scb and insert into the free scb list.
*-F*************************************************************************/
static void
aic7xxx_free_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- struct aic7xxx_scb *wscb;
+ struct aic7xxx_hwscb *hscb;
+ long flags;
+
+ hscb = scb->hscb;
+ save_flags(flags);
+ cli();
- scb->state = SCB_FREE;
+ scb->flags = SCB_FREE;
scb->cmd = NULL;
- scb->control = 0;
- scb->state = 0;
+ hscb->control = 0;
+ hscb->target_status = 0;
- if (scb->position == SCB_LIST_NULL)
- {
- scbq_insert_head(&p->page_scbs, scb);
- }
- else
- {
- /*
- * If there are any SCBS on the waiting queue, assign the slot of this
- * "freed" SCB to the first one. We'll run the waiting queues after
- * all command completes for a particular interrupt are completed or
- * when we start another command.
- */
- wscb = p->waiting_scbs.head;
- if (wscb != NULL)
- {
- scbq_remove_head(&p->waiting_scbs);
- wscb->position = scb->position;
- scbq_insert_tail(&p->assigned_scbs, wscb);
- wscb->state = (wscb->state & ~SCB_WAITINGQ) | SCB_ASSIGNEDQ;
-
- /*
- * The "freed" SCB will need to be assigned a slot before being
- * used, so put it in the page_scbs queue.
- */
- scb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->page_scbs, scb);
- }
- else
- {
- scbq_insert_head(&p->scb_link->free_scbs, scb);
- }
+ scbq_insert_head(&p->scb_data->free_scbs, scb);
#ifdef AIC7XXX_DEBUG
- p->scb_link->activescbs--; /* For debugging purposes. */
+ p->activescbs--; /* For debugging purposes. */
#endif
- }
+
+ restore_flags(flags);
}
/*+F*************************************************************************
@@ -1652,68 +1955,113 @@ aic7xxx_done(struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
Scsi_Cmnd *cmd = scb->cmd;
+ if (scb->flags & SCB_RECOVERY_SCB)
+ {
+ p->flags &= ~IN_TIMEOUT;
+ }
+ if (cmd->result == DID_OK)
+ {
+ if (scb->flags & SCB_ABORTED)
+ {
+ cmd->result = (DID_RESET << 16);
+ }
+ }
+ if ((scb->flags & (SCB_MSGOUT_WDTR | SCB_MSGOUT_SDTR)) != 0)
+ {
+ unsigned short mask;
+
+ mask = 0x01 << TARGET_INDEX(scb->cmd);
+ if (scb->flags & SCB_MSGOUT_WDTR)
+ {
+ p->wdtr_pending &= ~mask;
+ }
+ if (scb->flags & SCB_MSGOUT_SDTR)
+ {
+ p->sdtr_pending &= ~mask;
+ }
+ }
aic7xxx_free_scb(p, scb);
aic7xxx_queue_cmd_complete(p, cmd);
+#ifdef AIC7XXX_PROC_STATS
+ {
+ int actual;
+
+ /*
+ * XXX: we should actually know how much actually transferred
+ * XXX: for each command, but apparently that's too difficult.
+ */
+ actual = aic7xxx_length(cmd, 0);
+ if (!(scb->flags & (SCB_ABORTED | SCB_SENSE)) && (actual > 0)
+ && (aic7xxx_error(cmd) == 0))
+ {
+ struct aic7xxx_xferstats *sp;
+ long *ptr;
+ int x;
+
+ sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
+ sp->xfers++;
+
+ if (cmd->request.cmd == WRITE)
+ {
+ sp->w_total++;
+ sp->w_total512 += (actual >> 9);
+ ptr = sp->w_bins;
+ }
+ else
+ {
+ sp->r_total++;
+ sp->r_total512 += (actual >> 9);
+ ptr = sp->r_bins;
+ }
+ for (x = 9; x <= 17; x++)
+ {
+ if (actual < (1 << x))
+ {
+ ptr[x - 9]++;
+ break;
+ }
+ }
+ if (x > 17)
+ {
+ ptr[x - 9]++;
+ }
+ }
+ }
+#endif /* AIC7XXX_PROC_STATS */
}
/*+F*************************************************************************
* Function:
- * aic7xxx_done_aborted_scbs
+ * aic7xxx_run_done_queue
*
* Description:
- * Calls the scsi_done() for the Scsi_Cmnd of each scb in the
- * aborted list, and adds each scb to the free list.
+ * Calls the aic7xxx_done() for the Scsi_Cmnd of each scb in the
+ * aborted list, and adds each scb to the free list. If complete
+ * is TRUE, we also process the commands complete list.
*-F*************************************************************************/
static void
-aic7xxx_done_aborted_scbs(struct aic7xxx_host *p)
+aic7xxx_run_done_queue(struct aic7xxx_host *p, /*complete*/ int complete)
{
- Scsi_Cmnd *cmd;
struct aic7xxx_scb *scb;
int i;
- for (i = 0; i < p->scb_link->numscbs; i++)
+ for (i = 0; i < p->scb_data->numscbs; i++)
{
- scb = (p->scb_array[i]);
- if (scb->state & SCB_QUEUED_FOR_DONE)
+ scb = p->scb_data->scb_array[i];
+ if (scb->flags & SCB_QUEUED_FOR_DONE)
{
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (done_aborted_scbs) Aborting scb %d, TCL=%d/%d/%d\n",
- scb->position, TCL_OF_SCB(scb));
+ printk("(scsi%d:%d:%d) Aborting scb %d\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
#endif
- /*
- * Process the command after marking the scb as free
- * and adding it to the free list.
- */
- cmd = scb->cmd;
- p->device_status[TARGET_INDEX(cmd)].flags = 0;
- aic7xxx_free_scb(p, scb);
- cmd->scsi_done(cmd); /* call the done function */
+ aic7xxx_done(p, scb);
}
}
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_add_waiting_scb
- *
- * Description:
- * Add this SCB to the head of the "waiting for selection" list.
- *-F*************************************************************************/
-static void
-aic7xxx_add_waiting_scb(u_long base, struct aic7xxx_scb *scb)
-{
- unsigned char next;
- unsigned char curscb;
-
- curscb = inb(SCBPTR + base);
- next = inb(WAITING_SCBH + base);
-
- outb(scb->position, SCBPTR + base);
- outb(next, SCB_NEXT + base);
- outb(scb->position, WAITING_SCBH + base);
-
- outb(curscb, SCBPTR + base);
+ if (complete)
+ {
+ aic7xxx_done_cmds_complete(p);
+ }
}
/*+F*************************************************************************
@@ -1726,26 +2074,23 @@ aic7xxx_add_waiting_scb(u_long base, struct aic7xxx_scb *scb)
*-F*************************************************************************/
static unsigned char
aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
- unsigned char prev)
+ unsigned char scbpos, unsigned char prev)
{
unsigned char curscb, next;
- int target = (scb->target_channel_lun >> 4) & 0x0F;
- char channel = (scb->target_channel_lun & SELBUSB) ? 'B' : 'A';
- int base = p->base;
/*
* Select the SCB we want to abort and pull the next pointer out of it.
*/
- curscb = inb(SCBPTR + base);
- outb(scb->position, SCBPTR + base);
- next = inb(SCB_NEXT + base);
+ curscb = inb(p->base + SCBPTR);
+ outb(scbpos, p->base + SCBPTR);
+ next = inb(p->base + SCB_NEXT);
/*
* Clear the necessary fields
*/
- outb(0, SCB_CONTROL + base);
- outb(SCB_LIST_NULL, SCB_NEXT + base);
- aic7xxx_unbusy_target(target, channel, base);
+ outb(0, p->base + SCB_CONTROL);
+
+ aic7xxx_add_curscb_to_free_list(p);
/*
* Update the waiting list
@@ -1755,22 +2100,23 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
/*
* First in the list
*/
- outb(next, WAITING_SCBH + base);
+ outb(next, p->base + WAITING_SCBH);
}
else
{
/*
* Select the scb that pointed to us and update its next pointer.
*/
- outb(prev, SCBPTR + base);
- outb(next, SCB_NEXT + base);
+ outb(prev, p->base + SCBPTR);
+ outb(next, p->base + SCB_NEXT);
}
/*
* Point us back at the original scb position and inform the SCSI
* system that the command has been aborted.
*/
- outb(curscb, SCBPTR + base);
- scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+ outb(curscb, p->base + SCBPTR);
+ scb->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+ scb->flags &= ~SCB_ACTIVE;
scb->cmd->result = (DID_RESET << 16);
return (next);
@@ -1778,6 +2124,75 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
/*+F*************************************************************************
* Function:
+ * aic7xxx_search_qinfifo
+ *
+ * Description:
+ * Search the queue-in FIFO for matching SCBs and conditionally
+ * requeue. Returns the number of matching SCBs.
+ *-F*************************************************************************/
+static int
+aic7xxx_search_qinfifo(struct aic7xxx_host *p, int target, char channel,
+ int lun, unsigned char tag, int flags, int requeue)
+{
+ unsigned char saved_queue[AIC7XXX_MAXSCB];
+ int queued = inb(p->base + QINCNT) & p->qcntmask;
+ int i;
+ int found;
+ struct aic7xxx_scb *scbp;
+ scb_queue_type removed_scbs;
+
+ found = 0;
+ scbq_init (&removed_scbs);
+ for (i = 0; i < (queued - found); i++)
+ {
+ saved_queue[i] = inb(p->base + QINFIFO);
+ scbp = p->scb_data->scb_array[saved_queue[i]];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ {
+ /*
+ * We found an scb that needs to be removed.
+ */
+ if (requeue)
+ {
+ scbq_insert_head(&removed_scbs, scbp);
+ }
+ else
+ {
+ scbp->flags = flags;
+ scbp->flags &= ~SCB_ACTIVE;
+ /*
+ * XXX - Don't know what error to use here.
+ */
+ aic7xxx_error(scbp->cmd) = DID_RESET;
+ }
+ i--;
+ found++;
+ }
+ }
+ /* Now put the saved scbs back. */
+ for (queued = 0; queued < i; queued++)
+ outb(saved_queue[queued], p->base + QINFIFO);
+
+ if (requeue)
+ {
+ scbp = removed_scbs.head;
+ while (scbp != NULL)
+ {
+ scbq_remove_head(&removed_scbs);
+ /*
+ * XXX - Shouldn't we be adding this to the free list?
+ */
+ scbq_insert_head(&p->waiting_scbs, scbp);
+ scbp->flags |= SCB_WAITINGQ;
+ scbp = removed_scbs.head;
+ }
+ }
+
+ return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
* aic7xxx_reset_device
*
* Description:
@@ -1785,131 +2200,280 @@ aic7xxx_abort_waiting_scb(struct aic7xxx_host *p, struct aic7xxx_scb *scb,
* all active and queued scbs for that target/channel.
*-F*************************************************************************/
static int
-aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel)
+aic7xxx_reset_device(struct aic7xxx_host *p, int target, char channel,
+ int lun, unsigned char tag)
{
- int base = p->base;
- struct aic7xxx_scb *scb;
+ struct aic7xxx_scb *scbp;
unsigned char active_scb;
int i = 0;
- int found = 0;
+ int found;
/*
* Restore this when we're done
*/
- active_scb = inb(SCBPTR + base);
+ active_scb = inb(p->base + SCBPTR);
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_device) target/channel %d/%c, active_scb %d\n",
- target, channel, active_scb);
+ printk("(scsi%d:%d:%d) Reset device, active_scb %d\n",
+ p->host_no, target, CHAN_TO_INT(channel), active_scb);
#endif
+
/*
- * Search the QINFIFO.
+ * Deal with the busy target and linked next issues.
*/
{
- int saved_queue[AIC7XXX_MAXSCB];
- int queued = inb(QINCNT + base) & p->qcntmask;
+ int min_target, max_target;
+ unsigned char busy_scbid;
- for (i = 0; i < (queued - found); i++)
+ /* Make all targets 'relative' to bus A. */
+ if (target == ALL_TARGETS)
{
- saved_queue[i] = inb(QINFIFO + base);
- outb(saved_queue[i], SCBPTR + base);
- scb = (p->scb_array[inb(SCB_TAG + base)]);
- if (aic7xxx_match_scb(scb, target, channel))
+ switch (channel)
{
- /*
- * We found an scb that needs to be aborted.
- */
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_device) aborting SCB %d, TCL=%d/%d/%d\n",
- saved_queue[i], TCL_OF_SCB(scb));
-#endif
- scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
- scb->cmd->result = (DID_RESET << 16);
- outb(0, SCB_CONTROL + base);
- i--;
- found++;
+ case 'A':
+ min_target = 0;
+ max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
+ break;
+ case 'B':
+ min_target = 8;
+ max_target = 15;
+ break;
+ case ALL_CHANNELS:
+ default:
+ min_target = 0;
+ max_target = (p->bus_type == AIC_SINGLE) ? 7 : 15;
+ break;
}
}
- /*
- * Now put the saved scbs back.
- */
- for (queued = 0; queued < i; queued++)
+ else
+ {
+ min_target = target + channel == 'B' ? 8 : 0;
+ max_target = min_target;
+ }
+
+ for (i = min_target; i <= max_target; i++)
{
- outb(saved_queue[queued], QINFIFO + base);
+ busy_scbid = aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/FALSE);
+ if (busy_scbid < p->scb_data->numscbs)
+ {
+ struct aic7xxx_scb *busy_scb;
+ struct aic7xxx_scb *next_scb;
+ unsigned char next_scbid;
+
+ busy_scb = p->scb_data->scb_array[busy_scbid];
+
+ next_scbid = busy_scb->hscb->data_count >> 24;
+
+ if (next_scbid == SCB_LIST_NULL)
+ {
+ busy_scbid = aic7xxx_find_scb(p, busy_scb);
+
+ if (busy_scbid != SCB_LIST_NULL)
+ {
+ outb(busy_scbid, p->base + SCBPTR);
+ next_scbid = inb(p->base + SCB_LINKED_NEXT);
+ }
+ }
+
+ if (aic7xxx_match_scb(busy_scb, target, channel, lun, tag))
+ {
+ aic7xxx_index_busy_target(p, i, 'A', /*unbusy*/TRUE);
+ }
+
+ if (next_scbid != SCB_LIST_NULL)
+ {
+ next_scb = p->scb_data->scb_array[next_scbid];
+ if (aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+ {
+ continue;
+ }
+ /* Requeue for later processing */
+ scbq_insert_head(&p->waiting_scbs, next_scb);
+ next_scb->flags |= SCB_WAITINGQ;
+ }
+ }
}
}
+ found = aic7xxx_search_qinfifo(p, target, channel, lun, tag,
+ SCB_ABORTED | SCB_QUEUED_FOR_DONE, /* requeue */ FALSE);
+
/*
* Search waiting for selection list.
*/
{
- unsigned char next, prev;
+ unsigned char next, prev, scb_index;
- next = inb(WAITING_SCBH + base); /* Start at head of list. */
+ next = inb(p->base + WAITING_SCBH); /* Start at head of list. */
prev = SCB_LIST_NULL;
while (next != SCB_LIST_NULL)
{
- outb(next, SCBPTR + base);
- scb = (p->scb_array[inb(SCB_TAG + base)]);
- /*
- * Select the SCB.
- */
- if (aic7xxx_match_scb(scb, target, channel))
+ outb(next, p->base + SCBPTR);
+ scb_index = inb(p->base + SCB_TAG);
+ if (scb_index >= p->scb_data->numscbs)
+ {
+ panic("aic7xxx: Waiting List inconsistency; SCB index=%d, numscbs=%d\n",
+ scb_index, p->scb_data->numscbs);
+ }
+ scbp = p->scb_data->scb_array[scb_index];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
{
- next = aic7xxx_abort_waiting_scb(p, scb, prev);
+ unsigned char linked_next;
+
+ next = aic7xxx_abort_waiting_scb(p, scbp, next, prev);
+ linked_next = inb(p->base + SCB_LINKED_NEXT);
+ if (linked_next != SCB_LIST_NULL)
+ {
+ struct aic7xxx_scb *next_scb;
+ /*
+ * Requeue the waiting SCB via the waiting list.
+ */
+ next_scb = p->scb_data->scb_array[linked_next];
+ if (! aic7xxx_match_scb(next_scb, target, channel, lun, tag))
+ {
+ scbq_insert_head(&p->waiting_scbs, next_scb);
+ next_scb->flags |= SCB_WAITINGQ;
+ }
+ }
found++;
}
else
{
prev = next;
- next = inb(SCB_NEXT + base);
+ next = inb(p->base + SCB_NEXT);
+ }
+ }
+ }
+
+ /*
+ * Go through disconnected list and remove any entries we have queued
+ * for completion, zeroing their control byte too.
+ */
+ {
+ unsigned char next, prev, scb_index;
+
+ next = inb(p->base + DISCONNECTED_SCBH);
+ prev = SCB_LIST_NULL;
+
+ while (next != SCB_LIST_NULL)
+ {
+ outb(next, p->base + SCBPTR);
+ scb_index = inb(p->base + SCB_TAG);
+ if (scb_index > p->scb_data->numscbs)
+ {
+ panic("aic7xxx: Disconnected List inconsistency, SCB index = %d, "
+ "num scbs = %d.\n", scb_index, p->scb_data->numscbs);
+ }
+ scbp = p->scb_data->scb_array[scb_index];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ {
+ next = aic7xxx_rem_scb_from_disc_list(p, next);
+ }
+ else
+ {
+ prev = next;
+ next = inb(p->base + SCB_NEXT);
+ }
+ }
+ }
+
+ /*
+ * Go through the hardware SCB array looking for commands that
+ * were active but not on any list.
+ */
+ for (i = 0; i < p->scb_data->maxhscbs; i++)
+ {
+ unsigned char scbid;
+
+ outb(i, p->base + SCBPTR);
+ scbid = inb(p->base + SCB_TAG);
+ if (scbid < p->scb_data->numscbs)
+ {
+ scbp = p->scb_data->scb_array[scbid];
+ if (aic7xxx_match_scb(scbp, target, channel, lun, tag))
+ {
+ aic7xxx_add_curscb_to_free_list(p);
}
}
}
/*
* Go through the entire SCB array now and look for commands for
- * for this target that are active. These are other (most likely
+ * for this target that are stillactive. These are other (most likely
* tagged) commands that were disconnected when the reset occurred.
*/
- for (i = 0; i < p->scb_link->numscbs; i++)
+ for (i = 0; i < p->scb_data->numscbs; i++)
{
- scb = (p->scb_array[i]);
- if ((scb->state & SCB_ACTIVE) && aic7xxx_match_scb(scb, target, channel))
+ scbp = p->scb_data->scb_array[i];
+ if (((scbp->flags & SCB_ACTIVE) != 0) &&
+ aic7xxx_match_scb(scbp, target, channel, lun, tag))
{
- /*
- * Ensure the target is "free"
- */
- aic7xxx_unbusy_target(target, channel, base);
- if (! (scb->state & SCB_PAGED_OUT))
+ scbp->flags |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
+ scbp->flags &= ~SCB_ACTIVE;
+ aic7xxx_error(scbp->cmd) = DID_RESET;
+
+ found++;
+
+ if ((scbp->flags & SCB_WAITINGQ) != 0)
{
- outb(scb->position, SCBPTR + base);
- outb(0, SCB_CONTROL + base);
+ scbq_remove(&p->waiting_scbs, scbp);
+ scbp->flags &= ~SCB_WAITINGQ;
}
- scb->state |= SCB_ABORTED | SCB_QUEUED_FOR_DONE;
- scb->cmd->result = (DID_RESET << 16);
- found++;
}
}
- outb(active_scb, SCBPTR + base);
+ outb(active_scb, p->base + SCBPTR);
return (found);
}
/*+F*************************************************************************
* Function:
+ * aic7xxx_clear_intstat
+ *
+ * Description:
+ * Clears the interrupt status.
+ *-F*************************************************************************/
+static void
+aic7xxx_clear_intstat(struct aic7xxx_host *p)
+{
+ /* Clear any interrupt conditions this may have caused. */
+ outb(CLRSELDO | CLRSELDI | CLRSELINGO, p->base + CLRSINT0);
+ outb(CLRSELTIMEO | CLRATNO | CLRSCSIRSTI | CLRBUSFREE | CLRSCSIPERR |
+ CLRPHASECHG | CLRREQINIT, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+}
+
+/*+F*************************************************************************
+ * Function:
* aic7xxx_reset_current_bus
*
* Description:
* Reset the current SCSI bus.
*-F*************************************************************************/
static void
-aic7xxx_reset_current_bus(int base)
+aic7xxx_reset_current_bus(struct aic7xxx_host *p)
{
- outb(SCSIRSTO, SCSISEQ + base);
+ unsigned char scsiseq;
+
+ /* Disable reset interrupts. */
+ outb(inb(p->base + SIMODE1) & ~ENSCSIRST, p->base + SIMODE1);
+
+ /* Turn on the bus reset. */
+ scsiseq = inb(p->base + SCSISEQ);
+ outb(scsiseq | SCSIRSTO, p->base + SCSISEQ);
+
+ udelay(1000);
+
+ /* Turn off the bus reset. */
+ outb(scsiseq & ~SCSIRSTO, p->base + SCSISEQ);
+
+ aic7xxx_clear_intstat(p);
+
+ /* Re-enable reset interrupts. */
+ outb(inb(p->base + SIMODE1) | ENSCSIRST, p->base + SIMODE1);
+
udelay(1000);
- outb(0, SCSISEQ + base);
}
/*+F*************************************************************************
@@ -1922,25 +2486,24 @@ aic7xxx_reset_current_bus(int base)
static int
aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
{
- int base = p->base;
- unsigned char sblkctl;
- char cur_channel;
unsigned long offset, offset_max;
int found;
+ unsigned char sblkctl;
+ char cur_channel;
+ pause_sequencer(p);
/*
- * Clean up all the state information for the
- * pending transactions on this bus.
+ * Clean up all the state information for the pending transactions
+ * on this bus.
*/
- found = aic7xxx_reset_device(p, ALL_TARGETS, channel);
+ found = aic7xxx_reset_device(p, ALL_TARGETS, channel, ALL_LUNS, SCB_LIST_NULL);
if (channel == 'B')
{
p->needsdtr |= (p->needsdtr_copy & 0xFF00);
p->sdtr_pending &= 0x00FF;
- outb(0, ACTIVE_B + base);
- offset = TARG_SCRATCH + base + 8;
- offset_max = TARG_SCRATCH + base + 16;
+ offset = TARG_SCRATCH + 8;
+ offset_max = TARG_SCRATCH + 16;
}
else
{
@@ -1950,132 +2513,100 @@ aic7xxx_reset_channel(struct aic7xxx_host *p, char channel, int initiate_reset)
p->needwdtr = p->needwdtr_copy;
p->sdtr_pending = 0x0;
p->wdtr_pending = 0x0;
- outb(0, ACTIVE_A + base);
- outb(0, ACTIVE_B + base);
- offset = TARG_SCRATCH + base;
- offset_max = TARG_SCRATCH + base + 16;
+ offset = TARG_SCRATCH;
+ offset_max = TARG_SCRATCH + 16;
}
else
{
+ /* Channel A */
p->needsdtr |= (p->needsdtr_copy & 0x00FF);
p->sdtr_pending &= 0xFF00;
- outb(0, ACTIVE_A + base);
- offset = TARG_SCRATCH + base;
- offset_max = TARG_SCRATCH + base + 8;
+ offset = TARG_SCRATCH;
+ offset_max = TARG_SCRATCH + 8;
}
}
+
while (offset < offset_max)
{
/*
- * Revert to async/narrow transfers
- * until we renegotiate.
+ * Revert to async/narrow transfers until we renegotiate.
*/
u_char targ_scratch;
- targ_scratch = inb(offset);
+
+ targ_scratch = inb(p->base + offset);
targ_scratch &= SXFR;
- outb(targ_scratch, offset);
+ outb(targ_scratch, p->base + offset);
offset++;
}
/*
* Reset the bus and unpause/restart the controller
*/
-
- /*
- * Case 1: Command for another bus is active
- */
- sblkctl = inb(SBLKCTL + base);
+ sblkctl = inb(p->base + SBLKCTL);
cur_channel = (sblkctl & SELBUSB) ? 'B' : 'A';
if (cur_channel != channel)
{
+ /*
+ * Case 1: Command for another bus is active
+ */
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_channel) Stealthily resetting channel %c\n",
- channel);
+ printk("scsi%d: Stealthily resetting channel %c\n",
+ p->host_no, channel);
#endif
/*
- * Stealthily reset the other bus without upsetting the current bus
+ * Stealthily reset the other bus without upsetting the current bus.
*/
- outb(sblkctl ^ SELBUSB, SBLKCTL + base);
+ outb(sblkctl ^ SELBUSB, p->base + SBLKCTL);
+ outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
if (initiate_reset)
{
- aic7xxx_reset_current_bus(base);
+ aic7xxx_reset_current_bus(p);
+ /*
+ * Cause the mid-level SCSI code to delay any further
+ * queueing by the bus settle time for us.
+ */
+ p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
}
- outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
- outb(sblkctl, SBLKCTL + base);
-
- UNPAUSE_SEQUENCER(p);
+ outb(0, p->base + SCSISEQ);
+ aic7xxx_clear_intstat(p);
+ outb(sblkctl, p->base + SBLKCTL);
+ unpause_sequencer(p, /* unpause_always */ FALSE);
}
- /*
- * Case 2: A command from this bus is active or we're idle
- */
else
{
+ /*
+ * Case 2: A command from this bus is active or we're idle.
+ */
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_channel) Resetting current channel %c\n",
- channel);
+ printk("scsi%d: Resetting current channel %c\n",
+ p->host_no, channel);
#endif
+ outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
if (initiate_reset)
{
- aic7xxx_reset_current_bus(base);
+ aic7xxx_reset_current_bus(p);
+ /*
+ * Cause the mid-level SCSI code to delay any further
+ * queueing by the bus settle time for us.
+ */
+#if 0
+ p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
+#endif
}
- outb(CLRSCSIRSTI | CLRSELTIMEO, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
- RESTART_SEQUENCER(p);
+ outb(0, p->base + SCSISEQ);
+ aic7xxx_clear_intstat(p);
+ restart_sequencer(p);
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset_channel) Channel reset, sequencer restarted\n");
+ printk("scsi%d: Channel reset, sequencer restarted\n", p->host_no);
#endif
}
/*
- * Cause the mid-level SCSI code to delay any further
- * queueing by the bus settle time for us.
- */
- p->host->last_reset = (jiffies + (AIC7XXX_RESET_DELAY * HZ));
-
- /*
* Now loop through all the SCBs that have been marked for abortion,
* and call the scsi_done routines.
*/
- aic7xxx_done_aborted_scbs(p);
- return found;
-}
-
-/*+F*************************************************************************
- * Function:
- * aic7xxx_page_scb
- *
- * Description:
- * Swap in_scbp for out_scbp down in the cards SCB array.
- * We assume that the SCB for out_scbp is already selected in SCBPTR.
- *
- *-F*************************************************************************/
-static inline void
-aic7xxx_page_scb(struct aic7xxx_host *p, struct aic7xxx_scb *out_scbp,
- struct aic7xxx_scb *in_scbp)
-{
- int index;
-
- /* Page-out */
-#if 0
-printk("aic7xxx: Paging out target %d SCB and paging in target %d SCB\n",
- out_scbp->cmd->target, in_scbp->cmd->target);
-#endif
- aic7xxx_getscb(p, out_scbp);
- out_scbp->state |= SCB_PAGED_OUT;
- if (!(out_scbp->control & TAG_ENB))
- {
- /* Stick in non-tagged array */
- index = (out_scbp->target_channel_lun >> 4) |
- (out_scbp->target_channel_lun & SELBUSB);
- p->pagedout_ntscbs[index] = out_scbp;
- }
-
- /* Page-in */
- in_scbp->position = out_scbp->position;
- out_scbp->position = SCB_LIST_NULL;
- aic7xxx_putscb(p, in_scbp);
- in_scbp->state &= ~SCB_PAGED_OUT;
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+ return (found);
}
/*+F*************************************************************************
@@ -2083,1159 +2614,1326 @@ printk("aic7xxx: Paging out target %d SCB and paging in target %d SCB\n",
* aic7xxx_run_waiting_queues
*
* Description:
- * Scan the assigned_scbs and waiting_scbs queues. For scbs in the
- * assigned_scbs queue, we download and start them. For scbs in the
- * waiting_scbs queue, we page in as many as we can being careful
- * not to cause a deadlock for a reconnecting target.
- *
+ * Scan the awaiting_scbs queue downloading and starting as many
+ * scbs as we can.
*-F*************************************************************************/
static inline void
aic7xxx_run_waiting_queues(struct aic7xxx_host *p)
{
struct aic7xxx_scb *scb;
- u_char cur_scb, intstat;
- u_long base = p->base;
- long flags;
- if ((p->assigned_scbs.head == NULL) && (p->waiting_scbs.head == NULL))
+ if (p->waiting_scbs.head == NULL)
return;
- save_flags(flags);
- cli();
-
- PAUSE_SEQUENCER(p);
- cur_scb = inb(SCBPTR + base);
- intstat = inb(INTSTAT + base);
-
+ pause_sequencer(p);
/*
* First handle SCBs that are waiting but have been assigned a slot.
*/
- scb = p->assigned_scbs.head;
- while (scb != NULL)
- {
- scbq_remove_head(&(p->assigned_scbs));
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- /* Mark this as an active command. */
- scb->state = (scb->state & ~SCB_ASSIGNEDQ) | SCB_ACTIVE;
- outb(scb->position, QINFIFO + base);
- scb = p->assigned_scbs.head;
- }
-
- /* Now deal with SCBs that require paging. */
scb = p->waiting_scbs.head;
- if (scb != NULL)
+ while (scb != NULL)
{
- u_char disc_scb = inb(DISCONNECTED_SCBH + base);
- u_char active = inb(FLAGS + base) & (SELECTED | IDENTIFY_SEEN);
- int count = 0;
- u_char next_scb;
-
- while (scb != NULL)
+ if (p->curqincnt >= p->qfullcount)
{
- /* Attempt to page this SCB in */
- if (disc_scb == SCB_LIST_NULL)
- break;
-
- /*
- * Advance disc_scb to the next one in the list.
- */
- outb(disc_scb, SCBPTR + base);
- next_scb = inb(SCB_NEXT + base);
-
- /*
- * We have to be careful about when we allow an SCB to be paged out.
- * There must always be at least one slot availible for a reconnecting
- * target in case it references an SCB that has been paged out. Our
- * heuristic is that either the disconnected list has at least two
- * entries in it or there is one entry and the sequencer is activily
- * working on an SCB which implies that it will either complete or
- * disconnect before another reconnection can occur.
- */
- if ((next_scb != SCB_LIST_NULL) || active)
+ p->curqincnt = inb(p->base + QINCNT) & p->qcntmask;
+ if (p->curqincnt >= p->qfullcount)
{
- u_char out_scbi;
- struct aic7xxx_scb *out_scbp;
-
- scbq_remove_head(&(p->waiting_scbs));
-
- /*
- * Find the in-core SCB for the one we're paging out.
- */
- out_scbi = inb(SCB_TAG + base);
- out_scbp = (p->scb_array[out_scbi]);
-
- /* Do the page out and mark the paged in SCB as active. */
- aic7xxx_page_scb(p, out_scbp, scb);
-
- /* Mark this as an active command. */
- scb->state = (scb->state & ~SCB_WAITINGQ) | SCB_ACTIVE;
-
- /* Queue the command */
- outb(scb->position, QINFIFO + base);
- count++;
-
- /* Advance to the next disconnected SCB */
- disc_scb = next_scb;
- scb = p->waiting_scbs.head;
+ break;
}
- else
- scb = NULL;
}
- if (count)
+ /*
+ * We have some space.
+ */
+ scbq_remove_head(&(p->waiting_scbs));
+ scb->flags &= ~SCB_WAITINGQ;
+
+ outb(scb->hscb->tag, p->base + QINFIFO);
+
+ if ((p->flags & PAGE_ENABLED) != 0)
{
- /*
- * Update the head of the disconnected list.
+ /*
+ * We only care about this statistic when paging
+ * since it's impossible to overflow the qinfifo
+ * in the non-paging case.
*/
- outb(disc_scb, DISCONNECTED_SCBH + base);
- if (disc_scb != SCB_LIST_NULL)
- {
- outb(disc_scb, SCBPTR + base);
- outb(SCB_LIST_NULL, SCB_PREV + base);
- }
+ p->curqincnt++;
}
+ scb = p->waiting_scbs.head;
}
- /* Restore old position */
- outb(cur_scb, SCBPTR + base);
- /*
- * Guard against unpausing the sequencer if there is an interrupt
- * waiting to happen.
- */
- if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
- {
- UNPAUSE_SEQUENCER(p);
- }
+ unpause_sequencer(p, FALSE);
+}
- restore_flags(flags);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_construct_sdtr
+ *
+ * Description:
+ * Constucts a synchronous data transfer message in the message
+ * buffer on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_sdtr(struct aic7xxx_host *p, int start_byte,
+ unsigned char period, unsigned char offset)
+{
+ outb(MSG_EXTENDED, p->base + MSG_OUT + start_byte);
+ outb(MSG_EXT_SDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
+ outb(MSG_EXT_SDTR, p->base + MSG_OUT + 2 + start_byte);
+ outb(period, p->base + MSG_OUT + 3 + start_byte);
+ outb(offset, p->base + MSG_OUT + 4 + start_byte);
+ outb(start_byte + 5, p->base + MSG_LEN);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_isr
+ * aic7xxx_construct_wdtr
*
* Description:
- * SCSI controller interrupt handler.
+ * Constucts a wide data transfer message in the message buffer
+ * on the sequencer.
+ *-F*************************************************************************/
+static void
+aic7xxx_construct_wdtr(struct aic7xxx_host *p, int start_byte,
+ unsigned char bus_width)
+{
+ outb(MSG_EXTENDED, p->base + MSG_OUT + start_byte);
+ outb(MSG_EXT_WDTR_LEN, p->base + MSG_OUT + 1 + start_byte);
+ outb(MSG_EXT_WDTR, p->base + MSG_OUT + 2 + start_byte);
+ outb(bus_width, p->base + MSG_OUT + 3 + start_byte);
+ outb(start_byte + 4, p->base + MSG_LEN);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_calc_residual
*
- * NOTE: Since we declared this using SA_INTERRUPT, interrupts should
- * be disabled all through this function unless we say otherwise.
+ * Description:
+ * Calculate the residual data not yet transferred.
*-F*************************************************************************/
static void
-aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+aic7xxx_calculate_residual (struct aic7xxx_host *p, struct aic7xxx_scb *scb)
{
- int base, intstat, actual, scb_index, run_aborted_queue = FALSE;
- struct aic7xxx_host *p;
- struct aic7xxx_scb *scb = NULL;
- short transfer;
- unsigned char ha_flags, scsi_id, bus_width;
- unsigned char offset, rate, scratch, scratch_offset;
- unsigned char max_offset, rej_byte;
- unsigned short target_mask;
- char channel;
- unsigned int addr; /* must be 32 bits */
+ struct aic7xxx_hwscb *hscb;
Scsi_Cmnd *cmd;
+ int actual;
- p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+ cmd = scb->cmd;
+ hscb = scb->hscb;
/*
- * Search for the host with a pending interrupt. If we can't find
- * one, then we've encountered a spurious interrupt.
+ * Don't destroy valid residual information with
+ * residual coming from a check sense operation.
*/
- while ((p != NULL) && !(inb(INTSTAT + p->base) & INT_PEND))
+ if (((scb->hscb->control & DISCONNECTED) == 0) &&
+ (scb->flags & SCB_SENSE) == 0)
{
- if (p->next == NULL)
- {
- p = NULL;
- }
- else
+ /*
+ * We had an underflow. At this time, there's only
+ * one other driver that bothers to check for this,
+ * and cmd->underflow seems to be set rather half-
+ * heartedly in the higher-level SCSI code.
+ */
+ actual = aic7xxx_length(cmd, hscb->residual_SG_segment_count);
+
+ actual -= (hscb->residual_data_count[2] << 16) |
+ (hscb->residual_data_count[1] << 8) |
+ hscb->residual_data_count[0];
+
+ if (actual < cmd->underflow)
{
- p = (struct aic7xxx_host *) p->next->hostdata;
+ printk(KERN_WARNING "(scsi%d:%d:%d) Underflow - "
+ "Wanted at least %u, got %u, residual SG count %d.\n",
+ p->host_no, TC_OF_SCB(scb), cmd->underflow, actual,
+ hscb->residual_SG_segment_count);
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ aic7xxx_status(cmd) = hscb->target_status;
}
}
- if (p == NULL)
- return;
-
/*
- * Keep track of interrupts for /proc/scsi
+ * Clean out the residual information in the SCB for the
+ * next consumer.
*/
- p->isr_count++;
+ hscb->residual_data_count[2] = 0;
+ hscb->residual_data_count[1] = 0;
+ hscb->residual_data_count[0] = 0;
+ hscb->residual_SG_segment_count = 0;
+}
- if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_device_reset
+ *
+ * Description:
+ * Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_device_reset(struct aic7xxx_host *p, int target, char channel)
+{
+ unsigned short targ_mask;
+ unsigned char targ_scratch;
+ int scratch_offset = target;
+ int found;
+
+ if (channel == 'B')
{
- /*
- * We must only have one card at this IRQ and it must have been
- * added to the board data before the spurious interrupt occurred.
- * It is sufficient that we check isr_count and not the spurious
- * interrupt count.
- */
- printk("aic7xxx: (aic7xxx_isr) Encountered spurious interrupt.\n");
- return;
+ scratch_offset += 8;
}
-
- base = p->base;
+ targ_mask = (0x01 << scratch_offset);
/*
- * Handle all the interrupt sources - especially for SCSI
- * interrupts, we won't get a second chance at them.
+ * Go back to async/narrow transfers and renegotiate.
*/
- intstat = inb(INTSTAT + base);
+ p->needsdtr |= p->needsdtr_copy & targ_mask;
+ p->needwdtr |= p->needwdtr_copy & targ_mask;
+ p->sdtr_pending &= ~targ_mask;
+ p->wdtr_pending &= ~targ_mask;
+ targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+ targ_scratch &= SXFR;
+ outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+ found = aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
+ printk(KERN_WARNING "(scsi%d:%d:%d) Bus Device Reset delivered, "
+ "%d SCBs aborted.\n", p->host_no, target, CHAN_TO_INT(channel), found);
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+}
- /*
- * Indicate that we're in the interrupt handler.
- */
- p->flags |= IN_ISR;
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_seqint
+ *
+ * Description:
+ * Interrupt handler for sequencer interrupts (SEQINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_seqint(struct aic7xxx_host *p, unsigned char intstat)
+{
+ struct aic7xxx_scb *scb;
+ unsigned short target_mask;
+ unsigned char target, scratch_offset;
+ char channel;
- if (intstat & BRKADRINT)
+ if ((inb(p->base + SEQ_FLAGS) & RESELECTED) != 0)
{
- int i;
- unsigned char errno = inb(ERROR + base);
-
- printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
- for (i = 0; i < NUMBER(hard_error); i++)
- {
- if (errno & hard_error[i].errno)
- {
- printk(KERN_ERR " %s\n", hard_error[i].errmesg);
- }
- }
- panic("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
- inb(ERROR + base), (inb(SEQADDR1 + base) << 8) | inb(SEQADDR0 + base));
+ target = (inb(p->base + SELID) >> 4) & 0x0F;
}
+ else
+ {
+ target = (inb(p->base + SCSIID) >> 4) & 0x0F;
+ }
+ scratch_offset = target;
+ channel = 'A';
+ if (inb(p->base + SBLKCTL) & SELBUSB)
+ {
+ channel = 'B';
+ scratch_offset += 8;
+ }
+ target_mask = (0x01 << scratch_offset);
- if (intstat & SEQINT)
+ switch (intstat & SEQINT_MASK)
{
- /*
- * Although the sequencer is paused immediately on
- * a SEQINT, an interrupt for a SCSIINT condition will
- * unpaused the sequencer before this point.
- */
- PAUSE_SEQUENCER(p);
+ case NO_MATCH:
+ {
+ /*
+ * This could be for a normal abort request. Figure out
+ * which SCB we were trying to find and only give an error
+ * if we didn't ask for this to happen.
+ */
+ unsigned char scb_index;
+ unsigned char busy_scbid;
+ unsigned char arg1;
- scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
- scratch_offset = scsi_id;
- channel = 'A';
- if (inb(SBLKCTL + base) & SELBUSB)
- {
- channel = 'B';
- scratch_offset += 8;
- }
- target_mask = (0x01 << scratch_offset);
+ busy_scbid = aic7xxx_index_busy_target(p, target, channel,
+ /*unbusy*/ FALSE);
+ arg1 = inb(p->base + ARG_1);
- switch (intstat & SEQINT_MASK)
- {
- case NO_MATCH:
- if (p->flags & PAGE_ENABLED)
+ if (arg1 == SCB_LIST_NULL)
{
- /* SCB Page-in request */
- struct aic7xxx_scb *outscb;
- u_char arg_1 = inb(ARG_1 + base);
- int use_disconnected = FALSE;
-
- /*
- * The sequencer expects this value upon return. Assume
- * we will find the paged out SCB and set the value now.
- * If we don't, and one of the methods used to acquire an
- * SCB calls aic7xxx_done(), we will end up in our queue
- * routine and unpause the sequencer without giving it the
- * correct return value, which causes a hang.
- */
- outb(SCB_PAGEDIN, RETURN_1 + base);
- if (arg_1 == SCB_LIST_NULL)
- {
- /* Non-tagged command */
- int index = scsi_id;
- if (channel == 'B')
- {
- index |= SELBUSB;
- }
- scb = p->pagedout_ntscbs[index];
- }
- else
- scb = (p->scb_array[arg_1]);
+ /* untagged request */
+ scb_index = busy_scbid;
+ }
+ else
+ {
+ scb_index = arg1;
+ }
- if (!(scb->state & SCB_PAGED_OUT))
+ if (scb_index < p->scb_data->numscbs)
+ {
+ scb = p->scb_data->scb_array[scb_index];
+ if (scb->hscb->control & ABORT_SCB)
{
- printk(KERN_WARNING "scsi%d: No active paged-out SCB for reconnecting "
- "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- aic7xxx_unbusy_target(scsi_id, channel, base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(0, RETURN_1 + base);
+ /*
+ * We expected this. Let the busfree handler take care
+ * of this when we the abort is finially sent. Set
+ * IDENTIFY_SEEN so that the busfree handler knows that
+ * there is an SCB to cleanup.
+ */
+ outb(inb(p->base + SEQ_FLAGS) | IDENTIFY_SEEN, p->base + SEQ_FLAGS);
+ printk(KERN_INFO "(scsi%d:%d:%d) reconnect SCB abort successful\n",
+ p->host_no, TC_OF_SCB(scb));
break;
}
+ }
+ printk(KERN_WARNING "(scsi%d:%d:%d) No active SCB for reconnecting "
+ "target - Issuing BUS DEVICE RESET.\n",
+ p->host_no, target, CHAN_TO_INT(channel));
+
+ printk(KERN_WARNING " SAVED_TCL=0x%x, ARG_1=0x%x, SEQADDR=0x%x\n",
+ inb(p->base + SAVED_TCL), arg1,
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ aic7xxx_handle_device_reset(p, target, channel);
+ }
+ break;
- /*
- * Now to pick the SCB to page out. Either take a free SCB, an
- * assigned SCB, an SCB that just completed, or the first one
- * on the disconnected SCB list.
- */
- if (p->scb_link->free_scbs.head != NULL)
- {
- outscb = p->scb_link->free_scbs.head;
- scbq_remove_head(&p->scb_link->free_scbs);
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->page_scbs, outscb);
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
- }
- else if (p->assigned_scbs.head != NULL)
- {
- outscb = p->assigned_scbs.head;
- scbq_remove_head(&p->assigned_scbs);
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->waiting_scbs, outscb);
- outscb->state = (outscb->state & ~SCB_ASSIGNEDQ) | SCB_WAITINGQ;
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
- }
- else if (intstat & CMDCMPLT)
- {
- int scb_index;
+ case NO_MATCH_BUSY:
+ {
+ /*
+ * XXX - Leave this as a panic for the time being since it
+ * indicates a bug in the timeout code for this to happen.
+ */
+ unsigned char scb_index;
- outb(CLRCMDINT, CLRINT + base);
- scb_index = inb(QOUTFIFO + base);
- if (!(inb(QOUTCNT + base) & p->qcntmask))
- {
- intstat &= ~CMDCMPLT;
- }
- outscb = (p->scb_array[scb_index]);
- if (!(outscb->state & SCB_ACTIVE))
+ scb_index = inb(p->base + CUR_SCBID);
+ scb = p->scb_data->scb_array[scb_index];
+
+ panic("scsi%d: Target %d, channel %c, Target busy link failure, "
+ "but busy SCB exists!\n",
+ p->host_no, target, channel);
+ }
+ break;
+
+ case SEND_REJECT:
+ {
+ unsigned char rej_byte;
+
+ rej_byte = inb(p->base + REJBYTE);
+ printk(KERN_WARNING "(scsi%d:%d:%d) Rejecting unknown message (0x%x) "
+ "received from target, SEQ_FLAGS=0x%x\n",
+ p->host_no, target, CHAN_TO_INT(channel), rej_byte,
+ inb(p->base + SEQ_FLAGS));
+ }
+ break;
+
+ case NO_IDENT:
+ {
+ /*
+ * The reconnecting target either did not send an identify
+ * message, or did, but we didn't find and SCB to match and
+ * before it could respond to our ATN/abort, it hit a dataphase.
+ * The only safe thing to do is to blow it away with a bus
+ * reset.
+ */
+ int found;
+
+ printk(KERN_WARNING "(scsi%d:%d:%d): Target did not send an IDENTIFY "
+ "message; LASTPHASE 0x%x, SAVED_TCL 0x%x\n",
+ p->host_no, target, CHAN_TO_INT(channel),
+ inb(p->base + LASTPHASE), inb(p->base + SAVED_TCL));
+
+ found = aic7xxx_reset_channel(p, channel, /*initiate reset*/ TRUE);
+
+ printk(KERN_WARNING "scsi%d: Issued channel %c bus reset; "
+ "%d SCBs aborted\n", p->host_no, channel, found);
+ }
+ break;
+
+ case BAD_PHASE:
+ if (inb(p->base + LASTPHASE) == P_BUSFREE)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d): Missed busfree.\n",
+ p->host_no, CHAN_TO_INT(channel), target);
+ restart_sequencer(p);
+ }
+ else
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d): Unknown scsi bus phase, attempting "
+ "to continue\n", p->host_no, CHAN_TO_INT(channel), target);
+ }
+ break;
+
+ case EXTENDED_MSG:
+ {
+ unsigned char message_length;
+ unsigned char message_code;
+ unsigned char scb_index;
+
+ message_length = inb(p->base + MSGIN_EXT_LEN);
+ message_code = inb(p->base + MSGIN_EXT_OPCODE);
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+
+ switch (message_code)
+ {
+ case MSG_EXT_SDTR:
+ {
+ unsigned char period;
+ unsigned char offset;
+ unsigned char saved_offset;
+ unsigned char targ_scratch;
+ unsigned char max_offset;
+ unsigned char rate;
+
+ if (message_length != MSG_EXT_SDTR_LEN)
{
- printk(KERN_WARNING "scsi%d: No command for completed SCB %d "
- "during NO_MATCH interrupt\n", scb_index, p->host_no);
- use_disconnected = TRUE;
+ outb(SEND_REJ, p->base + RETURN_1);
+ break;
}
+
+ period = inb(p->base + MSGIN_EXT_BYTES);
+ saved_offset = inb(p->base + MSGIN_EXT_BYTES + 1);
+ targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+
+ if (targ_scratch & WIDEXFER)
+ max_offset = MAX_OFFSET_16BIT;
else
+ max_offset = MAX_OFFSET_8BIT;
+ offset = MIN(saved_offset, max_offset);
+
+ aic7xxx_scsirate(p, &rate, &period, &offset, target, channel);
+
+ /*
+ * Preserve the WideXfer flag.
+ */
+ targ_scratch = rate | (targ_scratch & WIDEXFER);
+
+ /*
+ * Update both the target scratch area and current SCSIRATE.
+ */
+ outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+ outb(targ_scratch, p->base + SCSIRATE);
+
+ /*
+ * See if we initiated Sync Negotiation and didn't have
+ * have to fall down to async transfers.
+ */
+ if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
{
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- outb(scb->position, SCBPTR + base);
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
- outscb->cmd->result |= (aic7xxx_error(outscb->cmd) << 16);
- if ((outscb->cmd->flags & WAS_SENSE) &&
- !(outscb->cmd->flags & ASKED_FOR_SENSE))
+ /* We started it. */
+ if (saved_offset == offset)
{
- /*
- * Got sense information.
- */
- outscb->cmd->flags &= ASKED_FOR_SENSE;
+ /*
+ * Don't send an SDTR back to the target.
+ */
+ outb(0, p->base + RETURN_1);
+ }
+ else
+ {
+ /* We went too low - force async. */
+ outb(SEND_REJ, p->base + RETURN_1);
}
- p->device_status[TARGET_INDEX(outscb->cmd)].flags
- |= DEVICE_SUCCESS;
- aic7xxx_done(p, outscb);
}
+ else
+ {
+ /*
+ * Send our own SDTR in reply.
+ *
+ * We want to see this message as we don't expect a target
+ * to send us a SDTR request first.
+ */
+ printk(KERN_WARNING "scsi%d: Sending SDTR!!\n", p->host_no);
+ aic7xxx_construct_sdtr(p, /* start byte */ 0, period, offset);
+ outb(SEND_MSG, p->base + RETURN_1);
+ }
+ /*
+ * Clear the flags.
+ */
+ p->needsdtr &= ~target_mask;
+ break;
}
- else
- {
- use_disconnected = TRUE;
- }
- if (use_disconnected)
+
+ case MSG_EXT_WDTR:
{
- u_char tag;
- u_char next;
- u_char disc_scb = inb(DISCONNECTED_SCBH + base);
- if (disc_scb != SCB_LIST_NULL)
+ unsigned char scratch, bus_width;
+
+ if (message_length != MSG_EXT_WDTR_LEN)
{
- outb(disc_scb, SCBPTR + base);
- tag = inb(SCB_TAG + base);
- outscb = (p->scb_array[tag]);
- next = inb(SCB_NEXT + base);
- if (next != SCB_LIST_NULL)
- {
- outb(next, SCBPTR + base);
- outb(SCB_LIST_NULL, SCB_PREV + base);
- outb(disc_scb, SCBPTR + base);
- }
- outb(next, DISCONNECTED_SCBH + base);
- aic7xxx_page_scb(p, outscb, scb);
- }
- else if (inb(QINCNT + base) & p->qcntmask)
+ outb(SEND_REJ, p->base + RETURN_1);
+ break;
+ }
+
+ bus_width = inb(p->base + MSGIN_EXT_BYTES);
+ scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+
+ if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
{
- /* Pull one of our queued commands as a last resort. */
- disc_scb = inb(QINFIFO + base);
- outb(disc_scb, SCBPTR + base);
- tag = inb(SCB_TAG + base);
- outscb = (p->scb_array[tag]);
- if ((outscb->control & 0x23) != TAG_ENB)
+ /*
+ * Don't send an WDTR back to the target, since we asked first.
+ */
+ outb(0, p->base + RETURN_1);
+ switch (bus_width)
{
- /*
- * This is not a simple tagged command so its position
- * in the queue matters. Take the command at the end of
- * the queue instead.
- */
- int i;
- int saved_queue[AIC7XXX_MAXSCB];
- int queued = inb(QINCNT + base) & p->qcntmask;
-
- /* Count the command we removed already */
- saved_queue[0] = disc_scb;
- queued++;
-
- /* Empty the input queue. */
- for (i = 1; i < queued; i++)
- {
- saved_queue[i] = inb(QINFIFO + base);
- }
-
- /* Put everyone back but the last entry. */
- queued--;
- for (i = 0; i < queued; i++)
- {
- outb(saved_queue[i], QINFIFO + base);
- }
-
- outb(saved_queue[queued], SCBPTR + base);
- tag = inb(SCB_TAG + base);
- outscb = (p->scb_array[tag]);
+ case BUS_8_BIT:
+ scratch &= 0x7F;
+ break;
+
+ case BUS_16_BIT:
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
+ "bit transfers.\n", p->host_no, target, channel);
+ }
+ scratch |= WIDEXFER;
+ break;
+
+ case BUS_32_BIT:
+ outb(SEND_REJ, p->base + RETURN_1);
+ /* No verbose here! We want to see this condition. */
+ printk(KERN_WARNING "scsi%d: Target %d, channel %c, "
+ "requesting 32 bit transfers, rejecting...\n",
+ p->host_no, target, channel);
+ break;
+
+ default:
+ break;
}
- scb->position = outscb->position;
- outscb->position = SCB_LIST_NULL;
- scbq_insert_head(&p->waiting_scbs, outscb);
- outscb->state |= SCB_WAITINGQ;
- aic7xxx_putscb(p, scb);
- scb->state &= ~SCB_PAGED_OUT;
}
else
{
- printk(KERN_WARNING "scsi%d: Page-in request with no candidates "
- "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- aic7xxx_unbusy_target(scsi_id, channel, base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(0, RETURN_1 + base);
+ /*
+ * Send our own WDTR in reply.
+ */
+ switch (bus_width)
+ {
+ case BUS_8_BIT:
+ scratch &= 0x7F;
+ break;
+
+ case BUS_32_BIT:
+ case BUS_16_BIT:
+ if (p->bus_type == AIC_WIDE)
+ {
+ printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 "
+ "bit transfers.\n", p->host_no, target, channel);
+ bus_width = BUS_16_BIT;
+ scratch |= WIDEXFER;
+ }
+ else
+ {
+ bus_width = BUS_8_BIT;
+ scratch &= 0x7F; /* XXX - FreeBSD doesn't do this. */
+ }
+ break;
+
+ default:
+ break;
+ }
+ aic7xxx_construct_wdtr(p, /* start byte */ 0, bus_width);
+ outb(SEND_MSG, p->base + RETURN_1);
}
- }
- }
- else
- {
- printk(KERN_WARNING "scsi%d: No active SCB for reconnecting "
- "target %d, channel %c - Issuing ABORT. SAVED_TCL(0x%x).\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- aic7xxx_unbusy_target(scsi_id, channel, base);
- outb(0, SCB_CONTROL + base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(0, RETURN_1 + base);
- }
- break;
-
- case BAD_PHASE:
- panic("scsi%d: Unknown scsi bus phase.\n", p->host_no);
- break;
-
- case SEND_REJECT:
- rej_byte = inb(REJBYTE + base);
- if ((rej_byte & 0xF0) == 0x20)
- {
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- printk(KERN_WARNING "scsi%d: Tagged message received without identify."
- "Disabling tagged commands for target %d channel %c.\n",
- p->host_no, scsi_id, channel);
- scb->cmd->device->tagged_supported = 0;
- scb->cmd->device->tagged_queue = 0;
- }
- else
- {
- printk(KERN_WARNING "scsi%d: Rejecting unknown message (0x%x) received "
- "from target %d channel %c.\n",
- p->host_no, rej_byte, scsi_id, channel);
- }
- break;
+ p->needwdtr &= ~target_mask;
+ outb(scratch, p->base + TARG_SCRATCH + scratch_offset);
+ outb(scratch, p->base + SCSIRATE);
+ break;
+ } /* case MSG_EXT_WDTR */
- case NO_IDENT:
- panic("scsi%d: Target %d, channel %c, did not send an IDENTIFY "
- "message. SAVED_TCL 0x%x.\n",
- p->host_no, scsi_id, channel, inb(SAVED_TCL + base));
- break;
+ default:
+ /*
+ * Unknown extended message - reject it.
+ */
+ outb(SEND_REJ, p->base + RETURN_1);
+ break;
+ } /* switch (message_code) */
+ } /* case EXTENDED_MSG */
+ break;
- case SDTR_MSG:
- /*
- * Help the sequencer to translate the negotiated
- * transfer rate. Transfer is 1/4 the period
- * in ns as is returned by the sync negotiation
- * message. So, we must multiply by four.
- */
- transfer = (inb(ARG_1 + base) << 2);
- offset = inb(ACCUM + base);
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
+ case REJECT_MSG:
+ {
/*
- * The maximum offset for a wide device is 0x08; for a
- * 8-bit bus device the maximum offset is 0x0F.
+ * What we care about here is if we had an outstanding SDTR
+ * or WDTR message for this target. If we did, this is a
+ * signal that the target is refusing negotiation.
*/
- if (scratch & WIDEXFER)
+ unsigned char targ_scratch;
+ unsigned char scb_index;
+
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+ targ_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+
+ if ((scb->flags & SCB_MSGOUT_WDTR) != 0)
{
- max_offset = 0x08;
+ /*
+ * note 8bit xfers and clear flag
+ */
+ targ_scratch &= 0x7F;
+ p->needwdtr &= ~target_mask;
+ printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
+ "negotiation; using 8 bit transfers.\n",
+ p->host_no, target, channel);
}
else
{
- max_offset = 0x0F;
- }
- aic7xxx_scsirate(p, &rate, transfer, MIN(offset, max_offset),
- scsi_id, channel);
- /*
- * Preserve the wide transfer flag.
- */
- scratch = rate | (scratch & WIDEXFER);
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- outb(scratch, SCSIRATE + base);
- if ((scratch & 0x0F) == 0)
- {
- /*
- * One of two things happened. Either the device requested
- * asynchronous data transfers, or it requested a synchronous
- * data transfer rate that was so low that asynchronous
- * transfers are faster (not to mention the controller won't
- * support them). In both cases the synchronous data transfer
- * rate and the offset are set to 0 indicating asynchronous
- * transfers.
- *
- * If the device requested an asynchronous transfer, then
- * accept the request. If the device is being forced to
- * asynchronous data transfers and this is the first time
- * we've seen the request, accept the request. If we've
- * already seen the request, then attempt to force
- * asynchronous data transfers by rejecting the message.
- */
- if ((offset == 0) || (p->sdtr_pending & target_mask))
+ if ((scb->flags & SCB_MSGOUT_SDTR) != 0)
{
/*
- * Device requested asynchronous transfers or we're
- * forcing asynchronous transfers for the first time.
+ * note asynch xfers and clear flag
*/
- outb(0, RETURN_1 + base);
+ targ_scratch &= 0xF0;
+ p->needsdtr &= ~target_mask;
+ printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
+ "synchronous negotiation; using asynchronous transfers.\n",
+ p->host_no, target, channel);
}
- else
- {
- /*
- * The first time in forcing asynchronous transfers
- * failed, so we try sending a reject message.
- */
- outb(SEND_REJ, RETURN_1 + base);
- }
- }
- else
- {
- /*
- * See if we initiated Sync Negotiation
- */
- if (p->sdtr_pending & target_mask)
- {
- /*
- * Don't send an SDTR back to the target.
- */
- outb(0, RETURN_1 + base);
- }
- else
- {
- /*
- * Send our own SDTR in reply.
- */
- printk("aic7xxx: Sending SDTR!!\n");
- outb(SEND_SDTR, RETURN_1 + base);
- }
- }
- /*
- * Clear the flags.
- */
- p->needsdtr &= ~target_mask;
- p->sdtr_pending &= ~target_mask;
- break;
-
- case WDTR_MSG:
- {
- bus_width = inb(ARG_1 + base);
- printk(KERN_INFO "scsi%d: Received MSG_WDTR, Target %d, channel %c "
- "needwdtr(0x%x).\n", p->host_no, scsi_id, channel, p->needwdtr);
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
-
- if (p->wdtr_pending & target_mask)
- {
- /*
- * Don't send an WDTR back to the target, since we asked first.
- */
- outb(0, RETURN_1 + base);
- switch (bus_width)
- {
- case BUS_8_BIT:
- scratch &= 0x7F;
- break;
-
- case BUS_16_BIT:
- printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
- "transfers.\n", p->host_no, scsi_id, channel);
- scratch |= 0x80;
- break;
-
- case BUS_32_BIT:
- outb(SEND_REJ, RETURN_1 + base);
- printk(KERN_INFO "scsi%d: Target %d, channel %c, requesting 32 bit "
- "transfers, rejecting...\n", p->host_no, scsi_id, channel);
- break;
- }
- }
- else
- {
- /*
- * Send our own WDTR in reply.
- */
- printk(KERN_INFO "scsi%d: Will send WDTR!!\n", p->host_no);
- switch (bus_width)
- {
- case BUS_8_BIT:
- scratch &= 0x7F;
- break;
-
- case BUS_32_BIT:
- /*
- * Negotiate 16 bits.
- */
- bus_width = BUS_16_BIT;
- /* Yes, we mean to fall thru here. */
-
- case BUS_16_BIT:
- printk(KERN_INFO "scsi%d: Target %d, channel %c, using 16 bit "
- "transfers.\n", p->host_no, scsi_id, channel);
- scratch |= 0x80;
- break;
- }
- outb(bus_width | SEND_WDTR, RETURN_1 + base);
+ /*
+ * Otherwise, we ignore it.
+ */
}
- p->needwdtr &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- outb(scratch, SCSIRATE + base);
- break;
+ outb(targ_scratch, p->base + TARG_SCRATCH + scratch_offset);
+ outb(targ_scratch, p->base + SCSIRATE);
}
+ break;
- case REJECT_MSG:
+ case BAD_STATUS:
{
- /*
- * What we care about here is if we had an
- * outstanding SDTR or WDTR message for this
- * target. If we did, this is a signal that
- * the target is refusing negotiation.
+ unsigned char scb_index;
+ struct aic7xxx_hwscb *hscb;
+ Scsi_Cmnd *cmd;
+
+ /* The sequencer will notify us when a command has an error that
+ * would be of interest to the kernel. This allows us to leave
+ * the sequencer running in the common case of command completes
+ * without error. The sequencer will have DMA'd the SCB back
+ * up to us, so we can reference the drivers SCB array.
*/
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
+ hscb = scb->hscb;
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
-
- if (p->wdtr_pending & target_mask)
- {
- /*
- * note 8bit xfers and clear flag
- */
- scratch &= 0x7F;
- p->needwdtr &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
- printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing WIDE "
- "negotiation; using 8 bit transfers.\n",
- p->host_no, scsi_id, channel);
- }
- else
- {
- if (p->sdtr_pending & target_mask)
- {
- /*
- * note asynch xfers and clear flag
- */
- scratch &= 0xF0;
- p->needsdtr &= ~target_mask;
- p->sdtr_pending &= ~target_mask;
- printk(KERN_WARNING "scsi%d: Target %d, channel %c, refusing "
- "synchronous negotiation; using asynchronous transfers.\n",
- p->host_no, scsi_id, channel);
- }
- /*
- * Otherwise, we ignore it.
- */
- }
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- outb(scratch, SCSIRATE + base);
- break;
- }
-
- case BAD_STATUS:
- /* The sequencer will notify us when a command has an error that
- * would be of interest to the kernel. This allows us to leave
- * the sequencerrunning in the common case of command completes
- * without error.
- */
-
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- outb(0, RETURN_1 + base); /* CHECK_CONDITION may change this */
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+ /*
+ * Set the default return value to 0 indicating not to send
+ * sense. The sense code will change this if needed and this
+ * reduces code duplication.
+ */
+ outb(0, p->base + RETURN_1);
+ if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
{
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
+ printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
+ "SEQINT 0x%x, scb %d, flags 0x%x, cmd 0x%x.\n", p->host_no,
+ intstat, scb_index, scb->flags, (unsigned int) scb->cmd);
}
else
{
- cmd = scb->cmd;
- scb->target_status = inb(SCB_TARGET_STATUS + base);
- aic7xxx_status(cmd) = scb->target_status;
+ cmd = scb->cmd;
+ hscb->target_status = inb(p->base + SCB_TARGET_STATUS);
+ aic7xxx_status(cmd) = hscb->target_status;
- cmd->result |= scb->target_status;
+ cmd->result |= hscb->target_status;
- switch (status_byte(scb->target_status))
- {
- case GOOD:
- printk(KERN_WARNING "aic7xxx: Interrupted for status of GOOD???\n");
- break;
-
- case CHECK_CONDITION:
- if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE))
- {
- unsigned char tcl;
- unsigned int req_buf; /* must be 32 bits */
+ switch (status_byte(hscb->target_status))
+ {
+ case GOOD:
+ printk(KERN_WARNING "(scsi%d:%d:%d) Interrupted for status of "
+ "GOOD???\n", p->host_no, TC_OF_SCB(scb));
+ break;
- tcl = scb->target_channel_lun;
+ case CHECK_CONDITION:
+ if ((aic7xxx_error(cmd) == 0) && !(scb->flags & SCB_SENSE))
+ {
+ unsigned int addr; /* must be 32 bits */
+ /*
+ * XXX - How do we save the residual (if there is one).
+ */
+ aic7xxx_calculate_residual(p, scb);
+
+ /*
+ * Send a sense command to the requesting target.
+ * XXX - revisit this and get rid of the memcopys.
+ */
+ memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+ sizeof(generic_sense));
+
+ scb->sense_cmd[1] = (cmd->lun << 5);
+ scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
+
+ scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
+ scb->sg_list[0].length = sizeof(cmd->sense_buffer);
+ cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
- /*
- * Send a sense command to the requesting target.
+ /*
+ * XXX - We should allow disconnection, but can't as it
+ * might allow overlapped tagged commands.
*/
- cmd->flags |= WAS_SENSE;
- memcpy((void *) scb->sense_cmd, (void *) generic_sense,
- sizeof(generic_sense));
-
- scb->sense_cmd[1] = (cmd->lun << 5);
- scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-
- scb->sg_list[0].address = VIRT_TO_BUS(&cmd->sense_buffer);
- scb->sg_list[0].length = sizeof(cmd->sense_buffer);
- req_buf = VIRT_TO_BUS(&scb->sg_list[0]);
- cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
-
- scb->control = scb->control & DISCENB;
- scb->target_channel_lun = tcl;
- addr = VIRT_TO_BUS(scb->sense_cmd);
- scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
- memcpy(scb->SCSI_cmd_pointer, &addr,
- sizeof(scb->SCSI_cmd_pointer));
- scb->SG_segment_count = 1;
- memcpy(scb->SG_list_pointer, &req_buf,
- sizeof(scb->SG_list_pointer));
- scb->data_count = scb->sg_list[0].length;
- memcpy(scb->data_pointer, &(scb->sg_list[0].address),
- sizeof(scb->data_pointer));
-
- aic7xxx_putscb(p, scb);
+ /* hscb->control &= DISCENB; */
+ hscb->control = 0;
+ hscb->target_status = 0;
+ hscb->SG_segment_count = 1;
+
+ addr = VIRT_TO_BUS(&scb->sg_list[0]);
+ memcpy(&hscb->SG_list_pointer, &addr,
+ sizeof(hscb->SG_list_pointer));
+
+ memcpy(&hscb->data_pointer, &(scb->sg_list[0].address),
+ sizeof(hscb->data_pointer));
+ /* Maintain SCB_LINKED_NEXT */
+ hscb->data_count &= 0xFF000000;
+ hscb->data_count |= scb->sg_list[0].length;
+
+ addr = VIRT_TO_BUS(scb->sense_cmd);
+ memcpy(&hscb->SCSI_cmd_pointer, &addr,
+ sizeof(hscb->SCSI_cmd_pointer));
+ hscb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+
+ scb->sg_count = hscb->SG_segment_count;
+ scb->flags |= SCB_SENSE;
/*
- * Ensure that the target is "BUSY" so we don't get overlapping
- * commands if we happen to be doing tagged I/O.
+ * Ensure the target is busy since this will be an
+ * an untagged request.
*/
- aic7xxx_busy_target(scsi_id, channel, base);
+ aic7xxx_busy_target(p, target, channel, hscb->tag);
+ outb(SEND_SENSE, p->base + RETURN_1);
+ } /* first time sense, no errors */
+ else
+ {
+ if (aic7xxx_error(cmd) == 0)
+ {
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ }
+ }
+ break;
- aic7xxx_add_waiting_scb(base, scb);
- outb(SEND_SENSE, RETURN_1 + base);
- } /* first time sense, no errors */
- else
+ case QUEUE_FULL:
+#ifdef NOT_YET
+ if (scb->hscb->control & TAG_ENB)
{
- cmd->flags &= ~ASKED_FOR_SENSE;
- if (aic7xxx_error(cmd) == 0)
- {
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- }
+ if (cmd->device->queue_depth > 2)
+ {
+ cmd->device->queue_depth--; /* Not correct */
+ printk(KERN_WARNING "(scsi%d:%d:%d) Tagged queue depth "
+ "reduced to %d\n", p->host_no,
+ TC_OF_SCB(scb), cmd->device->queue_depth);
+ }
+ /*
+ * XXX - Requeue this unconditionally?
+ */
+
+ /*
+ * We'd like to be able to give the SCB some more time
+ * (untimeout, then timeout).
+ */
+ break;
}
- break;
-
- case BUSY:
- printk(KERN_WARNING "scsi%d: Target busy, TCL=0x%x.\n",
- p->host_no, scb->target_channel_lun);
- if (!aic7xxx_error(cmd))
- {
- /* The error code here used to be DID_BUS_BUSY,
- * but after extensive testing, it has been determined
- * that a DID_BUS_BUSY return is a waste of time. If
- * the problem is something that will go away, then it
- * will, if it isn't, then you don't want the endless
- * looping that you get with a DID_BUS_BUSY. Better
- * to be on the safe side and specify an error condition
- * that will eventually lead to a reset or abort of some
- * sort instead of an endless loop.
- */
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- }
- break;
-
- case QUEUE_FULL:
- printk(KERN_WARNING "scsi%d: Queue full.\n", p->host_no);
- scb->state |= SCB_ASSIGNEDQ;
- scbq_insert_tail(&p->assigned_scbs, scb);
- break;
-
- default:
- printk(KERN_WARNING "scsi%d: Unexpected target status 0x%x.\n",
- p->host_no, scb->target_status);
- if (!aic7xxx_error(cmd))
- {
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- }
- break;
- } /* end switch */
+#endif
+ printk(KERN_WARNING "(scsi%d:%d:%d) Queue full received; "
+ "queue depth %d, active %d\n", p->host_no,
+ TC_OF_SCB(scb), cmd->device->queue_depth,
+ p->device_status[TARGET_INDEX(cmd)].active_cmds);
+
+ /* Else treat this as if it was a BUSY condition. */
+ scb->hscb->target_status = (BUSY << 1) |
+ (scb->hscb->target_status & 0x01);
+ /* Fall through to the BUSY case. */
+
+ case BUSY:
+ printk(KERN_WARNING "(scsi%d:%d:%d) Target busy\n",
+ p->host_no, TC_OF_SCB(scb));
+ if (!aic7xxx_error(cmd))
+ {
+ /*
+ * The mid-level SCSI code should be fixed to
+ * retry the command at a later time instead of
+ * trying right away.
+ */
+ aic7xxx_error(cmd) = DID_BUS_BUSY | (SUGGEST_RETRY << 8);
+ }
+ udelay(1000); /* A small pause (1ms) to help the drive */
+ break;
+
+ default:
+ printk(KERN_WARNING "(scsi%d:%d:%d) Unexpected target "
+ "status 0x%x.\n", p->host_no,
+ TC_OF_SCB(scb), scb->hscb->target_status);
+ if (!aic7xxx_error(cmd))
+ {
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ }
+ break;
+ } /* end switch */
} /* end else of */
- break;
+ }
+ break;
- case RESIDUAL:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
- }
- else
- {
- cmd = scb->cmd;
- /*
- * Don't destroy valid residual information with
- * residual coming from a check sense operation.
- */
- if (!(cmd->flags & WAS_SENSE))
- {
- /*
- * We had an underflow. At this time, there's only
- * one other driver that bothers to check for this,
- * and cmd->underflow seems to be set rather half-
- * heartedly in the higher-level SCSI code.
- */
- actual = aic7xxx_length(cmd, scb->residual_SG_segment_count);
-
- actual -= (inb(SCB_RESID_DCNT2 + base) << 16) |
- (inb(SCB_RESID_DCNT1 + base) << 8) |
- inb(SCB_RESID_DCNT0 + base);
-
- if (actual < cmd->underflow)
- {
- printk(KERN_WARNING "scsi%d: Target %d underflow - "
- "Wanted at least %u, got %u, residual SG count %d.\n",
- p->host_no, cmd->target, cmd->underflow, actual,
- inb(SCB_RESID_SGCNT + base));
- aic7xxx_error(cmd) = DID_RETRY_COMMAND;
- aic7xxx_status(cmd) = scb->target_status;
- }
- }
- }
- break;
+ case AWAITING_MSG:
+ {
+ unsigned char scb_index;
+ unsigned char message_offset;
- case ABORT_TAG:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
- }
- else
- {
- cmd = scb->cmd;
- /*
- * We didn't receive a valid tag back from the target
- * on a reconnect.
- */
- printk("scsi%d: Invalid tag received on target %d, channel %c, "
- "lun %d - Sending ABORT_TAG.\n", p->host_no,
- scsi_id, channel, cmd->lun & 0x07);
-
- cmd->result = (DID_RETRY_COMMAND << 16);
- aic7xxx_done(p, scb);
- }
- break;
+ scb_index = inb(p->base + SCB_TAG);
+ scb = p->scb_data->scb_array[scb_index];
- case AWAITING_MSG:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+ /*
+ * This SCB had a MK_MESSAGE set in its control byte informing
+ * the sequencer that we wanted to send a special message to
+ * this target.
+ */
+ message_offset = inb(p->base + MSG_LEN);
+ if (scb->flags & SCB_DEVICE_RESET)
{
- printk(KERN_WARNING "scsi%d: Referenced SCB not valid during "
- "SEQINT 0x%x, scb %d, state 0x%x, cmd 0x%lx.\n", p->host_no,
- intstat, scb_index, scb->state, (unsigned long) scb->cmd);
+ outb(MSG_BUS_DEV_RESET, p->base + MSG_OUT);
+ outb(1, p->base + MSG_LEN);
+ printk(KERN_INFO "(scsi%d:%d:%d) Bus device reset sent\n",
+ p->host_no, TC_OF_SCB(scb));
}
- else
+ else if (scb->flags & SCB_ABORT)
+ {
+ if ((scb->hscb->control & TAG_ENB) != 0)
+ {
+ outb(MSG_ABORT_TAG, p->base + MSG_OUT + message_offset);
+ }
+ else
+ {
+ outb(MSG_ABORT, p->base + MSG_OUT + message_offset);
+ }
+ outb(message_offset + 1, p->base + MSG_LEN);
+ printk(KERN_WARNING "(scsi%d:%d:%d): Abort message sent.\n",
+ p->host_no, TC_OF_SCB(scb));
+ }
+ else if (scb->flags & SCB_MSGOUT_WDTR)
{
- /*
- * This SCB had a zero length command, informing the sequencer
- * that we wanted to send a special message to this target.
- * We only do this for BUS_DEVICE_RESET messages currently.
- */
- if (scb->state & SCB_DEVICE_RESET)
- {
-#ifdef AIC7XXX_DEBUG_ABORT
- printk ("aic7xxx: (isr) sending bus device reset to target %d\n",
- scsi_id);
-#endif
- outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
- outb(1, MSG_LEN + base);
- }
- else
- {
- panic("scsi%d: AWAITING_SCB for an SCB that does "
- "not have a waiting message.\n", p->host_no);
- }
- }
- break;
-
- case IMMEDDONE:
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: received IMMEDDONE for target %d, scb %d, state %d\n",
- scsi_id, scb_index, scb->state);
-#endif
- if (scb->state & SCB_DEVICE_RESET)
+ aic7xxx_construct_wdtr(p, message_offset, BUS_16_BIT);
+ }
+ else if (scb->flags & SCB_MSGOUT_SDTR)
{
- int found;
+ unsigned char target_scratch;
+ unsigned short ultra_enable;
+ int i, sxfr;
/*
- * Go back to async/narrow transfers and renegotiate.
+ * Pull the user defined setting from scratch RAM.
*/
- aic7xxx_unbusy_target(scsi_id, channel, base);
- p->needsdtr |= (p->needsdtr_copy & target_mask);
- p->needwdtr |= (p->needwdtr_copy & target_mask);
- p->sdtr_pending &= ~target_mask;
- p->wdtr_pending &= ~target_mask;
- scratch = inb(TARG_SCRATCH + base + scratch_offset);
- scratch &= SXFR;
- outb(scratch, TARG_SCRATCH + base + scratch_offset);
- found = aic7xxx_reset_device(p, (int) scsi_id, channel);
- printk(KERN_INFO "scsi%d: Bus Device Reset delivered, %d SCBs "
- "aborted.\n", p->host_no, found);
- /* Indicate that we want to call aic7xxx_done_aborted_scbs() */
- run_aborted_queue = TRUE;
+ target_scratch = inb(p->base + TARG_SCRATCH + scratch_offset);
+ sxfr = target_scratch & SXFR;
+ ultra_enable = inb(p->base + ULTRA_ENB) |
+ (inb(p->base + ULTRA_ENB + 1) << 8);
+ if (ultra_enable & target_mask)
+ {
+ sxfr |= 0x100;
+ }
+ for (i = 0; i < num_aic7xxx_syncrates; i++)
+ {
+ if (sxfr == aic7xxx_syncrates[i].rate)
+ break;
+ }
+ aic7xxx_construct_sdtr(p, message_offset,
+ aic7xxx_syncrates[i].period,
+ target_scratch & WIDEXFER ?
+ MAX_OFFSET_16BIT : MAX_OFFSET_8BIT);
}
- else
+ else
{
- panic("scsi%d: Immediate complete for unknown operation.\n",
- p->host_no);
- }
- break;
+ panic("aic7xxx: AWAITING_MSG for an SCB that does "
+ "not have a waiting message.");
+ }
+ }
+ break;
- case DATA_OVERRUN:
+ case DATA_OVERRUN:
{
- unsigned int overrun;
-
- scb = (p->scb_array[inb(base + SCB_TAG)]);
- overrun = inb(base + STCNT0) | (inb(base + STCNT1) << 8) |
- (inb(base + STCNT2) << 16);
- overrun =0x00FFFFFF - overrun;
- printk(KERN_WARNING "scsi%d: data overrun of %d bytes detected; forcing "
- "a retry.\n", p->host_no, overrun);
- aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
- break;
+ unsigned char scb_index = inb(p->base + SCB_TAG);
+ unsigned char lastphase = inb(p->base + LASTPHASE);
+ unsigned int i, overrun;
+
+ scb = (p->scb_data->scb_array[scb_index]);
+ overrun = inb(p->base + STCNT) | (inb(p->base + STCNT + 1) << 8) |
+ (inb(p->base + STCNT + 2) << 16);
+ overrun = 0x00FFFFFF - overrun;
+ printk(KERN_WARNING "(scsi%d:%d:%d) Data overrun of %d bytes detected "
+ "in %s phase, tag %d; forcing a retry.\n",
+ p->host_no, TC_OF_SCB(scb), overrun,
+ lastphase == P_DATAIN ? "Data-In" : "Data-Out",
+ scb->hscb->tag);
+ printk(KERN_WARNING "%s seen Data Phase. Length = %d, NumSGs = %d.\n",
+ inb(p->base + SEQ_FLAGS) & DPHASE ? "Have" : "Haven't",
+ aic7xxx_length(scb->cmd, 0), scb->sg_count);
+ for (i = 0; i < scb->sg_count; i++)
+ {
+ printk(KERN_INFO " sg[%d] - Addr 0x%x : Length %d\n",
+ i, scb->sg_list[i].address, scb->sg_list[i].length);
+ }
+ /*
+ * XXX - What do we really want to do on an overrun? The
+ * mid-level SCSI code should handle this, but for now,
+ * we'll just indicate that the command should retried.
+ */
+ aic7xxx_error(scb->cmd) = DID_RETRY_COMMAND;
}
+ break;
-#if AIC7XXX_NOT_YET
- /* XXX Fill these in later */
- case MESG_BUFFER_BUSY:
- break;
- case MSGIN_PHASEMIS:
- break;
-#endif
+/* #if AIC7XXX_NOT_YET */
+ /* XXX Fill these in later */
+ case MSG_BUFFER_BUSY:
+ printk("aic7xxx: Message buffer busy.\n");
+ break;
+ case MSGIN_PHASEMIS:
+ printk("aic7xxx: Message-in phasemis.\n");
+ break;
+/*#endif */
+
+ case ABORT_CMDCMPLT:
+ /* This interrupt serves to pause the sequencer until we can clean
+ * up the QOUTFIFO allowing us to handle any abort SCBs that may
+ * completed yet still have an SCB in the QINFIFO or waiting for
+ * selection queue. By the time we get here, we should have
+ * already cleaned up the queues, so all we need to do is unpause
+ * the sequencer.
+ */
+ break;
+
+ default: /* unknown */
+ printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
+ p->host_no, intstat, inb(p->base + SCSISIGI));
+ break;
+ }
+
+ /*
+ * Clear the sequencer interrupt and unpause the sequencer.
+ */
+ outb(CLRSEQINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause always */ TRUE);
+}
- default: /* unknown */
- printk(KERN_WARNING "scsi%d: SEQINT, INTSTAT 0x%x, SCSISIGI 0x%x.\n",
- p->host_no, intstat, inb(SCSISIGI + base));
- break;
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_handle_scsiint
+ *
+ * Description:
+ * Interrupt handler for SCSI interrupts (SCSIINT).
+ *-F*************************************************************************/
+static void
+aic7xxx_handle_scsiint(struct aic7xxx_host *p, unsigned char intstat)
+{
+ unsigned char scb_index;
+ unsigned char status;
+ struct aic7xxx_scb *scb;
+
+ scb_index = inb(p->base + SCB_TAG);
+ status = inb(p->base + SSTAT1);
+
+ if (scb_index < p->scb_data->numscbs)
+ {
+ scb = p->scb_data->scb_array[scb_index];
+ if ((scb->flags & SCB_ACTIVE) == 0)
+ {
+ scb = NULL;
}
+ }
+ else
+ {
+ scb = NULL;
+ }
+
+ if ((status & SCSIRSTI) != 0)
+ {
+ char channel;
+ channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+
+ printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
+ p->host_no, channel);
/*
- * Clear the sequencer interrupt and unpause the sequencer.
+ * Go through and abort all commands for the channel, but do not
+ * reset the channel again.
*/
- outb(CLRSEQINT, CLRINT + base);
- UNPAUSE_SEQUENCER(p);
+ aic7xxx_reset_channel(p, channel, /* Initiate Reset */ FALSE);
+ scb = NULL;
}
-
- if (intstat & SCSIINT)
+ else if ( ((status & BUSFREE) != 0) && ((status & SELTO) == 0) )
{
- int status = inb(SSTAT1 + base);
- scsi_id = (inb(SCSIID + base) >> 4) & 0x0F;
- channel = 'A';
- if (inb(SBLKCTL + base) & SELBUSB)
- {
- channel = 'B';
- }
+ /*
+ * First look at what phase we were last in. If it's message-out,
+ * chances are pretty good that the bus free was in response to
+ * one of our abort requests.
+ */
+ unsigned char lastphase = inb(p->base + LASTPHASE);
+ unsigned char target = (inb(p->base + SAVED_TCL) >> 4) & 0x0F;
+ char channel = (inb(p->base + SBLKCTL) & SELBUSB) ? 'B' : 'A';
+ int printerror = TRUE;
- scb_index = inb(SCB_TAG + base);
- scb = (p->scb_array[scb_index]);
- if (status & SCSIRSTI)
- {
- PAUSE_SEQUENCER(p);
- printk(KERN_WARNING "scsi%d: SCSIINT - Someone reset channel %c.\n",
- p->host_no, channel);
- /*
- * Go through and abort all commands for the channel, but do not
- * reset the channel again.
- */
- aic7xxx_reset_channel(p, channel, FALSE);
- run_aborted_queue = TRUE;
- }
- else if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
+ outb(0, p->base + SCSISEQ);
+ if (lastphase == P_MESGOUT)
{
- printk(KERN_WARNING "scsi%d: SCSIINT - No command for SCB.\n", p->host_no);
- /*
- * Turn off the interrupt and set status to zero, so that it
- * falls through the rest of the SCSIINT code.
- */
- outb(status, CLRSINT1 + base);
- UNPAUSE_SEQUENCER(p);
- outb(CLRSCSIINT, CLRINT + base);
- scb = NULL;
+ unsigned char sindex;
+ unsigned char message;
+
+ sindex = inb(p->base + SINDEX);
+ message = inb(p->base + sindex - 1);
+
+ if (message == MSG_ABORT)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort completed.\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
+ aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), SCB_LIST_NULL);
+ aic7xxx_run_done_queue(p, /* complete */ TRUE);
+ scb = NULL;
+ printerror = 0;
+ }
+ else if (message == MSG_ABORT_TAG)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d) SCB %d abort Tag completed.\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag);
+ aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), scb->hscb->tag);
+ aic7xxx_run_done_queue(p, /* complete */ TRUE);
+ scb = NULL;
+ printerror = 0;
+ }
+ else if (message == MSG_BUS_DEV_RESET)
+ {
+ aic7xxx_handle_device_reset(p, target, channel);
+ scb = NULL;
+ printerror = 0;
+ }
}
- else if (status & SCSIPERR)
+ if (printerror != 0)
{
- char *phase;
- unsigned char mesg_out = MSG_NOP;
- unsigned char lastphase = inb(LASTPHASE + base);
+ if (scb != NULL)
+ {
+ unsigned char tag;
- cmd = scb->cmd;
- switch (lastphase)
+ if ((scb->hscb->control & TAG_ENB) != 0)
+ {
+ tag = scb->hscb->tag;
+ }
+ else
+ {
+ tag = SCB_LIST_NULL;
+ }
+ aic7xxx_reset_device(p, target, channel, SCB_LUN(scb), tag);
+ }
+ else
{
- case P_DATAOUT:
- phase = "Data-Out";
- break;
- case P_DATAIN:
- phase = "Data-In";
- mesg_out = MSG_INITIATOR_DET_ERROR;
- break;
- case P_COMMAND:
- phase = "Command";
- break;
- case P_MESGOUT:
- phase = "Message-Out";
- break;
- case P_STATUS:
- phase = "Status";
- mesg_out = MSG_INITIATOR_DET_ERROR;
- break;
- case P_MESGIN:
- phase = "Message-In";
- mesg_out = MSG_MSG_PARITY_ERROR;
- break;
- default:
- phase = "unknown";
- break;
+ aic7xxx_reset_device(p, target, channel, ALL_LUNS, SCB_LIST_NULL);
}
+ printk(KERN_WARNING "scsi%d: Unexpected busfree, LASTPHASE = 0x%x, "
+ "SEQADDR = 0x%x\n", p->host_no, lastphase,
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ }
+ outb(inb(p->base + SIMODE1) & ~ENBUSFREE, p->base + SIMODE1);
+ outb(CLRBUSFREE, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ restart_sequencer(p);
+ }
+ else if ((status & SELTO) != 0)
+ {
+ unsigned char scbptr;
+ unsigned char nextscb;
+ Scsi_Cmnd *cmd;
- /*
- * A parity error has occurred during a data
- * transfer phase. Flag it and continue.
- */
- printk(KERN_WARNING "scsi%d: Parity error during phase %s on target %d, "
- "channel %d, lun %d.\n", p->host_no, phase,
- cmd->target, cmd->channel & 0x01, cmd->lun & 0x07);
+ scbptr = inb(p->base + WAITING_SCBH);
+ outb(scbptr, p->base + SCBPTR);
+ scb_index = inb(p->base + SCB_TAG);
- /*
- * We've set the hardware to assert ATN if we get a parity
- * error on "in" phases, so all we need to do is stuff the
- * message buffer with the appropriate message. In phases
- * have set mesg_out to something other than MSG_NOP.
- */
- if (mesg_out != MSG_NOP)
- {
- outb(mesg_out, MSG0 + base);
- outb(1, MSG_LEN + base);
- cmd->result = DID_PARITY << 16;
- }
- else
+ scb = NULL;
+ if (scb_index < p->scb_data->numscbs)
+ {
+ scb = p->scb_data->scb_array[scb_index];
+ if ((scb->flags & SCB_ACTIVE) == 0)
{
- /*
- * Should we allow the target to make this decision for us?
- */
- cmd->result = DID_RETRY_COMMAND << 16;
+ scb = NULL;
}
- aic7xxx_done(p, scb);
}
- else if (status & SELTO)
+ if (scb == NULL)
{
- unsigned char waiting;
-
+ printk(KERN_WARNING "scsi%d: Referenced SCB %d not valid during SELTO.\n",
+ p->host_no, scb_index);
+ printk(KERN_WARNING " SCSISEQ = 0x%x SEQADDR = 0x%x SSTAT0 = 0x%x "
+ "SSTAT1 = 0x%x\n", inb(p->base + SCSISEQ),
+ inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
+ inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+ }
+ else
+ {
+ /*
+ * XXX - If we queued an abort tag, go clean up the disconnected list.
+ */
cmd = scb->cmd;
-
cmd->result = (DID_TIME_OUT << 16);
+
/*
* Clear an pending messages for the timed out
* target and mark the target as free.
*/
- ha_flags = inb(FLAGS + base);
- outb(0, MSG_LEN + base);
- aic7xxx_unbusy_target(scsi_id, channel, base);
+ outb(0, p->base + MSG_LEN);
+ aic7xxx_index_busy_target(p, cmd->target,
+ cmd->channel ? 'B': 'A', /*unbusy*/ TRUE);
+ outb(0, p->base + SCB_CONTROL);
+
/*
- * Stop the selection.
+ * Shift the waiting for selection queue forward
*/
- outb(0, SCSISEQ + base);
- outb(0, SCB_CONTROL + base);
- outb(CLRSELTIMEO, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
+ nextscb = inb(p->base + SCB_NEXT);
+ outb(nextscb, p->base + WAITING_SCBH);
/*
- * Shift the waiting for selection queue forward
+ * Put this SCB back on the free list.
*/
- waiting = inb(WAITING_SCBH + base);
- outb(waiting, SCBPTR + base);
- waiting = inb(SCB_NEXT + base);
- outb(waiting, WAITING_SCBH + base);
+ aic7xxx_add_curscb_to_free_list(p);
+ }
+ /*
+ * Stop the selection.
+ */
+ outb(0, p->base + SCSISEQ);
+ outb(CLRSELTIMEO | CLRBUSFREE, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ restart_sequencer(p);
+ }
+ else if (scb == NULL)
+ {
+ printk(KERN_WARNING "scsi%d: aic7xxx_isr - referenced scb not valid "
+ "during scsiint 0x%x scb(%d)\n"
+ " SIMODE0 0x%x, SIMODE1 0x%x, SSTAT0 0x%x, SEQADDR 0x%x\n",
+ p->host_no, status, scb_index, inb(p->base + SIMODE0),
+ inb(p->base + SIMODE1), inb(p->base + SSTAT0),
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ /*
+ * Turn off the interrupt and set status to zero, so that it
+ * falls through the rest of the SCSIINT code.
+ */
+ outb(status, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause always */ TRUE);
+ scb = NULL;
+ }
+ else if (status & SCSIPERR)
+ {
+ /*
+ * Determine the bus phase and queue an appropriate message.
+ */
+ char *phase;
+ Scsi_Cmnd *cmd;
+ unsigned char mesg_out = MSG_NOOP;
+ unsigned char lastphase = inb(p->base + LASTPHASE);
- RESTART_SEQUENCER(p);
- aic7xxx_done(p, scb);
+ cmd = scb->cmd;
+ switch (lastphase)
+ {
+ case P_DATAOUT:
+ phase = "Data-Out";
+ break;
+ case P_DATAIN:
+ phase = "Data-In";
+ mesg_out = MSG_INITIATOR_DET_ERR;
+ break;
+ case P_COMMAND:
+ phase = "Command";
+ break;
+ case P_MESGOUT:
+ phase = "Message-Out";
+ break;
+ case P_STATUS:
+ phase = "Status";
+ mesg_out = MSG_INITIATOR_DET_ERR;
+ break;
+ case P_MESGIN:
+ phase = "Message-In";
+ mesg_out = MSG_PARITY_ERROR;
+ break;
+ default:
+ phase = "unknown";
+ break;
+ }
+
+ /*
+ * A parity error has occurred during a data
+ * transfer phase. Flag it and continue.
+ */
+ printk(KERN_WARNING "(scsi%d:%d:%d) Parity error during phase %s.\n",
+ p->host_no, TC_OF_SCB(scb), phase);
+
+ /*
+ * We've set the hardware to assert ATN if we get a parity
+ * error on "in" phases, so all we need to do is stuff the
+ * message buffer with the appropriate message. "In" phases
+ * have set mesg_out to something other than MSG_NOP.
+ */
+ if (mesg_out != MSG_NOOP)
+ {
+ outb(mesg_out, p->base + MSG_OUT);
+ outb(1, p->base + MSG_LEN);
+ scb = NULL;
}
- else if (!(status & BUSFREE))
+ else
{
/*
- * We don't know what's going on. Turn off the
- * interrupt source and try to continue.
+ * Should we allow the target to make this decision for us?
*/
- printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
- outb(status, CLRSINT1 + base);
- UNPAUSE_SEQUENCER(p);
- outb(CLRSCSIINT, CLRINT + base);
+ cmd->result = DID_RETRY_COMMAND << 16;
+ }
+ outb(CLRSCSIPERR, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ }
+ else
+ {
+ /*
+ * We don't know what's going on. Turn off the
+ * interrupt source and try to continue.
+ */
+ printk(KERN_WARNING "aic7xxx: SSTAT1(0x%x).\n", status);
+ outb(status, p->base + CLRSINT1);
+ outb(CLRSCSIINT, p->base + CLRINT);
+ unpause_sequencer(p, /* unpause always */ TRUE);
+ scb = NULL;
+ }
+ if (scb != NULL)
+ {
+ aic7xxx_done(p, scb);
+ aic7xxx_done_cmds_complete(p);
+ }
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_isr
+ *
+ * Description:
+ * SCSI controller interrupt handler.
+ *
+ * NOTE: Since we declared this using SA_INTERRUPT, interrupts should
+ * be disabled all through this function unless we say otherwise.
+ *-F*************************************************************************/
+static void
+aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
+{
+ struct aic7xxx_host *p;
+ unsigned char intstat;
+ unsigned long flags;
+
+ p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+
+ /*
+ * Search for the host with a pending interrupt. If we can't find
+ * one, then we've encountered a spurious interrupt.
+ */
+ while ((p != NULL) && !(inb(p->base + INTSTAT) & INT_PEND))
+ {
+ if (p->next == NULL)
+ {
+ p = NULL;
+ }
+ else
+ {
+ p = (struct aic7xxx_host *) p->next->hostdata;
+ }
+ }
+
+ if (p == NULL)
+ return;
+
+ /*
+ * Handle all the interrupt sources - especially for SCSI
+ * interrupts, we won't get a second chance at them.
+ */
+ intstat = inb(p->base + INTSTAT);
+
+ /*
+ * Keep track of interrupts for /proc/scsi
+ */
+ p->isr_count++;
+
+ if (!(p->flags & A_SCANNED) && (p->isr_count == 1))
+ {
+ /*
+ * We must only have one card at this IRQ and it must have been
+ * added to the board data before the spurious interrupt occurred.
+ * It is sufficient that we check isr_count and not the spurious
+ * interrupt count.
+ */
+ printk("scsi%d: Encountered spurious interrupt.\n", p->host_no);
+ if (intstat)
+ {
+ /* Try clearing all interrupts. */
+ outb(CLRBRKADRINT | CLRSCSIINT | CLRCMDINT | CLRSEQINT, p->base + CLRINT);
}
+ return;
}
- if (run_aborted_queue)
- aic7xxx_done_aborted_scbs(p);
+ if (p->flags & IN_ISR)
+ {
+ printk(KERN_WARNING "scsi%d: Warning!! Interrupt routine called reentrantly!\n",
+ p->host_no);
+ return;
+ }
+
+ /*
+ * Indicate that we're in the interrupt handler.
+ */
+ save_flags(flags);
+ cli();
+ p->flags |= IN_ISR;
if (intstat & CMDCMPLT)
{
- int complete;
+ struct aic7xxx_scb *scb = NULL;
+ Scsi_Cmnd *cmd;
+ unsigned char qoutcnt;
+ unsigned char scb_index;
+ int i, interrupts_cleared = 0;
/*
* The sequencer will continue running when it
* issues this interrupt. There may be >1 commands
* finished, so loop until we've processed them all.
*/
- do {
- complete = inb(QOUTFIFO + base);
+ qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
- scb = (p->scb_array[complete]);
- if (!(scb->state & SCB_ACTIVE) || (scb->cmd == NULL))
- {
- printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d.\n"
- " QOUTCNT %d, QINCNT %d, SCB state 0x%x, cmd 0x%lx, "
- "pos(%d).\n", p->host_no, complete, inb(QOUTCNT + base),
- inb(QINCNT + base), scb->state, (unsigned long) scb->cmd,
- scb->position);
- outb(CLRCMDINT, CLRINT + base);
- continue;
- }
- cmd = scb->cmd;
- cmd->result |= (aic7xxx_error(cmd) << 16);
- if ((cmd->flags & WAS_SENSE) && !(cmd->flags & ASKED_FOR_SENSE))
+#if 1
+ if (qoutcnt >= p->qfullcount - 1)
+ printk(KERN_WARNING "aic7xxx: Command complete near Qfull count, "
+ "qoutcnt = %d.\n", qoutcnt);
+#endif
+ while (qoutcnt > 0)
+ {
+ for (i = 0; i < qoutcnt; i++)
{
- /*
- * Got sense information.
- */
- cmd->flags &= ASKED_FOR_SENSE;
+ scb_index = inb(p->base + QOUTFIFO);
+ scb = p->scb_data->scb_array[scb_index];
+ if (scb == NULL)
+ {
+ printk(KERN_WARNING "scsi%d: CMDCMPLT with invalid SCB index %d, "
+ "QOUTCNT %d, QINCNT %d\n", p->host_no, scb_index,
+ inb(p->base + QOUTCNT), inb(p->base + QINCNT));
+ continue;
+ }
+ else if (!(scb->flags & SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk(KERN_WARNING "scsi%d: CMDCMPLT without command for SCB %d, "
+ "QOUTCNT %d, QINCNT %d, SCB flags 0x%x, cmd 0x%lx\n",
+ p->host_no, scb_index, inb(p->base + QOUTCNT),
+ inb(p->base + QINCNT), scb->flags, (unsigned long) scb->cmd);
+ continue;
+ }
+ cmd = scb->cmd;
+ if (scb->hscb->residual_SG_segment_count != 0)
+ {
+ aic7xxx_calculate_residual(p, scb);
+ }
+ if ((scb->flags & SCB_QUEUED_ABORT) != 0)
+ {
+ /*
+ * Have to clean up any possible entries in the
+ * waiting queue and the QINFIFO.
+ */
+ int target;
+ char channel;
+ int lun;
+ unsigned char tag;
+
+ tag = SCB_LIST_NULL;
+ target = cmd->target;
+ lun = cmd->lun;
+ channel = (scb->hscb->target_channel_lun & SELBUSB) ? 'B' : 'A';
+ if (scb->hscb->control & TAG_ENB)
+ {
+ tag = scb->hscb->tag;
+ }
+ aic7xxx_reset_device(p, target, channel, lun, tag);
+ /*
+ * Run the done queue, but don't complete the commands; we
+ * do this once at the end of the loop.
+ */
+ aic7xxx_run_done_queue(p, /*complete*/ FALSE);
+ }
+ cmd->result |= (aic7xxx_error(cmd) << 16);
+ p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
+ aic7xxx_done(p, scb);
}
- p->device_status[TARGET_INDEX(cmd)].flags |= DEVICE_SUCCESS;
-
/*
* Clear interrupt status before checking the output queue again.
* This eliminates a race condition whereby a command could
@@ -3243,56 +3941,152 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
* so notification of the command being complete never made it
* back up to the kernel.
*/
- outb(CLRCMDINT, CLRINT + base);
- aic7xxx_done(p, scb);
+ outb(CLRCMDINT, p->base + CLRINT);
+ interrupts_cleared++;
+ qoutcnt = inb(p->base + QOUTCNT) & p->qcntmask;
+ }
-#ifdef AIC7XXX_PROC_STATS
- /*
- * XXX: we should actually know how much actually transferred
- * XXX: for each command, but apparently that's too difficult.
- */
- actual = aic7xxx_length(cmd, 0);
- if (!(cmd->flags & WAS_SENSE) && (actual > 0))
+ if (interrupts_cleared == 0)
+ {
+ outb(CLRCMDINT, p->base + CLRINT);
+ }
+
+ aic7xxx_done_cmds_complete(p);
+ }
+
+ if (intstat & BRKADRINT)
+ {
+ int i;
+ unsigned char errno = inb(p->base + ERROR);
+
+ printk(KERN_ERR "scsi%d: BRKADRINT error(0x%x):\n", p->host_no, errno);
+ for (i = 0; i < NUMBER(hard_error); i++)
+ {
+ if (errno & hard_error[i].errno)
{
- struct aic7xxx_xferstats *sp;
- long *ptr;
- int x;
+ printk(KERN_ERR " %s\n", hard_error[i].errmesg);
+ }
+ }
+ printk("scsi%d: BRKADRINT, error 0x%x, seqaddr 0x%x.\n", p->host_no,
+ inb(p->base + ERROR),
+ (inb(p->base + SEQADDR1) << 8) | inb(p->base + SEQADDR0));
+ aic7xxx_reset_device(p, ALL_TARGETS, ALL_CHANNELS, ALL_LUNS, SCB_LIST_NULL);
+ aic7xxx_run_done_queue(p, /*complete*/ TRUE);
+ }
+
+ if (intstat & SEQINT)
+ {
+ aic7xxx_handle_seqint(p, intstat);
+ }
- sp = &p->stats[cmd->channel & 0x01][cmd->target & 0x0F][cmd->lun & 0x07];
- sp->xfers++;
+ if (intstat & SCSIINT)
+ {
+ aic7xxx_handle_scsiint(p, intstat);
+ }
- if (cmd->request.cmd == WRITE)
+ if (p->waiting_scbs.head != NULL)
+ {
+ aic7xxx_run_waiting_queues(p);
+ }
+
+ p->flags &= ~IN_ISR;
+ restore_flags(flags);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_device_queue_depth
+ *
+ * Description:
+ * Determines the queue depth for a given device. There are two ways
+ * a queue depth can be obtained for a tagged queueing device. One
+ * way is the default queue depth which is determined by whether
+ * AIC7XXX_CMDS_PER_LUN is defined. If it is defined, then it is used
+ * as the default queue depth. Otherwise, we use either 4 or 8 as the
+ * default queue depth (dependent on the number of hardware SCBs).
+ * The other way we determine queue depth is through the use of the
+ * aic7xxx_tag_info array which is enabled by defining
+ * AIC7XXX_TAGGED_QUEUEING_BY_DEVICE. This array can be initialized
+ * with queue depths for individual devices. It also allows tagged
+ * queueing to be [en|dis]abled for a specific adapter.
+ *-F*************************************************************************/
+static void
+aic7xxx_device_queue_depth(struct aic7xxx_host *p, Scsi_Device *device)
+{
+ int default_depth = 2;
+
+ device->queue_depth = default_depth;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+ if (device->tagged_supported)
+ {
+ unsigned short target_mask;
+ int tag_enabled = TRUE;
+
+ target_mask = (1 << (device->id | (device->channel << 3)));
+
+#ifdef AIC7XXX_CMDS_PER_LUN
+ default_depth = AIC7XXX_CMDS_PER_LUN;
+#else
+ if (p->scb_data->maxhscbs <= 4)
+ {
+ default_depth = 4; /* Not many SCBs to work with. */
+ }
+ else
+ {
+ default_depth = 8;
+ }
+#endif
+
+ if (!(p->discenable & target_mask))
+ {
+ printk(KERN_INFO "(scsi%d:%d:%d) Disconnection disabled, unable to "
+ "enable tagged queueing.\n",
+ p->host_no, device->id, device->channel);
+ }
+ else
+ {
+#ifndef AIC7XXX_TAGGED_QUEUEING_BY_DEVICE
+ device->queue_depth = default_depth;
+#else
+ if (p->instance > NUMBER(aic7xxx_tag_info))
+ {
+ device->queue_depth = default_depth;
+ }
+ else
+ {
+ unsigned char tindex;
+
+ tindex = device->id | (device->channel << 3);
+ if (aic7xxx_tag_info[p->instance].tag_commands[tindex] < 0)
{
- sp->w_total++;
- sp->w_total512 += (actual >> 9);
- ptr = sp->w_bins;
+ tag_enabled = FALSE;
+ device->queue_depth = 2; /* Tagged queueing is disabled. */
}
- else
+ else if (aic7xxx_tag_info[p->instance].tag_commands[tindex] == 0)
{
- sp->r_total++;
- sp->r_total512 += (actual >> 9);
- ptr = sp->r_bins;
+ device->queue_depth = default_depth;
}
- for (x = 9; x <= 17; x++)
+ else
{
- if (actual < (1 << x))
- {
- ptr[x - 9]++;
- break;
- }
+ device->queue_depth =
+ aic7xxx_tag_info[p->instance].tag_commands[tindex];
}
- if (x > 17)
+ }
+#endif
+ if ((device->tagged_queue == 0) && tag_enabled)
+ {
+ if (aic7xxx_verbose)
{
- ptr[x - 9]++;
+ printk(KERN_INFO "(scsi%d:%d:%d) Enabled tagged queuing, "
+ "queue depth %d.\n", p->host_no,
+ device->id, device->channel, device->queue_depth);
}
+ device->tagged_queue = 1;
+ device->current_tag = SCB_LIST_NULL;
}
-#endif /* AIC7XXX_PROC_STATS */
-
- } while (inb(QOUTCNT + base) & p->qcntmask);
+ }
}
- aic7xxx_done_cmds_complete(p);
- p->flags &= ~IN_ISR;
- aic7xxx_run_waiting_queues(p);
+#endif
}
/*+F*************************************************************************
@@ -3307,59 +4101,18 @@ aic7xxx_isr(int irq, void *dev_id, struct pt_regs *regs)
* algorithm for determining the queue depth based on the maximum
* SCBs for the controller.
*-F*************************************************************************/
-static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
+static void
+aic7xxx_select_queue_depth(struct Scsi_Host *host,
Scsi_Device *scsi_devs)
{
- Scsi_Device *device = scsi_devs;
- int tq_depth = 2;
+ Scsi_Device *device;
struct aic7xxx_host *p = (struct aic7xxx_host *) host->hostdata;
-#ifdef AIC7XXX_CMDS_PER_LUN
- tq_depth = AIC7XXX_CMDS_PER_LUN;
-#else
- {
- if (p->maxhscbs <= 4)
- {
- tq_depth = 4; /* Not many SCBs to work with. */
- }
- else
- {
- tq_depth = 8;
- }
- }
-#endif
-
for (device = scsi_devs; device != NULL; device = device->next)
{
if (device->host == host)
{
- device->queue_depth = 2;
-#ifdef AIC7XXX_TAGGED_QUEUEING
- if (device->tagged_supported)
- {
- unsigned short target_mask = (1 << device->id) | device->channel;
-
- if (!(p->discenable & target_mask))
- {
- printk(KERN_INFO "scsi%d: Disconnection disabled, unable to enable "
- "tagged queueing for target %d, channel %d, LUN %d.\n",
- host->host_no, device->id, device->channel, device->lun);
- }
- else
- {
- device->queue_depth = tq_depth;
- if (device->tagged_queue == 0)
- {
- printk(KERN_INFO "scsi%d: Enabled tagged queuing for target %d, "
- "channel %d, LUN %d, queue depth %d.\n", host->host_no,
- device->id, device->channel, device->lun,
- device->queue_depth);
- device->tagged_queue = 1;
- device->current_tag = SCB_LIST_NULL;
- }
- }
- }
-#endif
+ aic7xxx_device_queue_depth(p, device);
}
}
}
@@ -3386,7 +4139,7 @@ static void aic7xxx_select_queue_depth(struct Scsi_Host *host,
* The fourth byte's lowest bit seems to be an enabled/disabled
* flag (rest of the bits are reserved?).
*-F*************************************************************************/
-static aha_type
+static aha_chip_type
aic7xxx_probe(int slot, int base, aha_status_type *bios)
{
int i;
@@ -3395,7 +4148,7 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
static struct {
int n;
unsigned char signature[sizeof(buf)];
- aha_type type;
+ aha_chip_type type;
int bios_disabled;
} AIC7xxx[] = {
{ 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_7771, FALSE }, /* host adapter 274x */
@@ -3434,7 +4187,8 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
return (AIC7xxx[i].type);
}
- printk("aic7xxx: Disabled at slot %d, ignored.\n", slot);
+ printk("aic7xxx: <Adaptec 7770 SCSI Host Adapter> "
+ "disabled at slot %d, ignored.\n", slot);
}
}
@@ -3461,10 +4215,9 @@ aic7xxx_probe(int slot, int base, aha_status_type *bios)
* useful in that it gives us an 800 nsec timer. After a read from the
* SEECTL_2840 register the timing flag is cleared and goes high 800 nsec
* later.
- *
*-F*************************************************************************/
static int
-read_2840_seeprom(int base, struct seeprom_config *sc)
+read_284x_seeprom(struct aic7xxx_host *p, struct seeprom_config *sc)
{
int i = 0, k = 0;
unsigned char temp;
@@ -3477,11 +4230,11 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
#define CLOCK_PULSE(p) \
- while ((inb(STATUS_2840 + base) & EEPROM_TF) == 0) \
+ while ((inb(p->base + STATUS_2840) & EEPROM_TF) == 0) \
{ \
; /* Do nothing */ \
} \
- (void) inb(SEECTL_2840 + base);
+ (void) inb(p->base + SEECTL_2840);
/*
* Read the first 32 registers of the seeprom. For the 2840,
@@ -3494,8 +4247,8 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
/*
* Send chip select for one clock cycle.
*/
- outb(CK_2840 | CS_2840, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(CK_2840 | CS_2840, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
/*
* Now we're ready to send the read command followed by the
@@ -3504,11 +4257,11 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
for (i = 0; i < seeprom_read.len; i++)
{
temp = CS_2840 | seeprom_read.bits[i];
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
/*
* Send the 6 bit address (MSB first, LSB last).
@@ -3518,11 +4271,11 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
temp = k;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = CS_2840 | temp;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
/*
@@ -3534,12 +4287,12 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
for (i = 0; i <= 16; i++)
{
temp = CS_2840;
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
temp = temp ^ CK_2840;
- seeprom[k] = (seeprom[k] << 1) | (inb(STATUS_2840 + base) & DI_2840);
- outb(temp, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ seeprom[k] = (seeprom[k] << 1) | (inb(p->base + STATUS_2840) & DI_2840);
+ outb(temp, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
/*
* The serial EEPROM has a checksum in the last word. Keep a
@@ -3555,12 +4308,12 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
/*
* Reset the chip select for the next command cycle.
*/
- outb(0, SEECTL_2840 + base);
- CLOCK_PULSE(base);
- outb(CK_2840, SEECTL_2840 + base);
- CLOCK_PULSE(base);
- outb(0, SEECTL_2840 + base);
- CLOCK_PULSE(base);
+ outb(0, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
+ outb(CK_2840, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
+ outb(0, p->base + SEECTL_2840);
+ CLOCK_PULSE(p);
}
#if 0
@@ -3589,6 +4342,53 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
/*+F*************************************************************************
* Function:
+ * acquire_seeprom
+ *
+ * Description:
+ * Acquires access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static inline int
+acquire_seeprom(struct aic7xxx_host *p)
+{
+ int wait;
+
+ /*
+ * Request access of the memory port. When access is
+ * granted, SEERDY will go high. We use a 1 second
+ * timeout which should be near 1 second more than
+ * is needed. Reason: after the 7870 chip reset, there
+ * should be no contention.
+ */
+ outb(SEEMS, p->base + SEECTL);
+ wait = 1000; /* 1000 msec = 1 second */
+ while ((wait > 0) && ((inb(p->base + SEECTL) & SEERDY) == 0))
+ {
+ wait--;
+ udelay(1000); /* 1 msec */
+ }
+ if ((inb(p->base + SEECTL) & SEERDY) == 0)
+ {
+ outb(0, p->base + SEECTL);
+ return (0);
+ }
+ return (1);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * release_seeprom
+ *
+ * Description:
+ * Releases access to the memory port on PCI controllers.
+ *-F*************************************************************************/
+static inline void
+release_seeprom(struct aic7xxx_host *p)
+{
+ outb(0, p->base + SEECTL);
+}
+
+/*+F*************************************************************************
+ * Function:
* read_seeprom
*
* Description:
@@ -3626,7 +4426,7 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
* first). The clock cycling from low to high initiates the next data
* bit to be sent from the chip.
*
- * The 7870 interface to the 93C46 serial EEPROM is through the SEECTL
+ * The 78xx interface to the 93C46 serial EEPROM is through the SEECTL
* register. After successful arbitration for the memory port, the
* SEECS bit of the SEECTL register is connected to the chip select.
* The SEECK, SEEDO, and SEEDI are connected to the clock, data out,
@@ -3636,17 +4436,14 @@ read_2840_seeprom(int base, struct seeprom_config *sc)
* to this is when we first request access to the memory port. The
* SEERDY goes high to signify that access has been granted and, for
* this case, has no implied timing.
- *
*-F*************************************************************************/
static int
-read_seeprom(int base, int offset, struct seeprom_config *sc,
- seeprom_chip_type chip)
+read_seeprom(struct aic7xxx_host *p, int offset, unsigned short *scarray,
+ unsigned int len, seeprom_chip_type chip)
{
int i = 0, k;
- unsigned long timeout;
unsigned char temp;
unsigned short checksum = 0;
- unsigned short *seeprom = (unsigned short *) sc;
struct seeprom_cmd {
unsigned char len;
unsigned char bits[3];
@@ -3654,43 +4451,33 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
#define CLOCK_PULSE(p) \
- while ((inb(SEECTL + base) & SEERDY) == 0) \
+ while ((inb(p->base + SEECTL) & SEERDY) == 0) \
{ \
; /* Do nothing */ \
}
/*
- * Request access of the memory port. When access is
- * granted, SEERDY will go high. We use a 1 second
- * timeout which should be near 1 second more than
- * is needed. Reason: after the 7870 chip reset, there
- * should be no contention.
+ * Request access of the memory port.
*/
- outb(SEEMS, SEECTL + base);
- timeout = jiffies + 100; /* 1 second timeout */
- while ((jiffies < timeout) && ((inb(SEECTL + base) & SEERDY) == 0))
- {
- ; /* Do nothing! Wait for access to be granted. */
- }
- if ((inb(SEECTL + base) & SEERDY) == 0)
+ if (acquire_seeprom(p) == 0)
{
- outb(0, SEECTL + base);
return (0);
}
/*
- * Read the first 32 registers of the seeprom. For the 7870,
- * the 93C46 SEEPROM is a 1024-bit device with 64 16-bit registers
- * but only the first 32 are used by Adaptec BIOS. The loop
- * will range from 0 to 31.
+ * Read 'len' registers of the seeprom. For the 7870, the 93C46
+ * SEEPROM is a 1024-bit device with 64 16-bit registers but only
+ * the first 32 are used by Adaptec BIOS. Some adapters use the
+ * 93C56 SEEPROM which is a 2048-bit device. The loop will range
+ * from 0 to 'len' - 1.
*/
- for (k = 0; k < (sizeof(*sc) / 2); k++)
+ for (k = 0; k < len; k++)
{
/*
* Send chip select for one clock cycle.
*/
- outb(SEEMS | SEECK | SEECS, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(SEEMS | SEECK | SEECS, p->base + SEECTL);
+ CLOCK_PULSE(p);
/*
* Now we're ready to send the read command followed by the
@@ -3699,25 +4486,25 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
for (i = 0; i < seeprom_read.len; i++)
{
temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
temp = temp ^ SEECK;
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
- * Send the 6 bit address (MSB first, LSB last).
+ * Send the 6 or 8 bit address (MSB first, LSB last).
*/
for (i = ((int) chip - 1); i >= 0; i--)
{
temp = k + offset;
temp = (temp >> i) & 1; /* Mask out all but lower bit. */
temp = SEEMS | SEECS | (temp << 1);
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
temp = temp ^ SEECK;
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
@@ -3729,56 +4516,57 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
for (i = 0; i <= 16; i++)
{
temp = SEEMS | SEECS;
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
temp = temp ^ SEECK;
- seeprom[k] = (seeprom[k] << 1) | (inb(SEECTL + base) & SEEDI);
- outb(temp, SEECTL + base);
- CLOCK_PULSE(base);
+ scarray[k] = (scarray[k] << 1) | (inb(p->base + SEECTL) & SEEDI);
+ outb(temp, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
- * The serial EEPROM has a checksum in the last word. Keep a
- * running checksum for all words read except for the last
- * word. We'll verify the checksum after all words have been
- * read.
+ * The serial EEPROM should have a checksum in the last word.
+ * Keep a running checksum for all words read except for the
+ * last word. We'll verify the checksum after all words have
+ * been read.
*/
- if (k < (sizeof(*sc) / 2) - 1)
+ if (k < (len - 1))
{
- checksum = checksum + seeprom[k];
+ checksum = checksum + scarray[k];
}
/*
* Reset the chip select for the next command cycle.
*/
- outb(SEEMS, SEECTL + base);
- CLOCK_PULSE(base);
- outb(SEEMS | SEECK, SEECTL + base);
- CLOCK_PULSE(base);
- outb(SEEMS, SEECTL + base);
- CLOCK_PULSE(base);
+ outb(SEEMS, p->base + SEECTL);
+ CLOCK_PULSE(p);
+ outb(SEEMS | SEECK, p->base + SEECTL);
+ CLOCK_PULSE(p);
+ outb(SEEMS, p->base + SEECTL);
+ CLOCK_PULSE(p);
}
/*
* Release access to the memory port and the serial EEPROM.
*/
- outb(0, SEECTL + base);
+ release_seeprom(p);
#if 0
- printk("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+ printk("Computed checksum 0x%x, checksum read 0x%x\n",
+ checksum, scarray[len - 1]);
printk("Serial EEPROM:");
- for (k = 0; k < (sizeof(*sc) / 2); k++)
+ for (k = 0; k < len; k++)
{
if (((k % 8) == 0) && (k != 0))
{
printk("\n ");
}
- printk(" 0x%x", seeprom[k]);
+ printk(" 0x%x", scarray[k]);
}
printk("\n");
#endif
- if (checksum != sc->checksum)
+ if (checksum != scarray[len - 1])
{
return (0);
}
@@ -3789,563 +4577,452 @@ read_seeprom(int base, int offset, struct seeprom_config *sc,
/*+F*************************************************************************
* Function:
- * detect_maxscb
+ * write_brdctl
*
* Description:
- * Detects the maximum number of SCBs for the controller and returns
- * the count and a mask in config (config->maxscbs, config->qcntmask).
+ * Writes a value to the BRDCTL register.
*-F*************************************************************************/
-static void
-detect_maxscb(struct aic7xxx_host_config *config)
+static inline void
+write_brdctl(struct aic7xxx_host *p, unsigned char value)
{
- unsigned char sblkctl_reg;
- int base, i;
-
-#ifdef AIC7XXX_PAGE_ENABLE
- config->flags |= PAGE_ENABLED;
-#endif
- base = config->base;
- switch (config->type)
- {
- case AIC_7770:
- case AIC_7771:
- case AIC_284x:
- /*
- * Check for Rev C or E boards. Rev E boards can supposedly have
- * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
- * It's still not clear extactly what is different about the Rev E
- * boards, but we think it allows 8 bit entries in the QOUTFIFO to
- * support "paging" SCBs (more than 4 commands can be active at once).
- *
- * The Rev E boards have a read/write autoflush bit in the
- * SBLKCTL register, while in the Rev C boards it is read only.
- */
- sblkctl_reg = inb(SBLKCTL + base) ^ AUTOFLUSHDIS;
- outb(sblkctl_reg, SBLKCTL + base);
- if (inb(SBLKCTL + base) == sblkctl_reg)
- {
- /*
- * We detected a Rev E board, we allow paging on this board.
- */
- printk(KERN_INFO "aic7xxx: %s Rev E and subsequent.\n",
- board_names[config->type]);
- outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL + base);
- }
- else
- {
- /* Do not allow paging. */
- config->flags &= ~PAGE_ENABLED;
- printk(KERN_INFO "aic7xxx: %s Rev C and previous.\n",
- board_names[config->type]);
- }
- break;
-
- default:
- break;
- }
-
- /*
- * Walk the SCBs to determine how many there are.
- */
- i = 1;
- outb(0, SCBPTR + base);
- outb(0, SCBARRAY + base);
-
- while (i < AIC7XXX_MAXSCB)
- {
- outb(i, SCBPTR + base);
- outb(i, SCBARRAY + base);
- if (inb(SCBARRAY + base) != i)
- break;
- outb(0, SCBPTR + base);
- if (inb(SCBARRAY + base) != 0)
- break;
-
- outb(i, SCBPTR + base); /* Clear the control byte. */
- outb(0, SCBARRAY + base);
-
- config->qcntmask |= i; /* Update the count mask. */
- i++;
- }
- outb(i, SCBPTR + base); /* Ensure we clear the control bytes. */
- outb(0, SCBARRAY + base);
- outb(0, SCBPTR + base);
- outb(0, SCBARRAY + base);
-
- config->maxhscbs = i;
- config->qcntmask |= i;
- if ((config->flags & PAGE_ENABLED) && (config->maxhscbs < AIC7XXX_MAXSCB))
- {
- config->maxscbs = AIC7XXX_MAXSCB;
- }
- else
- {
- config->flags &= ~PAGE_ENABLED; /* Disable paging if we have 255 SCBs!. */
- config->maxscbs = config->maxhscbs;
- }
-
- printk(KERN_INFO "aic7xxx: Memory check yields %d SCBs", config->maxhscbs);
- if (config->flags & PAGE_ENABLED)
- printk(", %d page-enabled SCBs.\n", config->maxscbs);
- else
- printk(", paging not enabled.\n");
-
+ unsigned char brdctl;
+
+ brdctl = BRDCS | BRDSTB;
+ outb(brdctl, p->base + BRDCTL);
+ brdctl |= value;
+ outb(brdctl, p->base + BRDCTL);
+ brdctl &= ~BRDSTB;
+ outb(brdctl, p->base + BRDCTL);
+ brdctl &= ~BRDCS;
+ outb(brdctl, p->base + BRDCTL);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_register
+ * read_brdctl
*
* Description:
- * Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ * Reads the BRDCTL register.
*-F*************************************************************************/
-static int
-aic7xxx_register(Scsi_Host_Template *template,
- struct aic7xxx_host_config *config)
+static inline unsigned char
+read_brdctl(struct aic7xxx_host *p)
{
- int i;
- unsigned char sblkctl, flags = 0;
- int max_targets;
- int found = 1;
- unsigned int sram, base;
- unsigned char target_settings;
- unsigned char scsi_conf, host_conf;
- unsigned short ultraenable = 0;
- int have_seeprom = FALSE;
- struct Scsi_Host *host;
- struct aic7xxx_host *p;
- struct seeprom_config sc;
-
- base = config->base;
-
- /*
- * Lock out other contenders for our i/o space.
- */
- request_region(base, MAXREG - MINREG, "aic7xxx");
+ outb(BRDRW | BRDCS, p->base + BRDCTL);
+ return (inb(p->base + BRDCTL));
+}
- switch (config->type)
+/*+F*************************************************************************
+ * Function:
+ * configure_termination
+ *
+ * Description:
+ * Configures the termination settings on PCI adapters that have
+ * SEEPROMs available.
+ *-F*************************************************************************/
+static void
+configure_termination(struct aic7xxx_host *p, unsigned char *sxfrctl1,
+ unsigned short adapter_control, unsigned char max_targ)
+{
+ unsigned char brdctl_int, brdctl_ext;
+ int internal50_present;
+ int internal68_present = 0;
+ int external_present = 0;
+ int eprom_present;
+ int high_on;
+ int low_on;
+ int old_verbose;
+
+ if (acquire_seeprom(p))
{
- case AIC_7770:
- case AIC_7771:
- /*
- * Use the boot-time option for the interrupt trigger type. If not
- * supplied (-1), then we use BIOS settings to determine the interrupt
- * trigger type (level or edge) and use this value for pausing and
- * unpausing the sequencer.
- */
- switch (aic7xxx_irq_trigger)
- {
- case 0: config->unpause = INTEN; /* Edge */
- break;
- case 1: config->unpause = IRQMS | INTEN; /* Level */
- break;
- case -1:
- default: config->unpause = (inb(HCNTRL + base) & IRQMS) | INTEN;
- break;
- }
- config->pause = config->unpause | PAUSE;
+ if (adapter_control & CFAUTOTERM)
+ {
+ old_verbose = aic7xxx_verbose;
+ printk(KERN_INFO "aic7xxx: Warning - detected auto-termination. Please "
+ "verify driver");
+ printk(KERN_INFO " detected settings and use manual termination "
+ "if necessary.");
+
+ /* Configure auto termination. */
+ outb(SEECS | SEEMS, p->base + SEECTL);
/*
- * For some 274x boards, we must clear the CHIPRST bit and pause
- * the sequencer. For some reason, this makes the driver work.
- * For 284x boards, we give it a CHIPRST just like the 294x boards.
+ * First read the status of our cables. Set the rom bank to
+ * 0 since the bank setting serves as a multiplexor for the
+ * cable detection logic. BRDDAT5 controls the bank switch.
*/
- outb(config->pause | CHIPRST, HCNTRL + base);
- aic7xxx_delay(1);
- if (inb(HCNTRL + base) & CHIPRST)
- {
- printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
- }
- outb(config->pause, HCNTRL + base);
+ write_brdctl(p, 0);
/*
- * Just to be on the safe side with the 274x, we will re-read the irq
- * since there was some issue about resetting the board.
+ * Now read the state of the internal connectors. The
+ * bits BRDDAT6 and BRDDAT7 are 0 when cables are present
+ * set when cables are not present (BRDDAT6 is INT50 and
+ * BRDDAT7 is INT68).
*/
- config->irq = inb(INTDEF + base) & 0x0F;
- if ((config->type == AIC_7771) &&
- (inb(HA_274_BIOSCTRL + base) & BIOSMODE) == BIOSDISABLED)
+ brdctl_int = read_brdctl(p);
+ internal50_present = (brdctl_int & BRDDAT6) ? 0 : 1;
+ if (max_targ > 8)
{
- config->bios = AIC_DISABLED;
- config->flags |= USE_DEFAULTS;
- }
- else
- {
- host_conf = inb(HOSTCONF + base);
- config->bus_speed = host_conf & DFTHRSH;
- config->busrtime = (host_conf << 2) & BOFF;
+ internal68_present = (brdctl_int & BRDDAT7) ? 0 : 1;
}
/*
- * Setup the FIFO threshold and the bus off time
+ * Set the rom bank to 1 and determine
+ * the other signals.
*/
- outb(config->bus_speed & DFTHRSH, BUSSPD + base);
- outb(config->busrtime, BUSTIME + base);
+ write_brdctl(p, BRDDAT5);
/*
- * A reminder until this can be detected automatically.
+ * Now read the state of the external connectors. BRDDAT6 is
+ * 0 when an external cable is present, and BRDDAT7 (EPROMPS) is
+ * set when the eprom is present.
*/
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
- break;
-
- case AIC_284x:
- outb(CHIPRST, HCNTRL + base);
- config->unpause = UNPAUSE_284X;
- config->pause = REQ_PAUSE; /* DWG would like to be like the rest */
- aic7xxx_delay(1);
- outb(config->pause, HCNTRL + base);
-
- config->parity = AIC_ENABLED;
- config->irq = inb(INTDEF + base) & 0x0F;
- host_conf = inb(HOSTCONF + base);
-
- printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
- have_seeprom = read_2840_seeprom(base, &sc);
- if (!have_seeprom)
+ brdctl_ext = read_brdctl(p);
+ external_present = (brdctl_ext & BRDDAT6) ? 0 : 1;
+ eprom_present = brdctl_ext & BRDDAT7;
+ if (aic7xxx_verbose)
{
- printk("aic7xxx: Unable to read SEEPROM.\n");
- }
- else
- {
- printk("done.\n");
- config->flags |= HAVE_SEEPROM;
- if (sc.bios_control & CF284XEXTEND)
- config->flags |= EXTENDED_TRANSLATION;
- if (!(sc.bios_control & CFBIOSEN))
+ if (max_targ > 8)
{
- /*
- * The BIOS is disabled; the values left over in scratch
- * RAM are still valid. Do not use defaults as in the
- * AIC-7770 case.
- */
- config->bios = AIC_DISABLED;
+ printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Int-68 %s, "
+ "Ext-68 %s)\n",
+ internal50_present ? "YES" : "NO",
+ internal68_present ? "YES" : "NO",
+ external_present ? "YES" : "NO");
}
else
{
- config->parity = (sc.adapter_control & CFSPARITY) ?
- AIC_ENABLED : AIC_DISABLED;
- config->low_term = (sc.adapter_control & CF284XSTERM) ?
- AIC_ENABLED : AIC_DISABLED;
- /*
- * XXX - Adaptec *does* make 284x wide controllers, but the
- * documents do not say where the high byte termination
- * enable bit is located.
- */
+ printk(KERN_INFO "aic7xxx: Cables present (Int-50 %s, Ext-50 %s)\n",
+ internal50_present ? "YES" : "NO",
+ external_present ? "YES" : "NO");
}
+ printk(KERN_INFO "aic7xxx: eprom %s present, brdctl_int=0x%x, "
+ "brdctl_ext=0x%x\n",
+ eprom_present ? "is" : "not", brdctl_int, brdctl_ext);
}
- host_conf = inb(HOSTCONF + base);
- config->bus_speed = host_conf & DFTHRSH;
- config->busrtime = (host_conf << 2) & BOFF;
-
- /*
- * Setup the FIFO threshold and the bus off time
- */
- outb(config->bus_speed & DFTHRSH, BUSSPD + base);
- outb(config->busrtime, BUSTIME + base);
-
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
- break;
-
- case AIC_7860:
- case AIC_7861:
- case AIC_7880:
- case AIC_7881:
- case AIC_7882:
- case AIC_7883:
- case AIC_7884:
- /*
- * Remember if Ultra was enabled in case there is no SEEPROM.
- * Fall through to the rest of the AIC_78xx code.
- */
- if ((inb(SXFRCTL0 + base) & ULTRAEN) || aic7xxx_enable_ultra)
- config->flags |= ULTRA_ENABLED;
-
- case AIC_7850:
- case AIC_7855:
- case AIC_7870:
- case AIC_7871:
- case AIC_7872:
- case AIC_7873:
- case AIC_7874:
/*
- * Grab the SCSI ID before chip reset in case there is no SEEPROM.
+ * Now set the termination based on what we found. BRDDAT6
+ * controls wide termination enable.
*/
- config->scsi_id = inb(SCSIID + base) & OID;
- outb(CHIPRST, HCNTRL + base);
- config->unpause = UNPAUSE_294X;
- config->pause = config->unpause | PAUSE;
- aic7xxx_delay(1);
- outb(config->pause, HCNTRL + base);
-
- config->parity = AIC_ENABLED;
+ high_on = FALSE;
+ low_on = FALSE;
+ if ((max_targ > 8) &&
+ ((external_present == 0) || (internal68_present == 0)))
+ {
+ high_on = TRUE;
+ }
- printk(KERN_INFO "aic7xxx: Reading SEEPROM...");
- if ((config->type == AIC_7873) || (config->type == AIC_7883))
+ if ((internal50_present + internal68_present + external_present) <= 1)
{
- have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
- &sc, c56_66);
+ low_on = TRUE;
}
- else
+
+ if (internal50_present && internal68_present && external_present)
{
- have_seeprom = read_seeprom(base, config->chan_num * (sizeof(sc) / 2),
- &sc, c46);
+ printk(KERN_WARNING "aic7xxx: Illegal cable configuration!!\n"
+ " Only two connectors on the adapter may be "
+ "used at a time!\n");
}
- if (!have_seeprom)
+
+ if (high_on == TRUE)
+ write_brdctl(p, BRDDAT6);
+ else
+ write_brdctl(p, 0);
+
+ if (low_on == TRUE)
+ *sxfrctl1 |= STPWEN;
+
+ if (aic7xxx_verbose)
{
- for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
+ if (max_targ > 8)
{
- if (inb(sram) != 0x00)
- break;
- }
- if (sram == base + TARG_SCRATCH)
- {
- for (sram = base + TARG_SCRATCH; sram < base + 0x60; sram++)
- {
- if (inb(sram) != 0xFF)
- break;
- }
- }
- if ((sram != base + 0x60) && (config->scsi_id != 0))
- {
- config->flags &= ~USE_DEFAULTS;
- printk("\naic7xxx: Unable to read SEEPROM; "
- "using leftover BIOS values.\n");
+ printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+ low_on ? "ON" : "OFF",
+ high_on ? "ON" : "OFF");
}
else
{
- printk("\n");
- printk(KERN_INFO "aic7xxx: Unable to read SEEPROM; using default "
- "settings.\n");
- config->flags |= USE_DEFAULTS;
- config->flags &= ~ULTRA_ENABLED;
- config->scsi_id = 7;
+ printk(KERN_INFO "aic7xxx: Termination %s\n", low_on ? "ON" : "OFF");
}
- scsi_conf = ENSPCHK | RESET_SCSI;
+ }
+ aic7xxx_verbose = old_verbose;
+ }
+ else
+ {
+ if (adapter_control & CFSTERM)
+ {
+ *sxfrctl1 |= STPWEN;
+ }
+ outb(SEEMS | SEECS, p->base + SEECTL);
+ /*
+ * Configure high byte termination.
+ */
+ if (adapter_control & CFWSTERM)
+ {
+ write_brdctl(p, BRDDAT6);
}
else
{
- printk("done.\n");
- config->flags |= HAVE_SEEPROM;
- if (!(sc.bios_control & CFBIOSEN))
- {
- /*
- * The BIOS is disabled; the values left over in scratch
- * RAM are still valid. Do not use defaults as in the
- * AIC-7770 case.
- */
- config->bios = AIC_DISABLED;
- scsi_conf = ENSPCHK | RESET_SCSI;
- }
- else
- {
- scsi_conf = 0;
- if (sc.adapter_control & CFRESETB)
- scsi_conf |= RESET_SCSI;
- if (sc.adapter_control & CFSPARITY)
- scsi_conf |= ENSPCHK;
- if (sc.bios_control & CFEXTEND)
- config->flags |= EXTENDED_TRANSLATION;
- config->scsi_id = (sc.brtime_id & CFSCSIID);
- config->parity = (sc.adapter_control & CFSPARITY) ?
- AIC_ENABLED : AIC_DISABLED;
- config->low_term = (sc.adapter_control & CFSTERM) ?
- AIC_ENABLED : AIC_DISABLED;
- config->high_term = (sc.adapter_control & CFWSTERM) ?
- AIC_ENABLED : AIC_DISABLED;
- config->busrtime = ((sc.brtime_id & CFBRTIME) >> 8);
- if (((config->type == AIC_7880) || (config->type == AIC_7881) ||
- (config->type == AIC_7882) || (config->type == AIC_7883) ||
- (config->type == AIC_7884)) && (sc.adapter_control & CFULTRAEN))
- {
- printk(KERN_INFO "aic7xxx: Enabling support for Ultra SCSI "
- "speed.\n");
- config->flags |= ULTRA_ENABLED;
- }
- }
+ write_brdctl(p, 0);
}
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Termination (Low %s, High %s)\n",
+ (adapter_control & CFSTERM) ? "ON" : "OFF",
+ (adapter_control & CFWSTERM) ? "ON" : "OFF");
+ }
+ }
+ release_seeprom(p);
+ }
+}
- outb(scsi_conf | (config->scsi_id & 0x07), SCSICONF + base);
- config->bus_speed = DFTHRSH_100;
- outb(config->bus_speed, DSPCISTATUS + base);
+/*+F*************************************************************************
+ * Function:
+ * detect_maxscb
+ *
+ * Description:
+ * Detects the maximum number of SCBs for the controller and returns
+ * the count and a mask in p (p->maxscbs, p->qcntmask).
+ *-F*************************************************************************/
+static void
+detect_maxscb(struct aic7xxx_host *p)
+{
+ int i;
+ unsigned char max_scbid = 255;
- /*
- * In case we are a wide card...
- */
- outb(config->scsi_id, SCSICONF + base + 1);
+ /*
+ * It's possible that we've already done this for multichannel
+ * adapters.
+ */
+ if (p->scb_data->maxhscbs == 0)
+ {
+ /*
+ * We haven't initialized the SCB settings yet. Walk the SCBs to
+ * determince how many there are.
+ */
+ outb(0, p->base + FREE_SCBH);
- printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
- (config->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
- break;
+ for (i = 0; i < AIC7XXX_MAXSCB; i++)
+ {
+ outb(i, p->base + SCBPTR);
+ outb(i, p->base + SCB_CONTROL);
+ if (inb(p->base + SCB_CONTROL) != i)
+ break;
+ outb(0, p->base + SCBPTR);
+ if (inb(p->base + SCB_CONTROL) != 0)
+ break;
- default:
- panic(KERN_WARNING "aic7xxx: (aic7xxx_register) Internal error.\n");
+ outb(i, p->base + SCBPTR);
+ outb(0, p->base + SCB_CONTROL); /* Clear the control byte. */
+ outb(i + 1, p->base + SCB_NEXT); /* Set the next pointer. */
+ outb(SCB_LIST_NULL, p->base + SCB_TAG); /* Make the tag invalid. */
+
+ /* Make the non-tagged targets not busy. */
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS);
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 1);
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 2);
+ outb(SCB_LIST_NULL, p->base + SCB_BUSYTARGETS + 3);
+ }
+
+ /* Make sure the last SCB terminates the free list. */
+ outb(i - 1, p->base + SCBPTR);
+ outb(SCB_LIST_NULL, p->base + SCB_NEXT);
+
+ /* Ensure we clear the first (0) SCBs control byte. */
+ outb(0, p->base + SCBPTR);
+ outb(0, p->base + SCB_CONTROL);
+
+ p->scb_data->maxhscbs = i;
}
- detect_maxscb(config);
+ if ((p->flags & PAGE_ENABLED) && (p->scb_data->maxhscbs < AIC7XXX_MAXSCB))
+ {
+ /* Determine the number of valid bits in the FIFOs. */
+ outb(max_scbid, p->base + QINFIFO);
+ max_scbid = inb(p->base + QINFIFO);
+ p->scb_data->maxscbs = MIN(AIC7XXX_MAXSCB, max_scbid + 1);
+ }
+ else
+ {
+ p->scb_data->maxscbs = p->scb_data->maxhscbs;
+ }
+ if (p->scb_data->maxscbs == p->scb_data->maxhscbs)
+ {
+ /*
+ * Disable paging if the QINFIFO doesn't allow more SCBs than
+ * we have in hardware.
+ */
+ p->flags &= ~PAGE_ENABLED;
+ }
- if (config->chip_type == AIC_777x)
+ /*
+ * Set the Queue Full Count. Some cards have more queue space than
+ * SCBs.
+ */
+ switch (p->chip_class)
{
- if (config->pause & IRQMS)
- {
- printk(KERN_INFO "aic7xxx: Using level sensitive interrupts.\n");
- }
- else
- {
- printk(KERN_INFO "aic7xxx: Using edge triggered interrupts.\n");
- }
+ case AIC_777x:
+ p->qfullcount = 4;
+ p->qcntmask = 0x07;
+ break;
+ case AIC_785x:
+ case AIC_786x:
+ p->qfullcount = 8;
+ p->qcntmask = 0x0f;
+ break;
+ case AIC_787x:
+ case AIC_788x:
+ if (p->scb_data->maxhscbs == AIC7XXX_MAXSCB)
+ {
+ p->qfullcount = AIC7XXX_MAXSCB;
+ p->qcntmask = 0xFF;
+ }
+ else
+ {
+ p->qfullcount = 16;
+ p->qcntmask = 0x1F;
+ }
+ break;
}
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_register
+ *
+ * Description:
+ * Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *-F*************************************************************************/
+static int
+aic7xxx_register(Scsi_Host_Template *template, struct aic7xxx_host *p)
+{
+ int i;
+ unsigned char sblkctl, flags = 0;
+ int max_targets;
+ int found = 1;
+ char channel_ids[] = {'A', 'B', 'C'};
+ unsigned char target_settings;
+ unsigned char scsi_conf, sxfrctl1;
+ unsigned short ultraenable = 0;
+ struct Scsi_Host *host;
+
+ /*
+ * Lock out other contenders for our i/o space.
+ */
+ request_region(p->base, MAXREG - MINREG, "aic7xxx");
/*
* Read the bus type from the SBLKCTL register. Set the FLAGS
* register in the sequencer for twin and wide bus cards.
*/
- sblkctl = inb(SBLKCTL + base);
- if (config->flags & PAGE_ENABLED)
+ sblkctl = inb(p->base + SBLKCTL);
+ if (p->flags & PAGE_ENABLED)
flags = PAGESCBS;
switch (sblkctl & SELBUS_MASK)
{
case SELNARROW: /* narrow/normal bus */
- config->scsi_id = inb(SCSICONF + base) & 0x07;
- config->bus_type = AIC_SINGLE;
- outb(flags | SINGLE_BUS, FLAGS + base);
+ p->scsi_id = inb(p->base + SCSICONF) & 0x07;
+ p->bus_type = AIC_SINGLE;
+ p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
+ if (p->flags & MULTI_CHANNEL)
+ {
+ printk(KERN_INFO "aic7xxx: Channel %c, SCSI ID %d, ",
+ channel_ids[p->chan_num], p->scsi_id);
+ }
+ else
+ {
+ printk (KERN_INFO "aic7xxx: Single Channel, SCSI ID %d, ",
+ p->scsi_id);
+ }
+ outb(flags | SINGLE_BUS, p->base + SEQ_FLAGS);
break;
case SELWIDE: /* Wide bus */
- config->scsi_id = inb(SCSICONF + base + 1) & 0x0F;
- config->bus_type = AIC_WIDE;
- printk("aic7xxx: Enabling wide channel of %s-Wide.\n",
- board_names[config->type]);
- outb(flags | WIDE_BUS, FLAGS + base);
+ p->scsi_id = inb(p->base + SCSICONF + 1) & HWSCSIID;
+ p->bus_type = AIC_WIDE;
+ p->flags &= ~FLAGS_CHANNEL_B_PRIMARY;
+ if (p->flags & MULTI_CHANNEL)
+ {
+ printk(KERN_INFO "aic7xxx: Wide Channel %c, SCSI ID %d, ",
+ channel_ids[p->chan_num], p->scsi_id);
+ }
+ else
+ {
+ printk (KERN_INFO "aic7xxx: Wide Channel, SCSI ID %d, ",
+ p->scsi_id);
+ }
+ outb(flags | WIDE_BUS, p->base + SEQ_FLAGS);
break;
case SELBUSB: /* Twin bus */
- config->scsi_id = inb(SCSICONF + base) & 0x07;
-#ifdef AIC7XXX_TWIN_SUPPORT
- config->scsi_id_b = inb(SCSICONF + base + 1) & 0x07;
- config->bus_type = AIC_TWIN;
- printk(KERN_INFO "aic7xxx: Enabled channel B of %s-Twin.\n",
- board_names[config->type]);
- outb(flags | TWIN_BUS, FLAGS + base);
-#else
- config->bus_type = AIC_SINGLE;
- printk(KERN_INFO "aic7xxx: Channel B of %s-Twin will be ignored.\n",
- board_names[config->type]);
- outb(flags, FLAGS + base);
-#endif
+ p->scsi_id = inb(p->base + SCSICONF) & HSCSIID;
+ p->scsi_id_b = inb(p->base + SCSICONF + 1) & HSCSIID;
+ p->bus_type = AIC_TWIN;
+ printk(KERN_INFO "aic7xxx: Twin Channel, A SCSI ID %d, B SCSI ID %d, ",
+ p->scsi_id, p->scsi_id_b);
+ outb(flags | TWIN_BUS, p->base + SEQ_FLAGS);
break;
default:
printk(KERN_WARNING "aic7xxx: Unsupported type 0x%x, please "
- "mail deang@teleport.com\n", inb(SBLKCTL + base));
- outb(0, FLAGS + base);
+ "mail deang@teleport.com\n", inb(p->base + SBLKCTL));
+ outb(0, p->base + SEQ_FLAGS);
return (0);
}
/*
- * For the 294x cards, clearing DIAGLEDEN and DIAGLEDON, will
- * take the card out of diagnostic mode and make the host adapter
- * LED follow bus activity (will not always be on).
+ * Detect SCB parameters and initialize the SCB array.
*/
- outb(sblkctl & ~(DIAGLEDEN | DIAGLEDON), SBLKCTL + base);
+ detect_maxscb(p);
+ printk("%d/%d SCBs, QFull %d, QMask 0x%x\n",
+ p->scb_data->maxhscbs, p->scb_data->maxscbs,
+ p->qfullcount, p->qcntmask);
- /*
- * The IRQ level in i/o port 4 maps directly onto the real
- * IRQ number. If it's ok, register it with the kernel.
- *
- * NB. the Adaptec documentation says the IRQ number is only
- * in the lower four bits; the ECU information shows the
- * high bit being used as well. Which is correct?
- *
- * The PCI cards get their interrupt from PCI BIOS.
- */
- if ((config->chip_type == AIC_777x) && ((config->irq < 9) || (config->irq > 15)))
- {
- printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ level, "
- "ignoring.\n");
- return (0);
- }
+ host = p->host;
- /*
- * Print out debugging information before re-enabling
- * the card - a lot of registers on it can't be read
- * when the sequencer is active.
- */
- debug_config(config);
-
- /*
- * Register each "host" and fill in the returned Scsi_Host
- * structure as best we can. Some of the parameters aren't
- * really relevant for bus types beyond ISA, and none of the
- * high-level SCSI code looks at it anyway. Why are the fields
- * there? Also save the pointer so that we can find the
- * information when an IRQ is triggered.
- */
- host = scsi_register(template, sizeof(struct aic7xxx_host));
- host->can_queue = config->maxscbs;
+ host->can_queue = p->scb_data->maxscbs;
host->cmd_per_lun = 2;
+ host->sg_tablesize = AIC7XXX_MAX_SG;
host->select_queue_depths = aic7xxx_select_queue_depth;
- host->this_id = config->scsi_id;
- host->io_port = config->base;
+ host->this_id = p->scsi_id;
+ host->io_port = p->base;
host->n_io_port = 0xFF;
- host->base = (unsigned char *)config->mbase;
- host->irq = config->irq;
- if (config->bus_type == AIC_WIDE)
+ host->base = (unsigned char *) p->mbase;
+ host->irq = p->irq;
+ if (p->bus_type == AIC_WIDE)
{
host->max_id = 16;
}
- if (config->bus_type == AIC_TWIN)
+ if (p->bus_type == AIC_TWIN)
{
host->max_channel = 1;
}
- p = (struct aic7xxx_host *) host->hostdata;
-
p->host = host;
- p->host_no = (int)host->host_no;
+ p->host_no = host->host_no;
p->isr_count = 0;
- p->base = base;
- p->maxscbs = config->maxscbs;
- p->maxhscbs = config->maxhscbs;
- p->qcntmask = config->qcntmask;
- p->mbase = (char *)config->mbase;
- p->type = config->type;
- p->chip_type = config->chip_type;
- p->flags = config->flags;
- p->chan_num = config->chan_num;
- p->scb_link = &(p->scb_usage);
-#if defined(CONFIG_PCI) && defined(AIC7XXX_SHARE_SCBS)
- if ((p->chan_num == 0) && ((p->type == AIC_7873) | (p->type == AIC_7883)))
- {
- shared_3985_scbs = &(p->scb_usage);
- p->scb_link = &(p->scb_usage);
- }
-#endif
- p->scb_link->numscbs = 0;
- p->bus_type = config->bus_type;
- p->seeprom = sc;
p->next = NULL;
p->completeq.head = NULL;
p->completeq.tail = NULL;
- scbq_init(&p->scb_link->free_scbs);
- scbq_init(&p->page_scbs);
+ scbq_init(&p->scb_data->free_scbs);
scbq_init(&p->waiting_scbs);
- scbq_init(&p->assigned_scbs);
- p->unpause = config->unpause;
- p->pause = config->pause;
-
- for (i = 0; i <= 15; i++)
+ for (i = 0; i <= NUMBER(p->device_status); i++)
{
p->device_status[i].commands_sent = 0;
p->device_status[i].flags = 0;
+ p->device_status[i].active_cmds = 0;
p->device_status[i].last_reset = 0;
}
- if (aic7xxx_boards[config->irq] == NULL)
+ if (aic7xxx_boards[p->irq] == NULL)
{
+ int result;
+ int irq_flags = 0;
+
+#ifdef AIC7XXX_OLD_ISR_TYPE
+ irg_flags = SA_INTERRUPT;
+#endif
/*
* Warning! This must be done before requesting the irq. It is
* possible for some boards to raise an interrupt as soon as
@@ -4353,17 +5030,26 @@ aic7xxx_register(Scsi_Host_Template *template,
* kernel, an interrupt is triggered immediately. Therefore, we
* must ensure the board data is correctly set before the request.
*/
- aic7xxx_boards[config->irq] = host;
+ aic7xxx_boards[p->irq] = host;
/*
- * Register IRQ with the kernel.
+ * Register IRQ with the kernel. Only allow sharing IRQs with
+ * PCI devices.
*/
- if (request_irq(config->irq, aic7xxx_isr, SA_INTERRUPT | SA_SHIRQ,
- "aic7xxx", NULL))
+ if (p->chip_class == AIC_777x)
+ {
+ result = (request_irq(p->irq, aic7xxx_isr, irq_flags, "aic7xxx", NULL));
+ }
+ else
+ {
+ result = (request_irq(p->irq, aic7xxx_isr, irq_flags | SA_SHIRQ,
+ "aic7xxx", NULL));
+ }
+ if (result < 0)
{
printk(KERN_WARNING "aic7xxx: Couldn't register IRQ %d, ignoring.\n",
- config->irq);
- aic7xxx_boards[config->irq] = NULL;
+ p->irq);
+ aic7xxx_boards[p->irq] = NULL;
return (0);
}
}
@@ -4374,79 +5060,74 @@ aic7xxx_register(Scsi_Host_Template *template,
* registered host adapter. Add this host adapter's Scsi_Host
* to the beginning of the linked list of hosts at the same IRQ.
*/
- p->next = aic7xxx_boards[config->irq];
- aic7xxx_boards[config->irq] = host;
- }
-
- /*
- * Load the sequencer program, then re-enable the board -
- * resetting the AIC-7770 disables it, leaving the lights
- * on with nobody home. On the PCI bus you *may* be home,
- * but then your mailing address is dynamically assigned
- * so no one can find you anyway :-)
- */
- printk(KERN_INFO "aic7xxx: Downloading sequencer code...");
- aic7xxx_loadseq(base);
-
- /*
- * Set Fast Mode and Enable the board
- */
- outb(FASTMODE, SEQCTL + base);
-
- if (p->chip_type == AIC_777x)
- {
- outb(ENABLE, BCTL + base);
+ p->next = aic7xxx_boards[p->irq];
+ aic7xxx_boards[p->irq] = host;
}
- printk("done.\n");
-
/*
* Set the SCSI Id, SXFRCTL0, SXFRCTL1, and SIMODE1, for both channels
*/
if (p->bus_type == AIC_TWIN)
{
/*
- * Select Channel B.
+ * The controller is gated to channel B after a chip reset; set
+ * bus B values first.
*/
- outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
-
- outb(config->scsi_id_b, SCSIID + base);
- scsi_conf = inb(SCSICONF + base + 1) & (ENSPCHK | STIMESEL);
- outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if EXPERIMENTAL_FLAGS
- outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
-#else
- outb(ENSELTIMO, SIMODE1 + base);
-#endif
+ outb(p->scsi_id_b, p->base + SCSIID);
+ scsi_conf = inb(p->base + SCSICONF + 1);
+ sxfrctl1 = inb(p->base + SXFRCTL1);
+ outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) |
+ ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
+ outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
if (p->flags & ULTRA_ENABLED)
{
- outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
}
else
{
- outb(DFON | SPIOEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN, p->base + SXFRCTL0);
}
- /*
- * Select Channel A
- */
- outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
+ if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+ {
+ /* Reset SCSI bus B. */
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Resetting channel B\n");
+
+ aic7xxx_reset_current_bus(p);
+ }
+
+ /* Select channel A */
+ outb(SELNARROW, p->base + SBLKCTL);
}
- outb(config->scsi_id, SCSIID + base);
- scsi_conf = inb(SCSICONF + base) & (ENSPCHK | STIMESEL);
- outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1 + base);
-#if EXPERIMENTAL_FLAGS
- outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, SIMODE1 + base);
-#else
- outb(ENSELTIMO, SIMODE1 + base);
-#endif
+
+ outb(p->scsi_id, p->base + SCSIID);
+ scsi_conf = inb(p->base + SCSICONF);
+ sxfrctl1 = inb(p->base + SXFRCTL1);
+ outb((scsi_conf & (ENSPCHK | STIMESEL)) | (sxfrctl1 & STPWEN) |
+ ENSTIMER | ACTNEGEN, p->base + SXFRCTL1);
+ outb(ENSELTIMO | ENSCSIRST | ENSCSIPERR, p->base + SIMODE1);
if (p->flags & ULTRA_ENABLED)
{
- outb(DFON | SPIOEN | ULTRAEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN | FAST20, p->base + SXFRCTL0);
}
else
{
- outb(DFON | SPIOEN, SXFRCTL0 + base);
+ outb(DFON | SPIOEN, p->base + SXFRCTL0);
+ }
+
+ if ((scsi_conf & RESET_SCSI) && (aic7xxx_no_reset == 0))
+ {
+ /* Reset SCSI bus A. */
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Resetting channel A\n");
+
+ aic7xxx_reset_current_bus(p);
+
+ /*
+ * Delay for the reset delay.
+ */
+ aic7xxx_delay(AIC7XXX_RESET_DELAY);
}
/*
@@ -4473,67 +5154,47 @@ aic7xxx_register(Scsi_Host_Template *template,
/*
* Grab the disconnection disable table and invert it for our needs
*/
- if (have_seeprom)
+ if (p->flags & USE_DEFAULTS)
{
- p->discenable = 0x0;
+ printk(KERN_INFO "aic7xxx: Host adapter BIOS disabled. Using default SCSI "
+ "device parameters.\n");
+ p->discenable = 0xFFFF;
}
else
{
- if (config->bios == AIC_DISABLED)
- {
- printk(KERN_INFO "aic7xxx : Host adapter BIOS disabled. Using default SCSI "
- "device parameters.\n");
- p->discenable = 0xFFFF;
- }
- else
- {
- p->discenable = ~((inb(DISC_DSB + base + 1) << 8) |
- inb(DISC_DSB + base));
- }
+ p->discenable = ~((inb(p->base + DISC_DSB + 1) << 8) |
+ inb(p->base + DISC_DSB));
}
for (i = 0; i < max_targets; i++)
{
- if (config->flags & USE_DEFAULTS)
+ if (p->flags & USE_DEFAULTS)
{
- target_settings = 0; /* 10 MHz */
+ target_settings = 0; /* 10 or 20 MHz depending on Ultra enable */
p->needsdtr_copy |= (0x01 << i);
p->needwdtr_copy |= (0x01 << i);
+ if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ ultraenable |= (0x01 << i);
}
else
{
- if (have_seeprom)
+ target_settings = inb(p->base + TARG_SCRATCH + i);
+ if (target_settings & 0x0F)
{
- target_settings = ((sc.device_flags[i] & CFXFER) << 4);
- if (sc.device_flags[i] & CFSYNCH)
- {
- p->needsdtr_copy |= (0x01 << i);
- }
- if (sc.device_flags[i] & CFWIDEB)
- {
- p->needwdtr_copy |= (0x01 << i);
- }
- if (sc.device_flags[i] & CFDISC)
- {
- p->discenable |= (0x01 << i);
- }
+ p->needsdtr_copy |= (0x01 << i);
+ /*
+ * Default to asynchronous transfers (0 offset)
+ */
+ target_settings &= 0xF0;
}
- else
+ if (target_settings & 0x80)
{
- target_settings = inb(TARG_SCRATCH + base + i);
- if (target_settings & 0x0F)
- {
- p->needsdtr_copy |= (0x01 << i);
- /*
- * Default to asynchronous transfers (0 offset)
- */
- target_settings &= 0xF0;
- }
- if (target_settings & 0x80)
- {
- p->needwdtr_copy |= (0x01 << i);
- target_settings &= 0x7F;
- }
+ p->needwdtr_copy |= (0x01 << i);
+ /*
+ * Clear the wide flag. When wide negotiation is successful,
+ * we'll enable it.
+ */
+ target_settings &= 0x7F;
}
if (p->flags & ULTRA_ENABLED)
{
@@ -4544,7 +5205,7 @@ aic7xxx_register(Scsi_Host_Template *template,
case 0x20:
ultraenable |= (0x01 << i);
break;
- case 0x40:
+ case 0x40: /* treat 10MHz as 10MHz without Ultra enabled */
target_settings &= ~(0x70);
break;
default:
@@ -4552,7 +5213,7 @@ aic7xxx_register(Scsi_Host_Template *template,
}
}
}
- outb(target_settings, (TARG_SCRATCH + base + i));
+ outb(target_settings, p->base + TARG_SCRATCH + i);
}
/*
@@ -4567,103 +5228,448 @@ aic7xxx_register(Scsi_Host_Template *template,
p->needsdtr = p->needsdtr_copy;
p->needwdtr = p->needwdtr_copy;
p->orderedtag = 0;
-#if 0
- printk("NeedSdtr = 0x%x, 0x%x\n", p->needsdtr_copy, p->needsdtr);
- printk("NeedWdtr = 0x%x, 0x%x\n", p->needwdtr_copy, p->needwdtr);
-#endif
- outb(ultraenable & 0xFF, ULTRA_ENB + base);
- outb((ultraenable >> 8) & 0xFF, ULTRA_ENB + base + 1);
+ outb(ultraenable & 0xFF, p->base + ULTRA_ENB);
+ outb((ultraenable >> 8) & 0xFF, p->base + ULTRA_ENB + 1);
/*
- * Set the number of available SCBs.
+ * Set the number of available hardware SCBs.
*/
- outb(config->maxhscbs, SCBCOUNT + base);
+ outb(p->scb_data->maxhscbs, p->base + SCBCOUNT);
/*
* 2s compliment of maximum tag value.
*/
- i = p->maxscbs;
- outb(-i & 0xFF, COMP_SCBCOUNT + base);
+ i = p->scb_data->maxscbs;
+ outb(-i & 0xFF, p->base + COMP_SCBCOUNT);
/*
- * Set the QCNT (queue count) mask to deal with broken aic7850s that
- * sporatically get garbage in the upper bits of their QCNT registers.
+ * Allocate enough hardware scbs to handle the maximum number of
+ * concurrent transactions we can have. We have to make sure that
+ * the allocated memory is contiguous memory. The Linux kmalloc
+ * routine should only allocate contiguous memory, but note that
+ * this could be a problem if kmalloc() is changed.
*/
- outb(config->qcntmask, QCNTMASK + base);
+ if (p->scb_data->hscbs == NULL)
+ {
+ size_t array_size;
+ unsigned int hscb_physaddr;
+
+ array_size = p->scb_data->maxscbs * sizeof(struct aic7xxx_hwscb);
+ p->scb_data->hscbs = kmalloc(array_size, GFP_ATOMIC);
+ if (p->scb_data->hscbs == NULL)
+ {
+ printk("aic7xxx: Unable to allocate hardware SCB array; "
+ "failing detection.\n");
+ release_region(p->base, MAXREG - MINREG);
+ /*
+ * Ensure that we only free the IRQ when there is _not_ another
+ * aic7xxx adapter sharing this IRQ. The adapters are always
+ * added to the beginning of the list, so we can grab the next
+ * pointer and place it back in the board array.
+ */
+ if (p->next == NULL)
+ {
+ free_irq(p->irq, aic7xxx_isr);
+ }
+ aic7xxx_boards[p->irq] = p->next;
+ return(0);
+ }
+ /* At least the control byte of each SCB needs to be 0. */
+ memset(p->scb_data->hscbs, 0, array_size);
+
+ /* Tell the sequencer where it can find the hardware SCB array. */
+ hscb_physaddr = VIRT_TO_BUS(p->scb_data->hscbs);
+ outb(hscb_physaddr & 0xFF, p->base + HSCB_ADDR);
+ outb((hscb_physaddr >> 8) & 0xFF, p->base + HSCB_ADDR + 1);
+ outb((hscb_physaddr >> 16) & 0xFF, p->base + HSCB_ADDR + 2);
+ outb((hscb_physaddr >> 24) & 0xFF, p->base + HSCB_ADDR + 3);
+ }
/*
- * Clear the active flags - no targets are busy.
- */
- outb(0, ACTIVE_A + base);
- outb(0, ACTIVE_B + base);
+ * QCount mask to deal with broken aic7850s that sporadically get
+ * garbage in the upper bits of their QCNT registers.
+ */
+ outb(p->qcntmask, p->base + QCNTMASK);
/*
* We don't have any waiting selections or disconnected SCBs.
*/
- outb(SCB_LIST_NULL, WAITING_SCBH + base);
- outb(SCB_LIST_NULL, DISCONNECTED_SCBH + base);
+ outb(SCB_LIST_NULL, p->base + WAITING_SCBH);
+ outb(SCB_LIST_NULL, p->base + DISCONNECTED_SCBH);
/*
* Message out buffer starts empty
*/
- outb(0, MSG_LEN + base);
+ outb(0, p->base + MSG_LEN);
/*
- * Reset the SCSI bus. Is this necessary?
- * There may be problems for a warm boot without resetting
- * the SCSI bus. Either BIOS settings in scratch RAM
- * will not get reinitialized, or devices may stay at
- * previous negotiated settings (SDTR and WDTR) while
- * the driver will think that no negotiations have been
- * performed.
- *
- * Some devices need a long time to "settle" after a SCSI
- * bus reset.
+ * Load the sequencer program, then re-enable the board -
+ * resetting the AIC-7770 disables it, leaving the lights
+ * on with nobody home. On the PCI bus you *may* be home,
+ * but then your mailing address is dynamically assigned
+ * so no one can find you anyway :-)
+ */
+ aic7xxx_loadseq(p);
+
+ if (p->chip_class == AIC_777x)
+ {
+ outb(ENABLE, p->base + BCTL); /* Enable the boards BUS drivers. */
+ }
+
+ /*
+ * Unpause the sequencer before returning and enable
+ * interrupts - we shouldn't get any until the first
+ * command is sent to us by the high-level SCSI code.
+ */
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+
+ return (found);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_chip_reset
+ *
+ * Description:
+ * Perform a chip reset on the aic7xxx SCSI controller. The controller
+ * is paused upon return.
+ *-F*************************************************************************/
+static void
+aic7xxx_chip_reset(struct aic7xxx_host *p)
+{
+ unsigned char hcntrl;
+ int wait;
+
+ /* Retain the IRQ type across the chip reset. */
+ hcntrl = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+
+ /*
+ * For some 274x boards, we must clear the CHIPRST bit and pause
+ * the sequencer. For some reason, this makes the driver work.
+ */
+ outb(PAUSE | CHIPRST, p->base + HCNTRL);
+
+ /*
+ * In the future, we may call this function as a last resort for
+ * error handling. Let's be nice and not do any unecessary delays.
+ */
+ wait = 1000; /* 1 second (1000 * 1000 usec) */
+ while ((wait > 0) && ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0))
+ {
+ udelay(1000); /* 1 msec = 1000 usec */
+ wait = wait - 1;
+ }
+
+ if ((inb(p->base + HCNTRL) & CHIPRSTACK) == 0)
+ {
+ printk(KERN_INFO "aic7xxx: Chip reset not cleared; clearing manually.\n");
+ }
+
+ outb(hcntrl | PAUSE, p->base + HCNTRL);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_alloc
+ *
+ * Description:
+ * Allocate and initialize a host structure. Returns NULL upon error
+ * and a pointer to a aic7xxx_host struct upon success.
+ *-F*************************************************************************/
+static struct aic7xxx_host *
+aic7xxx_alloc(Scsi_Host_Template *sht, unsigned int base, unsigned int mbase,
+ aha_chip_type chip_type, int flags, scb_data_type *scb_data)
+{
+ struct aic7xxx_host *p = NULL;
+ struct Scsi_Host *host;
+
+ /*
+ * Allocate a storage area by registering us with the mid-level
+ * SCSI layer.
*/
- if (!aic7xxx_no_reset)
+ host = scsi_register(sht, sizeof(struct aic7xxx_host));
+
+ if (host != NULL)
{
- printk("aic7xxx: Resetting the SCSI bus...");
- if (p->bus_type == AIC_TWIN)
+ p = (struct aic7xxx_host *) host->hostdata;
+ memset(p, 0, sizeof(struct aic7xxx_host));
+ p->host = host;
+
+ if (scb_data != NULL)
+ {
+ /*
+ * We are sharing SCB data areas; use the SCB data pointer
+ * provided.
+ */
+ p->scb_data = scb_data;
+ p->flags |= SHARED_SCBDATA;
+ }
+ else
{
/*
- * Select Channel B.
+ * We are not sharing SCB data; allocate one.
*/
- outb((sblkctl & ~SELBUS_MASK) | SELBUSB, SBLKCTL + base);
+ p->scb_data = kmalloc(sizeof(scb_data_type), GFP_ATOMIC);
+ if (p->scb_data != NULL)
+ {
+ memset(p->scb_data, 0, sizeof(scb_data_type));
+ scbq_init (&p->scb_data->free_scbs);
+ }
+ else
+ {
+ /*
+ * For some reason we don't have enough memory. Free the
+ * allocated memory for the aic7xxx_host struct, and return NULL.
+ */
+ scsi_unregister(host);
+ p = NULL;
+ }
+ }
+ if (p != NULL)
+ {
+ p->host_no = host->host_no;
+ p->base = base;
+ p->mbase = mbase;
+ p->maddr = NULL;
+ p->flags = flags;
+ p->chip_type = chip_type;
+ p->unpause = (inb(p->base + HCNTRL) & IRQMS) | INTEN;
+ p->pause = p->unpause | PAUSE;
+ }
+ }
+ return (p);
+}
- outb(SCSIRSTO, SCSISEQ + base);
- udelay(1000);
- outb(0, SCSISEQ + base);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_free
+ *
+ * Description:
+ * Frees and releases all resources associated with an instance of
+ * the driver (struct aic7xxx_host *).
+ *-F*************************************************************************/
+static void
+aic7xxx_free (struct aic7xxx_host *p)
+{
+ int i;
- /* Ensure we don't get a RSTI interrupt from this. */
- outb(CLRSCSIRSTI, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
+ /*
+ * We should be careful in freeing the scb_data area. For those
+ * adapters sharing external SCB RAM(398x), there will be only one
+ * scb_data area allocated. The flag SHARED_SCBDATA indicates if
+ * one adapter is sharing anothers SCB RAM.
+ */
+ if (!(p->flags & SHARED_SCBDATA))
+ {
+ /*
+ * Free the allocated hardware SCB space.
+ */
+ if (p->scb_data->hscbs != NULL)
+ {
+ kfree(p->scb_data->hscbs);
+ }
+ /*
+ * Free the driver SCBs. These were allocated on an as-need
+ * basis.
+ */
+ for (i = 0; i < p->scb_data->numscbs; i++)
+ {
+ kfree(p->scb_data->scb_array[i]);
+ }
+ /*
+ * Free the hardware SCBs.
+ */
+ if (p->scb_data->hscbs != NULL)
+ {
+ kfree(p->scb_data->hscbs);
+ }
- /*
- * Select Channel A.
+ /*
+ * Free the SCB data area.
+ */
+ kfree(p->scb_data);
+ }
+ /*
+ * Free the instance of the device structure.
+ */
+ scsi_unregister(p->host);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_load_seeprom
+ *
+ * Description:
+ * Load the seeprom and configure adapter and target settings.
+ * Returns 1 if the load was successful and 0 otherwise.
+ *-F*************************************************************************/
+static int
+load_seeprom (struct aic7xxx_host *p, unsigned char *sxfrctl1)
+{
+ int have_seeprom = 0;
+ int i, max_targets;
+ unsigned char target_settings, scsi_conf;
+ unsigned short scarray[128];
+ struct seeprom_config *sc = (struct seeprom_config *) scarray;
+
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Loading serial EEPROM...");
+ }
+ switch (p->chip_type)
+ {
+ case AIC_7770: /* None of these adapters have seeproms. */
+ case AIC_7771:
+ case AIC_7850:
+ case AIC_7855:
+ break;
+
+ case AIC_284x:
+ have_seeprom = read_284x_seeprom(p, (struct seeprom_config *) scarray);
+ break;
+
+ case AIC_7861:
+ case AIC_7870:
+ case AIC_7871:
+ case AIC_7872:
+ case AIC_7874:
+ case AIC_7881:
+ case AIC_7882:
+ case AIC_7884:
+ have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+ scarray, sizeof(*sc)/2, C46);
+ break;
+
+ case AIC_7860: /* Motherboard Ultra controllers might have RAID port. */
+ case AIC_7880:
+ have_seeprom = read_seeprom(p, 0, scarray, sizeof(*sc)/2, C46);
+ if (!have_seeprom)
+ {
+ have_seeprom = read_seeprom(p, 0, scarray, sizeof(scarray)/2, C56_66);
+ }
+ break;
+
+ case AIC_7873: /* The 3985 adapters use the 93c56 serial EEPROM. */
+ case AIC_7883:
+ have_seeprom = read_seeprom(p, p->chan_num * (sizeof(*sc)/2),
+ scarray, sizeof(scarray)/2, C56_66);
+ break;
+
+ default:
+ break;
+ }
+
+ if (!have_seeprom)
+ {
+ if (aic7xxx_verbose)
+ {
+ printk("\naic7xxx: No SEEPROM available; using defaults.\n");
+ }
+ p->flags |= USE_DEFAULTS;
+ }
+ else
+ {
+ if (aic7xxx_verbose)
+ {
+ printk("done\n");
+ }
+ p->flags |= HAVE_SEEPROM;
+
+ /*
+ * Update the settings in sxfrctl1 to match the termination settings.
+ */
+ *sxfrctl1 = 0;
+
+ /*
+ * First process the settings that are different between the VLB
+ * and PCI adapter seeproms.
+ */
+ if (p->chip_class == AIC_777x)
+ {
+ /* VLB adapter seeproms */
+ if (sc->bios_control & CF284XEXTEND)
+ p->flags |= EXTENDED_TRANSLATION;
+
+ if (sc->adapter_control & CF284XSTERM)
+ *sxfrctl1 |= STPWEN;
+ /*
+ * The 284x SEEPROM doesn't have a max targets field. We
+ * set it to 16 to make sure we take care of the 284x-wide
+ * adapters. For narrow adapters, going through the extra
+ * 8 target entries will not cause any harm since they will
+ * will not be used.
+ *
+ * XXX - We should probably break out the bus detection
+ * from the register function so we can use it here
+ * to tell us how many targets there really are.
*/
- outb((sblkctl & ~SELBUS_MASK) | SELNARROW, SBLKCTL + base);
+ max_targets = 16;
}
+ else
+ {
+ /* PCI adapter seeproms */
+ if (sc->bios_control & CFEXTEND)
+ p->flags |= EXTENDED_TRANSLATION;
- outb(SCSIRSTO, SCSISEQ + base);
- udelay(1000);
- outb(0, SCSISEQ + base);
+ if (sc->adapter_control & CFSTERM)
+ *sxfrctl1 |= STPWEN;
- /* Ensure we don't get a RSTI interrupt from this. */
- outb(CLRSCSIRSTI, CLRSINT1 + base);
- outb(CLRSCSIINT, CLRINT + base);
+ /* Limit to 16 targets just in case. */
+ max_targets = MIN(sc->max_targets & CFMAXTARG, 16);
+ }
- aic7xxx_delay(AIC7XXX_RESET_DELAY);
+ for (i = 0; i < max_targets; i++)
+ {
+ target_settings = (sc->device_flags[i] & CFXFER) << 4;
+ if (sc->device_flags[i] & CFSYNCH)
+ target_settings |= SOFS;
+ if (sc->device_flags[i] & CFWIDEB)
+ target_settings |= WIDEXFER;
+ if (sc->device_flags[i] & CFDISC)
+ p->discenable |= (0x01 << i);
+ outb(target_settings, p->base + TARG_SCRATCH + i);
+ }
+ outb(~(p->discenable & 0xFF), p->base + DISC_DSB);
+ outb(~((p->discenable >> 8) & 0xFF), p->base + DISC_DSB + 1);
- printk("done.\n");
- }
+ p->scsi_id = sc->brtime_id & CFSCSIID;
- /*
- * Unpause the sequencer before returning and enable
- * interrupts - we shouldn't get any until the first
- * command is sent to us by the high-level SCSI code.
- */
- UNPAUSE_SEQUENCER(p);
- return (found);
+ scsi_conf = (p->scsi_id & 0x7);
+ if (sc->adapter_control & CFSPARITY)
+ scsi_conf |= ENSPCHK;
+ if (sc->adapter_control & CFRESETB)
+ scsi_conf |= RESET_SCSI;
+
+ if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ {
+ /*
+ * We allow the operator to override ultra enable through
+ * the boot prompt.
+ */
+ if (!(sc->adapter_control & CFULTRAEN) && (aic7xxx_enable_ultra == 0))
+ {
+ /* Treat us as a non-ultra card */
+ p->flags &= ~ULTRA_ENABLED;
+ }
+ }
+
+ /* Set the host ID */
+ outb(scsi_conf, p->base + SCSICONF);
+ /* In case we are a wide card */
+ outb(p->scsi_id, p->base + SCSICONF + 1);
+
+ if (p->chip_class != AIC_777x)
+ {
+ /*
+ * Update the settings in sxfrctl1 to match the termination
+ * settings.
+ */
+ *sxfrctl1 = 0;
+ configure_termination(p, sxfrctl1, sc->adapter_control,
+ (unsigned char) sc->max_targets & CFMAXTARG);
+ }
+ }
+ return (have_seeprom);
}
/*+F*************************************************************************
@@ -4672,17 +5678,24 @@ aic7xxx_register(Scsi_Host_Template *template,
*
* Description:
* Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *
+ * XXX - This should really be called aic7xxx_probe(). A sequence of
+ * probe(), attach()/detach(), and init() makes more sense than
+ * one do-it-all function. This may be useful when (and if) the
+ * mid-level SCSI code is overhauled.
*-F*************************************************************************/
int
aic7xxx_detect(Scsi_Host_Template *template)
{
- int found = 0, slot, base;
- unsigned char irq = 0;
+ int found = 0;
+ aha_status_type adapter_bios;
+ aha_chip_class_type chip_class;
+ aha_chip_type chip_type;
+ int slot, base;
+ int chan_num = 0;
+ unsigned char hcntrl, sxfrctl1, sblkctl, hostconf, irq = 0;
int i;
- struct aic7xxx_host_config config;
-
- template->proc_dir = &proc_scsi_aic7xxx;
- config.chan_num = 0;
+ struct aic7xxx_host *p;
/*
* Since we may allow sharing of IRQs, it is imperative
@@ -4696,6 +5709,10 @@ aic7xxx_detect(Scsi_Host_Template *template)
aic7xxx_boards[i] = NULL;
}
+ template->proc_dir = &proc_scsi_aic7xxx;
+ template->name = aic7xxx_info(NULL);
+ template->sg_tablesize = AIC7XXX_MAX_SG;
+
/*
* Initialize the spurious count to 0.
*/
@@ -4717,33 +5734,174 @@ aic7xxx_detect(Scsi_Host_Template *template)
continue;
}
- config.type = aic7xxx_probe(slot, HID0 + base, &(config.bios));
- if (config.type != AIC_NONE)
+ chip_type = aic7xxx_probe(slot, base + HID0, &(adapter_bios));
+ if (chip_type != AIC_NONE)
{
+
+ switch (chip_type)
+ {
+ case AIC_7770:
+ case AIC_7771:
+ printk("aic7xxx: <%s> at EISA %d\n",
+ board_names[chip_type], slot);
+ break;
+ case AIC_284x:
+ printk("aic7xxx: <%s> at VLB %d\n",
+ board_names[chip_type], slot);
+ break;
+ default:
+ break;
+ }
+
/*
* We found a card, allow 1 spurious interrupt.
*/
aic7xxx_spurious_count = 1;
/*
- * We "find" a AIC-7770 if we locate the card
- * signature and we can set it up and register
- * it with the kernel without incident.
+ * Pause the card preserving the IRQ type. Allow the operator
+ * to override the IRQ trigger.
*/
- config.chip_type = AIC_777x;
- config.base = base;
- config.mbase = 0;
- config.irq = irq;
- config.parity = AIC_ENABLED;
- config.low_term = AIC_UNKNOWN;
- config.high_term = AIC_UNKNOWN;
- config.flags = 0;
- if (aic7xxx_extended)
- config.flags |= EXTENDED_TRANSLATION;
- config.bus_speed = DFTHRSH_100;
- config.busrtime = BOFF;
- found += aic7xxx_register(template, &config);
+ if (aic7xxx_irq_trigger == 1)
+ hcntrl = IRQMS; /* Level */
+ else if (aic7xxx_irq_trigger == 0)
+ hcntrl = 0; /* Edge */
+ else
+ hcntrl = inb(base + HCNTRL) & IRQMS; /* Default */
+ outb(hcntrl | PAUSE, base + HCNTRL);
+
+ irq = inb(INTDEF + base) & 0x0F;
+ switch (irq)
+ {
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 14:
+ case 15:
+ break;
+
+ default:
+ printk(KERN_WARNING "aic7xxx: Host adapter uses unsupported IRQ "
+ "level, ignoring.\n");
+ irq = 0;
+ break;
+ }
+
+ if (irq != 0)
+ {
+ p = aic7xxx_alloc(template, base, 0, chip_type, 0, NULL);
+ if (p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ continue;
+ }
+ p->irq = irq & 0x0F;
+ p->chip_class = AIC_777x;
+#ifdef AIC7XXX_PAGE_ENABLE
+ p->flags |= PAGE_ENABLED;
+#endif
+ p->instance = found;
+ if (aic7xxx_extended)
+ {
+ p->flags |= EXTENDED_TRANSLATION;
+ }
+ aic7xxx_chip_reset(p);
+
+ switch (p->chip_type)
+ {
+ case AIC_7770:
+ case AIC_7771:
+ {
+ unsigned char biosctrl = inb(p->base + HA_274_BIOSCTRL);
+
+ /*
+ * Get the primary channel information. Right now we don't
+ * do anything with this, but someday we will be able to inform
+ * the mid-level SCSI code which channel is primary.
+ */
+ if (biosctrl & CHANNEL_B_PRIMARY)
+ {
+ p->flags |= FLAGS_CHANNEL_B_PRIMARY;
+ }
+
+ if ((biosctrl & BIOSMODE) == BIOSDISABLED)
+ {
+ p->flags |= USE_DEFAULTS;
+ }
+ break;
+ }
+
+ case AIC_284x:
+ if (!load_seeprom(p, &sxfrctl1))
+ {
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: SEEPROM not available.\n");
+ }
+ break;
+
+ default: /* Won't get here. */
+ break;
+ }
+ printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, IRQ %d (%s), ",
+ (p->flags & USE_DEFAULTS) ? "dis" : "en", p->base, p->irq,
+ (p->pause & IRQMS) ? "level sensitive" : "edge triggered");
+ /*
+ * Check for Rev C or E boards. Rev E boards can supposedly have
+ * more than 4 SCBs, while the Rev C boards are limited to 4 SCBs.
+ * It's still not clear extactly what is different about the Rev E
+ * boards, but we think it allows 8 bit entries in the QOUTFIFO to
+ * support "paging" SCBs (more than 4 commands can be active at once).
+ *
+ * The Rev E boards have a read/write autoflush bit in the
+ * SBLKCTL register, while in the Rev C boards it is read only.
+ */
+ sblkctl = inb(p->base + SBLKCTL) ^ AUTOFLUSHDIS;
+ outb(sblkctl, p->base + SBLKCTL);
+ if (inb(p->base + SBLKCTL) == sblkctl)
+ {
+ /*
+ * We detected a Rev E board, we allow paging on this board.
+ */
+ printk("Revision >= E\n");
+ outb(sblkctl & ~AUTOFLUSHDIS, base + SBLKCTL);
+ }
+ else
+ {
+ /* Do not allow paging. */
+ p->flags &= ~PAGE_ENABLED;
+ printk("Revision <= C\n");
+ }
+
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+ (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+
+ /*
+ * Set the FIFO threshold and the bus off time.
+ */
+ hostconf = inb(p->base + HOSTCONF);
+ outb(hostconf & DFTHRSH, p->base + BUSSPD);
+ outb((hostconf << 2) & BOFF, p->base + BUSTIME);
+ /*
+ * Try to initialize the card and register it with the kernel.
+ */
+ if (aic7xxx_register(template, p))
+ {
+ /*
+ * We successfully found a board and registered it.
+ */
+ found = found + 1;
+ }
+ else
+ {
+ /*
+ * Something went wrong; release and free all resources.
+ */
+ aic7xxx_free(p);
+ }
+ }
/*
* Disallow spurious interrupts.
*/
@@ -4759,15 +5917,15 @@ aic7xxx_detect(Scsi_Host_Template *template)
{
struct
{
- unsigned short vendor_id;
- unsigned short device_id;
- aha_type card_type;
- aha_chip_type chip_type;
+ unsigned short vendor_id;
+ unsigned short device_id;
+ aha_chip_type chip_type;
+ aha_chip_class_type chip_class;
} const aic7xxx_pci_devices[] = {
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7850, AIC_7850, AIC_785x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7855, AIC_7855, AIC_785x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_785x},
- {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_785x},
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7860, AIC_7860, AIC_786x},
+ {PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7861, AIC_7861, AIC_786x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7870, AIC_7870, AIC_787x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7871, AIC_7871, AIC_787x},
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7872, AIC_7872, AIC_787x},
@@ -4780,14 +5938,14 @@ aic7xxx_detect(Scsi_Host_Template *template)
{PCI_VENDOR_ID_ADAPTEC, PCI_DEVICE_ID_ADAPTEC_7884, AIC_7884, AIC_788x}
};
- int error;
+ int error, flags;
int done = 0;
unsigned int iobase, mbase;
unsigned short index = 0;
unsigned char pci_bus, pci_device_fn;
- unsigned int csize_lattime;
- unsigned int class_revid;
- unsigned int devconfig;
+ unsigned char ultra_enb = 0;
+ unsigned int devconfig, class_revid;
+ scb_data_type *shared_scb_data = NULL;
char rev_id[] = {'B', 'C', 'D'};
for (i = 0; i < NUMBER(aic7xxx_pci_devices); i++)
@@ -4804,36 +5962,33 @@ aic7xxx_detect(Scsi_Host_Template *template)
}
else /* Found an Adaptec PCI device. */
{
- config.type = aic7xxx_pci_devices[i].card_type;
- config.chip_type = aic7xxx_pci_devices[i].chip_type;
- config.chan_num = 0;
- config.bios = AIC_ENABLED; /* Assume bios is enabled. */
- config.flags = 0;
- config.busrtime = 40;
- switch (config.type)
+ chip_class = aic7xxx_pci_devices[i].chip_class;
+ chip_type = aic7xxx_pci_devices[i].chip_type;
+ chan_num = 0;
+ flags = 0;
+ switch (aic7xxx_pci_devices[i].chip_type)
{
case AIC_7850:
case AIC_7855:
- case AIC_7860:
- case AIC_7861:
- config.bios = AIC_DISABLED;
- config.flags |= USE_DEFAULTS;
- config.bus_speed = DFTHRSH_100;
+ flags |= USE_DEFAULTS;
break;
case AIC_7872: /* 3940 */
case AIC_7882: /* 3940-Ultra */
- config.chan_num = number_of_3940s & 0x1; /* Has 2 controllers */
+ flags |= MULTI_CHANNEL;
+ chan_num = number_of_3940s & 0x1; /* Has 2 controllers */
number_of_3940s++;
break;
case AIC_7873: /* 3985 */
case AIC_7883: /* 3985-Ultra */
- config.chan_num = number_of_3985s; /* Has 3 controllers */
+ chan_num = number_of_3985s; /* Has 3 controllers */
+ flags |= MULTI_CHANNEL;
number_of_3985s++;
if (number_of_3985s == 3)
{
number_of_3985s = 0;
+ shared_scb_data = NULL;
}
break;
@@ -4850,39 +6005,165 @@ aic7xxx_detect(Scsi_Host_Template *template)
PCI_INTERRUPT_LINE, &irq);
error += pcibios_read_config_dword(pci_bus, pci_device_fn,
PCI_BASE_ADDRESS_1, &mbase);
+ error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+ DEVCONFIG, &devconfig);
+ error += pcibios_read_config_dword(pci_bus, pci_device_fn,
+ CLASS_PROGIF_REVID, &class_revid);
+
+ printk("aic7xxx: <%s> at PCI %d\n",
+ board_names[chip_type], PCI_SLOT(pci_device_fn));
/*
- * The first bit of PCI_BASE_ADDRESS_0 is always set, so
+ * The first bit (LSB) of PCI_BASE_ADDRESS_0 is always set, so
* we mask it off.
*/
iobase &= PCI_BASE_ADDRESS_IO_MASK;
+ p = aic7xxx_alloc(template, iobase, mbase, chip_type, flags,
+ shared_scb_data);
+
+ if (p == NULL)
+ {
+ printk(KERN_WARNING "aic7xxx: Unable to allocate device space.\n");
+ continue;
+ }
+
+ /* Remember to set the channel number, irq, and chip class. */
+ p->chan_num = chan_num;
+ p->irq = irq;
+ p->chip_class = chip_class;
+#ifdef AIC7XXX_PAGE_ENABLE
+ p->flags |= PAGE_ENABLED;
+#endif
+ p->instance = found;
+
/*
- * Read the PCI burst size and latency timer.
+ * Remember how the card was setup in case there is no seeprom.
*/
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- CSIZE_LATTIME, &csize_lattime);
- printk(KERN_INFO "aic7xxx: BurstLen = %d DWDs, Latency Timer = %d "
- "PCLKS\n", (int) (csize_lattime & CACHESIZE),
- (csize_lattime >> 8) & 0x000000ff);
+ p->scsi_id = inb(p->base + SCSIID) & OID;
+ if ((p->chip_class == AIC_786x) || (p->chip_class == AIC_788x))
+ {
+ p->flags |= ULTRA_ENABLED;
+ ultra_enb = inb(p->base + SXFRCTL1) & FAST20;
+ }
+ sxfrctl1 = inb(p->base + SXFRCTL1) & STPWEN;
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- CLASS_PROGIF_REVID, &class_revid);
- if ((class_revid & DEVREVID) < 3)
+ aic7xxx_chip_reset(p);
+
+#ifdef AIC7XXX_USE_EXT_SCBRAM
+ if (devconfig & RAMPSM)
{
- printk(KERN_INFO "aic7xxx: %s Rev %c.\n", board_names[config.type],
- rev_id[class_revid & DEVREVID]);
+ printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
+ "access.\n");
+ /*
+ * XXX - Assume 9 bit SRAM and enable parity checking.
+ */
+ devconfig |= EXTSCBPEN;
+
+ /*
+ * XXX - Assume fast SRAM and only enable 2 cycle access if we
+ * are sharing the SRAM across multiple adapters (398x).
+ */
+ if ((devconfig & MPORTMODE) == 0)
+ {
+ devconfig |= EXTSCBTIME;
+ }
+ devconfig &= ~SCBRAMSEL;
+ pcibios_write_config_dword(pci_bus, pci_device_fn,
+ DEVCONFIG, devconfig);
}
+#endif
- error += pcibios_read_config_dword(pci_bus, pci_device_fn,
- DEVCONFIG, &devconfig);
- if (error)
+ if ((p->flags & USE_DEFAULTS) == 0)
{
- panic("aic7xxx: (aic7xxx_detect) Error %d reading PCI registers.\n",
- error);
+ load_seeprom(p, &sxfrctl1);
+ }
+
+ /*
+ * Take the LED out of diagnostic mode
+ */
+ sblkctl = inb(p->base + SBLKCTL);
+ outb((sblkctl & ~(DIAGLEDEN | DIAGLEDON)), p->base + SBLKCTL);
+
+ /*
+ * We don't know where this is set in the SEEPROM or by the
+ * BIOS, so we default to 100%.
+ */
+ outb(DFTHRSH_100, p->base + DSPCISTATUS);
+
+ if (p->flags & USE_DEFAULTS)
+ {
+ int j;
+ /*
+ * Default setup; should only be used if the adapter does
+ * not have a SEEPROM.
+ */
+ /*
+ * Check the target scratch area to see if someone set us
+ * up already. We are previously set up if the scratch
+ * area contains something other than all zeroes and ones.
+ */
+ for (j = TARG_SCRATCH; j < 0x60; j++)
+ {
+ if (inb(p->base + j) != 0x00) /* Check for all zeroes. */
+ break;
+ }
+ if (j == TARG_SCRATCH)
+ {
+ for (j = TARG_SCRATCH; j < 0x60; j++)
+ {
+ if (inb(p->base + 1) != 0xFF) /* Check for all ones. */
+ break;
+ }
+ }
+ if ((j != 0x60) && (p->scsi_id != 0))
+ {
+ p->flags &= ~USE_DEFAULTS;
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: Using leftover BIOS values.\n");
+ }
+ }
+ else
+ {
+ if (aic7xxx_verbose)
+ {
+ printk(KERN_INFO "aic7xxx: No BIOS found; using default "
+ "settings.\n");
+ }
+ /*
+ * Assume only one connector and always turn on
+ * termination.
+ */
+ sxfrctl1 = STPWEN;
+ p->scsi_id = 7;
+ }
+ outb((p->scsi_id & HSCSIID) | ENSPCHK | RESET_SCSI,
+ p->base + SCSICONF);
+ /* In case we are a wide card. */
+ outb(p->scsi_id, p->base + SCSICONF + 1);
+ if ((ultra_enb == 0) && ((p->flags & USE_DEFAULTS) == 0))
+ {
+ /*
+ * If there wasn't a BIOS or the board wasn't in this mode
+ * to begin with, turn off Ultra.
+ */
+ p->flags &= ~ULTRA_ENABLED;
+ }
}
- printk(KERN_INFO "aic7xxx: devconfig = 0x%x.\n", devconfig);
+ /*
+ * Print some additional information about the adapter.
+ */
+ printk(KERN_INFO "aic7xxx: BIOS %sabled, IO Port 0x%x, "
+ "IO Mem 0x%x, IRQ %d",
+ (p->flags & USE_DEFAULTS) ? "dis" : "en",
+ p->base, p->mbase, p->irq);
+ if ((class_revid & DEVREVID) < 3)
+ {
+ printk(", Revision %c", rev_id[class_revid & DEVREVID]);
+ }
+ printk("\n");
/*
* I don't think we need to bother with allowing
@@ -4891,58 +6172,57 @@ aic7xxx_detect(Scsi_Host_Template *template)
*/
aic7xxx_spurious_count = 1;
- config.base = iobase;
- config.mbase = mbase;
- config.irq = irq;
- config.parity = AIC_ENABLED;
- config.low_term = AIC_UNKNOWN;
- config.high_term = AIC_UNKNOWN;
if (aic7xxx_extended)
- config.flags |= EXTENDED_TRANSLATION;
-#ifdef AIC7XXX_SHARE_SCBs
- if (devconfig & RAMPSM)
-#else
- if ((devconfig & RAMPSM) && (config.type != AIC_7873) &&
- (config.type != AIC_7883))
-#endif
+ p->flags |= EXTENDED_TRANSLATION;
+
+ if (aic7xxx_verbose)
+ printk(KERN_INFO "aic7xxx: Extended translation %sabled.\n",
+ (p->flags & EXTENDED_TRANSLATION) ? "en" : "dis");
+
+ /*
+ * Put our termination setting into sxfrctl1 now that the
+ * generic initialization is complete.
+ */
+ sxfrctl1 |= inb(p->base + SXFRCTL1);
+ outb(sxfrctl1, p->base + SXFRCTL1);
+
+ if (aic7xxx_register(template, p) == 0)
{
+ aic7xxx_free(p);
+ }
+ else
+ {
+ found = found + 1;
+
+#ifdef AIC7XXX_USE_EXT_SCBRAM
/*
- * External SRAM present. The probe will walk the SCBs to see
- * how much SRAM we have and set the number of SCBs accordingly.
- * We have to turn off SCBRAMSEL to access the external SCB
- * SRAM.
- *
- * It seems that early versions of the aic7870 didn't use these
- * bits, hence the hack for the 3940 above. I would guess that
- * recent 3940s using later aic7870 or aic7880 chips do actually
- * set RAMPSM.
+ * Set the shared SCB data once we've successfully probed a
+ * 398x adapter.
*
- * The documentation isn't clear, but it sounds like the value
- * written to devconfig must not have RAMPSM set. The second
- * sixteen bits of the register are R/O anyway, so it shouldn't
- * affect RAMPSM either way.
+ * Note that we can only do this if the use of external
+ * SCB RAM is enabled.
*/
- printk(KERN_INFO "aic7xxx: External RAM detected; enabling RAM "
- "access.\n");
- devconfig &= ~(RAMPSM | SCBRAMSEL);
- pcibios_write_config_dword(pci_bus, pci_device_fn,
- DEVCONFIG, devconfig);
+ if ((p->chip_type == AIC_7873) || (p->chip_type == AIC_7883))
+ {
+ if (shared_scb_data == NULL)
+ {
+ shared_scb_data = p->scb_data;
+ }
+ }
+#endif
}
- found += aic7xxx_register(template, &config);
+ index++;
/*
* Disable spurious interrupts.
*/
aic7xxx_spurious_count = 0;
-
- index++;
} /* Found an Adaptec PCI device. */
}
}
}
#endif CONFIG_PCI
- template->name = aic7xxx_info(NULL);
return (found);
}
@@ -4958,45 +6238,45 @@ static void
aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
struct aic7xxx_scb *scb)
{
- unsigned int addr; /* must be 32 bits */
unsigned short mask;
+ struct aic7xxx_hwscb *hscb;
mask = (0x01 << TARGET_INDEX(cmd));
+ hscb = scb->hscb;
+
/*
* Setup the control byte if we need negotiation and have not
* already requested it.
*/
-#ifdef AIC7XXX_TAGGED_QUEUEING
- if (cmd->device->tagged_queue)
+ if (p->discenable & mask)
{
- cmd->tag = scb->tag;
- cmd->device->current_tag = scb->tag;
- scb->control |= TAG_ENB;
- p->device_status[TARGET_INDEX(cmd)].commands_sent++;
- if (p->device_status[TARGET_INDEX(cmd)].commands_sent == 200)
- {
- scb->control |= 0x02;
- p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
- }
-#if 0
- if (p->orderedtag & mask)
+ hscb->control |= DISCENB;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+ if (cmd->device->tagged_queue)
{
- scb->control |= 0x02;
- p->orderedtag = p->orderedtag & ~mask;
+ cmd->tag = hscb->tag;
+ p->device_status[TARGET_INDEX(cmd)].commands_sent++;
+ if (p->device_status[TARGET_INDEX(cmd)].commands_sent < 75)
+ {
+ hscb->control |= MSG_SIMPLE_Q_TAG;
+ }
+ else
+ {
+ hscb->control |= MSG_ORDERED_Q_TAG;
+ p->device_status[TARGET_INDEX(cmd)].commands_sent = 0;
+ }
}
-#endif
- }
-#endif
- if (p->discenable & mask)
- {
- scb->control |= DISCENB;
+#endif /* Tagged queueing */
}
+
if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
{
p->wdtr_pending |= mask;
- scb->control |= NEEDWDTR;
+ hscb->control |= MK_MESSAGE;
+ scb->flags |= SCB_MSGOUT_WDTR;
#if 0
- printk("aic7xxx: Sending WDTR request to target %d.\n", cmd->target);
+ printk("scsi%d: Sending WDTR request to target %d.\n",
+ p->host_no, cmd->target);
#endif
}
else
@@ -5004,19 +6284,20 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
{
p->sdtr_pending |= mask;
- scb->control |= NEEDSDTR;
+ hscb->control |= MK_MESSAGE;
+ scb->flags |= SCB_MSGOUT_SDTR;
#if 0
- printk("aic7xxx: Sending SDTR request to target %d.\n", cmd->target);
+ printk("scsi%d: Sending SDTR request to target %d.\n",
+ p->host_no, cmd->target);
#endif
}
}
-
#if 0
printk("aic7xxx: (build_scb) Target %d, cmd(0x%x) size(%u) wdtr(0x%x) "
"mask(0x%x).\n",
cmd->target, cmd->cmnd[0], cmd->cmd_len, p->needwdtr, mask);
#endif
- scb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+ hscb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
/*
@@ -5030,9 +6311,8 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
* XXX - this relies on the host data being stored in a
* little-endian format.
*/
- addr = VIRT_TO_BUS(cmd->cmnd);
- scb->SCSI_cmd_length = cmd->cmd_len;
- memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
+ hscb->SCSI_cmd_length = cmd->cmd_len;
+ hscb->SCSI_cmd_pointer = VIRT_TO_BUS(cmd->cmnd);
if (cmd->use_sg)
{
@@ -5052,15 +6332,16 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
scb->sg_list[i].address = VIRT_TO_BUS(sg[i].address);
scb->sg_list[i].length = (unsigned int) sg[i].length;
}
- scb->SG_segment_count = cmd->use_sg;
- addr = VIRT_TO_BUS(scb->sg_list);
- memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
- memcpy(scb->data_pointer, &(scb->sg_list[0].address),
- sizeof(scb->data_pointer));
- scb->data_count = scb->sg_list[0].length;
+ hscb->SG_list_pointer = VIRT_TO_BUS(scb->sg_list);
+ hscb->SG_segment_count = cmd->use_sg;
+ scb->sg_count = hscb->SG_segment_count;
+
+ /* Copy the first SG into the data pointer area. */
+ hscb->data_pointer = scb->sg_list[0].address;
+ hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
#if 0
printk("aic7xxx: (build_scb) SG segs(%d), length(%u), sg[0].length(%d).\n",
- cmd->use_sg, aic7xxx_length(cmd, 0), scb->data_count);
+ cmd->use_sg, aic7xxx_length(cmd, 0), hscb->data_count);
#endif
}
else
@@ -5069,28 +6350,23 @@ aic7xxx_buildscb(struct aic7xxx_host *p, Scsi_Cmnd *cmd,
printk("aic7xxx: (build_scb) Creating scatterlist, addr(0x%lx) length(%d).\n",
(unsigned long) cmd->request_buffer, cmd->request_bufflen);
#endif
- if (cmd->request_bufflen == 0)
+ if (cmd->request_bufflen)
{
- /*
- * In case the higher level SCSI code ever tries to send a zero
- * length command, ensure the SCB indicates no data. The driver
- * will interpret a zero length command as a Bus Device Reset.
- */
- scb->SG_segment_count = 0;
- memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
- memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
- scb->data_count = 0;
+ hscb->SG_segment_count = 1;
+ scb->sg_count = 1;
+ scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
+ scb->sg_list[0].length = cmd->request_bufflen;
+ hscb->SG_list_pointer = VIRT_TO_BUS(&scb->sg_list[0]);
+ hscb->data_count = scb->sg_list[0].length | (SCB_LIST_NULL << 24);
+ hscb->data_pointer = VIRT_TO_BUS(cmd->request_buffer);
}
else
{
- scb->SG_segment_count = 1;
- scb->sg_list[0].address = VIRT_TO_BUS(cmd->request_buffer);
- scb->sg_list[0].length = cmd->request_bufflen;
- addr = VIRT_TO_BUS(&scb->sg_list[0]);
- memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
- scb->data_count = scb->sg_list[0].length;
- addr = VIRT_TO_BUS(cmd->request_buffer);
- memcpy(scb->data_pointer, &addr, sizeof(scb->data_pointer));
+ hscb->SG_segment_count = 0;
+ scb->sg_count = 0;
+ hscb->SG_list_pointer = 0;
+ hscb->data_pointer = 0;
+ hscb->data_count = SCB_LIST_NULL << 24;
}
}
}
@@ -5108,7 +6384,6 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
long processor_flags;
struct aic7xxx_host *p;
struct aic7xxx_scb *scb;
- u_char curscb, intstat;
p = (struct aic7xxx_host *) cmd->host->hostdata;
if (p->host != cmd->host)
@@ -5140,34 +6415,21 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
cmd->lun & 0x07);
#endif
- /*
- * This is a critical section, since we don't want the interrupt
- * routine mucking with the host data or the card. For this reason
- * it is nice to know that this function can only be called in one
- * of two ways from scsi.c First, as part of a routine queue command,
- * in which case, the irq for our card is disabled before this
- * function is called. This doesn't help us if there is more than
- * one card using more than one IRQ in our system, therefore, we
- * should disable all interrupts on these grounds alone. Second,
- * this can be called as part of the scsi_done routine, in which case
- * we are in the aic7xxx_isr routine already and interrupts are
- * disabled, therefore we should saveflags first, then disable the
- * interrupts, do our work, then restore the CPU flags. If it weren't
- * for the possibility of more than one card using more than one IRQ
- * in our system, we wouldn't have to touch the interrupt flags at all.
- */
- save_flags(processor_flags);
- cli();
-
+ if (p->device_status[TARGET_INDEX(cmd)].active_cmds
+ > cmd->device->queue_depth)
+ {
+ printk(KERN_WARNING "(scsi%d:%d:%d) Commands queued exceeds queue depth\n",
+ p->host_no, cmd->target, cmd->channel);
+ }
scb = aic7xxx_allocate_scb(p);
if (scb == NULL)
{
- panic("aic7xxx: (aic7xxx_free) Couldn't find a free SCB.\n");
+ panic("aic7xxx: (aic7xxx_queue) Couldn't find a free SCB.\n");
}
else
{
scb->cmd = cmd;
- aic7xxx_position(cmd) = scb->tag;
+ aic7xxx_position(cmd) = scb->hscb->tag;
#if 0
debug_scb(scb);
#endif;
@@ -5179,14 +6441,14 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
aic7xxx_buildscb(p, cmd, scb);
#if 0
- if (scb != (p->scb_array[scb->position]))
+ if (scb != (p->scb_data->scb_array[scb->hscb->tag]))
{
printk("aic7xxx: (queue) Address of SCB by position does not match SCB "
"address.\n");
}
printk("aic7xxx: (queue) SCB pos(%d) cmdptr(0x%x) state(%d) freescb(0x%x)\n",
- scb->position, (unsigned int) scb->cmd,
- scb->state, (unsigned int) p->free_scb);
+ scb->hscb->tag, (unsigned int) scb->cmd,
+ scb->flags, (unsigned int) p->free_scb);
#endif
/*
@@ -5201,70 +6463,28 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
cmd->host_scribble = NULL;
memset(&cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
- if (scb->position != SCB_LIST_NULL)
- {
- /* We've got a valid slot, yeah! */
- if (p->flags & IN_ISR)
- {
- scbq_insert_tail(&p->assigned_scbs, scb);
- scb->state |= SCB_ASSIGNEDQ;
- }
- else
- {
- /*
- * Pause the sequencer so we can play with its registers -
- * wait for it to acknowledge the pause.
- *
- * XXX - should the interrupts be left on while doing this?
- */
- PAUSE_SEQUENCER(p);
- intstat = inb(INTSTAT + p->base);
-
- /*
- * Save the SCB pointer and put our own pointer in - this
- * selects one of the four banks of SCB registers. Load
- * the SCB, then write its pointer into the queue in FIFO
- * and restore the saved SCB pointer.
- */
- curscb = inb(SCBPTR + p->base);
- outb(scb->position, SCBPTR + p->base);
- aic7xxx_putscb(p, scb);
- outb(curscb, SCBPTR + p->base);
- outb(scb->position, QINFIFO + p->base);
- scb->state |= SCB_ACTIVE;
+ scb->flags |= SCB_ACTIVE | SCB_WAITINGQ;
- /*
- * Guard against unpausing the sequencer if there is an interrupt
- * waiting to happen.
- */
- if (!(intstat & (BRKADRINT | SEQINT | SCSIINT)))
- {
- UNPAUSE_SEQUENCER(p);
- }
- }
- }
- else
+ save_flags(processor_flags);
+ cli();
+ scbq_insert_tail(&p->waiting_scbs, scb);
+ if ((p->flags & (IN_ISR | IN_TIMEOUT)) == 0)
{
- scb->state |= SCB_WAITINGQ;
- scbq_insert_tail(&p->waiting_scbs, scb);
- if (!(p->flags & IN_ISR))
- {
- aic7xxx_run_waiting_queues(p);
- }
+ aic7xxx_run_waiting_queues(p);
}
+ restore_flags(processor_flags);
#if 0
printk("aic7xxx: (queue) After - cmd(0x%lx) scb->cmd(0x%lx) pos(%d).\n",
- (long) cmd, (long) scb->cmd, scb->position);
+ (long) cmd, (long) scb->cmd, scb->hscb->tag);
#endif;
- restore_flags(processor_flags);
}
return (0);
}
/*+F*************************************************************************
* Function:
- * aic7xxx_abort_reset
+ * aic7xxx_bus_device_reset
*
* Description:
* Abort or reset the current SCSI command(s). If the scb has not
@@ -5276,204 +6496,257 @@ aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
static int
aic7xxx_bus_device_reset(struct aic7xxx_host *p, Scsi_Cmnd *cmd)
{
- struct aic7xxx_scb *scb;
+ struct aic7xxx_scb *scb;
+ struct aic7xxx_hwscb *hscb;
unsigned char bus_state;
- int base, result = -1;
+ int result = -1;
char channel;
- scb = (p->scb_array[aic7xxx_position(cmd)]);
- base = p->base;
+ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
+ hscb = scb->hscb;
- channel = scb->target_channel_lun & SELBUSB ? 'B': 'A';
- if ((cmd == scb->cmd) && (scb->state & SCB_IN_PROGRESS))
+ /*
+ * Ensure that the card doesn't do anything behind our back.
+ * Also make sure that we didn't just miss an interrupt that
+ * could affect this abort/reset.
+ */
+ pause_sequencer(p);
+ while (inb(p->base + INTSTAT) & INT_PEND);
{
+ aic7xxx_isr(p->irq, (void *) NULL, (void *) NULL);
+ pause_sequencer(p);
+ }
+ if ((cmd != scb->cmd) || ((scb->flags & SCB_ACTIVE) == 0))
+ {
+ result = SCSI_RESET_NOT_RUNNING;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ return(result);
+ }
+
- if (scb->state & SCB_IN_PROGRESS)
+ printk(KERN_WARNING "(scsi%d:%d:%d) Abort_reset, scb flags 0x%x, ",
+ p->host_no, TC_OF_SCB(scb), scb->flags);
+ bus_state = inb(p->base + LASTPHASE);
+
+ switch (bus_state)
+ {
+ case P_DATAOUT:
+ printk("Data-Out phase, ");
+ break;
+ case P_DATAIN:
+ printk("Data-In phase, ");
+ break;
+ case P_COMMAND:
+ printk("Command phase, ");
+ break;
+ case P_MESGOUT:
+ printk("Message-Out phase, ");
+ break;
+ case P_STATUS:
+ printk("Status phase, ");
+ break;
+ case P_MESGIN:
+ printk("Message-In phase, ");
+ break;
+ default:
+ /*
+ * We're not in a valid phase, so assume we're idle.
+ */
+ printk("while idle, LASTPHASE = 0x%x, ", bus_state);
+ break;
+ }
+ printk("SCSISIGI 0x%x, SEQADDR 0x%x, SSTAT0 0x%x, SSTAT1 0x%x\n",
+ inb(p->base + SCSISIGI),
+ inb(p->base + SEQADDR0) | (inb(p->base + SEQADDR1) << 8),
+ inb(p->base + SSTAT0), inb(p->base + SSTAT1));
+
+ channel = hscb->target_channel_lun & SELBUSB ? 'B': 'A';
+ /*
+ * Determine our course of action.
+ */
+ if (scb->flags & SCB_ABORT)
+ {
+ /*
+ * Been down this road before; do a full bus reset.
+ */
+ scb->flags |= SCB_RECOVERY_SCB;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ result = -1;
+ }
+#if 0
+ else if (hscb->control & TAG_ENB)
{
/*
- * Ensure that the card doesn't do anything
- * behind our back.
+ * We could be starving this command; try sending and ordered tag
+ * command to the target we come from.
*/
- PAUSE_SEQUENCER(p);
+ scb->flags |= SCB_SENTORDEREDTAG | SCB_RECOVERY_SCB;
+ p->orderedtag = p->orderedtag | 0xFF;
+ result = SCSI_RESET_PENDING;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ printk(KERN_WARNING "scsi%d: Abort_reset, odered tag queued.\n",
+ p->host_no);
+ }
+#endif
+ else
+ {
+ unsigned char active_scb_index, saved_scbptr;
+ struct aic7xxx_scb *active_scb;
- printk(KERN_WARNING "aic7xxx: (abort_reset) scb state 0x%x, ", scb->state);
- bus_state = inb(LASTPHASE + p->base);
+ /*
+ * Send an Abort Message:
+ * The target that is holding up the bus may not be the same as
+ * the one that triggered this timeout (different commands have
+ * different timeout lengths). Our strategy here is to queue an
+ * abort message to the timed out target if it is disconnected.
+ * Otherwise, if we have an active target we stuff the message buffer
+ * with an abort message and assert ATN in the hopes that the target
+ * will let go of the bus and go to the mesgout phase. If this
+ * fails, we'll get another timeout a few seconds later which will
+ * attempt a bus reset.
+ */
+ saved_scbptr = inb(p->base + SCBPTR);
+ active_scb_index = inb(p->base + SCB_TAG);
+ active_scb = p->scb_data->scb_array[active_scb_index];
- switch (bus_state)
+ if (bus_state != P_BUSFREE)
+ {
+ if (active_scb_index >= p->scb_data->numscbs)
{
- case P_DATAOUT:
- printk("Data-Out phase, ");
- break;
- case P_DATAIN:
- printk("Data-In phase, ");
- break;
- case P_COMMAND:
- printk("Command phase, ");
- break;
- case P_MESGOUT:
- printk("Message-Out phase, ");
- break;
- case P_STATUS:
- printk("Status phase, ");
- break;
- case P_MESGIN:
- printk("Message-In phase, ");
- break;
- default:
- printk("while idle, LASTPHASE = 0x%x, ", bus_state);
- /*
- * We're not in a valid phase, so assume we're idle.
- */
- bus_state = 0;
- break;
+ /*
+ * Perform a bus reset.
+ *
+ * XXX - We want to queue an abort for the timedout SCB
+ * instead.
+ */
+ result = -1;
+ printk(KERN_WARNING "scsi%d: Invalid SCB ID %d is active, "
+ "SCB flags = 0x%x.\n", p->host_no, scb->hscb->tag, scb->flags);
}
- printk("SCSISIGI = 0x%x\n", inb(p->base + SCSISIGI));
-
- /*
- * First, determine if we want to do a bus reset or simply a bus device
- * reset. If this is the first time that a transaction has timed out
- * and the SCB is not paged out, just schedule a bus device reset.
- * Otherwise, we reset the bus and abort all pending I/Os on that bus.
- */
- if (!(scb->state & (SCB_ABORTED | SCB_PAGED_OUT)))
+ else
{
-#if 0
- if (scb->control & TAG_ENB)
- {
+ /* Send the abort message to the active SCB. */
+ outb(1, p->base + MSG_LEN);
+ if (active_scb->hscb->control & TAG_ENB)
+ {
+ outb(MSG_ABORT_TAG, p->base + MSG_OUT);
+ }
+ else
+ {
+ outb(MSG_ABORT, p->base + MSG_OUT);
+ }
+ outb(bus_state | ATNO, p->base + SCSISIGO);
+ printk(KERN_WARNING "scsi%d: abort message in message buffer\n",
+ p->host_no);
+ active_scb->flags |= SCB_ABORT | SCB_RECOVERY_SCB;
+ if (active_scb != scb)
+ {
/*
- * We could be starving this command; try sending and ordered tag
- * command to the target we come from.
+ * XXX - We would like to increment the timeout on scb, but
+ * access to that routine is denied because it is hidden
+ * in scsi.c. If we were able to do this, it would give
+ * scb a new lease on life.
*/
- scb->state = scb->state | SCB_ABORTED | SCB_SENTORDEREDTAG;
- p->orderedtag = p->orderedtag | 0xFF;
result = SCSI_RESET_PENDING;
- UNPAUSE_SEQUENCER(p);
- printk(KERN_WARNING "aic7xxx: (abort_reset) Ordered tag queued.\n");
- }
-#endif
- unsigned char active_scb, control;
- struct aic7xxx_scb *active_scbp;
+ aic7xxx_error(active_scb->cmd) = DID_RESET;
+ }
+ else
+ {
+ aic7xxx_error(scb->cmd) = DID_RESET;
+ result = SCSI_RESET_PENDING;
+ }
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ }
+ }
+ else
+ {
+ unsigned char hscb_index, linked_next;
+ int disconnected;
- /*
- * Send a Bus Device Reset Message:
- * The target we select to send the message to may be entirely
- * different than the target pointed to by the scb that timed
- * out. If the command is in the QINFIFO or the waiting for
- * selection list, its not tying up the bus and isn't responsible
- * for the delay so we pick off the active command which should
- * be the SCB selected by SCBPTR. If its disconnected or active,
- * we device reset the target scbp points to. Although it may
- * be that this target is not responsible for the delay, it may
- * may also be that we're timing out on a command that just takes
- * too much time, so we try the bus device reset there first.
- */
- active_scb = inb(SCBPTR + base);
- active_scbp = (p->scb_array[inb(SCB_TAG + base)]);
- control = inb(SCB_CONTROL + base);
+ disconnected = FALSE;
+ hscb_index = aic7xxx_find_scb(p, scb);
+ if (hscb_index == SCB_LIST_NULL)
+ {
+ disconnected = TRUE;
+ linked_next = (scb->hscb->data_count >> 24) & 0xFF;
+ }
+ else
+ {
+ outb(hscb_index, p->base + SCBPTR);
+ if (inb(p->base + SCB_CONTROL) & DISCONNECTED)
+ {
+ disconnected = TRUE;
+ }
+ linked_next = inb(p->base + SCB_LINKED_NEXT);
+ }
+ if (disconnected)
+ {
+ /*
+ * Simply set the ABORT_SCB control bit and preserve the
+ * linked next pointer.
+ */
+ scb->hscb->control |= ABORT_SCB | MK_MESSAGE;
+ scb->hscb->data_count &= ~0xFF000000;
+ scb->hscb->data_count |= linked_next << 24;
+ if ((p->flags & PAGE_ENABLED) == 0)
+ {
+ scb->hscb->control &= ~DISCONNECTED;
+ }
+ scb->flags |= SCB_QUEUED_ABORT | SCB_ABORT | SCB_RECOVERY_SCB;
+ if (hscb_index != SCB_LIST_NULL)
+ {
+ unsigned char scb_control;
- /*
- * Test to see if scbp is disconnected
- */
- outb(scb->position, SCBPTR + base);
- if (inb(SCB_CONTROL + base) & DISCONNECTED)
- {
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (abort_scb) scb %d is disconnected; "
- "bus device reset message queued.\n", scb->position);
-#endif
- if (p->flags & PAGE_ENABLED)
- {
- /* Pull this SCB out of the disconnected list. */
- u_char prev = inb(SCB_PREV + base);
- u_char next = inb(SCB_NEXT + base);
- if (prev == SCB_LIST_NULL)
- {
- /* Head of list */
- outb(next, DISCONNECTED_SCBH + base);
- }
- else
- {
- outb(prev, SCBPTR + base);
- outb(next, SCB_NEXT + base);
- if (next != SCB_LIST_NULL)
- {
- outb(next, SCBPTR + base);
- outb(prev, SCB_PREV + base);
- }
- outb(scb->position, SCBPTR + base);
- }
- }
- scb->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
- scb->control = scb->control & DISCENB;
- scb->SCSI_cmd_length = 0;
- scb->SG_segment_count = 0;
- memset(scb->SG_list_pointer, 0, sizeof(scb->SG_list_pointer));
- memset(scb->data_pointer, 0, sizeof(scb->data_pointer));
- scb->data_count = 0;
- aic7xxx_putscb(p, scb);
- aic7xxx_add_waiting_scb(base, scb);
- outb(active_scb, SCBPTR + base);
- result = SCSI_RESET_PENDING;
- UNPAUSE_SEQUENCER(p);
- }
- else
- {
- /*
- * Is the active SCB really active?
- */
- if ((active_scbp->state & SCB_ACTIVE) && bus_state)
- {
- /*
- * Load the message buffer and assert attention.
- */
- active_scbp->state |= (SCB_DEVICE_RESET | SCB_ABORTED);
- outb(1, MSG_LEN + base);
- outb(MSG_BUS_DEVICE_RESET, MSG0 + base);
- outb(bus_state | ATNO, SCSISIGO + base);
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (abort_scb) asserted ATN - "
- "bus device reset in message buffer.\n");
-#endif
- if (active_scbp != scb)
- {
- /*
- * XXX - We would like to increment the timeout on scb, but
- * access to that routine is denied because it is hidden
- * in scsi.c. If we were able to do this, it would give
- * scb a new lease on life.
- */
- ;
- }
- aic7xxx_error(scb->cmd) = DID_RESET;
- /*
- * Restore the active SCB and unpause the sequencer.
- */
- outb(active_scb, SCBPTR + base);
- if (active_scbp != scb)
- {
- /*
- * The mid-level SCSI code requested us to reset a command
- * different from the one that we actually reset. Return
- * a "not running" indication and hope that the SCSI code
- * will Do the Right Thing (tm).
- */
- result = SCSI_RESET_NOT_RUNNING;
- }
- else
- {
- result = SCSI_RESET_PENDING;
- }
- UNPAUSE_SEQUENCER(p);
- }
- }
+ scb_control = inb(p->base + SCB_CONTROL);
+ outb(scb_control | MK_MESSAGE| ABORT_SCB, p->base + SCB_CONTROL);
+ }
+ /*
+ * Actually requeue this SCB in case we can select the
+ * device before it reconnects. If the transaction we
+ * want to abort is not tagged, unbusy it first so that
+ * we don't get held back from sending the command.
+ */
+ if ((scb->hscb->control & TAG_ENB) == 0)
+ {
+ unsigned char target;
+ int lun;
+
+ target = scb->cmd->target;
+ lun = scb->cmd->lun;
+ aic7xxx_search_qinfifo(p, target, channel, lun, SCB_LIST_NULL,
+ 0, /* requeue */ TRUE);
+ }
+ printk(KERN_WARNING "(scsi%d:%d:%d) Queueing an Abort SCB.\n",
+ p->host_no, TC_OF_SCB(scb));
+ scbq_insert_head(&p->waiting_scbs, scb);
+ scb->flags |= SCB_WAITINGQ;
+ outb(saved_scbptr, p->base + SCBPTR);
+ if ((p->flags & IN_ISR) == 0)
+ {
+ /*
+ * Processing the waiting queue may unpause us.
+ */
+ aic7xxx_run_waiting_queues(p);
+ /*
+ * If we are using AAP, aic7xxx_run_waiting_queues() will not
+ * unpause us, so ensure we are unpaused.
+ */
+ unpause_sequencer(p, /*unpause_always*/ FALSE);
+ }
+ else
+ {
+ unpause_sequencer(p, /*unpause_always*/ TRUE);
+ }
+ result = SCSI_RESET_PENDING;
+ }
+ else
+ {
+ scb->flags |= SCB_RECOVERY_SCB;
+ unpause_sequencer(p, /* unpause_always */ TRUE);
+ result = -1;
}
}
}
- /* Make sure the sequencer is unpaused upon return. */
- if (result == -1)
- {
- UNPAUSE_SEQUENCER(p);
- }
return (result);
}
@@ -5491,16 +6764,48 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p;
int base, result;
+ unsigned long processor_flags;
p = (struct aic7xxx_host *) cmd->host->hostdata;
- scb = (p->scb_array[aic7xxx_position(cmd)]);
+ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
base = p->base;
+ save_flags(processor_flags);
+ cli();
+
#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (abort) Aborting scb %d, TCL %d/%d/%d\n",
- scb->position, TCL_OF_SCB(scb));
+ if (scb != NULL)
+ {
+ printk("(scsi%d:%d:%d) Aborting scb %d, flags 0x%x\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+ }
+ else
+ {
+ printk("aic7xxx: Abort called with no SCB for cmd.\n");
+ }
#endif
+ if (p->flags & IN_TIMEOUT)
+ {
+ /*
+ * We've already started a recovery operation.
+ */
+ if ((scb->flags & SCB_RECOVERY_SCB) == 0)
+ {
+ restore_flags(processor_flags);
+ return (SCSI_ABORT_PENDING);
+ }
+ else
+ {
+ /*
+ * This is the second time we've tried to abort the recovery
+ * SCB. We want the mid-level SCSI code to call the reset
+ * function to reset the SCSI bus.
+ */
+ restore_flags(processor_flags);
+ return (SCSI_ABORT_NOT_RUNNING);
+ }
+ }
if (cmd->serial_number != cmd->serial_number_at_timeout)
{
result = SCSI_ABORT_NOT_RUNNING;
@@ -5509,14 +6814,34 @@ aic7xxx_abort(Scsi_Cmnd *cmd)
{
result = SCSI_ABORT_NOT_RUNNING;
}
- else if ((scb->cmd != cmd) || (!(scb->state & SCB_IN_PROGRESS)))
+ else if ((scb->cmd != cmd) || (!(scb->flags & SCB_ACTIVE)))
{
result = SCSI_ABORT_NOT_RUNNING;
}
else
{
- result = SCSI_ABORT_SNOOZE;
+ /*
+ * XXX - Check use of IN_TIMEOUT to see if we're Doing the
+ * Right Thing with it.
+ */
+ p->flags |= IN_TIMEOUT;
+ result = aic7xxx_bus_device_reset(p, scb->cmd);
+ switch (result)
+ {
+ case SCSI_RESET_NOT_RUNNING:
+ p->flags &= ~IN_TIMEOUT;
+ result = SCSI_ABORT_NOT_RUNNING;
+ break;
+ case SCSI_RESET_PENDING:
+ result = SCSI_ABORT_PENDING;
+ break;
+ default:
+ p->flags &= ~IN_TIMEOUT;
+ result = SCSI_ABORT_SNOOZE;
+ break;
+ }
}
+ restore_flags(processor_flags);
return (result);
}
@@ -5536,18 +6861,27 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
{
struct aic7xxx_scb *scb = NULL;
struct aic7xxx_host *p;
- int base, found, tindex, min_target, max_target, result = -1;
+ int base, found, tindex, min_target, max_target;
+ int result = -1;
char channel = 'A';
unsigned long processor_flags;
p = (struct aic7xxx_host *) cmd->host->hostdata;
- scb = (p->scb_array[aic7xxx_position(cmd)]);
+ scb = (p->scb_data->scb_array[aic7xxx_position(cmd)]);
base = p->base;
channel = cmd->channel ? 'B': 'A';
tindex = (cmd->channel << 4) | cmd->target;
-#ifdef AIC7XXX_DEBUG_ABORT
- printk("aic7xxx: (reset) target/channel %d/%d\n", cmd->target, cmd->channel);
+#ifdef 0 /* AIC7XXX_DEBUG_ABORT */
+ if (scb != NULL)
+ {
+ printk("(scsi%d:%d:%d) Reset called, scb %d, flags 0x%x\n",
+ p->host_no, TC_OF_SCB(scb), scb->hscb->tag, scb->flags);
+ }
+ else
+ {
+ printk("aic7xxx: Reset called with no SCB for cmd.\n");
+ }
#endif
/*
@@ -5562,34 +6896,45 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
if (scb->cmd != cmd)
scb = NULL;
- if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
- && (scb != NULL))
+ if (p->flags & IN_TIMEOUT)
{
/*
- * Attempt a bus device reset if commands have completed successfully
- * since the last bus device reset, or it has been less than 100ms
- * since the last reset.
+ * We've already started a recovery operation.
*/
- if ((p->flags & DEVICE_SUCCESS) ||
- ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
+ if ((scb->flags & SCB_RECOVERY_SCB) == 0)
{
- if (cmd->serial_number != cmd->serial_number_at_timeout)
- {
- result = SCSI_RESET_NOT_RUNNING;
- }
- else
+ restore_flags(processor_flags);
+ return (SCSI_RESET_PENDING);
+ }
+ }
+ else
+ {
+ if (!(flags & (SCSI_RESET_SUGGEST_HOST_RESET | SCSI_RESET_SUGGEST_BUS_RESET))
+ && (scb != NULL))
+ {
+ /*
+ * Attempt a bus device reset if commands have completed successfully
+ * since the last bus device reset, or it has been less than 100ms
+ * since the last reset.
+ */
+ if ((p->flags & DEVICE_SUCCESS) ||
+ ((jiffies - p->device_status[tindex].last_reset) < HZ/10))
{
- if (scb == NULL)
+ if (cmd->serial_number != cmd->serial_number_at_timeout)
+ {
+ result = SCSI_RESET_NOT_RUNNING;
+ }
+ else if (scb == NULL)
{
result = SCSI_RESET_NOT_RUNNING;
}
else if (flags & SCSI_RESET_ASYNCHRONOUS)
{
- if (scb->state & SCB_ABORTED)
+ if (scb->flags & SCB_ABORTED)
{
result = SCSI_RESET_PENDING;
}
- else if (!(scb->state & SCB_IN_PROGRESS))
+ else if (!(scb->flags & SCB_ACTIVE))
{
result = SCSI_RESET_NOT_RUNNING;
}
@@ -5600,20 +6945,23 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
if ((flags & SCSI_RESET_SYNCHRONOUS) &&
(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING))
{
- scb->state |= SCB_ABORTED;
+ scb->flags |= SCB_ABORTED;
result = SCSI_RESET_PENDING;
}
else
{
+ p->flags |= IN_TIMEOUT;
result = aic7xxx_bus_device_reset(p, cmd);
if (result == 0)
+ {
+ p->flags &= ~IN_TIMEOUT;
result = SCSI_RESET_PENDING;
+ }
}
- }
+ }
}
}
}
-
if (result == -1)
{
/*
@@ -5626,11 +6974,11 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
{
result = SCSI_RESET_NOT_RUNNING;
}
- else if (!(scb->state & SCB_IN_PROGRESS))
+ else if (!(scb->flags & SCB_ACTIVE))
{
result = SCSI_RESET_NOT_RUNNING;
}
- else if ((scb->state & SCB_ABORTED) &&
+ else if ((scb->flags & SCB_ABORTED) &&
(!(p->device_status[tindex].flags & BUS_DEVICE_RESET_PENDING)))
{
result = SCSI_RESET_PENDING;
@@ -5642,8 +6990,9 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
/*
* The reset channel function assumes that the sequencer is paused.
*/
- PAUSE_SEQUENCER(p);
+ pause_sequencer(p);
found = aic7xxx_reset_channel(p, channel, TRUE);
+ p->flags = p->flags & ~IN_TIMEOUT;
/*
* If this is a synchronous reset and there is no SCB for this
@@ -5689,8 +7038,10 @@ aic7xxx_reset(Scsi_Cmnd *cmd, unsigned int flags)
}
result = SCSI_RESET_SUCCESS | SCSI_RESET_HOST_RESET;
+ p->flags &= ~IN_TIMEOUT;
}
}
+ aic7xxx_run_waiting_queues(p);
restore_flags(processor_flags);
return (result);
}
diff --git a/drivers/scsi/aic7xxx.h b/drivers/scsi/aic7xxx.h
index d4de8fd83..11836c405 100644
--- a/drivers/scsi/aic7xxx.h
+++ b/drivers/scsi/aic7xxx.h
@@ -18,12 +18,12 @@
* along with this program; see the file COPYING. If not, write to
* the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Id: aic7xxx.h,v 3.2 1996/07/23 03:37:26 deang Exp $
+ * $Id: aic7xxx.h,v 1.1.1.1 1997/06/01 03:17:41 ralf Exp $
*-M*************************************************************************/
#ifndef _aic7xxx_h
#define _aic7xxx_h
-#define AIC7XXX_H_VERSION "$Revision: 3.2 $"
+#define AIC7XXX_H_VERSION "$Revision: 1.1.1.1 $"
/*
* Scsi_Host_Template (see hosts.h) for AIC-7xxx - some fields
@@ -40,13 +40,13 @@
aic7xxx_info, \
NULL, \
aic7xxx_queue, \
- aic7xxx_abort, \
+ NULL, \
aic7xxx_reset, \
NULL, \
aic7xxx_biosparam, \
-1, /* max simultaneous cmds */\
-1, /* scsi id of host adapter */\
- SG_ALL, /* max scatter-gather cmds */\
+ 0, /* max scatter-gather cmds */\
2, /* cmds per lun (linked cmds) */\
0, /* number of 7xxx's present */\
0, /* no memory DMA restrictions */\
@@ -57,7 +57,6 @@ 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/aic7xxx.seq b/drivers/scsi/aic7xxx.seq
index 98d4b9545..e69de29bb 100644
--- a/drivers/scsi/aic7xxx.seq
+++ b/drivers/scsi/aic7xxx.seq
@@ -1,1127 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx device driver for Linux and FreeBSD.
- *
- * Copyright (c) 1994 John Aycock
- * The University of Calgary Department of Computer Science.
- *
- *Modifications/enhancements:
- * Copyright (c) 1994, 1995, 1996 Justin Gibbs. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * FreeBSD, Twin, Wide, 2 command per target support, tagged queuing and other
- * optimizations provided by Justin T. Gibbs (gibbs@FreeBSD.org)
- *
- * This version corresponds to version 1.42 of FreeBSDs aic7xxx.seq.
- *
- *-M*************************************************************************/
-
-VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 4.0 1996/10/13 08:23:42 deang Exp $"
-
-#ifdef linux
-#include "aic7xxx_reg.h"
-#else
-#if defined(__NetBSD__)
-#include "../../../../dev/ic/aic7xxxreg.h"
-#elif defined(__FreeBSD__)
-#include "../../dev/aic7xxx/aic7xxx_reg.h"
-#endif
-#endif
-
-/*
- * We can't just use ACCUM in the sequencer code because it
- * must be treated specially by the assembler, and it currently
- * looks for the symbol 'A'. This is the only register defined in
- * the assembler's symbol space.
- */
-A = ACCUM
-
-/* After starting the selection hardware, we check for reconnecting targets
- * as well as for our selection to complete just in case the reselection wins
- * bus arbitration. The problem with this is that we must keep track of the
- * SCB that we've already pulled from the QINFIFO and started the selection
- * on just in case the reselection wins so that we can retry the selection at
- * a later time. This problem cannot be resolved by holding a single entry
- * in scratch ram since a reconnecting target can request sense and this will
- * create yet another SCB waiting for selection. The solution used here is to
- * use byte 27 of the SCB as a pseudo-next pointer and to thread a list
- * of SCBs that are awaiting selection. Since 0-0xfe are valid SCB offsets,
- * SCB_LIST_NULL is 0xff which is out of range. The kernel driver must
- * add an entry to this list every time a request sense occurs. The sequencer
- * will automatically consume the entries.
- */
-
-/*
- * We assume that the kernel driver may reset us at any time, even in the
- * middle of a DMA, so clear DFCNTRL too.
- */
-reset:
- clr DFCNTRL
- clr SCSISIGO /* De-assert BSY */
-/*
- * We jump to start after every bus free.
- */
-start:
- and FLAGS,0x0f /* clear target specific flags */
- mvi SCSISEQ,ENRSELI /* Always allow reselection */
- clr SCSIRATE /*
- * We don't know the target we will
- * connect to, so default to narrow
- * transfers to avoid parity problems.
- */
-poll_for_work:
- /*
- * Are we a twin channel device?
- * For fairness, we check the other bus first,
- * since we just finished a transaction on the
- * current channel.
- */
- test FLAGS,TWIN_BUS jz start2
- xor SBLKCTL,SELBUSB /* Toggle to the other bus */
- test SSTAT0,SELDI jnz reselect
- xor SBLKCTL,SELBUSB /* Toggle to the original bus */
-start2:
- test SSTAT0,SELDI jnz reselect
- cmp WAITING_SCBH,SCB_LIST_NULL jne start_waiting
- mov A, QCNTMASK
- test QINCNT,A jz poll_for_work
-
-/*
- * We have at least one queued SCB now and we don't have any
- * SCBs in the list of SCBs awaiting selection. Set the SCB
- * pointer from the FIFO so we see the right bank of SCB
- * registers.
- */
- mov SCBPTR,QINFIFO
-
-/*
- * See if there is not already an active SCB for this target. This code
- * locks out on a per target basis instead of target/lun. Although this
- * is not ideal for devices that have multiple luns active at the same
- * time, it is faster than looping through all SCB's looking for active
- * commands. It may be beneficial to make findscb a more general procedure
- * to see if the added cost of the search is negligible. This code also
- * assumes that the kernel driver will clear the active flags on board
- * initialization, board reset, and a target SELTO. Tagged commands
- * don't set the active bits since you can queue more than one command
- * at a time. We do, however, look to see if there are any non-tagged
- * I/Os in progress, and requeue the command if there are. Tagged and
- * non-tagged commands cannot be mixed to a single target.
- */
-
-test_busy:
- mov FUNCTION1,SCB_TCL
- mov A,FUNCTION1
- test SCB_TCL,0x88 jz test_a /* Id < 8 && A channel */
-
- test ACTIVE_B,A jnz requeue
- test SCB_CONTROL,TAG_ENB jnz start_scb
- /* Mark the current target as busy */
- or ACTIVE_B,A
- jmp start_scb
-
-/* Place the currently active SCB back on the queue for later processing */
-requeue:
- mov QINFIFO, SCBPTR
- jmp poll_for_work
-
-/*
- * Pull the first entry off of the waiting for selection list
- * We don't have to "test_busy" because only transactions that
- * have passed that test can be in the waiting_scb list.
- */
-start_waiting:
- mov SCBPTR,WAITING_SCBH
- jmp start_scb2
-
-test_a:
- test ACTIVE_A,A jnz requeue
- test SCB_CONTROL,TAG_ENB jnz start_scb
- /* Mark the current target as busy */
- or ACTIVE_A,A
-
-start_scb:
- mov SCB_NEXT,WAITING_SCBH
- mov WAITING_SCBH, SCBPTR
-start_scb2:
- and SINDEX,0xf7,SBLKCTL /* Clear the channel select bit */
- and A,0x08,SCB_TCL /* Get new channel bit */
- or SINDEX,A
- mov SBLKCTL,SINDEX /* select channel */
- mov SCB_TCL call initialize_scsiid
-
-/*
- * Enable selection phase as an initiator, and do automatic ATN
- * after the selection. We do this now so that we can overlap the
- * rest of our work to set up this target with the arbitration and
- * selection bus phases.
- */
-start_selection:
- mvi SCSISEQ,0x58 /* ENSELO|ENAUTOATNO|ENRSELI */
-
-/*
- * As soon as we get a successful selection, the target should go
- * into the message out phase since we have ATN asserted. Prepare
- * the message to send.
- *
- * Messages are stored in scratch RAM starting with a length byte
- * followed by the message itself.
- */
- test SCB_CMDLEN,0xff jnz mk_identify /* 0 Length Command? */
-
-/*
- * The kernel has sent us an SCB with no command attached. This implies
- * that the kernel wants to send a message of some sort to this target,
- * so we interrupt the driver, allow it to fill the message buffer, and
- * then go back into the arbitration loop
- */
- mvi INTSTAT,AWAITING_MSG
- jmp wait_for_selection
-
-mk_identify:
- and A,DISCENB,SCB_CONTROL /* mask off disconnect privledge */
-
- and MSG0,0x7,SCB_TCL /* lun */
- or MSG0,A /* or in disconnect privledge */
- or MSG0,MSG_IDENTIFY
- mvi MSG_LEN, 1
-
- test SCB_CONTROL,0xb0 jz !message /* WDTR, SDTR or TAG?? */
-/*
- * Send a tag message if TAG_ENB is set in the SCB control block.
- * Use SCB_TAG (the position in the kernel's SCB array) as the tag value.
- */
-
-mk_tag:
- mvi DINDEX, MSG1
- test SCB_CONTROL,TAG_ENB jz mk_tag_done
- and DINDIR,0x23,SCB_CONTROL
- mov DINDIR,SCB_TAG
-
- add MSG_LEN,COMP_MSG0,DINDEX /* update message length */
-
-mk_tag_done:
-
- test SCB_CONTROL,0x90 jz !message /* NEEDWDTR|NEEDSDTR */
- mov DINDEX call mk_dtr /* build DTR message if needed */
-
-!message:
-wait_for_selection:
- test SSTAT0,SELDO jnz select
- test SSTAT0,SELDI jz wait_for_selection
-
-/*
- * Reselection has been initiated by a target. Make a note that we've been
- * reselected, but haven't seen an IDENTIFY message from the target
- * yet.
- */
-reselect:
- clr MSG_LEN /* Don't have anything in the mesg buffer */
- mov SELID call initialize_scsiid
- or FLAGS,RESELECTED
- jmp select2
-
-/*
- * After the selection, remove this SCB from the "waiting for selection"
- * list. This is achieved by simply moving our "next" pointer into
- * WAITING_SCBH. Our next pointer will be set to null the next time this
- * SCB is used, so don't bother with it now.
- */
-select:
- mov WAITING_SCBH,SCB_NEXT
- or FLAGS,SELECTED
-select2:
-/*
- * Set CLRCHN here before the target has entered a data transfer mode -
- * with synchronous SCSI, if you do it later, you blow away some
- * data in the SCSI FIFO that the target has already sent to you.
- */
- or SXFRCTL0,CLRCHN
-/*
- * Initialize SCSIRATE with the appropriate value for this target.
- */
- call ndx_dtr
- mov SCSIRATE,SINDIR
-
-/*
- * Initialize Ultra mode setting.
- */
- mov FUNCTION1,SCSIID
- mov A,FUNCTION1
- and SINDEX,0xdf,SXFRCTL0 /* default to Ultra disabled */
- test SCSIID, 0x80 jnz ultra_b /* Target ID > 7 */
- test SBLKCTL, SELBUSB jnz ultra_b /* Second channel device */
- test ULTRA_ENB,A jz set_sxfrctl0
- or SINDEX, ULTRAEN jmp set_sxfrctl0
-ultra_b:
- test ULTRA_ENB_B,A jz set_sxfrctl0
- or SINDEX, ULTRAEN
-
-set_sxfrctl0:
- mov SXFRCTL0,SINDEX
-
- mvi SCSISEQ,ENAUTOATNP /*
- * ATN on parity errors
- * for "in" phases
- */
- mvi CLRSINT1,CLRBUSFREE
- mvi CLRSINT0,0x60 /* CLRSELDI|CLRSELDO */
-/*
- * Main loop for information transfer phases. If BSY is false, then
- * we have a bus free condition, expected or not. Otherwise, wait
- * for the target to assert REQ before checking MSG, C/D and I/O
- * for the bus phase.
- *
- */
-ITloop:
- test SSTAT1,BUSFREE jnz p_busfree
- test SSTAT1,REQINIT jz ITloop
-
- and A,PHASE_MASK,SCSISIGI
- mov LASTPHASE,A
- mov SCSISIGO,A
-
- cmp ALLZEROS,A je p_dataout
- cmp A,P_DATAIN je p_datain
- cmp A,P_COMMAND je p_command
- cmp A,P_MESGOUT je p_mesgout
- cmp A,P_STATUS je p_status
- cmp A,P_MESGIN je p_mesgin
-
- mvi INTSTAT,BAD_PHASE /* unknown phase - signal driver */
- jmp ITloop /* Try reading the bus again. */
-
-p_dataout:
- mvi DMAPARAMS,0x7d /*
- * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
- * DIRECTION|FIFORESET
- */
- jmp data_phase_init
-
-/*
- * If we re-enter the data phase after going through another phase, the
- * STCNT may have been cleared, so restore it from the residual field.
- */
-data_phase_reinit:
- mov STCNT0,SCB_RESID_DCNT0
- mov STCNT1,SCB_RESID_DCNT1
- mov STCNT2,SCB_RESID_DCNT2
- jmp data_phase_loop
-
-p_datain:
- mvi DMAPARAMS,0x79 /*
- * WIDEODD|SCSIEN|SDMAEN|HDMAEN|
- * !DIRECTION|FIFORESET
- */
-data_phase_init:
- call assert
-
- test FLAGS, DPHASE jnz data_phase_reinit
- call sg_scb2ram
- or FLAGS, DPHASE /* We have seen a data phase */
-
-data_phase_loop:
-/* Guard against overruns */
- test SG_COUNT, 0xff jnz data_phase_inbounds
-/*
- * Turn on 'Bit Bucket' mode, set the transfer count to
- * 16meg and let the target run until it changes phase.
- * When the transfer completes, notify the host that we
- * had an overrun.
- */
- or SXFRCTL1,BITBUCKET
- mvi STCNT0,0xff
- mvi STCNT1,0xff
- mvi STCNT2,0xff
-
-data_phase_inbounds:
-/* If we are the last SG block, don't set wideodd. */
- cmp SG_COUNT,0x01 jne data_phase_wideodd
- and DMAPARAMS, 0xbf /* Turn off WIDEODD */
-data_phase_wideodd:
- mov DMAPARAMS call dma
-
-/* Go tell the host about any overruns */
- test SXFRCTL1,BITBUCKET jnz data_phase_overrun
-
-/* Exit if we had an underrun */
- test SSTAT0,SDONE jz data_phase_finish /* underrun STCNT != 0 */
-
-/*
- * Advance the scatter-gather pointers if needed
- */
-sg_advance:
- dec SG_COUNT /* one less segment to go */
-
- test SG_COUNT, 0xff jz data_phase_finish /* Are we done? */
-
- clr A /* add sizeof(struct scatter) */
- add SG_NEXT0,SG_SIZEOF,SG_NEXT0
- adc SG_NEXT1,A,SG_NEXT1
-
-/*
- * Load a struct scatter and set up the data address and length.
- * If the working value of the SG count is nonzero, then
- * we need to load a new set of values.
- *
- * This, like all DMA's, assumes a little-endian host data storage.
- */
-sg_load:
- clr HCNT2
- clr HCNT1
- mvi HCNT0,SG_SIZEOF
-
- mov HADDR0,SG_NEXT0
- mov HADDR1,SG_NEXT1
- mov HADDR2,SG_NEXT2
- mov HADDR3,SG_NEXT3
-
- or DFCNTRL,0xd /* HDMAEN|DIRECTION|FIFORESET */
-
-/*
- * Wait for DMA from host memory to data FIFO to complete, then disable
- * DMA and wait for it to acknowledge that it's off.
- */
-dma_finish:
- test DFSTATUS,HDONE jz dma_finish
- /* Turn off DMA preserving WIDEODD */
- and DFCNTRL,WIDEODD
-dma_finish2:
- test DFCNTRL,HDMAENACK jnz dma_finish2
-
-/*
- * Copy data from FIFO into SCB data pointer and data count. In
- * both FreeBSD and Linux, the scatter list entry is 8 bytes.
- *
- * struct ahc_dma_seg {
- * physaddr addr; four bytes, little-endian order
- * long len; four bytes, little endian order
- * };
- */
-
- mov HADDR0,DFDAT
- mov HADDR1,DFDAT
- mov HADDR2,DFDAT
- mov HADDR3,DFDAT
- mov HCNT0,DFDAT
- mov HCNT1,DFDAT
- mov HCNT2,DFDAT
-
-/* Load STCNT as well. It is a mirror of HCNT */
- mov STCNT0,HCNT0
- mov STCNT1,HCNT1
- mov STCNT2,HCNT2
- test SSTAT1,PHASEMIS jz data_phase_loop
-
-data_phase_finish:
-/*
- * After a DMA finishes, save the SG and STCNT residuals back into the SCB
- * We use STCNT instead of HCNT, since it's a reflection of how many bytes
- * were transferred on the SCSI (as opposed to the host) bus.
- */
- mov SCB_RESID_DCNT0,STCNT0
- mov SCB_RESID_DCNT1,STCNT1
- mov SCB_RESID_DCNT2,STCNT2
- mov SCB_RESID_SGCNT, SG_COUNT
- jmp ITloop
-
-data_phase_overrun:
-/*
- * Turn off BITBUCKET mode and notify the host
- */
- and SXFRCTL1,0x7f /* ~BITBUCKET */
- mvi INTSTAT,DATA_OVERRUN
- jmp ITloop
-
-/*
- * Command phase. Set up the DMA registers and let 'er rip.
- */
-p_command:
- call assert
-
-/*
- * Load HADDR and HCNT.
- */
- mov HADDR0, SCB_CMDPTR0
- mov HADDR1, SCB_CMDPTR1
- mov HADDR2, SCB_CMDPTR2
- mov HADDR3, SCB_CMDPTR3
- mov HCNT0, SCB_CMDLEN
- clr HCNT1
- clr HCNT2
-
- mov STCNT0, HCNT0
- mov STCNT1, HCNT1
- mov STCNT2, HCNT2
-
- mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN|
- # DIRECTION|FIFORESET
- jmp ITloop
-
-/*
- * Status phase. Wait for the data byte to appear, then read it
- * and store it into the SCB.
- */
-p_status:
- mvi SCB_TARGET_STATUS call inb_first
- jmp mesgin_done
-
-/*
- * Message out phase. If there is not an active message, but the target
- * took us into this phase anyway, build a no-op message and send it.
- */
-p_mesgout:
- test MSG_LEN, 0xff jnz p_mesgout_start
- mvi MSG_NOP call mk_mesg /* build NOP message */
-
-p_mesgout_start:
-/*
- * Set up automatic PIO transfer from MSG0. Bit 3 in
- * SXFRCTL0 (SPIOEN) is already on.
- */
- mvi SINDEX,MSG0
- mov DINDEX,MSG_LEN
-
-/*
- * When target asks for a byte, drop ATN if it's the last one in
- * the message. Otherwise, keep going until the message is exhausted.
- *
- * Keep an eye out for a phase change, in case the target issues
- * a MESSAGE REJECT.
- */
-p_mesgout_loop:
- test SSTAT1,PHASEMIS jnz p_mesgout_phasemis
- test SSTAT0,SPIORDY jz p_mesgout_loop
- test SSTAT1,PHASEMIS jnz p_mesgout_phasemis
- cmp DINDEX,1 jne p_mesgout_outb /* last byte? */
- mvi CLRSINT1,CLRATNO /* drop ATN */
-p_mesgout_outb:
- dec DINDEX
- or CLRSINT0, CLRSPIORDY
- mov SCSIDATL,SINDIR
-
-p_mesgout4:
- test DINDEX,0xff jnz p_mesgout_loop
-
-/*
- * If the next bus phase after ATN drops is a message out, it means
- * that the target is requesting that the last message(s) be resent.
- */
-p_mesgout_snoop:
- test SSTAT1,BUSFREE jnz p_mesgout_done
- test SSTAT1,REQINIT jz p_mesgout_snoop
-
- test SSTAT1,PHASEMIS jnz p_mesgout_done
-
- or SCSISIGO,ATNO /* turn on ATNO */
-
- jmp ITloop
-
-p_mesgout_phasemis:
- mvi CLRSINT1,CLRATNO /* Be sure to turn ATNO off */
-p_mesgout_done:
- clr MSG_LEN /* no active msg */
- jmp ITloop
-
-/*
- * Message in phase. Bytes are read using Automatic PIO mode.
- */
-p_mesgin:
- mvi A call inb_first /* read the 1st message byte */
- mov REJBYTE,A /* save it for the driver */
-
- test A,MSG_IDENTIFY jnz mesgin_identify
- cmp A,MSG_DISCONNECT je mesgin_disconnect
- cmp A,MSG_SDPTRS je mesgin_sdptrs
- cmp ALLZEROS,A je mesgin_complete
- cmp A,MSG_RDPTRS je mesgin_rdptrs
- cmp A,MSG_EXTENDED je mesgin_extended
- cmp A,MSG_REJECT je mesgin_reject
-
-rej_mesgin:
-/*
- * We have no idea what this message in is, and there's no way
- * to pass it up to the kernel, so we issue a message reject and
- * hope for the best. Since we're now using manual PIO mode to
- * read in the message, there should no longer be a race condition
- * present when we assert ATN. In any case, rejection should be a
- * rare occurrence - signal the driver when it happens.
- */
- or SCSISIGO,ATNO /* turn on ATNO */
- mvi INTSTAT,SEND_REJECT /* let driver know */
-
- mvi MSG_REJECT call mk_mesg
-
-mesgin_done:
- call inb_last /*ack & turn auto PIO back on*/
- jmp ITloop
-
-
-mesgin_complete:
-/*
- * We got a "command complete" message, so put the SCB_TAG into QUEUEOUT,
- * and trigger a completion interrupt. Check status for non zero return
- * and interrupt driver if needed. This allows the driver to interpret
- * errors only when they occur instead of always uploading the scb. If
- * the status is SCSI_CHECK, the driver will download a new scb requesting
- * sense to replace the old one, modify the "waiting for selection" SCB list
- * and set RETURN_1 to SEND_SENSE. If RETURN_1 is set to SEND_SENSE the
- * sequencer imediately jumps to main loop where it will run down the waiting
- * SCB list and process the sense request. If the kernel driver does not
- * wish to request sense, it need only clear RETURN_1, and the command is
- * allowed to complete. We don't bother to post to the QOUTFIFO in the
- * error case since it would require extra work in the kernel driver to
- * ensure that the entry was removed before the command complete code tried
- * processing it.
- *
- * First check for residuals
- */
- test SCB_RESID_SGCNT,0xff jz check_status
-/*
- * If we have a residual count, interrupt and tell the host. Other
- * alternatives are to pause the sequencer on all command completes (yuck),
- * dma the resid directly to the host (slick, we may have space to do it now)
- * or have the sequencer pause itself when it encounters a non-zero resid
- * (unnecessary pause just to flag the command -yuck-, but takes one instruction
- * and since it shouldn't happen that often is good enough for our purposes).
- */
-resid:
- mvi INTSTAT,RESIDUAL
-
-check_status:
- test SCB_TARGET_STATUS,0xff jz status_ok /* Good Status? */
- mvi INTSTAT,BAD_STATUS /* let driver know */
- cmp RETURN_1, SEND_SENSE jne status_ok
- jmp mesgin_done
-
-status_ok:
-/* First, mark this target as free. */
- test SCB_CONTROL,TAG_ENB jnz test_immediate /*
- * Tagged commands
- * don't busy the
- * target.
- */
- mov FUNCTION1,SCB_TCL
- mov A,FUNCTION1
- test SCB_TCL,0x88 jz clear_a
- xor ACTIVE_B,A
- jmp test_immediate
-
-clear_a:
- xor ACTIVE_A,A
-
-test_immediate:
- test SCB_CMDLEN,0xff jnz complete /* Immediate message complete */
-/*
- * Pause the sequencer until the driver gets around to handling the command
- * complete. This is so that any action that might require careful timing
- * with the completion of this command can occur.
- */
- mvi INTSTAT,IMMEDDONE
- jmp start
-complete:
- mov QOUTFIFO,SCB_TAG
- mvi INTSTAT,CMDCMPLT
- jmp mesgin_done
-
-
-/*
- * Is it an extended message? We only support the synchronous and wide data
- * transfer request messages, which will probably be in response to
- * WDTR or SDTR message outs from us. If it's not SDTR or WDTR, reject it -
- * apparently this can be done after any message in byte, according
- * to the SCSI-2 spec.
- */
-mesgin_extended:
- mvi ARG_1 call inb_next /* extended message length */
- mvi REJBYTE_EXT call inb_next /* extended message code */
-
- cmp REJBYTE_EXT,MSG_SDTR je p_mesginSDTR
- cmp REJBYTE_EXT,MSG_WDTR je p_mesginWDTR
- jmp rej_mesgin
-
-p_mesginWDTR:
- cmp ARG_1,2 jne rej_mesgin /* extended mesg length=2 */
- mvi ARG_1 call inb_next /* Width of bus */
- mvi INTSTAT,WDTR_MSG /* let driver know */
- test RETURN_1,0xff jz mesgin_done /* Do we need to send WDTR? */
- cmp RETURN_1,SEND_REJ je rej_mesgin /*
- * Bus width was too large
- * Reject it.
- */
-
-/* We didn't initiate the wide negotiation, so we must respond to the request */
- and RETURN_1,0x7f /* Clear the SEND_WDTR Flag */
- mvi DINDEX,MSG0
- mvi MSG0 call mk_wdtr /* build WDTR message */
- or SCSISIGO,ATNO /* turn on ATNO */
- jmp mesgin_done
-
-p_mesginSDTR:
- cmp ARG_1,3 jne rej_mesgin /* extended mesg length=3 */
- mvi ARG_1 call inb_next /* xfer period */
- mvi A call inb_next /* REQ/ACK offset */
- mvi INTSTAT,SDTR_MSG /* call driver to convert */
-
- test RETURN_1,0xff jz mesgin_done /* Do we need to mk_sdtr/rej */
- cmp RETURN_1,SEND_REJ je rej_mesgin /*
- * Requested SDTR too small
- * Reject it.
- */
- clr ARG_1 /* Use the scratch ram rate */
- mvi DINDEX, MSG0
- mvi MSG0 call mk_sdtr
- or SCSISIGO,ATNO /* turn on ATNO */
- jmp mesgin_done
-
-/*
- * Is it a disconnect message? Set a flag in the SCB to remind us
- * and await the bus going free.
- */
-mesgin_disconnect:
- or SCB_CONTROL,DISCONNECTED
- test FLAGS, PAGESCBS jz mesgin_done
-/*
- * Link this SCB into the DISCONNECTED list. This list holds the
- * candidates for paging out an SCB if one is needed for a new command.
- * Modifying the disconnected list is a critical(pause dissabled) section.
- */
- mvi SCB_PREV, SCB_LIST_NULL
- mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */
- mov SCB_NEXT, DISCONNECTED_SCBH
- mov DISCONNECTED_SCBH, SCBPTR
- cmp SCB_NEXT,SCB_LIST_NULL je linkdone
- mov SCBPTR,SCB_NEXT
- mov SCB_PREV,DISCONNECTED_SCBH
- mov SCBPTR,DISCONNECTED_SCBH
-linkdone:
- mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */
- jmp mesgin_done
-
-/*
- * Save data pointers message? Copy working values into the SCB,
- * usually in preparation for a disconnect.
- */
-mesgin_sdptrs:
- call sg_ram2scb
- jmp mesgin_done
-
-/*
- * Restore pointers message? Data pointers are recopied from the
- * SCB anytime we enter a data phase for the first time, so all
- * we need to do is clear the DPHASE flag and let the data phase
- * code do the rest.
- */
-mesgin_rdptrs:
- and FLAGS,0xef /*
- * !DPHASE we'll reload them
- * the next time through
- */
- jmp mesgin_done
-
-/*
- * Identify message? For a reconnecting target, this tells us the lun
- * that the reconnection is for - find the correct SCB and switch to it,
- * clearing the "disconnected" bit so we don't "find" it by accident later.
- */
-mesgin_identify:
- test A,0x78 jnz rej_mesgin /*!DiscPriv|!LUNTAR|!Reserved*/
-
- and A,0x07 /* lun in lower three bits */
- or SAVED_TCL,A,SELID
- and SAVED_TCL,0xf7
- and A,SELBUSB,SBLKCTL /* B Channel?? */
- or SAVED_TCL,A
- call inb_last /* ACK */
-
-/*
- * Here we "snoop" the bus looking for a SIMPLE QUEUE TAG message.
- * If we get one, we use the tag returned to switch to find the proper
- * SCB. With SCB paging, this requires using findSCB for both tagged
- * and non-tagged transactions since the SCB may exist in any slot.
- * If we're not using SCB paging, we can use the tag as the direct
- * index to the SCB.
- */
- mvi ARG_1,SCB_LIST_NULL /* Default to no-tag */
-snoop_tag_loop:
- test SSTAT1,BUSFREE jnz use_findSCB
- test SSTAT1,REQINIT jz snoop_tag_loop
- test SSTAT1,PHASEMIS jnz use_findSCB
- mvi A call inb_first
- cmp A,MSG_SIMPLE_TAG jne use_findSCB
-get_tag:
- mvi ARG_1 call inb_next /* tag value */
-/*
- * See if the tag is in range. The tag is < SCBCOUNT if we add
- * the complement of SCBCOUNT to the incoming tag and there is
- * no carry.
- */
- mov A,COMP_SCBCOUNT
- add SINDEX,A,ARG_1
- jc abort_tag
-
-/*
- * Ensure that the SCB the tag points to is for a SCB transaction
- * to the reconnecting target.
- */
- test FLAGS, PAGESCBS jz index_by_tag
- call inb_last /* Ack Tag */
-use_findSCB:
- mov ALLZEROS call findSCB /* Have to search */
-setup_SCB:
- and SCB_CONTROL,0xfb /* clear disconnect bit in SCB */
- or FLAGS,IDENTIFY_SEEN /* make note of IDENTIFY */
- jmp ITloop
-index_by_tag:
- mov SCBPTR,ARG_1
- mov A,SAVED_TCL
- cmp SCB_TCL,A jne abort_tag
- test SCB_CONTROL,TAG_ENB jz abort_tag
- call inb_last /* Ack Successful tag */
- jmp setup_SCB
-
-abort_tag:
- or SCSISIGO,ATNO /* turn on ATNO */
- mvi INTSTAT,ABORT_TAG /* let driver know */
- mvi MSG_ABORT_TAG call mk_mesg /* ABORT TAG message */
- jmp mesgin_done
-
-/*
- * Message reject? Let the kernel driver handle this. If we have an
- * outstanding WDTR or SDTR negotiation, assume that it's a response from
- * the target selecting 8bit or asynchronous transfer, otherwise just ignore
- * it since we have no clue what it pertains to.
- */
-mesgin_reject:
- mvi INTSTAT, REJECT_MSG
- jmp mesgin_done
-
-/*
- * [ ADD MORE MESSAGE HANDLING HERE ]
- */
-
-/*
- * Bus free phase. It might be useful to interrupt the device
- * driver if we aren't expecting this. For now, make sure that
- * ATN isn't being asserted and look for a new command.
- */
-p_busfree:
- mvi CLRSINT1,CLRATNO
- clr LASTPHASE
-
-/*
- * if this is an immediate command, perform a pseudo command complete to
- * notify the driver.
- */
- test SCB_CMDLEN,0xff jz status_ok
- jmp start
-
-/*
- * Locking the driver out, build a one-byte message passed in SINDEX
- * if there is no active message already. SINDEX is returned intact.
- */
-mk_mesg:
- mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */
- test MSG_LEN,0xff jz mk_mesg1 /* Should always succeed */
-
- /*
- * Hmmm. For some reason the mesg buffer is in use.
- * Tell the driver. It should look at SINDEX to find
- * out what we wanted to use the buffer for and resolve
- * the conflict.
- */
- mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */
- mvi INTSTAT,MSG_BUFFER_BUSY
-
-mk_mesg1:
- mvi MSG_LEN,1 /* length = 1 */
- mov MSG0,SINDEX /* 1-byte message */
- mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */
-
-/*
- * Functions to read data in Automatic PIO mode.
- *
- * According to Adaptec's documentation, an ACK is not sent on input from
- * the target until SCSIDATL is read from. So we wait until SCSIDATL is
- * latched (the usual way), then read the data byte directly off the bus
- * using SCSIBUSL. When we have pulled the ATN line, or we just want to
- * acknowledge the byte, then we do a dummy read from SCISDATL. The SCSI
- * spec guarantees that the target will hold the data byte on the bus until
- * we send our ACK.
- *
- * The assumption here is that these are called in a particular sequence,
- * and that REQ is already set when inb_first is called. inb_{first,next}
- * use the same calling convention as inb.
- */
-
-inb_next:
- or CLRSINT0, CLRSPIORDY
- mov NONE,SCSIDATL /*dummy read from latch to ACK*/
-inb_next_wait:
- test SSTAT1,PHASEMIS jnz mesgin_phasemis
- test SSTAT0,SPIORDY jz inb_next_wait /* wait for next byte */
-inb_first:
- mov DINDEX,SINDEX
- test SSTAT1,PHASEMIS jnz mesgin_phasemis
- mov DINDIR,SCSIBUSL ret /*read byte directly from bus*/
-inb_last:
- mov NONE,SCSIDATL ret /*dummy read from latch to ACK*/
-
-mesgin_phasemis:
-/*
- * We expected to receive another byte, but the target changed phase
- */
- mvi INTSTAT, MSGIN_PHASEMIS
- jmp ITloop
-
-/*
- * DMA data transfer. HADDR and HCNT must be loaded first, and
- * SINDEX should contain the value to load DFCNTRL with - 0x3d for
- * host->scsi, or 0x39 for scsi->host. The SCSI channel is cleared
- * during initialization.
- */
-dma:
- mov DFCNTRL,SINDEX
-dma1:
- test SSTAT0,DMADONE jnz dma3
- test SSTAT1,PHASEMIS jz dma1 /* ie. underrun */
-
-/*
- * We will be "done" DMAing when the transfer count goes to zero, or
- * the target changes the phase (in light of this, it makes sense that
- * the DMA circuitry doesn't ACK when PHASEMIS is active). If we are
- * doing a SCSI->Host transfer, the data FIFO should be flushed auto-
- * magically on STCNT=0 or a phase change, so just wait for FIFO empty
- * status.
- */
-dma3:
- test SINDEX,DIRECTION jnz dma5
-dma4:
- test DFSTATUS,FIFOEMP jz dma4
-
-/*
- * Now shut the DMA enables off and make sure that the DMA enables are
- * actually off first lest we get an ILLSADDR.
- */
-dma5:
- /* disable DMA, but maintain WIDEODD */
- and DFCNTRL,WIDEODD
-dma6:
- test DFCNTRL,0x38 jnz dma6 /* SCSIENACK|SDMAENACK|HDMAENACK */
-
- ret
-
-/*
- * Common SCSI initialization for selection and reselection. Expects
- * the target SCSI ID to be in the upper four bits of SINDEX, and A's
- * contents are stomped on return.
- */
-initialize_scsiid:
- and SINDEX,0xf0 /* Get target ID */
- and A,0x0f,SCSIID
- or SINDEX,A
- mov SCSIID,SINDEX ret
-
-/*
- * Assert that if we've been reselected, then we've seen an IDENTIFY
- * message.
- */
-assert:
- test FLAGS,RESELECTED jz return /* reselected? */
- test FLAGS,IDENTIFY_SEEN jnz return /* seen IDENTIFY? */
-
- mvi INTSTAT,NO_IDENT ret /* no - cause a kernel panic */
-
-/*
- * Locate the SCB matching the target ID/channel/lun in SAVED_TCL, and the tag
- * value in ARG_1. If ARG_1 == SCB_LIST_NULL, we're looking for a non-tagged
- * SCB. Have the kernel print a warning message if it can't be found, and
- * generate an ABORT/ABORT_TAG message to the target. SINDEX should be
- * cleared on call.
- */
-findSCB:
- mov A,SAVED_TCL
- mov SCBPTR,SINDEX /* switch to next SCB */
- mvi SEQCTL,0x50 /* PAUSEDIS|FASTMODE */
- cmp SCB_TCL,A jne findSCB1 /* target ID/channel/lun match? */
- test SCB_CONTROL,DISCONNECTED jz findSCB1 /*should be disconnected*/
- test SCB_CONTROL,TAG_ENB jnz findTaggedSCB
- cmp ARG_1,SCB_LIST_NULL je foundSCB
- jmp findSCB1
-findTaggedSCB:
- mov A, ARG_1 /* Tag passed in ARG_1 */
- cmp SCB_TAG,A jne findSCB1 /* Found it? */
-foundSCB:
- test FLAGS,PAGESCBS jz foundSCB_ret
-/* Remove this SCB from the disconnection list */
- cmp SCB_NEXT,SCB_LIST_NULL je unlink_prev
- mov SAVED_LINKPTR, SCB_PREV
- mov SCBPTR, SCB_NEXT
- mov SCB_PREV, SAVED_LINKPTR
- mov SCBPTR, SINDEX
-unlink_prev:
- cmp SCB_PREV,SCB_LIST_NULL je rHead/* At the head of the list */
- mov SAVED_LINKPTR, SCB_NEXT
- mov SCBPTR, SCB_PREV
- mov SCB_NEXT, SAVED_LINKPTR
- mov SCBPTR, SINDEX
- mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */
-rHead:
- mov DISCONNECTED_SCBH,SCB_NEXT
-foundSCB_ret:
- mvi SEQCTL,0x10 ret /* !PAUSEDIS|FASTMODE */
-
-findSCB1:
- mvi SEQCTL,0x10 /* !PAUSEDIS|FASTMODE */
- inc SINDEX
- mov A,SCBCOUNT
- cmp SINDEX,A jne findSCB
-
- mvi INTSTAT,NO_MATCH /* not found - signal kernel */
- cmp RETURN_1,SCB_PAGEDIN je return
- or SCSISIGO,ATNO /* assert ATNO */
- cmp ARG_1,SCB_LIST_NULL jne find_abort_tag
- mvi MSG_ABORT call mk_mesg
- jmp ITloop
-find_abort_tag:
- mvi MSG_ABORT_TAG call mk_mesg
- jmp ITloop
-
-/*
- * Make a working copy of the scatter-gather parameters from the SCB.
- */
-sg_scb2ram:
- mov HADDR0, SCB_DATAPTR0
- mov HADDR1, SCB_DATAPTR1
- mov HADDR2, SCB_DATAPTR2
- mov HADDR3, SCB_DATAPTR3
- mov HCNT0, SCB_DATACNT0
- mov HCNT1, SCB_DATACNT1
- mov HCNT2, SCB_DATACNT2
-
- mov STCNT0, HCNT0
- mov STCNT1, HCNT1
- mov STCNT2, HCNT2
-
- mov SG_COUNT,SCB_SGCOUNT
-
- mov SG_NEXT0, SCB_SGPTR0
- mov SG_NEXT1, SCB_SGPTR1
- mov SG_NEXT2, SCB_SGPTR2
- mov SG_NEXT3, SCB_SGPTR3 ret
-
-/*
- * Copying RAM values back to SCB, for Save Data Pointers message, but
- * only if we've actually been into a data phase to change them. This
- * protects against bogus data in scratch ram and the residual counts
- * since they are only initialized when we go into data_in or data_out.
- */
-sg_ram2scb:
- test FLAGS, DPHASE jz return
- mov SCB_SGCOUNT,SG_COUNT
-
- mov SCB_SGPTR0,SG_NEXT0
- mov SCB_SGPTR1,SG_NEXT1
- mov SCB_SGPTR2,SG_NEXT2
- mov SCB_SGPTR3,SG_NEXT3
-
- mov SCB_DATAPTR0,SHADDR0
- mov SCB_DATAPTR1,SHADDR1
- mov SCB_DATAPTR2,SHADDR2
- mov SCB_DATAPTR3,SHADDR3
-
-/*
- * Use the residual number since STCNT is corrupted by any message transfer
- */
- mov SCB_DATACNT0,SCB_RESID_DCNT0
- mov SCB_DATACNT1,SCB_RESID_DCNT1
- mov SCB_DATACNT2,SCB_RESID_DCNT2 ret
-
-/*
- * Add the array base TARG_SCRATCH to the target offset (the target address
- * is in SCSIID), and return the result in SINDEX. The accumulator
- * contains the 3->8 decoding of the target ID on return.
- */
-ndx_dtr:
- shr A,SCSIID,4
- test SBLKCTL,SELBUSB jz ndx_dtr_2
- or A,0x08 /* Channel B entries add 8 */
-ndx_dtr_2:
- add SINDEX,TARG_SCRATCH,A ret
-
-/*
- * If we need to negotiate transfer parameters, build the WDTR or SDTR message
- * starting at the address passed in SINDEX. DINDEX is modified on return.
- * The SCSI-II spec requires that Wide negotiation occur first and you can
- * only negotiate one or the other at a time otherwise in the event of a message
- * reject, you wouldn't be able to tell which message was the culprit.
- */
-mk_dtr:
- test SCB_CONTROL,NEEDWDTR jnz mk_wdtr_16bit
- mvi ARG_1, MAXOFFSET /* Force an offset of 15 or 8 if WIDE */
-
-mk_sdtr:
- mvi DINDIR,1 /* extended message */
- mvi DINDIR,3 /* extended message length = 3 */
- mvi DINDIR,1 /* SDTR code */
- call sdtr_to_rate
- mov DINDIR,RETURN_1 /* REQ/ACK transfer period */
- cmp ARG_1, MAXOFFSET je mk_sdtr_max_offset
- and DINDIR,0x0f,SINDIR /* Sync Offset */
-
-mk_sdtr_done:
- add MSG_LEN,COMP_MSG0,DINDEX ret /* update message length */
-
-mk_sdtr_max_offset:
-/*
- * We're initiating sync negotiation, so request the max offset we can (15 or 8)
- */
- /* Talking to a WIDE device? */
- test SCSIRATE, WIDEXFER jnz wmax_offset
- mvi DINDIR, MAX_OFFSET_8BIT
- jmp mk_sdtr_done
-
-wmax_offset:
- mvi DINDIR, MAX_OFFSET_16BIT
- jmp mk_sdtr_done
-
-mk_wdtr_16bit:
- mvi ARG_1,BUS_16_BIT
-mk_wdtr:
- mvi DINDIR,1 /* extended message */
- mvi DINDIR,2 /* extended message length = 2 */
- mvi DINDIR,3 /* WDTR code */
- mov DINDIR,ARG_1 /* bus width */
-
- add MSG_LEN,COMP_MSG0,DINDEX ret /* update message length */
-
-sdtr_to_rate:
- call ndx_dtr /* index scratch space for target */
- shr A,SINDIR,0x4
- dec SINDEX /* Preserve SINDEX */
- and A,0x7
- clr RETURN_1
-sdtr_to_rate_loop:
- test A,0x0f jz sdtr_to_rate_done
- add RETURN_1,0x19
- dec A
- jmp sdtr_to_rate_loop
-sdtr_to_rate_done:
- shr RETURN_1,0x2
- add RETURN_1,0x19
- test SXFRCTL0,ULTRAEN jz return
- shr RETURN_1,0x1
-return:
- ret
diff --git a/drivers/scsi/aic7xxx_asm.c b/drivers/scsi/aic7xxx_asm.c
index 544edf0fa..e69de29bb 100644
--- a/drivers/scsi/aic7xxx_asm.c
+++ b/drivers/scsi/aic7xxx_asm.c
@@ -1,734 +0,0 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx sequencer code assembler.
- *
- * Copyright (c) 1994 John Aycock
- * The University of Calgary Department of Computer Science.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * Comments are started by `#' and continue to the end of the line; lines
- * may be of the form:
- * <label>*
- * <label>* <undef-sym> = <value>
- * <label>* <opcode> <operand>*
- *
- * A <label> is an <undef-sym> ending in a colon. Spaces, tabs, and commas
- * are token separators.
- *-M*************************************************************************/
-static const char id[] = "$Id: aic7xxx_asm.c,v 3.0 1996/04/16 08:52:23 deang Exp $";
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-
-#define MEMORY 448
-#define MAXLINE 1024
-#define MAXTOKEN 32
-#define ADOTOUT "a.out"
-#define NOVALUE -1
-
-#ifndef TRUE
-# define TRUE 1
-#endif
-#ifndef FALSE
-# define FALSE 0
-#endif
-#define MAX_ARGS 16
-static const char *cpp[] = {
- "/lib/cpp -P - -",
- "/usr/lib/cpp -P - -",
- "/usr/bin/cpp -P - -",
- "/usr/bin/gcc -E -P -",
- "/usr/bin/cc -E -P -"
-};
-
-#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
-
-/*
- * AIC-7770/AIC-7870 register definitions
- */
-#define R_SINDEX 0x65
-#define R_ALLONES 0x69
-#define R_ALLZEROS 0x6a
-#define R_NONE 0x6a
-
-int debug;
-int lineno, LC;
-char *filename;
-unsigned char M[MEMORY][4];
-
-void
-error(const char *s)
-{
- fprintf(stderr, "%s: %s at line %d\n", filename, s, lineno);
- exit(EXIT_FAILURE);
-}
-
-void *
-Malloc(size_t size)
-{
- void *p = malloc(size);
- if (!p)
- error("out of memory");
- return(p);
-}
-
-void *
-Realloc(void *ptr, size_t size)
-{
- void *p = realloc(ptr, size);
- if (!p)
- error("out of memory");
- return(p);
-}
-
-char *
-Strdup(char *s)
-{
- char *p = (char *)Malloc(strlen(s) + 1);
- strcpy(p, s);
- return(p);
-}
-
-typedef struct sym_t {
- struct sym_t *next; /* MUST BE FIRST */
- char *name;
- int value;
- int npatch;
- int *patch;
-} sym_t;
-
-sym_t *head;
-
-void
-define(char *name, int value)
-{
- sym_t *p, *q;
-
- for (p = head, q = (sym_t *)&head; p; p = p->next) {
- if (!strcmp(p->name, name))
- error("redefined symbol");
- q = p;
- }
-
- p = q->next = (sym_t *)Malloc(sizeof(sym_t));
- p->next = NULL;
- p->name = Strdup(name);
- p->value = value;
- p->npatch = 0;
- p->patch = NULL;
-
- if (debug) {
- fprintf(stderr, "\"%s\" ", p->name);
- if (p->value != NOVALUE)
- fprintf(stderr, "defined as 0x%x\n", p->value);
- else
- fprintf(stderr, "undefined\n");
- }
-}
-
-sym_t *
-lookup(char *name)
-{
- sym_t *p;
-
- for (p = head; p; p = p->next)
- if (!strcmp(p->name, name))
- return(p);
- return(NULL);
-}
-
-void
-patch(sym_t *p, int location)
-{
- p->npatch += 1;
- p->patch = (int *)Realloc(p->patch, p->npatch * sizeof(int *));
-
- p->patch[p->npatch - 1] = location;
-}
-
-void backpatch(void)
-{
- int i;
- sym_t *p;
-
- for (p = head; p; p = p->next) {
-
- if (p->value == NOVALUE) {
- fprintf(stderr,
- "%s: undefined symbol \"%s\"\n",
- filename, p->name);
- exit(EXIT_FAILURE);
- }
-
- if (p->npatch) {
- if (debug)
- fprintf(stderr,
- "\"%s\" (0x%x) patched at",
- p->name, p->value);
-
- for (i = 0; i < p->npatch; i++) {
- M[p->patch[i]][0] &= ~1;
- M[p->patch[i]][0] |= ((p->value >> 8) & 1);
- M[p->patch[i]][1] = p->value & 0xff;
-
- if (debug)
- fprintf(stderr, " 0x%x", p->patch[i]);
- }
-
- if (debug)
- fputc('\n', stderr);
- }
- }
-}
-
-/*
- * Output words in byte-reversed order (least significant first)
- * since the sequencer RAM is loaded that way.
- */
-void
-output(FILE *fp)
-{
- int i;
-
- for (i = 0; i < LC; i++)
- fprintf(fp, "\t0x%02x, 0x%02x, 0x%02x, 0x%02x,\n",
- M[i][3],
- M[i][2],
- M[i][1],
- M[i][0]);
- printf("%d out of %d instructions used.\n", LC, MEMORY);
-}
-
-char **
-getl(int *n)
-{
- int i;
- char *p, *quote;
- static char buf[MAXLINE];
- static char *a[MAXTOKEN];
-
- i = 0;
-
- while (fgets(buf, sizeof(buf), stdin)) {
-
- lineno += 1;
-
- if (buf[strlen(buf)-1] != '\n')
- error("line too long");
-
- p = strchr(buf, '#');
- if (p)
- *p = '\0';
- p = buf;
-rescan:
- quote = strchr(p, '\"');
- if (quote)
- *quote = '\0';
- for (p = strtok(p, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
- if (i < MAXTOKEN-1)
- a[i++] = p;
- else
- error("too many tokens");
- if (quote) {
- quote++;
- p = strchr(quote, '\"');
- if (!p)
- error("unterminated string constant");
- else if (i < MAXTOKEN-1) {
- a[i++] = quote;
- *p = '\0';
- p++;
- }
- else
- error("too many tokens");
- goto rescan;
- }
- if (i) {
- *n = i;
- return(a);
- }
- }
- return(NULL);
-}
-
-#define A 0x8000 /* `A'ccumulator ok */
-#define I 0x4000 /* use as immediate value */
-#define SL 0x2000 /* shift left */
-#define SR 0x1000 /* shift right */
-#define RL 0x0800 /* rotate left */
-#define RR 0x0400 /* rotate right */
-#define LO 0x8000 /* lookup: ori-{jmp,jc,jnc,call} */
-#define LA 0x4000 /* lookup: and-{jz,jnz} */
-#define LX 0x2000 /* lookup: xor-{je,jne} */
-#define NA -1 /* not applicable */
-
-struct {
- const char *name;
- int n; /* number of operands, including opcode */
- unsigned int op; /* immediate or L?|pos_from_0 */
- unsigned int dest; /* NA, pos_from_0, or I|immediate */
- unsigned int src; /* NA, pos_from_0, or I|immediate */
- unsigned int imm; /* pos_from_0, A|pos_from_0, or I|immediate */
- unsigned int addr; /* NA or pos_from_0 */
- int fmt; /* instruction format - 1, 2, or 3 */
-} instr[] = {
-/*
- * N OP DEST SRC IMM ADDR FMT
- */
- { "mov", 3, 1, 1, 2, I|0xff, NA, 1 },
- { "mov", 4, LO|2, NA, 1, I|0, 3, 3 },
- { "mvi", 3, 0, 1, I|R_ALLZEROS, A|2, NA, 1 },
- { "mvi", 4, LO|2, NA, I|R_ALLZEROS, 1, 3, 3 },
- { "not", 2, 2, 1, 1, I|0xff, NA, 1 },
- { "and", 3, 1, 1, 1, A|2, NA, 1 },
- { "and", 4, 1, 1, 3, A|2, NA, 1 },
- { "or", 3, 0, 1, 1, A|2, NA, 1 },
- { "or", 4, 0, 1, 3, A|2, NA, 1 },
- { "or", 5, LO|3, NA, 1, 2, 4, 3 },
- { "xor", 3, 2, 1, 1, A|2, NA, 1 },
- { "xor", 4, 2, 1, 3, A|2, NA, 1 },
- { "nop", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "inc", 2, 3, 1, 1, I|1, NA, 1 },
- { "inc", 3, 3, 1, 2, I|1, NA, 1 },
- { "dec", 2, 3, 1, 1, I|0xff, NA, 1 },
- { "dec", 3, 3, 1, 2, I|0xff, NA, 1 },
- { "jmp", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "jnc", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "call", 2, LO|0, NA, I|R_SINDEX, I|0, 1, 3 },
- { "test", 5, LA|3, NA, 1, A|2, 4, 3 },
- { "cmp", 5, LX|3, NA, 1, A|2, 4, 3 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "ret", 1, 1, I|R_NONE, I|R_ALLZEROS, I|0xff, NA, 1 },
- { "clc", 1, 3, I|R_NONE, I|R_ALLZEROS, I|1, NA, 1 },
- { "clc", 4, 3, 2, I|R_ALLZEROS, A|3, NA, 1 },
- { "stc", 2, 3, 1, I|R_ALLONES, I|1, NA, 1 },
- { "add", 3, 3, 1, 1, A|2, NA, 1 },
- { "add", 4, 3, 1, 3, A|2, NA, 1 },
- { "adc", 3, 4, 1, 1, A|2, NA, 1 },
- { "adc", 4, 4, 1, 3, A|2, NA, 1 },
- { "shl", 3, 5, 1, 1, SL|2, NA, 2 },
- { "shl", 4, 5, 1, 2, SL|3, NA, 2 },
- { "shr", 3, 5, 1, 1, SR|2, NA, 2 },
- { "shr", 4, 5, 1, 2, SR|3, NA, 2 },
- { "rol", 3, 5, 1, 1, RL|2, NA, 2 },
- { "rol", 4, 5, 1, 2, RL|3, NA, 2 },
- { "ror", 3, 5, 1, 1, RR|2, NA, 2 },
- { "ror", 4, 5, 1, 2, RR|3, NA, 2 },
- /*
- * Extensions (note also that mvi allows A)
- */
- { "clr", 2, 1, 1, I|R_ALLZEROS, I|0xff, NA, 1 },
- { 0, 0, 0, 0, 0, 0, 0, 0 }
-};
-
-int
-eval_operand(char **a, int spec)
-{
- int i;
- unsigned int want = spec & (LO|LA|LX);
-
- static struct {
- unsigned int what;
- const char *name;
- int value;
- } jmptab[] = {
- { LO, "jmp", 8 },
- { LO, "jc", 9 },
- { LO, "jnc", 10 },
- { LO, "call", 11 },
- { LA, "jz", 15 },
- { LA, "jnz", 13 },
- { LX, "je", 14 },
- { LX, "jne", 12 },
- };
-
- spec &= ~(LO|LA|LX);
-
- for (i = 0; i < sizeof(jmptab)/sizeof(jmptab[0]); i++)
- if (jmptab[i].what == want &&
- !strcmp(jmptab[i].name, a[spec]))
- {
- return(jmptab[i].value);
- }
-
- if (want)
- error("invalid jump");
-
- return(spec); /* "case 0" - no flags set */
-}
-
-int
-eval_sdi(char **a, int spec)
-{
- sym_t *p;
- unsigned val;
-
- if (spec == NA)
- return(NA);
-
- switch (spec & (A|I|SL|SR|RL|RR)) {
- case SL:
- case SR:
- case RL:
- case RR:
- if (isdigit(*a[spec &~ (SL|SR|RL|RR)]))
- val = strtol(a[spec &~ (SL|SR|RL|RR)], NULL, 0);
- else {
- p = lookup(a[spec &~ (SL|SR|RL|RR)]);
- if (!p)
- error("undefined symbol used");
- val = p->value;
- }
-
- switch (spec & (SL|SR|RL|RR)) { /* blech */
- case SL:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (val % 8));
- case SR:
- if (val > 7)
- return(0xf0);
- return(((val % 8) << 4) |
- (1 << 3) |
- ((8 - (val % 8)) % 8));
- case RL:
- return(val % 8);
- case RR:
- return((8 - (val % 8)) % 8);
- }
- case I:
- return(spec &~ I);
- case A:
- /*
- * An immediate field of zero selects
- * the accumulator. Vigorously object
- * if zero is given otherwise - it's
- * most likely an error.
- */
- spec &= ~A;
- if (!strcmp("A", a[spec]))
- return(0);
- if (isdigit(*a[spec]) &&
- strtol(a[spec], NULL, 0) == 0)
- {
- error("immediate value of zero selects accumulator");
- }
- /* falls through */
- case 0:
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
- p = lookup(a[spec]);
- if (p)
- return(p->value);
- error("undefined symbol used");
- }
-
- return(NA); /* shut the compiler up */
-}
-
-int
-eval_addr(char **a, int spec)
-{
- sym_t *p;
-
- if (spec == NA)
- return(NA);
- if (isdigit(*a[spec]))
- return(strtol(a[spec], NULL, 0));
-
- p = lookup(a[spec]);
-
- if (p) {
- if (p->value != NOVALUE)
- return(p->value);
- patch(p, LC);
- } else {
- define(a[spec], NOVALUE);
- p = lookup(a[spec]);
- patch(p, LC);
- }
-
- return(NA); /* will be patched in later */
-}
-
-int
-crack(char **a, int n)
-{
- int i;
- int I_imm, I_addr;
- int I_op, I_dest, I_src, I_ret;
-
- /*
- * Check for "ret" at the end of the line; remove
- * it unless it's "ret" alone - we still want to
- * look it up in the table.
- */
- I_ret = (strcmp(a[n-1], "ret") ? 0 : !0);
- if (I_ret && n > 1)
- n -= 1;
-
- for (i = 0; instr[i].name; i++) {
- /*
- * Look for match in table given constraints,
- * currently just the name and the number of
- * operands.
- */
- if (!strcmp(instr[i].name, *a) && instr[i].n == n)
- break;
- }
- if (!instr[i].name)
- error("unknown opcode or wrong number of operands");
-
- I_op = eval_operand(a, instr[i].op);
- I_src = eval_sdi(a, instr[i].src);
- I_imm = eval_sdi(a, instr[i].imm);
- I_dest = eval_sdi(a, instr[i].dest);
- I_addr = eval_addr(a, instr[i].addr);
-
- if( LC >= MEMORY )
- error("Memory exhausted!\n");
-
- switch (instr[i].fmt) {
- case 1:
- case 2:
- M[LC][0] = (I_op << 1) | I_ret;
- M[LC][1] = I_dest;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
- case 3:
- if (I_ret)
- error("illegal use of \"ret\"");
- M[LC][0] = (I_op << 1) | ((I_addr >> 8) & 1);
- M[LC][1] = I_addr & 0xff;
- M[LC][2] = I_src;
- M[LC][3] = I_imm;
- break;
- }
-
- return (1); /* no two-byte instructions yet */
-}
-
-#undef SL
-#undef SR
-#undef RL
-#undef RR
-#undef LX
-#undef LA
-#undef LO
-#undef I
-#undef A
-
-void
-assemble(FILE *ofile)
-{
- int n;
- char **a;
- sym_t *p;
-
- while ((a = getl(&n))) {
-
- while (a[0][strlen(*a)-1] == ':') {
- a[0][strlen(*a)-1] = '\0';
- p = lookup(*a);
- if (p)
- p->value = LC;
- else
- define(*a, LC);
- a += 1;
- n -= 1;
- }
-
- if (!n) /* line was all labels */
- continue;
-
- if (n == 3 && !strcmp("VERSION", *a))
- fprintf(ofile, "#define %s \"%s\"\n", a[1], a[2]);
- else {
- if (n == 3 && !strcmp("=", a[1]))
- define(*a, strtol(a[2], NULL, 0));
- else
- LC += crack(a, n);
- }
- }
-
- backpatch();
- output(ofile);
-
- if (debug)
- output(stderr);
-}
-
-int
-main(int argc, char **argv)
-{
- int c;
- int pid;
- int ifile;
- int status;
- FILE *ofile;
- char *ofilename;
- int fd[2];
-
- ofile = NULL;
- ofilename = NULL;
- while ((c = getopt(argc, argv, "dho:vD:")) != EOF) {
- switch (c) {
- case 'd':
- debug = !0;
- break;
- case 'D':
- {
- char *p;
- if ((p = strchr(optarg, '=')) != NULL) {
- *p = '\0';
- define(optarg, strtol(p + 1, NULL, 0));
- }
- else
- define(optarg, 1);
- break;
- }
- case 'o':
- ofilename = optarg;
- if ((ofile = fopen(ofilename, "w")) == NULL) {
- perror(optarg);
- exit(EXIT_FAILURE);
- }
- break;
- case 'h':
- printf("usage: %s [-d] [-Dname] [-ooutput] input\n",
- *argv);
- exit(EXIT_SUCCESS);
- break;
- case 'v':
- printf("%s\n", id);
- exit(EXIT_SUCCESS);
- break;
- default:
- exit(EXIT_FAILURE);
- break;
- }
- }
-
- if (argc - optind != 1) {
- fprintf(stderr, "%s: must have one input file\n", *argv);
- exit(EXIT_FAILURE);
- }
- filename = argv[optind];
-
-
- if ((ifile = open(filename, O_RDONLY)) < 0) {
- perror(filename);
- exit(EXIT_FAILURE);
- }
-
- if (!ofilename) {
- ofilename = ADOTOUT;
- if ((ofile = fopen(ofilename, "w")) < 0) {
- perror(ofilename);
- exit(EXIT_FAILURE);
- }
- }
-
- if (pipe(fd) < 0) {
- perror("pipe failed");
- exit(1);
- }
-
- if ((pid = fork()) < 0 ) {
- perror("fork failed");
- exit(1);
- }
- else if (pid > 0) { /* Parent */
- close(fd[1]); /* Close write end */
- if (fd[0] != STDIN_FILENO) {
- if (dup2(fd[0], STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(fd[0]);
- }
- assemble(ofile);
- if (wait(&status) < 0) {
- perror("wait error");
- }
-
- if (status != 0) {
- unlink(ofilename);
- }
- exit(status);
- } else { /* Child */
- int i, arg_cnt, found;
- char *args[MAX_ARGS];
- char *buf;
-
- arg_cnt = 0;
- found = FALSE;
- for (i = 0; (!found && (i < NUMBER(cpp))); i++) {
- char *bp;
-
- buf = strdup(cpp[i]);
-
- for (bp = strtok(buf, " \t\n"), arg_cnt = 0;
- bp != NULL;
- bp = strtok(NULL, " \t\n"), arg_cnt++) {
- if (arg_cnt == 0) {
- if (access(bp, X_OK) == 0) {
- found = TRUE;
- }
- }
-
- args[arg_cnt] = bp;
- }
-
- if (!found) {
- free(buf);
- }
- }
- args[arg_cnt] = NULL;
-
- if (found) {
- close(fd[0]); /* Close Read end */
- if (fd[1] != STDOUT_FILENO) {
- if (dup2(fd[1], STDOUT_FILENO) != STDOUT_FILENO) {
- perror("dup2 error on stdout");
- exit(EXIT_FAILURE);
- }
- close(fd[1]);
- }
- if (ifile != STDIN_FILENO) {
- if (dup2(ifile, STDIN_FILENO) != STDIN_FILENO) {
- perror("dup2 error on stdin");
- exit(EXIT_FAILURE);
- }
- close(ifile);
- }
-
- if (execvp(args[0], args) < 0) {
- perror("execvp() error");
- exit(EXIT_FAILURE);
- }
- } else {
- fprintf(stderr, "%s: Cannot find CPP command.\n", argv[0]);
- exit(EXIT_FAILURE);
- }
- }
- return(EXIT_SUCCESS);
-}
diff --git a/drivers/scsi/aic7xxx_proc.c b/drivers/scsi/aic7xxx_proc.c
index a968c324f..1092d4862 100644
--- a/drivers/scsi/aic7xxx_proc.c
+++ b/drivers/scsi/aic7xxx_proc.c
@@ -24,7 +24,7 @@
*
* Dean W. Gehnert, deang@teleport.com, 05/01/96
*
- * $Id: aic7xxx_proc.c,v 4.0 1996/10/13 08:23:42 deang Exp $
+ * $Id: aic7xxx_proc.c,v 4.1 1997/06/97 08:23:42 deang Exp $
*-M*************************************************************************/
#define BLS buffer + len + size
@@ -77,16 +77,18 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
struct Scsi_Host *HBAptr;
struct aic7xxx_host *p;
static u8 buff[512];
- int i;
+ int i;
+ int found = FALSE;
int size = 0;
int len = 0;
off_t begin = 0;
off_t pos = 0;
static char *bus_names[] = { "Single", "Twin", "Wide" };
- static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-787x", "AIC-788x" };
+ static char *chip_names[] = { "AIC-777x", "AIC-785x", "AIC-786x",
+ "AIC-787x", "AIC-788x" };
HBAptr = NULL;
- for (i = 0; i < NUMBER(aic7xxx_boards); i++)
+ for (i=0; i < NUMBER(aic7xxx_boards); i++)
{
if ((HBAptr = aic7xxx_boards[i]) != NULL)
{
@@ -95,16 +97,23 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
break;
}
- while ((HBAptr->hostdata != NULL) &&
+ while ((HBAptr->hostdata != NULL) && !found &&
((HBAptr = ((struct aic7xxx_host *) HBAptr->hostdata)->next) != NULL))
{
if (HBAptr->host_no == hostno)
{
- break; break;
+ found = TRUE;
}
}
- HBAptr = NULL;
+ if (!found)
+ {
+ HBAptr = NULL;
+ }
+ else
+ {
+ break;
+ }
}
}
@@ -129,8 +138,10 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
size += sprintf(BLS, "Adaptec AIC7xxx driver version: ");
size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_C_VERSION));
- size += sprintf(BLS, "%s/", rcs_version(AIC7XXX_H_VERSION));
+ size += sprintf(BLS, "%s", rcs_version(AIC7XXX_H_VERSION));
+#if 0
size += sprintf(BLS, "%s\n", rcs_version(AIC7XXX_SEQ_VER));
+#endif
len += size; pos = begin + len; size = 0;
size += sprintf(BLS, "\n");
@@ -141,11 +152,6 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
#ifdef AIC7XXX_CMDS_PER_LUN
size += sprintf(BLS, " AIC7XXX_CMDS_PER_LUN : %d\n", AIC7XXX_CMDS_PER_LUN);
#endif
-#ifdef AIC7XXX_TWIN_SUPPORT
- size += sprintf(BLS, " AIC7XXX_TWIN_SUPPORT : Enabled\n");
-#else
- size += sprintf(BLS, " AIC7XXX_TWIN_SUPPORT : Disabled\n");
-#endif
#ifdef AIC7XXX_TAGGED_QUEUEING
size += sprintf(BLS, " AIC7XXX_TAGGED_QUEUEING: Enabled\n");
#else
@@ -165,16 +171,18 @@ aic7xxx_proc_info(char *buffer, char **start, off_t offset, int length,
size += sprintf(BLS, "\n");
size += sprintf(BLS, "Adapter Configuration:\n");
- size += sprintf(BLS, " SCSI Adapter: %s\n", board_names[p->type]);
+ size += sprintf(BLS, " SCSI Adapter: %s\n",
+ board_names[p->chip_type]);
size += sprintf(BLS, " (%s chipset)\n",
- chip_names[p->chip_type]);
+ chip_names[p->chip_class]);
size += sprintf(BLS, " Host Bus: %s\n", bus_names[p->bus_type]);
size += sprintf(BLS, " Base IO: %#.4x\n", p->base);
+ size += sprintf(BLS, " Base IO Memory: 0x%x\n", p->mbase);
size += sprintf(BLS, " IRQ: %d\n", HBAptr->irq);
size += sprintf(BLS, " SCBs: Used %d, HW %d, Page %d\n",
- p->scb_link->numscbs, p->maxhscbs, p->maxscbs);
+ p->scb_data->numscbs, p->scb_data->maxhscbs, p->scb_data->maxscbs);
size += sprintf(BLS, " Interrupts: %d", p->isr_count);
- if (p->chip_type == AIC_777x)
+ if (p->chip_class == AIC_777x)
{
size += sprintf(BLS, " %s\n",
(p->pause & IRQMS) ? "(Level Sensitive)" : "(Edge Triggered)");
diff --git a/drivers/scsi/aic7xxx_reg.h b/drivers/scsi/aic7xxx_reg.h
index d26a0c20e..f3b8c349c 100644
--- a/drivers/scsi/aic7xxx_reg.h
+++ b/drivers/scsi/aic7xxx_reg.h
@@ -1,771 +1,469 @@
-/*+M*************************************************************************
- * Adaptec AIC7xxx register and scratch ram definitions.
- *
- * Copyright (c) 1994, 1995, 1996 Justin T. Gibbs.
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; see the file COPYING. If not, write to
- * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * This version corresponds to version 1.12 of FreeBSDs aic7xxx_reg.h
- *
- * $Id: aic7xxx_reg.h,v 4.0 1996/10/13 08:23:42 deang Exp $
- *-M*************************************************************************/
-
/*
- * This header is shared by the sequencer code and the kernel level driver.
- *
- * All page numbers refer to the Adaptec AIC-7770 Data Book available from
- * Adaptec's Technical Documents Department 1-800-934-2766
- */
+ * DO NOT EDIT - This file is automatically generated.
+ */
+
+#define SCSISEQ 0x00
+#define TEMODE 0x80
+#define ENSELO 0x40
+#define ENSELI 0x20
+#define ENRSELI 0x10
+#define ENAUTOATNO 0x08
+#define ENAUTOATNI 0x04
+#define ENAUTOATNP 0x02
+#define SCSIRSTO 0x01
+
+#define SXFRCTL0 0x01
+#define DFON 0x80
+#define DFPEXP 0x40
+#define FAST20 0x20
+#define CLRSTCNT 0x10
+#define SPIOEN 0x08
+#define SCAMEN 0x04
+#define CLRCHN 0x02
+
+#define SXFRCTL1 0x02
+#define BITBUCKET 0x80
+#define SWRAPEN 0x40
+#define ENSPCHK 0x20
+#define STIMESEL 0x18
+#define ENSTIMER 0x04
+#define ACTNEGEN 0x02
+#define STPWEN 0x01
+
+#define SCSISIGO 0x03
+#define CDO 0x80
+#define IOO 0x40
+#define MSGO 0x20
+#define ATNO 0x10
+#define SELO 0x08
+#define BSYO 0x04
+#define REQO 0x02
+#define ACKO 0x01
+
+#define SCSISIGI 0x03
+#define ATNI 0x10
+#define SELI 0x08
+#define BSYI 0x04
+#define REQI 0x02
+#define ACKI 0x01
+
+#define SCSIRATE 0x04
+#define WIDEXFER 0x80
+#define SXFR 0x70
+#define SOFS 0x0f
+
+#define SCSIID 0x05
+#define OID 0x0f
+
+#define SCSIDATL 0x06
+
+#define SCSIDATH 0x07
+
+#define STCNT 0x08
+
+#define CLRSINT0 0x0b
+#define CLRSELDO 0x40
+#define CLRSELDI 0x20
+#define CLRSELINGO 0x10
+#define CLRSWRAP 0x08
+#define CLRSPIORDY 0x02
+
+#define SSTAT0 0x0b
+#define TARGET 0x80
+#define SELDO 0x40
+#define SELDI 0x20
+#define SELINGO 0x10
+#define SWRAP 0x08
+#define SDONE 0x04
+#define SPIORDY 0x02
+#define DMADONE 0x01
+
+#define CLRSINT1 0x0c
+#define CLRSELTIMEO 0x80
+#define CLRATNO 0x40
+#define CLRSCSIRSTI 0x20
+#define CLRBUSFREE 0x08
+#define CLRSCSIPERR 0x04
+#define CLRPHASECHG 0x02
+#define CLRREQINIT 0x01
+
+#define SSTAT1 0x0c
+#define SELTO 0x80
+#define ATNTARG 0x40
+#define SCSIRSTI 0x20
+#define PHASEMIS 0x10
+#define BUSFREE 0x08
+#define SCSIPERR 0x04
+#define PHASECHG 0x02
+#define REQINIT 0x01
+
+#define SSTAT2 0x0d
+#define OVERRUN 0x80
+#define SFCNT 0x1f
+
+#define SSTAT3 0x0e
+#define SCSICNT 0xf0
+#define OFFCNT 0x0f
+
+#define SCSITEST 0x0f
+#define RQAKCNT 0x04
+#define CNTRTEST 0x02
+#define CMODE 0x01
+
+#define SIMODE0 0x10
+#define ENSELDO 0x40
+#define ENSELDI 0x20
+#define ENSELINGO 0x10
+#define ENSWRAP 0x08
+#define ENSDONE 0x04
+#define ENSPIORDY 0x02
+#define ENDMADONE 0x01
+
+#define SIMODE1 0x11
+#define ENSELTIMO 0x80
+#define ENATNTARG 0x40
+#define ENSCSIRST 0x20
+#define ENPHASEMIS 0x10
+#define ENBUSFREE 0x08
+#define ENSCSIPERR 0x04
+#define ENPHASECHG 0x02
+#define ENREQINIT 0x01
+
+#define SCSIBUSL 0x12
+
+#define SCSIBUSH 0x13
+
+#define SHADDR 0x14
+
+#define SELTIMER 0x18
+#define STAGE6 0x20
+#define STAGE5 0x10
+#define STAGE4 0x08
+#define STAGE3 0x04
+#define STAGE2 0x02
+#define STAGE1 0x01
+
+#define SELID 0x19
+#define SELID_MASK 0xf0
+#define ONEBIT 0x08
+
+#define BRDCTL 0x1d
+#define BRDDAT7 0x80
+#define BRDDAT6 0x40
+#define BRDDAT5 0x20
+#define BRDSTB 0x10
+#define BRDCS 0x08
+#define BRDRW 0x04
+#define BRDCTL1 0x02
+#define BRDCTL0 0x01
+
+#define SEECTL 0x1e
+#define EXTARBACK 0x80
+#define EXTARBREQ 0x40
+#define SEEMS 0x20
+#define SEERDY 0x10
+#define SEECS 0x08
+#define SEECK 0x04
+#define SEEDO 0x02
+#define SEEDI 0x01
+
+#define SBLKCTL 0x1f
+#define DIAGLEDEN 0x80
+#define DIAGLEDON 0x40
+#define AUTOFLUSHDIS 0x20
+#define SELWIDE 0x02
+
+#define SRAM_BASE 0x20
+
+#define TARG_SCRATCH 0x20
+
+#define ULTRA_ENB 0x30
+
+#define DISC_DSB 0x32
+
+#define MSG_LEN 0x34
+
+#define MSG_OUT 0x35
+
+#define DMAPARAMS 0x3d
+#define WIDEODD 0x40
+#define SCSIEN 0x20
+#define SDMAENACK 0x10
+#define SDMAEN 0x10
+#define HDMAEN 0x08
+#define HDMAENACK 0x08
+#define DIRECTION 0x04
+#define FIFOFLUSH 0x02
+#define FIFORESET 0x01
-/*
- * SCSI Sequence Control (p. 3-11).
- * Each bit, when set starts a specific SCSI sequence on the bus
- */
-#define SCSISEQ 0x000
-#define TEMODEO 0x80
-#define ENSELO 0x40
-#define ENSELI 0x20
-#define ENRSELI 0x10
-#define ENAUTOATNO 0x08
-#define ENAUTOATNI 0x04
-#define ENAUTOATNP 0x02
-#define SCSIRSTO 0x01
+#define SCBCOUNT 0x3e
-/*
- * SCSI Transfer Control 0 Register (pp. 3-13).
- * Controls the SCSI module data path.
- */
-#define SXFRCTL0 0x001
-#define DFON 0x80
-#define DFPEXP 0x40
-#define ULTRAEN 0x20
-#define CLRSTCNT 0x10
-#define SPIOEN 0x08
-#define SCAMEN 0x04
-#define CLRCHN 0x02
-/* UNUSED 0x01 */
+#define COMP_SCBCOUNT 0x3f
-/*
- * SCSI Transfer Control 1 Register (pp. 3-14,15).
- * Controls the SCSI module data path.
- */
-#define SXFRCTL1 0x002
-#define BITBUCKET 0x80
-#define SWRAPEN 0x40
-#define ENSPCHK 0x20
-#define STIMESEL 0x18
-#define ENSTIMER 0x04
-#define ACTNEGEN 0x02
-#define STPWEN 0x01 /* Powered Termination */
+#define QCNTMASK 0x40
-/*
- * SCSI Control Signal Read Register (p. 3-15).
- * Reads the actual state of the SCSI bus pins
- */
-#define SCSISIGI 0x003
-#define CDI 0x80
-#define IOI 0x40
-#define MSGI 0x20
-#define ATNI 0x10
-#define SELI 0x08
-#define BSYI 0x04
-#define REQI 0x02
-#define ACKI 0x01
+#define SEQ_FLAGS 0x41
+#define RESELECTED 0x80
+#define IDENTIFY_SEEN 0x40
+#define TAGGED_SCB 0x20
+#define DPHASE 0x10
+#define PAGESCBS 0x04
+#define WIDE_BUS 0x02
+#define TWIN_BUS 0x01
-/*
- * Possible phases in SCSISIGI
- */
-#define PHASE_MASK 0xe0
-#define P_DATAOUT 0x00
-#define P_DATAIN 0x40
-#define P_COMMAND 0x80
-#define P_MESGOUT 0xa0
-#define P_STATUS 0xc0
-#define P_MESGIN 0xe0
-/*
- * SCSI Control Signal Write Register (p. 3-16).
- * Writing to this register modifies the control signals on the bus. Only
- * those signals that are allowed in the current mode (Initiator/Target) are
- * asserted.
- */
-#define SCSISIGO 0x003
-#define CDO 0x80
-#define IOO 0x40
-#define MSGO 0x20
-#define ATNO 0x10
-#define SELO 0x08
-#define BSYO 0x04
-#define REQO 0x02
-#define ACKO 0x01
-
-/*
- * SCSI Rate Control (p. 3-17).
- * Contents of this register determine the Synchronous SCSI data transfer
- * rate and the maximum synchronous Req/Ack offset. An offset of 0 in the
- * SOFS (3:0) bits disables synchronous data transfers. Any offset value
- * greater than 0 enables synchronous transfers.
- */
-#define SCSIRATE 0x004
-#define WIDEXFER 0x80 /* Wide transfer control */
-#define SXFR 0x70 /* Sync transfer rate */
-#define SOFS 0x0f /* Sync offset */
+#define SAVED_TCL 0x42
-/*
- * SCSI ID (p. 3-18).
- * Contains the ID of the board and the current target on the
- * selected channel.
- */
-#define SCSIID 0x005
-#define TID 0xf0 /* Target ID mask */
-#define OID 0x0f /* Our ID mask */
+#define SG_COUNT 0x43
-/*
- * SCSI Latched Data (p. 3-19).
- * Read/Write latches used to transfer data on the SCSI bus during
- * Automatic or Manual PIO mode. SCSIDATH can be used for the
- * upper byte of a 16bit wide asynchronous data phase transfer.
- */
-#define SCSIDATL 0x006
-#define SCSIDATH 0x007
+#define SG_NEXT 0x44
-/*
- * SCSI Transfer Count (pp. 3-19,20)
- * These registers count down the number of bytes transfered
- * across the SCSI bus. The counter is decremented only once
- * the data has been safely transfered. SDONE in SSTAT0 is
- * set when STCNT goes to 0
- */
-#define STCNT 0x008
-#define STCNT0 0x008
-#define STCNT1 0x009
-#define STCNT2 0x00a
+#define WAITING_SCBH 0x48
-/*
- * Clear SCSI Interrupt 0 (p. 3-20)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT0.
- */
-#define CLRSINT0 0x00b
-#define CLRSELDO 0x40
-#define CLRSELDI 0x20
-#define CLRSELINGO 0x10
-#define CLRSWRAP 0x08
-/* UNUSED 0x04 */
-#define CLRSPIORDY 0x02
-/* UNUSED 0x01 */
+#define SAVED_LINKPTR 0x49
-/*
- * SCSI Status 0 (p. 3-21)
- * Contains one set of SCSI Interrupt codes
- * These are most likely of interest to the sequencer
- */
-#define SSTAT0 0x00b
-#define TARGET 0x80 /* Board acting as target */
-#define SELDO 0x40 /* Selection Done */
-#define SELDI 0x20 /* Board has been selected */
-#define SELINGO 0x10 /* Selection In Progress */
-#define SWRAP 0x08 /* 24bit counter wrap */
-#define SDONE 0x04 /* STCNT = 0x000000 */
-#define SPIORDY 0x02 /* SCSI PIO Ready */
-#define DMADONE 0x01 /* DMA transfer completed */
+#define SAVED_SCBPTR 0x4a
-/*
- * Clear SCSI Interrupt 1 (p. 3-23)
- * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
- */
-#define CLRSINT1 0x00c
-#define CLRSELTIMEO 0x80
-#define CLRATNO 0x40
-#define CLRSCSIRSTI 0x20
-/* UNUSED 0x10 */
-#define CLRBUSFREE 0x08
-#define CLRSCSIPERR 0x04
-#define CLRPHASECHG 0x02
-#define CLRREQINIT 0x01
+#define REJBYTE 0x4b
-/*
- * SCSI Status 1 (p. 3-24)
- */
-#define SSTAT1 0x00c
-#define SELTO 0x80
-#define ATNTARG 0x40
-#define SCSIRSTI 0x20
-#define PHASEMIS 0x10
-#define BUSFREE 0x08
-#define SCSIPERR 0x04
-#define PHASECHG 0x02
-#define REQINIT 0x01
+#define LASTPHASE 0x4c
+#define P_MESGIN 0xe0
+#define PHASE_MASK 0xe0
+#define P_STATUS 0xc0
+#define P_MESGOUT 0xa0
+#define P_COMMAND 0x80
+#define CDI 0x80
+#define IOI 0x40
+#define P_DATAIN 0x40
+#define MSGI 0x20
+#define P_BUSFREE 0x01
+#define P_DATAOUT 0x00
-/*
- * SCSI Interrupt Mode 1 (pp. 3-28,29)
- * Setting any bit will enable the corresponding function
- * in SIMODE1 to interrupt via the IRQ pin.
- */
-#define SIMODE1 0x011
-#define ENSELTIMO 0x80
-#define ENATNTARG 0x40
-#define ENSCSIRST 0x20
-#define ENPHASEMIS 0x10
-#define ENBUSFREE 0x08
-#define ENSCSIPERR 0x04
-#define ENPHASECHG 0x02
-#define ENREQINIT 0x01
+#define MSGIN_EXT_LEN 0x4d
-/*
- * SCSI Data Bus (High) (p. 3-29)
- * This register reads data on the SCSI Data bus directly.
- */
-#define SCSIBUSL 0x012
-#define SCSIBUSH 0x013
+#define MSGIN_EXT_OPCODE 0x4e
-/*
- * SCSI/Host Address (p. 3-30)
- * These registers hold the host address for the byte about to be
- * transfered on the SCSI bus. They are counted up in the same
- * manner as STCNT is counted down. SHADDR should always be used
- * to determine the address of the last byte transfered since HADDR
- * can be skewed by write ahead.
- */
-#define SHADDR 0x014
-#define SHADDR0 0x014
-#define SHADDR1 0x015
-#define SHADDR2 0x016
-#define SHADDR3 0x017
+#define MSGIN_EXT_BYTES 0x4f
-/*
- * Selection/Reselection ID (p. 3-31)
- * Upper four bits are the device id. The ONEBIT is set when the re/selecting
- * device did not set its own ID.
- */
-#define SELID 0x019
-#define SELID_MASK 0xf0
-#define ONEBIT 0x08
-/* UNUSED 0x07 */
+#define DISCONNECTED_SCBH 0x52
-/*
- * SCSI Block Control (p. 3-32)
- * Controls Bus type and channel selection. In a twin channel configuration
- * addresses 0x00-0x1e are gated to the appropriate channel based on this
- * register. SELWIDE allows for the coexistence of 8bit and 16bit devices
- * on a wide bus.
- */
-#define SBLKCTL 0x01f
-#define DIAGLEDEN 0x80 /* Aic78X0 only */
-#define DIAGLEDON 0x40 /* Aic78X0 only */
-#define AUTOFLUSHDIS 0x20
-/* UNUSED 0x10 */
-#define SELBUS_MASK 0x0a
-#define SELBUSB 0x08
-/* UNUSED 0x04 */
-#define SELWIDE 0x02
-/* UNUSED 0x01 */
-#define SELNARROW 0x00
+#define FREE_SCBH 0x53
-/*
- * Sequencer Control (p. 3-33)
- * Error detection mode and speed configuration
- */
-#define SEQCTL 0x060
-#define PERRORDIS 0x80
-#define PAUSEDIS 0x40
-#define FAILDIS 0x20
-#define FASTMODE 0x10
-#define BRKADRINTEN 0x08
-#define STEP 0x04
-#define SEQRESET 0x02
-#define LOADRAM 0x01
+#define HSCB_ADDR 0x54
-/*
- * Sequencer RAM Data (p. 3-34)
- * Single byte window into the Scratch Ram area starting at the address
- * specified by SEQADDR0 and SEQADDR1. To write a full word, simply write
- * four bytes in succession. The SEQADDRs will increment after the most
- * significant byte is written
- */
-#define SEQRAM 0x061
+#define CUR_SCBID 0x58
-/*
- * Sequencer Address Registers (p. 3-35)
- * Only the first bit of SEQADDR1 holds addressing information
- */
-#define SEQADDR0 0x062
-#define SEQADDR1 0x063
-#define SEQADDR1_MASK 0x01
+#define ARG_1 0x59
+#define RETURN_1 0x59
+#define SEND_MSG 0x80
+#define SEND_SENSE 0x40
+#define SEND_REJ 0x20
-/*
- * Accumulator
- * We cheat by passing arguments in the Accumulator up to the kernel driver
- */
-#define ACCUM 0x064
-
-#define SINDEX 0x065
-#define DINDEX 0x066
-#define ALLZEROS 0x06a
-#define NONE 0x06a
-#define SINDIR 0x06c
-#define DINDIR 0x06d
-#define FUNCTION1 0x06e
+#define SCSICONF 0x5a
+#define RESET_SCSI 0x40
-/*
- * Host Address (p. 3-48)
- * This register contains the address of the byte about
- * to be transfered across the host bus.
- */
-#define HADDR 0x088
-#define HADDR0 0x088
-#define HADDR1 0x089
-#define HADDR2 0x08a
-#define HADDR3 0x08b
-
-#define HCNT 0x08c
-#define HCNT0 0x08c
-#define HCNT1 0x08d
-#define HCNT2 0x08e
-/*
- * SCB Pointer (p. 3-49)
- * Gate one of the four SCBs into the SCBARRAY window.
- */
-#define SCBPTR 0x090
+#define HOSTCONF 0x5d
-/*
- * Board Control (p. 3-43)
- */
-#define BCTL 0x084
-/* RSVD 0xf0 */
-#define ACE 0x08 /* Support for external processors */
-/* RSVD 0x06 */
-#define ENABLE 0x01
+#define HA_274_BIOSCTRL 0x5f
+#define BIOSMODE 0x30
+#define BIOSDISABLED 0x30
+#define CHANNEL_B_PRIMARY 0x08
-/*
- * On the aic78X0 chips, Board Control is replaced by the DSCommand
- * register (p. 4-64)
- */
-#define DSCOMMAND 0x084
-#define CACHETHEN 0x80 /* Cache Threshold enable */
-#define DPARCKEN 0x40 /* Data Parity Check Enable */
-#define MPARCKEN 0x20 /* Memory Parity Check Enable */
-#define EXTREQLCK 0x10 /* External Request Lock */
+#define SEQCTL 0x60
+#define PERRORDIS 0x80
+#define PAUSEDIS 0x40
+#define FAILDIS 0x20
+#define FASTMODE 0x10
+#define BRKADRINTEN 0x08
+#define STEP 0x04
+#define SEQRESET 0x02
+#define LOADRAM 0x01
-/*
- * Bus On/Off Time (p. 3-44)
- */
-#define BUSTIME 0x085
-#define BOFF 0xf0
-#define BON 0x0f
+#define SEQRAM 0x61
-/*
- * Bus Speed (p. 3-45)
- */
-#define BUSSPD 0x086
-#define DFTHRSH 0xc0
-#define STBOFF 0x38
-#define STBON 0x07
-#define DFTHRSH_100 0xc0
+#define SEQADDR0 0x62
-/*
- * Host Control (p. 3-47) R/W
- * Overall host control of the device.
- */
-#define HCNTRL 0x087
-/* UNUSED 0x80 */
-#define POWRDN 0x40
-/* UNUSED 0x20 */
-#define SWINT 0x10
-#define IRQMS 0x08
-#define PAUSE 0x04
-#define INTEN 0x02
-#define CHIPRST 0x01
-#define CHIPRSTACK 0x01
+#define SEQADDR1 0x63
+#define SEQADDR1_MASK 0x01
-/*
- * Interrupt Status (p. 3-50)
- * Status for system interrupts
- */
-#define INTSTAT 0x091
-#define SEQINT_MASK 0xf1 /* SEQINT Status Codes */
-#define BAD_PHASE 0x01 /* unknown scsi bus phase */
-#define SEND_REJECT 0x11 /* sending a message reject */
-#define NO_IDENT 0x21 /* no IDENTIFY after reconnect*/
-#define NO_MATCH 0x31 /* no cmd match for reconnect */
-#define SDTR_MSG 0x41 /* SDTR message received */
-#define WDTR_MSG 0x51 /* WDTR message received */
-#define REJECT_MSG 0x61 /* Reject message received */
-#define BAD_STATUS 0x71 /* Bad status from target */
-#define RESIDUAL 0x81 /* Residual byte count != 0 */
-#define ABORT_TAG 0x91 /* Sent an ABORT_TAG message */
-#define AWAITING_MSG 0xa1 /*
- * Kernel requested to specify
- * a message to this target
- * (command was null), so tell
- * it that it can fill the
- * message buffer.
- */
-#define IMMEDDONE 0xb1 /*
- * An immediate command has
- * completed
- */
-#define MSG_BUFFER_BUSY 0xc1 /*
- * Sequencer wants to use the
- * message buffer, but it
- * already contains a message
- */
-#define MSGIN_PHASEMIS 0xd1 /*
- * Target changed phase on us
- * when we were expecting
- * another msgin byte.
- */
-#define DATA_OVERRUN 0xe1 /*
- * Target attempted to write
- * beyond the bounds of its
- * command.
- */
-#define BRKADRINT 0x08
-#define SCSIINT 0x04
-#define CMDCMPLT 0x02
-#define SEQINT 0x01
-#define INT_PEND (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
+#define ACCUM 0x64
-/*
- * Hard Error (p. 3-53)
- * Reporting of catastrophic errors. You usually cannot recover from
- * these without a full board reset.
- */
-#define ERROR 0x092
-/* UNUSED 0xf0 */
-#define PARERR 0x08
-#define ILLOPCODE 0x04
-#define ILLSADDR 0x02
-#define ILLHADDR 0x01
+#define SINDEX 0x65
-/*
- * Clear Interrupt Status (p. 3-52)
- */
-#define CLRINT 0x092
-#define CLRBRKADRINT 0x08
-#define CLRSCSIINT 0x04
-#define CLRCMDINT 0x02
-#define CLRSEQINT 0x01
-
-#define DFCNTRL 0x093
-#define WIDEODD 0x40
-#define SCSIEN 0x20
-#define SDMAEN 0x10
-#define SDMAENACK 0x10
-#define HDMAEN 0x08
-#define HDMAENACK 0x08
-#define DIRECTION 0x04
-#define FIFOFLUSH 0x02
-#define FIFORESET 0x01
-
-#define DFSTATUS 0x094
-#define HDONE 0x08
-#define FIFOEMP 0x01
-
-#define DFDAT 0x099
+#define DINDEX 0x66
-/*
- * SCB Auto Increment (p. 3-59)
- * Byte offset into the SCB Array and an optional bit to allow auto
- * incrementing of the address during download and upload operations
- */
-#define SCBCNT 0x09a
-#define SCBAUTO 0x80
-#define SCBCNT_MASK 0x1f
+#define ALLONES 0x69
-/*
- * Queue In FIFO (p. 3-60)
- * Input queue for queued SCBs (commands that the sequencer has yet to start)
- */
-#define QINFIFO 0x09b
+#define ALLZEROS 0x6a
-/*
- * Queue In Count (p. 3-60)
- * Number of queued SCBs
- */
-#define QINCNT 0x09c
+#define NONE 0x6a
-/*
- * Queue Out FIFO (p. 3-61)
- * Queue of SCBs that have completed and await the host
- */
-#define QOUTFIFO 0x09d
+#define FLAGS 0x6b
+#define ZERO 0x02
+#define CARRY 0x01
-/*
- * Queue Out Count (p. 3-61)
- * Number of queued SCBs in the Out FIFO
- */
-#define QOUTCNT 0x09e
+#define SINDIR 0x6c
-/*
- * SCB Definition (p. 5-4)
- * The two reserved bytes at SCBARRAY+1[23] are expected to be set to
- * zero. Bit 3 in SCBARRAY+0 is used as an internal flag to indicate
- * whether or not to DMA an SCB from host ram. This flag prevents the
- * "re-fetching" of transactions that are requeued because the target is
- * busy with another command. We also use bits 6 & 7 to indicate whether
- * or not to initiate SDTR or WDTR respectively when starting this command.
- */
-#define SCBARRAY 0x0a0
-#define SCB_CONTROL 0x0a0
-#define NEEDWDTR 0x80
-#define DISCENB 0x40
-#define TAG_ENB 0x20
-#define NEEDSDTR 0x10
-#define DISCONNECTED 0x04
-#define SCB_TAG_TYPE 0x03
-#define SCB_TCL 0x0a1
-#define SCB_TARGET_STATUS 0x0a2
-#define SCB_SGCOUNT 0x0a3
-#define SCB_SGPTR 0x0a4
-#define SCB_SGPTR0 0x0a4
-#define SCB_SGPTR1 0x0a5
-#define SCB_SGPTR2 0x0a6
-#define SCB_SGPTR3 0x0a7
-#define SCB_RESID_SGCNT 0x0a8
-#define SCB_RESID_DCNT 0x0a9
-#define SCB_RESID_DCNT0 0x0a9
-#define SCB_RESID_DCNT1 0x0aa
-#define SCB_RESID_DCNT2 0x0ab
-#define SCB_DATAPTR 0x0ac
-#define SCB_DATAPTR0 0x0ac
-#define SCB_DATAPTR1 0x0ad
-#define SCB_DATAPTR2 0x0ae
-#define SCB_DATAPTR3 0x0af
-#define SCB_DATACNT 0x0b0
-#define SCB_DATACNT0 0x0b0
-#define SCB_DATACNT1 0x0b1
-#define SCB_DATACNT2 0x0b2
-/* UNUSED - QUAD PADDING 0x0b3 */
-#define SCB_CMDPTR 0x0b4
-#define SCB_CMDPTR0 0x0b4
-#define SCB_CMDPTR1 0x0b5
-#define SCB_CMDPTR2 0x0b6
-#define SCB_CMDPTR3 0x0b7
-#define SCB_CMDLEN 0x0b8
-#define SCB_TAG 0x0b9
-#define SCB_NEXT 0x0ba
-#define SCB_PREV 0x0bb
-
-#define SG_SIZEOF 0x08 /* sizeof(struct ahc_dma) */
-
-/* --------------------- AHA-2840-only definitions -------------------- */
-
-#define SEECTL_2840 0x0c0
-/* UNUSED 0xf8 */
-#define CS_2840 0x04
-#define CK_2840 0x02
-#define DO_2840 0x01
-
-#define STATUS_2840 0x0c1
-#define EEPROM_TF 0x80
-#define BIOS_SEL 0x60
-#define ADSEL 0x1e
-#define DI_2840 0x01
-
-/* --------------------- AIC-7870-only definitions -------------------- */
-
-#define DSPCISTATUS 0x086
+#define DINDIR 0x6d
-/*
- * Serial EEPROM Control (p. 4-92 in 7870 Databook)
- * Controls the reading and writing of an external serial 1-bit
- * EEPROM Device. In order to access the serial EEPROM, you must
- * first set the SEEMS bit that generates a request to the memory
- * port for access to the serial EEPROM device. When the memory
- * port is not busy servicing another request, it reconfigures
- * to allow access to the serial EEPROM. When this happens, SEERDY
- * gets set high to verify that the memory port access has been
- * granted.
- *
- * After successful arbitration for the memory port, the SEECS bit of
- * the SEECTL register is connected to the chip select. The SEECK,
- * SEEDO, and SEEDI are connected to the clock, data out, and data in
- * lines respectively. The SEERDY bit of SEECTL is useful in that it
- * gives us an 800 nsec timer. After a write to the SEECTL register,
- * the SEERDY goes high 800 nsec later. The one exception to this is
- * when we first request access to the memory port. The SEERDY goes
- * high to signify that access has been granted and, for this case, has
- * no implied timing.
- *
- * See 93cx6.c for detailed information on the protocol necessary to
- * read the serial EEPROM.
- */
-#define SEECTL 0x01e
-#define EXTARBACK 0x80
-#define EXTARBREQ 0x40
-#define SEEMS 0x20
-#define SEERDY 0x10
-#define SEECS 0x08
-#define SEECK 0x04
-#define SEEDO 0x02
-#define SEEDI 0x01
-
-/* ---------------------- Scratch RAM Offsets ------------------------- */
-/* These offsets are either to values that are initialized by the board's
- * BIOS or are specified by the sequencer code.
- *
- * The host adapter card (at least the BIOS) uses 20-2f for SCSI
- * device information, 32-33 and 5a-5f as well. As it turns out, the
- * BIOS trashes 20-2f, writing the synchronous negotiation results
- * on top of the BIOS values, so we re-use those for our per-target
- * scratchspace (actually a value that can be copied directly into
- * SCSIRATE). The kernel driver will enable synchronous negotiation
- * for all targets that have a value other than 0 in the lower four
- * bits of the target scratch space. This should work regardless of
- * whether the bios has been installed.
- */
+#define FUNCTION1 0x6e
-/*
- * 1 byte per target starting at this address for configuration values
- */
-#define TARG_SCRATCH 0x020
+#define STACK 0x6f
-/*
- * The sequencer will stick the frist byte of any rejected message here so
- * we can see what is getting thrown away. Extended messages put the
- * extended message type in REJBYTE_EXT.
- */
-#define REJBYTE 0x030
-#define REJBYTE_EXT 0x031
+#define BCTL 0x84
+#define ACE 0x08
+#define ENABLE 0x01
-/*
- * Bit vector of targets that have disconnection disabled.
- */
-#define DISC_DSB 0x032
-#define DISC_DSB_A 0x032
-#define DISC_DSB_B 0x033
+#define DSCOMMAND 0x84
+#define CACHETHEN 0x80
+#define DPARCKEN 0x40
+#define MPARCKEN 0x20
+#define EXTREQLCK 0x10
-/*
- * Length of pending message
- */
-#define MSG_LEN 0x034
-
-/* We reserve 8bytes to store outgoing messages */
-#define MSG0 0x035
-#define COMP_MSG0 0xcb /* 2's complement of MSG0 */
-#define MSG1 0x036
-#define MSG2 0x037
-#define MSG3 0x038
-#define MSG4 0x039
-#define MSG5 0x03a
-#define MSG6 0x03b
-#define MSG7 0x03c
+#define BUSTIME 0x85
+#define BOFF 0xf0
+#define BON 0x0f
-/*
- * These are offsets into the card's scratch ram. Some of the values are
- * specified in the AHA2742 technical reference manual and are initialized
- * by the BIOS at boot time.
- */
-#define LASTPHASE 0x03d
-#define ARG_1 0x03e
-#define MAXOFFSET 0x01
-#define RETURN_1 0x03f
-#define SEND_WDTR 0x80
-#define SEND_SDTR 0x60
-#define SEND_SENSE 0x40
-#define SEND_REJ 0x20
-#define SCB_PAGEDIN 0x10
-
-#define SIGSTATE 0x040
-
-#define DMAPARAMS 0x041 /* Parameters for DMA Logic */
-
-#define SG_COUNT 0x042
-#define SG_NEXT 0x043 /* working value of SG pointer */
-#define SG_NEXT0 0x043
-#define SG_NEXT1 0x044
-#define SG_NEXT2 0x045
-#define SG_NEXT3 0x046
-
-#define SCBCOUNT 0x047 /*
- * Number of SCBs supported by
- * this card.
- */
-#define COMP_SCBCOUNT 0x048 /*
- * Two's compliment of SCBCOUNT
- */
-#define QCNTMASK 0x049 /*
- * Mask of bits to test against
- * when looking at the Queue Count
- * registers. Works around a bug
- * on aic7850 chips.
- */
-#define FLAGS 0x04a
-#define SINGLE_BUS 0x00
-#define TWIN_BUS 0x01
-#define WIDE_BUS 0x02
-#define PAGESCBS 0x04
-#define DPHASE 0x10
-#define SELECTED 0x20
-#define IDENTIFY_SEEN 0x40
-#define RESELECTED 0x80
-
-#define SAVED_TCL 0x04b /*
- * Temporary storage for the
- * target/channel/lun of a
- * reconnecting target
- */
-#define ACTIVE_A 0x04c
-#define ACTIVE_B 0x04d
-#define WAITING_SCBH 0x04e /*
- * head of list of SCBs awaiting
- * selection
- */
-#define DISCONNECTED_SCBH 0x04f /*
- * head of list of SCBs that are
- * disconnected. Used for SCB
- * paging.
- */
-#define SCB_LIST_NULL 0xff
-
-#define SAVED_LINKPTR 0x050
-#define SAVED_SCBPTR 0x051
-#define ULTRA_ENB 0x052
-#define ULTRA_ENB_B 0x053
-
-#define SCSICONF 0x05a
-#define RESET_SCSI 0x40
-
-#define HOSTCONF 0x05d
-
-#define HA_274_BIOSCTRL 0x05f
-#define BIOSMODE 0x30
-#define BIOSDISABLED 0x30
-#define CHANNEL_B_PRIMARY 0x08
-
-/* Message codes */
-#define MSG_EXTENDED 0x01
-#define MSG_SDTR 0x01
-#define MSG_WDTR 0x03
-#define MSG_SDPTRS 0x02
-#define MSG_RDPTRS 0x03
-#define MSG_DISCONNECT 0x04
-#define MSG_INITIATOR_DET_ERROR 0x05
-#define MSG_ABORT 0x06
-#define MSG_REJECT 0x07
-#define MSG_NOP 0x08
-#define MSG_MSG_PARITY_ERROR 0x09
-#define MSG_BUS_DEVICE_RESET 0x0c
-#define MSG_ABORT_TAG 0x0d
-#define MSG_SIMPLE_TAG 0x20
-#define MSG_IDENTIFY 0x80
-
-/* WDTR Message values */
-#define BUS_8_BIT 0x00
-#define BUS_16_BIT 0x01
-#define BUS_32_BIT 0x02
-
-#define MAX_OFFSET_8BIT 0x0f
-#define MAX_OFFSET_16BIT 0x08
+#define BUSSPD 0x86
+#define DFTHRSH_100 0xc0
+#define DFTHRSH 0xc0
+#define STBOFF 0x38
+#define STBON 0x07
+
+#define DSPCISTATUS 0x86
+
+#define HCNTRL 0x87
+#define POWRDN 0x40
+#define SWINT 0x10
+#define IRQMS 0x08
+#define PAUSE 0x04
+#define INTEN 0x02
+#define CHIPRST 0x01
+#define CHIPRSTACK 0x01
+
+#define HADDR 0x88
+
+#define HCNT 0x8c
+
+#define SCBPTR 0x90
+
+#define INTSTAT 0x91
+#define SEQINT_MASK 0xf1
+#define DATA_OVERRUN 0xe1
+#define MSGIN_PHASEMIS 0xd1
+#define MSG_BUFFER_BUSY 0xc1
+#define AWAITING_MSG 0xa1
+#define ABORT_CMDCMPLT 0x91
+#define RESIDUAL 0x81
+#define BAD_STATUS 0x71
+#define REJECT_MSG 0x61
+#define NO_MATCH_BUSY 0x51
+#define EXTENDED_MSG 0x41
+#define NO_MATCH 0x31
+#define NO_IDENT 0x21
+#define SEND_REJECT 0x11
+#define INT_PEND 0x0f
+#define BRKADRINT 0x08
+#define SCSIINT 0x04
+#define CMDCMPLT 0x02
+#define BAD_PHASE 0x01
+#define SEQINT 0x01
+
+#define CLRINT 0x92
+#define CLRBRKADRINT 0x08
+#define CLRSCSIINT 0x04
+#define CLRCMDINT 0x02
+#define CLRSEQINT 0x01
+
+#define ERROR 0x92
+#define PARERR 0x08
+#define ILLOPCODE 0x04
+#define ILLSADDR 0x02
+#define ILLHADDR 0x01
+
+#define DFCNTRL 0x93
+
+#define DFSTATUS 0x94
+#define DWORDEMP 0x20
+#define MREQPEND 0x10
+#define HDONE 0x08
+#define DFTHRESH 0x04
+#define FIFOFULL 0x02
+#define FIFOEMP 0x01
+
+#define DFDAT 0x99
+
+#define SCBCNT 0x9a
+#define SCBAUTO 0x80
+#define SCBCNT_MASK 0x1f
+
+#define QINFIFO 0x9b
+
+#define QINCNT 0x9c
+
+#define QOUTFIFO 0x9d
+
+#define QOUTCNT 0x9e
+
+#define SCB_CONTROL 0xa0
+#define MK_MESSAGE 0x80
+#define DISCENB 0x40
+#define TAG_ENB 0x20
+#define MUST_DMAUP_SCB 0x10
+#define ABORT_SCB 0x08
+#define DISCONNECTED 0x04
+#define SCB_TAG_TYPE 0x03
+
+#define SCB_BASE 0xa0
+
+#define SCB_TCL 0xa1
+#define TID 0xf0
+#define SELBUSB 0x08
+#define LID 0x07
+
+#define SCB_TARGET_STATUS 0xa2
+
+#define SCB_SGCOUNT 0xa3
+
+#define SCB_SGPTR 0xa4
+
+#define SCB_RESID_SGCNT 0xa8
+
+#define SCB_RESID_DCNT 0xa9
+
+#define SCB_DATAPTR 0xac
+
+#define SCB_DATACNT 0xb0
+
+#define SCB_LINKED_NEXT 0xb3
+
+#define SCB_CMDPTR 0xb4
+
+#define SCB_CMDLEN 0xb8
+
+#define SCB_TAG 0xb9
+
+#define SCB_NEXT 0xba
+
+#define SCB_PREV 0xbb
+
+#define SCB_BUSYTARGETS 0xbc
+
+#define SEECTL_2840 0xc0
+#define CS_2840 0x04
+#define CK_2840 0x02
+#define DO_2840 0x01
+
+#define STATUS_2840 0xc1
+#define EEPROM_TF 0x80
+#define BIOS_SEL 0x60
+#define ADSEL 0x1e
+#define DI_2840 0x01
+
+
+#define BUS_8_BIT 0x00
+#define MAX_OFFSET_8BIT 0x0f
+#define BUS_16_BIT 0x01
+#define MAX_OFFSET_16BIT 0x08
+#define SCB_LIST_NULL 0xff
+#define SG_SIZEOF 0x08
+#define BUS_32_BIT 0x02
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index 15dfb01f1..50ce159a2 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -90,6 +90,7 @@
#include <linux/sched.h>
#include <linux/interrupt.h>
#include <linux/init.h>
+#include <linux/nvram.h>
#include <asm/setup.h>
#include <asm/atarihw.h>
@@ -596,20 +597,6 @@ int atari_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
#endif
-#define RTC_READ(reg) \
- ({ unsigned char __val; \
- outb(reg,&tt_rtc.regsel); \
- __val = tt_rtc.data; \
- __val; \
- })
-
-#define RTC_WRITE(reg,val) \
- do { \
- outb(reg,&tt_rtc.regsel); \
- tt_rtc.data = (val); \
- } while(0)
-
-
int atari_scsi_detect (Scsi_Host_Template *host)
{
static int called = 0;
@@ -645,20 +632,11 @@ int atari_scsi_detect (Scsi_Host_Template *host)
/* use 7 as default */
host->this_id = 7;
/* Test if a host id is set in the NVRam */
- if (ATARIHW_PRESENT(TT_CLK)) {
- unsigned char sum = 0, b;
- int i;
-
- /* Make checksum */
- for( i = 14; i < 62; ++i )
- sum += RTC_READ(i);
-
- if (/* NV-Ram checksum valid? */
- RTC_READ(62) == sum && RTC_READ(63) == ~sum &&
- /* Arbitration enabled? (for TOS) */
- (b = RTC_READ( 30 )) & 0x80) {
+ if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
+ unsigned char b = nvram_read_byte( 14 );
+ /* Arbitration enabled? (for TOS) If yes, use configured host ID */
+ if (b & 0x80)
host->this_id = b & 7;
- }
}
}
diff --git a/drivers/scsi/eata.h b/drivers/scsi/eata.h
index cba391414..e69de29bb 100644
--- a/drivers/scsi/eata.h
+++ b/drivers/scsi/eata.h
@@ -1,41 +0,0 @@
-/*
- * eata.h - used by the low-level driver for EATA/DMA SCSI host adapters.
- */
-#ifndef _EATA_H
-#define _EATA_H
-
-#include <scsi/scsicam.h>
-
-int eata2x_detect(Scsi_Host_Template *);
-int eata2x_release(struct Scsi_Host *);
-int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int eata2x_abort(Scsi_Cmnd *);
-int eata2x_reset(Scsi_Cmnd *, unsigned int);
-
-#define EATA_VERSION "3.10.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 \
- }
-#endif
diff --git a/drivers/scsi/esp.c b/drivers/scsi/esp.c
index 0380ff99a..b479cc9fc 100644
--- a/drivers/scsi/esp.c
+++ b/drivers/scsi/esp.c
@@ -1705,7 +1705,7 @@ int esp_abort(Scsi_Cmnd *SCptr)
* the nexus and tell the device to abort. However, we really
* cannot 'reconnect' per se, therefore we tell the upper layer
* the safest thing we can. This is, wait a bit, if nothing
- * happens, we are really hung so reset the bug.
+ * happens, we are really hung so reset the bus.
*/
return SCSI_ABORT_SNOOZE;
@@ -1743,11 +1743,10 @@ static void esp_done(struct Sparc_ESP *esp, int error)
done_SC->request_bufflen,
esp->edev->my_bus);
} else {
- struct scatterlist *scl = (struct scatterlist *)done_SC->buffer;
#ifdef DEBUG_ESP_SG
printk("esp%d: unmapping sg ", esp->esp_id);
#endif
- mmu_release_scsi_sgl((struct mmu_sglist *) scl,
+ mmu_release_scsi_sgl((struct mmu_sglist *) done_SC->buffer,
done_SC->use_sg - 1,
esp->edev->my_bus);
#ifdef DEBUG_ESP_SG
@@ -2010,7 +2009,7 @@ static inline int dma_can_transfer(Scsi_Cmnd *sp, enum dvma_rev drev)
if(sz > 0x1000000)
sz = 0x1000000;
} else {
- base = ((__u32)sp->SCp.ptr);
+ base = ((__u32)((unsigned long)sp->SCp.ptr));
base &= (0x1000000 - 1);
end = (base + sp->SCp.this_residual);
if(end > 0x1000000)
@@ -2280,11 +2279,12 @@ static inline int esp_do_data(struct Sparc_ESP *esp, struct Sparc_ESP_regs *ereg
tmp |= DMA_ST_WRITE;
else
tmp &= ~(DMA_ST_WRITE);
- dregs->st_addr = ((__u32)SCptr->SCp.ptr);
+ dregs->st_addr = ((__u32)((unsigned long)SCptr->SCp.ptr));
dregs->cond_reg = tmp;
} else {
esp_setcount(eregs, hmuch, 0);
- dma_setup(dregs, esp->dma->revision, ((__u32)SCptr->SCp.ptr),
+ dma_setup(dregs, esp->dma->revision,
+ ((__u32)((unsigned long)SCptr->SCp.ptr)),
hmuch, (thisphase == in_datain));
ESPDATA(("DMA|TI --> do_intr_end\n"));
esp_cmd(esp, eregs, ESP_CMD_DMA | ESP_CMD_TI);
@@ -4059,8 +4059,12 @@ repeat:
}
#else
+/* XXX Gross hack for sun4u SMP, fix it right later... -DaveM */
#ifdef __sparc_v9__
-#error Dave you need to fix some things first...
+extern unsigned char ino_to_pil[];
+#define INO_TO_PIL(esp) (ino_to_pil[(esp)->irq])
+#else
+#define INO_TO_PIL(esp) ((esp)->irq & 0xf)
#endif
/* For SMP we only service one ESP on the list list at our IRQ level! */
@@ -4070,7 +4074,7 @@ static void esp_intr(int irq, void *dev_id, struct pt_regs *pregs)
/* Handle all ESP interrupts showing at this IRQ level. */
for_each_esp(esp) {
- if((esp->irq & 0xf) == irq) {
+ if(INO_TO_PIL(esp) == irq) {
if(DMA_IRQ_P(esp->dregs)) {
DMA_INTSOFF(esp->dregs);
diff --git a/drivers/scsi/ppa.c b/drivers/scsi/ppa.c
index e9bdcee9b..c28958703 100644
--- a/drivers/scsi/ppa.c
+++ b/drivers/scsi/ppa.c
@@ -144,7 +144,7 @@ static char *PPA_MODE_STRING[] =
"Unknown"};
typedef struct {
- struct ppd *dev; /* Parport device entry */
+ struct pardevice *dev; /* Parport device entry */
int speed; /* General PPA delay constant */
int speed_fast; /* Const for nibble/byte modes */
int epp_speed; /* Reset time period */
@@ -210,22 +210,22 @@ static int ppa_sg = SG_ALL; /* enable/disable scatter-gather. */
#define w_fifo(x,y) outb(y, PPA_BASE(x)+0x400)
#define w_ecr(x,y) outb(y, PPA_BASE(x)+0x402)
-int ppa_wakeup(void *ref)
+static void ppa_wakeup(void *ref)
{
ppa_struct *ppa_dev = (ppa_struct *) ref;
if (!ppa_dev->ppa_wait_q)
- return 1; /* Wake up whom ? */
+ return; /* Wake up whom ? */
/* Claim the Parport */
if (parport_claim(ppa_dev->dev))
- return 1; /* Shouldn't happen */
+ return; /* Shouldn't happen */
wake_up(&ppa_dev->ppa_wait_q);
- return 0;
+ return;
}
-int ppa_release(struct Scsi_Host *host)
+static int ppa_release(struct Scsi_Host *host)
{
int host_no = host->unique_id;
@@ -1137,7 +1137,7 @@ int ppa_detect(Scsi_Host_Template * host)
int modes = pb->modes;
/* We only understand PC-style ports */
- if (modes & PARPORT_MODE_SPP) {
+ if (modes & PARPORT_MODE_PCSPP) {
/* transfer global values here */
if (ppa_speed >= 0)
@@ -1156,16 +1156,16 @@ int ppa_detect(Scsi_Host_Template * host)
w_ctr(i, 0x0c);
ppa_hosts[i].mode = PPA_NIBBLE;
- if (modes & (PARPORT_MODE_EPP | PARPORT_MODE_ECPEPP)) {
+ if (modes & (PARPORT_MODE_PCEPP | PARPORT_MODE_PCECPEPP)) {
ppa_hosts[i].mode = PPA_EPP_32;
- printk("PPA: Parport [ EPP ]\n");
- } else if (modes & PARPORT_MODE_ECP) {
+ printk("PPA: Parport [ PCEPP ]\n");
+ } else if (modes & PARPORT_MODE_PCECP) {
w_ecr(i, 0x20);
ppa_hosts[i].mode = PPA_PS2;
- printk("PPA: Parport [ ECP in PS2 submode ]\n");
- } else if (modes & PARPORT_MODE_PS2) {
+ printk("PPA: Parport [ PCECP in PS2 submode ]\n");
+ } else if (modes & PARPORT_MODE_PCPS2) {
ppa_hosts[i].mode = PPA_PS2;
- printk("PPA: Parport [ PS2 ]\n");
+ printk("PPA: Parport [ PCPS2 ]\n");
}
/* Done configuration */
ppa_pb_release(i);
diff --git a/drivers/scsi/ppa.h b/drivers/scsi/ppa.h
index 84fa2dec8..cdc2fdaa6 100644
--- a/drivers/scsi/ppa.h
+++ b/drivers/scsi/ppa.h
@@ -52,7 +52,7 @@ int ppa_abort(Scsi_Cmnd *);
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*);
-int ppa_release(struct Scsi_Host *);
+static int ppa_release(struct Scsi_Host *);
#ifndef MODULE
#ifdef PPA_CODE
diff --git a/drivers/sgi/char/sgicons.c b/drivers/sgi/char/sgicons.c
index daf1b8fce..210bffec3 100644
--- a/drivers/sgi/char/sgicons.c
+++ b/drivers/sgi/char/sgicons.c
@@ -19,6 +19,9 @@
/* This is the system graphics console (the first adapter found) */
struct console_ops *gconsole = 0;
+/* To make psaux code cleaner */
+int aux_device_present = 0xaa;
+
void
register_gconsole (struct console_ops *gc)
{