VERSION = 1
PATCHLEVEL = 3
-SUBLEVEL = 4
+SUBLEVEL = 5
ARCH = i386
mrproper: clean
rm -f include/linux/autoconf.h include/linux/version.h
rm -f drivers/sound/local.h
+ rm -f drivers/scsi/aic7xxx_asm drivers/scsi/aic7xxx_seq.h
rm -f drivers/char/uni_hash_tbl.h drivers/char/conmakehash
rm -f .version .config* config.in config.old
rm -f include/asm
endif
distclean: mrproper
+ rm -f core `find . -name '*.orig' -print`
+
backup: mrproper
cd .. && tar cf - linux | gzip -9 > backup.gz
bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X n
bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n
bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y
-bool 'Adaptec AHA274X/284X support' CONFIG_SCSI_AHA274X n
+bool 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX n
bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
-bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
+bool 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA n
+bool 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO n
bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
call_pal PAL_wrmces
ret ($26)
.end wrmces
-
-.align 9
-.globl floppy_track_buffer
-floppy_track_buffer:
- .space 512*2*MAX_BUFFER_SECTORS,1
__writel(b, addr);
}
+/*
+ * Read COUNT 8-bit bytes from port PORT into memory starting at
+ * SRC.
+ */
+#undef insb
+void insb (unsigned long port, void *dst, unsigned long count)
+{
+ while (((unsigned long)dst) & 0x3) {
+ if (!count)
+ return;
+ count--;
+ *(unsigned char *) dst = inb(port);
+ ((unsigned char *) dst)++;
+ }
+
+ while (count >= 4) {
+ unsigned int w;
+ count -= 4;
+ w = inb(port);
+ w |= inb(port) << 8;
+ w |= inb(port) << 16;
+ w |= inb(port) << 24;
+ *(unsigned int *) dst = w;
+ ((unsigned int *) dst)++;
+ }
+
+ while (count) {
+ --count;
+ *(unsigned char *) dst = inb(port);
+ ((unsigned char *) dst)++;
+ }
+}
+
+
/*
* Read COUNT 16-bit words from port PORT into memory starting at
* SRC. SRC must be at least short aligned. This is used by the
#undef insw
void insw (unsigned long port, void *dst, unsigned long count)
{
- unsigned int *ip, w;
-
if (((unsigned long)dst) & 0x3) {
if (((unsigned long)dst) & 0x1) {
panic("insw: memory not short aligned");
}
- *(unsigned short*)dst = inw(port);
- dst += 2;
- --count;
+ if (!count)
+ return;
+ count--;
+ *(unsigned short* ) dst = inw(port);
+ ((unsigned short *) dst)++;
}
- ip = dst;
while (count >= 2) {
- w = inw(port);
- w |= inw(port) << 16;
+ unsigned int w;
count -= 2;
- *ip++ = w;
+ w = inw(port);
+ w |= inw(port) << 16;
+ *(unsigned int *) dst = w;
+ ((unsigned int *) dst)++;
}
if (count) {
- w = inw(port);
- *(unsigned short*)ip = w;
+ *(unsigned short*) dst = inw(port);
}
}
#undef insl
void insl (unsigned long port, void *dst, unsigned long count)
{
- unsigned int *ip, w;
-
if (((unsigned long)dst) & 0x3) {
panic("insl: memory not aligned");
}
- ip = dst;
- while (count > 0) {
- w = inw(port);
+ while (count) {
--count;
- *ip++ = w;
+ *(unsigned int *) dst = inl(port);
+ ((unsigned int *) dst)++;
}
}
+/*
+ * Like insb but in the opposite direction.
+ * Don't worry as much about doing aligned memory transfers:
+ * doing byte reads the "slow" way isn't nearly as slow as
+ * doing byte writes the slow way (no r-m-w cycle).
+ */
+#undef outsb
+void outsb(unsigned long port, void * src, unsigned long count)
+{
+ while (count) {
+ count--;
+ outb(*(char *)src, port);
+ ((char *) src)++;
+ }
+}
/*
* Like insw but in the opposite direction. This is used by the IDE
#undef outsw
void outsw (unsigned long port, void *src, unsigned long count)
{
- unsigned int *ip, w;
-
if (((unsigned long)src) & 0x3) {
if (((unsigned long)src) & 0x1) {
panic("outsw: memory not short aligned");
}
outw(*(unsigned short*)src, port);
- src += 2;
+ ((unsigned short *) src)++;
--count;
}
- ip = src;
while (count >= 2) {
- w = *ip++;
+ unsigned int w;
count -= 2;
+ w = *(unsigned int *) src;
+ ((unsigned int *) src)++;
outw(w >> 0, port);
outw(w >> 16, port);
}
if (count) {
- outw(*(unsigned short*)ip, port);
+ outw(*(unsigned short *) src, port);
}
}
#undef outsw
void outsl (unsigned long port, void *src, unsigned long count)
{
- unsigned int *ip, w;
-
if (((unsigned long)src) & 0x3) {
panic("outsw: memory not aligned");
}
- ip = src;
- while (count > 0) {
- w = *ip++;
+ while (count) {
--count;
- outw(w, port);
+ outl(*(unsigned int *) src, port);
+ ((unsigned int *) src)++;
+ }
+}
+
+
+/*
+ * Copy data from IO memory space to "real" memory space.
+ * This needs to be optimized.
+ */
+void memcpy_fromio(void * to, unsigned long from, unsigned long count)
+{
+ while (count) {
+ count--;
+ *(char *) to = readb(from);
+ ((char *) to)++;
+ from++;
+ }
+}
+
+/*
+ * Copy data from "real" memory space to IO memory space.
+ * This needs to be optimized.
+ */
+void memcpy_toio(unsigned long to, void * from, unsigned long count)
+{
+ while (count) {
+ count--;
+ writeb(*(char *) from, to);
+ ((char *) from)++;
+ to++;
+ }
+}
+
+/*
+ * "memset" on IO memory space.
+ * This needs to be optimized.
+ */
+void memset_io(unsigned long dst, int c, unsigned long count)
+{
+ while (count) {
+ count--;
+ writeb(c, dst);
+ dst++;
}
}
#
# ZLINKFLAGS = -Ttext 0x1000
# LINKFLAGS = -Ttext 0x100000
+#
+#
+
+ifdef CONFIG_KERNEL_ELF
+
+LD=ld -m elf_i386
+CPP=$(CC) -E -D__ELF__
+OBJDUMP =objdump
+OBJDUMP_FLAGS=-k -q
+LDFLAGS=-e startup_32
+LDFLAGS=-e stext
+ZIMAGE_OFFSET=0x1000
+IMAGE_OFFSET=0x100000
+ZLINKFLAGS =-Ttext $(ZIMAGE_OFFSET) $(LDFLAGS)
+LINKFLAGS =-Ttext $(IMAGE_OFFSET) $(LDFLAGS)
+
+else
+
#
# -qmagic (we need to remove the 32 byte header for bootup purposes)
#
ZLINKFLAGS =-qmagic -Ttext 0xfe0
LINKFLAGS =-qmagic -Ttext 0xfffe0
+endif
CFLAGS := $(CFLAGS) -pipe
ifdef CONFIG_M486
ARCHIVES := arch/i386/kernel/kernel.o arch/i386/mm/mm.o $(ARCHIVES)
LIBS := $(TOPDIR)/arch/i386/lib/lib.a $(LIBS) $(TOPDIR)/arch/i386/lib/lib.a
-ifdef CONFIG_IBCS
-SUBDIRS := $(SUBDIRS) arch/i386/ibcs
-DRIVERS := $(DRIVERS) arch/i386/ibcs/ibcs.o
-endif
-
ifdef CONFIG_MATH_EMULATION
SUBDIRS := $(SUBDIRS) arch/i386/math-emu
DRIVERS := $(DRIVERS) arch/i386/math-emu/math.a
AS86 =as86 -0 -a
LD86 =ld86 -0
+ifdef CONFIG_KERNEL_ELF
+CFLAGS := $(CFLAGS) -D__BFD__
+endif
+
zImage: $(CONFIGURE) bootsect setup compressed/vmlinux tools/build
+ifdef CONFIG_KERNEL_ELF
+ $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(ZIMAGE_OFFSET) compressed/vmlinux > compressed/vmlinux.out
+ tools/build bootsect setup compressed/vmlinux.out $(ROOT_DEV) > zImage
+else
tools/build bootsect setup compressed/vmlinux $(ROOT_DEV) > zImage
+endif
sync
compressed/vmlinux: $(TOPDIR)/vmlinux
clean:
rm -f bootsect setup
- rm -f zImage tools/build
+ rm -f zImage tools/build compressed/vmlinux.out
@$(MAKE) -C compressed clean
CFLAGS = -O2 -DSTDC_HEADERS
+ifdef CONFIG_KERNEL_ELF
+TARGET=--target elf32-i386
+INPUT_DATA=input_data
+INPUT_LEN=input_len
+endif
+
.c.s:
$(CC) $(CFLAGS) -S $<
.s.o:
all: vmlinux
-vmlinux: piggy.o $(OBJECTS)
- $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
+vmlinux: piggy.o $(OBJECTS)
+ $(LD) $(ZLINKFLAGS) -o vmlinux $(OBJECTS) piggy.o
+
+head.o: head.S $(TOPDIR)/include/linux/tasks.h
+ $(CC) -traditional -c head.S
-head.o: head.s
+ifdef CONFIG_KERNEL_ELF
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
- $(CPP) -traditional head.S -o head.s
+# You cannot compress a file and have the kernel uncompress it, it must
+# be stdin
+piggy.o: $(SYSTEM)
+ tmppiggy=/tmp/$$.piggy; \
+ rm -f $$tmppiggy $$tmppiggy.gz; \
+ $(OBJDUMP) $(OBJDUMP_FLAGS) -o $(IMAGE_OFFSET) $(SYSTEM) > $$tmppiggy; \
+ gzip -f -9 < $$tmppiggy > $$tmppiggy.gz; \
+ encaps $(TARGET) piggy.o $$tmppiggy.gz $(INPUT_DATA) $(INPUT_LEN); \
+ rm -f $$tmppiggy $$tmppiggy.gz
+else
piggy.o: $(SYSTEM) xtract piggyback
./xtract $(SYSTEM) | gzip -9 | ./piggyback > piggy.o
piggyback: piggyback.c
$(HOSTCC) $(CFLAGS) -o piggyback piggyback.c
+endif
+
clean:
rm -f xtract piggyback vmlinux
.text
#define __ASSEMBLY__
+#include <linux/linkage.h>
#include <asm/segment.h>
+ .globl startup_32
startup_32:
cld
cli
mov %ax,%es
mov %ax,%fs
mov %ax,%gs
- lss _stack_start,%esp
+ lss SYMBOL_NAME(stack_start),%esp
xorl %eax,%eax
1: incl %eax # check that A20 really IS enabled
movl %eax,0x000000 # loop forever if it isn't
* Clear BSS
*/
xorl %eax,%eax
- movl $__edata,%edi
- movl $__end,%ecx
+ movl $ SYMBOL_NAME(_edata),%edi
+ movl $ SYMBOL_NAME(_end),%ecx
subl %edi,%ecx
cld
rep
/*
* Do the decompression, and jump to the new kernel..
*/
- call _decompress_kernel
+ call SYMBOL_NAME(decompress_kernel)
ljmp $(KERNEL_CS), $0x100000
#include <fcntl.h>
#include <linux/a.out.h>
#include <linux/config.h>
+#include <errno.h>
#define MINIX_HEADER 32
#define N_MAGIC_OFFSET 1024
+#ifndef __BFD__
static int GCC_HEADER = sizeof(struct exec);
+#endif
#define SYS_SIZE DEF_SYSSIZE
int i,c,id, sz;
unsigned long sys_size;
char buf[1024];
+#ifndef __BFD__
struct exec *ex = (struct exec *)buf;
+#endif
char major_root, minor_root;
struct stat sb;
unsigned char setup_sectors;
if ((id=open(argv[3],O_RDONLY,0))<0)
die("Unable to open 'system'");
+#ifndef __BFD__
if (read(id,buf,GCC_HEADER) != GCC_HEADER)
die("Unable to read header of 'system'");
if (N_MAGIC(*ex) == ZMAGIC) {
ex->a_data /1024,
ex->a_bss /1024);
sz = N_SYMOFF(*ex) - GCC_HEADER + 4;
+#else
+ if (fstat (id, &sb)) {
+ perror ("fstat");
+ die ("Unable to stat 'system'");
+ }
+ sz = sb.st_size;
+ fprintf (stderr, "System is %d kB\n", sz/1024);
+#endif
sys_size = (sz + 15) / 16;
if (sys_size > SYS_SIZE)
die("System is too big");
bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y
bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n
-bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y
-if [ "$CONFIG_PCI" = "y" ]; then
- bool 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX n
-fi
+bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
+bool 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX n
bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
-bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
+bool 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA n
+bool 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO n
bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
fi
bool 'HP PCLAN+ (27247B and 27252A) support' CONFIG_HPLAN_PLUS n
bool 'HP PCLAN (27245 and other 27xxx series) support' CONFIG_HPLAN n
+ bool 'HP 10/100VG PCLAN (257X series) support' CONFIG_HP100 y
bool 'NE2000/NE1000 support' CONFIG_NE2000 y
if [ "$CONFIG_AX25" = "y" ]; then
bool 'Ottawa PI and PI/2 support' CONFIG_PI y
bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n
fi
bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n
- bool 'DE425, DE434, DE435 support' CONFIG_DE4X5 n
+ bool 'DE425, DE434, DE435, DE500 support' CONFIG_DE4X5 n
# bool 'DEC 21040 PCI support' CONFIG_DEC_ELCP n
# bool 'LPL T100V 100Mbs support' CONFIG_LPL_T100 n
# bool 'PCnet32 (32 bit VLB and PCI LANCE) support' CONFIG_PCNET32 n
+++ /dev/null
-#
-# Makefile for the iBCS emulator files
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-.S.s:
- $(CPP) -traditional $< -o $*.s
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) -c -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-
-SUBDIRS =
-
-OBJS = emulate.o
-
-ibcs.o: $(OBJS)
- $(LD) -r -o ibcs.o $(OBJS)
- sync
-
-dep:
- $(CPP) -M *.c > .depend
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
+++ /dev/null
-/*
- * These are the functions used to load COFF IBSC style executables.
- * Information on COFF format may be obtained in either the Intel Binary
- * Compatibility Specification 2 or O'Rilley's book on COFF. The shared
- * libraries are defined only the in the Intel book.
- *
- * This file is based upon code written by Eric Youngdale for the ELF object
- * file format.
- *
- * Author: Al Longyear (longyear@sii.com)
- *
- * Latest Revision:
- * 3 February 1994
- * Al Longyear (longyear@sii.com)
- * Cleared first page of bss section using put_fs_byte.
- */
-
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <asm/segment.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/coff.h>
-#include <linux/malloc.h>
-
-asmlinkage int sys_exit (int exit_code);
-asmlinkage int sys_close (unsigned fd);
-asmlinkage int sys_open (const char *, int, int);
-asmlinkage int sys_uselib(const char * library);
-
-static int preload_library (struct linux_binprm *exe_bprm,
- COFF_SCNHDR * sect,
- struct file *fp);
-
-static int load_object (struct linux_binprm *bprm,
- struct pt_regs *regs,
- int lib_ok);
-
-/*
- * Small procedure to test for the proper file alignment.
- */
-
-static inline int
-is_properly_aligned (COFF_SCNHDR *sect)
-{
- long scnptr = COFF_LONG (sect->s_scnptr);
- long vaddr = COFF_LONG (sect->s_vaddr);
-/*
- * Print the section information if needed
- */
-
-#ifdef COFF_DEBUG
- printk ("%s, scnptr = %d, vaddr = %d\n",
- sect->s_name,
- scnptr, vaddr);
-#endif
-
-/*
- * Return the error code if the section is not properly aligned.
- */
-
-#ifdef COFF_DEBUG
- if (((vaddr - scnptr) & ~PAGE_MASK) != 0)
- printk ("bad alignment in %s\n", sect->s_name);
-#endif
- return ((((vaddr - scnptr) & ~PAGE_MASK) != 0) ? -ENOEXEC : 0);
-}
-
-/*
- * Clear the bytes in the last page of data.
- */
-
-static
-int clear_memory (unsigned long addr, unsigned long size)
-{
- int status;
-
- size = (PAGE_SIZE - (addr & ~PAGE_MASK)) & ~PAGE_MASK;
- if (size == 0)
- status = 0;
- else {
-
-#ifdef COFF_DEBUG
- printk ("un-initialized storage in last page %d\n", size);
-#endif
-
- status = verify_area (VERIFY_WRITE,
- (void *) addr, size);
-#ifdef COFF_DEBUG
- printk ("result from verify_area = %d\n", status);
-#endif
-
- if (status >= 0)
- while (size-- != 0)
- put_fs_byte (0, addr++);
- }
- return status;
-}
-
-/*
- * Helper function to process the load operation.
- */
-
-static int
-load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok)
-{
- COFF_FILHDR *coff_hdr = (COFF_FILHDR *) bprm->buf; /* COFF Header */
- COFF_SCNHDR *sect_bufr; /* Pointer to section table */
- COFF_SCNHDR *text_sect; /* Pointer to the text section */
- COFF_SCNHDR *data_sect; /* Pointer to the data section */
- COFF_SCNHDR *bss_sect; /* Pointer to the bss section */
- int text_count; /* Number of text sections */
- int data_count; /* Number of data sections */
- int bss_count; /* Number of bss sections */
- int lib_count; /* Number of lib sections */
- unsigned int start_addr = 0;/* Starting location for program */
- int status = 0; /* Result status register */
- int fd = -1; /* Open file descriptor */
- struct file *fp = NULL; /* Pointer to the file at "fd" */
- short int sections = 0; /* Number of sections in the file */
- short int aout_size = 0; /* Size of the a.out header area */
- short int flags; /* Flag bits from the COFF header */
-
-#ifdef COFF_DEBUG
- printk ("binfmt_coff entry: %s\n", bprm->filename);
-#endif
-
-/*
- * Validate the magic value for the object file.
- */
- do {
- if (COFF_I386BADMAG (*coff_hdr)) {
-#ifdef COFF_DEBUG
- printk ("bad filehdr magic\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * The object file should have 32 BIT little endian format. Do not allow
- * it to have the 16 bit object file flag set as Linux is not able to run
- * on the 80286/80186/8086.
- */
- flags = COFF_SHORT (coff_hdr->f_flags);
- if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR) {
-#ifdef COFF_DEBUG
- printk ("invalid f_flags bits\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * Extract the header information which we need.
- */
- sections = COFF_SHORT (coff_hdr->f_nscns); /* Number of sections */
- aout_size = COFF_SHORT (coff_hdr->f_opthdr); /* Size of opt. headr */
-/*
- * If the file is not executable then reject the execution. This means
- * that there must not be external references.
- */
- if ((flags & COFF_F_EXEC) == 0) {
-#ifdef COFF_DEBUG
- printk ("not executable bit\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * There must be at least one section.
- */
- if (sections == 0) {
-#ifdef COFF_DEBUG
- printk ("no sections\n");
-#endif
- status = -ENOEXEC;
- break;
- }
-/*
- * Do some additional consistency checks.
- * The system requires mapping for this loader. If you try
- * to use a file system with no mapping, the format is not valid.
- */
- if (!bprm->inode->i_op ||
- !bprm->inode->i_op->default_file_ops->mmap) {
-#ifdef COFF_DEBUG
- printk ("no mmap in fs\n");
-#endif
- status = -ENOEXEC;
- }
- }
- while (0);
-/*
- * Allocate a buffer to hold the entire coff section list.
- */
- if (status >= 0) {
- int nbytes = sections * COFF_SCNHSZ;
-
- sect_bufr = (COFF_SCNHDR *) kmalloc (nbytes, GFP_KERNEL);
- if (0 == sect_bufr) {
-#ifdef COFF_DEBUG
- printk ("kmalloc failed\n");
-#endif
- status = -ENOEXEC;
- }
-/*
- * Read the section list from the disk file.
- */
- else {
- int old_fs = get_fs ();
- set_fs (get_ds ()); /* Make it point to the proper location */
- status = read_exec (bprm->inode, /* INODE for file */
- aout_size + COFF_FILHSZ, /* Offset in the file */
- (char *) sect_bufr, /* Buffer for read */
- nbytes); /* Byte count reqd. */
- set_fs (old_fs); /* Restore the selector */
-#ifdef COFF_DEBUG
- if (status < 0)
- printk ("read aout hdr, status = %d\n", status);
-#endif
- }
- }
- else
- sect_bufr = NULL; /* Errors do not have a section buffer */
-/*
- * Count the number of sections for the required types and store the location
- * of the last section for the three primary types.
- */
- text_count = 0;
- data_count = 0;
- bss_count = 0;
- lib_count = 0;
-
- text_sect = NULL;
- data_sect = NULL;
- bss_sect = NULL;
-/*
- * Loop through the sections and find the various types
- */
- if (status >= 0) {
- int nIndex;
- COFF_SCNHDR *sect_ptr = sect_bufr;
-
- for (nIndex = 0; nIndex < sections; ++nIndex) {
- long int sect_flags = COFF_LONG (sect_ptr->s_flags);
-
- switch (sect_flags) {
- case COFF_STYP_TEXT:
- text_sect = sect_ptr;
- ++text_count;
- status = is_properly_aligned (sect_ptr);
- break;
-
- case COFF_STYP_DATA:
- data_sect = sect_ptr;
- ++data_count;
- status = is_properly_aligned (sect_ptr);
- break;
-
- case COFF_STYP_BSS:
- bss_sect = sect_ptr;
- ++bss_count;
- break;
-
- case COFF_STYP_LIB:
-#ifdef COFF_DEBUG
- printk (".lib section found\n");
-#endif
- ++lib_count;
- break;
-
- default:
- break;
- }
- sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ];
- }
-/*
- * Ensure that there are the required sections. There must be one text
- * sections and one each of the data and bss sections for an executable.
- * A library may or may not have a data / bss section.
- */
- if (text_count != 1) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("no text sections\n");
-#endif
- }
- else {
- if (lib_ok) {
- if (data_count != 1 || bss_count != 1) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("no .data nor .bss sections\n");
-#endif
- }
- }
- }
- }
-/*
- * If there is no additional header then assume the file starts at
- * the first byte of the text section. This may not be the proper place,
- * so the best solution is to include the optional header. A shared library
- * __MUST__ have an optional header to indicate that it is a shared library.
- */
- if (status >= 0) {
- if (aout_size == 0) {
- if (!lib_ok) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("no header in library\n");
-#endif
- }
- start_addr = COFF_LONG (text_sect->s_vaddr);
- }
-/*
- * There is some header. Ensure that it is sufficient.
- */
- else {
- if (aout_size < COFF_AOUTSZ) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("header too small\n");
-#endif
- }
- else {
- COFF_AOUTHDR *aout_hdr = /* Pointer to a.out header */
- (COFF_AOUTHDR *) & ((char *) coff_hdr)[COFF_FILHSZ];
- short int aout_magic = COFF_SHORT (aout_hdr->magic); /* id */
-/*
- * Validate the magic number in the a.out header. If it is valid then
- * update the starting symbol location. Do not accept these file formats
- * when loading a shared library.
- */
- switch (aout_magic) {
- case COFF_OMAGIC:
- case COFF_ZMAGIC:
- case COFF_STMAGIC:
- if (!lib_ok) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("wrong a.out header magic\n");
-#endif
- }
- start_addr = (unsigned int) COFF_LONG (aout_hdr->entry);
- break;
-/*
- * Magic value for a shared library. This is valid only when loading a
- * shared library. (There is no need for a start_addr. It won't be used.)
- */
- case COFF_SHMAGIC:
- if (lib_ok) {
-#ifdef COFF_DEBUG
- printk ("wrong a.out header magic\n");
-#endif
- status = -ENOEXEC;
- }
- break;
-
- default:
-#ifdef COFF_DEBUG
- printk ("wrong a.out header magic\n");
-#endif
- status = -ENOEXEC;
- break;
- }
- }
- }
- }
-/*
- * Fetch a file pointer to the executable.
- */
- if (status >= 0) {
- fd = open_inode (bprm->inode, O_RDONLY);
- if (fd < 0) {
-#ifdef COFF_DEBUG
- printk ("can not open inode, result = %d\n", fd);
-#endif
- status = fd;
- }
- else
- fp = current->files->fd[fd];
- }
- else
- fd = -1; /* Invalidate the open file descriptor */
-/*
- * Generate the proper values for the text fields
- *
- * THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD
- * SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD.
- */
- if (status >= 0) {
- long text_scnptr = COFF_LONG (text_sect->s_scnptr);
- long text_size = COFF_LONG (text_sect->s_size);
- long text_vaddr = COFF_LONG (text_sect->s_vaddr);
-
- long data_scnptr;
- long data_size;
- long data_vaddr;
-
- long bss_size;
- long bss_vaddr;
-/*
- * Generate the proper values for the data fields
- */
- if (data_sect != NULL) {
- data_scnptr = COFF_LONG (data_sect->s_scnptr);
- data_size = COFF_LONG (data_sect->s_size);
- data_vaddr = COFF_LONG (data_sect->s_vaddr);
- }
- else {
- data_scnptr = 0;
- data_size = 0;
- data_vaddr = 0;
- }
-/*
- * Generate the proper values for the bss fields
- */
- if (bss_sect != NULL) {
- bss_size = COFF_LONG (bss_sect->s_size);
- bss_vaddr = COFF_LONG (bss_sect->s_vaddr);
- }
- else {
- bss_size = 0;
- bss_vaddr = 0;
- }
-/*
- * Flush the executable from memory. At this point the executable is
- * committed to being defined or a segmentation violation will occur.
- */
- if (lib_ok) {
-#ifdef COFF_DEBUG
- printk ("flushing executable\n");
-#endif
- flush_old_exec (bprm);
-/*
- * Define the initial locations for the various items in the new process
- */
- current->mm->mmap = NULL;
- current->mm->rss = 0;
-/*
- * Construct the parameter and environment string table entries.
- */
- bprm->p += change_ldt (0, bprm->page);
- bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
- bprm->p = (unsigned long) create_tables ((char *) bprm->p,
- bprm->argc,
- bprm->envc,
- 1);
-/*
- * Do the end processing once the stack has been constructed
- */
- current->mm->start_code = text_vaddr & PAGE_MASK;
- current->mm->end_code = text_vaddr + text_size;
- current->mm->end_data = data_vaddr + data_size;
- current->mm->start_brk =
- current->mm->brk = bss_vaddr + bss_size;
- current->suid =
- current->euid = bprm->e_uid;
- current->sgid =
- current->egid = bprm->e_gid;
- current->executable = bprm->inode; /* Store inode for file */
- ++bprm->inode->i_count; /* Count the open inode */
- regs->eip = start_addr; /* Current EIP register */
- regs->esp =
- current->mm->start_stack = bprm->p;
- }
-/*
- * Map the text pages
- */
-
-#ifdef COFF_DEBUG
- printk (".text: vaddr = %d, size = %d, scnptr = %d\n",
- text_vaddr,
- text_size,
- text_scnptr);
-#endif
- status = do_mmap (fp,
- text_vaddr & PAGE_MASK,
- text_size + (text_vaddr & ~PAGE_MASK),
- PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_SHARED,
- text_scnptr & PAGE_MASK);
-
- status = (status == (text_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
-/*
- * Map the data pages
- */
- if (status >= 0 && data_size != 0) {
-#ifdef COFF_DEBUG
- printk (".data: vaddr = %d, size = %d, scnptr = %d\n",
- data_vaddr,
- data_size,
- data_scnptr);
-#endif
- status = do_mmap (fp,
- data_vaddr & PAGE_MASK,
- data_size + (data_vaddr & ~PAGE_MASK),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE,
- data_scnptr & PAGE_MASK);
-
- status = (status == (data_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC;
- }
-/*
- * Construct the bss data for the process. The bss ranges from the
- * end of the data (which may not be on a page boundary) to the end
- * of the bss section. Allocate any necessary pages for the data.
- */
- if (status >= 0 && bss_size != 0) {
-#ifdef COFF_DEBUG
- printk (".bss: vaddr = %d, size = %d\n",
- bss_vaddr,
- bss_size);
-#endif
- zeromap_page_range (PAGE_ALIGN (bss_vaddr),
- PAGE_ALIGN (bss_size),
- PAGE_COPY);
-
- status = clear_memory (bss_vaddr, bss_size);
- }
-/*
- * Load any shared library for the executable.
- */
- if (status >= 0 && lib_ok && lib_count != 0) {
- int nIndex;
- COFF_SCNHDR *sect_ptr = sect_bufr;
-/*
- * Find the library sections. (There should be at least one. It was counted
- * earlier.) This will eventually recurse to our code and load the shared
- * library with our own procedures.
- */
- for (nIndex = 0; nIndex < sections; ++nIndex) {
- long int sect_flags = COFF_LONG (sect_ptr->s_flags);
- if (sect_flags == COFF_STYP_LIB) {
- status = preload_library (bprm, sect_ptr, fp);
- if (status != 0)
- break;
- }
- sect_ptr = (COFF_SCNHDR *) &((char *) sect_ptr) [COFF_SCNHSZ];
- }
- }
-/*
- * Generate any needed trap for this process. If an error occurred then
- * generate a segmentation violation. If the process is being debugged
- * then generate the load trap. (Note: If this is a library load then
- * do not generate the trap here. Pass the error to the caller who
- * will do it for the process in the outer lay of this procedure call.)
- */
- if (lib_ok) {
- if (status < 0)
- send_sig (SIGSEGV, current, 0); /* Generate the error trap */
- else {
- if (current->flags & PF_PTRACED)
- send_sig (SIGTRAP, current, 0);
- }
- status = 0; /* We are committed. It can't fail */
- }
- }
-/*
- * Do any cleanup processing
- */
- if (fd >= 0)
- sys_close (fd); /* Close unused code file */
-
- if (sect_bufr != NULL)
- kfree (sect_bufr); /* Release section list buffer */
-/*
- * Return the completion status.
- */
-#ifdef COFF_DEBUG
- printk ("binfmt_coff: result = %d\n", status);
-#endif
- return (status);
-}
-
-/*
- * This procedure will load the library listed in the file name given
- * as the parameter. The result will be non-zero should something fail
- * to load.
- */
-
-static int
-preload_this_library (struct linux_binprm *exe_bprm, char *lib_name)
-{
- int status;
- int old_fs = get_fs();
-/*
- * If debugging then print "we have arrived"
- */
-#ifdef COFF_DEBUG
- printk ("%s loading shared library %s\n",
- exe_bprm->filename,
- lib_name);
-#endif
-/*
- * Change the FS register to the proper kernel address space and attempt
- * to load the library. The library name is allocated from the kernel
- * pool.
- */
- set_fs (get_ds ());
- status = sys_uselib (lib_name);
- set_fs (old_fs);
-/*
- * Return the success/failure to the caller.
- */
- return (status);
-}
-
-/*
- * This procedure is called to load a library section. The various
- * libraries are loaded from the list given in the section data.
- */
-
-static int
-preload_library (struct linux_binprm *exe_bprm,
- COFF_SCNHDR * sect, struct file *fp)
-{
- int status = 0; /* Completion status */
- long nbytes; /* Count of bytes in the header area */
-/*
- * Fetch the size of the section. There must be enough room for at least
- * one entry.
- */
- nbytes = COFF_LONG (sect->s_size);
- if (nbytes < COFF_SLIBSZ) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("library section too small\n");
-#endif
- }
-/*
- * Allocate a buffer to hold the section data
- */
- else {
- COFF_SLIBHD *phdr;
- char *buffer = (char *) kmalloc (nbytes, GFP_KERNEL);
-
- if (0 == buffer) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("kmalloc failed\n");
-#endif
- }
- else {
- int old_fs = get_fs ();
-/*
- * Read the section data from the disk file.
- */
- set_fs (get_ds ()); /* Make it point to the proper location */
- status = read_exec (exe_bprm->inode, /* INODE for file */
- COFF_LONG (sect->s_scnptr), /* Disk location */
- buffer, /* Buffer for read */
- nbytes); /* Byte count reqd. */
- set_fs (old_fs); /* Restore the selector */
-/*
- * Check the result. The value returned is the byte count actually read.
- */
- if (status >= 0 && status != nbytes) {
-#ifdef COFF_DEBUG
- printk ("read of lib section was short\n");
-#endif
- status = -ENOEXEC;
- }
- }
-/*
- * At this point, go through the list of libraries in the data area.
- */
- phdr = (COFF_SLIBHD *) buffer;
- while (status >= 0 && nbytes > COFF_SLIBSZ) {
- int entry_size = COFF_LONG (phdr->sl_entsz) * sizeof (long);
- int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long);
-/*
- * Validate the sizes of the various items. I don't trust the linker!!
- */
- if ((unsigned) header_size >= (unsigned) nbytes ||
- entry_size <= 0 ||
- (unsigned) entry_size <= (unsigned) header_size) {
- status = -ENOEXEC;
-#ifdef COFF_DEBUG
- printk ("header count is invalid\n");
-#endif
- }
-/*
- * Load the library. Stop the load process on the first error.
- */
- else {
- status = preload_this_library (exe_bprm,
- &((char *) phdr)[header_size]);
-#ifdef COFF_DEBUG
- printk ("preload_this_library result = %d\n", status);
-#endif
- }
-/*
- * Point to the next library in the section data.
- */
- nbytes -= entry_size;
- phdr = (COFF_SLIBHD *) &((char *) phdr)[entry_size];
- }
-/*
- * Release the space for the library list.
- */
- if (buffer != NULL)
- kfree (buffer);
- }
-/*
- * Return the resulting status to the caller.
- */
- return (status);
-}
-
-/*
- * This procedure is called by the main load sequence. It will load
- * the executable and prepare it for execution. It provides the additional
- * parameters used by the recursive coff loader and tells the loader that
- * this is the main executable. How simple it is . . . .
- */
-
-int
-load_coff_binary (struct linux_binprm *bprm, struct pt_regs *regs)
-{
- return (load_object (bprm, regs, 1));
-}
-
-/*
- * Load the image for any shared library.
- *
- * This is called when we need to load a library based upon a file name.
- */
-
-int
-load_coff_library (int fd)
-{
- struct linux_binprm *bprm; /* Parameters for the load operation */
- int status; /* Status of the request */
-/*
- * Read the first portion of the file.
- */
- bprm = (struct linux_binprm *) kmalloc (sizeof (struct linux_binprm),
- GFP_KERNEL);
- if (0 == bprm) {
-#ifdef COFF_DEBUG
- printk ("kmalloc failed\n");
-#endif
- status = -ENOEXEC;
- }
- else {
- struct file *file; /* Pointer to the file table */
- struct pt_regs regs; /* Register work area */
- int old_fs = get_fs (); /* Previous FS register value */
-
- memset (bprm, '\0', sizeof (struct linux_binprm));
-
- file = current->files->fd[fd];
- bprm->inode = file->f_inode; /* The only item _really_ needed */
- bprm->filename = ""; /* Make it a legal string */
-/*
- * Read the section list from the disk file.
- */
- set_fs (get_ds ()); /* Make it point to the proper location */
- status = read_exec (bprm->inode, /* INODE for file */
- 0L, /* Offset in the file */
- bprm->buf, /* Buffer for read */
- sizeof (bprm->buf)); /* Size of the buffer */
- set_fs (old_fs); /* Restore the selector */
-/*
- * Try to load the library.
- */
- status = load_object (bprm, ®s, 0);
-/*
- * Release the work buffer and return the result.
- */
- kfree (bprm); /* Release the buffer area */
- }
-/*
- * Return the result of the load operation
- */
- return (status);
-}
+++ /dev/null
-/*
- * linux/fs/binfmt_elf.c
- *
- * These are the functions used to load ELF format executables as used
- * on SVr4 machines. Information on the format may be found in the book
- * "UNIX SYSTEM V RELEASE 4 Programmers Guide: Ansi C and Programming Support
- * Tools".
- *
- * Copyright 1993, 1994: Eric Youngdale (ericy@cais.com).
- */
-#include <linux/fs.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/mman.h>
-#include <linux/a.out.h>
-#include <linux/errno.h>
-#include <linux/signal.h>
-#include <linux/binfmts.h>
-#include <linux/string.h>
-#include <linux/fcntl.h>
-#include <linux/ptrace.h>
-#include <linux/malloc.h>
-#include <linux/shm.h>
-#include <linux/personality.h>
-
-#include <asm/segment.h>
-
-asmlinkage int sys_exit(int exit_code);
-asmlinkage int sys_close(unsigned fd);
-asmlinkage int sys_open(const char *, int, int);
-asmlinkage int sys_brk(unsigned long);
-
-#define DLINFO_ITEMS 8
-
-#include <linux/elf.h>
-
-/* We need to explicitly zero any fractional pages
- after the data section (i.e. bss). This would
- contain the junk from the file that should not
- be in memory */
-
-static void padzero(int elf_bss){
- unsigned int fpnt, nbyte;
-
- if(elf_bss & 0xfff) {
-
- nbyte = (PAGE_SIZE - (elf_bss & 0xfff)) & 0xfff;
- if(nbyte){
- verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
-
- fpnt = elf_bss;
- while(fpnt & 0xfff) put_fs_byte(0, fpnt++);
- };
- };
-}
-
-unsigned long * create_elf_tables(char * p,int argc,int envc,struct elfhdr * exec, unsigned int load_addr, int ibcs)
-{
- unsigned long *argv,*envp, *dlinfo;
- unsigned long * sp;
- struct vm_area_struct *mpnt;
-
- mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
- if (mpnt) {
- mpnt->vm_task = current;
- mpnt->vm_start = PAGE_MASK & (unsigned long) p;
- mpnt->vm_end = TASK_SIZE;
- mpnt->vm_page_prot = PAGE_COPY;
- mpnt->vm_flags = VM_STACK_FLAGS;
- mpnt->vm_ops = NULL;
- mpnt->vm_inode = NULL;
- mpnt->vm_offset = 0;
- mpnt->vm_pte = 0;
- insert_vm_struct(current, mpnt);
- }
- sp = (unsigned long *) (0xfffffffc & (unsigned long) p);
- if(exec) sp -= DLINFO_ITEMS*2;
- dlinfo = sp;
- sp -= envc+1;
- envp = sp;
- sp -= argc+1;
- argv = sp;
- if (!ibcs) {
- put_fs_long((unsigned long)envp,--sp);
- put_fs_long((unsigned long)argv,--sp);
- }
-
- /* The constant numbers (0-9) that we are writing here are
- described in the header file sys/auxv.h on at least
- some versions of SVr4 */
- if(exec) { /* Put this here for an ELF program interpreter */
- struct elf_phdr * eppnt;
- eppnt = (struct elf_phdr *) exec->e_phoff;
- put_fs_long(3,dlinfo++); put_fs_long(load_addr + exec->e_phoff,dlinfo++);
- put_fs_long(4,dlinfo++); put_fs_long(sizeof(struct elf_phdr),dlinfo++);
- put_fs_long(5,dlinfo++); put_fs_long(exec->e_phnum,dlinfo++);
- put_fs_long(9,dlinfo++); put_fs_long((unsigned long) exec->e_entry,dlinfo++);
- put_fs_long(7,dlinfo++); put_fs_long(SHM_RANGE_START,dlinfo++);
- put_fs_long(8,dlinfo++); put_fs_long(0,dlinfo++);
- put_fs_long(6,dlinfo++); put_fs_long(PAGE_SIZE,dlinfo++);
- put_fs_long(0,dlinfo++); put_fs_long(0,dlinfo++);
- };
-
- put_fs_long((unsigned long)argc,--sp);
- current->mm->arg_start = (unsigned long) p;
- while (argc-->0) {
- put_fs_long((unsigned long) p,argv++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,argv);
- current->mm->arg_end = current->mm->env_start = (unsigned long) p;
- while (envc-->0) {
- put_fs_long((unsigned long) p,envp++);
- while (get_fs_byte(p++)) /* nothing */ ;
- }
- put_fs_long(0,envp);
- current->mm->env_end = (unsigned long) p;
- return sp;
-}
-
-
-/* This is much more generalized than the library routine read function,
- so we keep this separate. Technically the library read function
- is only provided so that we can read a.out libraries that have
- an ELF header */
-
-static unsigned int load_elf_interp(struct elfhdr * interp_elf_ex,
- struct inode * interpreter_inode)
-{
- struct file * file;
- struct elf_phdr *elf_phdata = NULL;
- struct elf_phdr *eppnt;
- unsigned int len;
- unsigned int load_addr;
- int elf_exec_fileno;
- int elf_bss;
- int old_fs, retval;
- unsigned int last_bss;
- int error;
- int i, k;
-
- elf_bss = 0;
- last_bss = 0;
- error = load_addr = 0;
-
- /* First of all, some simple consistency checks */
- if((interp_elf_ex->e_type != ET_EXEC &&
- interp_elf_ex->e_type != ET_DYN) ||
- (interp_elf_ex->e_machine != EM_386 && interp_elf_ex->e_machine != EM_486) ||
- (!interpreter_inode->i_op ||
- !interpreter_inode->i_op->default_file_ops->mmap)){
- return 0xffffffff;
- };
-
- /* Now read in all of the header information */
-
- if(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum > PAGE_SIZE)
- return 0xffffffff;
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, GFP_KERNEL);
- if(!elf_phdata) return 0xffffffff;
-
- old_fs = get_fs();
- set_fs(get_ds());
- retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * interp_elf_ex->e_phnum);
- set_fs(old_fs);
-
- elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY);
- if (elf_exec_fileno < 0) return 0xffffffff;
- file = current->files->fd[elf_exec_fileno];
-
- eppnt = elf_phdata;
- for(i=0; i<interp_elf_ex->e_phnum; i++, eppnt++)
- if(eppnt->p_type == PT_LOAD) {
- error = do_mmap(file,
- eppnt->p_vaddr & 0xfffff000,
- eppnt->p_filesz + (eppnt->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_PRIVATE | (interp_elf_ex->e_type == ET_EXEC ? MAP_FIXED : 0),
- eppnt->p_offset & 0xfffff000);
-
- if(!load_addr && interp_elf_ex->e_type == ET_DYN)
- load_addr = error;
- k = load_addr + eppnt->p_vaddr + eppnt->p_filesz;
- if(k > elf_bss) elf_bss = k;
- if(error < 0 && error > -1024) break; /* Real error */
- k = load_addr + eppnt->p_memsz + eppnt->p_vaddr;
- if(k > last_bss) last_bss = k;
- }
-
- /* Now use mmap to map the library into memory. */
-
-
- sys_close(elf_exec_fileno);
- if(error < 0 && error > -1024) {
- kfree(elf_phdata);
- return 0xffffffff;
- }
-
- padzero(elf_bss);
- len = (elf_bss + 0xfff) & 0xfffff000; /* What we have mapped so far */
-
- /* Map the last of the bss segment */
- if (last_bss > len)
- do_mmap(NULL, len, last_bss-len,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- kfree(elf_phdata);
-
- return ((unsigned int) interp_elf_ex->e_entry) + load_addr;
-}
-
-static unsigned int load_aout_interp(struct exec * interp_ex,
- struct inode * interpreter_inode)
-{
- int retval;
- unsigned int elf_entry;
-
- current->mm->brk = interp_ex->a_bss +
- (current->mm->end_data = interp_ex->a_data +
- (current->mm->end_code = interp_ex->a_text));
- elf_entry = interp_ex->a_entry;
-
-
- if (N_MAGIC(*interp_ex) == OMAGIC) {
- do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode, 32, (char *) 0,
- interp_ex->a_text+interp_ex->a_data);
- } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) {
- do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- retval = read_exec(interpreter_inode,
- N_TXTOFF(*interp_ex) ,
- (char *) N_TXTADDR(*interp_ex),
- interp_ex->a_text+interp_ex->a_data);
- } else
- retval = -1;
-
- if(retval >= 0)
- do_mmap(NULL, (interp_ex->a_text + interp_ex->a_data + 0xfff) &
- 0xfffff000, interp_ex->a_bss,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- if(retval < 0) return 0xffffffff;
- return elf_entry;
-}
-
-/*
- * These are the functions used to load ELF style executables and shared
- * libraries. There is no binary dependent code anywhere else.
- */
-
-#define INTERPRETER_NONE 0
-#define INTERPRETER_AOUT 1
-#define INTERPRETER_ELF 2
-
-static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
-{
- struct elfhdr elf_ex;
- struct elfhdr interp_elf_ex;
- struct file * file;
- struct exec interp_ex;
- struct inode *interpreter_inode;
- unsigned int load_addr;
- unsigned int interpreter_type = INTERPRETER_NONE;
- int i;
- int old_fs;
- int error;
- struct elf_phdr * elf_ppnt, *elf_phdata;
- int elf_exec_fileno;
- unsigned int elf_bss, k, elf_brk;
- int retval;
- char * elf_interpreter;
- unsigned int elf_entry;
- int status;
- unsigned int start_code, end_code, end_data;
- unsigned int elf_stack;
- char passed_fileno[6];
-
- status = 0;
- load_addr = 0;
- elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
- return -ENOEXEC;
-
-
- /* First of all, some simple consistency checks */
- if(elf_ex.e_type != ET_EXEC ||
- (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
- (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops ||
- !bprm->inode->i_op->default_file_ops->mmap)){
- return -ENOEXEC;
- };
-
- /* Now read in all of the header information */
-
- elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize *
- elf_ex.e_phnum, GFP_KERNEL);
-
- old_fs = get_fs();
- set_fs(get_ds());
- retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata,
- elf_ex.e_phentsize * elf_ex.e_phnum);
- set_fs(old_fs);
- if (retval < 0) {
- kfree (elf_phdata);
- return retval;
- }
-
- elf_ppnt = elf_phdata;
-
- elf_bss = 0;
- elf_brk = 0;
-
- elf_exec_fileno = open_inode(bprm->inode, O_RDONLY);
-
- if (elf_exec_fileno < 0) {
- kfree (elf_phdata);
- return elf_exec_fileno;
- }
-
- file = current->files->fd[elf_exec_fileno];
-
- elf_stack = 0xffffffff;
- elf_interpreter = NULL;
- start_code = 0;
- end_code = 0;
- end_data = 0;
-
- old_fs = get_fs();
- set_fs(get_ds());
-
- for(i=0;i < elf_ex.e_phnum; i++){
- if(elf_ppnt->p_type == PT_INTERP) {
- /* This is the program interpreter used for shared libraries -
- for now assume that this is an a.out format binary */
-
- elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz,
- GFP_KERNEL);
-
- retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter,
- elf_ppnt->p_filesz);
-#if 0
- printk("Using ELF interpreter %s\n", elf_interpreter);
-#endif
- if(retval >= 0)
- retval = namei(elf_interpreter, &interpreter_inode);
- if(retval >= 0)
- retval = read_exec(interpreter_inode,0,bprm->buf,128);
-
- if(retval >= 0){
- interp_ex = *((struct exec *) bprm->buf); /* exec-header */
- interp_elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */
-
- };
- if(retval < 0) {
- kfree (elf_phdata);
- kfree(elf_interpreter);
- return retval;
- };
- };
- elf_ppnt++;
- };
-
- set_fs(old_fs);
-
- /* Some simple consistency checks for the interpreter */
- if(elf_interpreter){
- interpreter_type = INTERPRETER_ELF | INTERPRETER_AOUT;
- if(retval < 0) {
- kfree(elf_interpreter);
- kfree(elf_phdata);
- return -ELIBACC;
- };
- /* Now figure out which format our binary is */
- if((N_MAGIC(interp_ex) != OMAGIC) &&
- (N_MAGIC(interp_ex) != ZMAGIC) &&
- (N_MAGIC(interp_ex) != QMAGIC))
- interpreter_type = INTERPRETER_ELF;
-
- if (interp_elf_ex.e_ident[0] != 0x7f ||
- strncmp(&interp_elf_ex.e_ident[1], "ELF",3) != 0)
- interpreter_type &= ~INTERPRETER_ELF;
-
- if(!interpreter_type)
- {
- kfree(elf_interpreter);
- kfree(elf_phdata);
- return -ELIBBAD;
- };
- }
-
- /* OK, we are done with that, now set up the arg stuff,
- and then start this sucker up */
-
- if (!bprm->sh_bang) {
- char * passed_p;
-
- if(interpreter_type == INTERPRETER_AOUT) {
- sprintf(passed_fileno, "%d", elf_exec_fileno);
- passed_p = passed_fileno;
-
- if(elf_interpreter) {
- bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2);
- bprm->argc++;
- };
- };
- if (!bprm->p) {
- if(elf_interpreter) {
- kfree(elf_interpreter);
- }
- kfree (elf_phdata);
- return -E2BIG;
- }
- }
-
- /* OK, This is the point of no return */
- flush_old_exec(bprm);
-
- current->mm->end_data = 0;
- current->mm->end_code = 0;
- current->mm->start_mmap = ELF_START_MMAP;
- current->mm->mmap = NULL;
- elf_entry = (unsigned int) elf_ex.e_entry;
-
- /* Do this so that we can load the interpreter, if need be. We will
- change some of these later */
- current->mm->rss = 0;
- bprm->p += change_ldt(0, bprm->page);
- current->mm->start_stack = bprm->p;
-
- /* Now we do a little grungy work by mmaping the ELF image into
- the correct location in memory. At this point, we assume that
- the image should be loaded at fixed address, not at a variable
- address. */
-
- old_fs = get_fs();
- set_fs(get_ds());
-
- elf_ppnt = elf_phdata;
- for(i=0;i < elf_ex.e_phnum; i++){
-
- if(elf_ppnt->p_type == PT_INTERP) {
- /* Set these up so that we are able to load the interpreter */
- /* Now load the interpreter into user address space */
- set_fs(old_fs);
-
- if(interpreter_type & 1) elf_entry =
- load_aout_interp(&interp_ex, interpreter_inode);
-
- if(interpreter_type & 2) elf_entry =
- load_elf_interp(&interp_elf_ex, interpreter_inode);
-
- old_fs = get_fs();
- set_fs(get_ds());
-
- iput(interpreter_inode);
- kfree(elf_interpreter);
-
- if(elf_entry == 0xffffffff) {
- printk("Unable to load interpreter\n");
- kfree(elf_phdata);
- send_sig(SIGSEGV, current, 0);
- return 0;
- };
- };
-
-
- if(elf_ppnt->p_type == PT_LOAD) {
- error = do_mmap(file,
- elf_ppnt->p_vaddr & 0xfffff000,
- elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE,
- elf_ppnt->p_offset & 0xfffff000);
-
-#ifdef LOW_ELF_STACK
- if((elf_ppnt->p_vaddr & 0xfffff000) < elf_stack)
- elf_stack = elf_ppnt->p_vaddr & 0xfffff000;
-#endif
-
- if(!load_addr)
- load_addr = elf_ppnt->p_vaddr - elf_ppnt->p_offset;
- k = elf_ppnt->p_vaddr;
- if(k > start_code) start_code = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz;
- if(k > elf_bss) elf_bss = k;
- if((elf_ppnt->p_flags | PROT_WRITE) && end_code < k)
- end_code = k;
- if(end_data < k) end_data = k;
- k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz;
- if(k > elf_brk) elf_brk = k;
- };
- elf_ppnt++;
- };
- set_fs(old_fs);
-
- kfree(elf_phdata);
-
- if(interpreter_type != INTERPRETER_AOUT) sys_close(elf_exec_fileno);
-
- /* The following 3 lines need a little bit of work if we are loading
- an iBCS2 binary. We should initially load it this way, and if
- we get a lcall7, then we should look to see if the iBCS2 execution
- profile is present. If it is, then switch to that, otherwise
- bomb. */
- current->personality = PER_LINUX;
- current->lcall7 = no_lcall7;
- current->signal_map = current->signal_invmap = ident_map;
-
- current->executable = bprm->inode;
- bprm->inode->i_count++;
-#ifdef LOW_ELF_STACK
- current->start_stack = p = elf_stack - 4;
-#endif
- bprm->p -= MAX_ARG_PAGES*PAGE_SIZE;
- bprm->p = (unsigned long)
- create_elf_tables((char *)bprm->p,
- bprm->argc,
- bprm->envc,
- (interpreter_type == INTERPRETER_ELF ? &elf_ex : NULL),
- load_addr,
- (interpreter_type == INTERPRETER_AOUT ? 0 : 1));
- if(interpreter_type == INTERPRETER_AOUT)
- current->mm->arg_start += strlen(passed_fileno) + 1;
- current->mm->start_brk = current->mm->brk = elf_brk;
- current->mm->end_code = end_code;
- current->mm->start_code = start_code;
- current->mm->end_data = end_data;
- current->mm->start_stack = bprm->p;
- current->suid = current->euid = bprm->e_uid;
- current->sgid = current->egid = bprm->e_gid;
-
- /* Calling sys_brk effectively mmaps the pages that we need for the bss and break
- sections */
- current->mm->brk = (elf_bss + 0xfff) & 0xfffff000;
- sys_brk((elf_brk + 0xfff) & 0xfffff000);
-
- padzero(elf_bss);
-
- /* Why this, you ask??? Well SVr4 maps page 0 as read-only,
- and some applications "depend" upon this behavior.
- Since we do not have the power to recompile these, we
- emulate the SVr4 behavior. Sigh. */
- error = do_mmap(NULL, 0, 4096, PROT_READ | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE, 0);
-
- regs->eip = elf_entry; /* eip, magic happens :-) */
- regs->esp = bprm->p; /* stack pointer */
- if (current->flags & PF_PTRACED)
- send_sig(SIGTRAP, current, 0);
- return 0;
-}
-
-/* This is really simpleminded and specialized - we are loading an
- a.out library that is given an ELF header. */
-
-static int load_elf_library(int fd){
- struct file * file;
- struct elfhdr elf_ex;
- struct elf_phdr *elf_phdata = NULL;
- struct inode * inode;
- unsigned int len;
- int elf_bss;
- int old_fs, retval;
- unsigned int bss;
- int error;
- int i,j, k;
-
- len = 0;
- file = current->files->fd[fd];
- inode = file->f_inode;
- elf_bss = 0;
-
- set_fs(KERNEL_DS);
- if (file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)) != sizeof(elf_ex)) {
- sys_close(fd);
- return -EACCES;
- }
- set_fs(USER_DS);
-
- if (elf_ex.e_ident[0] != 0x7f ||
- strncmp(&elf_ex.e_ident[1], "ELF",3) != 0)
- return -ENOEXEC;
-
- /* First of all, some simple consistency checks */
- if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 ||
- (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) ||
- (!inode->i_op ||
- !inode->i_op->default_file_ops->mmap)){
- return -ENOEXEC;
- };
-
- /* Now read in all of the header information */
-
- if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE)
- return -ENOEXEC;
-
- elf_phdata = (struct elf_phdr *)
- kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL);
-
- old_fs = get_fs();
- set_fs(get_ds());
- retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata,
- sizeof(struct elf_phdr) * elf_ex.e_phnum);
- set_fs(old_fs);
-
- j = 0;
- for(i=0; i<elf_ex.e_phnum; i++)
- if((elf_phdata + i)->p_type == PT_LOAD) j++;
-
- if(j != 1) {
- kfree(elf_phdata);
- return -ENOEXEC;
- };
-
- while(elf_phdata->p_type != PT_LOAD) elf_phdata++;
-
- /* Now use mmap to map the library into memory. */
- error = do_mmap(file,
- elf_phdata->p_vaddr & 0xfffff000,
- elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff),
- PROT_READ | PROT_WRITE | PROT_EXEC,
- MAP_FIXED | MAP_PRIVATE,
- elf_phdata->p_offset & 0xfffff000);
-
- k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
- if(k > elf_bss) elf_bss = k;
-
- sys_close(fd);
- if (error != (elf_phdata->p_vaddr & 0xfffff000)) {
- kfree(elf_phdata);
- return error;
- }
-
- padzero(elf_bss);
-
- len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
- bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
- if (bss > len)
- do_mmap(NULL, len, bss-len,
- PROT_READ|PROT_WRITE|PROT_EXEC,
- MAP_FIXED|MAP_PRIVATE, 0);
- kfree(elf_phdata);
- return 0;
-}
-
-struct linux_binfmt elf_format = { NULL, load_elf_binary, load_elf_library };
+++ /dev/null
-/*
- * linux/abi/emulate.c
- *
- * Copyright (C) 1993 Linus Torvalds
- */
-
-/*
- * Yes, sir, this file is completely empty, waiting for some real code..
- * I still copyright it, silly me.
- */
$(AS) -o $*.o $<
.c.o:
$(CC) $(CFLAGS) -c $<
-.S.s:
- $(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
+#.S.s:
+# $(CPP) -D__ASSEMBLY__ -traditional $< -o $*.s
.S.o:
$(CC) -D__ASSEMBLY__ -traditional -c $< -o $*.o
all: kernel.o head.o
-head.o: head.s
+#head.o: head.s
-head.s: head.S $(TOPDIR)/include/linux/tasks.h
- $(CPP) -traditional -o $*.s $<
+head.o: head.S $(TOPDIR)/include/linux/tasks.h
+ $(CC) -D__ASSEMBLY__ -traditional -c $*.S -o $*.o
+# $(CPP) -traditional -o $*.s $<
kernel.o: $(OBJS)
$(LD) -r -o kernel.o $(OBJS)
*/
#include <linux/sys.h>
+#include <linux/linkage.h>
#include <asm/segment.h>
EBX = 0x00
ENOSYS = 38
-.globl _system_call,_lcall7
-.globl _device_not_available, _coprocessor_error
-.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op
-.globl _double_fault,_coprocessor_segment_overrun
-.globl _invalid_TSS,_segment_not_present,_stack_segment
-.globl _general_protection,_reserved
-.globl _alignment_check,_page_fault
-.globl ret_from_sys_call, _sys_call_table
-
#define SAVE_ALL \
cld; \
push %gs; \
#define RESTORE_ALL \
cmpw $(KERNEL_CS),CS(%esp); \
je 1f; \
- movl _current,%eax; \
+ movl SYMBOL_NAME(current),%eax; \
movl dbgreg7(%eax),%ebx; \
movl %ebx,%db7; \
1: popl %ebx; \
addl $4,%esp; \
iret
-.align 4
-_lcall7:
+ENTRY(lcall7)
pushfl # We get a different stack layout with call gates,
pushl %eax # which has to be cleaned up later..
SAVE_ALL
movl %edx,EIP(%esp) # Now we move them to their "normal" places
movl %ecx,CS(%esp) #
movl %esp,%eax
- movl _current,%edx
+ movl SYMBOL_NAME(current),%edx
pushl %eax
movl exec_domain(%edx),%edx # Get the execution domain
movl 4(%edx),%edx # Get the lcall7 handler for the domain
popl %eax
jmp ret_from_sys_call
-.align 4
+ ALIGN
handle_bottom_half:
pushfl
- incl _intr_count
+ incl SYMBOL_NAME(intr_count)
sti
- call _do_bottom_half
+ call SYMBOL_NAME(do_bottom_half)
popfl
- decl _intr_count
+ decl SYMBOL_NAME(intr_count)
jmp 9f
-.align 4
+ ALIGN
reschedule:
pushl $ret_from_sys_call
- jmp _schedule
-.align 4
-_system_call:
+ jmp SYMBOL_NAME(schedule)
+
+ENTRY(system_call)
pushl %eax # save orig_eax
SAVE_ALL
movl $-ENOSYS,EAX(%esp)
cmpl $(NR_syscalls),%eax
jae ret_from_sys_call
- movl _sys_call_table(,%eax,4),%eax
+ movl SYMBOL_NAME(sys_call_table)(,%eax,4),%eax
testl %eax,%eax
je ret_from_sys_call
- movl _current,%ebx
+ movl SYMBOL_NAME(current),%ebx
andl $~CF_MASK,EFLAGS(%esp) # clear carry - assume no errors
movl $0,errno(%ebx)
movl %db6,%edx
movl %edx,EAX(%esp)
orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
jmp ret_from_sys_call
-.align 4
-1: call _syscall_trace
+ ALIGN
+1: call SYMBOL_NAME(syscall_trace)
movl ORIG_EAX(%esp),%eax
- call _sys_call_table(,%eax,4)
+ call SYMBOL_NAME(sys_call_table)(,%eax,4)
movl %eax,EAX(%esp) # save the return value
- movl _current,%eax
+ movl SYMBOL_NAME(current),%eax
movl errno(%eax),%edx
negl %edx
je 1f
movl %edx,EAX(%esp)
orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error
-1: call _syscall_trace
+1: call SYMBOL_NAME(syscall_trace)
- .align 4,0x90
+ ALIGN
+ .globl ret_from_sys_call
ret_from_sys_call:
- cmpl $0,_intr_count
+ cmpl $0,SYMBOL_NAME(intr_count)
jne 2f
-9: movl _bh_mask,%eax
- andl _bh_active,%eax
+9: movl SYMBOL_NAME(bh_mask),%eax
+ andl SYMBOL_NAME(bh_active),%eax
jne handle_bottom_half
movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are
testl $(VM_MASK),%eax # different then
orl $(IF_MASK),%eax # these just try to make sure
andl $~NT_MASK,%eax # the program doesn't do anything
movl %eax,EFLAGS(%esp) # stupid
- cmpl $0,_need_resched
+ cmpl $0,SYMBOL_NAME(need_resched)
jne reschedule
- movl _current,%eax
- cmpl _task,%eax # task[0] cannot have signals
+ movl SYMBOL_NAME(current),%eax
+ cmpl SYMBOL_NAME(task),%eax # task[0] cannot have signals
je 2f
cmpl $0,state(%eax) # state
jne reschedule
andl signal(%eax),%ecx
jne signal_return
2: RESTORE_ALL
-.align 4
+ ALIGN
signal_return:
movl %esp,%ecx
pushl %ecx
testl $(VM_MASK),EFLAGS(%ecx)
jne v86_signal_return
pushl %ebx
- call _do_signal
+ call SYMBOL_NAME(do_signal)
popl %ebx
popl %ebx
RESTORE_ALL
-.align 4
+ ALIGN
v86_signal_return:
- call _save_v86_state
+ call SYMBOL_NAME(save_v86_state)
movl %eax,%esp
pushl %eax
pushl %ebx
- call _do_signal
+ call SYMBOL_NAME(do_signal)
popl %ebx
popl %ebx
RESTORE_ALL
-.align 4
-_divide_error:
+ENTRY(divide_error)
pushl $0 # no error code
- pushl $_do_divide_error
-.align 4,0x90
+ pushl $ SYMBOL_NAME(do_divide_error)
+ ALIGN
error_code:
push %fs
push %es
movl $(USER_DS),%edx
mov %dx,%fs
pushl %eax
- movl _current,%eax
+ movl SYMBOL_NAME(current),%eax
movl %db6,%edx
movl %edx,dbgreg6(%eax) # save current hardware debugging status
popl %eax
addl $8,%esp
jmp ret_from_sys_call
-.align 4
-_coprocessor_error:
+ENTRY(coprocessor_error)
pushl $0
- pushl $_do_coprocessor_error
+ pushl $ SYMBOL_NAME(do_coprocessor_error)
jmp error_code
-.align 4
-_device_not_available:
+ENTRY(device_not_available)
pushl $-1 # mark this as an int
SAVE_ALL
pushl $ret_from_sys_call
movl %cr0,%eax
testl $0x4,%eax # EM (math emulation bit)
- je _math_state_restore
+ je SYMBOL_NAME(math_state_restore)
pushl $0 # temporary storage for ORIG_EIP
- call _math_emulate
+ call SYMBOL_NAME(math_emulate)
addl $4,%esp
ret
-.align 4
-_debug:
+ENTRY(debug)
pushl $0
- pushl $_do_debug
+ pushl $ SYMBOL_NAME(do_debug)
jmp error_code
-.align 4
-_nmi:
+ENTRY(nmi)
pushl $0
- pushl $_do_nmi
+ pushl $ SYMBOL_NAME(do_nmi)
jmp error_code
-.align 4
-_int3:
+ENTRY(int3)
pushl $0
- pushl $_do_int3
+ pushl $ SYMBOL_NAME(do_int3)
jmp error_code
-.align 4
-_overflow:
+ENTRY(overflow)
pushl $0
- pushl $_do_overflow
+ pushl $ SYMBOL_NAME(do_overflow)
jmp error_code
-.align 4
-_bounds:
+ENTRY(bounds)
pushl $0
- pushl $_do_bounds
+ pushl $ SYMBOL_NAME(do_bounds)
jmp error_code
-.align 4
-_invalid_op:
+ENTRY(invalid_op)
pushl $0
- pushl $_do_invalid_op
+ pushl $ SYMBOL_NAME(do_invalid_op)
jmp error_code
-.align 4
-_coprocessor_segment_overrun:
+ENTRY(coprocessor_segment_overrun)
pushl $0
- pushl $_do_coprocessor_segment_overrun
+ pushl $ SYMBOL_NAME(do_coprocessor_segment_overrun)
jmp error_code
-.align 4
-_reserved:
+ENTRY(reserved)
pushl $0
- pushl $_do_reserved
+ pushl $ SYMBOL_NAME(do_reserved)
jmp error_code
-.align 4
-_double_fault:
- pushl $_do_double_fault
+ENTRY(double_fault)
+ pushl $ SYMBOL_NAME(do_double_fault)
jmp error_code
-.align 4
-_invalid_TSS:
- pushl $_do_invalid_TSS
+ENTRY(invalid_TSS)
+ pushl $ SYMBOL_NAME(do_invalid_TSS)
jmp error_code
-.align 4
-_segment_not_present:
- pushl $_do_segment_not_present
+ENTRY(segment_not_present)
+ pushl $ SYMBOL_NAME(do_segment_not_present)
jmp error_code
-.align 4
-_stack_segment:
- pushl $_do_stack_segment
+ENTRY(stack_segment)
+ pushl $ SYMBOL_NAME(do_stack_segment)
jmp error_code
-.align 4
-_general_protection:
- pushl $_do_general_protection
+ENTRY(general_protection)
+ pushl $ SYMBOL_NAME(do_general_protection)
jmp error_code
-.align 4
-_alignment_check:
- pushl $_do_alignment_check
+ENTRY(alignment_check)
+ pushl $ SYMBOL_NAME(do_alignment_check)
jmp error_code
-.align 4
-_page_fault:
- pushl $_do_page_fault
+ENTRY(page_fault)
+ pushl $ SYMBOL_NAME(do_page_fault)
jmp error_code
.data
-.align 4
-_sys_call_table:
- .long _sys_setup /* 0 */
- .long _sys_exit
- .long _sys_fork
- .long _sys_read
- .long _sys_write
- .long _sys_open /* 5 */
- .long _sys_close
- .long _sys_waitpid
- .long _sys_creat
- .long _sys_link
- .long _sys_unlink /* 10 */
- .long _sys_execve
- .long _sys_chdir
- .long _sys_time
- .long _sys_mknod
- .long _sys_chmod /* 15 */
- .long _sys_chown
- .long _sys_break
- .long _sys_stat
- .long _sys_lseek
- .long _sys_getpid /* 20 */
- .long _sys_mount
- .long _sys_umount
- .long _sys_setuid
- .long _sys_getuid
- .long _sys_stime /* 25 */
- .long _sys_ptrace
- .long _sys_alarm
- .long _sys_fstat
- .long _sys_pause
- .long _sys_utime /* 30 */
- .long _sys_stty
- .long _sys_gtty
- .long _sys_access
- .long _sys_nice
- .long _sys_ftime /* 35 */
- .long _sys_sync
- .long _sys_kill
- .long _sys_rename
- .long _sys_mkdir
- .long _sys_rmdir /* 40 */
- .long _sys_dup
- .long _sys_pipe
- .long _sys_times
- .long _sys_prof
- .long _sys_brk /* 45 */
- .long _sys_setgid
- .long _sys_getgid
- .long _sys_signal
- .long _sys_geteuid
- .long _sys_getegid /* 50 */
- .long _sys_acct
- .long _sys_phys
- .long _sys_lock
- .long _sys_ioctl
- .long _sys_fcntl /* 55 */
- .long _sys_mpx
- .long _sys_setpgid
- .long _sys_ulimit
- .long _sys_olduname
- .long _sys_umask /* 60 */
- .long _sys_chroot
- .long _sys_ustat
- .long _sys_dup2
- .long _sys_getppid
- .long _sys_getpgrp /* 65 */
- .long _sys_setsid
- .long _sys_sigaction
- .long _sys_sgetmask
- .long _sys_ssetmask
- .long _sys_setreuid /* 70 */
- .long _sys_setregid
- .long _sys_sigsuspend
- .long _sys_sigpending
- .long _sys_sethostname
- .long _sys_setrlimit /* 75 */
- .long _sys_getrlimit
- .long _sys_getrusage
- .long _sys_gettimeofday
- .long _sys_settimeofday
- .long _sys_getgroups /* 80 */
- .long _sys_setgroups
- .long _old_select
- .long _sys_symlink
- .long _sys_lstat
- .long _sys_readlink /* 85 */
- .long _sys_uselib
- .long _sys_swapon
- .long _sys_reboot
- .long _old_readdir
- .long _old_mmap /* 90 */
- .long _sys_munmap
- .long _sys_truncate
- .long _sys_ftruncate
- .long _sys_fchmod
- .long _sys_fchown /* 95 */
- .long _sys_getpriority
- .long _sys_setpriority
- .long _sys_profil
- .long _sys_statfs
- .long _sys_fstatfs /* 100 */
- .long _sys_ioperm
- .long _sys_socketcall
- .long _sys_syslog
- .long _sys_setitimer
- .long _sys_getitimer /* 105 */
- .long _sys_newstat
- .long _sys_newlstat
- .long _sys_newfstat
- .long _sys_uname
- .long _sys_iopl /* 110 */
- .long _sys_vhangup
- .long _sys_idle
- .long _sys_vm86
- .long _sys_wait4
- .long _sys_swapoff /* 115 */
- .long _sys_sysinfo
- .long _sys_ipc
- .long _sys_fsync
- .long _sys_sigreturn
- .long _sys_clone /* 120 */
- .long _sys_setdomainname
- .long _sys_newuname
- .long _sys_modify_ldt
- .long _sys_adjtimex
- .long _sys_mprotect /* 125 */
- .long _sys_sigprocmask
- .long _sys_create_module
- .long _sys_init_module
- .long _sys_delete_module
- .long _sys_get_kernel_syms /* 130 */
- .long _sys_quotactl
- .long _sys_getpgid
- .long _sys_fchdir
- .long _sys_bdflush
- .long _sys_sysfs /* 135 */
- .long _sys_personality
- .long 0 /* for afs_syscall */
- .long _sys_setfsuid
- .long _sys_setfsgid
- .long _sys_llseek /* 140 */
- .long _sys_getdents
- .long _sys_select
- .long _sys_flock
+ENTRY(sys_call_table)
+ .long SYMBOL_NAME(sys_setup) /* 0 */
+ .long SYMBOL_NAME(sys_exit)
+ .long SYMBOL_NAME(sys_fork)
+ .long SYMBOL_NAME(sys_read)
+ .long SYMBOL_NAME(sys_write)
+ .long SYMBOL_NAME(sys_open) /* 5 */
+ .long SYMBOL_NAME(sys_close)
+ .long SYMBOL_NAME(sys_waitpid)
+ .long SYMBOL_NAME(sys_creat)
+ .long SYMBOL_NAME(sys_link)
+ .long SYMBOL_NAME(sys_unlink) /* 10 */
+ .long SYMBOL_NAME(sys_execve)
+ .long SYMBOL_NAME(sys_chdir)
+ .long SYMBOL_NAME(sys_time)
+ .long SYMBOL_NAME(sys_mknod)
+ .long SYMBOL_NAME(sys_chmod) /* 15 */
+ .long SYMBOL_NAME(sys_chown)
+ .long SYMBOL_NAME(sys_break)
+ .long SYMBOL_NAME(sys_stat)
+ .long SYMBOL_NAME(sys_lseek)
+ .long SYMBOL_NAME(sys_getpid) /* 20 */
+ .long SYMBOL_NAME(sys_mount)
+ .long SYMBOL_NAME(sys_umount)
+ .long SYMBOL_NAME(sys_setuid)
+ .long SYMBOL_NAME(sys_getuid)
+ .long SYMBOL_NAME(sys_stime) /* 25 */
+ .long SYMBOL_NAME(sys_ptrace)
+ .long SYMBOL_NAME(sys_alarm)
+ .long SYMBOL_NAME(sys_fstat)
+ .long SYMBOL_NAME(sys_pause)
+ .long SYMBOL_NAME(sys_utime) /* 30 */
+ .long SYMBOL_NAME(sys_stty)
+ .long SYMBOL_NAME(sys_gtty)
+ .long SYMBOL_NAME(sys_access)
+ .long SYMBOL_NAME(sys_nice)
+ .long SYMBOL_NAME(sys_ftime) /* 35 */
+ .long SYMBOL_NAME(sys_sync)
+ .long SYMBOL_NAME(sys_kill)
+ .long SYMBOL_NAME(sys_rename)
+ .long SYMBOL_NAME(sys_mkdir)
+ .long SYMBOL_NAME(sys_rmdir) /* 40 */
+ .long SYMBOL_NAME(sys_dup)
+ .long SYMBOL_NAME(sys_pipe)
+ .long SYMBOL_NAME(sys_times)
+ .long SYMBOL_NAME(sys_prof)
+ .long SYMBOL_NAME(sys_brk) /* 45 */
+ .long SYMBOL_NAME(sys_setgid)
+ .long SYMBOL_NAME(sys_getgid)
+ .long SYMBOL_NAME(sys_signal)
+ .long SYMBOL_NAME(sys_geteuid)
+ .long SYMBOL_NAME(sys_getegid) /* 50 */
+ .long SYMBOL_NAME(sys_acct)
+ .long SYMBOL_NAME(sys_phys)
+ .long SYMBOL_NAME(sys_lock)
+ .long SYMBOL_NAME(sys_ioctl)
+ .long SYMBOL_NAME(sys_fcntl) /* 55 */
+ .long SYMBOL_NAME(sys_mpx)
+ .long SYMBOL_NAME(sys_setpgid)
+ .long SYMBOL_NAME(sys_ulimit)
+ .long SYMBOL_NAME(sys_olduname)
+ .long SYMBOL_NAME(sys_umask) /* 60 */
+ .long SYMBOL_NAME(sys_chroot)
+ .long SYMBOL_NAME(sys_ustat)
+ .long SYMBOL_NAME(sys_dup2)
+ .long SYMBOL_NAME(sys_getppid)
+ .long SYMBOL_NAME(sys_getpgrp) /* 65 */
+ .long SYMBOL_NAME(sys_setsid)
+ .long SYMBOL_NAME(sys_sigaction)
+ .long SYMBOL_NAME(sys_sgetmask)
+ .long SYMBOL_NAME(sys_ssetmask)
+ .long SYMBOL_NAME(sys_setreuid) /* 70 */
+ .long SYMBOL_NAME(sys_setregid)
+ .long SYMBOL_NAME(sys_sigsuspend)
+ .long SYMBOL_NAME(sys_sigpending)
+ .long SYMBOL_NAME(sys_sethostname)
+ .long SYMBOL_NAME(sys_setrlimit) /* 75 */
+ .long SYMBOL_NAME(sys_getrlimit)
+ .long SYMBOL_NAME(sys_getrusage)
+ .long SYMBOL_NAME(sys_gettimeofday)
+ .long SYMBOL_NAME(sys_settimeofday)
+ .long SYMBOL_NAME(sys_getgroups) /* 80 */
+ .long SYMBOL_NAME(sys_setgroups)
+ .long SYMBOL_NAME(old_select)
+ .long SYMBOL_NAME(sys_symlink)
+ .long SYMBOL_NAME(sys_lstat)
+ .long SYMBOL_NAME(sys_readlink) /* 85 */
+ .long SYMBOL_NAME(sys_uselib)
+ .long SYMBOL_NAME(sys_swapon)
+ .long SYMBOL_NAME(sys_reboot)
+ .long SYMBOL_NAME(old_readdir)
+ .long SYMBOL_NAME(old_mmap) /* 90 */
+ .long SYMBOL_NAME(sys_munmap)
+ .long SYMBOL_NAME(sys_truncate)
+ .long SYMBOL_NAME(sys_ftruncate)
+ .long SYMBOL_NAME(sys_fchmod)
+ .long SYMBOL_NAME(sys_fchown) /* 95 */
+ .long SYMBOL_NAME(sys_getpriority)
+ .long SYMBOL_NAME(sys_setpriority)
+ .long SYMBOL_NAME(sys_profil)
+ .long SYMBOL_NAME(sys_statfs)
+ .long SYMBOL_NAME(sys_fstatfs) /* 100 */
+ .long SYMBOL_NAME(sys_ioperm)
+ .long SYMBOL_NAME(sys_socketcall)
+ .long SYMBOL_NAME(sys_syslog)
+ .long SYMBOL_NAME(sys_setitimer)
+ .long SYMBOL_NAME(sys_getitimer) /* 105 */
+ .long SYMBOL_NAME(sys_newstat)
+ .long SYMBOL_NAME(sys_newlstat)
+ .long SYMBOL_NAME(sys_newfstat)
+ .long SYMBOL_NAME(sys_uname)
+ .long SYMBOL_NAME(sys_iopl) /* 110 */
+ .long SYMBOL_NAME(sys_vhangup)
+ .long SYMBOL_NAME(sys_idle)
+ .long SYMBOL_NAME(sys_vm86)
+ .long SYMBOL_NAME(sys_wait4)
+ .long SYMBOL_NAME(sys_swapoff) /* 115 */
+ .long SYMBOL_NAME(sys_sysinfo)
+ .long SYMBOL_NAME(sys_ipc)
+ .long SYMBOL_NAME(sys_fsync)
+ .long SYMBOL_NAME(sys_sigreturn)
+ .long SYMBOL_NAME(sys_clone) /* 120 */
+ .long SYMBOL_NAME(sys_setdomainname)
+ .long SYMBOL_NAME(sys_newuname)
+ .long SYMBOL_NAME(sys_modify_ldt)
+ .long SYMBOL_NAME(sys_adjtimex)
+ .long SYMBOL_NAME(sys_mprotect) /* 125 */
+ .long SYMBOL_NAME(sys_sigprocmask)
+ .long SYMBOL_NAME(sys_create_module)
+ .long SYMBOL_NAME(sys_init_module)
+ .long SYMBOL_NAME(sys_delete_module)
+ .long SYMBOL_NAME(sys_get_kernel_syms) /* 130 */
+ .long SYMBOL_NAME(sys_quotactl)
+ .long SYMBOL_NAME(sys_getpgid)
+ .long SYMBOL_NAME(sys_fchdir)
+ .long SYMBOL_NAME(sys_bdflush)
+ .long SYMBOL_NAME(sys_sysfs) /* 135 */
+ .long SYMBOL_NAME(sys_personality)
+ .long 0 /* for afs_syscall */
+ .long SYMBOL_NAME(sys_setfsuid)
+ .long SYMBOL_NAME(sys_setfsgid)
+ .long SYMBOL_NAME(sys_llseek) /* 140 */
+ .long SYMBOL_NAME(sys_getdents)
+ .long SYMBOL_NAME(sys_select)
+ .long SYMBOL_NAME(sys_flock)
.space (NR_syscalls-143)*4
*/
.text
-.globl _idt,_gdt,_stext,__stext
-.globl _swapper_pg_dir,_pg0
-.globl _empty_bad_page
-.globl _empty_bad_page_table
-.globl _empty_zero_page
-
-#define __ASSEMBLY__
#include <linux/tasks.h>
#include <linux/fd.h>
+#include <linux/linkage.h>
#include <asm/segment.h>
#define CL_MAGIC_ADDR 0x90020
* swapper_pg_dir is the main page directory, address 0x00001000 (or at
* address 0x00101000 for a compressed boot).
*/
-_stext:
-__stext:
+ENTRY(stext)
+ENTRY(_stext)
startup_32:
cld
movl $(KERNEL_DS),%eax
* Clear BSS first so that there are no surprises...
*/
xorl %eax,%eax
- movl $__edata,%edi
- movl $__end,%ecx
+ movl $ SYMBOL_NAME(_edata),%edi
+ movl $ SYMBOL_NAME(_end),%ecx
subl %edi,%ecx
cld
rep
* is for the command line.
*/
movl $0x90000,%esi
- movl $_empty_zero_page,%edi
+ movl $ SYMBOL_NAME(empty_zero_page),%edi
movl $512,%ecx
cld
rep
stosl
cmpw $(CL_MAGIC),CL_MAGIC_ADDR
jne 1f
- movl $_empty_zero_page+2048,%edi
+ movl $ SYMBOL_NAME(empty_zero_page)+2048,%edi
movzwl CL_OFFSET,%esi
addl $(CL_BASE_ADDR),%esi
movl $2048,%ecx
* apply at our cpl of 0 and the stack ought to be aligned already, and
* we don't need to preserve eflags.
*/
- movl $3,_x86
+ movl $3, SYMBOL_NAME(x86)
pushfl # push EFLAGS
popl %eax # get EFLAGS
movl %eax,%ecx # save original EFLAGS
xorl %ecx,%eax # change in flags
andl $0x40000,%eax # check if AC bit changed
je is386
- movl $4,_x86
+ movl $4,SYMBOL_NAME(x86)
movl %ecx,%eax
xorl $0x200000,%eax # check ID flag
pushl %eax
.byte 0x0f, 0xa2 # check the processor type
movb %al, %cl # save reg for future use
andb $0x0f,%ah # mask processor family
- movb %ah, _x86
+ movb %ah,SYMBOL_NAME(x86)
andb $0xf0, %eax # mask model
shrb $4, %al
- movb %al, _x86_model
+ movb %al,SYMBOL_NAME(x86_model)
andb $0x0f, %cl # mask mask revision
- movb %cl, _x86_mask
- movl %edx, _x86_capability
+ movb %cl,SYMBOL_NAME(x86_mask)
+ movl %edx,SYMBOL_NAME(x86_capability)
/* get vendor info */
xorl %eax, %eax # call CPUID with 0 -> return vendor ID
.byte 0x0f, 0xa2 # CPUID
- movl %ebx, _x86_vendor_id # lo 4 chars
- movl %edx, _x86_vendor_id+4 # next 4 chars
- movl %ecx, _x86_vendor_id+8 # last 4 chars
+ movl %ebx,SYMBOL_NAME(x86_vendor_id) # lo 4 chars
+ movl %edx,SYMBOL_NAME(x86_vendor_id)+4 # next 4 chars
+ movl %ecx,SYMBOL_NAME(x86_vendor_id)+8 # last 4 chars
movl %cr0,%eax # 486+
andl $0x80000011,%eax # Save PG,PE,ET
pushl %eax
pushl %eax
cld # gcc2 wants the direction flag cleared at all times
- call _start_kernel
+ call SYMBOL_NAME(start_kernel)
L6:
jmp L6 # main should never return here, but
# just in case, we know what happens.
* We depend on ET to be correct. This checks for 287/387.
*/
check_x87:
- movb $0,_hard_math
+ movb $0,SYMBOL_NAME(hard_math)
clts
fninit
fstsw %ax
xorl $4,%eax /* set EM */
movl %eax,%cr0
ret
-.align 2
-1: movb $1,_hard_math
+ ALIGN
+1: movb $1,SYMBOL_NAME(hard_math)
.byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */
ret
movw %dx,%ax /* selector = 0x0010 = cs */
movw $0x8E00,%dx /* interrupt gate - dpl=0, present */
- lea _idt,%edi
+ lea SYMBOL_NAME(idt),%edi
mov $256,%ecx
rp_sidt:
movl %eax,(%edi)
* (ref: update, 25Sept92) -- croutons@crunchy.uucp
* (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit)
*/
-.align 2
+ ALIGN
setup_paging:
movl $1024*2,%ecx /* 2 pages - swapper_pg_dir+1 page table */
xorl %eax,%eax
- movl $_swapper_pg_dir,%edi /* swapper_pg_dir is at 0x1000 */
+ movl $ SYMBOL_NAME(swapper_pg_dir),%edi /* swapper_pg_dir is at 0x1000 */
cld;rep;stosl
/* Identity-map the kernel in low 4MB memory for ease of transition */
- movl $_pg0+7,_swapper_pg_dir /* set present bit/user r/w */
+/* set present bit/user r/w */
+ movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)
/* But the real place is at 0xC0000000 */
- movl $_pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */
- movl $_pg0+4092,%edi
+/* set present bit/user r/w */
+ movl $ SYMBOL_NAME(pg0)+7,SYMBOL_NAME(swapper_pg_dir)+3072
+ movl $ SYMBOL_NAME(pg0)+4092,%edi
movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */
std
1: stosl /* fill the page backwards - more efficient :-) */
subl $0x1000,%eax
jge 1b
cld
- movl $_swapper_pg_dir,%eax
+ movl $ SYMBOL_NAME(swapper_pg_dir),%eax
movl %eax,%cr3 /* cr3 - page directory start */
movl %cr0,%eax
orl $0x80000000,%eax
* by 2-3k. This would be a good thing to do at some point.....
*/
.org 0x1000
-_swapper_pg_dir:
+ENTRY(swapper_pg_dir)
/*
* The page tables are initialized to only 4MB here - the final page
* tables are set up later depending on memory size.
*/
.org 0x2000
-_pg0:
+ENTRY(pg0)
.org 0x3000
-_empty_bad_page:
+ENTRY(empty_bad_page)
.org 0x4000
-_empty_bad_page_table:
+ENTRY(empty_bad_page_table)
.org 0x5000
-_empty_zero_page:
+ENTRY(empty_zero_page)
.org 0x6000
stack_start:
- .long _init_user_stack+4096
+ .long SYMBOL_NAME(init_user_stack)+4096
.long KERNEL_DS
/* This is the default interrupt "handler" :-) */
int_msg:
.asciz "Unknown interrupt\n"
-.align 2
+ ALIGN
ignore_int:
cld
pushl %eax
mov %ax,%es
mov %ax,%fs
pushl $int_msg
- call _printk
+ call SYMBOL_NAME(printk)
popl %eax
pop %fs
pop %es
/*
* The interrupt descriptor table has room for 256 idt's
*/
-.align 4
+ ALIGN
.word 0
idt_descr:
.word 256*8-1 # idt contains 256 entries
- .long 0xc0000000+_idt
+ .long 0xc0000000+SYMBOL_NAME(idt)
-.align 4
-_idt:
+ENTRY(idt)
.fill 256,8,0 # idt is uninitialized
-.align 4
+ ALIGN
.word 0
gdt_descr:
.word (8+2*NR_TASKS)*8-1
- .long 0xc0000000+_gdt
+ .long 0xc0000000+SYMBOL_NAME(gdt)
/*
* This gdt setup gives the kernel a 1GB address space at virtual
* address 0xC0000000 - space enough for expansion, I hope.
*/
-.align 4
-_gdt:
+ENTRY(gdt)
.quad 0x0000000000000000 /* NULL descriptor */
.quad 0x0000000000000000 /* not used */
.quad 0xc0c39a000000ffff /* 0x10 kernel 1GB code at 0xC0000000 */
__asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387));
}
+/*
+ * fill in the fpu structure for a core dump..
+ */
+int dump_fpu (struct user_i387_struct* fpu)
+{
+ int fpvalid;
+
+/* Flag indicating the math stuff is valid. We don't support this for the
+ soft-float routines yet */
+ if (hard_math) {
+ if ((fpvalid = current->used_math) != 0) {
+ if (last_task_used_math == current)
+ __asm__("clts ; fnsave %0": :"m" (*fpu));
+ else
+ memcpy(fpu,¤t->tss.i387.hard,sizeof(*fpu));
+ }
+ } else {
+ /* we should dump the emulator state here, but we need to
+ convert it into standard 387 format first.. */
+ fpvalid = 0;
+ }
+
+ return fpvalid;
+}
+
/*
* fill in the user structure for a core dump..
*/
dump->regs = *regs;
-/* Flag indicating the math stuff is valid. We don't support this for the
- soft-float routines yet */
- if (hard_math) {
- if ((dump->u_fpvalid = current->used_math) != 0) {
- if (last_task_used_math == current)
- __asm__("clts ; fnsave %0": :"m" (dump->i387));
- else
- memcpy(&dump->i387,¤t->tss.i387.hard,sizeof(dump->i387));
- }
- } else {
- /* we should dump the emulator state here, but we need to
- convert it into standard 387 format first.. */
- dump->u_fpvalid = 0;
- }
+ dump->u_fpvalid = dump_fpu (&dump->i387);
}
asmlinkage int sys_fork(struct pt_regs regs)
unsigned char aux_device_present;
extern int ramdisk_size;
extern int root_mountflags;
-extern int etext, edata, end;
+extern int _etext, _edata, _end;
extern char empty_zero_page[PAGE_SIZE];
#endif
if (MOUNT_ROOT_RDONLY)
root_mountflags |= MS_RDONLY;
- memory_start = (unsigned long) &end;
+ memory_start = (unsigned long) &_end;
init_task.mm->start_code = TASK_SIZE;
- init_task.mm->end_code = TASK_SIZE + (unsigned long) &etext;
- init_task.mm->end_data = TASK_SIZE + (unsigned long) &edata;
- init_task.mm->brk = TASK_SIZE + (unsigned long) &end;
+ init_task.mm->end_code = TASK_SIZE + (unsigned long) &_etext;
+ init_task.mm->end_data = TASK_SIZE + (unsigned long) &_edata;
+ init_task.mm->brk = TASK_SIZE + (unsigned long) &_end;
for (;;) {
if (c == ' ' && *(unsigned long *)from == *(unsigned long *)"mem=") {
unsigned long esp;
unsigned short ss;
unsigned long *stack, addr, module_start, module_end;
- extern char start_kernel, etext;
+ extern char start_kernel, _etext;
esp = (unsigned long) ®s->esp;
ss = KERNEL_DS;
* out the call path that was taken.
*/
if (((addr >= (unsigned long) &start_kernel) &&
- (addr <= (unsigned long) &etext)) ||
+ (addr <= (unsigned long) &_etext)) ||
((addr >= module_start) && (addr <= module_end))) {
if (i && ((i % 8) == 0))
printk("\n ");
.text
- .align 2,144
-
-.globl _div_Xsig
-
-_div_Xsig:
+ENTRY(div_Xsig)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
#include "fpu_asm.h"
.text
- .align 2,144
-
-.globl _div_small
-
-_div_small:
+ENTRY(div_small)
pushl %ebp
movl %esp,%ebp
#ifndef _FPU_ASM_H_
#define _FPU_ASM_H_
+#include <linux/linkage.h>
#include "fpu_emu.h"
-#define EXCEPTION _exception
+#define EXCEPTION SYMBOL_NAME(exception)
#define PARAM1 8(%ebp)
#include "fpu_asm.h"
.text
- .align 2,144
-.globl _mul32_Xsig
-_mul32_Xsig:
+ENTRY(mul32_Xsig)
pushl %ebp
movl %esp,%ebp
subl $16,%esp
ret
- .align 2,144
-.globl _mul64_Xsig
-_mul64_Xsig:
+ENTRY(mul64_Xsig)
pushl %ebp
movl %esp,%ebp
subl $16,%esp
- .align 2,144
-.globl _mul_Xsig_Xsig
-_mul_Xsig_Xsig:
+ENTRY(mul_Xsig_Xsig)
pushl %ebp
movl %esp,%ebp
subl $16,%esp
#define OVERFLOWED -16(%ebp) /* addition overflow flag */
.text
- .align 2,144
-.globl _polynomial_Xsig
-_polynomial_Xsig:
+ENTRY(polynomial_Xsig)
pushl %ebp
movl %esp,%ebp
subl $32,%esp
.text
- .align 2
-
-.globl _reg_div
-_reg_div:
+ENTRY(reg_div)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
cmpl EXP_UNDER,EXP(%esi)
jg xL_arg1_not_denormal
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
cmpl EXP_UNDER,EXP(%ebx)
jg xL_arg2_not_denormal
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
addl EXP_BIAS,%edx
movl %edx,EXP(%edi)
- jmp _divide_kernel
+ jmp SYMBOL_NAME(divide_kernel)
/*-----------------------------------------------------------------------*/
pushl %edi /* Destination */
pushl %esi
pushl %ebx /* Ordering is important here */
- call _real_2op_NaN
+ call SYMBOL_NAME(real_2op_NaN)
jmp LDiv_exit
/* Invalid operations */
L_zero_zero:
L_inf_inf:
pushl %edi /* Destination */
- call _arith_invalid /* 0/0 or Infinity/Infinity */
+ call SYMBOL_NAME(arith_invalid) /* 0/0 or Infinity/Infinity */
jmp LDiv_exit
L_no_NaN_arg:
cmpl EXP_UNDER,EXP(%ebx)
jg L_copy_arg1 /* Answer is Inf */
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
#endif DENORM_OPERAND
movb SIGN(%esi),%al
xorb SIGN(%ebx),%al
pushl %eax /* lower 8 bits have the sign */
- call _divide_by_zero
+ call SYMBOL_NAME(divide_by_zero)
jmp LDiv_exit
L_arg2_not_zero:
cmpl EXP_UNDER,EXP(%esi)
jg L_return_zero /* Answer is zero */
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
#endif DENORM_OPERAND
cmpl EXP_UNDER,EXP(%ebx)
jg L_copy_arg1 /* Answer is zero */
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
#endif DENORM_OPERAND
call EXCEPTION
/* Generate a NaN for unknown tags */
- movl _CONST_QNaN,%eax
+ movl SYMBOL_NAME(CONST_QNaN),%eax
movl %eax,(%edi)
- movl _CONST_QNaN+4,%eax
+ movl SYMBOL_NAME(CONST_QNaN)+4,%eax
movl %eax,SIGL(%edi)
- movl _CONST_QNaN+8,%eax
+ movl SYMBOL_NAME(CONST_QNaN)+8,%eax
movl %eax,SIGH(%edi)
jmp LDiv_exit /* %eax is nz */
#endif PARANOID
.text
-
- .align 2,144
-.globl _normalize
-
-_normalize:
+ENTRY(normalize)
pushl %ebp
movl %esp,%ebp
pushl %ebx
je L_ok
pushl $0x220
- call _exception
+ call SYMBOL_NAME(exception)
addl $4,%esp
L_ok:
L_underflow:
push %ebx
- call _arith_underflow
+ call SYMBOL_NAME(arith_underflow)
pop %ebx
jmp L_exit
L_overflow:
push %ebx
- call _arith_overflow
+ call SYMBOL_NAME(arith_overflow)
pop %ebx
jmp L_exit
/* Normalise without reporting underflow or overflow */
- .align 2,144
-.globl _normalize_nuo
-
-_normalize_nuo:
+ENTRY(normalize_nuo)
pushl %ebp
movl %esp,%ebp
pushl %ebx
je L_ok_nuo
pushl $0x221
- call _exception
+ call SYMBOL_NAME(exception)
addl $4,%esp
L_ok_nuo:
.text
- .align 2,144
.globl fpu_reg_round
.globl fpu_reg_round_sqrt
.globl fpu_Arith_exit
-.globl _round_reg
/* Entry point when called from C */
-_round_reg:
+ENTRY(round_reg)
pushl %ebp
movl %esp,%ebp
pushl %esi
*/
xL_precision_lost_up:
push %eax
- call _set_precision_flag_up
+ call SYMBOL_NAME(set_precision_flag_up)
popl %eax
jmp xL_no_precision_loss
*/
xL_precision_lost_down:
push %eax
- call _set_precision_flag_down
+ call SYMBOL_NAME(set_precision_flag_down)
popl %eax
jmp xL_no_precision_loss
/* There must be a masked underflow */
push %eax
pushl EX_Underflow
- call _exception
+ call SYMBOL_NAME(exception)
popl %eax
popl %eax
jmp xL_Normalised
*/
L_underflow_to_zero:
push %eax
- call _set_precision_flag_down
+ call SYMBOL_NAME(set_precision_flag_down)
popl %eax
push %eax
pushl EX_Underflow
- call _exception
+ call SYMBOL_NAME(exception)
popl %eax
popl %eax
/* The operations resulted in a number too large to represent. */
L_overflow:
push %edi
- call _arith_overflow
+ call SYMBOL_NAME(arith_overflow)
pop %edi
jmp fpu_reg_round_exit
#include "control_w.h"
.text
- .align 2,144
-.globl _reg_u_add
-_reg_u_add:
+ENTRY(reg_u_add)
pushl %ebp
movl %esp,%ebp
pushl %esi
cmpl EXP_UNDER,EXP(%esi)
jg xOp1_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
cmpl EXP_UNDER,EXP(%edi)
jg xOp2_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
.text
- .align 2,144
-
-.globl _reg_u_div
-
-.globl _divide_kernel
-
-_reg_u_div:
+ENTRY(reg_u_div)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
cmpl EXP_UNDER,%eax
jg xOp1_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
cmpl EXP_UNDER,%eax
jg xOp2_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
xOp2_not_denorm:
#endif DENORM_OPERAND
-_divide_kernel:
+ENTRY(divide_kernel)
#ifdef PARANOID
/* testl $0x80000000, SIGH(%esi) // Dividend */
/* je L_bugged */
.text
- .align 2,144
-
-.globl _reg_u_mul
-_reg_u_mul:
+ENTRY(reg_u_mul)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
cmpl EXP_UNDER,%eax
jg xOp1_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
cmpl EXP_UNDER,%eax
jg xOp2_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
#include "control_w.h"
.text
- .align 2,144
-.globl _reg_u_sub
-_reg_u_sub:
+ENTRY(reg_u_sub)
pushl %ebp
movl %esp,%ebp
pushl %esi
cmpl EXP_UNDER,EXP(%esi)
jg xOp1_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
cmpl EXP_UNDER,EXP(%edi)
jg xOp2_not_denorm
- call _denormal_operand
+ call SYMBOL_NAME(denormal_operand)
orl %eax,%eax
jnz fpu_Arith_exit
.text
-
- .align 2,144
-.globl _round_Xsig
-
-_round_Xsig:
+ENTRY(round_Xsig)
pushl %ebp
movl %esp,%ebp
pushl %ebx /* Reserve some space */
- .align 2,144
-.globl _norm_Xsig
-
-_norm_Xsig:
+ENTRY(norm_Xsig)
pushl %ebp
movl %esp,%ebp
pushl %ebx /* Reserve some space */
#include "fpu_asm.h"
.text
- .align 2,144
-
- .globl _shr_Xsig
-_shr_Xsig:
+ENTRY(shr_Xsig)
push %ebp
movl %esp,%ebp
pushl %esi
#include "fpu_asm.h"
.text
- .align 2,144
-
/*---------------------------------------------------------------------------+
| unsigned shrx(void *arg1, unsigned arg2) |
| |
| Results returned in the 64 bit arg and eax. |
+---------------------------------------------------------------------------*/
- .globl _shrx
-
-_shrx:
+ENTRY(shrx)
push %ebp
movl %esp,%ebp
pushl %esi
| part which has been shifted out of the arg. |
| Results returned in the 64 bit arg and eax. |
+---------------------------------------------------------------------------*/
- .globl _shrxs
-_shrxs:
+ENTRY(shrxs)
push %ebp
movl %esp,%ebp
pushl %esi
.text
- .align 2,144
-
-.globl _wm_sqrt
-_wm_sqrt:
+ENTRY(wm_sqrt)
pushl %ebp
movl %esp,%ebp
#ifndef NON_REENTRANT_FPU
int reservedpages = 0;
int datapages = 0;
unsigned long tmp;
- extern int etext;
+ extern int _etext;
end_mem &= PAGE_MASK;
high_memory = end_mem;
if (mem_map[MAP_NR(tmp)]) {
if (tmp >= 0xA0000 && tmp < 0x100000)
reservedpages++;
- else if (tmp < (unsigned long) &etext)
+ else if (tmp < (unsigned long) &_etext)
codepages++;
else
datapages++;
bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
bool 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC n
-bool 'EATA-DMA (DPT,NEC&ATT for ISA,EISA,PCI) support' CONFIG_SCSI_EATA_DMA n
+bool 'EATA-DMA (DPT, NEC, ATT, Olivetti) support' CONFIG_SCSI_EATA_DMA y
+bool 'EATA-PIO (old DPT PM2001, PM2012A) support' CONFIG_SCSI_EATA_PIO n
bool 'UltraStor 14F/34F support' CONFIG_SCSI_U14_34F n
bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 n
* console.c
*
* This module exports the console io functions:
- *
+ *
* 'void do_keyboard_interrupt(void)'
*
- * 'int vc_allocate(unsigned int console)'
+ * 'int vc_allocate(unsigned int console)'
* 'int vc_cons_allocated(unsigned int console)'
* 'int vc_resize(unsigned long lines, unsigned long cols)'
* 'void vc_disallocate(unsigned int currcons)'
* 'void scrollback(int lines)'
* 'void scrollfront(int lines)'
*
- * 'int con_get_font(char *data)'
+ * 'int con_get_font(char *data)'
* 'int con_set_font(char *data, int ch512)'
* 'int con_adjust_height(int fontheight)'
*
* Hopefully this will be a rather complete VT102 implementation.
*
* Beeping thanks to John T Kohl.
- *
+ *
* Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics
* Chars, and VT100 enhancements by Peter MacDonald.
*
unsigned long vc_report_mouse : 2;
unsigned char vc_utf : 1; /* Unicode UTF-8 encoding */
unsigned char vc_utf_count;
- long vc_utf_char;
+ long vc_utf_char;
unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */
unsigned char vc_palette[16*3]; /* Colour palette for VGA+ */
unsigned short * vc_translate;
#define utf_char (vc_cons[currcons].d->vc_utf_char)
#define video_mem_start (vc_cons[currcons].d->vc_video_mem_start)
#define video_mem_end (vc_cons[currcons].d->vc_video_mem_end)
-#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)
+#define video_erase_char (vc_cons[currcons].d->vc_video_erase_char)
#define disp_ctrl (vc_cons[currcons].d->vc_disp_ctrl)
#define toggle_meta (vc_cons[currcons].d->vc_toggle_meta)
#define decscnm (vc_cons[currcons].d->vc_decscnm)
int count ;
unsigned short * d = (unsigned short *) video_mem_base;
unsigned short * s = (unsigned short *) last_origin;
-
+
lines += last_origin_rel;
/* in case the top part of the screen has been modified since
* the scroll wrapped, copy the top bit back to the bottom */
count--;
scr_writew(video_erase_char, d++);
}
- if (scr_end > last_origin) /* we've wrapped into kept region */
+ if (scr_end > last_origin) /* we've wrapped into kept region */
__scrollback_mode = 0;
}
set_origin(currcons);
default:
if (par[i] >= 30 && par[i] <= 37)
color = color_table[par[i]-30]
- | background;
+ | background;
else if (par[i] >= 40 && par[i] <= 47)
color = (color_table[par[i]-40]<<4)
| foreground;
need_wrap = 0;
}
-enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
+enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey,
EShash, ESsetG0, ESsetG1, ESpercent, ESignore, ESnonstd,
ESpalette };
if (utf) {
/* Combine UTF-8 into Unicode */
/* Incomplete characters silently ignored */
- if(c > 0x7f) {
+ if(c > 0x7f) {
if (utf_count > 0 && (c & 0xc0) == 0x80) {
utf_char = (utf_char << 6) | (c & 0x3f);
utf_count--;
*/
ok = (tc && (c >= 32 || (!utf && !(((disp_ctrl ? CTRL_ALWAYS
: CTRL_ACTION) >> c) & 1))));
-
+
if (vc_state == ESnormal && ok) {
- /* Now try to find out how to display it */
- tc = conv_uni_to_pc(tc);
+ /* Now try to find out how to display it */
+ tc = conv_uni_to_pc(tc);
if ( tc == -4 )
{
/* If we got -4 (not found) then see if we have
case '=': /* Appl. keypad */
set_kbd(kbdapplic);
continue;
- }
+ }
continue;
case ESnonstd:
if (c=='P') { /* palette escape sequence */
console_driver.start = con_start;
console_driver.throttle = con_throttle;
console_driver.unthrottle = con_unthrottle;
-
+
if (tty_register_driver(&console_driver))
panic("Couldn't register console driver\n");
-
+
con_setsize(ORIG_VIDEO_LINES, ORIG_VIDEO_COLS);
video_page = ORIG_VIDEO_PAGE; /* never used */
__scrollback_mode = 0 ;
timer_table[BLANK_TIMER].expires = jiffies+blankinterval;
timer_active |= 1<<BLANK_TIMER;
}
-
+
if (ORIG_VIDEO_MODE == 7) /* Is this a monochrome display? */
{
video_mem_base = 0xb0000;
video_port_val = 0x3d5;
if ((ORIG_VIDEO_EGA_BX & 0xff) != 0x10)
{
- int i ;
-
- video_mem_term = 0xc0000;
-
- if (!ORIG_VIDEO_ISVGA) {
- video_type = VIDEO_TYPE_EGAC;
- display_desc = "EGA";
- request_region(0x3c0,32,"ega");
- } else {
- video_type = VIDEO_TYPE_VGAC;
- display_desc = "VGA+";
- request_region(0x3c0,32,"vga+");
-
- /* get 64K rather than 32K of video RAM */
- video_mem_base = 0xa0000 ;
- video_mem_term = 0xb0000 ;
- outb_p (6, 0x3ce) ;
- outb_p (6, 0x3cf) ;
-
- /* normalise the palette registers, to point the * 16 screen colours to the first 16 DAC entries */
-
- for (i=0; i<16; i++) {
- inb_p (0x3da) ;
- outb_p (i, 0x3c0) ;
- outb_p (i, 0x3c0) ;
- }
- outb_p (0x20, 0x3c0) ;
-
- /* now set the DAC registers back to their default
- * values */
-
- for (i=0; i<16; i++) {
+ int i ;
+
+ video_mem_term = 0xc0000;
+
+ if (!ORIG_VIDEO_ISVGA) {
+ video_type = VIDEO_TYPE_EGAC;
+ display_desc = "EGA";
+ request_region(0x3c0,32,"ega");
+ } else {
+ video_type = VIDEO_TYPE_VGAC;
+ display_desc = "VGA+";
+ request_region(0x3c0,32,"vga+");
+
+#ifdef VGA_CAN_DO_64KB
+ /*
+ * get 64K rather than 32K of video RAM.
+ * This doesn't actually work on all "VGA"
+ * controllers (it seems like setting MM=01
+ * and COE=1 isn't necessarily a good idea)
+ */
+ video_mem_base = 0xa0000 ;
+ video_mem_term = 0xb0000 ;
+ outb_p (6, 0x3ce) ;
+ outb_p (6, 0x3cf) ;
+#endif
+
+ /* normalise the palette registers, to point the * 16 screen colours to the first 16 DAC entries */
+
+ for (i=0; i<16; i++) {
+ inb_p (0x3da) ;
+ outb_p (i, 0x3c0) ;
+ outb_p (i, 0x3c0) ;
+ }
+ outb_p (0x20, 0x3c0) ;
+
+ /* now set the DAC registers back to their default
+ * values */
+
+ for (i=0; i<16; i++) {
outb_p (color_table[i], 0x3c8) ;
- outb_p (default_red[i], 0x3c9) ;
- outb_p (default_grn[i], 0x3c9) ;
- outb_p (default_blu[i], 0x3c9) ;
- }
- }
+ outb_p (default_red[i], 0x3c9) ;
+ outb_p (default_grn[i], 0x3c9) ;
+ outb_p (default_blu[i], 0x3c9) ;
+ }
+ }
}
else
{
request_region(0x3d4,2,"cga");
}
}
-
+
/* Initialize the variables used for scrolling (mostly EGA/VGA) */
/* Due to kmalloc roundup allocating statically is more efficient -
can figure out the appropriate screen size should we load
a different font */
+ printable = 1;
if ( video_type == VIDEO_TYPE_VGAC || video_type == VIDEO_TYPE_EGAC
|| video_type == VIDEO_TYPE_EGAM )
{
video_font_height, video_scan_lines);
}
- printable = 1;
printk("Console: %s %s %ldx%ld, %d virtual console%s (max %d)\n",
can_do_color ? "colour" : "mono",
display_desc,
console_blanked = -1; /* no longer of the form console+1 */
fg_console = new_console; /* this is the only (nonzero) assignment to fg_console */
/* consequently, fg_console will always be allocated */
- set_scrmem(fg_console, 0);
+ set_scrmem(fg_console, 0);
set_origin(fg_console);
set_cursor(fg_console);
set_leds();
int i;
idx = MINOR(tty->device) - tty->driver.minor_start;
-
+
i = vc_allocate(idx);
if (i)
return i;
vt_cons[idx]->vc_num = idx;
tty->driver_data = vt_cons[idx];
-
+
if (!tty->winsize.ws_row && !tty->winsize.ws_col) {
tty->winsize.ws_row = video_num_lines;
tty->winsize.ws_col = video_num_columns;
static int set_get_cmap(unsigned char * arg, int set) {
#ifdef CAN_LOAD_PALETTE
- int i;
+ int i;
- /* no use to set colourmaps in less than colour VGA */
+ /* no use to set colourmaps in less than colour VGA */
- if (video_type != VIDEO_TYPE_VGAC)
+ if (video_type != VIDEO_TYPE_VGAC)
return -EINVAL;
- i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
- if (i)
+ i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, 16*3);
+ if (i)
return i;
- for (i=0; i<16; i++) {
- if (set) {
+ for (i=0; i<16; i++) {
+ if (set) {
default_red[i] = get_user(arg++) ;
default_grn[i] = get_user(arg++) ;
default_blu[i] = get_user(arg++) ;
} else {
put_user (default_red[i], arg++) ;
- put_user (default_grn[i], arg++) ;
- put_user (default_blu[i], arg++) ;
- }
- }
+ put_user (default_grn[i], arg++) ;
+ put_user (default_blu[i], arg++) ;
+ }
+ }
if (set) {
for (i=0; i<MAX_NR_CONSOLES; i++)
if (vc_cons_allocated(i)) {
set_palette() ;
}
- return 0;
+ return 0;
#else
- return -EINVAL;
+ return -EINVAL;
#endif
}
int con_set_cmap (unsigned char *arg)
{
- return set_get_cmap (arg,1);
+ return set_get_cmap (arg,1);
}
int con_get_cmap (unsigned char *arg)
{
- return set_get_cmap (arg,0);
+ return set_get_cmap (arg,0);
}
void reset_palette (int currcons)
vt_cons[fg_console]->vc_mode == KD_GRAPHICS)
return ;
- for (i=j=0; i<16; i++) {
+ for (i=j=0; i<16; i++) {
outb_p (color_table[i], dac_reg) ;
outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
outb_p (vc_cons[fg_console].d->vc_palette[j++]>>2, dac_val) ;
- }
+ }
}
/*
if (fontheight > 32 || (video_type != VIDEO_TYPE_VGAC &&
video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM))
- return -EINVAL;
+ return -EINVAL;
if ( fontheight == video_font_height || fontheight == 0 )
return 0;
-
+
video_font_height = fontheight;
rows = video_scan_lines/fontheight; /* Number of video rows we end up with */
maxscan = rows*fontheight - 1; /* Scan lines to actually display-1 */
/* Reprogram the CRTC for the new font size
- Note: the attempt to read the overflow register will fail
+ Note: the attempt to read the overflow register will fail
on an EGA, but using 0xff for the previous value appears to
be OK for EGA text modes in the range 257-512 scan lines, so I
guess we don't need to worry about it.
cli();
outb_p( 0x07, video_port_reg ); /* CRTC overflow register */
ovr = inb_p(video_port_val);
- outb_p( 0x09, video_port_reg ); /* Font size register */
+ outb_p( 0x09, video_port_reg ); /* Font size register */
fsr = inb_p(video_port_val);
- outb_p( 0x0a, video_port_reg ); /* Cursor start */
+ outb_p( 0x0a, video_port_reg ); /* Cursor start */
curs = inb_p(video_port_val);
- outb_p( 0x0b, video_port_reg ); /* Cursor end */
+ outb_p( 0x0b, video_port_reg ); /* Cursor end */
cure = inb_p(video_port_val);
sti();
cli();
outb_p( 0x07, video_port_reg ); /* CRTC overflow register */
outb_p( ovr, video_port_val );
- outb_p( 0x09, video_port_reg ); /* Font size */
+ outb_p( 0x09, video_port_reg ); /* Font size */
outb_p( fsr, video_port_val );
- outb_p( 0x0a, video_port_reg ); /* Cursor start */
+ outb_p( 0x0a, video_port_reg ); /* Cursor start */
outb_p( curs, video_port_val );
- outb_p( 0x0b, video_port_reg ); /* Cursor end */
+ outb_p( 0x0b, video_port_reg ); /* Cursor end */
outb_p( cure, video_port_val );
- outb_p( 0x12, video_port_reg ); /* Vertical display limit */
+ outb_p( 0x12, video_port_reg ); /* Vertical display limit */
outb_p( vde, video_port_val );
sti();
return 0;
}
- vc_resize(rows, 0); /* Adjust console size */
+ vc_resize(rows, 0); /* Adjust console size */
return rows;
}
* 0xf000-0xf0ff "transparent" Unicodes) whereas the "new" variants set
* unicodes explictly.
*/
-int con_set_trans_old(char * arg)
+int con_set_trans_old(unsigned char * arg)
{
int i;
unsigned short *p = translations[USER_MAP];
return 0;
}
-int con_get_trans_old(char * arg)
+int con_get_trans_old(unsigned char * arg)
{
int i, ch;
unsigned short *p = translations[USER_MAP];
else {
unregister_chrdev(LP_MAJOR,"lp");
for (offset = 0; offset < LP_NO; offset++)
- if(LP_F(offset) && LP_EXIST)
+ if (LP_F(offset) & LP_EXIST)
release_region(LP_B(offset),3);
}
}
int retries=0;
while ((inb(AUX_STATUS)&0x03) && retries < MAX_RETRIES) {
- if (inb_p(AUX_STATUS) & AUX_OBUF_FULL == AUX_OBUF_FULL)
+ if ((inb_p(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL)
inb_p(AUX_INPUT_PORT);
current->state = TASK_INTERRUPTIBLE;
current->timeout = jiffies + (5*HZ + 99) / 100;
* routines to load custom translation table, EGA/VGA font and
* VGA colour palette from console.c
*/
-extern int con_set_trans_old(char * table);
-extern int con_get_trans_old(char * table);
+extern int con_set_trans_old(unsigned char * table);
+extern int con_get_trans_old(unsigned char * table);
extern int con_set_trans_new(unsigned short * table);
extern int con_get_trans_new(unsigned short * table);
extern void con_clear_unimap(struct unimapinit *ui);
case PIO_SCRNMAP:
if (!perm)
return -EPERM;
- return con_set_trans_old((char *)arg);
+ return con_set_trans_old((unsigned char *)arg);
case GIO_SCRNMAP:
- return con_get_trans_old((char *)arg);
+ return con_get_trans_old((unsigned char *)arg);
case PIO_UNISCRNMAP:
if (!perm)
* be here without 3C505 technical reference provided by
* 3Com.
*
- * Version: @(#)3c505.c 0.8 4-Jun-95
+ * Version: @(#)3c505.c 0.8.1 26-Jun-95
*
* Authors: Linux 3c505 device driver by
* Craig Southeren, <craigs@ineluki.apana.org.au>
* 3 = messages when interrupts received
*/
-#define ELP_VERSION "0.7.0"
+#define ELP_VERSION "0.8.1"
/*****************************************************************
*
*****************************************************************/
typedef struct {
- short got[NUM_TRANSMIT_CMDS]; /* flags for command completion */
+ volatile short got[NUM_TRANSMIT_CMDS]; /* flags for command completion */
pcb_struct tx_pcb; /* PCB for foreground sending */
pcb_struct rx_pcb; /* PCB for foreground receiving */
pcb_struct itx_pcb; /* PCB for background sending */
# If you want at least one board to not autosense then
# no board can autosense. For a board mix of several
# types, OR the manual values [eg for a DE500 (100M) with
-# a DE450 (AUI) use '-DDE4X5_AUTOSENSE=(0x80|0x08)']
-# For full auto media/mode selection = 0x4000
-# For manual TP media selection = 0x01
-# For manual TP/Nway media selection (DC21041) = 0x02
-# For manual BNC media selection = 0x04
-# For manual AUI media selection = 0x08
-# For manual BNC/AUI media selection (DC21040) = 0x10
-# For manual 10Mb/s mode selection (DC21140) = 0x40
-# For manual 100Mb/s mode selection (DC21140) = 0x80
+# a DE450 (AUI) use '-DDE4X5_AUTOSENSE=(_100Mb|AUI)']
+# For full auto media/mode selection = AUTO
+# For manual TP media selection = TP
+# For manual TP/Nway media selection (DC21041) = TP_NW
+# For manual BNC media selection = BNC
+# For manual AUI media selection = AUI
+# For manual BNC/AUI media selection (DC21040) = BNC_AUI
+# For manual 10Mb/s mode selection (DC21140) = _10Mb
+# For manual 100Mb/s mode selection (DC21140) = _100Mb
# The DC21040 will default to TP if TP_NW is specified
# The DC21041 will default to BNC if BNC_AUI is specified
# The DC21140 needs it's speed to be manually set to
PLIP_OPTS =
DEPCA_OPTS = -DDEPCA_DEBUG=1
EWRK3_OPTS = -DEWRK3_DEBUG=1
-DE4X5_OPTS = -DDE4X5_DEBUG=1 -DDE4X5_AUTOSENSE=0x4000
+DE4X5_OPTS = -DDE4X5_DEBUG=1 -DDE4X5_AUTOSENSE=AUTO
ELP_OPTS = -DELP_DEBUG=1 -DELP_NEED_HARD_RESET=0
+
NETDRV_OBJS := $(NETDRV_OBJS) tunnel.o
endif
+ifdef CONFIG_HP100
+NETDRV_OBJS := $(NETDRV_OBJS) hp100.o
+endif
+
ifdef CONFIG_WD80x3
NETDRV_OBJS := $(NETDRV_OBJS) wd.o
CONFIG_8390 = CONFIG_8390
MODULES := $(MODULES) de4x5.o
endif
de4x5.o: de4x5.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(DE4x5_OPTS) -c $<
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(DE4X5_OPTS) -c $<
ifdef CONFIG_NI52
NETDRV_OBJS := $(NETDRV_OBJS) ni52.o
ethernet adaptor have the name "eth[0123...]".
*/
+extern int hp100_probe(struct device *dev);
extern int ultra_probe(struct device *dev);
extern int wd_probe(struct device *dev);
extern int el2_probe(struct device *dev);
static int
ethif_probe(struct device *dev)
{
- short base_addr = dev->base_addr;
+ u_long base_addr = dev->base_addr;
- if (base_addr < 0 || base_addr == 1)
+ if ((base_addr == 0xffe0) || (base_addr == 1))
return 1; /* ENXIO */
if (1
+#if defined(CONFIG_HP100)
+ && hp100_probe(dev)
+#endif
#if defined(CONFIG_ULTRA)
&& ultra_probe(dev)
#endif
-/* de4x5.c: A DIGITAL DE425/DE434/DE435 ethernet driver for linux.
+/* de4x5.c: A DIGITAL DE425/DE434/DE435/DE500 ethernet driver for Linux.
Copyright 1994, 1995 Digital Equipment Corporation.
0) have a copy of the loadable modules code installed on your system.
1) copy de4x5.c from the /linux/drivers/net directory to your favourite
temporary directory.
- 2) edit the source code near line 1945 to reflect the I/O address and
+ 2) edit the source code near line 2762 to reflect the I/O address and
IRQ you're using, or assign these when loading by:
insmod de4x5.o irq=x io=y
pause whilst the driver figures out where its media went). My tests
using ping showed that it appears to work....
- A compile time switch to allow Zynx recognition has been added. This
+ A compile time switch to allow Znyx recognition has been added. This
"feature" is in no way supported nor tested in this driver and the user
may use it at his/her sole discretion. I have had 2 conflicting reports
- that my driver will or won't work with Zynx. Try Donald Becker's
+ that my driver will or won't work with Znyx. Try Donald Becker's
'tulip.c' if this driver doesn't work for you. I will not be supporting
- Zynx cards since I have no information on them and can't test them in a
+ Znyx cards since I have no information on them and can't test them in a
system.
TO DO:
Change media autodetection to allow manual setting.
Completed DE500 (DC21140) support.
0.241 18-Apr-95 Interim release without DE500 Autosense Algorithm.
+ 0.242 10-May-95 Minor changes
+ 0.30 12-Jun-95 Timer fix for DC21140
+ Portability changes.
+ Add ALPHA changes from <jestabro@ant.tay1.dec.com>.
+ Add DE500 semi automatic autosense.
+ Add Link Fail interrupt TP failure detection.
+ Add timer based link change detection.
+ Plugged a memory leak in de4x5_queue_pkt().
+ 0.31 13-Jun-95 Fixed PCI stuff for 1.3.1
+ 0.32 26-Jun-95 Added verify_area() calls in de4x5_ioctl() from
+ suggestion by <heiko@colossus.escape.de>
=========================================================================
*/
-static char *version = "de4x5.c:v0.241 4/18/95 davies@wanton.lkg.dec.com\n";
+static char *version = "de4x5.c:v0.32 6/26/95 davies@wanton.lkg.dec.com\n";
#include <linux/config.h>
#ifdef MODULE
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
+#include <linux/bios32.h>
#include <linux/pci.h>
#include <linux/delay.h>
#include <asm/bitops.h>
#ifdef DE4X5_AUTOSENSE /* Should be done on a per adapter basis */
static int de4x5_autosense = DE4X5_AUTOSENSE;
#else
-static int de4x5_autosense = AUTO; /* Do auto media/mode sensing */
+static int de4x5_autosense = AUTO; /* Do auto media/mode sensing */
#endif
+#ifdef DE4X5_FULL_DUPLEX /* Should be done on a per adapter basis */
+static s32 de4x5_full_duplex = 1;
+#else
+static s32 de4x5_full_duplex = 0;
+#endif
+
+#define DE4X5_NDA 0xffe0 /* No Device (I/O) Address */
+
/*
** Ethernet PROM defines
*/
/*
** Ethernet Info
*/
-#define PKT_BUF_SZ 1544 /* Buffer size for each Tx/Rx buffer */
+#define PKT_BUF_SZ 1536 /* Buffer size for each Tx/Rx buffer */
#define MAX_PKT_SZ 1514 /* Maximum ethernet packet length */
#define MAX_DAT_SZ 1500 /* Maximum ethernet data length */
#define MIN_DAT_SZ 1 /* Minimum ethernet data length */
#define PKT_HDR_LEN 14 /* Addresses and data length info */
+#define FAKE_FRAME_LEN (MAX_PKT_SZ + 1)
+#define QUEUE_PKT_TIMEOUT (300) /* Jiffies */
+
#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
*/
#define PCI_MAX_BUS_NUM 8
#define DE4X5_PCI_TOTAL_SIZE 0x80 /* I/O address extent */
+#define DE4X5_CLASS_CODE 0x00020000 /* Network controller, Ethernet */
/*
** Memory Alignment. Each descriptor is 4 longwords long. To force a
#define ALIGN ALIGN32 /* Keep the DC21040 happy... */
#define CACHE_ALIGN CAL_16LONG
#define DESC_SKIP_LEN DSL_0 /* Must agree with DESC_ALIGN */
-/*#define DESC_ALIGN u_long dummy[4]; / * Must agree with DESC_SKIP_LEN */
+/*#define DESC_ALIGN u32 dummy[4]; / * Must agree with DESC_SKIP_LEN */
#define DESC_ALIGN
#ifndef IS_NOT_DEC /* See README.de4x5 for using this */
/*
** DE4X5 IRQ ENABLE/DISABLE
*/
-static u_long irq_mask = IMR_SEM | IMR_RIM | IMR_RUM | IMR_TIM | IMR_TUM ;
-
-static u_long irq_en = IMR_NIM | IMR_AIM;
-
#define ENABLE_IRQs { \
- imr |= irq_en;\
+ imr |= lp->irq_en;\
outl(imr, DE4X5_IMR); /* Enable the IRQs */\
}
#define DISABLE_IRQs {\
imr = inl(DE4X5_IMR);\
- imr &= ~irq_en;\
+ imr &= ~lp->irq_en;\
outl(imr, DE4X5_IMR); /* Disable the IRQs */\
}
#define UNMASK_IRQs {\
- imr |= irq_mask;\
+ imr |= lp->irq_mask;\
outl(imr, DE4X5_IMR); /* Unmask the IRQs */\
}
#define MASK_IRQs {\
imr = inl(DE4X5_IMR);\
- imr &= ~irq_mask;\
+ imr &= ~lp->irq_mask;\
outl(imr, DE4X5_IMR); /* Mask the IRQs */\
}
*/
#define RESET_SIA outl(0, DE4X5_SICR); /* Reset SIA connectivity regs */
+/*
+** DE500 AUTOSENSE TIMER INTERVAL (MILLISECS)
+*/
+#define DE4X5_AUTOSENSE_MS 250
+
/*
** SROM Structure
*/
/*
** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous
** and have sizes of both a power of 2 and a multiple of 4.
-** A size of 256 bytes for each buffer was chosen because over 90% of
+** A size of 256 bytes for each buffer could be chosen because over 90% of
** all packets in our network are <256 bytes long and 64 longword alignment
-** is possible.
+** is possible. 1536 showed better 'ttcp' performance. Take your pick. 32 TX
+** descriptors are needed for machines with an ALPHA CPU.
*/
#define NUM_RX_DESC 8 /* Number of RX descriptors */
-#define NUM_TX_DESC 8 /* Number of TX descriptors */
+#define NUM_TX_DESC 32 /* Number of TX descriptors */
#define BUFF_ALLOC_RETRIES 10 /* In case of memory shortage */
#define RX_BUFF_SZ 1536 /* Power of 2 for kmalloc and */
/* Multiple of 4 for DC21040 */
-
struct de4x5_desc {
- volatile long status;
- u_long des1;
- char *buf;
- char *next;
+ volatile s32 status;
+ u32 des1;
+ u32 buf;
+ u32 next;
DESC_ALIGN
};
char setup_frame[SETUP_FRAME_LEN]; /* Holds MCA and PA info. */
struct enet_statistics stats; /* Public stats */
struct {
- unsigned long bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
- unsigned long unicast;
- unsigned long multicast;
- unsigned long broadcast;
- unsigned long excessive_collisions;
- unsigned long tx_underruns;
- unsigned long excessive_underruns;
+ u_int bins[DE4X5_PKT_STAT_SZ]; /* Private stats counters */
+ u_int unicast;
+ u_int multicast;
+ u_int broadcast;
+ u_int excessive_collisions;
+ u_int tx_underruns;
+ u_int excessive_underruns;
} pktStats;
char rxRingSize;
char txRingSize;
- char bus; /* EISA or PCI */
- u_short chipset; /* DC21040, DC21041 or DC21140 */
- long media; /* Media (eg TP), mode (eg 100B)*/
+ int bus; /* EISA or PCI */
+ int bus_num; /* PCI Bus number */
+ int chipset; /* DC21040, DC21041 or DC21140 */
+ s32 irq_mask; /* Interrupt Mask (Enable) bits */
+ s32 irq_en; /* Summary interrupt bits */
+ int media; /* Media (eg TP), mode (eg 100B)*/
+ int linkProb; /* Possible Link Problem */
int autosense; /* Allow/disallow autosensing */
int tx_enable; /* Enable descriptor polling */
- char lostMedia; /* Possibly lost media */
+ int lostMedia; /* Possibly lost media */
int setup_f; /* Setup frame filtering type */
};
#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
lp->tx_old+lp->txRingSize-lp->tx_new-1:\
lp->tx_old -lp->tx_new-1)
-/*#define TX_BUFFS_AVAIL ((lp->tx_ring[lp->tx_new].status)>=0 ? 1 : 0)*/
/*
** Public Functions
/*
** Private functions
*/
-static int de4x5_hw_init(struct device *dev, short iobase);
+static int de4x5_hw_init(struct device *dev, u_long iobase);
static int de4x5_init(struct device *dev);
static int de4x5_rx(struct device *dev);
static int de4x5_tx(struct device *dev);
+static int de4x5_ast(struct device *dev);
static int autoconf_media(struct device *dev);
static void create_packet(struct device *dev, char *frame, int len);
-static void dce_us_delay(u_long usec);
-static void dce_ms_delay(u_long msec);
-static void load_packet(struct device *dev, char *buf, u_long flags, struct sk_buff *skb);
+static void dce_us_delay(u32 usec);
+static void dce_ms_delay(u32 msec);
+static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb);
static void dc21040_autoconf(struct device *dev);
static void dc21041_autoconf(struct device *dev);
static void dc21140_autoconf(struct device *dev);
-static long test_media(struct device *dev, long irqs, long irq_mask, long csr13, long csr14, long csr15, long msec);
-static long ping_media(struct device *dev);
-static void reset_init_sia(struct device *dev, long sicr, long strr, long sigr);
-static int test_ans(struct device *dev, long irqs, long irq_mask, long msec);
-static void load_ms_timer(struct device *dev, u_long msec);
-static int EISA_signature(char *name, long eisa_id);
-static int DevicePresent(short iobase);
-static short srom_rd(u_short address, u_char offset);
-static void srom_latch(u_long command, u_short address);
-static void srom_command(u_long command, u_short address);
-static void srom_address(u_long command, u_short address, u_char offset);
-static short srom_data(u_long command, u_short address);
-/*static void srom_busy(u_long command, u_short address);*/
-static void sendto_srom(u_long command, u_short addr);
-static long getfrom_srom(u_short addr);
+static int test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec);
+/*static int test_sym_link(struct device *dev, u32 msec);*/
+static int ping_media(struct device *dev);
+static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr);
+static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec);
+static void load_ms_timer(struct device *dev, u32 msec);
+static int EISA_signature(char *name, s32 eisa_id);
+static int DevicePresent(u_long iobase);
+static short srom_rd(u_long address, u_char offset);
+static void srom_latch(u_int command, u_long address);
+static void srom_command(u_int command, u_long address);
+static void srom_address(u_int command, u_long address, u_char offset);
+static short srom_data(u_int command, u_long address);
+/*static void srom_busy(u_int command, u_long address);*/
+static void sendto_srom(u_int command, u_long addr);
+static int getfrom_srom(u_long addr);
static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs);
-static int aprom_crc (struct device *dev);
+static int get_hw_addr(struct device *dev);
-static void eisa_probe(struct device *dev, short iobase);
-static void pci_probe(struct device *dev, short iobase);
-static struct device *alloc_device(struct device *dev, int iobase);
+static void eisa_probe(struct device *dev, u_long iobase);
+static void pci_probe(struct device *dev, u_long iobase);
+static struct device *alloc_device(struct device *dev, u_long iobase);
static char *build_setup_frame(struct device *dev, int mode);
+static void disable_ast(struct device *dev);
+static void enable_ast(struct device *dev, u32 time_out);
+static void kick_tx(struct device *dev);
#ifdef MODULE
int init_module(void);
*/
static struct bus_type {
int bus;
+ int bus_num;
int device;
int chipset;
struct de4x5_srom srom;
** Miscellaneous defines...
*/
#define RESET_DE4X5 {\
- long i;\
+ int i;\
i=inl(DE4X5_BMR);\
+ dce_ms_delay(1);\
outl(i | BMR_SWR, DE4X5_BMR);\
+ dce_ms_delay(1);\
outl(i, DE4X5_BMR);\
- for (i=0;i<5;i++) inl(DE4X5_BMR);\
+ dce_ms_delay(1);\
+ for (i=0;i<5;i++) {inl(DE4X5_BMR); dce_ms_delay(1);}\
+ dce_ms_delay(1);\
}
\f
int de4x5_probe(struct device *dev)
{
- int tmp = num_de4x5s, iobase = dev->base_addr;
- int status = -ENODEV;
+ int tmp = num_de4x5s, status = -ENODEV;
+ u_long iobase = dev->base_addr;
if ((iobase == 0) && loading_module){
printk("Autoprobing is not supported when loading a module based driver.\n");
status = -EIO;
- } else { /* First probe for the Ethernet */
- /* Address PROM pattern */
+ } else {
eisa_probe(dev, iobase);
pci_probe(dev, iobase);
- if ((tmp == num_de4x5s) && (iobase != 0)) {
- printk("%s: de4x5_probe() cannot find device at 0x%04x.\n", dev->name,
+ if ((tmp == num_de4x5s) && (iobase != 0) && loading_module) {
+ printk("%s: de4x5_probe() cannot find device at 0x%04lx.\n", dev->name,
iobase);
}
}
static int
-de4x5_hw_init(struct device *dev, short iobase)
+de4x5_hw_init(struct device *dev, u_long iobase)
{
struct bus_type *lp = &bus;
int tmpbus, tmpchs, i, j, status=0;
char *tmp;
- u_long nicsr;
/* Ensure we're not sleeping */
if (lp->chipset == DC21041) {
RESET_DE4X5;
- if (((nicsr=inl(DE4X5_STS)) & (STS_TS | STS_RS)) == 0) {
+ if ((inl(DE4X5_STS) & (STS_TS | STS_RS)) == 0) {
/*
** Now find out what kind of DC21040/DC21041/DC21140 board we have.
*/
if (*name != '\0') { /* found a board signature */
dev->base_addr = iobase;
-
if (lp->bus == EISA) {
- printk("%s: %s at %#3x (EISA slot %d)",
- dev->name, name, (u_short)iobase, (((u_short)iobase>>12)&0x0f));
+ printk("%s: %s at %04lx (EISA slot %ld)",
+ dev->name, name, iobase, ((iobase>>12)&0x0f));
} else { /* PCI port address */
- printk("%s: %s at %#3x (PCI device %d)", dev->name, name, (u_short)iobase,lp->device);
+ printk("%s: %s at %04lx (PCI bus %d, device %d)", dev->name, name,
+ iobase, lp->bus_num, lp->device);
}
printk(", h/w address ");
- status = aprom_crc(dev);
+ status = get_hw_addr(dev);
for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet addr. */
printk("%2.2x:", dev->dev_addr[i]);
}
for (i=0; i<NUM_RX_DESC; i++) {
lp->rx_ring[i].status = 0;
lp->rx_ring[i].des1 = RX_BUFF_SZ;
- lp->rx_ring[i].buf = tmp + i * RX_BUFF_SZ;
- lp->rx_ring[i].next = NULL;
+ lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ);
+ lp->rx_ring[i].next = (u32)NULL;
}
+ barrier();
}
}
lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER;
/* Tell the adapter where the TX/RX rings are located. */
- outl((long)lp->rx_ring, DE4X5_RRBA);
- outl((long)lp->tx_ring, DE4X5_TRBA);
+ outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+ outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
+
+ /* Initialise the IRQ mask and Enable/Disable */
+ lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM ;
+ lp->irq_en = IMR_NIM | IMR_AIM;
lp->tx_enable = TRUE;
if (dev->irq < 2) {
#ifndef MODULE
unsigned char irqnum;
- u_long omr;
+ s32 omr;
autoirq_setup(0);
omr = inl(DE4X5_OMR);
} else { /* Incorrectly initialised hardware */
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
if (lp) {
- kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
+ kfree_s(bus_to_virt(lp->rx_ring[0].buf),
+ RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
}
if (dev->priv) {
kfree_s(dev->priv, sizeof(struct de4x5_private) + ALIGN);
de4x5_open(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- short iobase = dev->base_addr;
+ u_long iobase = dev->base_addr;
int i, status = 0;
- long imr, omr, sts;
+ s32 imr, omr, sts;
/*
** Wake up the adapter
}
printk("\n");
printk("Descriptor head addresses:\n");
- printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring);
+ printk("\t0x%8.8lx 0x%8.8lx\n",(u_long)lp->rx_ring,(u_long)lp->tx_ring);
printk("Descriptor addresses:\nRX: ");
for (i=0;i<lp->rxRingSize-1;i++){
if (i < 3) {
- printk("0x%8.8lx ",(long)&lp->rx_ring[i].status);
+ printk("0x%8.8lx ",(u_long)&lp->rx_ring[i].status);
}
}
- printk("...0x%8.8lx\n",(long)&lp->rx_ring[i].status);
+ printk("...0x%8.8lx\n",(u_long)&lp->rx_ring[i].status);
printk("TX: ");
for (i=0;i<lp->txRingSize-1;i++){
if (i < 3) {
- printk("0x%8.8lx ", (long)&lp->tx_ring[i].status);
+ printk("0x%8.8lx ", (u_long)&lp->tx_ring[i].status);
}
}
- printk("...0x%8.8lx\n", (long)&lp->tx_ring[i].status);
+ printk("...0x%8.8lx\n", (u_long)&lp->tx_ring[i].status);
printk("Descriptor buffers:\nRX: ");
for (i=0;i<lp->rxRingSize-1;i++){
if (i < 3) {
- printk("0x%8.8lx ",(long)lp->rx_ring[i].buf);
+ printk("0x%8.8x ",lp->rx_ring[i].buf);
}
}
- printk("...0x%8.8lx\n",(long)lp->rx_ring[i].buf);
+ printk("...0x%8.8x\n",lp->rx_ring[i].buf);
printk("TX: ");
for (i=0;i<lp->txRingSize-1;i++){
if (i < 3) {
- printk("0x%8.8lx ", (long)lp->tx_ring[i].buf);
+ printk("0x%8.8x ", lp->tx_ring[i].buf);
}
}
- printk("...0x%8.8lx\n", (long)lp->tx_ring[i].buf);
+ printk("...0x%8.8x\n", lp->tx_ring[i].buf);
printk("Ring size: \nRX: %d\nTX: %d\n",
(short)lp->rxRingSize,
(short)lp->txRingSize);
de4x5_init(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- short iobase = dev->base_addr;
- int status = 0;
- long i, j, bmr, omr;
+ u_long iobase = dev->base_addr;
+ int i, j, status = 0;
+ s32 bmr, omr;
/* Lock out other processes whilst setting up the hardware */
set_bit(0, (void *)&dev->tbusy);
omr = OMR_SDP | OMR_SF;
lp->setup_f = PERFECT;
}
- outl((long)lp->rx_ring, DE4X5_RRBA);
- outl((long)lp->tx_ring, DE4X5_TRBA);
+ outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA);
+ outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA);
lp->rx_new = lp->rx_old = 0;
lp->tx_new = lp->tx_old = 0;
lp->tx_ring[i].status = 0;
}
+ barrier();
+
/* Build the setup frame depending on filtering mode */
SetMulticastFilter(dev, 0, NULL);
outl(omr|OMR_ST, DE4X5_OMR);
/* Poll for completion of setup frame (interrupts are disabled for now) */
- for (j=0, i=0;(i<100) && (j==0);i++) {
+ for (j=0, i=jiffies;(i==jiffies) && (j==0);) {
if (lp->tx_ring[lp->tx_new].status >= 0) j=1;
}
outl(omr, DE4X5_OMR); /* Stop everything! */
- if (i == 100) {
+ if (j == 0) {
printk("%s: Setup frame timed out, status %08x\n", dev->name,
inl(DE4X5_STS));
status = -EIO;
static int
de4x5_queue_pkt(struct sk_buff *skb, struct device *dev)
{
- volatile struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
- int status = 0;
- u_long imr, omr, sts;
-
- sts = inl(DE4X5_STS);
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ int i, status = 0;
+ s32 imr, omr, sts;
+ /*
+ ** Clean out the TX ring asynchronously to interrupts - sometimes the
+ ** interrupts are lost by delayed descriptor status updates relative to
+ ** the irq assertion, especially with a busy PCI bus.
+ */
+ if (set_bit(0, (void*)&dev->tbusy) == 0) {
+ cli();
+ de4x5_tx(dev);
+ dev->tbusy = 0;
+ sti();
+ }
+
/*
** Transmitter timeout, possibly serious problems.
** The 'lostMedia' threshold accounts for transient errors that
** were noticed when switching media.
*/
if (dev->tbusy || (lp->lostMedia > LOST_MEDIA_THRESHOLD)) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 10 && (lp->lostMedia <= LOST_MEDIA_THRESHOLD)) {
+ u_long tickssofar = jiffies - dev->trans_start;
+ if ((tickssofar < QUEUE_PKT_TIMEOUT) &&
+ (lp->lostMedia <= LOST_MEDIA_THRESHOLD)) {
status = -1;
} else {
- printk("%s: transmit timed out, status %08x, tbusy:%d, lostMedia:%d tickssofar:%d, resetting.\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, tickssofar);
-
+ if (de4x5_debug >= 1) {
+ printk("%s: transmit timed out, status %08x, tbusy:%d, lostMedia:%d tickssofar:%ld, resetting.\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, tickssofar);
+ }
+
/* Stop and reset the TX and RX... */
STOP_DE4X5;
+
+ /* Re-queue any skb's. */
+ for (i=lp->tx_old; i!=lp->tx_new; i=(++i)%lp->txRingSize) {
+ if (lp->skb[i] != NULL) {
+ if (lp->skb[i]->len != FAKE_FRAME_LEN) {
+ if (lp->tx_ring[i].status == T_OWN) {
+ dev_queue_xmit(lp->skb[i], dev, SOPRI_NORMAL);
+ } else { /* already sent */
+ dev_kfree_skb(lp->skb[i], FREE_WRITE);
+ }
+ } else {
+ dev_kfree_skb(lp->skb[i], FREE_WRITE);
+ }
+ lp->skb[i] = NULL;
+ }
+ }
+ if (skb->len != FAKE_FRAME_LEN) {
+ dev_queue_xmit(skb, dev, SOPRI_NORMAL);
+ } else {
+ dev_kfree_skb(skb, FREE_WRITE);
+ }
+
+ /* Initialise the hardware */
status = de4x5_init(dev);
/* Unmask DE4X5 board interrupts */
}
} else if (skb == NULL) {
dev_tint(dev);
+ } else if (skb->len == FAKE_FRAME_LEN) { /* Don't TX a fake frame! */
+ dev_kfree_skb(skb, FREE_WRITE);
} else if (skb->len > 0) {
-
- /*
- ** Block a timer-based transmit from overlapping. This could better be
- ** done with atomic_swap(1, dev->tbusy), but set_bit() works as well.
- */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
+ /* Enforce 1 process per h/w access */
+ if (set_bit(0, (void*)&dev->tbusy) != 0) {
printk("%s: Transmitter access conflict.\n", dev->name);
+ status = -1; /* Re-queue packet */
+ } else {
+ cli();
+ if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
+ load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
+ if (lp->tx_enable) {
+ outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
+ }
- if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
- load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb);
- if (lp->tx_enable) {
- outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
- }
-
- lp->tx_new = (++lp->tx_new) % lp->txRingSize; /* Ensure a wrap */
-
- dev->trans_start = jiffies;
- }
+ lp->tx_new = (++lp->tx_new) % lp->txRingSize; /* Ensure a wrap */
+ dev->trans_start = jiffies;
- if (TX_BUFFS_AVAIL) {
- dev->tbusy = 0; /* Another pkt may be queued */
+ if (TX_BUFFS_AVAIL) {
+ dev->tbusy = 0; /* Another pkt may be queued */
+ }
+ } else { /* Ring full - re-queue */
+ status = -1;
+ }
+ sti();
}
}
/*
** The DE4X5 interrupt handler.
+**
+** I/O Read/Writes through intermediate PCI bridges are never 'posted',
+** so that the asserted interrupt always has some real data to work with -
+** if these I/O accesses are ever changed to memory accesses, ensure the
+** STS write is read immediately to complete the transaction if the adapter
+** is not on bus 0. Lost interrupts can still occur when the PCI bus load
+** is high and descriptor status bits cannot be set before the associated
+** interrupt is asserted and this routine entered.
*/
static void
de4x5_interrupt(int irq, struct pt_regs *regs)
{
struct device *dev = (struct device *)(irq2dev_map[irq]);
struct de4x5_private *lp;
- int iobase;
- u_long imr, omr, sts;
+ s32 imr, omr, sts;
+ u_long iobase;
if (dev == NULL) {
printk ("de4x5_interrupt(): irq %d for unknown device.\n", irq);
if (dev->interrupt)
printk("%s: Re-entering the interrupt handler.\n", dev->name);
+ DISABLE_IRQs; /* Ensure non re-entrancy */
dev->interrupt = MASK_INTERRUPTS;
- /*
- ** Get the interrupt information and disable them.
- ** The device read will ensure pending buffers are flushed
- ** in intermediate PCI bridges, so that the posted interrupt
- ** has some real data to work with.
- */
- sts = inl(DE4X5_STS);
- MASK_IRQs;
+ while ((sts = inl(DE4X5_STS)) & lp->irq_mask) { /* Read IRQ status */
+ outl(sts, DE4X5_STS); /* Reset the board interrupts */
+
+ if (sts & (STS_RI | STS_RU)) /* Rx interrupt (packet[s] arrived) */
+ de4x5_rx(dev);
- outl(sts, DE4X5_STS); /* Reset the board interrupts */
+ if (sts & (STS_TI | STS_TU)) /* Tx interrupt (packet sent) */
+ de4x5_tx(dev);
- if (sts & (STS_RI | STS_RU)) /* Rx interrupt (packet[s] arrived) */
- de4x5_rx(dev);
+ if (sts & STS_TM) /* Autosense tick */
+ de4x5_ast(dev);
- if (sts & (STS_TI | STS_TU)) /* Tx interrupt (packet sent) */
- de4x5_tx(dev);
+ if (sts & STS_LNF) { /* TP Link has failed */
+ lp->lostMedia = LOST_MEDIA_THRESHOLD + 1;
+ lp->irq_mask &= ~IMR_LFM;
+ kick_tx(dev);
+ }
- if (sts & STS_SE) { /* Bus Error */
- STOP_DE4X5;
- printk("%s: Fatal bus error occurred, sts=0x%08lx, device stopped.\n",
- dev->name, sts);
+ if (sts & STS_SE) { /* Bus Error */
+ STOP_DE4X5;
+ printk("%s: Fatal bus error occured, sts=%#8x, device stopped.\n",
+ dev->name, sts);
+ }
}
if (TX_BUFFS_AVAIL && dev->tbusy) {/* Any resources available? */
}
dev->interrupt = UNMASK_INTERRUPTS;
-
- UNMASK_IRQs;
+ ENABLE_IRQs;
}
return;
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
int i, entry;
- volatile long status;
+ s32 status;
char *buf;
for (entry = lp->rx_new; lp->rx_ring[entry].status >= 0;entry = lp->rx_new) {
if (entry < lp->rx_old) { /* Wrapped buffer */
short len = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ;
- memcpy(skb->data, lp->rx_ring[lp->rx_old].buf, len);
- memcpy(skb->data + len, lp->rx_ring[0].buf, pkt_len - len);
+ memcpy(skb->data, bus_to_virt(lp->rx_ring[lp->rx_old].buf), len);
+ memcpy(skb->data + len, bus_to_virt(lp->rx_ring[0].buf), pkt_len - len);
} else { /* Linear buffer */
- memcpy(skb->data, lp->rx_ring[lp->rx_old].buf, pkt_len);
+ memcpy(skb->data, bus_to_virt(lp->rx_ring[lp->rx_old].buf), pkt_len);
}
- /*
- ** Notify the upper protocol layers that there is another
- ** packet to handle
- */
+ /* Push up the protocol stack */
skb->protocol=eth_type_trans(skb,dev);
netif_rx(skb);
- /*
- ** Update stats
- */
+ /* Update stats */
lp->stats.rx_packets++;
for (i=1; i<DE4X5_PKT_STAT_SZ-1; i++) {
if (pkt_len < (i*DE4X5_PKT_BIN_SZ)) {
}
buf = skb->data; /* Look at the dest addr */
if (buf[0] & 0x01) { /* Multicast/Broadcast */
- if ((*(long *)&buf[0] == -1) && (*(short *)&buf[4] == -1)) {
+ if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) {
lp->pktStats.broadcast++;
} else {
lp->pktStats.multicast++;
}
- } else if ((*(long *)&buf[0] == *(long *)&dev->dev_addr[0]) &&
- (*(short *)&buf[4] == *(short *)&dev->dev_addr[4])) {
+ } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) &&
+ (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
lp->pktStats.unicast++;
}
/* Change buffer ownership for this last frame, back to the adapter */
for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)%lp->rxRingSize) {
lp->rx_ring[lp->rx_old].status = R_OWN;
+ barrier();
}
lp->rx_ring[entry].status = R_OWN;
+ barrier();
}
/*
de4x5_tx(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int entry, iobase = dev->base_addr;
- long status;
+ u_long iobase = dev->base_addr;
+ int entry;
+ s32 status;
for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
status = lp->tx_ring[entry].status;
if (status & TD_EC) lp->pktStats.excessive_collisions++;
if (status & TD_DE) lp->stats.tx_aborted_errors++;
- if (status & (TD_LO | TD_NC | TD_EC | TD_LF)) {
+ if ((status != 0x7fffffff) && /* Not setup frame */
+ (status & (TD_LO | TD_NC | TD_EC | TD_LF))) {
lp->lostMedia++;
+ if (lp->lostMedia > LOST_MEDIA_THRESHOLD) { /* Trip autosense */
+ kick_tx(dev);
+ }
} else {
outl(POLL_DEMAND, DE4X5_TPD); /* Restart a stalled TX */
}
/* Free the buffer if it's not a setup frame. */
if (lp->skb[entry] != NULL) {
dev_kfree_skb(lp->skb[entry], FREE_WRITE);
+ lp->skb[entry] = NULL;
}
/* Update all the pointers */
return 0;
}
+static int
+de4x5_ast(struct device *dev)
+{
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ s32 gep;
+
+ disable_ast(dev);
+
+ if (lp->chipset == DC21140) {
+ gep = inl(DE4X5_GEP);
+ if (((lp->media == _100Mb) && (gep & GEP_SLNK)) ||
+ ((lp->media == _10Mb) && (gep & GEP_LNP)) ||
+ ((lp->media == _10Mb) && !(gep & GEP_SLNK)) ||
+ (lp->media == NC)) {
+ if (lp->linkProb || ((lp->media == NC) && (!(gep & GEP_LNP)))) {
+ lp->lostMedia = LOST_MEDIA_THRESHOLD + 1;
+ lp->linkProb = 0;
+ kick_tx(dev);
+ } else {
+ switch(lp->media) {
+ case NC:
+ lp->linkProb = 0;
+ enable_ast(dev, DE4X5_AUTOSENSE_MS);
+ break;
+
+ case _10Mb:
+ lp->linkProb = 1; /* Flag a potential problem */
+ enable_ast(dev, 1500);
+ break;
+
+ case _100Mb:
+ lp->linkProb = 1; /* Flag a potential problem */
+ enable_ast(dev, 4000);
+ break;
+ }
+ }
+ } else {
+ lp->linkProb = 0; /* Link OK */
+ enable_ast(dev, DE4X5_AUTOSENSE_MS);
+ }
+ }
+
+ return 0;
+}
+
static int
de4x5_close(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
- u_long imr, omr;
+ u_long iobase = dev->base_addr;
+ s32 imr, omr;
dev->start = 0;
dev->tbusy = 1;
de4x5_get_stats(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
+ u_long iobase = dev->base_addr;
lp->stats.rx_missed_errors = (int) (inl(DE4X5_MFC) & (MFC_OVFL | MFC_CNTR));
return &lp->stats;
}
-static void load_packet(struct device *dev, char *buf, u_long flags, struct sk_buff *skb)
+static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- lp->tx_ring[lp->tx_new].buf = buf;
+ lp->tx_ring[lp->tx_new].buf = virt_to_bus(buf);
lp->tx_ring[lp->tx_new].des1 &= TD_TER;
lp->tx_ring[lp->tx_new].des1 |= flags;
lp->skb[lp->tx_new] = skb;
+ barrier();
lp->tx_ring[lp->tx_new].status = T_OWN;
+ barrier();
return;
}
set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
+ u_long iobase = dev->base_addr;
/* First, double check that the adapter is open */
if (irq2dev_map[dev->irq] != NULL) {
static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int i, j, bit, byte, iobase = dev->base_addr;
- u_short hashcode;
- u_long crc, omr, poly = CRC_POLYNOMIAL_LE;
+ u_long iobase = dev->base_addr;
+ int i, j, bit, byte;
+ u16 hashcode;
+ u32 omr, crc, poly = CRC_POLYNOMIAL_LE;
char *pa;
omr = inl(DE4X5_OMR);
** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
** the motherboard. Upto 15 EISA devices are supported.
*/
-static void eisa_probe(struct device *dev, short ioaddr)
+static void eisa_probe(struct device *dev, u_long ioaddr)
{
- int i, maxSlots;
- int status;
- u_short vendor, device, iobase;
+ int i, maxSlots, status;
+ u_short vendor, device;
+ s32 cfid;
+ u_long iobase;
struct bus_type *lp = &bus;
char name[DE4X5_STRLEN];
- long cfid;
if (!ioaddr && autoprobed) return ; /* Been here before ! */
if ((ioaddr < 0x1000) && (ioaddr > 0)) return; /* PCI MODULE special */
/* Write the PCI Configuration Registers */
outl(PCI_COMMAND_IO | PCI_COMMAND_MASTER, PCI_CFCS);
outl(0x00004000, PCI_CFLT);
- outl((u_long)iobase, PCI_CBIO);
+ outl(iobase, PCI_CBIO);
if (check_region(iobase, DE4X5_EISA_TOTAL_SIZE) == 0) {
if ((dev = alloc_device(dev, iobase)) != NULL) {
if ((status = de4x5_hw_init(dev, iobase)) == 0) {
num_de4x5s++;
}
- num_eth++;
+ num_eth++;
}
} else if (autoprobed) {
- printk("%s: region already allocated at 0x%04x.\n", dev->name, iobase);
+ printk("%s: region already allocated at 0x%04lx.\n", dev->name, iobase);
}
}
}
/*
** PCI bus I/O device probe
+** NB: PCI I/O accesses and Bus Mastering are enabled by the PCI BIOS, not
+** the driver. Some PCI BIOS's, pre V2.1, need the slot + features to be
+** enabled by the user first in the set up utility. Hence we just check for
+** enabled features and silently ignore the card if they're not.
+**
+** STOP PRESS: Some BIOS's __require__ the driver to enable the bus mastering
+** bit. Here, check for I/O accesses and then set BM. If you put the card in
+** a non BM slot, you're on your own (and complain to the PC vendor that your
+** PC doesn't conform to the PCI standard)!
*/
#define PCI_DEVICE (dev_num << 3)
#define PCI_LAST_DEV 32
-static void pci_probe(struct device *dev, short ioaddr)
-
+static void pci_probe(struct device *dev, u_long ioaddr)
{
u_char irq;
- u_short pb, dev_num, dev_last;
- u_short vendor, device, status;
- u_long class, iobase;
+ u_char pb, pbus, dev_num, dnum, dev_fn;
+ u_short vendor, device, index, status;
+ u_int class = DE4X5_CLASS_CODE;
+ u_int iobase;
struct bus_type *lp = &bus;
if (!ioaddr && autoprobed) return ; /* Been here before ! */
lp->bus = PCI;
if (ioaddr < 0x1000) {
- pb = (u_short)(ioaddr >> 8);
- dev_num = (u_short)(ioaddr & 0xff);
+ pbus = (u_short)(ioaddr >> 8);
+ dnum = (u_short)(ioaddr & 0xff);
} else {
- pb = 0;
- dev_num = 0;
- }
- if (ioaddr > 0) {
- dev_last = (dev_num < PCI_LAST_DEV) ? dev_num + 1 : PCI_LAST_DEV;
- } else {
- dev_last = PCI_LAST_DEV;
+ pbus = 0;
+ dnum = 0;
}
+
+ for (index=0;
+ (pcibios_find_class(class, index, &pb, &dev_fn)!= PCIBIOS_DEVICE_NOT_FOUND);
+ index++) {
+ dev_num = PCI_SLOT(dev_fn);
- for (; (dev_num < dev_last) && (dev != NULL); dev_num++) {
- pcibios_read_config_dword(pb, PCI_DEVICE, PCI_CLASS_REVISION, &class);
- if (class != 0xffffffff) {
+ if ((!pbus && !dnum) || ((pbus == pb) && (dnum == dev_num))) {
pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor);
pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device);
if (is_DC21040 || is_DC21041 || is_DC21140) {
/* Set the device number information */
lp->device = dev_num;
+ lp->bus_num = pb;
/* Set the chipset information */
lp->chipset = device;
/* Get the board I/O address */
pcibios_read_config_dword(pb, PCI_DEVICE, PCI_BASE_ADDRESS_0, &iobase);
iobase &= CBIO_MASK;
-
+
/* Fetch the IRQ to be used */
pcibios_read_config_byte(pb, PCI_DEVICE, PCI_INTERRUPT_LINE, &irq);
- /* Enable I/O Accesses and Bus Mastering */
+ /* Check if I/O accesses and Bus Mastering are enabled */
pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
- status |= PCI_COMMAND_IO | PCI_COMMAND_MASTER;
- pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
-
- /* If there is a device and I/O region is open, initialise dev. */
- if ((DevicePresent(DE4X5_APROM) == 0) || is_not_dec) {
- if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
- if ((dev = alloc_device(dev, iobase)) != NULL) {
- dev->irq = irq;
- if ((status = de4x5_hw_init(dev, iobase)) == 0) {
- num_de4x5s++;
+ if (status & PCI_COMMAND_IO) {
+ if (!(status & PCI_COMMAND_MASTER)) {
+ status |= PCI_COMMAND_MASTER;
+ pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status);
+ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status);
+ }
+ if (status & PCI_COMMAND_MASTER) {
+ if ((DevicePresent(DE4X5_APROM) == 0) || is_not_dec) {
+ if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) {
+ if ((dev = alloc_device(dev, iobase)) != NULL) {
+ dev->irq = irq;
+ if ((status = de4x5_hw_init(dev, iobase)) == 0) {
+ num_de4x5s++;
+ }
+ num_eth++;
+ }
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04x.\n", dev->name, (u_short)iobase);
}
- num_eth++;
}
- } else if (autoprobed) {
- printk("%s: region already allocated at 0x%04x.\n", dev->name, (u_short)iobase);
}
}
}
** Allocate the device by pointing to the next available space in the
** device structure. Should one not be available, it is created.
*/
-static struct device *alloc_device(struct device *dev, int iobase)
+static struct device *alloc_device(struct device *dev, u_long iobase)
{
int addAutoProbe = 0;
struct device *tmp = NULL, *ret;
*/
if (!loading_module) {
while (dev->next != NULL) {
- if ((dev->base_addr == 0xffe0) || (dev->base_addr == 0)) break;
+ if ((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0)) break;
dev = dev->next; /* walk through eth device list */
num_eth++; /* increment eth device number */
}
** If memory could not be allocated, print an error message.
*/
if ((dev->next == NULL) &&
- !((dev->base_addr == 0xffe0) || (dev->base_addr == 0))){
+ !((dev->base_addr == DE4X5_NDA) || (dev->base_addr == 0))){
dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
GFP_KERNEL);
*/
if (ret != NULL) {
if (addAutoProbe) {
- for (; (tmp->next!=NULL) && (tmp->base_addr!=0xffe0); tmp=tmp->next);
+ for (; (tmp->next!=NULL) && (tmp->base_addr!=DE4X5_NDA); tmp=tmp->next);
/*
** If no more device structures and can't use the current one, malloc
** one up. If memory could not be allocated, print an error message.
*/
- if ((tmp->next == NULL) && !(tmp->base_addr == 0xffe0)) {
+ if ((tmp->next == NULL) && !(tmp->base_addr == DE4X5_NDA)) {
tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8,
GFP_KERNEL);
tmp = tmp->next; /* point to the new device */
static int autoconf_media(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
+ u_long iobase = dev->base_addr;
+
+ lp->tx_enable = YES;
+ if (de4x5_debug > 0 ) {
+ if (lp->chipset != DC21140) {
+ printk("%s: Searching for media... ",dev->name);
+ } else {
+ printk("%s: Searching for mode... ",dev->name);
+ }
+ }
if (lp->chipset == DC21040) {
lp->media = (lp->autosense == AUTO ? TP : lp->autosense);
lp->media = (lp->autosense == AUTO ? TP_NW : lp->autosense);
dc21041_autoconf(dev);
} else if (lp->chipset == DC21140) {
- /* Force 10Mb/s (_100Mb for 100Mb/s) */
+ disable_ast(dev);
lp->media = (lp->autosense == AUTO ? _10Mb : lp->autosense);
dc21140_autoconf(dev);
}
- if (de4x5_debug >= 1 ) {
+ if (de4x5_debug > 0 ) {
if (lp->chipset != DC21140) {
- printk("%s: Media is %s\n",dev->name,
- (lp->media == NC ? "unconnected!" :
- (lp->media == TP ? "TP." :
- (lp->media == ANS ? "TP/Nway." :
- (lp->media == BNC ? "BNC." :
- (lp->media == AUI ? "AUI." :
- "BNC/AUI."
- ))))));
+ printk("media is %s\n", (lp->media == NC ? "unconnected!" :
+ (lp->media == TP ? "TP." :
+ (lp->media == ANS ? "TP/Nway." :
+ (lp->media == BNC ? "BNC." :
+ (lp->media == AUI ? "AUI." :
+ "BNC/AUI."
+ ))))));
} else {
- printk("%s: Mode is forced to %s\n",dev->name,
- (lp->media == NC ? "link down.":
- (lp->media == _100Mb ? "100Mb/s." :
- (lp->media == _10Mb ? "10Mb/s." :
- "\?\?\?"
- ))));
+ printk("mode is %s\n",(lp->media == NC ? "link down.":
+ (lp->media == _100Mb ? "100Mb/s." :
+ (lp->media == _10Mb ? "10Mb/s." :
+ "\?\?\?"
+ ))));
}
}
if (lp->media) {
lp->lostMedia = 0;
inl(DE4X5_MFC); /* Zero the lost frames counter */
+ if ((lp->media == TP) || (lp->media == ANS)) {
+ lp->irq_mask |= IMR_LFM;
+ }
}
dce_ms_delay(10);
static void dc21040_autoconf(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
- u_long i, sisr = 0, linkBad;
- u_long t_3s = 3000;
+ u_long iobase = dev->base_addr;
+ int i, linkBad;
+ s32 sisr = 0, t_3s = 3000;
switch (lp->media) {
case TP:
case AUI:
case BNC_AUI:
reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
- dce_ms_delay(330);
+ dce_ms_delay(500);
linkBad = ping_media(dev);
if (linkBad && (lp->autosense == AUTO)) {
lp->media = NC;
break;
case NC:
+#ifdef i386
reset_init_sia(dev, 0x8f01, 0xffff, 0x0000);
break;
+#else
+ /* JAE: for Alpha, default to BNC/AUI, *not* TP */
+ reset_init_sia(dev, 0x8f09, 0x0705, 0x0006);
+#endif /* i386 */
}
return;
static void dc21041_autoconf(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
- u_long sts, irqs, irq_mask, omr;
+ u_long iobase = dev->base_addr;
+ s32 sts, irqs, irq_mask, omr;
switch (lp->media) {
case TP_NW:
static void dc21140_autoconf(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
- u_long omr;
+ u_long iobase = dev->base_addr;
+ s32 omr;
switch(lp->media) {
case _100Mb: /* Set 100Mb/s, MII Port with PCS Function and Scrambler */
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
+ omr |= (de4x5_full_duplex ? OMR_FD : 0); /* Set up Full Duplex */
outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);
outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);
break;
case _10Mb: /* Set conventional 10Mb/s ENDEC interface */
omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));
+ omr |= (de4x5_full_duplex ? OMR_FD : 0); /* Set up Full Duplex */
outl(omr | OMR_TTM, DE4X5_OMR);
outl(GEP_FDXD, DE4X5_GEP);
break;
return;
}
-static long test_media(struct device *dev, long irqs, long irq_mask, long csr13, long csr14, long csr15, long msec)
+static int
+test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
- long sts, time, csr12;
+ u_long iobase = dev->base_addr;
+ s32 sts, time, csr12;
reset_init_sia(dev, csr13, csr14, csr15);
return sts;
}
+/*
+static int test_sym_link(struct device *dev, u32 msec)
+{
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+ u32 gep, time;
+
+ / * Set link_fail_inhibit_timer * /
+ load_ms_timer(dev, msec);
+ / * Poll for timeout or SYM_LINK=0 * /
+ do {
+ time = inl(DE4X5_GPT) & GPT_VAL;
+ gep = inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP);
+ } while ((time > 0) && (gep & GEP_SLNK));
+
+ return gep;
+}
+*/
/*
** Send a packet onto the media and watch for send errors that indicate the
** media is bad or unconnected.
*/
-static long ping_media(struct device *dev)
+static int ping_media(struct device *dev)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int entry, iobase = dev->base_addr;
+ u_long iobase = dev->base_addr;
+ int i, entry, linkBad;
+ s32 omr, t_3s = 4000;
char frame[64];
- long i, linkBad, omr;
- u_long t_3s = 3000;
create_packet(dev, frame, sizeof(frame));
** Check the Auto Negotiation State. Return OK when a link pass interrupt
** is received and the auto-negotiation status is NWAY OK.
*/
-static int test_ans(struct device *dev, long irqs, long irq_mask, long msec)
+static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
- long sts, ans;
+ u_long iobase = dev->base_addr;
+ s32 sts, ans;
outl(irq_mask, DE4X5_IMR);
/*
**
*/
-static void reset_init_sia(struct device *dev, long sicr, long strr, long sigr)
+static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
+ u_long iobase = dev->base_addr;
RESET_SIA;
outl(sigr, DE4X5_SIGR);
/*
** Load the timer on the DC21041 and 21140. Max time is 13.42 secs.
*/
-static void load_ms_timer(struct device *dev, u_long msec)
+static void load_ms_timer(struct device *dev, u32 msec)
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
- int iobase = dev->base_addr;
+ u_long iobase = dev->base_addr;
+ s32 i = 2048, j;
- outl((long)(msec * 10000)/2048, DE4X5_GPT);
+ if (lp->chipset == DC21140) {
+ j = inl(DE4X5_OMR);
+ if ((j & OMR_TTM) && (j & OMR_PS)) { /* 10Mb/s MII */
+ i = 8192;
+ } else if ((~j & OMR_TTM) && (j & OMR_PS)) { /* 100Mb/s MII */
+ i = 819;
+ }
+ }
+
+ outl((s32)(msec * 10000)/i, DE4X5_GPT);
return;
}
/*
** Known delay in microseconds
*/
-static void dce_us_delay(u_long usec)
+static void dce_us_delay(u32 usec)
{
udelay(usec);
/*
** Known delay in milliseconds, in millisecond steps.
*/
-static void dce_ms_delay(u_long msec)
+static void dce_ms_delay(u32 msec)
{
- u_long i;
+ u_int i;
for (i=0; i<msec; i++) {
dce_us_delay(1000);
/*
** Look for a particular board name in the EISA configuration space
*/
-int EISA_signature(char *name, long eisa_id)
+static int EISA_signature(char *name, s32 eisa_id)
{
- unsigned long i;
+ u_int i;
char *signatures[] = DE4X5_SIGNATURE;
char ManCode[DE4X5_STRLEN];
union {
- long ID;
+ s32 ID;
char Id[4];
} Eisa;
int status = 0;
** ethernet address for later read out.
*/
-static int DevicePresent(short aprom_addr)
+static int DevicePresent(u_long aprom_addr)
{
union {
struct {
- u_long a;
- u_long b;
+ u32 a;
+ u32 b;
} llsig;
- char Sig[sizeof(long) << 1];
+ char Sig[sizeof(u32) << 1];
} dev;
char data;
- long i, j, tmp;
+ int i, j, tmp, status = 0;
short sigLength;
- int status = 0;
struct bus_type *lp = &bus;
dev.llsig.a = ETH_PROM_SIG;
dev.llsig.b = ETH_PROM_SIG;
- sigLength = sizeof(long) << 1;
+ sigLength = sizeof(u32) << 1;
if (lp->chipset == DC21040) {
for (i=0,j=0;(j<sigLength) && (i<PROBE_LENGTH+sigLength-1);i++) {
return status;
}
-static int aprom_crc(struct device *dev)
+static int get_hw_addr(struct device *dev)
{
- int iobase = dev->base_addr;
- long i, k, tmp;
- unsigned short j,chksum;
- unsigned char status = 0;
+ u_long iobase = dev->base_addr;
+ int i, k, tmp, status = 0;
+ u_short j,chksum;
struct bus_type *lp = &bus;
for (i=0,k=0,j=0;j<3;j++) {
/*
** SROM Read
*/
-static short srom_rd(u_short addr, u_char offset)
+static short srom_rd(u_long addr, u_char offset)
{
sendto_srom(SROM_RD | SROM_SR, addr);
return srom_data(SROM_RD | SROM_SR | DT_CS, addr);
}
-static void srom_latch(u_long command, u_short addr)
+static void srom_latch(u_int command, u_long addr)
{
sendto_srom(command, addr);
sendto_srom(command | DT_CLK, addr);
return;
}
-static void srom_command(u_long command, u_short addr)
+static void srom_command(u_int command, u_long addr)
{
srom_latch(command, addr);
srom_latch(command, addr);
return;
}
-static void srom_address(u_long command, u_short addr, u_char offset)
+static void srom_address(u_int command, u_long addr, u_char offset)
{
- long i;
+ int i;
char a;
a = (char)(offset << 2);
i = (getfrom_srom(addr) >> 3) & 0x01;
if (i != 0) {
printk("Bad SROM address phase.....\n");
+/* printk(".");*/
}
return;
}
-static short srom_data(u_long command, u_short addr)
+static short srom_data(u_int command, u_long addr)
{
int i;
short word = 0;
- long tmp;
+ s32 tmp;
for (i=0; i<16; i++) {
sendto_srom(command | DT_CLK, addr);
}
/*
-static void srom_busy(u_long command, u_short addr)
+static void srom_busy(u_int command, u_long addr)
{
sendto_srom((command & 0x0000ff00) | DT_CS, addr);
}
*/
-static void sendto_srom(u_long command, u_short addr)
+static void sendto_srom(u_int command, u_long addr)
{
outl(command, addr);
dce_us_delay(1);
return;
}
-static long getfrom_srom(u_short addr)
+static int getfrom_srom(u_long addr)
{
- long tmp;
+ s32 tmp;
tmp = inl(addr);
dce_us_delay(1);
return pa; /* Points to the next entry */
}
+static void enable_ast(struct device *dev, u32 time_out)
+{
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ lp->irq_mask |= IMR_TMM;
+ outl(lp->irq_mask, DE4X5_IMR);
+ load_ms_timer(dev, time_out);
+
+ return;
+}
+
+static void disable_ast(struct device *dev)
+{
+ struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
+ u_long iobase = dev->base_addr;
+
+ lp->irq_mask &= ~IMR_TMM;
+ outl(lp->irq_mask, DE4X5_IMR);
+ load_ms_timer(dev, 0);
+
+ return;
+}
+
+static void kick_tx(struct device *dev)
+{
+ struct sk_buff *skb;
+
+ if ((skb = alloc_skb(0, GFP_ATOMIC)) != NULL) {
+ skb->len= FAKE_FRAME_LEN;
+ skb->arp=1;
+ skb->dev=dev;
+ dev_queue_xmit(skb, dev, SOPRI_NORMAL);
+ }
+
+ return;
+}
+
/*
** Perform IOCTL call functions here. Some are privileged operations and the
** effective uid is checked in those cases.
{
struct de4x5_private *lp = (struct de4x5_private *)dev->priv;
struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data;
- int i, j, iobase = dev->base_addr, status = 0;
- u_long omr;
+ u_long iobase = dev->base_addr;
+ int i, j, status = 0;
+ s32 omr;
union {
- unsigned char addr[(HASH_TABLE_LEN * ETH_ALEN)];
- unsigned short sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
- unsigned long lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
+ u8 addr[(HASH_TABLE_LEN * ETH_ALEN)];
+ u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
+ u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
} tmp;
switch(ioc->cmd) {
tmp.addr[i] = dev->dev_addr[i];
}
ioc->len = ETH_ALEN;
- memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+ if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+ }
break;
case DE4X5_SET_HWADDR: /* Set the hardware address */
if (suser()) {
- memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
- for (i=0; i<ETH_ALEN; i++) {
- dev->dev_addr[i] = tmp.addr[i];
- }
- build_setup_frame(dev, PHYS_ADDR_ONLY);
- /* Set up the descriptor and give ownership to the card */
- while (set_bit(0, (void *)&dev->tbusy) != 0); /* Wait for lock to free */
- if (lp->setup_f == HASH_PERF) {
- load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET |
+ if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) {
+ memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN);
+ for (i=0; i<ETH_ALEN; i++) {
+ dev->dev_addr[i] = tmp.addr[i];
+ }
+ build_setup_frame(dev, PHYS_ADDR_ONLY);
+ /* Set up the descriptor and give ownership to the card */
+ while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/
+ if (lp->setup_f == HASH_PERF) {
+ load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET |
SETUP_FRAME_LEN, NULL);
- } else {
- load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
+ } else {
+ load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET |
SETUP_FRAME_LEN, NULL);
+ }
+ lp->tx_new = (++lp->tx_new) % lp->txRingSize;
+ outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
+ dev->tbusy = 0; /* Unlock the TX ring */
}
- lp->tx_new = (++lp->tx_new) % lp->txRingSize;
- outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */
- dev->tbusy = 0; /* Unlock the TX ring */
-
} else {
status = -EPERM;
}
break;
case DE4X5_GET_MCA: /* Get the multicast address table */
ioc->len = (HASH_TABLE_LEN >> 3);
- memcpy_tofs(ioc->data, lp->setup_frame, 192);
+ if (!(status = verify_area(VERIFY_WRITE, ioc->data, 192))) {
+ memcpy_tofs(ioc->data, lp->setup_frame, 192);
+ }
break;
case DE4X5_SET_MCA: /* Set a multicast address */
if (suser()) {
if (ioc->len != HASH_TABLE_LEN) { /* MCA changes */
- memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+ if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN * ioc->len))) {
+ memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+ set_multicast_list(dev, ioc->len, tmp.addr);
+ }
+ } else {
+ set_multicast_list(dev, ioc->len, NULL);
}
- set_multicast_list(dev, ioc->len, tmp.addr);
} else {
status = -EPERM;
}
break;
case DE4X5_GET_STATS: /* Get the driver statistics */
cli();
- memcpy_tofs(ioc->data, &lp->pktStats, sizeof(lp->pktStats));
- ioc->len = DE4X5_PKT_STAT_SZ;
+ ioc->len = sizeof(lp->pktStats);
+ if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, sizeof(lp->pktStats)))) {
+ memcpy_tofs(ioc->data, &lp->pktStats, ioc->len);
+ }
sti();
break;
break;
case DE4X5_GET_OMR: /* Get the OMR Register contents */
tmp.addr[0] = inl(DE4X5_OMR);
- memcpy_tofs(ioc->data, tmp.addr, 1);
+ if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, 1))) {
+ memcpy_tofs(ioc->data, tmp.addr, 1);
+ }
break;
case DE4X5_SET_OMR: /* Set the OMR Register contents */
if (suser()) {
- memcpy_fromfs(tmp.addr, ioc->data, 1);
- outl(tmp.addr[0], DE4X5_OMR);
+ if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, 1))) {
+ memcpy_fromfs(tmp.addr, ioc->data, 1);
+ outl(tmp.addr[0], DE4X5_OMR);
+ }
} else {
status = -EPERM;
}
break;
case DE4X5_GET_REG: /* Get the DE4X5 Registers */
- tmp.lval[0] = inl(DE4X5_STS);
- tmp.lval[1] = inl(DE4X5_BMR);
- tmp.lval[2] = inl(DE4X5_IMR);
- tmp.lval[3] = inl(DE4X5_OMR);
- tmp.lval[4] = inl(DE4X5_SISR);
- tmp.lval[5] = inl(DE4X5_SICR);
- tmp.lval[6] = inl(DE4X5_STRR);
- tmp.lval[7] = inl(DE4X5_SIGR);
- memcpy_tofs(ioc->data, tmp.addr, 32);
-
+ j = 0;
+ tmp.lval[0] = inl(DE4X5_STS); j+=4;
+ tmp.lval[1] = inl(DE4X5_BMR); j+=4;
+ tmp.lval[2] = inl(DE4X5_IMR); j+=4;
+ tmp.lval[3] = inl(DE4X5_OMR); j+=4;
+ tmp.lval[4] = inl(DE4X5_SISR); j+=4;
+ tmp.lval[5] = inl(DE4X5_SICR); j+=4;
+ tmp.lval[6] = inl(DE4X5_STRR); j+=4;
+ tmp.lval[7] = inl(DE4X5_SIGR); j+=4;
+ ioc->len = j;
+ if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+ }
break;
#define DE4X5_DUMP 0x0f /* Dump the DE4X5 Status */
tmp.addr[j++] = dev->dev_addr[i];
}
tmp.addr[j++] = lp->rxRingSize;
- tmp.lval[j>>2] = (long)lp->rx_ring; j+=4;
- tmp.lval[j>>2] = (long)lp->tx_ring; j+=4;
+ tmp.lval[j>>2] = (s32)lp->rx_ring; j+=4;
+ tmp.lval[j>>2] = (s32)lp->tx_ring; j+=4;
for (i=0;i<lp->rxRingSize-1;i++){
if (i < 3) {
- tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
+ tmp.lval[j>>2] = (s32)&lp->rx_ring[i].status; j+=4;
}
}
- tmp.lval[j>>2] = (long)&lp->rx_ring[i].status; j+=4;
+ tmp.lval[j>>2] = (s32)&lp->rx_ring[i].status; j+=4;
for (i=0;i<lp->txRingSize-1;i++){
if (i < 3) {
- tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
+ tmp.lval[j>>2] = (s32)&lp->tx_ring[i].status; j+=4;
}
}
- tmp.lval[j>>2] = (long)&lp->tx_ring[i].status; j+=4;
-
+ tmp.lval[j>>2] = (s32)&lp->tx_ring[i].status; j+=4;
+
for (i=0;i<lp->rxRingSize-1;i++){
if (i < 3) {
- tmp.lval[j>>2] = (long)lp->rx_ring[i].buf; j+=4;
+ tmp.lval[j>>2] = (s32)lp->rx_ring[i].buf; j+=4;
}
}
- tmp.lval[j>>2] = (long)lp->rx_ring[i].buf; j+=4;
+ tmp.lval[j>>2] = (s32)lp->rx_ring[i].buf; j+=4;
for (i=0;i<lp->txRingSize-1;i++){
if (i < 3) {
- tmp.lval[j>>2] = (long)lp->tx_ring[i].buf; j+=4;
+ tmp.lval[j>>2] = (s32)lp->tx_ring[i].buf; j+=4;
}
}
- tmp.lval[j>>2] = (long)lp->tx_ring[i].buf; j+=4;
-
+ tmp.lval[j>>2] = (s32)lp->tx_ring[i].buf; j+=4;
+
for (i=0;i<lp->rxRingSize;i++){
tmp.lval[j>>2] = lp->rx_ring[i].status; j+=4;
}
tmp.lval[j>>2] = inl(DE4X5_SICR); j+=4;
tmp.lval[j>>2] = inl(DE4X5_STRR); j+=4;
tmp.lval[j>>2] = inl(DE4X5_SIGR); j+=4;
-
+
tmp.addr[j++] = lp->txRingSize;
tmp.addr[j++] = dev->tbusy;
-
+
ioc->len = j;
- memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+ if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+ }
break;
default:
0x2000, 10, /* I/O address, IRQ */
0, 0, 0, NULL, de4x5_probe };
-int io=0x000b; /* <--- EDIT THESE LINES FOR YOUR CONFIGURATION */
-int irq=10; /* or use the insmod io= irq= options */
+static int io=0x000b; /* EDIT THESE LINES FOR YOUR CONFIGURATION */
+static int irq=10; /* or use the insmod io= irq= options */
int
init_module(void)
if (MOD_IN_USE) {
printk("%s: device busy, remove delayed\n",thisDE4X5.name);
} else {
- release_region(thisDE4X5.base_addr, (lp->bus == PCI ?
- DE4X5_PCI_TOTAL_SIZE :
- DE4X5_EISA_TOTAL_SIZE));
if (lp) {
- kfree_s(lp->rx_ring[0].buf, RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
+ kfree_s(bus_to_virt(lp->rx_ring[0].buf), RX_BUFF_SZ * NUM_RX_DESC + ALIGN);
}
kfree_s(thisDE4X5.priv, sizeof(struct de4x5_private) + ALIGN);
thisDE4X5.priv = NULL;
+ release_region(thisDE4X5.base_addr, (lp->bus == PCI ?
+ DE4X5_PCI_TOTAL_SIZE :
+ DE4X5_EISA_TOTAL_SIZE));
unregister_netdev(&thisDE4X5);
}
}
/*
** PCI Configuration Base I/O Address Register (PCI_CBIO)
*/
-#define CBIO_MASK 0x0000ff80 /* Base I/O Address Mask */
+#define CBIO_MASK 0xffffff80 /* Base I/O Address Mask */
#define CBIO_IOSI 0x00000001 /* I/O Space Indicator (RO, value is 1) */
/*
#define DE4X5_GET_OMR 0x0c /* Get the OMR Register contents */
#define DE4X5_SET_OMR 0x0d /* Set the OMR Register contents */
#define DE4X5_GET_REG 0x0e /* Get the DE4X5 Registers */
-
-
-
/* depca.c: A DIGITAL DEPCA & EtherWORKS ethernet driver for linux.
- Written 1994 by David C. Davies.
+ Written 1994, 1995 by David C. Davies.
Copyright 1994 David C. Davies
United States Government
(as represented by the Director, National Security Agency).
+ Copyright 1995 Digital Equipment Corporation.
+
This software may be used and distributed according to the terms of
the GNU Public License, incorporated herein by reference.
This driver will NOT work for the DE203, DE204 and DE205 series of
cards, since they have a new custom ASIC in place of the AMD LANCE
- chip.
+ chip. See the 'ewrk3.c' driver in the Linux source tree for running
+ those cards.
+
+ I have benchmarked the driver with a DE100 at 595kB/s to (542kB/s from)
+ a DECstation 5000/200.
The author may be reached as davies@wanton.lkg.dec.com or
Digital Equipment Corporation, 550 King Street, Littleton MA 01460.
=========================================================================
- The driver was based on the 'lance.c' driver from Donald Becker which is
- included with the standard driver distribution for linux. Modifications
- were made to most routines and the hardware recognition routines were
- written from scratch. Primary references used were:
+
+ The driver was originally based on the 'lance.c' driver from Donald
+ Becker which is included with the standard driver distribution for
+ linux. V0.4 is a complete re-write with only the kernel interface
+ remaining from the original code.
1) Lance.c code in /linux/drivers/net/
2) "Ethernet/IEEE 802.3 Family. 1992 World Network Data Book/Handbook",
8) "DEC EtherWORKS Turbo_(TP BNC) Ethernet Controller Owners Manual",
Digital Equipment corporation, 1991, Pub. #EK-DE202-OM.001
- Peter Bauer's depca.c (V0.5) was referred to when debugging this driver.
- The hash filter code was derived from Reference 3 and has been tested
- only to the extent that the Table A-1, page A-7, was confirmed to fill
- the filter bit positions correctly. Hash filtering is not yet
- implemented in the current driver set.
+
+ Peter Bauer's depca.c (V0.5) was referred to when debugging V0.1 of this
+ driver.
The original DEPCA card requires that the ethernet ROM address counter
be enabled to count and has an 8 bit NICSR. The ROM counter enabling is
The ability to load this driver as a loadable module has been added. To
utilise this ability, you have to do <8 things:
+ 0) have a copy of the loadable modules code installed on your system.
1) copy depca.c from the /linux/drivers/net directory to your favourite
temporary directory.
- 2) edit the source code near line 1530 to reflect the I/O address and
- IRQ you're using.
+ 2) if you wish, edit the source code near line 1530 to reflect the I/O
+ address and IRQ you're using (see also 5).
3) compile depca.c, but include -DMODULE in the command line to ensure
that the correct bits are compiled (see end of source code).
4) if you are wanting to add a new card, goto 5. Otherwise, recompile a
kernel with the depca configuration turned off and reboot.
- 5) insmod depca.o
+ 5) insmod depca.o [irq=7] [io=0x200]
+ [Alan Cox: Changed the code to allow command line irq/io assignments]
6) run the net startup bits for your eth?? interface manually
(usually /etc/rc.inet[12] at boot time).
7) enjoy!
Note that autoprobing is not allowed in loadable modules - the system is
- already up and running and you're messing with interrupts. Also, there
- is no way to check on the number of depcas installed at the moment.
+ already up and running and you're messing with interrupts.
To unload a module, turn off the associated interface
'ifconfig eth?? down' then 'rmmod depca'.
- [Alan Cox: Changed to split off the module values as ints for insmod
-
- you can now do insmod depca.c irq=7 io=0x200 ]
-
TO DO:
------
- 1. Implement the 2k buffer mode - does anyone need it??
Revision History
----------------
0.382 9-feb-95 Fix recognition bug reported by <bkm@star.rl.ac.uk>.
0.383 22-feb-95 Fix for conflict with VESA SCSI reported by
<stromain@alf.dec.com>
+ 0.384 17-mar-95 Fix a ring full bug reported by <bkm@star.rl.ac.uk>
+ 0.385 3-apr-95 Fix a recognition bug reported by
+ <ryan.niemi@lastfrontier.com>
+ 0.386 21-apr-95 Fix the last fix...sorry, must be galloping senility
+ 0.40 25-May-95 Rewrite for portability & updated.
+ ALPHA support from <jestabro@amt.tay1.dec.com>
+ 0.41 26-Jun-95 Added verify_area() calls in depca_ioctl() from
+ suggestion by <heiko@colossus.escape.de>
=========================================================================
*/
-static char *version = "depca.c:v0.383 2/22/94 davies@wanton.lkg.dec.com\n";
+static char *version = "depca.c:v0.41 5/26/95 davies@wanton.lkg.dec.com\n";
#include <linux/config.h>
#ifdef MODULE
#define MOD_DEC_USE_COUNT
#endif /* MODULE */
+#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/malloc.h>
#include <linux/interrupt.h>
+#include <asm/segment.h>
#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
static int depca_debug = 1;
#endif
-#ifndef PROBE_LENGTH
-#define PROBE_LENGTH 32
-#endif
+#define DEPCA_NDA 0xffe0 /* No Device Address */
+/*
+** Ethernet PROM defines
+*/
+#define PROBE_LENGTH 32
#define ETH_PROM_SIG 0xAA5500FFUL
-#ifndef DEPCA_SIGNATURE
+/*
+** Set the number of Tx and Rx buffers. Ensure that the memory requested
+** here is <= to the amount of shared memory set up by the board switches.
+** The number of descriptors MUST BE A POWER OF 2.
+**
+** total_memory = NUM_RX_DESC*(8+RX_BUFF_SZ) + NUM_TX_DESC*(8+TX_BUFF_SZ)
+*/
+#define NUM_RX_DESC 8 /* Number of RX descriptors */
+#define NUM_TX_DESC 8 /* Number of TX descriptors */
+#define RX_BUFF_SZ 1536 /* Buffer size for each Rx buffer */
+#define TX_BUFF_SZ 1536 /* Buffer size for each Tx buffer */
+
+#define CRC_POLYNOMIAL_BE 0x04c11db7UL /* Ethernet CRC, big endian */
+#define CRC_POLYNOMIAL_LE 0xedb88320UL /* Ethernet CRC, little endian */
+
+/*
+** EISA bus defines
+*/
+#define DEPCA_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
+#define MAX_EISA_SLOTS 16
+#define EISA_SLOT_INC 0x1000
+
+/*
+** ISA Bus defines
+*/
+#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
+#define DEPCA_IO_PORTS {0x300, 0x200, 0}
+#define DEPCA_TOTAL_SIZE 0x10
+static short mem_chkd = 0;
+
+/*
+** Name <-> Adapter mapping
+*/
#define DEPCA_SIGNATURE {"DEPCA",\
"DE100","DE101",\
"DE200","DE201","DE202",\
"DE210",\
"DE422",\
""}
-#define DEPCA_NAME_LENGTH 8
-#endif
-
-#ifndef DEPCA_RAM_BASE_ADDRESSES
-#define DEPCA_RAM_BASE_ADDRESSES {0xc0000,0xd0000,0xe0000,0x00000}
-#endif
-static short mem_chkd = 0; /* holds which base addrs have been */
- /* checked, for multi-DEPCA case */
+static enum {DEPCA, de100, de101, de200, de201, de202, de210, de422, unknown} adapter;
-#ifndef DEPCA_IO_PORTS
-#define DEPCA_IO_PORTS {0x300, 0x200, 0}
-#endif
-
-#ifndef DEPCA_TOTAL_SIZE
-#define DEPCA_TOTAL_SIZE 0x10
-#endif
-
-#ifndef MAX_NUM_DEPCAS
+/*
+** Miscellaneous info...
+*/
+#define DEPCA_STRLEN 16
#define MAX_NUM_DEPCAS 2
-#endif
-
-#ifndef DEPCA_EISA_IO_PORTS
-#define DEPCA_EISA_IO_PORTS 0x0c00 /* I/O port base address, slot 0 */
-#endif
-
-#ifndef MAX_EISA_SLOTS
-#define MAX_EISA_SLOTS 8
-#endif
/*
-** Set the number of Tx and Rx buffers.
+** Memory Alignment. Each descriptor is 4 longwords long. To force a
+** particular alignment on the TX descriptor, adjust DESC_SKIP_LEN and
+** DESC_ALIGN. ALIGN aligns the start address of the private memory area
+** and hence the RX descriptor ring's first entry.
*/
-#ifndef DEPCA_BUFFER_LOG_SZ
-#define RING_SIZE 16 /* 16 buffers */
-#else
-#define RING_SIZE (1 << (DEPCA_BUFFERS_LOG_SZ))
-#endif /* DEPCA_BUFFER_LOG_SZ */
-
-#define PKT_BUF_SZ 1544 /* Buffer size for each Tx/Rx buffer */
-#define PKT_SZ 1514 /* Maximum ethernet packet length */
-#define DAT_SZ 1500 /* Maximum ethernet data length */
-#define PKT_HDR_LEN 14 /* Addresses and data length info */
-
-#ifdef HAVE_MULTICAST
-#ifndef CRC_POLYNOMIAL
-#define CRC_POLYNOMIAL 0x04c11db7 /* Ethernet CRC polynomial */
-#endif /* CRC_POLYNOMIAL */
-#endif /* HAVE_MULTICAST */
+#define ALIGN4 ((u_long)4 - 1) /* 1 longword align */
+#define ALIGN8 ((u_long)8 - 1) /* 2 longword (quadword) align */
+#define ALIGN ALIGN8 /* Keep the LANCE happy... */
/*
** The DEPCA Rx and Tx ring descriptors.
*/
-struct depca_rx_head {
- volatile long base;
- short buf_length; /* This length is negative 2's complement! */
- short msg_length; /* This length is "normal". */
+struct depca_rx_desc {
+ volatile s32 base;
+ s16 buf_length; /* This length is negative 2's complement! */
+ s16 msg_length; /* This length is "normal". */
};
-struct depca_tx_head {
- volatile long base;
- short length; /* This length is negative 2's complement! */
- short misc; /* Errors and TDR info */
+struct depca_tx_desc {
+ volatile s32 base;
+ s16 length; /* This length is negative 2's complement! */
+ s16 misc; /* Errors and TDR info */
};
#define LA_MASK 0x0000ffff /* LANCE address mask for mapping network RAM
** The Lance initialization block, described in databook, in common memory.
*/
struct depca_init {
- unsigned short mode; /* Mode register */
- unsigned char phys_addr[ETH_ALEN]; /* Physical ethernet address */
- unsigned short filter[4]; /* Multicast filter. */
- unsigned long rx_ring; /* Rx ring base pointer & ring length */
- unsigned long tx_ring; /* Tx ring base pointer & ring length */
+ u16 mode; /* Mode register */
+ u8 phys_addr[ETH_ALEN]; /* Physical ethernet address */
+ u8 mcast_table[8]; /* Multicast Hash Table. */
+ u32 rx_ring; /* Rx ring base pointer & ring length */
+ u32 tx_ring; /* Tx ring base pointer & ring length */
};
+#define DEPCA_PKT_STAT_SZ 16
+#define DEPCA_PKT_BIN_SZ 128 /* Should be >=100 unless you
+ increase DEPCA_PKT_STAT_SZ */
struct depca_private {
- char devname[8]; /* Device Product String */
- struct depca_rx_head *rx_ring; /* Pointer to start of RX descriptor ring */
- struct depca_tx_head *tx_ring; /* Pointer to start of TX descriptor ring */
- struct depca_init init_block;/* Initialization block */
- long bus_offset; /* (E)ISA bus address offset vs LANCE */
- long dma_buffs; /* Start address of Rx and Tx buffers. */
- int cur_rx, cur_tx; /* The next free ring entry */
- int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
- int dma;
+ char devname[DEPCA_STRLEN]; /* Device Product String */
+ char adapter_name[DEPCA_STRLEN];/* /proc/ioports string */
+ char adapter; /* Adapter type */
+ struct depca_rx_desc *rx_ring; /* Pointer to start of RX descriptor ring */
+ struct depca_tx_desc *tx_ring; /* Pointer to start of TX descriptor ring */
+ struct depca_init init_block;/* Shadow Initialization block */
+ char *rx_memcpy[NUM_RX_DESC]; /* CPU virt address of sh'd memory buffs */
+ char *tx_memcpy[NUM_TX_DESC]; /* CPU virt address of sh'd memory buffs */
+ u_long bus_offset; /* (E)ISA bus address offset vs LANCE */
+ u_long sh_mem; /* Physical start addr of shared mem area */
+ u_long dma_buffs; /* LANCE Rx and Tx buffers start address. */
+ int rx_new, tx_new; /* The next free ring entry */
+ int rx_old, tx_old; /* The ring entries to be free()ed. */
struct enet_statistics stats;
- char depca_na; /* NICSR access width: 0=>byte, 1=>word */
- short ringSize; /* ring size based on available memory */
- short rmask; /* modulus mask based on ring size */
- long rlen; /* log2(ringSize) for the descriptors */
+ struct { /* Private stats counters */
+ u32 bins[DEPCA_PKT_STAT_SZ];
+ u32 unicast;
+ u32 multicast;
+ u32 broadcast;
+ u32 excessive_collisions;
+ u32 tx_underruns;
+ u32 excessive_underruns;
+ } pktStats;
+ int txRingMask; /* TX ring mask */
+ int rxRingMask; /* RX ring mask */
+ s32 rx_rlen; /* log2(rxRingMask+1) for the descriptors */
+ s32 tx_rlen; /* log2(txRingMask+1) for the descriptors */
};
+/*
+** The transmit ring full condition is described by the tx_old and tx_new
+** pointers by:
+** tx_old = tx_new Empty ring
+** tx_old = tx_new+1 Full ring
+** tx_old+txRingMask = tx_new Full ring (wrapped condition)
+*/
+#define TX_BUFFS_AVAIL ((lp->tx_old<=lp->tx_new)?\
+ lp->tx_old+lp->txRingMask-lp->tx_new:\
+ lp->tx_old -lp->tx_new-1)
+
/*
** Public Functions
*/
-static int depca_open(struct device *dev);
-static int depca_start_xmit(struct sk_buff *skb, struct device *dev);
-static void depca_interrupt(int irq, struct pt_regs * regs);
-static int depca_close(struct device *dev);
+static int depca_open(struct device *dev);
+static int depca_start_xmit(struct sk_buff *skb, struct device *dev);
+static void depca_interrupt(int irq, struct pt_regs * regs);
+static int depca_close(struct device *dev);
+static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd);
static struct enet_statistics *depca_get_stats(struct device *dev);
-#ifdef HAVE_MULTICAST
-static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
-#endif
+static void set_multicast_list(struct device *dev,int num_addrs,void *addrs);
/*
** Private functions
*/
-static int depca_probe1(struct device *dev, short ioaddr);
-static void depca_init_ring(struct device *dev);
-static int depca_rx(struct device *dev);
-static int depca_tx(struct device *dev);
-
-static void LoadCSRs(struct device *dev);
-static int InitRestartDepca(struct device *dev);
-static char *DepcaSignature(unsigned long mem_addr);
-static int DevicePresent(short ioaddr);
-static int EISA_signature(short iobase);
-#ifdef HAVE_MULTICAST
-static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table);
-#endif
-
-#ifndef MODULE
-static struct device *isa_probe(struct device *dev);
-static struct device *eisa_probe(struct device *dev);
-static struct device *alloc_device(struct device *dev, int ioaddr);
-
-static int num_depcas = 0, num_eth = 0, autoprobed = 0;
-
-#else
-int init_module(void);
-void cleanup_module(void);
+static int depca_hw_init(struct device *dev, u_long ioaddr);
+static void depca_init_ring(struct device *dev);
+static int depca_rx(struct device *dev);
+static int depca_tx(struct device *dev);
+
+static void LoadCSRs(struct device *dev);
+static int InitRestartDepca(struct device *dev);
+static void DepcaSignature(char *name, u_long paddr);
+static int DevicePresent(u_long ioaddr);
+static int get_hw_addr(struct device *dev);
+static int EISA_signature(char *name, s32 eisa_id);
+static void SetMulticastFilter(struct device *dev,int num_addrs,char *addrs);
+static void isa_probe(struct device *dev, u_long iobase);
+static void eisa_probe(struct device *dev, u_long iobase);
+static struct device *alloc_device(struct device *dev, u_long iobase);
+static int load_packet(struct device *dev, struct sk_buff *skb);
+#ifdef MODULE
+int init_module(void);
+void cleanup_module(void);
+static int autoprobed = 1, loading_module = 1;
+# else
+static u_char de1xx_irq[] = {2,3,4,5,7,0};
+static u_char de2xx_irq[] = {5,9,10,11,15,0};
+static u_char de422_irq[] = {5,9,10,11,0};
+static u_char *depca_irq;
+static int autoprobed = 0, loading_module = 0;
#endif /* MODULE */
+static char name[DEPCA_STRLEN];
+static int num_depcas = 0, num_eth = 0;
+
/*
** Miscellaneous defines...
*/
outw(CSR0, DEPCA_ADDR);\
outw(STOP, DEPCA_DATA)
-
\f
int depca_probe(struct device *dev)
{
- short base_addr = dev->base_addr;
- int status = -ENODEV;
-#ifndef MODULE
- struct device *eth0;
-#endif
+ int tmp = num_depcas, status = -ENODEV;
+ u_long iobase = dev->base_addr;
- if (base_addr > 0x1ff) { /* Check a single specified location. */
- if (DevicePresent(base_addr) == 0) { /* Is DEPCA really here? */
- status = depca_probe1(dev, base_addr);
- }
- } else if (base_addr > 0) { /* Don't probe at all. */
- status = -ENXIO;
-
-#ifdef MODULE
- } else {
- printk("Autoprobing is not supported when loading a module based driver.\n");
- status = -EIO;
-#else
- } else if (!autoprobed) { /* First probe for the DEPCA test */
- /* pattern in ROM */
- eth0=isa_probe(dev);
- eth0=eisa_probe(eth0);
- if (dev->priv) status=0;
- autoprobed = 1;
- } else {
- status = -ENXIO;
-#endif /* MODULE */
+ if ((iobase == 0) && loading_module){
+ printk("Autoprobing is not supported when loading a module based driver.\n");
+ status = -EIO;
+ } else {
+ isa_probe(dev, iobase);
+ eisa_probe(dev, iobase);
+ if ((tmp == num_depcas) && (iobase != 0) && loading_module) {
+ printk("%s: depca_probe() cannot find device at 0x%04lx.\n", dev->name,
+ iobase);
}
- if (status) dev->base_addr = base_addr;
+ /*
+ ** Walk the device list to check that at least one device
+ ** initialised OK
+ */
+ for (; (dev->priv == NULL) && (dev->next != NULL); dev = dev->next);
+
+ if (dev->priv) status = 0;
+ if (iobase == 0) autoprobed = 1;
+ }
- return status; /* ENODEV would be more accurate. */
+ return status;
}
static int
-depca_probe1(struct device *dev, short ioaddr)
+depca_hw_init(struct device *dev, u_long ioaddr)
{
- struct depca_private *lp;
- int i,j, status=0;
- unsigned long mem_start, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
- char *name = NULL;
- unsigned int nicsr, offset, netRAM;
-
-
- /*
- ** Stop the DEPCA. Enable the DBR ROM. Disable interrupts and remote boot.
- */
- STOP_DEPCA;
-
- nicsr = inb(DEPCA_NICSR);
- nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
- outb(nicsr, DEPCA_NICSR);
-
- if (inw(DEPCA_DATA) == STOP) {
+ struct depca_private *lp;
+ int i, j, offset, netRAM, mem_len, status=0;
+ s16 nicsr;
+ u_long mem_start=0, mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
+
+ STOP_DEPCA;
+
+ nicsr = inb(DEPCA_NICSR);
+ nicsr = ((nicsr & ~SHE & ~RBE & ~IEN) | IM);
+ outb(nicsr, DEPCA_NICSR);
+
+ if (inw(DEPCA_DATA) == STOP) {
+ for (; mem_base[mem_chkd]; mem_chkd++) {
+ mem_start = mem_base[mem_chkd];
+ DepcaSignature(name, mem_start);
+ if (*name != '\0') break;
+ }
- /* Now find out what kind of DEPCA we have. The DE100 uses a different
- ** addressing scheme for some registers compared to the DE2xx series.
- ** Note that a base address location is marked as checked if no DEPCA is
- ** there or one is found (when the search is immediately terminated). This
- ** shortens the search time a little for multiple DEPCAs.
- */
+ if ((*name != '\0') && mem_start) { /* found a DEPCA device */
+ dev->base_addr = ioaddr;
- for (j = 0, i = 0; mem_base[i] && (j == 0);i++) {
- if (((mem_chkd >> i) & 0x01) == 0) { /* has the memory been checked? */
- name = DepcaSignature(mem_base[i]);/* check for a DEPCA here */
- mem_chkd |= (0x01 << i); /* mark location checked */
- if (*name != '\0') { /* one found? */
- j = 1; /* set exit flag */
- --i;
- }
- }
+ if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */
+ printk("%s: %s at 0x%04lx (EISA slot %d)",
+ dev->name, name, ioaddr, (int)((ioaddr>>12)&0x0f));
+ } else { /* ISA port address */
+ printk("%s: %s at 0x%04lx", dev->name, name, ioaddr);
}
- if (*name != '\0') { /* found a DEPCA device */
- mem_start = mem_base[i];
- dev->base_addr = ioaddr;
-
- if ((ioaddr&0x0fff)==DEPCA_EISA_IO_PORTS) {/* EISA slot address */
- printk("%s: %s at %#3x (EISA slot %d)",
- dev->name, name, ioaddr, ((ioaddr>>12)&0x0f));
- } else { /* ISA port address */
- printk("%s: %s at %#3x", dev->name, name, ioaddr);
- }
-
- /* There is a 32 byte station address PROM at DEPCA_PROM address.
- The first six bytes are the station address. They can be read
- directly since the signature search set up the ROM address
- counter correctly just before this function.
-
- For the DE100 we have to be careful about which port is used to
- read the ROM info.
- */
-
- if (strstr(name,"DE100")!= NULL) {
- j = 1;
- } else {
- j = 0;
- }
-
- printk(", h/w address ");
- for (i = 0; i < ETH_ALEN - 1; i++) { /* get the ethernet address */
- printk("%2.2x:", dev->dev_addr[i] = inb(DEPCA_PROM + j));
- }
- printk("%2.2x", dev->dev_addr[i] = inb(DEPCA_PROM + j));
-
- for (;i<32;i++) { /* leave ROM counter in known state */
- j=inb(DEPCA_PROM);
- }
-
- request_region(ioaddr, DEPCA_TOTAL_SIZE, dev->name);
-
- /*
- ** Set up the maximum amount of network RAM(kB)
- */
- if (strstr(name,"DEPCA")== NULL) {
- netRAM=64;
- } else {
- netRAM=48;
- }
+ printk(", h/w address ");
+ status = get_hw_addr(dev);
+ for (i=0; i<ETH_ALEN - 1; i++) { /* get the ethernet address */
+ printk("%2.2x:", dev->dev_addr[i]);
+ }
+ printk("%2.2x", dev->dev_addr[i]);
- /*
- ** Determine the base address for the DEPCA RAM from the NI-CSR
- ** and make up a DEPCA-specific-data structure.
- */
+ if (status == 0) {
+ /* Set up the maximum amount of network RAM(kB) */
+ netRAM = ((adapter != DEPCA) ? 64 : 48);
+ if ((nicsr & _128KB) && (adapter == de422)) netRAM = 128;
+ offset = 0x0000;
+ /* Shared Memory Base Address */
if (nicsr & BUF) {
offset = 0x8000; /* 32kbyte RAM offset*/
nicsr &= ~BS; /* DEPCA RAM in top 32k */
- printk(",\n has %dkB RAM", netRAM - 32);
- } else if ((nicsr & _128KB) && (netRAM!=48)) {
- offset = 0x0000;
- printk(",\n has 128kB RAM");
- } else {
- offset = 0x0000; /* 64k/48k bytes RAM */
- printk(",\n has %dkB RAM", netRAM);
+ netRAM -= 32;
}
-
mem_start += offset; /* (E)ISA start address */
- printk(" at 0x%.5lx", mem_start);
-
- /*
- ** Enable the shadow RAM.
- */
- if (strstr(name,"DEPCA") == NULL) {
- nicsr |= SHE;
- outb(nicsr, DEPCA_NICSR);
- }
+ if ((mem_len = (NUM_RX_DESC*(sizeof(struct depca_rx_desc)+RX_BUFF_SZ) +
+ NUM_TX_DESC*(sizeof(struct depca_tx_desc)+TX_BUFF_SZ) +
+ sizeof(struct depca_init))) <=
+ (netRAM<<10)) {
+ printk(",\n has %dkB RAM at 0x%.5lx", netRAM, mem_start);
+
+ /* Enable the shadow RAM. */
+ if (adapter != DEPCA) {
+ nicsr |= SHE;
+ outb(nicsr, DEPCA_NICSR);
+ }
- /*
- ** Calculate the ring size based on the available RAM
- ** found above. Allocate an equal number of buffers, each
- ** of size PKT_BUF_SZ (1544 bytes) to the Tx and Rx, allowing one
- ** descriptor entry (8 bytes) for each buffer. Make sure
- ** that this ring size is <= RING_SIZE. The ring size must be
- ** a power of 2.
- */
-
- j = (((netRAM << 10) - offset - sizeof(struct depca_private)) /
- (PKT_BUF_SZ + 8)) >> 1;
- for (i=0;j>1;i++) {
- j >>= 1;
- }
-
- /* Hold the ring size information here before the depca
- ** private structure is allocated. Need this for the memory
- ** space calculations.
- */
- j = 1 << i;
-
- /*
- ** Set up memory information in the device structure.
- ** Align the descriptor rings on an 8 byte (quadword) boundary.
- **
- ** depca_private area
- ** rx ring descriptors
- ** tx ring descriptors
- ** rx buffers
- ** tx buffers
- **
- */
-
- /* private area & initialise */
- dev->priv = (void *)((mem_start + 0x07) & ~0x07);
- lp = (struct depca_private *)dev->priv;
- memset(dev->priv, 0, sizeof(struct depca_private));
- strcpy(lp->devname,name);
-
- /* Tx & Rx descriptors (aligned to a quadword boundary) */
- mem_start = ((((unsigned long)dev->priv +
- sizeof(struct depca_private)) +
- (unsigned long)0x07) & (unsigned long)~0x07);
- lp->rx_ring = (struct depca_rx_head *)mem_start;
-
- mem_start += (sizeof(struct depca_rx_head) * j);
- lp->tx_ring = (struct depca_tx_head *)mem_start;
-
- mem_start += (sizeof(struct depca_tx_head) * j);
- lp->bus_offset = mem_start & 0x00ff0000;
- mem_start &= LA_MASK; /* LANCE re-mapped start address */
-
- lp->dma_buffs = mem_start;
-
- mem_start += (PKT_BUF_SZ * j);
- /* (mem_start now points to the start of the Tx buffers) */
-
- /* Initialise the data structures wrt CPU */
- memset(lp->rx_ring, 0, sizeof(struct depca_rx_head)*j);
- memset(lp->tx_ring, 0, sizeof(struct depca_tx_head)*j);
-
- /* This should never happen. */
- if ((long)(lp->rx_ring) & 0x07) {
- printk("\n **ERROR** DEPCA Rx and Tx descriptor rings not on a quadword boundary.\n");
- return -ENXIO;
- }
-
- /*
- ** Finish initialising the ring information.
- */
- lp->ringSize = j;
- if (lp->ringSize > RING_SIZE) lp->ringSize = RING_SIZE;
- lp->rmask = lp->ringSize - 1;
-
- /*
- ** calculate the real RLEN size for the descriptors. It is
- ** log2(ringSize).
- */
- for (i=0, j = lp->ringSize; j>1; i++) {
- j >>= 1;
- }
- lp->rlen = (unsigned long)(i << 29);
-
- /*
- ** load the initialisation block
- */
- depca_init_ring(dev);
+ /* Define the device private memory */
+ dev->priv = (void *) kmalloc(sizeof(struct depca_private), GFP_KERNEL);
+ lp = (struct depca_private *)dev->priv;
+ memset((char *)dev->priv, 0, sizeof(struct depca_private));
+ lp->adapter = adapter;
+ sprintf(lp->adapter_name,"%s (%s)", name, dev->name);
+ request_region(ioaddr, DEPCA_TOTAL_SIZE, lp->adapter_name);
+
+ /* Initialisation Block */
+ lp->sh_mem = mem_start;
+ mem_start += sizeof(struct depca_init);
+
+ /* Tx & Rx descriptors (aligned to a quadword boundary) */
+ mem_start = (mem_start + ALIGN) & ~ALIGN;
+ lp->rx_ring = (struct depca_rx_desc *)mem_start;
+
+ mem_start += (sizeof(struct depca_rx_desc) * NUM_RX_DESC);
+ lp->tx_ring = (struct depca_tx_desc *)mem_start;
+
+ mem_start += (sizeof(struct depca_tx_desc) * NUM_TX_DESC);
+ lp->bus_offset = mem_start & 0x00ff0000;
+ mem_start &= LA_MASK; /* LANCE re-mapped start address */
+
+ lp->dma_buffs = mem_start;
+
+ /* Finish initialising the ring information. */
+ lp->rxRingMask = NUM_RX_DESC - 1;
+ lp->txRingMask = NUM_TX_DESC - 1;
+
+ /* Calculate Tx/Rx RLEN size for the descriptors. */
+ for (i=0, j = lp->rxRingMask; j>0; i++) {
+ j >>= 1;
+ }
+ lp->rx_rlen = (s32)(i << 29);
+ for (i=0, j = lp->txRingMask; j>0; i++) {
+ j >>= 1;
+ }
+ lp->tx_rlen = (s32)(i << 29);
- /*
- ** Initialise the control and status registers
- */
- LoadCSRs(dev);
+ /* Load the initialisation block */
+ depca_init_ring(dev);
- /*
- ** Enable DEPCA board interrupts for autoprobing
- */
- nicsr = ((nicsr & ~IM)|IEN);
- outb(nicsr, DEPCA_NICSR);
+ /* Initialise the control and status registers */
+ LoadCSRs(dev);
- /* The DMA channel may be passed in on this parameter. */
- dev->dma = 0;
+ /* Enable DEPCA board interrupts for autoprobing */
+ nicsr = ((nicsr & ~IM)|IEN);
+ outb(nicsr, DEPCA_NICSR);
- /* To auto-IRQ we enable the initialization-done and DMA err,
- interrupts. For now we will always get a DMA error. */
- if (dev->irq < 2) {
+ /* To auto-IRQ we enable the initialization-done and DMA err,
+ interrupts. For now we will always get a DMA error. */
+ if (dev->irq < 2) {
#ifndef MODULE
- autoirq_setup(0);
+ unsigned char irqnum;
+ autoirq_setup(0);
+
+ /* Assign the correct irq list */
+ switch (lp->adapter) {
+ case DEPCA:
+ case de100:
+ case de101:
+ depca_irq = de1xx_irq;
+ break;
+ case de200:
+ case de201:
+ case de202:
+ case de210:
+ depca_irq = de2xx_irq;
+ break;
+ case de422:
+ depca_irq = de422_irq;
+ break;
+ }
- /* Trigger an initialization just for the interrupt. */
- outw(INEA | INIT, DEPCA_DATA);
+ /* Trigger an initialization just for the interrupt. */
+ outw(INEA | INIT, DEPCA_DATA);
- dev->irq = autoirq_report(1);
- if (dev->irq) {
- printk(" and uses IRQ%d.\n", dev->irq);
+ irqnum = autoirq_report(1);
+ if (!irqnum) {
+ printk(" and failed to detect IRQ line.\n");
+ status = -ENXIO;
+ } else {
+ for (dev->irq=0,i=0; (depca_irq[i]) && (!dev->irq); i++) {
+ if (irqnum == depca_irq[i]) {
+ dev->irq = irqnum;
+ printk(" and uses IRQ%d.\n", dev->irq);
+ }
+ }
+
+ if (!dev->irq) {
+ printk(" but incorrect IRQ line detected.\n");
+ status = -ENXIO;
+ }
+ }
+#endif /* MODULE */
} else {
- printk(" and failed to detect IRQ line.\n");
- status = -EAGAIN;
+ printk(" and assigned IRQ%d.\n", dev->irq);
}
-#endif /* MODULE */
+ if (status) release_region(ioaddr, DEPCA_TOTAL_SIZE);
} else {
- printk(" and assigned IRQ%d.\n", dev->irq);
+ printk(",\n requests %dkB RAM: only %dkB is available!\n",
+ (mem_len>>10), netRAM);
+ status = -ENXIO;
}
} else {
+ printk(" which has an Ethernet PROM CRC error.\n");
status = -ENXIO;
}
- if (!status) {
- if (depca_debug > 0) {
- printk(version);
- }
+ }
+ if (!status) {
+ if (depca_debug > 0) {
+ printk(version);
+ }
- /* The DEPCA-specific entries in the device structure. */
- dev->open = &depca_open;
- dev->hard_start_xmit = &depca_start_xmit;
- dev->stop = &depca_close;
- dev->get_stats = &depca_get_stats;
-#ifdef HAVE_MULTICAST
- dev->set_multicast_list = &set_multicast_list;
-#endif
+ /* The DEPCA-specific entries in the device structure. */
+ dev->open = &depca_open;
+ dev->hard_start_xmit = &depca_start_xmit;
+ dev->stop = &depca_close;
+ dev->get_stats = &depca_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+ dev->do_ioctl = &depca_ioctl;
- dev->mem_start = 0;
+ dev->mem_start = 0;
- /* Fill in the generic field of the device structure. */
- ether_setup(dev);
+ /* Fill in the generic field of the device structure. */
+ ether_setup(dev);
+ } else { /* Incorrectly initialised hardware */
+ if (dev->priv) {
+ kfree_s(dev->priv, sizeof(struct depca_private));
+ dev->priv = NULL;
}
- } else {
- status = -ENXIO;
}
+ } else {
+ status = -ENXIO;
+ }
- return status;
+ return status;
}
\f
depca_open(struct device *dev)
{
struct depca_private *lp = (struct depca_private *)dev->priv;
- int i,nicsr,ioaddr = dev->base_addr;
+ s16 nicsr;
+ u_long ioaddr = dev->base_addr;
+ int i, status = 0;
+ struct depca_init *p = (struct depca_init *)lp->sh_mem;
- if (request_irq(dev->irq, &depca_interrupt, 0, "depca")) {
+ if (request_irq(dev->irq, &depca_interrupt, 0, lp->adapter_name)) {
printk("depca_open(): Requested IRQ%d is busy\n",dev->irq);
- return -EAGAIN;
+ status = -EAGAIN;
}
irq2dev_map[dev->irq] = dev;
-
- /*
- ** Stop the DEPCA & get the board status information.
- */
STOP_DEPCA;
nicsr = inb(DEPCA_NICSR);
- /*
- ** Make sure the shadow RAM is enabled
- */
- if (strstr(lp->devname,"DEPCA") == NULL) {
+ /* Make sure the shadow RAM is enabled */
+ if (adapter != DEPCA) {
nicsr |= SHE;
outb(nicsr, DEPCA_NICSR);
}
- /*
- ** Re-initialize the DEPCA...
- */
- depca_init_ring(dev); /* initialize the descriptor rings */
+ /* Re-initialize the DEPCA... */
+ depca_init_ring(dev);
LoadCSRs(dev);
if (depca_debug > 1){
+ /* Copy the shadow init_block to shared memory */
+ memcpy_toio((char *)lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
+
printk("%s: depca open with irq %d\n",dev->name,dev->irq);
printk("Descriptor head addresses:\n");
- printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring,(long)lp->tx_ring);
- printk("Descriptor addresses:\n");
- for (i=0;i<lp->ringSize;i++){
- printk("\t0x%8.8lx 0x%8.8lx\n",(long)&lp->rx_ring[i].base,
- (long)&lp->tx_ring[i].base);
+ printk("\t0x%lx 0x%lx\n",(u_long)lp->rx_ring, (u_long)lp->tx_ring);
+ printk("Descriptor addresses:\nRX: ");
+ for (i=0;i<lp->rxRingMask;i++){
+ if (i < 3) {
+ printk("0x%8.8lx ", (long) &lp->rx_ring[i].base);
+ }
+ }
+ printk("...0x%8.8lx\n", (long) &lp->rx_ring[i].base);
+ printk("TX: ");
+ for (i=0;i<lp->txRingMask;i++){
+ if (i < 3) {
+ printk("0x%8.8lx ", (long) &lp->tx_ring[i].base);
+ }
}
- printk("Buffer addresses:\n");
- for (i=0;i<lp->ringSize;i++){
- printk("\t0x%8.8lx 0x%8.8lx\n",(long)lp->rx_ring[i].base,
- (long)lp->tx_ring[i].base);
+ printk("...0x%8.8lx\n", (long) &lp->tx_ring[i].base);
+ printk("\nDescriptor buffers:\nRX: ");
+ for (i=0;i<lp->rxRingMask;i++){
+ if (i < 3) {
+ printk("0x%8.8x ", readl(&lp->rx_ring[i].base));
+ }
}
- printk("Initialisation block at 0x%8.8lx\n",(long)&lp->init_block);
- printk("\tmode: 0x%4.4x\n",lp->init_block.mode);
+ printk("...0x%8.8x\n", readl(&lp->rx_ring[i].base));
+ printk("TX: ");
+ for (i=0;i<lp->txRingMask;i++){
+ if (i < 3) {
+ printk("0x%8.8x ", readl(&lp->tx_ring[i].base));
+ }
+ }
+ printk("...0x%8.8x\n", readl(&lp->tx_ring[i].base));
+ printk("Status: %d\n", status);
+ printk("Initialisation block at 0x%8.8lx\n",lp->sh_mem);
+ printk("\tmode: 0x%4.4x\n",readw(&p->mode));
printk("\tphysical address: ");
- for (i=0;i<6;i++){
- printk("%2.2x:",(short)lp->init_block.phys_addr[i]);
+ for (i=0;i<ETH_ALEN-1;i++){
+ printk("%2.2x:",(u_char)readb(&p->phys_addr[i]));
}
- printk("\n\tlogical address filter: 0x");
- for (i=0;i<4;i++){
- printk("%2.2x",(short)lp->init_block.filter[i]);
+ printk("%2.2x\n",(u_char)readb(&p->phys_addr[i]));
+ printk("\tmulticast hash table: ");
+ for (i=0;i<(HASH_TABLE_LEN >> 3)-1;i++){
+ printk("%2.2x:",(u_char)readb(&p->mcast_table[i]));
}
- printk("\n\trx_ring at: 0x%8.8lx\n",(long)lp->init_block.rx_ring);
- printk("\ttx_ring at: 0x%8.8lx\n",(long)lp->init_block.tx_ring);
- printk("dma_buffs: 0x%8.8lx\n",(long)lp->dma_buffs);
- printk("Ring size: %d\nMask: 0x%2.2x\nLog2(ringSize): 0x%8.8lx\n",
- (short)lp->ringSize,
- (char)lp->rmask,
- (long)lp->rlen);
+ printk("%2.2x\n",(u_char)readb(&p->mcast_table[i]));
+ printk("\trx_ring at: 0x%8.8x\n",readl(&p->rx_ring));
+ printk("\ttx_ring at: 0x%8.8x\n",readl(&p->tx_ring));
+ printk("dma_buffs: 0x%8.8lx\n",lp->dma_buffs);
+ printk("Ring size:\nRX: %d Log2(rxRingMask): 0x%8.8x\n",
+ (int)lp->rxRingMask + 1,
+ lp->rx_rlen);
+ printk("TX: %d Log2(txRingMask): 0x%8.8x\n",
+ (int)lp->txRingMask + 1,
+ lp->tx_rlen);
outw(CSR2,DEPCA_ADDR);
printk("CSR2&1: 0x%4.4x",inw(DEPCA_DATA));
outw(CSR1,DEPCA_ADDR);
printk("CSR3: 0x%4.4x\n",inw(DEPCA_DATA));
}
- /*
- ** Enable DEPCA board interrupts and turn off LED
- */
+ /* Enable DEPCA board interrupts and turn off LED */
nicsr = ((nicsr & ~IM & ~LED)|IEN);
outb(nicsr, DEPCA_NICSR);
outw(CSR0,DEPCA_ADDR);
dev->interrupt = 0;
dev->start = 1;
- InitRestartDepca(dev); /* ignore the return status */
+ status = InitRestartDepca(dev);
if (depca_debug > 1){
printk("CSR0: 0x%4.4x\n",inw(DEPCA_DATA));
MOD_INC_USE_COUNT;
- return 0; /* Always succeed */
+ return status;
}
/* Initialize the lance Rx and Tx descriptor rings. */
static void
depca_init_ring(struct device *dev)
{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- unsigned long i;
-
- lp->init_block.mode = DTX | DRX; /* Disable Rx and Tx. */
- lp->cur_rx = lp->cur_tx = 0;
- lp->dirty_rx = lp->dirty_tx = 0;
-
- /* Initialize the base addresses and length of each buffer in the ring */
- for (i = 0; i < lp->ringSize; i++) {
- lp->rx_ring[i].base = (lp->dma_buffs + i*PKT_BUF_SZ) | R_OWN;
- lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
- lp->tx_ring[i].base = (lp->dma_buffs + (i+lp->ringSize) * PKT_BUF_SZ) &
- (unsigned long)(0x00ffffff);
- }
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ u_int i;
+ u_long p;
- /* Set up the initialization block */
- for (i = 0; i < ETH_ALEN; i++) {
- lp->init_block.phys_addr[i] = dev->dev_addr[i];
- }
- for (i = 0; i < 4; i++) {
- lp->init_block.filter[i] = 0x0000;
- }
- lp->init_block.rx_ring = ((unsigned long)lp->rx_ring & LA_MASK) | lp->rlen;
- lp->init_block.tx_ring = ((unsigned long)lp->tx_ring & LA_MASK) | lp->rlen;
+ /* Lock out other processes whilst setting up the hardware */
+ set_bit(0, (void *)&dev->tbusy);
- lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */
+ lp->rx_new = lp->tx_new = 0;
+ lp->rx_old = lp->tx_old = 0;
+
+ /* Initialize the base addresses and length of each buffer in the ring */
+ for (i = 0; i <= lp->rxRingMask; i++) {
+ writel((p=lp->dma_buffs+i*RX_BUFF_SZ) | R_OWN, &lp->rx_ring[i].base);
+ writew(-RX_BUFF_SZ, &lp->rx_ring[i].buf_length);
+ lp->rx_memcpy[i]=(char *)(p+lp->bus_offset);
+ }
+ for (i = 0; i <= lp->txRingMask; i++) {
+ writel((p=lp->dma_buffs+(i+lp->txRingMask+1)*TX_BUFF_SZ) & 0x00ffffff,
+ &lp->tx_ring[i].base);
+ lp->tx_memcpy[i]=(char *)(p+lp->bus_offset);
+ }
+
+ /* Set up the initialization block */
+ lp->init_block.rx_ring = ((u32)((u_long)lp->rx_ring)&LA_MASK) | lp->rx_rlen;
+ lp->init_block.tx_ring = ((u32)((u_long)lp->tx_ring)&LA_MASK) | lp->tx_rlen;
+
+ SetMulticastFilter(dev, 0, NULL);
+
+ for (i = 0; i < ETH_ALEN; i++) {
+ lp->init_block.phys_addr[i] = dev->dev_addr[i];
+ }
+
+ lp->init_block.mode = 0x0000; /* Enable the Tx and Rx */
+
+ return;
}
/*
static int
depca_start_xmit(struct sk_buff *skb, struct device *dev)
{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- int ioaddr = dev->base_addr;
- int status = 0;
-
- /* Transmitter timeout, serious problems. */
- if (dev->tbusy) {
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 10) {
- status = -1;
- } else {
- printk("%s: transmit timed out, status %04x, resetting.\n",
- dev->name, inw(DEPCA_DATA));
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ u_long ioaddr = dev->base_addr;
+ int status = 0;
+
+ /* Transmitter timeout, serious problems. */
+ if (dev->tbusy) {
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 100) {
+ status = -1;
+ } else {
+ printk("%s: transmit timed out, status %04x, resetting.\n",
+ dev->name, inw(DEPCA_DATA));
- STOP_DEPCA;
- depca_init_ring(dev);
- LoadCSRs(dev);
- InitRestartDepca(dev);
- dev->tbusy=0;
- dev->trans_start = jiffies;
- }
- return status;
- }
-
- if (skb == NULL) {
- dev_tint(dev);
- return 0;
- }
-
- if (skb->len <= 0) {
- return 0;
- }
-
- if (depca_debug > 3) {
- outw(CSR0, DEPCA_ADDR);
- printk("%s: depca_start_xmit() called, csr0 %4.4x.\n", dev->name,
- inw(DEPCA_DATA));
- }
-
- /* Block a timer-based transmit from overlapping. This could better be
- done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
- if (set_bit(0, (void*)&dev->tbusy) != 0)
- printk("%s: Transmitter access conflict.\n", dev->name);
-
- /*
- ** The TX buffer, skb, has to be copied into the local network RAM
- ** for the LANCE to access it. The skb may be at > 16MB for large
- ** (memory) systems.
- */
- { /* Fill in a Tx ring entry */
- unsigned char *buf;
- int entry = lp->cur_tx++;
- int len;
- long skbL = skb->len;
- char *p = (char *) skb->data;
-
- entry &= lp->rmask; /* Ring around buffer number. */
- buf = (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
- 0x00ffffff);
-
- /* Wait for a full ring to free up */
- while (lp->tx_ring[entry].base < 0);
-
- /*
- ** Caution: the write order is important here... don't set up the
- ** ownership rights until all the other information is in place.
- */
- len = ((skbL > PKT_SZ) ? PKT_SZ : skbL); /* skb too long */
- if (len < ETH_ZLEN) len = ETH_ZLEN; /* len too short */
- skbL -= len;
- lp->tx_ring[entry].length = -len;
-
- /* Clears various error flags */
- lp->tx_ring[entry].misc = 0x0000;
-
- /* copy the data from the socket buffer to the net memory */
- memcpy((unsigned char *)(buf), skb->data, len);
-
- /* Hand over buffer ownership to the LANCE */
- if (skbL <= 0) lp->tx_ring[entry].base |= (T_ENP);
- lp->tx_ring[entry].base |= (T_OWN|T_STP);
-
- /* Trigger an immediate send demand. */
- outw(CSR0, DEPCA_ADDR);
- outw(INEA | TDMD, DEPCA_DATA);
-
+ STOP_DEPCA;
+ depca_init_ring(dev);
+ LoadCSRs(dev);
+ dev->interrupt = UNMASK_INTERRUPTS;
+ dev->start = 1;
+ dev->tbusy=0;
dev->trans_start = jiffies;
+ InitRestartDepca(dev);
+ }
+ return status;
+ } else if (skb == NULL) {
+ dev_tint(dev);
+ } else if (skb->len > 0) {
+ /* Enforce 1 process per h/w access */
+ if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ status = -1;
+ } else {
+ if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */
+ status = load_packet(dev, skb);
- for (p += len; skbL > 0; p += len) {
-
- /* Get new buffer pointer */
- entry = lp->cur_tx++;
- entry &= lp->rmask; /* Ring around buffer number. */
- buf = (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
- 0x00ffffff);
-
- /* Wait for a full ring to free up */
- while (lp->tx_ring[entry].base < 0);
- dev->tbusy=0;
-
- /* Copy ethernet header to the new buffer */
- memcpy((unsigned char *)buf, skb->data, PKT_HDR_LEN);
-
- /* Determine length of data buffer */
- len = ((skbL > DAT_SZ) ? DAT_SZ : skbL); /* skbL too long */
- if (len < ETH_ZLEN) len = ETH_ZLEN; /* len too short */
- skbL -= len;
- lp->tx_ring[entry].length = -len;
-
- /* Clears various error flags */
- lp->tx_ring[entry].misc = 0x0000;
-
- /* copy the data from the socket buffer to the net memory */
- memcpy((unsigned char *)(buf + PKT_HDR_LEN), (unsigned char *)p, len);
-
- /* Hand over buffer ownership to the LANCE */
- if (skbL <= 0) lp->tx_ring[entry].base |= T_ENP;
- lp->tx_ring[entry].base |= T_OWN;
- }
-
- if (depca_debug > 4) {
- unsigned char *pkt =
- (unsigned char *)((lp->tx_ring[entry].base+lp->bus_offset) &
- 0x00ffffff);
-
- printk("%s: tx ring[%d], %#lx, sk_buf %#lx len %d.\n",
- dev->name, entry, (unsigned long) &lp->tx_ring[entry],
- lp->tx_ring[entry].base, -lp->tx_ring[entry].length);
- printk("%s: Tx %2.2x %2.2x %2.2x ... %2.2x %2.2x %2.2x %2.2x...%2.2x len %2.2x %2.2x %2.2x %2.2x.\n",
- dev->name, pkt[0], pkt[1], pkt[2], pkt[5], pkt[6],
- pkt[7], pkt[8], pkt[11], pkt[12], pkt[13],
- pkt[14], pkt[15]);
- }
-
- /* Check if the TX ring is full or not - 'tbusy' cleared if not full. */
- if (lp->tx_ring[(entry+1) & lp->rmask].base >= 0) {
- dev->tbusy=0;
+ if (!status) {
+ /* Trigger an immediate send demand. */
+ outw(CSR0, DEPCA_ADDR);
+ outw(INEA | TDMD, DEPCA_DATA);
+
+ dev->trans_start = jiffies;
+ dev_kfree_skb(skb, FREE_WRITE);
+ }
+ if (TX_BUFFS_AVAIL) {
+ dev->tbusy=0;
+ }
+ } else {
+ status = -1;
}
-
- dev_kfree_skb (skb, FREE_WRITE);
}
-
- return 0;
+ }
+
+ return status;
}
/*
static void
depca_interrupt(int irq, struct pt_regs * regs)
{
- struct device *dev = (struct device *)(irq2dev_map[irq]);
- struct depca_private *lp;
- int csr0, ioaddr, nicsr;
-
- if (dev == NULL) {
- printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
- } else {
- lp = (struct depca_private *)dev->priv;
- ioaddr = dev->base_addr;
-
- if (dev->interrupt)
- printk("%s: Re-entering the interrupt handler.\n", dev->name);
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+ struct depca_private *lp;
+ s16 csr0, nicsr;
+ u_long ioaddr;
- dev->interrupt = MASK_INTERRUPTS;
+ if (dev == NULL) {
+ printk ("depca_interrupt(): irq %d for unknown device.\n", irq);
+ } else {
+ lp = (struct depca_private *)dev->priv;
+ ioaddr = dev->base_addr;
+
+ if (dev->interrupt)
+ printk("%s: Re-entering the interrupt handler.\n", dev->name);
- /* mask the DEPCA board interrupts and turn on the LED */
- nicsr = inb(DEPCA_NICSR);
- nicsr |= (IM|LED);
- outb(nicsr, DEPCA_NICSR);
+ dev->interrupt = MASK_INTERRUPTS;
- outw(CSR0, DEPCA_ADDR);
- csr0 = inw(DEPCA_DATA);
+ /* mask the DEPCA board interrupts and turn on the LED */
+ nicsr = inb(DEPCA_NICSR);
+ nicsr |= (IM|LED);
+ outb(nicsr, DEPCA_NICSR);
- /* Acknowledge all of the current interrupt sources ASAP. */
- outw(csr0 & ~(INEA|TDMD|STOP|STRT|INIT), DEPCA_DATA);
+ outw(CSR0, DEPCA_ADDR);
+ csr0 = inw(DEPCA_DATA);
- if (depca_debug > 5)
- printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n",
- dev->name, csr0, inw(DEPCA_DATA));
+ /* Acknowledge all of the current interrupt sources ASAP. */
+ outw(csr0 & INTE, DEPCA_DATA);
- if (csr0 & RINT) /* Rx interrupt (packet arrived) */
- depca_rx(dev);
+ if (csr0 & RINT) /* Rx interrupt (packet arrived) */
+ depca_rx(dev);
- if (csr0 & TINT) /* Tx interrupt (packet sent) */
- depca_tx(dev);
+ if (csr0 & TINT) /* Tx interrupt (packet sent) */
+ depca_tx(dev);
- /* Clear the interrupts we've handled. */
- outw(CSR0, DEPCA_ADDR);
- outw(BABL|CERR|MISS|MERR|RINT|TINT|IDON|INEA, DEPCA_DATA);
+ if ((TX_BUFFS_AVAIL >= 0) && dev->tbusy) { /* any resources available? */
+ dev->tbusy = 0; /* clear TX busy flag */
+ mark_bh(NET_BH);
+ }
- if (depca_debug > 4) {
- printk("%s: exiting interrupt, csr%d=%#4.4x.\n",
- dev->name, inw(DEPCA_ADDR),
- inw(DEPCA_DATA));
- }
+ /* Unmask the DEPCA board interrupts and turn off the LED */
+ nicsr = (nicsr & ~IM & ~LED);
+ outb(nicsr, DEPCA_NICSR);
- /* Unmask the DEPCA board interrupts and turn off the LED */
- nicsr = (nicsr & ~IM & ~LED);
- outb(nicsr, DEPCA_NICSR);
- dev->interrupt = UNMASK_INTERRUPTS;
- }
+ dev->interrupt = UNMASK_INTERRUPTS;
+ }
- return;
+ return;
}
static int
depca_rx(struct device *dev)
{
- struct depca_private *lp = (struct depca_private *)dev->priv;
- int entry = lp->cur_rx & lp->rmask;
-
- /* If we own the next entry, it's a new packet. Send it up. */
- for (; lp->rx_ring[entry].base >= 0; entry = (++lp->cur_rx) & lp->rmask) {
- int status = lp->rx_ring[entry].base >> 16 ;
- int chained;
-
- /*
- ** There is a tricky error noted by John Murphy, <murf@perftech.com>
- ** to Russ Nelson: even with full-sized buffers, it's possible for a
- ** jabber packet to use two buffers, with only the last one correctly
- ** noting the error.
- */
-
- /* Check for a chaining buffer */
- chained = 0;
- if (status == R_STP) {
- chained = 1;
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int i, entry;
+ s32 status;
+ char *buf;
+
+ for (entry=lp->rx_new;
+ !(readl(&lp->rx_ring[entry].base) & R_OWN);
+ entry=lp->rx_new){
+ status = readl(&lp->rx_ring[entry].base) >> 16 ;
+ if (status & R_STP) { /* Remember start of frame */
+ lp->rx_old = entry;
+ }
+ if (status & R_ENP) { /* Valid frame status */
+ if (status & R_ERR) { /* There was an error. */
+ lp->stats.rx_errors++; /* Update the error stats. */
+ if (status & R_FRAM) lp->stats.rx_frame_errors++;
+ if (status & R_OFLO) lp->stats.rx_over_errors++;
+ if (status & R_CRC) lp->stats.rx_crc_errors++;
+ if (status & R_BUFF) lp->stats.rx_fifo_errors++;
+ } else {
+ short len, pkt_len = readw(&lp->rx_ring[entry].msg_length);
+ struct sk_buff *skb;
+
+ skb = alloc_skb(pkt_len, GFP_ATOMIC);
+ if (skb != NULL) {
+ skb->len = pkt_len;
+ skb->dev = dev;
+ if (entry < lp->rx_old) { /* Wrapped buffer */
+ len = (lp->rxRingMask - lp->rx_old + 1) * RX_BUFF_SZ;
+ memcpy_fromio(skb->data, lp->rx_memcpy[lp->rx_old], len);
+ memcpy_fromio(skb->data+len, lp->rx_memcpy[0], pkt_len-len);
+ } else { /* Linear buffer */
+ memcpy_fromio(skb->data, lp->rx_memcpy[lp->rx_old], pkt_len);
+ }
/*
- ** Wait for next buffer to complete to check for errors. This
- ** is slow but infrequent and allows for correct hardware buffer
- ** chaining (whilst defeating the chaining's purpose).
+ ** Notify the upper protocol layers that there is another
+ ** packet to handle
*/
- while ((status=(lp->rx_ring[(entry+1)&lp->rmask].base >> 16)) < 0);
-
- /* NB: 'status' now comes from the buffer following 'entry'. */
- }
-
- if (status & R_ERR) { /* There was an error. */
- lp->stats.rx_errors++; /* Update the error stats. */
- if (status & R_FRAM) lp->stats.rx_frame_errors++;
- if (status & R_OFLO) lp->stats.rx_over_errors++;
- if (status & R_CRC) lp->stats.rx_crc_errors++;
- if (status & R_BUFF) lp->stats.rx_fifo_errors++;
- } else { /* Malloc up new buffer, compatible with net-2e. */
- short pkt_len = lp->rx_ring[entry].msg_length;
- struct sk_buff *skb;
-
- skb = alloc_skb(pkt_len, GFP_ATOMIC);
- if (skb == NULL) {
- printk("%s: Memory squeeze, deferring packet.\n", dev->name);
- lp->stats.rx_dropped++; /* Really, deferred. */
- break;
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx(skb);
+
+ /*
+ ** Update stats
+ */
+ lp->stats.rx_packets++;
+ for (i=1; i<DEPCA_PKT_STAT_SZ-1; i++) {
+ if (pkt_len < (i*DEPCA_PKT_BIN_SZ)) {
+ lp->pktStats.bins[i]++;
+ i = DEPCA_PKT_STAT_SZ;
}
- skb->len = pkt_len;
- skb->dev = dev;
- memcpy(skb->data,
- (unsigned char *)((lp->rx_ring[entry].base+lp->bus_offset) &
- 0x00ffffff),
- pkt_len);
- /*
- ** Notify the upper protocol layers that there is another
- ** packet to handle
- */
- skb->protocol=eth_type_trans(skb,dev);
- netif_rx(skb);
- lp->stats.rx_packets++;
- }
-
- /* turn over ownership of the current entry back to the LANCE */
- lp->rx_ring[entry].base |= R_OWN;
- if (chained && (status & R_ERR)) { /* next entry also bad */
- entry = (++lp->cur_rx) & lp->rmask;
- lp->rx_ring[entry].base |= R_OWN;
+ }
+ buf = skb->data; /* Look at the dest addr */
+ if (buf[0] & 0x01) { /* Multicast/Broadcast */
+ if ((*(s32 *)&buf[0] == -1) && (*(s16 *)&buf[4] == -1)) {
+ lp->pktStats.broadcast++;
+ } else {
+ lp->pktStats.multicast++;
+ }
+ } else if ((*(s32 *)&buf[0] == *(s32 *)&dev->dev_addr[0]) &&
+ (*(s16 *)&buf[4] == *(s16 *)&dev->dev_addr[4])) {
+ lp->pktStats.unicast++;
+ }
+
+ lp->pktStats.bins[0]++; /* Duplicates stats.rx_packets */
+ if (lp->pktStats.bins[0] == 0) { /* Reset counters */
+ memset((char *)&lp->pktStats, 0, sizeof(lp->pktStats));
+ }
+ } else {
+ printk("%s: Memory squeeze, deferring packet.\n", dev->name);
+ lp->stats.rx_dropped++; /* Really, deferred. */
+ break;
}
+ }
+ /* Change buffer ownership for this last frame, back to the adapter */
+ for (; lp->rx_old!=entry; lp->rx_old=(++lp->rx_old)&lp->rxRingMask) {
+ writel(readl(&lp->rx_ring[lp->rx_old].base) | R_OWN,
+ &lp->rx_ring[lp->rx_old].base);
+ }
+ writel(readl(&lp->rx_ring[entry].base) | R_OWN, &lp->rx_ring[entry].base);
}
- /*
- ** We should check that at least two ring entries are free. If not,
- ** we should free one and mark stats->rx_dropped++.
+ /*
+ ** Update entry information
*/
+ lp->rx_new = (++lp->rx_new) & lp->rxRingMask;
+ }
return 0;
}
depca_tx(struct device *dev)
{
struct depca_private *lp = (struct depca_private *)dev->priv;
- int dirty_tx = lp->dirty_tx & lp->rmask;
+ int entry;
+ s32 status;
+ u_long ioaddr = dev->base_addr;
- if (depca_debug > 5)
- printk("%s: Cleaning tx ring, dirty %d clean %d.\n",
- dev->name, dirty_tx, (lp->cur_tx & lp->rmask));
-
- /*
- ** While the dirty entry is not the current one AND
- ** the LANCE doesn't own it...
- */
- for (; dirty_tx!=(lp->cur_tx & lp->rmask) && lp->tx_ring[dirty_tx].base>0;
- dirty_tx = ++lp->dirty_tx & lp->rmask) {
- unsigned long *tmdp = (unsigned long *)(&lp->tx_ring[dirty_tx]);
- int status = lp->tx_ring[dirty_tx].base >> 16;
+ for (entry = lp->tx_old; entry != lp->tx_new; entry = lp->tx_old) {
+ status = readl(&lp->tx_ring[entry].base) >> 16 ;
if (status < 0) { /* Packet not yet sent! */
- printk("interrupt for packet not yet sent!\n");
break;
- }
- if (status & T_ERR) { /* There was an major error, log it. */
- int err_status = lp->tx_ring[dirty_tx].misc;
-
+ } else if (status & T_ERR) { /* An error occured. */
+ status = readl(&lp->tx_ring[entry].misc);
lp->stats.tx_errors++;
- if (err_status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
- if (err_status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
- if (err_status & TMD3_LCOL) lp->stats.tx_window_errors++;
- if (err_status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
- /* We should re-init() after the FIFO error. */
+ if (status & TMD3_RTRY) lp->stats.tx_aborted_errors++;
+ if (status & TMD3_LCAR) lp->stats.tx_carrier_errors++;
+ if (status & TMD3_LCOL) lp->stats.tx_window_errors++;
+ if (status & TMD3_UFLO) lp->stats.tx_fifo_errors++;
+ if (status & (TMD3_BUFF | TMD3_UFLO)) {
+ /* Trigger an immediate send demand. */
+ outw(CSR0, DEPCA_ADDR);
+ outw(INEA | TDMD, DEPCA_DATA);
+ }
} else if (status & (T_MORE | T_ONE)) {
lp->stats.collisions++;
} else {
lp->stats.tx_packets++;
}
- if (depca_debug > 5)
- printk("%s: Tx done entry %d, %4.4lx %4.4lx %4.4lx %4.4lx.\n",
- dev->name, dirty_tx,
- tmdp[0], tmdp[1], tmdp[2], tmdp[3]);
+ /* Update all the pointers */
+ lp->tx_old = (++lp->tx_old) & lp->txRingMask;
}
- /*mark_bh(INET_BH);*/
+
return 0;
}
depca_close(struct device *dev)
{
struct depca_private *lp = (struct depca_private *)dev->priv;
- int nicsr, ioaddr = dev->base_addr;
+ s16 nicsr;
+ u_long ioaddr = dev->base_addr;
dev->start = 0;
dev->tbusy = 1;
/*
** Give back the ROM in case the user wants to go to DOS
*/
- if (strstr(lp->devname,"DEPCA") == NULL) {
+ if (lp->adapter != DEPCA) {
nicsr = inb(DEPCA_NICSR);
nicsr &= ~SHE;
outb(nicsr, DEPCA_NICSR);
}
+ /*
+ ** Free the associated irq
+ */
free_irq(dev->irq);
-
- irq2dev_map[dev->irq] = 0;
+ irq2dev_map[dev->irq] = NULL;
MOD_DEC_USE_COUNT;
static void LoadCSRs(struct device *dev)
{
struct depca_private *lp = (struct depca_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ u_long ioaddr = dev->base_addr;
outw(CSR1, DEPCA_ADDR); /* initialisation block address LSW */
- outw((unsigned short)((unsigned long)(&lp->init_block) & LA_MASK),
- DEPCA_DATA);
+ outw((u16)(lp->sh_mem & LA_MASK), DEPCA_DATA);
outw(CSR2, DEPCA_ADDR); /* initialisation block address MSW */
- outw((unsigned short)(((unsigned long)(&lp->init_block) & LA_MASK) >> 16),
- DEPCA_DATA);
+ outw((u16)((lp->sh_mem & LA_MASK) >> 16), DEPCA_DATA);
outw(CSR3, DEPCA_ADDR); /* ALE control */
outw(ACON, DEPCA_DATA);
- outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
+
+ outw(CSR0, DEPCA_ADDR); /* Point back to CSR0 */
+
+ return;
}
static int InitRestartDepca(struct device *dev)
{
struct depca_private *lp = (struct depca_private *)dev->priv;
- int ioaddr = dev->base_addr;
+ u_long ioaddr = dev->base_addr;
int i, status=0;
+ /* Copy the shadow init_block to shared memory */
+ memcpy_toio((char *)lp->sh_mem, &lp->init_block, sizeof(struct depca_init));
+
outw(CSR0, DEPCA_ADDR); /* point back to CSR0 */
outw(INIT, DEPCA_DATA); /* initialize DEPCA */
/* clear IDON by writing a "1", enable interrupts and start lance */
outw(IDON | INEA | STRT, DEPCA_DATA);
if (depca_debug > 2) {
- printk("%s: DEPCA open after %d ticks, init block %#lx csr0 %4.4x.\n",
- dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
+ printk("%s: DEPCA open after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
+ dev->name, i, lp->sh_mem, inw(DEPCA_DATA));
}
} else {
+ printk("%s: DEPCA unopen after %d ticks, init block 0x%08lx csr0 %4.4x.\n",
+ dev->name, i, lp->sh_mem, inw(DEPCA_DATA));
status = -1;
- printk("%s: DEPCA unopened after %d ticks, init block %#lx csr0 %4.4x.\n",
- dev->name, i, (long) &lp->init_block, inw(DEPCA_DATA));
}
return status;
return &lp->stats;
}
-#ifdef HAVE_MULTICAST
/*
** Set or clear the multicast filter for this adaptor.
** num_addrs == -1 Promiscuous mode, receive all packets
** num_addrs > 0 Multicast mode, receive normal and MC packets, and do
** best-effort filtering.
*/
-#define hash_filter lp->init_block.filter
-
static void
set_multicast_list(struct device *dev, int num_addrs, void *addrs)
{
- short ioaddr = dev->base_addr;
struct depca_private *lp = (struct depca_private *)dev->priv;
+ u_long ioaddr = dev->base_addr;
if (irq2dev_map[dev->irq] != NULL) {
+ while(dev->tbusy); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
+
STOP_DEPCA; /* Temporarily stop the depca. */
depca_init_ring(dev); /* Initialize the descriptor rings */
if (num_addrs >= 0) {
- SetMulticastFilter(num_addrs, (char *)addrs, (char *)hash_filter);
+ SetMulticastFilter(dev, num_addrs, (char *)addrs);
lp->init_block.mode &= ~PROM; /* Unset promiscuous mode */
} else {
lp->init_block.mode |= PROM; /* Set promiscuous mode */
LoadCSRs(dev); /* Reload CSR3 */
InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
}
}
/*
** Calculate the hash code and update the logical address filter
** from a list of ethernet multicast addresses.
-** Derived from a 'C' program in the AMD data book:
-** "Am79C90 CMOS Local Area Network Controller for Ethernet (C-LANCE)",
-** Pub #17781, Rev. A, May 1993
+** Big endian crc one liner is mine, all mine, ha ha ha ha!
+** LANCE calculates its hash codes big endian.
*/
-static void SetMulticastFilter(int num_addrs, char *addrs, char *multicast_table)
+static void SetMulticastFilter(struct device *dev, int num_addrs, char *addrs)
{
- char j, ctrl, bit, octet, hashcode;
- short int i;
- long int CRC, poly = (long int) CRC_POLYNOMIAL;
-
- for (i=0;i<num_addrs;i++) { /* for each address in the list */
- if (((char) *(addrs+ETH_ALEN*i) & 0x01) == 1) {/* is multicast address? */
- CRC = (long int) 0xffffffff; /* init CRC for each address */
- for (octet=0;octet<ETH_ALEN;octet++) { /* for each address octet */
- for(j=0;j<8;j++) { /* process each address bit */
- bit = (((char)* (addrs+ETH_ALEN*i+octet)) >> j) & 0x01;
- ctrl = ((CRC < 0) ? 1 : 0); /* shift the control bit */
- CRC <<= 1; /* shift the CRC */
- if (bit ^ ctrl) { /* (bit) XOR (control bit) */
- CRC ^= poly; /* (CRC) XOR (polynomial) */
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int i, j, bit, byte;
+ u16 hashcode;
+ s32 crc, poly = CRC_POLYNOMIAL_BE;
+
+ if (num_addrs == HASH_TABLE_LEN) { /* Set all multicast bits */
+ for (i=0; i<(HASH_TABLE_LEN>>3); i++) {
+ lp->init_block.mcast_table[i] = (char)0xff;
+ }
+ } else {
+ /* Clear the multicast table first */
+ for (i=0; i<(HASH_TABLE_LEN>>3); i++){
+ lp->init_block.mcast_table[i]=0;
+ }
+
+ /* Add multicast addresses */
+ for (i=0;i<num_addrs;i++) { /* for each address in the list */
+ if ((*addrs & 0x01) == 1) { /* multicast address? */
+ crc = 0xffffffff; /* init CRC for each address */
+ for (byte=0;byte<ETH_ALEN;byte++) {/* for each address byte */
+ /* process each address bit */
+ for (bit = *addrs++,j=0;j<8;j++, bit>>=1) {
+ crc = (crc << 1) ^ ((((crc<0?1:0) ^ bit) & 0x01) ? poly : 0);
}
}
+ hashcode = (crc & 1); /* hashcode is 6 LSb of CRC ... */
+ for (j=0;j<5;j++) { /* ... in reverse order. */
+ hashcode = (hashcode << 1) | ((crc>>=1) & 1);
+ }
+
+
+ byte = hashcode >> 3; /* bit[3-5] -> byte in filter */
+ bit = 1 << (hashcode & 0x07); /* bit[0-2] -> bit in byte */
+ lp->init_block.mcast_table[byte] |= bit;
+ } else { /* skip this address */
+ addrs += ETH_ALEN;
}
- hashcode = (CRC & 0x00000001); /* hashcode is 6 LSb of CRC ... */
- for (j=0;j<5;j++) { /* ... in reverse order. */
- hashcode <<= 1;
- CRC >>= 1;
- hashcode |= (CRC & 0x00000001);
- }
- octet = hashcode >> 3; /* bit[3-5] -> octet in filter */
- /* bit[0-2] -> bit in octet */
- multicast_table[octet] |= (1 << (hashcode & 0x07));
}
}
+
return;
}
-#endif /* HAVE_MULTICAST */
-
-#ifndef MODULE
/*
** ISA bus I/O device probe
*/
-static struct device *isa_probe(struct device *dev)
+static void isa_probe(struct device *dev, u_long ioaddr)
{
- int *port, ports[] = DEPCA_IO_PORTS;
- int status;
-
- for (status = -ENODEV, port = &ports[0];
- *port && (num_depcas < MAX_NUM_DEPCAS); port++) {
- int ioaddr = *port;
+ int i = num_depcas, maxSlots;
+ s32 ports[] = DEPCA_IO_PORTS;
+
+ if (!ioaddr && autoprobed) return ; /* Been here before ! */
+ if (ioaddr > 0x400) return; /* EISA Address */
+ if (i >= MAX_NUM_DEPCAS) return; /* Too many ISA adapters */
+
+ if (ioaddr == 0) { /* Autoprobing */
+ maxSlots = MAX_NUM_DEPCAS;
+ } else { /* Probe a specific location */
+ ports[i] = ioaddr;
+ maxSlots = i + 1;
+ }
- if (DevicePresent(ioaddr) == 0) {
- if (num_depcas > 0) { /* only gets here in autoprobe */
- dev = alloc_device(dev, ioaddr);
- } else {
- if ((status = depca_probe1(dev, ioaddr)) == 0) {
- num_depcas++;
+ for (; (i<maxSlots) && (dev!=NULL) && ports[i]; i++) {
+ if (DevicePresent(ports[i]) == 0) {
+ if (check_region(ports[i], DEPCA_TOTAL_SIZE) == 0) {
+ if ((dev = alloc_device(dev, ports[i])) != NULL) {
+ if (depca_hw_init(dev, ports[i]) == 0) {
+ num_depcas++;
+ }
+ num_eth++;
}
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04x.\n", dev->name,ports[i]);
}
- num_eth++;
}
}
- return dev;
+
+ return;
}
/*
** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually
-** the motherboard.
+** the motherboard. Upto 15 EISA devices are supported.
*/
-static struct device *eisa_probe(struct device *dev)
+static void eisa_probe(struct device *dev, u_long ioaddr)
{
- int i, ioaddr = DEPCA_EISA_IO_PORTS;
- int status;
-
- ioaddr+=0x1000; /* get the first slot address */
- for (status = -ENODEV, i=1; i<MAX_EISA_SLOTS; i++, ioaddr+=0x1000) {
-
- if (EISA_signature(DEPCA_EISA_ID) == 0) {
- if (num_depcas > 0) { /* only gets here in autoprobe */
- dev = alloc_device(dev, ioaddr);
- } else {
- if ((status = depca_probe1(dev, ioaddr)) == 0) {
- num_depcas++;
+ int i, maxSlots;
+ u_long iobase;
+ char name[DEPCA_STRLEN];
+
+ if (!ioaddr && autoprobed) return ; /* Been here before ! */
+ if ((ioaddr < 0x400) && (ioaddr > 0)) return; /* ISA Address */
+
+ if (ioaddr == 0) { /* Autoprobing */
+ iobase = EISA_SLOT_INC; /* Get the first slot address */
+ i = 1;
+ maxSlots = MAX_EISA_SLOTS;
+ } else { /* Probe a specific location */
+ iobase = ioaddr;
+ i = (ioaddr >> 12);
+ maxSlots = i + 1;
+ }
+ if ((iobase & 0x0fff) == 0) iobase += DEPCA_EISA_IO_PORTS;
+
+ for (; (i<maxSlots) && (dev!=NULL); i++, iobase+=EISA_SLOT_INC) {
+ if (EISA_signature(name, EISA_ID)) {
+ if (DevicePresent(iobase) == 0) {
+ if (check_region(iobase, DEPCA_TOTAL_SIZE) == 0) {
+ if ((dev = alloc_device(dev, iobase)) != NULL) {
+ if (depca_hw_init(dev, iobase) == 0) {
+ num_depcas++;
+ }
+ num_eth++;
+ }
+ } else if (autoprobed) {
+ printk("%s: region already allocated at 0x%04lx.\n",dev->name,iobase);
}
}
- num_eth++;
}
}
- return dev;
+
+ return;
}
/*
** Allocate the device by pointing to the next available space in the
** device structure. Should one not be available, it is created.
*/
-static struct device *alloc_device(struct device *dev, int ioaddr)
+static struct device *alloc_device(struct device *dev, u_long iobase)
{
+ int addAutoProbe = 0;
+ struct device *tmp = NULL, *ret;
+ int (*init)(struct device *) = NULL;
+
/*
** Check the device structures for an end of list or unused device
*/
- while (dev->next != NULL) {
- if (dev->next->base_addr == 0xffe0) break;
- dev = dev->next; /* walk through eth device list */
- num_eth++; /* increment eth device number */
- }
+ if (!loading_module) {
+ while (dev->next != NULL) {
+ if ((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0)) break;
+ dev = dev->next; /* walk through eth device list */
+ num_eth++; /* increment eth device number */
+ }
- /*
- ** If no more device structures, malloc one up. If memory could
- ** not be allocated, print an error message.
- */
- if (dev->next == NULL) {
- dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
- GFP_KERNEL);
- if (dev->next == NULL) {
- printk("eth%d: Device not initialised, insufficient memory\n",
- num_eth);
+ /*
+ ** If an autoprobe is requested for another device, we must re-insert
+ ** the request later in the list. Remember the current information.
+ */
+ if ((dev->base_addr == 0) && (num_depcas > 0)) {
+ addAutoProbe++;
+ tmp = dev->next; /* point to the next device */
+ init = dev->init; /* remember the probe function */
}
- }
+
+ /*
+ ** If at end of list and can't use current entry, malloc one up.
+ ** If memory could not be allocated, print an error message.
+ */
+ if ((dev->next == NULL) &&
+ !((dev->base_addr == DEPCA_NDA) || (dev->base_addr == 0))){
+ dev->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+ GFP_KERNEL);
+
+ dev = dev->next; /* point to the new device */
+ if (dev == NULL) {
+ printk("eth%d: Device not initialised, insufficient memory\n",
+ num_eth);
+ } else {
+ /*
+ ** If the memory was allocated, point to the new memory area
+ ** and initialize it (name, I/O address, next device (NULL) and
+ ** initialisation probe routine).
+ */
+ dev->name = (char *)(dev + sizeof(struct device));
+ if (num_eth > 9999) {
+ sprintf(dev->name,"eth????"); /* New device name */
+ } else {
+ sprintf(dev->name,"eth%d", num_eth);/* New device name */
+ }
+ dev->base_addr = iobase; /* assign the io address */
+ dev->next = NULL; /* mark the end of list */
+ dev->init = &depca_probe; /* initialisation routine */
+ num_depcas++;
+ }
+ }
+ ret = dev; /* return current struct, or NULL */
- /*
- ** If the memory was allocated, point to the new memory area
- ** and initialize it (name, I/O address, next device (NULL) and
- ** initialisation probe routine).
- */
- if ((dev->next != NULL) &&
- (num_eth > 0) && (num_eth < 9999)) {
- dev = dev->next; /* point to the new device */
- dev->name = (char *)(dev + 1);
- sprintf(dev->name,"eth%d", num_eth);/* New device name */
- dev->base_addr = ioaddr; /* assign the io address */
- dev->next = NULL; /* mark the end of list */
- dev->init = &depca_probe; /* initialisation routine */
- num_depcas++;
+ /*
+ ** Now figure out what to do with the autoprobe that has to be inserted.
+ ** Firstly, search the (possibly altered) list for an empty space.
+ */
+ if (ret != NULL) {
+ if (addAutoProbe) {
+ for (;(tmp->next!=NULL) && (tmp->base_addr!=DEPCA_NDA); tmp=tmp->next);
+
+ /*
+ ** If no more device structures and can't use the current one, malloc
+ ** one up. If memory could not be allocated, print an error message.
+ */
+ if ((tmp->next == NULL) && !(tmp->base_addr == DEPCA_NDA)) {
+ tmp->next = (struct device *)kmalloc(sizeof(struct device) + 8,
+ GFP_KERNEL);
+ tmp = tmp->next; /* point to the new device */
+ if (tmp == NULL) {
+ printk("%s: Insufficient memory to extend the device list.\n",
+ dev->name);
+ } else {
+ /*
+ ** If the memory was allocated, point to the new memory area
+ ** and initialize it (name, I/O address, next device (NULL) and
+ ** initialisation probe routine).
+ */
+ tmp->name = (char *)(tmp + sizeof(struct device));
+ if (num_eth > 9999) {
+ sprintf(tmp->name,"eth????"); /* New device name */
+ } else {
+ sprintf(tmp->name,"eth%d", num_eth);/* New device name */
+ }
+ tmp->base_addr = 0; /* re-insert the io address */
+ tmp->next = NULL; /* mark the end of list */
+ tmp->init = init; /* initialisation routine */
+ }
+ } else { /* structure already exists */
+ tmp->base_addr = 0; /* re-insert the io address */
+ }
+ }
+ }
+ } else {
+ ret = dev;
}
- return dev;
+ return ret;
}
-#endif /* MODULE */
/*
** Look for a particular board name in the on-board Remote Diagnostics
-** and Boot (RDB) ROM. This will also give us a clue to the network RAM
+** and Boot (readb) ROM. This will also give us a clue to the network RAM
** base address.
*/
-static char *DepcaSignature(unsigned long mem_addr)
+static void DepcaSignature(char *name, u_long paddr)
{
- unsigned long i,j,k;
- static char signatures[][DEPCA_NAME_LENGTH] = DEPCA_SIGNATURE;
- static char thisName[DEPCA_NAME_LENGTH];
- char tmpstr[17];
+ u_int i,j,k;
+ char *signatures[] = DEPCA_SIGNATURE;
+ char tmpstr[16];
for (i=0;i<16;i++) { /* copy the first 16 bytes of ROM to */
- tmpstr[i] = *(unsigned char *)(mem_addr+0xc000+i); /* a temporary string */
+ tmpstr[i] = readb(paddr+0xc000+i); /* a temporary string */
}
- tmpstr[i]='\0';
- strcpy(thisName,"");
- for (i=0;*signatures[i]!='\0' && *thisName=='\0';i++) {
+ strcpy(name,"");
+ for (i=0;*signatures[i]!='\0' && *name=='\0';i++) {
for (j=0,k=0;j<16 && k<strlen(signatures[i]);j++) {
if (signatures[i][k] == tmpstr[j]) { /* track signature */
k++;
}
}
if (k == strlen(signatures[i])) {
- strcpy(thisName,signatures[i]);
+ strcpy(name,signatures[i]);
}
}
- return thisName; /* return the device name string */
+ adapter = i - 1;
+
+ return;
}
/*
** PROM address counter is correctly positioned at the start of the
** ethernet address for later read out.
*/
-static int DevicePresent(short ioaddr)
+static int DevicePresent(u_long ioaddr)
{
union {
struct {
- u_long a;
- u_long b;
+ u32 a;
+ u32 b;
} llsig;
- char Sig[sizeof(long) << 1];
+ char Sig[sizeof(u32) << 1];
} dev;
short sigLength=0;
- char data;
- int i, j, nicsr, status = 0;
+ s8 data;
+ s16 nicsr;
+ int i, j, status = 0;
data = inb(DEPCA_PROM); /* clear counter on DEPCA */
data = inb(DEPCA_PROM); /* read data */
dev.llsig.a = ETH_PROM_SIG;
dev.llsig.b = ETH_PROM_SIG;
- sigLength = sizeof(long) << 1;
+ sigLength = sizeof(u32) << 1;
for (i=0,j=0;j<sigLength && i<PROBE_LENGTH+sigLength-1;i++) {
data = inb(DEPCA_PROM);
if (dev.Sig[j] == data) { /* track signature */
j++;
- } else { /* lost signature; begin search again */
+ } else { /* lost signature; begin search again */
if (data == dev.Sig[0]) { /* rare case.... */
j=1;
} else {
return status;
}
+/*
+** The DE100 and DE101 PROM accesses were made non-standard for some bizarre
+** reason: access the upper half of the PROM with x=0; access the lower half
+** with x=1.
+*/
+static int get_hw_addr(struct device *dev)
+{
+ u_long ioaddr = dev->base_addr;
+ int i, k, tmp, status = 0;
+ u_short j, x, chksum;
+
+ x = (((adapter == de100) || (adapter == de101)) ? 1 : 0);
+
+ for (i=0,k=0,j=0;j<3;j++) {
+ k <<= 1 ;
+ if (k > 0xffff) k-=0xffff;
+
+ k += (u_char) (tmp = inb(DEPCA_PROM + x));
+ dev->dev_addr[i++] = (u_char) tmp;
+ k += (u_short) ((tmp = inb(DEPCA_PROM + x)) << 8);
+ dev->dev_addr[i++] = (u_char) tmp;
+
+ if (k > 0xffff) k-=0xffff;
+ }
+ if (k == 0xffff) k=0;
+
+ chksum = (u_char) inb(DEPCA_PROM + x);
+ chksum |= (u_short) (inb(DEPCA_PROM + x) << 8);
+ if (k != chksum) status = -1;
+
+ return status;
+}
+
+/*
+** Load a packet into the shared memory
+*/
+static int load_packet(struct device *dev, struct sk_buff *skb)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ int i, entry, end, len, status = 0;
+
+ entry = lp->tx_new; /* Ring around buffer number. */
+ end = (entry + (skb->len - 1) / TX_BUFF_SZ) & lp->txRingMask;
+ if (!(readl(&lp->tx_ring[end].base) & T_OWN)) {/* Enough room? */
+ /*
+ ** Caution: the write order is important here... don't set up the
+ ** ownership rights until all the other information is in place.
+ */
+ if (end < entry) { /* wrapped buffer */
+ len = (lp->txRingMask - entry + 1) * TX_BUFF_SZ;
+ memcpy_toio(lp->tx_memcpy[entry], skb->data, len);
+ memcpy_toio(lp->tx_memcpy[0], skb->data + len, skb->len - len);
+ } else { /* linear buffer */
+ memcpy_toio(lp->tx_memcpy[entry], skb->data, skb->len);
+ }
+
+ /* set up the buffer descriptors */
+ len = (skb->len < ETH_ZLEN) ? ETH_ZLEN : skb->len;
+ for (i = entry; i != end; i = (++i) & lp->txRingMask) {
+ /* clean out flags */
+ writel(readl(&lp->tx_ring[i].base) & ~T_FLAGS, &lp->tx_ring[i].base);
+ writew(0x0000, &lp->tx_ring[i].misc); /* clears other error flags */
+ writew(-TX_BUFF_SZ, &lp->tx_ring[i].length);/* packet length in buffer */
+ len -= TX_BUFF_SZ;
+ }
+ /* clean out flags */
+ writel(readl(&lp->tx_ring[end].base) & ~T_FLAGS, &lp->tx_ring[end].base);
+ writew(0x0000, &lp->tx_ring[end].misc); /* clears other error flags */
+ writew(-len, &lp->tx_ring[end].length); /* packet length in last buff */
+
+ /* start of packet */
+ writel(readl(&lp->tx_ring[entry].base) | T_STP, &lp->tx_ring[entry].base);
+ /* end of packet */
+ writel(readl(&lp->tx_ring[end].base) | T_ENP, &lp->tx_ring[end].base);
+
+ for (i=end; i!=entry; --i) {
+ /* ownership of packet */
+ writel(readl(&lp->tx_ring[i].base) | T_OWN, &lp->tx_ring[i].base);
+ if (i == 0) i=lp->txRingMask+1;
+ }
+ writel(readl(&lp->tx_ring[entry].base) | T_OWN, &lp->tx_ring[entry].base);
+
+ lp->tx_new = (++end) & lp->txRingMask; /* update current pointers */
+ } else {
+ status = -1;
+ }
+
+ return status;
+}
+
/*
** Look for a particular board name in the EISA configuration space
*/
-static int EISA_signature(short iobase)
+static int EISA_signature(char *name, s32 eisa_id)
{
- unsigned long i;
- int status;
+ u_int i;
char *signatures[] = DEPCA_SIGNATURE;
- char ManCode[8];
+ char ManCode[DEPCA_STRLEN];
union {
- u_long ID;
- u_char Id[4];
+ s32 ID;
+ char Id[4];
} Eisa;
+ int status = 0;
- for (i=0; i<4; i++) {
- Eisa.Id[i] = inb(iobase + i);
- }
+ *name = '\0';
+ Eisa.ID = inl(eisa_id);
ManCode[0]=(((Eisa.Id[0]>>2)&0x1f)+0x40);
ManCode[1]=(((Eisa.Id[1]&0xe0)>>5)+((Eisa.Id[0]&0x03)<<3)+0x40);
ManCode[4]=(((Eisa.Id[3]>>4)&0x0f)+0x30);
ManCode[5]='\0';
- for (status = -ENXIO, i=0;*signatures[i] != '\0' && status;i++) {
+ for (i=0;(*signatures[i] != '\0') && (*name == '\0');i++) {
if (strstr(ManCode, signatures[i]) != NULL) {
- status = 0;
+ strcpy(name,ManCode);
+ status = 1;
}
}
-
- return status; /* return the device name string */
+
+ return status;
+}
+
+/*
+** Perform IOCTL call functions here. Some are privileged operations and the
+** effective uid is checked in those cases.
+*/
+static int depca_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+{
+ struct depca_private *lp = (struct depca_private *)dev->priv;
+ struct depca_ioctl *ioc = (struct depca_ioctl *) &rq->ifr_data;
+ int i, status = 0;
+ u_long ioaddr = dev->base_addr;
+ union {
+ u8 addr[(HASH_TABLE_LEN * ETH_ALEN)];
+ u16 sval[(HASH_TABLE_LEN * ETH_ALEN) >> 1];
+ u32 lval[(HASH_TABLE_LEN * ETH_ALEN) >> 2];
+ } tmp;
+
+ switch(ioc->cmd) {
+ case DEPCA_GET_HWADDR: /* Get the hardware address */
+ for (i=0; i<ETH_ALEN; i++) {
+ tmp.addr[i] = dev->dev_addr[i];
+ }
+ ioc->len = ETH_ALEN;
+ if (!(status = verify_area(VERIFY_WRITE, (void *)ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+ }
+
+ break;
+ case DEPCA_SET_HWADDR: /* Set the hardware address */
+ if (suser()) {
+ if (!(status = verify_area(VERIFY_READ, (void *)ioc->data, ETH_ALEN))) {
+ memcpy_fromfs(tmp.addr,ioc->data,ETH_ALEN);
+ for (i=0; i<ETH_ALEN; i++) {
+ dev->dev_addr[i] = tmp.addr[i];
+ }
+ while(dev->tbusy); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new);/* Wait for the ring to empty */
+
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
+ }
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_SET_PROM: /* Set Promiscuous Mode */
+ if (suser()) {
+ while(dev->tbusy); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
+
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ lp->init_block.mode |= PROM; /* Set promiscuous mode */
+
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_CLR_PROM: /* Clear Promiscuous Mode */
+ if (suser()) {
+ while(dev->tbusy); /* Stop ring access */
+ set_bit(0, (void*)&dev->tbusy);
+ while(lp->tx_old != lp->tx_new); /* Wait for the ring to empty */
+
+ STOP_DEPCA; /* Temporarily stop the depca. */
+ depca_init_ring(dev); /* Initialize the descriptor rings */
+ lp->init_block.mode &= ~PROM; /* Clear promiscuous mode */
+
+ LoadCSRs(dev); /* Reload CSR3 */
+ InitRestartDepca(dev); /* Resume normal operation. */
+ dev->tbusy = 0; /* Unlock the TX ring */
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_SAY_BOO: /* Say "Boo!" to the kernel log file */
+ printk("%s: Boo!\n", dev->name);
+
+ break;
+ case DEPCA_GET_MCA: /* Get the multicast address table */
+ ioc->len = (HASH_TABLE_LEN >> 3);
+ if (!(status = verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, lp->init_block.mcast_table, ioc->len);
+ }
+
+ break;
+ case DEPCA_SET_MCA: /* Set a multicast address */
+ if (suser()) {
+ if (ioc->len != HASH_TABLE_LEN) { /* MCA changes */
+ if (!(status=verify_area(VERIFY_READ, ioc->data, ETH_ALEN*ioc->len))) {
+ memcpy_fromfs(tmp.addr, ioc->data, ETH_ALEN * ioc->len);
+ set_multicast_list(dev, ioc->len, tmp.addr);
+ }
+ } else {
+ set_multicast_list(dev, ioc->len, NULL);
+ }
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_CLR_MCA: /* Clear all multicast addresses */
+ if (suser()) {
+ set_multicast_list(dev, 0, NULL);
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_MCA_EN: /* Enable pass all multicast addressing */
+ if (suser()) {
+ set_multicast_list(dev, HASH_TABLE_LEN, NULL);
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_GET_STATS: /* Get the driver statistics */
+ cli();
+ ioc->len = sizeof(lp->pktStats);
+ if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, &lp->pktStats, ioc->len);
+ }
+ sti();
+
+ break;
+ case DEPCA_CLR_STATS: /* Zero out the driver statistics */
+ if (suser()) {
+ cli();
+ memset(&lp->pktStats, 0, sizeof(lp->pktStats));
+ sti();
+ } else {
+ status = -EPERM;
+ }
+
+ break;
+ case DEPCA_GET_REG: /* Get the DEPCA Registers */
+ i=0;
+ tmp.sval[i++] = inw(DEPCA_NICSR);
+ outw(CSR0, DEPCA_ADDR); /* status register */
+ tmp.sval[i++] = inw(DEPCA_DATA);
+ memcpy(&tmp.sval[i], &lp->init_block, sizeof(struct depca_init));
+ ioc->len = i+sizeof(struct depca_init);
+ if (!(status=verify_area(VERIFY_WRITE, ioc->data, ioc->len))) {
+ memcpy_tofs(ioc->data, tmp.addr, ioc->len);
+ }
+
+ break;
+ default:
+ status = -EOPNOTSUPP;
+ }
+
+ return status;
}
#ifdef MODULE
0x200, 7, /* I/O address, IRQ */
0, 0, 0, NULL, depca_probe };
-/*
- * This is a tweak to keep the insmod program happy. It can only
- * set int values with var=value so we split these out.
- */
-
-int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */
-int io=0x200; /* Or use the irq= io= options to insmod */
+static int irq=7; /* EDIT THESE LINE FOR YOUR CONFIGURATION */
+static int io=0x200; /* Or use the irq= io= options to insmod */
int
init_module(void)
thisDepca.base_addr=io;
if (register_netdev(&thisDepca) != 0)
return -EIO;
+
return 0;
}
printk("%s: device busy, remove delayed\n",thisDepca.name);
} else {
release_region(thisDepca.base_addr, DEPCA_TOTAL_SIZE);
+ if (thisDepca.priv) {
+ kfree_s(thisDepca.priv, sizeof(struct depca_private));
+ thisDepca.priv = NULL;
+ }
+
unregister_netdev(&thisDepca);
}
}
#define STOP 0x0004 /* Stop */
#define STRT 0x0002 /* Start */
#define INIT 0x0001 /* Initialize */
+#define INTM 0xff00 /* Interrupt Mask */
+#define INTE 0xfff0 /* Interrupt Enable */
/*
** CONTROL AND STATUS REGISTER 3 (CSR3)
#define T_DEF 0x0400 /* Deferred */
#define T_STP 0x02000000 /* Start of Packet */
#define T_ENP 0x01000000 /* End of Packet */
+#define T_FLAGS 0xff000000 /* TX Flags Field */
/*
** Transmit Message Descriptor 3 (TMD3) bit definitions.
/*
** Miscellaneous
*/
+#define HASH_TABLE_LEN 64 /* Bits */
+#define HASH_BITS 0x003f /* 6 LS bits */
#define MASK_INTERRUPTS 1
#define UNMASK_INTERRUPTS 0
-#define EISA_EN 0x0001 /* Enable EISA bus buffers */
-#define DEPCA_EISA_ID ioaddr+0x80 /* ID long word for EISA card */
-#define DEPCA_EISA_CTRL ioaddr+0x84 /* Control word for EISA card */
+#define EISA_EN 0x0001 /* Enable EISA bus buffers */
+#define EISA_ID iobase+0x0080 /* ID long word for EISA card */
+#define EISA_CTRL iobase+0x0084 /* Control word for EISA card */
+
+/*
+** Include the IOCTL stuff
+*/
+#include <linux/sockios.h>
+
+#define DEPCAIOCTL SIOCDEVPRIVATE
+
+struct depca_ioctl {
+ unsigned short cmd; /* Command to run */
+ unsigned short len; /* Length of the data buffer */
+ unsigned char *data; /* Pointer to the data buffer */
+};
+
+/*
+** Recognised commands for the driver
+*/
+#define DEPCA_GET_HWADDR 0x01 /* Get the hardware address */
+#define DEPCA_SET_HWADDR 0x02 /* Get the hardware address */
+#define DEPCA_SET_PROM 0x03 /* Set Promiscuous Mode */
+#define DEPCA_CLR_PROM 0x04 /* Clear Promiscuous Mode */
+#define DEPCA_SAY_BOO 0x05 /* Say "Boo!" to the kernel log file */
+#define DEPCA_GET_MCA 0x06 /* Get a multicast address */
+#define DEPCA_SET_MCA 0x07 /* Set a multicast address */
+#define DEPCA_CLR_MCA 0x08 /* Clear a multicast address */
+#define DEPCA_MCA_EN 0x09 /* Enable a multicast address group */
+#define DEPCA_GET_STATS 0x0a /* Get the driver statistics */
+#define DEPCA_CLR_STATS 0x0b /* Zero out the driver statistics */
+#define DEPCA_GET_REG 0x0c /* Get the Register contents */
+#define DEPCA_SET_REG 0x0d /* Set the Register contents */
+#define DEPCA_DUMP 0x0f /* Dump the DEPCA Status */
+
--- /dev/null
+/*
+ * hp100.c: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
+ *
+ * Author: Jaroslav Kysela, <perex@pf.jcu.cz>
+ *
+ * Supports only the following Hewlett Packard cards:
+ *
+ * HP J2577 10/100 EISA card with REVA Cascade chip
+ * HP J2573 10/100 ISA card with REVA Cascade chip
+ * HP 27248B 10 only EISA card with Cascade chip
+ * HP J2577 10/100 EISA card with Cascade chip
+ * HP J2573 10/100 ISA card with Cascade chip
+ *
+ * Other ATT2MD01 Chip based boards might be supported in the future
+ * (there are some minor changes needed).
+ *
+ * This driver is based on the 'hpfepkt' crynwr packet driver.
+ *
+ * This source/code is public free; you can distribute it and/or modify
+ * it under terms of the GNU General Public License (published by the
+ * Free Software Foundation) either version two of this License, or any
+ * later version.
+ * ----------------------------------------------------------------------------
+ *
+ * Note: Some routines (interrupt handling, transmit) assumes that
+ * there is the PERFORMANCE page selected...
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * If you are going to use the module version of this driver, you may
+ * change this values at the "insert time" :
+ *
+ * Variable Description
+ *
+ * hp100_default_rx_ratio Range 1-99 - onboard memory used for RX
+ * packets in %.
+ * hp100_port Adapter port (for example 0x380).
+ *
+ * ----------------------------------------------------------------------------
+ * MY BEST REGARDS GOING TO:
+ *
+ * IPEX s.r.o which lend me two HP J2573 cards and
+ * the HP AdvanceStack 100VG Hub-15 for debugging.
+ *
+ * Russel Nellson <nelson@crynwr.com> for help with obtaining sources
+ * of the 'hpfepkt' packet driver.
+ *
+ * Also thanks to Abacus Electric s.r.o which let me to use their
+ * motherboard for my second computer.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * TO DO:
+ * ======
+ * - ioctl handling - some runtime setup things
+ * - PCI card support
+ *
+ * Revision history:
+ * =================
+ *
+ * Version Date Description
+ *
+ * 0.1 14-May-95 Initial writing. ALPHA code was released.
+ * Only HP J2573 on 10Mb/s (two machines) tested.
+ * 0.11 14-Jun-95 Reset interface bug fixed?
+ * Little bug in hp100_close function fixed.
+ * 100Mb/s connection debugged.
+ *
+ */
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif /* MODULE */
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/interrupt.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+
+#include <linux/types.h>
+
+#include "hp100.h"
+
+/*
+ * defines
+ */
+
+#define HP100_MAX_PACKET_SIZE (1536+4)
+#define HP100_MIN_PACKET_SIZE 60
+
+#ifndef HP100_RX_RATIO
+/* default - 65% onboard memory on the card are used for RX packets */
+#define HP100_RX_RATIO 65
+#endif
+
+/*
+ * structures
+ */
+
+struct hp100_eisa_id {
+ u_int id;
+ char *name;
+};
+
+struct hp100_private {
+ struct hp100_eisa_id *id;
+ u_short soft_model;
+ u_int memory_size;
+ u_short rx_ratio;
+ short lan_type; /* 10Mb/s, 100Mb/s or -1 (error) */
+ int hub_status; /* login to hub successfull? */
+ u_char mac1_mode;
+ u_char mac2_mode;
+ struct enet_statistics stats;
+};
+
+struct hp100_rx_look {
+ struct hp100_rx_header header;
+ char something[ 24 ]; /* 2 * MAC @6 + protocol @2+8 + pad to 4 byte */
+};
+
+/*
+ * variables
+ */
+
+static struct hp100_eisa_id hp100_eisa_ids[] = {
+ { 0x080F1F022, "HP J2577 rev A" }, /* 10/100 EISA card with REVA Cascade chip */
+ { 0x050F1F022, "HP J2573 rev A" }, /* 10/100 ISA card with REVA Cascade chip */
+ { 0x02019F022, "HP 27248B" }, /* 10 only EISA card with Cascade chip */
+ { 0x04019F022, "HP J2577" }, /* 10/100 EISA card with Cascade chip */
+ { 0x05019F022, "HP J2573" } /* 10/100 ISA card with Cascade chip */
+};
+
+#ifdef MODULE
+int hp100_default_rx_ratio = HP100_RX_RATIO;
+#endif
+
+/*
+ * prototypes
+ */
+
+static int hp100_probe1( struct device *dev, int ioaddr );
+static int hp100_open( struct device *dev );
+static int hp100_close( struct device *dev );
+static int hp100_start_xmit( struct sk_buff *skb, struct device *dev );
+static void hp100_rx( struct device *dev );
+static struct enet_statistics *hp100_get_stats( struct device *dev );
+static void hp100_update_stats( struct device *dev );
+#ifdef HAVE_MULTICAST
+static void hp100_set_multicast_list( struct device *dev, int num_addrs, void *addrs );
+#endif
+#ifndef LINUX_1_1_52
+static void hp100_interrupt( int irq, struct pt_regs *regs );
+#else
+static void hp100_interrupt( int irq );
+#endif
+
+static void hp100_start_interface( struct device *dev );
+static void hp100_stop_interface( struct device *dev );
+static void hp100_load_eeprom( struct device *dev );
+static int hp100_sense_lan( struct device *dev );
+static int hp100_login_to_vg_hub( struct device *dev );
+static int hp100_down_vg_link( struct device *dev );
+
+/*
+ * probe functions
+ */
+
+int hp100_probe( struct device *dev )
+{
+ int base_addr = dev ? dev -> base_addr : 0;
+ int ioaddr;
+
+ if ( base_addr > 0xff ) /* Check a single specified location. */
+ return hp100_probe1(dev, base_addr);
+ else
+ if ( base_addr != 0 ) return -ENXIO;
+
+ /* at first - probe all EISA possible port regions (if EISA bus present) */
+
+ for ( ioaddr = 0x1c38; EISA_bus && ioaddr < 0x10000; ioaddr += 0x400 )
+ {
+ if ( check_region( ioaddr, 0x20 ) ) continue;
+ if ( hp100_probe1( dev, ioaddr ) == 0 ) return 0;
+ }
+
+ /* at second - probe all ISA possible port regions */
+
+ for ( ioaddr = 0x100; ioaddr < 0x400; ioaddr += 0x20 )
+ {
+ if ( check_region( ioaddr, 0x20 ) ) continue;
+ if ( hp100_probe1( dev, ioaddr ) == 0 ) return 0;
+ }
+
+ return -ENODEV;
+}
+
+static int hp100_probe1( struct device *dev, int ioaddr )
+{
+ int i;
+ u_char uc;
+ u_int eisa_id;
+ struct hp100_private *lp;
+ struct hp100_eisa_id *eid;
+
+ if ( dev == NULL )
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100_probe1: dev == NULL ?\n" );
+#endif
+ return EIO;
+ }
+
+ if ( inb( ioaddr + 0 ) != HP100_HW_ID_0 ||
+ inb( ioaddr + 1 ) != HP100_HW_ID_1 ||
+ ( inb( ioaddr + 2 ) & 0xf0 ) != HP100_HW_ID_2_REVA ||
+ inb( ioaddr + 3 ) != HP100_HW_ID_3 )
+ return -ENODEV;
+
+ dev -> base_addr = ioaddr;
+
+#ifdef HP100_DEBUG_PROBE1
+ printk( "hp100_probe1: card found at port 0x%x\n", ioaddr );
+#endif
+
+ hp100_page( ID_MAC_ADDR );
+ for ( i = uc = eisa_id = 0; i < 4; i++ )
+ {
+ eisa_id >>= 8;
+ eisa_id |= ( hp100_inb( BOARD_ID + i ) ) << 24;
+ uc += eisa_id >> 24;
+ }
+ uc += hp100_inb( BOARD_ID + 4 );
+
+#ifdef HP100_DEBUG_PROBE1
+ printk( "hp100_probe1: EISA ID = 0x%08x checksum = 0x%02x\n", eisa_id, uc );
+#endif
+
+ if ( uc != 0xff ) /* bad checksum? */
+ {
+ printk( "hp100_probe: bad EISA ID checksum at base port 0x%x\n", ioaddr );
+ return -ENODEV;
+ }
+
+ for ( i = 0; i < sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ); i++ )
+ if ( ( hp100_eisa_ids[ i ].id & 0xf0ffffff ) == ( eisa_id & 0xf0ffffff ) )
+ break;
+ if ( i >= sizeof( hp100_eisa_ids ) / sizeof( struct hp100_eisa_id ) )
+ {
+ printk( "hp100_probe1: card at port 0x%x isn't known\n", ioaddr );
+ return -ENODEV;
+ }
+ eid = &hp100_eisa_ids[ i ];
+ if ( ( eid -> id & 0x0f000000 ) < ( eisa_id & 0x0f000000 ) )
+ {
+ printk( "hp100_probe1: newer version of card %s at port 0x%x - unsupported\n",
+ eid -> name, ioaddr );
+ return -ENODEV;
+ }
+
+ for ( i = uc = 0; i < 7; i++ )
+ uc += hp100_inb( LAN_ADDR + i );
+ if ( uc != 0xff )
+ {
+ printk( "hp100_probe1: bad lan address checksum (card %s at port 0x%x)\n",
+ eid -> name, ioaddr );
+ return -EIO;
+ }
+
+ hp100_page( HW_MAP );
+ if ( hp100_inw( OPTION_LSW ) & ( HP100_MEM_EN | HP100_BM_WRITE | HP100_BM_READ ) )
+ {
+ printk( "hp100_probe1: memory mapped io isn't supported (card %s at port 0x%x)\n",
+ eid -> name, ioaddr );
+ return -EIO;
+ }
+
+ if ( ( dev -> priv = kmalloc( sizeof( struct hp100_private ), GFP_KERNEL ) ) == NULL )
+ return -ENOMEM;
+ memset( dev -> priv, 0, sizeof( struct hp100_private ) );
+
+ lp = (struct hp100_private *)dev -> priv;
+ lp -> id = eid;
+ hp100_page( ID_MAC_ADDR );
+ lp -> soft_model = hp100_inb( SOFT_MODEL );
+ lp -> mac1_mode = HP100_MAC1MODE3;
+ lp -> mac2_mode = HP100_MAC2MODE3;
+
+ dev -> base_addr = ioaddr;
+ hp100_page( HW_MAP );
+ dev -> irq = hp100_inb( IRQ_CHANNEL ) & HP100_IRQ_MASK;
+ if ( dev -> irq == 2 ) dev -> irq = 9;
+ lp -> memory_size = 0x200 << ( ( hp100_inb( SRAM ) & 0xe0 ) >> 5 );
+#ifndef MODULE
+ lp -> rx_ratio = HP100_RX_RATIO;
+#else
+ lp -> rx_ratio = hp100_default_rx_ratio;
+#endif
+
+ dev -> open = hp100_open;
+ dev -> stop = hp100_close;
+ dev -> hard_start_xmit = hp100_start_xmit;
+ dev -> get_stats = hp100_get_stats;
+#ifdef HAVE_MULTICAST
+ dev -> set_multicast_list = &hp100_set_multicast_list;
+#endif
+
+#ifndef LINUX_1_1_52
+ request_region( dev -> base_addr, 0x20, eid -> name );
+#endif
+
+ hp100_page( ID_MAC_ADDR );
+ for ( i = uc = 0; i < 6; i++ )
+ dev -> dev_addr[ i ] = hp100_inb( LAN_ADDR + i );
+
+ ether_setup( dev );
+
+ lp -> lan_type = hp100_sense_lan( dev );
+
+ printk( "%s: %s at 0x%x, IRQ %d, %dkB SRAM (rx/tx %d%%), ",
+ dev -> name, lp -> id -> name, ioaddr, dev -> irq,
+ lp -> memory_size >> ( 10 - 4 ), lp -> rx_ratio );
+ switch ( lp -> lan_type ) {
+ case HP100_LAN_100: printk( "100Mb/s VG TP" ); break;
+ case HP100_LAN_10: printk( "10Mb/s TP" ); break;
+ default: printk( "link down" ); break;
+ }
+ printk( ".\n" );
+
+ return 0;
+}
+
+/*
+ * open/close functions
+ */
+
+static int hp100_open( struct device *dev )
+{
+ int i;
+ int ioaddr = dev -> base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+ if ( ( lp -> lan_type = hp100_sense_lan( dev ) ) < 0 )
+ {
+ printk( "%s: no connection found - check wire\n", dev -> name );
+ return -EIO;
+ }
+
+ if ( request_irq( dev -> irq, hp100_interrupt, SA_INTERRUPT, lp -> id -> name ) )
+ {
+ printk( "%s: unable to get IRQ %d\n", dev -> name, dev -> irq );
+ return -EAGAIN;
+ }
+ irq2dev_map[ dev -> irq ] = dev;
+
+#ifdef MODULE
+ MOD_INC_USE_COUNT;
+#endif
+
+ dev -> tbusy = 0;
+ dev -> trans_start = jiffies;
+ dev -> interrupt = 0;
+ dev -> start = 1;
+
+ lp -> mac1_mode = HP100_MAC1MODE3;
+ lp -> mac2_mode = HP100_MAC2MODE3;
+
+ hp100_page( MAC_CTRL );
+ hp100_orw( HP100_LINK_BEAT_DIS, LAN_CFG_10 );
+
+ hp100_stop_interface( dev );
+ hp100_reset_card();
+ hp100_load_eeprom( dev );
+
+ hp100_outw( HP100_MMAP_DIS | HP100_SET_HB |
+ HP100_IO_EN | HP100_SET_LB, OPTION_LSW );
+ hp100_outw( HP100_DEBUG_EN | HP100_RX_HDR | HP100_EE_EN | HP100_RESET_HB |
+ HP100_FAKE_INT | HP100_RESET_LB, OPTION_LSW );
+#if 0
+ hp100_outw( HP100_PRIORITY_TX | HP100_ADV_NXT_PKT |
+ HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
+#else
+ hp100_outw( HP100_ADV_NXT_PKT | HP100_TX_CMD | HP100_RESET_LB, OPTION_MSW );
+#endif
+
+ hp100_page( MAC_ADDRESS );
+ for ( i = 0; i < 6; i++ )
+ hp100_outb( dev -> dev_addr[ i ], MAC_ADDR + i );
+ for ( i = 0; i < 8; i++ ) /* setup multicast filter to receive all */
+ hp100_outb( 0xff, HASH_BYTE0 + i );
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+ hp100_outw( 0xffff, IRQ_STATUS ); /* ack */
+ hp100_outw( (HP100_RX_PACKET | HP100_RX_ERROR | HP100_SET_HB) |
+ (HP100_TX_ERROR | HP100_SET_LB ), IRQ_MASK );
+ /* and enable few */
+ hp100_reset_card();
+ hp100_page( MMU_CFG );
+ hp100_outw( ( lp -> memory_size * lp -> rx_ratio ) / 100, RX_MEM_STOP );
+ hp100_outw( lp -> memory_size - 1, TX_MEM_STOP );
+ hp100_unreset_card();
+
+ if ( lp -> lan_type == HP100_LAN_100 )
+ lp -> hub_status = hp100_login_to_vg_hub( dev );
+
+ hp100_start_interface( dev );
+
+ return 0;
+}
+
+static int hp100_close( struct device *dev )
+{
+ int ioaddr = dev -> base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+ hp100_page( PERFORMANCE );
+ hp100_outw( 0xfefe, IRQ_MASK ); /* mask off all ints */
+
+ hp100_stop_interface( dev ); /* relogin */
+
+ if ( lp -> lan_type == HP100_LAN_100 )
+ hp100_login_to_vg_hub( dev );
+
+ dev -> tbusy = 1;
+ dev -> start = 0;
+
+ free_irq( dev -> irq );
+ irq2dev_map[ dev -> irq ] = NULL;
+#ifdef MODULE
+ MOD_DEC_USE_COUNT;
+#endif
+ return 0;
+}
+
+/*
+ * transmit
+ */
+
+static int hp100_start_xmit( struct sk_buff *skb, struct device *dev )
+{
+ int i;
+ int ioaddr = dev -> base_addr;
+ u_short val;
+ struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+ if ( ( i = ( hp100_inl( TX_MEM_FREE ) & ~0x7fffffff ) ) < skb -> len + 16 )
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100_start_xmit: rx free mem = 0x%x\n", i );
+#endif
+ if ( jiffies - dev -> trans_start < 2 * HZ ) return -EAGAIN;
+ if ( lp -> lan_type == HP100_LAN_100 && lp -> hub_status < 0 )
+ /* 100Mb/s adapter isn't connected to hub */
+ {
+ printk( "%s: login to 100Mb/s hub retry\n", dev -> name );
+ hp100_ints_off();
+ hp100_stop_interface( dev );
+ lp -> hub_status = hp100_login_to_vg_hub( dev );
+ hp100_start_interface( dev );
+ hp100_ints_on();
+ }
+ else
+ {
+ hp100_ints_off();
+ i = hp100_sense_lan( dev );
+ hp100_page( PERFORMANCE );
+ hp100_ints_on();
+ if ( i == HP100_LAN_ERR )
+ printk( "%s: link down detected\n", dev -> name );
+ else
+ if ( lp -> lan_type != i )
+ {
+ /* it's very heavy - all network setting must be changed!!! */
+ printk( "%s: cable change 10Mb/s <-> 100Mb/s detected\n", dev -> name );
+ lp -> lan_type = i;
+ hp100_ints_off();
+ hp100_stop_interface( dev );
+ if ( lp -> lan_type == HP100_LAN_100 )
+ lp -> hub_status = hp100_login_to_vg_hub( dev );
+ hp100_start_interface( dev );
+ hp100_ints_on();
+ }
+ else
+ {
+ printk( "%s: interface reset\n", dev -> name );
+ hp100_ints_off();
+ hp100_stop_interface( dev );
+ hp100_start_interface( dev );
+ hp100_ints_on();
+ }
+ }
+ dev -> trans_start = jiffies;
+ return -EAGAIN;
+ }
+
+ if ( skb == NULL )
+ {
+ dev_tint( dev );
+ return 0;
+ }
+
+ if ( skb -> len <= 0 ) return 0;
+
+ for ( i = 0; i < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_TX_CMD ); i++ )
+ {
+#ifdef HP100_DEBUG_TX
+ printk( "hp100_start_xmit: busy\n" );
+#endif
+ }
+
+ hp100_ints_off();
+ val = hp100_inw( IRQ_STATUS );
+ hp100_outw( val & HP100_TX_COMPLETE, IRQ_STATUS );
+#ifdef HP100_DEBUG_TX
+ printk( "hp100_start_xmit: irq_status = 0x%x, len = %d\n", val, (int)skb -> len );
+#endif
+ if ( skb -> len >= HP100_MIN_PACKET_SIZE )
+ {
+ hp100_outw( skb -> len, DATA32 ); /* length to memory manager */
+ hp100_outw( skb -> len, FRAGMENT_LEN );
+ outsl( ioaddr + HP100_REG_DATA32, skb -> data, ( skb -> len + 3 ) >> 2 );
+ hp100_outw( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
+ }
+ else
+ {
+ hp100_outw( HP100_MIN_PACKET_SIZE, DATA32 ); /* length to memory manager */
+ hp100_outw( HP100_MIN_PACKET_SIZE, FRAGMENT_LEN );
+ i = skb -> len + 3;
+ outsl( ioaddr + HP100_REG_DATA32, skb -> data, i >> 2 );
+ for ( i &= ~3; i < HP100_MIN_PACKET_SIZE; i += 4 )
+ hp100_outl( 0, DATA32 );
+ hp100_outw( HP100_TX_CMD | HP100_SET_LB, OPTION_MSW ); /* send packet */
+ }
+ lp -> stats.tx_packets++;
+ dev -> trans_start = jiffies;
+ hp100_ints_on();
+
+ dev_kfree_skb( skb, FREE_WRITE );
+
+#ifdef HP100_DEBUG_TX
+ printk( "hp100_start_xmit: end\n" );
+#endif
+
+ return 0;
+}
+
+/*
+ * receive - called from interrupt handler
+ */
+
+static void hp100_rx( struct device *dev )
+{
+ int packets, pkt_len;
+ int ioaddr = dev -> base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+ u_int header;
+ struct sk_buff *skb;
+
+ packets = hp100_inb( RX_PKT_CNT );
+#ifdef HP100_DEBUG
+ if ( packets > 1 )
+ printk( "hp100_rx: waiting packets = %d\n", packets );
+#endif
+ while ( packets-- > 0 )
+ {
+ for ( pkt_len = 0; pkt_len < 6000 && ( hp100_inw( OPTION_MSW ) & HP100_ADV_NXT_PKT ); pkt_len++ )
+ {
+#ifdef HP100_DEBUG_TX
+ printk( "hp100_rx: busy, remaining packets = %d\n", packets );
+#endif
+ }
+ header = hp100_inl( DATA32 );
+ pkt_len = header & HP100_PKT_LEN_MASK;
+#ifdef HP100_DEBUG_RX
+ printk( "hp100_rx: new packet - length = %d, errors = 0x%x, dest = 0x%x\n",
+ header & HP100_PKT_LEN_MASK, ( header >> 16 ) & 0xfff8, ( header >> 16 ) & 7 );
+#endif
+ skb = alloc_skb( ( pkt_len + 3 ) & ~3, GFP_ATOMIC );
+ if ( skb == NULL )
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100_rx: couldn't allocate a sk_buff of size %d\n", pkt_len );
+#endif
+ lp -> stats.rx_dropped++;
+ }
+ else
+ {
+ skb -> len = pkt_len;
+ skb -> dev = dev;
+ insl( ioaddr + HP100_REG_DATA32, skb -> data, ( pkt_len + 3 ) >> 2 );
+ skb->protocol=eth_type_trans(skb,dev);
+ netif_rx( skb );
+ lp -> stats.rx_packets++;
+ }
+ hp100_outw( HP100_ADV_NXT_PKT | HP100_SET_LB, OPTION_MSW );
+ switch ( header & 0x00070000 ) {
+ case (HP100_MULTI_ADDR_HASH<<16):
+ case (HP100_MULTI_ADDR_NO_HASH<<16):
+ lp -> stats.multicast++; break;
+ }
+ }
+#ifdef HP100_DEBUG_RX
+ printk( "hp100_rx: end\n" );
+#endif
+}
+
+/*
+ * statistics
+ */
+
+static struct enet_statistics *hp100_get_stats( struct device *dev )
+{
+ int ioaddr = dev -> base_addr;
+
+ hp100_ints_off();
+ hp100_update_stats( dev );
+ hp100_ints_on();
+ return &((struct hp100_private *)dev -> priv) -> stats;
+}
+
+static void hp100_update_stats( struct device *dev )
+{
+ int ioaddr = dev -> base_addr;
+ u_short val;
+ struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+ hp100_page( MAC_CTRL ); /* get all statistics bytes */
+ val = hp100_inw( DROPPED ) & 0x0fff;
+ lp -> stats.rx_errors += val;
+ lp -> stats.rx_over_errors += val;
+ val = hp100_inb( CRC );
+ lp -> stats.rx_errors += val;
+ lp -> stats.rx_crc_errors += val;
+ val = hp100_inb( ABORT );
+ lp -> stats.tx_errors += val;
+ lp -> stats.tx_aborted_errors += val;
+ hp100_page( PERFORMANCE );
+}
+
+/*
+ * multicast setup
+ */
+
+#ifdef HAVE_MULTICAST
+
+/*
+ * Set or clear the multicast filter for this adapter.
+ *
+ * num_addrs == -1 Promiscuous mode, receive all packets
+ * num_addrs == 0 Normal mode, clear multicast list
+ * num_addrs > 0 Multicast mode, receive normal and MC packets,
+ * best-effort filtering.
+ */
+
+static void hp100_set_multicast_list( struct device *dev, int num_addrs, void *addrs )
+{
+ int ioaddr = dev -> base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+#ifdef HP100_DEBUG_MULTI
+ printk( "hp100_set_multicast_list: num_addrs = %d\n", num_addrs );
+#endif
+ hp100_ints_off();
+ cli();
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 ); /* stop rx/tx */
+
+ if ( num_addrs < 0 )
+ {
+ lp -> mac2_mode = HP100_MAC2MODE6; /* promiscuous mode, all good */
+ lp -> mac1_mode = HP100_MAC1MODE6; /* packets on the net */
+ }
+ else
+ if ( num_addrs > 0 )
+ {
+ lp -> mac2_mode = HP100_MAC2MODE5; /* multicast mode, packets for me */
+ lp -> mac1_mode = HP100_MAC1MODE5; /* broadcasts and all multicasts */
+ }
+ else
+ {
+ lp -> mac2_mode = HP100_MAC2MODE3; /* normal mode, packets for me */
+ lp -> mac1_mode = HP100_MAC1MODE3; /* and broadcasts */
+ }
+
+ hp100_outb( lp -> mac2_mode, MAC_CFG_2 );
+ hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 );
+ hp100_orb( lp -> mac1_mode, MAC_CFG_1 );
+
+ hp100_orb( HP100_RX_EN | HP100_RX_IDLE, MAC_CFG_1 ); /* enable rx */
+ hp100_orb( HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 ); /* enable tx */
+ hp100_page( PERFORMANCE );
+ sti();
+ hp100_ints_on();
+}
+
+#endif /* HAVE_MULTICAST */
+
+/*
+ * hardware interrupt handling
+ */
+
+#ifndef LINUX_1_1_52
+static void hp100_interrupt( int irq, struct pt_regs *regs )
+#else
+static void hp100_interrupt( int irq )
+#endif
+{
+ struct device *dev = (struct device *)irq2dev_map[ irq ];
+ struct hp100_private *lp;
+ int ioaddr;
+ u_short val;
+
+ if ( dev == NULL ) return;
+ ioaddr = dev -> base_addr;
+ if ( dev -> interrupt )
+ printk( "%s: re-entering the interrupt handler\n", dev -> name );
+ hp100_ints_off();
+ dev -> interrupt = 1;
+ val = hp100_inw( IRQ_STATUS );
+#ifdef HP100_DEBUG_IRQ
+ printk( "hp100_interrupt: irq_status = 0x%x\n", val );
+#endif
+ if ( val & HP100_RX_PACKET )
+ {
+ hp100_rx( dev );
+ hp100_outw( HP100_RX_PACKET, IRQ_STATUS );
+ }
+ if ( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE) )
+ {
+ hp100_outw( val & (HP100_TX_SPACE_AVAIL | HP100_TX_COMPLETE), IRQ_STATUS );
+ }
+ if ( val & ( HP100_TX_ERROR | HP100_RX_ERROR ) )
+ {
+ lp = (struct hp100_private *)dev -> priv;
+ hp100_update_stats( dev );
+ hp100_outw( val & (HP100_TX_ERROR | HP100_RX_ERROR), IRQ_STATUS );
+ }
+#ifdef HP100_DEBUG_IRQ
+ printk( "hp100_interrupt: end\n" );
+#endif
+ dev -> interrupt = 0;
+ hp100_ints_on();
+}
+
+/*
+ * some misc functions
+ */
+
+static void hp100_start_interface( struct device *dev )
+{
+ int ioaddr = dev -> base_addr;
+ struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+ hp100_unreset_card();
+ cli();
+ hp100_page( MAC_CTRL );
+ hp100_outb( lp -> mac2_mode, MAC_CFG_2 );
+ hp100_andb( HP100_MAC1MODEMASK, MAC_CFG_1 );
+ hp100_orb( lp -> mac1_mode, MAC_CFG_1 );
+ hp100_orb( HP100_RX_EN | HP100_RX_IDLE, MAC_CFG_1 );
+ hp100_orb( HP100_TX_EN | HP100_TX_IDLE, MAC_CFG_1 );
+ hp100_page( PERFORMANCE );
+ hp100_outw( HP100_INT_EN | HP100_SET_LB, OPTION_LSW );
+ hp100_outw( HP100_TRI_INT | HP100_RESET_HB, OPTION_LSW );
+ sti();
+}
+
+static void hp100_stop_interface( struct device *dev )
+{
+ int ioaddr = dev -> base_addr;
+ u_short val;
+
+ hp100_outw( HP100_INT_EN | HP100_RESET_LB |
+ HP100_TRI_INT | HP100_SET_HB, OPTION_LSW );
+ val = hp100_inw( OPTION_LSW );
+ hp100_page( HW_MAP );
+ hp100_andb( HP100_BM_SLAVE, BM );
+ hp100_page( MAC_CTRL );
+ hp100_andb( ~(HP100_RX_EN | HP100_TX_EN), MAC_CFG_1 );
+ if ( !(val & HP100_HW_RST) ) return;
+ for ( val = 0; val < 6000; val++ )
+ if ( ( hp100_inb( MAC_CFG_1 ) & (HP100_TX_IDLE | HP100_RX_IDLE) ) ==
+ (HP100_TX_IDLE | HP100_RX_IDLE) )
+ return;
+ printk( "%s: hp100_stop_interface - timeout\n", dev -> name );
+}
+
+static void hp100_load_eeprom( struct device *dev )
+{
+ int i;
+ int ioaddr = dev -> base_addr;
+
+ hp100_page( EEPROM_CTRL );
+ hp100_andw( ~HP100_EEPROM_LOAD, EEPROM_CTRL );
+ hp100_orw( HP100_EEPROM_LOAD, EEPROM_CTRL );
+ for ( i = 0; i < 6000; i++ )
+ if ( !( hp100_inw( OPTION_MSW ) & HP100_EE_LOAD ) ) return;
+ printk( "%s: hp100_load_eeprom - timeout\n", dev -> name );
+}
+
+/* return values: LAN_10, LAN_100 or LAN_ERR (not connected or hub is down)... */
+
+static int hp100_sense_lan( struct device *dev )
+{
+ int i;
+ int ioaddr = dev -> base_addr;
+ u_short val_VG, val_10;
+ struct hp100_private *lp = (struct hp100_private *)dev -> priv;
+
+ hp100_page( MAC_CTRL );
+ hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
+ val_10 = hp100_inw( LAN_CFG_10 );
+ val_VG = hp100_inw( LAN_CFG_VG );
+#ifdef HP100_DEBUG_SENSE
+ printk( "hp100_sense_lan: val_VG = 0x%04x, val_10 = 0x%04x\n", val_VG, val_10 );
+#endif
+ if ( val_10 & HP100_LINK_BEAT_ST ) return HP100_LAN_10;
+ if ( lp -> id -> id == 0x02019F022 ) /* HP J27248B doesn't have 100Mb/s interface */
+ return HP100_LAN_ERR;
+ for ( i = 0; i < 2500; i++ )
+ {
+ val_VG = hp100_inw( LAN_CFG_VG );
+ if ( val_VG & HP100_LINK_CABLE_ST ) return HP100_LAN_100;
+ }
+ return HP100_LAN_ERR;
+}
+
+static int hp100_down_vg_link( struct device *dev )
+{
+ int ioaddr = dev -> base_addr;
+ unsigned long time;
+ int i;
+
+ hp100_page( MAC_CTRL );
+ for ( i = 2500; i > 0; i-- )
+ if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
+ if ( i <= 0 ) /* not signal - not logout */
+ return 0;
+ hp100_andw( ~HP100_LINK_CMD, LAN_CFG_VG );
+ time = jiffies + 10;
+ while ( time > jiffies )
+ if ( !( hp100_inw( LAN_CFG_VG ) & ( HP100_LINK_UP_ST |
+ HP100_LINK_CABLE_ST |
+ HP100_LINK_GOOD_ST ) ) )
+ return 0;
+#ifdef HP100_DEBUG
+ printk( "hp100_down_vg_link: timeout\n" );
+#endif
+ return -EIO;
+}
+
+static int hp100_login_to_vg_hub( struct device *dev )
+{
+ int i;
+ int ioaddr = dev -> base_addr;
+ u_short val;
+ unsigned long time;
+
+ hp100_page( MAC_CTRL );
+ hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
+ time = jiffies + ( HZ / 2 );
+ do {
+ if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
+ } while ( time > jiffies );
+ if ( time <= jiffies )
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100_login_to_vg_hub: timeout for link\n" );
+#endif
+ return -EIO;
+ }
+
+ if ( hp100_down_vg_link( dev ) < 0 ) /* if fail, try reset VG link */
+ {
+ hp100_andw( ~HP100_VG_RESET, LAN_CFG_VG );
+ hp100_orw( HP100_VG_RESET, LAN_CFG_VG );
+ }
+ /* bring up link */
+ hp100_orw( HP100_LOAD_ADDR | HP100_LINK_CMD, LAN_CFG_VG );
+ for ( i = 2500; i > 0; i-- )
+ if ( hp100_inw( LAN_CFG_VG ) & HP100_LINK_CABLE_ST ) break;
+ if ( i <= 0 )
+ {
+#ifdef HP100_DEBUG
+ printk( "hp100_login_to_vg_hub: timeout for link (bring up)\n" );
+#endif
+ goto down_link;
+ }
+
+ time = jiffies + ( HZ / 2 );
+ do {
+ val = hp100_inw( LAN_CFG_VG );
+ if ( ( val & ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) ) ==
+ ( HP100_LINK_UP_ST | HP100_LINK_GOOD_ST ) )
+ return 0; /* success */
+ } while ( time > jiffies );
+ if ( val & HP100_LINK_GOOD_ST )
+ printk( "%s: 100Mb cable training failed, check cable.\n", dev -> name );
+ else
+ printk( "%s: 100Mb node not accepted by hub, check frame type or security.\n", dev -> name );
+
+down_link:
+ hp100_down_vg_link( dev );
+ hp100_page( MAC_CTRL );
+ hp100_andw( ~( HP100_LOAD_ADDR | HP100_PROM_MODE ), LAN_CFG_VG );
+ hp100_orw( HP100_LINK_CMD, LAN_CFG_VG );
+ return -EIO;
+}
+
+/*
+ * module section
+ */
+
+#ifdef MODULE
+
+char kernel_version[] = UTS_RELEASE;
+
+static int hp100_port = -1;
+
+static struct device dev_hp100 = {
+ " ", 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, hp100_probe
+};
+
+int init_module( void )
+{
+ if ( hp100_port > 0 ) dev_hp100.base_addr = hp100_port;
+ if ( register_netdev( &dev_hp100 ) != 0 ) return -EIO;
+ return 0;
+}
+
+void cleanup_module( void )
+{
+ unregister_netdev( &dev_hp100 );
+ release_region( dev_hp100.base_addr, 0x20 );
+ kfree_s( dev_hp100.priv, sizeof( struct hp100_private ) );
+ dev_hp100.priv = NULL;
+}
+
+#endif
--- /dev/null
+/*
+ * hp100.h: Hewlett Packard HP10/100VG ANY LAN ethernet driver for Linux.
+ *
+ * Author: Jaroslav Kysela, <perex@pf.jcu.cz>
+ *
+ * Header file...
+ *
+ * This driver is based on the 'hpfepkt' crynwr packet driver.
+ *
+ * This source/code is public free; you can distribute it and/or modify
+ * it under terms of the GNU General Public License (published by the
+ * Free Software Foundation) either version two of this License, or any
+ * later version.
+ */
+
+/****************************************************************************
+ * Hardware Constants
+ ****************************************************************************/
+
+/*
+ * ATT2MD01 Register Page Constants
+ */
+
+#define HP100_PAGE_PERFORMANCE 0x0 /* Page 0 */
+#define HP100_PAGE_MAC_ADDRESS 0x1 /* Page 1 */
+#define HP100_PAGE_HW_MAP 0x2 /* Page 2 */
+#define HP100_PAGE_EEPROM_CTRL 0x3 /* Page 3 */
+#define HP100_PAGE_MAC_CTRL 0x4 /* Page 4 */
+#define HP100_PAGE_MMU_CFG 0x5 /* Page 5 */
+#define HP100_PAGE_ID_MAC_ADDR 0x6 /* Page 6 */
+#define HP100_PAGE_MMU_POINTER 0x7 /* Page 7 */
+
+/*
+ * ATT2MD01 Register Addresses
+ */
+
+/* Present on all pages */
+
+#define HP100_REG_HW_ID 0x00 /* R: (16) Unique card ID */
+#define HP100_REG_TRACE 0x00 /* W: (16) Used for debug output */
+#define HP100_REG_PAGING 0x02 /* R: (16),15:4 Card ID */
+ /* W: (16),3:0 Switch pages */
+#define HP100_REG_OPTION_LSW 0x04 /* RW: (16) Select card functions */
+#define HP100_REG_OPTION_MSW 0x06 /* RW: (16) Select card functions */
+
+/* Page 0 - Performance */
+
+#define HP100_REG_IRQ_STATUS 0x08 /* RW: (16) Which ints are pending */
+#define HP100_REG_IRQ_MASK 0x0a /* RW: (16) Select ints to allow */
+#define HP100_REG_FRAGMENT_LEN 0x0c /* RW: (16)12:0 Current fragment len */
+#define HP100_REG_OFFSET 0x0e /* RW: (16)12:0 Offset to start read */
+#define HP100_REG_DATA32 0x10 /* RW: (32) I/O mode data port */
+#define HP100_REG_DATA16 0x12 /* RW: WORDs must be read from here */
+#define HP100_REG_TX_MEM_FREE 0x14 /* RD: (32) Amount of free Tx mem */
+#define HP100_REG_RX_PKT_CNT 0x18 /* RD: (8) Rx count of pkts on card */
+#define HP100_REG_TX_PKT_CNT 0x19 /* RD: (8) Tx count of pkts on card */
+
+/* Page 1 - MAC Address/Hash Table */
+
+#define HP100_REG_MAC_ADDR 0x08 /* RW: (8) Cards MAC address */
+#define HP100_REG_HASH_BYTE0 0x10 /* RW: (8) Cards multicast filter */
+
+/* Page 2 - Hardware Mapping */
+
+#define HP100_REG_MEM_MAP_LSW 0x08 /* RW: (16) LSW of cards mem addr */
+#define HP100_REG_MEM_MAP_MSW 0x0a /* RW: (16) MSW of cards mem addr */
+#define HP100_REG_IO_MAP 0x0c /* RW: (8) Cards I/O address */
+#define HP100_REG_IRQ_CHANNEL 0x0d /* RW: (8) IRQ and edge/level int */
+#define HP100_REG_SRAM 0x0e /* RW: (8) How much RAM on card */
+#define HP100_REG_BM 0x0f /* RW: (8) Controls BM functions */
+
+/* Page 3 - EEPROM/Boot ROM */
+
+#define HP100_REG_EEPROM_CTRL 0x08 /* RW: (16) Used to load EEPROM */
+
+/* Page 4 - LAN Configuration */
+
+#define HP100_REG_LAN_CFG_10 0x08 /* RW: (16) Set 10M XCVR functions */
+#define HP100_REG_LAN_CFG_VG 0x0a /* RW: (16) Set 100M XCVR functions */
+#define HP100_REG_MAC_CFG_1 0x0c /* RW: (8) Types of pkts to accept */
+#define HP100_REG_MAC_CFG_2 0x0d /* RW: (8) Misc MAC functions */
+/* The follow clear when read: */
+#define HP100_REG_DROPPED 0x10 /* R: (16),11:0 Pkts cant fit in mem*/
+#define HP100_REG_CRC 0x12 /* R: (8) Pkts with CRC */
+#define HP100_REG_ABORT 0x13 /* R: (8) Aborted Tx pkts */
+
+/* Page 5 - MMU */
+
+#define HP100_REG_RX_MEM_STOP 0x0c /* RW: (16) End of Rx ring addr */
+#define HP100_REG_TX_MEM_STOP 0x0e /* RW: (16) End of Tx ring addr */
+
+/* Page 6 - Card ID/Physical LAN Address */
+
+#define HP100_REG_BOARD_ID 0x08 /* R: (8) EISA/ISA card ID */
+#define HP100_REG_BOARD_IO_CHCK 0x0c /* R: (8) Added to ID to get FFh */
+#define HP100_REG_SOFT_MODEL 0x0d /* R: (8) Config program defined */
+#define HP100_REG_LAN_ADDR 0x10 /* R: (8) MAC addr of card */
+#define HP100_REG_LAN_ADDR_CHCK 0x16 /* R: (8) Added to addr to get FFh */
+
+/* Page 7 - MMU Current Pointers */
+
+#define HP100_REG_RX_MEM_BR 0x08 /* R: (16) Current begin of Rx ring */
+#define HP100_REG_RX_MEM_ER 0x0a /* R: (16) Current end of Rx ring */
+#define HP100_REG_TX_MEM_BR 0x0c /* R: (16) Current begin of Tx ring */
+#define HP100_REG_TX_MEM_ER 0x0e /* R: (16) Current end of Rx ring */
+#define HP100_REG_MEM_DEBUG 0x1a /* RW: (16) Used for memory tests */
+
+/*
+ * HardwareIDReg bits/masks
+ */
+
+#define HP100_HW_ID_0 0x50 /* Hardware ID bytes. */
+#define HP100_HW_ID_1 0x48
+#define HP100_HW_ID_2_REVA 0x50 /* Rev. A ID. NOTE: lower nibble not used */
+#define HP100_HW_ID_3 0x53
+
+/*
+ * OptionLSWReg bits/masks
+ */
+
+#define HP100_DEBUG_EN 0x8000 /* 0:Disable, 1:Enable Debug Dump Pointer */
+#define HP100_RX_HDR 0x4000 /* 0:Disable, 1:Enable putting pkt into */
+ /* system memory before Rx interrupt */
+#define HP100_MMAP_DIS 0x2000 /* 0:Enable, 1:Disable memory mapping. */
+ /* MMAP_DIS must be 0 and MEM_EN must */
+ /* be 1 for memory-mapped mode to be */
+ /* enabled */
+#define HP100_EE_EN 0x1000 /* 0:Disable,1:Enable EEPROM writing */
+#define HP100_BM_WRITE 0x0800 /* 0:Slave, 1:Bus Master for Tx data */
+#define HP100_BM_READ 0x0400 /* 0:Slave, 1:Bus Master for Rx data */
+#define HP100_TRI_INT 0x0200 /* 0:Dont, 1:Do tri-state the int */
+#define HP100_MEM_EN 0x0040 /* Config program set this to */
+ /* 0:Disable, 1:Enable mem map. */
+ /* See MMAP_DIS. */
+#define HP100_IO_EN 0x0020 /* 0:Disable, 1:Enable I/O transfers */
+#define HP100_BOOT_EN 0x0010 /* 0:Disable, 1:Enable boot ROM access */
+#define HP100_FAKE_INT 0x0008 /* 0:No int, 1:int */
+#define HP100_INT_EN 0x0004 /* 0:Disable, 1:Enable ints from card */
+#define HP100_HW_RST 0x0002 /* 0:Reset, 1:Out of reset */
+
+/*
+ * OptionMSWReg bits/masks
+ */
+#define HP100_PRIORITY_TX 0x0080 /* 0:Don't, 1:Do all Tx pkts as priority */
+#define HP100_EE_LOAD 0x0040 /* 1:EEPROM loading, 0 when done */
+#define HP100_ADV_NXT_PKT 0x0004 /* 1:Advance to next pkt in Rx queue, */
+ /* h/w will set to 0 when done */
+#define HP100_TX_CMD 0x0002 /* 1:Tell h/w download done, h/w will set */
+ /* to 0 when done */
+
+/*
+ * InterruptStatusReg/InterruptMaskReg bits/masks. These bits will 0 when a 1
+ * is written to them.
+ */
+#define HP100_RX_PACKET 0x0400 /* 0:No, 1:Yes pkt has been Rx */
+#define HP100_RX_ERROR 0x0200 /* 0:No, 1:Yes Rx pkt had error */
+#define HP100_TX_SPACE_AVAIL 0x0010 /* 0:<8192, 1:>=8192 Tx free bytes */
+#define HP100_TX_COMPLETE 0x0008 /* 0:No, 1:Yes a Tx has completed */
+#define HP100_TX_ERROR 0x0002 /* 0:No, 1:Yes Tx pkt had error */
+
+/*
+ * TxMemoryFreeCountReg bits/masks.
+ */
+#define HP100_AUTO_COMPARE 0x8000 /* Says at least 8k is available for Tx. */
+ /* NOTE: This mask is for the upper */
+ /* word of the register. */
+
+/*
+ * IRQChannelReg bits/masks.
+ */
+#define HP100_ZERO_WAIT_EN 0x80 /* 0:No, 1:Yes assers NOWS signal */
+#define HP100_LEVEL_IRQ 0x10 /* 0:Edge, 1:Level type interrupts. */
+ /* Only valid on EISA cards. */
+#define HP100_IRQ_MASK 0x0F /* Isolate the IRQ bits */
+
+/*
+ * SRAMReg bits/masks.
+ */
+#define HP100_RAM_SIZE_MASK 0xe0 /* AND to get SRAM size index */
+#define HP100_RAM_SIZE_SHIFT 0x05 /* Shift count to put index in lower bits */
+
+/*
+ * BMReg bits/masks.
+ */
+#define HP100_BM_SLAVE 0x04 /* 0:Slave, 1:BM mode */
+
+/*
+ * EEPROMControlReg bits/masks.
+ */
+#define HP100_EEPROM_LOAD 0x0001 /* 0->1 loads the EEPROM into registers. */
+ /* When it goes back to 0, load is */
+ /* complete. This should take ~600us. */
+
+/*
+ * LANCntrCfg10Reg bits/masks.
+ */
+#define HP100_SQU_ST 0x0100 /* 0:No, 1:Yes collision signal sent */
+ /* after Tx. Only used for AUI. */
+#define HP100_MAC10_SEL 0x00c0 /* Get bits to indicate MAC */
+#define HP100_AUI_SEL 0x0020 /* Status of AUI selection */
+#define HP100_LOW_TH 0x0010 /* 0:No, 1:Yes allow better cabling */
+#define HP100_LINK_BEAT_DIS 0x0008 /* 0:Enable, 1:Disable link beat */
+#define HP100_LINK_BEAT_ST 0x0004 /* 0:No, 1:Yes link beat being Rx */
+#define HP100_R_ROL_ST 0x0002 /* 0:No, 1:Yes Rx twisted pair has been */
+ /* reversed */
+#define HP100_AUI_ST 0x0001 /* 0:No, 1:Yes use AUI on TP card */
+
+/* MAC Selection, use with MAC10_SEL bits */
+#define HP100_AUTO_SEL_10 0x0 /* Auto select */
+#define HP100_XCVR_LXT901_10 0x1 /* LXT901 10BaseT transceiver */
+#define HP100_XCVR_7213 0x2 /* 7213 transceiver */
+#define HP100_XCVR_82503 0x3 /* 82503 transceiver */
+
+
+/*
+ * LANCntrCfgVGReg bits/masks.
+ */
+#define HP100_FRAME_FORMAT 0x0800 /* 0:802.3, 1:802.5 frames */
+#define HP100_BRIDGE 0x0400 /* 0:No, 1:Yes tell hub it's a bridge */
+#define HP100_PROM_MODE 0x0200 /* 0:No, 1:Yes tell hub card is */
+ /* promiscuous */
+#define HP100_REPEATER 0x0100 /* 0:No, 1:Yes tell hub MAC wants to be */
+ /* a cascaded repeater */
+#define HP100_MAC100_SEL 0x0080 /* 0:No, 1:Yes use 100 Mbit MAC */
+#define HP100_LINK_UP_ST 0x0040 /* 0:No, 1:Yes endnode logged in */
+#define HP100_LINK_CABLE_ST 0x0020 /* 0:No, 1:Yes cable can hear tones from */
+ /* hub */
+#define HP100_LOAD_ADDR 0x0010 /* 0->1 card addr will be sent to hub. */
+ /* 100ms later the link status bits are */
+ /* valid */
+#define HP100_LINK_CMD 0x0008 /* 0->1 link will attempt to log in. */
+ /* 100ms later the link status bits are */
+ /* valid */
+#define HP100_LINK_GOOD_ST 0x0002 /* 0:No, 1:Yes cable passed training */
+#define HP100_VG_RESET 0x0001 /* 0:Yes, 1:No reset the 100VG MAC */
+
+
+/*
+ * MACConfiguration1Reg bits/masks.
+ */
+#define HP100_RX_IDLE 0x80 /* 0:Yes, 1:No currently receiving pkts */
+#define HP100_TX_IDLE 0x40 /* 0:Yes, 1:No currently Txing pkts */
+#define HP100_RX_EN 0x20 /* 0:No, 1:Yes allow receiving of pkts */
+#define HP100_TX_EN 0x10 /* 0:No, 1:Yes allow transmiting of pkts */
+#define HP100_ACC_ERRORED 0x08 /* 0:No, 1:Yes allow Rx of errored pkts */
+#define HP100_ACC_MC 0x04 /* 0:No, 1:Yes allow Rx of multicast pkts */
+#define HP100_ACC_BC 0x02 /* 0:No, 1:Yes allow Rx of broadcast pkts */
+#define HP100_ACC_PHY 0x01 /* 0:No, 1:Yes allow Rx of ALL physical pkts */
+
+#define HP100_MAC1MODEMASK 0xf0 /* Hide ACC bits */
+#define HP100_MAC1MODE1 0x00 /* Receive nothing, must also disable RX */
+#define HP100_MAC1MODE2 0x00
+#define HP100_MAC1MODE3 HP100_MAC1MODE2 | HP100_ACC_BC
+#define HP100_MAC1MODE4 HP100_MAC1MODE3 | HP100_ACC_MC
+#define HP100_MAC1MODE5 HP100_MAC1MODE4 /* set mc hash to all ones also */
+#define HP100_MAC1MODE6 HP100_MAC1MODE5 | HP100_ACC_PHY /* Promiscuous */
+
+/* Note MODE6 will receive all GOOD packets on the LAN. This really needs
+ a mode 7 defined to be LAN Analyzer mode, which will receive errored and
+ runt packets, and keep the CRC bytes. */
+
+#define HP100_MAC1MODE7 MAC1MODE6 OR ACC_ERRORED
+
+/*
+ * MACConfiguration2Reg bits/masks.
+ */
+#define HP100_TR_MODE 0x80 /* 0:No, 1:Yes support Token Ring formats */
+#define HP100_TX_SAME 0x40 /* 0:No, 1:Yes Tx same packet continuous */
+#define HP100_LBK_XCVR 0x20 /* 0:No, 1:Yes loopback through MAC & */
+ /* transceiver */
+#define HP100_LBK_MAC 0x10 /* 0:No, 1:Yes loopback through MAC */
+#define HP100_CRC_I 0x08 /* 0:No, 1:Yes inhibit CRC on Tx packets */
+#define HP100_KEEP_CRC 0x02 /* 0:No, 1:Yes keep CRC on Rx packets. */
+ /* The length will reflect this. */
+
+#define HP100_MAC2MODEMASK 0x02
+#define HP100_MAC2MODE1 0x00
+#define HP100_MAC2MODE2 0x00
+#define HP100_MAC2MODE3 0x00
+#define HP100_MAC2MODE4 0x00
+#define HP100_MAC2MODE5 0x00
+#define HP100_MAC2MODE6 0x00
+#define HP100_MAC2MODE7 KEEP_CRC
+
+/*
+ * Set/Reset bits
+ */
+#define HP100_SET_HB 0x0100 /* 0:Set fields to 0 whose mask is 1 */
+#define HP100_SET_LB 0x0001 /* HB sets upper byte, LB sets lower byte */
+#define HP100_RESET_HB 0x0000 /* For readability when resetting bits */
+#define HP100_RESET_LB 0x0000 /* For readability when resetting bits */
+
+/*
+ * Misc. Constants
+ */
+#define HP100_LAN_100 100 /* lan_type value for VG */
+#define HP100_LAN_10 10 /* lan_type value for 10BaseT */
+#define HP100_LAN_ERR (-1) /* lan_type value for link down */
+
+/*
+ * Receive Header Definition.
+ */
+
+struct hp100_rx_header {
+ u_short rx_length; /* Pkt length is bits 12:0 */
+ u_short rx_status; /* status of the packet */
+};
+
+#define HP100_PKT_LEN_MASK 0x1FFF /* AND with RxLength to get length bits */
+
+/* Receive Packet Status. Note, the error bits are only valid if ACC_ERRORED
+ bit in the MAC Configuration Register 1 is set. */
+
+#define HP100_RX_PRI 0x8000 /* 0:No, 1:Yes packet is priority */
+#define HP100_SDF_ERR 0x4000 /* 0:No, 1:Yes start of frame error */
+#define HP100_SKEW_ERR 0x2000 /* 0:No, 1:Yes skew out of range */
+#define HP100_BAD_SYMBOL_ERR 0x1000 /* 0:No, 1:Yes invalid symbol received */
+#define HP100_RCV_IPM_ERR 0x0800 /* 0:No, 1:Yes pkt had an invalid packet */
+ /* marker */
+#define HP100_SYMBOL_BAL_ERR 0x0400 /* 0:No, 1:Yes symbol balance error */
+#define HP100_VG_ALN_ERR 0x0200 /* 0:No, 1:Yes non-octet received */
+#define HP100_TRUNC_ERR 0x0100 /* 0:No, 1:Yes the packet was truncated */
+#define HP100_RUNT_ERR 0x0040 /* 0:No, 1:Yes pkt length < Min Pkt */
+ /* Length Reg. */
+#define HP100_ALN_ERR 0x0010 /* 0:No, 1:Yes align error. */
+#define HP100_CRC_ERR 0x0008 /* 0:No, 1:Yes CRC occurred. */
+
+/* The last three bits indicate the type of destination address */
+
+#define HP100_MULTI_ADDR_HASH 0x0006 /* 110: Addr multicast, matched hash */
+#define HP100_BROADCAST_ADDR 0x0003 /* x11: Addr broadcast */
+#define HP100_MULTI_ADDR_NO_HASH 0x0002 /* 010: Addr multicast, didn't match hash */
+#define HP100_PHYS_ADDR_MATCH 0x0001 /* x01: Addr was physical and mine */
+#define HP100_PHYS_ADDR_NO_MATCH 0x0000 /* x00: Addr was physical but not mine */
+
+/*
+ * macros
+ */
+
+#define hp100_inb( reg ) \
+ inb( ioaddr + HP100_REG_##reg )
+#define hp100_inw( reg ) \
+ inw( ioaddr + HP100_REG_##reg )
+#define hp100_inl( reg ) \
+ inl( ioaddr + HP100_REG_##reg )
+#define hp100_outb( data, reg ) \
+ outb( data, ioaddr + HP100_REG_##reg )
+#define hp100_outw( data, reg ) \
+ outw( data, ioaddr + HP100_REG_##reg )
+#define hp100_outl( data, reg ) \
+ outl( data, ioaddr + HP100_REG_##reg )
+#define hp100_orb( data, reg ) \
+ outb( inb( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg )
+#define hp100_orw( data, reg ) \
+ outw( inw( ioaddr + HP100_REG_##reg ) | (data), ioaddr + HP100_REG_##reg )
+#define hp100_andb( data, reg ) \
+ outb( inb( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg )
+#define hp100_andw( data, reg ) \
+ outw( inw( ioaddr + HP100_REG_##reg ) & (data), ioaddr + HP100_REG_##reg )
+
+#define hp100_page( page ) \
+ outw( HP100_PAGE_##page, ioaddr + HP100_REG_PAGING )
+#define hp100_ints_off() \
+ outw( HP100_INT_EN | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW )
+#define hp100_ints_on() \
+ outw( HP100_INT_EN | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW )
+#define hp100_mem_map_enable() \
+ outw( HP100_MMAP_DIS | HP100_RESET_HB, ioaddr + HP100_REG_OPTION_LSW )
+#define hp100_mem_map_disable() \
+ outw( HP100_MMAP_DIS | HP100_SET_HB, ioaddr + HP100_REG_OPTION_LSW )
+#define hp100_reset_card() \
+ outw( HP100_HW_RST | HP100_RESET_LB, ioaddr + HP100_REG_OPTION_LSW )
+#define hp100_unreset_card() \
+ outw( HP100_HW_RST | HP100_SET_LB, ioaddr + HP100_REG_OPTION_LSW )
case PPPIOCSDEBUG:
error = verify_area (VERIFY_READ, (void *) l, sizeof (temp_i));
if (error == 0) {
- ppp_debug = get_int ((int *) l);
+ ppp_debug = get_user ((int *) l);
ppp_debug_netpackets = (ppp_debug & 0xff00) >> 8;
ppp_debug &= 0xff;
PRINTKN (1, (KERN_INFO "ppp_ioctl: set debug level %d, netpacket %d\n",
DEVICE( NCR, NCR_53C825, "53c825"),
DEVICE( ADAPTEC, ADAPTEC_2940, "2940"),
DEVICE( ADAPTEC, ADAPTEC_294x, "294x"),
+ DEVICE( ADAPTEC, ADAPTEC_7850, "AIC-7850"),
DEVICE( DPT, DPT, "SmartCache/Raid"),
DEVICE( S3, S3_864_1, "Vision 864-P"),
DEVICE( S3, S3_864_2, "Vision 864-P"),
BRIDGE( UMC, UMC_UM8881F, "UM8881F", 0x02),
BRIDGE( UMC, UMC_UM8891A, "UM8891A", 0x01),
DEVICE( UMC, UMC_UM8886F, "UM8886F"),
+ DEVICE( UMC, UMC_UM8886A, "UM8886A"),
DEVICE( UMC, UMC_UM8673F, "UM8673F"),
DEVICE( DEC, DEC_TULIP, "DC21040"),
- DEVICE( DEC, DEC_TULIP_FAST, "DC21040"),
+ DEVICE( DEC, DEC_TULIP_FAST, "DC21140"),
+ DEVICE( DEC, DEC_TULIP_PLUS, "DC21041"),
DEVICE( DEC, DEC_FDDI, "DEFPA"),
DEVICE( DEC, DEC_BRD, "DC21050"),
DEVICE( MATROX, MATROX_MGA_2, "Atlas PX2085"),
DEVICE( CIRRUS, CIRRUS_5434_4, "GD 5434"),
DEVICE( CIRRUS, CIRRUS_5434_8, "GD 5434"),
DEVICE( CIRRUS, CIRRUS_6729, "CL 6729"),
+ DEVICE( CIRRUS, CIRRUS_7542, "CL 7542"),
DEVICE( BUSLOGIC, BUSLOGIC_946C, "946C"),
DEVICE( BUSLOGIC, BUSLOGIC_946C_2,"946C"),
DEVICE( N9, N9_I128, "Imagine 128"),
DEVICE( PROMISE, PROMISE_5300, "DC5030"),
DEVICE( QLOGIC, QLOGIC_ISP1020, "ISP1020"),
DEVICE( QLOGIC, QLOGIC_ISP1022, "ISP1022"),
- DEVICE( X, X_AGX016, "ITT AGX016")
+ DEVICE( X, X_AGX016, "ITT AGX016"),
+ DEVICE( VORTEX, VORTEX_GDT, "GDT 6000b")
};
case PCI_VENDOR_ID_3COM: return "3Com";
case PCI_VENDOR_ID_PROMISE: return "Promise Technology";
case PCI_VENDOR_ID_QLOGIC: return "Q Logic";
+ case PCI_VENDOR_ID_X: return "X TECHNOLOGY";
+ case PCI_VENDOR_ID_ACC: return "ACC MICROELECTRONICS";
+ case PCI_VENDOR_ID_VORTEX: return "VORTEX";
default: return "Unknown vendor";
}
}
#include <linux/errno.h>
#include <linux/bios32.h>
#include <linux/pci.h>
+#include <linux/proc_fs.h>
#include <linux/string.h>
#include <linux/mm.h>
#include "../block/blk.h"
*
* NCR53c720/710 - need to add fatal interrupt or GEN code for
* command completion signaling. Need to take care of
- * ADD WITH CARRY instructions since carry is unimplemented.
+ * ADD WITH CARRY instructions since carry is unimplemented.
* Also need to modify all SDID, SCID, etc. registers,
* and table indirect select code since these use bit
* fielded (ie 1<<target) instead of binary encoded
hostdata->expecting_sto = 0;
if ((hostdata->run_tests && hostdata->run_tests(host) == -1) ||
- (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
+ (hostdata->options & OPTION_DEBUG_TESTS_ONLY)) {
/* XXX Should disable interrupts, etc. here */
scsi_unregister (host);
return -1;
/* Size of dynamic part of command structure : */
2 * /* Worst case : we don't know if we need DATA IN or DATA out */
( 2 * /* Current instructions per scatter/gather segment */
- tpnt->sg_tablesize +
- 3 /* Current startup / termination required per phase */
+ tpnt->sg_tablesize +
+ 3 /* Current startup / termination required per phase */
) *
8 /* Each instruction is eight bytes */;
/* Note that alignment will be guaranteed, since we put the command
ASSUMPTION :
Regardless of how many simultaneous SCSI commands we allow,
- the probe code only executes a _single_ instruction at a time,
+ the probe code only executes a _single_ instruction at a time,
so we only need one here, and don't need to allocate NCR53c7x0_cmd
structures for each target until we are no longer in scan_scsis
and kmalloc() has become functional (memory_init() happens
(error = pcibios_read_config_word (bus, device_fn, PCI_COMMAND,
&command)) ||
(error = pcibios_read_config_dword (bus, device_fn,
- PCI_BASE_ADDRESS_0, &io_port)) ||
+ PCI_BASE_ADDRESS_0, (int *) &io_port)) ||
(error = pcibios_read_config_dword (bus, device_fn,
- PCI_BASE_ADDRESS_1, &base)) ||
+ PCI_BASE_ADDRESS_1, (int *) &base)) ||
(error = pcibios_read_config_byte (bus, device_fn, PCI_CLASS_REVISION,
&revision)) ||
(error = pcibios_read_config_byte (bus, device_fn, PCI_INTERRUPT_LINE,
if (chip && device_id != expected_id)
printk ("scsi-ncr53c7,8xx : warning : device id of 0x%04x doesn't\n"
- " match expected 0x%04x\n",
+ " match expected 0x%04x\n",
(unsigned int) device_id, (unsigned int) expected_id );
if (max_revision != -1 && revision > max_revision)
!pcibios_find_device (PCI_VENDOR_ID_NCR,
pci_chip_ids[i].pci_device_id, pci_index, &pci_bus,
&pci_device_fn) &&
- !ncr_pci_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip,
+ !ncr_pci_init (tpnt, BOARD_GENERIC, pci_chip_ids[i].chip,
pci_bus, pci_device_fn, /* no options */ 0);
++count, ++pci_index);
}
if (hostdata->test_dest != 0xdeadbeef) {
printk ("scsi%d : driver test 1 read 0x%x instead of 0xdeadbeef indicating a\n"
- " probable cache invalidation problem. Please configure caching\n"
+ " probable cache invalidation problem. Please configure caching\n"
" as write-through or disabled\n",
host->host_no, hostdata->test_dest);
}
* status, etc are used.
*/
- cmd->cmd->result = 0xffff;
+ cmd->cmd->result = 0xffff;
/*
* Restart command as a REQUEST SENSE.
* and SCSI recommended .5s selection timeout.
*/
+ /*
+ * The new gcc won't recognize preprocessing directives
+ * within macro args.
+ */
+#if 0
NCR53c7x0_write8(STIME0_REG_800,
((14 << STIME0_800_SEL_SHIFT) & STIME0_800_SEL_MASK)
/* Disable HTH interrupt */
-#if 0
- | ((15 << STIME0_800_HTH_SHIFT) & STIME0_800_HTH_MASK)
+ | ((15 << STIME0_800_HTH_SHIFT) & STIME0_800_HTH_MASK));
+#else
+ NCR53c7x0_write8(STIME0_REG_800,
+ ((14 << STIME0_800_SEL_SHIFT) & STIME0_800_SEL_MASK));
#endif
- );
NCR53c7x0_local_declare();
struct Scsi_Host *host = cmd->host;
struct NCR53c7x0_hostdata *hostdata = (struct NCR53c7x0_hostdata *)
- host->hostdata;
+ host->hostdata;
struct NCR53c7x0_cmd *tmp = NULL; /* NCR53c7x0_cmd structure for this command */
int datain, /* Number of instructions per phase */
dataout;
DCMD_TCI_CD | DCMD_TCI_IO | DCMD_TCI_MSG) << 24) |
DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE | DBC_TCI_TRUE;
cmd_datain[3] = virt_to_bus(hostdata->script) +
- hostdata->E_msg_in;
+ hostdata->E_msg_in;
#if 0
print_insn (host, cmd_datain, "dynamic ", 1);
print_insn (host, cmd_datain + 2, "dynamic ", 1);
DCMD_TCI_CD | DCMD_TCI_IO | DCMD_TCI_MSG) << 24) |
DBC_TCI_WAIT_FOR_VALID | DBC_TCI_COMPARE_PHASE | DBC_TCI_TRUE;
cmd_dataout[3] = virt_to_bus(hostdata->script) +
- hostdata->E_msg_in;
+ hostdata->E_msg_in;
#if 0
print_insn (host, cmd_dataout, "dynamic ", 1);
print_insn (host, cmd_dataout + 2, "dynamic ", 1);
/* selection timeout */
if ((is_8xx_chip && (sist1 & SIST1_800_STO)) ||
- (!is_8xx_chip && (sstat0_sist0 & SSTAT0_700_STO))) {
+ (!is_8xx_chip && (sstat0_sist0 & SSTAT0_700_STO))) {
fatal = 1;
if (hostdata->options & OPTION_DEBUG_INTR) {
printk ("scsi%d : Selection Timeout\n", host->host_no);
restart:
for (cmd_prev_ptr = (struct NCR53c7x0_cmd **)
&(hostdata->running_list), cmd =
- (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
- cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next),
+ (struct NCR53c7x0_cmd *) hostdata->running_list; cmd ;
+ cmd_prev_ptr = (struct NCR53c7x0_cmd **) &(cmd->next),
cmd = (struct NCR53c7x0_cmd *) cmd->next) {
Scsi_Cmnd *tmp;
*/
for (curr = (volatile struct NCR53c7x0_cmd *) hostdata->issue_queue,
- prev = (volatile struct NCR53c7x0_cmd **) &(hostdata->issue_queue);
+ prev = (volatile struct NCR53c7x0_cmd **) &(hostdata->issue_queue);
curr && curr->cmd != cmd; prev = (volatile struct NCR53c7x0_cmd **)
- &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
+ &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
if (curr) {
*prev = (struct NCR53c7x0_cmd *) curr->next;
for (curr = (volatile struct NCR53c7x0_cmd *) hostdata->running_list,
prev = (volatile struct NCR53c7x0_cmd **) &(hostdata->running_list);
curr && curr->cmd != cmd; prev = (volatile struct NCR53c7x0_cmd **)
- &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
+ &(curr->next), curr = (volatile struct NCR53c7x0_cmd *) curr->next);
if (curr) {
restore_flags(flags);
tmp = NCR53c7x0_read8(SSTAT0_REG);
}
} else if (istat & ISTAT_DIP) {
- NCR53c7x0_write8(hostdata->istat, 0);
+ NCR53c7x0_write8(hostdata->istat, 0);
tmp = NCR53c7x0_read8(DSTAT_REG);
if (tmp & DSTAT_ABRT)
break;
#define NCR53c7xx_release NULL
#endif
-#define NCR53c7xx {NULL, NULL, "NCR53c{7,8}xx (rel 4)", NCR53c7xx_detect, \
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
+#define NCR53c7xx {NULL, NULL, generic_proc_info, "NCR53c7xx", \
+ PROC_SCSI_NCR53C7xx, "NCR53c{7,8}xx (rel 4)", NCR53c7xx_detect, \
NULL, /* info */ NULL, /* command, deprecated */ NULL, \
NCR53c7xx_queue_command, NCR53c7xx_abort, NCR53c7xx_reset, \
- NULL /* slave attach */, scsicam_bios_param, /* can queue */ 1, \
+ NULL /* slave attach */, scsicam_bios_param, /* can queue */ 1, \
/* id */ 7, 127 /* old SG_ALL */, /* cmd per lun */ 1 , \
- /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING}
+ /* present */ 0, /* unchecked isa dma */ 0, DISABLE_CLUSTERING}
#endif /* defined(HOSTS_C) || defined(MODULE) */
#ifndef HOSTS_C
/* 0x80 - 0x04 are reserved */
#define CTEST0_700_RTRG 0x02 /* Real target mode */
#define CTEST0_700_DDIR 0x01 /* Data direction, 1 =
- * SCSI bus to host, 0 =
- * host to SCSI.
- */
+ * SCSI bus to host, 0 =
+ * host to SCSI.
+ */
#define CTEST1_REG_700 0x15 /* Chip test 1 ro */
#define CTEST1_REG_800 0x19 /* Chip test 1 ro */
#define CTEST7_EVP 0x04 /* 1 = host bus even parity, 0 = odd */
#define CTEST7_10_TT1 0x02 /* Transfer type */
#define CTEST7_00_DC 0x02 /* Set to drive DC low during instruction
- fetch */
+ fetch */
#define CTEST7_DIFF 0x01 /* Differential mode */
#define CTEST7_SAVE ( CTEST7_EVP | CTEST7_DIFF )
* speeds.
*/
#define CTEST8_0066_DAS 0x02 /* Disable automatic target/initiator
- * switching.
- */
+ * switching.
+ */
#define CTEST8_0066_LDE 0x01 /* Last disconnect enable.
* The status of pending
* disconnect is maintained by
volatile struct NCR53c7x0_cmd *next, *prev;
- /* Linux maintained lists. Note that
+ /* Linux maintained lists. Note that
hostdata->free is a singly linked
list; the rest are doubly linked */
+ long dsa_size; /* Size of DSA structure */
u32 *data_transfer_start; /* Start of data transfer routines */
u32 *data_transfer_end; /* Address after end of data transfer o
* NCR53c700-66 = 70066
* NCR53c710 = 710
* NCR53c720 = 720
- * NCR53c810 = 810
+ * NCR53c810 = 810
*/
/*
to other target/lun combinations */
int debug_count_limit; /* Number of commands to execute
- before puking to limit debugging
+ before puking to limit debugging
output */
(offset)]); \
}
-#define patch_abs_rwri_data(script, offset, symbol, value) \
+#define patch_abs_rwri_data(script, offset, symbol, value) \
for (i = 0; i < (sizeof (A_##symbol##_used) / sizeof \
(u32)); ++i) \
(script)[A_##symbol##_used[i] - (offset)] = \
+Mon May 15 19:33:14 1995 Michael Neuffer <neuffer@goofy.zdv.uni-mainz.de>
+ * scsi.c: Added native multichannel and wide scsi support.
+
+ * proc.c (dispatch_scsi_info) (build_proc_dir_hba_entries):
+ Updated /proc/scsi interface.
+
+Thu May 4 17:58:48 1995 Michael Neuffer <neuffer@goofy.zdv.uni-mainz.de>
+
+ * sd.c (requeue_sd_request): zero out the scatterlist only if
+ scsi_malloc returned memory for it.
+
+ * eata_dma.c (register_HBA) (eata_queue): add support for
+ large scatter/gatter tables and set use_clustering accordingly
+
+ * hosts.c: make use_clustering changable in the Scsi_Host structure.
+
Wed Apr 12 15:25:52 1995 Eric Youngdale (eric@andante)
* Linux 1.2.5 released.
complete commands per interrupt. Seems to come up with faster
cards.
- * eata_dma.c: Modularize. Update to 2.3.5r.
+ * eata_dma.c: Update to 2.3.5r. Modularize. Improved error handling
+ thruout and fixed bug interrupt routine which resulted in shifted
+ status bytes. Added blink LED state checks for ISA and EISA HBAs.
+ Memory mamagement bug seems to have disapeared ==> increasing
+ C_P_L_CURRENT_MAX to 16 for now. Decreasing C_P_L_DIV to 3 for
+ performance reasons.
* scsi.c: If we get a FMK, EOM, or ILI when attempting to scan
the bus, assume that it was just noise on the bus, and ignore
* hosts.h: Change io_port to long int from short.
- * 53c7,8xx.c: crash on AEN fixed, SCSI reset is no longer a NOP,
- NULL pointer panic on odd UDCs fixed, two bugs in diagnostic output
- fixed, should initialize correctly if left running, now loadable,
- new memory allocation, extraneous diagnostic output suppressed,
- splx() replaced with save/restore flags. [ Drew ]
+ * 53c7,8xx.c: crash on AEN fixed, SCSI reset is no longer a NOP,
+ NULL pointer panic on odd UDCs fixed, two bugs in diagnostic output
+ fixed, should initialize correctly if left running, now loadable,
+ new memory allocation, extraneous diagnostic output suppressed,
+ splx() replaced with save/restore flags. [ Drew ]
* hosts.c, hosts.h, scsi_ioctl.c, sd.c, sd_ioctl.c, sg.c, sr.c,
sr_ioctl.c: Add special junk at end that Emacs will use for
* eata.c: Update to 1.17.
- * eata_dma.c: Add more support for /proc/scsi, add HBA_interpret flag.
+ * eata_dma.c: Update to 2.31a. Add more support for /proc/scsi.
+ Continuing modularization. Less crashes because of the bug in the
+ memory management ==> increase C_P_L_CURRENT_MAX to 10
+ and decrease C_P_L_DIV to 4.
* hosts.c: If we remove last host registered, reuse host number.
When freeing memory from host being deregistered, free extra_bytes
* NCR5380.c: Update interrupt handler with new arglist. Minor
cleanups.
- * eata_dma.c: Modularize. Add hooks for /proc/scsi.
- New version 2.3.0a.
+ * eata_dma.c: Begin to modularize. Add hooks for /proc/scsi.
+ New version 2.3.0a. Add code in interrupt handler to allow
+ certain CDROM drivers to be detected which return a
+ CHECK_CONDITION during SCSI bus scan. Add opcode check to get
+ all DATA IN and DATA OUT phases right. Utilize HBA_interpret flag.
+ Improvements in HBA identification. Various other minor stuff.
* hosts.c: Initialize ->dma_channel and ->io_port when registering
a new host.
* 53c7,8xx.h: Change SG size to 127.
- * eata_dma: Update to version 0i.
+ * eata_dma: Update to version 2.10i. Remove bug in the registration
+ of multiple HBAs and channels. Minor other improvements and stylistic
+ changes.
* scsi.c: Test for Toshiba XM-3401TA and exclude from detection
as toshiba drive - photo cd does not work with this drive.
* aha152x.c: Update to version 1.8 from Juergen.
- * eata_dma.c: Update from Michael Neuffer
+ * eata_dma.c: Update from Michael Neuffer.
+ Remove hard limit of 2 commands per lun and make it better
+ configurable. Improvements in HBA identification.
* in2000.c: Fix biosparam to support large disks.
* buslogic.c: Likewise.
* eata_dma.c: Use min of 2 cmd_per_lun for OCS_enabled boards.
-
+
* scsi.c: Make RECOVERED_ERROR a SUGGEST_IS_OK.
* sd.c: Fail if we are opening a non-existent partition.
* sr_ioctl.c: Remove CDROMMULTISESSION_SYS ioctl.
* ultrastor.c: Fix bug in call to ultrastor_interrupt (wrong #args).
-
+
Mon Jan 16 07:18:23 1995 Eric Youngdale (eric@andante)
* Linux 1.1.82 released.
-# Makefile for kernel/blk_drv/scsi
+# Makefile for linux/drivers/scsi
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
.c.o:
$(CC) $(CFLAGS) -c $<
+# This is used for ELF - it needs to migrate or be moved.
+LD_RFLAG = -m elf_i386
+
AHA152X = -DDEBUG_AHA152X -DAUTOCONF -DSKIP_BIOSTEST -DIRQ=11
ifeq (${CFLAGS},)
CFLAGS = -D__KERNEL__=1 \
- -Wall -Wstrict-prototypes -I. -I../../include \
+ -DMODULE -Wall -Wstrict-prototypes -I. -I../../include \
-O2 -fomit-frame-pointer -m486
include ../../.config
SCSI_OBJS =
SCSI_SRCS =
+SCSI_DEP =
SCSI_MODULE_OBJS =
-ifdef CONFIG_SCSI
+SCSI_SRCS := hosts.c scsi.c scsi_ioctl.c constants.c scsicam.c scsi_proc.c
-SCSI_OBJS := hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o
-SCSI_SRCS := hosts.c scsi.c scsi_ioctl.c constants.c scsicam.c
+ifdef CONFIG_SCSI
+SCSI_OBJS := hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) scsi_mod.o
+endif
+SCSI_SRCS := $(SCSI_SRCS) st.c
ifdef CONFIG_CHR_DEV_ST
SCSI_OBJS := $(SCSI_OBJS) st.o
-SCSI_SRCS := $(SCSI_SRCS) st.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) st.o
endif
+SCSI_SRCS := $(SCSI_SRCS) sd.c sd_ioctl.c
ifdef CONFIG_BLK_DEV_SD
SCSI_OBJS := $(SCSI_OBJS) sd.o sd_ioctl.o
-SCSI_SRCS := $(SCSI_SRCS) sd.c sd_ioctl.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) sd_mod.o
endif
+SCSI_SRCS := $(SCSI_SRCS) sr.c sr_ioctl.c
ifdef CONFIG_BLK_DEV_SR
SCSI_OBJS := $(SCSI_OBJS) sr.o sr_ioctl.o
-SCSI_SRCS := $(SCSI_SRCS) sr.c sr_ioctl.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) sr_mod.o
endif
+SCSI_SRCS := $(SCSI_SRCS) sg.c
ifdef CONFIG_CHR_DEV_SG
SCSI_OBJS := $(SCSI_OBJS) sg.o
-SCSI_SRCS := $(SCSI_SRCS) sg.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) sg.o
endif
SCSI_SRCS := $(SCSI_SRCS) qlogic.c
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) qlogic.o
endif
+SCSI_SRCS := $(SCSI_SRCS) aha152x.c
ifdef CONFIG_SCSI_AHA152X
SCSI_OBJS := $(SCSI_OBJS) aha152x.o
-SCSI_SRCS := $(SCSI_SRCS) aha152x.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha152x.o
endif
-ifdef CONFIG_SCSI_AHA1542
SCSI_SRCS := $(SCSI_SRCS) aha1542.c
+ifdef CONFIG_SCSI_AHA1542
SCSI_OBJS := $(SCSI_OBJS) aha1542.o
else
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha1542.o
endif
+SCSI_SRCS := $(SCSI_SRCS) aha1740.c
ifdef CONFIG_SCSI_AHA1740
SCSI_OBJS := $(SCSI_OBJS) aha1740.o
-SCSI_SRCS := $(SCSI_SRCS) aha1740.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aha1740.o
endif
+SCSI_SRCS := $(SCSI_SRCS) aic7xxx.c
+SCSI_DEP := $(SCSI_DEP) aic7xxx_seq.h
ifdef CONFIG_SCSI_AIC7XXX
SCSI_OBJS := $(SCSI_OBJS) aic7xxx.o
-SCSI_SRCS := $(SCSI_SRCS) aic7xxx.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) aic7xxx.o
endif
+SCSI_SRCS := $(SCSI_SRCS) buslogic.c
ifdef CONFIG_SCSI_BUSLOGIC
SCSI_OBJS := $(SCSI_OBJS) buslogic.o
-SCSI_SRCS := $(SCSI_SRCS) buslogic.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) buslogic.o
endif
SCSI_SRCS := $(SCSI_SRCS) eata_dma.c
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata_dma.o
endif
+SCSI_SRCS := $(SCSI_SRCS) eata_pio.c
+ifdef CONFIG_SCSI_EATA_PIO
+SCSI_OBJS := $(SCSI_OBJS) eata_pio.o
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata_pio.o
+endif
+
+SCSI_SRCS := $(SCSI_SRCS) u14-34f.c
ifdef CONFIG_SCSI_U14_34F
SCSI_OBJS := $(SCSI_OBJS) u14-34f.o
-SCSI_SRCS := $(SCSI_SRCS) u14-34f.c
else
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) u14-34f.o
endif
-ifdef CONFIG_SCSI_DEBUG
SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c
+ifdef CONFIG_SCSI_DEBUG
SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o
else
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) scsi_debug.o
endif
+SCSI_SRCS := $(SCSI_SRCS) fdomain.c
ifdef CONFIG_SCSI_FUTURE_DOMAIN
SCSI_OBJS := $(SCSI_OBJS) fdomain.o
-SCSI_SRCS := $(SCSI_SRCS) fdomain.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) fdomain.o
endif
-ifdef CONFIG_SCSI_IN2000
SCSI_SRCS := $(SCSI_SRCS) in2000.c
+ifdef CONFIG_SCSI_IN2000
SCSI_OBJS := $(SCSI_OBJS) in2000.o
else
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) in2000.o
endif
+SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c
ifdef CONFIG_SCSI_GENERIC_NCR5380
SCSI_OBJS := $(SCSI_OBJS) g_NCR5380.o
-SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c
endif
+SCSI_SRCS := $(SCSI_SRCS) 53c7,8xx.c
ifdef CONFIG_SCSI_NCR53C7xx
SCSI_OBJS := $(SCSI_OBJS) 53c7,8xx.o
-SCSI_SRCS := $(SCSI_SRCS) 53c7,8xx.c
else
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) 53c7,8xx.o
endif
+SCSI_SRCS := $(SCSI_SRCS) pas16.c
ifdef CONFIG_SCSI_PAS16
SCSI_OBJS := $(SCSI_OBJS) pas16.o
-SCSI_SRCS := $(SCSI_SRCS) pas16.c
endif
+SCSI_SRCS := $(SCSI_SRCS) seagate.c
ifdef CONFIG_SCSI_SEAGATE
SCSI_OBJS := $(SCSI_OBJS) seagate.o
-SCSI_SRCS := $(SCSI_SRCS) seagate.c
else
ifdef CONFIG_SCSI_FD_8xx
SCSI_OBJS := $(SCSI_OBJS) seagate.o
-SCSI_SRCS := $(SCSI_SRCS) seagate.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) seagate.o
endif
endif
+SCSI_SRCS := $(SCSI_SRCS) wd7000.c
ifdef CONFIG_SCSI_7000FASST
SCSI_OBJS := $(SCSI_OBJS) wd7000.o
-SCSI_SRCS := $(SCSI_SRCS) wd7000.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) wd7000.o
endif
+SCSI_SRCS := $(SCSI_SRCS) t128.c
ifdef CONFIG_SCSI_T128
SCSI_OBJS := $(SCSI_OBJS) t128.o
-SCSI_SRCS := $(SCSI_SRCS) t128.c
endif
+SCSI_SRCS := $(SCSI_SRCS) ultrastor.c
ifdef CONFIG_SCSI_ULTRASTOR
SCSI_OBJS := $(SCSI_OBJS) ultrastor.o
-SCSI_SRCS := $(SCSI_SRCS) ultrastor.c
+else
+SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) ultrastor.o
endif
+SCSI_SRCS := $(SCSI_SRCS) eata.c
ifdef CONFIG_SCSI_EATA
SCSI_OBJS := $(SCSI_OBJS) eata.o
-SCSI_SRCS := $(SCSI_SRCS) eata.c
else
SCSI_MODULE_OBJS := $(SCSI_MODULE_OBJS) eata.o
endif
aha152x.o: aha152x.c
$(CC) $(CFLAGS) $(AHA152X) -c aha152x.c
-aic7770: aic7770.c
- $(CC) $(CFLAGS) -o $@ aic7770.c
+aic7xxx_asm: aic7xxx_asm.c
+ $(CC) $(CFLAGS) -o $@ aic7xxx_asm.c
-aic7xxx_seq.h: aic7770 aic7xxx.seq
- ./aic7770 -o $@ aic7xxx.seq
+aic7xxx_seq.h: aic7xxx_asm aic7xxx.seq
+ ./aic7xxx_asm -o $@ aic7xxx.seq
seagate.o: seagate.c
$(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -c seagate.c
mv scriptu.h 53c8xx_u.h
rm fake.c
-modules: $(SCSI_MODULE_OBJS)
- echo $(SCSI_MODULE_OBJS) > ../../modules/SCSI_MODULES
- (cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done)
+scsi_mod.o: hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
+ $(LD) $(LD_RFLAG) -r -o $@ hosts.o scsi.o scsi_ioctl.o constants.o scsicam.o scsi_proc.o
-dep:
- $(CPP) -M $(AHA152X) $(SCSI_SRCS) > .depend
- $(CPP) -M -DMODULE $(SCSI_MODULE_OBJS:.o=.c) >> .depend
+sr_mod.o: sr.o sr_ioctl.o
+ $(LD) $(LD_RFLAG) -r -o $@ sr.o sr_ioctl.o
-else
+sd_mod.o: sd.o sd_ioctl.o
+ $(LD) $(LD_RFLAG) -r -o $@ sd.o sd_ioctl.o
-scsi.a:
- rm -f scsi.a
- @echo No SCSI drivers configured
- $(AR) rcs scsi.a
-dep:
+modules: $(SCSI_MODULE_OBJS)
+ echo $(SCSI_MODULE_OBJS) > ../../modules/SCSI_MODULES
+ (cd ../../modules;for i in $(SCSI_MODULE_OBJS); do ln -sf ../drivers/scsi/$$i .; done)
-endif
+dep: $(SCSI_DEP)
+ $(CPP) -M $(AHA152X) $(SCSI_SRCS) > .depend
+ $(CPP) -M -DMODULE $(patsubst sd_mod.c,sd.c sd_ioctl.c, \
+ $(patsubst sr_mod.c,sr.c sr_ioctl.c, $(SCSI_MODULE_OBJS:.o=.c))) >> .depend
#
# include a dependency file if one exists
cli();
if (!main_running) {
main_running = 1;
- NCR5380_main();
+ NCR5380_main();
/*
- * main_running is cleared in NCR5380_main once it can't do
+ * main_running is cleared in NCR5380_main once it can't do
* more work, and NCR5380_main exits with interrupts disabled.
*/
sti();
#ifndef AUTOSENSE
if ((instance->cmd_per_lun > 1) || instance->can_queue > 1))
printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n"
- " without AUTOSENSE option, contingent allegiance conditions may\n"
- " be incorrectly cleared.\n", instance->host_no);
+ " without AUTOSENSE option, contingent allegiance conditions may\n"
+ " be incorrectly cleared.\n", instance->host_no);
#endif /* def AUTOSENSE */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
&& jiffies < timeout)
;
if (jiffies >= timeout)
- printk("scsi: timeout at %d\n", __LINE__);
+ printk("scsi: timeout at %d\n", __LINE__);
}
#else /* NCR_TIMEOUT */
while (NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK);
NCR5380_setup(instance);
if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
- *phase = tmp;
- return -1;
+ *phase = tmp;
+ return -1;
}
#if defined(REAL_DMA) || defined(REAL_DMA_POLL)
#ifdef READ_OVERRUNS
#ifdef READ_OVERRUNS
udelay(10);
if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH|BASR_ACK)) ==
- (BASR_PHASE_MATCH | BASR_ACK))) {
- saved_data = NCR5380_read(INPUT_DATA_REGISTER);
- overrun = 1;
+ (BASR_PHASE_MATCH | BASR_ACK))) {
+ saved_data = NCR5380_read(INPUT_DATA_REGISTER);
+ overrun = 1;
}
#endif
} else {
int limit = 100;
while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) ||
- (NCR5380_read(STATUS_REG) & SR_REQ)) {
- if (!(tmp & BASR_PHASE_MATCH)) break;
- if (--limit < 0) break;
+ (NCR5380_read(STATUS_REG) & SR_REQ)) {
+ if (!(tmp & BASR_PHASE_MATCH)) break;
+ if (--limit < 0) break;
}
}
if (*phase == p && (p & SR_IO) && residue == 0) {
if (overrun) {
#if (NDEBUG & NDEBUG_DMA)
- printk("Got an input overrun, using saved byte\n");
+ printk("Got an input overrun, using saved byte\n");
#endif
- **data = saved_data;
- *data += 1;
- *count -= 1;
- cnt = toPIO = 1;
+ **data = saved_data;
+ *data += 1;
+ *count -= 1;
+ cnt = toPIO = 1;
} else {
- printk("No overrun??\n");
- cnt = toPIO = 2;
+ printk("No overrun??\n");
+ cnt = toPIO = 2;
}
#if (NDEBUG & NDEBUG_DMA)
printk("Doing %d-byte PIO to 0x%X\n", cnt, *data);
#if 1
while (!(NCR5380_read(BUS_AND_STATUS_REG) &
BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) &
- BASR_PHASE_MATCH));
+ BASR_PHASE_MATCH));
#else
if (NCR5380_read(STATUS_REG) & SR_REQ) {
for (; timeout &&
if (!cmd->device->borken &&
(transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) {
#else
- transfersize = cmd->transfersize;
+ transfersize = cmd->transfersize;
#ifdef LIMIT_TRANSFERSIZE /* If we have problems with interrupt service */
- if( transfersize > 512 )
- transfersize = 512;
+ if( transfersize > 512 )
+ transfersize = 512;
#endif /* LIMIT_TRANSFERSIZE */
- if (!cmd->device->borken && transfersize &&
- cmd->SCp.this_residual && !(cmd->SCp.this_residual %
- transfersize)) {
+ if (!cmd->device->borken && transfersize &&
+ cmd->SCp.this_residual && !(cmd->SCp.this_residual %
+ transfersize)) {
#endif
len = transfersize;
if (NCR5380_transfer_dma(instance, &phase,
cli();
cmd->host_scribble = (unsigned char *)
hostdata->issue_queue;
- hostdata->issue_queue = (Scsi_Cmnd *) cmd;
- sti();
+ hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+ sti();
#if (NDEBUG & NDEBUG_QUEUES)
printk("scsi%d : REQUEST SENSE added to head of issue queue\n");
#endif
sti();
#if (NDEBUG & NDEBUG_QUEUES)
printk("scsi%d : command for target %d lun %d was moved from connected to"
- " the disconnected_queue\n", instance->host_no,
+ " the disconnected_queue\n", instance->host_no,
cmd->target, cmd->lun);
#endif
/*
#if (NDEBUG & NDEBUG_ABORT)
printk("scsi%d : abort failed, command connected.\n", instance->host_no);
#endif
- return SCSI_ABORT_NOT_RUNNING;
+ return SCSI_ABORT_NOT_RUNNING;
}
/*
for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
tmp = (Scsi_Cmnd *) tmp->host_scribble)
- if (cmd == tmp) {
- sti();
+ if (cmd == tmp) {
+ sti();
#if (NDEBUG & NDEBUG_ABORT)
printk("scsi%d : aborting disconnected command.\n", instance->host_no);
#endif
- if (NCR5380_select (instance, cmd, (int) cmd->tag))
+ if (NCR5380_select (instance, cmd, (int) cmd->tag))
return SCSI_ABORT_BUSY;
#if (NDEBUG & NDEBUG_ABORT)
sti();
printk("scsi%d : warning : SCSI command probably completed successfully\n"
- " before abortion\n", instance->host_no);
+ " before abortion\n", instance->host_no);
return SCSI_ABORT_NOT_RUNNING;
}
static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag);
#if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
static int NCR5380_transfer_dma (struct Scsi_Host *instance,
- unsigned char *phase, int *count, unsigned char **data);
+ unsigned char *phase, int *count, unsigned char **data);
#endif
static int NCR5380_transfer_pio (struct Scsi_Host *instance,
- unsigned char *phase, int *count, unsigned char **data);
+ unsigned char *phase, int *count, unsigned char **data);
#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) && defined(i386)
static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance,
+++ /dev/null
-The 274x/284x support is basically the same as in the kernel, with
-some minor structural changes. The 294x support is preliminary, with
-a few things still hardwired (like the SCSI ID and FIFO threshold).
-You have been warned.
-
-To function properly, you must use this with a kernel version 1.1.68
-or above - these have the SCSI changes in the kernel which support
-varying numbers of outstanding SCSI commands per driver instance (they
-also contain the Adaptec PCI definitions).
-
-You can find instructions in the SCSI-HOWTO on how to install SCSI
-drivers into the kernel. In a nutshell, find all the aha274x stuff
-and change it to aic7xxx.
-
-Please direct all problems to the AIC7770 mailing list - see the README
-for details.
-:ja
#include <linux/string.h>
#include <linux/wait.h>
#include <linux/ioport.h>
+#include <linux/proc_fs.h>
#include "aha152x.h"
else
{
for( end=*SC;
- end->host_scribble;
- end = (Scsi_Cmnd *) end->host_scribble )
- ;
+ end->host_scribble;
+ end = (Scsi_Cmnd *) end->host_scribble )
+ ;
end->host_scribble = (unsigned char *) new_SC;
}
}
while( 1 )
{
do
- {
- while( !( ( sstat1 = GETPORT( SSTAT1 ) ) & (BUSFREE|SCSIRSTI|REQINIT ) ) )
- ;
- if( sstat1 & BUSFREE )
- return P_BUSFREE;
- if( sstat1 & SCSIRSTI )
- {
- /* IBM drive responds with RSTI to RSTO */
- printk("aha152x: RESET IN\n");
- SETPORT( SSTAT1, SCSIRSTI );
- }
- }
+ {
+ while( !( ( sstat1 = GETPORT( SSTAT1 ) ) & (BUSFREE|SCSIRSTI|REQINIT ) ) )
+ ;
+ if( sstat1 & BUSFREE )
+ return P_BUSFREE;
+ if( sstat1 & SCSIRSTI )
+ {
+ /* IBM drive responds with RSTI to RSTO */
+ printk("aha152x: RESET IN\n");
+ SETPORT( SSTAT1, SCSIRSTI );
+ }
+ }
while( TESTHI( SCSISIG, ACKI ) || TESTLO( SSTAT1, REQINIT ) );
SETPORT( SSTAT1, CLRSCSIPERR );
phase = GETPORT( SCSISIG ) & P_MASK ;
if( TESTHI( SSTAT1, SCSIPERR ) )
- {
- if( (phase & (CDO|MSGO))==0 ) /* DATA phase */
- return P_PARITY;
+ {
+ if( (phase & (CDO|MSGO))==0 ) /* DATA phase */
+ return P_PARITY;
- make_acklow();
- }
+ make_acklow();
+ }
else
- return phase;
+ return phase;
}
}
#else
if(setup_called>5)
#endif
- {
- printk("\naha152x: %s\n", setup_str );
+ {
+ printk("\naha152x: %s\n", setup_str );
#ifdef DEBUG_AHA152X
- printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>[,<DEBUG>]]]]]\n");
+ printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>[,<DEBUG>]]]]]\n");
#else
- printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>]]]]\n");
+ printk("aha152x: usage: aha152x=<PORTBASE>[,<IRQ>[,<SCSI ID>[,<RECONNECT>[,<PARITY>]]]]\n");
#endif
- panic("aha152x panics in line %d", __LINE__);
- }
+ panic("aha152x panics in line %d", __LINE__);
+ }
port_base = setup_portbase;
interrupt_level = setup_irq;
#ifndef PCMCIA
for( i=0; i<PORT_COUNT && (port_base != ports[i]); i++)
- ;
+ ;
if(i==PORT_COUNT)
- {
- printk("unknown portbase 0x%03x\n", port_base);
- panic("aha152x panics in line %d", __LINE__);
- }
+ {
+ printk("unknown portbase 0x%03x\n", port_base);
+ panic("aha152x panics in line %d", __LINE__);
+ }
#endif
if(!aha152x_porttest(port_base))
- {
- printk("portbase 0x%03x fails probe\n", port_base);
+ {
+ printk("portbase 0x%03x fails probe\n", port_base);
#ifdef PCMCIA
- return 0;
+ return 0;
#else
- panic("aha152x panics in line %d", __LINE__);
+ panic("aha152x panics in line %d", __LINE__);
#endif
- }
+ }
#ifndef PCMCIA
i=0;
while(irqs[i] && (interrupt_level!=irqs[i]))
- i++;
+ i++;
if(!irqs[i])
- {
- printk("illegal IRQ %d\n", interrupt_level);
- panic("aha152x panics in line %d", __LINE__);
- }
+ {
+ printk("illegal IRQ %d\n", interrupt_level);
+ panic("aha152x panics in line %d", __LINE__);
+ }
#endif
if( (this_host < 0) || (this_host > 7) )
- {
- printk("illegal SCSI ID %d\n", this_host);
- panic("aha152x panics in line %d", __LINE__);
- }
+ {
+ printk("illegal SCSI ID %d\n", this_host);
+ panic("aha152x panics in line %d", __LINE__);
+ }
if( (can_disconnect < 0) || (can_disconnect > 1) )
- {
- printk("reconnect %d should be 0 or 1\n", can_disconnect);
- panic("aha152x panics in line %d", __LINE__);
- }
+ {
+ printk("reconnect %d should be 0 or 1\n", can_disconnect);
+ panic("aha152x panics in line %d", __LINE__);
+ }
if( (can_doparity < 0) || (can_doparity > 1) )
- {
- printk("parity %d should be 0 or 1\n", can_doparity);
- panic("aha152x panics in line %d", __LINE__);
- }
+ {
+ printk("parity %d should be 0 or 1\n", can_doparity);
+ panic("aha152x panics in line %d", __LINE__);
+ }
printk("ok\n");
}
else
ok=0;
for( i=0; i < ADDRESS_COUNT && !ok; i++)
- for( j=0; (j < SIGNATURE_COUNT) && !ok; j++)
- ok=!memcmp((void *) addresses[i]+signatures[j].sig_offset,
- (void *) signatures[j].signature,
- (int) signatures[j].sig_length);
+ for( j=0; (j < SIGNATURE_COUNT) && !ok; j++)
+ ok=!memcmp((void *) addresses[i]+signatures[j].sig_offset,
+ (void *) signatures[j].signature,
+ (int) signatures[j].sig_length);
if(!ok)
- return 0;
+ return 0;
printk("aha152x: BIOS test: passed, ");
#else
#if !defined(PORTBASE)
printk("porttest: ");
for( i=0; i<PORT_COUNT && !aha152x_porttest(ports[i]); i++)
- ;
+ ;
if(i==PORT_COUNT)
- {
- printk("failed\n");
- return 0;
- }
+ {
+ printk("failed\n");
+ return 0;
+ }
else
- port_base=ports[i];
+ port_base=ports[i];
printk("ok, ");
#else
port_base=PORTBASE;
if(ok<0)
{
if(ok == -EINVAL)
- {
- printk("aha152x: bad IRQ %d.\n", interrupt_level);
- printk(" Contact author.\n");
- }
+ {
+ printk("aha152x: bad IRQ %d.\n", interrupt_level);
+ printk(" Contact author.\n");
+ }
else
- if( ok == -EBUSY)
- printk( "aha152x: IRQ %d already in use. Configure another.\n",
- interrupt_level);
- else
- {
- printk( "\naha152x: Unexpected error code on requesting IRQ %d.\n",
- interrupt_level);
- printk(" Contact author.\n");
- }
+ if( ok == -EBUSY)
+ printk( "aha152x: IRQ %d already in use. Configure another.\n",
+ interrupt_level);
+ else
+ {
+ printk( "\naha152x: Unexpected error code on requesting IRQ %d.\n",
+ interrupt_level);
+ printk(" Contact author.\n");
+ }
panic("aha152x: driver needs an IRQ.\n");
}
aha152x_reset(NULL);
printk("aha152x: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d, reconnect=%s, parity=%s\n",
- port_base,
- interrupt_level,
- this_host,
- can_disconnect ? "enabled" : "disabled",
- can_doparity ? "enabled" : "disabled");
+ port_base,
+ interrupt_level,
+ this_host,
+ can_disconnect ? "enabled" : "disabled",
+ can_doparity ? "enabled" : "disabled");
request_region(port_base, 0x20, "aha152x"); /* Register */
printk( "SCpnt (target = %d lun = %d cmnd = ", SCpnt->target, SCpnt->lun);
print_command(SCpnt->cmnd);
printk( ", cmd_len=%d, pieces = %d size = %u), ",
- SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen );
+ SCpnt->cmd_len, SCpnt->use_sg, SCpnt->request_bufflen );
disp_ports();
}
#endif
SCpnt->SCp.buffer = NULL;
SCpnt->SCp.buffers_residual = 0;
}
-
+
SCpnt->SCp.Status = CHECK_CONDITION;
SCpnt->SCp.Message = 0;
SCpnt->SCp.have_data_in = 0;
{
/* dequeue */
if(prev)
- prev->host_scribble = ptr->host_scribble;
+ prev->host_scribble = ptr->host_scribble;
else
- issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
+ issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
restore_flags(flags);
ptr->host_scribble = NULL;
/* fail abortion, if bus is busy */
if(!current_SC)
- printk("bus busy w/o current command, ");
+ printk("bus busy w/o current command, ");
restore_flags(flags);
return SCSI_ABORT_BUSY;
if(ptr)
if(!aborting)
{
- /* dequeue */
- if(prev)
- prev->host_scribble = ptr->host_scribble;
- else
- disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
+ /* dequeue */
+ if(prev)
+ prev->host_scribble = ptr->host_scribble;
+ else
+ disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
- /* set command current and initiate selection,
- let the interrupt routine take care of the abortion */
- current_SC = ptr;
- ptr->SCp.phase = in_selection|aborted;
- SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
+ /* set command current and initiate selection,
+ let the interrupt routine take care of the abortion */
+ current_SC = ptr;
+ ptr->SCp.phase = in_selection|aborted;
+ SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
- /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
- SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
- SETPORT( SIMODE1, ENSELTIMO );
+ /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
+ SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
+ SETPORT( SIMODE1, ENSELTIMO );
- /* Enable SELECTION OUT sequence */
- SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
+ /* Enable SELECTION OUT sequence */
+ SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
- SETBITS( DMACNTRL0, INTEN );
- abort_result=SCSI_ABORT_SUCCESS;
- aborting++;
- abortion_complete=0;
+ SETBITS( DMACNTRL0, INTEN );
+ abort_result=SCSI_ABORT_SUCCESS;
+ aborting++;
+ abortion_complete=0;
- sti(); /* Hi Eric, guess what ;-) */
+ sti(); /* Hi Eric, guess what ;-) */
- /* sleep until the abortion is complete */
- while(!abortion_complete)
+ /* sleep until the abortion is complete */
+ while(!abortion_complete)
barrier();
- aborting=0;
- return abort_result;
+ aborting=0;
+ return abort_result;
}
else
{
- /* we're already aborting a command */
- restore_flags(flags);
- return SCSI_ABORT_BUSY;
+ /* we're already aborting a command */
+ restore_flags(flags);
+ return SCSI_ABORT_BUSY;
}
/* command wasn't found */
#endif
if(current_SC && !current_SC->device->soft_reset)
- {
- current_SC->host_scribble = NULL;
- current_SC->result = DID_RESET << 16;
- current_SC->done(current_SC);
- current_SC=NULL;
- }
+ {
+ current_SC->host_scribble = NULL;
+ current_SC->result = DID_RESET << 16;
+ current_SC->done(current_SC);
+ current_SC=NULL;
+ }
save_flags(flags);
cli();
#if defined( DEBUG_RESET )
if(aha152x_debug & debug_reset)
{
- printk("commands on targets w/ soft-resets:\n");
- show_queues();
+ printk("commands on targets w/ soft-resets:\n");
+ show_queues();
}
#endif
if(aha152x_debug & debug_biosparam)
{
printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
- info_array[0], info_array[1], info_array[2]);
+ info_array[0], info_array[1], info_array[2]);
printk("WARNING: check, if the bios geometry is correct.\n");
}
#endif
{
#if defined(DEBUG_DONE)
if(aha152x_debug & debug_done)
- printk("done(%x), ", error);
+ printk("done(%x), ", error);
#endif
save_flags(flags);
/* turn led off, when no commands are in the driver */
commands--;
if(!commands)
- SETPORT( PORTA, 0 ); /* turn led off */
+ SETPORT( PORTA, 0 ); /* turn led off */
#if defined(DEBUG_QUEUES)
if(aha152x_debug & debug_queues)
- printk("ok (%d), ", commands);
+ printk("ok (%d), ", commands);
#endif
restore_flags(flags);
#if defined(DEBUG_PHASES)
if(aha152x_debug & debug_phases)
- printk("BUS FREE loop, ");
+ printk("BUS FREE loop, ");
#endif
while( TESTLO( SSTAT1, BUSFREE ) )
- ;
+ ;
#if defined(DEBUG_PHASES)
if(aha152x_debug & debug_phases)
- printk("BUS FREE\n");
+ printk("BUS FREE\n");
#endif
done_SC->result = error;
if(done_SC->scsi_done)
- {
+ {
#if defined(DEBUG_DONE)
- if(aha152x_debug & debug_done)
- printk("calling scsi_done, ");
+ if(aha152x_debug & debug_done)
+ printk("calling scsi_done, ");
#endif
- done_SC->scsi_done( done_SC );
+ done_SC->scsi_done( done_SC );
#if defined(DEBUG_DONE)
- if(aha152x_debug & debug_done)
- printk("done returned, ");
+ if(aha152x_debug & debug_done)
+ printk("done returned, ");
#endif
- }
+ }
else
- panic( "aha152x: current_SC->scsi_done() == NULL" );
+ panic( "aha152x: current_SC->scsi_done() == NULL" );
}
else
aha152x_panic( "done() called outside of command" );
int identify_msg, target, i;
/* Avoid conflicts when a target reconnects
- while we are trying to connect to another. */
+ while we are trying to connect to another. */
if(current_SC)
- {
+ {
#if defined(DEBUG_QUEUES)
if(aha152x_debug & debug_queues)
- printk("i+, ");
+ printk("i+, ");
#endif
save_flags(flags);
- cli();
- append_SC( &issue_SC, current_SC);
- current_SC=NULL;
- restore_flags(flags);
- }
+ cli();
+ append_SC( &issue_SC, current_SC);
+ current_SC=NULL;
+ restore_flags(flags);
+ }
/* disable sequences */
SETPORT( SCSISEQ, 0 );
#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_queues|debug_phases))
- printk("reselected, ");
+ printk("reselected, ");
#endif
i = GETPORT(SELID) & ~(1 << this_host);
target=0;
if(i)
- for( ; (i & 1)==0; target++, i>>=1)
- ;
+ for( ; (i & 1)==0; target++, i>>=1)
+ ;
else
- aha152x_panic("reconnecting target unknown");
+ aha152x_panic("reconnecting target unknown");
#if defined(DEBUG_QUEUES)
if(aha152x_debug & debug_queues)
- printk("SELID=%02x, target=%d, ", GETPORT(SELID), target );
+ printk("SELID=%02x, target=%d, ", GETPORT(SELID), target );
#endif
SETPORT( SCSIID, (this_host << OID_) | target );
SETPORT( SCSISEQ, ENRESELI );
if(TESTLO( SSTAT0, SELDI ))
- aha152x_panic("RESELI failed");
+ aha152x_panic("RESELI failed");
SETPORT( SCSISIG, P_MSGI );
/* Get identify message */
if((i=getphase())!=P_MSGI)
- {
- printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
- aha152x_panic("unknown lun");
- }
+ {
+ printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
+ aha152x_panic("unknown lun");
+ }
SETPORT( SCSISEQ, 0 );
SETPORT( SXFRCTL0, CH1);
identify_msg = GETPORT(SCSIBUS);
if(!(identify_msg & IDENTIFY_BASE))
- {
- printk("target=%d, inbound message (%02x) != IDENTIFY\n",
- target, identify_msg);
- aha152x_panic("unknown lun");
- }
+ {
+ printk("target=%d, inbound message (%02x) != IDENTIFY\n",
+ target, identify_msg);
+ aha152x_panic("unknown lun");
+ }
make_acklow();
getphase();
#if defined(DEBUG_QUEUES)
if(aha152x_debug & debug_queues)
- printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
+ printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
#endif
save_flags(flags);
#if defined(DEBUG_QUEUES)
if(aha152x_debug & debug_queues)
- printk("d-, ");
+ printk("d-, ");
#endif
current_SC = remove_SC( &disconnected_SC,
- target,
- identify_msg & 0x3f );
+ target,
+ identify_msg & 0x3f );
if(!current_SC)
- {
- printk("lun=%d, ", identify_msg & 0x3f );
- aha152x_panic("no disconnected command for that lun");
- }
+ {
+ printk("lun=%d, ", identify_msg & 0x3f );
+ aha152x_panic("no disconnected command for that lun");
+ }
current_SC->SCp.phase &= ~disconnected;
restore_flags(flags);
{
/* bus is free to issue a queued command */
if(TESTHI( SSTAT1, BUSFREE) && issue_SC)
- {
- save_flags(flags);
- cli();
+ {
+ save_flags(flags);
+ cli();
#if defined(DEBUG_QUEUES)
- if(aha152x_debug & debug_queues)
- printk("i-, ");
+ if(aha152x_debug & debug_queues)
+ printk("i-, ");
#endif
- current_SC = remove_first_SC( &issue_SC );
- restore_flags(flags);
+ current_SC = remove_first_SC( &issue_SC );
+ restore_flags(flags);
#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
- printk("issuing command, ");
+ printk("issuing command, ");
#endif
- current_SC->SCp.phase = in_selection;
+ current_SC->SCp.phase = in_selection;
#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_intr|debug_selection|debug_phases))
- printk("selecting %d, ", current_SC->target);
+ printk("selecting %d, ", current_SC->target);
#endif
- SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
+ SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
- /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
- SETPORT( SXFRCTL1, can_doparity ? (ENSPCHK|ENSTIMER) : ENSTIMER);
+ /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
+ SETPORT( SXFRCTL1, can_doparity ? (ENSPCHK|ENSTIMER) : ENSTIMER);
- /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
- SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
- SETPORT( SIMODE1, ENSELTIMO );
+ /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
+ SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
+ SETPORT( SIMODE1, ENSELTIMO );
- /* Enable SELECTION OUT sequence */
- SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
-
+ /* Enable SELECTION OUT sequence */
+ SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
+
#if defined(DEBUG_RACE)
- leave_driver("(selecting) intr");
+ leave_driver("(selecting) intr");
#endif
- SETBITS( DMACNTRL0, INTEN );
- return;
- }
+ SETBITS( DMACNTRL0, INTEN );
+ return;
+ }
/* No command we are busy with and no new to issue */
printk("aha152x: ignoring spurious interrupt, nothing to do\n");
if(current_SC->SCp.phase & in_selection)
{
if( TESTLO( SSTAT1, SELTO ) )
- /* no timeout */
- if( TESTHI( SSTAT0, SELDO ) )
- {
- /* clear BUS FREE interrupt */
- SETPORT( SSTAT1, CLRBUSFREE);
+ /* no timeout */
+ if( TESTHI( SSTAT0, SELDO ) )
+ {
+ /* clear BUS FREE interrupt */
+ SETPORT( SSTAT1, CLRBUSFREE);
- /* Disable SELECTION OUT sequence */
- CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
+ /* Disable SELECTION OUT sequence */
+ CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
- /* Disable SELECTION OUT DONE interrupt */
- CLRBITS(SIMODE0, ENSELDO);
- CLRBITS(SIMODE1, ENSELTIMO);
+ /* Disable SELECTION OUT DONE interrupt */
+ CLRBITS(SIMODE0, ENSELDO);
+ CLRBITS(SIMODE1, ENSELTIMO);
- if( TESTLO(SSTAT0, SELDO) )
- {
- printk("aha152x: passing bus free condition\n");
+ if( TESTLO(SSTAT0, SELDO) )
+ {
+ printk("aha152x: passing bus free condition\n");
#if defined(DEBUG_RACE)
- leave_driver("(passing bus free) intr");
+ leave_driver("(passing bus free) intr");
#endif
- SETBITS( DMACNTRL0, INTEN);
+ SETBITS( DMACNTRL0, INTEN);
- if(current_SC->SCp.phase & aborted)
- {
- abort_result=SCSI_ABORT_ERROR;
+ if(current_SC->SCp.phase & aborted)
+ {
+ abort_result=SCSI_ABORT_ERROR;
abortion_complete++;
- }
+ }
- aha152x_done( DID_NO_CONNECT << 16 );
- return;
- }
+ aha152x_done( DID_NO_CONNECT << 16 );
+ return;
+ }
#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_selection|debug_phases))
- printk("SELDO (SELID=%x), ", GETPORT(SELID));
+ printk("SELDO (SELID=%x), ", GETPORT(SELID));
#endif
- /* selection was done */
- SETPORT( SSTAT0, CLRSELDO );
+ /* selection was done */
+ SETPORT( SSTAT0, CLRSELDO );
#if defined(DEBUG_ABORT)
- if((aha152x_debug & debug_abort) && (current_SC->SCp.phase & aborted))
- printk("(ABORT) target selected, ");
+ if((aha152x_debug & debug_abort) && (current_SC->SCp.phase & aborted))
+ printk("(ABORT) target selected, ");
#endif
- current_SC->SCp.phase &= ~in_selection;
- current_SC->SCp.phase |= in_other;
+ current_SC->SCp.phase &= ~in_selection;
+ current_SC->SCp.phase |= in_other;
#if defined(DEBUG_RACE)
- leave_driver("(SELDO) intr");
+ leave_driver("(SELDO) intr");
#endif
- SETPORT( SCSISIG, P_MSGO );
+ SETPORT( SCSISIG, P_MSGO );
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENREQINIT|ENBUSFREE );
- SETBITS( DMACNTRL0, INTEN);
- return;
- }
- else
- aha152x_panic("neither timeout nor selection\007");
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENREQINIT|ENBUSFREE );
+ SETBITS( DMACNTRL0, INTEN);
+ return;
+ }
+ else
+ aha152x_panic("neither timeout nor selection\007");
else
- {
+ {
#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_selection|debug_phases))
- printk("SELTO, ");
+ printk("SELTO, ");
#endif
/* end selection attempt */
- CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
+ CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
- /* timeout */
- SETPORT( SSTAT1, CLRSELTIMO );
+ /* timeout */
+ SETPORT( SSTAT1, CLRSELTIMO );
- SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
- SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
- SETBITS( DMACNTRL0, INTEN );
+ SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
+ SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+ SETBITS( DMACNTRL0, INTEN );
#if defined(DEBUG_RACE)
- leave_driver("(SELTO) intr");
+ leave_driver("(SELTO) intr");
#endif
- if(current_SC->SCp.phase & aborted)
- {
+ if(current_SC->SCp.phase & aborted)
+ {
#if defined(DEBUG_ABORT)
if(aha152x_debug & debug_abort)
- printk("(ABORT) selection timeout, ");
-#endif
- abort_result=SCSI_ABORT_ERROR;
- abortion_complete++;
- }
-
- if( TESTLO( SSTAT0, SELINGO ) )
- /* ARBITRATION not won */
- aha152x_done( DID_BUS_BUSY << 16 );
- else
- /* ARBITRATION won, but SELECTION failed */
- aha152x_done( DID_NO_CONNECT << 16 );
- return;
- }
+ printk("(ABORT) selection timeout, ");
+#endif
+ abort_result=SCSI_ABORT_ERROR;
+ abortion_complete++;
+ }
+
+ if( TESTLO( SSTAT0, SELINGO ) )
+ /* ARBITRATION not won */
+ aha152x_done( DID_BUS_BUSY << 16 );
+ else
+ /* ARBITRATION won, but SELECTION failed */
+ aha152x_done( DID_NO_CONNECT << 16 );
+ return;
+ }
}
/* enable interrupt, when target leaves current phase */
{
case P_MSGO: /* MESSAGE OUT */
{
- unsigned char message;
+ unsigned char message;
#if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_intr|debug_msgo|debug_phases))
- printk("MESSAGE OUT, ");
+ if(aha152x_debug & (debug_intr|debug_msgo|debug_phases))
+ printk("MESSAGE OUT, ");
#endif
- if( current_SC->SCp.phase & aborted )
- {
+ if( current_SC->SCp.phase & aborted )
+ {
#if defined(DEBUG_MSGO) || defined(DEBUG_ABORT)
- if(aha152x_debug & (debug_msgo|debug_abort))
- printk("ABORT, ");
-#endif
- message=ABORT;
- }
- else
- /* If we didn't identify yet, do it. Otherwise there's nothing to do,
- but reject (probably we got an message before, that we have to
- reject (SDTR, WDTR, etc.) */
- if( !(current_SC->SCp.phase & sent_ident))
- {
- message=IDENTIFY(can_disconnect,current_SC->lun);
+ if(aha152x_debug & (debug_msgo|debug_abort))
+ printk("ABORT, ");
+#endif
+ message=ABORT;
+ }
+ else
+ /* If we didn't identify yet, do it. Otherwise there's nothing to do,
+ but reject (probably we got an message before, that we have to
+ reject (SDTR, WDTR, etc.) */
+ if( !(current_SC->SCp.phase & sent_ident))
+ {
+ message=IDENTIFY(can_disconnect,current_SC->lun);
#if defined(DEBUG_MSGO)
- if(aha152x_debug & debug_msgo)
- printk("IDENTIFY (reconnect=%s;lun=%d), ",
- can_disconnect ? "enabled" : "disabled", current_SC->lun);
-#endif
- }
- else
- {
- message=MESSAGE_REJECT;
+ if(aha152x_debug & debug_msgo)
+ printk("IDENTIFY (reconnect=%s;lun=%d), ",
+ can_disconnect ? "enabled" : "disabled", current_SC->lun);
+#endif
+ }
+ else
+ {
+ message=MESSAGE_REJECT;
#if defined(DEBUG_MSGO)
- if(aha152x_debug & debug_msgo)
- printk("REJECT, ");
+ if(aha152x_debug & debug_msgo)
+ printk("REJECT, ");
#endif
- }
-
- CLRBITS( SXFRCTL0, ENDMA);
+ }
+
+ CLRBITS( SXFRCTL0, ENDMA);
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE );
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT|ENBUSFREE );
- /* wait for data latch to become ready or a phase change */
- while( TESTLO( DMASTAT, INTSTAT ) )
- ;
+ /* wait for data latch to become ready or a phase change */
+ while( TESTLO( DMASTAT, INTSTAT ) )
+ ;
- if( TESTHI( SSTAT1, PHASEMIS ) )
- aha152x_panic("unable to send message");
+ if( TESTHI( SSTAT1, PHASEMIS ) )
+ aha152x_panic("unable to send message");
- /* Leave MESSAGE OUT after transfer */
- SETPORT( SSTAT1, CLRATNO);
+ /* Leave MESSAGE OUT after transfer */
+ SETPORT( SSTAT1, CLRATNO);
- SETPORT( SCSIDAT, message );
+ SETPORT( SCSIDAT, message );
- make_acklow();
- getphase();
+ make_acklow();
+ getphase();
- if(message==IDENTIFY(can_disconnect,current_SC->lun))
- current_SC->SCp.phase |= sent_ident;
+ if(message==IDENTIFY(can_disconnect,current_SC->lun))
+ current_SC->SCp.phase |= sent_ident;
- if(message==ABORT)
- {
- /* revive abort(); abort() enables interrupts */
- abort_result=SCSI_ABORT_SUCCESS;
- abortion_complete++;
+ if(message==ABORT)
+ {
+ /* revive abort(); abort() enables interrupts */
+ abort_result=SCSI_ABORT_SUCCESS;
+ abortion_complete++;
- current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
+ current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
- /* exit */
- SETBITS( DMACNTRL0, INTEN );
+ /* exit */
+ SETBITS( DMACNTRL0, INTEN );
#if defined(DEBUG_RACE)
- leave_driver("(ABORT) intr");
+ leave_driver("(ABORT) intr");
#endif
- aha152x_done(DID_ABORT<<16);
- return;
- }
+ aha152x_done(DID_ABORT<<16);
+ return;
+ }
}
break;
case P_CMD: /* COMMAND phase */
#if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_intr|debug_cmd|debug_phases))
- printk("COMMAND, ");
+ printk("COMMAND, ");
#endif
if( !(current_SC->SCp.sent_command) )
- {
- if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
- printk("aha152x: P_CMD: %d(%d) bytes left in FIFO, resetting\n",
- GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
-
- /* reset fifo and enable writes */
- SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
- SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
-
- /* clear transfer count and scsi fifo */
- SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
- SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
+ {
+ if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
+ printk("aha152x: P_CMD: %d(%d) bytes left in FIFO, resetting\n",
+ GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
+
+ /* reset fifo and enable writes */
+ SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
+ SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
+
+ /* clear transfer count and scsi fifo */
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
+ SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
- /* missing phase raises INTSTAT */
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+ /* missing phase raises INTSTAT */
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
#if defined(DEBUG_CMD)
- if(aha152x_debug & debug_cmd)
- printk("waiting, ");
+ if(aha152x_debug & debug_cmd)
+ printk("waiting, ");
#endif
- /* wait for FIFO to get empty */
- while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
- ;
+ /* wait for FIFO to get empty */
+ while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
+ ;
- if( TESTHI( SSTAT1, PHASEMIS ) )
- aha152x_panic("target left COMMAND phase");
+ if( TESTHI( SSTAT1, PHASEMIS ) )
+ aha152x_panic("target left COMMAND phase");
#if defined(DEBUG_CMD)
- if(aha152x_debug & debug_cmd)
- {
- printk("DFIFOEMP, outsw (%d bytes, %d words), ",
+ if(aha152x_debug & debug_cmd)
+ {
+ printk("DFIFOEMP, outsw (%d bytes, %d words), ",
current_SC->cmd_len, current_SC->cmd_len >> 1 );
- disp_ports();
- }
+ disp_ports();
+ }
#endif
- outsw( DATAPORT, ¤t_SC->cmnd, current_SC->cmd_len >> 1 );
+ outsw( DATAPORT, ¤t_SC->cmnd, current_SC->cmd_len >> 1 );
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
- {
- printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
- disp_ports();
- }
+ {
+ printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
+ disp_ports();
+ }
#endif
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
- printk("waiting for SEMPTY, ");
+ printk("waiting for SEMPTY, ");
#endif
- /* wait for SCSI FIFO to get empty.
- very important to send complete commands. */
- while( TESTLO ( SSTAT2, SEMPTY ) )
- ;
+ /* wait for SCSI FIFO to get empty.
+ very important to send complete commands. */
+ while( TESTLO ( SSTAT2, SEMPTY ) )
+ ;
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
- printk("SEMPTY, ");
+ printk("SEMPTY, ");
#endif
- CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
- /* transfer can be considered ended, when SCSIEN reads back zero */
- while( TESTHI( SXFRCTL0, SCSIEN ) )
- ;
+ CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+ /* transfer can be considered ended, when SCSIEN reads back zero */
+ while( TESTHI( SXFRCTL0, SCSIEN ) )
+ ;
#if defined(DEBUG_CMD)
if(aha152x_debug & debug_cmd)
- printk("!SEMPTY, ");
+ printk("!SEMPTY, ");
#endif
- CLRBITS(DMACNTRL0, ENDMA);
+ CLRBITS(DMACNTRL0, ENDMA);
#if defined(DEBUG_CMD) || defined(DEBUG_INTR)
- if(debug_cmd & debug_intr)
- printk("sent %d/%d command bytes, ", GETSTCNT(),
- current_SC->cmd_len);
+ if(debug_cmd & debug_intr)
+ printk("sent %d/%d command bytes, ", GETSTCNT(),
+ current_SC->cmd_len);
#endif
- }
+ }
else
- aha152x_panic("Nothing to sent while in COMMAND OUT");
+ aha152x_panic("Nothing to sent while in COMMAND OUT");
break;
case P_MSGI: /* MESSAGE IN phase */
#if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_intr|debug_msgi|debug_phases))
- printk("MESSAGE IN, ");
+ printk("MESSAGE IN, ");
#endif
SETPORT( SXFRCTL0, CH1);
SETPORT( SIMODE1, ENBUSFREE);
while( phase == P_MSGI )
- {
- current_SC->SCp.Message = GETPORT( SCSIBUS );
- switch(current_SC->SCp.Message)
- {
- case DISCONNECT:
+ {
+ current_SC->SCp.Message = GETPORT( SCSIBUS );
+ switch(current_SC->SCp.Message)
+ {
+ case DISCONNECT:
#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_msgi|debug_phases))
- printk("target disconnected, ");
-#endif
- current_SC->SCp.Message = 0;
- current_SC->SCp.phase |= disconnected;
- if(!can_disconnect)
- aha152x_panic("target was not allowed to disconnect");
- break;
-
- case COMMAND_COMPLETE:
+ printk("target disconnected, ");
+#endif
+ current_SC->SCp.Message = 0;
+ current_SC->SCp.phase |= disconnected;
+ if(!can_disconnect)
+ aha152x_panic("target was not allowed to disconnect");
+ break;
+
+ case COMMAND_COMPLETE:
#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_msgi|debug_phases))
- printk("inbound message ( COMMAND COMPLETE ), ");
+ printk("inbound message ( COMMAND COMPLETE ), ");
#endif
- done++;
- break;
+ done++;
+ break;
- case MESSAGE_REJECT:
+ case MESSAGE_REJECT:
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
- printk("inbound message ( MESSAGE REJECT ), ");
+ printk("inbound message ( MESSAGE REJECT ), ");
#endif
- break;
+ break;
- case SAVE_POINTERS:
+ case SAVE_POINTERS:
#if defined(DEBUG_MSGI)
if(aha152x_debug & debug_msgi)
- printk("inbound message ( SAVE DATA POINTERS ), ");
+ printk("inbound message ( SAVE DATA POINTERS ), ");
#endif
- break;
+ break;
- case EXTENDED_MESSAGE:
- {
- int i, code;
+ case EXTENDED_MESSAGE:
+ {
+ int i, code;
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("inbound message ( EXTENDED MESSAGE ), ");
+ if(aha152x_debug & debug_msgi)
+ printk("inbound message ( EXTENDED MESSAGE ), ");
#endif
- make_acklow();
- if(getphase()!=P_MSGI)
- break;
+ make_acklow();
+ if(getphase()!=P_MSGI)
+ break;
- i=GETPORT(SCSIBUS);
+ i=GETPORT(SCSIBUS);
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("length (%d), code ( ", i);
+ if(aha152x_debug & debug_msgi)
+ printk("length (%d), code ( ", i);
#endif
- make_acklow();
- if(getphase()!=P_MSGI)
- break;
+ make_acklow();
+ if(getphase()!=P_MSGI)
+ break;
- code = GETPORT(SCSIBUS);
+ code = GETPORT(SCSIBUS);
- switch( code )
- {
- case 0x00:
+ switch( code )
+ {
+ case 0x00:
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("MODIFY DATA POINTER ");
+ if(aha152x_debug & debug_msgi)
+ printk("MODIFY DATA POINTER ");
#endif
- SETPORT(SCSISIG, P_MSGI|ATNO);
- break;
- case 0x01:
+ SETPORT(SCSISIG, P_MSGI|ATNO);
+ break;
+ case 0x01:
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
+ if(aha152x_debug & debug_msgi)
+ printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
#endif
- SETPORT(SCSISIG, P_MSGI|ATNO);
- break;
- case 0x02:
+ SETPORT(SCSISIG, P_MSGI|ATNO);
+ break;
+ case 0x02:
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("EXTENDED IDENTIFY ");
+ if(aha152x_debug & debug_msgi)
+ printk("EXTENDED IDENTIFY ");
#endif
- break;
- case 0x03:
+ break;
+ case 0x03:
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("WIDE DATA TRANSFER REQUEST ");
+ if(aha152x_debug & debug_msgi)
+ printk("WIDE DATA TRANSFER REQUEST ");
#endif
- SETPORT(SCSISIG, P_MSGI|ATNO);
- break;
- default:
+ SETPORT(SCSISIG, P_MSGI|ATNO);
+ break;
+ default:
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- if( code & 0x80 )
- printk("reserved (%d) ", code );
- else
- printk("vendor specific (%d) ", code);
-#endif
- SETPORT(SCSISIG, P_MSGI|ATNO);
- break;
- }
+ if(aha152x_debug & debug_msgi)
+ if( code & 0x80 )
+ printk("reserved (%d) ", code );
+ else
+ printk("vendor specific (%d) ", code);
+#endif
+ SETPORT(SCSISIG, P_MSGI|ATNO);
+ break;
+ }
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk(" ), data ( ");
+ if(aha152x_debug & debug_msgi)
+ printk(" ), data ( ");
#endif
- while( --i && (make_acklow(), getphase()==P_MSGI))
- {
+ while( --i && (make_acklow(), getphase()==P_MSGI))
+ {
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk("%x ", GETPORT(SCSIBUS) );
+ if(aha152x_debug & debug_msgi)
+ printk("%x ", GETPORT(SCSIBUS) );
#else
- GETPORT(SCSIBUS);
+ GETPORT(SCSIBUS);
#endif
- }
+ }
#if defined(DEBUG_MSGI)
- if(aha152x_debug & debug_msgi)
- printk(" ), ");
-#endif
- /* We reject all extended messages. To do this
- we just enter MSGO by asserting ATN. Since
- we have already identified a REJECT message
- will be sent. */
- SETPORT(SCSISIG, P_MSGI|ATNO);
- }
- break;
+ if(aha152x_debug & debug_msgi)
+ printk(" ), ");
+#endif
+ /* We reject all extended messages. To do this
+ we just enter MSGO by asserting ATN. Since
+ we have already identified a REJECT message
+ will be sent. */
+ SETPORT(SCSISIG, P_MSGI|ATNO);
+ }
+ break;
- default:
- printk("unsupported inbound message %x, ", current_SC->SCp.Message);
- break;
+ default:
+ printk("unsupported inbound message %x, ", current_SC->SCp.Message);
+ break;
- }
+ }
- make_acklow();
- phase=getphase();
- }
+ make_acklow();
+ phase=getphase();
+ }
/* clear SCSI fifo on BUSFREE */
if(phase==P_BUSFREE)
- SETPORT(SXFRCTL0, CH1|CLRCH1);
+ SETPORT(SXFRCTL0, CH1|CLRCH1);
if(current_SC->SCp.phase & disconnected)
- {
- save_flags(flags);
- cli();
+ {
+ save_flags(flags);
+ cli();
#if defined(DEBUG_QUEUES)
if(aha152x_debug & debug_queues)
- printk("d+, ");
+ printk("d+, ");
#endif
- append_SC( &disconnected_SC, current_SC);
- current_SC = NULL;
- restore_flags(flags);
+ append_SC( &disconnected_SC, current_SC);
+ current_SC = NULL;
+ restore_flags(flags);
- SETBITS( SCSISEQ, ENRESELI );
+ SETBITS( SCSISEQ, ENRESELI );
- SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
- SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+ SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
+ SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
- SETBITS( DMACNTRL0, INTEN );
- return;
- }
+ SETBITS( DMACNTRL0, INTEN );
+ return;
+ }
break;
case P_STATUS: /* STATUS IN phase */
#if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
if(aha152x_debug & (debug_status|debug_intr|debug_phases))
- printk("STATUS, ");
+ printk("STATUS, ");
#endif
SETPORT( SXFRCTL0, CH1);
#if defined(DEBUG_STATUS)
if(aha152x_debug & debug_status)
{
- printk("inbound status ");
- print_status( current_SC->SCp.Status );
- printk(", ");
+ printk("inbound status ");
+ print_status( current_SC->SCp.Status );
+ printk(", ");
}
#endif
break;
case P_DATAI: /* DATA IN phase */
{
- int fifodata, data_count, done;
+ int fifodata, data_count, done;
#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_datai|debug_intr|debug_phases))
- printk("DATA IN, ");
+ if(aha152x_debug & (debug_datai|debug_intr|debug_phases))
+ printk("DATA IN, ");
#endif
- if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
- printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
- GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
+ if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT))
+ printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n",
+ GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT));
- /* reset host fifo */
- SETPORT(DMACNTRL0, RSTFIFO);
- SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
+ /* reset host fifo */
+ SETPORT(DMACNTRL0, RSTFIFO);
+ SETPORT(DMACNTRL0, RSTFIFO|ENDMA);
- SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN );
+ SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN );
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
- /* done is set when the FIFO is empty after the target left DATA IN */
- done=0;
+ /* done is set when the FIFO is empty after the target left DATA IN */
+ done=0;
- /* while the target stays in DATA to transfer data */
- while ( !done )
- {
+ /* while the target stays in DATA to transfer data */
+ while ( !done )
+ {
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
- printk("expecting data, ");
-#endif
- /* wait for PHASEMIS or full FIFO */
- while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) )
- ;
-
- if( TESTHI( DMASTAT, DFIFOFULL ) )
- fifodata=GETPORT(FIFOSTAT);
- else
- {
- /* wait for SCSI fifo to get empty */
- while( TESTLO( SSTAT2, SEMPTY ) )
- ;
-
- /* rest of data in FIFO */
- fifodata=GETPORT(FIFOSTAT);
+ if(aha152x_debug & debug_datai)
+ printk("expecting data, ");
+#endif
+ /* wait for PHASEMIS or full FIFO */
+ while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) )
+ ;
+
+ if( TESTHI( DMASTAT, DFIFOFULL ) )
+ fifodata=GETPORT(FIFOSTAT);
+ else
+ {
+ /* wait for SCSI fifo to get empty */
+ while( TESTLO( SSTAT2, SEMPTY ) )
+ ;
+
+ /* rest of data in FIFO */
+ fifodata=GETPORT(FIFOSTAT);
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
- printk("last transfer, ");
+ if(aha152x_debug & debug_datai)
+ printk("last transfer, ");
#endif
- done=1;
- }
+ done=1;
+ }
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
- printk("fifodata=%d, ", fifodata);
+ if(aha152x_debug & debug_datai)
+ printk("fifodata=%d, ", fifodata);
#endif
- while( fifodata && current_SC->SCp.this_residual )
- {
- data_count=fifodata;
+ while( fifodata && current_SC->SCp.this_residual )
+ {
+ data_count=fifodata;
- /* limit data transfer to size of first sg buffer */
- if (data_count > current_SC->SCp.this_residual)
- data_count = current_SC->SCp.this_residual;
+ /* limit data transfer to size of first sg buffer */
+ if (data_count > current_SC->SCp.this_residual)
+ data_count = current_SC->SCp.this_residual;
- fifodata -= data_count;
+ fifodata -= data_count;
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
- printk("data_count=%d, ", data_count);
+ if(aha152x_debug & debug_datai)
+ printk("data_count=%d, ", data_count);
#endif
- if(data_count&1)
- {
- /* get a single byte in byte mode */
- SETBITS(DMACNTRL0, _8BIT );
- *current_SC->SCp.ptr++ = GETPORT( DATAPORT );
- current_SC->SCp.this_residual--;
- }
- if(data_count>1)
- {
- CLRBITS(DMACNTRL0, _8BIT );
- data_count >>= 1; /* Number of words */
- insw( DATAPORT, current_SC->SCp.ptr, data_count );
+ if(data_count&1)
+ {
+ /* get a single byte in byte mode */
+ SETBITS(DMACNTRL0, _8BIT );
+ *current_SC->SCp.ptr++ = GETPORT( DATAPORT );
+ current_SC->SCp.this_residual--;
+ }
+ if(data_count>1)
+ {
+ CLRBITS(DMACNTRL0, _8BIT );
+ data_count >>= 1; /* Number of words */
+ insw( DATAPORT, current_SC->SCp.ptr, data_count );
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
+ if(aha152x_debug & debug_datai)
/* show what comes with the last transfer */
- if(done)
- {
- int i;
- unsigned char *data;
+ if(done)
+ {
+ int i;
+ unsigned char *data;
- printk("data on last transfer (%d bytes: ",
- 2*data_count);
- data = (unsigned char *) current_SC->SCp.ptr;
- for( i=0; i<2*data_count; i++)
- printk("%2x ", *data++);
- printk("), ");
- }
-#endif
- current_SC->SCp.ptr += 2 * data_count;
- current_SC->SCp.this_residual -= 2 * data_count;
- }
-
- /* if this buffer is full and there are more buffers left */
- if (!current_SC->SCp.this_residual &&
- current_SC->SCp.buffers_residual)
- {
- /* advance to next buffer */
- current_SC->SCp.buffers_residual--;
- current_SC->SCp.buffer++;
- current_SC->SCp.ptr =
- current_SC->SCp.buffer->address;
- current_SC->SCp.this_residual =
- current_SC->SCp.buffer->length;
- }
- }
+ printk("data on last transfer (%d bytes: ",
+ 2*data_count);
+ data = (unsigned char *) current_SC->SCp.ptr;
+ for( i=0; i<2*data_count; i++)
+ printk("%2x ", *data++);
+ printk("), ");
+ }
+#endif
+ current_SC->SCp.ptr += 2 * data_count;
+ current_SC->SCp.this_residual -= 2 * data_count;
+ }
+
+ /* if this buffer is full and there are more buffers left */
+ if (!current_SC->SCp.this_residual &&
+ current_SC->SCp.buffers_residual)
+ {
+ /* advance to next buffer */
+ current_SC->SCp.buffers_residual--;
+ current_SC->SCp.buffer++;
+ current_SC->SCp.ptr =
+ current_SC->SCp.buffer->address;
+ current_SC->SCp.this_residual =
+ current_SC->SCp.buffer->length;
+ }
+ }
- /*
- * Fifo should be empty
- */
- if(fifodata>0)
- {
- printk("aha152x: more data than expected (%d bytes)\n",
- GETPORT(FIFOSTAT));
- SETBITS(DMACNTRL0, _8BIT );
- printk("aha152x: data ( ");
- while(fifodata--)
- printk("%2x ", GETPORT( DATAPORT ));
- printk(")\n");
- }
+ /*
+ * Fifo should be empty
+ */
+ if(fifodata>0)
+ {
+ printk("aha152x: more data than expected (%d bytes)\n",
+ GETPORT(FIFOSTAT));
+ SETBITS(DMACNTRL0, _8BIT );
+ printk("aha152x: data ( ");
+ while(fifodata--)
+ printk("%2x ", GETPORT( DATAPORT ));
+ printk(")\n");
+ }
#if defined(DEBUG_DATAI)
- if(aha152x_debug & debug_datai)
- if(!fifodata)
- printk("fifo empty, ");
- else
- printk("something left in fifo, ");
+ if(aha152x_debug & debug_datai)
+ if(!fifodata)
+ printk("fifo empty, ");
+ else
+ printk("something left in fifo, ");
#endif
- }
+ }
#if defined(DEBUG_DATAI)
- if((aha152x_debug & debug_datai) && (current_SC->SCp.buffers_residual || current_SC->SCp.this_residual))
- printk("left buffers (buffers=%d, bytes=%d), ",
- current_SC->SCp.buffers_residual,
- current_SC->SCp.this_residual);
+ if((aha152x_debug & debug_datai) && (current_SC->SCp.buffers_residual || current_SC->SCp.this_residual))
+ printk("left buffers (buffers=%d, bytes=%d), ",
+ current_SC->SCp.buffers_residual,
+ current_SC->SCp.this_residual);
#endif
- /* transfer can be considered ended, when SCSIEN reads back zero */
- CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
- while( TESTHI( SXFRCTL0, SCSIEN ) )
- ;
- CLRBITS(DMACNTRL0, ENDMA );
+ /* transfer can be considered ended, when SCSIEN reads back zero */
+ CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+ while( TESTHI( SXFRCTL0, SCSIEN ) )
+ ;
+ CLRBITS(DMACNTRL0, ENDMA );
#if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
- if(aha152x_debug & (debug_datai|debug_intr))
- printk("got %d bytes, ", GETSTCNT());
+ if(aha152x_debug & (debug_datai|debug_intr))
+ printk("got %d bytes, ", GETSTCNT());
#endif
- current_SC->SCp.have_data_in++;
+ current_SC->SCp.have_data_in++;
}
break;
case P_DATAO: /* DATA OUT phase */
{
- int data_count;
+ int data_count;
#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
- if(aha152x_debug & (debug_datao|debug_intr|debug_phases))
- printk("DATA OUT, ");
+ if(aha152x_debug & (debug_datao|debug_intr|debug_phases))
+ printk("DATA OUT, ");
#endif
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
- printk("got data to send (bytes=%d, buffers=%d), ",
- current_SC->SCp.this_residual,
- current_SC->SCp.buffers_residual );
+ if(aha152x_debug & debug_datao)
+ printk("got data to send (bytes=%d, buffers=%d), ",
+ current_SC->SCp.this_residual,
+ current_SC->SCp.buffers_residual );
#endif
- if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT) )
- {
- printk("%d(%d) left in FIFO, ", GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT) );
- aha152x_panic("FIFO should be empty");
- }
+ if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT) )
+ {
+ printk("%d(%d) left in FIFO, ", GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT) );
+ aha152x_panic("FIFO should be empty");
+ }
- SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
- SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
+ SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
+ SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
- SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
- SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
+ SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
- SETPORT( SIMODE0, 0 );
- SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
-
- /* while current buffer is not empty or
- there are more buffers to transfer */
- while( TESTLO( SSTAT1, PHASEMIS ) &&
- (current_SC->SCp.this_residual ||
- current_SC->SCp.buffers_residual) )
- {
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+
+ /* while current buffer is not empty or
+ there are more buffers to transfer */
+ while( TESTLO( SSTAT1, PHASEMIS ) &&
+ (current_SC->SCp.this_residual ||
+ current_SC->SCp.buffers_residual) )
+ {
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
- printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
- current_SC->SCp.this_residual,
- current_SC->SCp.buffers_residual);
+ if(aha152x_debug & debug_datao)
+ printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
+ current_SC->SCp.this_residual,
+ current_SC->SCp.buffers_residual);
#endif
- /* transfer rest of buffer, but max. 128 byte */
- data_count = current_SC->SCp.this_residual > 128 ?
- 128 : current_SC->SCp.this_residual ;
+ /* transfer rest of buffer, but max. 128 byte */
+ data_count = current_SC->SCp.this_residual > 128 ?
+ 128 : current_SC->SCp.this_residual ;
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
- printk("data_count=%d, ", data_count);
+ if(aha152x_debug & debug_datao)
+ printk("data_count=%d, ", data_count);
#endif
- if(data_count&1)
- {
- /* put a single byte in byte mode */
- SETBITS(DMACNTRL0, _8BIT );
- SETPORT(DATAPORT, *current_SC->SCp.ptr++);
- current_SC->SCp.this_residual--;
- }
- if(data_count>1)
- {
- CLRBITS(DMACNTRL0, _8BIT );
- data_count >>= 1; /* Number of words */
- outsw( DATAPORT, current_SC->SCp.ptr, data_count );
- current_SC->SCp.ptr += 2 * data_count;
- current_SC->SCp.this_residual -= 2 * data_count;
- }
-
- /* wait for FIFO to get empty */
- while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
- ;
+ if(data_count&1)
+ {
+ /* put a single byte in byte mode */
+ SETBITS(DMACNTRL0, _8BIT );
+ SETPORT(DATAPORT, *current_SC->SCp.ptr++);
+ current_SC->SCp.this_residual--;
+ }
+ if(data_count>1)
+ {
+ CLRBITS(DMACNTRL0, _8BIT );
+ data_count >>= 1; /* Number of words */
+ outsw( DATAPORT, current_SC->SCp.ptr, data_count );
+ current_SC->SCp.ptr += 2 * data_count;
+ current_SC->SCp.this_residual -= 2 * data_count;
+ }
+
+ /* wait for FIFO to get empty */
+ while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
+ ;
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
- printk("fifo (%d bytes), transfered (%d bytes), ",
- GETPORT(FIFOSTAT), GETSTCNT() );
-#endif
-
- /* if this buffer is empty and there are more buffers left */
- if ( TESTLO( SSTAT1, PHASEMIS ) &&
- !current_SC->SCp.this_residual &&
- current_SC->SCp.buffers_residual)
- {
- /* advance to next buffer */
- current_SC->SCp.buffers_residual--;
- current_SC->SCp.buffer++;
- current_SC->SCp.ptr =
- current_SC->SCp.buffer->address;
- current_SC->SCp.this_residual =
- current_SC->SCp.buffer->length;
- }
- }
-
- if ( current_SC->SCp.this_residual ||
- current_SC->SCp.buffers_residual )
- {
- /* target leaves DATA OUT for an other phase
- (perhaps disconnect) */
-
- /* data in fifos has to be resend */
- data_count = GETPORT(SSTAT2) & (SFULL|SFCNT);
-
- data_count += GETPORT(FIFOSTAT) ;
- current_SC->SCp.ptr -= data_count;
- current_SC->SCp.this_residual += data_count;
+ if(aha152x_debug & debug_datao)
+ printk("fifo (%d bytes), transfered (%d bytes), ",
+ GETPORT(FIFOSTAT), GETSTCNT() );
+#endif
+
+ /* if this buffer is empty and there are more buffers left */
+ if ( TESTLO( SSTAT1, PHASEMIS ) &&
+ !current_SC->SCp.this_residual &&
+ current_SC->SCp.buffers_residual)
+ {
+ /* advance to next buffer */
+ current_SC->SCp.buffers_residual--;
+ current_SC->SCp.buffer++;
+ current_SC->SCp.ptr =
+ current_SC->SCp.buffer->address;
+ current_SC->SCp.this_residual =
+ current_SC->SCp.buffer->length;
+ }
+ }
+
+ if ( current_SC->SCp.this_residual ||
+ current_SC->SCp.buffers_residual )
+ {
+ /* target leaves DATA OUT for an other phase
+ (perhaps disconnect) */
+
+ /* data in fifos has to be resend */
+ data_count = GETPORT(SSTAT2) & (SFULL|SFCNT);
+
+ data_count += GETPORT(FIFOSTAT) ;
+ current_SC->SCp.ptr -= data_count;
+ current_SC->SCp.this_residual += data_count;
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
- printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ",
- current_SC->SCp.this_residual,
- current_SC->SCp.buffers_residual,
- data_count );
-#endif
- SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
- CLRBITS(SXFRCTL0, SCSIEN|DMAEN );
- CLRBITS(DMACNTRL0, ENDMA);
- }
- else
- {
+ if(aha152x_debug & debug_datao)
+ printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ",
+ current_SC->SCp.this_residual,
+ current_SC->SCp.buffers_residual,
+ data_count );
+#endif
+ SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
+ CLRBITS(SXFRCTL0, SCSIEN|DMAEN );
+ CLRBITS(DMACNTRL0, ENDMA);
+ }
+ else
+ {
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
- printk("waiting for SCSI fifo to get empty, ");
+ if(aha152x_debug & debug_datao)
+ printk("waiting for SCSI fifo to get empty, ");
#endif
- /* wait for SCSI fifo to get empty */
- while( TESTLO( SSTAT2, SEMPTY ) )
- ;
+ /* wait for SCSI fifo to get empty */
+ while( TESTLO( SSTAT2, SEMPTY ) )
+ ;
#if defined(DEBUG_DATAO)
- if(aha152x_debug & debug_datao)
- printk("ok, left data (bytes=%d, buffers=%d) ",
- current_SC->SCp.this_residual,
- current_SC->SCp.buffers_residual);
+ if(aha152x_debug & debug_datao)
+ printk("ok, left data (bytes=%d, buffers=%d) ",
+ current_SC->SCp.this_residual,
+ current_SC->SCp.buffers_residual);
#endif
- CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+ CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
- /* transfer can be considered ended, when SCSIEN reads back zero */
- while( TESTHI( SXFRCTL0, SCSIEN ) )
- ;
+ /* transfer can be considered ended, when SCSIEN reads back zero */
+ while( TESTHI( SXFRCTL0, SCSIEN ) )
+ ;
- CLRBITS(DMACNTRL0, ENDMA);
- }
+ CLRBITS(DMACNTRL0, ENDMA);
+ }
#if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
- if(aha152x_debug & (debug_datao|debug_intr))
- printk("sent %d data bytes, ", GETSTCNT() );
+ if(aha152x_debug & (debug_datao|debug_intr))
+ printk("sent %d data bytes, ", GETSTCNT() );
#endif
}
break;
#endif
#if defined(DEBUG_PHASES)
if(aha152x_debug & debug_phases)
- printk("unexpected BUS FREE, ");
+ printk("unexpected BUS FREE, ");
#endif
current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
{
#if defined(DEBUG_INTR)
if(aha152x_debug & debug_intr)
- printk("command done.\n");
+ printk("command done.\n");
#endif
#if defined(DEBUG_RACE)
leave_driver("(done) intr");
SETBITS( DMACNTRL0, INTEN );
aha152x_done( (current_SC->SCp.Status & 0xff)
- | ( (current_SC->SCp.Message & 0xff) << 8)
- | ( DID_OK << 16) );
+ | ( (current_SC->SCp.Message & 0xff) << 8)
+ | ( DID_OK << 16) );
#if defined(DEBUG_RACE)
printk("done returned (DID_OK: Status=%x; Message=%x).\n",
- current_SC->SCp.Status, current_SC->SCp.Message);
+ current_SC->SCp.Status, current_SC->SCp.Message);
#endif
return;
}
static void show_command(Scsi_Cmnd *ptr)
{
printk("0x%08x: target=%d; lun=%d; cmnd=( ",
- (unsigned int) ptr, ptr->target, ptr->lun);
+ (unsigned int) ptr, ptr->target, ptr->lun);
print_command(ptr->cmnd);
printk("); residual=%d; buffers=%d; phase |",
- ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+ ptr->SCp.this_residual, ptr->SCp.buffers_residual);
if( ptr->SCp.phase & not_issued ) printk("not issued|");
if( ptr->SCp.phase & in_selection ) printk("in selection|");
{
printk("; in other(");
switch( (ptr->SCp.phase >> 16) & P_MASK )
- {
- case P_DATAO:
- printk("DATA OUT");
- break;
- case P_DATAI:
- printk("DATA IN");
- break;
- case P_CMD:
- printk("COMMAND");
- break;
- case P_STATUS:
- printk("STATUS");
- break;
- case P_MSGO:
- printk("MESSAGE OUT");
- break;
- case P_MSGI:
- printk("MESSAGE IN");
- break;
- default:
- printk("*illegal*");
- break;
- }
+ {
+ case P_DATAO:
+ printk("DATA OUT");
+ break;
+ case P_DATAI:
+ printk("DATA IN");
+ break;
+ case P_CMD:
+ printk("COMMAND");
+ break;
+ case P_STATUS:
+ printk("STATUS");
+ break;
+ case P_MSGO:
+ printk("MESSAGE OUT");
+ break;
+ case P_MSGI:
+ printk("MESSAGE IN");
+ break;
+ default:
+ printk("*illegal*");
+ break;
+ }
printk(")");
if(ptr->SCp.phase & (1<<16))
- printk("; phaseend");
+ printk("; phaseend");
}
printk("; next=0x%08x\n", (unsigned int) ptr->host_scribble);
}
disp_enintr();
restore_flags(flags);
}
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = AHA152X;
+
+#include "scsi_module.c"
+#endif
int aha152x_reset(Scsi_Cmnd *);
int aha152x_biosparam(Disk *, int, int*);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
/* number of queueable commands
(unless we support more than 1 cmd_per_lun this should do) */
#define AHA152X_MAXQUEUE 7
/* Initial value of Scsi_Host entry */
#define AHA152X { /* next */ NULL, \
/* usage_count */ NULL, \
+ generic_proc_info, \
+ "aha152x", \
+ PROC_SCSI_AHA152X, \
/* name */ AHA152X_REVID, \
/* detect */ aha152x_detect, \
/* release */ NULL, \
- /* info */ NULL, \
+ /* info */ NULL, \
/* command */ aha152x_command, \
/* queuecommand */ aha152x_queue, \
- /* abort */ aha152x_abort, \
- /* reset */ aha152x_reset, \
- /* slave_attach */ /* NULL */ 0, \
- /* bios_param */ aha152x_biosparam, \
+ /* abort */ aha152x_abort, \
+ /* reset */ aha152x_reset, \
+ /* slave_attach */ /* NULL */ 0, \
+ /* bios_param */ aha152x_biosparam, \
/* can_queue */ 1, \
- /* this_id */ 7, \
- /* sg_tablesize */ SG_ALL, \
- /* cmd_per_lun */ 1, \
- /* present */ 0, \
- /* unchecked_isa_dma */ 0, \
+ /* this_id */ 7, \
+ /* sg_tablesize */ SG_ALL, \
+ /* cmd_per_lun */ 1, \
+ /* present */ 0, \
+ /* unchecked_isa_dma */ 0, \
/* use_clustering */ DISABLE_CLUSTERING }
#endif
/* SCSI transfer count */
#define GETSTCNT() ( (GETPORT(STCNT2)<<16) \
- + (GETPORT(STCNT1)<< 8) \
- + GETPORT(STCNT0) )
+ + (GETPORT(STCNT1)<< 8) \
+ + GETPORT(STCNT0) )
#define SETSTCNT(X) { SETPORT(STCNT2, ((X) & 0xFF0000) >> 16); \
- SETPORT(STCNT1, ((X) & 0x00FF00) >> 8); \
- SETPORT(STCNT0, ((X) & 0x0000FF) ); }
+ SETPORT(STCNT1, ((X) & 0x00FF00) >> 8); \
+ SETPORT(STCNT0, ((X) & 0x0000FF) ); }
/* SCSI interrupt status */
#define TARGET 0x80
#ifdef DEBUG_AHA152X
enum {
- debug_skipports =0x0001,
- debug_queue =0x0002,
- debug_intr =0x0004,
- debug_selection =0x0008,
- debug_msgo =0x0010,
- debug_msgi =0x0020,
- debug_status =0x0040,
- debug_cmd =0x0080,
- debug_datai =0x0100,
- debug_datao =0x0200,
- debug_abort =0x0400,
- debug_done =0x0800,
- debug_biosparam =0x1000,
- debug_phases =0x2000,
- debug_queues =0x4000,
- debug_reset =0x8000,
+ debug_skipports =0x0001,
+ debug_queue =0x0002,
+ debug_intr =0x0004,
+ debug_selection =0x0008,
+ debug_msgo =0x0010,
+ debug_msgi =0x0020,
+ debug_status =0x0040,
+ debug_cmd =0x0080,
+ debug_datai =0x0100,
+ debug_datao =0x0200,
+ debug_abort =0x0400,
+ debug_done =0x0800,
+ debug_biosparam =0x1000,
+ debug_phases =0x2000,
+ debug_queues =0x4000,
+ debug_reset =0x8000,
};
#endif
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ioport.h>
-
#include <linux/delay.h>
-
#include <linux/sched.h>
+#include <linux/proc_fs.h>
#include <asm/dma.h>
-
#include <asm/system.h>
#include <asm/io.h>
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
+
#include "aha1542.h"
#ifdef DEBUG
struct aha1542_hostdata{
/* This will effectively start both of them at the first mailbox */
- int bios_translation; /* Mapping bios uses - for compatibility */
+ int bios_translation; /* Mapping bios uses - for compatibility */
int aha1542_last_mbi_used;
int aha1542_last_mbo_used;
Scsi_Cmnd * SCint[AHA1542_MAILBOXES];
case 6:
atbt = 0x04;
break;
- case 7:
+ case 7:
atbt = 0x01;
break;
case 8:
int aha1542_reset(Scsi_Cmnd *);
int aha1542_biosparam(Disk *, int, int*);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
#define AHA1542_MAILBOXES 8
#define AHA1542_SCATTER 16
#define AHA1542_CMDLUN 1
#endif
#define AHA1542 { NULL, NULL, \
+ generic_proc_info, \
+ "aha1542", \
+ PROC_SCSI_AHA1542, \
"Adaptec 1542", \
aha1542_detect, \
NULL, \
aha1542_queuecommand, \
aha1542_abort, \
aha1542_reset, \
- NULL, \
+ NULL, \
aha1542_biosparam, \
AHA1542_MAILBOXES, \
7, \
* if it doesn't work for your devices, take a look.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/kernel.h>
#include <linux/head.h>
#include <linux/types.h>
#include <linux/string.h>
#include <linux/ioport.h>
-
+#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/dma.h>
retval = DID_ERROR; /* Didn't find a better error */
}
/* In any other case return DID_OK so for example
- CONDITION_CHECKS make it through to the appropriate
+ CONDITION_CHECKS make it through to the appropriate
device driver */
}
}
ecbptr = (struct ecb *) bus_to_virt(inl(MBOXIN0));
outb(G2CNTRL_IRST,G2CNTRL); /* interrupt reset */
- switch ( adapstat & G2INTST_MASK )
+ switch ( adapstat & G2INTST_MASK )
{
case G2INTST_CCBRETRY:
case G2INTST_CCBERROR:
if(*cmd == REQUEST_SENSE)
{
- if (bufflen != sizeof(SCpnt->sense_buffer))
+ if (bufflen != sizeof(SCpnt->sense_buffer))
{
printk("Wrong buffer length supplied for request sense (%d)\n",bufflen);
- }
- SCpnt->result = 0;
- done(SCpnt);
- return 0;
+ }
+ SCpnt->result = 0;
+ done(SCpnt);
+ return 0;
}
#ifdef DEBUG
if (*cmd == READ_10 || *cmd == WRITE_10)
- i = xscsi2int(cmd+2);
+ i = xscsi2int(cmd+2);
else if (*cmd == READ_6 || *cmd == WRITE_6)
- i = scsi2int(cmd+2);
+ i = scsi2int(cmd+2);
else
- i = -1;
+ i = -1;
printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen);
printk("scsi cmd:");
for (i = 0; i < SCpnt->cmd_len; i++) printk("%02x ", cmd[i]);
if (SCpnt->use_sg)
{
- struct scatterlist * sgpnt;
- struct aha1740_chain * cptr;
- int i;
+ struct scatterlist * sgpnt;
+ struct aha1740_chain * cptr;
+ int i;
#ifdef DEBUG
- unsigned char * ptr;
+ unsigned char * ptr;
#endif
- ecb[ecbno].sg = 1; /* SCSI Initiator Command w/scatter-gather*/
- SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
- sgpnt = (struct scatterlist *) SCpnt->request_buffer;
- cptr = (struct aha1740_chain *) SCpnt->host_scribble;
- if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
- for(i=0; i<SCpnt->use_sg; i++)
+ ecb[ecbno].sg = 1; /* SCSI Initiator Command w/scatter-gather*/
+ SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
+ sgpnt = (struct scatterlist *) SCpnt->request_buffer;
+ cptr = (struct aha1740_chain *) SCpnt->host_scribble;
+ if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n");
+ for(i=0; i<SCpnt->use_sg; i++)
{
cptr[i].dataptr = (long) sgpnt[i].address;
cptr[i].datalen = sgpnt[i].length;
- }
- ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
- ecb[ecbno].dataptr = (long) cptr;
+ }
+ ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain);
+ ecb[ecbno].dataptr = (long) cptr;
#ifdef DEBUG
- printk("cptr %x: ",cptr);
- ptr = (unsigned char *) cptr;
- for(i=0;i<24;i++) printk("%02x ", ptr[i]);
+ printk("cptr %x: ",cptr);
+ ptr = (unsigned char *) cptr;
+ for(i=0;i<24;i++) printk("%02x ", ptr[i]);
#endif
}
else
{
- SCpnt->host_scribble = NULL;
- ecb[ecbno].datalen = bufflen;
- ecb[ecbno].dataptr = (long) buff;
+ SCpnt->host_scribble = NULL;
+ ecb[ecbno].datalen = bufflen;
+ ecb[ecbno].dataptr = (long) buff;
}
ecb[ecbno].lun = SCpnt->lun;
ecb[ecbno].ses = 1; /* Suppress underrun errors */
#ifdef DEBUG
{
int i;
- printk("aha1740_command: sending.. ");
- for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
- printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
+ printk("aha1740_command: sending.. ");
+ for (i = 0; i < sizeof(ecb[ecbno])-10; i++)
+ printk("%02x ", ((unchar *)&ecb[ecbno])[i]);
}
printk("\n");
#endif
non-terminating while loops with interrupts disabled. So did
I when I wrote it, but the Adaptec Spec says the card is so fast,
that this problem virtually never occurs so I've kept it. We
- do printk a warning first, so that you'll know if it happens.
+ do printk a warning first, so that you'll know if it happens.
In practice the only time we've seen this message is when some-
thing else is in the driver was broken, like _makecode(), or
when a scsi device hung the scsi bus. Even under these conditions,
if ( (inb(G2STAT) & (G2STAT_MBXOUT | G2STAT_BUSY) ) != G2STAT_MBXOUT )
{ /* If the card isn't ready, hard reset it */
- outb(G2CNTRL_HRST,G2CNTRL);
- outb(0,G2CNTRL);
+ outb(G2CNTRL_HRST,G2CNTRL);
+ outb(0,G2CNTRL);
}
printk("Configuring Adaptec at IO:%x, IRQ %d\n",base,
if (request_irq(irq_level,aha1740_intr_handle, 0, "aha1740"))
{
- printk("Unable to allocate IRQ for adaptec controller.\n");
- return 0;
+ printk("Unable to allocate IRQ for adaptec controller.\n");
+ return 0;
}
request_region(base, 0x5c,"aha1740"); /* Reserve the space that we need to use */
return 1;
return 0;
}
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = AHA1740;
+
+#include "scsi_module.c"
+#endif
+
/* Okay, you made it all the way through. As of this writing, 3/31/93, I'm
brad@saturn.gaylord.com or brad@bradpc.gaylord.com. I'll try to help as time
permits if you have any trouble with this driver. Happy Linuxing! */
int aha1740_reset(Scsi_Cmnd *);
int aha1740_biosparam(Disk *, int, int*);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
#define AHA1740_ECBS 32
#define AHA1740_SCATTER 16
#endif
#define AHA1740 {NULL, NULL, \
+ generic_proc_info, \
+ "aha1740", \
+ PROC_SCSI_AHA1740, \
"Adaptec 174x (EISA)", \
aha1740_detect, \
NULL, \
aha1740_queuecommand, \
aha1740_abort, \
aha1740_reset, \
- NULL, \
+ NULL, \
aha1740_biosparam, \
AHA1740_ECBS, \
7, \
+++ /dev/null
-/*
- * Adaptec 274x/284x/294x device driver for Linux.
- * Copyright (c) 1994 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 of the License, 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; if not, write to the Free Software
- * Foundation, Inc., 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.
- */
-
-#define _POSIX_SOURCE 1
-#define _POSIX_C_SOURCE 2
-
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#define MEMORY 512 /* 2^9 29-bit words */
-#define MAXLINE 1024
-#define MAXTOKEN 32
-#define ADOTOUT "a.out"
-#define NOVALUE -1
-
-/*
- * AIC-7770 register definitions
- */
-#define R_SINDEX 0x65
-#define R_ALLONES 0x69
-#define R_ALLZEROS 0x6a
-#define R_NONE 0x6a
-
-static
-char sccsid[] =
- "@(#)aic7770.c 1.10 94/07/22 jda";
-
-int debug;
-int lineno, LC;
-char *filename;
-FILE *ifp, *ofp;
-unsigned char M[MEMORY][4];
-
-void error(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, *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]);
-}
-
-char **getl(int *n)
-{
- int i;
- char *p;
- static char buf[MAXLINE];
- static char *a[MAXTOKEN];
-
- i = 0;
-
- while (fgets(buf, sizeof(buf), ifp)) {
-
- lineno += 1;
-
- if (buf[strlen(buf)-1] != '\n')
- error("line too long");
-
- p = strchr(buf, '#');
- if (p)
- *p = '\0';
-
- for (p = strtok(buf, ", \t\n"); p; p = strtok(NULL, ", \t\n"))
- if (i < MAXTOKEN-1)
- a[i++] = p;
- else
- error("too many tokens");
- 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 {
- 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,
- "not", 3, 2, 1, 2, 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,
- "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", 1, 3, I|R_NONE, I|R_ALLONES, I|1, 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
-};
-
-int eval_operand(char **a, int spec)
-{
- int i;
- unsigned int want = spec & (LO|LA|LX);
-
- static struct {
- unsigned int what;
- 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);
-
- 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(void)
-{
- 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(ofp, "#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(ofp);
-
- if (debug)
- output(stderr);
-}
-
-int main(int argc, char **argv)
-{
- int c;
-
- while ((c = getopt(argc, argv, "dho:")) != EOF) {
- switch (c) {
- case 'd':
- debug = !0;
- break;
- case 'o':
- ofp = fopen(optarg, "w");
- if (!ofp) {
- perror(optarg);
- exit(EXIT_FAILURE);
- }
- break;
- case 'h':
- printf("usage: %s [-d] [-ooutput] input\n", *argv);
- exit(EXIT_SUCCESS);
- case NULL:
- /*
- * An impossible option to shut the compiler
- * up about sccsid[].
- */
- exit((int)sccsid);
- default:
- exit(EXIT_FAILURE);
- }
- }
-
- if (argc - optind != 1) {
- fprintf(stderr, "%s: must have one input file\n", *argv);
- exit(EXIT_FAILURE);
- }
- filename = argv[optind];
-
- ifp = fopen(filename, "r");
- if (!ifp) {
- perror(filename);
- exit(EXIT_FAILURE);
- }
-
- if (!ofp) {
- ofp = fopen(ADOTOUT, "w");
- if (!ofp) {
- perror(ADOTOUT);
- exit(EXIT_FAILURE);
- }
- }
-
- assemble();
- exit(EXIT_SUCCESS);
-}
-/*
- * @(#)aic7xxx.c 1.34 94/11/30 jda
+/*+M*************************************************************************
+ * Adaptec 274x/284x/294x device driver for Linux.
*
- * Adaptec 274x/284x/294x device driver for Linux.
- * Copyright (c) 1994 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 of the License, 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; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ * Copyright (c) 1994 John Aycock
+ * The University of Calgary Department of Computer Science.
+ * All rights reserved.
*
- * Sources include the Adaptec 1740 driver (aha1740.c), the
- * Ultrastor 24F driver (ultrastor.c), various Linux kernel
- * source, the Adaptec EISA config file (!adp7771.cfg), the
- * Adaptec AHA-2740A Series User's Guide, the Linux Kernel
- * Hacker's Guide, Writing a SCSI Device Driver for Linux,
- * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA
- * overlay file (adp7770.ovl), the Adaptec AHA-2740 Series
- * Technical Reference Manual, the Adaptec AIC-7770 Data
- * Book, the ANSI SCSI specification, the ANSI SCSI-2
- * specification (draft 10c), ...
+ * 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.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of Calgary
+ * Department of Computer Science and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
*
- * On a twin-bus adapter card, channel B is ignored. Rationale:
- * it would greatly complicate the sequencer and host driver code,
- * and both busses are multiplexed on to the EISA bus anyway. So
- * I don't really see any technical advantage to supporting both.
+ * 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.
+ *
+ * Sources include the Adaptec 1740 driver (aha1740.c), the Ultrastor 24F
+ * driver (ultrastor.c), various Linux kernel source, the Adaptec EISA
+ * config file (!adp7771.cfg), the Adaptec AHA-2740A Series User's Guide,
+ * the Linux Kernel Hacker's Guide, Writing a SCSI Device Driver for Linux,
+ * the Adaptec 1542 driver (aha1542.c), the Adaptec EISA overlay file
+ * (adp7770.ovl), the Adaptec AHA-2740 Series Technical Reference Manual,
+ * the Adaptec AIC-7770 Data Book, the ANSI SCSI specification, the
+ * ANSI SCSI-2 specification (draft 10c), ...
*
- * As well, multiple adapter card using the same IRQ level are
- * not supported. It doesn't make sense to configure the cards
- * this way from a performance standpoint. Not to mention that
- * the kernel would have to support two devices per registered IRQ.
- */
+ * ----------------------------------------------------------------
+ * Modified to include support for wide and twin bus adapters,
+ * DMAing of SCBs, tagged queueing, IRQ sharing, bug fixes,
+ * and other rework of the code.
+ *
+ * Parts of this driver are based on the FreeBSD driver by Justin
+ * T. Gibbs.
+ *
+ * A Boot time option was also added for not resetting the scsi bus.
+ *
+ * Form: aic7xxx=extended,no_reset
+ *
+ * -- Daniel M. Eischen, deischen@iworks.InterWorks.org, 04/03/95
+ *
+ * $Id: aic7xxx.c,v 1.49 1995/06/28 05:41:09 deang Exp $
+ *-M*************************************************************************/
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
#include <stdarg.h>
#include <asm/io.h>
#include <linux/ioport.h>
#include <linux/bios32.h>
#include <linux/delay.h>
+#include <linux/sched.h>
#include <linux/pci.h>
-
+#include <linux/proc_fs.h>
#include "../block/blk.h"
#include "sd.h"
#include "scsi.h"
#include "hosts.h"
#include "aic7xxx.h"
+#define AIC7XXX_C_VERSION "$Revision: 1.49 $"
+
+#define NUMBER(arr) (sizeof(arr) / sizeof(arr[0]))
+#define MIN(a,b) ((a < b) ? a : b)
+
+/*
+ * Defines for PCI bus support, testing twin bus support, DMAing of
+ * SCBs, and tagged queueing.
+ *
+ * o PCI bus support - this has been implemented and working since
+ * the December 1, 1994 release of this driver. If you don't have
+ * a PCI bus and do not wish to configure your kernel with PCI
+ * support, then make sure this define is set to the cprrect
+ * define for PCI support (CONFIG_PCI) and configure your kernel
+ * without PCI support (make config).
+ *
+ * o Twin bus support - this has been tested and does work.
+ *
+ * o DMAing of SCBs - thanks to Kai Makisara, this now works
+ *
+ * o Tagged queueing - this driver is capable of tagged queueing
+ * but I am unsure as to how well the higher level driver implements
+ * tagged queueing. Therefore, the maximum commands per lun is
+ * set to 2. If you want to implement tagged queueing, ensure
+ * this define is not commented out.
+ *
+ * o Sharing IRQs - allowed for sharing of IRQs. This will allow
+ * for multiple aic7xxx host adapters sharing the same IRQ, but
+ * not for sharing IRQs with other devices. The higher level
+ * PCI code and interrupt handling needs to be modified to
+ * support this.
+ *
+ * Daniel M. Eischen, deischen@iworks.InterWorks.org, 03/11/95
+ */
+
+/* Uncomment this for testing twin bus support. */
+#define AIC7XXX_TWIN_SUPPORT
+
+/* Uncomment this for DMAing of SCBs. */
+#define AIC7XXX_USE_DMA
+
+/* Uncomment this for tagged queueing. */
+/* #define AIC7XXX_TAGGED_QUEUEING */
+
+/* Uncomment this for allowing sharing of IRQs. */
+#define AIC7XXX_SHARE_IRQS
+
+/* Set this to the delay in seconds after SCSI bus reset. */
+#define AIC7XXX_RESET_DELAY 15
+
+/*
+ * Uncomment this to always use scatter/gather lists.
+ * *NOTE: The sequencer must be changed also!
+ */
+#define AIC7XXX_USE_SG
+
+/*
+ * Controller type and options
+ */
+typedef enum {
+ AIC_NONE,
+ AIC_274x, /* EISA aic7770 */
+ AIC_284x, /* VLB aic7770 */
+ AIC_7870, /* PCI aic7870 */
+ AIC_7850, /* PCI aic7850 */
+ AIC_7872 /* PCI aic7870 on 394x */
+} aha_type;
+
+typedef enum {
+ AIC_SINGLE, /* Single Channel */
+ AIC_TWIN, /* Twin Channel */
+ AIC_WIDE /* Wide Channel */
+} aha_bus_type;
+
+typedef enum {
+ AIC_UNKNOWN,
+ AIC_ENABLED,
+ AIC_DISABLED
+} aha_status_type;
+
/*
- * There should be a specific return value for this in scsi.h, but
- * it seems that most drivers ignore it.
+ * There should be a specific return value for this in scsi.h, but
+ * it seems that most drivers ignore it.
*/
-#define DID_UNDERFLOW DID_ERROR
+#define DID_UNDERFLOW DID_ERROR
-/* EISA/VL-bus stuff */
+/*
+ * What we want to do is have the higher level scsi driver requeue
+ * the command to us. There is no specific driver status for this
+ * condition, but the higher level scsi driver will requeue the
+ * command on a DID_BUS_BUSY error.
+ */
+#define DID_RETRY_COMMAND DID_BUS_BUSY
+/*
+ * EISA/VL-bus stuff
+ */
#define MINSLOT 1
#define MAXSLOT 15
#define SLOTBASE(x) ((x) << 12)
-
#define MAXIRQ 15
-/* AIC-7770 offset definitions */
-
-#define O_MINREG(x) ((x) + 0xc00) /* i/o range to reserve */
-#define O_MAXREG(x) ((x) + 0xcbf)
-
-#define O_SCSISEQ(x) ((x) + 0xc00) /* scsi sequence control */
-#define O_SCSISIGI(x) ((x) + 0xc03) /* scsi control signal read */
-#define O_SCSISIGO(x) ((x) + 0xc03) /* scsi control signal write */
-#define O_SCSIID(x) ((x) + 0xc05) /* scsi id */
-#define O_SSTAT0(x) ((x) + 0xc0b) /* scsi status register 0 */
-#define O_CLRSINT1(x) ((x) + 0xc0c) /* clear scsi interrupt 1 */
-#define O_SSTAT1(x) ((x) + 0xc0c) /* scsi status register 1 */
-#define O_SELID(x) ((x) + 0xc19) /* [re]selection id */
-#define O_SBLKCTL(x) ((x) + 0xc1f) /* scsi block control */
-#define O_SEQCTL(x) ((x) + 0xc60) /* sequencer control */
-#define O_SEQRAM(x) ((x) + 0xc61) /* sequencer ram data */
-#define O_SEQADDR(x) ((x) + 0xc62) /* sequencer address (W) */
-#define O_BIDx(x) ((x) + 0xc80) /* board id */
-#define O_BCTL(x) ((x) + 0xc84) /* board control */
-#define O_HCNTRL(x) ((x) + 0xc87) /* host control */
-#define O_SCBPTR(x) ((x) + 0xc90) /* scb pointer */
-#define O_INTSTAT(x) ((x) + 0xc91) /* interrupt status */
-#define O_ERROR(x) ((x) + 0xc92) /* hard error */
-#define O_CLRINT(x) ((x) + 0xc92) /* clear interrupt status */
-#define O_SCBCNT(x) ((x) + 0xc9a) /* scb auto increment */
-#define O_QINFIFO(x) ((x) + 0xc9b) /* queue in fifo */
-#define O_QINCNT(x) ((x) + 0xc9c) /* queue in count */
-#define O_QOUTFIFO(x) ((x) + 0xc9d) /* queue out fifo */
-#define O_QOUTCNT(x) ((x) + 0xc9e) /* queue out count */
-#define O_SCBARRAY(x) ((x) + 0xca0) /* scb array start */
-
-/* AIC-7870-only definitions */
-
-#define O_DSPCISTATUS(x) ((x) + 0xc86) /* ??? */
-
-/* host adapter offset definitions */
-
-#define HA_REJBYTE(x) ((x) + 0xc31) /* 1st message in byte */
-#define HA_MSG_FLAGS(x) ((x) + 0xc35) /* outgoing message flag */
-#define HA_MSG_LEN(x) ((x) + 0xc36) /* outgoing message length */
-#define HA_MSG_START(x) ((x) + 0xc37) /* outgoing message body */
-#define HA_ARG_1(x) ((x) + 0xc4c) /* sdtr <-> rate parameters */
-#define HA_ARG_2(x) ((x) + 0xc4d)
-#define HA_RETURN_1(x) ((x) + 0xc4c)
-#define HA_RETURN_2(x) ((x) + 0xc4d)
-#define HA_SIGSTATE(x) ((x) + 0xc4e) /* value in SCSISIGO */
-#define HA_NEEDSDTR(x) ((x) + 0xc4f) /* synchronous negotiation? */
-#define HA_SCBCOUNT(x) ((x) + 0xc56) /* number of hardware SCBs */
-
-#define HA_SCSICONF(x) ((x) + 0xc5a) /* SCSI config register */
-#define HA_INTDEF(x) ((x) + 0xc5c) /* interrupt def'n register */
-#define HA_HOSTCONF(x) ((x) + 0xc5d) /* host config def'n register */
-
-/* debugging code */
+/*
+ * Standard EISA Host ID regs (Offset from slot base)
+ */
+#define HID0(x) ((x) + 0xC80) /* 0,1: msb of ID2, 2-7: ID1 */
+#define HID1(x) ((x) + 0xC81) /* 0-4: ID3, 5-7: LSB ID2 */
+#define HID2(x) ((x) + 0xC82) /* product */
+#define HID3(x) ((x) + 0xC83) /* firmware revision */
/*
-#define AIC7XXX_DEBUG
-*/
+ * AIC-7770 I/O range to reserve for a card
+ */
+#define MINREG(x) ((x) + 0xC00ul)
+#define MAXREG(x) ((x) + 0xCBFul)
+
+/* -------------------- AIC-7770 offset definitions ----------------------- */
/*
- * If a parity error occurs during a data transfer phase, run the
- * command to completion - it's easier that way - making a note
- * of the error condition in this location. This then will modify
- * a DID_OK status into a DID_PARITY one for the higher-level SCSI
- * code.
+ * SCSI Sequence Control (p. 3-11).
+ * Each bit, when set starts a specific SCSI sequence on the bus
*/
-#define aic7xxx_parity(cmd) ((cmd)->SCp.Status)
+#define SCSISEQ(x) ((x) + 0xC00ul)
+#define TEMODEO 0x80
+#define ENSELO 0x40
+#define ENSELI 0x20
+#define ENRSELI 0x10
+#define ENAUTOATNO 0x08
+#define ENAUTOATNI 0x04
+#define ENAUTOATNP 0x02
+#define SCSIRSTO 0x01
/*
- * Since the sequencer code DMAs the scatter-gather structures
- * directly from memory, we use this macro to assert that the
- * kernel structure hasn't changed.
+ * SCSI Transfer Control 1 Register (pp. 3-14,15).
+ * Controls the SCSI module data path.
*/
-#define SG_STRUCT_CHECK(sg) \
- ((char *)&(sg).address - (char *)&(sg) != 0 || \
- (char *)&(sg).length - (char *)&(sg) != 8 || \
- sizeof((sg).address) != 4 || \
- sizeof((sg).length) != 4 || \
- sizeof(sg) != 12)
+#define SXFRCTL1(x) ((x) + 0xC02ul)
+#define BITBUCKET 0x80
+#define SWRAPEN 0x40
+#define ENSPCHK 0x20
+#define STIMESEL 0x18
+#define ENSTIMER 0x04
+#define ACTNEGEN 0x02
+#define STPWEN 0x01 /* Powered Termination */
/*
- * "Static" structures. Note that these are NOT initialized
- * to zero inside the kernel - we have to initialize them all
- * explicitly.
- *
- * We support a maximum of one adapter card per IRQ level (see the
- * rationale for this above). On an interrupt, use the IRQ as an
- * index into aic7xxx_boards[] to locate the card information.
+ * SCSI Control Signal Read Register (p. 3-15).
+ * Reads the actual state of the SCSI bus pins
*/
-static struct Scsi_Host *aic7xxx_boards[MAXIRQ + 1];
+#define SCSISIGI(x) ((x) + 0xC03ul)
+#define CDI 0x80
+#define IOI 0x40
+#define MSGI 0x20
+#define ATNI 0x10
+#define SELI 0x08
+#define BSYI 0x04
+#define REQI 0x02
+#define ACKI 0x01
/*
- * 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!
+ * SCSI Contol 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 AIC7XXX_MAXSCB 16
+#define SCSISIGO(x) ((x) + 0xC03ul)
+#define CDO 0x80
+#define IOO 0x40
+#define MSGO 0x20
+#define ATNO 0x10
+#define SELO 0x08
+#define BSYO 0x04
+#define REQO 0x02
+#define ACKO 0x01
-struct aic7xxx_host {
- int base; /* card base address */
- int maxscb; /* hardware SCBs */
- int startup; /* intr type check */
- int extended; /* extended xlate? */
- volatile int unpause; /* value for HCNTRL */
- volatile Scsi_Cmnd *SCB_array[AIC7XXX_MAXSCB]; /* active commands */
-};
+/*
+ * SCSI Rate
+ */
+#define SCSIRATE(x) ((x) + 0xC04ul)
-struct aic7xxx_host_config {
- int irq; /* IRQ number */
- int base; /* I/O base */
- int maxscb; /* hardware SCBs */
- int unpause; /* value for HCNTRL */
- int scsi_id; /* host SCSI id */
- int extended; /* extended xlate? */
-};
+/*
+ * SCSI ID (p. 3-18).
+ * Contains the ID of the board and the current target on the
+ * selected channel
+ */
+#define SCSIID(x) ((x) + 0xC05ul)
+#define TID 0xF0 /* Target ID mask */
+#define OID 0x0F /* Our ID mask */
-struct aic7xxx_scb {
- unsigned char control;
- unsigned char target_channel_lun; /* 4/1/3 bits */
- unsigned char SG_segment_count;
- unsigned char SG_list_pointer[4];
- unsigned char SCSI_cmd_pointer[4];
- unsigned char SCSI_cmd_length;
- unsigned char RESERVED[2]; /* must be zero */
- unsigned char target_status;
- unsigned char residual_data_count[3];
- unsigned char residual_SG_segment_count;
- unsigned char data_pointer[4];
- unsigned char data_count[3];
-#if 0
- /*
- * No real point in transferring this to the
- * SCB registers.
- */
- unsigned char RESERVED[6];
-#endif
-};
+/*
+ * SCSI Status 0 (p. 3-21)
+ * Contains one set of SCSI Interrupt codes
+ * These are most likely of interest to the sequencer
+ */
+#define SSTAT0(x) ((x) + 0xC0Bul)
+#define TARGET 0x80 /* Board is a 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 */
/*
- * NB. This table MUST be ordered shortest period first.
+ * Clear SCSI Interrupt 1 (p. 3-23)
+ * Writing a 1 to a bit clears the associated SCSI Interrupt in SSTAT1.
*/
-static struct {
- short period;
- short rate;
- char *english;
-} aic7xxx_synctab[] = {
- 100, 0, "10.0",
- 125, 1, "8.0",
- 150, 2, "6.67",
- 175, 3, "5.7",
- 200, 4, "5.0",
- 225, 5, "4.4",
- 250, 6, "4.0",
- 275, 7, "3.6"
-};
+#define CLRSINT1(x) ((x) + 0xC0Cul)
+#define CLRSELTIMEO 0x80
+#define CLRATNO 0x40
+#define CLRSCSIRSTI 0x20
+/* UNUSED 0x10 */
+#define CLRBUSFREE 0x08
+#define CLRSCSIPERR 0x04
+#define CLRPHASECHG 0x02
+#define CLRREQINIT 0x01
-static int aic7xxx_synctab_max =
- sizeof(aic7xxx_synctab) / sizeof(aic7xxx_synctab[0]);
+/*
+ * SCSI Status 1 (p. 3-24)
+ * These interrupt bits are of interest to the kernel driver
+ */
+#define SSTAT1(x) ((x) + 0xC0Cul)
+#define SELTO 0x80
+#define ATNTARG 0x40
+#define SCSIRSTI 0x20
+#define PHASEMIS 0x10
+#define BUSFREE 0x08
+#define SCSIPERR 0x04
+#define PHASECHG 0x02
+#define REQINIT 0x01
-enum aha_type {
- T_NONE,
- T_274X,
- T_284X,
- T_294X,
- T_MAX
-};
+/*
+ * SCSI Interrrupt Mode 1 (pp. 3-28,29).
+ * Set bits in this register enable the corresponding
+ * interrupt source.
+ */
+#define SIMODE1(x) ((x) + 0xC11ul)
+#define ENSELTIMO 0x80
+#define ENATNTARG 0x40
+#define ENSCSIRST 0x20
+#define ENPHASEMIS 0x10
+#define ENBUSFREE 0x08
+#define ENSCSIPERR 0x04
+#define ENPHASECHG 0x02
+#define ENREQINIT 0x01
-#ifdef AIC7XXX_DEBUG
+/*
+ * 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(x) ((x) + 0xC19ul)
+#define SELID_MASK 0xF0
+#define ONEBIT 0x08
+/* UNUSED 0x07 */
- extern int vsprintf(char *, const char *, va_list);
+/*
+ * 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. See aic7xxx_read_eprom for detailed information on
+ * the protocol necessary to read the serial EEPROM.
+ */
+#define SEECTL(x) ((x) + 0xC1Eul)
+#define EXTARBACK 0x80
+#define EXTARBREQ 0x40
+#define SEEMS 0x20
+#define SEERDY 0x10
+#define SEECS 0x08
+#define SEECK 0x04
+#define SEEDO 0x02
+#define SEEDI 0x01
- static
- void debug(const char *fmt, ...)
- {
- va_list ap;
- char buf[256];
+/*
+ * 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(x) ((x) + 0xC1Ful)
+/* UNUSED 0xC0 */
+#define AUTOFLUSHDIS 0x20 /* used for Rev C check */
+/* UNUSED 0x10 */
+#define SELBUSB 0x08
+/* UNUSED 0x04 */
+#define SELWIDE 0x02
+/* UNUSED 0x01 */
+#define SELSINGLE 0x00
- va_start(ap, fmt);
- vsprintf(buf, fmt, ap);
- printk(buf);
- va_end(ap);
- }
+/*
+ * Sequencer Control (p. 3-33)
+ * Error detection mode and speed configuration
+ */
+#define SEQCTL(x) ((x) + 0xC60ul)
+#define PERRORDIS 0x80
+#define PAUSEDIS 0x40
+#define FAILDIS 0x20
+#define FASTMODE 0x10
+#define BRKADRINTEN 0x08
+#define STEP 0x04
+#define SEQRESET 0x02
+#define LOADRAM 0x01
- static
- void debug_config(enum aha_type type, struct aic7xxx_host_config *p)
- {
- int ioport2, ioport3;
-
- static char *BRT[T_MAX][16] = {
- { }, /* T_NONE */
- {
- "2", "???", "???", "12", /* T_274X */
- "???", "???", "???", "28",
- "???", "???", "???", "44",
- "???", "???", "???", "60"
- },
- {
- "2", "4", "8", "12", /* T_284X */
- "16", "20", "24", "28",
- "32", "36", "40", "44",
- "48", "52", "56", "60"
- },
- {
- "???", "???", "???", "???", /* T_294X */
- "???", "???", "???", "???",
- "???", "???", "???", "???",
- "???", "???", "???", "???"
- }
- };
- static int DFT[4] = {
- 0, 50, 75, 100
- };
- static int SST[4] = {
- 256, 128, 64, 32
- };
-
- ioport2 = inb(HA_HOSTCONF(p->base));
- ioport3 = inb(HA_SCSICONF(p->base));
-
- switch (type) {
- case T_274X:
- printk("AHA274X AT EISA SLOT %d:\n", p->base >> 12);
- break;
- case T_284X:
- printk("AHA284X AT SLOT %d:\n", p->base >> 12);
- break;
- case T_294X:
- printk("AHA294X (PCI-bus):\n");
- break;
- default:
- panic("aic7xxx debug_config: internal error\n");
- }
+/*
+ * 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 sucessesion. The SEQADDRs will increment after the most
+ * significant byte is written
+ */
+#define SEQRAM(x) ((x) + 0xC61ul)
- printk(" irq %d\n"
- " bus release time %s bclks\n"
- " data fifo threshold %d%%\n",
- p->irq,
- BRT[type][(ioport2 >> 2) & 0xf],
- DFT[(ioport2 >> 6) & 0x3]);
-
- printk(" SCSI CHANNEL A:\n"
- " scsi id %d\n"
- " scsi bus parity check %sabled\n"
- " scsi selection timeout %d ms\n"
- " scsi bus reset at power-on %sabled\n",
- ioport3 & 0x7,
- (ioport3 & 0x20) ? "en" : "dis",
- SST[(ioport3 >> 3) & 0x3],
- (ioport3 & 0x40) ? "en" : "dis");
-
- if (type == T_274X) {
- printk(" scsi bus termination %sabled\n",
- (ioport3 & 0x80) ? "en" : "dis");
- }
- }
+/*
+ * Sequencer Address Registers (p. 3-35)
+ * Only the first bit of SEQADDR1 holds addressing information
+ */
+#define SEQADDR0(x) ((x) + 0xC62ul)
+#define SEQADDR1(x) ((x) + 0xC63ul)
- static
- void debug_rate(int base, int rate)
- {
- int target = inb(O_SCSIID(base)) >> 4;
-
- if (rate) {
- printk("aic7xxx: target %d now synchronous at %sMb/s\n",
- target,
- aic7xxx_synctab[(rate >> 4) & 0x7].english);
- } else {
- printk("aic7xxx: target %d using asynchronous mode\n",
- target);
- }
- }
+#define ACCUM(x) ((x) + 0xC64ul) /* accumulator */
-#else
+/*
+ * Board Control (p. 3-43)
+ */
+#define BCTL(x) ((x) + 0xC84ul)
+/* RSVD 0xF0 */
+#define ACE 0x08 /* Support for external processors */
+/* RSVD 0x06 */
+#define ENABLE 0x01
-# define debug(fmt, args...)
-# define debug_config(x)
-# define debug_rate(x,y)
+#define BUSSPD(x) ((x) + 0xC86ul) /* FIFO threshold bits ? */
-#endif AIC7XXX_DEBUG
+/*
+ * Host Control (p. 3-47) R/W
+ * Overal host control of the device.
+ */
+#define HCNTRL(x) ((x) + 0xC87ul)
+/* UNUSED 0x80 */
+#define POWRDN 0x40
+/* UNUSED 0x20 */
+#define SWINT 0x10
+#define IRQMS 0x08
+#define PAUSE 0x04
+#define INTEN 0x02
+#define CHIPRST 0x01
+#define REQ_PAUSE IRQMS | PAUSE | INTEN
+#define UNPAUSE_274X IRQMS | INTEN
+#define UNPAUSE_284X INTEN
+#define UNPAUSE_294X IRQMS | INTEN
/*
- * 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?
+ * SCB Pointer (p. 3-49)
+ * Gate one of the four SCBs into the SCBARRAY window.
*/
-static int aic7xxx_extended = 0; /* extended translation on? */
+#define SCBPTR(x) ((x) + 0xC90ul)
-void aic7xxx_setup(char *s, int *dummy)
-{
- int i;
- char *p;
-
- static struct {
- char *name;
- int *flag;
- } options[] = {
- "extended", &aic7xxx_extended,
- NULL
- };
-
- for (p = strtok(s, ","); p; p = strtok(NULL, ",")) {
- for (i = 0; options[i].name; i++)
- if (!strcmp(options[i].name, p))
- *(options[i].flag) = !0;
- }
-}
+/*
+ * Interrupt Status (p. 3-50)
+ * Status for system interrupts
+ */
+#define INTSTAT(x) ((x) + 0xC91ul)
+#define SEQINT_MASK 0xF0 /* SEQINT Status Codes */
+#define BAD_PHASE 0x00
+#define SEND_REJECT 0x10
+#define NO_IDENT 0x20
+#define NO_MATCH 0x30
+#define MSG_SDTR 0x40
+#define MSG_WDTR 0x50
+#define MSG_REJECT 0x60
+#define BAD_STATUS 0x70
+#define RESIDUAL 0x80
+#define ABORT_TAG 0x90
+#define AWAITING_MSG 0xa0
+#define BRKADRINT 0x08
+#define SCSIINT 0x04
+#define CMDCMPLT 0x02
+#define SEQINT 0x01
+#define INT_PEND (BRKADRINT | SEQINT | SCSIINT | CMDCMPLT)
-static
-void aic7xxx_getscb(int base, struct aic7xxx_scb *scb)
-{
- /*
- * This is almost identical to aic7xxx_putscb().
- */
- outb(0x80, O_SCBCNT(base)); /* SCBAUTO */
+/*
+ * Hard Error (p. 3-53)
+ * Reporting of catastrophic errors. You usually cannot recover from
+ * these without a full board reset.
+ */
+#define ERROR(x) ((x) + 0xC92ul)
+/* UNUSED 0xF0 */
+#define PARERR 0x08
+#define ILLOPCODE 0x04
+#define ILLSADDR 0x02
+#define ILLHADDR 0x01
- asm volatile("cld\n\t"
- "rep\n\t"
- "insb"
- : /* no output */
- :"D" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
- :"di", "cx", "dx");
+/*
+ * Clear Interrupt Status (p. 3-52)
+ */
+#define CLRINT(x) ((x) + 0xC92ul)
+#define CLRBRKADRINT 0x08
+#define CLRSCSIINT 0x04
+#define CLRCMDINT 0x02
+#define CLRSEQINT 0x01
- outb(0, O_SCBCNT(base));
-}
+/*
+ * 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(x) ((x) + 0xC9Aul)
+#define SCBAUTO 0x80
+#define SCBCNT_MASK 0x1F
/*
- * 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.
+ * Queue In FIFO (p. 3-60)
+ * Input queue for queued SCBs (commands that the seqencer has yet to start)
*/
-static
-unsigned aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
-{
- int i, segments;
- unsigned length;
- struct scatterlist *sg;
+#define QINFIFO(x) ((x) + 0xC9Bul)
- segments = cmd->use_sg - sg_last;
- sg = (struct scatterlist *)cmd->buffer;
+/*
+ * Queue In Count (p. 3-60)
+ * Number of queued SCBs
+ */
+#define QINCNT(x) ((x) + 0xC9Cul)
- if (cmd->use_sg) {
- for (i = length = 0;
- i < cmd->use_sg && i < segments;
- i++)
- {
- length += sg[i].length;
- }
- } else
- length = cmd->request_bufflen;
+/*
+ * Queue Out FIFO (p. 3-61)
+ * Queue of SCBs that have completed and await the host
+ */
+#define QOUTFIFO(x) ((x) + 0xC9Dul)
- return(length);
-}
+/*
+ * Queue Out Count (p. 3-61)
+ * Number of queued SCBs in the Out FIFO
+ */
+#define QOUTCNT(x) ((x) + 0xC9Eul)
-static
-void aic7xxx_sg_check(Scsi_Cmnd *cmd)
-{
- int i;
- struct scatterlist *sg = (struct scatterlist *)cmd->buffer;
+#define SCBARRAY(x) ((x) + 0xCA0ul)
- if (cmd->use_sg) {
- for (i = 0; i < cmd->use_sg; i++)
- if ((unsigned)sg[i].length > 0xffff)
- panic("aic7xxx_sg_check: s/g segment > 64k\n");
- }
-}
+/* ---------------- END AIC-7770 Register Definitions ----------------- */
-static
-void aic7xxx_to_scsirate(unsigned char *rate,
- unsigned char transfer,
- unsigned char offset)
-{
- int i;
+/* --------------------- AIC-7870-only definitions -------------------- */
- transfer *= 4;
+#define DSPCISTATUS(x) ((x) + 0xC86ul)
+#define DFTHRESH 0xC0
- for (i = 0; i < aic7xxx_synctab_max-1; i++) {
+/* Scratch RAM offset definitions */
- if (transfer == aic7xxx_synctab[i].period) {
- *rate = (aic7xxx_synctab[i].rate << 4) | (offset & 0xf);
- return;
- }
+/* ---------------------- Scratch RAM Offsets ------------------------- */
+/* These offsets are either to values that are initialized by the board's
+ * BIOS or are specified by the Linux sequencer code. If I can figure out
+ * how to read the EISA configuration info at probe time, the cards could
+ * be run without BIOS support installed
+ */
- if (transfer > aic7xxx_synctab[i].period &&
- transfer < aic7xxx_synctab[i+1].period)
- {
- *rate = (aic7xxx_synctab[i+1].rate << 4) |
- (offset & 0xf);
- return;
- }
- }
- *rate = 0;
-}
+/*
+ * 1 byte per target starting at this address for configuration values
+ */
+#define HA_TARG_SCRATCH(x) ((x) + 0xC20ul)
/*
- * Pause the sequencer and wait for it to actually stop - this
- * is important since the sequencer can disable pausing for critical
- * sections.
+ * The sequencer will stick the first byte of any rejected message here so
+ * we can see what is getting thrown away.
*/
-#define PAUSE_SEQUENCER(p) \
- do { \
- outb(0xe, O_HCNTRL(p->base)); /* IRQMS|PAUSE|INTEN */ \
- \
- while ((inb(O_HCNTRL(p->base)) & 0x4) == 0) \
- ; \
- } while (0)
+#define HA_REJBYTE(x) ((x) + 0xC31ul)
/*
- * Unpause the sequencer. Unremarkable, yet done often enough to
- * warrant an easy way to do it.
+ * Bit vector of targets that have disconnection disabled.
*/
-#define UNPAUSE_SEQUENCER(p) \
- outb(p->unpause, O_HCNTRL(p->base)) /* IRQMS|INTEN */
+#define HA_DISC_DSB ((x) + 0xc32ul)
/*
- * See comments in aic7xxx_loadram() wrt this.
+ * Length of pending message
*/
-#define RESTART_SEQUENCER(p) \
- do { \
- do { \
- outb(0x2, O_SEQCTL(p->base)); \
- \
- } while (inb(O_SEQADDR(p->base)) != 0 && \
- inb(O_SEQADDR(p->base) + 1) != 0); \
- \
- UNPAUSE_SEQUENCER(p); \
- } while (0)
+#define HA_MSG_LEN(x) ((x) + 0xC34ul)
/*
- * Since we declared this using SA_INTERRUPT, interrupts should
- * be disabled all through this function unless we say otherwise.
+ * Outgoing Message Body
*/
-static
-void aic7xxx_isr(int irq)
-{
- int base, intstat;
- struct aic7xxx_host *p;
-
- p = (struct aic7xxx_host *)aic7xxx_boards[irq]->hostdata;
- base = p->base;
+#define HA_MSG_START(x) ((x) + 0xC35ul)
- /*
- * Check the startup flag - if no commands have been queued,
- * we probably have the interrupt type set wrong. Reverse
- * the stored value and the active one in the host control
- * register.
- */
- if (p->startup) {
- p->unpause ^= 0x8;
- outb(inb(O_HCNTRL(p->base)) ^ 0x8, O_HCNTRL(p->base));
- return;
- }
+/*
+ * 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 HA_ARG_1(x) ((x) + 0xC4Aul) /* sdtr <-> rate parameters */
+#define HA_RETURN_1(x) ((x) + 0xC4Aul)
+#define SEND_SENSE 0x80
+#define SEND_SDTR 0x80
+#define SEND_WDTR 0x80
+#define SEND_REJ 0x40
+
+#define HA_SIGSTATE(x) ((x) + 0xC4Bul) /* value in SCSISIGO */
+#define HA_SCBCOUNT(x) ((x) + 0xC52ul) /* number of hardware SCBs */
+
+#define HA_FLAGS(x) ((x) + 0xC53ul) /* TWIN and WIDE bus flags */
+#define SINGLE_BUS 0x00
+#define TWIN_BUS 0x01
+#define WIDE_BUS 0x02
+#define ACTIVE_MSG 0x20
+#define IDENTIFY_SEEN 0x40
+#define RESELECTING 0x80
+
+#define HA_ACTIVE0(x) ((x) + 0xC54ul) /* Active bits; targets 0-7 */
+#define HA_ACTIVE1(x) ((x) + 0xC55ul) /* Active bits; targets 8-15 */
+#define SAVED_TCL(x) ((x) + 0xC56ul) /* Saved target, channel, LUN */
+#define WAITING_SCBH(x) ((x) + 0xC57ul) /* Head of disconnected targets list. */
+#define WAITING_SCBT(x) ((x) + 0xC58ul) /* Tail of disconnected targets list. */
+
+#define HA_SCSICONF(x) ((x) + 0xC5Aul) /* SCSI config register */
+#define HA_INTDEF(x) ((x) + 0xC5Cul) /* interrupt def'n register */
+#define HA_HOSTCONF(x) ((x) + 0xC5Dul) /* host config def'n register */
+
+#define MSG_ABORT 0x06
+#define MSG_BUS_DEVICE_RESET 0x0c
+#define BUS_8_BIT 0x00
+#define BUS_16_BIT 0x01
+#define BUS_32_BIT 0x02
- /*
- * Handle all the interrupt sources - especially for SCSI
- * interrupts, we won't get a second chance at them.
- */
- intstat = inb(O_INTSTAT(base));
- if (intstat & 0x8) { /* BRKADRINT */
+/*
+ *
+ * Define the format of the SEEPROM registers (16 bits).
+ *
+ */
+struct seeprom_config {
- panic("aic7xxx_isr: brkadrint, error = 0x%x, seqaddr = 0x%x\n",
- inb(O_ERROR(base)), inw(O_SEQADDR(base)));
- }
+/*
+ * SCSI ID Configuration Flags
+ */
+#define CFXFER 0x0007 /* synchronous transfer rate */
+#define CFSYNCH 0x0008 /* enable synchronous transfer */
+#define CFDISC 0x0010 /* enable disconnection */
+#define CFWIDEB 0x0020 /* wide bus device */
+/* UNUSED 0x00C0 */
+#define CFSTART 0x0100 /* send start unit SCSI command */
+#define CFINCBIOS 0x0200 /* include in BIOS scan */
+#define CFRNFOUND 0x0400 /* report even if not found */
+/* UNUSED 0xF800 */
+ unsigned short device_flags[16]; /* words 0-15 */
- if (intstat & 0x4) { /* SCSIINT */
-
- int scbptr = inb(O_SCBPTR(base));
- int status = inb(O_SSTAT1(base));
- Scsi_Cmnd *cmd;
-
- cmd = (Scsi_Cmnd *)p->SCB_array[scbptr];
- if (!cmd) {
- printk("aic7xxx_isr: no command for scb (scsiint)\n");
- /*
- * Turn off the interrupt and set status
- * to zero, so that it falls through the
- * reset of the SCSIINT code.
- */
- outb(status, O_CLRSINT1(base));
- UNPAUSE_SEQUENCER(p);
- outb(0x4, O_CLRINT(base)); /* undocumented */
- status = 0;
- }
- p->SCB_array[scbptr] = NULL;
+/*
+ * BIOS Control Bits
+ */
+#define CFSUPREM 0x0001 /* support all removeable drives */
+#define CFSUPREMB 0x0002 /* support removeable drives for boot only */
+#define CFBIOSEN 0x0004 /* BIOS enabled */
+/* UNUSED 0x0008 */
+#define CFSM2DRV 0x0010 /* support more than two drives */
+/* UNUSED 0x0060 */
+#define CFEXTEND 0x0080 /* extended translation enabled */
+/* UNUSED 0xFF00 */
+ unsigned short bios_control; /* word 16 */
- /*
- * Only the SCSI Status 1 register has information
- * about exceptional conditions that we'd have a
- * SCSIINT about; anything in SSTAT0 will be handled
- * by the sequencer. Note that there can be multiple
- * bits set.
- */
- if (status & 0x80) { /* SELTO */
- /*
- * Hardware selection timer has expired. Turn
- * off SCSI selection sequence.
- */
- outb(0, O_SCSISEQ(base));
- cmd->result = DID_TIME_OUT << 16;
-
- /*
- * If there's an active message, it belongs to the
- * command that is getting punted - remove it.
- */
- outb(0, HA_MSG_FLAGS(base));
-
- /*
- * Shut off the offending interrupt sources, reset
- * the sequencer address to zero and unpause it,
- * then call the high-level SCSI completion routine.
- *
- * WARNING! This is a magic sequence! After many
- * hours of guesswork, turning off the SCSI interrupts
- * in CLRSINT? does NOT clear the SCSIINT bit in
- * INTSTAT. By writing to the (undocumented, unused
- * according to the AIC-7770 manual) third bit of
- * CLRINT, you can clear INTSTAT. But, if you do it
- * while the sequencer is paused, you get a BRKADRINT
- * with an Illegal Host Address status, so the
- * sequencer has to be restarted first.
- */
- outb(0x80, O_CLRSINT1(base)); /* CLRSELTIMO */
- RESTART_SEQUENCER(p);
-
- outb(0x4, O_CLRINT(base)); /* undocumented */
- cmd->scsi_done(cmd);
- }
+/*
+ * Host Adapter Control Bits
+ */
+/* UNUSED 0x0003 */
+#define CFWSTERM 0x0008 /* SCSI high byte termination (wide card) */
+#define CFSTERM 0x0004 /* SCSI low byte termination (non-wide cards) */
+#define CFSPARITY 0x0010 /* SCSI parity */
+/* UNUSED 0x0020 */
+#define CFRESETB 0x0040 /* reset SCSI bus at IC initialization */
+/* UNUSED 0xFF80 */
+ unsigned short adapter_control; /* word 17 */
- if (status & 0x4) { /* SCSIPERR */
- /*
- * A parity error has occurred during a data
- * transfer phase. Flag it and continue.
- */
- printk("aic7xxx: parity error on target %d, lun %d\n",
- cmd->target,
- cmd->lun);
- aic7xxx_parity(cmd) = DID_PARITY;
-
- /*
- * Clear interrupt and resume as above.
- */
- outb(0x4, O_CLRSINT1(base)); /* CLRSCSIPERR */
- UNPAUSE_SEQUENCER(p);
-
- outb(0x4, O_CLRINT(base)); /* undocumented */
- }
+/*
+ * Bus Release, Host Adapter ID
+ */
+#define CFSCSIID 0x000F /* host adapter SCSI ID */
+/* UNUSED 0x00F0 */
+#define CFBRTIME 0xFF00 /* bus release time */
+ unsigned short brtime_id; /* word 18 */
- if ((status & (0x8|0x4)) == 0 && status) {
- /*
- * We don't know what's going on. Turn off the
- * interrupt source and try to continue.
- */
- printk("aic7xxx_isr: sstat1 = 0x%x\n", status);
- outb(status, O_CLRSINT1(base));
- UNPAUSE_SEQUENCER(p);
- outb(0x4, O_CLRINT(base)); /* undocumented */
- }
- }
+/*
+ * Maximum targets
+ */
+#define CFMAXTARG 0x00FF /* maximum targets */
+/* UNUSED 0xFF00 */
+ unsigned short max_targets; /* word 19 */
- if (intstat & 0x2) { /* CMDCMPLT */
+ unsigned short res_1[11]; /* words 20-30 */
+ unsigned short checksum; /* word 31 */
- int complete, old_scbptr;
- struct aic7xxx_scb scb;
- unsigned actual;
- Scsi_Cmnd *cmd;
+};
- /*
- * 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(O_QOUTFIFO(base));
-
- cmd = (Scsi_Cmnd *)p->SCB_array[complete];
- if (!cmd) {
- printk("aic7xxx warning: "
- "no command for scb (cmdcmplt)\n");
- continue;
- }
- p->SCB_array[complete] = NULL;
-
- PAUSE_SEQUENCER(p);
-
- /*
- * After pausing the sequencer (and waiting
- * for it to stop), save its SCB pointer, then
- * write in our completed one and read the SCB
- * registers. Afterwards, restore the saved
- * pointer, unpause the sequencer and call the
- * higher-level completion function - unpause
- * first since we have no idea how long done()
- * will take.
- */
- old_scbptr = inb(O_SCBPTR(base));
- outb(complete, O_SCBPTR(base));
-
- aic7xxx_getscb(base, &scb);
- outb(old_scbptr, O_SCBPTR(base));
-
- UNPAUSE_SEQUENCER(p);
-
- cmd->result = scb.target_status |
- (aic7xxx_parity(cmd) << 16);
-
- /*
- * Did we 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 -= ((scb.residual_data_count[2] << 16) |
- (scb.residual_data_count[1] << 8) |
- (scb.residual_data_count[0]));
-
- if (actual < cmd->underflow) {
- printk("aic7xxx: target %d underflow - "
- "wanted (at least) %u, got %u\n",
- cmd->target, cmd->underflow, actual);
-
- cmd->result = scb.target_status |
- (DID_UNDERFLOW << 16);
- }
-
- cmd->scsi_done(cmd);
-
- /*
- * Clear interrupt status before checking
- * the output queue again. This eliminates
- * a race condition whereby a command could
- * complete between the queue poll and the
- * interrupt clearing, so notification of the
- * command being complete never made it back
- * up to the kernel.
- */
- outb(0x2, O_CLRINT(base)); /* CLRCMDINT */
-
- } while (inb(O_QOUTCNT(base)));
- }
- if (intstat & 0x1) { /* SEQINT */
+#define AIC7XXX_DEBUG
- unsigned char transfer, offset, rate;
+/*
+ * 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) \
+ outb(p->pause, HCNTRL(p->base)); \
+ while ((inb(HCNTRL(p->base)) & PAUSE) == 0) \
+ ; \
- /*
- * Although the sequencer is paused immediately on
- * a SEQINT, an interrupt for a SCSIINT or a CMDCMPLT
- * condition will have unpaused the sequencer before
- * this point.
- */
- PAUSE_SEQUENCER(p);
-
- switch (intstat & 0xf0) {
- case 0x00:
- panic("aic7xxx_isr: unknown scsi bus phase\n");
- case 0x10:
- debug("aic7xxx_isr warning: "
- "issuing message reject, 1st byte 0x%x\n",
- inb(HA_REJBYTE(base)));
- break;
- case 0x20:
- panic("aic7xxx_isr: reconnecting target %d "
- "didn't issue IDENTIFY message\n",
- (inb(O_SELID(base)) >> 4) & 0xf);
- case 0x30:
- debug("aic7xxx_isr: sequencer couldn't find match "
- "for reconnecting target %d - issuing ABORT\n",
- (inb(O_SELID(base)) >> 4) & 0xf);
- break;
- case 0x40:
- transfer = inb(HA_ARG_1(base));
- offset = inb(HA_ARG_2(base));
- aic7xxx_to_scsirate(&rate, transfer, offset);
- outb(rate, HA_RETURN_1(base));
- debug_rate(base, rate);
- break;
- default:
- debug("aic7xxx_isr: seqint, "
- "intstat = 0x%x, scsisigi = 0x%x\n",
- intstat, inb(O_SCSISIGI(base)));
- break;
- }
+/*
+ * 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))
- outb(0x1, O_CLRINT(base)); /* CLRSEQINT */
- UNPAUSE_SEQUENCER(p);
- }
-}
+/*
+ * 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);
/*
- * Probing for EISA boards: it looks like the first two bytes
- * are a manufacturer code - three characters, five bits each:
- *
- * BYTE 0 BYTE 1 BYTE 2 BYTE 3
- * ?1111122 22233333 PPPPPPPP RRRRRRRR
- *
- * The characters are baselined off ASCII '@', so add that value
- * to each to get the real ASCII code for it. The next two bytes
- * appear to be a product and revision number, probably vendor-
- * specific. This is what is being searched for at each port,
- * and what should probably correspond to the ID= field in the
- * ECU's .cfg file for the card - if your card is not detected,
- * make sure your signature is listed in the array.
- *
- * The fourth byte's lowest bit seems to be an enabled/disabled
- * flag (rest of the bits are reserved?).
+ * If an error occurs during a data transfer phase, run the comand
+ * to completion - it's easier that way - making a note of the error
+ * condition in this location. This then will modify a DID_OK status
+ * into an appropriate error for the higher-level SCSI code.
*/
+#define aic7xxx_error(cmd) ((cmd)->SCp.Status)
-static
-enum aha_type aic7xxx_probe(int slot, int s_base)
-{
- int i;
- unsigned char buf[4];
-
- static struct {
- int n;
- unsigned char signature[sizeof(buf)];
- enum aha_type type;
- } S[] = {
- 4, { 0x04, 0x90, 0x77, 0x71 }, T_274X, /* host adapter 274x */
- 4, { 0x04, 0x90, 0x77, 0x70 }, T_274X, /* motherboard 274x */
- 4, { 0x04, 0x90, 0x77, 0x56 }, T_284X, /* 284x, BIOS enabled */
- };
-
- for (i = 0; i < sizeof(buf); i++) {
- /*
- * The VL-bus cards need to be primed by
- * writing before a signature check.
- */
- outb(0x80 + i, s_base);
- buf[i] = inb(s_base + i);
- }
+/*
+ * Keep track of the targets returned status.
+ */
+#define aic7xxx_status(cmd) ((cmd)->SCp.sent_command)
- for (i = 0; i < sizeof(S)/sizeof(S[0]); i++) {
- if (!memcmp(buf, S[i].signature, S[i].n)) {
- /*
- * Signature match on enabled card?
- */
- if (inb(s_base + 4) & 1)
- return(S[i].type);
- printk("aic7xxx disabled at slot %d, ignored\n", slot);
- }
- }
- return(T_NONE);
-}
+/*
+ * The position of the SCSI commands scb within the scb array.
+ */
+#define aic7xxx_position(cmd) ((cmd)->SCp.have_data_in)
/*
- * Return ' ' for plain 274x, 'T' for twin-channel, 'W' for
- * wide channel, '?' for anything else.
+ * Since the sequencer code DMAs the scatter-gather structures
+ * directly from memory, we use this macro to assert that the
+ * kernel structure hasn't changed.
*/
+#define SG_STRUCT_CHECK(sg) \
+ ((char *)&(sg).address - (char *)&(sg) != 0 || \
+ (char *)&(sg).length - (char *)&(sg) != 8 || \
+ sizeof((sg).address) != 4 || \
+ sizeof((sg).length) != 4 || \
+ sizeof(sg) != 12)
-static
-char aic7xxx_type(int base)
-{
- /*
- * AIC-7770/7870s can be wired so that, on chip reset,
- * the SCSI Block Control register indicates how many
- * busses the chip is configured for. The two high bits
- * set indicate a 294x.
- */
- switch (inb(O_SBLKCTL(base))) {
- case 0:
- case 0xc0:
- return(' ');
- case 2:
- case 0xc2:
- return('W');
- case 8:
- return('T');
- default:
- printk("aic7xxx has unknown bus configuration\n");
- return('?');
- }
-}
+/*
+ * "Static" structures. Note that these are NOT initialized
+ * to zero inside the kernel - we have to initialize them all
+ * explicitly.
+ *
+ * We support a maximum of one adapter card per IRQ level (see the
+ * rationale for this above). On an interrupt, use the IRQ as an
+ * index into aic7xxx_boards[] to locate the card information.
+ */
+static struct Scsi_Host *aic7xxx_boards[MAXIRQ + 1];
-static
-void aic7xxx_loadram(int base)
-{
- 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"
- };
+/*
+ * The driver keeps up to four scb structures per card in memory. Only the
+ * first 26 bytes of the structure are valid for the hardware, the rest used
+ * for driver level bookeeping. The driver is further optimized
+ * so that we only have to download the first 19 bytes since as long
+ * as we always use S/G, the last fields should be zero anyway.
+ */
+#ifdef AIC7XXX_USE_SG
+#define SCB_DOWNLOAD_SIZE 19 /* amount to actually download */
+#else
+#define SCB_DOWNLOAD_SIZE 26
+#endif
+#define SCB_UPLOAD_SIZE 19 /* amount to actually upload */
+
+struct aic7xxx_scb {
+/* ------------ Begin hardware supported fields ---------------- */
+/*1 */ unsigned char control;
+#define SCB_NEEDWDTR 0x80 /* Initiate Wide Negotiation */
+#define SCB_NEEDSDTR 0x40 /* Initiate Sync Negotiation */
+#define SCB_NEEDDMA 0x08 /* SCB needs to be DMA'd from
+ * from host memory
+ */
+#define SCB_REJ_MDP 0x80 /* Reject MDP message */
+#define SCB_DISEN 0x40 /* SCB Disconnect enable */
+#define SCB_TE 0x20 /* Tag enable */
+/* RESERVED 0x10 */
+#define SCB_WAITING 0x08 /* Waiting */
+#define SCB_DIS 0x04 /* Disconnected */
+#define SCB_TAG_TYPE 0x03
+#define SIMPLE_QUEUE 0x00 /* Simple Queue */
+#define HEAD_QUEUE 0x01 /* Head of Queue */
+#define ORD_QUEUE 0x02 /* Ordered Queue */
+/* ILLEGAL 0x03 */
+/*2 */ unsigned char target_channel_lun; /* 4/1/3 bits */
+/*3 */ unsigned char SG_segment_count;
+/*7 */ unsigned char SG_list_pointer[4] __attribute__ ((packed));
+/*11*/ unsigned char SCSI_cmd_pointer[4] __attribute__ ((packed));
+/*12*/ unsigned char SCSI_cmd_length;
+/*14*/ unsigned char RESERVED[2]; /* must be zero */
+/*15*/ unsigned char target_status;
+/*18*/ unsigned char residual_data_count[3];
+/*19*/ unsigned char residual_SG_segment_count;
+/*23*/ unsigned char data_pointer[4] __attribute__ ((packed));
+/*26*/ unsigned char data_count[3];
+/*30*/ unsigned char host_scb[4] __attribute__ ((packed));
+/*31*/ u_char next_waiting; /* Used to thread SCBs awaiting selection. */
+#define SCB_LIST_NULL 0x10 /* SCB list equivelent to NULL */
+#if 0
/*
- * 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.
+ * No real point in transferring this to the
+ * SCB registers.
*/
- outb(0x83, O_SEQCTL(base)); /* PERRORDIS|SEQRESET|LOADRAM */
+ unsigned char RESERVED[1];
+#endif
- asm volatile("cld\n\t"
- "rep\n\t"
- "outsb"
- : /* no output */
- :"S" (seqprog), "c" (sizeof(seqprog)), "d" (O_SEQRAM(base))
- :"si", "cx", "dx");
+ /*-----------------end of hardware supported fields----------------*/
+ struct aic7xxx_scb *next; /* next ptr when in free list */
+ Scsi_Cmnd *cmd; /* Scsi_Cmnd for this scb */
+ int state; /* current state of scb */
+#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
+ unsigned int position; /* Position in scb array */
+#ifdef AIC7XXX_USE_SG
+ struct scatterlist sg;
+ struct scatterlist sense_sg;
+#endif
+ unsigned char sense_cmd[6]; /* Allocate 6 characters for sense command */
+};
- /*
- * 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?)
- */
- outb(0, O_SEQCTL(base));
- do {
- /*
- * Actually, reset it until
- * the address shows up as
- * zero just to be safe..
- */
- outb(0x2, O_SEQCTL(base)); /* SEQRESET */
+static struct {
+ unsigned char errno;
+ char *errmesg;
+} hard_error[] = {
+ { ILLHADDR, "Illegal Host Access" },
+ { ILLSADDR, "Illegal Sequencer Address referrenced" },
+ { ILLOPCODE, "Illegal Opcode in sequencer program" },
+ { PARERR, "Sequencer Ram Parity Error" }
+};
- } while (inb(O_SEQADDR(base)) != 0 && inb(O_SEQADDR(base) + 1) != 0);
-}
+static unsigned char
+generic_sense[] = { REQUEST_SENSE, 0, 0, 0, 255, 0 };
-static
-void aha274x_config(struct aic7xxx_host_config *p, va_list ap)
-{
- int base = va_arg(ap, int);
+/*
+ * 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 16
- /*
- * Give the AIC-7770 a reset - reading the 274x's registers
- * returns zeroes unless you do. This forces a pause of the
- * Sequencer.
- */
- outb(1, O_HCNTRL(base)); /* CHIPRST */
+/*
+ * Define a structure used for each host adapter, only one per IRQ.
+ */
+struct aic7xxx_host {
+ int base; /* card base address */
+ int maxscb; /* hardware SCBs */
+ int numscb; /* current number of scbs */
+ int extended; /* extended xlate? */
+ aha_type type; /* card type */
+ aha_bus_type bus_type; /* normal/twin/wide bus */
+ unsigned char a_scanned; /* 0 not scanned, 1 scanned */
+ unsigned char b_scanned; /* 0 not scanned, 1 scanned */
+ unsigned int isr_count; /* Interrupt count */
+ volatile unsigned char unpause; /* unpause value for HCNTRL */
+ volatile unsigned char pause; /* pause value for HCNTRL */
+ volatile unsigned short needsdtr_copy; /* default config */
+ volatile unsigned short needsdtr;
+ volatile unsigned short sdtr_pending;
+ volatile unsigned short needwdtr_copy; /* default config */
+ volatile unsigned short needwdtr;
+ volatile unsigned short wdtr_pending;
+ struct seeprom_config seeprom;
+ int have_seeprom;
+ struct Scsi_Host *next; /* allow for multiple IRQs */
+ struct aic7xxx_scb scb_array[AIC7XXX_MAXSCB]; /* active commands */
+ struct aic7xxx_scb *free_scb; /* list of free SCBs */
+};
- p->base = base;
- p->irq = inb(HA_INTDEF(base)) & 0xf;
- p->scsi_id = inb(HA_SCSICONF(base)) & 0x7;
+struct aic7xxx_host_config {
+ int irq; /* IRQ number */
+ int base; /* I/O base */
+ int maxscb; /* hardware SCBs */
+ 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 */
+ int extended; /* extended xlate? */
+ int busrtime; /* bus release time */
+ aha_type type; /* card type */
+ aha_bus_type bus_type; /* normal/twin/wide bus */
+ 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) */
+};
- /*
- * This value for HCNTRL may be changed in the ISR if we
- * catch a spurious interrupt right away.
- */
- p->unpause = 0xa;
+/*
+ * Valid SCSIRATE values. (p. 3-17)
+ * Provides a mapping of tranfer periods in ns to the proper value to
+ * stick in the scsiscfr reg to use that transfer rate.
+ */
+static struct {
+ short period;
+ short rate;
+ char *english;
+} aic7xxx_syncrates[] = {
+ { 100, 0, "10.0" },
+ { 125, 1, "8.0" },
+ { 150, 2, "6.67" },
+ { 175, 3, "5.7" },
+ { 200, 4, "5.0" },
+ { 225, 5, "4.4" },
+ { 250, 6, "4.0" },
+ { 275, 7, "3.6" }
+};
- /*
- * XXX - these are values that I don't know how to query
- * the hardware for. Apparently some revision E
- * '7770s can have more SCBs, and I don't know how
- * to get the "extended translation" flag from the
- * EISA data area.
- */
- p->maxscb = 4;
- p->extended = aic7xxx_extended;
+static int num_aic7xxx_syncrates =
+ sizeof(aic7xxx_syncrates) / sizeof(aic7xxx_syncrates[0]);
- /*
- * A reminder until this can be detected automatically.
- */
- printk("aha274x: extended translation %sabled\n",
- p->extended ? "en" : "dis");
-}
+#ifdef AIC7XXX_DEBUG
+extern int vsprintf(char *, const char *, va_list);
-static
-void aha284x_config(struct aic7xxx_host_config *p, va_list ap)
+static void
+debug(const char *fmt, ...)
{
- int base = va_arg(ap, int);
+ va_list ap;
+ char buf[256];
- /*
- * Give the AIC-7770 a reset - this forces a pause of the
- * Sequencer and returns everything to default values.
- */
- outb(1, O_HCNTRL(base)); /* CHIPRST */
+ va_start(ap, fmt);
+ vsprintf(buf, fmt, ap);
+ printk(buf);
+ va_end(ap);
+}
- p->base = base;
- p->unpause = 0x2;
- p->irq = inb(HA_INTDEF(base)) & 0xf;
- p->scsi_id = inb(HA_SCSICONF(base)) & 0x7;
+static void
+debug_config(struct aic7xxx_host_config *p)
+{
+ int host_conf, scsi_conf;
+ unsigned char brelease;
+ unsigned char dfthresh;
+
+ static int DFT[] = { 0, 50, 75, 100 };
+ static int SST[] = { 256, 128, 64, 32 };
+ static char *BUSW[] = { "", "-TWIN", "-WIDE" };
+
+ host_conf = inb(HA_HOSTCONF(p->base));
+ scsi_conf = inb(HA_SCSICONF(p->base));
+
+ /*
+ * The 7870 gets the bus release time and data FIFO threshold
+ * from the serial EEPROM (stored in the config structure) and
+ * scsi_conf register respectively. The 7770 gets the bus
+ * release time and data FIFO threshold from the scsi_conf and
+ * host_conf registers respectively.
+ */
+ if ((p->type == AIC_274x) || (p->type == AIC_284x))
+ {
+ brelease = scsi_conf & 0x3F;
+ dfthresh = host_conf >> 6;
+ }
+ else
+ {
+ brelease = p->busrtime;
+ dfthresh = scsi_conf >> 6;
+ }
+ if (brelease == 0)
+ {
+ brelease = 2;
+ }
+
+ switch (p->type)
+ {
+ case AIC_274x:
+ printk("AIC7770%s AT EISA SLOT %d:\n", BUSW[p->bus_type], p->base >> 12);
+ break;
+
+ case AIC_284x:
+ printk("AIC7770%s AT VLB SLOT %d:\n", BUSW[p->bus_type], p->base >> 12);
+ break;
+
+ case AIC_7870:
+ printk("AIC7870%s (PCI-bus):\n", BUSW[p->bus_type]);
+ break;
+
+ case AIC_7850:
+ printk("AIC7850%s (PCI-bus):\n", BUSW[p->bus_type]);
+ break;
+
+ case AIC_7872:
+ printk("AIC7872%s (PCI-bus):\n", BUSW[p->bus_type]);
+ 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->type == AIC_274x) || (p->type == AIC_284x)) && 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_274x)
+ {
+ 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");
+ }
+}
+#else
+# define debug(fmt, args...)
+# define debug_config(x)
+#endif AIC7XXX_DEBUG
- /*
- * XXX - these are values that I don't know how to query
- * the hardware for. Apparently some revision E
- * '7770s can have more SCBs, and I don't know how
- * to get the "extended translation" flag from the
- * onboard memory.
- */
- p->maxscb = 4;
- p->extended = aic7xxx_extended;
+/*
+ * 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?
+ */
+static int aic7xxx_extended = 0; /* extended translation on? */
+static int aic7xxx_no_reset = 0; /* no resetting of SCSI bus */
- /*
- * A reminder until this can be detected automatically.
- */
- printk("aha284x: extended translation %sabled\n",
- p->extended ? "en" : "dis");
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_setup
+ *
+ * Description:
+ * Handle Linux boot parameters.
+ *-F*************************************************************************/
+void
+aic7xxx_setup(char *s, int *dummy)
+{
+ int i;
+ char *p;
+
+ static struct {
+ char *name;
+ int *flag;
+ } options[] = {
+ { "extended", &aic7xxx_extended },
+ { "no_reset", &aic7xxx_no_reset },
+ { NULL, NULL}
+ };
+
+ for (p = strtok(s, ","); p; p = strtok(NULL, ","))
+ {
+ for (i = 0; options[i].name; i++)
+ {
+ if (!strcmp(options[i].name, p))
+ {
+ *(options[i].flag) = !0;
+ }
+ }
+ }
}
-static
-void aha294x_config(struct aic7xxx_host_config *p, va_list ap)
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_loadseq
+ *
+ * Description:
+ * Load the sequencer code into the controller memory.
+ *-F*************************************************************************/
+static void
+aic7xxx_loadseq(int base)
{
- int error;
- unsigned long io_port;
- unsigned char bus, device_fn, irq;
+ 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"
+ };
+
+ /*
+ * 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));
+
+ asm volatile("cld\n\t"
+ "rep\n\t"
+ "outsb"
+ : /* no output */
+ :"S" (seqprog), "c" (sizeof(seqprog)), "d" (SEQRAM(base))
+ :"si", "cx", "dx");
+
+ /*
+ * 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));
+}
- bus = va_arg(ap, unsigned char);
- device_fn = va_arg(ap, unsigned char);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_delay
+ *
+ * Description:
+ * Delay for specified amount of time.
+ *-F*************************************************************************/
+static void
+aic7xxx_delay(int seconds)
+{
+ unsigned long i;
- /*
- * Read esundry information from PCI BIOS.
- */
- error = pcibios_read_config_dword(bus,
- device_fn,
- PCI_BASE_ADDRESS_0,
- &io_port);
- if (error) {
- panic("aha294x_config: error %s reading i/o port\n",
- pcibios_strerror(error));
- }
+ i = jiffies + (seconds * 100); /* compute time to stop */
- error = pcibios_read_config_byte(bus,
- device_fn,
- PCI_INTERRUPT_LINE,
- &irq);
- if (error) {
- panic("aha294x_config: error %s reading irq\n",
- pcibios_strerror(error));
- }
+ while (jiffies < i)
+ {
+ ; /* Do nothing! */
+ }
+}
- /*
- * Make the base I/O register look like EISA and VL-bus.
- */
- p->base = io_port - 0xc01;
+/*+F*************************************************************************
+ * Function:
+ * rcs_version
+ *
+ * Description:
+ * Return a string containing just the RCS version number from either
+ * an Id or Revison RCS clause.
+ *-F*************************************************************************/
+const char *
+rcs_version(const char *version_info)
+{
+ static char buf[10];
+ char *bp, *ep;
+
+ bp = NULL;
+ strcpy(buf, "????");
+ if (!strncmp(version_info, "$Id: ", 5))
+ {
+ if ((bp = strchr(version_info, ' ')) != NULL)
+ {
+ bp++;
+ if ((bp = strchr(bp, ' ')) != NULL)
+ {
+ bp++;
+ }
+ }
+ }
+ else
+ {
+ if (!strncmp(version_info, "$Revision: ", 11))
+ {
+ if ((bp = strchr(version_info, ' ')) != NULL)
+ {
+ bp++;
+ }
+ }
+ }
+
+ if (bp != NULL)
+ {
+ if ((ep = strchr(bp, ' ')) != NULL)
+ {
+ register int len = ep - bp;
+
+ strncpy(buf, bp, len);
+ buf[len] = '\0';
+ }
+ }
+
+ return buf;
+}
- /*
- * Give the AIC-7870 a reset - this forces a pause of the
- * Sequencer and returns everything to default values.
- */
- outb(1, O_HCNTRL(p->base)); /* CHIPRST */
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_info
+ *
+ * Description:
+ * Return a string describing the driver.
+ *-F*************************************************************************/
+const char *
+aic7xxx_info(struct Scsi_Host *notused)
+{
+ static char buffer[128];
- p->irq = irq;
- p->maxscb = 16;
- p->unpause = 0xa;
+ strcpy(buffer, "Adaptec AHA274x/284x/294x (EISA/VLB/PCI-Fast SCSI) ");
+ strcat(buffer, rcs_version(AIC7XXX_C_VERSION));
+ strcat(buffer, "/");
+ strcat(buffer, rcs_version(AIC7XXX_H_VERSION));
+ strcat(buffer, "/");
+ strcat(buffer, rcs_version(AIC7XXX_SEQ_VER));
- /*
- * XXX - these are values that I don't know how to query
- * the hardware for, so for now the SCSI host ID is
- * hardwired to 7, and the "extended translation"
- * flag is taken from boot-time flags.
- */
- p->scsi_id = 7;
- p->extended = aic7xxx_extended;
+ return buffer;
+}
- /*
- * XXX - force data fifo threshold to 100%. Why does this
- * need to be done?
- */
-# define DFTHRESH 3
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_putscb
+ *
+ * Description:
+ * Transfer a SCB to the controller.
+ *-F*************************************************************************/
+static void
+aic7xxx_putscb(int base, struct aic7xxx_scb *scb)
+{
+#ifdef AIC7XXX_USE_DMA
+ /*
+ * All we need to do, is to output the position
+ * of the SCB in the SCBARRAY to the QINFIFO
+ * of the host adapter.
+ */
+ outb(scb->position, QINFIFO(base));
+#else
+ /*
+ * 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.
+ */
+ outb(SCBAUTO, SCBCNT(base));
+
+ asm volatile("cld\n\t"
+ "rep\n\t"
+ "outsb"
+ : /* no output */
+ :"S" (scb), "c" (SCB_DOWNLOAD_SIZE), "d" (SCBARRAY(base))
+ :"si", "cx", "dx");
+
+ outb(0, SCBCNT(base));
+#endif
+}
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_putdmascb
+ *
+ * Description:
+ * DMA a SCB to the controller.
+ *-F*************************************************************************/
+static void
+aic7xxx_putdmascb(int base, struct aic7xxx_scb *scb)
+{
+ /*
+ * 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.
+ */
+ outb(SCBAUTO, SCBCNT(base));
+
+ asm volatile("cld\n\t"
+ "rep\n\t"
+ "outsb"
+ : /* no output */
+ :"S" (scb), "c" (31), "d" (SCBARRAY(base))
+ :"si", "cx", "dx");
+
+ outb(0, SCBCNT(base));
+}
- outb(DFTHRESH << 6, O_DSPCISTATUS(p->base));
- outb(p->scsi_id | (DFTHRESH << 6), HA_SCSICONF(p->base));
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_getscb
+ *
+ * Description:
+ * Get a SCB from the controller.
+ *-F*************************************************************************/
+static void
+aic7xxx_getscb(int base, struct aic7xxx_scb *scb)
+{
+ /*
+ * This is almost identical to aic7xxx_putscb().
+ */
+ outb(SCBAUTO, SCBCNT(base));
+
+ asm volatile("cld\n\t"
+ "rep\n\t"
+ "insb"
+ : /* no output */
+ :"D" (scb), "c" (SCB_UPLOAD_SIZE), "d" (SCBARRAY(base))
+ :"di", "cx", "dx");
+
+ outb(0, SCBCNT(base));
+}
- /*
- * A reminder until this can be detected automatically.
- */
- printk("aha294x: extended translation %sabled\n",
- p->extended ? "en" : "dis");
+/*+F*************************************************************************
+ * Function:
+ * 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.
+ *-F*************************************************************************/
+static unsigned
+aic7xxx_length(Scsi_Cmnd *cmd, int sg_last)
+{
+ int i, segments;
+ unsigned length;
+ struct scatterlist *sg;
+
+ segments = cmd->use_sg - sg_last;
+ sg = (struct scatterlist *) cmd->buffer;
+
+ if (cmd->use_sg)
+ {
+ for (i = length = 0; i < cmd->use_sg && i < segments; i++)
+ {
+ length += sg[i].length;
+ }
+ }
+ else
+ {
+ length = cmd->request_bufflen;
+ }
+
+ return(length);
}
-static
-int aic7xxx_register(Scsi_Host_Template *template, enum aha_type type, ...)
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_scsirate
+ *
+ * Description:
+ * Look up the valid period to SCSIRATE conversion in our table
+ *-F*************************************************************************/
+static void
+aic7xxx_scsirate(unsigned char *scsirate, unsigned char period,
+ unsigned char offset, int target)
{
- va_list ap;
- int i, base;
- struct Scsi_Host *host;
- struct aic7xxx_host *p;
- struct aic7xxx_host_config config;
-
- va_start(ap, type);
-
- switch (type) {
- case T_274X:
- aha274x_config(&config, ap);
- break;
- case T_284X:
- aha284x_config(&config, ap);
- break;
- case T_294X:
- aha294x_config(&config, ap);
- break;
- default:
- panic("aic7xxx_register: internal error\n");
+ int i;
+
+ for (i = 0; i < num_aic7xxx_syncrates; i++)
+ {
+ if ((aic7xxx_syncrates[i].period - period) >= 0)
+ {
+ *scsirate = (aic7xxx_syncrates[i].rate << 4) | (offset & 0x0F);
+ printk("aic7xxx: target %d now synchronous at %sMb/s, offset = 0x%x\n",
+ target, aic7xxx_syncrates[i].english, offset);
+ return;
+ }
+ }
+
+ /*
+ * Default to asyncronous transfer
+ */
+ *scsirate = 0;
+ printk("aic7xxx: target %d using asynchronous transfers\n", target);
+}
+
+/*+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, struct pt_regs * regs)
+{
+ int base, intstat;
+ struct aic7xxx_host *p;
+ struct aic7xxx_scb *scb;
+ unsigned char active, ha_flags, transfer;
+ unsigned char scsi_id, bus_width;
+ unsigned char offset, rate, scratch;
+ unsigned char max_offset;
+ unsigned char head, tail;
+ unsigned short target_mask;
+ long flags;
+ void *addr;
+ int actual;
+ int target, tcl;
+ int scbptr;
+ Scsi_Cmnd *cmd;
+#if 0
+static int_count = 0;
+#endif
+
+ p = (struct aic7xxx_host *) aic7xxx_boards[irq]->hostdata;
+#ifdef AIC7XXX_SHARE_IRQS
+ /*
+ * Search for the host with a pending interrupt.
+ */
+ while ((p != NULL) && !(inb(INTSTAT(p->base)) & INT_PEND))
+ {
+ p = (struct aic7xxx_host *) p->next->hostdata;
+ }
+ if (p == NULL)
+ {
+ printk("aic7xxx_isr: Encountered spurious interrupt.\n");
+ return;
+ }
+#endif
+ base = p->base;
+ if (p->isr_count == 0xffffffff)
+ {
+ p->isr_count = 0;
+ }
+ else
+ {
+ p->isr_count = p->isr_count + 1;
+ }
+ if ((p->a_scanned == 0) && (p->isr_count == 1))
+ {
+ /* Allow for one interrupt when the card is enabled. */
+ return;
+ }
+
+ /*
+ * Handle all the interrupt sources - especially for SCSI
+ * interrupts, we won't get a second chance at them.
+ */
+ intstat = inb(INTSTAT(base));
+
+ if (intstat & BRKADRINT)
+ {
+ int i;
+ unsigned char errno = inb(ERROR(base));
+
+ printk("aic7xxx_isr: brkadrint (0x%x):\n", errno);
+ for (i = 0; i < NUMBER(hard_error); i++)
+ {
+ if (errno & hard_error[i].errno)
+ {
+ printk(" %s\n", hard_error[i].errmesg);
+ }
+ }
+
+ panic("aic7xxx_isr: brkadrint, error = 0x%x, seqaddr = 0x%x\n",
+ inb(ERROR(base)),
+ inb(SEQADDR1(base)) << 8 | inb(SEQADDR0(base)));
+ }
+
+ if (intstat & SEQINT)
+ {
+ /*
+ * Although the sequencer is paused immediately on
+ * a SEQINT, an interrupt for a SCSIINT or a CMDCMPLT
+ * condition will have unpaused the sequencer before
+ * this point.
+ */
+ PAUSE_SEQUENCER(p);
+
+ switch (intstat & SEQINT_MASK)
+ {
+ case BAD_PHASE:
+ panic("aic7xxx_isr: unknown scsi bus phase\n");
+
+ case SEND_REJECT:
+ debug("aic7xxx_isr warning: issuing message reject, 1st byte 0x%x\n",
+ inb(HA_REJBYTE(base)));
+ break;
+
+ case NO_IDENT:
+ panic("aic7xxx_isr: reconnecting target %d at seqaddr 0x%x "
+ "didn't issue IDENTIFY message\n",
+ (inb(SELID(base)) >> 4) & 0x0F,
+ (inb(SEQADDR1(base)) << 8) | inb(SEQADDR0(base)));
+ break;
+
+ case NO_MATCH:
+ tcl = inb(SCBARRAY(base) + 1);
+ target = (tcl >> 4) & 0x0F;
+ /* Purposefully mask off the top bit of targets 8-15. */
+ target_mask = 0x01 << (target & 0x07);
+
+ debug("aic7xxx_isr: sequencer couldn't find match "
+ "for reconnecting target %d, channel %d, lun %d - "
+ "issuing ABORT\n", target, (tcl & 0x08) >> 3, tcl & 0x07);
+ if (tcl & 0x88)
+ {
+ /* Second channel stores its info in byte
+ * two of HA_ACTIVE
+ */
+ active = inb(HA_ACTIVE1(base));
+ active = active & ~(target_mask);
+ outb(active, HA_ACTIVE1(base));
}
- va_end(ap);
+ else
+ {
+ active = inb(HA_ACTIVE0(base));
+ active = active & ~(target_mask);
+ outb(active, HA_ACTIVE0(base));
+ }
+#ifdef AIC7XXX_USE_DMA
+ outb(SCB_NEEDDMA, SCBARRAY(base));
+#endif
- base = config.base;
+ /*
+ * Check out why this use to be outb(0x80, CLRINT(base))
+ * clear the timeout
+ */
+ outb(CLRSELTIMEO, CLRSINT1(base));
+ RESTART_SEQUENCER(p);
+ break;
+ case MSG_SDTR:
/*
- * 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?
+ * 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.
*/
- if (config.irq < 9 || config.irq > 15) {
- printk("aic7xxx uses unsupported IRQ level, ignoring\n");
- return(0);
+ transfer = (inb(HA_ARG_1(base)) << 2);
+ offset = inb(ACCUM(base));
+ scsi_id = inb(SCSIID(base)) >> 0x04;
+ if (inb(SBLKCTL(base)) & 0x08)
+ {
+ scsi_id = scsi_id + 8; /* B channel */
}
-
+ target_mask = (0x01 << scsi_id);
+ scratch = inb(HA_TARG_SCRATCH(base) + scsi_id);
/*
- * Lock out other contenders for our i/o space.
+ * The maximum offset for a wide device is 0x08; for a
+ * 8-bit bus device the maximum offset is 0x0f.
*/
- snarf_region(O_MINREG(base), O_MAXREG(base)-O_MINREG(base));
-
+ if (scratch & 0x80)
+ {
+ max_offset = 0x08;
+ }
+ else
+ {
+ max_offset = 0x0f;
+ }
+ aic7xxx_scsirate(&rate, transfer, MIN(offset, max_offset), scsi_id);
/*
- * Any card-type-specific adjustments before we register
- * the scsi host(s).
+ * Preserve the wide transfer flag.
*/
- switch (aic7xxx_type(base)) {
- case 'T':
- printk("aic7xxx warning: ignoring channel B of 274x-twin\n");
- break;
- case ' ':
- break;
- default:
- printk("aic7xxx is an unsupported type, ignoring\n");
- return(0);
+ rate = rate | (scratch & 0x80);
+ outb(rate, HA_TARG_SCRATCH(base) + scsi_id);
+ outb(rate, SCSIRATE(base));
+ if ((rate & 0xf) == 0)
+ { /*
+ * The requested rate was so low that asynchronous transfers
+ * are faster (not to mention the controller won't support
+ * them), so we issue a reject to ensure we go to asynchronous
+ * transfers.
+ */
+ outb(SEND_REJ, HA_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, HA_RETURN_1(base));
+ }
+ else
+ {
+ /*
+ * Send our own SDTR in reply.
+ */
+ printk("Sending SDTR!!\n");
+ outb(SEND_SDTR, HA_RETURN_1(base));
+ }
}
-
/*
- * Before registry, make sure that the offsets of the
- * struct scatterlist are what the sequencer will expect,
- * otherwise disable scatter-gather altogether until someone
- * can fix it. This is important since the sequencer will
- * DMA elements of the SG array in while executing commands.
+ * Clear the flags.
*/
- if (template->sg_tablesize != SG_NONE) {
- struct scatterlist sg;
+ p->needsdtr = p->needsdtr & ~target_mask;
+ p->sdtr_pending = p->sdtr_pending & ~target_mask;
+ break;
+
+ case MSG_WDTR:
+ {
+ bus_width = inb(ACCUM(base));
+ scsi_id = inb(SCSIID(base)) >> 0x04;
+ if (inb(SBLKCTL(base)) & 0x08)
+ {
+ scsi_id = scsi_id + 8; /* B channel */
+ }
+ printk("Received MSG_WDTR, scsi_id = %d, "
+ "needwdtr = 0x%x\n", scsi_id, p->needwdtr);
+ scratch = inb(HA_TARG_SCRATCH(base) + scsi_id);
- if (SG_STRUCT_CHECK(sg)) {
- printk("aic7xxx warning: kernel scatter-gather "
- "structures changed, disabling it\n");
- template->sg_tablesize = SG_NONE;
- }
+ target_mask = (0x01 << scsi_id);
+ if (p->wdtr_pending & target_mask)
+ {
+ /*
+ * Don't send an WDTR back to the target, since we asked first.
+ */
+ outb(0, HA_RETURN_1(base));
+ switch (bus_width)
+ {
+ case BUS_8_BIT:
+ scratch = scratch & 0x7F;
+ break;
+
+ case BUS_16_BIT:
+ printk("aic7xxx_isr: target %d using 16 bit transfers\n",
+ scsi_id);
+ scratch = scratch | 0x80;
+ break;
+ }
}
-
+ else
+ {
+ /*
+ * Send our own WDTR in reply.
+ */
+ printk("Will send WDTR!!\n");
+ switch (bus_width)
+ {
+ case BUS_8_BIT:
+ scratch = 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("aic7xxx_isr: target %d using 16 bit transfers\n",
+ scsi_id);
+ scratch = scratch | 0x80;
+ break;
+ }
+ outb(bus_width | SEND_WDTR, HA_RETURN_1(base));
+ }
+ p->needwdtr = p->needwdtr & ~target_mask;
+ p->wdtr_pending = p->wdtr_pending & ~target_mask;
+ outb(scratch, HA_TARG_SCRATCH(base) + scsi_id);
+ outb(scratch, SCSIRATE(base));
+ break;
+ }
+
+ case MSG_REJECT:
+ {
/*
- * 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.
+ * 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.
*/
- host = scsi_register(template, sizeof(struct aic7xxx_host));
- host->can_queue = config.maxscb;
- host->this_id = config.scsi_id;
- host->irq = config.irq;
- aic7xxx_boards[config.irq] = host;
-
- p = (struct aic7xxx_host *)host->hostdata;
- for (i = 0; i < AIC7XXX_MAXSCB; i++)
- p->SCB_array[i] = NULL;
+ unsigned char targ_scratch, scsi_id;
+ unsigned short mask;
- p->base = config.base;
- p->maxscb = config.maxscb;
- p->extended = config.extended;
+ scsi_id = inb(SCSIID(base)) >> 0x04;
+ if (inb(SBLKCTL(base)) & 0x08)
+ {
+ scsi_id = scsi_id + 8;
+ }
- /*
- * The interrupt trigger is different depending
- * on whether the card is EISA or VL-bus - sometimes.
- * The startup variable will be cleared once the first
- * command is queued, and is checked in the isr to
- * try and detect when the interrupt type is set
- * incorrectly, triggering an interrupt immediately.
- * This is now just set on a per-card-type basis.
- */
- p->unpause = config.unpause;
- p->startup = !0;
+ mask = (0x01 << scsi_id);
- /*
- * Register IRQ with the kernel _after_ the host information
- * is set up, in case we take an interrupt right away, due to
- * the interrupt type being set wrong.
- */
- if (request_irq(config.irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx")) {
- printk("aic7xxx couldn't register irq %d, ignoring\n",
- config.irq);
- return(0);
- }
+ targ_scratch = inb(HA_TARG_SCRATCH(base) + scsi_id);
- /*
- * Print out debugging information before re-enabling
- * the card - a lot of registers on it can't be read
- * when the sequencer is active.
- */
-#ifdef AIC7XXX_DEBUG
- debug_config(type, &config);
+ if (p->wdtr_pending & mask)
+ {
+ /*
+ * note 8bit xfers and clear flag
+ */
+ targ_scratch = targ_scratch & 0x7F;
+ p->needwdtr = p->needwdtr & ~mask;
+ p->wdtr_pending = p->wdtr_pending & ~mask;
+ outb(targ_scratch, HA_TARG_SCRATCH(base) + scsi_id);
+ printk("aic7xxx: target %d refusing WIDE negotiation. Using "
+ "8 bit transfers\n", scsi_id);
+ }
+ else
+ {
+ if (p->sdtr_pending & mask)
+ {
+ /*
+ * note asynch xfers and clear flag
+ */
+ targ_scratch = targ_scratch & 0xF0;
+ p->needsdtr = p->needsdtr & ~mask;
+ p->sdtr_pending = p->sdtr_pending & ~mask;
+ outb(targ_scratch, HA_TARG_SCRATCH(base) + scsi_id);
+ printk("aic7xxx: target %d refusing syncronous negotiation. Using "
+ "asyncronous transfers\n", scsi_id);
+ }
+ /*
+ * Otherwise, we ignore it.
+ */
+ }
+ outb(targ_scratch, HA_TARG_SCRATCH(base) + scsi_id);
+ outb(targ_scratch, SCSIRATE(base));
+ break;
+ }
+
+ case BAD_STATUS:
+ scsi_id = inb(SCSIID(base)) >> 0x04;
+ scbptr = inb(SCBPTR(base));
+ scb = &(p->scb_array[scbptr]);
+ outb(0, HA_RETURN_1(base)); /* CHECK_CONDITION may change this */
+ if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk("aic7xxx_isr: referenced scb not valid "
+ "during seqint 0x%x scb(%d) state(%x), cmd(%x)\n",
+ intstat, scbptr, scb->state, (unsigned int) scb->cmd);
+ }
+ else
+ {
+ cmd = scb->cmd;
+ aic7xxx_getscb(base, scb);
+ aic7xxx_status(cmd) = scb->target_status;
+
+ cmd->result = cmd->result | scb->target_status;
+
+ /*
+ * This test is just here for debugging purposes.
+ * It will go away when the timeout problem is resolved.
+ */
+ switch (status_byte(scb->target_status))
+ {
+ case GOOD:
+ break;
+
+ case CHECK_CONDITION:
+ if ((aic7xxx_error(cmd) == 0) && !(cmd->flags & WAS_SENSE))
+ {
+ void *req_buf;
+#ifndef AIC7XXX_USE_SG
+ unsigned int req_buflen;
#endif
- /*
- * 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_loadram(base);
- if (type != T_294X)
- outb(1, O_BCTL(base)); /* ENABLE */
-
- /*
- * Set the host adapter registers to indicate that synchronous
- * negotiation should be attempted the first time the targets
- * are communicated with. Also initialize the active message
- * flag to indicate that there is no message.
- */
- outb(0xff, HA_NEEDSDTR(base));
- outb(0, HA_MSG_FLAGS(base));
+ /* Update the timeout for the SCSI command. */
+/* update_timeout(cmd, SENSE_TIMEOUT); */
- /*
- * For reconnecting targets, the sequencer code needs to
- * know how many SCBs it has to search through.
- */
- outb(config.maxscb, HA_SCBCOUNT(base));
+ /* Send a sense command to the requesting target. */
+ cmd->flags = cmd->flags | WAS_SENSE;
+ memcpy((void *) scb->sense_cmd, (void *) generic_sense,
+ sizeof(generic_sense));
- /*
- * 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(1);
-}
+ scb->sense_cmd[1] = cmd->lun << 5;
+ scb->sense_cmd[4] = sizeof(cmd->sense_buffer);
-int aic7xxx_detect(Scsi_Host_Template *template)
-{
- enum aha_type type;
- int found = 0, slot, base;
+#ifdef AIC7XXX_USE_SG
+ scb->sense_sg.address = (char *) &cmd->sense_buffer;
+ scb->sense_sg.length = sizeof(cmd->sense_buffer);
+ req_buf = &scb->sense_sg;
+#else
+ req_buf = &cmd->sense_buffer;
+ req_buflen = sizeof(cmd->sense_buffer);
+#endif
+ cmd->cmd_len = COMMAND_SIZE(cmd->cmnd[0]);
+ memset(scb, 0, SCB_DOWNLOAD_SIZE);
+ scb->target_channel_lun = ((cmd->target << 4) & 0xF0) |
+ ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+ addr = scb->sense_cmd;
+ scb->SCSI_cmd_length = COMMAND_SIZE(scb->sense_cmd[0]);
+ memcpy(scb->SCSI_cmd_pointer, &addr,
+ sizeof(scb->SCSI_cmd_pointer));
+#ifdef AIC7XXX_USE_SG
+ scb->SG_segment_count = 1;
+ memcpy (scb->SG_list_pointer, &req_buf,
+ sizeof(scb->SG_list_pointer));
+#else
+ scb->SG_segment_count = 0;
+ memcpy (scb->data_pointer, &req_buf,
+ sizeof(scb->data_pointer));
+ memcpy (scb->data_count, &req_buflen, 3);
+#endif
- /*
- * EISA/VL-bus card signature probe.
- */
- for (slot = MINSLOT; slot <= MAXSLOT; slot++) {
+ outb(SCBAUTO, SCBCNT(base));
+ asm volatile("cld\n\t"
+ "rep\n\t"
+ "outsb"
+ : /* no output */
+ :"S" (scb), "c" (SCB_DOWNLOAD_SIZE), "d" (SCBARRAY(base))
+ :"si", "cx", "dx");
+ outb(0, SCBCNT(base));
+ outb(SCB_LIST_NULL, (SCBARRAY(base) + 30));
- base = SLOTBASE(slot);
-
- if (check_region(O_MINREG(base),
- O_MAXREG(base)-O_MINREG(base)))
+ /*
+ * Add this SCB to the "waiting for selection" list.
+ */
+ head = inb(WAITING_SCBH(base));
+ tail = inb(WAITING_SCBT(base));
+ if (head & SCB_LIST_NULL)
+ { /* list is empty */
+ head = scb->position;
+ tail = SCB_LIST_NULL;
+ }
+ else
{
- /*
- * Some other driver has staked a
- * claim to this i/o region already.
- */
- continue;
+ if (tail & SCB_LIST_NULL)
+ { /* list has one element */
+ tail = scb->position;
+ outb(head, SCBPTR(base));
+ outb(tail, (SCBARRAY(base) + 30));
+ }
+ else
+ { /* list has more than one element */
+ outb(tail, SCBPTR(base));
+ tail = scb->position;
+ outb(tail, (SCBARRAY(base) + 30));
+ }
}
+ outb(head, WAITING_SCBH(base));
+ outb(tail, WAITING_SCBT(base));
+ outb(SEND_SENSE, HA_RETURN_1(base));
+ } /* first time sense, no errors */
+ else
+ {
+ /*
+ * Indicate that we asked for sense, have the sequencer do
+ * a normal command complete, and have the scsi driver handle
+ * this condition.
+ */
+ cmd->flags = cmd->flags | ASKED_FOR_SENSE;
+ }
+ break;
+
+ case BUSY:
+ printk("aic7xxx_isr: Target busy\n");
+ if (!aic7xxx_error(cmd))
+ {
+ aic7xxx_error(cmd) = DID_BUS_BUSY;
+ }
+ break;
+
+ case QUEUE_FULL:
+ printk("aic7xxx_isr: Queue full\n");
+ if (!aic7xxx_error(cmd))
+ {
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ }
+ break;
- type = aic7xxx_probe(slot, O_BIDx(base));
-
- if (type != T_NONE) {
- /*
- * We "find" a 274x if we locate the card
- * signature and we can set it up and register
- * it with the kernel without incident.
- */
- found += aic7xxx_register(template, type, base);
- }
+ default:
+ printk("aic7xxx_isr: Unexpected target status 0x%x\n",
+ scb->target_status);
+ if (!aic7xxx_error(cmd))
+ {
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ }
+ break;
+ } /* end switch */
+ } /* end else of */
+ break;
+
+ case RESIDUAL:
+ scbptr = inb(SCBPTR(base));
+ scb = &(p->scb_array[scbptr]);
+ if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk("aic7xxx_isr: referenced scb not valid "
+ "during seqint 0x%x scb(%d) state(%x), cmd(%x)\n",
+ intstat, scbptr, scb->state, (unsigned int) scb->cmd);
}
-
- /*
- * PCI-bus probe.
- */
- if (pcibios_present()) {
- int index = 0;
- unsigned char bus, device_fn;
-
- while (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
- PCI_DEVICE_ID_ADAPTEC_2940,
- index,
- &bus,
- &device_fn))
- {
- found += aic7xxx_register(template, T_294X,
- bus, device_fn);
- index += 1;
- }
+ 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(SCBARRAY(base + 17)) << 16) |
+ (inb(SCBARRAY(base + 16)) << 8) |
+ inb(SCBARRAY(base + 15)));
+
+ if (actual < cmd->underflow)
+ {
+ printk("aic7xxx: target %d underflow - "
+ "wanted (at least) %u, got %u\n",
+ cmd->target, cmd->underflow, actual);
+
+ aic7xxx_error(cmd) = DID_RETRY_COMMAND;
+ aic7xxx_status(cmd) = scb->target_status;
+ }
+ }
}
+ break;
- template->name = (char *)aic7xxx_info(NULL);
- return(found);
-}
-
-const char *aic7xxx_info(struct Scsi_Host *notused)
-{
- return("Adaptec AHA274x/284x/294x (EISA/VL-bus/PCI -> Fast SCSI) "
- AIC7XXX_SEQ_VERSION "/"
- AIC7XXX_H_VERSION "/"
- "1.34");
-}
-
-static
-void aic7xxx_buildscb(struct aic7xxx_host *p,
- Scsi_Cmnd *cmd,
- struct aic7xxx_scb *scb)
-{
- void *addr;
- unsigned length;
-
- memset(scb, 0, sizeof(*scb));
+ case ABORT_TAG:
+ scbptr = inb(SCBPTR(base));
+ scb = &(p->scb_array[scbptr]);
+ if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk("aic7xxx_isr: referenced scb not valid "
+ "during seqint 0x%x scb(%d) state(%x), cmd(%x)\n",
+ intstat, scbptr, scb->state, (unsigned int) scb->cmd);
+ }
+ else
+ {
+ cmd = scb->cmd;
+ /*
+ * We didn't recieve a valid tag back from the target
+ * on a reconnect.
+ */
+ printk("aic7xxx_isr: invalid tag recieved on channel %c "
+ "target %d, lun %d -- sending ABORT_TAG\n",
+ (cmd->channel & 0x01) ? 'B':'A',
+ cmd->target, cmd->lun & 0x07);
+ /*
+ * This is a critical section, since we don't want the
+ * queue routine mucking with the host data.
+ */
+ save_flags(flags);
+ cli();
+
+ /*
+ * Process the command after marking the scb as free
+ * and adding it to the free list.
+ */
+ scb->state = SCB_FREE;
+ scb->cmd = NULL;
+ scb->next = p->free_scb; /* preserve next pointer */
+ p->free_scb = scb; /* add at head of list */
+
+ restore_flags (flags);
+ cmd->result = (DID_RETRY_COMMAND << 16);
+ cmd->scsi_done(cmd);
+ }
+ break;
- /*
- * NB. channel selection (bit 3) is always zero.
- */
- scb->target_channel_lun = ((cmd->target << 4) & 0xf0) |
- (cmd->lun & 0x7);
+ case AWAITING_MSG:
+ scbptr = inb(SCBPTR(base));
+ scb = &(p->scb_array[scbptr]);
+ if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk("aic7xxx_isr: referenced scb not valid "
+ "during seqint 0x%x scb(%d) state(%x), cmd(%x)\n",
+ intstat, scbptr, scb->state, (unsigned int) scb->cmd);
+ }
+ else
+ {
+ /*
+ * 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)
+ {
+ outb(MSG_BUS_DEVICE_RESET, HA_MSG_START(base));
+ outb(1, HA_MSG_LEN(base));
+ }
+ else
+ {
+ panic ("aic7xxx_isr: AWAITING_SCB for an SCB that does "
+ "not have a waiting message");
+ }
+ }
+ break;
+
+ default: /* unknown */
+ debug("aic7xxx_isr: seqint, intstat = 0x%x, scsisigi = 0x%x\n",
+ intstat, inb(SCSISIGI(base)));
+ break;
+ }
+ outb(CLRSEQINT, CLRINT(base));
+ UNPAUSE_SEQUENCER(p);
+ }
+
+ if (intstat & SCSIINT)
+ {
+ int status = inb(SSTAT1(base));
+
+ scbptr = inb(SCBPTR(base));
+ scb = &p->scb_array[scbptr];
+ if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk("aic7xxx_isr: no command for scb (scsiint)\n");
+ /*
+ * Turn off the interrupt and set status
+ * to zero, so that it falls through the
+ * reset of the SCSIINT code.
+ */
+ outb(status, CLRSINT1(base));
+ UNPAUSE_SEQUENCER(p);
+ outb(CLRSCSIINT, CLRINT(base));
+ status = 0;
+ scb = NULL;
+ }
+ else
+ {
+ cmd = scb->cmd;
+
+ /*
+ * Only the SCSI Status 1 register has information
+ * about exceptional conditions that we'd have a
+ * SCSIINT about; anything in SSTAT0 will be handled
+ * by the sequencer. Note that there can be multiple
+ * bits set.
+ */
+ if (status & SELTO)
+ {
+ unsigned char target_mask = (1 << (cmd->target & 0x07));
+ unsigned char waiting;
/*
- * The interpretation of request_buffer and request_bufflen
- * changes depending on whether or not use_sg is zero; a
- * non-zero use_sg indicates the number of elements in the
- * scatter-gather array.
- *
- * The AIC-7770 can't support transfers of any sort larger
- * than 2^24 (three-byte count) without backflips. For what
- * the kernel is doing, this shouldn't occur. I hope.
+ * Hardware selection timer has expired. Turn
+ * off SCSI selection sequence.
*/
- length = aic7xxx_length(cmd, 0);
-
+ outb(ENRSELI, SCSISEQ(base));
+ cmd->result = (DID_TIME_OUT << 16);
/*
- * The sequencer code cannot yet handle scatter-gather segments
- * larger than 64k (two-byte length). The 1.1.x kernels, however,
- * have a four-byte length field in the struct scatterlist, so
- * make sure we don't exceed 64k on these kernels for now.
+ * Clear an pending messages for the timed out
+ * target and mark the target as free.
*/
- aic7xxx_sg_check(cmd);
+ ha_flags = inb(HA_FLAGS(base));
+ outb(ha_flags & ~ACTIVE_MSG, HA_FLAGS(base));
- if (length > 0xffffff) {
- panic("aic7xxx_buildscb: can't transfer > 2^24 - 1 bytes\n");
+ if (scb->target_channel_lun & 0x88)
+ {
+ active = inb(HA_ACTIVE1(base));
+ active = active & ~(target_mask);
+ outb(active, HA_ACTIVE1(base));
}
-
- /*
- * XXX - this relies on the host data being stored in a
- * little-endian format.
- */
- addr = cmd->cmnd;
- scb->SCSI_cmd_length = cmd->cmd_len;
- memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
-
- if (cmd->use_sg) {
-#if 0
- debug("aic7xxx_buildscb: SG used, %d segments, length %u\n",
- cmd->use_sg,
- length);
-#endif
- scb->SG_segment_count = cmd->use_sg;
- memcpy(scb->SG_list_pointer,
- &cmd->request_buffer,
- sizeof(scb->SG_list_pointer));
- } else {
- scb->SG_segment_count = 0;
- memcpy(scb->data_pointer,
- &cmd->request_buffer,
- sizeof(scb->data_pointer));
- memcpy(scb->data_count,
- &cmd->request_bufflen,
- sizeof(scb->data_count));
+ else
+ {
+ active = inb(HA_ACTIVE0(base));
+ active = active & ~(target_mask);
+ outb(active, HA_ACTIVE0(base));
}
-}
-static
-void aic7xxx_putscb(int base, struct aic7xxx_scb *scb)
-{
- /*
- * 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.
- */
- outb(0x80, O_SCBCNT(base)); /* SCBAUTO */
-
- asm volatile("cld\n\t"
- "rep\n\t"
- "outsb"
- : /* no output */
- :"S" (scb), "c" (sizeof(*scb)), "d" (O_SCBARRAY(base))
- :"si", "cx", "dx");
-
- outb(0, O_SCBCNT(base));
-}
-
-int aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
-{
- long flags;
- int empty, old_scbptr;
- struct aic7xxx_host *p;
- struct aic7xxx_scb scb;
-
-#if 0
- debug("aic7xxx_queue: cmd 0x%x (size %u), target %d, lun %d\n",
- cmd->cmnd[0],
- cmd->cmd_len,
- cmd->target,
- cmd->lun);
+#ifdef AIC7XXX_USE_DMA
+ outb(SCB_NEEDDMA, SCBARRAY(base));
#endif
- p = (struct aic7xxx_host *)cmd->host->hostdata;
-
/*
- * Construct the SCB beforehand, so the sequencer is
- * paused a minimal amount of time.
+ * Shut off the offending interrupt sources, reset
+ * the sequencer address to zero and unpause it,
+ * then call the high-level SCSI completion routine.
+ *
+ * WARNING! This is a magic sequence! After many
+ * hours of guesswork, turning off the SCSI interrupts
+ * in CLRSINT? does NOT clear the SCSIINT bit in
+ * INTSTAT. By writing to the (undocumented, unused
+ * according to the AIC-7770 manual) third bit of
+ * CLRINT, you can clear INTSTAT. But, if you do it
+ * while the sequencer is paused, you get a BRKADRINT
+ * with an Illegal Host Address status, so the
+ * sequencer has to be restarted first.
*/
- aic7xxx_buildscb(p, cmd, &scb);
+ outb(CLRSELTIMEO, CLRSINT1(base));
- /*
- * Clear the startup flag - we can now legitimately
- * expect interrupts.
- */
- p->startup = 0;
+ outb(CLRSCSIINT, CLRINT(base));
+ /* Shift the waiting for selection queue forward */
+ waiting = inb(WAITING_SCBH(base));
+ outb(waiting, SCBPTR(base));
+ waiting = inb(SCBARRAY(base) + 30);
+ outb(waiting, WAITING_SCBH(base));
+
+ RESTART_SEQUENCER(p);
/*
- * This is a critical section, since we don't want the
- * interrupt routine mucking with the host data or the
- * card. Since the kernel documentation is vague on
- * whether or not we are in a cli/sti pair already, save
- * the flags to be on the safe side.
+ * This is a critical section, since we don't want the
+ * queue routine mucking with the host data.
*/
save_flags(flags);
cli();
/*
- * Find a free slot in the SCB array to load this command
- * into. Since can_queue is set to the maximum number of
- * SCBs for the card, we should always find one.
- */
- for (empty = 0; empty < p->maxscb; empty++)
- if (!p->SCB_array[empty])
- break;
- if (empty == p->maxscb)
- panic("aic7xxx_queue: couldn't find a free scb\n");
-
- /*
- * 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);
-
- /*
- * 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.
+ * Process the command after marking the scb as free
+ * and adding it to the free list.
*/
- old_scbptr = inb(O_SCBPTR(p->base));
- outb(empty, O_SCBPTR(p->base));
-
- aic7xxx_putscb(p->base, &scb);
+ scb->state = SCB_FREE;
+ scb->cmd = NULL;
+ scb->next = p->free_scb; /* preserve next pointer */
+ p->free_scb = scb; /* add at head of list */
- outb(empty, O_QINFIFO(p->base));
- outb(old_scbptr, O_SCBPTR(p->base));
+ restore_flags(flags);
- /*
- * Make sure the Scsi_Cmnd pointer is saved, the struct it
- * points to is set up properly, and the parity error flag
- * is reset, then unpause the sequencer and watch the fun
- * begin.
- */
- cmd->scsi_done = fn;
- p->SCB_array[empty] = cmd;
- aic7xxx_parity(cmd) = DID_OK;
+ cmd->scsi_done(cmd);
+#if 0
+ printk("aic7xxx_isr: SELTO scb(%d) state(%x), cmd(%x)\n",
+ scb->position, scb->state, (unsigned int) scb->cmd);
+#endif
+ }
+ else
+ {
+ if (status & SCSIPERR)
+ {
+ /*
+ * A parity error has occurred during a data
+ * transfer phase. Flag it and continue.
+ */
+ printk("aic7xxx: parity error on target %d, "
+ "channel %d, lun %d\n",
+ cmd->target,
+ cmd->channel & 0x01,
+ cmd->lun & 0x07);
+ aic7xxx_error(cmd) = DID_PARITY;
+
+ /*
+ * Clear interrupt and resume as above.
+ */
+ outb(CLRSCSIPERR, CLRSINT1(base));
+ UNPAUSE_SEQUENCER(p);
+
+ outb(CLRSCSIINT, CLRINT(base));
+ scb = NULL;
+ }
+ else
+ {
+ if (! (status & BUSFREE))
+ {
+ /*
+ * We don't know what's going on. Turn off the
+ * interrupt source and try to continue.
+ */
+ printk("aic7xxx_isr: sstat1 = 0x%x\n", status);
+ outb(status, CLRSINT1(base));
+ UNPAUSE_SEQUENCER(p);
+ outb(CLRSCSIINT, CLRINT(base));
+ scb = NULL;
+ }
+ }
+ }
+ } /* else */
+ }
+
+ if (intstat & CMDCMPLT)
+ {
+ int complete;
+
+ /*
+ * 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));
+
+ scb = &(p->scb_array[complete]);
+ if ((scb->state != SCB_ACTIVE) || (scb->cmd == NULL))
+ {
+ printk("aic7xxx warning: "
+ "no command for scb %d (cmdcmplt)\n"
+ "QOUTCNT = %d, SCB state = 0x%x, CMD = 0x%x\n",
+ complete, inb(QOUTFIFO(base)),
+ scb->state, (unsigned int) scb->cmd);
+ outb(CLRCMDINT, CLRINT(base));
+ continue;
+ }
+ cmd = scb->cmd;
+
+ cmd->result = (aic7xxx_error(cmd) << 16) | aic7xxx_status(cmd);
+ if ((cmd->flags & WAS_SENSE) && !(cmd->flags & ASKED_FOR_SENSE))
+ { /* Got sense information. */
+ cmd->flags = cmd->flags & ASKED_FOR_SENSE;
+ }
+#if 0
+ printk("aic7xxx_intr: (complete) state = %d, cmd = 0x%x, free = 0x%x\n",
+ scb->state, (unsigned int) scb->cmd, (unsigned int) p->free_scb);
+#endif
+ /*
+ * This is a critical section, since we don't want the
+ * queue routine mucking with the host data.
+ */
+ save_flags(flags);
+ cli();
+
+ scb->state = SCB_FREE;
+ scb->next = p->free_scb;
+ scb->cmd = NULL;
+ p->free_scb = &(p->scb_array[scb->position]);
+
+ restore_flags(flags);
+#if 0
+ if (scb != &p->scb_array[scb->position])
+ {
+ printk("aic7xxx_isr: (complete) address mismatch, pos %d\n", scb->position);
+ }
+ printk("aic7xxx_isr: (complete) state = %d, cmd = 0x%x, free = 0x%x\n",
+ scb->state, (unsigned int) scb->cmd, (unsigned int) p->free_scb);
+#endif
- UNPAUSE_SEQUENCER(p);
+ cmd->scsi_done(cmd);
+
+ /*
+ * Clear interrupt status before checking
+ * the output queue again. This eliminates
+ * a race condition whereby a command could
+ * complete between the queue poll and the
+ * interrupt clearing, so notification of the
+ * command being complete never made it back
+ * up to the kernel.
+ */
+ outb(CLRCMDINT, CLRINT(base));
+ } while (inb(QOUTCNT(base)));
+ }
+}
- restore_flags(flags);
- return(0);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_probe
+ *
+ * Description:
+ * Probing for EISA boards: it looks like the first two bytes
+ * are a manufacturer code - three characters, five bits each:
+ *
+ * BYTE 0 BYTE 1 BYTE 2 BYTE 3
+ * ?1111122 22233333 PPPPPPPP RRRRRRRR
+ *
+ * The characters are baselined off ASCII '@', so add that value
+ * to each to get the real ASCII code for it. The next two bytes
+ * appear to be a product and revision number, probably vendor-
+ * specific. This is what is being searched for at each port,
+ * and what should probably correspond to the ID= field in the
+ * ECU's .cfg file for the card - if your card is not detected,
+ * make sure your signature is listed in the array.
+ *
+ * The fourth byte's lowest bit seems to be an enabled/disabled
+ * flag (rest of the bits are reserved?).
+ *-F*************************************************************************/
+static aha_type
+aic7xxx_probe(int slot, int base)
+{
+ int i;
+ unsigned char buf[4];
+
+ static struct {
+ int n;
+ unsigned char signature[sizeof(buf)];
+ aha_type type;
+ } AIC7xxx[] = {
+ { 4, { 0x04, 0x90, 0x77, 0x71 }, AIC_274x }, /* host adapter 274x */
+ { 4, { 0x04, 0x90, 0x77, 0x70 }, AIC_274x }, /* motherboard 274x */
+ { 4, { 0x04, 0x90, 0x77, 0x56 }, AIC_284x }, /* 284x, BIOS enabled */
+ { 4, { 0x04, 0x90, 0x77, 0x57 }, AIC_284x } /* 284x, BIOS disabled */
+ };
+
+ /*
+ * The VL-bus cards need to be primed by
+ * writing before a signature check.
+ */
+ for (i = 0; i < sizeof(buf); i++)
+ {
+ outb(0x80 + i, base);
+ buf[i] = inb(base + i);
+ }
+
+ for (i = 0; i < NUMBER(AIC7xxx); i++)
+ {
+ /*
+ * Signature match on enabled card?
+ */
+ if (!memcmp(buf, AIC7xxx[i].signature, AIC7xxx[i].n))
+ {
+ if (inb(base + 4) & 1)
+ {
+ return(AIC7xxx[i].type);
+ }
+
+ printk("aic7xxx disabled at slot %d, ignored\n", slot);
+ }
+ }
+
+ return(AIC_NONE);
}
-/* return values from aic7xxx_kill */
+/*+F*************************************************************************
+ * Function:
+ * read_seeprom
+ *
+ * Description:
+ * Reads the serial EEPROM and returns 1 if successful and 0 if
+ * not successful.
+ *
+ * The instruction set of the 93C46 chip is as follows:
+ *
+ * Start OP
+ * Function Bit Code Address Data Description
+ * -------------------------------------------------------------------
+ * READ 1 10 A5 - A0 Reads data stored in memory,
+ * starting at specified address
+ * EWEN 1 00 11XXXX Write enable must preceed
+ * all programming modes
+ * ERASE 1 11 A5 - A0 Erase register A5A4A3A2A1A0
+ * WRITE 1 01 A5 - A0 D15 - D0 Writes register
+ * ERAL 1 00 10XXXX Erase all registers
+ * WRAL 1 00 01XXXX D15 - D0 Writes to all registers
+ * EWDS 1 00 00XXXX Disables all programming
+ * instructions
+ * *Note: A value of X for address is a don't care condition.
+ *
+ * The 93C46 has a four wire interface: clock, chip select, data in, and
+ * data out. In order to perform one of the above functions, you need
+ * to enable the chip select for a clock period (typically a minimum of
+ * 1 usec, with the clock high and low a minimum of 750 and 250 nsec
+ * respectively. While the chip select remains high, you can clock in
+ * the instructions (above) starting with the start bit, followed by the
+ * OP code, Address, and Data (if needed). For the READ instruction, the
+ * requested 16-bit register contents is read from the data out line but
+ * is preceded by an initial zero (leading 0, followed by 16-bits, MSB
+ * 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
+ * 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,
+ * 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.
+ *
+ *-F*************************************************************************/
+static int
+read_seeprom(int base, struct seeprom_config *sc)
+{
+ int i = 0, k = 0;
+ 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];
+ };
+ struct seeprom_cmd seeprom_read = {3, {1, 1, 0}};
+
+#define CLOCK_PULSE(p) \
+ while ((inb(SEECTL(base)) & 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.
+ */
+ 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)
+ {
+ 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.
+ */
+ for (k = 0; k < (sizeof(*sc) / 2); k = k + 1)
+ {
+ /* Send chip select for one clock cycle. */
+ outb(SEEMS | SEECK | SEECS, SEECTL(base));
+ CLOCK_PULSE(base);
+
+ /*
+ * Now we're ready to send the read command followed by the
+ * address of the 16-bit register we want to read.
+ */
+ for (i = 0; i < seeprom_read.len; i = i + 1)
+ {
+ temp = SEEMS | SEECS | (seeprom_read.bits[i] << 1);
+ outb(temp, SEECTL(base));
+ CLOCK_PULSE(base);
+ temp = temp ^ SEECK;
+ outb(temp, SEECTL(base));
+ CLOCK_PULSE(base);
+ }
+ /* Send the 6 bit address (MSB first, LSB last). */
+ for (i = 5; i >= 0; i = i - 1)
+ {
+ temp = k;
+ temp = (temp >> i) & 1; /* Mask out all but lower bit. */
+ temp = SEEMS | SEECS | (temp << 1);
+ outb(temp, SEECTL(base));
+ CLOCK_PULSE(base);
+ temp = temp ^ SEECK;
+ outb(temp, SEECTL(base));
+ CLOCK_PULSE(base);
+ }
+
+ /*
+ * Now read the 16 bit register. An initial 0 precedes the
+ * register contents which begins with bit 15 (MSB) and ends
+ * with bit 0 (LSB). The initial 0 will be shifted off the
+ * top of our word as we let the loop run from 0 to 16.
+ */
+ for (i = 0; i <= 16; i = i + 1)
+ {
+ temp = SEEMS | SEECS;
+ outb(temp, SEECTL(base));
+ CLOCK_PULSE(base);
+ temp = temp ^ SEECK;
+ seeprom[k] = (seeprom[k] << 1) | (inb(SEECTL(base)) & SEEDI);
+ outb(temp, SEECTL(base));
+ CLOCK_PULSE(base);
+ }
+
+ /*
+ * 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.
+ */
+ if (k < (sizeof(*sc) / 2) - 1)
+ {
+ checksum = checksum + seeprom[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);
+ }
+
+ if (checksum != sc->checksum)
+ {
+ printk ("aic7xxx : SEEPROM checksum error, ignoring SEEPROM settings.\n");
+ return (0);
+ }
-enum k_state {
- k_ok, /* scb found and message sent */
- k_busy, /* message already present */
- k_absent, /* couldn't locate scb */
- k_disconnect, /* scb found, but disconnected */
-};
+#if 0
+ printk ("Computed checksum 0x%x, checksum read 0x%x\n", checksum, sc->checksum);
+ printk ("Serial EEPROM:");
+ for (k = 0; k < (sizeof(*sc) / 2); k = k + 1)
+ {
+ if (((k % 8) == 0) && (k != 0))
+ {
+ printk ("\n ");
+ }
+ printk (" 0x%x", seeprom[k]);
+ }
+ printk ("\n");
+#endif
-/*
- * This must be called with interrupts disabled - it's going to
- * be messing around with the host data, and an interrupt being
- * fielded in the middle could get ugly.
- *
- * Since so much of the abort and reset code is shared, this
- * function performs more magic than it really should. If the
- * command completes ok, then it will call scsi_done with the
- * result code passed in. The unpause parameter controls whether
- * or not the sequencer gets unpaused - the reset function, for
- * instance, may want to do something more aggressive.
+ /* Release access to the memory port and the serial EEPROM. */
+ outb(0, SEECTL(base));
+ return (1);
+}
+
+/*+F*************************************************************************
+ * Function:
+ * detect_maxscb
*
- * Note that the command is checked for in our SCB_array first
- * before the sequencer is paused, so if k_absent is returned,
- * then the sequencer is NOT paused.
- */
+ * Description:
+ * Return the maximum number of SCB's allowed for a given controller.
+ *-F*************************************************************************/
+static int
+detect_maxscb(aha_type type, int base)
+{
+ unsigned char sblkctl_reg;
+ int maxscb = 0;
+
+ switch (type)
+ {
+ case AIC_274x:
+ 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.
+ * Until we know how to access more than 4 SCBs for the Rev E chips,
+ * we limit them, along with the Rev C chips, to 4 SCBs.
+ *
+ * The Rev E boards have a read/write autoflush bit in the
+ * SBLKCTL registor, 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. */
+ printk("aic7770: Rev E and subsequent; using 4 SCB's\n");
+ outb(sblkctl_reg ^ AUTOFLUSHDIS, SBLKCTL(base));
+ maxscb = 4;
+ }
+ else
+ {
+ printk("aic7770: Rev C and previous; using 4 SCB's\n");
+ maxscb = 4;
+ }
+ break;
+
+ case AIC_7850:
+ maxscb = 3;
+ break;
+
+ case AIC_7870:
+ maxscb = 16;
+ break;
+
+ case AIC_7872:
+ /*
+ * Really has 255, but we'll wait to verify that we access
+ * them the same way and do not have to set the card to
+ * use the memory port to access external SCB RAM.
+ */
+ maxscb = 16;
+ break;
+
+ case AIC_NONE:
+ /*
+ * This should never happen... But just in case.
+ */
+ break;
+ }
+
+ return(maxscb);
+}
-static
-enum k_state aic7xxx_kill(Scsi_Cmnd *cmd, unsigned char message,
- unsigned int result, int unpause)
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_register
+ *
+ * Description:
+ * Register a Adaptec aic7xxx chip SCSI controller with the kernel.
+ *-F*************************************************************************/
+static int
+aic7xxx_register(Scsi_Host_Template *template, aha_type type,
+ int base, unsigned char irq)
{
- struct aic7xxx_host *p;
- int i, scb, found, queued;
- unsigned char scbsave[AIC7XXX_MAXSCB];
+ static char * board_name[] = {"", "274x", "284x", "7870", "7850", "7872"};
+ int i;
+ unsigned char sblkctl;
+ int max_targets;
+ int found = 1;
+ unsigned char target_settings;
+ unsigned char scsi_conf;
+ int have_seeprom = 0;
+ struct Scsi_Host *host;
+ struct aic7xxx_host *p;
+ struct aic7xxx_host_config config;
+ struct seeprom_config sc;
+
+ config.type = type;
+ config.base = base;
+ config.irq = irq;
+ config.parity = AIC_UNKNOWN;
+ config.low_term = AIC_UNKNOWN;
+ config.high_term = AIC_UNKNOWN;
+ config.busrtime = 0;
+
+ /*
+ * Lock out other contenders for our i/o space.
+ */
+ request_region(MINREG(base), MAXREG(base) - MINREG(base), "aic7xxx");
+
+ switch (type)
+ {
+ case AIC_274x:
+#if 1
+ printk("aha274x: aic7770 hcntrl=0x%x\n", inb(HCNTRL(config.base)));
+#endif
+ /*
+ * 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.
+ *
+ * Use the BIOS settings to determine the interrupt
+ * trigger type (level or edge) and use this value
+ * for pausing and unpausing the sequencer.
+ */
+ config.unpause = (inb(HCNTRL(config.base)) & IRQMS) | INTEN;
+ config.pause = config.unpause | PAUSE;
+ config.extended = aic7xxx_extended;
+
+ /*
+ * I don't think we need to kick the reset again, the initial probe
+ * does a reset, it seems that this is kicking a dead horse here.
+ * So... I will try to just verify that the chip has come out of the
+ * reset state and continue the same as the 284x.
+ * In the Calgary version of the driver:
+ * 1) Chip Reset
+ * 2) Set unpause to IRQMS | INTEN
+ * 3) If an interrupt occured without any commands queued, the
+ * unpause was set to just INTEN
+ * I changed the initial reset code to just mask in the CHIPRST bit
+ * and try to leave the other settings alone.
+ *
+ * I don't think we need the warning about chip reset not being clear.
+ * On both my test machines (2842 & 2940), they work just fine with a
+ * HCNTRL() of 0x5 (PAUSE | CHIPRST). Notice though, the 274x also
+ * adds the INTEN flag, where neither the 284x or 294x do.
+ */
+ outb(config.pause | CHIPRST, HCNTRL(config.base));
+ aic7xxx_delay(1);
+ if (inb(HCNTRL(config.base)) & CHIPRST)
+ {
+ printk("aic7xxx_register: Chip reset not cleared; clearing manually.\n");
+ }
+ outb(config.pause, HCNTRL(config.base));
+
+ /*
+ * Just to be on the safe side with the 274x, we will re-read the irq
+ * since there was some issue about reseting the board.
+ */
+ config.irq = inb(HA_INTDEF(config.base)) & 0x0F;
+ config.busrtime = inb(HA_SCSICONF(config.base)) & 0x3C;
+
+ /*
+ * A reminder until this can be detected automatically.
+ */
+ printk("aha274x: extended translation %sabled\n",
+ config.extended ? "en" : "dis");
+ break;
+
+ case AIC_284x:
+#if 1
+ printk("aha284x: aic7770 hcntrl=0x%x\n", inb(HCNTRL(config.base)));
+#endif
+ outb(CHIPRST, HCNTRL(config.base));
+ config.unpause = UNPAUSE_284X;
+ config.pause = REQ_PAUSE; /* DWG would like to be like the rest */
+ config.extended = aic7xxx_extended;
+ config.irq = inb(HA_INTDEF(config.base)) & 0x0F;
+
+ /*
+ * A reminder until this can be detected automatically.
+ */
+ printk("aha284x: extended translation %sabled\n",
+ config.extended ? "en" : "dis");
+ break;
+
+ case AIC_7850:
+ case AIC_7870:
+ case AIC_7872:
+#if 1
+ printk("aic%s hcntrl=0x%x\n", board_name[type], inb(HCNTRL(config.base)));
+#endif
- p = (struct aic7xxx_host *)cmd->host->hostdata;
+ outb(CHIPRST, HCNTRL(config.base));
+ config.unpause = UNPAUSE_294X;
+ config.pause = config.unpause | PAUSE;
+ config.extended = aic7xxx_extended;
+ config.scsi_id = 7;
+
+ printk ("aic78xx: Reading SEEPROM... ");
+ have_seeprom = read_seeprom(base, &sc);
+ if (! have_seeprom)
+ {
+ printk ("Unable to read SEEPROM\n");
+ }
+ else
+ {
+ printk ("done\n");
+ config.extended = (sc.bios_control & CFEXTEND) >> 7;
+ 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;
+ }
+
+ /*
+ * XXX - force data fifo threshold to 100%. Why does this
+ * need to be done?
+ */
+ outb(inb(DSPCISTATUS(config.base)) | DFTHRESH, DSPCISTATUS(config.base));
+ outb(config.scsi_id | DFTHRESH, HA_SCSICONF(config.base));
+
+ /*
+ * In case we are a wide card, place scsi ID in second conf byte.
+ */
+ outb(config.scsi_id, (HA_SCSICONF(config.base) + 1));
+
+ /*
+ * A reminder until this can be detected automatically.
+ */
+ printk("aic%s: extended translation %sabled\n", board_name[type],
+ config.extended ? "en" : "dis");
+ break;
+
+ default:
+ panic("aic7xxx_register: internal error\n");
+ }
+
+ config.maxscb = detect_maxscb(type, base);
+
+ if ((config.type == AIC_274x) || (config.type == AIC_284x))
+ {
+ if (config.pause & IRQMS)
+ {
+ printk("aic7xxx: Using Level Sensitive Interrupts\n");
+ }
+ else
+ {
+ printk("aic7xxx: Using Edge Triggered Interrupts\n");
+ }
+ }
+
+ /*
+ * 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)) & 0x0F; /* mask out upper two bits */
+ switch (sblkctl)
+ {
+ case 0: /* narrow/normal bus */
+ config.scsi_id = inb(HA_SCSICONF(base)) & 0x07;
+ config.bus_type = AIC_SINGLE;
+ outb(0, HA_FLAGS(base));
+ break;
+
+ case 2: /* Wide bus */
+ config.scsi_id = inb(HA_SCSICONF(base) + 1) & 0x0F;
+ config.bus_type = AIC_WIDE;
+ printk("aic7xxx : Enabling wide channel of %s-Wide\n",
+ board_name[config.type]);
+ outb(WIDE_BUS, HA_FLAGS(base));
+ break;
+
+ case 8: /* Twin bus */
+ config.scsi_id = inb(HA_SCSICONF(base)) & 0x07;
+#ifdef AIC7XXX_TWIN_SUPPORT
+ config.scsi_id_b = inb(HA_SCSICONF(base) + 1) & 0x07;
+ config.bus_type = AIC_TWIN;
+ printk("aic7xxx : Enabled channel B of %s-Twin\n",
+ board_name[config.type]);
+ outb(TWIN_BUS, HA_FLAGS(base));
+#else
+ config.bus_type = AIC_SINGLE;
+ printk("aic7xxx : Channel B of %s-Twin will be ignored\n",
+ board_name[config.type]);
+ outb(0, HA_FLAGS(base));
+#endif
+ break;
+
+ default:
+ printk("aic7xxx is an unsupported type 0x%x, please "
+ "mail deang@ims.com\n", inb(SBLKCTL(base)));
+ outb(0, HA_FLAGS(base));
+ return(0);
+ }
+
+ /*
+ * Clear the upper two bits. For the 294x cards, clearing the
+ * upper two bits, will take the card out of diagnostic mode
+ * and make the host adatper LED follow bus activity (will not
+ * always be on).
+ */
+ outb(sblkctl, SBLKCTL(base));
+
+ /*
+ * 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 294x cards (PCI) get their interrupt from PCI BIOS.
+ */
+ if (((config.type == AIC_274x) || (config.type == AIC_284x))
+ && (config.irq < 9 || config.irq > 15))
+ {
+ printk("aic7xxx uses unsupported IRQ level, ignoring\n");
+ return(0);
+ }
+
+ /*
+ * Check the IRQ to see if it is shared by another aic7xxx
+ * controller. If it is and sharing of IRQs is not defined,
+ * then return 0 hosts found. If sharing of IRQs is allowed
+ * or the IRQ is not shared by another host adapter, then
+ * proceed.
+ */
+#ifndef AIC7XXX_SHARE_IRQS
+ if (aic7xxx_boards[config.irq] != NULL)
+ {
+ printk("aic7xxx_register: Sharing of IRQs is not configured.\n");
+ return(0);
+ }
+#endif
+ /*
+ * 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);
+
+ /*
+ * Before registry, make sure that the offsets of the
+ * struct scatterlist are what the sequencer will expect,
+ * otherwise disable scatter-gather altogether until someone
+ * can fix it. This is important since the sequencer will
+ * DMA elements of the SG array in while executing commands.
+ */
+ if (template->sg_tablesize != SG_NONE)
+ {
+ struct scatterlist sg;
+
+ if (SG_STRUCT_CHECK(sg))
+ {
+ printk("aic7xxx warning: kernel scatter-gather "
+ "structures changed, disabling it\n");
+ template->sg_tablesize = SG_NONE;
+ }
+ }
+
+ /*
+ * 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.maxscb;
+#ifdef AIC7XXX_TAGGED_QUEUEING
+ host->cmd_per_lun = 2;
+#else
+ host->cmd_per_lun = 1;
+#endif
+ host->this_id = config.scsi_id;
+ host->irq = config.irq;
+ if (config.bus_type == AIC_WIDE)
+ {
+ host->max_id = 16;
+ }
+ if (config.bus_type == AIC_TWIN)
+ {
+ host->max_channel = 1;
+ }
+
+ p = (struct aic7xxx_host *) host->hostdata;
+
+ /* Initialize the scb array by setting the state to free. */
+ for (i = 0; i < AIC7XXX_MAXSCB; i = i + 1)
+ {
+ p->scb_array[i].state = SCB_FREE;
+ p->scb_array[i].next = NULL;
+ p->scb_array[i].cmd = NULL;
+ }
+
+ p->isr_count = 0;
+ p->a_scanned = 0;
+ p->b_scanned = 0;
+ p->base = config.base;
+ p->maxscb = config.maxscb;
+ p->numscb = 0;
+ p->extended = config.extended;
+ p->type = config.type;
+ p->bus_type = config.bus_type;
+ p->have_seeprom = have_seeprom;
+ p->seeprom = sc;
+ p->free_scb = NULL;
+ p->next = NULL;
+
+ p->unpause = config.unpause;
+ p->pause = config.pause;
+
+ if (aic7xxx_boards[config.irq] == NULL)
+ {
+ /*
+ * Register IRQ with the kernel.
+ */
+ if (request_irq(config.irq, aic7xxx_isr, SA_INTERRUPT, "aic7xxx"))
+ {
+ printk("aic7xxx couldn't register irq %d, ignoring\n", config.irq);
+ return(0);
+ }
+ aic7xxx_boards[config.irq] = host;
+ }
+ else
+ {
+ /*
+ * We have found a host adapter sharing an IRQ of a previously
+ * 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("aic7xxx: Downloading sequencer code..");
+ aic7xxx_loadseq(base);
+
+ /* Set Fast Mode and Enable the board */
+ outb(FASTMODE, SEQCTL(base));
+
+ if ((p->type == AIC_274x || p->type == AIC_284x))
+ {
+ outb(ENABLE, BCTL(base));
+ }
+
+ printk("done.\n");
+
+ /*
+ * Set the SCSI Id, SXFRCTL1, and SIMODE1, for both channels
+ */
+ if (p->bus_type == AIC_TWIN)
+ {
+ /*
+ * The device is gated to channel B after a chip reset,
+ * so set those values first.
+ */
+ outb(config.scsi_id_b, SCSIID(base));
+ scsi_conf = inb(HA_SCSICONF(base) + 1) & (ENSPCHK | STIMESEL);
+ scsi_conf = scsi_conf | ENSTIMER | ACTNEGEN | STPWEN;
+ outb(scsi_conf, SXFRCTL1(base));
+ outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
+ /* Select Channel A */
+ outb(0, SBLKCTL(base));
+ }
+ outb(config.scsi_id, SCSIID(base));
+ scsi_conf = inb(HA_SCSICONF(base)) & (ENSPCHK | STIMESEL);
+ outb(scsi_conf | ENSTIMER | ACTNEGEN | STPWEN, SXFRCTL1(base));
+ outb(ENSELTIMO | ENSCSIPERR, SIMODE1(base));
+
+ /* Look at the information that board initialization or the board
+ * BIOS has left us. In the lower four bits of each target's
+ * scratch space any value other than 0 indicates that we should
+ * initiate synchronous transfers. If it's zero, the user or the
+ * BIOS has decided to disable synchronous negotiation to that
+ * target so we don't activate the needsdtr flag.
+ */
+ p->needsdtr_copy = 0;
+ p->sdtr_pending = 0;
+ p->needwdtr_copy = 0;
+ p->wdtr_pending = 0;
+ if (p->bus_type == AIC_SINGLE)
+ {
+ max_targets = 8;
+ }
+ else
+ {
+ max_targets = 16;
+ }
+
+ for (i = 0; i < max_targets; i = i + 1)
+ {
+ if (have_seeprom)
+ {
+ target_settings = (sc.device_flags[i] & CFXFER) << 4;
+ if (sc.device_flags[i] & CFSYNCH)
+ {
+ p->needsdtr_copy = p->needsdtr_copy | (0x01 << i);
+ }
+ if ((sc.device_flags[i] & CFWIDEB) && (p->bus_type == AIC_WIDE))
+ {
+ p->needwdtr_copy = p->needwdtr_copy | (0x01 << i);
+ }
+ }
+ else
+ {
+ target_settings = inb(HA_TARG_SCRATCH(base) + i);
+ if (target_settings & 0x0F)
+ {
+ p->needsdtr_copy = p->needsdtr_copy | (0x01 << i);
/*
- * If we can't find the command, assume it just completed
- * and shrug it away.
+ * Default to asynchronous transfers (0 offset)
*/
- for (scb = 0; scb < p->maxscb; scb++)
- if (p->SCB_array[scb] == cmd)
- break;
+ target_settings = target_settings & 0xF0;
+ }
+ /*
+ * If we are not wide, forget WDTR. This makes the driver
+ * work on some cards that don't leave these fields cleared
+ * when BIOS is not installed.
+ */
+ if ((target_settings & 0x80) && (p->bus_type == AIC_WIDE))
+ {
+ p->needwdtr_copy = p->needwdtr_copy | (0x01 << i);
+ target_settings = target_settings & 0x7F;
+ }
+ }
+ outb(target_settings, (HA_TARG_SCRATCH(base) + i));
+ }
+
+ p->needsdtr = p->needsdtr_copy;
+ p->needwdtr = p->needwdtr_copy;
+ printk("NeedSdtr = 0x%x, 0x%x\n", p->needsdtr_copy, p->needsdtr);
+ printk("NeedWdtr = 0x%x, 0x%x\n", p->needwdtr_copy, p->needwdtr);
+
+ /*
+ * Clear the control byte for every SCB so that the sequencer
+ * doesn't get confused and think that one of them is valid
+ */
+ for (i = 0; i < config.maxscb; i = i + 1)
+ {
+ outb(i, SCBPTR(base));
+ outb(0, SCBARRAY(base));
+ }
+
+ /*
+ * For reconnecting targets, the sequencer code needs to
+ * know how many SCBs it has to search through.
+ */
+ outb(config.maxscb, HA_SCBCOUNT(base));
+
+ /*
+ * Clear the active flags - no targets are busy.
+ */
+ outb(0, HA_ACTIVE0(base));
+ outb(0, HA_ACTIVE1(base));
+
+ /* We don't have any waiting selections */
+ outb (SCB_LIST_NULL, WAITING_SCBH(base));
+ outb (SCB_LIST_NULL, WAITING_SCBT(base));
+
+ /*
+ * 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.
+ */
+
+ if (!aic7xxx_no_reset)
+ {
+ printk("Resetting the SCSI bus...\n");
+ outb(SCSIRSTO, SCSISEQ(base));
+ udelay(1000);
+ outb(0, SCSISEQ(base));
+ aic7xxx_delay(AIC7XXX_RESET_DELAY);
+ }
+
+ /*
+ * 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);
+}
- if (scb == p->maxscb)
- return(k_absent);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_detect
+ *
+ * Description:
+ * Try to detect and register an Adaptec 7770 or 7870 SCSI controller.
+ *-F*************************************************************************/
+int
+aic7xxx_detect(Scsi_Host_Template *template)
+{
+ aha_type type = AIC_NONE;
+ int found = 0, slot, base;
+ unsigned char irq = 0;
+ int i;
+
+ /*
+ * Since we may allow sharing of IRQs, it is imperative
+ * that we "null-out" the aic7xxx_boards array. It is
+ * not guaranteed to be initialized to 0 (NULL). We use
+ * a NULL entry to indicate that no prior hosts have
+ * been found/registered for that IRQ.
+ */
+ for (i = 0; i <= MAXIRQ; i++)
+ {
+ aic7xxx_boards[i] = NULL;
+ }
+
+ /*
+ * EISA/VL-bus card signature probe.
+ */
+ for (slot = MINSLOT; slot <= MAXSLOT; slot++)
+ {
+ base = SLOTBASE(slot);
+
+ if (check_region(MINREG(base), MAXREG(base) - MINREG(base)))
+ {
+ /*
+ * Some other driver has staked a
+ * claim to this i/o region already.
+ */
+ continue;
+ }
+
+ type = aic7xxx_probe(slot, HID0(base));
+ if (type != AIC_NONE)
+ {
+ printk("aic7xxx: hcntrl=0x%x\n", inb(HCNTRL(base)));
+#if 0
+ outb(inb(HCNTRL(base)) | CHIPRST, HCNTRL(base));
+ irq = inb(HA_INTDEF(base)) & 0x0F;
+#endif
- PAUSE_SEQUENCER(p);
+ /*
+ * 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.
+ */
+ found += aic7xxx_register(template, type, base, irq);
+ }
+ }
+
+#ifdef CONFIG_PCI
+
+#define DEVREVID 0x08
+#define DEVCONFIG 0x40
+#define DEVSTATUS 0x41
+#define RAMPSM 0x02
+
+/* This should be defined in pci.h */
+#define PCI_DEVICE_ID_ADAPTEC_7850 0x5078
+#define PCI_DEVICE_ID_ADAPTEC_7872 0x7278
+
+ /*
+ * PCI-bus probe.
+ */
+ if (pcibios_present())
+ {
+ int error;
+ int done = 0;
+ unsigned int io_port;
+ unsigned short index = 0;
+ unsigned char pci_bus, pci_device_fn;
+ unsigned char devrevid, devconfig, devstatus;
+ char rev_id[] = {'B', 'C', 'D'};
+
+ while (!done)
+ {
+ if ((!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+ PCI_DEVICE_ID_ADAPTEC_294x,
+ index, &pci_bus, &pci_device_fn)) ||
+ (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+ PCI_DEVICE_ID_ADAPTEC_2940,
+ index, &pci_bus, &pci_device_fn)))
+ {
+ type = AIC_7870;
+ }
+ else
+ {
+ if (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+ PCI_DEVICE_ID_ADAPTEC_7850,
+ index, &pci_bus, &pci_device_fn))
+ {
+ type = AIC_7850;
+ }
+ else
+ {
+ if (!pcibios_find_device(PCI_VENDOR_ID_ADAPTEC,
+ PCI_DEVICE_ID_ADAPTEC_7872,
+ index, &pci_bus, &pci_device_fn))
+ {
+ type = AIC_7872;
+ }
+ else
+ {
+ type = AIC_NONE;
+ done = 1;
+ }
+ }
+ }
+ if (!done)
+ {
/*
- * This is the best case, really. Check to see if the
- * command is still in the sequencer's input queue. If
- * so, simply remove it. Reload the queue afterward.
+ * Read esundry information from PCI BIOS.
*/
- queued = inb(O_QINCNT(p->base));
-
- for (i = found = 0; i < queued; i++) {
- scbsave[i] = inb(O_QINFIFO(p->base));
-
- if (scbsave[i] == scb) {
- found = 1;
- i -= 1;
- }
- }
+ error = pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, &io_port);
- queued -= found;
- for (i = 0; i < queued; i++)
- outb(scbsave[i], O_QINFIFO(p->base));
-
- if (found)
- goto complete;
+ if (error)
+ {
+ panic("aic7xxx_detect: error 0x%x reading i/o port.\n", error);
+ }
- /*
- * Check the current SCB bank. If it's not the one belonging
- * to the command we want to kill, assume that the command
- * is disconnected. It's rather a pain to force a reconnect
- * and send a message to the target, so we abdicate responsibility
- * in this case.
- */
- if (inb(O_SCBPTR(p->base)) != scb) {
- if (unpause)
- UNPAUSE_SEQUENCER(p);
- return(k_disconnect);
+ error = pcibios_read_config_byte(pci_bus, pci_device_fn,
+ PCI_INTERRUPT_LINE, &irq);
+ if (error)
+ {
+ panic("aic7xxx_detect: error %d reading irq.\n", error);
}
/*
- * Presumably at this point our target command is active. Check
- * to see if there's a message already in effect. If not, place
- * our message in and assert ATN so the target goes into MESSAGE
- * OUT phase.
+ * Make the base I/O register look like EISA and VL-bus.
*/
- if (inb(HA_MSG_FLAGS(p->base)) & 0x80) {
- if (unpause)
- UNPAUSE_SEQUENCER(p);
- return(k_busy);
- }
+ base = io_port - 0xC01;
- outb(0x80, HA_MSG_FLAGS(p->base)); /* active message */
- outb(1, HA_MSG_LEN(p->base)); /* length = 1 */
- outb(message, HA_MSG_START(p->base)); /* message body */
+ printk("aic7xxx: hcntrl=0x%x\n", inb(HCNTRL(base)));
+ outb(inb(HCNTRL(base)) | CHIPRST, HCNTRL(base));
- /*
- * Assert ATN. Use the value of SCSISIGO saved by the
- * sequencer code so we don't alter its contents radically
- * in the middle of something critical.
- */
- outb(inb(HA_SIGSTATE(p->base)) | 0x10, O_SCSISIGO(p->base));
+ error = pcibios_read_config_byte(pci_bus, pci_device_fn,
+ DEVREVID, &devrevid);
+ if (devrevid < 3)
+ {
+ printk ("aic7xxx_detect: AIC-7870 Rev %c\n", rev_id[devrevid]);
+ }
+ error = pcibios_read_config_byte(pci_bus, pci_device_fn,
+ DEVCONFIG, &devconfig);
+ error = pcibios_read_config_byte(pci_bus, pci_device_fn,
+ DEVSTATUS, &devstatus);
+ printk ("aic7xxx_detect: devconfig 0x%x, devstatus 0x%x\n",
+ devconfig, devstatus);
+ if (devstatus & RAMPSM)
+ {
+ printk ("aic7xxx_detect: detected external SCB RAM, "
+ "mail deang@ims.com for test patch");
+ }
- /*
- * The command has been killed. Do the bookkeeping, unpause
- * the sequencer, and notify the higher-level SCSI code.
- */
-complete:
- p->SCB_array[scb] = NULL;
- if (unpause)
- UNPAUSE_SEQUENCER(p);
+ found += aic7xxx_register(template, type, base, irq);
+ index += 1;
+ }
+ }
+ }
+#endif CONFIG_PCI
- cmd->result = result << 16;
- cmd->scsi_done(cmd);
- return(k_ok);
+ template->name = (char *) aic7xxx_info(NULL);
+ return(found);
}
-int aic7xxx_abort(Scsi_Cmnd *cmd)
-{
- int rv;
- long flags;
-
- save_flags(flags);
- cli();
- switch (aic7xxx_kill(cmd, ABORT, DID_ABORT, !0)) {
- case k_ok: rv = SCSI_ABORT_SUCCESS; break;
- case k_busy: rv = SCSI_ABORT_BUSY; break;
- case k_absent: rv = SCSI_ABORT_NOT_RUNNING; break;
- case k_disconnect: rv = SCSI_ABORT_SNOOZE; break;
- default:
- panic("aic7xxx_do_abort: internal error\n");
- }
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_buildscb
+ *
+ * Description:
+ * Build a SCB.
+ *-F*************************************************************************/
+static void
+aic7xxx_buildscb(struct aic7xxx_host *p,
+ Scsi_Cmnd *cmd,
+ struct aic7xxx_scb *scb)
+{
+ void *addr;
+ unsigned length;
+ unsigned short mask;
+
+ /*
+ * Setup the control byte if we need negotiation and have not
+ * already requested it.
+ */
+#ifdef AIC7XXX_TAGGED_QUEUEING
+ if (cmd->device->tagged_supported)
+ {
+ if (cmd->device->tagged_queue == 0)
+ {
+ printk ("aic7xxx_buildscb: Enabling tagged queuing for target %d, "
+ "channel %d\n", cmd->target, cmd->channel);
+ cmd->device->tagged_queue = 1;
+ cmd->device->current_tag = 1; /* enable tagging */
+ }
+ cmd->tag = cmd->device->current_tag;
+ cmd->device->current_tag = cmd->device->current_tag + 1;
+ scb->control = scb->control | SCB_TE;
+ }
+#endif
+ mask = (0x01 << cmd->target);
+ if ((p->needwdtr & mask) && !(p->wdtr_pending & mask))
+ {
+ p->wdtr_pending = p->wdtr_pending | mask;
+ scb->control = scb->control | SCB_NEEDWDTR;
+#if 0
+ printk("Sending WDTR request to target %d.\n", cmd->target);
+#endif
+ }
+ else
+ {
+ if ((p->needsdtr & mask) && !(p->sdtr_pending & mask))
+ {
+ p->sdtr_pending = p->sdtr_pending | mask;
+ scb->control = scb->control | SCB_NEEDSDTR;
+#if 0
+ printk("Sending SDTR request to target %d.\n", cmd->target);
+#endif
+ }
+ }
- restore_flags(flags);
- return(rv);
+#if 0
+ printk("aic7xxx_queue: 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) |
+ ((cmd->channel & 0x01) << 3) | (cmd->lun & 0x07);
+
+ /*
+ * The interpretation of request_buffer and request_bufflen
+ * changes depending on whether or not use_sg is zero; a
+ * non-zero use_sg indicates the number of elements in the
+ * scatter-gather array.
+ *
+ * The AIC-7770 can't support transfers of any sort larger
+ * than 2^24 (three-byte count) without backflips. For what
+ * the kernel is doing, this shouldn't occur. I hope.
+ */
+ length = aic7xxx_length(cmd, 0);
+
+ if (length > 0xFFFFFF)
+ {
+ panic("aic7xxx_buildscb: can't transfer > 2^24 - 1 bytes\n");
+ }
+
+ /*
+ * XXX - this relies on the host data being stored in a
+ * little-endian format.
+ */
+ addr = cmd->cmnd;
+ scb->SCSI_cmd_length = cmd->cmd_len;
+ memcpy(scb->SCSI_cmd_pointer, &addr, sizeof(scb->SCSI_cmd_pointer));
+
+ if (cmd->use_sg)
+ {
+#if 0
+ debug("aic7xxx_buildscb: SG used, %d segments, length %u\n",
+ cmd->use_sg, length);
+#endif
+ scb->SG_segment_count = cmd->use_sg;
+ memcpy(scb->SG_list_pointer, &cmd->request_buffer,
+ sizeof(scb->SG_list_pointer));
+ }
+ else
+ {
+#if 0
+ debug ("aic7xxx_buildscb: Creating scatterlist, addr=0x%lx, length=%d.\n",
+ (unsigned long) cmd->request_buffer, cmd->request_bufflen);
+#endif
+#ifdef AIC7XXX_USE_SG
+ scb->SG_segment_count = 1;
+ scb->sg.address = (char *) cmd->request_buffer;
+ scb->sg.length = cmd->request_bufflen;
+ addr = &scb->sg;
+ memcpy(scb->SG_list_pointer, &addr, sizeof(scb->SG_list_pointer));
+#else
+ scb->SG_segment_count = 0;
+ memcpy(scb->data_pointer, &cmd->request_buffer, sizeof(scb->data_pointer));
+ memcpy(scb->data_count, &cmd->request_bufflen, 3);
+#endif
+ }
}
-/*
- * Resetting the bus always succeeds - is has to, otherwise the
- * kernel will panic! Try a surgical technique - sending a BUS
- * DEVICE RESET message - on the offending target before pulling
- * the SCSI bus reset line.
- */
-
-int aic7xxx_reset(Scsi_Cmnd *cmd)
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_queue
+ *
+ * Description:
+ * Queue a SCB to the controller.
+ *-F*************************************************************************/
+int
+aic7xxx_queue(Scsi_Cmnd *cmd, void (*fn)(Scsi_Cmnd *))
{
- int i;
- long flags;
- Scsi_Cmnd *reset;
- struct aic7xxx_host *p;
-
- p = (struct aic7xxx_host *)cmd->host->hostdata;
- save_flags(flags);
- cli();
+ long flags;
+#ifndef AIC7XXX_USE_DMA
+ int old_scbptr;
+#endif
+ struct aic7xxx_host *p;
+ struct aic7xxx_scb *scb;
+ unsigned char curscb;
+
+ p = (struct aic7xxx_host *) cmd->host->hostdata;
+
+ /* Check to see if channel was scanned. */
+ if (!p->a_scanned && (cmd->channel == 0))
+ {
+ printk("aic7xxx: Scanning channel A for devices.\n");
+ p->a_scanned = 1;
+ }
+ else
+ {
+ if (!p->b_scanned && (cmd->channel == 1))
+ {
+ printk("aic7xxx: Scanning channel B for devices.\n");
+ p->b_scanned = 1;
+ }
+ }
- switch (aic7xxx_kill(cmd, BUS_DEVICE_RESET, DID_RESET, 0)) {
+#if 0
+ debug("aic7xxx_queue: cmd 0x%x (size %u), target %d, channel %d, lun %d\n",
+ cmd->cmnd[0], cmd->cmd_len, cmd->target, cmd->channel,
+ cmd->lun & 0x07);
+#endif
- case k_ok:
- /*
- * The RESET message was sent to the target
- * with no problems. Flag that target as
- * needing a SDTR negotiation on the next
- * connection and restart the sequencer.
- */
- outb((1 << cmd->target), HA_NEEDSDTR(p->base));
- UNPAUSE_SEQUENCER(p);
- break;
+ /*
+ * This is a critical section, since we don't want the
+ * interrupt routine mucking with the host data or the
+ * card. Since the kernel documentation is vague on
+ * whether or not we are in a cli/sti pair already, save
+ * the flags to be on the safe side.
+ */
+ save_flags(flags);
+ cli();
+
+ /*
+ * Find a free slot in the SCB array to load this command
+ * into. Since can_queue is set to the maximum number of
+ * SCBs for the card, we should always find one.
+ *
+ * First try to find an scb in the free list. If there are
+ * none in the free list, then check the current number of
+ * of scbs and take an unused one from the scb array.
+ */
+ scb = p->free_scb;
+ if (scb != NULL)
+ { /* found one in the free list */
+ p->free_scb = scb->next; /* remove and update head of list */
+ /*
+ * Warning! For some unknown reason, the scb at the head
+ * of the free list is not the same address that it should
+ * be. That's why we set the scb pointer taken by the
+ * position in the array. The scb at the head of the list
+ * should match this address, but it doesn't.
+ */
+ scb = &(p->scb_array[scb->position]);
+ scb->control = 0;
+ scb->state = SCB_ACTIVE;
+ }
+ else
+ {
+ if (p->numscb >= p->maxscb)
+ {
+ panic("aic7xxx_queue: couldn't find a free scb\n");
+ }
+ else
+ {
+ /*
+ * Initialize the scb within the scb array. The
+ * position within the array is the position on
+ * the board that it will be loaded.
+ */
+ scb = &(p->scb_array[p->numscb]);
+ memset(scb, 0, sizeof(*scb));
+
+ scb->position = p->numscb;
+ p->numscb = p->numscb + 1;
+ scb->state = SCB_ACTIVE;
+ scb->next_waiting = SCB_LIST_NULL;
+ memcpy(scb->host_scb, &scb, sizeof(scb));
+#ifdef AIC7XXX_USE_DMA
+ scb->control = SCB_NEEDDMA;
+#endif
+ PAUSE_SEQUENCER(p);
+ curscb = inb(SCBPTR(p->base));
+ outb(scb->position, SCBPTR(p->base));
+ aic7xxx_putdmascb(p->base, scb);
+ outb(curscb, SCBPTR(p->base));
+ UNPAUSE_SEQUENCER(p);
+ scb->control = 0;
+ }
+ }
+
+ scb->cmd = cmd;
+ aic7xxx_position(cmd) = scb->position;
+
+ /*
+ * Construct the SCB beforehand, so the sequencer is
+ * paused a minimal amount of time.
+ */
+ aic7xxx_buildscb(p, cmd, scb);
- case k_absent:
- /*
- * The sequencer will not be paused if aic7xxx_kill()
- * couldn't find the command.
- */
- PAUSE_SEQUENCER(p);
- /* falls through */
+#if 0
+ if (scb != &p->scb_array[scb->position])
+ {
+ 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);
+#endif
+ /*
+ * 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);
+
+ /*
+ * 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.
+ */
+#ifdef AIC7XXX_USE_DMA
+ aic7xxx_putscb(p->base, scb);
+#else
+ old_scbptr = inb(SCBPTR(p->base));
+ outb(scb->position, SCBPTR(p->base));
- case k_busy:
- case k_disconnect:
- /*
- * Do a hard reset of the SCSI bus. According to the
- * SCSI-2 draft specification, reset has to be asserted
- * for at least 25us. I'm invoking the kernel delay
- * function for 30us since I'm not totally trusting of
- * the busy loop timing.
- *
- * XXX - I'm not convinced this works. I tried resetting
- * the bus before, trying to get the devices on the
- * bus to revert to asynchronous transfer, and it
- * never seemed to work.
- */
- debug("aic7xxx: attempting to reset scsi bus and card\n");
+ aic7xxx_putscb(p->base, scb);
- outb(1, O_SCSISEQ(p->base)); /* SCSIRSTO */
- udelay(30);
- outb(0, O_SCSISEQ(p->base)); /* !SCSIRSTO */
+ outb(scb->position, QINFIFO(p->base));
+ outb(old_scbptr, SCBPTR(p->base));
+#endif
+ /*
+ * Make sure the Scsi_Cmnd pointer is saved, the struct it
+ * points to is set up properly, and the parity error flag
+ * is reset, then unpause the sequencer and watch the fun
+ * begin.
+ */
+ cmd->scsi_done = fn;
+ aic7xxx_error(cmd) = DID_OK;
+ aic7xxx_status(cmd) = 0;
+
+ cmd->result = 0;
+ memset (&cmd->sense_buffer, 0, sizeof (cmd->sense_buffer));
+
+ UNPAUSE_SEQUENCER(p);
+ restore_flags(flags);
+ return(0);
+}
- outb(0xff, HA_NEEDSDTR(p->base));
- UNPAUSE_SEQUENCER(p);
+/* return values from aic7xxx_kill */
+typedef enum {
+ k_ok, /* scb found and message sent */
+ k_busy, /* message already present */
+ k_absent, /* couldn't locate scb */
+ k_disconnect, /* scb found, but disconnected */
+} k_state;
+
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_kill
+ *
+ * Description:
+ * This must be called with interrupts disabled - it's going to
+ * be messing around with the host data, and an interrupt being
+ * fielded in the middle could get ugly.
+ *
+ * Since so much of the abort and reset code is shared, this
+ * function performs more magic than it really should. If the
+ * command completes ok, then it will call scsi_done with the
+ * result code passed in. The unpause parameter controls whether
+ * or not the sequencer gets unpaused - the reset function, for
+ * instance, may want to do something more aggressive.
+ *
+ * Note that the command is checked for in our SCB_array first
+ * before the sequencer is paused, so if k_absent is returned,
+ * then the sequencer is NOT paused.
+ *-F*************************************************************************/
+static k_state
+aic7xxx_kill(Scsi_Cmnd *cmd, unsigned char message,
+ unsigned int result, int unpause)
+{
+ struct aic7xxx_host *p;
+ struct aic7xxx_scb *scb;
+ int i, active_scb, found, queued;
+ unsigned char scbsave[AIC7XXX_MAXSCB];
+ unsigned char flags;
+ int scb_control;
+ k_state status;
- /*
- * Locate the command and return a "reset" status
- * for it. This is not completely correct and will
- * probably return to haunt me later.
- */
- for (i = 0; i < p->maxscb; i++) {
- if (cmd == p->SCB_array[i]) {
- reset = (Scsi_Cmnd *)p->SCB_array[i];
- p->SCB_array[i] = NULL;
- reset->result = DID_RESET << 16;
- reset->scsi_done(reset);
- break;
- }
- }
- break;
+ p = (struct aic7xxx_host *) cmd->host->hostdata;
+ scb = &p->scb_array[aic7xxx_position(cmd)];
- default:
- panic("aic7xxx_reset: internal error\n");
- }
+#if 0
+ printk("aic7xxx_kill: In the kill function...\n");
+#endif
+ PAUSE_SEQUENCER(p);
+
+ /*
+ * Case 1: In the QINFIFO
+ *
+ * This is the best case, really. Check to see if the
+ * command is still in the sequencer's input queue. If
+ * so, simply remove it. Reload the queue afterward.
+ */
+ queued = inb(QINCNT(p->base));
+
+ for (i = found = 0; i < (queued - found); i++)
+ {
+ scbsave[i] = inb(QINFIFO(p->base));
+
+ if (scbsave[i] == scb->position)
+ {
+ found = 1;
+ i = i - 1;
+ }
+ }
+
+ for (queued = 0; queued < i; queued++)
+ {
+ outb(scbsave[queued], QINFIFO(p->base));
+ }
+
+ if (found)
+ {
+ status = k_ok;
+ goto complete;
+ }
+
+ active_scb = inb(SCBPTR(p->base));
+ /*
+ * Case 2: Not the active command
+ *
+ * Check the current SCB bank. If it's not the one belonging
+ * to the command we want to kill, select the scb we want to
+ * abort and turn off the disconnected bit. The driver will
+ * then abort the command and notify us of the abort.
+ */
+ if (active_scb != scb->position)
+ {
+ outb(scb->position, SCBPTR(p->base));
+ scb_control = inb(SCBARRAY(p->base));
+ scb_control = scb_control & ~SCB_DIS;
+ outb(scb_control, SCBARRAY(p->base));
+ outb(active_scb, SCBPTR(p->base));
+ status = k_disconnect;
+ goto complete;
+ }
+
+ scb_control = inb(SCBARRAY(p->base));
+ if (scb_control & SCB_DIS)
+ {
+ scb_control = scb_control & ~SCB_DIS;
+ outb(scb_control, SCBARRAY(p->base));
+ status = k_disconnect;
+ goto complete;
+ }
+
+ /*
+ * Presumably at this point our target command is active. Check
+ * to see if there's a message already in effect. If not, place
+ * our message in and assert ATN so the target goes into MESSAGE
+ * OUT phase.
+ */
+ flags = inb(HA_FLAGS(p->base));
+ if (flags & ACTIVE_MSG)
+ {
+ /*
+ * If there is a message in progress, reset the bus
+ * and have all devices renegotiate.
+ */
+ if (cmd->channel & 0x01)
+ {
+ p->needsdtr = p->needsdtr_copy & 0xFF00;
+ p->sdtr_pending = p->sdtr_pending & 0x00FF;
+ outb(0, HA_ACTIVE1(p->base));
+ }
+ else
+ {
+ if (p->bus_type == AIC_WIDE)
+ {
+ p->needsdtr = p->needsdtr_copy;
+ p->needwdtr = p->needwdtr_copy;
+ p->sdtr_pending = 0;
+ p->wdtr_pending = 0;
+ outb(0, HA_ACTIVE0(p->base));
+ outb(0, HA_ACTIVE1(p->base));
+ }
+ else
+ {
+ p->needsdtr = p->needsdtr_copy & 0x00FF;
+ p->sdtr_pending = p->sdtr_pending & 0xFF00;
+ outb(0, HA_ACTIVE0(p->base));
+ }
+ }
+ /* Reset the bus. */
+ outb(SCSIRSTO, SCSISEQ(p->base));
+ udelay(1000);
+ outb(0, SCSISEQ(p->base));
+ aic7xxx_delay(AIC7XXX_RESET_DELAY);
+
+ status = k_busy;
+ goto complete;
+ }
+
+ outb(flags | ACTIVE_MSG, HA_FLAGS(p->base)); /* active message */
+ outb(1, HA_MSG_LEN(p->base)); /* length = 1 */
+ outb(message, HA_MSG_START(p->base)); /* message body */
+
+ /*
+ * Assert ATN. Use the value of SCSISIGO saved by the
+ * sequencer code so we don't alter its contents radically
+ * in the middle of something critical.
+ */
+ outb(inb(HA_SIGSTATE(p->base)) | 0x10, SCSISIGO(p->base));
+
+ status = k_ok;
+
+ /*
+ * The command has been killed. Do the bookkeeping, unpause
+ * the sequencer, and notify the higher-level SCSI code.
+ */
+complete:
+ if (unpause)
+ {
+ UNPAUSE_SEQUENCER(p);
+ }
+
+ /*
+ * Mark the scb as free and clear the scbs command pointer.
+ * Add the scb to the head of the free list being careful
+ * to preserve the next pointers.
+ */
+ scb->state = SCB_FREE; /* mark the scb as free */
+ scb->cmd = NULL; /* clear the command pointer */
+ scb->next = p->free_scb; /* preserve next pointer */
+ p->free_scb = scb; /* add at head of free list */
+ cmd->result = cmd->result << 16;
+ cmd->scsi_done(cmd);
+ return(status);
+}
- restore_flags(flags);
- return(SCSI_RESET_SUCCESS);
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_abort
+ *
+ * Description:
+ * Abort the current SCSI command(s).
+ *-F*************************************************************************/
+int
+aic7xxx_abort(Scsi_Cmnd *cmd)
+{
+ int rv;
+ long flags;
+
+ save_flags(flags);
+ cli();
+
+ switch (aic7xxx_kill(cmd, ABORT, DID_ABORT, !0))
+ {
+ case k_ok: rv = SCSI_ABORT_SUCCESS; break;
+ case k_busy: rv = SCSI_ABORT_BUSY; break;
+ case k_absent: rv = SCSI_ABORT_NOT_RUNNING; break;
+ case k_disconnect: rv = SCSI_ABORT_SNOOZE; break;
+ default: panic("aic7xxx_abort: internal error\n");
+ }
+
+ restore_flags(flags);
+ return(rv);
}
-int aic7xxx_biosparam(Disk *disk, int devno, int geom[])
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_reset
+ *
+ * Description:
+ * Resetting the bus always succeeds - is has to, otherwise the
+ * kernel will panic! Try a surgical technique - sending a BUS
+ * DEVICE RESET message - on the offending target before pulling
+ * the SCSI bus reset line.
+ *-F*************************************************************************/
+int
+aic7xxx_reset(Scsi_Cmnd *cmd)
{
- int heads, sectors, cylinders;
- struct aic7xxx_host *p;
-
- p = (struct aic7xxx_host *)disk->device->host->hostdata;
+ long flags;
+ struct aic7xxx_host *p;
+
+ p = (struct aic7xxx_host *) cmd->host->hostdata;
+ save_flags(flags);
+ cli();
+
+ switch (aic7xxx_kill(cmd, BUS_DEVICE_RESET, DID_RESET, 0))
+ {
+ case k_ok:
+ /*
+ * The RESET message was sent to the target
+ * with no problems. Flag that target as
+ * needing a SDTR negotiation on the next
+ * connection and restart the sequencer.
+ */
+ p->needsdtr = p->needsdtr & (1 << cmd->target);
+ UNPAUSE_SEQUENCER(p);
+ break;
+
+ case k_absent:
+ /*
+ * The sequencer will not be paused if aic7xxx_kill()
+ * couldn't find the command.
+ */
+ PAUSE_SEQUENCER(p);
+ /* falls through */
+
+ case k_busy:
+ cmd->result = DID_RESET << 16; /* return reset code */
+ cmd->scsi_done(cmd);
+ break;
+
+ case k_disconnect:
+ /*
+ * Do a hard reset of the SCSI bus. According to the
+ * SCSI-2 draft specification, reset has to be asserted
+ * for at least 25us. I'm invoking the kernel delay
+ * function for 30us since I'm not totally trusting of
+ * the busy loop timing.
+ *
+ * XXX - I'm not convinced this works. I tried resetting
+ * the bus before, trying to get the devices on the
+ * bus to revert to asynchronous transfer, and it
+ * never seemed to work.
+ */
+ debug("aic7xxx: attempting to reset scsi bus and card\n");
+
+ outb(SCSIRSTO, SCSISEQ(p->base));
+ udelay(1000);
+ outb(0, SCSISEQ(p->base));
+ aic7xxx_delay(AIC7XXX_RESET_DELAY);
+
+ UNPAUSE_SEQUENCER(p);
+
+ /*
+ * Locate the command and return a "reset" status
+ * for it. This is not completely correct and will
+ * probably return to haunt me later.
+ */
+ cmd->result = DID_RESET << 16; /* return reset code */
+ cmd->scsi_done(cmd);
+ break;
+
+ default:
+ panic("aic7xxx_reset: internal error\n");
+ }
+
+ restore_flags(flags);
+ return(SCSI_RESET_SUCCESS);
+}
- /*
- * XXX - if I could portably find the card's configuration
- * information, then this could be autodetected instead
- * of left to a boot-time switch.
- */
- heads = 64;
- sectors = 32;
- cylinders = disk->capacity / (heads * sectors);
-
- if (p->extended && cylinders > 1024) {
- heads = 255;
- sectors = 63;
- cylinders = disk->capacity / (255 * 63);
- }
+/*+F*************************************************************************
+ * Function:
+ * aic7xxx_biosparam
+ *
+ * Description:
+ * Return the disk geometry for the given SCSI device.
+ *-F*************************************************************************/
+int
+aic7xxx_biosparam(Disk *disk, int devno, int geom[])
+{
+ int heads, sectors, cylinders;
+ struct aic7xxx_host *p;
+
+ p = (struct aic7xxx_host *) disk->device->host->hostdata;
+
+ /*
+ * XXX - if I could portably find the card's configuration
+ * information, then this could be autodetected instead
+ * of left to a boot-time switch.
+ */
+ heads = 64;
+ sectors = 32;
+ cylinders = disk->capacity / (heads * sectors);
+
+ if (p->extended && cylinders > 1024)
+ {
+ heads = 255;
+ sectors = 63;
+ cylinders = disk->capacity / (255 * 63);
+ }
+
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
+
+ return(0);
+}
- geom[0] = heads;
- geom[1] = sectors;
- geom[2] = cylinders;
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = AIC7XXX;
- return(0);
-}
+#include "scsi_module.c"
+#endif
-/* @(#)aic7xxx.h 1.14 94/11/30 jda */
-
-/*
+/*+M*************************************************************************
* Adaptec 274x/284x/294x device driver for Linux.
- * Copyright (c) 1994 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 of the License, 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.
+ *
+ * Copyright (c) 1994 John Aycock
+ * The University of Calgary Department of Computer Science.
+ * 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.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of Calgary
+ * Department of Computer Science and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
*
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#ifndef aic7xxx_h
-#define aic7xxx_h
+ * $Id: aic7xxx.h,v 1.18 1995/06/22 04:17:56 deang Exp $
+ *-M*************************************************************************/
+#ifndef _aic7xxx_h
+#define _aic7xxx_h
-#define AIC7XXX_H_VERSION "1.14"
+#define AIC7XXX_H_VERSION "$Revision: 1.18 $"
/*
- * Scsi_Host_Template (see hosts.h) for 274x - some fields
- * to do with card config are filled in after the card is
- * detected.
+ * Scsi_Host_Template (see hosts.h) for AIC-7770/AIC-7870 - some fields
+ * to do with card config are filled in after the card is detected.
*/
#define AIC7XXX { \
NULL, \
NULL, \
+ generic_proc_info, \
+ "aic7xxx", \
+ PROC_SCSI_AIC7XXX, \
NULL, \
aic7xxx_detect, \
NULL, \
-1, /* max simultaneous cmds */\
-1, /* scsi id of host adapter */\
SG_ALL, /* max scatter-gather cmds */\
- 1, /* cmds per lun (linked cmds) */\
- 0, /* number of 274x's present */\
+ 2, /* cmds per lun (linked cmds) */\
+ 0, /* number of 7xxx's present */\
0, /* no memory DMA restrictions */\
- DISABLE_CLUSTERING \
+ ENABLE_CLUSTERING \
}
extern int aic7xxx_queue(Scsi_Cmnd *, void (*)(Scsi_Cmnd *));
extern const char *aic7xxx_info(struct Scsi_Host *);
-#endif
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
+#endif /* _aic7xxx_h */
-# @(#)aic7xxx.seq 1.32 94/11/29 jda
-#
-# Adaptec 274x/284x/294x device driver for Linux.
-# Copyright (c) 1994 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 of the License, 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.
+##+M#########################################################################
+# Adaptec 274x/284x/294x device driver for Linux and FreeBSD.
+#
+# Copyright (c) 1994 John Aycock
+# The University of Calgary Department of Computer Science.
+# All rights reserved.
+#
+# Modifications/enhancements:
+# Copyright (c) 1994, 1995 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.
+# 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. All advertising materials mentioning features or use of this software
+# must display the following acknowledgement:
+# This product includes software developed by the University of Calgary
+# Department of Computer Science and its contributors.
+# 4. Neither the name of the University nor the names of its contributors
+# may be used to endorse or promote products derived from this software
+# without specific prior written permission.
+#
+# 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.
#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 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)
+#
+##-M#########################################################################
-VERSION AIC7XXX_SEQ_VERSION 1.32
+VERSION AIC7XXX_SEQ_VER "$Id: aic7xxx.seq,v 1.19 1995/06/05 06:11:41 deang Exp $"
SCBMASK = 0x1f
SCSISEQ = 0x00
+ENRSELI = 0x10
SXFRCTL0 = 0x01
SXFRCTL1 = 0x02
SCSISIGI = 0x03
STCNT+0 = 0x08
STCNT+1 = 0x09
STCNT+2 = 0x0a
+CLRSINT0 = 0x0b
SSTAT0 = 0x0b
+SELDO = 0x40
+SELDI = 0x20
CLRSINT1 = 0x0c
SSTAT1 = 0x0c
SIMODE1 = 0x11
DINDIR = 0x6d
FUNCTION1 = 0x6e
HADDR = 0x88
+HADDR+1 = 0x89
+HADDR+2 = 0x8a
+HADDR+3 = 0x8b
HCNT = 0x8c
HCNT+0 = 0x8c
HCNT+1 = 0x8d
QINCNT = 0x9c
QOUTFIFO = 0x9d
-SCSICONF = 0x5a
+SCSICONF_A = 0x5a
+SCSICONF_B = 0x5b
# The two reserved bytes at SCBARRAY+1[23] are expected to be set to
# zero, and the reserved bit in SCBARRAY+0 is used as an internal flag
# to indicate whether or not to reload scatter-gather parameters after
-# a disconnect.
+# a disconnect. We also use bits 6 & 7 to indicate whether or not to
+# initiate SDTR or WDTR repectively when starting this command.
#
SCBARRAY+0 = 0xa0
+
+DISCONNECTED = 0x04
+NEEDDMA = 0x08
+SG_LOAD = 0x10
+TAG_ENB = 0x20
+NEEDSDTR = 0x40
+NEEDWDTR = 0x80
+
SCBARRAY+1 = 0xa1
SCBARRAY+2 = 0xa2
SCBARRAY+3 = 0xa3
+SCBARRAY+4 = 0xa4
+SCBARRAY+5 = 0xa5
+SCBARRAY+6 = 0xa6
SCBARRAY+7 = 0xa7
+SCBARRAY+8 = 0xa8
+SCBARRAY+9 = 0xa9
+SCBARRAY+10 = 0xaa
SCBARRAY+11 = 0xab
+SCBARRAY+12 = 0xac
+SCBARRAY+13 = 0xad
SCBARRAY+14 = 0xae
SCBARRAY+15 = 0xaf
SCBARRAY+16 = 0xb0
SCBARRAY+23 = 0xb7
SCBARRAY+24 = 0xb8
SCBARRAY+25 = 0xb9
+SCBARRAY+26 = 0xba
+SCBARRAY+27 = 0xbb
+SCBARRAY+28 = 0xbc
+SCBARRAY+29 = 0xbd
+SCBARRAY+30 = 0xbe
+
+BAD_PHASE = 0x01 # unknown scsi bus phase
+CMDCMPLT = 0x02 # Command Complete
+SEND_REJECT = 0x11 # sending a message reject
+NO_IDENT = 0x21 # no IDENTIFY after reconnect
+NO_MATCH = 0x31 # no cmd match for reconnect
+MSG_SDTR = 0x41 # SDTR message recieved
+MSG_WDTR = 0x51 # WDTR message recieved
+MSG_REJECT = 0x61 # Reject message recieved
+BAD_STATUS = 0x71 # Bad status from target
+RESIDUAL = 0x81 # Residual byte count != 0
+ABORT_TAG = 0x91 # Sent an ABORT_TAG message
+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.
-SIGNAL_0 = 0x01 # unknown scsi bus phase
-SIGNAL_1 = 0x11 # message reject
-SIGNAL_2 = 0x21 # no IDENTIFY after reconnect
-SIGNAL_3 = 0x31 # no cmd match for reconnect
-SIGNAL_4 = 0x41 # SDTR -> SCSIRATE conversion
# The host adapter card (at least the BIOS) uses 20-2f for SCSI
-# device information, 32-33 and 5a-5f as well. Since we don't support
-# wide or twin-bus SCSI, 28-2f can be reclaimed. As it turns out, the
-# BIOS trashes 20-27 anyway, writing the synchronous negotiation results
+# 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). This implies, since we can't get the BIOS config values,
-# that all targets will be negotiated with for synchronous transfer.
-# NEEDSDTR has one bit per target indicating if an SDTR message is
-# needed for that device - this will be set initially, as well as
-# after a bus reset condition.
-#
-# The high bit of DROPATN is set if ATN should be dropped before the ACK
-# when outb is called. REJBYTE contains the first byte of a MESSAGE IN
-# message, so the driver can report an intelligible error if a message is
-# rejected.
-#
-# RESELECT's high bit is true if we are currently handling a reselect;
+# 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 irregardless of
+# whether the bios has been installed. NEEDWDTR and NEEDSDTR are the top
+# two bits of the SCB control byte. The kernel driver will set these
+# when a WDTR or SDTR message should be sent to the target the SCB's
+# command references.
+#
+# REJBYTE contains the first byte of a MESSAGE IN message, so the driver
+# can report an intelligible error if a message is rejected.
+#
+# FLAGS's high bit is true if we are currently handling a reselect;
# its next-highest bit is true ONLY IF we've seen an IDENTIFY message
# from the reselecting target. If we haven't had IDENTIFY, then we have
# no idea what the lun is, and we can't select the right SCB register
# bank, so force a kernel panic if the target attempts a data in/out or
-# command phase instead of corrupting something.
+# command phase instead of corrupting something. FLAGS also contains
+# configuration bits so that we can optimize for TWIN and WIDE controllers
+# as well as the MAX_OFFSET bit which we set when we want to negotiate for
+# maximum sync offset irregardless of what the per target scratch space says.
#
# Note that SG_NEXT occupies four bytes.
#
SYNCNEG = 0x20
-DISC_DSB_A = 0x32
-DROPATN = 0x30
REJBYTE = 0x31
-RESELECT = 0x34
-
-MSG_FLAGS = 0x35
-MSG_LEN = 0x36
-MSG_START+0 = 0x37
-MSG_START+1 = 0x38
-MSG_START+2 = 0x39
-MSG_START+3 = 0x3a
-MSG_START+4 = 0x3b
-MSG_START+5 = 0x3c
--MSG_START+0 = 0xc9 # 2's complement of MSG_START+0
-
-ARG_1 = 0x4c # sdtr conversion args & return
-ARG_2 = 0x4d
-RETURN_1 = 0x4c
-
-SIGSTATE = 0x4e # value written to SCSISIGO
-NEEDSDTR = 0x4f # send SDTR message, 1 bit/trgt
-
-SG_SIZEOF = 12 # sizeof(struct scatterlist)
-SG_NOLOAD = 0x50 # load SG pointer/length?
-SG_COUNT = 0x51 # working value of SG count
-SG_NEXT = 0x52 # working value of SG pointer
-SG_NEXT+0 = 0x52
-SG_NEXT+1 = 0x53
-SG_NEXT+2 = 0x54
-SG_NEXT+3 = 0x55
-
-SCBCOUNT = 0x56 # the actual number of SCBs
+DISC_DSB_A = 0x32
+DISC_DSB_B = 0x33
+
+MSG_LEN = 0x34
+MSG_START+0 = 0x35
+MSG_START+1 = 0x36
+MSG_START+2 = 0x37
+MSG_START+3 = 0x38
+MSG_START+4 = 0x39
+MSG_START+5 = 0x3a
+-MSG_START+0 = 0xcb # 2's complement of MSG_START+0
+
+ARG_1 = 0x4a # sdtr conversion args & return
+BUS_16_BIT = 0x01
+RETURN_1 = 0x4a
+
+SIGSTATE = 0x4b # value written to SCSISIGO
+
+# Linux users should use 0xc (12) for SG_SIZEOF
+#SG_SIZEOF = 0x8 # sizeof(struct ahc_dma)
+SG_SIZEOF = 0xc # sizeof(struct scatterlist)
+# if AIC7XXX_USE_SG
+SCB_SIZEOF = 0x13 # sizeof SCB to DMA (19 bytes)
+# else
+#SCB_SIZEOF = 0x1a # sizeof SCB without SG
+# endif
+
+SG_NOLOAD = 0x4c # load SG pointer/length?
+SG_COUNT = 0x4d # working value of SG count
+SG_NEXT = 0x4e # working value of SG pointer
+SG_NEXT+0 = 0x4e
+SG_NEXT+1 = 0x4f
+SG_NEXT+2 = 0x50
+SG_NEXT+3 = 0x51
+
+SCBCOUNT = 0x52 # the actual number of SCBs
+FLAGS = 0x53 # Device configuration flags
+TWIN_BUS = 0x01
+WIDE_BUS = 0x02
+MAX_OFFSET = 0x08
+ACTIVE_MSG = 0x20
+IDENTIFY_SEEN = 0x40
+RESELECTED = 0x80
+
+MAX_OFFSET_8BIT = 0x0f
+MAX_OFFSET_WIDE = 0x08
+
+ACTIVE_A = 0x54
+ACTIVE_B = 0x55
+SAVED_TCL = 0x56 # Temporary storage for the
+ # target/channel/lun of a
+ # reconnecting target
+
+# After starting the selection hardware, we return to the "poll_for_work"
+# loop so that we can 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 31 of the SCB as a psuedo-next pointer and to thread a list
+# of SCBs that are awaiting selection. Since 0 is a valid SCB offset,
+# SCB_LIST_NULL is 0x10 which is out of range. The kernel driver must
+# add an entry to this list everytime a request sense occurs. The sequencer
+# will automatically consume the entries.
+
+WAITING_SCBH = 0x57 # head of list of SCBs awaiting
+ # selection
+WAITING_SCBT = 0x58 # tail of list of SCBs awaiting
+ # selection
+SCB_LIST_NULL = 0x10
+
# Poll QINCNT for work - the lower bits contain
# the number of entries in the Queue In FIFO.
#
start:
- test SCSISIGI,0x4 jnz reselect # BSYI
- test QINCNT,SCBMASK jz start
-
-# We have at least one queued SCB now. Set the SCB pointer
-# from the FIFO so we see the right bank of SCB registers,
-# then set SCSI options and set the initiator and target
-# SCSI IDs.
+ test WAITING_SCBH,SCB_LIST_NULL jz start_waiting
+poll_for_work:
+ test FLAGS,TWIN_BUS jz start2 # Are we a twin channel device?
+# For fairness, we check the other bus first, since we just finished a
+# transaction on the current channel.
+ xor SBLKCTL,0x08 # Toggle to the other bus
+ test SSTAT0,SELDI jnz reselect
+ test SSTAT0,SELDO jnz select
+ xor SBLKCTL,0x08 # Toggle to the original bus
+start2:
+ test SSTAT0,SELDI jnz reselect
+ test SSTAT0,SELDO jnz select
+ test WAITING_SCBH,SCB_LIST_NULL jz start_waiting
+ test QINCNT,SCBMASK 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, then set SCSI options and set the initiator and
+# target SCSI IDs.
#
mov SCBPTR,QINFIFO
- mov SCBARRAY+1 call initialize
+
+# If the control byte of this SCB has the NEEDDMA flag set, we have
+# yet to DMA it from host memory
+
+test SCBARRAY+0,NEEDDMA jz test_busy
+ clr HCNT+2
+ clr HCNT+1
+ mvi HCNT+0,SCB_SIZEOF
+
+ mvi DINDEX,HADDR
+ mvi SCBARRAY+26 call bcopy_4
+
+ mvi 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.
+#
+ call dma_finish
+
+# Copy the SCB from the FIFO to the SCBARRAY
+
+ mvi DINDEX, SCBARRAY+0
+ call bcopy_3_dfdat
+ call bcopy_4_dfdat
+ call bcopy_4_dfdat
+ call bcopy_4_dfdat
+ call bcopy_4_dfdat
+# ifndef AIC7XXX_USE_SG
+# call bcopy_3_dfdat
+# call bcopy_4_dfdat
+# endif
+
+# 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 benificial 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's SELTO.
+
+test_busy:
+ test SCBARRAY+0,0x20 jnz start_scb
+ and FUNCTION1,0x70,SCBARRAY+1
+ mov A,FUNCTION1
+ test SCBARRAY+1,0x88 jz test_a # Id < 8 && A channel
+
+ test ACTIVE_B,A jnz requeue
+ or ACTIVE_B,A # Mark the current target as busy
+ jmp start_scb
+
+# Place the currently active 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
+start_waiting:
+ mov SCBPTR,WAITING_SCBH
+ jmp start_scb
+
+test_a:
+ test ACTIVE_A,A jnz requeue
+ or ACTIVE_A,A # Mark the current target as busy
+
+start_scb:
+ and SINDEX,0xf7,SBLKCTL #Clear the channel select bit
+ and A,0x08,SCBARRAY+1 #Get new channel bit
+ or SINDEX,A
+ mov SBLKCTL,SINDEX # select channel
+ mov SCBARRAY+1 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:
+ or SCSISEQ,0x48 # ENSELO|ENAUTOATNO
+ mov WAITING_SCBH, SCBPTR
clr SG_NOLOAD
- clr RESELECT
+ and FLAGS,0x3f # !RESELECTING
# 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, locking out the device driver. If the device
# driver hasn't beaten us with an ABORT or RESET message, then tack
-# on a SDTR negotiation if required.
+# on an SDTR negotiation if required.
#
# Messages are stored in scratch RAM starting with a flag byte (high bit
# set means active message), one length byte, and then the message itself.
#
+
+ test SCBARRAY+11,0xff jnz 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 poll_for_work
+
+identify:
mov SCBARRAY+1 call disconnect # disconnect ok?
and SINDEX,0x7,SCBARRAY+1 # lun
or SINDEX,0x80 call mk_mesg # IDENTIFY message
mov A,SINDEX
+ test SCBARRAY+0,0xe0 jz !message # WDTR, SDTR or TAG??
cmp MSG_START+0,A jne !message # did driver beat us?
- mvi MSG_START+1 call mk_sdtr # build SDTR message if needed
-!message:
+# Tag Message if Tag enabled in SCB control block. Use SCBPTR as the tag
+# value
-# Enable selection phase as an initiator, and do automatic ATN
-# after the selection.
-#
- mvi SCSISEQ,0x48 # ENSELO|ENAUTOATNO
+mk_tag:
+ mvi DINDEX, MSG_START+1
+ test SCBARRAY+0,TAG_ENB jz mk_tag_done
+ and A,0x23,SCBARRAY+0
+ mov DINDIR,A
+ mov DINDIR,SCBPTR
-# Wait for successful arbitration. The AIC-7770 documentation says
-# that SELINGO indicates successful arbitration, and that it should
-# be used to look for SELDO. However, if the sequencer is paused at
-# just the right time - a parallel fsck(8) on two drives did it for
-# me - then SELINGO can flip back to false before we've seen it. This
-# makes the sequencer sit in the arbitration loop forever. This is
-# Not Good.
-#
-# Therefore, I've added a check in the arbitration loop for SELDO
-# too. This could arguably be made a critical section by disabling
-# pauses, but I don't want to make a potentially infinite loop a CS.
-# I suppose you could fold it into the select loop, too, but since
-# I've been hunting this bug for four days it's kinda like a trophy.
-#
-arbitrate:
- test SSTAT0,0x40 jnz *select # SELDO
- test SSTAT0,0x10 jz arbitrate # SELINGO
+ add MSG_LEN,-MSG_START+0,DINDEX # update message length
-# Wait for a successful selection. If the hardware selection
-# timer goes off, then the driver gets the interrupt, so we don't
-# need to worry about it.
-#
-select:
- test SSTAT0,0x40 jz select # SELDO
- jmp *select
+mk_tag_done:
+
+ mov DINDEX call mk_dtr # build DTR message if needed
+
+!message:
+ jmp poll_for_work
-# Reselection is being initiated by a target - we've seen the BSY
-# line driven active, and we didn't do it! Enable the reselection
-# hardware, and wait for it to finish. Make a note that we've been
+# 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:
- mvi SCSISEQ,0x10 # ENRSELI
+ mov SELID call initialize_scsiid
+ and FLAGS,0x3f # reselected, no IDENTIFY
+ or FLAGS,RESELECTED jmp select2
-reselect1:
- test SSTAT0,0x20 jz reselect1 # SELDI
- mov SELID call initialize
-
- mvi RESELECT,0x80 # reselected, no IDENTIFY
-
-# After the [re]selection, make sure that the [re]selection enable
-# bit is off. This chip is flaky enough without extra things
-# turned on. Also clear the BUSFREE bit in SSTAT1 since we'll be
-# using it shortly.
+# After the selection, remove this SCB from the "waiting for selection"
+# list. This is achieved by simply moving our "next" pointer into
+# WAITING_SCBH and setting our next pointer to null so that the next
+# time this SCB is used, we don't get confused.
#
-*select:
- clr SCSISEQ
+select:
+ or SCBARRAY+0,NEEDDMA
+ mov WAITING_SCBH,SCBARRAY+30
+ mvi SCBARRAY+30,SCB_LIST_NULL
+select2:
+ call initialize_for_target
+ mvi SCSISEQ,ENRSELI
+ mvi CLRSINT0,0x60 # CLRSELDI|CLRSELDO
mvi CLRSINT1,0x8 # CLRBUSFREE
# Main loop for information transfer phases. If BSY is false, then
cmp A,0xa0 je p_mesgout
cmp A,0xe0 je p_mesgin
- mvi INTSTAT,SIGNAL_0 # unknown - signal driver
+ mvi INTSTAT,BAD_PHASE # unknown - signal driver
p_dataout:
mvi 0 call scsisig # !CDO|!IOO|!MSGO
call assert
call sg_load
- mvi A,3
- mvi DINDEX,HCNT
- mvi SCBARRAY+23 call bcopy
+ mvi DINDEX,HADDR
+ mvi SCBARRAY+19 call bcopy_4
- mvi A,3
- mvi DINDEX,STCNT
- mvi SCBARRAY+23 call bcopy
+# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR
+ mvi SCBARRAY+23 call bcopy_3
- mvi A,4
- mvi DINDEX,HADDR
- mvi SCBARRAY+19 call bcopy
+ mvi DINDEX,STCNT
+ mvi SCBARRAY+23 call bcopy_3
+# If we are the last SG block, don't set wideodd.
+ test SCBARRAY+18,0xff jnz p_dataout_wideodd
mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN|
# DIRECTION|FIFORESET
+ jmp p_dataout_rest
+p_dataout_wideodd:
+ mvi 0xbd call dma # WIDEODD|SCSIEN|SDMAEN|HDMAEN|
+ # DIRECTION|FIFORESET
+
+p_dataout_rest:
# After a DMA finishes, save the final transfer pointer and count
# back into the SCB, in case a device disconnects in the middle of
# a transfer. Use SHADDR and STCNT instead of HADDR and HCNT, since
# it's a reflection of how many bytes were transferred on the SCSI
# (as opposed to the host) bus.
#
- mvi A,3
mvi DINDEX,SCBARRAY+23
- mvi STCNT call bcopy
+ mvi STCNT call bcopy_3
- mvi A,4
mvi DINDEX,SCBARRAY+19
- mvi SHADDR call bcopy
+ mvi SHADDR call bcopy_4
call sg_advance
mov SCBARRAY+18,SG_COUNT # residual S/G count
call assert
call sg_load
- mvi A,3
- mvi DINDEX,HCNT
- mvi SCBARRAY+23 call bcopy
+ mvi DINDEX,HADDR
+ mvi SCBARRAY+19 call bcopy_4
+
+# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR
+ mvi SCBARRAY+23 call bcopy_3
- mvi A,3
mvi DINDEX,STCNT
- mvi SCBARRAY+23 call bcopy
-
- mvi A,4
- mvi DINDEX,HADDR
- mvi SCBARRAY+19 call bcopy
+ mvi SCBARRAY+23 call bcopy_3
+# If we are the last SG block, don't set wideodd.
+ test SCBARRAY+18,0xff jnz p_datain_wideodd
mvi 0x39 call dma # SCSIEN|SDMAEN|HDMAEN|
# !DIRECTION|FIFORESET
- mvi A,3
+ jmp p_datain_rest
+p_datain_wideodd:
+ mvi 0xb9 call dma # WIDEODD|SCSIEN|SDMAEN|HDMAEN|
+ # !DIRECTION|FIFORESET
+p_datain_rest:
mvi DINDEX,SCBARRAY+23
- mvi STCNT call bcopy
+ mvi STCNT call bcopy_3
- mvi A,4
mvi DINDEX,SCBARRAY+19
- mvi SHADDR call bcopy
+ mvi SHADDR call bcopy_4
call sg_advance
mov SCBARRAY+18,SG_COUNT # residual S/G count
mvi 0x80 call scsisig # CDO|!IOO|!MSGO
call assert
- mvi A,3
- mvi DINDEX,HCNT
- mvi SCBARRAY+11 call bcopy
+ mvi DINDEX,HADDR
+ mvi SCBARRAY+7 call bcopy_4
- mvi A,3
- mvi DINDEX,STCNT
- mvi SCBARRAY+11 call bcopy
+# mvi DINDEX,HCNT # implicit since HCNT is next to HADDR
+ mvi SCBARRAY+11 call bcopy_3
- mvi A,4
- mvi DINDEX,HADDR
- mvi SCBARRAY+7 call bcopy
+ mvi DINDEX,STCNT
+ mvi SCBARRAY+11 call bcopy_3
mvi 0x3d call dma # SCSIEN|SDMAEN|HDMAEN|
# DIRECTION|FIFORESET
p_status:
mvi 0xc0 call scsisig # CDO|IOO|!MSGO
- mvi SCBARRAY+14 call inb
- jmp ITloop
+ mvi SCBARRAY+14 call inb_first
+ jmp p_mesgin_done
# Message out phase. If there is no active message, but the target
# took us into this phase anyway, build a no-op message and send it.
mvi 0xa0 call scsisig # CDO|!IOO|MSGO
mvi 0x8 call mk_mesg # build NOP message
+ clr STCNT+2
+ clr STCNT+1
+
# Set up automatic PIO transfer from MSG_START. Bit 3 in
# SXFRCTL0 (SPIOEN) is already on.
#
mvi SINDEX,MSG_START+0
mov DINDEX,MSG_LEN
- clr A
# 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.
# an SPIORDY that hadn't dropped yet.
#
p_mesgout3:
- call one_stcnt
+ mvi STCNT+0, 0x01
mov SCSIDATL,SINDIR
p_mesgout4:
test SSTAT0,0x4 jz p_mesgout4 # SDONE
dec DINDEX
- inc A
- cmp MSG_LEN,A jne p_mesgout2
+ test DINDEX,0xff jnz p_mesgout2
# 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_mesgout6:
mvi CLRSINT1,0x40 # CLRATNO - in case of PHASEMIS
- clr MSG_FLAGS # no active msg
+ and FLAGS,0xdf # no active msg
jmp ITloop
# Message in phase. Bytes are read using Automatic PIO mode, but not
# We got a "command complete" message, so put the SCB pointer
# into the Queue Out, 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 0x80. If RETURN_1 is set to 0x80 the sequencer imediately
+# jumps to main loop where it will run down the waiting SCB list.
+# 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 SCBARRAY+15,0xff jnz resid
+ test SCBARRAY+16,0xff jnz resid
+ test SCBARRAY+17,0xff jnz resid
+
+check_status:
+ test SCBARRAY+14,0xff jz status_ok # 0 Status?
+ mvi INTSTAT,BAD_STATUS # let driver know
+ test RETURN_1, 0x80 jz status_ok
+ jmp p_mesgin_done
+
+status_ok:
+# First, mark this target as free.
+ test SCBARRAY+0,0x20 jnz complete # Tagged command
+ and FUNCTION1,0x70,SCBARRAY+1
+ mov A,FUNCTION1
+ test SCBARRAY+1,0x88 jz clear_a
+ xor ACTIVE_B,A
+ jmp complete
+
+clear_a:
+ xor ACTIVE_A,A
+
+complete:
mov QOUTFIFO,SCBPTR
- mvi INTSTAT,0x2 # CMDCMPLT
+ mvi INTSTAT,CMDCMPLT
+ test SCBARRAY+11,0xff jz start # Immediate message complete
jmp p_mesgin_done
-# Is it an extended message? We only support the synchronous data
-# transfer request message, which will probably be in response to
-# an SDTR message out from us. If it's not an SDTR, reject it -
+# 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, but a ton of instructions), or
+# have the sequencer pause itself when it encounters a non-zero resid
+# (unecessary pause just to flag the command -- yuck, but takes few instructions
+# and since it shouldn't happen that often is good enough for our purposes).
+
+resid:
+ mvi INTSTAT,RESIDUAL
+ jmp check_status
+
+# 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.
#
-# XXX - we should really reject this if we didn't initiate the SDTR
-# negotiation; this may cause problems with unusual devices.
-#
p_mesgin1:
cmp A,1 jne p_mesgin2 # extended message code?
- mvi A call inb_next
- cmp A,3 jne p_mesginN # extended mesg length = 3
- mvi A call inb_next
- cmp A,1 jne p_mesginN # SDTR code
+ mvi ARG_1 call inb_next # extended message length
+ mvi A call inb_next # extended message code
+
+ cmp A,1 je p_mesginSDTR # Syncronous negotiation message
+ cmp A,3 je p_mesginWDTR # Wide negotiation message
+ jmp p_mesginN
+
+p_mesginWDTR:
+ cmp ARG_1,2 jne p_mesginN # extended mesg length = 2
+ mvi A call inb_next # Width of bus
+ mvi INTSTAT,MSG_WDTR # let driver know
+ test RETURN_1,0x80 jz p_mesgin_done# Do we need to send WDTR?
+
+# We didn't initiate the wide negotiation, so we must respond to the request
+ and RETURN_1,0x7f # Clear the SEND_WDTR Flag
+ or FLAGS,ACTIVE_MSG
+ mvi DINDEX,MSG_START+0
+ mvi MSG_START+0 call mk_wdtr # build WDTR message
+ or SINDEX,0x10,SIGSTATE # turn on ATNO
+ call scsisig
+ jmp p_mesgin_done
+p_mesginSDTR:
+ cmp ARG_1,3 jne p_mesginN # extended mesg length = 3
mvi ARG_1 call inb_next # xfer period
- mvi ARG_2 call inb_next # REQ/ACK offset
- mvi INTSTAT,SIGNAL_4 # call driver to convert
-
- call ndx_sdtr # index sync config for target
- mov DINDEX,SINDEX
- mov DINDIR,RETURN_1 # save returned value
-
- not A # turn off "need sdtr" flag
- and NEEDSDTR,A
-
-# Even though the SCSI-2 specification says that a device responding
-# to our SDTR message should honor our parameters for transmitting
-# to us, it doesn't seem to work too well in real life. In particular,
-# a lot of CD-ROM and tape units don't function: try using the SDTR
-# parameters the device sent us for both transmitting and receiving.
-#
- mov SCSIRATE,RETURN_1
+ mvi A call inb_next # REQ/ACK offset
+ mvi INTSTAT,MSG_SDTR # call driver to convert
+
+ test RETURN_1,0xc0 jz p_mesgin_done# Do we need to mk_sdtr or rej?
+ test RETURN_1,0x40 jnz p_mesginN # Requested SDTR too small - rej
+ or FLAGS,ACTIVE_MSG
+ mvi DINDEX, MSG_START+0
+ mvi MSG_START+0 call mk_sdtr
+ or SINDEX,0x10,SIGSTATE # turn on ATNO
+ call scsisig
jmp p_mesgin_done
# Is it a disconnect message? Set a flag in the SCB to remind us
test A,0x78 jnz p_mesginN # !DiscPriv|!LUNTAR|!Reserved
- mov A call findSCB # switch to correct SCB
-
-# If a active message is present after calling findSCB, then either it
-# or the driver is trying to abort the command. Either way, something
-# untoward has happened and we should just leave it alone.
-#
- test MSG_FLAGS,0x80 jnz p_mesgin_done
-
- xor SCBARRAY+0,0x4 # clear disconnect bit in SCB
- mvi RESELECT,0xc0 # make note of IDENTIFY
+ and A,0x07 # lun in lower three bits
+ or SAVED_TCL,A,SELID
+ and SAVED_TCL,0xf7
+ and A,0x08,SBLKCTL # B Channel??
+ or SAVED_TCL,A
+ call inb_last # ACK
+ mov ALLZEROS call findSCB
+setup_SCB:
+ and SCBARRAY+0,0xfb # clear disconnect bit in SCB
+ or FLAGS,IDENTIFY_SEEN # make note of IDENTIFY
call sg_scb2ram # implied restore pointers
# required on reselect
- jmp p_mesgin_done
+ jmp ITloop
+get_tag:
+ mvi A call inb_first
+ cmp A,0x20 jne return # Simple Tag message?
+ mvi A call inb_next
+ call inb_last
+ test A,0xf0 jnz abort_tag # Tag in range?
+ mov SCBPTR,A
+ mov A,SAVED_TCL
+ cmp SCBARRAY+1,A jne abort_tag
+ test SCBARRAY+0,TAG_ENB jz abort_tag
+ ret
+abort_tag:
+ or SINDEX,0x10,SIGSTATE # turn on ATNO
+ call scsisig
+ mvi INTSTAT,ABORT_TAG # let driver know
+ mvi 0xd call mk_mesg # ABORT TAG message
+ ret
-# Message reject? If we have an outstanding SDTR negotiation, assume
-# that it's a response from the target selecting asynchronous transfer,
-# otherwise just ignore it since we have no clue what it pertains to.
-#
-# XXX - I don't have a device that responds this way. Does this code
-# actually work?
+# 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.
#
p_mesgin6:
cmp A,7 jne p_mesgin7 # message reject code?
- and FUNCTION1,0x70,SCSIID # outstanding SDTR message?
- mov A,FUNCTION1
- test NEEDSDTR,A jz p_mesgin_done # no - ignore rejection
-
- call ndx_sdtr # note use of asynch xfer
- mov DINDEX,SINDEX
- clr DINDIR
-
- not A # turn off "active sdtr" flag
- and NEEDSDTR,A
-
- clr SCSIRATE # select asynch xfer
+ mvi INTSTAT, MSG_REJECT
jmp p_mesgin_done
# [ ADD MORE MESSAGE HANDLING HERE ]
p_mesginN:
or SINDEX,0x10,SIGSTATE # turn on ATNO
call scsisig
- mvi INTSTAT,SIGNAL_1 # let driver know
+ mvi INTSTAT,SEND_REJECT # let driver know
mvi 0x7 call mk_mesg # MESSAGE REJECT message
call inb_last # ack & turn auto PIO back on
jmp ITloop
+
# 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,0x40 # CLRATNO
clr SIGSTATE
+
+# if this is an immediate command, perform a psuedo command complete to
+# notify the driver.
+ test SCBARRAY+11,0xff jz status_ok
jmp start
-# Bcopy: number of bytes to transfer should be in A, DINDEX should
-# contain the destination address, and SINDEX should contain the
-# source address. All input parameters are trashed on return.
-#
-bcopy:
+# Instead of a generic bcopy routine that requires an argument, we unroll
+# the two cases that are actually used, and call them explicitly. This
+# not only reduces the overhead of doing a bcopy by 2/3rds, but ends up
+# saving space in the program since you don't have to put the argument
+# into the accumulator before the call. Both functions expect DINDEX to
+# contain the destination address and SINDEX to contain the source
+# address.
+bcopy_3:
mov DINDIR,SINDIR
- dec A
- cmp ALLZEROS,A jne bcopy
- ret
+ mov DINDIR,SINDIR
+ mov DINDIR,SINDIR ret
+
+bcopy_4:
+ mov DINDIR,SINDIR
+ mov DINDIR,SINDIR
+ mov DINDIR,SINDIR
+ mov DINDIR,SINDIR ret
+
+bcopy_3_dfdat:
+ mov DINDIR,DFDAT
+ mov DINDIR,DFDAT
+ mov DINDIR,DFDAT ret
+
+bcopy_4_dfdat:
+ mov DINDIR,DFDAT
+ mov DINDIR,DFDAT
+ mov DINDIR,DFDAT
+ mov DINDIR,DFDAT ret
# 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,0x40 # PAUSEDIS
- test MSG_FLAGS,0x80 jnz mk_mesg1 # active message?
+ mvi SEQCTL,0x50 # PAUSEDIS|FASTMODE
+ test FLAGS,ACTIVE_MSG jnz mk_mesg1 # active message?
- mvi MSG_FLAGS,0x80 # if not, there is now
+ or FLAGS,ACTIVE_MSG # if not, there is now
mvi MSG_LEN,1 # length = 1
mov MSG_START+0,SINDEX # 1-byte message
mk_mesg1:
- clr SEQCTL # !PAUSEDIS
- ret
-
-# Input byte in Automatic PIO mode. The address to store the byte
-# in should be in SINDEX. DINDEX will be used by this routine.
-#
-inb:
- test SSTAT0,0x2 jz inb # SPIORDY
- mov DINDEX,SINDEX
- call one_stcnt # xfer one byte
- mov DINDIR,SCSIDATL
-inb1:
- test SSTAT0,0x4 jz inb1 # SDONE - wait to "finish"
- ret
+ mvi SEQCTL,0x10 ret # !PAUSEDIS|FASTMODE
# Carefully read data in Automatic PIO mode. I first tried this using
# Manual PIO mode, but it gave me continual underrun errors, probably
# use the same calling convention as inb.
#
inb_first:
+ clr STCNT+2
+ clr STCNT+1
mov DINDEX,SINDEX
mov DINDIR,SCSIBUSL ret # read byte directly from bus
inb_next:
mov DINDEX,SINDEX # save SINDEX
- call one_stcnt # xfer one byte
+ mvi STCNT+0,1 # xfer one byte
mov NONE,SCSIDATL # dummy read from latch to ACK
inb_next1:
test SSTAT0,0x4 jz inb_next1 # SDONE
mov DINDIR,SCSIBUSL ret # read byte directly from bus
inb_last:
- call one_stcnt # ACK with dummy read
+ mvi STCNT+0,1 # ACK with dummy read
mov NONE,SCSIDATL
inb_last1:
test SSTAT0,0x4 jz inb_last1 # wait for completion
ret
-# Output byte in Automatic PIO mode. The byte to output should be
-# in SINDEX. If DROPATN's high bit is set, then ATN will be dropped
-# before the byte is output.
-#
-outb:
- test SSTAT0,0x2 jz outb # SPIORDY
- call one_stcnt # xfer one byte
-
- test DROPATN,0x80 jz outb1
- mvi CLRSINT1,0x40 # CLRATNO
- clr DROPATN
-outb1:
- mov SCSIDATL,SINDEX
-outb2:
- test SSTAT0,0x4 jz outb2 # SDONE
- ret
-
-# Write the value "1" into the STCNT registers, for Automatic PIO
-# transfers.
-#
-one_stcnt:
- clr STCNT+2
- clr STCNT+1
- mvi STCNT+0,1 ret
-
# 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
dma6:
test DFCNTRL,0x38 jnz dma6 # SCSIENACK|SDMAENACK|HDMAENACK
- mvi A,3
mvi DINDEX,SCBARRAY+15
- mvi STCNT call bcopy
+ mvi STCNT call bcopy_3
ret
+dma_finish:
+ test DFSTATUS,0x8 jz dma_finish # HDONE
+
+ clr DFCNTRL # disable DMA
+dma_finish2:
+ test DFCNTRL,0x8 jnz dma_finish2 # 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:
- clr SBLKCTL # channel A, !wide
- and SCSIID,0xf0,SINDEX # target ID
- and A,0x7,SCSICONF # SCSI_ID_A[210]
- or SCSIID,A
-
-# Esundry initialization.
-#
- clr DROPATN
- clr SIGSTATE
+initialize_scsiid:
+ and SINDEX,0xf0 # Get target ID
+ and A,0x0f,SCSIID
+ or SINDEX,A
+ mov SCSIID,SINDEX ret
-# Turn on Automatic PIO mode now, before we expect to see an REQ
+initialize_for_target:
+# Turn on Automatic PIO mode now, before we expect to see a REQ
# from the target. It shouldn't hurt anything to leave it on. 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.
#
-# DFON is a 7870 bit enabling digital filtering of REQ and ACK signals.
-#
+ clr SIGSTATE
+
mvi SXFRCTL0,0x8a # DFON|SPIOEN|CLRCHN
-# Set SCSI bus parity checking and the selection timeout value,
-# and enable the hardware selection timer. Set the SELTO interrupt
-# to signal the driver.
-#
-# STPWEN is 7870-specific, enabling an external termination power source.
-#
- and A,0x38,SCSICONF # PARITY_ENB_A|SEL_TIM_A[10]
- or SXFRCTL1,0x5,A # ENSTIMER|STPWEN
- mvi SIMODE1,0x84 # ENSELTIMO|ENSCSIPERR
-
# Initialize scatter-gather pointers by setting up the working copy
# in scratch RAM.
#
# Initialize SCSIRATE with the appropriate value for this target.
#
- call ndx_sdtr
- mov SCSIRATE,SINDIR
- ret
+ call ndx_dtr
+ mov SCSIRATE,SINDIR ret
# Assert that if we've been reselected, then we've seen an IDENTIFY
# message.
#
assert:
- test RESELECT,0x80 jz assert1 # reselected?
- test RESELECT,0x40 jnz assert1 # seen IDENTIFY?
-
- mvi INTSTAT,SIGNAL_2 # no - cause a kernel panic
+ test FLAGS,RESELECTED jz return # reselected?
+ test FLAGS,IDENTIFY_SEEN jnz return # seen IDENTIFY?
-assert1:
- ret
+ mvi INTSTAT,NO_IDENT ret # no - cause a kernel panic
# Find out if disconnection is ok from the information the BIOS has left
-# us. The target ID should be in the upper four bits of SINDEX; A will
+# us. The tcl from SCBARRAY+1 should be in SINDEX; A will
# contain either 0x40 (disconnection ok) or 0x00 (disconnection not ok)
# on exit.
#
-# This is the only place the target ID is limited to three bits, so we
-# can use the FUNCTION1 register.
+# To allow for wide or twin busses, we check the upper bit of the target ID
+# and the channel ID and look at the appropriate disconnect register.
#
disconnect:
and FUNCTION1,0x70,SINDEX # strip off extra just in case
mov A,FUNCTION1
- test DISC_DSB_A,A jz disconnect1 # bit nonzero if DISabled
+ test SINDEX, 0x88 jz disconnect_a
+ test DISC_DSB_B,A jz disconnect1 # bit nonzero if DISabled
clr A ret
+
+disconnect_a:
+ test DISC_DSB_A,A jz disconnect1 # bit nonzero if DISabled
+ clr A ret
+
disconnect1:
mvi A,0x40 ret
-# Locate the SCB matching the target ID in SELID and the lun in the lower
-# three bits of SINDEX, and switch the SCB to it. Have the kernel print
-# a warning message if it can't be found, and generate an ABORT message
-# to the target.
+# Locate the SCB matching the target ID/channel/lun in SAVED_TCL and switch
+# the SCB to it. Have the kernel print a warning message if it can't be
+# found, and generate an ABORT message to the target. SINDEX should be
+# cleared on call.
#
findSCB:
- and A,0x7,SINDEX # lun in lower three bits
- or A,A,SELID # can I do this?
- and A,0xf7 # only channel A implemented
- mov DINDEX,A # save in DINDEX for later
-
- clr SINDEX
-
-findSCB1:
- mov A,DINDEX # reload A after 1st iteration
+ mov A,SAVED_TCL
mov SCBPTR,SINDEX # switch to new SCB
- cmp SCBARRAY+1,A jne findSCB2 # target ID/channel/lun match?
- test SCBARRAY+0,0x4 jz findSCB2 # should be disconnected
-
+ cmp SCBARRAY+1,A jne findSCB1 # target ID/channel/lun match?
+ test SCBARRAY+0,0x4 jz findSCB1 # should be disconnected
+ test SCBARRAY+0,TAG_ENB jnz get_tag
ret
-findSCB2:
+findSCB1:
inc SINDEX
mov A,SCBCOUNT
- cmp SINDEX,A jne findSCB1
+ cmp SINDEX,A jne findSCB
- mvi INTSTAT,SIGNAL_3 # not found - signal kernel
+ mvi INTSTAT,NO_MATCH # not found - signal kernel
mvi 0x6 call mk_mesg # ABORT message
or SINDEX,0x10,SIGSTATE # assert ATNO
sg_scb2ram:
mov SG_COUNT,SCBARRAY+2
- mvi A,4
mvi DINDEX,SG_NEXT
- mvi SCBARRAY+3 call bcopy
+ mvi SCBARRAY+3 call bcopy_4
mvi SG_NOLOAD,0x80
- test SCBARRAY+0,0x10 jnz sg_scb2ram1 # don't reload s/g?
- clr SG_NOLOAD
-
-sg_scb2ram1:
- ret
+ test SCBARRAY+0,0x10 jnz return # don't reload s/g?
+ clr SG_NOLOAD ret
# Copying RAM values back to SCB, for Save Data Pointers message.
#
sg_ram2scb:
mov SCBARRAY+2,SG_COUNT
- mvi A,4
mvi DINDEX,SCBARRAY+3
- mvi SG_NEXT call bcopy
+ mvi SG_NEXT call bcopy_4
and SCBARRAY+0,0xef,SCBARRAY+0
- test SG_NOLOAD,0x80 jz sg_ram2scb1 # reload s/g?
- or SCBARRAY+0,0x10
-
-sg_ram2scb1:
- ret
+ test SG_NOLOAD,0x80 jz return # reload s/g?
+ or SCBARRAY+0,SG_LOAD ret
# Load a struct scatter if needed and set up the data address and
# length. If the working value of the SG count is nonzero, then
# This, like the above DMA, assumes a little-endian host data storage.
#
sg_load:
- test SG_COUNT,0xff jz sg_load3 # SG being used?
- test SG_NOLOAD,0x80 jnz sg_load3 # don't reload s/g?
+ test SG_COUNT,0xff jz return # SG being used?
+ test SG_NOLOAD,0x80 jnz return # don't reload s/g?
clr HCNT+2
clr HCNT+1
mvi HCNT+0,SG_SIZEOF
- mvi A,4
mvi DINDEX,HADDR
- mvi SG_NEXT call bcopy
+ mvi SG_NEXT call bcopy_4
mvi 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.
#
-sg_load1:
- test DFSTATUS,0x8 jz sg_load1 # HDONE
- clr DFCNTRL # disable DMA
-sg_load2:
- test DFCNTRL,0x8 jnz sg_load2 # HDMAENACK
+ call dma_finish
# Copy data from FIFO into SCB data pointer and data count. This assumes
# that the struct scatterlist has this structure (this and sizeof(struct
# unsigned short length; /* two bytes, little-endian order */
# }
#
- mov SCBARRAY+19,DFDAT # new data address
- mov SCBARRAY+20,DFDAT
- mov SCBARRAY+21,DFDAT
- mov SCBARRAY+22,DFDAT
- mov NONE,DFDAT # throw away four bytes
+# Not in FreeBSD. the scatter list entry is only 8 bytes.
+#
+# struct ahc_dma_seg {
+# physaddr addr; /* four bytes, little-endian order */
+# long len; /* four bytes, little endian order */
+# };
+#
+
+ mvi DINDEX, SCBARRAY+19
+ call bcopy_4_dfdat
+
+# For Linux, we must throw away four bytes since there is a 32bit gap
+# in the middle of a struct scatterlist
+ mov NONE,DFDAT
mov NONE,DFDAT
mov NONE,DFDAT
mov NONE,DFDAT
- mov SCBARRAY+23,DFDAT
- mov SCBARRAY+24,DFDAT
- clr SCBARRAY+25
-
-sg_load3:
+ call bcopy_3_dfdat #Only support 24 bit length.
ret
# Advance the scatter-gather pointers only IF NEEDED. If SG is enabled,
# next time.
#
sg_advance:
- test SG_COUNT,0xff jz sg_advance2 # s/g enabled?
+ test SG_COUNT,0xff jz return # s/g enabled?
test STCNT+0,0xff jnz sg_advance1 # SCSI transfer count nonzero?
test STCNT+1,0xff jnz sg_advance1
add SG_NEXT+0,SG_SIZEOF,SG_NEXT+0
adc SG_NEXT+1,A,SG_NEXT+1
adc SG_NEXT+2,A,SG_NEXT+2
- adc SG_NEXT+3,A,SG_NEXT+3
-
- ret
+ adc SG_NEXT+3,A,SG_NEXT+3 ret
sg_advance1:
- mvi SG_NOLOAD,0x80 # don't reload s/g next time
-sg_advance2:
- ret
+ mvi SG_NOLOAD,0x80 ret # don't reload s/g next time
# Add the array base SYNCNEG 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_sdtr:
+ndx_dtr:
shr A,SCSIID,4
- and A,0x7
+ test SBLKCTL,0x08 jz ndx_dtr_2
+ or A,0x08 # Channel B entries add 8
+ndx_dtr_2:
add SINDEX,SYNCNEG,A
and FUNCTION1,0x70,SCSIID # 3-bit target address decode
mov A,FUNCTION1 ret
-# If we need to negotiate transfer parameters, build the SDTR message
+# 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 negotiat 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 culpret.
#
-mk_sdtr:
- mov DINDEX,SINDEX # save SINDEX
+mk_dtr:
+ test SCBARRAY+0,0xc0 jz return # NEEDWDTR|NEEDSDTR
+ test SCBARRAY+0,NEEDWDTR jnz mk_wdtr_16bit
+ or FLAGS, MAX_OFFSET # Force an offset of 15 or 8 if WIDE
- call ndx_sdtr
- test NEEDSDTR,A jnz mk_sdtr1 # do we need negotiation?
- ret
-
-mk_sdtr1:
+mk_sdtr:
mvi DINDIR,1 # extended message
mvi DINDIR,3 # extended message length = 3
mvi DINDIR,1 # SDTR code
- mvi DINDIR,25 # REQ/ACK transfer period
- mvi DINDIR,15 # REQ/ACK offset
-
- add MSG_LEN,-MSG_START+0,DINDEX # update message length
- ret
+ call sdtr_to_rate
+ mov DINDIR,RETURN_1 # REQ/ACK transfer period
+ test FLAGS, MAX_OFFSET jnz mk_sdtr_max_offset
+ and DINDIR,0x0f,SINDIR # Sync Offset
+
+mk_sdtr_done:
+ add MSG_LEN,-MSG_START+0,DINDEX ret # update message length
+
+mk_sdtr_max_offset:
+# We're initiating sync negotiation, so request the max offset we can (15 or 8)
+ xor FLAGS, MAX_OFFSET
+ test SCSIRATE, 0x80 jnz wmax_offset # Talking to a WIDE device?
+ mvi DINDIR, MAX_OFFSET_8BIT
+ jmp mk_sdtr_done
+
+wmax_offset:
+ mvi DINDIR, MAX_OFFSET_WIDE
+ 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,-MSG_START+0,DINDEX ret # update message length
+
# Set SCSI bus control signal state. This also saves the last-written
# value into a location where the higher-level driver can read it - if
# it has to send an ABORT or RESET message, then it needs to know this
scsisig:
mov SIGSTATE,SINDEX
mov SCSISIGO,SINDEX ret
+
+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,0x18
+ dec A
+ jmp sdtr_to_rate_loop
+sdtr_to_rate_done:
+ shr RETURN_1,0x2
+ add RETURN_1,0x18 ret
+
+return:
+ ret
--- /dev/null
+/*+M*************************************************************************
+ * Adaptec AIC7770/AIC7870 sequencer code assembler.
+ *
+ * Copyright (c) 1994 John Aycock
+ * The University of Calgary Department of Computer Science.
+ * 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.
+ * 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. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * This product includes software developed by the University of Calgary
+ * Department of Computer Science and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * 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.
+ *
+ * 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 char id[] = "$Id: aic7xxx_asm.c,v 1.8 1995/05/25 06:25:36 root Exp $";
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#define MEMORY 448
+#define MAXLINE 1024
+#define MAXTOKEN 32
+#define ADOTOUT "a.out"
+#define NOVALUE -1
+
+/*
+ * 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;
+FILE *ifp, *ofp;
+unsigned char M[MEMORY][4];
+
+void
+error(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), ifp)) {
+
+ 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 {
+ 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;
+ 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(void)
+{
+ 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(ofp, "#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(ofp);
+
+ if (debug)
+ output(stderr);
+}
+
+int
+main(int argc, char **argv)
+{
+ int c;
+
+ 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':
+ ofp = fopen(optarg, "w");
+ if (!ofp) {
+ 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];
+
+ ifp = fopen(filename, "r");
+ if (!ifp) {
+ perror(filename);
+ exit(EXIT_FAILURE);
+ }
+
+ if (!ofp) {
+ ofp = fopen(ADOTOUT, "w");
+ if (!ofp) {
+ perror(ADOTOUT);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ assemble();
+ exit(EXIT_SUCCESS);
+}
#include <linux/ioport.h>
#include <linux/delay.h>
#include <linux/config.h>
-
+#include <linux/proc_fs.h>
#include <asm/io.h>
#include <asm/system.h>
#include <asm/dma.h>
int buslogic_reset(Scsi_Cmnd *);
int buslogic_biosparam(Disk *, int, int *);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
#define BUSLOGIC { NULL, NULL, \
+ generic_proc_info, \
+ "buslogic", \
+ PROC_SCSI_BUSLOGIC, \
"BusLogic", \
buslogic_detect, \
0, /* no release func */ \
#include "scsi.h"
#include "hosts.h"
-#define CONST_COMMAND 0x01
-#define CONST_STATUS 0x02
-#define CONST_SENSE 0x04
-#define CONST_XSENSE 0x08
-#define CONST_CMND 0x10
-#define CONST_MSG 0x20
+#define CONST_COMMAND 0x01
+#define CONST_STATUS 0x02
+#define CONST_SENSE 0x04
+#define CONST_XSENSE 0x08
+#define CONST_CMND 0x10
+#define CONST_MSG 0x20
static const char unknown[] = "UNKNOWN";
/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal",
/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position",
/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Defect Data",
-/* 38-3c */ unknown, "Compare","Copy Verify", "Write Buffer", "Read Buffer",
-/* 3d-39 */ unknown, "Read Long", unknown,
+/* 38-3c */ "Medium Scan", "Compare","Copy Verify", "Write Buffer", "Read Buffer",
+/* 3d-3f */ "Update Block", "Read Long", "Write Long",
};
static const char *group_2_commands[] = {
-/* 40-41 */ "Change Definition", unknown,
-/* 42-48 */ unknown, unknown, unknown, unknown, unknown, unknown, unknown,
-/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown,
+/* 40-41 */ "Change Definition", "Write Same",
+/* 42-48 */ unknown, unknown, unknown, unknown, unknown, unknown, unknown,
+/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown, unknown,
/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)",
/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown,
/* 5c-5f */ unknown, unknown, unknown,
#define group(opcode) (((opcode) >> 5) & 7)
#define RESERVED_GROUP 0
-#define VENDOR_GROUP 1
-#define NOTEXT_GROUP 2
+#define VENDOR_GROUP 1
+#define NOTEXT_GROUP 2
static const char **commands[] = {
-group_0_commands, group_1_commands, group_2_commands,
-(const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP,
-(const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP,
-(const char **) VENDOR_GROUP};
+ group_0_commands, group_1_commands, group_2_commands,
+ (const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP,
+ (const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP,
+ (const char **) VENDOR_GROUP
+};
static const char reserved[] = "RESERVED";
static const char vendor[] = "VENDOR SPECIFIC";
static void print_opcode(int opcode) {
- const char **table = commands[ group(opcode) ];
- switch ((unsigned long) table) {
- case RESERVED_GROUP:
- printk("%s(0x%02x) ", reserved, opcode);
- break;
- case NOTEXT_GROUP:
- printk("%s(0x%02x) ", unknown, opcode);
- break;
- case VENDOR_GROUP:
- printk("%s(0x%02x) ", vendor, opcode);
- break;
- default:
- printk("%s ",table[opcode & 0x1f]);
- }
+ const char **table = commands[ group(opcode) ];
+ switch ((unsigned long) table) {
+ case RESERVED_GROUP:
+ printk("%s(0x%02x) ", reserved, opcode);
+ break;
+ case NOTEXT_GROUP:
+ printk("%s(0x%02x) ", unknown, opcode);
+ break;
+ case VENDOR_GROUP:
+ printk("%s(0x%02x) ", vendor, opcode);
+ break;
+ default:
+ printk("%s ",table[opcode & 0x1f]);
+ }
}
#else /* CONST & CONST_COMMAND */
static void print_opcode(int opcode) {
- printk("0x%02x ", opcode);
+ printk("0x%02x ", opcode);
}
#endif
void print_command (unsigned char *command) {
- int i,s;
- print_opcode(command[0]);
- for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- printk("%02x ", command[i]);
- printk("\n");
+ int i,s;
+ print_opcode(command[0]);
+ for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
+ printk("%02x ", command[i]);
+ printk("\n");
}
#if (CONSTANTS & CONST_STATUS)
#endif
void print_status (int status) {
- status = (status >> 1) & 0xf;
+ status = (status >> 1) & 0xf;
#if (CONSTANTS & CONST_STATUS)
- printk("%s ",statuses[status]);
+ printk("%s ",statuses[status]);
#else
- printk("0x%0x ", status);
+ printk("0x%0x ", status);
#endif
}
#define C 0x200 /* COMMUNICATION DEVICE */
struct error_info{
- unsigned char code1, code2;
- unsigned short int devices;
- char * text;
+ unsigned char code1, code2;
+ unsigned short int devices;
+ char * text;
};
struct error_info2{
- unsigned char code1, code2_min, code2_max;
- unsigned short int devices;
- char * text;
+ unsigned char code1, code2_min, code2_max;
+ unsigned short int devices;
+ char * text;
};
static struct error_info2 additional2[] =
#if (CONSTANTS & CONST_SENSE)
static char *snstext[] = {
- "None","Recovered Error","Not Ready","Medium Error","Hardware Error",
- "Illegal Request","Unit Attention","Data Protect","Blank Check",
- "Key=9","Copy Aborted","Aborted Command","End-Of-Medium",
- "Volume Overflow", "Miscompare", "Key=15"};
+ "None","Recovered Error","Not Ready","Medium Error","Hardware Error",
+ "Illegal Request","Unit Attention","Data Protect","Blank Check",
+ "Key=9","Copy Aborted","Aborted Command","End-Of-Medium",
+ "Volume Overflow", "Miscompare", "Key=15"};
#endif
/* Print sense information */
void print_sense(char * devclass, Scsi_Cmnd * SCpnt)
{
- int i, s;
- int sense_class, valid, code;
- unsigned char * sense_buffer = SCpnt->sense_buffer;
- char * error = NULL;
- int dev = SCpnt->request.dev;
-
- sense_class = (sense_buffer[0] >> 4) & 0x07;
- code = sense_buffer[0] & 0xf;
- valid = sense_buffer[0] & 0x80;
-
- if (sense_class == 7) {
- s = sense_buffer[7] + 8;
- if(s > sizeof(SCpnt->sense_buffer)) s = sizeof(SCpnt->sense_buffer);
-
- if (!valid)
+ int i, s;
+ int sense_class, valid, code;
+ unsigned char * sense_buffer = SCpnt->sense_buffer;
+ char * error = NULL;
+ int dev = SCpnt->request.dev;
+
+ sense_class = (sense_buffer[0] >> 4) & 0x07;
+ code = sense_buffer[0] & 0xf;
+ valid = sense_buffer[0] & 0x80;
+
+ if (sense_class == 7) {
+ s = sense_buffer[7] + 8;
+ if(s > sizeof(SCpnt->sense_buffer)) s = sizeof(SCpnt->sense_buffer);
+
+ if (!valid)
printk("extra data not valid ");
-
- if (sense_buffer[2] & 0x80) printk( "FMK ");
- if (sense_buffer[2] & 0x40) printk( "EOM ");
- if (sense_buffer[2] & 0x20) printk( "ILI ");
-
- switch (code) {
- case 0x0:
+
+ if (sense_buffer[2] & 0x80) printk( "FMK ");
+ if (sense_buffer[2] & 0x40) printk( "EOM ");
+ if (sense_buffer[2] & 0x20) printk( "ILI ");
+
+ switch (code) {
+ case 0x0:
error = "Current";
break;
- case 0x1:
+ case 0x1:
error = "Deferred";
break;
- default:
+ default:
error = "Invalid";
- }
-
- printk("%s error ", error);
-
+ }
+
+ printk("%s error ", error);
+
#if (CONSTANTS & CONST_SENSE)
- printk( "%s%x: sense key %s\n", devclass, dev, snstext[sense_buffer[2] & 0x0f]);
+ printk( "%s%x: sense key %s\n", devclass, dev, snstext[sense_buffer[2] & 0x0f]);
#else
- printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]);
+ printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]);
#endif
/* Check to see if additional sense information is available */
#if (CONSTANTS & CONST_XSENSE)
for(i=0; additional[i].text; i++)
- if(additional[i].code1 == sense_buffer[12] &&
- additional[i].code2 == sense_buffer[13])
- printk("Additional sense indicates %s\n", additional[i].text);
+ if(additional[i].code1 == sense_buffer[12] &&
+ additional[i].code2 == sense_buffer[13])
+ printk("Additional sense indicates %s\n", additional[i].text);
for(i=0; additional2[i].text; i++)
- if(additional2[i].code1 == sense_buffer[12] &&
- additional2[i].code2_min >= sense_buffer[13] &&
- additional2[i].code2_max <= sense_buffer[13]) {
- printk("Additional sense indicates ");
- printk(additional2[i].text, sense_buffer[13]);
- printk("\n");
- };
+ if(additional2[i].code1 == sense_buffer[12] &&
+ additional2[i].code2_min >= sense_buffer[13] &&
+ additional2[i].code2_max <= sense_buffer[13]) {
+ printk("Additional sense indicates ");
+ printk(additional2[i].text, sense_buffer[13]);
+ printk("\n");
+ };
#else
printk("ASC=%2x ASCQ=%2x\n", sense_buffer[12], sense_buffer[13]);
#endif
- } else {
-
+ } else {
+
#if (CONSTANTS & CONST_SENSE)
- if (sense_buffer[0] < 15)
+ if (sense_buffer[0] < 15)
printk("%s%x: old sense key %s\n", devclass, dev, snstext[sense_buffer[0] & 0x0f]);
- else
+ else
#endif
printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]);
-
- printk("Non-extended sense class %d code 0x%0x ", sense_class, code);
- s = 4;
- }
- done:
+ printk("Non-extended sense class %d code 0x%0x ", sense_class, code);
+ s = 4;
+ }
+
+ done:
#if !(CONSTANTS & CONST_SENSE)
- printk("Raw sense data:");
- for (i = 0; i < s; ++i)
- printk("0x%02x ", sense_buffer[i]);
- printk("\n");
+ printk("Raw sense data:");
+ for (i = 0; i < s; ++i)
+ printk("0x%02x ", sense_buffer[i]);
+ printk("\n");
#endif
- return;
+ return;
}
#if (CONSTANTS & CONST_MSG)
switch (msg[2]) {
case EXTENDED_MODIFY_DATA_POINTER:
printk("pointer = %d", (int) (msg[3] << 24) | (msg[4] << 16) |
- (msg[5] << 8) | msg[6]);
+ (msg[5] << 8) | msg[6]);
break;
case EXTENDED_SDTR:
printk("period = %d ns, offset = %d", (int) msg[3] * 4, (int)
- msg[4]);
+ msg[4]);
break;
case EXTENDED_WDTR:
printk("width = 2^%d bytes", msg[3]);
for (i = 0; i < len; ++i)
printk("%02x ", msg[i]);
#endif
- /* Identify */
+ /* Identify */
} else if (msg[0] & 0x80) {
#if (CONSTANTS & CONST_MSG)
printk("Identify disconnect %sallowed %s %d ",
- (msg[0] & 0x40) ? "" : "not ",
- (msg[0] & 0x20) ? "target routine" : "lun",
- msg[0] & 0x7);
+ (msg[0] & 0x40) ? "" : "not ",
+ (msg[0] & 0x20) ? "target routine" : "lun",
+ msg[0] & 0x7);
#else
- printk("%02x ", msg[0]);
+ printk("%02x ", msg[0]);
#endif
- len = 1;
- /* Normal One byte */
+ len = 1;
+ /* Normal One byte */
} else if (msg[0] < 0x1f) {
#if (CONSTANTS & CONST_MSG)
if (msg[0] < NO_ONE_BYTE_MSGS)
printk("%02x ", msg[0]);
#endif
len = 1;
- /* Two byte */
+ /* Two byte */
} else if (msg[0] <= 0x2f) {
#if (CONSTANTS & CONST_MSG)
if ((msg[0] - 0x20) < NO_TWO_BYTE_MSGS)
printk("%s %02x ", two_byte_msgs[msg[0] - 0x20],
- msg[1]);
+ msg[1]);
else
printk("reserved two byte (%02x %02x) ",
- msg[0], msg[1]);
+ msg[0], msg[1]);
#else
printk("%02x %02x", msg[0], msg[1]);
#endif
#if (CONSTANTS & CONST_MSG)
printk(reserved);
#else
- printk("%02x ", msg[0]);
+ printk("%02x ", msg[0]);
#endif
return len;
}
void print_Scsi_Cmnd (Scsi_Cmnd *cmd) {
printk("scsi%d : destination target %d, lun %d\n",
- cmd->host->host_no,
- cmd->target,
- cmd->lun);
+ cmd->host->host_no,
+ cmd->target,
+ cmd->lun);
printk(" command = ");
print_command (cmd->cmnd);
}
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
ulong data_len; /* Number of valid bytes after this field */
ulong sign; /* ASCII "EATA" signature */
unchar :4, /* unused low nibble */
- version:4; /* EATA version, should be 0x1 */
+ version:4; /* EATA version, should be 0x1 */
unchar ocsena:1, /* Overlap Command Support Enabled */
- tarsup:1, /* Target Mode Supported */
- :2,
- dmasup:1, /* DMA Supported */
- drqvld:1, /* DRQ Index (DRQX) is valid */
- ata:1, /* This is an ATA device */
- haaval:1; /* Host Adapter Address Valid */
+ tarsup:1, /* Target Mode Supported */
+ :2,
+ dmasup:1, /* DMA Supported */
+ drqvld:1, /* DRQ Index (DRQX) is valid */
+ ata:1, /* This is an ATA device */
+ haaval:1; /* Host Adapter Address Valid */
ushort cp_pad_len; /* Number of pad bytes after cp_len */
unchar host_addr[3]; /* Host Adapter SCSI ID for channels 2, 1, 0 */
unchar reserved;
ushort unused;
ushort scatt_size; /* Max number of entries in scatter/gather table */
unchar irq:4, /* Interrupt Request assigned to this controller */
- irq_tr:1, /* 0 for edge triggered, 1 for level triggered */
- second:1, /* 1 if this is a secondary (not primary) controller */
- drqx:2; /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
+ irq_tr:1, /* 0 for edge triggered, 1 for level triggered */
+ second:1, /* 1 if this is a secondary (not primary) controller */
+ drqx:2; /* DRQ Index (0=DMA0, 1=DMA7, 2=DMA6, 3=DMA5) */
unchar sync; /* 1 if scsi target id 7...0 is running sync scsi */
/* Structure extension defined in EATA 2.0B */
unchar isaena:1, /* ISA i/o addressing is disabled/enabled */
- forcaddr:1, /* Port address has been forced */
- :6;
+ forcaddr:1, /* Port address has been forced */
+ :6;
unchar max_id:5, /* Max number of SCSI target IDs */
- max_chan:3; /* Max SCSI channel number on this board */
+ max_chan:3; /* Max SCSI channel number on this board */
ushort ipad[249];
};
struct eata_config {
ushort len; /* Number of bytes following this field */
unchar edis:1, /* Disable EATA interface after config command */
- ocena:1, /* Overlapped Commands Enabled */
- mdpena:1, /* Transfer all Modified Data Pointer Messages */
- tarena:1, /* Target Mode Enabled for this controller */
- :4;
+ ocena:1, /* Overlapped Commands Enabled */
+ mdpena:1, /* Transfer all Modified Data Pointer Messages */
+ tarena:1, /* Target Mode Enabled for this controller */
+ :4;
unchar cpad[511];
};
/* Returned status packet structure */
struct mssp {
unchar adapter_status:7, /* State related to current command */
- eoc:1; /* End Of Command (1 = command completed) */
+ eoc:1; /* End Of Command (1 = command completed) */
unchar target_status; /* SCSI status received after data transfer */
unchar unused[2];
ulong inv_res_len; /* Number of bytes not transferred */
/* MailBox SCSI Command Packet */
struct mscp {
unchar sreset:1, /* SCSI Bus Reset Signal should be asserted */
- init:1, /* Re-initialize controller and self test */
- reqsen:1, /* Transfer Request Sense Data to addr using DMA */
- sg:1, /* Use Scatter/Gather */
- :1,
- interp:1, /* The controller interprets cp, not the target */
- dout:1, /* Direction of Transfer is Out (Host to Target) */
- din:1; /* Direction of Transfer is In (Target to Host) */
+ init:1, /* Re-initialize controller and self test */
+ reqsen:1, /* Transfer Request Sense Data to addr using DMA */
+ sg:1, /* Use Scatter/Gather */
+ :1,
+ interp:1, /* The controller interprets cp, not the target */
+ dout:1, /* Direction of Transfer is Out (Host to Target) */
+ din:1; /* Direction of Transfer is In (Target to Host) */
unchar sense_len; /* Request Sense Length */
unchar unused[4];
unchar phsunit:1, /* Send to Target Physical Unit (bypass RAID) */
- notused:7;
+ notused:7;
unchar target; /* SCSI Target ID */
unchar lun:3, /* LUN */
- :2,
- luntar:1, /* This cp is for Target (not LUN) */
- dispri:1, /* Disconnect Privilege granted */
- one:1; /* 1 */
+ :2,
+ luntar:1, /* This cp is for Target (not LUN) */
+ dispri:1, /* Disconnect Privilege granted */
+ one:1; /* 1 */
unchar mess[3]; /* Massage to/from Target */
unchar cdb[12]; /* Command Descriptor Block */
ulong data_len; /* If sg=0 Data Length, if sg=1 sglist length */
for (p = start; p <= end; p++) {
while (!(inb(iobase + REG_STATUS) & DRQ_ASSERTED))
- if (--loop == 0) return TRUE;
+ if (--loop == 0) return TRUE;
loop = MAXLOOP;
*p = inw(iobase);
}
static inline int port_detect(ushort *port_base, unsigned int j,
- Scsi_Host_Template * tpnt) {
+ Scsi_Host_Template * tpnt) {
unsigned char irq, dma_channel, subversion;
unsigned char protocol_rev;
struct eata_info info;
if(check_region(*port_base, REGION_SIZE)) {
printk("%s: address 0x%03x in use, skipping probe.\n",
- name, *port_base);
+ name, *port_base);
return FALSE;
}
if (ntohl(info.data_len) < EATA_2_0A_SIZE) {
printk("%s: config structure size (%ld bytes) too short, detaching.\n",
- name, ntohl(info.data_len));
+ name, ntohl(info.data_len));
return FALSE;
}
else if (ntohl(info.data_len) == EATA_2_0A_SIZE)
if (*port_base & EISA_RANGE) {
if (!info.haaval || info.ata || info.drqvld) {
- printk("%s: unusable EISA board found (%d%d%d), detaching.\n",
- name, info.haaval, info.ata, info.drqvld);
- return FALSE;
- }
+ printk("%s: unusable EISA board found (%d%d%d), detaching.\n",
+ name, info.haaval, info.ata, info.drqvld);
+ return FALSE;
+ }
subversion = ESA;
dma_channel = NO_DMA;
else {
if (!info.haaval || info.ata || !info.drqvld) {
- printk("%s: unusable ISA board found (%d%d%d), detaching.\n",
- name, info.haaval, info.ata, info.drqvld);
- return FALSE;
- }
+ printk("%s: unusable ISA board found (%d%d%d), detaching.\n",
+ name, info.haaval, info.ata, info.drqvld);
+ return FALSE;
+ }
subversion = ISA;
dma_channel = dma_channel_table[3 - info.drqx];
if (subversion == ESA && !info.irq_tr)
printk("%s: warning, LEVEL triggering is suggested for IRQ %u.\n",
- name, irq);
+ name, irq);
if (info.second)
board_status = "Sec.";
if (subversion == ISA && request_dma(dma_channel, driver_name)) {
printk("%s: unable to allocate DMA channel %u, detaching.\n",
- name, dma_channel);
+ name, dma_channel);
free_irq(irq);
return FALSE;
}
strcpy(BN(j), name);
printk("%s: 2.0%c, %s, ID %d, PORT 0x%03x, IRQ %u, DMA %u, SG %d, "\
- "Mbox %d, CmdLun %d.\n", BN(j), HD(j)->protocol_rev, board_status,
- sh[j]->this_id, sh[j]->io_port, sh[j]->irq, sh[j]->dma_channel,
- sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun);
+ "Mbox %d, CmdLun %d.\n", BN(j), HD(j)->protocol_rev, board_status,
+ sh[j]->this_id, sh[j]->io_port, sh[j]->irq, sh[j]->dma_channel,
+ sh[j]->sg_tablesize, sh[j]->can_queue, sh[j]->cmd_per_lun);
/* DPT PM2012 does not allow to detect sg_tablesize correctly */
if (sh[j]->sg_tablesize > MAX_SGLIST || sh[j]->sg_tablesize < 2) {
#if defined (DEBUG_DETECT)
if (protocol_rev != 'A')
printk("%s: EATA 2.0%c, isaena %u, forcaddr %u, max_id %u,"\
- " max_chan %u.\n", name, protocol_rev, info.isaena,
- info.forcaddr, info.max_id, info.max_chan);
+ " max_chan %u.\n", name, protocol_rev, info.isaena,
+ info.forcaddr, info.max_id, info.max_chan);
printk("%s: Version 0x%x, SYNC 0x%x, infol %ld, cpl %ld spl %ld.\n",
- name, info.version, info.sync, ntohl(info.data_len),
- ntohl(info.cp_len), ntohl(info.sp_len));
+ name, info.version, info.sync, ntohl(info.data_len),
+ ntohl(info.cp_len), ntohl(info.sp_len));
#endif
return TRUE;
if (i >= sh[j]->can_queue) i = 0;
if (HD(j)->cp_stat[i] == FREE) {
- HD(j)->last_cp_used = i;
- break;
- }
+ HD(j)->last_cp_used = i;
+ break;
+ }
}
if (k == sh[j]->can_queue) {
printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
if (HD(j)->in_reset)
- printk("%s: qcomm, already in reset.\n", BN(j));
+ printk("%s: qcomm, already in reset.\n", BN(j));
else if (eata2x_reset(SCpnt) == SCSI_RESET_SUCCESS)
- panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
+ panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
SCpnt->result = DID_BUS_BUSY << 16;
SCpnt->host_scribble = NULL;
SCpnt->host_scribble = (unsigned char *) &cpp->index;
if (do_trace) printk("%s: qcomm, mbox %d, target %d, pid %ld.\n",
- BN(j), i, SCpnt->target, SCpnt->pid);
+ BN(j), i, SCpnt->target, SCpnt->pid);
for (k = 0; k < ARRAY_SIZE(data_out_cmds); k++)
if (SCpnt->cmnd[0] == data_out_cmds[k]) {
- cpp->dout = TRUE;
- break;
- }
+ cpp->dout = TRUE;
+ break;
+ }
cpp->din = !cpp->dout;
cpp->reqsen = TRUE;
SCpnt->result = DID_ERROR << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d, pid %ld, adapter busy, DID_ERROR, done.\n",
- BN(j), SCpnt->target, SCpnt->pid);
+ BN(j), SCpnt->target, SCpnt->pid);
restore_flags(flags);
done(SCpnt);
return 0;
if (SCarg->host_scribble == NULL) {
printk("%s: abort, target %d, pid %ld inactive.\n",
- BN(j), SCarg->target, SCarg->pid);
+ BN(j), SCarg->target, SCarg->pid);
return SCSI_ABORT_NOT_RUNNING;
}
i = *(unsigned int *)SCarg->host_scribble;
printk("%s: abort, mbox %d, target %d, pid %ld.\n",
- BN(j), i, SCarg->target, SCarg->pid);
+ BN(j), i, SCarg->target, SCarg->pid);
if (i >= sh[j]->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
printk("%s: abort, mbox %d is in use.\n", BN(j), i);
if (SCarg != HD(j)->cp[i].SCpnt)
- panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
- BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+ panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+ BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
restore_flags(flags);
return SCSI_ABORT_SNOOZE;
cli();
j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
printk("%s: reset, enter, target %d, pid %ld.\n",
- BN(j), SCarg->target, SCarg->pid);
+ BN(j), SCarg->target, SCarg->pid);
if (SCarg->host_scribble == NULL)
printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
if (HD(j)->cp_stat[i] == FREE) continue;
if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
- continue;
- }
+ HD(j)->cp_stat[i] = FREE;
+ printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+ continue;
+ }
SCpnt = HD(j)->cp[i].SCpnt;
HD(j)->cp_stat[i] = IN_RESET;
printk("%s: reset, mbox %d in reset, pid %ld.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->pid);
if (SCpnt == NULL)
- panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+ panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
if (SCpnt->host_scribble == NULL)
- panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+ panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+ panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
if (SCpnt->scsi_done == NULL)
- panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+ panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
if (SCpnt == SCarg) arg_done = TRUE;
}
HD(j)->cp_stat[i] = LOCKED;
printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->pid);
restore_flags(flags);
SCpnt->scsi_done(SCpnt);
cli();
}
if (do_trace) printk("%s: ihdlr, enter, irq %d, calls %d.\n",
- driver_name, irq, calls[irq]);
+ driver_name, irq, calls[irq]);
/* Service all the boards configured on this irq */
for (j = 0; sh[j] != NULL; j++) {
/* Loop until all interrupts for a board are serviced */
while (inb(sh[j]->io_port + REG_AUX_STATUS) & IRQ_ASSERTED) {
- total_loops++;
- loops++;
+ total_loops++;
+ loops++;
- if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
- BN(j), HD(j)->iocount);
+ if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
+ BN(j), HD(j)->iocount);
- /* Read the status register to clear the interrupt indication */
- inb(sh[j]->io_port + REG_STATUS);
+ /* Read the status register to clear the interrupt indication */
+ inb(sh[j]->io_port + REG_STATUS);
- /* Service all mailboxes of this board */
- for (i = 0; i < sh[j]->can_queue; i++) {
- spp = &HD(j)->sp[i];
+ /* Service all mailboxes of this board */
+ for (i = 0; i < sh[j]->can_queue; i++) {
+ spp = &HD(j)->sp[i];
- /* Check if this mailbox has completed the operation */
- if (spp->eoc == FALSE) continue;
+ /* Check if this mailbox has completed the operation */
+ if (spp->eoc == FALSE) continue;
- spp->eoc = FALSE;
+ spp->eoc = FALSE;
- if (HD(j)->cp_stat[i] == IGNORE) {
- HD(j)->cp_stat[i] = FREE;
- continue;
- }
- else if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
- BN(j), i, HD(j)->iocount);
- continue;
- }
- else if (HD(j)->cp_stat[i] == FREE) {
- printk("%s: ihdlr, mbox %d is free, count %d.\n",
- BN(j), i, HD(j)->iocount);
- continue;
- }
- else if (HD(j)->cp_stat[i] == IN_RESET)
- printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
- else if (HD(j)->cp_stat[i] != IN_USE)
- panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
+ if (HD(j)->cp_stat[i] == IGNORE) {
+ HD(j)->cp_stat[i] = FREE;
+ continue;
+ }
+ else if (HD(j)->cp_stat[i] == LOCKED) {
+ HD(j)->cp_stat[i] = FREE;
+ printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
+ BN(j), i, HD(j)->iocount);
+ continue;
+ }
+ else if (HD(j)->cp_stat[i] == FREE) {
+ printk("%s: ihdlr, mbox %d is free, count %d.\n",
+ BN(j), i, HD(j)->iocount);
+ continue;
+ }
+ else if (HD(j)->cp_stat[i] == IN_RESET)
+ printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
+ else if (HD(j)->cp_stat[i] != IN_USE)
+ panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
- HD(j)->cp_stat[i] = FREE;
- cpp = &HD(j)->cp[i];
- SCpnt = spp->SCpnt;
+ HD(j)->cp_stat[i] = FREE;
+ cpp = &HD(j)->cp[i];
+ SCpnt = spp->SCpnt;
- if (SCpnt == NULL)
- panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
+ if (SCpnt == NULL)
+ panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
- if (SCpnt != cpp->SCpnt)
- panic("%s: ihdlr, mbox %d, sp SCpnt %p, cp SCpnt %p.\n",
- BN(j), i, SCpnt, cpp->SCpnt);
+ if (SCpnt != cpp->SCpnt)
+ panic("%s: ihdlr, mbox %d, sp SCpnt %p, cp SCpnt %p.\n",
+ BN(j), i, SCpnt, cpp->SCpnt);
- if (SCpnt->host_scribble == NULL)
- panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n",
- BN(j), i, SCpnt->pid, SCpnt);
+ if (SCpnt->host_scribble == NULL)
+ panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n",
+ BN(j), i, SCpnt->pid, SCpnt);
- if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d,"\
- " irq %d.\n", BN(j), i, SCpnt->pid,
- *(unsigned int *)SCpnt->host_scribble, irq);
+ if (*(unsigned int *)SCpnt->host_scribble != i)
+ panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d,"\
+ " irq %d.\n", BN(j), i, SCpnt->pid,
+ *(unsigned int *)SCpnt->host_scribble, irq);
- tstatus = status_byte(spp->target_status);
+ tstatus = status_byte(spp->target_status);
- switch (spp->adapter_status) {
- case ASOK: /* status OK */
+ switch (spp->adapter_status) {
+ case ASOK: /* status OK */
- /* Forces a reset if a disk drive keeps returning BUSY */
- if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
- status = DID_ERROR << 16;
+ /* Forces a reset if a disk drive keeps returning BUSY */
+ if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
+ status = DID_ERROR << 16;
- /* If there was a bus reset, redo operation on each target */
- else if (tstatus != GOOD
- && SCpnt->device->type == TYPE_DISK
- && HD(j)->target_reset[SCpnt->target])
- status = DID_BUS_BUSY << 16;
+ /* If there was a bus reset, redo operation on each target */
+ else if (tstatus != GOOD
+ && SCpnt->device->type == TYPE_DISK
+ && HD(j)->target_reset[SCpnt->target])
+ status = DID_BUS_BUSY << 16;
- /* Works around a flaw in scsi.c */
- else if (tstatus == CHECK_CONDITION
- && SCpnt->device->type == TYPE_DISK
- && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
- status = DID_BUS_BUSY << 16;
-
- else
- status = DID_OK << 16;
+ /* Works around a flaw in scsi.c */
+ else if (tstatus == CHECK_CONDITION
+ && SCpnt->device->type == TYPE_DISK
+ && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+ status = DID_BUS_BUSY << 16;
+
+ else
+ status = DID_OK << 16;
- if (tstatus == GOOD)
- HD(j)->target_reset[SCpnt->target] = FALSE;
+ if (tstatus == GOOD)
+ HD(j)->target_reset[SCpnt->target] = FALSE;
- if (spp->target_status && SCpnt->device->type == TYPE_DISK)
- printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
- "0x%x, sense key 0x%x.\n", BN(j),
- SCpnt->target, SCpnt->lun, SCpnt->pid,
- spp->target_status, SCpnt->sense_buffer[2]);
+ if (spp->target_status && SCpnt->device->type == TYPE_DISK)
+ printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
+ "0x%x, sense key 0x%x.\n", BN(j),
+ SCpnt->target, SCpnt->lun, SCpnt->pid,
+ spp->target_status, SCpnt->sense_buffer[2]);
- HD(j)->target_time_out[SCpnt->target] = 0;
+ HD(j)->target_time_out[SCpnt->target] = 0;
- break;
- case ASST: /* Selection Time Out */
- case 0x02: /* Command Time Out */
+ break;
+ case ASST: /* Selection Time Out */
+ case 0x02: /* Command Time Out */
- if (HD(j)->target_time_out[SCpnt->target] > 1)
- status = DID_ERROR << 16;
- else {
- status = DID_TIME_OUT << 16;
- HD(j)->target_time_out[SCpnt->target]++;
- }
+ if (HD(j)->target_time_out[SCpnt->target] > 1)
+ status = DID_ERROR << 16;
+ else {
+ status = DID_TIME_OUT << 16;
+ HD(j)->target_time_out[SCpnt->target]++;
+ }
- break;
- case 0x03: /* SCSI Bus Reset Received */
- case 0x04: /* Initial Controller Power-up */
+ break;
+ case 0x03: /* SCSI Bus Reset Received */
+ case 0x04: /* Initial Controller Power-up */
- if (SCpnt->device->type != TYPE_TAPE)
- status = DID_BUS_BUSY << 16;
- else
- status = DID_ERROR << 16;
+ if (SCpnt->device->type != TYPE_TAPE)
+ status = DID_BUS_BUSY << 16;
+ else
+ status = DID_ERROR << 16;
- for (k = 0; k < MAX_TARGET; k++)
- HD(j)->target_reset[k] = TRUE;
+ for (k = 0; k < MAX_TARGET; k++)
+ HD(j)->target_reset[k] = TRUE;
- break;
- case 0x07: /* Bus Parity Error */
- case 0x0c: /* Controller Ram Parity */
- case 0x05: /* Unexpected Bus Phase */
- case 0x06: /* Unexpected Bus Free */
- case 0x08: /* SCSI Hung */
- case 0x09: /* Unexpected Message Reject */
- case 0x0a: /* SCSI Bus Reset Stuck */
- case 0x0b: /* Auto Request-Sense Failed */
- default:
- status = DID_ERROR << 16;
- break;
- }
+ break;
+ case 0x07: /* Bus Parity Error */
+ case 0x0c: /* Controller Ram Parity */
+ case 0x05: /* Unexpected Bus Phase */
+ case 0x06: /* Unexpected Bus Free */
+ case 0x08: /* SCSI Hung */
+ case 0x09: /* Unexpected Message Reject */
+ case 0x0a: /* SCSI Bus Reset Stuck */
+ case 0x0b: /* Auto Request-Sense Failed */
+ default:
+ status = DID_ERROR << 16;
+ break;
+ }
- SCpnt->result = status | spp->target_status;
- HD(j)->iocount++;
+ SCpnt->result = status | spp->target_status;
+ HD(j)->iocount++;
- if (loops > 1) HD(j)->multicount++;
+ if (loops > 1) HD(j)->multicount++;
#if defined (DEBUG_INTERRUPT)
- if (SCpnt->result || do_trace)
+ if (SCpnt->result || do_trace)
#else
- if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
- (spp->adapter_status != ASOK &&
- spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
- do_trace)
+ if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
+ (spp->adapter_status != ASOK &&
+ spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
+ do_trace)
#endif
- printk("%s: ihdlr, mbox %d, err 0x%x:%x,"\
- " target %d:%d, pid %ld, count %d.\n",
- BN(j), i, spp->adapter_status, spp->target_status,
- SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount);
+ printk("%s: ihdlr, mbox %d, err 0x%x:%x,"\
+ " target %d:%d, pid %ld, count %d.\n",
+ BN(j), i, spp->adapter_status, spp->target_status,
+ SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount);
- /* Set the command state to inactive */
- SCpnt->host_scribble = NULL;
+ /* Set the command state to inactive */
+ SCpnt->host_scribble = NULL;
- restore_flags(flags);
- SCpnt->scsi_done(SCpnt);
- cli();
+ restore_flags(flags);
+ SCpnt->scsi_done(SCpnt);
+ cli();
- } /* Mailbox loop */
+ } /* Mailbox loop */
- } /* Multiple command loop */
+ } /* Multiple command loop */
} /* Boards loop */
if (total_loops == 0)
printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
- driver_name, irq, calls[irq]);
+ driver_name, irq, calls[irq]);
if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n",
- driver_name, irq, calls[irq]);
+ driver_name, irq, calls[irq]);
#if defined (DEBUG_STATISTICS)
if ((calls[irq] % 100000) == 10000)
for (j = 0; sh[j] != NULL; j++)
- printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
- calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
+ printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
+ calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
#endif
restore_flags(flags);
int eata2x_reset(Scsi_Cmnd *);
#define EATA { \
- NULL, /* Ptr for modules */ \
- NULL, /* usage count for modules */ \
- "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
- eata2x_detect, \
- NULL, /* Release */ \
- NULL, \
+ NULL, /* Ptr for modules */ \
+ NULL, /* usage count for modules */ \
+ "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
+ eata2x_detect, \
+ NULL, /* Release */ \
+ NULL, \
NULL, \
eata2x_queuecommand, \
eata2x_abort, \
eata2x_reset, \
- NULL, \
+ 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 */ \
+ 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 \
- }
+ 1, /* unchecked isa dma, reset by detect */ \
+ ENABLE_CLUSTERING \
+ }
#endif
* -supports all PCI based EATA-DMA boards *
* -supports multiple HBAs with & without IRQ sharing *
* -supports all SCSI channels on multi channel boards *
- * -displays (more or less useful) infos in /proc/scsi *
* -can be loaded as module *
+ * -displays statistical and hardware information *
+ * in /proc/scsi/eata_dma *
+ * -needs identical HBA ids on all channels *
* *
* (c)1993,94,95 Michael Neuffer *
* neuffer@goofy.zdv.uni-mainz.de *
* Thanks also to Greg Hosler who did a lot of testing and *
* found quite a number of bugs during the development. *
************************************************************
- * last change: 95/04/10 OS: Linux 1.2.00 or higher *
+ * last change: 95/06/28 OS: Linux 1.3.4 + pre1.3 SCSI pat.*
************************************************************/
/* Look in eata_dma.h for configuration and revision information */
#include <linux/in.h>
#include <linux/bios32.h>
#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <asm/byteorder.h>
#include <asm/types.h>
#include <asm/io.h>
#include <asm/dma.h>
#include "hosts.h"
#include <linux/scsicam.h>
#include "eata_dma.h"
+#include "eata_dma_proc.h"
-#if EATA_DMA_PROC
-#include "eata_dma_proc.h" /* If you're interested send me a mail */
-ulong reads[13]; /* /proc/scsi probably won't get */
-ulong writes[13]; /* into the kernel before pl. 1.3 */
-#endif
-static uint ISAbases[] =
+static u32 ISAbases[] =
{0x1F0, 0x170, 0x330, 0x230};
static unchar EISAbases[] =
{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
static unchar HBA_interpret = FALSE;
static u32 fake_int_base;
static u32 fake_int_result;
-static struct geom_emul geometry; /* Drive 1 & 2 geometry */
static ulong int_counter = 0;
static ulong queue_counter = 0;
void eata_scsi_done (Scsi_Cmnd * SCpnt)
{
return;
-}
+}
void eata_fake_int_handler(s32 irq, struct pt_regs * regs)
{
fake_int_result = inb(fake_int_base + HA_RSTATUS);
- DBG(DBG_INTR3, printk("eata_fake_int_handler called irq%ld base %#lx res %#lx\n",
- irq, fake_int_base, fake_int_result));
+ DBG(DBG_INTR3, printk("eata_fake_int_handler called irq%d base %#x"
+ " res %#x\n", irq, fake_int_base, fake_int_result));
return;
}
-#if EATA_DMA_PROC
#include "eata_dma_proc.c"
-#endif
+#ifdef MODULE
int eata_release(struct Scsi_Host *sh)
{
- if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq);
- else reg_IRQ[sh->irq]--;
+ uint i;
+ if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq);
+ else reg_IRQ[sh->irq]--;
scsi_init_free((void *)status, 512);
+ scsi_init_free((void *)dma_scratch, 512);
+ for (i = 0; i < sh->can_queue; i++){ /* Free all SG arrays */
+ if(SD(sh)->ccb[i].sg_list != NULL)
+ scsi_init_free((void *) SD(sh)->ccb[i].sg_list,
+ sh->sg_tablesize * sizeof(struct eata_sg_list));
+ }
- if (SD(sh)->channel == 0) {
- if (sh->dma_channel != 0xff) free_dma(sh->dma_channel);
- if (sh->io_port && sh->n_io_port)
- release_region(sh->io_port, sh->n_io_port);
- }
- return(TRUE);
+ if (SD(sh)->channel == 0) {
+ if (sh->dma_channel != 0xff) free_dma(sh->dma_channel);
+ if (sh->io_port && sh->n_io_port)
+ release_region(sh->io_port, sh->n_io_port);
+ }
+ return(TRUE);
}
+#endif
const char *eata_info(struct Scsi_Host *host)
{
cli();
for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) {
- if (sh->irq != irq)
+ if (sh->irq != irq)
continue;
- if (!(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ))
+ if (!(inb((uint)sh->base + HA_RAUXSTAT) & HA_AIRQ))
continue;
-
+
int_counter++;
-
+
sp=&SD(sh)->sp;
-
+
cp = sp->ccb;
cmd = cp->cmd;
base = (uint) cmd->host->base;
-
+
hba_stat = sp->hba_stat;
-
- scsi_stat = (sp->scsi_stat >> 1) && 0x1f;
-
+
+ scsi_stat = (sp->scsi_stat >> 1) & 0x1f;
+
if (sp->EOC == FALSE) {
eata_stat = inb(base + HA_RSTATUS);
printk("eata_dma: int_handler, board: %x cmd %lx returned "
"unfinished.\nEATA: %x HBA: %x SCSI: %x spadr %lx spadrirq "
"%lx, irq%d\n", base, (long)cp, eata_stat, hba_stat,
scsi_stat,(long)&status, (long)&status[irq], irq);
- DBG(DBG_DELAY,DEL2(800));
+ DBG(DBG_DELAY, DEL2(800));
restore_flags(flags);
return;
}
-
+
if (cp->status == LOCKED) {
cp->status = FREE;
eata_stat = inb(base + HA_RSTATUS);
printk("eata_dma: int_handler, freeing locked queueslot\n");
- DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+ DBG(DBG_INTR && DBG_DELAY, DEL2(800));
restore_flags(flags);
return;
}
-
- eata_stat = inb(base + HA_RSTATUS);
+
+ eata_stat = inb(base + HA_RSTATUS);
DBG(DBG_INTR, printk("IRQ %d received, base %#.4x, pid %ld, target: "
"%x, lun: %x, ea_s: %#.2x, hba_s: %#.2x \n",
irq, base, cmd->pid, cmd->target, cmd->lun,
case HA_NO_ERROR: /* NO Error */
if (scsi_stat == CONDITION_GOOD
&& cmd->device->type == TYPE_DISK
- && (HD(cmd)->t_state[cmd->target] == RESET))
- result = DID_BUS_BUSY << 16;
- else if (scsi_stat == GOOD)
- HD(cmd)->t_state[cmd->target] = FALSE;
+ && (HD(cmd)->t_state[cp->cp_channel][cp->cp_id] == RESET))
+ result = DID_BUS_BUSY << 16;
+ else if (scsi_stat == GOOD)
+ HD(cmd)->t_state[cp->cp_channel][cp->cp_id] = OK;
else if (scsi_stat == CHECK_CONDITION
- && cmd->device->type == TYPE_DISK
- && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
- result = DID_BUS_BUSY << 16;
+ && cmd->device->type == TYPE_DISK
+ && (cmd->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+ result = DID_BUS_BUSY << 16;
else
- result = DID_OK << 16;
- HD(cmd)->t_timeout[cmd->target] = FALSE;
+ result = DID_OK << 16;
+ HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] = OK;
break;
- case HA_ERR_SEL_TO: /* Selection Timeout */
+ case HA_ERR_SEL_TO: /* Selection Timeout */
result = DID_BAD_TARGET << 16;
break;
- case HA_ERR_CMD_TO: /* Command Timeout */
- if (HD(cmd)->t_timeout[cmd->target] > 1)
+ case HA_ERR_CMD_TO: /* Command Timeout */
+ if (HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id] > 1)
result = DID_ERROR << 16;
else {
result = DID_TIME_OUT << 16;
- HD(cmd)->t_timeout[cmd->target]++;
+ HD(cmd)->t_timeout[cp->cp_channel][cp->cp_id]++;
}
break;
- case HA_ERR_RESET: /* SCSI Bus Reset Received */
- case HA_INIT_POWERUP: /* Initial Controller Power-up */
+ case HA_ERR_RESET: /* SCSI Bus Reset Received */
+ case HA_INIT_POWERUP: /* Initial Controller Power-up */
if (cmd->device->type != TYPE_TAPE)
result = DID_BUS_BUSY << 16;
else
result = DID_ERROR << 16;
-
+
for (i = 0; i < MAXTARGET; i++)
- HD(cmd)->t_state[i] = RESET;
+ HD(cmd)->t_state[cp->cp_channel][i] = RESET;
break;
- case HA_UNX_BUSPHASE: /* Unexpected Bus Phase */
- case HA_UNX_BUS_FREE: /* Unexpected Bus Free */
- case HA_BUS_PARITY: /* Bus Parity Error */
- case HA_SCSI_HUNG: /* SCSI Hung */
- case HA_UNX_MSGRJCT: /* Unexpected Message Reject */
- case HA_RESET_STUCK: /* SCSI Bus Reset Stuck */
- case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */
- case HA_PARITY_ERR: /* Controller Ram Parity */
+ case HA_UNX_BUSPHASE: /* Unexpected Bus Phase */
+ case HA_UNX_BUS_FREE: /* Unexpected Bus Free */
+ case HA_BUS_PARITY: /* Bus Parity Error */
+ case HA_SCSI_HUNG: /* SCSI Hung */
+ case HA_UNX_MSGRJCT: /* Unexpected Message Reject */
+ case HA_RESET_STUCK: /* SCSI Bus Reset Stuck */
+ case HA_RSENSE_FAIL: /* Auto Request-Sense Failed */
+ case HA_PARITY_ERR: /* Controller Ram Parity */
default:
result = DID_ERROR << 16;
break;
}
cmd->result = result | (scsi_stat << 1);
-
+
#if DBG_INTR2
- if (scsi_stat || result || hba_stat || eata_stat != 0x50)
- printk("eata_stat: %#x hba_stat: %#.2x,scsi_stat: %#.2x, "
- "sense_key: %#x, result: %#.8x\n", eata_stat, hba_stat,
- scsi_stat,cmd->sense_buffer[2] & 0xf, cmd->result);
+ if (scsi_stat || result || hba_stat || eata_stat != 0x50
+ || cmd->scsi_done == NULL || cmd->device->id == 7)
+ printk("HBA: %d, channel %d, id: %d, lun %d, pid %ld:\n"
+ "eata_stat %#x, hba_stat %#.2x, scsi_stat %#.2x, "
+ "sense_key: %#x, result: %#.8x\n",
+ x, cmd->device->channel, cmd->device->id, cmd->device->lun,
+ cmd->pid, eata_stat, hba_stat, scsi_stat,
+ cmd->sense_buffer[2] & 0xf, cmd->result);
DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
#endif
-
- cp->status = FREE; /* now we can release the slot */
-
+
+ cp->status = FREE; /* now we can release the slot */
+
restore_flags(flags);
if(cmd->scsi_done != eata_scsi_done) cmd->scsi_done(cmd);
else {
cli();
}
restore_flags(flags);
-
+
return;
}
-inline uint eata_send_command(ulong addr, uint base, unchar command)
+inline int eata_send_command(u32 addr, u32 base, u8 command)
{
- uint loop = R_LIMIT;
-
+ long loop = R_LIMIT;
+
while (inb(base + HA_RAUXSTAT) & HA_ABUSY)
- if (--loop == 0)
- return(FALSE);
-
- outb(addr & 0x000000ff, base + HA_WDMAADDR);
- outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
+ if (--loop == 0)
+ return(FALSE);
+
+ outb( addr & 0x000000ff, base + HA_WDMAADDR);
+ outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
outb(command, base + HA_WCOMMAND);
return(TRUE);
}
-int eata_queue(Scsi_Cmnd * cmd, void *(done) (Scsi_Cmnd *))
+#if 0
+inline int eata_send_immediate(u32 addr, u32 base, u8 cmnd, u8 cmnd2, u8 id,
+ u8 lun)
{
- uint i, x, y;
- long flags;
+ if(addr){
+ outb( addr & 0x000000ff, base + HA_WDMAADDR);
+ outb((addr & 0x0000ff00) >> 8, base + HA_WDMAADDR + 1);
+ outb((addr & 0x00ff0000) >> 16, base + HA_WDMAADDR + 2);
+ outb((addr & 0xff000000) >> 24, base + HA_WDMAADDR + 3);
+ } else {
+ outb(id, base + HA_WSUBCODE);
+ outb(lun, base + HA_WSUBLUN);
+ }
+
+ outb(cmnd2, base + HA_WCOMMAND2);
+ outb(cmnd, base + HA_WCOMMAND);
+ return(TRUE);
+}
+#endif
+int eata_queue(Scsi_Cmnd * cmd, void (* done) (Scsi_Cmnd *))
+{
+ unsigned int i, x, y;
+ u32 flags;
hostdata *hd;
struct Scsi_Host *sh;
struct eata_ccb *cp;
cli();
queue_counter++;
-
+
if (done == (void *)eata_scsi_done) {
- if (internal_command_finished == TRUE)
+ if (internal_command_finished == TRUE)
internal_command_finished = FALSE;
- else
+ else
cmd->result = (DID_ERROR << 16) + QUEUE_FULL;
}
hd = HD(cmd);
sh = cmd->host;
-
+
/* check for free slot */
- for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) {
+ for (y = hd->last_ccb + 1, x = 0; x < sh->can_queue; x++, y++) {
if (y >= sh->can_queue)
y = 0;
if (hd->ccb[y].status == FREE)
break;
}
-
+
hd->last_ccb = y;
-
+
if (x == sh->can_queue) {
-
- DBG(DBG_QUEUE, printk("can_queue %d, x %d, y %d\n",sh->can_queue,x,y));
+
+ DBG(DBG_QUEUE, printk("can_queue %d, x %d, y %d\n",
+ sh->can_queue, x, y));
#if DEBUG_EATA
- panic("eata_dma: run out of queue slots cmdno:%ld intrno: %ld\n",
+ panic("eata_dma: run out of queue slots cmdno:%ld intrno: %ld\n",
queue_counter, int_counter);
#else
- panic("eata_dma: run out of queue slots....\n");
+ panic("eata_dma: run out of queue slots....\n");
#endif
}
-
+
cp = &hd->ccb[y];
-
- memset(cp, 0, sizeof(struct eata_ccb));
-
- cp->status = USED; /* claim free slot */
+
+ memset(cp, 0, sizeof(struct eata_ccb) - sizeof(struct eata_sg_list *));
+
+ cp->status = USED; /* claim free slot */
DBG(DBG_QUEUE, printk("eata_queue pid %ld, target: %x, lun: %x, y %d\n",
cmd->pid, cmd->target, cmd->lun, y));
DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
-
cmd->scsi_done = (void *)done;
-
+
switch (cmd->cmnd[0]) {
case CHANGE_DEFINITION: case COMPARE: case COPY:
case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT:
case SEARCH_HIGH_12: case SEARCH_EQUAL_12: case SEARCH_LOW_12:
case WRITE_12: case WRITE_VERIFY_12: case SET_WINDOW:
case MEDIUM_SCAN: case SEND_VOLUME_TAG:
- case 0xea: /* alternate number for WRITE LONG */
- cp->DataOut = TRUE; /* Output mode */
- break;
- case 0x00:
+ case 0xea: /* alternate number for WRITE LONG */
+ cp->DataOut = TRUE; /* Output mode */
+ break;
+ case TEST_UNIT_READY:
default:
- cp->DataIn = TRUE; /* Input mode */
+ cp->DataIn = TRUE; /* Input mode */
}
-
- if (done == (void *) eata_scsi_done && HBA_interpret == TRUE)
- cp->Interpret = TRUE; /* Interpret command */
-
+
+ if ((done == (void *) eata_scsi_done && HBA_interpret == TRUE)
+ || cmd->target == sh->this_id)
+ cp->Interpret = TRUE; /* Interpret command */
+
if (cmd->use_sg) {
- cp->scatter = TRUE; /* SG mode */
- cp->cp_dataDMA = htonl((long)&cp->sg_list);
- cp->cp_datalen = htonl(cmd->use_sg*8);
+ cp->scatter = TRUE; /* SG mode */
+ if (cp->sg_list == NULL) {
+ cp->sg_list = kmalloc(SG_SIZE_BIG*sizeof(struct eata_sg_list),
+ GFP_ATOMIC | GFP_DMA);
+ }
+ cp->cp_dataDMA = htonl((ulong)cp->sg_list);
+ if (cp->cp_dataDMA == 0)
+ panic("eata_dma: Run out of DMA memory for SG lists !\n");
+
+ cp->cp_datalen = htonl(cmd->use_sg * sizeof(struct eata_sg_list));
sl=(struct scatterlist *)cmd->request_buffer;
-
for(i = 0; i < cmd->use_sg; i++, sl++){
- cp->sg_list[i].data = htonl((ulong) sl->address);
- cp->sg_list[i].len = htonl((ulong) sl->length);
- }
+ cp->sg_list[i].data = htonl((u32) sl->address);
+ cp->sg_list[i].len = htonl((u32) sl->length);
+ }
} else {
- cp->scatter = FALSE;
+ cp->scatter = FALSE;
cp->cp_datalen = htonl(cmd->request_bufflen);
- cp->cp_dataDMA = htonl((ulong)cmd->request_buffer);
+ cp->cp_dataDMA = htonl((u32)cmd->request_buffer);
}
-
+
cp->Auto_Req_Sen = TRUE;
- cp->cp_reqDMA = htonl((ulong) cmd->sense_buffer);
+ cp->cp_reqDMA = htonl((u32) cmd->sense_buffer);
cp->reqlen = sizeof(cmd->sense_buffer);
-
+
cp->cp_id = cmd->target;
+ cp->cp_channel = cmd->channel;
cp->cp_lun = cmd->lun;
cp->cp_dispri = TRUE;
cp->cp_identify = TRUE;
memcpy(cp->cp_cdb, cmd->cmnd, cmd->cmd_len);
-
- cp->cp_statDMA = htonl((ulong) &(hd->sp));
-
+
+ cp->cp_statDMA = htonl((u32) &(hd->sp));
+
cp->cp_viraddr = cp;
cp->cmd = cmd;
- cmd->host_scribble = (char *)&hd->ccb[y];
-
- if(eata_send_command((ulong) cp, (uint) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {
- cmd->result = DID_ERROR << 16;
- printk("eata_queue target %d, pid %ld, HBA busy, returning DID_ERROR, done.\n",
- cmd->target, cmd->pid);
- restore_flags(flags);
- if(done != (void *)eata_scsi_done) done(cmd);
- return (0);
+ cmd->host_scribble = (char *)&hd->ccb[y];
+
+ if(eata_send_command((u32) cp, (u32) sh->base, EATA_CMD_DMA_SEND_CP) == FALSE) {
+ cmd->result = DID_ERROR << 16;
+ printk("eata_queue target %d, pid %ld, HBA busy, returning DID_ERROR,"
+ " done.\n", cmd->target, cmd->pid);
+ restore_flags(flags);
+ if(done != (void *)eata_scsi_done) done(cmd);
+ return (0);
}
- DBG(DBG_QUEUE,printk("Queued base %#.4lx pid: %ld target: %x lun: %x slot %d irq %d\n",
- (long)sh->base, cmd->pid, cmd->target, cmd->lun, y, sh->irq));
+ DBG(DBG_QUEUE,printk("Queued base %#.4x pid: %ld target: %x lun: %x "
+ "slot %d irq %d\n", (s32)sh->base, cmd->pid,
+ cmd->target, cmd->lun, y, sh->irq));
DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
restore_flags(flags);
return (0);
}
-static volatile int internal_done_flag = 0;
-static volatile int internal_done_errcode = 0;
-
-static void internal_done(Scsi_Cmnd * cmd)
-{
- internal_done_errcode = cmd->result;
- ++internal_done_flag;
-}
-
-int eata_command(Scsi_Cmnd * cmd)
-{
-
- DBG(DBG_COM, printk("eata_command: calling eata_queue\n"));
-
- eata_queue(cmd, (void *)internal_done);
-
- while (!internal_done_flag);
- internal_done_flag = 0;
- return (internal_done_errcode);
-}
int eata_abort(Scsi_Cmnd * cmd)
{
ulong flags;
- uint loop = R_LIMIT;
+ ulong loop = R_LIMIT;
save_flags(flags);
cli();
- DBG(DBG_ABNORM, printk("eata_abort called pid: %ld target: %x lun: %x reason %x\n",
- cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
+ DBG(DBG_ABNORM, printk("eata_abort called pid: %ld target: %x lun: %x"
+ " reason %x\n", cmd->pid, cmd->target, cmd->lun,
+ cmd->abort_reason));
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-
-
- while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
- if (--loop == 0) {
+
+
+ while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
+ if (--loop == 0) {
printk("eata_dma: abort, timeout error.\n");
restore_flags(flags);
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
return (SCSI_ABORT_ERROR);
}
+ if (CD(cmd)->status == USED) {
+ DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));
+ restore_flags(flags);
+ return (SCSI_ABORT_BUSY); /* SNOOZE */
+ }
if (CD(cmd)->status == FREE) {
- DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n"));
+ DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n"));
restore_flags(flags);
return (SCSI_ABORT_NOT_RUNNING);
}
- if (CD(cmd)->status == USED) {
- DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));
- restore_flags(flags);
- return (SCSI_ABORT_BUSY); /* SNOOZE */
- }
if (CD(cmd)->status == RESET) {
restore_flags(flags);
- printk("eata_dma: abort, command reset error.\n");
+ printk("eata_dma: abort, command reset error.\n");
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
- return (SCSI_ABORT_ERROR);
+ return (SCSI_ABORT_ERROR);
}
if (CD(cmd)->status == LOCKED) {
restore_flags(flags);
- DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
- return (SCSI_ABORT_NOT_RUNNING);
+ DBG(DBG_ABNORM, printk("eata_dma: abort, queue slot locked.\n"));
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ return (SCSI_ABORT_NOT_RUNNING);
} else
panic("eata_dma: abort: invalid slot status\n");
}
int eata_reset(Scsi_Cmnd * cmd)
{
- uint x, z, time, limit = 0;
- uint loop = R_LIMIT;
+ ushort x, z;
+ ulong time, limit = 0;
+ ulong loop = R_LIMIT;
ulong flags;
unchar success = FALSE;
Scsi_Cmnd *sp;
-
+
save_flags(flags);
cli();
-
- DBG(DBG_ABNORM, printk("eata_reset called pid:%ld target: %x lun: %x reason %x\n",
- cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
-
-
+
+ DBG(DBG_ABNORM, printk("eata_reset called pid:%ld target: %x lun: %x"
+ " reason %x\n", cmd->pid, cmd->target, cmd->lun,
+ cmd->abort_reason));
+
if (HD(cmd)->state == RESET) {
printk("eata_reset: exit, already in reset.\n");
restore_flags(flags);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
- return (SCSI_RESET_ERROR);
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ return (SCSI_RESET_ERROR);
}
-
- while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
- if (--loop == 0) {
- printk("eata_reset: exit, timeout error.\n");
+
+ while (inb((u32)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
+ if (--loop == 0) {
+ printk("eata_reset: exit, timeout error.\n");
restore_flags(flags);
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
return (SCSI_RESET_ERROR);
}
- for (z = 0; z < MAXTARGET; z++) {
- HD(cmd)->t_state[z] = RESET;
- HD(cmd)->t_timeout[z] = FALSE;
+
+ for (x = 0; x < MAXCHANNEL; x++) {
+ for (z = 0; z < MAXTARGET; z++) {
+ HD(cmd)->t_state[x][z] = RESET;
+ HD(cmd)->t_timeout[x][z] = NO_TIMEOUT;
+ }
}
for (x = 0; x < cmd->host->can_queue; x++) {
-
if (HD(cmd)->ccb[x].status == FREE)
continue;
-
+
if (HD(cmd)->ccb[x].status == LOCKED) {
HD(cmd)->ccb[x].status = FREE;
printk("eata_reset: locked slot %d forced free.\n", x);
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
- continue;
+ continue;
}
sp = HD(cmd)->ccb[x].cmd;
HD(cmd)->ccb[x].status = RESET;
printk("eata_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+
if (sp == NULL)
panic("eata_reset: slot %d, sp==NULL.\n", x);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+
if (sp == cmd)
success = TRUE;
}
-
+
/* hard reset the HBA */
- inb((uint) (cmd->host->base) + HA_RSTATUS); /* This might cause trouble */
- eata_send_command(0, (uint) cmd->host->base, EATA_CMD_RESET);
-
+ inb((u32) (cmd->host->base) + HA_RSTATUS); /* This might cause trouble */
+ eata_send_command(0, (u32) cmd->host->base, EATA_CMD_RESET);
+
DBG(DBG_ABNORM, printk("eata_reset: board reset done, enabling interrupts.\n"));
HD(cmd)->state = RESET;
-
+
restore_flags(flags);
-
+
time = jiffies;
- while (jiffies < (time + 300) && limit++ < 10000000);
-
+ while (jiffies < (time + 300) && limit++ < 10000000)
+ /* nothing */;
+
save_flags(flags);
cli();
-
- DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %d.\n", limit));
+
+ DBG(DBG_ABNORM, printk("eata_reset: interrupts disabled, loops %ld.\n",
+ limit));
DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
-
+
for (x = 0; x < cmd->host->can_queue; x++) {
-
+
/* Skip slots already set free by interrupt */
if (HD(cmd)->ccb[x].status != RESET)
continue;
-
+
sp = HD(cmd)->ccb[x].cmd;
sp->result = DID_RESET << 16;
-
+
/* This mailbox is still waiting for its interrupt */
HD(cmd)->ccb[x].status = LOCKED;
-
+
printk("eata_reset: slot %d locked, DID_RESET, pid %ld done.\n",
- x, sp->pid);
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ x, sp->pid);
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
restore_flags(flags);
sp->scsi_done(sp);
cli();
}
-
+
HD(cmd)->state = FALSE;
restore_flags(flags);
-
+
if (success) {
DBG(DBG_ABNORM, printk("eata_reset: exit, success.\n"));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
- return (SCSI_RESET_SUCCESS);
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ return (SCSI_RESET_SUCCESS);
} else {
DBG(DBG_ABNORM, printk("eata_reset: exit, wakeup.\n"));
- DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
- return (SCSI_RESET_PUNT);
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ return (SCSI_RESET_PUNT);
}
}
-char * get_board_data(ulong base, uint irq, uint id)
+char * get_board_data(u32 base, u32 irq, u32 id)
{
- struct eata_ccb cp;
- struct eata_sp sp;
+ struct eata_ccb *cp;
+ struct eata_sp *sp;
static char *buff;
- u32 i;
+ ulong i;
+ ulong limit = 0;
- buff = dma_scratch;
+ cp = (struct eata_ccb *) scsi_init_malloc(sizeof(struct eata_ccb),
+ GFP_ATOMIC | GFP_DMA);
+ sp = (struct eata_sp *) scsi_init_malloc(sizeof(struct eata_sp),
+ GFP_ATOMIC | GFP_DMA);
- memset(&cp, 0, sizeof(struct eata_ccb));
- memset(&sp, 0, sizeof(struct eata_sp));
+ buff = dma_scratch;
+
+ memset(cp, 0, sizeof(struct eata_ccb));
+ memset(sp, 0, sizeof(struct eata_sp));
memset(buff, 0, 256);
- cp.DataIn = TRUE;
- cp.Interpret = TRUE; /* Interpret command */
+ cp->DataIn = TRUE;
+ cp->Interpret = TRUE; /* Interpret command */
- cp.cp_datalen = htonl(255);
- cp.cp_dataDMA = htonl((s32)buff);
- cp.cp_viraddr = &cp;
-
- cp.cp_id = id;
- cp.cp_lun = 0;
+ cp->cp_datalen = htonl(255);
+ cp->cp_dataDMA = htonl((s32)buff);
+ cp->cp_viraddr = cp;
+
+ cp->cp_id = id;
+ cp->cp_lun = 0;
- cp.cp_cdb[0] = INQUIRY;
- cp.cp_cdb[1] = 0;
- cp.cp_cdb[2] = 0;
- cp.cp_cdb[3] = 0;
- cp.cp_cdb[4] = 255;
- cp.cp_cdb[5] = 0;
+ cp->cp_cdb[0] = INQUIRY;
+ cp->cp_cdb[1] = 0;
+ cp->cp_cdb[2] = 0;
+ cp->cp_cdb[3] = 0;
+ cp->cp_cdb[4] = 255;
+ cp->cp_cdb[5] = 0;
- cp.cp_statDMA = htonl((ulong) &sp);
+ cp->cp_statDMA = htonl((ulong) sp);
fake_int_base = base;
fake_int_result = 0;
- eata_send_command((u32) &cp, (u32) base, EATA_CMD_DMA_SEND_CP);
+ eata_send_command((u32) cp, (u32) base, EATA_CMD_DMA_SEND_CP);
i = jiffies + 300;
- while (!fake_int_result && jiffies <= i)
- /* nothing */;
+ while (fake_int_result == FALSE && jiffies <= i)
+ barrier();
- DBG(DBG_INTR3, printk("fake_int_result: %#lx hbastat %#lx scsistat %#lx,"
+ DBG(DBG_INTR3, printk("fake_int_result: %#x hbastat %#x scsistat %#x,"
" buff %p sp %p\n",
- fake_int_result, (u32) (sp.hba_stat & 0x7f),
- (u32) sp.scsi_stat, buff, &sp));
+ fake_int_result, (u32) (sp->hba_stat & 0x7f),
+ (u32) sp->scsi_stat, buff, sp));
+
+ scsi_init_free((void *)cp, sizeof(struct eata_ccb));
+ scsi_init_free((void *)sp, sizeof(struct eata_sp));
- if (jiffies > i || (fake_int_result & 1))
- return (NULL);
- else
- return (buff);
+ if ((fake_int_result & HA_SERROR) || jiffies > i){
+ /* hard reset the HBA */
+ inb((u32) (base) + HA_RSTATUS);
+ eata_send_command(0, base, EATA_CMD_RESET);
+ i = jiffies;
+ while (jiffies < (i + 300) && limit++ < 10000000)
+ barrier();
+ return (NULL);
+ } else
+ return (buff);
}
int check_blink_state(long base)
{
- uint loops = 10;
- ulong blinkindicator = 0x42445054;
- ulong state = 0x12345678;
- ulong oldstate = 0;
+ ushort loops = 10;
+ u32 blinkindicator;
+ u32 state = 0x12345678;
+ u32 oldstate = 0;
+ blinkindicator = htonl(0x54504442);
while ((loops--) && (state != oldstate)) {
oldstate = state;
state = inl((uint) base + 1);
}
DBG(DBG_BLINK, printk("Did Blink check. Status: %d\n",
- (state == oldstate) && (state == blinkindicator)));
+ (state == oldstate) && (state == blinkindicator)));
if ((state == oldstate) && (state == blinkindicator))
- return(TRUE);
+ return(TRUE);
else
- return (FALSE);
+ return (FALSE);
}
-int get_conf_PIO(struct eata_register *base, struct get_conf *buf)
+int get_conf_PIO(u32 base, struct get_conf *buf)
{
ulong loop = R_LIMIT;
- ushort *p;
+ u16 *p;
- u8 warning = FALSE;
-
- if(check_region((int) base, 9)) {
- if ((int)base == 0x1f0 || (int)base == 0x170) {
- warning = 1;
- } else
- return (FALSE);
- }
-
+ if(check_region(base, 9))
+ return (FALSE);
+
memset(buf, 0, sizeof(struct get_conf));
- while (inb((uint) base + HA_RSTATUS) & HA_SBUSY)
+ while (inb(base + HA_RSTATUS) & HA_SBUSY)
if (--loop == 0)
return (FALSE);
- DBG(DBG_PIO && DBG_PROBE,printk("Issuing PIO READ CONFIG to HBA at %lx\n",
- (long)base));
- eata_send_command(0, (uint) base, EATA_CMD_PIO_READ_CONFIG);
+ DBG(DBG_PIO && DBG_PROBE,
+ printk("Issuing PIO READ CONFIG to HBA at %#x\n", base));
+ eata_send_command(0, base, EATA_CMD_PIO_READ_CONFIG);
+
loop = R_LIMIT;
- for (p = (ushort *) buf;
- (long)p <= ((long)buf + (sizeof(struct get_conf)/ 2)); p++) {
- while (!(inb((uint) base + HA_RSTATUS) & HA_SDRQ))
+ for (p = (u16 *) buf;
+ (long)p <= ((long)buf + (sizeof(struct get_conf) / 2)); p++) {
+ while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
if (--loop == 0)
- return (FALSE);
+ return (FALSE);
+
loop = R_LIMIT;
- *p = inw((uint) base + HA_RDATA);
+ *p = inw(base + HA_RDATA);
}
- if (!(inb((uint) base + HA_RSTATUS) & HA_SERROR)) { /* Error ? */
- DBG(DBG_PIO&&DBG_PROBE, printk("\nSignature: %c%c%c%c\n",
- (char)buf->sig[0], (char)buf->sig[1],
- (char)buf->sig[2], (char)buf->sig[3]));
- if ((buf->sig[0] == 'E') && (buf->sig[1] == 'A')
- && (buf->sig[2] == 'T') && (buf->sig[3] == 'A')) {
+ if (!(inb(base + HA_RSTATUS) & HA_SERROR)) { /* Error ? */
+ if (htonl(EATA_SIGNATURE) == buf->signature) {
DBG(DBG_PIO&&DBG_PROBE, printk("EATA Controller found at %x "
- "EATA Level: %x\n", (uint) base, (uint) (buf->version)));
-
- while (inb((uint) base + HA_RSTATUS) & HA_SDRQ)
- inw((uint) base + HA_RDATA);
- if (warning == TRUE)
- printk("Warning: HBA with IO on 0x%p detected,\n"
- " this IO space is already allocated, probably by the IDE driver.\n"
- " This might lead to problems.", base);
- return (TRUE);
+ "EATA Level: %x\n", (uint) base,
+ (uint) (buf->version)));
+
+ while (inb(base + HA_RSTATUS) & HA_SDRQ)
+ inw(base + HA_RDATA);
+ return (TRUE);
}
} else {
- DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer "
- "for HBA at %lx\n", (long)base));
+ DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer "
+ "for HBA at %lx\n", (long)base));
}
return (FALSE);
}
{
printk("Please check values: (read config data)\n");
printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d DMAS:%d\n",
- (uint) ntohl(gc->len), gc->version,
- gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support,
- gc->DMA_support);
+ (u32) ntohl(gc->len), gc->version,
+ gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support,
+ gc->DMA_support);
printk("DMAV:%d HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n",
- gc->DMA_valid, gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
- gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
- printk("IRQ:%d IRQT:%d DMAC:%d FORCADR:%d MCH:%d RIDQ:%d PCI:%d EISA:%d\n",
- gc->IRQ, gc->IRQ_TR, (8 - gc->DMA_channel) & 7, gc->FORCADR,
- gc->MAX_CHAN, gc->ID_qest, gc->is_PCI, gc->is_EISA);
+ gc->DMA_valid, gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
+ gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
+ printk("IRQ:%d IRQT:%d DMAC:%d FORCADR:%d SG_64K:%d SG_UAE:%d MID:%d "
+ "MCH:%d MLUN:%d\n",
+ gc->IRQ, gc->IRQ_TR, (8 - gc->DMA_channel) & 7, gc->FORCADR,
+ gc->SG_64K, gc->SG_UAE, gc->MAX_ID, gc->MAX_CHAN, gc->MAX_LUN);
+ printk("RIDQ:%d PCI:%d EISA:%d\n",
+ gc->ID_qest, gc->is_PCI, gc->is_EISA);
DBG(DPT_DEBUG, DELAY(1400));
}
-int register_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
+short register_HBA(u32 base, struct get_conf *gc, Scsi_Host_Template * tpnt,
+ u8 bustype)
{
ulong size = 0;
unchar dma_channel = 0;
- char *buff;
- uint i;
+ char *buff = 0;
+ unchar bugs = 0;
struct Scsi_Host *sh;
hostdata *hd;
+
DBG(DBG_REGISTER, print_config(gc));
- if(gc->HAA_valid == FALSE || ntohl(gc->len) < 0x22)
- gc->MAX_CHAN = 0;
+ if (gc->DMA_support == FALSE) {
+ printk("The EATA HBA at %#.4x does not support DMA.\n"
+ "Please use the EATA-PIO driver.\n", base);
+ return (FALSE);
+ }
- if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */
- if (!request_irq(gc->IRQ, (void *) eata_fake_int_handler, SA_INTERRUPT, "eata_dma")){
- reg_IRQ[gc->IRQ] += (gc->MAX_CHAN+1);
+ if(gc->HAA_valid == FALSE || ntohl(gc->len) < 0x22)
+ gc->MAX_CHAN = 0;
+
+ if (reg_IRQ[gc->IRQ] == FALSE) { /* Interrupt already registered ? */
+ if (!request_irq(gc->IRQ, (void *) eata_fake_int_handler, SA_INTERRUPT,
+ "eata_dma")){
+ reg_IRQ[gc->IRQ]++;
if (!gc->IRQ_TR)
- reg_IRQL[gc->IRQ] = TRUE; /* IRQ is edge triggered */
+ reg_IRQL[gc->IRQ] = TRUE; /* IRQ is edge triggered */
} else {
printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
return (FALSE);
}
- } else { /* More than one HBA on this IRQ */
+ } else { /* More than one HBA on this IRQ */
if (reg_IRQL[gc->IRQ] == TRUE) {
printk("Can't support more than one HBA on this IRQ,\n"
" if the IRQ is edge triggered. Sorry.\n");
return (FALSE);
} else
- reg_IRQ[gc->IRQ] += (gc->MAX_CHAN+1);
+ reg_IRQ[gc->IRQ]++;
}
-
+
/* if gc->DMA_valid it must be an ISA HBA and we have to register it */
dma_channel = 0xff;
if (gc->DMA_valid) {
- if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "eata_dma")) {
- printk("Unable to allocate DMA channel %d for ISA HBA at %#.4lx.\n",
- dma_channel, base);
- reg_IRQ[gc->IRQ] -= (gc->MAX_CHAN+1);
- if (reg_IRQ[gc->IRQ] == 0)
- free_irq(gc->IRQ);
- if (!gc->IRQ_TR)
- reg_IRQL[gc->IRQ] = FALSE;
- return (FALSE);
- }
- }
-
- buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]);
+ if (request_dma(dma_channel = (8 - gc->DMA_channel) & 7, "eata_dma")) {
+ printk("Unable to allocate DMA channel %d for ISA HBA at %#.4x.\n",
+ dma_channel, base);
+ reg_IRQ[gc->IRQ]--;
+ if (reg_IRQ[gc->IRQ] == 0)
+ free_irq(gc->IRQ);
+ if (gc->IRQ_TR == FALSE)
+ reg_IRQL[gc->IRQ] = FALSE;
+ return (FALSE);
+ }
+ }
+
+ if (bustype != IS_EISA)
+ buff = get_board_data(base, gc->IRQ, gc->scsi_id[3]);
if (buff == NULL) {
- if (gc->DMA_support == FALSE)
- printk("HBA at %#.4lx doesn't support DMA. Sorry\n", base);
- else
- printk("HBA at %#.4lx didn't react on INQUIRY. Sorry.\n", base);
- if (gc->DMA_valid)
- free_dma(dma_channel);
- reg_IRQ[gc->IRQ] -= (gc->MAX_CHAN+1);
- if (reg_IRQ[gc->IRQ] == 0)
- free_irq(gc->IRQ);
- if (!gc->IRQ_TR)
- reg_IRQL[gc->IRQ] = FALSE;
- return (FALSE);
+ if (bustype == IS_EISA) {
+ bugs = bugs || BROKEN_INQUIRY;
+ } else {
+ if (gc->DMA_support == FALSE)
+ printk("HBA at %#.4x doesn't support DMA. Sorry\n", base);
+ else
+ printk("HBA at %#.4x does not react on INQUIRY. Sorry.\n",
+ base);
+ if (gc->DMA_valid)
+ free_dma(dma_channel);
+ reg_IRQ[gc->IRQ]--;
+ if (reg_IRQ[gc->IRQ] == 0)
+ free_irq(gc->IRQ);
+ if (gc->IRQ_TR == FALSE)
+ reg_IRQL[gc->IRQ] = FALSE;
+ return (FALSE);
+ }
}
if (gc->DMA_support == FALSE && buff != NULL)
- printk("HBA %.12sat %#.4lx doesn't set the DMA_support flag correctly.\n",
- &buff[16], base);
+ printk("HBA %.12sat %#.4x doesn't set the DMA_support flag correctly.\n",
+ &buff[16], base);
request_region(base, 9, "eata_dma"); /* We already checked the
- * availability, so this could
- * only fail if we're on
- * 0x1f0 or 0x170.
- */
-
+ * availability, so this
+ * should not fail.
+ */
+
if(ntohs(gc->queuesiz) == 0) {
- gc->queuesiz = ntohs(64);
- printk("Warning: Queue size had to be corrected.\n"
- "This might be a PM2012 with a defective Firmware\n");
+ gc->queuesiz = ntohs(64);
+ printk("Warning: Queue size has to be corrected. Assuming 64 queueslots\n"
+ " This might be a PM2012B with a defective Firmware\n");
}
- size = sizeof(hostdata) + ((sizeof(struct eata_ccb) * ntohs(gc->queuesiz))/
- (gc->MAX_CHAN + 1));
+ size = sizeof(hostdata) + ((sizeof(struct eata_ccb) + sizeof(long))
+ * ntohs(gc->queuesiz));
- if (gc->MAX_CHAN) {
- printk("This is a multichannel HBA. Linux doesn't support them,\n");
- printk("so we'll try to register every channel as a virtual HBA.\n");
+ DBG(DBG_REGISTER, printk("scsi_register size: %ld\n", size));
+
+ sh = scsi_register(tpnt, size);
+
+ if(sh == NULL) {
+ if (gc->DMA_valid)
+ free_dma(dma_channel);
+
+ reg_IRQ[gc->IRQ]--;
+ if (reg_IRQ[gc->IRQ] == 0)
+ free_irq(gc->IRQ);
+ if (gc->IRQ_TR == FALSE)
+ reg_IRQL[gc->IRQ] = FALSE;
+ return (FALSE);
}
- for (i = 0; i <= gc->MAX_CHAN; i++) {
-
- sh = scsi_register(tpnt, size);
-
- if(sh == NULL) {
- if (gc->DMA_valid)
- free_dma(dma_channel);
- reg_IRQ[gc->IRQ] -= 1;
- if (reg_IRQ[gc->IRQ] == 0)
- free_irq(gc->IRQ);
- if (!gc->IRQ_TR)
- reg_IRQL[gc->IRQ] = FALSE;
- return (FALSE);
- }
+ hd = SD(sh);
+
+ memset(hd->ccb, 0, sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
+ memset(hd->reads, 0, sizeof(u32) * 26);
- hd = SD(sh);
+ hd->broken_INQUIRY = (bugs & BROKEN_INQUIRY);
- memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)) /
- (gc->MAX_CHAN + 1));
- memset(hd->reads, 0, sizeof(ulong) * 26);
-
+ if(hd->broken_INQUIRY == TRUE) {
+ strcpy(SD(sh)->vendor, "DPT");
+ strcpy(SD(sh)->name, "??????????");
+ strcpy(SD(sh)->revision, "???.?");
+ } else {
strncpy(SD(sh)->vendor, &buff[8], 8);
SD(sh)->vendor[8] = 0;
strncpy(SD(sh)->name, &buff[16], 17);
SD(sh)->revision[3] = '.';
SD(sh)->revision[4] = buff[35];
SD(sh)->revision[5] = 0;
- switch (ntohl(gc->len)) {
- case 0x1c:
- SD(sh)->EATA_revision = 'a';
- break;
- case 0x1e:
- SD(sh)->EATA_revision = 'b';
- break;
- case 0x22:
- SD(sh)->EATA_revision = 'c';
- break;
- default:
- SD(sh)->EATA_revision = '?';
- }
- sh->base = (char *) base;
- sh->io_port = (ushort) base;
- sh->n_io_port = 9;
- sh->irq = gc->IRQ;
- sh->dma_channel = dma_channel;
- sh->this_id = gc->scsi_id[3 - i];
- sh->can_queue = ntohs(gc->queuesiz) / (gc->MAX_CHAN + 1);
-
- if (gc->OCS_enabled == TRUE) {
- sh->cmd_per_lun = sh->can_queue/C_P_L_DIV;
-#if 0 /* The memory management seems to be more stable now */
- if (sh->cmd_per_lun > C_P_L_CURRENT_MAX)
- sh->cmd_per_lun = C_P_L_CURRENT_MAX;
-#endif
- } else {
- sh->cmd_per_lun = 1;
- }
- sh->sg_tablesize = ntohs(gc->SGsiz);
- if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
- sh->sg_tablesize = SG_SIZE;
- if (ntohs(gc->SGsiz) == 0)
- printk("Warning: SG size had to be corrected.\n"
- "This might be a PM2012 with a defective Firmware\n");
- }
+ }
- hd->channel = i;
+ switch (ntohl(gc->len)) {
+ case 0x1c:
+ SD(sh)->EATA_revision = 'a';
+ break;
+ case 0x1e:
+ SD(sh)->EATA_revision = 'b';
+ break;
+ case 0x22:
+ SD(sh)->EATA_revision = 'c';
+ break;
+ case 0x24:
+ SD(sh)->EATA_revision = 'z';
+ default:
+ SD(sh)->EATA_revision = '?';
+ }
+ if(ntohl(gc->len) >= 0x22) {
+ if (gc->is_PCI == TRUE)
+ hd->bustype = IS_PCI;
+ else if (gc->is_EISA == TRUE)
+ hd->bustype = IS_EISA;
+ else
+ hd->bustype = IS_ISA;
+ } else if(hd->broken_INQUIRY == FALSE) {
if (buff[21] == '4')
- hd->bustype = 'P';
+ hd->bustype = IS_PCI;
else if (buff[21] == '2')
- hd->bustype = 'E';
+ hd->bustype = IS_EISA;
else
- hd->bustype = 'I';
+ hd->bustype = IS_ISA;
+ } else
+ hd->bustype = bustype;
+
+ if(ntohl(gc->len) >= 0x22) {
+ sh->max_id = gc->MAX_ID;
+ sh->max_lun = gc->MAX_LUN;
+ } else {
+ sh->max_id = 8;
+ sh->max_lun = 8;
+ }
- if (gc->SECOND)
- hd->primary = FALSE;
+ hd->channel = gc->MAX_CHAN;
+ sh->max_channel = gc->MAX_CHAN;
+ sh->base = (char *) base;
+ sh->io_port = (u16) base;
+ sh->n_io_port = 9;
+ sh->irq = gc->IRQ;
+ sh->dma_channel = dma_channel;
+
+ /* FIXME:
+ * SCSI midlevel code should support different HBA ids on every channel
+ */
+ sh->this_id = gc->scsi_id[3];
+ sh->can_queue = ntohs(gc->queuesiz);
+
+ if (gc->OCS_enabled == TRUE)
+ if(hd->bustype != IS_ISA)
+ sh->cmd_per_lun = sh->can_queue/C_P_L_DIV;
else
- hd->primary = TRUE;
-
- if (hd->bustype != 'I') {
- sh->unchecked_isa_dma = FALSE;
- sh->wish_block = FALSE;
- }
- else {
- sh->unchecked_isa_dma = TRUE; /* We're doing ISA DMA */
- sh->wish_block = TRUE; /* This will reduce performance */
- }
- if((hd->primary == TRUE) && (i == 0) && HARDCODED){
- geometry.drv[0].heads = HEADS0;
- geometry.drv[0].sectors = SECTORS0;
- geometry.drv[0].cylinder = CYLINDER0;
- geometry.drv[0].id = ID0;
- geometry.drv[0].trans = TRUE;
- geometry.drv[1].heads = HEADS1;
- geometry.drv[1].sectors = SECTORS1;
- geometry.drv[1].cylinder = CYLINDER1;
- geometry.drv[1].id = ID1;
- geometry.drv[1].trans = TRUE;
- } else {
- geometry.drv[0].id=-1;
- geometry.drv[1].id=-1;
+ sh->cmd_per_lun = 8;
+ else
+ sh->cmd_per_lun = 1;
+
+ /* FIXME:
+ * SG should be allocated more dynamically
+ */
+ /*
+ * If we are using a ISA board, we can't use extended SG,
+ * because we would need exessive amounts of memory for
+ * bounce buffers.
+ */
+ if (gc->SG_64K == TRUE && ntohs(gc->SGsiz) == 64 && hd->bustype != IS_ISA){
+ sh->sg_tablesize = SG_SIZE_BIG;
+ sh->use_clustering = FALSE;
+ } else {
+ sh->sg_tablesize = ntohs(gc->SGsiz);
+ sh->use_clustering = TRUE;
+ if (sh->sg_tablesize > SG_SIZE || sh->sg_tablesize == 0) {
+ sh->sg_tablesize = SG_SIZE;
+ if (ntohs(gc->SGsiz) == 0)
+ printk("Warning: SG size had to be corrected.\n"
+ "This might be a PM2012 with a defective Firmware\n");
}
-
- hd->next = NULL; /* build a linked list of all HBAs */
- hd->prev = last_HBA;
- if(hd->prev != NULL)
- SD(hd->prev)->next = sh;
- last_HBA = sh;
- if (first_HBA == NULL)
- first_HBA = sh;
- registered_HBAs++;
}
- return (1);
+
+ if (gc->SECOND)
+ hd->primary = FALSE;
+ else
+ hd->primary = TRUE;
+
+ sh->wish_block = FALSE;
+
+ if (hd->bustype != IS_ISA) {
+ sh->unchecked_isa_dma = FALSE;
+ } else {
+ sh->unchecked_isa_dma = TRUE; /* We're doing ISA DMA */
+ }
+
+ hd->next = NULL; /* build a linked list of all HBAs */
+ hd->prev = last_HBA;
+ if(hd->prev != NULL)
+ SD(hd->prev)->next = sh;
+ last_HBA = sh;
+ if (first_HBA == NULL)
+ first_HBA = sh;
+ registered_HBAs++;
+
+ return (TRUE);
}
-long find_EISA(struct get_conf *buf)
+void find_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
{
- struct eata_register *base;
+ u32 base;
int i;
-
+
#if CHECKPAL
- unsigned char pal1, pal2, pal3, *p;
+ u8 pal1, pal2, pal3;
#endif
-
+
for (i = 0; i < MAXEISA; i++) {
- if (EISAbases[i] == TRUE) { /* Still a possibility ? */
-
- base = (void *)0x1c88 + (i * 0x1000);
+ if (EISAbases[i] == TRUE) { /* Still a possibility ? */
+
+ base = 0x1c88 + (i * 0x1000);
#if CHECKPAL
- p = (char *)base;
- pal1 = *(p - 8);
- pal2 = *(p - 7);
- pal3 = *(p - 6);
-
+ pal1 = inb((u16)base - 8);
+ pal2 = inb((u16)base - 7);
+ pal3 = inb((u16)base - 6);
+
if (((pal1 == 0x12) && (pal2 == 0x14)) ||
((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) ||
((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
DBG(DBG_PROBE, printk("EISA EATA id tags found: %x %x %x \n",
- (int)pal1, (int)pal2, (int)pal3));
+ (int)pal1, (int)pal2, (int)pal3));
#endif
if (get_conf_PIO(base, buf) == TRUE) {
- DBG(DBG_PROBE&&DBG_EISA,print_config(buf));
- if (buf->IRQ) { /* We'll check the
- * primary/secondary stuff
- * later
- */
- EISAbases[i] = 0;
- return ((ulong)base);
- }
- printk("No valid IRQ. HBA removed from list\n");
+ DBG(DBG_PROBE && DBG_EISA, print_config(buf));
+ if (buf->IRQ) {
+ register_HBA(base, buf, tpnt, IS_EISA);
+ } else
+ printk("eata_dma: No valid IRQ. HBA removed from list\n");
+ } else {
+ if (check_blink_state(base))
+ printk("HBA is in BLINK state. Consult your HBAs "
+ " Manual to correct this.\n");
}
/* Nothing found here so we take it from the list */
EISAbases[i] = 0;
#endif
}
}
- return (0l); /* Nothing found :-( */
+ return;
}
-long find_ISA(struct get_conf *buf)
+void find_ISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
{
- int l;
- long ret;
-
- for (l = 0; l < MAXISA; l++) {
- if (ISAbases[l]) {
- if (get_conf_PIO((struct eata_register *)ISAbases[l],buf) == TRUE){
- ret = ISAbases[l];
- ISAbases[l] = 0;
- return (ret);
- } else
- ISAbases[l] = 0;
- }
+ int i;
+
+ for (i = 0; i < MAXISA; i++) {
+ if (ISAbases[i]) {
+ if (get_conf_PIO(ISAbases[i],buf) == TRUE){
+ register_HBA(ISAbases[i], buf, tpnt, IS_ISA);
+ } else {
+ if (check_blink_state(ISAbases[i]))
+ printk("HBA is in BLINK state. Consult your HBAs "
+ "Manual to correct this.\n");
+ }
+ ISAbases[i] = 0;
+ }
}
- return ((long)NULL);
+ return;
}
void find_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
#ifndef CONFIG_PCI
printk("Kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
#else
-
- unchar pci_bus, pci_device_fn;
- static short pci_index = 0; /* Device index to PCI BIOS calls */
- ulong base = 0;
- ushort com_adr;
- ushort rev_device;
- uint error, i, x;
+
+ u8 pci_bus, pci_device_fn;
+ static s16 pci_index = 0; /* Device index to PCI BIOS calls */
+ u32 base = 0;
+ u16 com_adr;
+ u16 rev_device;
+ u32 error, i, x;
if (pcibios_present()) {
for (i = 0; i <= MAXPCI; ++i, ++pci_index) {
-
if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT,
pci_index, &pci_bus, &pci_device_fn))
break;
- DBG(DBG_PROBE && DBG_PCI, printk("eata_dma: HBA at bus %d, device %d,"
- " function %d, index %d\n", (int)pci_bus,
- (int)((pci_device_fn & 0xf8) >> 3),
- (int)(pci_device_fn & 7), pci_index));
-
+ DBG(DBG_PROBE && DBG_PCI,
+ printk("eata_dma: HBA at bus %d, device %d,"
+ " function %d, index %d\n", (s32)pci_bus,
+ (s32)((pci_device_fn & 0xf8) >> 3),
+ (s32)(pci_device_fn & 7), pci_index));
+
if (!(error = pcibios_read_config_word(pci_bus, pci_device_fn,
- PCI_CLASS_DEVICE, &rev_device))) {
- if (rev_device == PCI_CLASS_STORAGE_SCSI) {
+ PCI_CLASS_DEVICE, &rev_device))) {
+ if (rev_device == PCI_CLASS_STORAGE_SCSI) {
if (!(error = pcibios_read_config_word(pci_bus,
- pci_device_fn, PCI_COMMAND,
- (ushort *) & com_adr))) {
- if (!((com_adr & PCI_COMMAND_IO) &&
+ pci_device_fn, PCI_COMMAND,
+ (u16 *) & com_adr))) {
+ if (!((com_adr & PCI_COMMAND_IO) &&
(com_adr & PCI_COMMAND_MASTER))) {
printk("HBA has IO or BUSMASTER mode disabled\n");
continue;
}
} else
- printk("error %x while reading PCI_COMMAND\n", error);
- } else
- printk("DEVICECLASSID %x didn't match\n", rev_device);
+ printk("eata_dma: error %x while reading "
+ "PCI_COMMAND\n", error);
+ } else
+ printk("DEVICECLASSID %x didn't match\n", rev_device);
} else {
- printk("error %x while reading PCI_CLASS_BASE\n", error);
- continue;
+ printk("eata_dma: error %x while reading PCI_CLASS_BASE\n",
+ error);
+ continue;
}
-
+
if (!(error = pcibios_read_config_dword(pci_bus, pci_device_fn,
- PCI_BASE_ADDRESS_0, &base))){
-
- /* Check if the address is valid */
- if (base & 0x01) {
+ PCI_BASE_ADDRESS_0, (int *) &base))){
+
+ /* Check if the address is valid */
+ if (base & 0x01) {
base &= 0xfffffffe;
- /* EISA tag there ? */
+ /* EISA tag there ? */
if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
- continue; /* Jep, it's forced, so move on */
- base += 0x10; /* Now, THIS is the real address */
+ continue; /* Jep, it's forced, so move on */
+ base += 0x10; /* Now, THIS is the real address */
if (base != 0x1f8) {
- /* We didn't find it in the primary search */
- if (get_conf_PIO((struct eata_register *)base, buf)) {
- if (buf->FORCADR) /* If the address is forced */
- continue; /* we'll find it later */
-
+ /* We didn't find it in the primary search */
+ if (get_conf_PIO(base, buf) == TRUE) {
+ if (buf->FORCADR) /* If the address is forced */
+ continue; /* we'll find it later */
+
/* OK. We made it till here, so we can go now
* and register it. We only have to check and
* eventually remove it from the EISA and ISA list
*/
-
- register_HBA(base, buf, tpnt);
-
+
+ register_HBA(base, buf, tpnt, IS_PCI);
+
if (base < 0x1000) {
- for (x = 0; x < MAXISA; ++x) {
+ for (x = 0; x < MAXISA; ++x) {
if (ISAbases[x] == base) {
- ISAbases[x] = 0;
+ ISAbases[x] = 0;
break;
}
- }
+ }
} else if ((base & 0x0fff) == 0x0c88) {
- x = (base >> 12) & 0x0f;
+ x = (base >> 12) & 0x0f;
EISAbases[x] = 0;
}
- continue; /*break;*/
- } else if (check_blink_state(base)) {
- printk("HBA is in BLINK state. Consult your HBAs "
- " Manual to correct this.\n");
+ continue; /* break; */
+ } else if (check_blink_state(base) == TRUE) {
+ printk("eata_dma: HBA is in BLINK state.\n"
+ "Consult your HBAs Manual to correct this.\n");
}
}
}
} else
- printk("error %x while reading PCI_BASE_ADDRESS_0\n", error);
+ printk("eata_dma: error %x while reading "
+ "PCI_BASE_ADDRESS_0\n", error);
}
} else
- printk("No BIOS32 extensions present. This release still depends on it."
- " Sorry.\n");
+ printk("No BIOS32 extensions present. This eata_dma release "
+ "still depends on it.\nSkipping scan for PCI HBAs. Sorry.\n");
#endif /* #ifndef CONFIG_PCI */
return;
}
{
struct Scsi_Host *HBA_ptr;
struct get_conf gc;
- ulong base = 0;
int i;
-
- geometry.drv[0].trans = geometry.drv[1].trans = 0;
-
- DBG((DBG_PROBE && DBG_DELAY)|| DPT_DEBUG,
+
+ DBG((DBG_PROBE && DBG_DELAY) || DPT_DEBUG,
printk("Using lots of delays to let you read the debugging output\n"));
status = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA);
dma_scratch = scsi_init_malloc(512, GFP_ATOMIC | GFP_DMA);
find_PCI(&gc, tpnt);
-
- for (i = 0; i < MAXEISA; i++) {
- base = find_EISA(&gc);
- if (base)
- register_HBA(base, &gc, tpnt);
- }
-
- for (i = 0; i <= MAXISA; i++) {
- base = find_ISA(&gc);
- if (base)
- register_HBA(base, &gc, tpnt);
- }
-
+
+ find_EISA(&gc, tpnt);
+
+ find_ISA(&gc, tpnt);
+
for (i = 0; i <= MAXIRQ; i++)
if (reg_IRQ[i]){
free_irq(i);
- request_irq(i, eata_int_handler, SA_INTERRUPT, "EATA-DMA");
+ request_irq(i, (void *)(eata_int_handler), SA_INTERRUPT, "eata_dma");
}
-
+
HBA_ptr = first_HBA;
-
+
if (registered_HBAs != 0) {
- printk("EATA (Extended Attachment) driver version: %d.%d%s\n"
+ printk("EATA (Extended Attachment) driver version: %d.%d%s\n"
"developed in co-operation with DPT\n"
- "(c) 1993-95 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de\n",
+ "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n",
VER_MAJOR, VER_MINOR, VER_SUB);
- printk("Registered HBAs:\n");
- printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: DMA: Ch: ID: Pr: QS: SG: CPL:\n");
- for (i = 1; i <= registered_HBAs; i++) {
- printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4lx %2d",
- HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
- SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')?
- "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
- (u32) HBA_ptr->base, HBA_ptr->irq);
- if(HBA_ptr->dma_channel != 0xff)
- printk(" %2x ", HBA_ptr->dma_channel);
- else
- printk(" %s", "BMST");
- printk(" %d %d %c %2d %2d %2d\n", SD(HBA_ptr)->channel,
- HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N',
- HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
- HBA_ptr = SD(HBA_ptr)->next;
+ printk("Registered HBAs:");
+ printk("\nHBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: DMA: Ch: "
+ "ID: Pr: QS: SG: CPL:\n");
+ for (i = 1; i <= registered_HBAs; i++) {
+ printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4x %2d",
+ HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
+ SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')?
+ "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
+ (u32) HBA_ptr->base, HBA_ptr->irq);
+ if(HBA_ptr->dma_channel != 0xff)
+ printk(" %2x ", HBA_ptr->dma_channel);
+ else
+ printk(" %s", "BMST");
+ printk(" %d %d %c %2d %2d %2d\n", SD(HBA_ptr)->channel,
+ HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N',
+ HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+ HBA_ptr = SD(HBA_ptr)->next;
+ }
+ } else {
+ scsi_init_free((void *)status, 512);
}
- } else
- scsi_init_free((void *)status, 512);
-
+
scsi_init_free((void *)dma_scratch, 512);
- DBG(DPT_DEBUG,DELAY(1200));
+ DBG(DPT_DEBUG, DELAY(1200));
- return (registered_HBAs);
+ return(registered_HBAs);
}
#ifdef MODULE
/* Eventually this will go into an include file, but this will be later */
Scsi_Host_Template driver_template = EATA_DMA;
-
#include "scsi_module.c"
#endif
-
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
* Header file for eata_dma.c Linux EATA-DMA SCSI driver *
* (c) 1993,94,95 Michael Neuffer *
*********************************************************
-* last change: 95/04/10 *
+* last change: 95/06/20 *
********************************************************/
#ifndef _EATA_DMA_H
#define _EATA_DMA_H
-#define VER_MAJOR 2
-#define VER_MINOR 3
-#define VER_SUB "5r"
+#ifndef HOSTS_C
-/************************************************************************
- * Here you can configure your drives that are using a non-standard *
- * geometry. *
- * To enable this set HARDCODED to 1 *
- * If you have only one drive that need reconfiguration, set ID1 to -1 *
- ************************************************************************/
-#define HARDCODED 0 /* Here are drives running in emu. mode */
+#include "eata_generic.h"
+
+
+#define VER_MAJOR 2
+#define VER_MINOR 5
+#define VER_SUB "6a"
-#define ID0 0 /* SCSI ID of "IDE" drive mapped to C:
- * If you're not sure check your config
- * utility that came with your controller
- */
-#define HEADS0 13 /* Number of emulated heads of this drive */
-#define SECTORS0 38 /* Number of emulated sectors */
-#define CYLINDER0 719 /* Number of emulated cylinders */
-
-#define ID1 1 /* SCSI ID of "IDE" drive mapped to D: */
-#define HEADS1 16 /* Number of emulated heads of this drive */
-#define SECTORS1 62 /* Number of emulated sectors */
-#define CYLINDER1 1024 /* Number of emulated cylinders */
/************************************************************************
* Here you can switch parts of the code on and of *
************************************************************************/
#define CHECKPAL 0 /* EISA pal checking on/off */
-#define EATA_DMA_PROC 0 /* proc-fs support */
/************************************************************************
* Debug options. *
* Enable DEBUG and whichever options you require. *
************************************************************************/
-#define DEBUG_EATA 1 /* Enable debug code. */
+#define DEBUG_EATA 1 /* Enable debug code. */
#define DPT_DEBUG 0 /* Bobs special */
-#define DBG_DELAY 0 /* Build in delays so debug messages can be
+#define DBG_DELAY 0 /* Build in delays so debug messages can be
* be read before they vanish of the top of
- * the screen!
- */
-#define DBG_PROBE 0 /* Debug probe routines. */
+ * the screen! */
+#define DBG_PROBE 0 /* Debug probe routines. */
#define DBG_PCI 0 /* Trace PCI routines */
#define DBG_EISA 0 /* Trace EISA routines */
#define DBG_ISA 0 /* Trace ISA routines */
#define DBG_BLINK 0 /* Trace Blink check */
#define DBG_PIO 0 /* Trace get_config_PIO */
-#define DBG_COM 0 /* Trace command call */
-#define DBG_QUEUE 0 /* Trace command queueing. */
-#define DBG_INTR 0 /* Trace interrupt service routine. */
-#define DBG_INTR2 0 /* Trace interrupt service routine. */
-#define DBG_INTR3 0 /* Trace interrupt service routine. */
+#define DBG_COM 0 /* Trace command call */
+#define DBG_QUEUE 0 /* Trace command queueing. */
+#define DBG_QUEUE2 0 /* Trace command queueing SG. */
+#define DBG_INTR 0 /* Trace interrupt service routine. */
+#define DBG_INTR2 0 /* Trace interrupt service routine. */
+#define DBG_INTR3 0 /* Trace get_board_data interrupts. */
#define DBG_PROC 0 /* Debug proc-fs related statistics */
+#define DBG_PROC_WRITE 0
#define DBG_REGISTER 0 /* */
-#define DBG_ABNORM 1 /* Debug abnormal actions (reset, abort)*/
+#define DBG_ABNORM 1 /* Debug abnormal actions (reset, abort)*/
#if DEBUG_EATA
-#define DBG(x, y) if ((x)) {y;}
+#define DBG(x, y) if ((x)) {y;}
#else
#define DBG(x, y)
#endif
-
-#define EATA_DMA { \
- NULL, NULL, \
- "EATA (Extended Attachment) driver", \
- eata_detect, \
- eata_release, \
- eata_info, \
- eata_command, \
- eata_queue, \
- eata_abort, \
- eata_reset, \
- NULL, /* Slave attach */ \
- scsicam_bios_param, \
- 0, /* Canqueue */ \
- 0, /* this_id */ \
- 0, /* sg_tablesize */ \
- 0, /* cmd_per_lun */ \
- 0, /* present */ \
- 1, /* True if ISA */ \
- ENABLE_CLUSTERING }
+#endif /* !HOSTS_C */
int eata_detect(Scsi_Host_Template *);
const char *eata_info(struct Scsi_Host *);
int eata_command(Scsi_Cmnd *);
-int eata_queue(Scsi_Cmnd *, void *(done)(Scsi_Cmnd *));
+int eata_queue(Scsi_Cmnd *, void (* done)(Scsi_Cmnd *));
int eata_abort(Scsi_Cmnd *);
int eata_reset(Scsi_Cmnd *);
+int eata_proc_info(char *, char **, off_t, int, int, int);
+#ifdef MODULE
int eata_release(struct Scsi_Host *);
-
-/*********************************************
- * Misc. definitions *
- *********************************************/
-
-#ifndef TRUE
-# define TRUE 1
-#endif
-#ifndef FALSE
-# define FALSE 0
+#else
+#define eata_release NULL
#endif
-#define R_LIMIT 0x20000
-
-#define MAXISA 4
-#define MAXEISA 16
-#define MAXPCI 16
-#define MAXIRQ 16
-#define MAXTARGET 8
-
-#define MAX_PCI_DEVICES 32 /* Maximum # Of Devices Per Bus */
-#define MAX_METHOD_2 16 /* Max Devices For Method 2 */
-#define MAX_PCI_BUS 16 /* Maximum # Of Busses Allowed */
-
-#define SG_SIZE 64
-
-#define C_P_L_CURRENT_MAX 16 /* Until this limit in the mm is removed
- * Kernels < 1.1.86 died horrible deaths
- * if you used values >2. The memory management
- * since pl1.1.86 seems to cope with up to 10
- * queued commands per device.
- * Since 1.2.0 the memory management seems to
- * have no more problems......
- */
-#define C_P_L_DIV 3 /* 1 <= C_P_L_DIV <= 8
- * You can use this parameter to fine-tune
- * the driver. Depending on the number of
- * devices and their speed and ability to queue
- * commands, you will get the best results with a
- * value
- * ~= numdevices-(devices_unable_to_queue_commands/2)
- * The reason for this is that the disk driver
- * tends to flood the queue, so that other
- * drivers have problems to queue commands
- * themselves. This can for example result in
- * the effect that the tape stops during disk
- * accesses.
- */
-
-#define FREE 0
-#define USED 1
-#define TIMEOUT 2
-#define RESET 4
-#define LOCKED 8
-
-#define HD(cmd) ((hostdata *)&(cmd->host->hostdata))
-#define CD(cmd) ((struct eata_ccb *)(cmd->host_scribble))
-#define SD(host) ((hostdata *)&(host->hostdata))
-
-#define DELAY(x) { int i; i = jiffies + x; while (jiffies < i); }
-#define DEL2(x) { ulong i; for (i = 0; i < 0xffff*x; i++); }
-
-/***********************************************
- * EATA Command & Register definitions *
- ***********************************************/
-#define PCI_REG_DPTconfig 0x40
-#define PCI_REG_PumpModeAddress 0x44
-#define PCI_REG_PumpModeData 0x48
-#define PCI_REG_ConfigParam1 0x50
-#define PCI_REG_ConfigParam2 0x54
-
-
-#define EATA_CMD_PIO_READ_CONFIG 0xf0
-#define EATA_CMD_PIO_SET_CONFIG 0xf1
-#define EATA_CMD_PIO_SEND_CP 0xf2
-#define EATA_CMD_PIO_RECEIVE_SP 0xf3
-#define EATA_CMD_PIO_TRUNC 0xf4
-
-#define EATA_CMD_RESET 0xf9
-
-#define EATA_CMD_DMA_READ_CONFIG 0xfd
-#define EATA_CMD_DMA_SET_CONFIG 0xfe
-#define EATA_CMD_DMA_SEND_CP 0xff
-
-#define ECS_EMULATE_SENSE 0xd4
-
-#define HA_WCOMMAND 0x07 /* command register offset */
-#define HA_WDMAADDR 0x02 /* DMA address LSB offset */
-#define HA_RAUXSTAT 0x08 /* aux status register offset*/
-#define HA_RSTATUS 0x07 /* status register offset */
-#define HA_RDATA 0x00 /* data register (16bit) */
-
-#define HA_ABUSY 0x01 /* aux busy bit */
-#define HA_AIRQ 0x02 /* aux IRQ pending bit */
-#define HA_SERROR 0x01 /* pr. command ended in error*/
-#define HA_SMORE 0x02 /* more data soon to come */
-#define HA_SCORR 0x04 /* data corrected */
-#define HA_SDRQ 0x08 /* data request active */
-#define HA_SSC 0x10 /* seek complete */
-#define HA_SFAULT 0x20 /* write fault */
-#define HA_SREADY 0x40 /* drive ready */
-#define HA_SBUSY 0x80 /* drive busy */
-#define HA_SDRDY HA_SSC+HA_SREADY+HA_SDRQ
-
-#define HA_NO_ERROR 0x00
-#define HA_ERR_SEL_TO 0x01
-#define HA_ERR_CMD_TO 0x02
-#define HA_ERR_RESET 0x03
-#define HA_INIT_POWERUP 0x04
-#define HA_UNX_BUSPHASE 0x05
-#define HA_UNX_BUS_FREE 0x06
-#define HA_BUS_PARITY 0x07
-#define HA_SCSI_HUNG 0x08
-#define HA_UNX_MSGRJCT 0x09
-#define HA_RESET_STUCK 0x0a
-#define HA_RSENSE_FAIL 0x0b
-#define HA_PARITY_ERR 0x0c
-#define HA_CP_ABORT_NA 0x0d
-#define HA_CP_ABORTED 0x0e
-#define HA_CP_RESET_NA 0x0f
-#define HA_CP_RESET 0x10
-
-/**********************************************
- * Message definitions *
- **********************************************/
-
-struct reg_bit { /* reading this one will clear the interrupt */
- unchar error:1; /* previous command ended in an error */
- unchar more:1; /* more DATA coming soon, poll BSY & DRQ (PIO) */
- unchar corr:1; /* data read was successfully corrected with ECC*/
- unchar drq:1; /* data request active */
- unchar sc:1; /* seek complete */
- unchar fault:1; /* write fault */
- unchar ready:1; /* drive ready */
- unchar busy:1; /* controller busy */
-};
-
-struct reg_abit { /* reading this won't clear the interrupt */
- unchar abusy:1; /* auxiliary busy */
- unchar irq:1; /* set when drive interrupt is asserted */
- unchar dummy:6;
-};
-
-struct eata_register { /* EATA register set */
- unchar data_reg[2]; /* R, couldn't figure this one out */
- unchar cp_addr[4]; /* W, CP address register */
- union {
- unchar command; /* W, command code: [read|set] conf, send CP*/
- struct reg_bit status; /* R, see register_bit1 */
- unchar statusunchar;
- } ovr;
- struct reg_abit aux_stat; /* R, see register_bit2 */
-};
-
-/**********************************************
- * Other definitions *
- **********************************************/
-
-struct eata_sg_list
-{
- ulong data;
- ulong len;
-};
-
-struct get_conf { /* Read Configuration Array */
- ulong len; /* Should return 0x22 */
- unchar sig[4]; /* Signature MUST be "EATA" */
- unchar version2:4,
- version:4; /* EATA Version level */
- unchar OCS_enabled:1, /* Overlap Command Support enabled */
- TAR_support:1, /* SCSI Target Mode supported */
- TRNXFR:1, /* Truncate Transfer Cmd not necessary */
- /* Only used in PIO Mode */
- MORE_support:1, /* MORE supported (only PIO Mode) */
- DMA_support:1, /* DMA supported Driver uses only */
- /* this mode */
- DMA_valid:1, /* DRQ value in Byte 30 is valid */
- ATA:1, /* ATA device connected (not supported) */
- HAA_valid:1; /* Hostadapter Address is valid */
-
- ushort cppadlen; /* Number of pad unchars send after CD data */
- /* set to zero for DMA commands */
- unchar scsi_id[4]; /* SCSI ID of controller 2-0 Byte 0 res. */
- /* if not, zero is returned */
- ulong cplen; /* CP length: number of valid cp unchars */
- ulong splen; /* Number of unchars returned after */
- /* Receive SP command */
- ushort queuesiz; /* max number of queueable CPs */
- ushort dummy;
- ushort SGsiz; /* max number of SG table entries */
- unchar IRQ:4, /* IRQ used this HA */
- IRQ_TR:1, /* IRQ Trigger: 0=edge, 1=level */
- SECOND:1, /* This is a secondary controller */
- DMA_channel:2; /* DRQ index, DRQ is 2comp of DRQX */
- unchar sync; /* device at ID 7 tru 0 is running in */
- /* synchronous mode, this will disappear */
- unchar DSBLE:1, /* ISA i/o addressing is disabled */
- FORCADR:1, /* i/o address has been forced */
- :6;
- unchar MAX_ID:5, /* Max number of SCSI target IDs */
- MAX_CHAN:3; /* Number of SCSI busses on HBA */
- unchar MAX_LUN; /* Max number of LUNs */
- unchar :5,
- ID_qest:1, /* Raidnum ID is questionable */
- is_PCI:1, /* HBA is PCI */
- is_EISA:1; /* HBA is EISA */
- unchar unused[478];
-};
-
-struct eata_ccb { /* Send Command Packet structure */
-
- unchar SCSI_Reset:1, /* Cause a SCSI Bus reset on the cmd */
- HBA_Init:1, /* Cause Controller to reinitialize */
- Auto_Req_Sen:1, /* Do Auto Request Sense on errors */
- scatter:1, /* Data Ptr points to a SG Packet */
- Resrvd:1, /* RFU */
- Interpret:1, /* Interpret the SCSI cdb of own use */
- DataOut:1, /* Data Out phase with command */
- DataIn:1; /* Data In phase with command */
- unchar reqlen; /* Request Sense Length */
- /* Valid if Auto_Req_Sen=1 */
- unchar unused[3];
- unchar FWNEST:1, /* send cmd to phys RAID component*/
- unused2:7;
- unchar Phsunit:1, /* physical unit on mirrored pair */
- I_AT:1, /* inhibit address translation */
- I_HBA_C:1, /* HBA Inhibit caching */
- unused3:5;
-
- unchar cp_id; /* SCSI Device ID of target */
- unchar cp_lun:3,
- :2,
- cp_luntar:1, /* CP is for target ROUTINE */
- cp_dispri:1, /* Grant disconnect privilege */
- cp_identify:1; /* Always TRUE */
- unchar cp_msg1; /* Message bytes 0-3 */
- unchar cp_msg2;
- unchar cp_msg3;
- unchar cp_cdb[12]; /* Command Descriptor Block */
- ulong cp_datalen; /* Data Transfer Length */
- /* If scatter=1 len of sg package */
- void *cp_viraddr; /* address of this ccb */
- ulong cp_dataDMA; /* Data Address, if scatter=1 */
- /* address of scatter packet */
- ulong cp_statDMA; /* address for Status Packet */
- ulong cp_reqDMA; /* Request Sense Address, used if */
- /* CP command ends with error */
-
- ulong timeout;
- unchar retries;
- unchar status; /* status of this queueslot */
- struct eata_sg_list sg_list[SG_SIZE];
- Scsi_Cmnd *cmd; /* address of cmd */
-};
-
-
-struct eata_sp {
- unchar hba_stat:7, /* HBA status */
- EOC:1; /* True if command finished */
- unchar scsi_stat; /* Target SCSI status */
- unchar reserved[2];
- ulong residue_len; /* Number of unchars not transferred */
- struct eata_ccb *ccb; /* Address set in COMMAND PACKET */
- unchar msg[12];
-};
-
-typedef struct hstd {
- char vendor[9];
- char name[18];
- char revision[6];
- char EATA_revision;
- unchar bustype; /* bustype of HBA */
- unchar channel; /* no. of scsi channel */
- unchar state; /* state of HBA */
- unchar primary; /* true if primary */
- ulong reads[13];
- ulong writes[13];
- unchar t_state[MAXTARGET]; /* state of Target (RESET,..) */
- uint t_timeout[MAXTARGET]; /* timeouts on target */
- uint last_ccb; /* Last used ccb */
- struct Scsi_Host *next;
- struct Scsi_Host *prev;
- struct eata_sp sp; /* status packet */
- struct eata_ccb ccb[0]; /* ccb array begins here */
-}hostdata;
-
-
-
-/* structure for max. 2 emulated drives */
-struct drive_geom_emul {
- unchar trans; /* translation flag 1=transl */
- unchar channel; /* SCSI channel number */
- unchar HBA; /* HBA number (prim/sec) */
- unchar id; /* drive id */
- unchar lun; /* drive lun */
- uint heads; /* number of heads */
- uint sectors; /* number of sectors */
- uint cylinder; /* number of cylinders */
-};
+#define EATA_DMA { \
+ NULL, NULL, \
+ eata_proc_info,/* procinfo */ \
+ "eata_dma", /* proc dir entry */ \
+ PROC_SCSI_EATA,/* proc dir inode */ \
+ "EATA (Extended Attachment) driver", \
+ eata_detect, \
+ eata_release, \
+ NULL, NULL, \
+ eata_queue, \
+ eata_abort, \
+ eata_reset, \
+ NULL, /* Slave attach */ \
+ scsicam_bios_param, \
+ 0, /* Canqueue */ \
+ 0, /* this_id */ \
+ 0, /* sg_tablesize */ \
+ 0, /* cmd_per_lun */ \
+ 0, /* present */ \
+ 1, /* True if ISA */ \
+ ENABLE_CLUSTERING }
-struct geom_emul {
- int bios_drives; /* number of emulated drives */
- struct drive_geom_emul drv[2]; /* drive structures */
-};
-#endif /* _EATA_H */
+#endif /* _EATA_DMA_H */
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+
+#define MAX_SCSI_DEVICE_CODE 10
+const char *const scsi_dev_types[MAX_SCSI_DEVICE_CODE] =
+{
+ "Direct-Access ",
+ "Sequential-Access",
+ "Printer ",
+ "Processor ",
+ "WORM ",
+ "CD-ROM ",
+ "Scanner ",
+ "Optical Device ",
+ "Medium Changer ",
+ "Communications "
+};
+
+
+void swap_statistics(u8 *p)
+{
+ u32 y;
+ u32 *lp, h_lp;
+ u16 *sp, h_sp;
+ u8 *bp;
+
+ lp = (u32 *)p;
+ sp = ((short *)lp) + 1; /* Convert Header */
+ h_sp = *sp = ntohs(*sp);
+ lp++;
+
+ do {
+ sp = (u16 *)lp; /* Convert SubHeader */
+ *sp = ntohs(*sp);
+ bp = (u8 *) lp;
+ y = *(bp + 3);
+ lp++;
+ for (h_lp = (u32)lp; (u32)lp < h_lp + ((u32)*(bp + 3)); lp++)
+ *lp = ntohl(*lp);
+ }while ((u32)lp < ((u32)p) + 4 + h_sp);
+
+}
+
+/*
+ * eata_set_info
+ * buffer : pointer to the data that has been written to the hostfile
+ * length : number of bytes written to the hostfile
+ * HBA_ptr: pointer to the Scsi_Host struct
+ */
+int eata_set_info(char *buffer, int length, struct Scsi_Host *HBA_ptr)
+{
+ DBG(DBG_PROC_WRITE, printk("%s\n", buffer));
+ return(-ENOSYS); /* Currently this is a no-op */
+}
+
+/*
+ * eata_proc_info
+ * inout : decides on the direction of the dataflow and the meaning of the variables
+ * buffer: If inout==FALSE data is beeing written to it else read from it
+ * *start: If inout==FALSE start of the valid data in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer else number of bytes in the buffer
+ */
+int eata_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+{
+
+ Scsi_Device *scd;
+ struct Scsi_Host *HBA_ptr;
+ Scsi_Cmnd scmd;
+ static u8 buff[512];
+ static u8 buff2[512];
+ hst_cmd_stat *rhcs, *whcs;
+ coco *cc;
+ scsitrans *st;
+ scsimod *sm;
+ hobu *hb;
+ scbu *sb;
+ boty *bt;
+ memco *mc;
+ firm *fm;
+ subinf *si;
+ pcinf *pi;
+ arrlim *al;
+ int i, x;
+ int size, len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+
+ HBA_ptr = first_HBA;
+ for (i = 1; i <= registered_HBAs; i++) {
+ if (HBA_ptr->host_no == hostno)
+ break;
+ HBA_ptr = SD(HBA_ptr)->next;
+ }
+
+ if(inout == TRUE) /* Has data been writen to the file ? */
+ return(eata_set_info(buffer, length, HBA_ptr));
+
+ if (offset == 0)
+ memset(buff, 0, sizeof(buff));
+
+ cc = (coco *) (buff + 0x148);
+ st = (scsitrans *)(buff + 0x164);
+ sm = (scsimod *) (buff + 0x16c);
+ hb = (hobu *) (buff + 0x172);
+ sb = (scbu *) (buff + 0x178);
+ bt = (boty *) (buff + 0x17e);
+ mc = (memco *) (buff + 0x186);
+ fm = (firm *) (buff + 0x18e);
+ si = (subinf *) (buff + 0x196);
+ pi = (pcinf *) (buff + 0x19c);
+ al = (arrlim *) (buff + 0x1a2);
+
+ size = sprintf(buffer+len, "EATA (Extended Attachment) driver version: "
+ "%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
+ len += size; pos = begin + len;
+ size = sprintf(buffer + len, "queued commands: %10ld\n"
+ "processed interrupts:%10ld\n", queue_counter, int_counter);
+ len += size; pos = begin + len;
+
+ if(SD(HBA_ptr)->bustype == IS_EISA)
+ goto devices;
+
+ scmd.cmnd[0] = LOG_SENSE;
+ scmd.cmnd[1] = 0;
+ scmd.cmnd[2] = 0x33 + (3<<6);
+ scmd.cmnd[3] = 0;
+ scmd.cmnd[4] = 0;
+ scmd.cmnd[5] = 0;
+ scmd.cmnd[6] = 0;
+ scmd.cmnd[7] = 0x00;
+ scmd.cmnd[8] = 0x66;
+ scmd.cmnd[9] = 0;
+ scmd.cmd_len = 10;
+
+ scmd.host = HBA_ptr;
+ scmd.target = HBA_ptr->this_id;
+ scmd.lun = 0;
+ scmd.channel = 0;
+
+ scmd.use_sg = 0;
+ scmd.request_bufflen = 0x66;
+ scmd.request_buffer = buff + 0x144;
+ HBA_interpret = TRUE;
+
+ eata_queue(&scmd, (void *) eata_scsi_done);
+ while (internal_command_finished == FALSE)
+ barrier();
+
+ size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
+ HBA_ptr->host_no, SD(HBA_ptr)->name);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "Firmware revision: v%s\n",
+ SD(HBA_ptr)->revision);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "Hardware Configuration:\n");
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "IRQ: %2d, %s triggered\n", cc->interrupt,
+ (cc->intt == TRUE)?"level":"edge");
+ len += size;
+ pos = begin + len;
+ if (HBA_ptr->dma_channel == 0xff)
+ size = sprintf(buffer + len, "DMA: BUSMASTER\n");
+ else
+ size = sprintf(buffer + len, "DMA: %d\n", HBA_ptr->dma_channel);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "CPU: MC680%02d %dMHz\n", bt->cpu_type,
+ bt->cpu_speed);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "Host Bus: %s\n",
+ (SD(HBA_ptr)->bustype == IS_PCI)?"PCI ":
+ (SD(HBA_ptr)->bustype == IS_EISA)?"EISA":"ISA ");
+
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "SCSI Bus:%s%s Speed: %sMB/sec. %s\n",
+ (sb->wide == TRUE)?" WIDE":"",
+ (sb->dif == TRUE)?" DIFFERENTIAL":"",
+ (sb->speed == 0)?"5":(sb->speed == 1)?"10":"20",
+ (sb->ext == TRUE)?"With external cable detection":"");
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "SCSI channel expansion Module: %s installed\n",
+ (bt->sx1 == TRUE)?"SX1 (one channel)":
+ ((bt->sx2 == TRUE)?"SX2 (two channels)":"not"));
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "SmartRAID hardware: %spresent.\n",
+ (cc->srs == TRUE)?"":"not ");
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, " Type: %s\n",
+ ((cc->key == TRUE)?((bt->dmi == TRUE)?"integrated"
+ :((bt->dm4 == TRUE)?"DM401X"
+ :(bt->dm4k == TRUE)?"DM4000"
+ :"-"))
+ :"-"));
+ len += size;
+ pos = begin + len;
+
+ size = sprintf(buffer + len, " Max array groups: %d\n",
+ (al->code == 0x0e)?al->max_groups:7);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, " Max drives per RAID 0 array: %d\n",
+ (al->code == 0x0e)?al->raid0_drv:7);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, " Max drives per RAID 3/5 array: %d\n",
+ (al->code == 0x0e)?al->raid35_drv:7);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "Cache Module: %sinstalled.\n",
+ (cc->csh)?"":"not ");
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, " Type: %s\n",
+ ((cc->csh == TRUE)?((bt->cmi == TRUE)?"integrated"
+ :((bt->cm4 == TRUE)?"CM401X"
+ :((bt->cm4k == TRUE)?"CM4000"
+ :"-")))
+ :"-"));
+ len += size;
+ pos = begin + len;
+ for (x = 0; x <= 3; x++) {
+ size = sprintf(buffer + len, " Bank%d: %dMB with%s ECC\n",x,
+ mc->banksize[x] & 0x7f,
+ (mc->banksize[x] & 0x80)?"":"out");
+ len += size;
+ pos = begin + len;
+ }
+ size = sprintf(buffer + len, "Timer Modification: %sinstalled\n",
+ (cc->tmr == TRUE)?"":"not ");
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "NVRAM: %spresent\n",
+ (cc->nvr == TRUE)?"":"not ");
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "SmartROM: %senabled\n",
+ (bt->srom == TRUE)?"not ":"");
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "HBA indicates %salarm.\n",
+ (bt->alrm == TRUE)?"":"no ");
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+
+ scmd.cmnd[0] = LOG_SENSE;
+ scmd.cmnd[1] = 0;
+ scmd.cmnd[2] = 0x32 + (3<<6);
+ scmd.cmnd[3] = 0;
+ scmd.cmnd[4] = 0;
+ scmd.cmnd[5] = 0;
+ scmd.cmnd[6] = 0;
+ scmd.cmnd[7] = 0x01;
+ scmd.cmnd[8] = 0x44;
+ scmd.cmnd[9] = 0;
+ scmd.cmd_len = 10;
+ scmd.host = HBA_ptr;
+ scmd.target = HBA_ptr->this_id;
+ scmd.lun = 0;
+ scmd.channel = 0;
+ scmd.use_sg = 0;
+ scmd.request_bufflen = 0x144;
+ scmd.request_buffer = buff2;
+ HBA_interpret = TRUE;
+
+ eata_queue(&scmd, (void *) eata_scsi_done);
+ while (internal_command_finished == FALSE)
+ barrier();
+
+ swap_statistics(buff2);
+ rhcs = (hst_cmd_stat *)(buff2 + 0x2c);
+ whcs = (hst_cmd_stat *)(buff2 + 0x8c);
+
+ for (x = 0; x <= 11; x++) {
+ SD(HBA_ptr)->reads[x] += rhcs->sizes[x];
+ SD(HBA_ptr)->writes[x] += whcs->sizes[x];
+ SD(HBA_ptr)->reads[12] += rhcs->sizes[x];
+ SD(HBA_ptr)->writes[12] += whcs->sizes[x];
+ }
+ size = sprintf(buffer + len, "Host Disk Command Statistics:\n"
+ " Reads: Writes:\n");
+ len += size;
+ pos = begin + len;
+ for (x = 0; x <= 10; x++) {
+ size = sprintf(buffer+len,"%5dk:%12u %12u\n", 1 << x,
+ SD(HBA_ptr)->reads[x],
+ SD(HBA_ptr)->writes[x]);
+ len += size;
+ pos = begin + len;
+ }
+ size = sprintf(buffer+len,">1024k:%12u %12u\n",
+ SD(HBA_ptr)->reads[11],
+ SD(HBA_ptr)->writes[11]);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer+len,"Sum :%12u %12u\n",
+ SD(HBA_ptr)->reads[12],
+ SD(HBA_ptr)->writes[12]);
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+
+ devices:
+ scd = scsi_devices;
+
+ size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+ len += size;
+ pos = begin + len;
+
+ while (scd) {
+ if (scd->host == HBA_ptr) {
+
+ size = sprintf(buffer + len, "Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
+ scd->channel, scd->id, scd->lun);
+ for (x = 0; x < 8; x++) {
+ if (scd->vendor[x] >= 0x20)
+ size += sprintf(buffer + len + size, "%c", scd->vendor[x]);
+ else
+ size += sprintf(buffer + len + size," ");
+ }
+ size += sprintf(buffer + len + size, " Model: ");
+ for (x = 0; x < 16; x++) {
+ if (scd->model[x] >= 0x20)
+ size += sprintf(buffer + len + size, "%c", scd->model[x]);
+ else
+ size += sprintf(buffer + len + size, " ");
+ }
+ size += sprintf(buffer + len + size, " Rev: ");
+ for (x = 0; x < 4; x++) {
+ if (scd->rev[x] >= 0x20)
+ size += sprintf(buffer + len + size, "%c", scd->rev[x]);
+ else
+ size += sprintf(buffer + len + size, " ");
+ }
+ size += sprintf(buffer + len + size, "\n");
+
+ size += sprintf(buffer + len + size, " Type: %s ",
+ scd->type < MAX_SCSI_DEVICE_CODE ?
+ scsi_dev_types[(int)scd->type] : "Unknown " );
+ size += sprintf(buffer + len + size, " ANSI"
+ " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
+ if (scd->scsi_level == 2)
+ size += sprintf(buffer + len + size, " CCS\n");
+ else
+ size += sprintf(buffer + len + size, "\n");
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+ }
+ scd = scd->next;
+ }
+
+ stop_output:
+ DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
+ *start=buffer+(offset-begin); /* Start of wanted data */
+ len-=(offset-begin); /* Start slop */
+ if(len>length)
+ len = length; /* Ending slop */
+ DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
+
+ return (len);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
--- /dev/null
+
+struct lun_map {
+ __u8 id:5,
+ chan:3;
+ __u8 lun;
+};
+
+typedef struct emul_pp {
+ __u8 p_code:6,
+ null:1,
+ p_save:1;
+ __u8 p_length;
+ __u16 cylinder;
+ __u8 heads;
+ __u8 sectors;
+ __u8 null2;
+ __u8 s_lunmap:4,
+ ems:1;
+ __u16 drive_type; /* In Little Endian ! */
+ struct lun_map lunmap[4];
+}emulpp;
+
+
+/* Log Sense pages */
+
+typedef struct log_sheader {
+ __u8 page_code,
+ reserved;
+ __u16 length;
+}logsh;
+
+
+/* Log Sense Statistics */
+
+typedef struct read_command_statistics {
+ __u16 code; /* 0x01 */
+ __u8 flags;
+ __u8 length; /* 0x24 */
+ __u32 h_commands,
+ uncached,
+ la_cmds,
+ la_blks,
+ la_hits,
+ missed,
+ hits,
+ seq_la_blks,
+ seq_la_hits;
+}r_cmd_stat;
+
+typedef struct write_command_statistics {
+ __u16 code; /* 0x03 */
+ __u8 flags;
+ __u8 length; /* 0x28 */
+ __u32 h_commands,
+ uncached,
+ thru,
+ bypass,
+ soft_err,
+ hits,
+ b_idle,
+ b_activ,
+ b_blks,
+ b_blks_clean;
+}w_cmd_stat;
+
+typedef struct host_command_statistics {
+ __u16 code; /* 0x02, 0x04 */
+ __u8 flags;
+ __u8 length; /* 0x30 */
+ __u32 sizes[12];
+}hst_cmd_stat;
+
+typedef struct physical_command_statistics {
+ __u16 code; /* 0x06, 0x07 */
+ __u8 flags;
+ __u8 length; /* 0x34 */
+ __u32 sizes[13];
+}phy_cmd_stat;
+
+typedef struct misc_device_statistics {
+ __u16 code; /* 0x05 */
+ __u8 flags;
+ __u8 length; /* 0x10 */
+ __u32 disconnect,
+ pass_thru,
+ sg_commands,
+ stripe_boundary_crosses;
+}msc_stats;
+
+/* Configuration Pages */
+
+typedef struct controller_configuration {
+ __u16 code; /* 0x01 */
+ __u8 flags;
+ __u8 length; /* 0x02 */
+ __u8 intt:1,
+ sec:1,
+ csh:1,
+ key:1,
+ tmr:1,
+ srs:1,
+ nvr:1;
+ __u8 interrupt;
+}coco;
+
+typedef struct controller_hardware_errors {
+ __u16 code; /* 0x02 */
+ __u8 flags;
+ __u8 length; /* 0x02 */
+ __u8 unused:1,
+ per:1;
+ __u8 interrupt;
+}coher;
+
+typedef struct memory_map {
+ __u16 code; /* 0x03, 0x04 */
+ __u8 flags;
+ __u8 length; /* 0x04 */
+ __u32 memory_map;
+}mema;
+
+typedef struct scsi_transfer {
+ __u16 code; /* 0x05 */
+ __u8 flags;
+ __u8 length; /* 0x04 */
+ __u8 offset,
+ period;
+ __u16 speed;
+}scsitrans;
+
+typedef struct scsi_modes {
+ __u16 code; /* 0x06 */
+ __u8 flags;
+ __u8 length; /* 0x02 */
+ __u8 que:1,
+ cdis:1,
+ wtru:1,
+ dasd:1,
+ ncr:1,
+ awre:1;
+ __u8 reserved;
+}scsimod;
+
+typedef struct host_bus {
+ __u16 code; /* 0x07 */
+ __u8 flags;
+ __u8 length; /* 0x02 */
+ __u8 speed:6,
+ pci:1,
+ eisa:1;
+ __u8 reserved;
+}hobu;
+
+typedef struct scsi_bus {
+ __u16 code; /* 0x08 */
+ __u8 flags;
+ __u8 length; /* 0x02 */
+ __u8 speed:4,
+ res:1,
+ ext:1,
+ wide:1,
+ dif:1;
+ __u8 busnum;
+}scbu;
+
+typedef struct board_type {
+ __u16 code; /* 0x09 */
+ __u8 flags;
+ __u8 length; /* 0x04 */
+ __u8 unused:1,
+ cmi:1,
+ dmi:1,
+ cm4k:1,
+ cm4:1,
+ dm4k:1,
+ dm4:1,
+ hba:1;
+ __u8 cpu_type,
+ cpu_speed;
+ __u8 sx1:1,
+ sx2:1,
+ unused2:4,
+ alrm:1,
+ srom:1;
+}boty;
+
+typedef struct memory_config {
+ __u16 code; /* 0x0a */
+ __u8 flags;
+ __u8 length; /* 0x04 */
+ __u8 banksize[4];
+}memco;
+
+typedef struct firmware_info {
+ __u16 code; /* 0x0b */
+ __u8 flags;
+ __u8 length; /* 0x04 */
+ __u8 dnld:1,
+ bs528:1,
+ fmt:1,
+ fw528:1;
+ __u8 unused1,
+ fw_type,
+ unused;
+}firm;
+
+typedef struct subsystem_info {
+ __u16 code; /* 0x0c */
+ __u8 flags;
+ __u8 length; /* 0x02 */
+ __u8 shlf:1,
+ swap:1,
+ noss:1;
+ __u8 reserved;
+}subinf;
+
+typedef struct per_channel_info {
+ __u16 code; /* 0x0d */
+ __u8 flags;
+ __u8 length; /* 0x02 */
+ __u8 channel;
+ __u8 shlf:1,
+ swap:1,
+ noss:1,
+ srs:1,
+ que:1,
+ ext:1,
+ wide:1,
+ diff:1;
+}pcinf;
+
+typedef struct array_limits {
+ __u16 code; /* 0x0e */
+ __u8 flags;
+ __u8 length; /* 0x04 */
+ __u8 max_groups,
+ raid0_drv,
+ raid35_drv,
+ unused;
+}arrlim;
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
+
--- /dev/null
+/********************************************************
+* Header file for eata_dma.c and eata_pio.c *
+* Linux EATA SCSI drivers *
+* (c) 1993,94,95 Michael Neuffer *
+*********************************************************
+* last change: 95/06/20 *
+********************************************************/
+
+
+#ifndef _EATA_GENERIC_H
+#define _EATA_GENERIC_H
+
+
+
+/*********************************************
+ * Misc. definitions *
+ *********************************************/
+
+#ifndef TRUE
+#define TRUE 1
+#endif
+#ifndef FALSE
+#define FALSE 0
+#endif
+
+#define min(a,b) ((a<b)?(a):(b))
+
+#define R_LIMIT 0x20000
+
+#define MAXISA 4
+#define MAXEISA 16
+#define MAXPCI 16
+#define MAXIRQ 16
+#define MAXTARGET 16
+#define MAXCHANNEL 3
+
+#define IS_ISA 'I'
+#define IS_EISA 'E'
+#define IS_PCI 'P'
+
+#define BROKEN_INQUIRY 1
+
+#define EATA_SIGNATURE 0x45415441 /* BIG ENDIAN coded "EATA" sig. */
+#define EATA_CP_SIZE 44
+
+#define MAX_PCI_DEVICES 32 /* Maximum # Of Devices Per Bus */
+#define MAX_METHOD_2 16 /* Max Devices For Method 2 */
+#define MAX_PCI_BUS 16 /* Maximum # Of Busses Allowed */
+
+#define SG_SIZE 64
+#define SG_SIZE_BIG 509 /* max. 509 */
+
+#define C_P_L_DIV 2 /* 1 <= C_P_L_DIV <= 8
+ * You can use this parameter to fine-tune
+ * the driver. Depending on the number of
+ * devices and their speed and ability to queue
+ * commands, you will get the best results with a
+ * value
+ * ~= numdevices-(devices_unable_to_queue_commands/2)
+ * The reason for this is that the disk driver
+ * tends to flood the queue, so that other
+ * drivers have problems to queue commands
+ * themselves. This can for example result in
+ * the effect that the tape stops during disk
+ * accesses.
+ */
+
+#define FREE 0
+#define OK 0
+#define NO_TIMEOUT 0
+#define USED 1
+#define TIMEOUT 2
+#define RESET 4
+#define LOCKED 8
+
+#define HD(cmd) ((hostdata *)&(cmd->host->hostdata))
+#define CD(cmd) ((struct eata_ccb *)(cmd->host_scribble))
+#define SD(host) ((hostdata *)&(host->hostdata))
+
+#define DELAY(x) { __u32 i; i = jiffies + x; while (jiffies < i); }
+#define DEL2(x) { __u32 i; for (i = 0; i < 0xffff * x; i++); }
+
+/***********************************************
+ * EATA Command & Register definitions *
+ ***********************************************/
+#define PCI_REG_DPTconfig 0x40
+#define PCI_REG_PumpModeAddress 0x44
+#define PCI_REG_PumpModeData 0x48
+#define PCI_REG_ConfigParam1 0x50
+#define PCI_REG_ConfigParam2 0x54
+
+
+#define EATA_CMD_PIO_SETUPTEST 0xc6
+#define EATA_CMD_PIO_READ_CONFIG 0xf0
+#define EATA_CMD_PIO_SET_CONFIG 0xf1
+#define EATA_CMD_PIO_SEND_CP 0xf2
+#define EATA_CMD_PIO_RECEIVE_SP 0xf3
+#define EATA_CMD_PIO_TRUNC 0xf4
+
+#define EATA_CMD_RESET 0xf9
+#define EATA_CMD_IMMEDIATE 0xfa
+
+#define EATA_CMD_DMA_READ_CONFIG 0xfd
+#define EATA_CMD_DMA_SET_CONFIG 0xfe
+#define EATA_CMD_DMA_SEND_CP 0xff
+
+#define ECS_EMULATE_SENSE 0xd4
+
+
+#define GENERIC_ABORT 0x00
+#define SPECIFIC_RESET 0x01
+#define BUS_RESET 0x02
+#define SPECIFIC_ABORT 0x03
+#define QUIET_INTR 0x04
+#define COLD_BOOT_HBA 0x06 /* Only as a last resort */
+#define FORCE_IO 0x07
+
+
+#define HA_WCOMMAND 0x07 /* command register offset */
+#define HA_WCOMMAND2 0x06 /* immediate command offset */
+#define HA_WSUBCODE 0x05
+#define HA_WSUBLUN 0x04
+#define HA_WDMAADDR 0x02 /* DMA address LSB offset */
+#define HA_RAUXSTAT 0x08 /* aux status register offset*/
+#define HA_RSTATUS 0x07 /* status register offset */
+#define HA_RDATA 0x00 /* data register (16bit) */
+
+#define HA_ABUSY 0x01 /* aux busy bit */
+#define HA_AIRQ 0x02 /* aux IRQ pending bit */
+#define HA_SERROR 0x01 /* pr. command ended in error*/
+#define HA_SMORE 0x02 /* more data soon to come */
+#define HA_SCORR 0x04 /* data corrected */
+#define HA_SDRQ 0x08 /* data request active */
+#define HA_SSC 0x10 /* seek complete */
+#define HA_SFAULT 0x20 /* write fault */
+#define HA_SREADY 0x40 /* drive ready */
+#define HA_SBUSY 0x80 /* drive busy */
+#define HA_SDRDY HA_SSC+HA_SREADY+HA_SDRQ
+
+/**********************************************
+ * Message definitions *
+ **********************************************/
+
+#define HA_NO_ERROR 0x00 /* No Error */
+#define HA_ERR_SEL_TO 0x01 /* Selection Timeout */
+#define HA_ERR_CMD_TO 0x02 /* Command Timeout */
+#define HA_ERR_RESET 0x03 /* SCSI Bus Reset Received */
+#define HA_INIT_POWERUP 0x04 /* Initial Controller Power-up */
+#define HA_UNX_BUSPHASE 0x05 /* Unexpected Bus Phase */
+#define HA_UNX_BUS_FREE 0x06 /* Unexpected Bus Free */
+#define HA_BUS_PARITY 0x07 /* Bus Parity Error */
+#define HA_SCSI_HUNG 0x08 /* SCSI Hung */
+#define HA_UNX_MSGRJCT 0x09 /* Unexpected Message Rejected */
+#define HA_RESET_STUCK 0x0a /* SCSI Bus Reset Stuck */
+#define HA_RSENSE_FAIL 0x0b /* Auto Request-Sense Failed */
+#define HA_PARITY_ERR 0x0c /* Controller Ram Parity Error */
+#define HA_CP_ABORT_NA 0x0d /* Abort Message sent to non-active cmd */
+#define HA_CP_ABORTED 0x0e /* Abort Message sent to active cmd */
+#define HA_CP_RESET_NA 0x0f /* Reset Message sent to non-active cmd */
+#define HA_CP_RESET 0x10 /* Reset Message sent to active cmd */
+#define HA_ECC_ERR 0x11 /* Controller Ram ECC Error */
+#define HA_PCI_PARITY 0x12 /* PCI Parity Error */
+#define HA_PCI_MABORT 0x13 /* PCI Master Abort */
+#define HA_PCI_TABORT 0x14 /* PCI Target Abort */
+#define HA_PCI_STABORT 0x15 /* PCI Signaled Target Abort */
+
+/**********************************************
+ * Other definitions *
+ **********************************************/
+
+struct reg_bit { /* reading this one will clear the interrupt */
+ __u8 error:1; /* previous command ended in an error */
+ __u8 more:1; /* more DATA coming soon, poll BSY & DRQ (PIO) */
+ __u8 corr:1; /* data read was successfully corrected with ECC*/
+ __u8 drq:1; /* data request active */
+ __u8 sc:1; /* seek complete */
+ __u8 fault:1; /* write fault */
+ __u8 ready:1; /* drive ready */
+ __u8 busy:1; /* controller busy */
+};
+
+struct reg_abit { /* reading this won't clear the interrupt */
+ __u8 abusy:1; /* auxiliary busy */
+ __u8 irq:1; /* set when drive interrupt is asserted */
+ __u8 dummy:6;
+};
+
+struct eata_register { /* EATA register set */
+ __u8 data_reg[2]; /* R, couldn't figure this one out */
+ __u8 cp_addr[4]; /* W, CP address register */
+ union {
+ __u8 command; /* W, command code: [read|set] conf, send CP*/
+ struct reg_bit status; /* R, see register_bit1 */
+ __u8 statusbyte;
+ } ovr;
+ struct reg_abit aux_stat; /* R, see register_bit2 */
+};
+
+struct get_conf { /* Read Configuration Array */
+ __u32 len; /* Should return 0x22, 0x24, etc */
+ __u32 signature; /* Signature MUST be "EATA" */
+ __u8 version2:4,
+ version:4; /* EATA Version level */
+ __u8 OCS_enabled:1, /* Overlap Command Support enabled */
+ TAR_support:1, /* SCSI Target Mode supported */
+ TRNXFR:1, /* Truncate Transfer Cmd not necessary */
+ /* Only used in PIO Mode */
+ MORE_support:1, /* MORE supported (only PIO Mode) */
+ DMA_support:1, /* DMA supported Driver uses only */
+ /* this mode */
+ DMA_valid:1, /* DRQ value in Byte 30 is valid */
+ ATA:1, /* ATA device connected (not supported) */
+ HAA_valid:1; /* Hostadapter Address is valid */
+
+ __u16 cppadlen; /* Number of pad bytes send after CD data */
+ /* set to zero for DMA commands */
+ __u8 scsi_id[4]; /* SCSI ID of controller 2-0 Byte 0 res. */
+ /* if not, zero is returned */
+ __u32 cplen; /* CP length: number of valid cp bytes */
+ __u32 splen; /* Number of bytes returned after */
+ /* Receive SP command */
+ __u16 queuesiz; /* max number of queueable CPs */
+ __u16 dummy;
+ __u16 SGsiz; /* max number of SG table entries */
+ __u8 IRQ:4, /* IRQ used this HA */
+ IRQ_TR:1, /* IRQ Trigger: 0=edge, 1=level */
+ SECOND:1, /* This is a secondary controller */
+ DMA_channel:2; /* DRQ index, DRQ is 2comp of DRQX */
+ __u8 sync; /* device at ID 7 tru 0 is running in */
+ /* synchronous mode, this will disappear */
+ __u8 DSBLE:1, /* ISA i/o addressing is disabled */
+ FORCADR:1, /* i/o address has been forced */
+ SG_64K:1,
+ SG_UAE:1,
+ :4;
+ __u8 MAX_ID:5, /* Max number of SCSI target IDs */
+ MAX_CHAN:3; /* Number of SCSI busses on HBA */
+ __u8 MAX_LUN; /* Max number of LUNs */
+ __u8 :3,
+ AUTOTRM:1,
+ M1_inst:1,
+ ID_qest:1, /* Raidnum ID is questionable */
+ is_PCI:1, /* HBA is PCI */
+ is_EISA:1; /* HBA is EISA */
+ __u8 unused[478];
+};
+
+struct eata_sg_list
+{
+ __u32 data;
+ __u32 len;
+};
+
+struct eata_ccb { /* Send Command Packet structure */
+
+ __u8 SCSI_Reset:1, /* Cause a SCSI Bus reset on the cmd */
+ HBA_Init:1, /* Cause Controller to reinitialize */
+ Auto_Req_Sen:1, /* Do Auto Request Sense on errors */
+ scatter:1, /* Data Ptr points to a SG Packet */
+ Resrvd:1, /* RFU */
+ Interpret:1, /* Interpret the SCSI cdb of own use */
+ DataOut:1, /* Data Out phase with command */
+ DataIn:1; /* Data In phase with command */
+ __u8 reqlen; /* Request Sense Length */
+ /* Valid if Auto_Req_Sen=1 */
+ __u8 unused[3];
+ __u8 FWNEST:1, /* send cmd to phys RAID component*/
+ unused2:7;
+ __u8 Phsunit:1, /* physical unit on mirrored pair */
+ I_AT:1, /* inhibit address translation */
+ I_HBA_C:1, /* HBA inhibit caching */
+ unused3:5;
+
+ __u8 cp_id:5, /* SCSI Device ID of target */
+ cp_channel:3; /* SCSI Channel # of HBA */
+ __u8 cp_lun:3,
+ :2,
+ cp_luntar:1, /* CP is for target ROUTINE */
+ cp_dispri:1, /* Grant disconnect privilege */
+ cp_identify:1; /* Always TRUE */
+ __u8 cp_msg1; /* Message bytes 0-3 */
+ __u8 cp_msg2;
+ __u8 cp_msg3;
+ __u8 cp_cdb[12]; /* Command Descriptor Block */
+ __u32 cp_datalen; /* Data Transfer Length */
+ /* If scatter=1 len of sg package */
+ void *cp_viraddr; /* address of this ccb */
+ __u32 cp_dataDMA; /* Data Address, if scatter=1 *
+ * address of scatter packet */
+ __u32 cp_statDMA; /* address for Status Packet */
+ __u32 cp_reqDMA; /* Request Sense Address, used if */
+ /* CP command ends with error */
+ /* Additional CP info begins here */
+ __u32 timeout;
+ __u8 retries;
+ __u8 status; /* status of this queueslot */
+
+ Scsi_Cmnd *cmd; /* address of cmd */
+ struct eata_sg_list *sg_list;
+};
+
+
+struct eata_sp {
+ __u8 hba_stat:7, /* HBA status */
+ EOC:1; /* True if command finished */
+ __u8 scsi_stat; /* Target SCSI status */
+ __u8 reserved[2];
+ __u32 residue_len; /* Number of bytes not transferred */
+ struct eata_ccb *ccb; /* Address set in COMMAND PACKET */
+ __u8 msg[12];
+};
+
+typedef struct hstd {
+ __u8 vendor[9];
+ __u8 name[18];
+ __u8 revision[6];
+ __u8 EATA_revision;
+ __u8 bustype; /* bustype of HBA */
+ __u8 channel; /* # of avail. scsi channels */
+ __u8 state; /* state of HBA */
+ __u8 primary; /* true if primary */
+ __u8 broken_INQUIRY:1; /* This is an EISA HBA with *
+ * broken INQUIRY */
+ __u32 reads[13];
+ __u32 writes[13];
+ /* state of Target (RESET,..) */
+ __u8 t_state[MAXCHANNEL][MAXTARGET];
+ /* timeouts on target */
+ __u32 t_timeout[MAXCHANNEL][MAXTARGET];
+ __u32 last_ccb; /* Last used ccb */
+ __u32 cplen; /* size of CP in words */
+ __u16 cppadlen; /* pad length of cp in words */
+ __u8 hostid; /* SCSI ID of HBA */
+ __u8 devflags; /* bits set for detected devices */
+ __u8 moresupport; /* HBA supports MORE flag */
+ struct Scsi_Host *next;
+ struct Scsi_Host *prev;
+ struct eata_sp sp; /* status packet */
+ struct eata_ccb ccb[0]; /* ccb array begins here */
+}hostdata;
+
+/* structure for max. 2 emulated drives */
+struct drive_geom_emul {
+ __u8 trans; /* translation flag 1=transl */
+ __u8 channel; /* SCSI channel number */
+ __u8 HBA; /* HBA number (prim/sec) */
+ __u8 id; /* drive id */
+ __u8 lun; /* drive lun */
+ __u32 heads; /* number of heads */
+ __u32 sectors; /* number of sectors */
+ __u32 cylinder; /* number of cylinders */
+};
+
+struct geom_emul {
+ __u8 bios_drives; /* number of emulated drives */
+ struct drive_geom_emul drv[2]; /* drive structures */
+};
+
+#endif /* _EATA_GENERIC_H */
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+/************************************************************
+ * *
+ * Linux EATA SCSI PIO driver *
+ * *
+ * based on the CAM document CAM/89-004 rev. 2.0c, *
+ * DPT's driver kit, some internal documents and source, *
+ * and several other Linux scsi drivers and kernel docs. *
+ * *
+ * The driver currently: *
+ * -supports all EATA-PIO boards *
+ * -only supports DASD devices *
+ * *
+ * (c)1993,94,95 Michael Neuffer, Alfred Arnold *
+ * neuffer@goofy.zdv.uni-mainz.de *
+ * a.arnold@kfa-juelich.de *
+ * *
+ * 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 of the License, 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 kernel; if not, write to *
+ * the Free Software Foundation, Inc., 675 Mass Ave, *
+ * Cambridge, MA 02139, USA. *
+ * *
+ ************************************************************
+ * last change: 95/06/20 OS: Linux 1.3.3 + pre1.3 SCSI pat.*
+ ************************************************************/
+
+/* Look in eata_pio.h for configuration information */
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <linux/in.h>
+#include <linux/bios32.h>
+#include <linux/pci.h>
+#include <linux/proc_fs.h>
+#include <asm/io.h>
+#include "eata_pio.h"
+#include "eata_dma_proc.h"
+#include "scsi.h"
+#include "sd.h"
+
+static uint ISAbases[MAXISA] =
+{0x1F0, 0x170, 0x330, 0x230};
+static uint ISAirqs[MAXISA] =
+{14,12,15,11};
+static unchar EISAbases[] =
+{1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
+static uint registered_HBAs = 0;
+static struct Scsi_Host *last_HBA = NULL;
+static struct Scsi_Host *first_HBA = NULL;
+static unchar reg_IRQ[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+static unchar reg_IRQL[] =
+{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+static uint internal_command_finished = TRUE;
+
+static ulong int_counter = 0;
+static ulong queue_counter = 0;
+
+void hprint(char *str)
+{
+ char *hptr =(char *) 0x000b0000;
+ char *hptr2=(char *) 0x000b00a0;
+ char *hptr3=(char *) 0x000b0f00;
+ int z;
+
+ memmove(hptr,hptr2,24*80*2);
+ for (z=0; z<strlen(str); z++)
+ hptr3[z*2]=str[z];
+ for (; z<80; z++)
+ hptr3[z*2]=' ';
+}
+
+void eata_pio_scsi_done (Scsi_Cmnd * SCpnt)
+{
+ return;
+}
+
+#include "eata_pio_proc.c"
+
+#ifdef MODULE
+int eata_pio_release(struct Scsi_Host *sh)
+{
+ if (sh->irq && reg_IRQ[sh->irq] == 1) free_irq(sh->irq);
+ else reg_IRQ[sh->irq]--;
+ if (SD(sh)->channel == 0) {
+ if (sh->io_port && sh->n_io_port)
+ release_region(sh->io_port, sh->n_io_port);
+ }
+ return(TRUE);
+}
+#endif
+
+void IncStat(Scsi_Pointer *SCp, uint Increment)
+{
+ SCp->ptr+=Increment;
+ if ((SCp->this_residual-=Increment)==0)
+ {
+ if ((--SCp->buffers_residual)==0) SCp->Status=FALSE;
+ else
+ {
+ SCp->buffer++;
+ SCp->ptr=SCp->buffer->address;
+ SCp->this_residual=SCp->buffer->length;
+ }
+ }
+}
+
+void eata_pio_int_handler(int irq, struct pt_regs * regs)
+{
+ uint eata_stat = 0xfffff;
+ Scsi_Cmnd *cmd;
+ hostdata *hd;
+ struct eata_ccb *cp;
+ uint base;
+ ulong flags;
+ uint x,z;
+ struct Scsi_Host *sh;
+ ushort zwickel=0;
+ unchar stat,odd;
+
+ save_flags(flags);
+ cli();
+
+ for (x = 1, sh = first_HBA; x <= registered_HBAs; x++, sh = SD(sh)->prev) {
+ if (sh->irq != irq)
+ continue;
+ if (inb((uint)sh->base + HA_RSTATUS) & HA_SBUSY)
+ continue;
+
+ int_counter++;
+
+ hd=SD(sh);
+
+ cp = &hd->ccb[0];
+ cmd = cp->cmd;
+ base = (uint) cmd->host->base;
+
+ do
+ {
+ stat=inb(base+HA_RSTATUS);
+ if (stat&HA_SDRQ)
+ if (cp->DataIn)
+ {
+ z=256; odd=FALSE;
+ while ((cmd->SCp.Status)&&((z>0)||(odd)))
+ {
+ if (odd)
+ {
+ *(cmd->SCp.ptr)=zwickel>>8;
+ IncStat(&cmd->SCp,1);
+ odd=FALSE;
+ }
+ x=min(z,cmd->SCp.this_residual/2);
+ insw(base+HA_RDATA,cmd->SCp.ptr,x);
+ z-=x;
+ IncStat(&cmd->SCp,2*x);
+ if ((z>0)&&(cmd->SCp.this_residual==1))
+ {
+ zwickel=inw(base+HA_RDATA);
+ *(cmd->SCp.ptr)=zwickel&0xff;
+ IncStat(&cmd->SCp,1); z--;
+ odd=TRUE;
+ }
+ }
+ while (z>0) {
+ zwickel=inw(base+HA_RDATA);
+ z--;
+ }
+ }
+ else /* cp->DataOut */
+ {
+ odd=FALSE; z=256;
+ while ((cmd->SCp.Status)&&((z>0)||(odd)))
+ {
+ if (odd)
+ {
+ zwickel+=*(cmd->SCp.ptr)<<8;
+ IncStat(&cmd->SCp,1);
+ outw(zwickel,base+HA_RDATA);
+ z--;
+ odd=FALSE;
+ }
+ x=min(z,cmd->SCp.this_residual/2);
+ outsw(base+HA_RDATA,cmd->SCp.ptr,x);
+ z-=x;
+ IncStat(&cmd->SCp,2*x);
+ if ((z>0)&&(cmd->SCp.this_residual==1))
+ {
+ zwickel=*(cmd->SCp.ptr);
+ zwickel&=0xff;
+ IncStat(&cmd->SCp,1);
+ odd=TRUE;
+ }
+ }
+ while (z>0||odd) {
+ outw(zwickel,base+HA_RDATA);
+ z--;
+ odd=FALSE;
+ }
+ }
+ }
+ while ((stat&HA_SDRQ)||((stat&HA_SMORE)&&hd->moresupport));
+
+ /* terminate handler if HBA goes busy again, i.e. transfers
+ * more data */
+
+ if (stat&HA_SBUSY) break;
+
+ /* OK, this is quite stupid, but I haven't found any correct
+ * way to get HBA&SCSI status so far */
+
+ if (!(inb(base+HA_RSTATUS)&HA_SERROR))
+ {
+ cmd->result=(DID_OK<<16);
+ hd->devflags|=(1<<cp->cp_id);
+ }
+ else if (hd->devflags&1<<cp->cp_id)
+ cmd->result=(DID_OK<<16)+0x02;
+ else cmd->result=(DID_NO_CONNECT<<16);
+
+ if (cp->status == LOCKED) {
+ cp->status = FREE;
+ eata_stat = inb(base + HA_RSTATUS);
+ printk("eata_pio: int_handler, freeing locked queueslot\n");
+ DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+ restore_flags(flags);
+ return;
+ }
+
+#if DBG_INTR2
+ if (stat != 0x50)
+ printk("stat: %#.2x, result: %#.8x\n", stat, cmd->result);
+ DBG(DBG_INTR&&DBG_DELAY,DEL2(800));
+#endif
+
+ cp->status = FREE; /* now we can release the slot */
+
+ restore_flags(flags);
+ if(cmd->scsi_done != eata_pio_scsi_done) cmd->scsi_done(cmd);
+ else internal_command_finished = TRUE;
+ save_flags(flags);
+ cli();
+ }
+ restore_flags(flags);
+
+ return;
+}
+
+inline uint eata_pio_send_command(uint base, unchar command)
+{
+ uint loop = R_LIMIT;
+
+ while (inb(base + HA_RSTATUS) & HA_SBUSY)
+ if (--loop == 0)
+ return(TRUE);
+
+ outb(command, base + HA_WCOMMAND);
+ return(FALSE);
+}
+
+int eata_pio_queue(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+ uint x, y;
+ long flags;
+ uint base;
+
+ hostdata *hd;
+ struct Scsi_Host *sh;
+ struct eata_ccb *cp;
+
+ save_flags(flags);
+ cli();
+
+ queue_counter++;
+
+ if (done == (void *)eata_pio_scsi_done) {
+ if (internal_command_finished == TRUE)
+ internal_command_finished = FALSE;
+ else
+ cmd->result = (DID_ERROR << 16) + QUEUE_FULL;
+ }
+
+ hd = HD(cmd);
+ sh = cmd->host;
+ base = (uint) sh->base;
+
+ /* use only slot 0, as 2001 can handle only one cmd at a time */
+
+ y = x = 0;
+
+ if (hd->ccb[y].status!=FREE) {
+
+ DBG(DBG_QUEUE, printk("can_queue %d, x %d, y %d\n",sh->can_queue,x,y));
+#if DEBUG_EATA
+ panic("eata_pio: run out of queue slots cmdno:%ld intrno: %ld\n",
+ queue_counter, int_counter);
+#else
+ panic("eata_pio: run out of queue slots....\n");
+#endif
+ }
+
+ cp = &hd->ccb[y];
+
+ memset(cp, 0, sizeof(struct eata_ccb));
+ memset(cmd->sense_buffer, 0, sizeof(cmd->sense_buffer));
+
+ cp->status = USED; /* claim free slot */
+
+ DBG(DBG_QUEUE, printk("eata_pio_queue pid %ld, target: %x, lun: %x, y %d\n",
+ cmd->pid, cmd->target, cmd->lun, y));
+ DBG(DBG_QUEUE && DBG_DELAY, DEL2(250));
+
+ cmd->scsi_done = (void *)done;
+
+ switch (cmd->cmnd[0]) {
+ case CHANGE_DEFINITION: case COMPARE: case COPY:
+ case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT:
+ case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER:
+ case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE:
+ case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW:
+ case WRITE_6: case WRITE_10: case WRITE_VERIFY:
+ case UPDATE_BLOCK: case WRITE_LONG: case WRITE_SAME:
+ case SEARCH_HIGH_12: case SEARCH_EQUAL_12: case SEARCH_LOW_12:
+ case WRITE_12: case WRITE_VERIFY_12: case SET_WINDOW:
+ case MEDIUM_SCAN: case SEND_VOLUME_TAG:
+ case 0xea: /* alternate number for WRITE LONG */
+ cp->DataOut = TRUE; /* Output mode */
+ break;
+ case TEST_UNIT_READY:
+ default:
+ cp->DataIn = TRUE; /* Input mode */
+ }
+
+ cp->Interpret = (cmd->target==hd->hostid);
+ cp->cp_datalen=htonl((ulong)cmd->request_bufflen);
+ cp->Auto_Req_Sen = FALSE;
+ cp->cp_reqDMA = htonl(0);
+ cp->reqlen = 0;
+
+ cp->cp_id = cmd->target;
+ cp->cp_lun = cmd->lun;
+ cp->cp_dispri = FALSE;
+ cp->cp_identify = TRUE;
+ memcpy(cp->cp_cdb, cmd->cmnd, COMMAND_SIZE(*cmd->cmnd));
+
+ cp->cp_statDMA = htonl(0);
+
+ cp->cp_viraddr = cp;
+ cp->cmd = cmd;
+ cmd->host_scribble = (char *)&hd->ccb[y];
+
+ if (cmd->use_sg==0)
+ {
+ cmd->SCp.buffers_residual=1;
+ cmd->SCp.ptr=cmd->request_buffer;
+ cmd->SCp.this_residual=cmd->request_bufflen;
+ cmd->SCp.buffer=NULL;
+ }
+ else
+ {
+ cmd->SCp.buffer=cmd->request_buffer;
+ cmd->SCp.buffers_residual=cmd->use_sg;
+ cmd->SCp.ptr=cmd->SCp.buffer->address;
+ cmd->SCp.this_residual=cmd->SCp.buffer->length;
+ }
+ cmd->SCp.Status=(cmd->SCp.this_residual!=0); /* TRUE as long as bytes
+ are to transfer */
+
+ if (eata_pio_send_command(base, EATA_CMD_PIO_SEND_CP))
+ {
+ cmd->result = DID_ERROR << 16;
+ printk("eata_pio_queue target %d, pid %ld, HBA busy, returning DID_ERROR, done.\n",
+ cmd->target, cmd->pid);
+ restore_flags(flags);
+ if(done != (void *)eata_pio_scsi_done) done(cmd);
+ return (0);
+ }
+ while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
+ outsw(base + HA_RDATA, cp, hd->cplen);
+ outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
+ for (x=0; x<hd->cppadlen; x++) outw(0, base + HA_RDATA);
+
+ DBG(DBG_QUEUE,printk("Queued base %#.4lx pid: %ld target: %x lun: %x "
+ "slot %d irq %d\n", (long)sh->base, cmd->pid,
+ cmd->target, cmd->lun, y, sh->irq));
+ DBG(DBG_QUEUE && DBG_DELAY, DEL2(200));
+
+ restore_flags(flags);
+ return (0);
+}
+
+int eata_pio_abort(Scsi_Cmnd * cmd)
+{
+ ulong flags;
+ uint loop = R_LIMIT;
+
+ save_flags(flags);
+ cli();
+
+ DBG(DBG_ABNORM, printk("eata_pio_abort called pid: %ld target: %x lun: %x reason %x\n",
+ cmd->pid, cmd->target, cmd->lun, cmd->abort_reason));
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+
+
+ while (inb((uint)(cmd->host->base) + HA_RAUXSTAT) & HA_ABUSY)
+ if (--loop == 0) {
+ printk("eata_pio: abort, timeout error.\n");
+ restore_flags(flags);
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ return (SCSI_ABORT_ERROR);
+ }
+ if (CD(cmd)->status == FREE) {
+ DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_NOT_RUNNING\n"));
+ restore_flags(flags);
+ return (SCSI_ABORT_NOT_RUNNING);
+ }
+ if (CD(cmd)->status == USED) {
+ DBG(DBG_ABNORM, printk("Returning: SCSI_ABORT_BUSY\n"));
+ restore_flags(flags);
+ return (SCSI_ABORT_BUSY); /* SNOOZE */
+ }
+ if (CD(cmd)->status == RESET) {
+ restore_flags(flags);
+ printk("eata_pio: abort, command reset error.\n");
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ return (SCSI_ABORT_ERROR);
+ }
+ if (CD(cmd)->status == LOCKED) {
+ restore_flags(flags);
+ DBG(DBG_ABNORM, printk("eata_pio: abort, queue slot locked.\n"));
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ return (SCSI_ABORT_NOT_RUNNING);
+ } else
+ panic("eata_pio: abort: invalid slot status\n");
+}
+
+int eata_pio_reset(Scsi_Cmnd * cmd)
+{
+ uint x, z, time, limit = 0;
+ ulong flags;
+ unchar success = FALSE;
+ Scsi_Cmnd *sp;
+
+ save_flags(flags);
+ cli();
+ hprint("reset");
+ DBG(DBG_ABNORM, printk("eata_pio_reset called pid:%ld target: %x lun: %x "
+ "reason %x\n", cmd->pid, cmd->target, cmd->lun,
+ cmd->abort_reason));
+
+ if (HD(cmd)->state == RESET) {
+ printk("eata_pio_reset: exit, already in reset.\n");
+ restore_flags(flags);
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ return (SCSI_RESET_ERROR);
+ }
+
+ for (z = 0; z < MAXTARGET; z++) {
+ HD(cmd)->t_state[0][z] = RESET;
+ HD(cmd)->t_timeout[0][z] = NO_TIMEOUT;
+ }
+
+ /* force all slots to be free */
+
+ for (x = 0; x < cmd->host->can_queue; x++) {
+
+ if (HD(cmd)->ccb[x].status == FREE)
+ continue;
+
+ sp = HD(cmd)->ccb[x].cmd;
+ HD(cmd)->ccb[x].status = RESET;
+ printk("eata_pio_reset: slot %d in reset, pid %ld.\n", x, sp->pid);
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+
+ if (sp == NULL)
+ panic("eata_pio_reset: slot %d, sp==NULL.\n", x);
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ }
+
+ /* hard reset the HBA */
+ outb((uint) cmd->host->base+HA_WCOMMAND, EATA_CMD_RESET);
+
+ DBG(DBG_ABNORM, printk("eata_pio_reset: board reset done.\n"));
+ HD(cmd)->state = RESET;
+
+ time = jiffies;
+ while (jiffies < (time + 300) && limit++ < 10000000);
+
+ DBG(DBG_ABNORM, printk("eata_pio_reset: interrupts disabled, loops %d.\n", limit));
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+
+ for (x = 0; x < cmd->host->can_queue; x++) {
+
+ /* Skip slots already set free by interrupt */
+ if (HD(cmd)->ccb[x].status != RESET)
+ continue;
+
+ sp = HD(cmd)->ccb[x].cmd;
+ sp->result = DID_RESET << 16;
+
+ /* This mailbox is terminated */
+ printk("eata_pio_reset: resetted ccb %d.\n",x);
+ HD(cmd)->ccb[x].status = FREE;
+
+ restore_flags(flags);
+ sp->scsi_done(sp);
+ cli();
+ }
+
+ HD(cmd)->state = FALSE;
+ restore_flags(flags);
+
+ if (success) { /* hmmm... */
+ DBG(DBG_ABNORM, printk("eata_pio_reset: exit, success.\n"));
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ return (SCSI_RESET_SUCCESS);
+ } else {
+ DBG(DBG_ABNORM, printk("eata_pio_reset: exit, wakeup.\n"));
+ DBG(DBG_ABNORM && DBG_DELAY, DEL2(500));
+ return (SCSI_RESET_PUNT);
+ }
+}
+
+char * get_pio_board_data(ulong base, uint irq, uint id, ulong cplen, ushort cppadlen)
+{
+ struct eata_ccb cp;
+ static char buff[256];
+ int z;
+
+ memset(&cp, 0, sizeof(struct eata_ccb));
+ memset(buff, 0, sizeof(buff));
+
+ cp.DataIn = TRUE;
+ cp.Interpret = TRUE; /* Interpret command */
+
+ cp.cp_datalen = htonl(254);
+ cp.cp_dataDMA = htonl(0);
+
+ cp.cp_id = id;
+ cp.cp_lun = 0;
+
+ cp.cp_cdb[0] = INQUIRY;
+ cp.cp_cdb[1] = 0;
+ cp.cp_cdb[2] = 0;
+ cp.cp_cdb[3] = 0;
+ cp.cp_cdb[4] = 254;
+ cp.cp_cdb[5] = 0;
+
+ if (eata_pio_send_command((uint) base, EATA_CMD_PIO_SEND_CP)) return (NULL);
+ while (!(inb(base + HA_RSTATUS) & HA_SDRQ));
+ outsw(base + HA_RDATA, &cp, cplen);
+ outb(EATA_CMD_PIO_TRUNC, base + HA_WCOMMAND);
+ for (z=0; z<cppadlen; z++) outw(0, base + HA_RDATA);
+
+ while (inb(base + HA_RSTATUS) & HA_SBUSY);
+ if (inb(base + HA_RSTATUS) & HA_SERROR)
+ return (NULL);
+ else if (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+ return (NULL);
+ else
+ {
+ insw(base+HA_RDATA, &buff, 127);
+ while (inb(base+HA_RSTATUS)&HA_SDRQ) inw(base+HA_RDATA);
+ return (buff);
+ }
+}
+
+int get_pio_conf_PIO(u32 base, struct get_conf *buf)
+{
+ ulong loop = R_LIMIT;
+ int z;
+ ushort *p;
+
+ if(check_region(base, 9))
+ return (FALSE);
+
+ memset(buf, 0, sizeof(struct get_conf));
+
+ while (inb(base + HA_RSTATUS) & HA_SBUSY)
+ if (--loop == 0)
+ return (FALSE);
+
+ DBG(DBG_PIO && DBG_PROBE,
+ printk("Issuing PIO READ CONFIG to HBA at %#x\n", base));
+ eata_pio_send_command(base, EATA_CMD_PIO_READ_CONFIG);
+
+ loop = R_LIMIT;
+ for (p = (ushort *) buf;
+ (long)p <= ((long)buf + (sizeof(struct get_conf)/ 2)); p++) {
+ while (!(inb(base + HA_RSTATUS) & HA_SDRQ))
+ if (--loop == 0)
+ return (FALSE);
+
+ loop = R_LIMIT;
+ *p = inw(base + HA_RDATA);
+ }
+ if (!(inb(base + HA_RSTATUS) & HA_SERROR)) { /* Error ? */
+ if (htonl(EATA_SIGNATURE) == buf->signature) {
+ DBG(DBG_PIO&&DBG_PROBE, printk("EATA Controller found at %#4x "
+ "EATA Level: %x\n", base,
+ (uint) (buf->version)));
+
+ while (inb(base + HA_RSTATUS) & HA_SDRQ)
+ inw(base + HA_RDATA);
+ if(ALLOW_DMA_BOARDS == FALSE) {
+ for (z = 0; z < MAXISA; z++)
+ if (base == ISAbases[z]) {
+ buf->IRQ = ISAirqs[z];
+ break;
+ }
+ }
+ return (TRUE);
+ }
+ } else {
+ DBG(DBG_PROBE, printk("eata_dma: get_conf_PIO, error during transfer "
+ "for HBA at %x\n", base));
+ }
+ return (FALSE);
+}
+
+void print_pio_config(struct get_conf *gc)
+{
+ printk("Please check values: (read config data)\n");
+ printk("LEN: %d ver:%d OCS:%d TAR:%d TRNXFR:%d MORES:%d\n",
+ (uint) ntohl(gc->len), gc->version,
+ gc->OCS_enabled, gc->TAR_support, gc->TRNXFR, gc->MORE_support);
+ printk("HAAV:%d SCSIID0:%d ID1:%d ID2:%d QUEUE:%d SG:%d SEC:%d\n",
+ gc->HAA_valid, gc->scsi_id[3], gc->scsi_id[2],
+ gc->scsi_id[1], ntohs(gc->queuesiz), ntohs(gc->SGsiz), gc->SECOND);
+ printk("IRQ:%d IRQT:%d FORCADR:%d MCH:%d RIDQ:%d\n",
+ gc->IRQ, gc->IRQ_TR, gc->FORCADR,
+ gc->MAX_CHAN, gc->ID_qest);
+ DBG(DPT_DEBUG, DELAY(1400));
+}
+
+static uint print_selftest(uint base)
+{
+ unchar buffer[512];
+#ifdef VERBOSE_SETUP
+ int z;
+#endif
+
+ printk("eata_pio: executing controller self test & setup...\n");
+ while (inb(base+HA_RSTATUS)&HA_SBUSY);
+ outb(EATA_CMD_PIO_SETUPTEST,base+HA_WCOMMAND);
+ do {
+ while (inb(base+HA_RSTATUS)&HA_SBUSY)
+ /* nothing */ ;
+ if (inb(base+HA_RSTATUS)&HA_SDRQ)
+ {
+ insw(base+HA_RDATA,&buffer,256);
+#ifdef VERBOSE_SETUP
+ /* no beeps please... */
+ for (z=0; z < 511 && buffer[z]; z++)
+ if (buffer[z] != 7) printk("%c", buffer[z]);
+#endif
+ }
+ } while (inb(base+HA_RSTATUS)&(HA_SBUSY|HA_SDRQ));
+
+ return (!(inb(base+HA_RSTATUS)&HA_SERROR));
+}
+
+int register_pio_HBA(long base, struct get_conf *gc, Scsi_Host_Template * tpnt)
+{
+ ulong size = 0;
+ char *buff;
+ ulong cplen;
+ ushort cppadlen;
+ struct Scsi_Host *sh;
+ hostdata *hd;
+
+ DBG(DBG_REGISTER, print_pio_config(gc));
+
+ if (gc->DMA_support == TRUE) {
+ printk("HBA at %#.4lx supports DMA. Please use EATA-DMA driver.\n",base);
+ if(ALLOW_DMA_BOARDS == FALSE)
+ return (FALSE);
+ }
+
+ if ((buff = get_pio_board_data((uint)base, gc->IRQ, gc->scsi_id[3],
+ cplen =(htonl(gc->cplen )+1)/2,
+ cppadlen=(htons(gc->cppadlen)+1)/2)) == NULL)
+ {
+ printk("HBA at %#lx didn't react on INQUIRY. Sorry.\n", (ulong) base);
+ return (FALSE);
+ }
+
+ if (print_selftest(base) == FALSE && ALLOW_DMA_BOARDS == FALSE)
+ {
+ printk("HBA at %#lx failed while performing self test & setup.\n",
+ (ulong) base);
+ return (FALSE);
+ }
+
+ if (!reg_IRQ[gc->IRQ]) { /* Interrupt already registered ? */
+ if (!request_irq(gc->IRQ, eata_pio_int_handler, SA_INTERRUPT,
+ "EATA-PIO")){
+ reg_IRQ[gc->IRQ]++;
+ if (!gc->IRQ_TR)
+ reg_IRQL[gc->IRQ] = TRUE; /* IRQ is edge triggered */
+ } else {
+ printk("Couldn't allocate IRQ %d, Sorry.", gc->IRQ);
+ return (FALSE);
+ }
+ } else { /* More than one HBA on this IRQ */
+ if (reg_IRQL[gc->IRQ] == TRUE) {
+ printk("Can't support more than one HBA on this IRQ,\n"
+ " if the IRQ is edge triggered. Sorry.\n");
+ return (FALSE);
+ } else
+ reg_IRQ[gc->IRQ]++;
+ }
+
+ request_region(base, 8, "eata_pio");
+
+ size = sizeof(hostdata) + (sizeof(struct eata_ccb) * ntohs(gc->queuesiz));
+
+ sh = scsi_register(tpnt, size);
+ hd = SD(sh);
+
+ memset(hd->ccb, 0, (sizeof(struct eata_ccb) * ntohs(gc->queuesiz)));
+ memset(hd->reads, 0, sizeof(ulong) * 26);
+
+ strncpy(SD(sh)->vendor, &buff[8], 8);
+ SD(sh)->vendor[8] = 0;
+ strncpy(SD(sh)->name, &buff[16], 17);
+ SD(sh)->name[17] = 0;
+ SD(sh)->revision[0] = buff[32];
+ SD(sh)->revision[1] = buff[33];
+ SD(sh)->revision[2] = buff[34];
+ SD(sh)->revision[3] = '.';
+ SD(sh)->revision[4] = buff[35];
+ SD(sh)->revision[5] = 0;
+ switch (ntohl(gc->len)) {
+ case 0x1c:
+ SD(sh)->EATA_revision = 'a';
+ break;
+ case 0x1e:
+ SD(sh)->EATA_revision = 'b';
+ break;
+ case 0x22:
+ SD(sh)->EATA_revision = 'c';
+ break;
+ default:
+ SD(sh)->EATA_revision = '?';
+ }
+ SD(sh)->cplen=cplen;
+ SD(sh)->cppadlen=cppadlen;
+ SD(sh)->hostid=gc->scsi_id[3];
+ SD(sh)->devflags=1<<gc->scsi_id[3];
+ SD(sh)->moresupport=gc->MORE_support;
+ sh->base = (char *) base;
+ sh->io_port = (ushort) base;
+ sh->n_io_port = 8;
+ sh->irq = gc->IRQ;
+ sh->dma_channel = 0xfe; /* PIO */
+ sh->this_id = gc->scsi_id[3];
+ sh->can_queue = 1;
+ sh->cmd_per_lun = 1;
+ sh->sg_tablesize = SG_ALL;
+
+ hd->channel = 0;
+
+ if(ntohl(gc->len) >= 0x22) {
+ if (gc->is_PCI == TRUE)
+ hd->bustype = IS_PCI;
+ else if (gc->is_EISA == TRUE)
+ hd->bustype = IS_EISA;
+ else
+ hd->bustype = IS_ISA;
+ } else {
+ if (buff[21] == '4')
+ hd->bustype = IS_PCI;
+ else if (buff[21] == '2')
+ hd->bustype = IS_EISA;
+ else
+ hd->bustype = IS_ISA;
+ }
+
+ sh->max_id = 8;
+ sh->max_lun = 8;
+
+ if (gc->SECOND)
+ hd->primary = FALSE;
+ else
+ hd->primary = TRUE;
+
+ sh->unchecked_isa_dma = FALSE; /* We can only do PIO */
+
+ hd->next = NULL; /* build a linked list of all HBAs */
+ hd->prev = last_HBA;
+ if(hd->prev != NULL)
+ SD(hd->prev)->next = sh;
+ last_HBA = sh;
+ if (first_HBA == NULL)
+ first_HBA = sh;
+ registered_HBAs++;
+ return (1);
+}
+
+void find_pio_ISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
+{
+ int i;
+
+ for (i = 0; i < MAXISA; i++) {
+ if (ISAbases[i]) {
+ if (get_pio_conf_PIO(ISAbases[i], buf) == TRUE){
+ register_pio_HBA(ISAbases[i], buf, tpnt);
+ }
+ ISAbases[i] = 0;
+ }
+ }
+ return;
+}
+
+void find_pio_EISA(struct get_conf *buf, Scsi_Host_Template * tpnt)
+{
+ u32 base;
+ int i;
+
+#if CHECKPAL
+ u8 pal1, pal2, pal3;
+#endif
+
+ for (i = 0; i < MAXEISA; i++) {
+ if (EISAbases[i] == TRUE) { /* Still a possibility ? */
+
+ base = 0x1c88 + (i * 0x1000);
+#if CHECKPAL
+ pal1 = inb((u16)base - 8);
+ pal2 = inb((u16)base - 7);
+ pal3 = inb((u16)base - 6);
+
+ if (((pal1 == 0x12) && (pal2 == 0x14)) ||
+ ((pal1 == 0x38) && (pal2 == 0xa3) && (pal3 == 0x82)) ||
+ ((pal1 == 0x06) && (pal2 == 0x94) && (pal3 == 0x24))) {
+ DBG(DBG_PROBE, printk("EISA EATA id tags found: %x %x %x \n",
+ (int)pal1, (int)pal2, (int)pal3));
+#endif
+ if (get_pio_conf_PIO(base, buf) == TRUE) {
+ DBG(DBG_PROBE && DBG_EISA, print_pio_config(buf));
+ if (buf->IRQ) {
+ register_pio_HBA(base, buf, tpnt);
+ } else
+ printk("eata_dma: No valid IRQ. HBA removed from list\n");
+ }
+ /* Nothing found here so we take it from the list */
+ EISAbases[i] = 0;
+#if CHECKPAL
+ }
+#endif
+ }
+ }
+ return;
+}
+
+void find_pio_PCI(struct get_conf *buf, Scsi_Host_Template * tpnt)
+{
+
+#ifndef CONFIG_PCI
+ printk("Kernel PCI support not enabled. Skipping scan for PCI HBAs.\n");
+#else
+
+ u8 pci_bus, pci_device_fn;
+ static s16 pci_index = 0; /* Device index to PCI BIOS calls */
+ u32 base = 0;
+ u16 com_adr;
+ u16 rev_device;
+ u32 error, i, x;
+
+ if (pcibios_present()) {
+ for (i = 0; i <= MAXPCI; ++i, ++pci_index) {
+ if (pcibios_find_device(PCI_VENDOR_ID_DPT, PCI_DEVICE_ID_DPT,
+ pci_index, &pci_bus, &pci_device_fn))
+ break;
+ DBG(DBG_PROBE && DBG_PCI,
+ printk("eata_pio: HBA at bus %d, device %d,"
+ " function %d, index %d\n", (s32)pci_bus,
+ (s32)((pci_device_fn & 0xf8) >> 3),
+ (s32)(pci_device_fn & 7), pci_index));
+
+ if (!(error = pcibios_read_config_word(pci_bus, pci_device_fn,
+ PCI_CLASS_DEVICE, &rev_device))) {
+ if (rev_device == PCI_CLASS_STORAGE_SCSI) {
+ if (!(error = pcibios_read_config_word(pci_bus,
+ pci_device_fn, PCI_COMMAND,
+ (u16 *) & com_adr))) {
+ if (!((com_adr & PCI_COMMAND_IO) &&
+ (com_adr & PCI_COMMAND_MASTER))) {
+ printk("HBA has IO or BUSMASTER mode disabled\n");
+ continue;
+ }
+ } else
+ printk("eata_pio: error %x while reading "
+ "PCI_COMMAND\n", error);
+ } else
+ printk("DEVICECLASSID %x didn't match\n", rev_device);
+ } else {
+ printk("eata_pio: error %x while reading PCI_CLASS_BASE\n",
+ error);
+ continue;
+ }
+
+ if (!(error = pcibios_read_config_dword(pci_bus, pci_device_fn,
+ PCI_BASE_ADDRESS_0, (int *) &base))){
+
+ /* Check if the address is valid */
+ if (base & 0x01) {
+ base &= 0xfffffffe;
+ /* EISA tag there ? */
+ if ((inb(base) == 0x12) && (inb(base + 1) == 0x14))
+ continue; /* Jep, it's forced, so move on */
+ base += 0x10; /* Now, THIS is the real address */
+ if (base != 0x1f8) {
+ /* We didn't find it in the primary search */
+ if (get_pio_conf_PIO(base, buf) == TRUE) {
+ if (buf->FORCADR) /* If the address is forced */
+ continue; /* we'll find it later */
+
+ /* OK. We made it till here, so we can go now
+ * and register it. We only have to check and
+ * eventually remove it from the EISA and ISA list
+ */
+
+ register_pio_HBA(base, buf, tpnt);
+
+ if (base < 0x1000) {
+ for (x = 0; x < MAXISA; ++x) {
+ if (ISAbases[x] == base) {
+ ISAbases[x] = 0;
+ break;
+ }
+ }
+ } else if ((base & 0x0fff) == 0x0c88) {
+ x = (base >> 12) & 0x0f;
+ EISAbases[x] = 0;
+ }
+ continue; /* break; */
+ }
+ }
+ }
+ } else
+ printk("eata_pio: error %x while reading "
+ "PCI_BASE_ADDRESS_0\n", error);
+ }
+ } else
+ printk("No BIOS32 extensions present. This eata_pio release "
+ "still depends on it.\n"
+ "Skipping scan for PCI HBAs. Sorry.\n");
+#endif /* #ifndef CONFIG_PCI */
+ return;
+}
+
+
+int eata_pio_detect(Scsi_Host_Template * tpnt)
+{
+ struct Scsi_Host *HBA_ptr;
+ struct get_conf gc;
+ int i;
+
+ DBG((DBG_PROBE && DBG_DELAY) || DPT_DEBUG,
+ printk("Using lots of delays to let you read the debugging output\n"));
+
+#ifndef DBG_EISA
+
+printk("DBG_EISA not defined !!!\n");
+
+#endif
+
+ find_pio_PCI(&gc, tpnt);
+
+ find_pio_EISA(&gc, tpnt);
+
+ find_pio_ISA(&gc, tpnt);
+
+ for (i = 0; i <= MAXIRQ; i++)
+ if (reg_IRQ[i])
+ request_irq(i, eata_pio_int_handler, SA_INTERRUPT, "EATA-PIO");
+
+ HBA_ptr = first_HBA;
+
+ if (registered_HBAs != 0) {
+ printk("EATA (Extended Attachment) PIO driver version: %d.%d%s\n"
+ "(c) 1993-95 Michael Neuffer, neuffer@goofy.zdv.uni-mainz.de\n"
+ " Alfred Arnold, a.arnold@kfa-juelich.de\n"
+ "This release only supports DASD devices (harddisks)\n",
+ VER_MAJOR, VER_MINOR, VER_SUB);
+
+ printk("Registered HBAs:\n");
+ printk("HBA no. Boardtype: Revis: EATA: Bus: BaseIO: IRQ: Ch: ID: Pr: QS: SG: CPL:\n");
+ for (i = 1; i <= registered_HBAs; i++) {
+ printk("scsi%-2d: %.10s v%s 2.0%c %s %#.4x %2d %d %d %c %2d %2d %2d\n",
+ HBA_ptr->host_no, SD(HBA_ptr)->name, SD(HBA_ptr)->revision,
+ SD(HBA_ptr)->EATA_revision, (SD(HBA_ptr)->bustype == 'P')?
+ "PCI ":(SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ",
+ (uint) HBA_ptr->base, HBA_ptr->irq,
+ SD(HBA_ptr)->channel, HBA_ptr->this_id, (SD(HBA_ptr)->primary == TRUE)?'Y':'N',
+ HBA_ptr->can_queue, HBA_ptr->sg_tablesize, HBA_ptr->cmd_per_lun);
+ HBA_ptr = SD(HBA_ptr)->next;
+ }
+ }
+ DBG(DPT_DEBUG,DELAY(1200));
+
+ return (registered_HBAs);
+}
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = EATA_PIO;
+
+#include "scsi_module.c"
+#endif
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
--- /dev/null
+/********************************************************
+* Header file for eata_pio.c Linux EATA-PIO SCSI driver *
+* (c) 1993,94,95 Michael Neuffer *
+*********************************************************
+* last change: 95/06/21 *
+********************************************************/
+
+
+#ifndef _EATA_PIO_H
+#define _EATA_PIO_H
+
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#include <linux/scsicam.h>
+
+#ifndef HOSTS_C
+#include "eata_generic.h"
+
+#define VER_MAJOR 0
+#define VER_MINOR 0
+#define VER_SUB "1a"
+
+/************************************************************************
+ * Here you can switch parts of the code on and of *
+ ************************************************************************/
+
+#define VERBOSE_SETUP /* show startup screen of 2001 */
+#define ALLOW_DMA_BOARDS 1
+
+/************************************************************************
+ * Debug options. *
+ * Enable DEBUG and whichever options you require. *
+ ************************************************************************/
+#define DEBUG_EATA 1 /* Enable debug code. */
+#define DPT_DEBUG 0 /* Bobs special */
+#define DBG_DELAY 0 /* Build in delays so debug messages can be
+ * be read before they vanish of the top of
+ * the screen!
+ */
+#define DBG_PROBE 0 /* Debug probe routines. */
+#define DBG_ISA 0 /* Trace ISA routines */
+#define DBG_EISA 0 /* Trace EISA routines */
+#define DBG_PCI 0 /* Trace PCI routines */
+#define DBG_PIO 0 /* Trace get_config_PIO */
+#define DBG_COM 0 /* Trace command call */
+#define DBG_QUEUE 0 /* Trace command queueing. */
+#define DBG_INTR 0 /* Trace interrupt service routine. */
+#define DBG_INTR2 0 /* Trace interrupt service routine. */
+#define DBG_PROC 0 /* Debug proc-fs related statistics */
+#define DBG_PROC_WRITE 0
+#define DBG_REGISTER 0 /* */
+#define DBG_ABNORM 1 /* Debug abnormal actions (reset, abort) */
+
+#if DEBUG_EATA
+#define DBG(x, y) if ((x)) {y;}
+#else
+#define DBG(x, y)
+#endif
+
+#endif /* !HOSTS_C */
+
+int eata_pio_detect(Scsi_Host_Template *);
+const char *eata_pio_info(struct Scsi_Host *);
+int eata_pio_command(Scsi_Cmnd *);
+int eata_pio_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int eata_pio_abort(Scsi_Cmnd *);
+int eata_pio_reset(Scsi_Cmnd *);
+int eata_pio_proc_info(char *, char **, off_t, int, int, int);
+#ifdef MODULE
+int eata_pio_release(struct Scsi_Host *);
+#else
+#define eata_pio_release NULL
+#endif
+
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
+
+#define EATA_PIO { \
+ NULL, NULL, \
+ eata_pio_proc_info,/* procinfo */ \
+ "eata_pio", /* proc dir entry */ \
+ PROC_SCSI_EATA_PIO,/* proc dir inode */ \
+ "EATA (Extended Attachment) PIO driver",\
+ eata_pio_detect, \
+ eata_pio_release, \
+ NULL, NULL, \
+ eata_pio_queue, \
+ eata_pio_abort, \
+ eata_pio_reset, \
+ NULL, /* Slave attach */ \
+ scsicam_bios_param, \
+ 0, /* Canqueue */ \
+ 0, /* this_id */ \
+ 0, /* sg_tablesize */ \
+ 0, /* cmd_per_lun */ \
+ 0, /* present */ \
+ 1, /* True if ISA */ \
+ ENABLE_CLUSTERING }
+
+#endif /* _EATA_PIO_H */
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
--- /dev/null
+
+#define MAX_SCSI_DEVICE_CODE 10
+const char *const pio_scsi_dev_types[MAX_SCSI_DEVICE_CODE] =
+{
+ "Direct-Access ",
+ "Sequential-Access",
+ "Printer ",
+ "Processor ",
+ "WORM ",
+ "CD-ROM ",
+ "Scanner ",
+ "Optical Device ",
+ "Medium Changer ",
+ "Communications "
+};
+
+/*
+ * eata_set_info
+ * buffer : pointer to the data that has been written to the hostfile
+ * length : number of bytes written to the hostfile
+ * HBA_ptr: pointer to the Scsi_Host struct
+ */
+int eata_pio_set_info(char *buffer, int length, struct Scsi_Host *HBA_ptr)
+{
+ DBG(DBG_PROC_WRITE, printk("%s\n", buffer));
+ return(-ENOSYS); /* Currently this is a no-op */
+}
+
+/*
+ * eata_proc_info
+ * inout : decides on the direction of the dataflow and the meaning of the variables
+ * buffer: If inout==FALSE data is beeing written to it else read from it
+ * *start: If inout==FALSE start of the valid data in the buffer
+ * offset: If inout==FALSE offset from the beginning of the imaginary file from which we start writing into the buffer
+ * length: If inout==FALSE max number of bytes to be written into the buffer else number of bytes in the buffer
+ */
+int eata_pio_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int inout)
+{
+
+ Scsi_Device *scd;
+ struct Scsi_Host *HBA_ptr;
+ static u8 buff[512];
+ int i, x;
+ int size, len = 0;
+ off_t begin = 0;
+ off_t pos = 0;
+
+ HBA_ptr = first_HBA;
+ for (i = 1; i <= registered_HBAs; i++) {
+ if (HBA_ptr->host_no == hostno)
+ break;
+ HBA_ptr = SD(HBA_ptr)->next;
+ }
+
+ if(inout == TRUE) /* Has data been writen to the file ? */
+ return(eata_pio_set_info(buffer, length, HBA_ptr));
+
+ if (offset == 0)
+ memset(buff, 0, sizeof(buff));
+
+ size = sprintf(buffer+len, "EATA (Extended Attachment) PIO driver version: "
+ "%d.%d%s\n",VER_MAJOR, VER_MINOR, VER_SUB);
+ len += size; pos = begin + len;
+ size = sprintf(buffer + len, "queued commands: %10ld\n"
+ "processed interrupts:%10ld\n", queue_counter, int_counter);
+ len += size; pos = begin + len;
+
+ size = sprintf(buffer + len, "\nscsi%-2d: HBA %.10s\n",
+ HBA_ptr->host_no, SD(HBA_ptr)->name);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "Firmware revision: v%s\n",
+ SD(HBA_ptr)->revision);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "IO: PIO\n");
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "Base IO : %#.4x\n", (u32) HBA_ptr->base);
+ len += size;
+ pos = begin + len;
+ size = sprintf(buffer + len, "Host Bus: %s\n",
+ (SD(HBA_ptr)->bustype == 'P')?"PCI ":
+ (SD(HBA_ptr)->bustype == 'E')?"EISA":"ISA ");
+
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+
+ scd = scsi_devices;
+
+ size = sprintf(buffer+len,"Attached devices: %s\n", (scd)?"":"none");
+ len += size;
+ pos = begin + len;
+
+ while (scd) {
+ if (scd->host == HBA_ptr) {
+
+ size = sprintf(buffer + len, "Channel: %02d Id: %02d Lun: %02d\n Vendor: ",
+ scd->channel, scd->id, scd->lun);
+ for (x = 0; x < 8; x++) {
+ if (scd->vendor[x] >= 0x20)
+ size += sprintf(buffer + len + size, "%c", scd->vendor[x]);
+ else
+ size += sprintf(buffer + len + size," ");
+ }
+ size += sprintf(buffer + len + size, " Model: ");
+ for (x = 0; x < 16; x++) {
+ if (scd->model[x] >= 0x20)
+ size += sprintf(buffer + len + size, "%c", scd->model[x]);
+ else
+ size += sprintf(buffer + len + size, " ");
+ }
+ size += sprintf(buffer + len + size, " Rev: ");
+ for (x = 0; x < 4; x++) {
+ if (scd->rev[x] >= 0x20)
+ size += sprintf(buffer + len + size, "%c", scd->rev[x]);
+ else
+ size += sprintf(buffer + len + size, " ");
+ }
+ size += sprintf(buffer + len + size, "\n");
+
+ size += sprintf(buffer + len + size, " Type: %s ",
+ scd->type < MAX_SCSI_DEVICE_CODE ?
+ pio_scsi_dev_types[(int)scd->type] : "Unknown " );
+ size += sprintf(buffer + len + size, " ANSI"
+ " SCSI revision: %02x", (scd->scsi_level < 3)?1:2);
+ if (scd->scsi_level == 2)
+ size += sprintf(buffer + len + size, " CCS\n");
+ else
+ size += sprintf(buffer + len + size, "\n");
+ len += size;
+ pos = begin + len;
+
+ if (pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+ if (pos > offset + length)
+ goto stop_output;
+ }
+ scd = scd->next;
+ }
+
+ stop_output:
+ DBG(DBG_PROC, printk("2pos: %ld offset: %ld len: %d\n", pos, offset, len));
+ *start=buffer+(offset-begin); /* Start of wanted data */
+ len-=(offset-begin); /* Start slop */
+ if(len>length)
+ len = length; /* Ending slop */
+ DBG(DBG_PROC, printk("3pos: %ld offset: %ld len: %d\n", pos, offset, len));
+
+ return (len);
+}
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
**************************************************************************/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/sched.h>
#include <asm/io.h>
#include "../block/blk.h"
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/ioport.h>
+#include <linux/proc_fs.h>
#include <linux/bios32.h>
#include <linux/pci.h>
-
+
#define VERSION "$Revision: 5.31 $"
/* START OF USER DEFINABLE OPTIONS */
(unsigned)bios_base, shpnt->this_id );
/* If this driver works for later FD PCI
- boards, we will have to modify banner
- for additional PCI cards, but for now if
- it's PCI it's a TMC-3260 - JTM */
+ boards, we will have to modify banner
+ for additional PCI cards, but for now if
+ it's PCI it's a TMC-3260 - JTM */
printk( "scsi%d <fdomain>: %s chip at 0x%x irq ",
shpnt->host_no,
chip == tmc1800 ? "TMC-1800"
if (inb( port + LSB_ID_Code ) != 0x27) return 0;
if (inb( port + MSB_ID_Code ) != 0x61) return 0;
chip = tmc1800;
- } else { /* test for 0xe960 id */
+ } else { /* test for 0xe960 id */
if (inb( port + MSB_ID_Code ) != 0x60) return 0;
chip = tmc18c50;
#else
/* That should have worked, but appears to
- have problems. Lets assume it is an
- 18c30 if the RAM is disabled. */
+ have problems. Lets assume it is an
+ 18c30 if the RAM is disabled. */
if (inb( port + Configuration2 ) & 0x02) {
chip = tmc18c30;
outb( adapter_mask, port_base + SCSI_Data_NoACK ); /* Set our id bit */
outb( 0x04 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */
- timeout = jiffies + 50; /* 500 mS */
+ timeout = jiffies + 50; /* 500 mS */
while (jiffies < timeout) {
status = inb( TMC_Status_port ); /* Read adapter status */
if (status & 0x02) /* Arbitration complete */
/* Stop arbitration and enable parity */
outb( PARITY_MASK, TMC_Cntl_port );
- timeout = jiffies + 35; /* 350mS -- because of timeouts
+ timeout = jiffies + 35; /* 350mS -- because of timeouts
(was 250mS) */
while (jiffies < timeout) {
status = inb( SCSI_Status_port ); /* Read adapter status */
- if (status & 1) { /* Busy asserted */
+ if (status & 1) { /* Busy asserted */
/* Enable SCSI Bus (on error, should make bus idle with 0) */
outb( 0x80, SCSI_Cntl_port );
return 0;
unsigned data_count;
/* The fdomain_16x0_intr is only called via
- the interrupt handler. The goal of the
- sti() here is to allow other
- interruptions while this routine is
- running. */
+ the interrupt handler. The goal of the
+ sti() here is to allow other
+ interruptions while this routine is
+ running. */
sti(); /* Yes, we really want sti() here */
retcode = kernel_scsi_ioctl( disk->device,
SCSI_IOCTL_SEND_COMMAND,
(void *)buf );
- if (!retcode /* SCSI command ok */
+ if (!retcode /* SCSI command ok */
&& data[511] == 0xaa && data[510] == 0x55 /* Partition table valid */
&& data[0x1c2]) { /* Partition type */
Start: 0x1b3h
Offset: 0 = partition status
- 1 = starting head
+ 1 = starting head
2 = starting sector and cylinder (word, encoded)
4 = partition type
5 = ending head
3) partitions never divide cylinders
Note that (1) may be FALSE for NetBSD (and other BSD flavors),
- as well as for Linux. Note also, that Linux doesn't pay any
- attention to the fields that are used by this algorithm -- it
- only uses the absolute sector data. Recent versions of Linux's
- fdisk(1) will fill this data in correctly, and forthcoming
- versions will check for consistency.
+ as well as for Linux. Note also, that Linux doesn't pay any
+ attention to the fields that are used by this algorithm -- it
+ only uses the absolute sector data. Recent versions of Linux's
+ fdisk(1) will fill this data in correctly, and forthcoming
+ versions will check for consistency.
Checking for a non-zero partition type is not part of the
- Future Domain algorithm, but it seemed to be a reasonable thing
- to do, especially in the Linux and BSD worlds. */
+ Future Domain algorithm, but it seemed to be a reasonable thing
+ to do, especially in the Linux and BSD worlds. */
info_array[0] = data[0x1c3] + 1; /* heads */
info_array[1] = data[0x1c4] & 0x3f; /* sectors */
} else {
/* Note that this new method guarantees that there will always be
- less than 1024 cylinders on a platter. This is good for drives
- up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
+ less than 1024 cylinders on a platter. This is good for drives
+ up to approximately 7.85GB (where 1GB = 1024 * 1024 kB). */
if ((unsigned int)size >= 0x7e0000U) {
info_array[0] = 0xff; /* heads = 255 */
return 0;
}
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = FDOMAIN_16X0;
+
+#include "scsi_module.c"
+#endif
int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) );
int fdomain_16x0_biosparam( Disk *, int, int * );
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
#define FDOMAIN_16X0 { NULL, \
NULL, \
- NULL, \
+ generic_proc_info, \
+ "fdomain", \
+ PROC_SCSI_FUTURE_DOMAIN, \
+ NULL, \
fdomain_16x0_detect, \
NULL, \
fdomain_16x0_info, \
fdomain_16x0_biosparam, \
1, \
6, \
- 64, \
+ 64, \
1, \
0, \
0, \
#ifdef HOSTS_C
-#define GENERIC_NCR5380 {NULL, NULL, "Trantor T128/T128F/T228", \
- generic_NCR5380_detect, NULL, NULL, NULL, \
+#define GENERIC_NCR5380 {NULL, NULL, generic_proc_info, "g_NCR5380", \
+ PROC_SCSI_GENERIC_NCR5380, "Trantor T128/T128F/T228", \
+ generic_NCR5380_detect, NULL, NULL, NULL, \
generic_NCR5380_queue_command, generic_NCR5380_abort, \
generic_NCR5380_reset, NULL, \
NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
/*
- * hosts.c Copyright (C) 1992 Drew Eckhardt
- * Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ * hosts.c Copyright (C) 1992 Drew Eckhardt
+ * Copyright (C) 1993, 1994, 1995 Eric Youngdale
*
- * mid to lowlevel SCSI driver interface
- * Initial versions: Drew Eckhardt
- * Subsequent revisions: Eric Youngdale
+ * mid to lowlevel SCSI driver interface
+ * Initial versions: Drew Eckhardt
+ * Subsequent revisions: Eric Youngdale
*
- * <drew@colorado.edu>
+ * <drew@colorado.edu>
*/
/*
- * This file contains the medium level SCSI
- * host interface initialization, as well as the scsi_hosts array of SCSI
- * hosts currently present in the system.
+ * This file contains the medium level SCSI
+ * host interface initialization, as well as the scsi_hosts array of SCSI
+ * hosts currently present in the system.
*/
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/proc_fs.h>
#include "scsi.h"
#include "eata_dma.h"
#endif
+#ifdef CONFIG_SCSI_EATA_PIO
+#include "eata_pio.h"
+#endif
+
#ifdef CONFIG_SCSI_U14_34F
#include "u14-34f.h"
#endif
*/
/*
- * The scsi host entries should be in the order you wish the
- * cards to be detected. A driver may appear more than once IFF
- * it can deal with being detected (and therefore initialized)
- * with more than one simultaneous host number, can handle being
- * reentrant, etc.
+ * The scsi host entries should be in the order you wish the
+ * cards to be detected. A driver may appear more than once IFF
+ * it can deal with being detected (and therefore initialized)
+ * with more than one simultaneous host number, can handle being
+ * reentrant, etc.
*
- * They may appear in any order, as each SCSI host is told which host number it is
- * during detection.
+ * They may appear in any order, as each SCSI host is told which host
+ * number it is during detection.
*/
/* This is a placeholder for controllers that are not configured into
- the system - we do this to ensure that the controller numbering is
- always consistent, no matter how the kernel is configured. */
+ * the system - we do this to ensure that the controller numbering is
+ * always consistent, no matter how the kernel is configured. */
#define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
- NULL, NULL, 0, 0, 0, 0, 0, 0}
+ NULL, NULL, 0, 0, 0, 0, 0, 0}
/*
- * When figure is run, we don't want to link to any object code. Since
- * the macro for each host will contain function pointers, we cannot
- * use it and instead must use a "blank" that does no such
- * idiocy.
+ * When figure is run, we don't want to link to any object code. Since
+ * the macro for each host will contain function pointers, we cannot
+ * use it and instead must use a "blank" that does no such
+ * idiocy.
*/
Scsi_Host_Template * scsi_hosts = NULL;
static Scsi_Host_Template builtin_scsi_hosts[] =
- {
+{
#ifdef CONFIG_SCSI_U14_34F
- ULTRASTOR_14_34F,
+ ULTRASTOR_14_34F,
#endif
#ifdef CONFIG_SCSI_ULTRASTOR
- ULTRASTOR_14F,
+ ULTRASTOR_14F,
#endif
#ifdef CONFIG_SCSI_AHA152X
- AHA152X,
+ AHA152X,
#endif
/* Buslogic must come before aha1542.c */
#ifdef CONFIG_SCSI_BUSLOGIC
- BUSLOGIC,
+ BUSLOGIC,
#endif
#ifdef CONFIG_SCSI_AHA1542
- AHA1542,
+ AHA1542,
#endif
#ifdef CONFIG_SCSI_AHA1740
- AHA1740,
+ AHA1740,
#endif
#ifdef CONFIG_SCSI_AIC7XXX
- AIC7XXX,
+ AIC7XXX,
#endif
#ifdef CONFIG_SCSI_FUTURE_DOMAIN
- FDOMAIN_16X0,
+ FDOMAIN_16X0,
#endif
#ifdef CONFIG_SCSI_IN2000
- IN2000,
+ IN2000,
#endif
#ifdef CONFIG_SCSI_GENERIC_NCR5380
- GENERIC_NCR5380,
+ GENERIC_NCR5380,
#endif
#ifdef CONFIG_SCSI_QLOGIC
- QLOGIC,
+ QLOGIC,
#endif
#ifdef CONFIG_SCSI_PAS16
- MV_PAS16,
+ MV_PAS16,
#endif
#ifdef CONFIG_SCSI_SEAGATE
- SEAGATE_ST0X,
+ SEAGATE_ST0X,
#endif
#ifdef CONFIG_SCSI_T128
- TRANTOR_T128,
+ TRANTOR_T128,
#endif
#ifdef CONFIG_SCSI_NCR53C7xx
- NCR53c7xx,
+ NCR53c7xx,
#endif
#ifdef CONFIG_SCSI_EATA_DMA
- EATA_DMA,
+ EATA_DMA,
+#endif
+#ifdef CONFIG_SCSI_EATA_PIO
+ EATA_PIO,
#endif
#ifdef CONFIG_SCSI_7000FASST
- WD7000,
+ WD7000,
#endif
#ifdef CONFIG_SCSI_EATA
- EATA,
+ EATA,
#endif
#ifdef CONFIG_SCSI_DEBUG
- SCSI_DEBUG,
+ SCSI_DEBUG,
#endif
- };
+};
#define MAX_SCSI_HOSTS (sizeof(builtin_scsi_hosts) / sizeof(Scsi_Host_Template))
+
/*
- * Our semaphores and timeout counters, where size depends on MAX_SCSI_HOSTS here.
+ * Our semaphores and timeout counters, where size depends on
+ * MAX_SCSI_HOSTS here.
*/
struct Scsi_Host * scsi_hostlist = NULL;
-struct Scsi_Device_Template * scsi_devicelist;
+struct Scsi_Device_Template * scsi_devicelist = NULL;
int max_scsi_hosts = 0;
int next_scsi_host = 0;
void
scsi_unregister(struct Scsi_Host * sh){
- struct Scsi_Host * shpnt;
-
- if(scsi_hostlist == sh)
- scsi_hostlist = sh->next;
- else {
- shpnt = scsi_hostlist;
- while(shpnt->next != sh) shpnt = shpnt->next;
- shpnt->next = shpnt->next->next;
- };
-
- /* If we are removing the last host registered, it is safe to reuse
- its host number (this avoids "holes" at boot time) (DB) */
- if (max_scsi_hosts == next_scsi_host && !scsi_loadable_module_flag)
- max_scsi_hosts--;
-
- next_scsi_host--;
- scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + sh->extra_bytes);
+ struct Scsi_Host * shpnt;
+
+ if(scsi_hostlist == sh)
+ scsi_hostlist = sh->next;
+ else {
+ shpnt = scsi_hostlist;
+ while(shpnt->next != sh) shpnt = shpnt->next;
+ shpnt->next = shpnt->next->next;
+ }
+
+ /* If we are removing the last host registered, it is safe to reuse
+ * its host number (this avoids "holes" at boot time) (DB)
+ */
+ if (max_scsi_hosts == next_scsi_host && !scsi_loadable_module_flag)
+ max_scsi_hosts--;
+
+ next_scsi_host--;
+ scsi_init_free((char *) sh, sizeof(struct Scsi_Host) + sh->extra_bytes);
}
/* We call this when we come across a new host adapter. We only do this
- once we are 100% sure that we want to use this host adapter - it is a
- pain to reverse this, so we try and avoid it */
+ * once we are 100% sure that we want to use this host adapter - it is a
+ * pain to reverse this, so we try and avoid it
+ */
struct Scsi_Host * scsi_register(Scsi_Host_Template * tpnt, int j){
- struct Scsi_Host * retval, *shpnt;
- retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j,
- (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
- retval->host_busy = 0;
- retval->block = NULL;
- retval->wish_block = 0;
- if(j > 0xffff) panic("Too many extra bytes requested\n");
- retval->extra_bytes = j;
- retval->loaded_as_module = scsi_loadable_module_flag;
- retval->host_no = max_scsi_hosts++; /* never reuse host_no (DB) */
- next_scsi_host++;
- retval->host_queue = NULL;
- retval->host_wait = NULL;
- retval->last_reset = 0;
- retval->irq = 0;
- retval->dma_channel = 0xff;
- retval->io_port = 0;
- retval->forbidden_addr = 0;
- retval->forbidden_size = 0;
- retval->hostt = tpnt;
- retval->next = NULL;
+ struct Scsi_Host * retval, *shpnt;
+ retval = (struct Scsi_Host *)scsi_init_malloc(sizeof(struct Scsi_Host) + j,
+ (tpnt->unchecked_isa_dma && j ? GFP_DMA : 0) | GFP_ATOMIC);
+ retval->host_busy = 0;
+ retval->block = NULL;
+ retval->wish_block = 0;
+ if(j > 0xffff) panic("Too many extra bytes requested\n");
+ retval->extra_bytes = j;
+ retval->loaded_as_module = scsi_loadable_module_flag;
+ retval->host_no = max_scsi_hosts++; /* never reuse host_no (DB) */
+ next_scsi_host++;
+ retval->host_queue = NULL;
+ retval->host_wait = NULL;
+ retval->last_reset = 0;
+ retval->irq = 0;
+ retval->dma_channel = 0xff;
+
+ /* These three are default values which can be overridden */
+ retval->max_channel = 0;
+ retval->max_id = 8;
+ retval->max_lun = 8;
+
+ retval->io_port = 0;
+ retval->forbidden_addr = 0;
+ retval->forbidden_size = 0;
+ retval->hostt = tpnt;
+ retval->next = NULL;
#ifdef DEBUG
- printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
-#endif
-
- /* The next four are the default values which can be overridden
- if need be */
- retval->this_id = tpnt->this_id;
- retval->can_queue = tpnt->can_queue;
- retval->sg_tablesize = tpnt->sg_tablesize;
- retval->cmd_per_lun = tpnt->cmd_per_lun;
- retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
-
- if(!scsi_hostlist)
- scsi_hostlist = retval;
- else
- {
- shpnt = scsi_hostlist;
- while(shpnt->next) shpnt = shpnt->next;
- shpnt->next = retval;
- }
-
- return retval;
+ printk("Register %x %x: %d\n", (int)retval, (int)retval->hostt, j);
+#endif
+
+ /* The next six are the default values which can be overridden
+ * if need be */
+ retval->this_id = tpnt->this_id;
+ retval->can_queue = tpnt->can_queue;
+ retval->sg_tablesize = tpnt->sg_tablesize;
+ retval->cmd_per_lun = tpnt->cmd_per_lun;
+ retval->unchecked_isa_dma = tpnt->unchecked_isa_dma;
+ retval->use_clustering = tpnt->use_clustering;
+ if(!scsi_hostlist)
+ scsi_hostlist = retval;
+ else
+ {
+ shpnt = scsi_hostlist;
+ while(shpnt->next) shpnt = shpnt->next;
+ shpnt->next = retval;
+ }
+
+ return retval;
}
int
scsi_register_device(struct Scsi_Device_Template * sdpnt)
{
- if(sdpnt->next) panic("Device already registered");
- sdpnt->next = scsi_devicelist;
- scsi_devicelist = sdpnt;
- return 0;
+ if(sdpnt->next) panic("Device already registered");
+ sdpnt->next = scsi_devicelist;
+ scsi_devicelist = sdpnt;
+ return 0;
}
unsigned int scsi_init()
{
- static int called = 0;
- int i, pcount;
- Scsi_Host_Template * tpnt;
- struct Scsi_Host * shpnt;
- const char * name;
-
- if(called) return 0;
-
- called = 1;
- for (tpnt = &builtin_scsi_hosts[0], i = 0; i < MAX_SCSI_HOSTS; ++i, tpnt++)
+ static int called = 0;
+ int i, pcount;
+ Scsi_Host_Template * tpnt;
+ struct Scsi_Host * shpnt;
+ const char * name;
+
+ if(called) return 0;
+
+ called = 1;
+ for (tpnt = &builtin_scsi_hosts[0], i = 0; i < MAX_SCSI_HOSTS; ++i, tpnt++)
+ {
+ /*
+ * Initialize our semaphores. -1 is interpreted to mean
+ * "inactive" - where as 0 will indicate a time out condition.
+ */
+
+ pcount = next_scsi_host;
+ if ((tpnt->detect) &&
+ (tpnt->present =
+ tpnt->detect(tpnt)))
{
- /*
- * Initialize our semaphores. -1 is interpreted to mean
- * "inactive" - where as 0 will indicate a time out condition.
- */
-
- pcount = next_scsi_host;
- if ((tpnt->detect) &&
- (tpnt->present =
- tpnt->detect(tpnt)))
- {
- /* The only time this should come up is when people use
- some kind of patched driver of some kind or another. */
- if(pcount == next_scsi_host) {
- if(tpnt->present > 1)
- panic("Failure to register low-level scsi driver");
- /* The low-level driver failed to register a driver. We
- can do this now. */
- scsi_register(tpnt,0);
- };
- tpnt->next = scsi_hosts;
- scsi_hosts = tpnt;
- }
- }
-
-
- for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
- {
- if(shpnt->hostt->info)
- name = shpnt->hostt->info(shpnt);
- else
- name = shpnt->hostt->name;
- printk ("scsi%d : %s\n", /* And print a little message */
- shpnt->host_no, name);
+ /* The only time this should come up is when people use
+ * some kind of patched driver of some kind or another. */
+ if(pcount == next_scsi_host) {
+ if(tpnt->present > 1)
+ panic("Failure to register low-level scsi driver");
+ /* The low-level driver failed to register a driver. We
+ * can do this now. */
+ scsi_register(tpnt,0);
}
-
- printk ("scsi : %d host%s.\n", next_scsi_host,
- (next_scsi_host == 1) ? "" : "s");
-
- scsi_make_blocked_list();
-
- /* Now attach the high level drivers */
+ tpnt->next = scsi_hosts;
+ scsi_hosts = tpnt;
+ }
+ }
+
+ /* Add the drivers to /proc/scsi */
+#if CONFIG_PROC_FS
+ build_proc_dir_entries();
+#endif
+
+ for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+ {
+ if(shpnt->hostt->info)
+ name = shpnt->hostt->info(shpnt);
+ else
+ name = shpnt->hostt->name;
+ printk ("scsi%d : %s\n", /* And print a little message */
+ shpnt->host_no, name);
+ }
+
+ printk ("scsi : %d host%s.\n", next_scsi_host,
+ (next_scsi_host == 1) ? "" : "s");
+
+ scsi_make_blocked_list();
+
+ /* Now attach the high level drivers */
#ifdef CONFIG_BLK_DEV_SD
- scsi_register_device(&sd_template);
+ scsi_register_device(&sd_template);
#endif
#ifdef CONFIG_BLK_DEV_SR
- scsi_register_device(&sr_template);
+ scsi_register_device(&sr_template);
#endif
#ifdef CONFIG_CHR_DEV_ST
- scsi_register_device(&st_template);
+ scsi_register_device(&st_template);
#endif
#ifdef CONFIG_CHR_DEV_SG
- scsi_register_device(&sg_template);
+ scsi_register_device(&sg_template);
#endif
-
+
#if 0
- max_scsi_hosts = next_scsi_host;
+ max_scsi_hosts = next_scsi_host;
#endif
- return 0;
+ return 0;
}
}
}
}
- next_host:
+ next_host:
continue;
}
}
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
* c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
* End:
*/
/*
- * hosts.h Copyright (C) 1992 Drew Eckhardt
- * mid to low-level SCSI driver interface header by
- * Drew Eckhardt
+ * hosts.h Copyright (C) 1992 Drew Eckhardt
+ * mid to low-level SCSI driver interface header by
+ * Drew Eckhardt
*
- * <drew@colorado.edu>
+ * <drew@colorado.edu>
*
* Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
* add scatter-gather, multiple outstanding request, and other
* enhancements.
*
- * Further modified by Eric Youngdale to support multiple host adapters
- * of the same type.
+ * Further modified by Eric Youngdale to support multiple host adapters
+ * of the same type.
*/
#ifndef _HOSTS_H
#define _HOSTS_H
/*
- $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.h,v 1.3 1993/09/24 12:21:00 drew Exp drew $
+ $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.h,v 1.3 1993/09/24 12:21:00 drew Exp drew $
*/
/* It is senseless to set SG_ALL any higher than this - the performance
- does not get any better, and it wastes memory */
+ * does not get any better, and it wastes memory
+ */
#define SG_NONE 0
#define SG_ALL 0xff
#define ENABLE_CLUSTERING 1
/* The various choices mean:
- NONE: Self evident. Host adapter is not capable of scatter-gather.
- ALL: Means that the host adapter module can do scatter-gather,
- and that there is no limit to the size of the table to which
- we scatter/gather data.
- Anything else: Indicates the maximum number of chains that can be
- used in one scatter-gather request.
-*/
+ * NONE: Self evident. Host adapter is not capable of scatter-gather.
+ * ALL: Means that the host adapter module can do scatter-gather,
+ * and that there is no limit to the size of the table to which
+ * we scatter/gather data.
+ * Anything else: Indicates the maximum number of chains that can be
+ * used in one scatter-gather request.
+ */
/*
- The Scsi_Host_Template type has all that is needed to interface with a SCSI
- host in a device independent matter. There is one entry for each different
- type of host adapter that is supported on the system.
-*/
+ * The Scsi_Host_Template type has all that is needed to interface with a SCSI
+ * host in a device independent matter. There is one entry for each different
+ * type of host adapter that is supported on the system.
+ */
typedef struct scsi_disk Disk;
typedef struct SHT
- {
-
- /* Used with loadable modules so we can construct a linked list. */
- struct SHT * next;
-
- /* Used with loadable modules so that we know when it is safe to unload */
- int * usage_count;
-
- /*
- The name pointer is a pointer to the name of the SCSI
- device detected.
- */
-
- char *name;
-
- /*
- The detect function shall return non zero on detection,
- indicating the number of host adapters of this particular
- type were found. It should also
- initialize all data necessary for this particular
- SCSI driver. It is passed the host number, so this host
- knows where the first entry is in the scsi_hosts[] array.
-
- Note that the detect routine MUST not call any of the mid level
- functions to queue commands because things are not guaranteed
- to be set up yet. The detect routine can send commands to
- the host adapter as long as the program control will not be
- passed to scsi.c in the processing of the command. Note
- especially that scsi_malloc/scsi_free must not be called.
- */
-
- int (* detect)(struct SHT *);
-
- /* Used with loadable modules to unload the host structures. Note:
- there is a default action built into the modules code which may
- be sufficient for most host adapters. Thus you may not have to supply
- this at all. */
- int (*release)(struct Scsi_Host *);
- /*
- The info function will return whatever useful
- information the developer sees fit. If not provided, then
- the name field will be used instead.
- */
-
- const char *(* info)(struct Scsi_Host *);
-
- /*
- The command function takes a target, a command (this is a SCSI
- command formatted as per the SCSI spec, nothing strange), a
- data buffer pointer, and data buffer length pointer. The return
- is a status int, bit fielded as follows :
- Byte What
- 0 SCSI status code
- 1 SCSI 1 byte message
- 2 host error return.
- 3 mid level error return
- */
-
- int (* command)(Scsi_Cmnd *);
-
- /*
- The QueueCommand function works in a similar manner
- to the command function. It takes an additional parameter,
- void (* done)(int host, int code) which is passed the host
- # and exit result when the command is complete.
- Host number is the POSITION IN THE hosts array of THIS
- host adapter.
- */
-
- int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-
- /*
- Since the mid level driver handles time outs, etc, we want to
- be able to abort the current command. Abort returns 0 if the
- abortion was successful. The field SCpnt->abort reason
- can be filled in with the appropriate reason why we wanted
- the abort in the first place, and this will be used
- in the mid-level code instead of the host_byte().
- If non-zero, the code passed to it
- will be used as the return code, otherwise
- DID_ABORT should be returned.
-
- Note that the scsi driver should "clean up" after itself,
- resetting the bus, etc. if necessary.
- */
-
- int (* abort)(Scsi_Cmnd *);
-
- /*
- The reset function will reset the SCSI bus. Any executing
- commands should fail with a DID_RESET in the host byte.
- The Scsi_Cmnd is passed so that the reset routine can figure
- out which host adapter should be reset, and also which command
- within the command block was responsible for the reset in
- the first place. Some hosts do not implement a reset function,
- and these hosts must call scsi_request_sense(SCpnt) to keep
- the command alive.
- */
-
- int (* reset)(Scsi_Cmnd *);
- /*
- This function is used to select synchronous communications,
- which will result in a higher data throughput. Not implemented
- yet.
- */
-
- int (* slave_attach)(int, int);
- /*
- This function determines the bios parameters for a given
- harddisk. These tend to be numbers that are made up by
- the host adapter. Parameters:
- size, device number, list (heads, sectors, cylinders)
- */
-
- int (* bios_param)(Disk *, int, int []);
-
- /*
- This determines if we will use a non-interrupt driven
- or an interrupt driven scheme, It is set to the maximum number
- of simultaneous commands a given host adapter will accept.
- */
- int can_queue;
-
- /*
- In many instances, especially where disconnect / reconnect are
- supported, our host also has an ID on the SCSI bus. If this is
- the case, then it must be reserved. Please set this_id to -1 if
- your setup is in single initiator mode, and the host lacks an
- ID.
- */
-
- int this_id;
-
- /*
- This determines the degree to which the host adapter is capable
- of scatter-gather.
- */
-
- short unsigned int sg_tablesize;
-
- /*
- True if this host adapter can make good use of linked commands.
- This will allow more than one command to be queued to a given
- unit on a given host. Set this to the maximum number of command
- blocks to be provided for each device. Set this to 1 for one
- command block per lun, 2 for two, etc. Do not set this to 0.
- You should make sure that the host adapter will do the right thing
- before you try setting this above 1.
- */
-
- short cmd_per_lun;
- /*
- present contains counter indicating how many boards of this
- type were found when we did the scan.
- */
-
- unsigned char present;
- /*
- true if this host adapter uses unchecked DMA onto an ISA bus.
- */
- unsigned unchecked_isa_dma:1;
- /*
- true if this host adapter can make good use of clustering.
- I originally thought that if the tablesize was large that it
- was a waste of CPU cycles to prepare a cluster list, but
- it works out that the Buslogic is faster if you use a smaller
- number of segments (i.e. use clustering). I guess it is
- inefficient.
- */
- unsigned use_clustering:1;
- } Scsi_Host_Template;
+{
+
+ /* Used with loadable modules so we can construct a linked list. */
+ struct SHT * next;
+
+ /* Used with loadable modules so that we know when it is safe to unload */
+ int * usage_count;
+
+ /* proc-fs info function.
+ * Can be used to export driver statistics and other infos to the world
+ * outside the kernel ie. userspace and it also provides an interface
+ * to feed the driver with information. Check eata_dma_proc.c for reference.
+ */
+ int (*proc_info)(char *, char **, off_t, int, int, int);
+
+ /* driver name that will appear in the /proc/scsi directory */
+ char *procname;
+
+ /* low_ino of the drivers /proc/scsi entry. Defined in proc_fs.h */
+ unsigned short low_ino;
+
+ /*
+ * The name pointer is a pointer to the name of the SCSI
+ * device detected.
+ */
+ char *name;
+
+ /*
+ * The detect function shall return non zero on detection,
+ * indicating the number of host adapters of this particular
+ * type were found. It should also
+ * initialize all data necessary for this particular
+ * SCSI driver. It is passed the host number, so this host
+ * knows where the first entry is in the scsi_hosts[] array.
+ *
+ * Note that the detect routine MUST not call any of the mid level
+ * functions to queue commands because things are not guaranteed
+ * to be set up yet. The detect routine can send commands to
+ * the host adapter as long as the program control will not be
+ * passed to scsi.c in the processing of the command. Note
+ * especially that scsi_malloc/scsi_free must not be called.
+ */
+ int (* detect)(struct SHT *);
+
+ /* Used with loadable modules to unload the host structures. Note:
+ * there is a default action built into the modules code which may
+ * be sufficient for most host adapters. Thus you may not have to supply
+ * this at all.
+ */
+ int (*release)(struct Scsi_Host *);
+
+ /*
+ * The info function will return whatever useful
+ * information the developer sees fit. If not provided, then
+ * the name field will be used instead.
+ */
+ const char *(* info)(struct Scsi_Host *);
+
+ /*
+ * The command function takes a target, a command (this is a SCSI
+ * command formatted as per the SCSI spec, nothing strange), a
+ * data buffer pointer, and data buffer length pointer. The return
+ * is a status int, bit fielded as follows :
+ * Byte What
+ * 0 SCSI status code
+ * 1 SCSI 1 byte message
+ * 2 host error return.
+ * 3 mid level error return
+ */
+ int (* command)(Scsi_Cmnd *);
+
+ /*
+ * The QueueCommand function works in a similar manner
+ * to the command function. It takes an additional parameter,
+ * void (* done)(int host, int code) which is passed the host
+ * # and exit result when the command is complete.
+ * Host number is the POSITION IN THE hosts array of THIS
+ * host adapter.
+ */
+ int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+
+ /*
+ * Since the mid level driver handles time outs, etc, we want to
+ * be able to abort the current command. Abort returns 0 if the
+ * abortion was successful. The field SCpnt->abort reason
+ * can be filled in with the appropriate reason why we wanted
+ * the abort in the first place, and this will be used
+ * in the mid-level code instead of the host_byte().
+ * If non-zero, the code passed to it
+ * will be used as the return code, otherwise
+ * DID_ABORT should be returned.
+ *
+ * Note that the scsi driver should "clean up" after itself,
+ * resetting the bus, etc. if necessary.
+ */
+ int (* abort)(Scsi_Cmnd *);
+
+ /*
+ * The reset function will reset the SCSI bus. Any executing
+ * commands should fail with a DID_RESET in the host byte.
+ * The Scsi_Cmnd is passed so that the reset routine can figure
+ * out which host adapter should be reset, and also which command
+ * within the command block was responsible for the reset in
+ * the first place. Some hosts do not implement a reset function,
+ * and these hosts must call scsi_request_sense(SCpnt) to keep
+ * the command alive.
+ */
+ int (* reset)(Scsi_Cmnd *);
+
+ /*
+ * This function is used to select synchronous communications,
+ * which will result in a higher data throughput. Not implemented
+ * yet.
+ */
+ int (* slave_attach)(int, int);
+
+ /*
+ * This function determines the bios parameters for a given
+ * harddisk. These tend to be numbers that are made up by
+ * the host adapter. Parameters:
+ * size, device number, list (heads, sectors, cylinders)
+ */
+ int (* bios_param)(Disk *, int, int []);
+
+ /*
+ * This determines if we will use a non-interrupt driven
+ * or an interrupt driven scheme, It is set to the maximum number
+ * of simultaneous commands a given host adapter will accept.
+ */
+ int can_queue;
+
+ /*
+ * In many instances, especially where disconnect / reconnect are
+ * supported, our host also has an ID on the SCSI bus. If this is
+ * the case, then it must be reserved. Please set this_id to -1 if
+ * your setup is in single initiator mode, and the host lacks an
+ * ID.
+ */
+ int this_id;
+
+ /*
+ * This determines the degree to which the host adapter is capable
+ * of scatter-gather.
+ */
+ short unsigned int sg_tablesize;
+
+ /*
+ * True if this host adapter can make good use of linked commands.
+ * This will allow more than one command to be queued to a given
+ * unit on a given host. Set this to the maximum number of command
+ * blocks to be provided for each device. Set this to 1 for one
+ * command block per lun, 2 for two, etc. Do not set this to 0.
+ * You should make sure that the host adapter will do the right thing
+ * before you try setting this above 1.
+ */
+ short cmd_per_lun;
+
+ /*
+ * present contains counter indicating how many boards of this
+ * type were found when we did the scan.
+ */
+ unsigned char present;
+
+ /*
+ * true if this host adapter uses unchecked DMA onto an ISA bus.
+ */
+ unsigned unchecked_isa_dma:1;
+
+ /*
+ * true if this host adapter can make good use of clustering.
+ * I originally thought that if the tablesize was large that it
+ * was a waste of CPU cycles to prepare a cluster list, but
+ * it works out that the Buslogic is faster if you use a smaller
+ * number of segments (i.e. use clustering). I guess it is
+ * inefficient.
+ */
+ unsigned use_clustering:1;
+
+} Scsi_Host_Template;
/*
- The scsi_hosts array is the array containing the data for all
- possible <supported> scsi hosts. This is similar to the
- Scsi_Host_Template, except that we have one entry for each
- actual physical host adapter on the system, stored as a linked
- list. Note that if there are 2 aha1542 boards, then there will
- be two Scsi_Host entries, but only 1 Scsi_Host_Template entries.
-*/
+ * The scsi_hosts array is the array containing the data for all
+ * possible <supported> scsi hosts. This is similar to the
+ * Scsi_Host_Template, except that we have one entry for each
+ * actual physical host adapter on the system, stored as a linked
+ * list. Note that if there are 2 aha1542 boards, then there will
+ * be two Scsi_Host entries, but only 1 Scsi_Host_Template entries.
+ */
struct Scsi_Host
- {
- struct Scsi_Host * next;
- unsigned short extra_bytes;
- volatile unsigned char host_busy;
- char host_no; /* Used for IOCTL_GET_IDLUN */
- int last_reset;
- struct wait_queue *host_wait;
- Scsi_Cmnd *host_queue;
- Scsi_Host_Template * hostt;
-
- /* Pointer to a circularly linked list - this indicates the hosts
- that should be locked out of performing I/O while we have an active
- command on this host. */
- struct Scsi_Host * block;
- unsigned wish_block:1;
-
- /* These parameters should be set by the detect routine */
- unsigned char *base;
- unsigned int io_port;
- unsigned char n_io_port;
- unsigned char irq;
- unsigned char dma_channel;
-
- /*
- Set these if there are conflicts between memory
- in the < 1mb region and regions at 16mb multiples.
- The address must be on a page boundary.
- */
- unsigned long forbidden_addr;
- unsigned long forbidden_size;
-
- /*
- The rest can be copied from the template, or specifically
- initialized, as required.
- */
-
- int this_id;
- int can_queue;
- short cmd_per_lun;
- short unsigned int sg_tablesize;
- unsigned unchecked_isa_dma:1;
- /*
- True if this host was loaded as a loadable module
- */
- unsigned loaded_as_module:1;
-
- int hostdata[0]; /* Used for storage of host specific stuff */
- };
+{
+ struct Scsi_Host * next;
+ unsigned short extra_bytes;
+ volatile unsigned char host_busy;
+ char host_no; /* Used for IOCTL_GET_IDLUN, /proc/scsi et al. */
+ int last_reset;
+ struct wait_queue *host_wait;
+ Scsi_Cmnd *host_queue;
+ Scsi_Host_Template * hostt;
+
+ /*
+ * These three parameters can be used to allow for wide scsi,
+ * and for host adapters that support multiple busses
+ * The first two should be set to 1 more than the actual max id
+ * or lun (i.e. 8 for normal systems).
+ */
+ unsigned int max_id;
+ unsigned int max_lun;
+ unsigned int max_channel;
+
+ /*
+ * Pointer to a circularly linked list - this indicates the hosts
+ * that should be locked out of performing I/O while we have an active
+ * command on this host.
+ */
+ struct Scsi_Host * block;
+ unsigned wish_block:1;
+
+ /* These parameters should be set by the detect routine */
+ unsigned char *base;
+ unsigned int io_port;
+ unsigned char n_io_port;
+ unsigned char irq;
+ unsigned char dma_channel;
+
+ /*
+ * Set these if there are conflicts between memory
+ * in the < 1mb region and regions at 16mb multiples.
+ * The address must be on a page boundary.
+ */
+ unsigned long forbidden_addr;
+ unsigned long forbidden_size;
+
+ /*
+ * The rest can be copied from the template, or specifically
+ * initialized, as required.
+ */
+
+ int this_id;
+ int can_queue;
+ short cmd_per_lun;
+ short unsigned int sg_tablesize;
+ unsigned unchecked_isa_dma:1;
+ unsigned use_clustering:1;
+ /*
+ * True if this host was loaded as a loadable module
+ */
+ unsigned loaded_as_module:1;
+
+ int hostdata[0]; /* Used for storage of host specific stuff */
+};
extern struct Scsi_Host * scsi_hostlist;
extern struct Scsi_Device_Template * scsi_devicelist;
extern Scsi_Host_Template * scsi_hosts;
/*
- scsi_init initializes the scsi hosts.
-*/
-
+ * scsi_init initializes the scsi hosts.
+ */
-/* We use these goofy things because the MM is not set up when we init
- the scsi subsystem. By using these functions we can write code that
- looks normal. Also, it makes it possible to use the same code for a
- loadable module. */
+/*
+ * We use these goofy things because the MM is not set up when we init
+ * the scsi subsystem. By using these functions we can write code that
+ * looks normal. Also, it makes it possible to use the same code for a
+ * loadable module.
+ */
extern void * scsi_init_malloc(unsigned int size, int priority);
extern void scsi_init_free(char * ptr, unsigned int size);
-void scan_scsis (struct Scsi_Host * shpnt);
+void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded,
+ unchar hchannel, unchar hid, unchar hlun);
extern int next_scsi_host;
struct Scsi_Device_Template
{
- struct Scsi_Device_Template * next;
- char * name;
- char * tag;
- unsigned char scsi_type;
- unsigned char major;
- unsigned char nr_dev; /* Number currently attached */
- unsigned char dev_noticed; /* Number of devices detected. */
- unsigned char dev_max; /* Current size of arrays */
- unsigned blk:1; /* 0 if character device */
- int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
- void (*init)(void); /* Sizes arrays based upon number of devices detected */
- void (*finish)(void); /* Perform initialization after attachment */
- int (*attach)(Scsi_Device *); /* Attach devices to arrays */
- void (*detach)(Scsi_Device *);
+ struct Scsi_Device_Template * next;
+ char * name;
+ char * tag;
+ int * usage_count; /* Used for loadable modules */
+ unsigned char scsi_type;
+ unsigned char major;
+ unsigned char nr_dev; /* Number currently attached */
+ unsigned char dev_noticed; /* Number of devices detected. */
+ unsigned char dev_max; /* Current size of arrays */
+ unsigned blk:1; /* 0 if character device */
+ int (*detect)(Scsi_Device *); /* Returns 1 if we can attach this device */
+ void (*init)(void); /* Sizes arrays based upon number of devices
+ * detected */
+ void (*finish)(void); /* Perform initialization after attachment */
+ int (*attach)(Scsi_Device *); /* Attach devices to arrays */
+ void (*detach)(Scsi_Device *);
};
extern struct Scsi_Device_Template sd_template;
/*
- * This is an ugly hack. If we expect to be able to load devices at run time, we need
- * to leave extra room in some of the data structures. Doing a realloc to enlarge
- * the structures would be riddled with race conditions, so until a better solution
- * is discovered, we use this crude approach
+ * This is an ugly hack. If we expect to be able to load devices at run time,
+ * we need to leave extra room in some of the data structures. Doing a
+ * realloc to enlarge the structures would be riddled with race conditions,
+ * so until a better solution is discovered, we use this crude approach
*/
#define SD_EXTRA_DEVS 2
#define ST_EXTRA_DEVS 2
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
* c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
* End:
*/
* larger SCSI hard drives (untested).
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/kernel.h>
#include <linux/head.h>
#include <linux/types.h>
#include <linux/string.h>
-
#include <linux/sched.h>
+#include <linux/proc_fs.h>
#include <asm/dma.h>
-
#include <asm/system.h>
#include <asm/io.h>
#include "../block/blk.h"
else if(fic > 64) count = 512;
else if (fic > 32) count = 256;
else if ( count2 < in2000_datalen ) /* if drive has < what we want */
- count = in2000_datalen - count2; /* FIFO has the rest */
+ count = in2000_datalen - count2; /* FIFO has the rest */
if ( count > in2000_datalen ) /* count2 is lesser of FIFO & rqst */
count2 = in2000_datalen >> 1; /* converted to word count */
else
outb(CONTROL,INSTAT); /* WD BUS Mode */
outb(0x4C,INDATA);
if ( in2000_datalen ) /* if data xfer cmd */
- outb(0,ININTR); /* Enable FIFO intrpt some boards? */
+ outb(0,ININTR); /* Enable FIFO intrpt some boards? */
outb(COMMAND,INSTAT);
outb(0,INNLED);
outb(8,INDATA); /* Select w/ATN & Transfer */
int in2000_reset(Scsi_Cmnd *);
int in2000_biosparam(Disk *, int, int*);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
#ifndef NULL
#define NULL 0
/* next may be "SG_NONE" or "SG_ALL" or nr. of (1k) blocks per R/W Cmd. */
#define IN2000_SG SG_ALL
-#define IN2000 {NULL, NULL, "Always IN2000", in2000_detect, NULL, \
+#define IN2000 {NULL, NULL, generic_proc_info, \
+ "in2000", PROC_SCSI_IN2000, \
+ "Always IN2000", in2000_detect, NULL, \
NULL, in2000_command, \
in2000_queuecommand, \
in2000_abort, \
in2000_reset, \
- NULL, \
+ NULL, \
in2000_biosparam, \
1, 7, IN2000_SG, 1, 0, 0}
* (255 is the IRQ_NONE constant in NCR5380.h)
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <asm/system.h>
#include <linux/signal.h>
+#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/io.h>
#include "../block/blk.h"
[] = PAS16_OVERRIDE;
#else
[4] = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO},
- {0,IRQ_AUTO}};
+ {0,IRQ_AUTO}};
#endif
#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
unsigned short pas16_offset[ 8 ] =
{
- 0x1c00, /* OUTPUT_DATA_REG */
- 0x1c01, /* INITIATOR_COMMAND_REG */
- 0x1c02, /* MODE_REG */
- 0x1c03, /* TARGET_COMMAND_REG */
- 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */
- 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
- 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
- * START_DMA_TARGET_RECEIVE_REG wo
- */
- 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro,
- * START_DMA_INITIATOR_RECEIVE_REG wo
- */
+ 0x1c00, /* OUTPUT_DATA_REG */
+ 0x1c01, /* INITIATOR_COMMAND_REG */
+ 0x1c02, /* MODE_REG */
+ 0x1c03, /* TARGET_COMMAND_REG */
+ 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */
+ 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
+ 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
+ * START_DMA_TARGET_RECEIVE_REG wo
+ */
+ 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro,
+ * START_DMA_INITIATOR_RECEIVE_REG wo
+ */
};
unsigned int tmp;
unsigned int pas_irq_code;
- /* Initialize the SCSI part of the board */
+ /* Initialize the SCSI part of the board */
- outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG ); /* Timeout counter */
- outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */
- outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
+ outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG ); /* Timeout counter */
+ outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */
+ outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
- NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+ NCR5380_read( RESET_PARITY_INTERRUPT_REG );
/* Set the SCSI interrupt pointer without mucking up the sound
* interrupt pointer in the same byte.
static int commandline_current = 0;
int i;
if (ints[0] != 2)
- printk("pas16_setup : usage pas16=io_port,irq\n");
+ printk("pas16_setup : usage pas16=io_port,irq\n");
else
- if (commandline_current < NO_OVERRIDES) {
- overrides[commandline_current].io_port = (unsigned short) ints[1];
- overrides[commandline_current].irq = ints[2];
- for (i = 0; i < NO_BASES; ++i)
- if (bases[i].io_port == (unsigned short) ints[1]) {
+ if (commandline_current < NO_OVERRIDES) {
+ overrides[commandline_current].io_port = (unsigned short) ints[1];
+ overrides[commandline_current].irq = ints[2];
+ for (i = 0; i < NO_BASES; ++i)
+ if (bases[i].io_port == (unsigned short) ints[1]) {
bases[i].noauto = 1;
break;
}
#if (PDEBUG & PDEBUG_INIT)
printk("scsi-pas16 : probing io_port %04x\n", (unsigned int) bases[current_base].io_port);
#endif
- if ( !bases[current_base].noauto &&
+ if ( !bases[current_base].noauto &&
pas16_hw_detect( current_base ) ){
- io_port = bases[current_base].io_port;
+ io_port = bases[current_base].io_port;
init_board( io_port, default_irqs[ current_base ], 0 );
#if (PDEBUG & PDEBUG_INIT)
- printk("scsi-pas16 : detected board.\n");
+ printk("scsi-pas16 : detected board.\n");
#endif
}
}
if (instance->irq == IRQ_NONE) {
printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
- /* Disable 5380 interrupts, leave drive params the same */
- outb( 0x4d, io_port + SYS_CONFIG_4 );
+ /* Disable 5380 interrupts, leave drive params the same */
+ outb( 0x4d, io_port + SYS_CONFIG_4 );
outb( (inb(io_port + IO_CONFIG_3) & 0x0f), io_port + IO_CONFIG_3 );
}
ip[1] = 32;
ip[2] = size >> 11; /* I think I have it as /(32*64) */
if( ip[2] > 1024 ) { /* yes, >, not >= */
- ip[0]=255;
- ip[1]=63;
- ip[2]=size/(63*255);
- if( ip[2] > 1023 ) /* yes >1023... */
- ip[2] = 1023;
+ ip[0]=255;
+ ip[1]=63;
+ ip[2]=size/(63*255);
+ if( ip[2] > 1023 ) /* yes >1023... */
+ ip[2] = 1023;
}
return 0;
int len) {
register unsigned char *d = dst;
register unsigned short reg = (unsigned short) (instance->io_port +
- P_DATA_REG_OFFSET);
+ P_DATA_REG_OFFSET);
register i = len;
while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) );
insb( reg, d, i );
if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
- outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
+ outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
printk("scsi%d : watchdog timer fired in NCR5380_pread()\n",
instance->host_no);
return -1;
outsb( reg, s, i );
if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
- outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
+ outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
printk("scsi%d : watchdog timer fired in NCR5380_pwrite()\n",
instance->host_no);
return -1;
int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
int pas16_reset(Scsi_Cmnd *);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
#ifndef NULL
#define NULL 0
#endif
#ifdef HOSTS_C
-#define MV_PAS16 {NULL, NULL, "Pro Audio Spectrum-16 SCSI", \
+#define MV_PAS16 {NULL, NULL, generic_proc_info, "pas16", PROC_SCSI_PAS16, \
+ "Pro Audio Spectrum-16 SCSI", \
pas16_detect, NULL, NULL, \
NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL, \
pas16_biosparam, \
#include <linux/string.h>
#include <linux/ioport.h>
#include <linux/sched.h>
+#include <linux/proc_fs.h>
#include <linux/unistd.h>
#include <asm/io.h>
#include <asm/irq.h>
int qlogic_reset(Scsi_Cmnd *);
int qlogic_biosparam(Disk *,int,int[]);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
#ifndef NULL
#define NULL (0)
#endif
#define QLOGIC { \
NULL, \
NULL, \
+ generic_proc_info, \
+ "qlogic", \
+ PROC_SCSI_QLOGIC, \
NULL, \
qlogic_detect, \
NULL, \
/*
- * scsi.c Copyright (C) 1992 Drew Eckhardt
- * Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ * scsi.c Copyright (C) 1992 Drew Eckhardt
+ * Copyright (C) 1993, 1994, 1995 Eric Youngdale
*
- * generic mid-level SCSI driver
- * Initial versions: Drew Eckhardt
- * Subsequent revisions: Eric Youngdale
+ * generic mid-level SCSI driver
+ * Initial versions: Drew Eckhardt
+ * Subsequent revisions: Eric Youngdale
*
- * <drew@colorado.edu>
+ * <drew@colorado.edu>
*
- * Bug correction thanks go to :
- * Rik Faith <faith@cs.unc.edu>
- * Tommy Thorn <tthorn>
- * Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
+ * Bug correction thanks go to :
+ * Rik Faith <faith@cs.unc.edu>
+ * Tommy Thorn <tthorn>
+ * Thomas Wuensche <tw@fgb1.fgb.mw.tu-muenchen.de>
*
- * Modified by Eric Youngdale ericy@cais.com to
- * add scatter-gather, multiple outstanding request, and other
- * enhancements.
+ * Modified by Eric Youngdale ericy@cais.com to
+ * add scatter-gather, multiple outstanding request, and other
+ * enhancements.
+ *
+ * Native multichannel and wide scsi support added
+ * by Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
*/
#include <asm/system.h>
#include <asm/irq.h>
#include <asm/dma.h>
#include <linux/ioport.h>
+#include <linux/kernel.h>
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "constants.h"
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
+#endif
+
#undef USE_STATIC_SCSI_MEMORY
/*
static int time_elapsed;
static volatile struct Scsi_Host * host_active = NULL;
#define SCSI_BLOCK(HOST) ((HOST->block && host_active && HOST != host_active) \
- || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
+ || (HOST->can_queue && HOST->host_busy >= HOST->can_queue))
#define MAX_SCSI_DEVICE_CODE 10
const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
{
- "Direct-Access ",
- "Sequential-Access",
- "Printer ",
- "Processor ",
- "WORM ",
- "CD-ROM ",
- "Scanner ",
- "Optical Device ",
- "Medium Changer ",
- "Communications "
+ "Direct-Access ",
+ "Sequential-Access",
+ "Printer ",
+ "Processor ",
+ "WORM ",
+ "CD-ROM ",
+ "Scanner ",
+ "Optical Device ",
+ "Medium Changer ",
+ "Communications "
};
/*
- global variables :
- scsi_devices an array of these specifying the address for each
- (host, id, LUN)
-*/
+ * global variables :
+ * scsi_devices an array of these specifying the address for each
+ * (host, id, LUN)
+ */
Scsi_Device * scsi_devices = NULL;
/* This variable is merely a hook so that we can debug the kernel with gdb. */
Scsi_Cmnd * last_cmnd = NULL;
+/* This is the pointer to the /proc/scsi code.
+ * It is only initialized to !=0 if the scsi code is present
+ */
+extern int (* dispatch_scsi_info_ptr)(int ino, char *buffer, char **start, off_t offset, int length, int inout);
+extern int dispatch_scsi_info(int ino, char *buffer, char **start, off_t offset, int length, int inout);
+
/*
- * As the scsi do command functions are intelligent, and may need to
- * redo a command, we need to keep track of the last command
- * executed on each one.
+ * As the scsi do command functions are intelligent, and may need to
+ * redo a command, we need to keep track of the last command
+ * executed on each one.
*/
-#define WAS_RESET 0x01
-#define WAS_TIMEDOUT 0x02
-#define WAS_SENSE 0x04
-#define IS_RESETTING 0x08
-#define IS_ABORTING 0x10
+#define WAS_RESET 0x01
+#define WAS_TIMEDOUT 0x02
+#define WAS_SENSE 0x04
+#define IS_RESETTING 0x08
+#define IS_ABORTING 0x10
#define ASKED_FOR_SENSE 0x20
/*
- * This is the number of clock ticks we should wait before we time out
- * and abort the command. This is for where the scsi.c module generates
- * the command, not where it originates from a higher level, in which
- * case the timeout is specified there.
+ * This is the number of clock ticks we should wait before we time out
+ * and abort the command. This is for where the scsi.c module generates
+ * the command, not where it originates from a higher level, in which
+ * case the timeout is specified there.
*
- * ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
- * respectively.
+ * ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT
+ * respectively.
*/
#ifdef DEBUG_TIMEOUT
#ifdef DEBUG
- #define SCSI_TIMEOUT (5*HZ)
+ #define SCSI_TIMEOUT (5*HZ)
#else
- #define SCSI_TIMEOUT (1*HZ)
+ #define SCSI_TIMEOUT (1*HZ)
#endif
#ifdef DEBUG
- #define SENSE_TIMEOUT SCSI_TIMEOUT
- #define ABORT_TIMEOUT SCSI_TIMEOUT
- #define RESET_TIMEOUT SCSI_TIMEOUT
+ #define SENSE_TIMEOUT SCSI_TIMEOUT
+ #define ABORT_TIMEOUT SCSI_TIMEOUT
+ #define RESET_TIMEOUT SCSI_TIMEOUT
#else
- #define SENSE_TIMEOUT (5*HZ/10)
- #define RESET_TIMEOUT (5*HZ/10)
- #define ABORT_TIMEOUT (5*HZ/10)
+ #define SENSE_TIMEOUT (5*HZ/10)
+ #define RESET_TIMEOUT (5*HZ/10)
+ #define ABORT_TIMEOUT (5*HZ/10)
#endif
#define MIN_RESET_DELAY (1*HZ)
#define MIN_RESET_PERIOD (10*HZ)
/* The following devices are known not to tolerate a lun != 0 scan for
- one reason or another. Some will respond to all luns, others will
- lock up. */
+ * one reason or another. Some will respond to all luns, others will
+ * lock up.
+ */
- struct blist{
- char * vendor;
- char * model;
- char * revision; /* Latest revision known to be bad. Not used yet */
- };
+struct blist{
+ char * vendor;
+ char * model;
+ char * revision; /* Latest revision known to be bad. Not used yet */
+};
static struct blist blacklist[] =
{
- {"CHINON","CD-ROM CDS-431","H42"}, /* Locks up if polled for lun != 0 */
- {"CHINON","CD-ROM CDS-535","Q14"}, /* Lockup if polled for lun != 0 */
- {"DENON","DRD-25X","V"}, /* A cdrom that locks up when probed at lun != 0 */
- {"HITACHI","DK312C","CM81"}, /* Responds to all lun - dtg */
- {"HITACHI","DK314C","CR21" }, /* responds to all lun */
- {"IMS", "CDD521/10","2.06"}, /* Locks-up when LUN>0 polled. */
- {"MAXTOR","XT-3280","PR02"}, /* Locks-up when LUN>0 polled. */
- {"MAXTOR","XT-4380S","B3C"}, /* Locks-up when LUN>0 polled. */
- {"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN > 0 polled */
- {"MAXTOR","XT-4170S","B5A"}, /* Locks-up sometimes when LUN>0 polled. */
- {"MAXTOR","XT-8760S","B7B"}, /* guess what? */
- {"NEC","CD-ROM DRIVE:841","1.0"}, /* Locks-up when LUN>0 polled. */
- {"RODIME","RO3000S","2.33"}, /* Locks up if polled for lun != 0 */
- {"SEAGATE", "ST157N", "\004|j"}, /* causes failed REQUEST SENSE on lun 1 for aha152x
- * controller, which causes SCSI code to reset bus.*/
- {"SEAGATE", "ST296","921"}, /* Responds to all lun */
- {"SONY","CD-ROM CDU-541","4.3d"},
- {"SONY","CD-ROM CDU-55S","1.0i"},
- {"TANDBERG","TDC 3600","U07"}, /* Locks up if polled for lun != 0 */
- {"TEAC","CD-ROM","1.06"}, /* causes failed REQUEST SENSE on lun 1 for seagate
- * controller, which causes SCSI code to reset bus.*/
- {"TEXEL","CD-ROM","1.06"}, /* causes failed REQUEST SENSE on lun 1 for seagate
- * controller, which causes SCSI code to reset bus.*/
- {"QUANTUM","LPS525S","3110"},/* Locks sometimes if polled for lun != 0 */
- {"QUANTUM","PD1225S","3110"},/* Locks sometimes if polled for lun != 0 */
- {"MEDIAVIS","CDR-H93MV","1.31"}, /* Locks up if polled for lun != 0 */
- {"SANKYO", "CP525","6.64"}, /* causes failed REQ SENSE, extra reset */
- {"HP", "C1750A", "3226"}, /* scanjet iic */
- {"HP", "C1790A", ""}, /* scanjet iip */
- {"HP", "C2500A", ""}, /* scanjet iicx */
- {NULL, NULL, NULL}};
+{"CHINON","CD-ROM CDS-431","H42"}, /* Locks up if polled for lun != 0 */
+{"CHINON","CD-ROM CDS-535","Q14"}, /* Locks up if polled for lun != 0 */
+{"DENON","DRD-25X","V"}, /* Locks up if probed for lun != 0 */
+{"HITACHI","DK312C","CM81"}, /* Responds to all lun - dtg */
+{"HITACHI","DK314C","CR21" }, /* responds to all lun */
+{"IMS", "CDD521/10","2.06"}, /* Locks-up when LUN>0 polled. */
+{"MAXTOR","XT-3280","PR02"}, /* Locks-up when LUN>0 polled. */
+{"MAXTOR","XT-4380S","B3C"}, /* Locks-up when LUN>0 polled. */
+{"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN>0 polled */
+{"MAXTOR","XT-4170S","B5A"}, /* Locks-up sometimes when LUN>0 polled. */
+{"MAXTOR","XT-8760S","B7B"}, /* guess what? */
+{"NEC","CD-ROM DRIVE:841","1.0"}, /* Locks-up when LUN>0 polled. */
+{"RODIME","RO3000S","2.33"}, /* Locks up if polled for lun != 0 */
+{"SEAGATE", "ST157N", "\004|j"}, /* causes failed REQUEST SENSE on lun 1
+ * for aha152x controller, which causes
+ * SCSI code to reset bus.*/
+{"SEAGATE", "ST296","921"}, /* Responds to all lun */
+{"SONY","CD-ROM CDU-541","4.3d"},
+{"SONY","CD-ROM CDU-55S","1.0i"},
+{"TANDBERG","TDC 3600","U07"}, /* Locks up if polled for lun != 0 */
+{"TEAC","CD-ROM","1.06"}, /* causes failed REQUEST SENSE on lun 1
+ * for seagate controller, which causes
+ * SCSI code to reset bus.*/
+{"TEXEL","CD-ROM","1.06"}, /* causes failed REQUEST SENSE on lun 1
+ * for seagate controller, which causes
+ * SCSI code to reset bus.*/
+{"QUANTUM","LPS525S","3110"}, /* Locks sometimes if polled for lun != 0 */
+{"QUANTUM","PD1225S","3110"}, /* Locks sometimes if polled for lun != 0 */
+{"MEDIAVIS","CDR-H93MV","1.31"}, /* Locks up if polled for lun != 0 */
+{"SANKYO", "CP525","6.64"}, /* causes failed REQ SENSE, extra reset */
+{"HP", "C1750A", "3226"}, /* scanjet iic */
+{"HP", "C1790A", ""}, /* scanjet iip */
+{"HP", "C2500A", ""}, /* scanjet iicx */
+{NULL, NULL, NULL}
+};
static int blacklisted(unsigned char * response_data){
- int i = 0;
- unsigned char * pnt;
- for(i=0; 1; i++){
- if(blacklist[i].vendor == NULL) return 0;
- pnt = &response_data[8];
- while(*pnt && *pnt == ' ') pnt++;
- if(memcmp(blacklist[i].vendor, pnt,
- strlen(blacklist[i].vendor))) continue;
- pnt = &response_data[16];
- while(*pnt && *pnt == ' ') pnt++;
- if(memcmp(blacklist[i].model, pnt,
- strlen(blacklist[i].model))) continue;
- return 1;
- }
+ int i = 0;
+ unsigned char * pnt;
+ for(i=0; 1; i++){
+ if(blacklist[i].vendor == NULL) return 0;
+ pnt = &response_data[8];
+ while(*pnt && *pnt == ' ') pnt++;
+ if(memcmp(blacklist[i].vendor, pnt,
+ strlen(blacklist[i].vendor))) continue;
+ pnt = &response_data[16];
+ while(*pnt && *pnt == ' ') pnt++;
+ if(memcmp(blacklist[i].model, pnt,
+ strlen(blacklist[i].model))) continue;
+ return 1;
+ }
}
/*
- * As the actual SCSI command runs in the background, we must set up a
- * flag that tells scan_scsis() when the result it has is valid.
- * scan_scsis can set the_result to -1, and watch for it to become the
- * actual return code for that call. the scan_scsis_done function() is
- * our user specified completion function that is passed on to the
- * scsi_do_cmd() function.
+ * As the actual SCSI command runs in the background, we must set up a
+ * flag that tells scan_scsis() when the result it has is valid.
+ * scan_scsis can set the_result to -1, and watch for it to become the
+ * actual return code for that call. the scan_scsis_done function() is
+ * our user specified completion function that is passed on to the
+ * scsi_do_cmd() function.
*/
volatile int in_scan_scsis = 0;
static int the_result;
void scsi_make_blocked_list(void) {
- int block_count = 0, index;
- unsigned int flags;
- struct Scsi_Host * sh[128], * shpnt;
-
- /*
- * Create a circular linked list from the scsi hosts which have
- * the "wish_block" field in the Scsi_Host structure set.
- * The blocked list should include all the scsi hosts using ISA DMA.
- * In some systems, using two dma channels simultaneously causes
- * unpredictable results.
- * Among the scsi hosts in the blocked list, only one host at a time
- * is allowed to have active commands queued. The transition from
- * one active host to the next one is allowed only when host_busy == 0
- * for the active host (which implies host_busy == 0 for all the hosts
- * in the list). Moreover for block devices the transition to a new
- * active host is allowed only when a request is completed, since a
- * block device request can be divided into multiple scsi commands
- * (when there are few sg lists or clustering is disabled).
- *
- * (DB, 4 Feb 1995)
- */
-
- save_flags(flags);
- cli();
- host_active = NULL;
-
- for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
-
+ int block_count = 0, index;
+ unsigned int flags;
+ struct Scsi_Host * sh[128], * shpnt;
+
+ /*
+ * Create a circular linked list from the scsi hosts which have
+ * the "wish_block" field in the Scsi_Host structure set.
+ * The blocked list should include all the scsi hosts using ISA DMA.
+ * In some systems, using two dma channels simultaneously causes
+ * unpredictable results.
+ * Among the scsi hosts in the blocked list, only one host at a time
+ * is allowed to have active commands queued. The transition from
+ * one active host to the next one is allowed only when host_busy == 0
+ * for the active host (which implies host_busy == 0 for all the hosts
+ * in the list). Moreover for block devices the transition to a new
+ * active host is allowed only when a request is completed, since a
+ * block device request can be divided into multiple scsi commands
+ * (when there are few sg lists or clustering is disabled).
+ *
+ * (DB, 4 Feb 1995)
+ */
+
+ save_flags(flags);
+ cli();
+ host_active = NULL;
+
+ for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next) {
+
#if 0
- /*
- * Is this is a candidate for the blocked list?
- * Useful to put into the blocked list all the hosts whose driver
- * does not know about the host->block feature.
- */
- if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1;
+ /*
+ * Is this is a candidate for the blocked list?
+ * Useful to put into the blocked list all the hosts whose driver
+ * does not know about the host->block feature.
+ */
+ if (shpnt->unchecked_isa_dma) shpnt->wish_block = 1;
#endif
-
- if (shpnt->wish_block) sh[block_count++] = shpnt;
- }
-
- if (block_count == 1) sh[0]->block = NULL;
-
- else if (block_count > 1) {
-
- for(index = 0; index < block_count - 1; index++) {
- sh[index]->block = sh[index + 1];
+
+ if (shpnt->wish_block) sh[block_count++] = shpnt;
+ }
+
+ if (block_count == 1) sh[0]->block = NULL;
+
+ else if (block_count > 1) {
+
+ for(index = 0; index < block_count - 1; index++) {
+ sh[index]->block = sh[index + 1];
+ printk("scsi%d : added to blocked host list.\n",
+ sh[index]->host_no);
+ }
+
+ sh[block_count - 1]->block = sh[0];
printk("scsi%d : added to blocked host list.\n",
sh[index]->host_no);
- }
-
- sh[block_count - 1]->block = sh[0];
- printk("scsi%d : added to blocked host list.\n",
- sh[index]->host_no);
- }
-
- restore_flags(flags);
- }
+ }
+
+ restore_flags(flags);
+}
static void scan_scsis_done (Scsi_Cmnd * SCpnt)
- {
-
+{
+
#ifdef DEBUG
- printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);
+ printk ("scan_scsis_done(%p, %06x)\n", SCpnt->host, SCpnt->result);
#endif
- SCpnt->request.dev = 0xfffe;
-
- if (SCpnt->request.sem != NULL)
- up(SCpnt->request.sem);
- }
+ SCpnt->request.dev = 0xfffe;
+
+ if (SCpnt->request.sem != NULL)
+ up(SCpnt->request.sem);
+}
#ifdef CONFIG_SCSI_MULTI_LUN
static int max_scsi_luns = 8;
}
/*
- * Detecting SCSI devices :
- * We scan all present host adapter's busses, from ID 0 to ID 6.
- * We use the INQUIRY command, determine device type, and pass the ID /
- * lun address of all sequential devices to the tape driver, all random
- * devices to the disk driver.
+ * Detecting SCSI devices :
+ * We scan all present host adapter's busses, from ID 0 to ID 6.
+ * We use the INQUIRY command, determine device type, and pass the ID /
+ * lun address of all sequential devices to the tape driver, all random
+ * devices to the disk driver.
*/
-void scan_scsis (struct Scsi_Host * shpnt)
+void scan_scsis (struct Scsi_Host * shpnt, unchar hardcoded,
+ unchar hchannel, unchar hid, unchar hlun)
{
- int dev, lun, type;
- unsigned char scsi_cmd [12];
- unsigned char scsi_result0 [256];
- unsigned char * scsi_result;
- Scsi_Device * SDpnt, *SDtail;
- struct Scsi_Device_Template * sdtpnt;
- Scsi_Cmnd *SCpnt;
-
- ++in_scan_scsis;
- lun = 0;
- type = -1;
- SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC|GFP_DMA);
- SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
- SDtail = scsi_devices;
-
- if(scsi_devices) while(SDtail->next) SDtail = SDtail->next;
-
- /* Make sure we have something that is valid for DMA purposes */
- scsi_result = ((current == task[0] || !shpnt->unchecked_isa_dma)
- ? &scsi_result0[0] : scsi_malloc(512));
-
-
- shpnt->host_queue = SCpnt; /* We need this so that commands can time out */
-
- for (dev = 0; dev < 8; ++dev)
- if (shpnt->this_id != dev)
-
-/*
- * We need the for so our continue, etc. work fine.
- */
- for (lun = 0; lun < max_scsi_luns; ++lun)
- {
- memset(SDpnt, 0, sizeof(Scsi_Device));
- SDpnt->host = shpnt;
- SDpnt->id = dev;
- SDpnt->lun = lun;
-
- /* Some low level driver could use device->type (DB) */
- SDpnt->type = -1;
-/*
- * Assume that the device will have handshaking problems, and then
- * fix this field later if it turns out it doesn't.
- */
- SDpnt->borken = 1;
-
- scsi_cmd[0] = TEST_UNIT_READY;
- scsi_cmd[1] = lun << 5;
- scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
-
- memset(SCpnt, 0, sizeof(Scsi_Cmnd));
- SCpnt->host = SDpnt->host;
- SCpnt->device = SDpnt;
- SCpnt->target = SDpnt->id;
- SCpnt->lun = SDpnt->lun;
-
- /* Used for mutex if loading devices after boot */
- SCpnt->request.sem = NULL;
-
- SCpnt->request.dev = 0xffff; /* Mark not busy */
-
- scsi_do_cmd (SCpnt, (void *) scsi_cmd, (void *) scsi_result,
- 256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
-
- /* Wait for command to finish. Use simple wait if we are booting, else
- do it right and use a mutex */
-
- if (current == task[0])
- while (SCpnt->request.dev != 0xfffe) barrier();
- else if (SCpnt->request.dev != 0xfffe) {
- struct semaphore sem = MUTEX_LOCKED;
-
- SCpnt->request.sem = &sem;
- down(&sem);
-
- /* Hmm.. Have to ask about this one */
- while (SCpnt->request.dev != 0xfffe) schedule();
- }
+ int dev, lun, type, channel;
+ unsigned char scsi_cmd [12];
+ unsigned char scsi_result0 [256];
+ unsigned char * scsi_result;
+ Scsi_Device * SDpnt, *SDtail;
+ struct Scsi_Device_Template * sdtpnt;
+ Scsi_Cmnd *SCpnt;
+
+ ++in_scan_scsis;
+ lun = 0;
+ type = -1;
+ SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC|GFP_DMA);
+ SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
+ SDtail = scsi_devices;
+
+ if(scsi_devices) while(SDtail->next) SDtail = SDtail->next;
+
+ /* Make sure we have something that is valid for DMA purposes */
+ scsi_result = ((current->pid == 0 || !shpnt->unchecked_isa_dma)
+ ? &scsi_result0[0] : scsi_malloc(512));
+
+ if(scsi_result == NULL) {
+ printk("Unable to obtain scsi_result buffer\n");
+ goto leave;
+ }
+
+ shpnt->host_queue = SCpnt; /* We need this so that commands can time out */
+
+ if(hardcoded == 1) {
+ channel = hchannel;
+ dev = hid;
+ lun = hlun;
+ goto crude;
+ }
+ for (channel = 0; channel <= shpnt->max_channel; channel++)
+ {
+ for (dev = 0; dev < shpnt->max_id; ++dev) {
+ if (shpnt->this_id != dev) {
+
+ /*
+ * We need the for so our continue, etc. work fine.
+ */
+ for (lun = 0; lun < (max_scsi_luns < shpnt->max_lun ?
+ max_scsi_luns : shpnt->max_lun); ++lun)
+ {
+ crude:
+ memset(SDpnt, 0, sizeof(Scsi_Device));
+ SDpnt->host = shpnt;
+ SDpnt->id = dev;
+ SDpnt->lun = lun;
+ SDpnt->channel = channel;
+
+ /* Some low level driver could use device->type (DB) */
+ SDpnt->type = -1;
+ /*
+ * Assume that the device will have handshaking problems,
+ * and then fix this field later if it turns out it doesn't
+ */
+ SDpnt->borken = 1;
+
+ scsi_cmd[0] = TEST_UNIT_READY;
+ scsi_cmd[1] = lun << 5;
+ scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[4] = scsi_cmd[5] = 0;
+
+ memset(SCpnt, 0, sizeof(Scsi_Cmnd));
+ SCpnt->host = SDpnt->host;
+ SCpnt->device = SDpnt;
+ SCpnt->target = SDpnt->id;
+ SCpnt->lun = SDpnt->lun;
+ SCpnt->channel = SDpnt->channel;
+
+ /* Used for mutex if loading devices after boot */
+ SCpnt->request.sem = NULL;
+
+ SCpnt->request.dev = 0xffff; /* Mark not busy */
+
+ scsi_do_cmd (SCpnt, (void *) scsi_cmd,
+ (void *) scsi_result,
+ 256, scan_scsis_done, SCSI_TIMEOUT + 4 * HZ, 5);
+
+ /*
+ * Wait for command to finish. Use simple wait if we are
+ * booting, else do it right and use a mutex
+ */
+
+ if (current->pid == 0)
+ while (SCpnt->request.dev != 0xfffe)
+ barrier();
+ else if (SCpnt->request.dev != 0xfffe) {
+ struct semaphore sem = MUTEX_LOCKED;
+
+ SCpnt->request.sem = &sem;
+ down(&sem);
+
+ /* Hmm.. Have to ask about this one */
+ while (SCpnt->request.dev != 0xfffe) schedule();
+ }
+
#if defined(DEBUG) || defined(DEBUG_INIT)
- printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
- printk("scsi: return code %08x\n", SCpnt->result);
+ printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
+ printk("scsi: return code %08x\n", SCpnt->result);
#endif
-
- if(SCpnt->result) {
- if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
- (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
- ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
- if (SCpnt->sense_buffer[2] &0xe0)
- continue; /* No devices here... */
- if(((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
- ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION))
- continue;
- }
- else
- break;
- }
-
+ if(SCpnt->result) {
+ if (((driver_byte(SCpnt->result) & DRIVER_SENSE) ||
+ (status_byte(SCpnt->result) & CHECK_CONDITION)) &&
+ ((SCpnt->sense_buffer[0] & 0x70) >> 4) == 7) {
+ if (SCpnt->sense_buffer[2] &0xe0)
+ continue; /* No devices here... */
+ if(((SCpnt->sense_buffer[2] & 0xf) != NOT_READY) &&
+ ((SCpnt->sense_buffer[2] & 0xf) != UNIT_ATTENTION))
+ continue;
+ }
+ else
+ break;
+ }
+
#if defined (DEBUG) || defined(DEBUG_INIT)
- printk("scsi: performing INQUIRY\n");
-#endif
-
- /*
- * Build an INQUIRY command block.
- */
- scsi_cmd[0] = INQUIRY;
- scsi_cmd[1] = (lun << 5) & 0xe0;
- scsi_cmd[2] = 0;
- scsi_cmd[3] = 0;
- scsi_cmd[4] = 255;
- scsi_cmd[5] = 0;
-
- SCpnt->request.dev = 0xffff; /* Mark not busy */
- SCpnt->cmd_len = 0;
-
- scsi_do_cmd (SCpnt, (void *) scsi_cmd, (void *) scsi_result,
- 256, scan_scsis_done, SCSI_TIMEOUT, 3);
-
- if (current == task[0])
- while (SCpnt->request.dev != 0xfffe) barrier();
- else if (SCpnt->request.dev != 0xfffe) {
- struct semaphore sem = MUTEX_LOCKED;
-
- SCpnt->request.sem = &sem;
- down(&sem);
-
- /* Hmm.. Have to ask about this one */
- while (SCpnt->request.dev != 0xfffe) schedule();
- }
-
- the_result = SCpnt->result;
-
-#if defined(DEBUG) || defined(DEBUG_INIT)
- if (!the_result)
- printk("scsi: INQUIRY successful\n");
- else
- printk("scsi: INQUIRY failed with code %08x\n", the_result);
-#endif
-
- if(the_result) break;
-
- /* skip other luns on this device */
-
- if (!the_result)
- {
- /* It would seem some TOSHIBA CD-ROM gets things wrong */
- if (!strncmp(scsi_result+8,"TOSHIBA",7) &&
- !strncmp(scsi_result+16,"CD-ROM",6) &&
- scsi_result[0] == TYPE_DISK) {
- scsi_result[0] = TYPE_ROM;
- scsi_result[1] |= 0x80; /* removable */
- }
-
- if (!strncmp(scsi_result+8,"NEC",3)) {
- if (!strncmp(scsi_result+16,"CD-ROM DRIVE:84 ",16) ||
- !strncmp(scsi_result+16,"CD-ROM DRIVE:25",15))
- SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR;
- else
- SDpnt->manufacturer = SCSI_MAN_NEC;
- } else if (!strncmp(scsi_result+8,"TOSHIBA",7))
- SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
- else
- SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
-
- SDpnt->removable = (0x80 &
- scsi_result[1]) >> 7;
- SDpnt->lockable = SDpnt->removable;
- SDpnt->changed = 0;
- SDpnt->access_count = 0;
- SDpnt->busy = 0;
-/*
- * Currently, all sequential devices are assumed to be tapes,
- * all random devices disk, with the appropriate read only
- * flags set for ROM / WORM treated as RO.
- */
-
- switch (type = (scsi_result[0] & 0x1f))
- {
- case TYPE_TAPE :
- case TYPE_DISK :
- case TYPE_MOD :
- case TYPE_PROCESSOR :
- case TYPE_SCANNER :
- SDpnt->writeable = 1;
- break;
- case TYPE_WORM :
- case TYPE_ROM :
- SDpnt->writeable = 0;
- break;
- default :
-#if 0
-#ifdef DEBUG
- printk("scsi: unknown type %d\n", type);
- print_inquiry(scsi_result);
-#endif
- type = -1;
+ printk("scsi: performing INQUIRY\n");
#endif
- }
-
- SDpnt->soft_reset =
- (scsi_result[7] & 1) && ((scsi_result[3] & 7) == 2);
- SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
- SDpnt->type = (type & 0x1f);
-
- if (type != -1)
- {
- print_inquiry(scsi_result);
-
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->detect) SDpnt->attached +=
- (*sdtpnt->detect)(SDpnt);
-
- SDpnt->scsi_level = scsi_result[2] & 0x07;
- if (SDpnt->scsi_level >= 2 ||
- (SDpnt->scsi_level == 1 &&
- (scsi_result[3] & 0x0f) == 1))
- SDpnt->scsi_level++;
-/*
- * Set the tagged_queue flag for SCSI-II devices that purport to support
- * tagged queuing in the INQUIRY data.
- */
-
- SDpnt->tagged_queue = 0;
-
- if ((SDpnt->scsi_level >= SCSI_2) &&
- (scsi_result[7] & 2)) {
- SDpnt->tagged_supported = 1;
- SDpnt->current_tag = 0;
- }
-
-/*
- * Accommodate drivers that want to sleep when they should be in a polling
- * loop.
- */
-
- SDpnt->disconnect = 0;
-
-/*
- * Some revisions of the Texel CD ROM drives have handshaking
- * problems when used with the Seagate controllers. Before we
- * know what type of device we're talking to, we assume it's
- * borken and then change it here if it turns out that it isn't
- * a TEXEL drive.
- */
-
- if(strncmp("TEXEL", (char *) &scsi_result[8], 5) != 0 ||
- strncmp("CD-ROM", (char *) &scsi_result[16], 6) != 0
-/*
- * XXX 1.06 has problems, some one should figure out the others too so
- * ALL TEXEL drives don't suffer in performance, especially when I finish
- * integrating my seagate patches which do multiple I_T_L nexuses.
- */
-#ifdef notyet
- || (strncmp("1.06", (char *) &scsi_result[[, 4) != 0)))
-#endif
- )
- SDpnt->borken = 0;
-
-
- /* These devices need this "key" to unlock the device
- so we can use it */
- if(memcmp("INSITE", &scsi_result[8], 6) == 0 &&
- (memcmp("Floptical F*8I", &scsi_result[16], 16) == 0
- || memcmp("I325VM", &scsi_result[16], 6) == 0)) {
- printk("Unlocked floptical drive.\n");
- SDpnt->lockable = 0;
- scsi_cmd[0] = MODE_SENSE;
+ /*
+ * Build an INQUIRY command block.
+ */
+ scsi_cmd[0] = INQUIRY;
scsi_cmd[1] = (lun << 5) & 0xe0;
- scsi_cmd[2] = 0x2e;
+ scsi_cmd[2] = 0;
scsi_cmd[3] = 0;
- scsi_cmd[4] = 0x2a;
+ scsi_cmd[4] = 255;
scsi_cmd[5] = 0;
-
+
SCpnt->request.dev = 0xffff; /* Mark not busy */
SCpnt->cmd_len = 0;
- scsi_do_cmd (SCpnt, (void *) scsi_cmd,
- (void *) scsi_result, 0x2a, scan_scsis_done,
- SCSI_TIMEOUT, 3);
-
- if (current == task[0])
- while (SCpnt->request.dev != 0xfffe) barrier();
+ scsi_do_cmd (SCpnt, (void *) scsi_cmd,
+ (void *) scsi_result,
+ 256, scan_scsis_done, SCSI_TIMEOUT, 3);
+
+ if (current->pid == 0)
+ while (SCpnt->request.dev != 0xfffe)
+ barrier();
else if (SCpnt->request.dev != 0xfffe) {
struct semaphore sem = MUTEX_LOCKED;
-
+
SCpnt->request.sem = &sem;
down(&sem);
-
+
/* Hmm.. Have to ask about this one */
while (SCpnt->request.dev != 0xfffe) schedule();
+ }
+
+ the_result = SCpnt->result;
+
+#if defined(DEBUG) || defined(DEBUG_INIT)
+ if (!the_result)
+ printk("scsi: INQUIRY successful\n");
+ else
+ printk("scsi: INQUIRY failed with code %08x\n", the_result);
+#endif
+
+ if(the_result) break;
+
+ /* skip other luns on this device */
+
+ if (!the_result)
+ {
+ /* It would seem some TOSHIBA CDROM
+ * gets things wrong
+ */
+ if (!strncmp(scsi_result+8,"TOSHIBA",7) &&
+ !strncmp(scsi_result+16,"CD-ROM",6) &&
+ scsi_result[0] == TYPE_DISK) {
+ scsi_result[0] = TYPE_ROM;
+ scsi_result[1] |= 0x80; /* removable */
}
- }
- /* Add this device to the linked list at the end */
- if(SDtail)
- SDtail->next = SDpnt;
- else
- scsi_devices = SDpnt;
- SDtail = SDpnt;
-
- SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
- /* Some scsi devices cannot be polled for lun != 0
- due to firmware bugs */
- if(blacklisted(scsi_result)) break;
- /* Old drives like the MAXTOR XT-3280 say vers=0 */
- if ((scsi_result[2] & 0x07) == 0)
- break;
- /* Some scsi-1 peripherals do not handle lun != 0.
- I am assuming that scsi-2 peripherals do better */
- if((scsi_result[2] & 0x07) == 1 &&
- (scsi_result[3] & 0x0f) == 0) break;
- }
- } /* if result == DID_OK ends */
- } /* for lun ends */
-
- shpnt->host_queue = NULL; /* No longer needed here */
-
- /* Last device block does not exist. Free memory. */
- scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
-
- scsi_init_free((char *) SCpnt, sizeof(Scsi_Cmnd));
-
-
- /* If we allocated a buffer so we could do DMA, free it now */
- if (scsi_result != &scsi_result0[0]) scsi_free(scsi_result, 512);
+
+ if (!strncmp(scsi_result+8,"NEC",3)) {
+ if (!strncmp(scsi_result+16,"CD-ROM DRIVE:84 ",16) ||
+ !strncmp(scsi_result+16,"CD-ROM DRIVE:25",15))
+ SDpnt->manufacturer = SCSI_MAN_NEC_OLDCDR;
+ else
+ SDpnt->manufacturer = SCSI_MAN_NEC;
+ } else if (!strncmp(scsi_result+8,"TOSHIBA",7))
+ SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
+ else
+ SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
+
+ memcpy(SDpnt->vendor, scsi_result+8, 8);
+ memcpy(SDpnt->model, scsi_result+16, 16);
+ memcpy(SDpnt->rev, scsi_result+32, 4);
+
+ SDpnt->removable = (0x80 & scsi_result[1]) >> 7;
+ SDpnt->lockable = SDpnt->removable;
+ SDpnt->changed = 0;
+ SDpnt->access_count = 0;
+ SDpnt->busy = 0;
+ /*
+ * Currently, all sequential devices are assumed to be
+ * tapes, all random devices disk, with the appropriate
+ * read only flags set for ROM / WORM treated as RO.
+ */
+
+ switch (type = (scsi_result[0] & 0x1f))
+ {
+ case TYPE_TAPE :
+ case TYPE_DISK :
+ case TYPE_MOD :
+ case TYPE_PROCESSOR :
+ case TYPE_SCANNER :
+ SDpnt->writeable = 1;
+ break;
+ case TYPE_WORM :
+ case TYPE_ROM :
+ SDpnt->writeable = 0;
+ break;
+ default :
+#if 0
+#ifdef DEBUG
+ printk("scsi: unknown type %d\n", type);
+ print_inquiry(scsi_result);
+#endif
+ type = -1;
+#endif
+ }
+
+ SDpnt->soft_reset =
+ (scsi_result[7] & 1) && ((scsi_result[3] &7) == 2);
+ SDpnt->random = (type == TYPE_TAPE) ? 0 : 1;
+ SDpnt->type = (type & 0x1f);
+
+ if (type != -1)
+ {
+ print_inquiry(scsi_result);
+
+ for(sdtpnt = scsi_devicelist; sdtpnt;
+ sdtpnt = sdtpnt->next)
+ if(sdtpnt->detect) SDpnt->attached +=
+ (*sdtpnt->detect)(SDpnt);
+
+ SDpnt->scsi_level = scsi_result[2] & 0x07;
+ if (SDpnt->scsi_level >= 2 ||
+ (SDpnt->scsi_level == 1 &&
+ (scsi_result[3] & 0x0f) == 1))
+ SDpnt->scsi_level++;
+ /*
+ * Set the tagged_queue flag for SCSI-II devices
+ * that purport to support
+ * tagged queuing in the INQUIRY data.
+ */
+
+ SDpnt->tagged_queue = 0;
+
+ if ((SDpnt->scsi_level >= SCSI_2) &&
+ (scsi_result[7] & 2)) {
+ SDpnt->tagged_supported = 1;
+ SDpnt->current_tag = 0;
+ }
+
+ /*
+ * Accommodate drivers that want to sleep when
+ * they should be in a polling loop.
+ */
- in_scan_scsis = 0;
+ SDpnt->disconnect = 0;
+
+ /*
+ * Some revisions of the Texel CD ROM drives have
+ * handshaking problems when used with the Seagate
+ * controllers. Before we know what type of device
+ * we're talking to, we assume it's borken and then
+ * change it here if it turns out that it isn't
+ * a TEXEL drive.
+ */
+ if((strncmp("SONY",(char *) &scsi_result[8], 4)!= 0
+ || strncmp("CD-ROM CDU-8001",
+ (char *) &scsi_result[16], 15) != 0)
+ && (strncmp("TEXEL",
+ (char *) &scsi_result[8], 5) != 0
+ || strncmp("CD-ROM",
+ (char *) &scsi_result[16], 6) != 0
+ /*
+ * XXX 1.06 has problems, some one should
+ * figure out the others too so ALL TEXEL
+ * drives don't suffer in performance,
+ * especially when I finish integrating my
+ * seagate patches which do multiple I_T_L
+ * nexuses.
+ */
+
+#ifdef notyet
+ || (strncmp("1.06",
+ (char *) &scsi_result, 4) != 0)
+#endif
+ ))
+ SDpnt->borken = 0;
+
+
+ /* These devices need this "key" to unlock the
+ * devices so we can use it
+ */
+ if(memcmp("INSITE", &scsi_result[8], 6) == 0 &&
+ (memcmp("Floptical F*8I",
+ &scsi_result[16], 16) == 0
+ || memcmp("I325VM",
+ &scsi_result[16], 6) == 0)) {
+ printk("Unlocked floptical drive.\n");
+ SDpnt->lockable = 0;
+ scsi_cmd[0] = MODE_SENSE;
+ scsi_cmd[1] = (lun << 5) & 0xe0;
+ scsi_cmd[2] = 0x2e;
+ scsi_cmd[3] = 0;
+ scsi_cmd[4] = 0x2a;
+ scsi_cmd[5] = 0;
+
+ SCpnt->request.dev = 0xffff; /* Mark not busy */
+ SCpnt->cmd_len = 0;
+
+ scsi_do_cmd (SCpnt, (void *) scsi_cmd,
+ (void *) scsi_result, 0x2a,
+ scan_scsis_done, SCSI_TIMEOUT, 3);
+
+ if (current->pid == 0)
+ while (SCpnt->request.dev != 0xfffe);
+ else if (SCpnt->request.dev != 0xfffe) {
+ struct semaphore sem = MUTEX_LOCKED;
+
+ SCpnt->request.sem = &sem;
+ down(&sem);
+
+ /* Hmm.. Have to ask about this one */
+ while (SCpnt->request.dev != 0xfffe)
+ schedule();
+ }
+ }
+ /* Add this device to the linked list at the end */
+ if(SDtail)
+ SDtail->next = SDpnt;
+ else
+ scsi_devices = SDpnt;
+ SDtail = SDpnt;
+
+ SDpnt = (Scsi_Device *) scsi_init_malloc(sizeof (Scsi_Device), GFP_ATOMIC);
+ /* Some scsi devices cannot be polled for lun != 0
+ * due to firmware bugs
+ */
+ if(blacklisted(scsi_result)) break;
+ /* Old drives like the MAXTOR XT-3280 say vers=0 */
+ if ((scsi_result[2] & 0x07) == 0)
+ break;
+ /* Some scsi-1 peripherals do not handle lun != 0.
+ * I am assuming that scsi-2 peripherals do better
+ */
+ if((scsi_result[2] & 0x07) == 1 &&
+ (scsi_result[3] & 0x0f) == 0) break;
+ }
+ } /* if result == DID_OK ends */
+
+ if(hardcoded == 1)
+ goto leave;
+ } /* for lun ends */
+ } /* if this_id != id ends */
+ } /* for dev ends */
+ } /* for channel ends */
+
+ leave:
+ shpnt->host_queue = NULL; /* No longer needed here */
+
+
+ /* Last device block does not exist. Free memory. */
+ if(SDpnt != NULL)
+ scsi_init_free((char *) SDpnt, sizeof(Scsi_Device));
+
+ if(SDpnt != NULL)
+ scsi_init_free((char *) SCpnt, sizeof(Scsi_Cmnd));
+
+ /* If we allocated a buffer so we could do DMA, free it now */
+ if (scsi_result != &scsi_result0[0] && scsi_result != NULL)
+ scsi_free(scsi_result, 512);
+
+ in_scan_scsis = 0;
} /* scan_scsis ends */
/*
- * Flag bits for the internal_timeout array
+ * Flag bits for the internal_timeout array
*/
#define NORMAL_TIMEOUT 0
#define IN_ABORT 1
#define IN_RESET 2
+
/*
- This is our time out function, called when the timer expires for a
- given host adapter. It will attempt to abort the currently executing
- command, that failing perform a kernel panic.
-*/
+ * This is our time out function, called when the timer expires for a
+ * given host adapter. It will attempt to abort the currently executing
+ * command, that failing perform a kernel panic.
+ */
static void scsi_times_out (Scsi_Cmnd * SCpnt, int pid)
- {
-
- switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
- {
- case NORMAL_TIMEOUT:
- if (!in_scan_scsis) {
+{
+
+ switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
+ {
+ case NORMAL_TIMEOUT:
+ if (!in_scan_scsis) {
#ifdef DEBUG_TIMEOUT
- scsi_dump_status();
+ scsi_dump_status();
#endif
- }
-
- if (!scsi_abort (SCpnt, DID_TIME_OUT, pid))
- return;
- case IN_ABORT:
- printk("SCSI host %d abort() timed out - resetting\n",
- SCpnt->host->host_no);
- if (!scsi_reset (SCpnt))
- return;
- case IN_RESET:
- case (IN_ABORT | IN_RESET):
- /* This might be controversial, but if there is a bus hang,
- you might conceivably want the machine up and running
- esp if you have an ide disk. */
- printk("Unable to reset scsi host %d - ",SCpnt->host->host_no);
- printk("probably a SCSI bus hang.\n");
- return;
-
- default:
- INTERNAL_ERROR;
- }
-
}
+
+ if (!scsi_abort (SCpnt, DID_TIME_OUT, pid))
+ return;
+ case IN_ABORT:
+ printk("SCSI host %d abort() timed out - resetting\n",
+ SCpnt->host->host_no);
+ if (!scsi_reset (SCpnt))
+ return;
+ case IN_RESET:
+ case (IN_ABORT | IN_RESET):
+ /* This might be controversial, but if there is a bus hang,
+ * you might conceivably want the machine up and running
+ * esp if you have an ide disk.
+ */
+ printk("Unable to reset scsi host %d - ", SCpnt->host->host_no);
+ printk("probably a SCSI bus hang.\n");
+ return;
+
+ default:
+ INTERNAL_ERROR;
+ }
+
+}
/* This function takes a quick look at a request, and decides if it
-can be queued now, or if there would be a stall while waiting for
-something else to finish. This routine assumes that interrupts are
-turned off when entering the routine. It is the responsibility
-of the calling code to ensure that this is the case. */
+ * can be queued now, or if there would be a stall while waiting for
+ * something else to finish. This routine assumes that interrupts are
+ * turned off when entering the routine. It is the responsibility
+ * of the calling code to ensure that this is the case.
+ */
Scsi_Cmnd * request_queueable (struct request * req, Scsi_Device * device)
{
- Scsi_Cmnd * SCpnt = NULL;
- int tablesize;
- struct buffer_head * bh, *bhp;
-
- if (!device)
- panic ("No device passed to request_queueable().\n");
-
- if (req && req->dev <= 0)
- panic("Invalid device in request_queueable");
-
- SCpnt = device->host->host_queue;
+ Scsi_Cmnd * SCpnt = NULL;
+ int tablesize;
+ struct buffer_head * bh, *bhp;
+
+ if (!device)
+ panic ("No device passed to request_queueable().\n");
+
+ if (req && req->dev <= 0)
+ panic("Invalid device in request_queueable");
+
+ SCpnt = device->host->host_queue;
while(SCpnt){
- if(SCpnt->target == device->id &&
- SCpnt->lun == device->lun)
- if(SCpnt->request.dev < 0) break;
- SCpnt = SCpnt->next;
+ if(SCpnt->target == device->id && SCpnt->lun == device->lun
+ && SCpnt->channel == device->channel)
+ if(SCpnt->request.dev < 0) break;
+ SCpnt = SCpnt->next;
}
-
- if (!SCpnt) return NULL;
-
- if (SCSI_BLOCK(device->host)) return NULL;
-
- if (req) {
- memcpy(&SCpnt->request, req, sizeof(struct request));
- tablesize = device->host->sg_tablesize;
- bhp = bh = req->bh;
- if(!tablesize) bh = NULL;
- /* Take a quick look through the table to see how big it is. We already
- have our copy of req, so we can mess with that if we want to. */
- while(req->nr_sectors && bh){
+
+ if (!SCpnt) return NULL;
+
+ if (SCSI_BLOCK(device->host)) return NULL;
+
+ if (req) {
+ memcpy(&SCpnt->request, req, sizeof(struct request));
+ tablesize = device->host->sg_tablesize;
+ bhp = bh = req->bh;
+ if(!tablesize) bh = NULL;
+ /* Take a quick look through the table to see how big it is.
+ * We already have our copy of req, so we can mess with that
+ * if we want to.
+ */
+ while(req->nr_sectors && bh){
bhp = bhp->b_reqnext;
if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;
req->nr_sectors -= bh->b_size >> 9;
req->sector += bh->b_size >> 9;
if(!tablesize) break;
bh = bhp;
- }
- if(req->nr_sectors && bh && bh->b_reqnext){ /* Any leftovers? */
- SCpnt->request.bhtail = bh;
- req->bh = bh->b_reqnext; /* Divide request */
- bh->b_reqnext = NULL;
- bh = req->bh;
-
- /* Now reset things so that req looks OK */
- SCpnt->request.nr_sectors -= req->nr_sectors;
- req->current_nr_sectors = bh->b_size >> 9;
- req->buffer = bh->b_data;
- SCpnt->request.sem = NULL; /* Wait until whole thing done */
+ }
+ if(req->nr_sectors && bh && bh->b_reqnext){ /* Any leftovers? */
+ SCpnt->request.bhtail = bh;
+ req->bh = bh->b_reqnext; /* Divide request */
+ bh->b_reqnext = NULL;
+ bh = req->bh;
+
+ /* Now reset things so that req looks OK */
+ SCpnt->request.nr_sectors -= req->nr_sectors;
+ req->current_nr_sectors = bh->b_size >> 9;
+ req->buffer = bh->b_data;
+ SCpnt->request.sem = NULL; /* Wait until whole thing done */
+ } else {
+ req->dev = -1;
+ wake_up(&wait_for_request);
+ }
} else {
- req->dev = -1;
- wake_up(&wait_for_request);
+ SCpnt->request.dev = 0xffff; /* Busy, but no request */
+ SCpnt->request.sem = NULL; /* And no one is waiting for the device
+ * either */
}
- } else {
- SCpnt->request.dev = 0xffff; /* Busy, but no request */
- SCpnt->request.sem = NULL; /* And no one is waiting for the device either */
- }
-
- SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
- SCpnt->old_use_sg = 0;
- SCpnt->transfersize = 0;
- SCpnt->underflow = 0;
- SCpnt->cmd_len = 0;
- return SCpnt;
+
+ SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
+ SCpnt->old_use_sg = 0;
+ SCpnt->transfersize = 0;
+ SCpnt->underflow = 0;
+ SCpnt->cmd_len = 0;
+#if 1
+/* Since not everyone seems to set the device info correctly
+ * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+ */
+ SCpnt->channel = device->channel;
+ SCpnt->lun = device->lun;
+ SCpnt->target = device->id;
+#endif
+ return SCpnt;
}
/* This function returns a structure pointer that will be valid for
-the device. The wait parameter tells us whether we should wait for
-the unit to become free or not. We are also able to tell this routine
-not to return a descriptor if the host is unable to accept any more
-commands for the time being. We need to keep in mind that there is no
-guarantee that the host remain not busy. Keep in mind the
-request_queueable function also knows the internal allocation scheme
-of the packets for each device */
+ * the device. The wait parameter tells us whether we should wait for
+ * the unit to become free or not. We are also able to tell this routine
+ * not to return a descriptor if the host is unable to accept any more
+ * commands for the time being. We need to keep in mind that there is no
+ * guarantee that the host remain not busy. Keep in mind the
+ * request_queueable function also knows the internal allocation scheme
+ * of the packets for each device
+ */
Scsi_Cmnd * allocate_device (struct request ** reqp, Scsi_Device * device,
int wait)
{
- int dev = -1;
- struct request * req = NULL;
- int tablesize;
- unsigned int flags;
- struct buffer_head * bh, *bhp;
- struct Scsi_Host * host;
- Scsi_Cmnd * SCpnt = NULL;
- Scsi_Cmnd * SCwait = NULL;
-
- if (!device)
- panic ("No device passed to allocate_device().\n");
-
- if (reqp) req = *reqp;
-
- /* See if this request has already been queued by an interrupt routine */
- if (req && (dev = req->dev) <= 0) return NULL;
-
- host = device->host;
-
- if (intr_count && SCSI_BLOCK(host)) return NULL;
-
- while (1==1){
- SCpnt = host->host_queue;
- while(SCpnt){
- if(SCpnt->target == device->id &&
- SCpnt->lun == device->lun) {
- SCwait = SCpnt;
- if(SCpnt->request.dev < 0) break;
- }
- SCpnt = SCpnt->next;
- }
- save_flags(flags);
- cli();
+ int dev = -1;
+ struct request * req = NULL;
+ int tablesize;
+ unsigned int flags;
+ struct buffer_head * bh, *bhp;
+ struct Scsi_Host * host;
+ Scsi_Cmnd * SCpnt = NULL;
+ Scsi_Cmnd * SCwait = NULL;
+
+ if (!device)
+ panic ("No device passed to allocate_device().\n");
+
+ if (reqp) req = *reqp;
+
/* See if this request has already been queued by an interrupt routine */
- if (req && ((req->dev < 0) || (req->dev != dev))) {
- restore_flags(flags);
- return NULL;
- }
- if (!SCpnt || SCpnt->request.dev >= 0) /* Might have changed */
- {
- restore_flags(flags);
- if(!wait) return NULL;
- if (!SCwait) {
- printk("Attempt to allocate device target %d, lun %d\n",
- device->id ,device->lun);
- panic("No device found in allocate_device\n");
+ if (req && (dev = req->dev) <= 0) return NULL;
+
+ host = device->host;
+
+ if (intr_count && SCSI_BLOCK(host)) return NULL;
+
+ while (1==1){
+ SCpnt = host->host_queue;
+ while(SCpnt){
+ if(SCpnt->target == device->id && SCpnt->lun == device->lun
+ && SCpnt->channel == device->channel) {
+ SCwait = SCpnt;
+ if(SCpnt->request.dev < 0) break;
+ }
+ SCpnt = SCpnt->next;
}
- SCSI_SLEEP(&device->device_wait,
- (SCwait->request.dev > 0));
- } else {
- if (req) {
- memcpy(&SCpnt->request, req, sizeof(struct request));
- tablesize = device->host->sg_tablesize;
- bhp = bh = req->bh;
- if(!tablesize) bh = NULL;
- /* Take a quick look through the table to see how big it is. We already
- have our copy of req, so we can mess with that if we want to. */
- while(req->nr_sectors && bh){
- bhp = bhp->b_reqnext;
- if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;
- req->nr_sectors -= bh->b_size >> 9;
- req->sector += bh->b_size >> 9;
- if(!tablesize) break;
- bh = bhp;
- }
- if(req->nr_sectors && bh && bh->b_reqnext){ /* Any leftovers? */
- SCpnt->request.bhtail = bh;
- req->bh = bh->b_reqnext; /* Divide request */
- bh->b_reqnext = NULL;
- bh = req->bh;
- /* Now reset things so that req looks OK */
- SCpnt->request.nr_sectors -= req->nr_sectors;
- req->current_nr_sectors = bh->b_size >> 9;
- req->buffer = bh->b_data;
- SCpnt->request.sem = NULL; /* Wait until whole thing done */
- }
- else
- {
- req->dev = -1;
- *reqp = req->next;
- wake_up(&wait_for_request);
+ save_flags(flags);
+ cli();
+ /* See if this request has already been queued by an interrupt routine
+ */
+ if (req && ((req->dev < 0) || (req->dev != dev))) {
+ restore_flags(flags);
+ return NULL;
+ }
+ if (!SCpnt || SCpnt->request.dev >= 0) /* Might have changed */
+ {
+ restore_flags(flags);
+ if(!wait) return NULL;
+ if (!SCwait) {
+ printk("Attempt to allocate device channel %d, target %d, "
+ "lun %d\n", device->channel, device->id, device->lun);
+ panic("No device found in allocate_device\n");
}
+ SCSI_SLEEP(&device->device_wait,
+ (SCwait->request.dev > 0));
} else {
- SCpnt->request.dev = 0xffff; /* Busy */
- SCpnt->request.sem = NULL; /* And no one is waiting for this to complete */
+ if (req) {
+ memcpy(&SCpnt->request, req, sizeof(struct request));
+ tablesize = device->host->sg_tablesize;
+ bhp = bh = req->bh;
+ if(!tablesize) bh = NULL;
+ /* Take a quick look through the table to see how big it is.
+ * We already have our copy of req, so we can mess with that
+ * if we want to.
+ */
+ while(req->nr_sectors && bh){
+ bhp = bhp->b_reqnext;
+ if(!bhp || !CONTIGUOUS_BUFFERS(bh,bhp)) tablesize--;
+ req->nr_sectors -= bh->b_size >> 9;
+ req->sector += bh->b_size >> 9;
+ if(!tablesize) break;
+ bh = bhp;
+ }
+ if(req->nr_sectors && bh && bh->b_reqnext){/* Any leftovers? */
+ SCpnt->request.bhtail = bh;
+ req->bh = bh->b_reqnext; /* Divide request */
+ bh->b_reqnext = NULL;
+ bh = req->bh;
+ /* Now reset things so that req looks OK */
+ SCpnt->request.nr_sectors -= req->nr_sectors;
+ req->current_nr_sectors = bh->b_size >> 9;
+ req->buffer = bh->b_data;
+ SCpnt->request.sem = NULL; /* Wait until whole thing done*/
+ }
+ else
+ {
+ req->dev = -1;
+ *reqp = req->next;
+ wake_up(&wait_for_request);
+ }
+ } else {
+ SCpnt->request.dev = 0xffff; /* Busy */
+ SCpnt->request.sem = NULL; /* And no one is waiting for this
+ * to complete */
+ }
+ restore_flags(flags);
+ break;
}
- restore_flags(flags);
- break;
- }
- }
-
- SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
- SCpnt->old_use_sg = 0;
- SCpnt->transfersize = 0; /* No default transfer size */
- SCpnt->cmd_len = 0;
- SCpnt->underflow = 0; /* Do not flag underflow conditions */
- return SCpnt;
+ }
+
+ SCpnt->use_sg = 0; /* Reset the scatter-gather flag */
+ SCpnt->old_use_sg = 0;
+ SCpnt->transfersize = 0; /* No default transfer size */
+ SCpnt->cmd_len = 0;
+ SCpnt->underflow = 0; /* Do not flag underflow conditions */
+#if 1
+/* Since not everyone seems to set the device info correctly
+ * before Scsi_Cmnd gets send out to scsi_do_command, we do it here.
+ */
+ SCpnt->channel = device->channel;
+ SCpnt->lun = device->lun;
+ SCpnt->target = device->id;
+#endif
+ return SCpnt;
}
/*
- This is inline because we have stack problemes if we recurse to deeply.
-*/
+ * This is inline because we have stack problemes if we recurse to deeply.
+ */
inline void internal_cmnd (Scsi_Cmnd * SCpnt)
- {
- int temp;
- struct Scsi_Host * host;
- unsigned int flags;
+{
+ int temp;
+ struct Scsi_Host * host;
+ unsigned int flags;
#ifdef DEBUG_DELAY
- int clock;
+ int clock;
#endif
-
- host = SCpnt->host;
-
-/*
- We will wait MIN_RESET_DELAY clock ticks after the last reset so
- we can avoid the drive not being ready.
-*/
-save_flags(flags);
-sti();
-temp = host->last_reset + MIN_RESET_DELAY;
-while (jiffies < temp);
-restore_flags(flags);
-
-update_timeout(SCpnt, SCpnt->timeout_per_command);
-
-/*
- We will use a queued command if possible, otherwise we will emulate the
- queuing and calling of completion function ourselves.
-*/
+
+ host = SCpnt->host;
+
+ /*
+ * We will wait MIN_RESET_DELAY clock ticks after the last reset so
+ * we can avoid the drive not being ready.
+ */
+ save_flags(flags);
+ sti();
+ temp = host->last_reset + MIN_RESET_DELAY;
+ while (jiffies < temp);
+ restore_flags(flags);
+
+ update_timeout(SCpnt, SCpnt->timeout_per_command);
+
+ /*
+ * We will use a queued command if possible, otherwise we will emulate the
+ * queuing and calling of completion function ourselves.
+ */
#ifdef DEBUG
- printk("internal_cmnd (host = %d, target = %d, command = %p, buffer = %p, \n"
- "bufflen = %d, done = %p)\n", SCpnt->host->host_no, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
+ printk("internal_cmnd (host = %d, channel = %d, target = %d, "
+ "command = %p, buffer = %p, \nbufflen = %d, done = %p)\n",
+ SCpnt->host->host_no, SCpnt->channel, SCpnt->target, SCpnt->cmnd,
+ SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
#endif
-
- if (host->can_queue)
- {
+
+ if (host->can_queue)
+ {
#ifdef DEBUG
printk("queuecommand : routine at %p\n",
- host->hostt->queuecommand);
+ host->hostt->queuecommand);
#endif
- /* This locking tries to prevent all sorts of races between
- queuecommand and the interrupt code. In effect,
- we are only allowed to be in queuecommand once at
- any given time, and we can only be in the interrupt
- handler and the queuecommand function at the same time
- when queuecommand is called while servicing the
- interrupt. */
-
- if(!intr_count && SCpnt->host->irq)
- disable_irq(SCpnt->host->irq);
-
- host->hostt->queuecommand (SCpnt, scsi_done);
-
- if(!intr_count && SCpnt->host->irq)
- enable_irq(SCpnt->host->irq);
- }
- else
- {
-
+ /* This locking tries to prevent all sorts of races between
+ * queuecommand and the interrupt code. In effect,
+ * we are only allowed to be in queuecommand once at
+ * any given time, and we can only be in the interrupt
+ * handler and the queuecommand function at the same time
+ * when queuecommand is called while servicing the
+ * interrupt.
+ */
+
+ if(!intr_count && SCpnt->host->irq)
+ disable_irq(SCpnt->host->irq);
+
+ host->hostt->queuecommand (SCpnt, scsi_done);
+
+ if(!intr_count && SCpnt->host->irq)
+ enable_irq(SCpnt->host->irq);
+ }
+ else
+ {
+
#ifdef DEBUG
printk("command() : routine at %p\n", host->hostt->command);
#endif
- temp=host->hostt->command (SCpnt);
- SCpnt->result = temp;
+ temp=host->hostt->command (SCpnt);
+ SCpnt->result = temp;
#ifdef DEBUG_DELAY
- clock = jiffies + 4*HZ;
+ clock = jiffies + 4 * HZ;
while (jiffies < clock);
- printk("done(host = %d, result = %04x) : routine at %08x\n", host->host_no, temp);
+ printk("done(host = %d, result = %04x) : routine at %08x\n",
+ host->host_no, temp);
#endif
- scsi_done(SCpnt);
- }
+ scsi_done(SCpnt);
+ }
#ifdef DEBUG
- printk("leaving internal_cmnd()\n");
+ printk("leaving internal_cmnd()\n");
#endif
- }
+}
static void scsi_request_sense (Scsi_Cmnd * SCpnt)
- {
- unsigned int flags;
-
- save_flags(flags);
- cli();
- SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
- update_timeout(SCpnt, SENSE_TIMEOUT);
- restore_flags(flags);
-
-
- memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
- sizeof(generic_sense));
-
- SCpnt->cmnd[1] = SCpnt->lun << 5;
- SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
-
- SCpnt->request_buffer = &SCpnt->sense_buffer;
- SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
- SCpnt->use_sg = 0;
- SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
- internal_cmnd (SCpnt);
- }
+{
+ unsigned int flags;
+
+ save_flags(flags);
+ cli();
+ SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE;
+ update_timeout(SCpnt, SENSE_TIMEOUT);
+ restore_flags(flags);
+
+
+ memcpy ((void *) SCpnt->cmnd , (void *) generic_sense,
+ sizeof(generic_sense));
+
+ SCpnt->cmnd[1] = SCpnt->lun << 5;
+ SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
+
+ SCpnt->request_buffer = &SCpnt->sense_buffer;
+ SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer);
+ SCpnt->use_sg = 0;
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ internal_cmnd (SCpnt);
+}
/*
- scsi_do_cmd sends all the commands out to the low-level driver. It
- handles the specifics required for each low level driver - ie queued
- or non queued. It also prevents conflicts when different high level
- drivers go for the same host at the same time.
-*/
+ * scsi_do_cmd sends all the commands out to the low-level driver. It
+ * handles the specifics required for each low level driver - ie queued
+ * or non queued. It also prevents conflicts when different high level
+ * drivers go for the same host at the same time.
+ */
void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
- int timeout, int retries
- )
- {
- unsigned long flags;
- struct Scsi_Host * host = SCpnt->host;
-
+ int timeout, int retries)
+{
+ unsigned long flags;
+ struct Scsi_Host * host = SCpnt->host;
+
#ifdef DEBUG
- {
+ {
int i;
int target = SCpnt->target;
- printk ("scsi_do_cmd (host = %d, target = %d, buffer =%p, "
- "bufflen = %d, done = %p, timeout = %d, retries = %d)\n"
- "command : " , host->host_no, target, buffer, bufflen, done, timeout, retries);
+ printk ("scsi_do_cmd (host = %d, channel = %d target = %d, "
+ "buffer =%p, bufflen = %d, done = %p, timeout = %d, "
+ "retries = %d)\n"
+ "command : " , host->host_no, SCpnt->channel, target, buffer,
+ bufflen, done, timeout, retries);
for (i = 0; i < 10; ++i)
- printk ("%02x ", ((unsigned char *) cmnd)[i]);
+ printk ("%02x ", ((unsigned char *) cmnd)[i]);
printk("\n");
- }
+ }
#endif
+
+ if (!host)
+ {
+ panic ("Invalid or not present host.\n");
+ }
+
+
+ /*
+ * We must prevent reentrancy to the lowlevel host driver. This prevents
+ * it - we enter a loop until the host we want to talk to is not busy.
+ * Race conditions are prevented, as interrupts are disabled in between the
+ * time we check for the host being not busy, and the time we mark it busy
+ * ourselves.
+ */
- if (!host)
- {
- panic ("Invalid or not present host.\n");
- }
-
-
-/*
- We must prevent reentrancy to the lowlevel host driver. This prevents
- it - we enter a loop until the host we want to talk to is not busy.
- Race conditions are prevented, as interrupts are disabled in between the
- time we check for the host being not busy, and the time we mark it busy
- ourselves.
-*/
-
- save_flags(flags);
- cli();
- SCpnt->pid = scsi_pid++;
-
- while (SCSI_BLOCK(host)) {
- restore_flags(flags);
- SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
- cli();
- }
-
- if (host->block) host_active = host;
-
- host->host_busy++;
+ save_flags(flags);
+ cli();
+ SCpnt->pid = scsi_pid++;
+
+ while (SCSI_BLOCK(host)) {
restore_flags(flags);
-
-/*
- Our own function scsi_done (which marks the host as not busy, disables
- the timeout counter, etc) will be called by us or by the
- scsi_hosts[host].queuecommand() function needs to also call
- the completion function for the high level driver.
-
-*/
-
- memcpy ((void *) SCpnt->data_cmnd , (void *) cmnd, 12);
+ SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
+ cli();
+ }
+
+ if (host->block) host_active = host;
+
+ host->host_busy++;
+ restore_flags(flags);
+
+ /*
+ * Our own function scsi_done (which marks the host as not busy, disables
+ * the timeout counter, etc) will be called by us or by the
+ * scsi_hosts[host].queuecommand() function needs to also call
+ * the completion function for the high level driver.
+ */
+
+ memcpy ((void *) SCpnt->data_cmnd , (void *) cmnd, 12);
#if 0
- SCpnt->host = host;
- SCpnt->target = target;
- SCpnt->lun = (SCpnt->data_cmnd[1] >> 5);
+ SCpnt->host = host;
+ SCpnt->channel = channel;
+ SCpnt->target = target;
+ SCpnt->lun = (SCpnt->data_cmnd[1] >> 5);
#endif
- SCpnt->bufflen = bufflen;
- SCpnt->buffer = buffer;
- SCpnt->flags=0;
- SCpnt->retries=0;
- SCpnt->allowed=retries;
- SCpnt->done = done;
- SCpnt->timeout_per_command = timeout;
-
- memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 12);
- /* Zero the sense buffer. Some host adapters automatically request
- sense on error. 0 is not a valid sense code. */
- memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
- SCpnt->request_buffer = buffer;
- SCpnt->request_bufflen = bufflen;
- SCpnt->old_use_sg = SCpnt->use_sg;
- if (SCpnt->cmd_len == 0)
- SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
- SCpnt->old_cmd_len = SCpnt->cmd_len;
-
- /* Start the timer ticking. */
-
- SCpnt->internal_timeout = 0;
- SCpnt->abort_reason = 0;
- internal_cmnd (SCpnt);
+ SCpnt->bufflen = bufflen;
+ SCpnt->buffer = buffer;
+ SCpnt->flags=0;
+ SCpnt->retries=0;
+ SCpnt->allowed=retries;
+ SCpnt->done = done;
+ SCpnt->timeout_per_command = timeout;
+
+ memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 12);
+ /* Zero the sense buffer. Some host adapters automatically request
+ * sense on error. 0 is not a valid sense code.
+ */
+ memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
+ SCpnt->request_buffer = buffer;
+ SCpnt->request_bufflen = bufflen;
+ SCpnt->old_use_sg = SCpnt->use_sg;
+ if (SCpnt->cmd_len == 0)
+ SCpnt->cmd_len = COMMAND_SIZE(SCpnt->cmnd[0]);
+ SCpnt->old_cmd_len = SCpnt->cmd_len;
+
+ /* Start the timer ticking. */
+
+ SCpnt->internal_timeout = 0;
+ SCpnt->abort_reason = 0;
+ internal_cmnd (SCpnt);
#ifdef DEBUG
- printk ("Leaving scsi_do_cmd()\n");
+ printk ("Leaving scsi_do_cmd()\n");
#endif
- }
+}
/*
- The scsi_done() function disables the timeout timer for the scsi host,
- marks the host as not busy, and calls the user specified completion
- function for that host's current command.
-*/
+ * The scsi_done() function disables the timeout timer for the scsi host,
+ * marks the host as not busy, and calls the user specified completion
+ * function for that host's current command.
+ */
static void reset (Scsi_Cmnd * SCpnt)
{
#ifdef DEBUG
- printk("scsi: reset(%d)\n", SCpnt->host->host_no);
+ printk("scsi: reset(%d, channel %d)\n", SCpnt->host->host_no,
+ SCpnt->channel);
#endif
- SCpnt->flags |= (WAS_RESET | IS_RESETTING);
- scsi_reset(SCpnt);
+ SCpnt->flags |= (WAS_RESET | IS_RESETTING);
+ scsi_reset(SCpnt);
#ifdef DEBUG
- printk("performing request sense\n");
+ printk("performing request sense\n");
#endif
#if 0 /* FIXME - remove this when done */
- if(SCpnt->flags & NEEDS_JUMPSTART) {
- SCpnt->flags &= ~NEEDS_JUMPSTART;
- scsi_request_sense (SCpnt);
- }
+ if(SCpnt->flags & NEEDS_JUMPSTART) {
+ SCpnt->flags &= ~NEEDS_JUMPSTART;
+ scsi_request_sense (SCpnt);
+ }
#endif
}
static int check_sense (Scsi_Cmnd * SCpnt)
- {
- /* If there is no sense information, request it. If we have already
- requested it, there is no point in asking again - the firmware must be
- confused. */
- if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
- if(!(SCpnt->flags & ASKED_FOR_SENSE))
- return SUGGEST_SENSE;
- else
- return SUGGEST_RETRY;
- }
-
- SCpnt->flags &= ~ASKED_FOR_SENSE;
-
+{
+ /* If there is no sense information, request it. If we have already
+ * requested it, there is no point in asking again - the firmware must
+ * be confused.
+ */
+ if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) {
+ if(!(SCpnt->flags & ASKED_FOR_SENSE))
+ return SUGGEST_SENSE;
+ else
+ return SUGGEST_RETRY;
+ }
+
+ SCpnt->flags &= ~ASKED_FOR_SENSE;
+
#ifdef DEBUG_INIT
- printk("scsi%d : ", SCpnt->host->host_no);
- print_sense("", SCpnt);
- printk("\n");
+ printk("scsi%d, channel%d : ", SCpnt->host->host_no, SCpnt->channel);
+ print_sense("", SCpnt);
+ printk("\n");
#endif
- if (SCpnt->sense_buffer[2] &0xe0)
- return SUGGEST_ABORT;
-
- switch (SCpnt->sense_buffer[2] & 0xf)
- {
- case NO_SENSE:
- return 0;
- case RECOVERED_ERROR:
- return SUGGEST_IS_OK;
-
- case ABORTED_COMMAND:
- return SUGGEST_RETRY;
- case NOT_READY:
- case UNIT_ATTENTION:
- return SUGGEST_ABORT;
-
- /* these three are not supported */
- case COPY_ABORTED:
- case VOLUME_OVERFLOW:
- case MISCOMPARE:
-
- case MEDIUM_ERROR:
- return SUGGEST_REMAP;
- case BLANK_CHECK:
- case DATA_PROTECT:
- case HARDWARE_ERROR:
- case ILLEGAL_REQUEST:
- default:
- return SUGGEST_ABORT;
- }
- }
+ if (SCpnt->sense_buffer[2] & 0xe0)
+ return SUGGEST_ABORT;
+
+ switch (SCpnt->sense_buffer[2] & 0xf)
+ {
+ case NO_SENSE:
+ return 0;
+ case RECOVERED_ERROR:
+ return SUGGEST_IS_OK;
+
+ case ABORTED_COMMAND:
+ return SUGGEST_RETRY;
+ case NOT_READY:
+ case UNIT_ATTENTION:
+ return SUGGEST_ABORT;
+
+ /* these three are not supported */
+ case COPY_ABORTED:
+ case VOLUME_OVERFLOW:
+ case MISCOMPARE:
+
+ case MEDIUM_ERROR:
+ return SUGGEST_REMAP;
+ case BLANK_CHECK:
+ case DATA_PROTECT:
+ case HARDWARE_ERROR:
+ case ILLEGAL_REQUEST:
+ default:
+ return SUGGEST_ABORT;
+ }
+}
/* This function is the mid-level interrupt routine, which decides how
* to handle error conditions. Each invocation of this function must
* called again once the reset is complete.
*
* If none of the above actions are taken, the drive in question
- * will hang. If more than one of the above actions are taken by
- * scsi_done, then unpredictable behavior will result.
+ * will hang. If more than one of the above actions are taken by
+ * scsi_done, then unpredictable behavior will result.
*/
static void scsi_done (Scsi_Cmnd * SCpnt)
- {
- int status=0;
- int exit=0;
- int checked;
- int oldto;
- struct Scsi_Host * host = SCpnt->host;
- int result = SCpnt->result;
- oldto = update_timeout(SCpnt, 0);
-
+{
+ int status=0;
+ int exit=0;
+ int checked;
+ int oldto;
+ struct Scsi_Host * host = SCpnt->host;
+ int result = SCpnt->result;
+ oldto = update_timeout(SCpnt, 0);
+
#ifdef DEBUG_TIMEOUT
- if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
- result, SCpnt->target, SCpnt->lun);
+ if(result) printk("Non-zero result in scsi_done %x %d:%d\n",
+ result, SCpnt->target, SCpnt->lun);
#endif
-
- /* If we requested an abort, (and we got it) then fix up the return
- status to say why */
- if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
- SCpnt->result = result = (result & 0xff00ffff) |
+
+ /* If we requested an abort, (and we got it) then fix up the return
+ * status to say why
+ */
+ if(host_byte(result) == DID_ABORT && SCpnt->abort_reason)
+ SCpnt->result = result = (result & 0xff00ffff) |
(SCpnt->abort_reason << 16);
#define FINISHED 0
#define MAYREDO 1
-#define REDO 3
+#define REDO 3
#define PENDING 4
#ifdef DEBUG
- printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
+ printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
#endif
- if(SCpnt->flags & WAS_SENSE)
+ if(SCpnt->flags & WAS_SENSE)
+ {
+ SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
+ }
+
+ switch (host_byte(result))
+ {
+ case DID_OK:
+ if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
+ /* Failed to obtain sense information */
{
- SCpnt->use_sg = SCpnt->old_use_sg;
- SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->flags &= ~WAS_SENSE;
+ SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+
+ if (!(SCpnt->flags & WAS_RESET))
+ {
+ printk("scsi%d : channel %d target %d lun %d request sense"
+ " failed, performing reset.\n",
+ SCpnt->host->host_no, SCpnt->channel, SCpnt->target,
+ SCpnt->lun);
+ reset(SCpnt);
+ return;
+ }
+ else
+ {
+ exit = (DRIVER_HARD | SUGGEST_ABORT);
+ status = FINISHED;
+ }
}
-
- switch (host_byte(result))
+ else switch(msg_byte(result))
{
- case DID_OK:
- if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
- /* Failed to obtain sense information */
- {
- SCpnt->flags &= ~WAS_SENSE;
- SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-
- if (!(SCpnt->flags & WAS_RESET))
- {
- printk("scsi%d : target %d lun %d request sense failed, performing reset.\n",
- SCpnt->host->host_no, SCpnt->target, SCpnt->lun);
- reset(SCpnt);
- return;
- }
- else
- {
- exit = (DRIVER_HARD | SUGGEST_ABORT);
- status = FINISHED;
- }
- }
- else switch(msg_byte(result))
- {
- case COMMAND_COMPLETE:
- switch (status_byte(result))
- {
- case GOOD:
- if (SCpnt->flags & WAS_SENSE)
- {
+ case COMMAND_COMPLETE:
+ switch (status_byte(result))
+ {
+ case GOOD:
+ if (SCpnt->flags & WAS_SENSE)
+ {
#ifdef DEBUG
- printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n");
+ printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n");
#endif
-
- SCpnt->flags &= ~WAS_SENSE;
- SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-
- switch (checked = check_sense(SCpnt))
- {
- case SUGGEST_SENSE:
- case 0:
+ SCpnt->flags &= ~WAS_SENSE;
+ SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
+
+ switch (checked = check_sense(SCpnt))
+ {
+ case SUGGEST_SENSE:
+ case 0:
#ifdef DEBUG
- printk("NO SENSE. status = REDO\n");
+ printk("NO SENSE. status = REDO\n");
#endif
-
- update_timeout(SCpnt, oldto);
- status = REDO;
- break;
- case SUGGEST_IS_OK:
- break;
- case SUGGEST_REMAP:
- case SUGGEST_RETRY:
+ update_timeout(SCpnt, oldto);
+ status = REDO;
+ break;
+ case SUGGEST_IS_OK:
+ break;
+ case SUGGEST_REMAP:
+ case SUGGEST_RETRY:
#ifdef DEBUG
- printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");
+ printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");
#endif
-
- status = MAYREDO;
- exit = DRIVER_SENSE | SUGGEST_RETRY;
- break;
- case SUGGEST_ABORT:
+ status = MAYREDO;
+ exit = DRIVER_SENSE | SUGGEST_RETRY;
+ break;
+ case SUGGEST_ABORT:
#ifdef DEBUG
- printk("SENSE SUGGEST ABORT - status = FINISHED");
+ printk("SENSE SUGGEST ABORT - status = FINISHED");
#endif
-
- status = FINISHED;
- exit = DRIVER_SENSE | SUGGEST_ABORT;
- break;
- default:
- printk ("Internal error %s %d \n", __FILE__,
- __LINE__);
- }
- }
- else
- {
+ status = FINISHED;
+ exit = DRIVER_SENSE | SUGGEST_ABORT;
+ break;
+ default:
+ printk ("Internal error %s %d \n", __FILE__,
+ __LINE__);
+ }
+ }
+ else
+ {
#ifdef DEBUG
- printk("COMMAND COMPLETE message returned, status = FINISHED. \n");
+ printk("COMMAND COMPLETE message returned, status = FINISHED. \n");
#endif
-
- exit = DRIVER_OK;
- status = FINISHED;
- }
- break;
-
- case CHECK_CONDITION:
- switch (check_sense(SCpnt))
- {
- case 0:
- update_timeout(SCpnt, oldto);
- status = REDO;
- break;
- case SUGGEST_REMAP:
- case SUGGEST_RETRY:
- status = MAYREDO;
- exit = DRIVER_SENSE | SUGGEST_RETRY;
- break;
- case SUGGEST_ABORT:
- status = FINISHED;
- exit = DRIVER_SENSE | SUGGEST_ABORT;
- break;
- case SUGGEST_SENSE:
- scsi_request_sense (SCpnt);
- status = PENDING;
- break;
- }
- break;
-
- case CONDITION_GOOD:
- case INTERMEDIATE_GOOD:
- case INTERMEDIATE_C_GOOD:
- break;
-
- case BUSY:
- update_timeout(SCpnt, oldto);
- status = REDO;
- break;
-
- case RESERVATION_CONFLICT:
- printk("scsi%d : RESERVATION CONFLICT performing reset.\n",
- SCpnt->host->host_no);
- reset(SCpnt);
- return;
+ exit = DRIVER_OK;
+ status = FINISHED;
+ }
+ break;
+
+ case CHECK_CONDITION:
+ switch (check_sense(SCpnt))
+ {
+ case 0:
+ update_timeout(SCpnt, oldto);
+ status = REDO;
+ break;
+ case SUGGEST_REMAP:
+ case SUGGEST_RETRY:
+ status = MAYREDO;
+ exit = DRIVER_SENSE | SUGGEST_RETRY;
+ break;
+ case SUGGEST_ABORT:
+ status = FINISHED;
+ exit = DRIVER_SENSE | SUGGEST_ABORT;
+ break;
+ case SUGGEST_SENSE:
+ scsi_request_sense (SCpnt);
+ status = PENDING;
+ break;
+ }
+ break;
+
+ case CONDITION_GOOD:
+ case INTERMEDIATE_GOOD:
+ case INTERMEDIATE_C_GOOD:
+ break;
+
+ case BUSY:
+ update_timeout(SCpnt, oldto);
+ status = REDO;
+ break;
+
+ case RESERVATION_CONFLICT:
+ printk("scsi%d, channel %d : RESERVATION CONFLICT performing"
+ " reset.\n", SCpnt->host->host_no, SCpnt->channel);
+ reset(SCpnt);
+ return;
#if 0
- exit = DRIVER_SOFT | SUGGEST_ABORT;
- status = MAYREDO;
- break;
+ exit = DRIVER_SOFT | SUGGEST_ABORT;
+ status = MAYREDO;
+ break;
#endif
- default:
- printk ("Internal error %s %d \n"
- "status byte = %d \n", __FILE__,
- __LINE__, status_byte(result));
-
- }
- break;
- default:
- panic("scsi: unsupported message byte %d received\n", msg_byte(result));
- }
- break;
- case DID_TIME_OUT:
+ default:
+ printk ("Internal error %s %d \n"
+ "status byte = %d \n", __FILE__,
+ __LINE__, status_byte(result));
+
+ }
+ break;
+ default:
+ panic("scsi: unsupported message byte %d received\n",
+ msg_byte(result));
+ }
+ break;
+ case DID_TIME_OUT:
#ifdef DEBUG
printk("Host returned DID_TIME_OUT - ");
#endif
-
- if (SCpnt->flags & WAS_TIMEDOUT)
- {
+
+ if (SCpnt->flags & WAS_TIMEDOUT)
+ {
#ifdef DEBUG
- printk("Aborting\n");
+ printk("Aborting\n");
#endif
- exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
- }
- else
- {
+ exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
+ }
+ else
+ {
#ifdef DEBUG
- printk ("Retrying.\n");
+ printk ("Retrying.\n");
#endif
- SCpnt->flags |= WAS_TIMEDOUT;
- SCpnt->internal_timeout &= ~IN_ABORT;
- status = REDO;
- }
- break;
- case DID_BUS_BUSY:
- case DID_PARITY:
- status = REDO;
- break;
- case DID_NO_CONNECT:
+ SCpnt->flags |= WAS_TIMEDOUT;
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ status = REDO;
+ }
+ break;
+ case DID_BUS_BUSY:
+ case DID_PARITY:
+ status = REDO;
+ break;
+ case DID_NO_CONNECT:
#ifdef DEBUG
- printk("Couldn't connect.\n");
+ printk("Couldn't connect.\n");
#endif
- exit = (DRIVER_HARD | SUGGEST_ABORT);
+ exit = (DRIVER_HARD | SUGGEST_ABORT);
+ break;
+ case DID_ERROR:
+ status = MAYREDO;
+ exit = (DRIVER_HARD | SUGGEST_ABORT);
+ break;
+ case DID_BAD_TARGET:
+ case DID_ABORT:
+ exit = (DRIVER_INVALID | SUGGEST_ABORT);
+ break;
+ case DID_RESET:
+ if (SCpnt->flags & IS_RESETTING)
+ {
+ SCpnt->flags &= ~IS_RESETTING;
+ status = REDO;
+ break;
+ }
+
+ if(msg_byte(result) == GOOD &&
+ status_byte(result) == CHECK_CONDITION) {
+ switch (check_sense(SCpnt)) {
+ case 0:
+ update_timeout(SCpnt, oldto);
+ status = REDO;
break;
- case DID_ERROR:
+ case SUGGEST_REMAP:
+ case SUGGEST_RETRY:
status = MAYREDO;
- exit = (DRIVER_HARD | SUGGEST_ABORT);
+ exit = DRIVER_SENSE | SUGGEST_RETRY;
break;
- case DID_BAD_TARGET:
- case DID_ABORT:
- exit = (DRIVER_INVALID | SUGGEST_ABORT);
+ case SUGGEST_ABORT:
+ status = FINISHED;
+ exit = DRIVER_SENSE | SUGGEST_ABORT;
break;
- case DID_RESET:
- if (SCpnt->flags & IS_RESETTING)
- {
- SCpnt->flags &= ~IS_RESETTING;
- status = REDO;
- break;
- }
-
- if(msg_byte(result) == GOOD &&
- status_byte(result) == CHECK_CONDITION) {
- switch (check_sense(SCpnt)) {
- case 0:
- update_timeout(SCpnt, oldto);
- status = REDO;
- break;
- case SUGGEST_REMAP:
- case SUGGEST_RETRY:
- status = MAYREDO;
- exit = DRIVER_SENSE | SUGGEST_RETRY;
- break;
- case SUGGEST_ABORT:
- status = FINISHED;
- exit = DRIVER_SENSE | SUGGEST_ABORT;
- break;
- case SUGGEST_SENSE:
- scsi_request_sense (SCpnt);
- status = PENDING;
- break;
- }
- } else {
- status=REDO;
- exit = SUGGEST_RETRY;
- }
+ case SUGGEST_SENSE:
+ scsi_request_sense (SCpnt);
+ status = PENDING;
break;
- default :
- exit = (DRIVER_ERROR | SUGGEST_DIE);
+ }
+ } else {
+ status=REDO;
+ exit = SUGGEST_RETRY;
}
-
- switch (status)
- {
- case FINISHED:
- case PENDING:
- break;
- case MAYREDO:
-
+ break;
+ default :
+ exit = (DRIVER_ERROR | SUGGEST_DIE);
+ }
+
+ switch (status)
+ {
+ case FINISHED:
+ case PENDING:
+ break;
+ case MAYREDO:
#ifdef DEBUG
printk("In MAYREDO, allowing %d retries, have %d\n",
SCpnt->allowed, SCpnt->retries);
#endif
-
- if ((++SCpnt->retries) < SCpnt->allowed)
- {
- if ((SCpnt->retries >= (SCpnt->allowed >> 1))
- && !(jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
- && !(SCpnt->flags & WAS_RESET))
- {
- printk("scsi%d : resetting for second half of retries.\n",
- SCpnt->host->host_no);
- reset(SCpnt);
- break;
- }
-
- }
- else
- {
- status = FINISHED;
- break;
- }
- /* fall through to REDO */
-
- case REDO:
-
- if (SCpnt->flags & WAS_SENSE)
- scsi_request_sense(SCpnt);
- else
- {
- memcpy ((void *) SCpnt->cmnd,
- (void*) SCpnt->data_cmnd,
- sizeof(SCpnt->data_cmnd));
- SCpnt->request_buffer = SCpnt->buffer;
- SCpnt->request_bufflen = SCpnt->bufflen;
- SCpnt->use_sg = SCpnt->old_use_sg;
- SCpnt->cmd_len = SCpnt->old_cmd_len;
- internal_cmnd (SCpnt);
- }
- break;
- default:
- INTERNAL_ERROR;
- }
-
-
- if (status == FINISHED) {
+ if ((++SCpnt->retries) < SCpnt->allowed)
+ {
+ if ((SCpnt->retries >= (SCpnt->allowed >> 1))
+ && !(jiffies < SCpnt->host->last_reset + MIN_RESET_PERIOD)
+ && !(SCpnt->flags & WAS_RESET))
+ {
+ printk("scsi%d channel %d : resetting for second half of retries.\n",
+ SCpnt->host->host_no, SCpnt->channel);
+ reset(SCpnt);
+ break;
+ }
+
+ }
+ else
+ {
+ status = FINISHED;
+ break;
+ }
+ /* fall through to REDO */
+
+ case REDO:
+
+ if (SCpnt->flags & WAS_SENSE)
+ scsi_request_sense(SCpnt);
+ else
+ {
+ memcpy ((void *) SCpnt->cmnd,
+ (void*) SCpnt->data_cmnd,
+ sizeof(SCpnt->data_cmnd));
+ SCpnt->request_buffer = SCpnt->buffer;
+ SCpnt->request_bufflen = SCpnt->bufflen;
+ SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
+ internal_cmnd (SCpnt);
+ }
+ break;
+ default:
+ INTERNAL_ERROR;
+ }
+
+ if (status == FINISHED) {
#ifdef DEBUG
- printk("Calling done function - at address %p\n", SCpnt->done);
+ printk("Calling done function - at address %p\n", SCpnt->done);
#endif
- host->host_busy--; /* Indicate that we are free */
-
- if (host->block && host->host_busy == 0) {
- host_active = NULL;
-
- /* For block devices "wake_up" is done in end_scsi_request */
- if (MAJOR(SCpnt->request.dev) != SCSI_DISK_MAJOR &&
- MAJOR(SCpnt->request.dev) != SCSI_CDROM_MAJOR) {
- struct Scsi_Host * next;
-
- for (next = host->block; next != host; next = next->block)
+ host->host_busy--; /* Indicate that we are free */
+
+ if (host->block && host->host_busy == 0) {
+ host_active = NULL;
+
+ /* For block devices "wake_up" is done in end_scsi_request */
+ if (MAJOR(SCpnt->request.dev) != SCSI_DISK_MAJOR &&
+ MAJOR(SCpnt->request.dev) != SCSI_CDROM_MAJOR) {
+ struct Scsi_Host * next;
+
+ for (next = host->block; next != host; next = next->block)
wake_up(&next->host_wait);
- }
-
- }
-
- wake_up(&host->host_wait);
- SCpnt->result = result | ((exit & 0xff) << 24);
- SCpnt->use_sg = SCpnt->old_use_sg;
- SCpnt->cmd_len = SCpnt->old_cmd_len;
- SCpnt->done (SCpnt);
- }
-
+ }
+
+ }
+
+ wake_up(&host->host_wait);
+ SCpnt->result = result | ((exit & 0xff) << 24);
+ SCpnt->use_sg = SCpnt->old_use_sg;
+ SCpnt->cmd_len = SCpnt->old_cmd_len;
+ SCpnt->done (SCpnt);
+ }
+
#undef FINISHED
#undef REDO
#undef MAYREDO
#undef PENDING
- }
+}
/*
- The scsi_abort function interfaces with the abort() function of the host
- we are aborting, and causes the current command to not complete. The
- caller should deal with any error messages or status returned on the
- next call.
-
- This will not be called reentrantly for a given host.
-*/
+ * The scsi_abort function interfaces with the abort() function of the host
+ * we are aborting, and causes the current command to not complete. The
+ * caller should deal with any error messages or status returned on the
+ * next call.
+ *
+ * This will not be called reentrantly for a given host.
+ */
/*
- Since we're nice guys and specified that abort() and reset()
- can be non-reentrant. The internal_timeout flags are used for
- this.
-*/
+ * Since we're nice guys and specified that abort() and reset()
+ * can be non-reentrant. The internal_timeout flags are used for
+ * this.
+ */
int scsi_abort (Scsi_Cmnd * SCpnt, int why, int pid)
- {
- int oldto;
- unsigned long flags;
- struct Scsi_Host * host = SCpnt->host;
-
- while(1)
- {
- save_flags(flags);
- cli();
+{
+ int oldto;
+ unsigned long flags;
+ struct Scsi_Host * host = SCpnt->host;
+
+ while(1)
+ {
+ save_flags(flags);
+ cli();
+
+ /*
+ * Protect against races here. If the command is done, or we are
+ * on a different command forget it.
+ */
+ if (SCpnt->request.dev == -1 || pid != SCpnt->pid) {
+ restore_flags(flags);
+ return 0;
+ }
- /*
- * Protect against races here. If the command is done, or we are
- * on a different command forget it.
+ if (SCpnt->internal_timeout & IN_ABORT)
+ {
+ restore_flags(flags);
+ while (SCpnt->internal_timeout & IN_ABORT)
+ barrier();
+ }
+ else
+ {
+ SCpnt->internal_timeout |= IN_ABORT;
+ oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
+
+ if ((SCpnt->flags & IS_RESETTING) &&
+ SCpnt->device->soft_reset) {
+ /* OK, this command must have died when we did the
+ * reset. The device itself must have lied.
*/
- if (SCpnt->request.dev == -1 || pid != SCpnt->pid) {
- restore_flags(flags);
- return 0;
- }
-
- if (SCpnt->internal_timeout & IN_ABORT)
- {
- restore_flags(flags);
- while (SCpnt->internal_timeout & IN_ABORT)
- barrier();
- }
- else
- {
- SCpnt->internal_timeout |= IN_ABORT;
- oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
-
- if ((SCpnt->flags & IS_RESETTING) &&
- SCpnt->device->soft_reset) {
- /* OK, this command must have died when we did the
- reset. The device itself must have lied. */
- printk("Stale command on %d:%d appears to have died when"
- " the bus was reset\n", SCpnt->target, SCpnt->lun);
- }
-
+ printk("Stale command on %d %d:%d appears to have died when"
+ " the bus was reset\n",
+ SCpnt->channel, SCpnt->target, SCpnt->lun);
+ }
+
+ restore_flags(flags);
+ if (!host->host_busy) {
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ update_timeout(SCpnt, oldto);
+ return 0;
+ }
+ printk("scsi : aborting command due to timeout : pid %lu, scsi%d,"
+ " channel %d, id %d, lun %d ",
+ SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->channel,
+ (int) SCpnt->target, (int) SCpnt->lun);
+ print_command (SCpnt->cmnd);
+ if (SCpnt->request.dev == -1 || pid != SCpnt->pid)
+ return 0;
+ SCpnt->abort_reason = why;
+ switch(host->hostt->abort(SCpnt)) {
+ /* We do not know how to abort. Try waiting another
+ * time increment and see if this helps. Set the
+ * WAS_TIMEDOUT flag set so we do not try this twice
+ */
+ case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
+ * this is too severe
+ */
+ case SCSI_ABORT_SNOOZE:
+ if(why == DID_TIME_OUT) {
+ save_flags(flags);
+ cli();
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ if(SCpnt->flags & WAS_TIMEDOUT) {
restore_flags(flags);
- if (!host->host_busy) {
- SCpnt->internal_timeout &= ~IN_ABORT;
- update_timeout(SCpnt, oldto);
- return 0;
- }
- printk("scsi : aborting command due to timeout : pid %lu, scsi%d, id %d, lun %d ",
- SCpnt->pid, SCpnt->host->host_no, (int) SCpnt->target, (int)
- SCpnt->lun);
- print_command (SCpnt->cmnd);
- if (SCpnt->request.dev == -1 || pid != SCpnt->pid)
- return 0;
- SCpnt->abort_reason = why;
- switch(host->hostt->abort(SCpnt)) {
- /* We do not know how to abort. Try waiting another
- time increment and see if this helps. Set the
- WAS_TIMEDOUT flag set so we do not try this twice
- */
- case SCSI_ABORT_BUSY: /* Tough call - returning 1 from
- this is too severe */
- case SCSI_ABORT_SNOOZE:
- if(why == DID_TIME_OUT) {
- save_flags(flags);
- cli();
- SCpnt->internal_timeout &= ~IN_ABORT;
- if(SCpnt->flags & WAS_TIMEDOUT) {
- restore_flags(flags);
- return 1; /* Indicate we cannot handle this.
- We drop down into the reset handler
- and try again */
- } else {
- SCpnt->flags |= WAS_TIMEDOUT;
- oldto = SCpnt->timeout_per_command;
- update_timeout(SCpnt, oldto);
- }
- restore_flags(flags);
- }
- return 0;
- case SCSI_ABORT_PENDING:
- if(why != DID_TIME_OUT) {
- save_flags(flags);
- cli();
- update_timeout(SCpnt, oldto);
- restore_flags(flags);
- }
- return 0;
- case SCSI_ABORT_SUCCESS:
- /* We should have already aborted this one. No
- need to adjust timeout */
- case SCSI_ABORT_NOT_RUNNING:
- SCpnt->internal_timeout &= ~IN_ABORT;
- update_timeout(SCpnt, 0);
- return 0;
- case SCSI_ABORT_ERROR:
- default:
- SCpnt->internal_timeout &= ~IN_ABORT;
- return 1;
- }
- }
- }
- }
+ return 1; /* Indicate we cannot handle this.
+ * We drop down into the reset handler
+ * and try again
+ */
+ } else {
+ SCpnt->flags |= WAS_TIMEDOUT;
+ oldto = SCpnt->timeout_per_command;
+ update_timeout(SCpnt, oldto);
+ }
+ restore_flags(flags);
+ }
+ return 0;
+ case SCSI_ABORT_PENDING:
+ if(why != DID_TIME_OUT) {
+ save_flags(flags);
+ cli();
+ update_timeout(SCpnt, oldto);
+ restore_flags(flags);
+ }
+ return 0;
+ case SCSI_ABORT_SUCCESS:
+ /* We should have already aborted this one. No
+ * need to adjust timeout
+ */
+ case SCSI_ABORT_NOT_RUNNING:
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ update_timeout(SCpnt, 0);
+ return 0;
+ case SCSI_ABORT_ERROR:
+ default:
+ SCpnt->internal_timeout &= ~IN_ABORT;
+ return 1;
+ }
+ }
+ }
+}
int scsi_reset (Scsi_Cmnd * SCpnt)
- {
- int temp, oldto;
- unsigned long flags;
- Scsi_Cmnd * SCpnt1;
- struct Scsi_Host * host = SCpnt->host;
+{
+ int temp, oldto;
+ unsigned long flags;
+ Scsi_Cmnd * SCpnt1;
+ struct Scsi_Host * host = SCpnt->host;
#ifdef DEBUG
- printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",host->host_no);
+ printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",
+ host->host_no);
#endif
- while (1) {
- save_flags(flags);
- cli();
- if (SCpnt->internal_timeout & IN_RESET)
- {
- restore_flags(flags);
- while (SCpnt->internal_timeout & IN_RESET)
- barrier();
- }
- else
- {
- SCpnt->internal_timeout |= IN_RESET;
- oldto = update_timeout(SCpnt, RESET_TIMEOUT);
-
- if (host->host_busy)
- {
- restore_flags(flags);
- SCpnt1 = host->host_queue;
- while(SCpnt1) {
- if (SCpnt1->request.dev > 0) {
+ while (1) {
+ save_flags(flags);
+ cli();
+ if (SCpnt->internal_timeout & IN_RESET)
+ {
+ restore_flags(flags);
+ while (SCpnt->internal_timeout & IN_RESET)
+ barrier();
+ }
+ else
+ {
+ SCpnt->internal_timeout |= IN_RESET;
+ oldto = update_timeout(SCpnt, RESET_TIMEOUT);
+
+ if (host->host_busy)
+ {
+ restore_flags(flags);
+ SCpnt1 = host->host_queue;
+ while(SCpnt1) {
+ if (SCpnt1->request.dev > 0) {
#if 0
- if (!(SCpnt1->flags & IS_RESETTING) &&
- !(SCpnt1->internal_timeout & IN_ABORT))
- scsi_abort(SCpnt1, DID_RESET, SCpnt->pid);
+ if (!(SCpnt1->flags & IS_RESETTING) &&
+ !(SCpnt1->internal_timeout & IN_ABORT))
+ scsi_abort(SCpnt1, DID_RESET, SCpnt->pid);
#endif
- SCpnt1->flags |= IS_RESETTING;
- }
- SCpnt1 = SCpnt1->next;
- }
-
- host->last_reset = jiffies;
- temp = host->hostt->reset(SCpnt);
- host->last_reset = jiffies;
- }
- else
- {
- if (!host->block) host->host_busy++;
- restore_flags(flags);
- host->last_reset = jiffies;
- temp = host->hostt->reset(SCpnt);
- host->last_reset = jiffies;
- if (!host->block) host->host_busy--;
- }
-
+ SCpnt1->flags |= IS_RESETTING;
+ }
+ SCpnt1 = SCpnt1->next;
+ }
+
+ host->last_reset = jiffies;
+ temp = host->hostt->reset(SCpnt);
+ host->last_reset = jiffies;
+ }
+ else
+ {
+ if (!host->block) host->host_busy++;
+ restore_flags(flags);
+ host->last_reset = jiffies;
+ temp = host->hostt->reset(SCpnt);
+ host->last_reset = jiffies;
+ if (!host->block) host->host_busy--;
+ }
+
#ifdef DEBUG
- printk("scsi reset function returned %d\n", temp);
+ printk("scsi reset function returned %d\n", temp);
#endif
- switch(temp) {
- case SCSI_RESET_SUCCESS:
- save_flags(flags);
- cli();
- SCpnt->internal_timeout &= ~IN_RESET;
- update_timeout(SCpnt, oldto);
- restore_flags(flags);
- return 0;
- case SCSI_RESET_PENDING:
- return 0;
- case SCSI_RESET_PUNT:
- case SCSI_RESET_WAKEUP:
- SCpnt->internal_timeout &= ~IN_RESET;
- scsi_request_sense (SCpnt);
- return 0;
- case SCSI_RESET_SNOOZE:
- /* In this case, we set the timeout field to 0
- so that this command does not time out any more,
- and we return 1 so that we get a message on the
- screen. */
- save_flags(flags);
- cli();
- SCpnt->internal_timeout &= ~IN_RESET;
- update_timeout(SCpnt, 0);
- restore_flags(flags);
- /* If you snooze, you lose... */
- case SCSI_RESET_ERROR:
- default:
- return 1;
- }
-
- return temp;
- }
- }
+ switch(temp) {
+ case SCSI_RESET_SUCCESS:
+ save_flags(flags);
+ cli();
+ SCpnt->internal_timeout &= ~IN_RESET;
+ update_timeout(SCpnt, oldto);
+ restore_flags(flags);
+ return 0;
+ case SCSI_RESET_PENDING:
+ return 0;
+ case SCSI_RESET_PUNT:
+ case SCSI_RESET_WAKEUP:
+ SCpnt->internal_timeout &= ~IN_RESET;
+ scsi_request_sense (SCpnt);
+ return 0;
+ case SCSI_RESET_SNOOZE:
+ /* In this case, we set the timeout field to 0
+ * so that this command does not time out any more,
+ * and we return 1 so that we get a message on the
+ * screen.
+ */
+ save_flags(flags);
+ cli();
+ SCpnt->internal_timeout &= ~IN_RESET;
+ update_timeout(SCpnt, 0);
+ restore_flags(flags);
+ /* If you snooze, you lose... */
+ case SCSI_RESET_ERROR:
+ default:
+ return 1;
+ }
+
+ return temp;
}
+ }
+}
static void scsi_main_timeout(void)
- {
- /*
- We must not enter update_timeout with a timeout condition still pending.
- */
-
- int timed_out, pid;
- unsigned long flags;
- struct Scsi_Host * host;
- Scsi_Cmnd * SCpnt = NULL;
-
- do {
- save_flags(flags);
- cli();
-
- update_timeout(NULL, 0);
+{
+ /*
+ * We must not enter update_timeout with a timeout condition still pending.
+ */
+
+ int timed_out, pid;
+ unsigned long flags;
+ struct Scsi_Host * host;
+ Scsi_Cmnd * SCpnt = NULL;
+
+ do {
+ save_flags(flags);
+ cli();
+
+ update_timeout(NULL, 0);
/*
- Find all timers such that they have 0 or negative (shouldn't happen)
- time remaining on them.
- */
-
- timed_out = 0;
- for(host = scsi_hostlist; host; host = host->next) {
- for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
- if (SCpnt->timeout == -1)
- {
- SCpnt->timeout = 0;
- pid = SCpnt->pid;
- restore_flags(flags);
- scsi_times_out(SCpnt, pid);
- ++timed_out;
- save_flags(flags);
- cli();
- }
+ * Find all timers such that they have 0 or negative (shouldn't happen)
+ * time remaining on them.
+ */
+
+ timed_out = 0;
+ for(host = scsi_hostlist; host; host = host->next) {
+ for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
+ if (SCpnt->timeout == -1)
+ {
+ SCpnt->timeout = 0;
+ pid = SCpnt->pid;
+ restore_flags(flags);
+ scsi_times_out(SCpnt, pid);
+ ++timed_out;
+ save_flags(flags);
+ cli();
}
- } while (timed_out);
- restore_flags(flags);
- }
+ }
+ } while (timed_out);
+ restore_flags(flags);
+}
/*
- The strategy is to cause the timer code to call scsi_times_out()
- when the soonest timeout is pending.
- The arguments are used when we are queueing a new command, because
- we do not want to subtract the time used from this time, but when we
- set the timer, we want to take this value into account.
-*/
+ * The strategy is to cause the timer code to call scsi_times_out()
+ * when the soonest timeout is pending.
+ * The arguments are used when we are queueing a new command, because
+ * we do not want to subtract the time used from this time, but when we
+ * set the timer, we want to take this value into account.
+ */
static int update_timeout(Scsi_Cmnd * SCset, int timeout)
- {
- unsigned int least, used;
- unsigned int oldto;
- unsigned long flags;
- struct Scsi_Host * host;
- Scsi_Cmnd * SCpnt = NULL;
-
- save_flags(flags);
- cli();
-
-/*
- Figure out how much time has passed since the last time the timeouts
- were updated
-*/
- used = (time_start) ? (jiffies - time_start) : 0;
+{
+ unsigned int least, used;
+ unsigned int oldto;
+ unsigned long flags;
+ struct Scsi_Host * host;
+ Scsi_Cmnd * SCpnt = NULL;
-/*
- Find out what is due to timeout soonest, and adjust all timeouts for
- the amount of time that has passed since the last time we called
- update_timeout.
-*/
+ save_flags(flags);
+ cli();
- oldto = 0;
+ /*
+ * Figure out how much time has passed since the last time the timeouts
+ * were updated
+ */
+ used = (time_start) ? (jiffies - time_start) : 0;
- if(SCset){
- oldto = SCset->timeout - used;
- SCset->timeout = timeout + used;
- }
+ /*
+ * Find out what is due to timeout soonest, and adjust all timeouts for
+ * the amount of time that has passed since the last time we called
+ * update_timeout.
+ */
- least = 0xffffffff;
+ oldto = 0;
+
+ if(SCset){
+ oldto = SCset->timeout - used;
+ SCset->timeout = timeout + used;
+ }
- for(host = scsi_hostlist; host; host = host->next)
- for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
+ least = 0xffffffff;
+
+ for(host = scsi_hostlist; host; host = host->next)
+ for(SCpnt = host->host_queue; SCpnt; SCpnt = SCpnt->next)
if (SCpnt->timeout > 0) {
- SCpnt->timeout -= used;
- if(SCpnt->timeout <= 0) SCpnt->timeout = -1;
- if(SCpnt->timeout > 0 && SCpnt->timeout < least)
- least = SCpnt->timeout;
+ SCpnt->timeout -= used;
+ if(SCpnt->timeout <= 0) SCpnt->timeout = -1;
+ if(SCpnt->timeout > 0 && SCpnt->timeout < least)
+ least = SCpnt->timeout;
}
-
-/*
- If something is due to timeout again, then we will set the next timeout
- interrupt to occur. Otherwise, timeouts are disabled.
-*/
-
- if (least != 0xffffffff)
- {
- time_start = jiffies;
- timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
- timer_active |= 1 << SCSI_TIMER;
- }
- else
- {
- timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
- timer_active &= ~(1 << SCSI_TIMER);
- }
- restore_flags(flags);
- return oldto;
- }
+
+ /*
+ * If something is due to timeout again, then we will set the next timeout
+ * interrupt to occur. Otherwise, timeouts are disabled.
+ */
+
+ if (least != 0xffffffff)
+ {
+ time_start = jiffies;
+ timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies;
+ timer_active |= 1 << SCSI_TIMER;
+ }
+ else
+ {
+ timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0;
+ timer_active &= ~(1 << SCSI_TIMER);
+ }
+ restore_flags(flags);
+ return oldto;
+}
static unsigned char * dma_malloc_freelist = NULL;
void *scsi_malloc(unsigned int len)
{
- unsigned int nbits, mask;
- unsigned long flags;
- int i, j;
- if((len & 0x1ff) || len > (1<<MALLOC_PAGEBITS))
- return NULL;
-
- save_flags(flags);
- cli();
- nbits = len >> 9;
- mask = (1 << nbits) - 1;
-
- for(i=0;i < (dma_sectors >> (MALLOC_PAGEBITS - 9)); i++)
- for(j=0; j<=(sizeof(*dma_malloc_freelist) * 8) - nbits; j++){
- if ((dma_malloc_freelist[i] & (mask << j)) == 0){
- dma_malloc_freelist[i] |= (mask << j);
- restore_flags(flags);
- dma_free_sectors -= nbits;
+ unsigned int nbits, mask;
+ unsigned long flags;
+ int i, j;
+ if((len & 0x1ff) || len > (1<<MALLOC_PAGEBITS))
+ return NULL;
+
+ save_flags(flags);
+ cli();
+ nbits = len >> 9;
+ mask = (1 << nbits) - 1;
+
+ for(i=0;i < (dma_sectors >> (MALLOC_PAGEBITS - 9)); i++)
+ for(j=0; j<=(sizeof(*dma_malloc_freelist) * 8) - nbits; j++){
+ if ((dma_malloc_freelist[i] & (mask << j)) == 0){
+ dma_malloc_freelist[i] |= (mask << j);
+ restore_flags(flags);
+ dma_free_sectors -= nbits;
#ifdef DEBUG
- printk("SMalloc: %d %p ",len, dma_malloc_pages[i] + (j << 9));
+ printk("SMalloc: %d %p ",len, dma_malloc_pages[i] + (j << 9));
#endif
- return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
- }
- }
- restore_flags(flags);
- return NULL; /* Nope. No more */
+ return (void *) ((unsigned long) dma_malloc_pages[i] + (j << 9));
+ }
+ }
+ restore_flags(flags);
+ return NULL; /* Nope. No more */
}
int scsi_free(void *obj, unsigned int len)
{
- int page, sector, nbits, mask;
- long offset;
- unsigned long flags;
-
+ int page, sector, nbits, mask;
+ long offset;
+ unsigned long flags;
+
#ifdef DEBUG
- printk("Sfree %p %d\n",obj, len);
+ printk("Sfree %p %d\n",obj, len);
#endif
-
- offset = -1;
- for (page = 0; page < (dma_sectors >> 3); page++)
+
+ offset = -1;
+ for (page = 0; page < (dma_sectors >> 3); page++)
if ((unsigned long) obj >= (unsigned long) dma_malloc_pages[page] &&
- (unsigned long) obj < (unsigned long) dma_malloc_pages[page] + (1 << MALLOC_PAGEBITS))
- {
- offset = ((unsigned long) obj) - ((unsigned long)dma_malloc_pages[page]);
- break;
- }
-
- if (page == (dma_sectors >> 3)) panic("Bad offset");
- sector = offset >> 9;
- if(sector >= dma_sectors) panic ("Bad page");
-
- sector = (offset >> 9) & (sizeof(*dma_malloc_freelist) * 8 - 1);
- nbits = len >> 9;
- mask = (1 << nbits) - 1;
-
- if ((mask << sector) > 0xffff) panic ("Bad memory alignment");
-
- save_flags(flags);
- cli();
- if((dma_malloc_freelist[page] & (mask << sector)) != (mask<<sector))
- panic("Trying to free unused memory");
-
- dma_free_sectors += nbits;
- dma_malloc_freelist[page] &= ~(mask << sector);
- restore_flags(flags);
- return 0;
+ (unsigned long) obj < (unsigned long) dma_malloc_pages[page]
+ + (1 << MALLOC_PAGEBITS))
+ {
+ offset = ((unsigned long) obj) - ((unsigned long)dma_malloc_pages[page]);
+ break;
+ }
+
+ if (page == (dma_sectors >> 3)) panic("Bad offset");
+ sector = offset >> 9;
+ if(sector >= dma_sectors) panic ("Bad page");
+
+ sector = (offset >> 9) & (sizeof(*dma_malloc_freelist) * 8 - 1);
+ nbits = len >> 9;
+ mask = (1 << nbits) - 1;
+
+ if ((mask << sector) > 0xffff) panic ("Bad memory alignment");
+
+ save_flags(flags);
+ cli();
+ if((dma_malloc_freelist[page] & (mask << sector)) != (mask<<sector))
+ panic("Trying to free unused memory");
+
+ dma_free_sectors += nbits;
+ dma_malloc_freelist[page] &= ~(mask << sector);
+ restore_flags(flags);
+ return 0;
}
-
-/* These are special functions that can be used to obtain memory at boot time.
- They act line a malloc function, but they simply take memory from the
- pool */
+/*
+ * These are special functions that can be used to obtain memory at boot time.
+ * They act line a malloc function, but they simply take memory from the pool
+ */
static unsigned long scsi_init_memory_start = 0;
static unsigned long scsi_memory_lower_value = 0;
void * scsi_init_malloc(unsigned int size, int priority)
{
- unsigned long retval;
-
-/* Use the statically allocated memory instead of kmalloc (DB) */
+ unsigned long retval;
+
+ /* Use the statically allocated memory instead of kmalloc (DB) */
#if defined(USE_STATIC_SCSI_MEMORY)
- if(scsi_loadable_module_flag && !(priority & GFP_DMA))
+ if(scsi_loadable_module_flag && !(priority & GFP_DMA))
#else
- if(scsi_loadable_module_flag)
+ if(scsi_loadable_module_flag)
#endif
- retval = (unsigned long) kmalloc(size, priority);
- else {
- /*
- * Keep all memory aligned on 16-byte boundaries. Some host adaptors
- * (e.g. BusLogic BT-445S) require DMA buffers to be aligned that way.
- */
- size = (size + 15) & ~15;
-
- if(scsi_loadable_module_flag &&
- (scsi_init_memory_start + size) > scsi_memory_upper_value) {
- retval = 0;
- printk("scsi_init_malloc: no more statically allocated memory.\n");
- }
- else {
- retval = scsi_init_memory_start;
- scsi_init_memory_start += size;
- }
- }
- memset((void *) retval, 0, size);
- return (void *) retval;
+ {
+ /*
+ * For buffers used by the DMA pool, we assume page aligned
+ * structures.
+ */
+ if(size == PAGE_SIZE)
+ retval = (unsigned long) __get_dma_pages(priority & GFP_LEVEL_MASK, 0);
+ else
+ retval = (unsigned long) kmalloc(size, priority);
+ } else {
+ /*
+ * Keep all memory aligned on 16-byte boundaries. Some host
+ * adaptors (e.g. BusLogic BT-445S) require DMA buffers to be
+ * aligned that way.
+ */
+ size = (size + 15) & ~15;
+
+ if(scsi_loadable_module_flag &&
+ (scsi_init_memory_start + size) > scsi_memory_upper_value) {
+ retval = 0;
+ printk("scsi_init_malloc: no more statically allocated memory.\n");
+ }
+ else {
+ retval = scsi_init_memory_start;
+ scsi_init_memory_start += size;
+ }
+ }
+ memset((void *) retval, 0, size);
+ return (void *) retval;
}
void scsi_init_free(char * ptr, unsigned int size)
-{ /* We need to compare addresses to see whether this was kmalloc'd or not */
-
- if((unsigned long) ptr >= scsi_init_memory_start ||
- (unsigned long) ptr < scsi_memory_lower_value) kfree(ptr);
- else {
- size = (size + 15) & ~15; /* Use the same alignment as scsi_init_malloc() */
+{
+ /* We need to compare addresses to see whether this was kmalloc'd or not */
+
+ if((unsigned long) ptr >= scsi_init_memory_start ||
+ (unsigned long) ptr < scsi_memory_lower_value) {
+ /*
+ * We need this special code here because the DMA pool assumes
+ * page aligned data. Besides, it is wasteful to allocate
+ * page sized chunks with kmalloc.
+ */
+ if(size == PAGE_SIZE)
+ free_pages((unsigned long)ptr, 0);
+ else
+ kfree(ptr);
+ } else {
+ /* Use the same alignment as scsi_init_malloc() */
+ size = (size + 15) & ~15;
+
+ if(((unsigned long) ptr) + size == scsi_init_memory_start)
+ scsi_init_memory_start = (unsigned long) ptr;
+ }
+}
- if(((unsigned long) ptr) + size == scsi_init_memory_start)
- scsi_init_memory_start = (unsigned long) ptr;
+void scsi_build_commandblocks(Scsi_Device * SDpnt)
+{
+ int j;
+ Scsi_Cmnd * SCpnt;
+ struct Scsi_Host * host = NULL;
+
+ for(j=0;j<SDpnt->host->cmd_per_lun;j++){
+ SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
+ SCpnt->host = SDpnt->host;
+ SCpnt->device = SDpnt;
+ SCpnt->target = SDpnt->id;
+ SCpnt->lun = SDpnt->lun;
+ SCpnt->channel = SDpnt->channel;
+ SCpnt->request.dev = -1; /* Mark not busy */
+ SCpnt->use_sg = 0;
+ SCpnt->old_use_sg = 0;
+ SCpnt->old_cmd_len = 0;
+ SCpnt->timeout = 0;
+ SCpnt->underflow = 0;
+ SCpnt->transfersize = 0;
+ SCpnt->host_scribble = NULL;
+ host = SDpnt->host;
+ if(host->host_queue)
+ host->host_queue->prev = SCpnt;
+ SCpnt->next = host->host_queue;
+ SCpnt->prev = NULL;
+ host->host_queue = SCpnt;
}
}
/*
- scsi_dev_init() is our initialization routine, which in turn calls host
- initialization, bus scanning, and sd/st initialization routines. It
- should be called from main().
-*/
+ * scsi_dev_init() is our initialization routine, which in turn calls host
+ * initialization, bus scanning, and sd/st initialization routines. It
+ * should be called from main().
+ */
-unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end)
- {
- struct Scsi_Host * host = NULL;
- Scsi_Device * SDpnt;
- struct Scsi_Host * shpnt;
- struct Scsi_Device_Template * sdtpnt;
- Scsi_Cmnd * SCpnt;
- int i;
+unsigned long scsi_dev_init (unsigned long memory_start, unsigned long memory_end)
+{
+ struct Scsi_Host * host = NULL;
+ Scsi_Device * SDpnt;
+ struct Scsi_Host * shpnt;
+ struct Scsi_Device_Template * sdtpnt;
+ int i;
#ifdef FOO_ON_YOU
- return;
+ return;
#endif
- /* Init a few things so we can "malloc" memory. */
- scsi_loadable_module_flag = 0;
- /* Align everything on 16-byte boundaries. */
- scsi_init_memory_start = (memory_start + 15) & ~ 15;
- scsi_memory_lower_value = scsi_init_memory_start;
+ /* Yes we're here... */
+ dispatch_scsi_info_ptr = dispatch_scsi_info;
- timer_table[SCSI_TIMER].fn = scsi_main_timeout;
- timer_table[SCSI_TIMER].expires = 0;
+ /* Init a few things so we can "malloc" memory. */
+ scsi_loadable_module_flag = 0;
+
+ /* Align everything on 16-byte boundaries. */
+ scsi_init_memory_start = (memory_start + 15) & ~ 15;
+ scsi_memory_lower_value = scsi_init_memory_start;
+
+ timer_table[SCSI_TIMER].fn = scsi_main_timeout;
+ timer_table[SCSI_TIMER].expires = 0;
- /* initialize all hosts */
- scsi_init();
+ /* initialize all hosts */
+ scsi_init();
- scsi_devices = (Scsi_Device *) NULL;
+ scsi_devices = (Scsi_Device *) NULL;
- for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
- scan_scsis(shpnt); /* scan for scsi devices */
+ for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ scan_scsis(shpnt,0,0,0,0); /* scan for scsi devices */
- printk("scsi : detected ");
- for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if (sdtpnt->dev_noticed && sdtpnt->name)
+ printk("scsi : detected ");
+ for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ if (sdtpnt->dev_noticed && sdtpnt->name)
printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
- (sdtpnt->dev_noticed != 1) ? "s" : "");
- printk("total.\n");
+ (sdtpnt->dev_noticed != 1) ? "s" : "");
+ printk("total.\n");
+
+ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
+ for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
+ SDpnt->scsi_request_fn = NULL;
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
-
- for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
- int j;
- SDpnt->scsi_request_fn = NULL;
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
-
- if(SDpnt->attached){
- for(j=0;j<SDpnt->host->cmd_per_lun;j++){
- SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
- SCpnt->host = SDpnt->host;
- SCpnt->device = SDpnt;
- SCpnt->target = SDpnt->id;
- SCpnt->lun = SDpnt->lun;
- SCpnt->request.dev = -1; /* Mark not busy */
- SCpnt->use_sg = 0;
- SCpnt->old_use_sg = 0;
- SCpnt->old_cmd_len = 0;
- SCpnt->timeout = 0;
- SCpnt->underflow = 0;
- SCpnt->transfersize = 0;
- SCpnt->host_scribble = NULL;
- host = SDpnt->host;
- if(host->host_queue)
- host->host_queue->prev = SCpnt;
- SCpnt->next = host->host_queue;
- SCpnt->prev = NULL;
- host->host_queue = SCpnt;
- }
- }
- }
-
- if (scsi_devicelist)
- dma_sectors = 16; /* Base value we use */
-
- if (memory_end-1 > ISA_DMA_THRESHOLD)
- scsi_need_isa_bounce_buffers = 1;
- else
- scsi_need_isa_bounce_buffers = 0;
-
- for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
- host = SDpnt->host;
-
- if(SDpnt->type != TYPE_TAPE)
+ if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
+ if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
+ }
+
+ if (scsi_devicelist)
+ dma_sectors = 16; /* Base value we use */
+
+ if (memory_end-1 > ISA_DMA_THRESHOLD)
+ scsi_need_isa_bounce_buffers = 1;
+ else
+ scsi_need_isa_bounce_buffers = 0;
+
+ for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
+ host = SDpnt->host;
+
+ if(SDpnt->type != TYPE_TAPE)
dma_sectors += ((host->sg_tablesize *
sizeof(struct scatterlist) + 511) >> 9) *
- host->cmd_per_lun;
-
- if(host->unchecked_isa_dma &&
- memory_end - 1 > ISA_DMA_THRESHOLD &&
- SDpnt->type != TYPE_TAPE) {
+ host->cmd_per_lun;
+
+ if(host->unchecked_isa_dma &&
+ memory_end - 1 > ISA_DMA_THRESHOLD &&
+ SDpnt->type != TYPE_TAPE) {
dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
- host->cmd_per_lun;
+ host->cmd_per_lun;
need_isa_buffer++;
- }
}
-
- dma_sectors = (dma_sectors + 15) & 0xfff0;
- dma_free_sectors = dma_sectors; /* This must be a multiple of 16 */
-
- dma_malloc_freelist = (unsigned char *)
- scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
- memset(dma_malloc_freelist, 0, dma_sectors >> 3);
-
- dma_malloc_pages = (unsigned char **)
- scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
- memset(dma_malloc_pages, 0, dma_sectors >> 1);
-
- for(i=0; i< dma_sectors >> 3; i++)
- dma_malloc_pages[i] = (unsigned char *)
+ }
+
+ dma_sectors = (dma_sectors + 15) & 0xfff0;
+ dma_free_sectors = dma_sectors; /* This must be a multiple of 16 */
+
+ dma_malloc_freelist = (unsigned char *)
+ scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
+ memset(dma_malloc_freelist, 0, dma_sectors >> 3);
+
+ dma_malloc_pages = (unsigned char **)
+ scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
+ memset(dma_malloc_pages, 0, dma_sectors >> 1);
+
+ for(i=0; i< dma_sectors >> 3; i++)
+ dma_malloc_pages[i] = (unsigned char *)
scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-
-
- /* OK, now we finish the initialization by doing spin-up, read
- capacity, etc, etc */
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->finish && sdtpnt->nr_dev)
+
+ /* OK, now we finish the initialization by doing spin-up, read
+ * capacity, etc, etc
+ */
+ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ if(sdtpnt->finish && sdtpnt->nr_dev)
(*sdtpnt->finish)();
-
- scsi_loadable_module_flag = 1;
-
-
-/* This allocates statically some extra memory to be used for modules,
- until the kmalloc problem is fixed (DB) */
-
+
+ scsi_loadable_module_flag = 1;
+
+ /* This allocates statically some extra memory to be used for modules,
+ * until the kmalloc problem is fixed (DB)
+ */
+
#if defined(USE_STATIC_SCSI_MEMORY)
- scsi_memory_upper_value = scsi_init_memory_start + 256 * 1024;
- printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
- (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
- (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
- (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
- return scsi_memory_upper_value;
+ scsi_memory_upper_value = scsi_init_memory_start + 256 * 1024;
+ printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
+ (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
+ (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
+ (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
+ return scsi_memory_upper_value;
#else
- return scsi_init_memory_start;
+ return scsi_init_memory_start;
#endif
- }
+}
static void print_inquiry(unsigned char *data)
{
- int i;
+ int i;
+
+ printk(" Vendor: ");
+ for (i = 8; i < 16; i++)
+ {
+ if (data[i] >= 0x20 && i < data[4] + 5)
+ printk("%c", data[i]);
+ else
+ printk(" ");
+ }
+
+ printk(" Model: ");
+ for (i = 16; i < 32; i++)
+ {
+ if (data[i] >= 0x20 && i < data[4] + 5)
+ printk("%c", data[i]);
+ else
+ printk(" ");
+ }
+
+ printk(" Rev: ");
+ for (i = 32; i < 36; i++)
+ {
+ if (data[i] >= 0x20 && i < data[4] + 5)
+ printk("%c", data[i]);
+ else
+ printk(" ");
+ }
+
+ printk("\n");
+
+ i = data[0] & 0x1f;
+
+ printk(" Type: %s ",
+ i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown " );
+ printk(" ANSI SCSI revision: %02x", data[2] & 0x07);
+ if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
+ printk(" CCS\n");
+ else
+ printk("\n");
+}
- printk(" Vendor: ");
- for (i = 8; i < 16; i++)
- {
- if (data[i] >= 0x20 && i < data[4] + 5)
- printk("%c", data[i]);
- else
- printk(" ");
- }
- printk(" Model: ");
- for (i = 16; i < 32; i++)
- {
- if (data[i] >= 0x20 && i < data[4] + 5)
- printk("%c", data[i]);
- else
- printk(" ");
- }
+#ifdef CONFIG_PROC_FS
+int scsi_proc_info(char *buffer, char **start, off_t offset, int length,
+ int hostno, int inout)
+{
+ Scsi_Device *scd;
+ struct Scsi_Host *HBA_ptr;
+ int parameter[4];
+ char *p;
- printk(" Rev: ");
- for (i = 32; i < 36; i++)
- {
- if (data[i] >= 0x20 && i < data[4] + 5)
- printk("%c", data[i]);
- else
- printk(" ");
- }
+ scd = scsi_devices;
+ HBA_ptr = scsi_hostlist;
- printk("\n");
+ if(inout == 0) /* We can only write to this file right now */
+ return(-ENOSYS); /* This is still a no-op */
- i = data[0] & 0x1f;
+ if(!buffer || length < 25 || strncmp("scsi", buffer, 4))
+ return(-EINVAL);
- printk(" Type: %s ",
- i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown " );
- printk(" ANSI SCSI revision: %02x", data[2] & 0x07);
- if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
- printk(" CCS\n");
- else
- printk("\n");
+ if(!strncmp("singledevice", buffer + 5, 12)) {
+ p = buffer + 17;
+
+ parameter[0] = simple_strtoul(p , &p, 0);
+ parameter[1] = simple_strtoul(p , &p, 0);
+ parameter[2] = simple_strtoul(p , &p, 0);
+ parameter[3] = simple_strtoul(p , &p, 0);
+
+ while(scd && scd->host->host_no != parameter[0]
+ && scd->channel != parameter[1]
+ && scd->id != parameter[2]
+ && scd->lun != parameter[3]) {
+ scd = scd->next;
+ }
+ if(scd)
+ return(-ENOSYS); /* We do not yet support unplugging */
+ while(HBA_ptr && HBA_ptr->host_no != parameter[0])
+ HBA_ptr = HBA_ptr->next;
+
+ if(!HBA_ptr)
+ return(-ENXIO);
+
+ scan_scsis (HBA_ptr, 1, parameter[1], parameter[2], parameter[3]);
+ return(0);
+ }
+ return(-EINVAL);
}
+#endif
+
/*
* This entry point should be called by a loadable module if it is trying
*/
static int scsi_register_host(Scsi_Host_Template * tpnt)
{
- int pcount;
- struct Scsi_Host * shpnt;
- struct Scsi_Host * host = NULL;
- unsigned long flags;
- Scsi_Device * SDpnt;
- Scsi_Cmnd * SCpnt;
- struct Scsi_Device_Template * sdtpnt;
- int j, i;
- const char * name;
-
- if (tpnt->next || !tpnt->detect) return 1; /* Must be already loaded, or
- no detect routine available */
- pcount = next_scsi_host;
- if ((tpnt->present = tpnt->detect(tpnt)))
+ int pcount;
+ struct Scsi_Host * shpnt;
+ struct Scsi_Host * host = NULL;
+ unsigned long flags;
+ Scsi_Device * SDpnt;
+ struct Scsi_Device_Template * sdtpnt;
+ int i;
+ const char * name;
+
+ if (tpnt->next || !tpnt->detect) return 1;/* Must be already loaded, or
+ * no detect routine available
+ */
+ pcount = next_scsi_host;
+ if ((tpnt->present = tpnt->detect(tpnt)))
{
- if(pcount == next_scsi_host) {
- if(tpnt->present > 1) {
- printk("Failure to register low-level scsi driver");
- scsi_unregister_host(tpnt);
- return 1;
+ if(pcount == next_scsi_host) {
+ if(tpnt->present > 1) {
+ printk("Failure to register low-level scsi driver");
+ scsi_unregister_host(tpnt);
+ return 1;
+ }
+ /* The low-level driver failed to register a driver. We
+ * can do this now.
+ */
+ scsi_register(tpnt,0);
}
- /* The low-level driver failed to register a driver. We
- can do this now. */
- scsi_register(tpnt,0);
- }
- tpnt->next = scsi_hosts; /* Add to the linked list */
- scsi_hosts = tpnt;
-
- for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
- if(shpnt->hostt == tpnt)
- {
- if(tpnt->info)
- name = tpnt->info(shpnt);
- else
- name = tpnt->name;
- printk ("scsi%d : %s\n", /* And print a little message */
- shpnt->host_no, name);
- }
-
- printk ("scsi : %d host%s.\n", next_scsi_host,
+ tpnt->next = scsi_hosts; /* Add to the linked list */
+ scsi_hosts = tpnt;
+
+ /* Add the new driver to /proc/scsi */
+#if CONFIG_PROC_FS
+ build_proc_dir_entries();
+#endif
+
+ for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+ if(shpnt->hostt == tpnt)
+ {
+ if(tpnt->info)
+ name = tpnt->info(shpnt);
+ else
+ name = tpnt->name;
+ printk ("scsi%d : %s\n", /* And print a little message */
+ shpnt->host_no, name);
+ }
+
+ printk ("scsi : %d host%s.\n", next_scsi_host,
(next_scsi_host == 1) ? "" : "s");
-
- scsi_make_blocked_list();
-
- /* The next step is to call scan_scsis here. This generates the
- Scsi_Devices entries */
-
- for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
- if(shpnt->hostt == tpnt) scan_scsis(shpnt);
-
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
-
- /* Next we create the Scsi_Cmnd structures for this host */
-
- for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
- if(SDpnt->host->hostt == tpnt)
- {
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
- if(SDpnt->attached){
- for(j=0;j<SDpnt->host->cmd_per_lun;j++){
- SCpnt = (Scsi_Cmnd *) scsi_init_malloc(sizeof(Scsi_Cmnd), GFP_ATOMIC);
- SCpnt->host = SDpnt->host;
- SCpnt->device = SDpnt;
- SCpnt->target = SDpnt->id;
- SCpnt->lun = SDpnt->lun;
- SCpnt->request.dev = -1; /* Mark not busy */
- SCpnt->request.sem = NULL;
- SCpnt->use_sg = 0;
- SCpnt->old_use_sg = 0;
- SCpnt->underflow = 0;
- SCpnt->timeout = 0;
- SCpnt->transfersize = 0;
- SCpnt->host_scribble = NULL;
- host = SDpnt->host;
- SCpnt->next = host->host_queue;
- SCpnt->prev = NULL;
- host->host_queue = SCpnt;
- if(host->host_queue)
- host->host_queue->prev = SCpnt;
- }
+
+ scsi_make_blocked_list();
+
+ /* The next step is to call scan_scsis here. This generates the
+ * Scsi_Devices entries
+ */
+
+ for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+ if(shpnt->hostt == tpnt) scan_scsis(shpnt,0,0,0,0);
+
+ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
+
+ /* Next we create the Scsi_Cmnd structures for this host */
+
+ for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+ if(SDpnt->host->hostt == tpnt)
+ {
+ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ if(sdtpnt->attach) (*sdtpnt->attach)(SDpnt);
+ if(SDpnt->attached) scsi_build_commandblocks(SDpnt);
}
- }
+
/* Next, check to see if we need to extend the DMA buffer pool */
- {
- unsigned char * new_dma_malloc_freelist = NULL;
- unsigned int new_dma_sectors = 0;
- unsigned int new_need_isa_buffer = 0;
- unsigned char ** new_dma_malloc_pages = NULL;
-
- if (scsi_devicelist)
- new_dma_sectors = 16; /* Base value we use */
-
- for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
+ {
+ unsigned char * new_dma_malloc_freelist = NULL;
+ unsigned int new_dma_sectors = 0;
+ unsigned int new_need_isa_buffer = 0;
+ unsigned char ** new_dma_malloc_pages = NULL;
+
+ new_dma_sectors = 16; /* Base value we use */
+ if (scsi_devicelist)
+ for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
+ new_dma_sectors += 8; /* Increment for each host */
+
+ for (SDpnt=scsi_devices; SDpnt; SDpnt = SDpnt->next) {
host = SDpnt->host;
-
+
if(SDpnt->type != TYPE_TAPE)
- new_dma_sectors += ((host->sg_tablesize *
- sizeof(struct scatterlist) + 511) >> 9) *
- host->cmd_per_lun;
-
+ new_dma_sectors += ((host->sg_tablesize *
+ sizeof(struct scatterlist) + 511) >> 9) *
+ host->cmd_per_lun;
+
if(host->unchecked_isa_dma &&
scsi_need_isa_bounce_buffers &&
SDpnt->type != TYPE_TAPE) {
- new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
- host->cmd_per_lun;
- new_need_isa_buffer++;
+ new_dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
+ host->cmd_per_lun;
+ new_need_isa_buffer++;
}
- }
-
- new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
-
- new_dma_malloc_freelist = (unsigned char *)
+ }
+
+ new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
+
+ /*
+ * We never shrink the buffers - this leads to
+ * race conditions that I would rather not even think
+ * about right now.
+ */
+ if( new_dma_sectors < dma_sectors )
+ new_dma_sectors = dma_sectors;
+
+ new_dma_malloc_freelist = (unsigned char *)
scsi_init_malloc(new_dma_sectors >> 3, GFP_ATOMIC);
- memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
-
- new_dma_malloc_pages = (unsigned char **)
+ memset(new_dma_malloc_freelist, 0, new_dma_sectors >> 3);
+
+ new_dma_malloc_pages = (unsigned char **)
scsi_init_malloc(new_dma_sectors >> 1, GFP_ATOMIC);
- memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
-
- for(i=dma_sectors >> 3; i< new_dma_sectors >> 3; i++)
- new_dma_malloc_pages[i] = (unsigned char *)
+ memset(new_dma_malloc_pages, 0, new_dma_sectors >> 1);
+
+ /*
+ * If we need more buffers, expand the list.
+ */
+ if( new_dma_sectors > dma_sectors ) {
+ for(i=dma_sectors >> 3; i< new_dma_sectors >> 3; i++)
+ new_dma_malloc_pages[i] = (unsigned char *)
scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
-
-
- /* When we dick with the actual DMA list, we need to protect things */
-
- save_flags(flags);
- cli();
- memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
- scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
- dma_malloc_freelist = new_dma_malloc_freelist;
-
- memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
- scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
-
- dma_free_sectors += new_dma_sectors - dma_sectors;
- dma_malloc_pages = new_dma_malloc_pages;
- dma_sectors = new_dma_sectors;
- need_isa_buffer = new_need_isa_buffer;
- restore_flags(flags);
-
-
}
- /* This does any final handling that is required. */
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->finish && sdtpnt->nr_dev)
- (*sdtpnt->finish)();
+
+ /* When we dick with the actual DMA list, we need to
+ * protect things
+ */
+ save_flags(flags);
+ cli();
+ memcpy(new_dma_malloc_freelist, dma_malloc_freelist, dma_sectors >> 3);
+ scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
+ dma_malloc_freelist = new_dma_malloc_freelist;
+
+ memcpy(new_dma_malloc_pages, dma_malloc_pages, dma_sectors >> 1);
+ scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
+
+ dma_free_sectors += new_dma_sectors - dma_sectors;
+ dma_malloc_pages = new_dma_malloc_pages;
+ dma_sectors = new_dma_sectors;
+ need_isa_buffer = new_need_isa_buffer;
+ restore_flags(flags);
}
-
+
+ /* This does any final handling that is required. */
+ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ if(sdtpnt->finish && sdtpnt->nr_dev)
+ (*sdtpnt->finish)();
+ }
+
#if defined(USE_STATIC_SCSI_MEMORY)
- printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
- (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
- (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
- (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
+ printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
+ (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
+ (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
+ (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
#endif
-
- return 0;
+
+ MOD_INC_USE_COUNT;
+ return 0;
}
/*
*/
static void scsi_unregister_host(Scsi_Host_Template * tpnt)
{
- Scsi_Host_Template * SHT, *SHTp;
- Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
- Scsi_Cmnd * SCpnt;
- unsigned long flags;
- struct Scsi_Device_Template * sdtpnt;
- struct Scsi_Host * shpnt, *sh1;
- int pcount;
-
- /* First verify that this host adapter is completely free with no pending
- commands */
-
- for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
- if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->usage_count
- && *sdpnt->host->hostt->usage_count) return;
-
- for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ Scsi_Host_Template * SHT, *SHTp;
+ Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
+ Scsi_Cmnd * SCpnt;
+ unsigned long flags;
+ struct Scsi_Device_Template * sdtpnt;
+ struct Scsi_Host * shpnt, *sh1;
+ int pcount;
+
+ /* First verify that this host adapter is completely free with no pending
+ * commands */
+
+ for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
+ if(sdpnt->host->hostt == tpnt && sdpnt->host->hostt->usage_count
+ && *sdpnt->host->hostt->usage_count) return;
+
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
{
- if (shpnt->hostt != tpnt) continue;
- for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
+ if (shpnt->hostt != tpnt) continue;
+ for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
{
- save_flags(flags);
- cli();
- if(SCpnt->request.dev != -1) {
+ save_flags(flags);
+ cli();
+ if(SCpnt->request.dev != -1) {
+ restore_flags(flags);
+ for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
+ if(SCpnt->request.dev == 0xffe0) SCpnt->request.dev = -1;
+ printk("Device busy???\n");
+ return;
+ }
+ SCpnt->request.dev = 0xffe0; /* Mark as busy */
restore_flags(flags);
- for(SCpnt = shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
- if(SCpnt->request.dev == 0xffe0) SCpnt->request.dev = -1;
- printk("Device busy???\n");
- return;
- }
- SCpnt->request.dev = 0xffe0; /* Mark as busy */
- restore_flags(flags);
}
}
- /* Next we detach the high level drivers from the Scsi_Device structures */
-
- for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
- if(sdpnt->host->hostt == tpnt)
- {
- for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
- if(sdtpnt->detach) (*sdtpnt->detach)(sdpnt);
- /* If something still attached, punt */
- if (sdpnt->attached) {
- printk("Attached usage count = %d\n", sdpnt->attached);
- return;
+ /* Next we detach the high level drivers from the Scsi_Device structures */
+
+ for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
+ if(sdpnt->host->hostt == tpnt)
+ {
+ for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ if(sdtpnt->detach) (*sdtpnt->detach)(sdpnt);
+ /* If something still attached, punt */
+ if (sdpnt->attached) {
+ printk("Attached usage count = %d\n", sdpnt->attached);
+ return;
+ }
}
- }
-
- /* Next we free up the Scsi_Cmnd structures for this host */
-
- for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
- if(sdpnt->host->hostt == tpnt)
- while (sdpnt->host->host_queue) {
- SCpnt = sdpnt->host->host_queue->next;
- scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
- sdpnt->host->host_queue = SCpnt;
- if (SCpnt) SCpnt->prev = NULL;
- }
-
- /* Next free up the Scsi_Device structures for this host */
-
- sdppnt = NULL;
- for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1)
+
+ /* Next we free up the Scsi_Cmnd structures for this host */
+
+ for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
+ if(sdpnt->host->hostt == tpnt)
+ while (sdpnt->host->host_queue) {
+ SCpnt = sdpnt->host->host_queue->next;
+ scsi_init_free((char *) sdpnt->host->host_queue, sizeof(Scsi_Cmnd));
+ sdpnt->host->host_queue = SCpnt;
+ if (SCpnt) SCpnt->prev = NULL;
+ }
+
+ /* Next free up the Scsi_Device structures for this host */
+
+ sdppnt = NULL;
+ for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt1)
{
- sdpnt1 = sdpnt->next;
- if (sdpnt->host->hostt == tpnt) {
- if (sdppnt)
- sdppnt->next = sdpnt->next;
- else
- scsi_devices = sdpnt->next;
- scsi_init_free((char *) sdpnt, sizeof (Scsi_Device));
- } else
- sdppnt = sdpnt;
+ sdpnt1 = sdpnt->next;
+ if (sdpnt->host->hostt == tpnt) {
+ if (sdppnt)
+ sdppnt->next = sdpnt->next;
+ else
+ scsi_devices = sdpnt->next;
+ scsi_init_free((char *) sdpnt, sizeof (Scsi_Device));
+ } else
+ sdppnt = sdpnt;
}
-
- /* Next we go through and remove the instances of the individual hosts
- that were detected */
-
- shpnt = scsi_hostlist;
- while(shpnt) {
- sh1 = shpnt->next;
- if(shpnt->hostt == tpnt) {
- if(shpnt->loaded_as_module) {
- pcount = next_scsi_host;
- if(tpnt->release)
- (*tpnt->release)(shpnt);
- else {
- /* This is the default case for the release function. It should do the right
- thing for most correctly written host adapters. */
- if (shpnt->irq) free_irq(shpnt->irq);
- if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel);
- if (shpnt->io_port && shpnt->n_io_port)
- release_region(shpnt->io_port, shpnt->n_io_port);
+
+ /* Next we go through and remove the instances of the individual hosts
+ * that were detected */
+
+ shpnt = scsi_hostlist;
+ while(shpnt) {
+ sh1 = shpnt->next;
+ if(shpnt->hostt == tpnt) {
+ if(shpnt->loaded_as_module) {
+ pcount = next_scsi_host;
+ if(tpnt->release)
+ (*tpnt->release)(shpnt);
+ else {
+ /* This is the default case for the release function.
+ * It should do the right thing for most correctly
+ * written host adapters.
+ */
+ if (shpnt->irq) free_irq(shpnt->irq);
+ if (shpnt->dma_channel != 0xff) free_dma(shpnt->dma_channel);
+ if (shpnt->io_port && shpnt->n_io_port)
+ release_region(shpnt->io_port, shpnt->n_io_port);
+ }
+ if(pcount == next_scsi_host) scsi_unregister(shpnt);
+ tpnt->present--;
+ }
}
- if(pcount == next_scsi_host) scsi_unregister(shpnt);
- tpnt->present--;
- }
+ shpnt = sh1;
}
- shpnt = sh1;
- }
-
- printk ("scsi : %d host%s.\n", next_scsi_host,
- (next_scsi_host == 1) ? "" : "s");
-
+
+ printk ("scsi : %d host%s.\n", next_scsi_host,
+ (next_scsi_host == 1) ? "" : "s");
+
#if defined(USE_STATIC_SCSI_MEMORY)
- printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
- (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
- (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
- (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
+ printk ("SCSI memory: total %ldKb, used %ldKb, free %ldKb.\n",
+ (scsi_memory_upper_value - scsi_memory_lower_value) / 1024,
+ (scsi_init_memory_start - scsi_memory_lower_value) / 1024,
+ (scsi_memory_upper_value - scsi_init_memory_start) / 1024);
+#endif
+
+ scsi_make_blocked_list();
+
+ /* There were some hosts that were loaded at boot time, so we cannot
+ do any more than this */
+ if (tpnt->present) return;
+
+ /* OK, this is the very last step. Remove this host adapter from the
+ linked list. */
+ for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next)
+ if(SHT == tpnt) {
+ if(SHTp)
+ SHTp->next = SHT->next;
+ else
+ scsi_hosts = SHT->next;
+ SHT->next = NULL;
+ break;
+ }
+
+ /* Rebuild the /proc/scsi directory entries */
+#if CONFIG_PROC_FS
+ build_proc_dir_entries();
#endif
+ MOD_DEC_USE_COUNT;
+}
+
+/*
+ * This entry point should be called by a loadable module if it is trying
+ * add a high level scsi driver to the system.
+ */
+static int scsi_register_device_module(struct Scsi_Device_Template * tpnt)
+{
+ Scsi_Device * SDpnt;
+ int previous_attachment;
+
+ if (tpnt->next) return 1;
+
+ scsi_register_device(tpnt);
+ /*
+ * First scan the devices that we know about, and see if we notice them.
+ */
+
+ for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+ if(tpnt->detect) SDpnt->attached += (*tpnt->detect)(SDpnt);
+
+ /*
+ * If any of the devices would match this driver, then perform the
+ * init function. +
+ */
+ if(tpnt->init && tpnt->dev_noticed) (*tpnt->init)();
+
+ /*
+ * Now actually connect the devices to the new driver.
+ */
+ for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+ {
+ previous_attachment = SDpnt->attached;
+ if(tpnt->attach) (*tpnt->attach)(SDpnt);
+ /*
+ * If this driver attached to the device, and we no longer
+ * have anything attached, release the scso command blocks.
+ */
+ if(SDpnt->attached && previous_attachment == 0)
+ scsi_build_commandblocks(SDpnt);
+ }
+
+ /*
+ * This does any final handling that is required.
+ */
+ if(tpnt->finish && tpnt->nr_dev) (*tpnt->finish)();
+ MOD_INC_USE_COUNT;
+ return 0;
+}
- scsi_make_blocked_list();
-
- /* There were some hosts that were loaded at boot time, so we cannot
- do any more than this */
- if (tpnt->present) return;
-
- /* OK, this is the very last step. Remove this host adapter from the
- linked list. */
- for(SHTp=NULL, SHT=scsi_hosts; SHT; SHTp=SHT, SHT=SHT->next)
- if(SHT == tpnt) {
- if(SHTp)
- SHTp->next = SHT->next;
- else
- scsi_hosts = SHT->next;
- SHT->next = NULL;
- break;
+static int scsi_unregister_device(struct Scsi_Device_Template * tpnt)
+{
+ Scsi_Device * SDpnt;
+ Scsi_Cmnd * SCpnt;
+ struct Scsi_Device_Template * spnt;
+ struct Scsi_Device_Template * prev_spnt;
+
+ /*
+ * If we are busy, this is not going to fly.
+ */
+ if( *tpnt->usage_count != 0) return 0;
+ /*
+ * Next, detach the devices from the driver.
+ */
+
+ for(SDpnt = scsi_devices; SDpnt; SDpnt = SDpnt->next)
+ {
+ if(tpnt->detach) (*tpnt->detach)(SDpnt);
+ if(SDpnt->attached == 0)
+ {
+ /*
+ * Nobody is using this device any more. Free all of the
+ * command structures.
+ */
+ for(SCpnt = SDpnt->host->host_queue; SCpnt; SCpnt = SCpnt->next)
+ {
+ if(SCpnt->device == SDpnt)
+ {
+ if(SCpnt->prev != NULL)
+ SCpnt->prev->next = SCpnt->next;
+ if(SCpnt->next != NULL)
+ SCpnt->next->prev = SCpnt->prev;
+ if(SCpnt == SDpnt->host->host_queue)
+ SDpnt->host->host_queue = SCpnt->next;
+ scsi_init_free((char *) SCpnt, sizeof(*SCpnt));
+ }
+ }
+ }
+ }
+ /*
+ * Extract the template from the linked list.
+ */
+ spnt = scsi_devicelist;
+ prev_spnt = NULL;
+ while(spnt != tpnt)
+ {
+ prev_spnt = spnt;
+ spnt = spnt->next;
}
+ if(prev_spnt == NULL)
+ scsi_devicelist = tpnt->next;
+ else
+ prev_spnt->next = spnt->next;
+
+ MOD_DEC_USE_COUNT;
+ /*
+ * Final cleanup for the driver is done in the driver sources in the
+ * cleanup function.
+ */
+ return 0;
}
+
int scsi_register_module(int module_type, void * ptr)
{
- switch(module_type){
- case MODULE_SCSI_HA:
- return scsi_register_host((Scsi_Host_Template *) ptr);
- /* The rest of these are not yet implemented */
-
- /* Load constants.o */
- case MODULE_SCSI_CONST:
-
- /* Load specialized ioctl handler for some device. Intended for cdroms that
- have non-SCSI2 audio command sets. */
- case MODULE_SCSI_IOCTL:
-
- /* Load upper level device handler of some kind */
- case MODULE_SCSI_DEV:
- default:
- return 1;
- }
+ switch(module_type){
+ case MODULE_SCSI_HA:
+ return scsi_register_host((Scsi_Host_Template *) ptr);
+
+ /* Load upper level device handler of some kind */
+ case MODULE_SCSI_DEV:
+ return scsi_register_device_module((struct Scsi_Device_Template *) ptr);
+ /* The rest of these are not yet implemented */
+
+ /* Load constants.o */
+ case MODULE_SCSI_CONST:
+
+ /* Load specialized ioctl handler for some device. Intended for
+ * cdroms that have non-SCSI2 audio command sets. */
+ case MODULE_SCSI_IOCTL:
+
+ default:
+ return 1;
+ }
}
void scsi_unregister_module(int module_type, void * ptr)
{
- switch(module_type) {
- case MODULE_SCSI_HA:
- scsi_unregister_host((Scsi_Host_Template *) ptr);
- break;
- /* The rest of these are not yet implemented. */
- case MODULE_SCSI_CONST:
- case MODULE_SCSI_IOCTL:
- case MODULE_SCSI_DEV:
- default:
- }
- return;
+ switch(module_type) {
+ case MODULE_SCSI_HA:
+ scsi_unregister_host((Scsi_Host_Template *) ptr);
+ break;
+ case MODULE_SCSI_DEV:
+ scsi_unregister_device((struct Scsi_Device_Template *) ptr);
+ break;
+ /* The rest of these are not yet implemented. */
+ case MODULE_SCSI_CONST:
+ case MODULE_SCSI_IOCTL:
+ break;
+ default:
+ }
+ return;
}
#ifdef DEBUG_TIMEOUT
static void
scsi_dump_status(void)
{
- int i;
- struct Scsi_Host * shpnt;
- Scsi_Cmnd * SCpnt;
- printk("Dump of scsi parameters:\n");
- i = 0;
- for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
- for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
- {
- /* (0) 0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x */
- printk("(%d) %d:%d:%d (%4.4x %ld %ld %ld %ld) (%d %d %x) (%d %d %d) %x %x %x\n",
- i++, SCpnt->host->host_no,
- SCpnt->target,
- SCpnt->lun,
- SCpnt->request.dev,
- SCpnt->request.sector,
- SCpnt->request.nr_sectors,
- SCpnt->request.current_nr_sectors,
- SCpnt->use_sg,
- SCpnt->retries,
- SCpnt->allowed,
- SCpnt->flags,
- SCpnt->timeout_per_command,
- SCpnt->timeout,
- SCpnt->internal_timeout,
- SCpnt->cmnd[0],
- SCpnt->sense_buffer[2],
- SCpnt->result);
- }
- printk("wait_for_request = %p\n", wait_for_request);
- /* Now dump the request lists for each block device */
- printk("Dump of pending block device requests\n");
- for(i=0; i<MAX_BLKDEV; i++)
- if(blk_dev[i].current_request)
- {
- struct request * req;
- printk("%d: ", i);
- req = blk_dev[i].current_request;
- while(req) {
- printk("(%x %d %ld %ld %ld) ",
- req->dev,
- req->cmd,
- req->sector,
- req->nr_sectors,
- req->current_nr_sectors);
- req = req->next;
+ int i;
+ struct Scsi_Host * shpnt;
+ Scsi_Cmnd * SCpnt;
+ printk("Dump of scsi parameters:\n");
+ i = 0;
+ for(shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
+ for(SCpnt=shpnt->host_queue; SCpnt; SCpnt = SCpnt->next)
+ {
+ /* (0) 0:0:0:0 (802 123434 8 8 0) (3 3 2) (%d %d %d) %d %x */
+ printk("(%d) %d:%d:%d:%d (%4.4x %ld %ld %ld %ld) (%d %d %x) (%d %d %d) %x %x %x\n",
+ i++, SCpnt->host->host_no,
+ SCpnt->channel,
+ SCpnt->target,
+ SCpnt->lun,
+ SCpnt->request.dev,
+ SCpnt->request.sector,
+ SCpnt->request.nr_sectors,
+ SCpnt->request.current_nr_sectors,
+ SCpnt->use_sg,
+ SCpnt->retries,
+ SCpnt->allowed,
+ SCpnt->flags,
+ SCpnt->timeout_per_command,
+ SCpnt->timeout,
+ SCpnt->internal_timeout,
+ SCpnt->cmnd[0],
+ SCpnt->sense_buffer[2],
+ SCpnt->result);
+ }
+ printk("wait_for_request = %p\n", wait_for_request);
+ /* Now dump the request lists for each block device */
+ printk("Dump of pending block device requests\n");
+ for(i=0; i<MAX_BLKDEV; i++)
+ if(blk_dev[i].current_request)
+ {
+ struct request * req;
+ printk("%d: ", i);
+ req = blk_dev[i].current_request;
+ while(req) {
+ printk("(%x %d %ld %ld %ld) ",
+ req->dev,
+ req->cmd,
+ req->sector,
+ req->nr_sectors,
+ req->current_nr_sectors);
+ req = req->next;
+ }
+ printk("\n");
}
- printk("\n");
- }
}
#endif
+
+#ifdef MODULE
+/*
+extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+*/
+
+struct symbol_table scsi_symbol_table = {
+#include <linux/symtab_begin.h>
+#ifdef CONFIG_MODVERSIONS
+ { (void *)1 /* Version version :-) */, "_Using_Versions" },
+#endif
+ X(scsi_register_module),
+ X(scsi_unregister_module),
+ X(scsi_free),
+ X(scsi_malloc),
+ X(scsi_register),
+ X(scsi_unregister),
+ X(scsicam_bios_param),
+ X(allocate_device),
+ X(scsi_do_cmd),
+ X(scsi_command_size),
+ X(scsi_init_malloc),
+ X(scsi_init_free),
+ X(scsi_ioctl),
+ X(print_command),
+ X(print_sense),
+ X(dma_free_sectors),
+ X(kernel_scsi_ioctl),
+ X(need_isa_buffer),
+ X(request_queueable),
+/*
+ * These are here only while I debug the rest of the scsi stuff.
+ */
+ X(scsi_hostlist),
+ X(scsi_hosts),
+ X(scsi_devicelist),
+ X(scsi_devices),
+
+ /********************************************************
+ * Do not add anything below this line,
+ * as the stacked modules depend on this!
+ */
+#include <linux/symtab_end.h>
+};
+
+char kernel_version[] = UTS_RELEASE;
+
+int init_module(void) {
+ timer_table[SCSI_TIMER].fn = scsi_main_timeout;
+ timer_table[SCSI_TIMER].expires = 0;
+ register_symtab(&scsi_symbol_table);
+ scsi_loadable_module_flag = 1;
+
+ dma_sectors = PAGE_SIZE / 512;
+ /*
+ * Set up a minimal DMA buffer list - this will be used during scan_scsis
+ * in some cases.
+ */
+
+ /* One bit per sector to indicate free/busy */
+ dma_malloc_freelist = (unsigned char *)
+ scsi_init_malloc(dma_sectors >> 3, GFP_ATOMIC);
+ memset(dma_malloc_freelist, 0, dma_sectors >> 3);
+
+ /* One pointer per page for the page list */
+ dma_malloc_pages = (unsigned char **)
+ scsi_init_malloc(dma_sectors >> 1, GFP_ATOMIC);
+ dma_malloc_pages[0] = (unsigned char *)
+ scsi_init_malloc(PAGE_SIZE, GFP_ATOMIC | GFP_DMA);
+ return 0;
+}
+
+void cleanup_module( void)
+{
+ int i;
+
+ if (MOD_IN_USE) {
+ printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+ return;
+ }
+
+ /* No, we're not here anymore. Don't show the /proc/scsi files. */
+ dispatch_scsi_info_ptr = 0L;
+
+ /*
+ * Free up the DMA pool.
+ */
+ for(i=0; i < dma_sectors >> 3; i++)
+ scsi_init_free(dma_malloc_pages[i], PAGE_SIZE);
+ scsi_init_free((char *) dma_malloc_pages, dma_sectors>>1);
+ scsi_init_free(dma_malloc_freelist, dma_sectors>>3);
+
+ timer_table[SCSI_TIMER].fn = NULL;
+ timer_table[SCSI_TIMER].expires = 0;
+ /*
+ * Supposedly you just do this, and the last symtab registered will
+ * be removed. If someone else registered a symtab, this could
+ * blow up in our faces. FIXME.
+ */
+ register_symtab(0);
+}
+#endif /* MODULE */
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
* c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
* End:
*/
/*
- * scsi.h Copyright (C) 1992 Drew Eckhardt
- * generic SCSI package header file by
- * Drew Eckhardt
+ * scsi.h Copyright (C) 1992 Drew Eckhardt
+ * generic SCSI package header file by
+ * Drew Eckhardt
*
- * <drew@colorado.edu>
+ * <drew@colorado.edu>
*
* Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
* add scatter-gather, multiple outstanding request, and other
#define _SCSI_H
/*
- $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $
+ $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $
- For documentation on the OPCODES, MESSAGES, and SENSE values,
- please consult the SCSI standard.
+ For documentation on the OPCODES, MESSAGES, and SENSE values,
+ please consult the SCSI standard.
*/
/*
- SCSI opcodes
-*/
+ * SCSI opcodes
+ */
-#define TEST_UNIT_READY 0x00
-#define REZERO_UNIT 0x01
-#define REQUEST_SENSE 0x03
-#define FORMAT_UNIT 0x04
-#define READ_BLOCK_LIMITS 0x05
-#define REASSIGN_BLOCKS 0x07
-#define READ_6 0x08
-#define WRITE_6 0x0a
-#define SEEK_6 0x0b
-#define READ_REVERSE 0x0f
-#define WRITE_FILEMARKS 0x10
-#define SPACE 0x11
-#define INQUIRY 0x12
-#define RECOVER_BUFFERED_DATA 0x14
-#define MODE_SELECT 0x15
-#define RESERVE 0x16
-#define RELEASE 0x17
-#define COPY 0x18
-#define ERASE 0x19
-#define MODE_SENSE 0x1a
-#define START_STOP 0x1b
-#define RECEIVE_DIAGNOSTIC 0x1c
-#define SEND_DIAGNOSTIC 0x1d
-#define ALLOW_MEDIUM_REMOVAL 0x1e
-
-#define SET_WINDOW 0x24
-#define READ_CAPACITY 0x25
-#define READ_10 0x28
-#define WRITE_10 0x2a
-#define SEEK_10 0x2b
-#define WRITE_VERIFY 0x2e
-#define VERIFY 0x2f
-#define SEARCH_HIGH 0x30
-#define SEARCH_EQUAL 0x31
-#define SEARCH_LOW 0x32
-#define SET_LIMITS 0x33
-#define PRE_FETCH 0x34
-#define READ_POSITION 0x34
-#define SYNCHRONIZE_CACHE 0x35
-#define LOCK_UNLOCK_CACHE 0x36
-#define READ_DEFECT_DATA 0x37
-#define MEDIUM_SCAN 0x38
-#define COMPARE 0x39
-#define COPY_VERIFY 0x3a
-#define WRITE_BUFFER 0x3b
-#define READ_BUFFER 0x3c
-#define UPDATE_BLOCK 0x3d
-#define READ_LONG 0x3e
-#define WRITE_LONG 0x3f
-#define CHANGE_DEFINITION 0x40
-#define WRITE_SAME 0x41
-#define LOG_SELECT 0x4c
-#define LOG_SENSE 0x4d
-#define MODE_SELECT_10 0x55
-#define MODE_SENSE_10 0x5a
-#define WRITE_12 0xaa
-#define WRITE_VERIFY_12 0xae
-#define SEARCH_HIGH_12 0xb0
-#define SEARCH_EQUAL_12 0xb1
-#define SEARCH_LOW_12 0xb2
-#define SEND_VOLUME_TAG 0xb6
+#define TEST_UNIT_READY 0x00
+#define REZERO_UNIT 0x01
+#define REQUEST_SENSE 0x03
+#define FORMAT_UNIT 0x04
+#define READ_BLOCK_LIMITS 0x05
+#define REASSIGN_BLOCKS 0x07
+#define READ_6 0x08
+#define WRITE_6 0x0a
+#define SEEK_6 0x0b
+#define READ_REVERSE 0x0f
+#define WRITE_FILEMARKS 0x10
+#define SPACE 0x11
+#define INQUIRY 0x12
+#define RECOVER_BUFFERED_DATA 0x14
+#define MODE_SELECT 0x15
+#define RESERVE 0x16
+#define RELEASE 0x17
+#define COPY 0x18
+#define ERASE 0x19
+#define MODE_SENSE 0x1a
+#define START_STOP 0x1b
+#define RECEIVE_DIAGNOSTIC 0x1c
+#define SEND_DIAGNOSTIC 0x1d
+#define ALLOW_MEDIUM_REMOVAL 0x1e
+
+#define SET_WINDOW 0x24
+#define READ_CAPACITY 0x25
+#define READ_10 0x28
+#define WRITE_10 0x2a
+#define SEEK_10 0x2b
+#define WRITE_VERIFY 0x2e
+#define VERIFY 0x2f
+#define SEARCH_HIGH 0x30
+#define SEARCH_EQUAL 0x31
+#define SEARCH_LOW 0x32
+#define SET_LIMITS 0x33
+#define PRE_FETCH 0x34
+#define READ_POSITION 0x34
+#define SYNCHRONIZE_CACHE 0x35
+#define LOCK_UNLOCK_CACHE 0x36
+#define READ_DEFECT_DATA 0x37
+#define MEDIUM_SCAN 0x38
+#define COMPARE 0x39
+#define COPY_VERIFY 0x3a
+#define WRITE_BUFFER 0x3b
+#define READ_BUFFER 0x3c
+#define UPDATE_BLOCK 0x3d
+#define READ_LONG 0x3e
+#define WRITE_LONG 0x3f
+#define CHANGE_DEFINITION 0x40
+#define WRITE_SAME 0x41
+#define LOG_SELECT 0x4c
+#define LOG_SENSE 0x4d
+#define MODE_SELECT_10 0x55
+#define MODE_SENSE_10 0x5a
+#define WRITE_12 0xaa
+#define WRITE_VERIFY_12 0xae
+#define SEARCH_HIGH_12 0xb0
+#define SEARCH_EQUAL_12 0xb1
+#define SEARCH_LOW_12 0xb2
+#define SEND_VOLUME_TAG 0xb6
+#define WRITE_LONG_2 0xea
extern void scsi_make_blocked_list(void);
extern volatile int in_scan_scsis;
#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
/*
- MESSAGE CODES
-*/
+ * MESSAGE CODES
+ */
-#define COMMAND_COMPLETE 0x00
-#define EXTENDED_MESSAGE 0x01
-#define EXTENDED_MODIFY_DATA_POINTER 0x00
-#define EXTENDED_SDTR 0x01
-#define EXTENDED_EXTENDED_IDENTIFY 0x02 /* SCSI-I only */
-#define EXTENDED_WDTR 0x03
-#define SAVE_POINTERS 0x02
-#define RESTORE_POINTERS 0x03
-#define DISCONNECT 0x04
-#define INITIATOR_ERROR 0x05
-#define ABORT 0x06
-#define MESSAGE_REJECT 0x07
-#define NOP 0x08
-#define MSG_PARITY_ERROR 0x09
-#define LINKED_CMD_COMPLETE 0x0a
-#define LINKED_FLG_CMD_COMPLETE 0x0b
-#define BUS_DEVICE_RESET 0x0c
-
-#define INITIATE_RECOVERY 0x0f /* SCSI-II only */
-#define RELEASE_RECOVERY 0x10 /* SCSI-II only */
-
-#define SIMPLE_QUEUE_TAG 0x20
-#define HEAD_OF_QUEUE_TAG 0x21
-#define ORDERED_QUEUE_TAG 0x22
-
-#define IDENTIFY_BASE 0x80
+#define COMMAND_COMPLETE 0x00
+#define EXTENDED_MESSAGE 0x01
+#define EXTENDED_MODIFY_DATA_POINTER 0x00
+#define EXTENDED_SDTR 0x01
+#define EXTENDED_EXTENDED_IDENTIFY 0x02 /* SCSI-I only */
+#define EXTENDED_WDTR 0x03
+#define SAVE_POINTERS 0x02
+#define RESTORE_POINTERS 0x03
+#define DISCONNECT 0x04
+#define INITIATOR_ERROR 0x05
+#define ABORT 0x06
+#define MESSAGE_REJECT 0x07
+#define NOP 0x08
+#define MSG_PARITY_ERROR 0x09
+#define LINKED_CMD_COMPLETE 0x0a
+#define LINKED_FLG_CMD_COMPLETE 0x0b
+#define BUS_DEVICE_RESET 0x0c
+
+#define INITIATE_RECOVERY 0x0f /* SCSI-II only */
+#define RELEASE_RECOVERY 0x10 /* SCSI-II only */
+
+#define SIMPLE_QUEUE_TAG 0x20
+#define HEAD_OF_QUEUE_TAG 0x21
+#define ORDERED_QUEUE_TAG 0x22
+
+#define IDENTIFY_BASE 0x80
#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\
- ((can_disconnect) ? 0x40 : 0) |\
- ((lun) & 0x07))
+ ((can_disconnect) ? 0x40 : 0) |\
+ ((lun) & 0x07))
-
+
/*
- Status codes
-*/
-
-#define GOOD 0x00
-#define CHECK_CONDITION 0x01
-#define CONDITION_GOOD 0x02
-#define BUSY 0x04
-#define INTERMEDIATE_GOOD 0x08
-#define INTERMEDIATE_C_GOOD 0x0a
-#define RESERVATION_CONFLICT 0x0c
-#define QUEUE_FULL 0x1a
+ * Status codes
+ */
-#define STATUS_MASK 0x1e
-
+#define GOOD 0x00
+#define CHECK_CONDITION 0x01
+#define CONDITION_GOOD 0x02
+#define BUSY 0x04
+#define INTERMEDIATE_GOOD 0x08
+#define INTERMEDIATE_C_GOOD 0x0a
+#define RESERVATION_CONFLICT 0x0c
+#define QUEUE_FULL 0x1a
+
+#define STATUS_MASK 0x1e
+
/*
- the return of the status word will be in the following format :
- The low byte is the status returned by the SCSI command,
- with vendor specific bits masked.
-
- The next byte is the message which followed the SCSI status.
- This allows a stos to be used, since the Intel is a little
- endian machine.
-
- The final byte is a host return code, which is one of the following.
-
- IE
- lsb msb
- status msg host code
+ * the return of the status word will be in the following format :
+ * The low byte is the status returned by the SCSI command,
+ * with vendor specific bits masked.
+ *
+ * The next byte is the message which followed the SCSI status.
+ * This allows a stos to be used, since the Intel is a little
+ * endian machine.
+ *
+ * The final byte is a host return code, which is one of the following.
+ *
+ * IE
+ * lsb msb
+ * status msg host code
+ *
+ * Our errors returned by OUR driver, NOT SCSI message. Or'd with
+ * SCSI message passed back to driver <IF any>.
+ */
- Our errors returned by OUR driver, NOT SCSI message. Or'd with
- SCSI message passed back to driver <IF any>.
-*/
-/* NO error */
-#define DID_OK 0x00
-/* Couldn't connect before timeout period */
-#define DID_NO_CONNECT 0x01
-/* BUS stayed busy through time out period */
-#define DID_BUS_BUSY 0x02
-/* TIMED OUT for other reason */
-#define DID_TIME_OUT 0x03
-/* BAD target. */
-#define DID_BAD_TARGET 0x04
-/* Told to abort for some other reason */
-#define DID_ABORT 0x05
-/*
- Parity error
-*/
-#define DID_PARITY 0x06
-/*
- Internal error
-*/
-#define DID_ERROR 0x07
-/*
- Reset by somebody.
-*/
-#define DID_RESET 0x08
-/*
- Got an interrupt we weren't expecting.
-*/
-#define DID_BAD_INTR 0x09
+#define DID_OK 0x00 /* NO error */
+#define DID_NO_CONNECT 0x01 /* Couldn't connect before timeout period */
+#define DID_BUS_BUSY 0x02 /* BUS stayed busy through time out period */
+#define DID_TIME_OUT 0x03 /* TIMED OUT for other reason */
+#define DID_BAD_TARGET 0x04 /* BAD target. */
+#define DID_ABORT 0x05 /* Told to abort for some other reason */
+#define DID_PARITY 0x06 /* Parity error */
+#define DID_ERROR 0x07 /* Internal error */
+#define DID_RESET 0x08 /* Reset by somebody. */
+#define DID_BAD_INTR 0x09 /* Got an interrupt we weren't expecting. */
+#define DRIVER_OK 0x00 /* Driver status */
/*
- Driver status
-*/
-#define DRIVER_OK 0x00
-
-/*
- These indicate the error that occurred, and what is available.
-*/
+ * These indicate the error that occurred, and what is available.
+ */
-#define DRIVER_BUSY 0x01
-#define DRIVER_SOFT 0x02
-#define DRIVER_MEDIA 0x03
-#define DRIVER_ERROR 0x04
+#define DRIVER_BUSY 0x01
+#define DRIVER_SOFT 0x02
+#define DRIVER_MEDIA 0x03
+#define DRIVER_ERROR 0x04
-#define DRIVER_INVALID 0x05
-#define DRIVER_TIMEOUT 0x06
-#define DRIVER_HARD 0x07
+#define DRIVER_INVALID 0x05
+#define DRIVER_TIMEOUT 0x06
+#define DRIVER_HARD 0x07
-#define SUGGEST_RETRY 0x10
-#define SUGGEST_ABORT 0x20
-#define SUGGEST_REMAP 0x30
-#define SUGGEST_DIE 0x40
-#define SUGGEST_SENSE 0x80
-#define SUGGEST_IS_OK 0xff
+#define SUGGEST_RETRY 0x10
+#define SUGGEST_ABORT 0x20
+#define SUGGEST_REMAP 0x30
+#define SUGGEST_DIE 0x40
+#define SUGGEST_SENSE 0x80
+#define SUGGEST_IS_OK 0xff
-#define DRIVER_SENSE 0x08
+#define DRIVER_SENSE 0x08
-#define DRIVER_MASK 0x0f
-#define SUGGEST_MASK 0xf0
+#define DRIVER_MASK 0x0f
+#define SUGGEST_MASK 0xf0
/*
+ * SENSE KEYS
+ */
- SENSE KEYS
-*/
-
-#define NO_SENSE 0x00
-#define RECOVERED_ERROR 0x01
-#define NOT_READY 0x02
-#define MEDIUM_ERROR 0x03
-#define HARDWARE_ERROR 0x04
-#define ILLEGAL_REQUEST 0x05
-#define UNIT_ATTENTION 0x06
-#define DATA_PROTECT 0x07
-#define BLANK_CHECK 0x08
-#define COPY_ABORTED 0x0a
-#define ABORTED_COMMAND 0x0b
-#define VOLUME_OVERFLOW 0x0d
-#define MISCOMPARE 0x0e
+#define NO_SENSE 0x00
+#define RECOVERED_ERROR 0x01
+#define NOT_READY 0x02
+#define MEDIUM_ERROR 0x03
+#define HARDWARE_ERROR 0x04
+#define ILLEGAL_REQUEST 0x05
+#define UNIT_ATTENTION 0x06
+#define DATA_PROTECT 0x07
+#define BLANK_CHECK 0x08
+#define COPY_ABORTED 0x0a
+#define ABORTED_COMMAND 0x0b
+#define VOLUME_OVERFLOW 0x0d
+#define MISCOMPARE 0x0e
/*
- DEVICE TYPES
+ * DEVICE TYPES
+ */
-*/
+#define TYPE_DISK 0x00
+#define TYPE_TAPE 0x01
+#define TYPE_PROCESSOR 0x03 /* HP scanners use this */
+#define TYPE_WORM 0x04 /* Treated as ROM by our system */
+#define TYPE_ROM 0x05
+#define TYPE_SCANNER 0x06
+#define TYPE_MOD 0x07 /* Magneto-optical disk -
+ * - treated as TYPE_DISK */
+#define TYPE_NO_LUN 0x7f
-#define TYPE_DISK 0x00
-#define TYPE_TAPE 0x01
-#define TYPE_PROCESSOR 0x03 /* HP scanners use this */
-#define TYPE_WORM 0x04 /* Treated as ROM by our system */
-#define TYPE_ROM 0x05
-#define TYPE_SCANNER 0x06
-#define TYPE_MOD 0x07 /* Magneto-optical disk - treated as TYPE_DISK */
-#define TYPE_NO_LUN 0x7f
+#define MAX_COMMAND_SIZE 12
-#define MAX_COMMAND_SIZE 12
/*
- SCSI command sets
-
-*/
+ * SCSI command sets
+ */
-#define SCSI_UNKNOWN 0
-#define SCSI_1 1
-#define SCSI_1_CCS 2
-#define SCSI_2 3
+#define SCSI_UNKNOWN 0
+#define SCSI_1 1
+#define SCSI_1_CCS 2
+#define SCSI_2 3
/*
- Every SCSI command starts with a one byte OP-code.
- The next byte's high three bits are the LUN of the
- device. Any multi-byte quantities are stored high byte
- first, and may have a 5 bit MSB in the same byte
- as the LUN.
-*/
+ * Every SCSI command starts with a one byte OP-code.
+ * The next byte's high three bits are the LUN of the
+ * device. Any multi-byte quantities are stored high byte
+ * first, and may have a 5 bit MSB in the same byte
+ * as the LUN.
+ */
/*
- Manufacturers list
-*/
+ * Manufacturers list
+ */
#define SCSI_MAN_UNKNOWN 0
#define SCSI_MAN_NEC 1
#define SCSI_MAN_NEC_OLDCDR 3
/*
- The scsi_device struct contains what we know about each given scsi
- device.
-*/
+ * As the scsi do command functions are intelligent, and may need to
+ * redo a command, we need to keep track of the last command
+ * executed on each one.
+ */
+
+#define WAS_RESET 0x01
+#define WAS_TIMEDOUT 0x02
+#define WAS_SENSE 0x04
+#define IS_RESETTING 0x08
+#define IS_ABORTING 0x10
+#define ASKED_FOR_SENSE 0x20
+
+/*
+ * The scsi_device struct contains what we know about each given scsi
+ * device.
+ */
typedef struct scsi_device {
- struct scsi_device * next; /* Used for linked list */
- unsigned char id, lun;
- unsigned int manufacturer; /* Manufacturer of device, for using vendor-specific cmd's */
- int attached; /* # of high level drivers attached to this */
- int access_count; /* Count of open channels/mounts */
- struct wait_queue * device_wait; /* Used to wait if device is busy */
- struct Scsi_Host * host;
- void (*scsi_request_fn)(void); /* Used to jumpstart things after an ioctl */
- void *hostdata; /* available to low-level driver */
- char type;
- char scsi_level;
- unsigned writeable:1;
- unsigned removable:1;
- unsigned random:1;
- unsigned changed:1; /* Data invalid due to media change */
- unsigned busy:1; /* Used to prevent races */
- unsigned lockable:1; /* Able to prevent media removal */
- unsigned borken:1; /* Tell the Seagate driver to be
- painfully slow on this device */
- unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
- unsigned tagged_queue:1; /*SCSI-II tagged queuing enabled */
- unsigned disconnect:1; /* can disconnect */
- unsigned soft_reset:1; /* Uses soft reset option */
- unsigned char current_tag; /* current tag */
- unsigned sync:1; /* Negotiate for sync transfers */
- unsigned char sync_min_period; /* Not less than this period */
- unsigned char sync_max_offset; /* Not greater than this offset */
+ struct scsi_device * next; /* Used for linked list */
+
+ unsigned char id, lun, channel;
+
+ unsigned int manufacturer; /* Manufacturer of device, for using
+ * vendor-specific cmd's */
+ int attached; /* # of high level drivers attached to
+ * this */
+ int access_count; /* Count of open channels/mounts */
+ struct wait_queue * device_wait;/* Used to wait if device is busy */
+ struct Scsi_Host * host;
+ void (*scsi_request_fn)(void); /* Used to jumpstart things after an
+ * ioctl */
+ void *hostdata; /* available to low-level driver */
+ char type;
+ char scsi_level;
+ char vendor[8], model[16], rev[4];
+ unsigned writeable:1;
+ unsigned removable:1;
+ unsigned random:1;
+ unsigned changed:1; /* Data invalid due to media change */
+ unsigned busy:1; /* Used to prevent races */
+ unsigned lockable:1; /* Able to prevent media removal */
+ unsigned borken:1; /* Tell the Seagate driver to be
+ * painfully slow on this device */
+ unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
+ unsigned tagged_queue:1; /* SCSI-II tagged queuing enabled */
+ unsigned disconnect:1; /* can disconnect */
+ unsigned soft_reset:1; /* Uses soft reset option */
+ unsigned sync:1; /* Negotiate for sync transfers */
+ unsigned char current_tag; /* current tag */
+ unsigned char sync_min_period; /* Not less than this period */
+ unsigned char sync_max_offset; /* Not greater than this offset */
} Scsi_Device;
+
/*
- Use these to separate status msg and our bytes
-*/
+ * Use these to separate status msg and our bytes
+ */
#define status_byte(result) (((result) >> 1) & 0xf)
-#define msg_byte(result) (((result) >> 8) & 0xff)
-#define host_byte(result) (((result) >> 16) & 0xff)
+#define msg_byte(result) (((result) >> 8) & 0xff)
+#define host_byte(result) (((result) >> 16) & 0xff)
#define driver_byte(result) (((result) >> 24) & 0xff)
-#define suggestion(result) (driver_byte(result) & SUGGEST_MASK)
+#define suggestion(result) (driver_byte(result) & SUGGEST_MASK)
-#define sense_class(sense) (((sense) >> 4) & 0x7)
-#define sense_error(sense) ((sense) & 0xf)
-#define sense_valid(sense) ((sense) & 0x80);
+#define sense_class(sense) (((sense) >> 4) & 0x7)
+#define sense_error(sense) ((sense) & 0xf)
+#define sense_valid(sense) ((sense) & 0x80);
/*
- These are the SCSI devices available on the system.
-*/
+ * These are the SCSI devices available on the system.
+ */
extern Scsi_Device * scsi_devices;
+
/*
- Initializes all SCSI devices. This scans all scsi busses.
-*/
+ * Initializes all SCSI devices. This scans all scsi busses.
+ */
extern unsigned long scsi_dev_init (unsigned long, unsigned long);
struct scatterlist {
- char * address; /* Location data is to be transferred to */
- char * alt_address; /* Location of actual if address is a
- dma indirect buffer. NULL otherwise */
- unsigned int length;
- };
+ char * address; /* Location data is to be transferred to */
+ char * alt_address; /* Location of actual if address is a
+ * dma indirect buffer. NULL otherwise */
+ unsigned int length;
+};
#ifdef __alpha__
# define ISA_DMA_THRESHOLD (~0UL)
* and reset functions must correctly indicate what it has done.
*/
-/* We did not do anything. Wait
- some more for this command to complete, and if this does not work, try
- something more serious. */
+/* We did not do anything.
+ * Wait some more for this command to complete, and if this does not work,
+ * try something more serious. */
#define SCSI_ABORT_SNOOZE 0
/* This means that we were able to abort the command. We have already
- called the mid-level done function, and do not expect an interrupt that will
- lead to another call to the mid-level done function for this command */
+ * called the mid-level done function, and do not expect an interrupt that
+ * will lead to another call to the mid-level done function for this command */
#define SCSI_ABORT_SUCCESS 1
/* We called for an abort of this command, and we should get an interrupt
- when this succeeds. Thus we should not restore the timer for this
- command in the mid-level abort function. */
+ * when this succeeds. Thus we should not restore the timer for this
+ * command in the mid-level abort function. */
#define SCSI_ABORT_PENDING 2
/* Unable to abort - command is currently on the bus. Grin and bear it. */
#define SCSI_ABORT_BUSY 3
/* The command is not active in the low level code. Command probably
- finished. */
+ * finished. */
#define SCSI_ABORT_NOT_RUNNING 4
/* Something went wrong. The low level driver will indicate the correct
- error condition when it calls scsi_done, so the mid-level abort function
- can simply wait until this comes through */
+ * error condition when it calls scsi_done, so the mid-level abort function
+ * can simply wait until this comes through */
#define SCSI_ABORT_ERROR 5
/* We do not know how to reset the bus, or we do not want to. Bummer.
- Anyway, just wait a little more for the command in question, and hope that
- it eventually finishes. If it never finishes, the SCSI device could
- hang, so use this with caution. */
+ * Anyway, just wait a little more for the command in question, and hope that
+ * it eventually finishes. If it never finishes, the SCSI device could
+ * hang, so use this with caution. */
#define SCSI_RESET_SNOOZE 0
/* We do not know how to reset the bus, or we do not want to. Bummer.
- We have given up on this ever completing. The mid-level code will
- request sense information to decide how to proceed from here. */
+ * We have given up on this ever completing. The mid-level code will
+ * request sense information to decide how to proceed from here. */
#define SCSI_RESET_PUNT 1
/* This means that we were able to reset the bus. We have restarted all of
- the commands that should be restarted, and we should be able to continue
- on normally from here. We do not expect any interrupts that will return
- DID_RESET to any of the other commands in the host_queue, and the mid-level
- code does not need to do anything special to keep the commands alive. */
+ * the commands that should be restarted, and we should be able to continue
+ * on normally from here. We do not expect any interrupts that will return
+ * DID_RESET to any of the other commands in the host_queue, and the mid-level
+ * code does not need to do anything special to keep the commands alive. */
#define SCSI_RESET_SUCCESS 2
/* We called for a reset of this bus, and we should get an interrupt
- when this succeeds. Each command should get its own status
- passed up to scsi_done, but this has not happened yet. */
+ * when this succeeds. Each command should get its own status
+ * passed up to scsi_done, but this has not happened yet. */
#define SCSI_RESET_PENDING 3
/* We did a reset, but do not expect an interrupt to signal DID_RESET.
- This tells the upper level code to request the sense info, and this
- should keep the command alive. */
+ * This tells the upper level code to request the sense info, and this
+ * should keep the command alive. */
#define SCSI_RESET_WAKEUP 4
/* Something went wrong, and we do not know how to fix it. */
void * scsi_malloc(unsigned int);
int scsi_free(void *, unsigned int);
-extern unsigned int dma_free_sectors; /* How much room do we have left */
+extern unsigned int dma_free_sectors; /* How much room do we have left */
extern unsigned int need_isa_buffer; /* True if some devices need indirection
- buffers */
+ * buffers */
/*
- The Scsi_Cmnd structure is used by scsi.c internally, and for communication with
- low level drivers that support multiple outstanding commands.
-*/
+ * The Scsi_Cmnd structure is used by scsi.c internally, and for communication
+ * with low level drivers that support multiple outstanding commands.
+ */
typedef struct scsi_pointer {
- char * ptr; /* data pointer */
- int this_residual; /* left in this buffer */
- struct scatterlist *buffer; /* which buffer */
- int buffers_residual; /* how many buffers left */
-
- volatile int Status;
- volatile int Message;
- volatile int have_data_in;
- volatile int sent_command;
- volatile int phase;
+ char * ptr; /* data pointer */
+ int this_residual; /* left in this buffer */
+ struct scatterlist *buffer; /* which buffer */
+ int buffers_residual; /* how many buffers left */
+
+ volatile int Status;
+ volatile int Message;
+ volatile int have_data_in;
+ volatile int sent_command;
+ volatile int phase;
} Scsi_Pointer;
typedef struct scsi_cmnd {
- struct Scsi_Host * host;
- Scsi_Device * device;
- unsigned char target, lun;
- unsigned char cmd_len;
- unsigned char old_cmd_len;
- struct scsi_cmnd *next, *prev;
-
-/* These elements define the operation we are about to perform */
- unsigned char cmnd[12];
- unsigned request_bufflen; /* Actual request size */
-
- void * request_buffer; /* Actual requested buffer */
-
-/* These elements define the operation we ultimately want to perform */
- unsigned char data_cmnd[12];
- unsigned short old_use_sg; /* We save use_sg here when requesting
- sense info */
- unsigned short use_sg; /* Number of pieces of scatter-gather */
- unsigned short sglist_len; /* size of malloc'd scatter-gather list */
- unsigned short abort_reason; /* If the mid-level code requests an
- abort, this is the reason. */
- unsigned bufflen; /* Size of data buffer */
- void *buffer; /* Data buffer */
-
- unsigned underflow; /* Return error if less than this amount is
- transfered */
-
- unsigned transfersize; /* How much we are guaranteed to transfer with
- each SCSI transfer (ie, between disconnect /
- reconnects. Probably == sector size */
-
-
-
- struct request request; /* A copy of the command we are working on*/
-
- unsigned char sense_buffer[16]; /* Sense for this command, if needed*/
+ struct Scsi_Host * host;
+ Scsi_Device * device;
+ unsigned char target, lun, channel;
+ unsigned char cmd_len;
+ unsigned char old_cmd_len;
+ struct scsi_cmnd *next, *prev;
+
+ /* These elements define the operation we are about to perform */
+ unsigned char cmnd[12];
+ unsigned request_bufflen; /* Actual request size */
+
+ void * request_buffer; /* Actual requested buffer */
+
+ /* These elements define the operation we ultimately want to perform */
+ unsigned char data_cmnd[12];
+ unsigned short old_use_sg; /* We save use_sg here when requesting
+ * sense info */
+ unsigned short use_sg; /* Number of pieces of scatter-gather */
+ unsigned short sglist_len; /* size of malloc'd scatter-gather list */
+ unsigned short abort_reason;/* If the mid-level code requests an
+ * abort, this is the reason. */
+ unsigned bufflen; /* Size of data buffer */
+ void *buffer; /* Data buffer */
+
+ unsigned underflow; /* Return error if less than this amount is
+ * transfered */
+
+ unsigned transfersize; /* How much we are guaranteed to transfer with
+ * each SCSI transfer (ie, between disconnect /
+ * reconnects. Probably == sector size */
+
+
+ struct request request; /* A copy of the command we are working on */
+
+ unsigned char sense_buffer[16]; /* Sense for this command, if needed */
+
+
+ int retries;
+ int allowed;
+ int timeout_per_command, timeout_total, timeout;
+
+ /*
+ * We handle the timeout differently if it happens when a reset,
+ * abort, etc are in process.
+ */
+ unsigned volatile char internal_timeout;
+
+ unsigned flags;
+
+ /* These variables are for the cdrom only. Once we have variable size
+ * buffers in the buffer cache, they will go away. */
+ int this_count;
+ /* End of special cdrom variables */
+
+ /* Low-level done function - can be used by low-level driver to point
+ * to completion function. Not used by mid/upper level code. */
+ void (*scsi_done)(struct scsi_cmnd *);
+ void (*done)(struct scsi_cmnd *); /* Mid-level done function */
+
+ /*
+ * The following fields can be written to by the host specific code.
+ * Everything else should be left alone.
+ */
+
+ Scsi_Pointer SCp; /* Scratchpad used by some host adapters */
+
+ unsigned char * host_scribble; /* The host adapter is allowed to
+ * call scsi_malloc and get some memory
+ * and hang it here. The host adapter
+ * is also expected to call scsi_free
+ * to release this memory. (The memory
+ * obtained by scsi_malloc is guaranteed
+ * to be at an address < 16Mb). */
+
+ int result; /* Status code from lower level driver */
+
+ unsigned char tag; /* SCSI-II queued command tag */
+ unsigned long pid; /* Process ID, starts at 0 */
+} Scsi_Cmnd;
-
- int retries;
- int allowed;
- int timeout_per_command, timeout_total, timeout;
/*
- * We handle the timeout differently if it happens when a reset,
- * abort, etc are in process.
+ * scsi_abort aborts the current command that is executing on host host.
+ * The error code, if non zero is returned in the host byte, otherwise
+ * DID_ABORT is returned in the hostbyte.
*/
- unsigned volatile char internal_timeout;
-
- unsigned flags;
-
-/* These variables are for the cdrom only. Once we have variable size buffers
- in the buffer cache, they will go away. */
- int this_count;
-/* End of special cdrom variables */
-
- /* Low-level done function - can be used by low-level driver to point
- to completion function. Not used by mid/upper level code. */
- void (*scsi_done)(struct scsi_cmnd *);
- void (*done)(struct scsi_cmnd *); /* Mid-level done function */
-
-/* The following fields can be written to by the host specific code.
- Everything else should be left alone. */
-
- Scsi_Pointer SCp; /* Scratchpad used by some host adapters */
-
- unsigned char * host_scribble; /* The host adapter is allowed to
- call scsi_malloc and get some memory
- and hang it here. The host adapter
- is also expected to call scsi_free
- to release this memory. (The memory
- obtained by scsi_malloc is guaranteed
- to be at an address < 16Mb). */
-
- int result; /* Status code from lower level driver */
-
- unsigned char tag; /* SCSI-II queued command tag */
- unsigned long pid; /* Process ID, starts at 0 */
- } Scsi_Cmnd;
-
-/*
- scsi_abort aborts the current command that is executing on host host.
- The error code, if non zero is returned in the host byte, otherwise
- DID_ABORT is returned in the hostbyte.
-*/
-
extern int scsi_abort (Scsi_Cmnd *, int code, int pid);
extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd ,
- void *buffer, unsigned bufflen, void (*done)(struct scsi_cmnd *),
- int timeout, int retries);
+ void *buffer, unsigned bufflen,
+ void (*done)(struct scsi_cmnd *),
+ int timeout, int retries);
extern Scsi_Cmnd * allocate_device(struct request **, Scsi_Device *, int);
extern int max_scsi_hosts;
+extern void build_proc_dir_entries(void);
+
+extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg);
+extern void print_command(unsigned char *);
+extern void print_sense(char *, Scsi_Cmnd *);
+
+
#if defined(MAJOR_NR) && (MAJOR_NR != SCSI_TAPE_MAJOR)
#include "hosts.h"
+
static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
{
- struct request * req;
- struct buffer_head * bh;
-
- req = &SCpnt->request;
- req->errors = 0;
- if (!uptodate) {
- printk(DEVICE_NAME " I/O error: dev %04x, sector %lu\n",
- req->dev,req->sector);
- }
-
- do {
- if ((bh = req->bh) != NULL) {
+ struct request * req;
+ struct buffer_head * bh;
+
+ req = &SCpnt->request;
+ req->errors = 0;
+ if (!uptodate) {
+ printk(DEVICE_NAME " I/O error: dev %04x, sector %lu\n",
+ req->dev,req->sector);
+ }
+
+ do {
+ if ((bh = req->bh) != NULL) {
req->bh = bh->b_reqnext;
req->nr_sectors -= bh->b_size >> 9;
req->sector += bh->b_size >> 9;
unlock_buffer(bh);
sectors -= bh->b_size >> 9;
if ((bh = req->bh) != NULL) {
- req->current_nr_sectors = bh->b_size >> 9;
- if (req->nr_sectors < req->current_nr_sectors) {
- req->nr_sectors = req->current_nr_sectors;
- printk("end_scsi_request: buffer-list destroyed\n");
- }
+ req->current_nr_sectors = bh->b_size >> 9;
+ if (req->nr_sectors < req->current_nr_sectors) {
+ req->nr_sectors = req->current_nr_sectors;
+ printk("end_scsi_request: buffer-list destroyed\n");
+ }
}
- }
- } while(sectors && bh);
- if (req->bh){
- req->buffer = bh->b_data;
- return SCpnt;
- };
- DEVICE_OFF(req->dev);
- if (req->sem != NULL) {
- up(req->sem);
}
-
- if (SCpnt->host->block) {
- struct Scsi_Host * next;
-
- for (next = SCpnt->host->block; next != SCpnt->host;
- next = next->block)
- wake_up(&next->host_wait);
- }
-
- req->dev = -1;
- wake_up(&wait_for_request);
- wake_up(&SCpnt->device->device_wait);
- return NULL;
+ } while(sectors && bh);
+ if (req->bh){
+ req->buffer = bh->b_data;
+ return SCpnt;
+ };
+ DEVICE_OFF(req->dev);
+ if (req->sem != NULL) {
+ up(req->sem);
+ }
+
+ if (SCpnt->host->block) {
+ struct Scsi_Host * next;
+
+ for (next = SCpnt->host->block; next != SCpnt->host;
+ next = next->block)
+ wake_up(&next->host_wait);
+ }
+
+ req->dev = -1;
+ wake_up(&wait_for_request);
+ wake_up(&SCpnt->device->device_wait);
+ return NULL;
}
/* This is just like INIT_REQUEST, but we need to be aware of the fact
- that an interrupt may start another request, so we run this with interrupts
- turned off */
-
+ * that an interrupt may start another request, so we run this with interrupts
+ * turned off
+ */
#define INIT_SCSI_REQUEST \
- if (!CURRENT) {\
- CLEAR_INTR; \
- restore_flags(flags); \
- return; \
- } \
- if (MAJOR(CURRENT->dev) != MAJOR_NR) \
- panic(DEVICE_NAME ": request list destroyed"); \
- if (CURRENT->bh) { \
- if (!CURRENT->bh->b_lock) \
- panic(DEVICE_NAME ": block not locked"); \
- }
+ if (!CURRENT) {\
+ CLEAR_INTR; \
+ restore_flags(flags); \
+ return; \
+ } \
+ if (MAJOR(CURRENT->dev) != MAJOR_NR) \
+ panic(DEVICE_NAME ": request list destroyed"); \
+ if (CURRENT->bh) { \
+ if (!CURRENT->bh->b_lock) \
+ panic(DEVICE_NAME ": block not locked"); \
+ }
#endif
-#define SCSI_SLEEP(QUEUE, CONDITION) { \
- if (CONDITION) { \
- struct wait_queue wait = { current, NULL}; \
- add_wait_queue(QUEUE, &wait); \
- for(;;) { \
- current->state = TASK_UNINTERRUPTIBLE; \
- if (CONDITION) { \
- if (intr_count) \
- panic("scsi: trying to call schedule() in interrupt" \
- ", file %s, line %d.\n", __FILE__, __LINE__); \
- schedule(); \
- } \
- else \
- break; \
- } \
- remove_wait_queue(QUEUE, &wait); \
- current->state = TASK_RUNNING; \
- }; }
+#define SCSI_SLEEP(QUEUE, CONDITION) { \
+ if (CONDITION) { \
+ struct wait_queue wait = { current, NULL}; \
+ add_wait_queue(QUEUE, &wait); \
+ for(;;) { \
+ current->state = TASK_UNINTERRUPTIBLE; \
+ if (CONDITION) { \
+ if (intr_count) \
+ panic("scsi: trying to call schedule() in interrupt" \
+ ", file %s, line %d.\n", __FILE__, __LINE__); \
+ schedule(); \
+ } \
+ else \
+ break; \
+ } \
+ remove_wait_queue(QUEUE, &wait); \
+ current->state = TASK_RUNNING; \
+ }; }
#endif
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
* c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
* End:
*/
* anything out of the ordinary is seen.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/timer.h>
#include <linux/string.h>
#include <linux/genhd.h>
#include <linux/fs.h>
+#include <linux/proc_fs.h>
#include <asm/system.h>
#include <asm/io.h>
+
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
/* Number of real scsi disks that will be detected ahead of time */
static int NR_REAL=-1;
-#define NR_BLK_DEV 12
+#define NR_BLK_DEV 12
#ifndef MAJOR_NR
#define MAJOR_NR 8
#endif
#define VERIFY_DEBUG(RW) 1
#else
-#define VERIFY1_DEBUG(RW) \
- if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \
- start = 0; \
- if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1]; \
- if (bh){ \
- if (bh->b_size != 1024) panic ("Wrong bh size"); \
- if ((bh->b_blocknr << 1) + start != block) \
- { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \
- panic ("Wrong bh block#");}; \
+#define VERIFY1_DEBUG(RW) \
+ if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \
+ start = 0; \
+ if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1]; \
+ if (bh){ \
+ if (bh->b_size != 1024) panic ("Wrong bh size"); \
+ if ((bh->b_blocknr << 1) + start != block) \
+ { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \
+ panic ("Wrong bh block#"); \
+ }; \
if (bh->b_dev != SCpnt->request.dev) panic ("Bad bh target");\
- };
+ };
#if 0
/* This had been in the VERIFY_DEBUG macro, but it fails if there is already
- a disk on the system */
- if ((SCpnt->request.dev & 0xfff0) != ((target + NR_REAL) << 4) +(MAJOR_NR << 8)){ \
- printk("Dev #s %x %x ",SCpnt->request.dev, target); \
- panic ("Bad target");}; \
+ * a disk on the system */
+ if ((SCpnt->request.dev & 0xfff0) != ((target + NR_REAL) << 4) +(MAJOR_NR << 8)){ \
+ printk("Dev #s %x %x ",SCpnt->request.dev, target); \
+ panic ("Bad target");\
+ }; \
#endif
-#define VERIFY_DEBUG(RW) \
- if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \
- start = 0; \
- if ((SCpnt->request.dev & 0xf) > npart) panic ("Bad partition"); \
- if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1]; \
- if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \
- if (SCpnt->request.sector + start != block) panic("Wrong block."); \
- if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \
- if (SCpnt->request.bh){ \
- if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
- if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \
- { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \
- panic ("Wrong bh block#");}; \
+#define VERIFY_DEBUG(RW) \
+ if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \
+ start = 0; \
+ if ((SCpnt->request.dev & 0xf) > npart) panic ("Bad partition"); \
+ if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1]; \
+ if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \
+ if (SCpnt->request.sector + start != block) panic("Wrong block."); \
+ if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \
+ if (SCpnt->request.bh){ \
+ if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \
+ if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \
+ { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \
+ panic ("Wrong bh block#"); \
+ }; \
if (SCpnt->request.bh->b_dev != SCpnt->request.dev) panic ("Bad bh target");\
- };
+ };
#endif
static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, };
static char sense_buffer[128] = {0,};
static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){
- int i;
+ int i;
#if 0
- unsigned char * pnt;
+ unsigned char * pnt;
#endif
- unsigned int * lpnt;
- struct scatterlist * sgpnt = NULL;
- printk("use_sg: %d",SCpnt->use_sg);
- if (SCpnt->use_sg){
- sgpnt = (struct scatterlist *) SCpnt->buffer;
- for(i=0; i<SCpnt->use_sg; i++) {
- lpnt = (int *) sgpnt[i].alt_address;
- printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
- if (lpnt) printk(" (Alt %x) ",lpnt[15]);
+ unsigned int * lpnt;
+ struct scatterlist * sgpnt = NULL;
+ printk("use_sg: %d",SCpnt->use_sg);
+ if (SCpnt->use_sg){
+ sgpnt = (struct scatterlist *) SCpnt->buffer;
+ for(i=0; i<SCpnt->use_sg; i++) {
+ lpnt = (int *) sgpnt[i].alt_address;
+ printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+ if (lpnt) printk(" (Alt %x) ",lpnt[15]);
+ };
+ } else {
+ printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+ SCpnt->bufflen);
+ lpnt = (int *) SCpnt->request.buffer;
+ if (lpnt) printk(" (Alt %x) ",lpnt[15]);
+ };
+ lpnt = (unsigned int *) SCpnt;
+ for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
+ if ((i & 7) == 0) printk("\n");
+ printk("%x ",*lpnt++);
+ };
+ printk("\n");
+ if (flag == 0) return;
+ lpnt = (unsigned int *) sgpnt[0].alt_address;
+ for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
+ if ((i & 7) == 0) printk("\n");
+ printk("%x ",*lpnt++);
};
- } else {
- printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
- SCpnt->bufflen);
- lpnt = (int *) SCpnt->request.buffer;
- if (lpnt) printk(" (Alt %x) ",lpnt[15]);
- };
- lpnt = (unsigned int *) SCpnt;
- for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
- if ((i & 7) == 0) printk("\n");
- printk("%x ",*lpnt++);
- };
- printk("\n");
- if (flag == 0) return;
- lpnt = (unsigned int *) sgpnt[0].alt_address;
- for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
- if ((i & 7) == 0) printk("\n");
- printk("%x ",*lpnt++);
- };
#if 0
- printk("\n");
- lpnt = (unsigned int *) sgpnt[0].address;
- for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
- if ((i & 7) == 0) printk("\n");
- printk("%x ",*lpnt++);
- };
- printk("\n");
+ printk("\n");
+ lpnt = (unsigned int *) sgpnt[0].address;
+ for (i=0;i<sizeof(Scsi_Cmnd)/4+1; i++) {
+ if ((i & 7) == 0) printk("\n");
+ printk("%x ",*lpnt++);
+ };
+ printk("\n");
#endif
- printk("DMA free %d sectors.\n", dma_free_sectors);
+ printk("DMA free %d sectors.\n", dma_free_sectors);
}
int scsi_debug_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
int i;
sgcount = 0;
sgpnt = NULL;
-
+
DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;});
buff = (unsigned char *) SCpnt->request_buffer;
-
+
if(target>=1 || SCpnt->lun != 0) {
- SCpnt->result = DID_NO_CONNECT << 16;
- done(SCpnt);
- return 0;
+ SCpnt->result = DID_NO_CONNECT << 16;
+ done(SCpnt);
+ return 0;
};
switch(*cmd){
case REQUEST_SENSE:
- printk("Request sense...\n");
+ printk("Request sense...\n");
#ifndef DEBUG
- { int i;
- printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);
- for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
- printk("\n");
- };
+ {
+ int i;
+ printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen);
+ for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
+ printk("\n");
+ };
#endif
- memset(buff, 0, bufflen);
- memcpy(buff, sense_buffer, bufflen);
- memset(sense_buffer, 0, sizeof(sense_buffer));
- SCpnt->result = 0;
- done(SCpnt);
- return 0;
+ memset(buff, 0, bufflen);
+ memcpy(buff, sense_buffer, bufflen);
+ memset(sense_buffer, 0, sizeof(sense_buffer));
+ SCpnt->result = 0;
+ done(SCpnt);
+ return 0;
case ALLOW_MEDIUM_REMOVAL:
- if(cmd[4]) printk("Medium removal inhibited...");
- else printk("Medium removal enabled...");
- scsi_debug_errsts = 0;
- break;
+ if(cmd[4]) printk("Medium removal inhibited...");
+ else printk("Medium removal enabled...");
+ scsi_debug_errsts = 0;
+ break;
case INQUIRY:
- printk("Inquiry...(%x %d)\n", buff, bufflen);
- memset(buff, 0, bufflen);
- buff[0] = TYPE_DISK;
- buff[1] = 0x80; /* Removable disk */
- buff[2] = 1;
- buff[4] = 33 - 5;
- memcpy(&buff[8],"Foo Inc",7);
- memcpy(&buff[16],"XYZZY",5);
- memcpy(&buff[32],"1",1);
- scsi_debug_errsts = 0;
- break;
- case TEST_UNIT_READY:
- printk("Test unit ready.\n");
- if (buff)
+ printk("Inquiry...(%x %d)\n", buff, bufflen);
memset(buff, 0, bufflen);
- scsi_debug_errsts = 0;
- break;
+ buff[0] = TYPE_DISK;
+ buff[1] = 0x80; /* Removable disk */
+ buff[2] = 1;
+ buff[4] = 33 - 5;
+ memcpy(&buff[8],"Foo Inc",7);
+ memcpy(&buff[16],"XYZZY",5);
+ memcpy(&buff[32],"1",1);
+ scsi_debug_errsts = 0;
+ break;
+ case TEST_UNIT_READY:
+ printk("Test unit ready.\n");
+ if (buff)
+ memset(buff, 0, bufflen);
+ scsi_debug_errsts = 0;
+ break;
case READ_CAPACITY:
- printk("Read Capacity\n");
- if(NR_REAL < 0) NR_REAL = (SCpnt->request.dev >> 4) & 0x0f;
- memset(buff, 0, bufflen);
- buff[0] = (CAPACITY >> 24);
- buff[1] = (CAPACITY >> 16) & 0xff;
- buff[2] = (CAPACITY >> 8) & 0xff;
- buff[3] = CAPACITY & 0xff;
- buff[6] = 2; /* 512 byte sectors */
- scsi_debug_errsts = 0;
- break;
+ printk("Read Capacity\n");
+ if(NR_REAL < 0) NR_REAL = (SCpnt->request.dev >> 4) & 0x0f;
+ memset(buff, 0, bufflen);
+ buff[0] = (CAPACITY >> 24);
+ buff[1] = (CAPACITY >> 16) & 0xff;
+ buff[2] = (CAPACITY >> 8) & 0xff;
+ buff[3] = CAPACITY & 0xff;
+ buff[6] = 2; /* 512 byte sectors */
+ scsi_debug_errsts = 0;
+ break;
case READ_10:
case READ_6:
#ifdef DEBUG
- printk("Read...");
+ printk("Read...");
#endif
- if ((*cmd) == READ_10)
- block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
- else
- block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
- VERIFY_DEBUG(READ);
+ if ((*cmd) == READ_10)
+ block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
+ else
+ block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
+ VERIFY_DEBUG(READ);
#if defined(SCSI_SETUP_LATENCY) || defined(SCSI_DATARATE)
- {
+ {
int delay = SCSI_SETUP_LATENCY;
double usec;
-
+
usec = 0.0;
usec = (SCpnt->request.nr_sectors << 9) * 1.0e6 / SCSI_DATARATE;
delay += usec;
if(delay) usleep(delay);
- };
+ };
#endif
-
+
#ifdef DEBUG
- printk("(r%d)",SCpnt->request.nr_sectors);
+ printk("(r%d)",SCpnt->request.nr_sectors);
#endif
- nbytes = bufflen;
- if(SCpnt->use_sg){
- sgcount = 0;
- sgpnt = (struct scatterlist *) buff;
- buff = sgpnt[sgcount].address;
- bufflen = sgpnt[sgcount].length;
- bh = SCpnt->request.bh;
- };
- scsi_debug_errsts = 0;
- do{
- VERIFY1_DEBUG(READ);
-/* For the speedy test, we do not even want to fill the buffer with anything */
+ nbytes = bufflen;
+ if(SCpnt->use_sg){
+ sgcount = 0;
+ sgpnt = (struct scatterlist *) buff;
+ buff = sgpnt[sgcount].address;
+ bufflen = sgpnt[sgcount].length;
+ bh = SCpnt->request.bh;
+ };
+ scsi_debug_errsts = 0;
+ do{
+ VERIFY1_DEBUG(READ);
+ /* For the speedy test, we do not even want to fill the buffer with anything */
#ifndef SPEEDY
- memset(buff, 0, bufflen);
+ memset(buff, 0, bufflen);
#endif
-/* If this is block 0, then we want to read the partition table for this
- device. Let's make one up */
- if(block == 0 && target == 0) {
- *((unsigned short *) (buff+510)) = 0xAA55;
- p = (struct partition* ) (buff + 0x1be);
- npart = 0;
- while(starts[npart+1]){
- p->start_sect = starts[npart];
- p->nr_sects = starts[npart+1] - starts [npart];
- p->sys_ind = 0x81; /* Linux partition */
- p++;
- npart++;
- };
- scsi_debug_errsts = 0;
- break;
- };
+ /* If this is block 0, then we want to read the partition table for this
+ * device. Let's make one up */
+ if(block == 0 && target == 0) {
+ *((unsigned short *) (buff+510)) = 0xAA55;
+ p = (struct partition* ) (buff + 0x1be);
+ npart = 0;
+ while(starts[npart+1]){
+ p->start_sect = starts[npart];
+ p->nr_sects = starts[npart+1] - starts [npart];
+ p->sys_ind = 0x81; /* Linux partition */
+ p++;
+ npart++;
+ };
+ scsi_debug_errsts = 0;
+ break;
+ };
#ifdef DEBUG
- if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors,
- SCpnt->request.current_nr_sectors);
+ if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors,
+ SCpnt->request.current_nr_sectors);
#endif
-
+
#if 0
- /* Simulate a disk change */
- if(block == 0xfff0) {
- sense_buffer[0] = 0x70;
- sense_buffer[2] = UNIT_ATTENTION;
- starts[0] += 10;
- starts[1] += 10;
- starts[2] += 10;
-
+ /* Simulate a disk change */
+ if(block == 0xfff0) {
+ sense_buffer[0] = 0x70;
+ sense_buffer[2] = UNIT_ATTENTION;
+ starts[0] += 10;
+ starts[1] += 10;
+ starts[2] += 10;
+
#ifdef DEBUG
- { int i;
- printk("scsi_debug: Filling sense buffer:");
- for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
- printk("\n");
- };
+ {
+ int i;
+ printk("scsi_debug: Filling sense buffer:");
+ for(i=0;i<12;i++) printk("%d ",sense_buffer[i]);
+ printk("\n");
+ };
#endif
- scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
- break;
- } /* End phony disk change code */
+ scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1);
+ break;
+ } /* End phony disk change code */
#endif
-
+
#ifndef SPEEDY
- memcpy(buff, &target, sizeof(target));
- memcpy(buff+sizeof(target), cmd, 24);
- memcpy(buff+60, &block, sizeof(block));
- memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd));
+ memcpy(buff, &target, sizeof(target));
+ memcpy(buff+sizeof(target), cmd, 24);
+ memcpy(buff+60, &block, sizeof(block));
+ memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd));
#endif
- nbytes -= bufflen;
- if(SCpnt->use_sg){
+ nbytes -= bufflen;
+ if(SCpnt->use_sg){
#ifndef SPEEDY
- memcpy(buff+128, bh, sizeof(struct buffer_head));
+ memcpy(buff+128, bh, sizeof(struct buffer_head));
#endif
- block += bufflen >> 9;
- bh = bh->b_reqnext;
- sgcount++;
- if (nbytes) {
- if(!bh) panic("Too few blocks for linked request.");
- buff = sgpnt[sgcount].address;
- bufflen = sgpnt[sgcount].length;
- };
- }
- } while(nbytes);
-
- SCpnt->result = 0;
- (done)(SCpnt);
- return;
-
- if (SCpnt->use_sg && !scsi_debug_errsts)
- if(bh) scsi_dump(SCpnt, 0);
- break;
+ block += bufflen >> 9;
+ bh = bh->b_reqnext;
+ sgcount++;
+ if (nbytes) {
+ if(!bh) panic("Too few blocks for linked request.");
+ buff = sgpnt[sgcount].address;
+ bufflen = sgpnt[sgcount].length;
+ };
+ }
+ } while(nbytes);
+
+ SCpnt->result = 0;
+ (done)(SCpnt);
+ return;
+
+ if (SCpnt->use_sg && !scsi_debug_errsts)
+ if(bh) scsi_dump(SCpnt, 0);
+ break;
case WRITE_10:
case WRITE_6:
#ifdef DEBUG
- printk("Write\n");
+ printk("Write\n");
#endif
- if ((*cmd) == WRITE_10)
- block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
- else
- block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
- VERIFY_DEBUG(WRITE);
-/* printk("(w%d)",SCpnt->request.nr_sectors); */
- if (SCpnt->use_sg){
- if ((bufflen >> 9) != SCpnt->request.nr_sectors)
- panic ("Trying to write wrong number of blocks\n");
- sgpnt = (struct scatterlist *) buff;
- buff = sgpnt[sgcount].address;
- };
+ if ((*cmd) == WRITE_10)
+ block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24);
+ else
+ block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16);
+ VERIFY_DEBUG(WRITE);
+ /* printk("(w%d)",SCpnt->request.nr_sectors); */
+ if (SCpnt->use_sg){
+ if ((bufflen >> 9) != SCpnt->request.nr_sectors)
+ panic ("Trying to write wrong number of blocks\n");
+ sgpnt = (struct scatterlist *) buff;
+ buff = sgpnt[sgcount].address;
+ };
#if 0
- if (block != *((unsigned long *) (buff+60))) {
- printk("%x %x :",block, *((unsigned long *) (buff+60)));
- scsi_dump(SCpnt,1);
- panic("Bad block written.\n");
- };
+ if (block != *((unsigned long *) (buff+60))) {
+ printk("%x %x :",block, *((unsigned long *) (buff+60)));
+ scsi_dump(SCpnt,1);
+ panic("Bad block written.\n");
+ };
#endif
- scsi_debug_errsts = 0;
- break;
- default:
- printk("Unknown command %d\n",*cmd);
- SCpnt->result = DID_NO_CONNECT << 16;
- done(SCpnt);
- return 0;
+ scsi_debug_errsts = 0;
+ break;
+ default:
+ printk("Unknown command %d\n",*cmd);
+ SCpnt->result = DID_NO_CONNECT << 16;
+ done(SCpnt);
+ return 0;
};
-
- save_flags(flags);
- cli();
+
+ save_flags(flags);
+ cli();
for(i=0;i<SCSI_DEBUG_MAILBOXES; i++){
- if (SCint[i] == 0) break;
+ if (SCint[i] == 0) break;
};
-
+
if (i >= SCSI_DEBUG_MAILBOXES || SCint[i] != 0)
- panic("Unable to find empty SCSI_DEBUG command slot.\n");
-
+ panic("Unable to find empty SCSI_DEBUG command slot.\n");
+
SCint[i] = SCpnt;
-
+
if (done) {
DEB(printk("scsi_debug_queuecommand: now waiting for interrupt "););
if (do_done[i])
- printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n");
+ printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n");
else
- do_done[i] = done;
+ do_done[i] = done;
}
else
- printk("scsi_debug_queuecommand: done cant be NULL\n");
-
+ printk("scsi_debug_queuecommand: done cant be NULL\n");
+
#ifdef IMMEDIATE
SCpnt->result = scsi_debug_errsts;
scsi_debug_intr_handle(); /* No timer - do this one right away */
#else
timeout[i] = jiffies+DISK_SPEED;
-
-/* If no timers active, then set this one */
+
+ /* If no timers active, then set this one */
if ((timer_active & (1 << SCSI_DEBUG_TIMER)) == 0) {
- timer_table[SCSI_DEBUG_TIMER].expires = timeout[i];
- timer_active |= 1 << SCSI_DEBUG_TIMER;
+ timer_table[SCSI_DEBUG_TIMER].expires = timeout[i];
+ timer_active |= 1 << SCSI_DEBUG_TIMER;
};
-
+
SCpnt->result = scsi_debug_errsts;
restore_flags(flags);
-
+
#if 0
printk("Sending command (%d %x %d %d)...", i, done, timeout[i],jiffies);
#endif
#endif
-
+
return 0;
}
{
DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n"));
scsi_debug_queuecommand(SCpnt, internal_done);
-
+
while (!internal_done_flag);
internal_done_flag = 0;
return internal_done_errcode;
}
/* A "high" level interrupt handler. This should be called once per jiffy
- to simulate a regular scsi disk. We use a timer to do this. */
+ * to simulate a regular scsi disk. We use a timer to do this. */
static void scsi_debug_intr_handle(void)
{
void (*my_done)(Scsi_Cmnd *);
unsigned long flags;
int to;
-
+
#ifndef IMMEDIATE
timer_table[SCSI_DEBUG_TIMER].expires = 0;
timer_active &= ~(1 << SCSI_DEBUG_TIMER);
#endif
-
- repeat:
+
+ repeat:
save_flags(flags);
cli();
for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
- if (SCint[i] == 0) continue;
+ if (SCint[i] == 0) continue;
#ifndef IMMEDIATE
- if (timeout[i] == 0) continue;
- if (timeout[i] <= jiffies) break;
+ if (timeout[i] == 0) continue;
+ if (timeout[i] <= jiffies) break;
#else
- break;
+ break;
#endif
};
-
+
if(i == SCSI_DEBUG_MAILBOXES){
#ifndef IMMEDIATE
- pending = INT_MAX;
- for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
- if (SCint[i] == 0) continue;
- if (timeout[i] == 0) continue;
- if (timeout[i] <= jiffies) {restore_flags(flags); goto repeat;};
- if (timeout[i] > jiffies) {
- if (pending > timeout[i]) pending = timeout[i];
- continue;
+ pending = INT_MAX;
+ for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
+ if (SCint[i] == 0) continue;
+ if (timeout[i] == 0) continue;
+ if (timeout[i] <= jiffies) {restore_flags(flags); goto repeat;};
+ if (timeout[i] > jiffies) {
+ if (pending > timeout[i]) pending = timeout[i];
+ continue;
+ };
};
- };
- if (pending && pending != INT_MAX) {
- timer_table[SCSI_DEBUG_TIMER].expires =
- (pending <= jiffies ? jiffies+1 : pending);
- timer_active |= 1 << SCSI_DEBUG_TIMER;
- };
- restore_flags(flags);
+ if (pending && pending != INT_MAX) {
+ timer_table[SCSI_DEBUG_TIMER].expires =
+ (pending <= jiffies ? jiffies+1 : pending);
+ timer_active |= 1 << SCSI_DEBUG_TIMER;
+ };
+ restore_flags(flags);
#endif
- return;
+ return;
};
-
+
if(i < SCSI_DEBUG_MAILBOXES){
- timeout[i] = 0;
- my_done = do_done[i];
- do_done[i] = NULL;
- to = timeout[i];
- timeout[i] = 0;
- SCtmp = (Scsi_Cmnd *) SCint[i];
- SCint[i] = NULL;
- restore_flags(flags);
-
- if (!my_done) {
- printk("scsi_debug_intr_handle: Unexpected interrupt\n");
- return;
- }
-
+ timeout[i] = 0;
+ my_done = do_done[i];
+ do_done[i] = NULL;
+ to = timeout[i];
+ timeout[i] = 0;
+ SCtmp = (Scsi_Cmnd *) SCint[i];
+ SCint[i] = NULL;
+ restore_flags(flags);
+
+ if (!my_done) {
+ printk("scsi_debug_intr_handle: Unexpected interrupt\n");
+ return;
+ }
+
#ifdef DEBUG
- printk("In intr_handle...");
- printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
- printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
+ printk("In intr_handle...");
+ printk("...done %d %x %d %d\n",i , my_done, to, jiffies);
+ printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done);
#endif
-
- my_done(SCtmp);
+
+ my_done(SCtmp);
#ifdef DEBUG
- printk("Called done.\n");
+ printk("Called done.\n");
#endif
};
goto repeat;
int j;
void (*my_done)(Scsi_Cmnd *);
unsigned long flags;
-
+
DEB(printk("scsi_debug_abort\n"));
SCpnt->result = SCpnt->abort_reason << 16;
for(j=0;j<SCSI_DEBUG_MAILBOXES; j++) {
- if(SCpnt == SCint[j]) {
- my_done = do_done[j];
- my_done(SCpnt);
- save_flags(flags);
- cli();
- timeout[j] = 0;
- SCint[j] = NULL;
- do_done[j] = NULL;
- restore_flags(flags);
- };
+ if(SCpnt == SCint[j]) {
+ my_done = do_done[j];
+ my_done(SCpnt);
+ save_flags(flags);
+ cli();
+ timeout[j] = 0;
+ SCint[j] = NULL;
+ do_done[j] = NULL;
+ restore_flags(flags);
+ };
};
return 0;
}
int scsi_debug_biosparam(Disk * disk, int dev, int* info){
- int size = disk->capacity;
- info[0] = 32;
- info[1] = 64;
- info[2] = (size + 2047) >> 11;
- if (info[2] >= 1024) info[2] = 1024;
- return 0;
+ int size = disk->capacity;
+ info[0] = 32;
+ info[1] = 64;
+ info[2] = (size + 2047) >> 11;
+ if (info[2] >= 1024) info[2] = 1024;
+ return 0;
}
int scsi_debug_reset(Scsi_Cmnd * SCpnt)
{
int i;
unsigned long flags;
-
+
void (*my_done)(Scsi_Cmnd *);
DEB(printk("scsi_debug_reset called\n"));
for(i=0;i<SCSI_DEBUG_MAILBOXES; i++) {
do_done[i] = NULL;
timeout[i] = 0;
restore_flags(flags);
- };
+ };
return 0;
}
const char *scsi_debug_info(void)
{
- static char buffer[] = " "; /* looks nicer without anything here */
+ static char buffer[] = " "; /* looks nicer without anything here */
return buffer;
}
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = SCSI_DEBUG;
+#include "scsi_module.c"
+#endif
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
int scsi_debug_biosparam(Disk *, int, int[]);
int scsi_debug_reset(Scsi_Cmnd *);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
#ifndef NULL
#define NULL 0
#endif
#define SCSI_DEBUG_MAILBOXES 8
-#define SCSI_DEBUG {NULL, NULL, "SCSI DEBUG", scsi_debug_detect, NULL, \
+#define SCSI_DEBUG {NULL, NULL, generic_proc_info, "scsi_debug", \
+ PROC_SCSI_SCSI_DEBUG, "SCSI DEBUG", scsi_debug_detect, NULL, \
NULL, scsi_debug_command, \
scsi_debug_queuecommand, \
scsi_debug_abort, \
#include "hosts.h"
#include "scsi_ioctl.h"
-#define MAX_RETRIES 5
+#define MAX_RETRIES 5
#define MAX_TIMEOUT 900
#define MAX_BUF 4096
static int ioctl_probe(struct Scsi_Host * host, void *buffer)
{
- int temp;
- unsigned int len,slen;
- const char * string;
-
- if ((temp = host->hostt->present) && buffer) {
- len = get_user ((unsigned int *) buffer);
- if(host->hostt->info)
- string = host->hostt->info(host);
- else
- string = host->hostt->name;
- if(string) {
- slen = strlen(string);
- if (len > slen)
- len = slen + 1;
- verify_area(VERIFY_WRITE, buffer, len);
- memcpy_tofs (buffer, string, len);
- }
+ int temp;
+ unsigned int len,slen;
+ const char * string;
+
+ if ((temp = host->hostt->present) && buffer) {
+ len = get_user ((unsigned int *) buffer);
+ if(host->hostt->info)
+ string = host->hostt->info(host);
+ else
+ string = host->hostt->name;
+ if(string) {
+ slen = strlen(string);
+ if (len > slen)
+ len = slen + 1;
+ verify_area(VERIFY_WRITE, buffer, len);
+ memcpy_tofs (buffer, string, len);
}
- return temp;
+ }
+ return temp;
}
/*
static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
{
- struct request * req;
-
- req = &SCpnt->request;
- req->dev = 0xfffe; /* Busy, but indicate request done */
-
- if (req->sem != NULL) {
- up(req->sem);
- }
-}
+ struct request * req;
+
+ req = &SCpnt->request;
+ req->dev = 0xfffe; /* Busy, but indicate request done */
+
+ if (req->sem != NULL) {
+ up(req->sem);
+ }
+}
static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
{
- int result;
- Scsi_Cmnd * SCpnt;
-
- SCpnt = allocate_device(NULL, dev, 1);
- scsi_do_cmd(SCpnt, cmd, NULL, 0,
- scsi_ioctl_done, MAX_TIMEOUT,
- MAX_RETRIES);
-
- if (SCpnt->request.dev != 0xfffe){
- struct semaphore sem = MUTEX_LOCKED;
- SCpnt->request.sem = &sem;
- down(&sem);
- /* Hmm.. Have to ask about this one */
- while (SCpnt->request.dev != 0xfffe) schedule();
- };
-
- if(driver_byte(SCpnt->result) != 0)
- switch(SCpnt->sense_buffer[2] & 0xf) {
- case ILLEGAL_REQUEST:
+ int result;
+ Scsi_Cmnd * SCpnt;
+
+ SCpnt = allocate_device(NULL, dev, 1);
+ scsi_do_cmd(SCpnt, cmd, NULL, 0,
+ scsi_ioctl_done, MAX_TIMEOUT,
+ MAX_RETRIES);
+
+ if (SCpnt->request.dev != 0xfffe){
+ struct semaphore sem = MUTEX_LOCKED;
+ SCpnt->request.sem = &sem;
+ down(&sem);
+ /* Hmm.. Have to ask about this one */
+ while (SCpnt->request.dev != 0xfffe) schedule();
+ };
+
+ if(driver_byte(SCpnt->result) != 0)
+ switch(SCpnt->sense_buffer[2] & 0xf) {
+ case ILLEGAL_REQUEST:
if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0;
else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n");
break;
- case NOT_READY: /* This happens if there is no disc in drive */
+ case NOT_READY: /* This happens if there is no disc in drive */
if(dev->removable){
- printk("Device not ready. Make sure there is a disc in the drive.\n");
- break;
+ printk("Device not ready. Make sure there is a disc in the drive.\n");
+ break;
};
- case UNIT_ATTENTION:
+ case UNIT_ATTENTION:
if (dev->removable){
- dev->changed = 1;
- SCpnt->result = 0; /* This is no longer considered an error */
- printk("Disc change detected.\n");
- break;
+ dev->changed = 1;
+ SCpnt->result = 0; /* This is no longer considered an error */
+ printk("Disc change detected.\n");
+ break;
};
- default: /* Fall through for non-removable media */
+ default: /* Fall through for non-removable media */
printk("SCSI CD error: host %d id %d lun %d return code = %x\n",
dev->host->host_no,
dev->id,
sense_class(SCpnt->sense_buffer[0]),
sense_error(SCpnt->sense_buffer[0]),
SCpnt->sense_buffer[2] & 0xf);
-
- };
-
- result = SCpnt->result;
- SCpnt->request.dev = -1;
- wake_up(&SCpnt->device->device_wait);
- return result;
+
+ };
+
+ result = SCpnt->result;
+ SCpnt->request.dev = -1;
+ wake_up(&SCpnt->device->device_wait);
+ return result;
}
static int ioctl_command(Scsi_Device *dev, void *buffer)
{
- char * buf;
- char cmd[12];
- char * cmd_in;
- Scsi_Cmnd * SCpnt;
- unsigned char opcode;
- int inlen, outlen, cmdlen;
- int needed, buf_needed;
- int result;
-
- if (!buffer)
- return -EINVAL;
-
- inlen = get_user((unsigned int *) buffer);
- outlen = get_user( ((unsigned int *) buffer) + 1);
-
- cmd_in = (char *) ( ((int *)buffer) + 2);
- opcode = get_user(cmd_in);
-
- needed = buf_needed = (inlen > outlen ? inlen : outlen);
- if(buf_needed){
- buf_needed = (buf_needed + 511) & ~511;
- if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
- buf = (char *) scsi_malloc(buf_needed);
- if (!buf) return -ENOMEM;
- memset(buf, 0, buf_needed);
- } else
- buf = NULL;
-
- memcpy_fromfs ((void *) cmd, cmd_in, cmdlen = COMMAND_SIZE (opcode));
- memcpy_fromfs ((void *) buf, (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen);
-
- cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
-
+ char * buf;
+ char cmd[12];
+ char * cmd_in;
+ Scsi_Cmnd * SCpnt;
+ unsigned char opcode;
+ int inlen, outlen, cmdlen;
+ int needed, buf_needed;
+ int result;
+
+ if (!buffer)
+ return -EINVAL;
+
+ inlen = get_user((unsigned int *) buffer);
+ outlen = get_user( ((unsigned int *) buffer) + 1);
+
+ cmd_in = (char *) ( ((int *)buffer) + 2);
+ opcode = get_user(cmd_in);
+
+ needed = buf_needed = (inlen > outlen ? inlen : outlen);
+ if(buf_needed){
+ buf_needed = (buf_needed + 511) & ~511;
+ if (buf_needed > MAX_BUF) buf_needed = MAX_BUF;
+ buf = (char *) scsi_malloc(buf_needed);
+ if (!buf) return -ENOMEM;
+ memset(buf, 0, buf_needed);
+ } else
+ buf = NULL;
+
+ memcpy_fromfs ((void *) cmd, cmd_in, cmdlen = COMMAND_SIZE (opcode));
+ memcpy_fromfs ((void *) buf, (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen);
+
+ cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
+
#ifndef DEBUG_NO_CMD
-
- SCpnt = allocate_device(NULL, dev, 1);
-
- scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, MAX_TIMEOUT,
- MAX_RETRIES);
-
- if (SCpnt->request.dev != 0xfffe){
- struct semaphore sem = MUTEX_LOCKED;
- SCpnt->request.sem = &sem;
- down(&sem);
- /* Hmm.. Have to ask about this one */
- while (SCpnt->request.dev != 0xfffe) schedule();
- };
-
-
- /* If there was an error condition, pass the info back to the user. */
- if(SCpnt->result) {
- result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer));
- if (result)
+
+ SCpnt = allocate_device(NULL, dev, 1);
+
+ scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, MAX_TIMEOUT,
+ MAX_RETRIES);
+
+ if (SCpnt->request.dev != 0xfffe){
+ struct semaphore sem = MUTEX_LOCKED;
+ SCpnt->request.sem = &sem;
+ down(&sem);
+ /* Hmm.. Have to ask about this one */
+ while (SCpnt->request.dev != 0xfffe) schedule();
+ };
+
+
+ /* If there was an error condition, pass the info back to the user. */
+ if(SCpnt->result) {
+ result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer));
+ if (result)
return result;
- memcpy_tofs((void *) cmd_in, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
- } else {
-
- result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF : outlen);
- if (result)
+ memcpy_tofs((void *) cmd_in, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
+ } else {
+
+ result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF : outlen);
+ if (result)
return result;
- memcpy_tofs ((void *) cmd_in, buf, (outlen > MAX_BUF) ? MAX_BUF : outlen);
- };
- result = SCpnt->result;
- SCpnt->request.dev = -1; /* Mark as not busy */
- if (buf) scsi_free(buf, buf_needed);
-
- if(SCpnt->device->scsi_request_fn)
- (*SCpnt->device->scsi_request_fn)();
-
- wake_up(&SCpnt->device->device_wait);
- return result;
+ memcpy_tofs ((void *) cmd_in, buf, (outlen > MAX_BUF) ? MAX_BUF : outlen);
+ };
+ result = SCpnt->result;
+ SCpnt->request.dev = -1; /* Mark as not busy */
+ if (buf) scsi_free(buf, buf_needed);
+
+ if(SCpnt->device->scsi_request_fn)
+ (*SCpnt->device->scsi_request_fn)();
+
+ wake_up(&SCpnt->device->device_wait);
+ return result;
#else
- {
+ {
int i;
printk("scsi_ioctl : device %d. command = ", dev->id);
for (i = 0; i < 12; ++i)
- printk("%02x ", cmd[i]);
+ printk("%02x ", cmd[i]);
printk("\nbuffer =");
for (i = 0; i < 20; ++i)
- printk("%02x ", buf[i]);
+ printk("%02x ", buf[i]);
printk("\n");
printk("inlen = %d, outlen = %d, cmdlen = %d\n",
- inlen, outlen, cmdlen);
+ inlen, outlen, cmdlen);
printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in);
- }
- return 0;
+ }
+ return 0;
#endif
}
/*
- the scsi_ioctl() function differs from most ioctls in that it does
- not take a major/minor number as the dev filed. Rather, it takes
- a pointer to a scsi_devices[] element, a structure.
-*/
+ * the scsi_ioctl() function differs from most ioctls in that it does
+ * not take a major/minor number as the dev filed. Rather, it takes
+ * a pointer to a scsi_devices[] element, a structure.
+ */
int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
{
- char scsi_cmd[12];
-
- /* No idea how this happens.... */
- if (!dev) return -ENXIO;
-
- switch (cmd) {
- case SCSI_IOCTL_GET_IDLUN:
- verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
- put_user(dev->id + (dev->lun << 8) +
- (dev->host->host_no << 16), (unsigned int *) arg);
- return 0;
- case SCSI_IOCTL_TAGGED_ENABLE:
- if(!suser()) return -EACCES;
- if(!dev->tagged_supported) return -EINVAL;
- dev->tagged_queue = 1;
- dev->current_tag = 1;
- break;
- case SCSI_IOCTL_TAGGED_DISABLE:
- if(!suser()) return -EACCES;
- if(!dev->tagged_supported) return -EINVAL;
- dev->tagged_queue = 0;
- dev->current_tag = 0;
- break;
- case SCSI_IOCTL_PROBE_HOST:
- return ioctl_probe(dev->host, arg);
- case SCSI_IOCTL_SEND_COMMAND:
- if(!suser()) return -EACCES;
- return ioctl_command((Scsi_Device *) dev, arg);
- case SCSI_IOCTL_DOORLOCK:
- if (!dev->removable || !dev->lockable) return 0;
- scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
- scsi_cmd[1] = dev->lun << 5;
- scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
- scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
- return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
- break;
- case SCSI_IOCTL_DOORUNLOCK:
- if (!dev->removable || !dev->lockable) return 0;
- scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
- scsi_cmd[1] = dev->lun << 5;
- scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
- scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
- return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
- case SCSI_IOCTL_TEST_UNIT_READY:
- scsi_cmd[0] = TEST_UNIT_READY;
- scsi_cmd[1] = dev->lun << 5;
- scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
- scsi_cmd[4] = 0;
- return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
- break;
- default :
- return -EINVAL;
- }
+ char scsi_cmd[12];
+
+ /* No idea how this happens.... */
+ if (!dev) return -ENXIO;
+
+ switch (cmd) {
+ case SCSI_IOCTL_GET_IDLUN:
+ verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
+ put_user(dev->id + (dev->lun << 8) + (dev->host->host_no << 16) +
+ /* This has been added to support
+ * multichannel HBAs, it might cause
+ * problems with some software */
+ (dev->channel << 24),
+ (unsigned long *) arg);
+ return 0;
+ case SCSI_IOCTL_TAGGED_ENABLE:
+ if(!suser()) return -EACCES;
+ if(!dev->tagged_supported) return -EINVAL;
+ dev->tagged_queue = 1;
+ dev->current_tag = 1;
+ break;
+ case SCSI_IOCTL_TAGGED_DISABLE:
+ if(!suser()) return -EACCES;
+ if(!dev->tagged_supported) return -EINVAL;
+ dev->tagged_queue = 0;
+ dev->current_tag = 0;
+ break;
+ case SCSI_IOCTL_PROBE_HOST:
+ return ioctl_probe(dev->host, arg);
+ case SCSI_IOCTL_SEND_COMMAND:
+ if(!suser()) return -EACCES;
+ return ioctl_command((Scsi_Device *) dev, arg);
+ case SCSI_IOCTL_DOORLOCK:
+ if (!dev->removable || !dev->lockable) return 0;
+ scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+ scsi_cmd[1] = dev->lun << 5;
+ scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+ scsi_cmd[4] = SCSI_REMOVAL_PREVENT;
+ return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
+ break;
+ case SCSI_IOCTL_DOORUNLOCK:
+ if (!dev->removable || !dev->lockable) return 0;
+ scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL;
+ scsi_cmd[1] = dev->lun << 5;
+ scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+ scsi_cmd[4] = SCSI_REMOVAL_ALLOW;
+ return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
+ case SCSI_IOCTL_TEST_UNIT_READY:
+ scsi_cmd[0] = TEST_UNIT_READY;
+ scsi_cmd[1] = dev->lun << 5;
+ scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
+ scsi_cmd[4] = 0;
+ return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd);
+ break;
+ default :
return -EINVAL;
+ }
+ return -EINVAL;
}
/*
*/
int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) {
- unsigned long oldfs;
- int tmp;
- oldfs = get_fs();
- set_fs(get_ds());
- tmp = scsi_ioctl (dev, cmd, arg);
- set_fs(oldfs);
- return tmp;
+ unsigned long oldfs;
+ int tmp;
+ oldfs = get_fs();
+ set_fs(get_ds());
+ tmp = scsi_ioctl (dev, cmd, arg);
+ set_fs(oldfs);
+ return tmp;
}
/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
* c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
* End:
*/
/*
- * scsi_module.c Copyright (1994, 1995) Eric Youngdale.
+ * scsi_module.c Copyright (1994, 1995) Eric Youngdale.
*
* Support for loading low-level scsi drivers using the linux kernel loadable
* module interface.
char kernel_version[] = UTS_RELEASE;
int init_module(void) {
- driver_template.usage_count = &mod_use_count_;
- scsi_register_module(MODULE_SCSI_HA, &driver_template);
- return (driver_template.present == 0);
+ driver_template.usage_count = &mod_use_count_;
+ scsi_register_module(MODULE_SCSI_HA, &driver_template);
+ return (driver_template.present == 0);
}
void cleanup_module( void) {
- if (MOD_IN_USE) {
- printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
- }
- scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
+ if (MOD_IN_USE) {
+ printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+ return;
+ }
+ scsi_unregister_module(MODULE_SCSI_HA, &driver_template);
}
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
--- /dev/null
+/*
+ * linux/drivers/scsi/scsi_proc.c
+ *
+ * The functions in this file provide an interface between
+ * the PROC file system and the SCSI device drivers
+ * It is mainly used for debugging, statistics and to pass
+ * information directly to the lowlevel driver.
+ *
+ * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
+ * Version: 0.99.5 last change: 95/06/28
+ *
+ * generic command parser provided by:
+ * Andreas Heilwagen <crashcar@informatik.uni-koblenz.de>
+ */
+
+
+#include <linux/string.h>
+#include <linux/mm.h>
+#include <linux/malloc.h>
+#include <linux/proc_fs.h>
+#include <linux/errno.h>
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+
+#ifndef TRUE
+#define TRUE 1
+#define FALSE 0
+#endif
+
+extern struct proc_dir_entry scsi_dir[];
+extern struct proc_dir_entry scsi_hba_dir[];
+extern int scsi_proc_info(char *, char **, off_t, int, int, int);
+
+
+int get_hba_index(int ino)
+{
+ Scsi_Host_Template *tpnt = scsi_hosts;
+ struct Scsi_Host *hpnt = scsi_hostlist;
+ uint x = 0;
+
+ while (tpnt) {
+ if (ino == tpnt->low_ino)
+ return(x);
+ x += 3;
+ while (hpnt) {
+ hpnt = hpnt->next;
+ x++;
+ }
+ tpnt = tpnt->next;
+ }
+ return(0);
+}
+
+/* generic_proc_info
+ * Used if the driver currently has no own support for /proc/scsi
+ */
+int generic_proc_info(char *buffer, char **start, off_t offset,
+ int length, int inode, int inout)
+{
+ int len, pos, begin;
+
+ if(inout == TRUE)
+ return(-ENOSYS); /* This is a no-op */
+
+ begin = 0;
+ pos = len = sprintf(buffer,
+ "The driver does not yet support the proc-fs\n");
+ if(pos < offset)
+ {
+ len = 0;
+ begin = pos;
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin);
+ if(len > length)
+ len = length;
+
+ return(len);
+}
+
+/* dispatch_scsi_info is the central dispatcher
+ * It is the interface between the proc-fs and the SCSI subsystem code
+ */
+extern int dispatch_scsi_info(int ino, char *buffer, char **start,
+ off_t offset, int length, int func)
+{
+ struct Scsi_Host *hpnt = scsi_hostlist;
+
+ if(func != 2) {
+ if(ino == PROC_SCSI_SCSI)
+ return(scsi_proc_info(buffer, start, offset, length,
+ hpnt->host_no, func));
+ while(hpnt) {
+ if (ino == (hpnt->host_no + PROC_SCSI_FILE))
+ return(hpnt->hostt->proc_info(buffer, start, offset, length,
+ hpnt->host_no, func));
+ hpnt = hpnt->next;
+ }
+ return(-EBADF);
+ } else
+ return(get_hba_index(ino));
+}
+
+inline uint count_templates(void)
+{
+ Scsi_Host_Template *tpnt = scsi_hosts;
+ uint x = 0;
+
+ while (tpnt) {
+ tpnt = tpnt->next;
+ x++;
+ }
+ return (x);
+}
+
+void build_proc_dir_hba_entries(void)
+{
+ Scsi_Host_Template *tpnt = scsi_hosts;
+ struct Scsi_Host *hpnt = scsi_hostlist;
+ static char names[PROC_SCSI_LAST - PROC_SCSI_FILE][3];
+ uint x, y;
+
+ x = y = 0;
+
+ while (tpnt) {
+ scsi_hba_dir[x].low_ino = tpnt->low_ino;
+ scsi_hba_dir[x].namelen = 1;
+ scsi_hba_dir[x++].name = ".";
+ scsi_hba_dir[x].low_ino = PROC_SCSI;
+ scsi_hba_dir[x].namelen = 2;
+ scsi_hba_dir[x++].name = "..";
+
+ while (hpnt) {
+ if (tpnt == hpnt->hostt) {
+ scsi_hba_dir[x].low_ino = PROC_SCSI_FILE + hpnt->host_no;
+ scsi_hba_dir[x].namelen = sprintf(names[y],"%d",hpnt->host_no);
+ scsi_hba_dir[x].name = names[y];
+ y++;
+ x++;
+ }
+ hpnt = hpnt->next;
+ }
+
+ scsi_hba_dir[x].low_ino = 0;
+ scsi_hba_dir[x].namelen = 0;
+ scsi_hba_dir[x++].name = NULL;
+ tpnt = tpnt->next;
+ }
+}
+
+void build_proc_dir_entries(void)
+{
+ Scsi_Host_Template *tpnt = scsi_hosts;
+
+ uint newnum;
+ uint x;
+
+ newnum = count_templates();
+
+ scsi_dir[0].low_ino = PROC_SCSI;
+ scsi_dir[0].namelen = 1;
+ scsi_dir[0].name = ".";
+ scsi_dir[1].low_ino = PROC_ROOT_INO;
+ scsi_dir[1].namelen = 2;
+ scsi_dir[1].name = "..";
+ scsi_dir[2].low_ino = PROC_SCSI_SCSI;
+ scsi_dir[2].namelen = 4;
+ scsi_dir[2].name = "scsi";
+ for(x = 3; x < newnum + 3; x++, tpnt = tpnt->next) {
+ scsi_dir[x].low_ino = tpnt->low_ino;
+ scsi_dir[x].namelen = strlen(tpnt->procname);
+ scsi_dir[x].name = tpnt->procname;
+ }
+ scsi_dir[x].low_ino = 0;
+ scsi_dir[x].namelen = 0;
+ scsi_dir[x].name = NULL;
+
+ build_proc_dir_hba_entries();
+}
+
+
+/*
+ * parseHandle *parseInit(char *buf, char *cmdList, int cmdNum);
+ * gets a pointer to a null terminated data buffer
+ * and a list of commands with blanks as delimiter
+ * in between.
+ * The commands have to be alphanumerically sorted.
+ * cmdNum has to contain the number of commands.
+ * On success, a pointer to a handle structure
+ * is returned, NULL on failure
+ *
+ * int parseOpt(parseHandle *handle, char **param);
+ * processes the next parameter. On success, the
+ * index of the appropriate command in the cmdList
+ * is returned, starting with zero.
+ * param points to the null terminated parameter string.
+ * On failure, -1 is returned.
+ *
+ * The databuffer buf may only contain pairs of commands
+ * options, separated by blanks:
+ * <Command> <Parameter> [<Command> <Parameter>]*
+ */
+
+typedef struct
+{
+ char *buf, /* command buffer */
+ *cmdList, /* command list */
+ *bufPos, /* actual position */
+ **cmdPos, /* cmdList index */
+ cmdNum; /* cmd number */
+} parseHandle;
+
+
+inline int parseFree (parseHandle *handle) /* free memory */
+{
+ kfree (handle->cmdPos);
+ kfree (handle);
+
+ return(-1);
+}
+
+
+parseHandle *parseInit(char *buf, char *cmdList, int cmdNum)
+{
+ char *ptr; /* temp pointer */
+ parseHandle *handle; /* new handle */
+
+ if (!buf || !cmdList) /* bad input ? */
+ return(NULL);
+ if ((handle = (parseHandle*) kmalloc(sizeof(parseHandle), 1)) == 0)
+ return(NULL); /* out of memory */
+ if ((handle->cmdPos = (char**) kmalloc(sizeof(int), cmdNum)) == 0) {
+ kfree(handle);
+ return(NULL); /* out of memory */
+ }
+
+ handle->buf = handle->bufPos = buf; /* init handle */
+ handle->cmdList = cmdList;
+ handle->cmdNum = cmdNum;
+
+ handle->cmdPos[cmdNum = 0] = cmdList;
+ for (ptr = cmdList; *ptr; ptr++) { /* scan command string */
+ if(*ptr == ' ') { /* and insert zeroes */
+ *ptr++ = 0;
+ handle->cmdPos[++cmdNum] = ptr++;
+ }
+ }
+ return(handle);
+}
+
+
+int parseOpt(parseHandle *handle, char **param)
+{
+ int cmdIndex = 0,
+ cmdLen = 0;
+ char *startPos;
+
+ if (!handle) /* invalid handle */
+ return(parseFree(handle));
+ /* skip spaces */
+ for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
+ if (!*(handle->bufPos))
+ return(parseFree(handle)); /* end of data */
+
+ startPos = handle->bufPos; /* store cmd start */
+ for (; handle->cmdPos[cmdIndex][cmdLen] && *(handle->bufPos); handle->bufPos++)
+ { /* no string end? */
+ for (;;)
+ {
+ if (*(handle->bufPos) == handle->cmdPos[cmdIndex][cmdLen])
+ break; /* char matches ? */
+ else
+ if (memcmp(startPos, (char*)(handle->cmdPos[++cmdIndex]), cmdLen))
+ return(parseFree(handle)); /* unknown command */
+
+ if (cmdIndex >= handle->cmdNum)
+ return(parseFree(handle)); /* unknown command */
+ }
+
+ cmdLen++; /* next char */
+ }
+
+ /* Get param. First skip all blanks, then insert zero after param */
+
+ for (; *(handle->bufPos) && *(handle->bufPos) == ' '; handle->bufPos++);
+ *param = handle->bufPos;
+
+ for (; *(handle->bufPos) && *(handle->bufPos) != ' '; handle->bufPos++);
+ *(handle->bufPos++) = 0;
+
+ return(cmdIndex);
+}
+
+
+/*
+ * Overrides for Emacs so that we get a uniform tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
+ * End:
+ */
/*
* Function : static int partsize(struct buffer_head *bh, unsigned long
- * capacity,unsigned int *cyls, unsigned int *hds, unsigned int secs);
+ * capacity,unsigned int *cyls, unsigned int *hds, unsigned int *secs);
*
* Purpose : to determine the BIOS mapping used to create the partition
* table, storing the results in *cyls, *hds, and *secs
/*
* Function : static int setsize(unsigned long capacity,unsigned int *cyls,
- * unsigned int *hds, unsigned int secs);
+ * unsigned int *hds, unsigned int *secs);
*
* Purpose : to determine a near-optimal int 0x13 mapping for a
* SCSI disk in terms of lost space of size capacity, storing
/*
- * sd.c Copyright (C) 1992 Drew Eckhardt
- * Copyright (C) 1993, 1994, 1995 Eric Youngdale
+ * sd.c Copyright (C) 1992 Drew Eckhardt
+ * Copyright (C) 1993, 1994, 1995 Eric Youngdale
*
- * Linux scsi disk driver
- * Initial versions: Drew Eckhardt
- * Subsequent revisions: Eric Youngdale
+ * Linux scsi disk driver
+ * Initial versions: Drew Eckhardt
+ * Subsequent revisions: Eric Youngdale
*
- * <drew@colorado.edu>
+ * <drew@colorado.edu>
*
* Modified by Eric Youngdale ericy@cais.com to
* add scatter-gather, multiple outstanding request, and other
* enhancements.
*
- * Modified by Eric Youngdale eric@aib.com to support loadable
- * low-level scsi drivers.
+ * Modified by Eric Youngdale eric@aib.com to support loadable
+ * low-level scsi drivers.
*/
#include <linux/fs.h>
#include <linux/genhd.h>
/*
-static const char RCSid[] = "$Header:";
-*/
+ * static const char RCSid[] = "$Header:";
+ */
#define MAX_RETRIES 5
/*
- * Time out in seconds for disks and Magneto-opticals (which are slower).
+ * Time out in seconds for disks and Magneto-opticals (which are slower).
*/
-#define SD_TIMEOUT 600
+#define SD_TIMEOUT 700
#define SD_MOD_TIMEOUT 750
-#define CLUSTERABLE_DEVICE(SC) (SC->host->hostt->use_clustering && \
- SC->device->type != TYPE_MOD)
+#define CLUSTERABLE_DEVICE(SC) (SC->host->use_clustering && \
+ SC->device->type != TYPE_MOD)
struct hd_struct * sd;
int revalidate_scsidisk(int dev, int maxusage);
Scsi_Disk * rscsi_disks = NULL;
static int * sd_sizes;
static int * sd_blocksizes;
-static int * sd_hardsizes; /* Hardware sector size */
+static int * sd_hardsizes; /* Hardware sector size */
extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
static int sd_detect(Scsi_Device *);
static void sd_detach(Scsi_Device *);
-struct Scsi_Device_Template sd_template = {NULL, "disk", "sd", TYPE_DISK,
- SCSI_DISK_MAJOR, 0, 0, 0, 1,
- sd_detect, sd_init,
- sd_finish, sd_attach, sd_detach};
+struct Scsi_Device_Template sd_template =
+{ NULL, "disk", "sd", NULL, TYPE_DISK,
+ SCSI_DISK_MAJOR, 0, 0, 0, 1,
+ sd_detect, sd_init,
+ sd_finish, sd_attach, sd_detach
+};
static int sd_open(struct inode * inode, struct file * filp)
{
- int target;
- target = DEVICE_NR(MINOR(inode->i_rdev));
-
- if(target >= sd_template.dev_max || !rscsi_disks[target].device)
- return -ENXIO; /* No such device */
+ int target;
+ target = DEVICE_NR(MINOR(inode->i_rdev));
+
+ if(target >= sd_template.dev_max || !rscsi_disks[target].device)
+ return -ENXIO; /* No such device */
+
+ /*
+ * Make sure that only one process can do a check_change_disk at one time.
+ * This is also used to lock out further access when the partition table
+ * is being re-read.
+ */
+
+ while (rscsi_disks[target].device->busy)
+ barrier();
+ if(rscsi_disks[target].device->removable) {
+ check_disk_change(inode->i_rdev);
-/* Make sure that only one process can do a check_change_disk at one time.
- This is also used to lock out further access when the partition table is being re-read. */
-
- while (rscsi_disks[target].device->busy)
- barrier();
-
- if(rscsi_disks[target].device->removable) {
- check_disk_change(inode->i_rdev);
-
- if(!rscsi_disks[target].device->access_count)
+ if(!rscsi_disks[target].device->access_count)
sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
- };
- /*
- * See if we are requesting a non-existent partition. Do this
- * after checking for disk change.
- */
- if(sd_sizes[MINOR(inode->i_rdev)] == 0)
- return -ENXIO;
+ };
- rscsi_disks[target].device->access_count++;
- if (rscsi_disks[target].device->host->hostt->usage_count)
- (*rscsi_disks[target].device->host->hostt->usage_count)++;
- return 0;
+ /*
+ * See if we are requesting a non-existent partition. Do this
+ * after checking for disk change.
+ */
+ if(sd_sizes[MINOR(inode->i_rdev)] == 0)
+ return -ENXIO;
+
+ rscsi_disks[target].device->access_count++;
+ if (rscsi_disks[target].device->host->hostt->usage_count)
+ (*rscsi_disks[target].device->host->hostt->usage_count)++;
+ if(sd_template.usage_count) (*sd_template.usage_count)++;
+ return 0;
}
static void sd_release(struct inode * inode, struct file * file)
{
- int target;
- sync_dev(inode->i_rdev);
-
- target = DEVICE_NR(MINOR(inode->i_rdev));
-
- rscsi_disks[target].device->access_count--;
- if (rscsi_disks[target].device->host->hostt->usage_count)
- (*rscsi_disks[target].device->host->hostt->usage_count)--;
-
- if(rscsi_disks[target].device->removable) {
- if(!rscsi_disks[target].device->access_count)
+ int target;
+ sync_dev(inode->i_rdev);
+
+ target = DEVICE_NR(MINOR(inode->i_rdev));
+
+ rscsi_disks[target].device->access_count--;
+ if (rscsi_disks[target].device->host->hostt->usage_count)
+ (*rscsi_disks[target].device->host->hostt->usage_count)--;
+ if(sd_template.usage_count) (*sd_template.usage_count)--;
+
+ if(rscsi_disks[target].device->removable) {
+ if(!rscsi_disks[target].device->access_count)
sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
- };
+ }
}
static void sd_geninit(void);
static struct file_operations sd_fops = {
- NULL, /* lseek - default */
- block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
- NULL, /* readdir - bad */
- NULL, /* select */
- sd_ioctl, /* ioctl */
- NULL, /* mmap */
- sd_open, /* open code */
- sd_release, /* release */
- block_fsync, /* fsync */
- NULL, /* fasync */
- check_scsidisk_media_change, /* Disk change */
- fop_revalidate_scsidisk /* revalidate */
+ NULL, /* lseek - default */
+ block_read, /* read - general block-dev read */
+ block_write, /* write - general block-dev write */
+ NULL, /* readdir - bad */
+ NULL, /* select */
+ sd_ioctl, /* ioctl */
+ NULL, /* mmap */
+ sd_open, /* open code */
+ sd_release, /* release */
+ block_fsync, /* fsync */
+ NULL, /* fasync */
+ check_scsidisk_media_change, /* Disk change */
+ fop_revalidate_scsidisk /* revalidate */
};
static struct gendisk sd_gendisk = {
- MAJOR_NR, /* Major number */
- "sd", /* Major name */
- 4, /* Bits to shift to get real from partition */
- 1 << 4, /* Number of partitions per real */
- 0, /* maximum number of real */
- sd_geninit, /* init function */
- NULL, /* hd struct */
- NULL, /* block sizes */
- 0, /* number */
- NULL, /* internal */
- NULL /* next */
+ MAJOR_NR, /* Major number */
+ "sd", /* Major name */
+ 4, /* Bits to shift to get real from partition */
+ 1 << 4, /* Number of partitions per real */
+ 0, /* maximum number of real */
+ sd_geninit, /* init function */
+ NULL, /* hd struct */
+ NULL, /* block sizes */
+ 0, /* number */
+ NULL, /* internal */
+ NULL /* next */
};
static void sd_geninit (void)
{
- int i;
-
- for (i = 0; i < sd_template.dev_max; ++i)
- if(rscsi_disks[i].device)
+ int i;
+
+ for (i = 0; i < sd_template.dev_max; ++i)
+ if(rscsi_disks[i].device)
sd[i << 4].nr_sects = rscsi_disks[i].capacity;
#if 0
- /* No longer needed - we keep track of this as we attach/detach */
- sd_gendisk.nr_real = sd_template.dev_max;
+ /* No longer needed - we keep track of this as we attach/detach */
+ sd_gendisk.nr_real = sd_template.dev_max;
#endif
}
/*
- rw_intr is the interrupt routine for the device driver. It will
- be notified on the end of a SCSI read / write, and
- will take on of several actions based on success or failure.
-*/
+ * rw_intr is the interrupt routine for the device driver. It will
+ * be notified on the end of a SCSI read / write, and
+ * will take on of several actions based on success or failure.
+ */
static void rw_intr (Scsi_Cmnd *SCpnt)
{
- int result = SCpnt->result;
- int this_count = SCpnt->bufflen >> 9;
-
+ int result = SCpnt->result;
+ int this_count = SCpnt->bufflen >> 9;
+
#ifdef DEBUG
- printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.dev), SCpnt->host->host_no, result);
+ printk("sd%c : rw_intr(%d, %d)\n", 'a' + MINOR(SCpnt->request.dev),
+ SCpnt->host->host_no, result);
#endif
+
+ /*
+ * First case : we assume that the command succeeded. One of two things
+ * will happen here. Either we will be finished, or there will be more
+ * sectors that we were unable to read last time.
+ */
-/*
- First case : we assume that the command succeeded. One of two things will
- happen here. Either we will be finished, or there will be more
- sectors that we were unable to read last time.
-*/
-
- if (!result) {
-
+ if (!result) {
+
#ifdef DEBUG
- printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.dev), SCpnt->request.nr_sectors);
- printk("use_sg is %d\n ",SCpnt->use_sg);
+ printk("sd%c : %d sectors remain.\n", 'a' + MINOR(SCpnt->request.dev),
+ SCpnt->request.nr_sectors);
+ printk("use_sg is %d\n ",SCpnt->use_sg);
#endif
- if (SCpnt->use_sg) {
- struct scatterlist * sgpnt;
- int i;
- sgpnt = (struct scatterlist *) SCpnt->buffer;
- for(i=0; i<SCpnt->use_sg; i++) {
+ if (SCpnt->use_sg) {
+ struct scatterlist * sgpnt;
+ int i;
+ sgpnt = (struct scatterlist *) SCpnt->buffer;
+ for(i=0; i<SCpnt->use_sg; i++) {
#ifdef DEBUG
- printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+ printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address,
+ sgpnt[i].length);
#endif
- if (sgpnt[i].alt_address) {
- if (SCpnt->request.cmd == READ)
- memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
- scsi_free(sgpnt[i].address, sgpnt[i].length);
- };
- };
- scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */
- } else {
- if (SCpnt->buffer != SCpnt->request.buffer) {
+ if (sgpnt[i].alt_address) {
+ if (SCpnt->request.cmd == READ)
+ memcpy(sgpnt[i].alt_address, sgpnt[i].address,
+ sgpnt[i].length);
+ scsi_free(sgpnt[i].address, sgpnt[i].length);
+ };
+ };
+
+ /* Free list of scatter-gather pointers */
+ scsi_free(SCpnt->buffer, SCpnt->sglist_len);
+ } else {
+ if (SCpnt->buffer != SCpnt->request.buffer) {
#ifdef DEBUG
- printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
- SCpnt->bufflen);
-#endif
- if (SCpnt->request.cmd == READ)
- memcpy(SCpnt->request.buffer, SCpnt->buffer,
- SCpnt->bufflen);
- scsi_free(SCpnt->buffer, SCpnt->bufflen);
- };
- };
-/*
- * If multiple sectors are requested in one buffer, then
- * they will have been finished off by the first command. If
- * not, then we have a multi-buffer command.
- */
- if (SCpnt->request.nr_sectors > this_count)
- {
- SCpnt->request.errors = 0;
-
- if (!SCpnt->request.bh)
- {
+ printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+ SCpnt->bufflen);
+#endif
+ if (SCpnt->request.cmd == READ)
+ memcpy(SCpnt->request.buffer, SCpnt->buffer,
+ SCpnt->bufflen);
+ scsi_free(SCpnt->buffer, SCpnt->bufflen);
+ };
+ };
+ /*
+ * If multiple sectors are requested in one buffer, then
+ * they will have been finished off by the first command.
+ * If not, then we have a multi-buffer command.
+ */
+ if (SCpnt->request.nr_sectors > this_count)
+ {
+ SCpnt->request.errors = 0;
+
+ if (!SCpnt->request.bh)
+ {
#ifdef DEBUG
- printk("sd%c : handling page request, no buffer\n",
- 'a' + MINOR(SCpnt->request.dev));
+ printk("sd%c : handling page request, no buffer\n",
+ 'a' + MINOR(SCpnt->request.dev));
#endif
-/*
- The SCpnt->request.nr_sectors field is always done in 512 byte sectors,
- even if this really isn't the case.
-*/
- panic("sd.c: linked page request (%lx %x)",
- SCpnt->request.sector, this_count);
- }
- }
- SCpnt = end_scsi_request(SCpnt, 1, this_count);
- requeue_sd_request(SCpnt);
- return;
- }
-
-/* Free up any indirection buffers we allocated for DMA purposes. */
+ /*
+ * The SCpnt->request.nr_sectors field is always done in
+ * 512 byte sectors, even if this really isn't the case.
+ */
+ panic("sd.c: linked page request (%lx %x)",
+ SCpnt->request.sector, this_count);
+ }
+ }
+ SCpnt = end_scsi_request(SCpnt, 1, this_count);
+ requeue_sd_request(SCpnt);
+ return;
+ }
+
+ /* Free up any indirection buffers we allocated for DMA purposes. */
if (SCpnt->use_sg) {
- struct scatterlist * sgpnt;
- int i;
- sgpnt = (struct scatterlist *) SCpnt->buffer;
- for(i=0; i<SCpnt->use_sg; i++) {
+ struct scatterlist * sgpnt;
+ int i;
+ sgpnt = (struct scatterlist *) SCpnt->buffer;
+ for(i=0; i<SCpnt->use_sg; i++) {
#ifdef DEBUG
- printk("err: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+ printk("err: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
SCpnt->bufflen);
#endif
- if (sgpnt[i].alt_address) {
- scsi_free(sgpnt[i].address, sgpnt[i].length);
+ if (sgpnt[i].alt_address) {
+ scsi_free(sgpnt[i].address, sgpnt[i].length);
+ };
};
- };
- scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */
+ scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */
} else {
#ifdef DEBUG
- printk("nosgerr: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
- SCpnt->bufflen);
+ printk("nosgerr: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer,
+ SCpnt->bufflen);
#endif
- if (SCpnt->buffer != SCpnt->request.buffer)
- scsi_free(SCpnt->buffer, SCpnt->bufflen);
+ if (SCpnt->buffer != SCpnt->request.buffer)
+ scsi_free(SCpnt->buffer, SCpnt->bufflen);
};
+
+ /*
+ * Now, if we were good little boys and girls, Santa left us a request
+ * sense buffer. We can extract information from this, so we
+ * can choose a block to remap, etc.
+ */
-/*
- Now, if we were good little boys and girls, Santa left us a request
- sense buffer. We can extract information from this, so we
- can choose a block to remap, etc.
-*/
-
- if (driver_byte(result) != 0) {
- if (suggestion(result) == SUGGEST_REMAP) {
+ if (driver_byte(result) != 0) {
+ if (suggestion(result) == SUGGEST_REMAP) {
#ifdef REMAP
-/*
- Not yet implemented. A read will fail after being remapped,
- a write will call the strategy routine again.
-*/
+ /*
+ * Not yet implemented. A read will fail after being remapped,
+ * a write will call the strategy routine again.
+ */
if rscsi_disks[DEVICE_NR(SCpnt->request.dev)].remap
- {
+ {
result = 0;
- }
+ }
else
-
#endif
- }
-
- if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
+ }
+
+ if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
- if(rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->removable) {
- /* detected disc change. set a bit and quietly refuse */
- /* further access. */
-
- rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->changed = 1;
- SCpnt = end_scsi_request(SCpnt, 0, this_count);
- requeue_sd_request(SCpnt);
- return;
- }
+ if(rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->removable) {
+ /* detected disc change. set a bit and quietly refuse
+ * further access.
+ */
+ rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->changed = 1;
+ SCpnt = end_scsi_request(SCpnt, 0, this_count);
+ requeue_sd_request(SCpnt);
+ return;
+ }
}
- }
-
-
-/* If we had an ILLEGAL REQUEST returned, then we may have
-performed an unsupported command. The only thing this should be would
-be a ten byte read where only a six byte read was supported. Also,
-on a system where READ CAPACITY failed, we have have read past the end
-of the disk.
-*/
+ }
+
+
+ /* If we had an ILLEGAL REQUEST returned, then we may have
+ * performed an unsupported command. The only thing this should be
+ * would be a ten byte read where only a six byte read was supported.
+ * Also, on a system where READ CAPACITY failed, we have have read
+ * past the end of the disk.
+ */
- if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
+ if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) {
if (rscsi_disks[DEVICE_NR(SCpnt->request.dev)].ten) {
- rscsi_disks[DEVICE_NR(SCpnt->request.dev)].ten = 0;
- requeue_sd_request(SCpnt);
- result = 0;
+ rscsi_disks[DEVICE_NR(SCpnt->request.dev)].ten = 0;
+ requeue_sd_request(SCpnt);
+ result = 0;
} else {
+ /* ???? */
}
- }
- } /* driver byte != 0 */
- if (result) {
- printk("SCSI disk error : host %d id %d lun %d return code = %x\n",
- rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->host->host_no,
- rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->id,
- rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->lun, result);
-
- if (driver_byte(result) & DRIVER_SENSE)
- print_sense("sd", SCpnt);
- SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
- requeue_sd_request(SCpnt);
- return;
}
+ } /* driver byte != 0 */
+ if (result) {
+ printk("SCSI disk error : host %d channel %d id %d lun %d return code = %x\n",
+ rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->host->host_no,
+ rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->channel,
+ rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->id,
+ rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->lun, result);
+
+ if (driver_byte(result) & DRIVER_SENSE)
+ print_sense("sd", SCpnt);
+ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
+ requeue_sd_request(SCpnt);
+ return;
+ }
}
/*
- requeue_sd_request() is the request handler function for the sd driver.
- Its function in life is to take block device requests, and translate
- them to SCSI commands.
-*/
+ * requeue_sd_request() is the request handler function for the sd driver.
+ * Its function in life is to take block device requests, and translate
+ * them to SCSI commands.
+ */
static void do_sd_request (void)
{
- Scsi_Cmnd * SCpnt = NULL;
- struct request * req = NULL;
- unsigned long flags;
- int flag = 0;
-
- save_flags(flags);
- while (1==1){
- cli();
- if (CURRENT != NULL && CURRENT->dev == -1) {
- restore_flags(flags);
- return;
- };
-
- INIT_SCSI_REQUEST;
-
-
-/* We have to be careful here. allocate_device will get a free pointer, but
- there is no guarantee that it is queueable. In normal usage, we want to
- call this, because other types of devices may have the host all tied up,
- and we want to make sure that we have at least one request pending for this
- type of device. We can also come through here while servicing an
- interrupt, because of the need to start another command. If we call
- allocate_device more than once, then the system can wedge if the command
- is not queueable. The request_queueable function is safe because it checks
- to make sure that the host is able to take another command before it returns
- a pointer. */
-
- if (flag++ == 0)
- SCpnt = allocate_device(&CURRENT,
- rscsi_disks[DEVICE_NR(MINOR(CURRENT->dev))].device, 0);
- else SCpnt = NULL;
-
- /*
- * The following restore_flags leads to latency problems. FIXME.
- * Using a "sti()" gets rid of the latency problems but causes
- * race conditions and crashes.
- */
- restore_flags(flags);
+ Scsi_Cmnd * SCpnt = NULL;
+ struct request * req = NULL;
+ unsigned long flags;
+ int flag = 0;
+
+ save_flags(flags);
+ while (1==1){
+ cli();
+ if (CURRENT != NULL && CURRENT->dev == -1) {
+ restore_flags(flags);
+ return;
+ };
+
+ INIT_SCSI_REQUEST;
+
+ /* We have to be careful here. allocate_device will get a free pointer,
+ * but there is no guarantee that it is queueable. In normal usage,
+ * we want to call this, because other types of devices may have the
+ * host all tied up, and we want to make sure that we have at least
+ * one request pending for this type of device. We can also come
+ * through here while servicing an interrupt, because of the need to
+ * start another command. If we call allocate_device more than once,
+ * then the system can wedge if the command is not queueable. The
+ * request_queueable function is safe because it checks to make sure
+ * that the host is able to take another command before it returns
+ * a pointer.
+ */
-/* This is a performance enhancement. We dig down into the request list and
- try and find a queueable request (i.e. device not busy, and host able to
- accept another command. If we find one, then we queue it. This can
- make a big difference on systems with more than one disk drive. We want
- to have the interrupts off when monkeying with the request list, because
- otherwise the kernel might try and slip in a request in between somewhere. */
+ if (flag++ == 0)
+ SCpnt = allocate_device(&CURRENT,
+ rscsi_disks[DEVICE_NR(MINOR(CURRENT->dev))].device, 0);
+ else SCpnt = NULL;
+
+ /*
+ * The following restore_flags leads to latency problems. FIXME.
+ * Using a "sti()" gets rid of the latency problems but causes
+ * race conditions and crashes.
+ */
+ restore_flags(flags);
+
+ /* This is a performance enhancement. We dig down into the request
+ * list and try and find a queueable request (i.e. device not busy,
+ * and host able to accept another command. If we find one, then we
+ * queue it. This can make a big difference on systems with more than
+ * one disk drive. We want to have the interrupts off when monkeying
+ * with the request list, because otherwise the kernel might try and
+ * slip in a request in between somewhere.
+ */
- if (!SCpnt && sd_template.nr_dev > 1){
- struct request *req1;
- req1 = NULL;
- cli();
- req = CURRENT;
- while(req){
- SCpnt = request_queueable(req,
- rscsi_disks[DEVICE_NR(MINOR(req->dev))].device);
- if(SCpnt) break;
- req1 = req;
- req = req->next;
- };
- if (SCpnt && req->dev == -1) {
- if (req == CURRENT)
- CURRENT = CURRENT->next;
- else
- req1->next = req->next;
- };
- restore_flags(flags);
- };
-
- if (!SCpnt) return; /* Could not find anything to do */
-
- /* Queue command */
- requeue_sd_request(SCpnt);
- }; /* While */
+ if (!SCpnt && sd_template.nr_dev > 1){
+ struct request *req1;
+ req1 = NULL;
+ cli();
+ req = CURRENT;
+ while(req){
+ SCpnt = request_queueable(req, rscsi_disks[DEVICE_NR(MINOR(req->dev))].device);
+ if(SCpnt) break;
+ req1 = req;
+ req = req->next;
+ };
+ if (SCpnt && req->dev == -1) {
+ if (req == CURRENT)
+ CURRENT = CURRENT->next;
+ else
+ req1->next = req->next;
+ };
+ restore_flags(flags);
+ };
+
+ if (!SCpnt) return; /* Could not find anything to do */
+
+ /* Queue command */
+ requeue_sd_request(SCpnt);
+ }; /* While */
}
static void requeue_sd_request (Scsi_Cmnd * SCpnt)
{
- int dev, block, this_count;
- unsigned char cmd[10];
- int bounce_size, contiguous;
- int max_sg;
- struct buffer_head * bh, *bhp;
- char * buff, *bounce_buffer;
-
-repeat:
-
- if(!SCpnt || SCpnt->request.dev <= 0) {
- do_sd_request();
- return;
- }
-
- dev = MINOR(SCpnt->request.dev);
- block = SCpnt->request.sector;
- this_count = 0;
-
-#ifdef DEBUG
- printk("Doing sd request, dev = %d, block = %d\n", dev, block);
-#endif
-
- if (dev >= (sd_template.dev_max << 4) ||
- !rscsi_disks[DEVICE_NR(dev)].device ||
- block + SCpnt->request.nr_sectors > sd[dev].nr_sects)
- {
- SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
- goto repeat;
- }
-
- block += sd[dev].start_sect;
- dev = DEVICE_NR(dev);
-
- if (rscsi_disks[dev].device->changed)
- {
-/*
- * quietly refuse to do anything to a changed disc until the changed bit has been reset
- */
- /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
- SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
- goto repeat;
- }
+ int dev, block, this_count;
+ unsigned char cmd[10];
+ int bounce_size, contiguous;
+ int max_sg;
+ struct buffer_head * bh, *bhp;
+ char * buff, *bounce_buffer;
+
+ repeat:
+
+ if(!SCpnt || SCpnt->request.dev <= 0) {
+ do_sd_request();
+ return;
+ }
+
+ dev = MINOR(SCpnt->request.dev);
+ block = SCpnt->request.sector;
+ this_count = 0;
#ifdef DEBUG
- printk("sd%c : real dev = /dev/sd%c, block = %d\n", 'a' + MINOR(SCpnt->request.dev), dev, block);
+ printk("Doing sd request, dev = %d, block = %d\n", dev, block);
#endif
-
+
+ if (dev >= (sd_template.dev_max << 4) ||
+ !rscsi_disks[DEVICE_NR(dev)].device ||
+ block + SCpnt->request.nr_sectors > sd[dev].nr_sects)
+ {
+ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+ goto repeat;
+ }
+
+ block += sd[dev].start_sect;
+ dev = DEVICE_NR(dev);
+
+ if (rscsi_disks[dev].device->changed)
+ {
/*
- * If we have a 1K hardware sectorsize, prevent access to single
- * 512 byte sectors. In theory we could handle this - in fact
- * the scsi cdrom driver must be able to handle this because
- * we typically use 1K blocksizes, and cdroms typically have
- * 2K hardware sectorsizes. Of course, things are simpler
- * with the cdrom, since it is read-only. For performance
- * reasons, the filesystems should be able to handle this
- * and not force the scsi disk driver to use bounce buffers
- * for this.
+ * quietly refuse to do anything to a changed disc until the changed
+ * bit has been reset
*/
- if (rscsi_disks[dev].sector_size == 1024)
- if((block & 1) || (SCpnt->request.nr_sectors & 1)) {
- printk("sd.c:Bad block number requested");
- SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
- goto repeat;
+ /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */
+ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+ goto repeat;
+ }
+
+#ifdef DEBUG
+ printk("sd%c : real dev = /dev/sd%c, block = %d\n",
+ 'a' + MINOR(SCpnt->request.dev), dev, block);
+#endif
+
+ /*
+ * If we have a 1K hardware sectorsize, prevent access to single
+ * 512 byte sectors. In theory we could handle this - in fact
+ * the scsi cdrom driver must be able to handle this because
+ * we typically use 1K blocksizes, and cdroms typically have
+ * 2K hardware sectorsizes. Of course, things are simpler
+ * with the cdrom, since it is read-only. For performance
+ * reasons, the filesystems should be able to handle this
+ * and not force the scsi disk driver to use bounce buffers
+ * for this.
+ */
+ if (rscsi_disks[dev].sector_size == 1024)
+ if((block & 1) || (SCpnt->request.nr_sectors & 1)) {
+ printk("sd.c:Bad block number requested");
+ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+ goto repeat;
}
-
- switch (SCpnt->request.cmd)
- {
- case WRITE :
- if (!rscsi_disks[dev].device->writeable)
- {
- SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
- goto repeat;
- }
- cmd[0] = WRITE_6;
- break;
- case READ :
- cmd[0] = READ_6;
- break;
- default :
- panic ("Unknown sd command %d\n", SCpnt->request.cmd);
- }
-
- SCpnt->this_count = 0;
-
- /* If the host adapter can deal with very large scatter-gather
- requests, it is a waste of time to cluster */
- contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 :1);
- bounce_buffer = NULL;
- bounce_size = (SCpnt->request.nr_sectors << 9);
-
- /* First see if we need a bounce buffer for this request. If we do, make sure
- that we can allocate a buffer. Do not waste space by allocating a bounce
- buffer if we are straddling the 16Mb line */
-
-
- if (contiguous && SCpnt->request.bh &&
- ((long) SCpnt->request.bh->b_data) + (SCpnt->request.nr_sectors << 9) - 1 >
- ISA_DMA_THRESHOLD && SCpnt->host->unchecked_isa_dma) {
- if(((long) SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
+
+ switch (SCpnt->request.cmd)
+ {
+ case WRITE :
+ if (!rscsi_disks[dev].device->writeable)
+ {
+ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+ goto repeat;
+ }
+ cmd[0] = WRITE_6;
+ break;
+ case READ :
+ cmd[0] = READ_6;
+ break;
+ default :
+ panic ("Unknown sd command %d\n", SCpnt->request.cmd);
+ }
+
+ SCpnt->this_count = 0;
+
+ /* If the host adapter can deal with very large scatter-gather
+ * requests, it is a waste of time to cluster
+ */
+ contiguous = (!CLUSTERABLE_DEVICE(SCpnt) ? 0 :1);
+ bounce_buffer = NULL;
+ bounce_size = (SCpnt->request.nr_sectors << 9);
+
+ /* First see if we need a bounce buffer for this request. If we do, make
+ * sure that we can allocate a buffer. Do not waste space by allocating
+ * a bounce buffer if we are straddling the 16Mb line
+ */
+ if (contiguous && SCpnt->request.bh &&
+ ((long) SCpnt->request.bh->b_data)
+ + (SCpnt->request.nr_sectors << 9) - 1 > ISA_DMA_THRESHOLD
+ && SCpnt->host->unchecked_isa_dma) {
+ if(((long) SCpnt->request.bh->b_data) > ISA_DMA_THRESHOLD)
bounce_buffer = (char *) scsi_malloc(bounce_size);
- if(!bounce_buffer) contiguous = 0;
- };
-
- if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext)
- for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp,
- bhp = bhp->b_reqnext) {
+ if(!bounce_buffer) contiguous = 0;
+ };
+
+ if(contiguous && SCpnt->request.bh && SCpnt->request.bh->b_reqnext)
+ for(bh = SCpnt->request.bh, bhp = bh->b_reqnext; bhp; bh = bhp,
+ bhp = bhp->b_reqnext) {
if(!CONTIGUOUS_BUFFERS(bh,bhp)) {
- if(bounce_buffer) scsi_free(bounce_buffer, bounce_size);
- contiguous = 0;
- break;
+ if(bounce_buffer) scsi_free(bounce_buffer, bounce_size);
+ contiguous = 0;
+ break;
}
- };
- if (!SCpnt->request.bh || contiguous) {
-
- /* case of page request (i.e. raw device), or unlinked buffer */
- this_count = SCpnt->request.nr_sectors;
- buff = SCpnt->request.buffer;
- SCpnt->use_sg = 0;
-
- } else if (SCpnt->host->sg_tablesize == 0 ||
- (need_isa_buffer &&
- dma_free_sectors <= 10)) {
-
- /* Case of host adapter that cannot scatter-gather. We also
- come here if we are running low on DMA buffer memory. We set
- a threshold higher than that we would need for this request so
- we leave room for other requests. Even though we would not need
- it all, we need to be conservative, because if we run low enough
- we have no choice but to panic. */
-
- if (SCpnt->host->sg_tablesize != 0 &&
- need_isa_buffer &&
- dma_free_sectors <= 10)
+ };
+ if (!SCpnt->request.bh || contiguous) {
+
+ /* case of page request (i.e. raw device), or unlinked buffer */
+ this_count = SCpnt->request.nr_sectors;
+ buff = SCpnt->request.buffer;
+ SCpnt->use_sg = 0;
+
+ } else if (SCpnt->host->sg_tablesize == 0 ||
+ (need_isa_buffer && dma_free_sectors <= 10)) {
+
+ /* Case of host adapter that cannot scatter-gather. We also
+ * come here if we are running low on DMA buffer memory. We set
+ * a threshold higher than that we would need for this request so
+ * we leave room for other requests. Even though we would not need
+ * it all, we need to be conservative, because if we run low enough
+ * we have no choice but to panic.
+ */
+ if (SCpnt->host->sg_tablesize != 0 &&
+ need_isa_buffer &&
+ dma_free_sectors <= 10)
printk("Warning: SCSI DMA buffer space running low. Using non scatter-gather I/O.\n");
-
- this_count = SCpnt->request.current_nr_sectors;
- buff = SCpnt->request.buffer;
- SCpnt->use_sg = 0;
-
- } else {
-
- /* Scatter-gather capable host adapter */
- struct scatterlist * sgpnt;
- int count, this_count_max;
- int counted;
-
- bh = SCpnt->request.bh;
- this_count = 0;
- this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff);
- count = 0;
- bhp = NULL;
- while(bh) {
+
+ this_count = SCpnt->request.current_nr_sectors;
+ buff = SCpnt->request.buffer;
+ SCpnt->use_sg = 0;
+
+ } else {
+
+ /* Scatter-gather capable host adapter */
+ struct scatterlist * sgpnt;
+ int count, this_count_max;
+ int counted;
+
+ bh = SCpnt->request.bh;
+ this_count = 0;
+ this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff);
+ count = 0;
+ bhp = NULL;
+ while(bh) {
if ((this_count + (bh->b_size >> 9)) > this_count_max) break;
if(!bhp || !CONTIGUOUS_BUFFERS(bhp,bh) ||
!CLUSTERABLE_DEVICE(SCpnt) ||
(SCpnt->host->unchecked_isa_dma &&
- ((unsigned long) bh->b_data-1) == ISA_DMA_THRESHOLD)) {
- if (count < SCpnt->host->sg_tablesize) count++;
- else break;
+ ((unsigned long) bh->b_data-1) == ISA_DMA_THRESHOLD)) {
+ if (count < SCpnt->host->sg_tablesize) count++;
+ else break;
};
this_count += (bh->b_size >> 9);
bhp = bh;
bh = bh->b_reqnext;
- };
+ };
#if 0
- if(SCpnt->host->unchecked_isa_dma &&
- ((unsigned int) SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--;
+ if(SCpnt->host->unchecked_isa_dma &&
+ ((unsigned int) SCpnt->request.bh->b_data-1) == ISA_DMA_THRESHOLD) count--;
#endif
- SCpnt->use_sg = count; /* Number of chains */
- count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes*/
- while( count < (SCpnt->use_sg * sizeof(struct scatterlist)))
+ SCpnt->use_sg = count; /* Number of chains */
+ count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes */
+ while( count < (SCpnt->use_sg * sizeof(struct scatterlist)))
count = count << 1;
- SCpnt->sglist_len = count;
- max_sg = count / sizeof(struct scatterlist);
- if(SCpnt->host->sg_tablesize < max_sg) max_sg = SCpnt->host->sg_tablesize;
- sgpnt = (struct scatterlist * ) scsi_malloc(count);
- memset(sgpnt, 0, count); /* Zero so it is easy to fill */
- if (!sgpnt) {
+ SCpnt->sglist_len = count;
+ max_sg = count / sizeof(struct scatterlist);
+ if(SCpnt->host->sg_tablesize < max_sg)
+ max_sg = SCpnt->host->sg_tablesize;
+ sgpnt = (struct scatterlist * ) scsi_malloc(count);
+ if (!sgpnt) {
printk("Warning - running *really* short on DMA buffers\n");
- SCpnt->use_sg = 0; /* No memory left - bail out */
+ SCpnt->use_sg = 0; /* No memory left - bail out */
this_count = SCpnt->request.current_nr_sectors;
buff = SCpnt->request.buffer;
- } else {
+ } else {
+ memset(sgpnt, 0, count); /* Zero so it is easy to fill, but only
+ * if memory is available
+ */
buff = (char *) sgpnt;
counted = 0;
for(count = 0, bh = SCpnt->request.bh, bhp = bh->b_reqnext;
count < SCpnt->use_sg && bh;
count++, bh = bhp) {
-
- bhp = bh->b_reqnext;
-
- if(!sgpnt[count].address) sgpnt[count].address = bh->b_data;
- sgpnt[count].length += bh->b_size;
- counted += bh->b_size >> 9;
-
- if (((long) sgpnt[count].address) + sgpnt[count].length - 1 >
- ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
- !sgpnt[count].alt_address) {
- sgpnt[count].alt_address = sgpnt[count].address;
- /* We try and avoid exhausting the DMA pool, since it is easier
- to control usage here. In other places we might have a more
- pressing need, and we would be screwed if we ran out */
- if(dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
- sgpnt[count].address = NULL;
- } else {
- sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
- };
-/* If we start running low on DMA buffers, we abort the scatter-gather
- operation, and free all of the memory we have allocated. We want to
- ensure that all scsi operations are able to do at least a non-scatter/gather
- operation */
- if(sgpnt[count].address == NULL){ /* Out of dma memory */
+
+ bhp = bh->b_reqnext;
+
+ if(!sgpnt[count].address) sgpnt[count].address = bh->b_data;
+ sgpnt[count].length += bh->b_size;
+ counted += bh->b_size >> 9;
+
+ if (((long) sgpnt[count].address) + sgpnt[count].length - 1 >
+ ISA_DMA_THRESHOLD && (SCpnt->host->unchecked_isa_dma) &&
+ !sgpnt[count].alt_address) {
+ sgpnt[count].alt_address = sgpnt[count].address;
+ /* We try and avoid exhausting the DMA pool, since it is
+ * easier to control usage here. In other places we might
+ * have a more pressing need, and we would be screwed if
+ * we ran out */
+ if(dma_free_sectors < (sgpnt[count].length >> 9) + 10) {
+ sgpnt[count].address = NULL;
+ } else {
+ sgpnt[count].address =
+ (char *) scsi_malloc(sgpnt[count].length);
+ };
+ /* If we start running low on DMA buffers, we abort the
+ * scatter-gather operation, and free all of the memory
+ * we have allocated. We want to ensure that all scsi
+ * operations are able to do at least a non-scatter/gather
+ * operation */
+ if(sgpnt[count].address == NULL){ /* Out of dma memory */
#if 0
- printk("Warning: Running low on SCSI DMA buffers");
- /* Try switching back to a non scatter-gather operation. */
- while(--count >= 0){
- if(sgpnt[count].alt_address)
- scsi_free(sgpnt[count].address, sgpnt[count].length);
- };
- this_count = SCpnt->request.current_nr_sectors;
- buff = SCpnt->request.buffer;
- SCpnt->use_sg = 0;
- scsi_free(sgpnt, SCpnt->sglist_len);
+ printk("Warning: Running low on SCSI DMA buffers");
+ /* Try switching back to a non s-g operation. */
+ while(--count >= 0){
+ if(sgpnt[count].alt_address)
+ scsi_free(sgpnt[count].address,
+ sgpnt[count].length);
+ };
+ this_count = SCpnt->request.current_nr_sectors;
+ buff = SCpnt->request.buffer;
+ SCpnt->use_sg = 0;
+ scsi_free(sgpnt, SCpnt->sglist_len);
#endif
- SCpnt->use_sg = count;
- this_count = counted -= bh->b_size >> 9;
- break;
- };
-
- };
-
- /* Only cluster buffers if we know that we can supply DMA buffers
- large enough to satisfy the request. Do not cluster a new
- request if this would mean that we suddenly need to start
- using DMA bounce buffers */
- if(bhp && CONTIGUOUS_BUFFERS(bh,bhp) && CLUSTERABLE_DEVICE(SCpnt)) {
- char * tmp;
-
- if (((long) sgpnt[count].address) + sgpnt[count].length +
- bhp->b_size - 1 > ISA_DMA_THRESHOLD &&
- (SCpnt->host->unchecked_isa_dma) &&
- !sgpnt[count].alt_address) continue;
-
- if(!sgpnt[count].alt_address) {count--; continue; }
- if(dma_free_sectors > 10)
- tmp = (char *) scsi_malloc(sgpnt[count].length + bhp->b_size);
- else {
- tmp = NULL;
- max_sg = SCpnt->use_sg;
- };
- if(tmp){
- scsi_free(sgpnt[count].address, sgpnt[count].length);
- sgpnt[count].address = tmp;
- count--;
- continue;
+ SCpnt->use_sg = count;
+ this_count = counted -= bh->b_size >> 9;
+ break;
+ };
+
};
-
- /* If we are allowed another sg chain, then increment counter so we
- can insert it. Otherwise we will end up truncating */
-
- if (SCpnt->use_sg < max_sg) SCpnt->use_sg++;
- }; /* contiguous buffers */
+
+ /* Only cluster buffers if we know that we can supply DMA
+ * buffers large enough to satisfy the request. Do not cluster
+ * a new request if this would mean that we suddenly need to
+ * start using DMA bounce buffers */
+ if(bhp && CONTIGUOUS_BUFFERS(bh,bhp)
+ && CLUSTERABLE_DEVICE(SCpnt)) {
+ char * tmp;
+
+ if (((long) sgpnt[count].address) + sgpnt[count].length +
+ bhp->b_size - 1 > ISA_DMA_THRESHOLD &&
+ (SCpnt->host->unchecked_isa_dma) &&
+ !sgpnt[count].alt_address) continue;
+
+ if(!sgpnt[count].alt_address) {count--; continue; }
+ if(dma_free_sectors > 10)
+ tmp = (char *) scsi_malloc(sgpnt[count].length
+ + bhp->b_size);
+ else {
+ tmp = NULL;
+ max_sg = SCpnt->use_sg;
+ };
+ if(tmp){
+ scsi_free(sgpnt[count].address, sgpnt[count].length);
+ sgpnt[count].address = tmp;
+ count--;
+ continue;
+ };
+
+ /* If we are allowed another sg chain, then increment
+ * counter so we can insert it. Otherwise we will end
+ up truncating */
+
+ if (SCpnt->use_sg < max_sg) SCpnt->use_sg++;
+ }; /* contiguous buffers */
}; /* for loop */
-
- this_count = counted; /* This is actually how many we are going to transfer */
-
- if(count < SCpnt->use_sg || SCpnt->use_sg > SCpnt->host->sg_tablesize){
- bh = SCpnt->request.bh;
- printk("Use sg, count %d %x %d\n", SCpnt->use_sg, count, dma_free_sectors);
- printk("maxsg = %x, counted = %d this_count = %d\n", max_sg, counted, this_count);
- while(bh){
- printk("[%p %lx] ", bh->b_data, bh->b_size);
- bh = bh->b_reqnext;
- };
- if(SCpnt->use_sg < 16)
- for(count=0; count<SCpnt->use_sg; count++)
- printk("{%d:%p %p %d} ", count,
- sgpnt[count].address,
- sgpnt[count].alt_address,
- sgpnt[count].length);
- panic("Ooops");
+
+ /* This is actually how many we are going to transfer */
+ this_count = counted;
+
+ if(count < SCpnt->use_sg || SCpnt->use_sg
+ > SCpnt->host->sg_tablesize){
+ bh = SCpnt->request.bh;
+ printk("Use sg, count %d %x %d\n",
+ SCpnt->use_sg, count, dma_free_sectors);
+ printk("maxsg = %x, counted = %d this_count = %d\n",
+ max_sg, counted, this_count);
+ while(bh){
+ printk("[%p %lx] ", bh->b_data, bh->b_size);
+ bh = bh->b_reqnext;
+ };
+ if(SCpnt->use_sg < 16)
+ for(count=0; count<SCpnt->use_sg; count++)
+ printk("{%d:%p %p %d} ", count,
+ sgpnt[count].address,
+ sgpnt[count].alt_address,
+ sgpnt[count].length);
+ panic("Ooops");
};
-
+
if (SCpnt->request.cmd == WRITE)
- for(count=0; count<SCpnt->use_sg; count++)
- if(sgpnt[count].alt_address)
- memcpy(sgpnt[count].address, sgpnt[count].alt_address,
- sgpnt[count].length);
- }; /* Able to malloc sgpnt */
- }; /* Host adapter capable of scatter-gather */
-
-/* Now handle the possibility of DMA to addresses > 16Mb */
-
- if(SCpnt->use_sg == 0){
- if (((long) buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD &&
+ for(count=0; count<SCpnt->use_sg; count++)
+ if(sgpnt[count].alt_address)
+ memcpy(sgpnt[count].address, sgpnt[count].alt_address,
+ sgpnt[count].length);
+ }; /* Able to malloc sgpnt */
+ }; /* Host adapter capable of scatter-gather */
+
+ /* Now handle the possibility of DMA to addresses > 16Mb */
+
+ if(SCpnt->use_sg == 0){
+ if (((long) buff) + (this_count << 9) - 1 > ISA_DMA_THRESHOLD &&
(SCpnt->host->unchecked_isa_dma)) {
if(bounce_buffer)
- buff = bounce_buffer;
+ buff = bounce_buffer;
else
- buff = (char *) scsi_malloc(this_count << 9);
+ buff = (char *) scsi_malloc(this_count << 9);
if(buff == NULL) { /* Try backing off a bit if we are low on mem*/
- this_count = SCpnt->request.current_nr_sectors;
- buff = (char *) scsi_malloc(this_count << 9);
- if(!buff) panic("Ran out of DMA buffers.");
+ this_count = SCpnt->request.current_nr_sectors;
+ buff = (char *) scsi_malloc(this_count << 9);
+ if(!buff) panic("Ran out of DMA buffers.");
};
if (SCpnt->request.cmd == WRITE)
- memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
- };
+ memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9);
};
+ };
#ifdef DEBUG
- printk("sd%c : %s %d/%d 512 byte blocks.\n", 'a' + MINOR(SCpnt->request.dev),
- (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
- this_count, SCpnt->request.nr_sectors);
+ printk("sd%c : %s %d/%d 512 byte blocks.\n",
+ 'a' + MINOR(SCpnt->request.dev),
+ (SCpnt->request.cmd == WRITE) ? "writing" : "reading",
+ this_count, SCpnt->request.nr_sectors);
#endif
-
- cmd[1] = (SCpnt->lun << 5) & 0xe0;
-
- if (rscsi_disks[dev].sector_size == 1024){
- if(block & 1) panic("sd.c:Bad block number requested");
- if(this_count & 1) panic("sd.c:Bad block number requested");
- block = block >> 1;
- this_count = this_count >> 1;
- };
-
- if (rscsi_disks[dev].sector_size == 256){
- block = block << 1;
- this_count = this_count << 1;
- };
-
- if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten)
- {
- if (this_count > 0xffff)
- this_count = 0xffff;
-
- cmd[0] += READ_10 - READ_6 ;
- cmd[2] = (unsigned char) (block >> 24) & 0xff;
- cmd[3] = (unsigned char) (block >> 16) & 0xff;
- cmd[4] = (unsigned char) (block >> 8) & 0xff;
- cmd[5] = (unsigned char) block & 0xff;
- cmd[6] = cmd[9] = 0;
- cmd[7] = (unsigned char) (this_count >> 8) & 0xff;
- cmd[8] = (unsigned char) this_count & 0xff;
- }
- else
- {
- if (this_count > 0xff)
- this_count = 0xff;
-
- cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
- cmd[2] = (unsigned char) ((block >> 8) & 0xff);
- cmd[3] = (unsigned char) block & 0xff;
- cmd[4] = (unsigned char) this_count;
- cmd[5] = 0;
- }
-
-/*
- * We shouldn't disconnect in the middle of a sector, so with a dumb
- * host adapter, it's safe to assume that we can at least transfer
- * this many bytes between each connect / disconnect.
- */
-
- SCpnt->transfersize = rscsi_disks[dev].sector_size;
- SCpnt->underflow = this_count << 9;
- scsi_do_cmd (SCpnt, (void *) cmd, buff,
- this_count * rscsi_disks[dev].sector_size,
- rw_intr,
- (SCpnt->device->type == TYPE_DISK ?
- SD_TIMEOUT : SD_MOD_TIMEOUT),
- MAX_RETRIES);
+
+ cmd[1] = (SCpnt->lun << 5) & 0xe0;
+
+ if (rscsi_disks[dev].sector_size == 1024){
+ if(block & 1) panic("sd.c:Bad block number requested");
+ if(this_count & 1) panic("sd.c:Bad block number requested");
+ block = block >> 1;
+ this_count = this_count >> 1;
+ };
+
+ if (rscsi_disks[dev].sector_size == 256){
+ block = block << 1;
+ this_count = this_count << 1;
+ };
+
+ if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten)
+ {
+ if (this_count > 0xffff)
+ this_count = 0xffff;
+
+ cmd[0] += READ_10 - READ_6 ;
+ cmd[2] = (unsigned char) (block >> 24) & 0xff;
+ cmd[3] = (unsigned char) (block >> 16) & 0xff;
+ cmd[4] = (unsigned char) (block >> 8) & 0xff;
+ cmd[5] = (unsigned char) block & 0xff;
+ cmd[6] = cmd[9] = 0;
+ cmd[7] = (unsigned char) (this_count >> 8) & 0xff;
+ cmd[8] = (unsigned char) this_count & 0xff;
+ }
+ else
+ {
+ if (this_count > 0xff)
+ this_count = 0xff;
+
+ cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+ cmd[2] = (unsigned char) ((block >> 8) & 0xff);
+ cmd[3] = (unsigned char) block & 0xff;
+ cmd[4] = (unsigned char) this_count;
+ cmd[5] = 0;
+ }
+
+ /*
+ * We shouldn't disconnect in the middle of a sector, so with a dumb
+ * host adapter, it's safe to assume that we can at least transfer
+ * this many bytes between each connect / disconnect.
+ */
+
+ SCpnt->transfersize = rscsi_disks[dev].sector_size;
+ SCpnt->underflow = this_count << 9;
+ scsi_do_cmd (SCpnt, (void *) cmd, buff,
+ this_count * rscsi_disks[dev].sector_size,
+ rw_intr,
+ (SCpnt->device->type == TYPE_DISK ?
+ SD_TIMEOUT : SD_MOD_TIMEOUT),
+ MAX_RETRIES);
}
static int check_scsidisk_media_change(dev_t full_dev){
- int retval;
- int target;
- struct inode inode;
- int flag = 0;
-
- target = DEVICE_NR(MINOR(full_dev));
-
- if (target >= sd_template.dev_max ||
- !rscsi_disks[target].device) {
- printk("SCSI disk request error: invalid device.\n");
- return 0;
- };
-
- if(!rscsi_disks[target].device->removable) return 0;
-
- inode.i_rdev = full_dev; /* This is all we really need here */
- retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
-
- if(retval){ /* Unable to test, unit probably not ready. This usually
- means there is no disc in the drive. Mark as changed,
- and we will figure it out later once the drive is
- available again. */
-
- rscsi_disks[target].device->changed = 1;
- return 1; /* This will force a flush, if called from
- check_disk_change */
- };
-
- retval = rscsi_disks[target].device->changed;
- if(!flag) rscsi_disks[target].device->changed = 0;
- return retval;
+ int retval;
+ int target;
+ struct inode inode;
+ int flag = 0;
+
+ target = DEVICE_NR(MINOR(full_dev));
+
+ if (target >= sd_template.dev_max ||
+ !rscsi_disks[target].device) {
+ printk("SCSI disk request error: invalid device.\n");
+ return 0;
+ };
+
+ if(!rscsi_disks[target].device->removable) return 0;
+
+ inode.i_rdev = full_dev; /* This is all we really need here */
+ retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
+
+ if(retval){ /* Unable to test, unit probably not ready. This usually
+ * means there is no disc in the drive. Mark as changed,
+ * and we will figure it out later once the drive is
+ * available again. */
+
+ rscsi_disks[target].device->changed = 1;
+ return 1; /* This will force a flush, if called from
+ * check_disk_change */
+ };
+
+ retval = rscsi_disks[target].device->changed;
+ if(!flag) rscsi_disks[target].device->changed = 0;
+ return retval;
}
static void sd_init_done (Scsi_Cmnd * SCpnt)
{
- struct request * req;
-
- req = &SCpnt->request;
- req->dev = 0xfffe; /* Busy, but indicate request done */
-
- if (req->sem != NULL) {
- up(req->sem);
- }
+ struct request * req;
+
+ req = &SCpnt->request;
+ req->dev = 0xfffe; /* Busy, but indicate request done */
+
+ if (req->sem != NULL) {
+ up(req->sem);
+ }
}
static int sd_init_onedisk(int i)
{
- unsigned char cmd[10];
- unsigned char *buffer;
- unsigned long spintime;
- int the_result, retries;
- Scsi_Cmnd * SCpnt;
-
- /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is considered
- a fatal error, and many devices report such an error just after a scsi
- bus reset. */
-
- SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1);
- buffer = (unsigned char *) scsi_malloc(512);
-
- spintime = 0;
-
- /* Spin up drives, as required. Only do this at boot time */
- if (current == task[0]){
- do{
- cmd[0] = TEST_UNIT_READY;
- cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
- memset ((void *) &cmd[2], 0, 8);
- SCpnt->request.dev = 0xffff; /* Mark as really busy again */
- SCpnt->cmd_len = 0;
- SCpnt->sense_buffer[0] = 0;
- SCpnt->sense_buffer[2] = 0;
-
- scsi_do_cmd (SCpnt,
- (void *) cmd, (void *) buffer,
- 512, sd_init_done, SD_TIMEOUT,
- MAX_RETRIES);
-
- while(SCpnt->request.dev != 0xfffe) barrier();
-
- the_result = SCpnt->result;
-
- /* Look for non-removable devices that return NOT_READY. Issue command
- to spin up drive for these cases. */
- if(the_result && !rscsi_disks[i].device->removable &&
- SCpnt->sense_buffer[2] == NOT_READY) {
- int time1;
- if(!spintime){
- printk( "sd%c: Spinning up disk...", 'a' + i );
- cmd[0] = START_STOP;
- cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
- cmd[1] |= 1; /* Return immediately */
- memset ((void *) &cmd[2], 0, 8);
- cmd[4] = 1; /* Start spin cycle */
- SCpnt->request.dev = 0xffff; /* Mark as really busy again */
- SCpnt->cmd_len = 0;
- SCpnt->sense_buffer[0] = 0;
- SCpnt->sense_buffer[2] = 0;
-
- scsi_do_cmd (SCpnt,
- (void *) cmd, (void *) buffer,
- 512, sd_init_done, SD_TIMEOUT,
- MAX_RETRIES);
-
- while(SCpnt->request.dev != 0xfffe) barrier();
-
- spintime = jiffies;
- };
-
- time1 = jiffies;
- while(jiffies < time1 + HZ); /* Wait 1 second for next try */
- printk( "." );
- };
- } while(the_result && spintime && spintime+100*HZ > jiffies);
- if (spintime) {
- if (the_result)
- printk( "not responding...\n" );
- else
- printk( "ready\n" );
- }
- }; /* current == task[0] */
-
-
- retries = 3;
- do {
- cmd[0] = READ_CAPACITY;
- cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
- memset ((void *) &cmd[2], 0, 8);
- memset ((void *) buffer, 0, 8);
- SCpnt->request.dev = 0xffff; /* Mark as really busy again */
- SCpnt->cmd_len = 0;
- SCpnt->sense_buffer[0] = 0;
- SCpnt->sense_buffer[2] = 0;
-
- scsi_do_cmd (SCpnt,
- (void *) cmd, (void *) buffer,
- 8, sd_init_done, SD_TIMEOUT,
- MAX_RETRIES);
+ unsigned char cmd[10];
+ unsigned char *buffer;
+ unsigned long spintime;
+ int the_result, retries;
+ Scsi_Cmnd * SCpnt;
- if (current == task[0])
- while(SCpnt->request.dev != 0xfffe) barrier();
- else
- if (SCpnt->request.dev != 0xfffe){
- struct semaphore sem = MUTEX_LOCKED;
- SCpnt->request.sem = &sem;
- down(&sem);
- /* Hmm.. Have to ask about this one.. */
- while (SCpnt->request.dev != 0xfffe) schedule();
- };
-
- the_result = SCpnt->result;
- retries--;
-
- } while(the_result && retries);
-
- SCpnt->request.dev = -1; /* Mark as not busy */
-
- wake_up(&SCpnt->device->device_wait);
-
- /* Wake up a process waiting for device*/
-
- /*
- * The SCSI standard says "READ CAPACITY is necessary for self configuring software"
- * While not mandatory, support of READ CAPACITY is strongly encouraged.
- * We used to die if we couldn't successfully do a READ CAPACITY.
- * But, now we go on about our way. The side effects of this are
- *
- * 1. We can't know block size with certainty. I have said "512 bytes is it"
- * as this is most common.
- *
- * 2. Recovery from when some one attempts to read past the end of the raw device will
- * be slower.
- */
-
- if (the_result)
+ /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is
+ * considered a fatal error, and many devices report such an error
+ * just after a scsi bus reset. */
+
+ SCpnt = allocate_device(NULL, rscsi_disks[i].device, 1);
+ buffer = (unsigned char *) scsi_malloc(512);
+
+ spintime = 0;
+
+ /* Spin up drives, as required. Only do this at boot time */
+ if (current->pid == 0){
+ do{
+ retries = 0;
+ while(retries < 3)
+ {
+ cmd[0] = TEST_UNIT_READY;
+ cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+ memset ((void *) &cmd[2], 0, 8);
+ SCpnt->request.dev = 0xffff; /* Mark as really busy again */
+ SCpnt->cmd_len = 0;
+ SCpnt->sense_buffer[0] = 0;
+ SCpnt->sense_buffer[2] = 0;
+
+ scsi_do_cmd (SCpnt,
+ (void *) cmd, (void *) buffer,
+ 512, sd_init_done, SD_TIMEOUT,
+ MAX_RETRIES);
+
+ while(SCpnt->request.dev != 0xfffe) barrier();
+
+ the_result = SCpnt->result;
+ retries++;
+ if( the_result == 0
+ || SCpnt->sense_buffer[2] != UNIT_ATTENTION)
+ break;
+ }
+
+ /* Look for non-removable devices that return NOT_READY.
+ * Issue command to spin up drive for these cases. */
+ if(the_result && !rscsi_disks[i].device->removable &&
+ SCpnt->sense_buffer[2] == NOT_READY) {
+ int time1;
+ if(!spintime){
+ printk( "sd%c: Spinning up disk...", 'a' + i );
+ cmd[0] = START_STOP;
+ cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+ cmd[1] |= 1; /* Return immediately */
+ memset ((void *) &cmd[2], 0, 8);
+ cmd[4] = 1; /* Start spin cycle */
+ /* Mark as really busy again */
+ SCpnt->request.dev = 0xffff;
+ SCpnt->cmd_len = 0;
+ SCpnt->sense_buffer[0] = 0;
+ SCpnt->sense_buffer[2] = 0;
+
+ scsi_do_cmd (SCpnt,
+ (void *) cmd, (void *) buffer,
+ 512, sd_init_done, SD_TIMEOUT,
+ MAX_RETRIES);
+
+ while(SCpnt->request.dev != 0xfffe)
+ barrier();
+
+ spintime = jiffies;
+ };
+
+ time1 = jiffies;
+ while(jiffies < time1 + HZ); /* Wait 1 second for next try */
+ printk( "." );
+ };
+ } while(the_result && spintime && spintime+100*HZ > jiffies);
+ if (spintime) {
+ if (the_result)
+ printk( "not responding...\n" );
+ else
+ printk( "ready\n" );
+ }
+ }; /* current->pid == 0 */
+
+
+ retries = 3;
+ do {
+ cmd[0] = READ_CAPACITY;
+ cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0;
+ memset ((void *) &cmd[2], 0, 8);
+ memset ((void *) buffer, 0, 8);
+ SCpnt->request.dev = 0xffff; /* Mark as really busy again */
+ SCpnt->cmd_len = 0;
+ SCpnt->sense_buffer[0] = 0;
+ SCpnt->sense_buffer[2] = 0;
+
+ scsi_do_cmd (SCpnt,
+ (void *) cmd, (void *) buffer,
+ 8, sd_init_done, SD_TIMEOUT,
+ MAX_RETRIES);
+
+ if (current->pid == 0)
+ while(SCpnt->request.dev != 0xfffe)
+ barrier();
+ else
+ if (SCpnt->request.dev != 0xfffe){
+ struct semaphore sem = MUTEX_LOCKED;
+ SCpnt->request.sem = &sem;
+ down(&sem);
+ /* Hmm.. Have to ask about this one.. */
+ while (SCpnt->request.dev != 0xfffe)
+ schedule();
+ };
+
+ the_result = SCpnt->result;
+ retries--;
+
+ } while(the_result && retries);
+
+ SCpnt->request.dev = -1; /* Mark as not busy */
+
+ wake_up(&SCpnt->device->device_wait);
+
+ /* Wake up a process waiting for device */
+
+ /*
+ * The SCSI standard says:
+ * "READ CAPACITY is necessary for self configuring software"
+ * While not mandatory, support of READ CAPACITY is strongly encouraged.
+ * We used to die if we couldn't successfully do a READ CAPACITY.
+ * But, now we go on about our way. The side effects of this are
+ *
+ * 1. We can't know block size with certainty. I have said "512 bytes
+ * is it" as this is most common.
+ *
+ * 2. Recovery from when some one attempts to read past the end of the
+ * raw device will be slower.
+ */
+
+ if (the_result)
{
- printk ("sd%c : READ CAPACITY failed.\n"
- "sd%c : status = %x, message = %02x, host = %d, driver = %02x \n",
- 'a' + i, 'a' + i,
- status_byte(the_result),
- msg_byte(the_result),
- host_byte(the_result),
- driver_byte(the_result)
- );
- if (driver_byte(the_result) & DRIVER_SENSE)
- printk("sd%c : extended sense code = %1x \n", 'a' + i, SCpnt->sense_buffer[2] & 0xf);
- else
- printk("sd%c : sense not available. \n", 'a' + i);
-
- printk("sd%c : block size assumed to be 512 bytes, disk size 1GB. \n", 'a' + i);
- rscsi_disks[i].capacity = 0x1fffff;
- rscsi_disks[i].sector_size = 512;
-
- /* Set dirty bit for removable devices if not ready - sometimes drives
- will not report this properly. */
- if(rscsi_disks[i].device->removable &&
- SCpnt->sense_buffer[2] == NOT_READY)
- rscsi_disks[i].device->changed = 1;
-
+ printk ("sd%c : READ CAPACITY failed.\n"
+ "sd%c : status = %x, message = %02x, host = %d, driver = %02x \n",
+ 'a' + i, 'a' + i,
+ status_byte(the_result),
+ msg_byte(the_result),
+ host_byte(the_result),
+ driver_byte(the_result)
+ );
+ if (driver_byte(the_result) & DRIVER_SENSE)
+ printk("sd%c : extended sense code = %1x \n",
+ 'a' + i, SCpnt->sense_buffer[2] & 0xf);
+ else
+ printk("sd%c : sense not available. \n", 'a' + i);
+
+ printk("sd%c : block size assumed to be 512 bytes, disk size 1GB. \n",
+ 'a' + i);
+ rscsi_disks[i].capacity = 0x1fffff;
+ rscsi_disks[i].sector_size = 512;
+
+ /* Set dirty bit for removable devices if not ready - sometimes drives
+ * will not report this properly. */
+ if(rscsi_disks[i].device->removable &&
+ SCpnt->sense_buffer[2] == NOT_READY)
+ rscsi_disks[i].device->changed = 1;
+
}
- else
+ else
{
- rscsi_disks[i].capacity = (buffer[0] << 24) |
- (buffer[1] << 16) |
- (buffer[2] << 8) |
- buffer[3];
-
- rscsi_disks[i].sector_size = (buffer[4] << 24) |
- (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
-
- if (rscsi_disks[i].sector_size != 512 &&
- rscsi_disks[i].sector_size != 1024 &&
- rscsi_disks[i].sector_size != 256)
+ rscsi_disks[i].capacity = (buffer[0] << 24) |
+ (buffer[1] << 16) |
+ (buffer[2] << 8) |
+ buffer[3];
+
+ rscsi_disks[i].sector_size = (buffer[4] << 24) |
+ (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
+
+ if (rscsi_disks[i].sector_size != 512 &&
+ rscsi_disks[i].sector_size != 1024 &&
+ rscsi_disks[i].sector_size != 256)
{
- printk ("sd%c : unsupported sector size %d.\n",
- 'a' + i, rscsi_disks[i].sector_size);
- if(rscsi_disks[i].device->removable){
- rscsi_disks[i].capacity = 0;
- } else {
- printk ("scsi : deleting disk entry.\n");
- rscsi_disks[i].device = NULL;
- sd_template.nr_dev--;
- return i;
- };
+ printk ("sd%c : unsupported sector size %d.\n",
+ 'a' + i, rscsi_disks[i].sector_size);
+ if(rscsi_disks[i].device->removable){
+ rscsi_disks[i].capacity = 0;
+ } else {
+ printk ("scsi : deleting disk entry.\n");
+ rscsi_disks[i].device = NULL;
+ sd_template.nr_dev--;
+ return i;
+ };
}
{
- /*
- The msdos fs need to know the hardware sector size
- So I have created this table. See ll_rw_blk.c
- Jacques Gelinas (Jacques@solucorp.qc.ca)
- */
- int m;
- int hard_sector = rscsi_disks[i].sector_size;
- /* There is 16 minor allocated for each devices */
- for (m=i<<4; m<((i+1)<<4); m++){
- sd_hardsizes[m] = hard_sector;
- }
- printk ("SCSI Hardware sector size is %d bytes on device sd%c\n"
- ,hard_sector,i+'a');
+ /*
+ * The msdos fs need to know the hardware sector size
+ * So I have created this table. See ll_rw_blk.c
+ * Jacques Gelinas (Jacques@solucorp.qc.ca)
+ */
+ int m;
+ int hard_sector = rscsi_disks[i].sector_size;
+ /* There is 16 minor allocated for each devices */
+ for (m=i<<4; m<((i+1)<<4); m++){
+ sd_hardsizes[m] = hard_sector;
+ }
+ printk ("SCSI Hardware sector size is %d bytes on device sd%c\n",
+ hard_sector,i+'a');
}
- if(rscsi_disks[i].sector_size == 1024)
- rscsi_disks[i].capacity <<= 1; /* Change this into 512 byte sectors */
- if(rscsi_disks[i].sector_size == 256)
- rscsi_disks[i].capacity >>= 1; /* Change this into 512 byte sectors */
+ if(rscsi_disks[i].sector_size == 1024)
+ rscsi_disks[i].capacity <<= 1; /* Change into 512 byte sectors */
+ if(rscsi_disks[i].sector_size == 256)
+ rscsi_disks[i].capacity >>= 1; /* Change into 512 byte sectors */
}
-
- rscsi_disks[i].ten = 1;
- rscsi_disks[i].remap = 1;
- scsi_free(buffer, 512);
- return i;
+
+ rscsi_disks[i].ten = 1;
+ rscsi_disks[i].remap = 1;
+ scsi_free(buffer, 512);
+ return i;
}
/*
- The sd_init() function looks at all SCSI drives present, determines
- their size, and reads partition table entries for them.
-*/
+ * The sd_init() function looks at all SCSI drives present, determines
+ * their size, and reads partition table entries for them.
+ */
static void sd_init()
{
- int i;
- static int sd_registered = 0;
-
- if (sd_template.dev_noticed == 0) return;
-
- if(!sd_registered) {
+ int i;
+ static int sd_registered = 0;
+
+ if (sd_template.dev_noticed == 0) return;
+
+ if(!sd_registered) {
if (register_blkdev(MAJOR_NR,"sd",&sd_fops)) {
- printk("Unable to get major %d for SCSI disk\n",MAJOR_NR);
- return;
+ printk("Unable to get major %d for SCSI disk\n",MAJOR_NR);
+ return;
}
sd_registered++;
- }
-
- /* We do not support attaching loadable devices yet. */
- if(rscsi_disks) return;
-
- sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
-
- rscsi_disks = (Scsi_Disk *)
- scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
- memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
-
- sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
+ }
+
+ /* We do not support attaching loadable devices yet. */
+ if(rscsi_disks) return;
+
+ sd_template.dev_max = sd_template.dev_noticed + SD_EXTRA_DEVS;
+
+ rscsi_disks = (Scsi_Disk *)
+ scsi_init_malloc(sd_template.dev_max * sizeof(Scsi_Disk), GFP_ATOMIC);
+ memset(rscsi_disks, 0, sd_template.dev_max * sizeof(Scsi_Disk));
+
+ sd_sizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
+ sizeof(int), GFP_ATOMIC);
+ memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
+
+ sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
+ sizeof(int), GFP_ATOMIC);
+
+ sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
sizeof(int), GFP_ATOMIC);
- memset(sd_sizes, 0, (sd_template.dev_max << 4) * sizeof(int));
-
- sd_blocksizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
- sizeof(int), GFP_ATOMIC);
-
- sd_hardsizes = (int *) scsi_init_malloc((sd_template.dev_max << 4) *
- sizeof(struct hd_struct), GFP_ATOMIC);
-
- for(i=0;i<(sd_template.dev_max << 4);i++){
- sd_blocksizes[i] = 1024;
- sd_hardsizes[i] = 512;
- }
- blksize_size[MAJOR_NR] = sd_blocksizes;
- hardsect_size[MAJOR_NR] = sd_hardsizes;
- sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
- sizeof(struct hd_struct),
- GFP_ATOMIC);
-
-
- sd_gendisk.max_nr = sd_template.dev_max;
- sd_gendisk.part = sd;
- sd_gendisk.sizes = sd_sizes;
- sd_gendisk.real_devices = (void *) rscsi_disks;
-
+
+ for(i=0;i<(sd_template.dev_max << 4);i++){
+ sd_blocksizes[i] = 1024;
+ sd_hardsizes[i] = 512;
+ }
+ blksize_size[MAJOR_NR] = sd_blocksizes;
+ hardsect_size[MAJOR_NR] = sd_hardsizes;
+ sd = (struct hd_struct *) scsi_init_malloc((sd_template.dev_max << 4) *
+ sizeof(struct hd_struct),
+ GFP_ATOMIC);
+
+
+ sd_gendisk.max_nr = sd_template.dev_max;
+ sd_gendisk.part = sd;
+ sd_gendisk.sizes = sd_sizes;
+ sd_gendisk.real_devices = (void *) rscsi_disks;
+
}
static void sd_finish()
{
- int i;
-
- blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-
- sd_gendisk.next = gendisk_head;
- gendisk_head = &sd_gendisk;
-
- for (i = 0; i < sd_template.dev_max; ++i)
- if (!rscsi_disks[i].capacity &&
- rscsi_disks[i].device)
- {
- i = sd_init_onedisk(i);
- if (scsi_loadable_module_flag
- && !rscsi_disks[i].has_part_table) {
- sd_sizes[i << 4] = rscsi_disks[i].capacity;
- revalidate_scsidisk(i << 4, 0);
- }
- rscsi_disks[i].has_part_table = 1;
- }
-
- /* If our host adapter is capable of scatter-gather, then we increase
- the read-ahead to 16 blocks (32 sectors). If not, we use
- a two block (4 sector) read ahead. */
- if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize)
- read_ahead[MAJOR_NR] = 120;
- /* 64 sector read-ahead */
- else
- read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
-
- return;
+ int i;
+
+ blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+
+ sd_gendisk.next = gendisk_head;
+ gendisk_head = &sd_gendisk;
+
+ for (i = 0; i < sd_template.dev_max; ++i)
+ if (!rscsi_disks[i].capacity &&
+ rscsi_disks[i].device)
+ {
+ i = sd_init_onedisk(i);
+ if (scsi_loadable_module_flag
+ && !rscsi_disks[i].has_part_table) {
+ sd_sizes[i << 4] = rscsi_disks[i].capacity;
+ revalidate_scsidisk(i << 4, 0);
+ }
+ rscsi_disks[i].has_part_table = 1;
+ }
+
+ /* If our host adapter is capable of scatter-gather, then we increase
+ * the read-ahead to 16 blocks (32 sectors). If not, we use
+ * a two block (4 sector) read ahead.
+ */
+ if(rscsi_disks[0].device && rscsi_disks[0].device->host->sg_tablesize)
+ read_ahead[MAJOR_NR] = 120;
+ /* 64 sector read-ahead */
+ else
+ read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
+
+ return;
}
static int sd_detect(Scsi_Device * SDp){
- if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
-
- printk("Detected scsi disk sd%c at scsi%d, id %d, lun %d\n",
- 'a'+ (sd_template.dev_noticed++),
- SDp->host->host_no , SDp->id, SDp->lun);
-
- return 1;
-
+ if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
+
+ printk("Detected scsi disk sd%c at scsi%d, channel %d, id %d, lun %d\n",
+ 'a'+ (sd_template.dev_noticed++),
+ SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+
+ return 1;
}
static int sd_attach(Scsi_Device * SDp){
- Scsi_Disk * dpnt;
- int i;
-
- if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
-
- if(sd_template.nr_dev >= sd_template.dev_max) {
+ Scsi_Disk * dpnt;
+ int i;
+
+ if(SDp->type != TYPE_DISK && SDp->type != TYPE_MOD) return 0;
+
+ if(sd_template.nr_dev >= sd_template.dev_max) {
SDp->attached--;
return 1;
- }
-
- for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
- if(!dpnt->device) break;
-
- if(i >= sd_template.dev_max) panic ("scsi_devices corrupt (sd)");
-
- SDp->scsi_request_fn = do_sd_request;
- rscsi_disks[i].device = SDp;
- rscsi_disks[i].has_part_table = 0;
- sd_template.nr_dev++;
- sd_gendisk.nr_real++;
- return 0;
+ }
+
+ for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
+ if(!dpnt->device) break;
+
+ if(i >= sd_template.dev_max) panic ("scsi_devices corrupt (sd)");
+
+ SDp->scsi_request_fn = do_sd_request;
+ rscsi_disks[i].device = SDp;
+ rscsi_disks[i].has_part_table = 0;
+ sd_template.nr_dev++;
+ sd_gendisk.nr_real++;
+ return 0;
}
#define DEVICE_BUSY rscsi_disks[target].device->busy
#define GENDISK_STRUCT sd_gendisk
/* This routine is called to flush all partitions and partition tables
- for a changed scsi disk, and then re-read the new partition table.
- If we are revalidating a disk because of a media change, then we
- enter with usage == 0. If we are using an ioctl, we automatically have
- usage == 1 (we need an open channel to use an ioctl :-), so this
- is our limit.
+ * for a changed scsi disk, and then re-read the new partition table.
+ * If we are revalidating a disk because of a media change, then we
+ * enter with usage == 0. If we are using an ioctl, we automatically have
+ * usage == 1 (we need an open channel to use an ioctl :-), so this
+ * is our limit.
*/
int revalidate_scsidisk(int dev, int maxusage){
- int target, major;
- struct gendisk * gdev;
- unsigned long flags;
- int max_p;
- int start;
- int i;
-
- target = DEVICE_NR(MINOR(dev));
- gdev = &GENDISK_STRUCT;
-
- save_flags(flags);
- cli();
- if (DEVICE_BUSY || USAGE > maxusage) {
- restore_flags(flags);
- printk("Device busy for revalidation (usage=%d)\n", USAGE);
- return -EBUSY;
- };
- DEVICE_BUSY = 1;
- restore_flags(flags);
-
- max_p = gdev->max_p;
- start = target << gdev->minor_shift;
- major = MAJOR_NR << 8;
-
- for (i=max_p - 1; i >=0 ; i--) {
- sync_dev(major | start | i);
- invalidate_inodes(major | start | i);
- invalidate_buffers(major | start | i);
- gdev->part[start+i].start_sect = 0;
- gdev->part[start+i].nr_sects = 0;
- };
-
+ int target, major;
+ struct gendisk * gdev;
+ unsigned long flags;
+ int max_p;
+ int start;
+ int i;
+
+ target = DEVICE_NR(MINOR(dev));
+ gdev = &GENDISK_STRUCT;
+
+ save_flags(flags);
+ cli();
+ if (DEVICE_BUSY || USAGE > maxusage) {
+ restore_flags(flags);
+ printk("Device busy for revalidation (usage=%d)\n", USAGE);
+ return -EBUSY;
+ };
+ DEVICE_BUSY = 1;
+ restore_flags(flags);
+
+ max_p = gdev->max_p;
+ start = target << gdev->minor_shift;
+ major = MAJOR_NR << 8;
+
+ for (i=max_p - 1; i >=0 ; i--) {
+ sync_dev(major | start | i);
+ invalidate_inodes(major | start | i);
+ invalidate_buffers(major | start | i);
+ gdev->part[start+i].start_sect = 0;
+ gdev->part[start+i].nr_sects = 0;
+ };
+
#ifdef MAYBE_REINIT
- MAYBE_REINIT;
+ MAYBE_REINIT;
#endif
-
- gdev->part[start].nr_sects = CAPACITY;
- resetup_one_dev(gdev, target);
-
- DEVICE_BUSY = 0;
- return 0;
+
+ gdev->part[start].nr_sects = CAPACITY;
+ resetup_one_dev(gdev, target);
+
+ DEVICE_BUSY = 0;
+ return 0;
}
static int fop_revalidate_scsidisk(dev_t dev){
- return revalidate_scsidisk(dev, 0);
+ return revalidate_scsidisk(dev, 0);
}
static void sd_detach(Scsi_Device * SDp)
{
- Scsi_Disk * dpnt;
- int i;
- int max_p;
- int major;
- int start;
-
- for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
- if(dpnt->device == SDp) {
+ Scsi_Disk * dpnt;
+ int i;
+ int max_p;
+ int major;
+ int start;
+
+ for(dpnt = rscsi_disks, i=0; i<sd_template.dev_max; i++, dpnt++)
+ if(dpnt->device == SDp) {
+
+ /* If we are disconnecting a disk driver, sync and invalidate
+ * everything */
+ max_p = sd_gendisk.max_p;
+ start = i << sd_gendisk.minor_shift;
+ major = MAJOR_NR << 8;
+
+ for (i=max_p - 1; i >=0 ; i--) {
+ sync_dev(major | start | i);
+ invalidate_inodes(major | start | i);
+ invalidate_buffers(major | start | i);
+ sd_gendisk.part[start+i].start_sect = 0;
+ sd_gendisk.part[start+i].nr_sects = 0;
+ sd_sizes[start+i] = 0;
+ };
+
+ dpnt->has_part_table = 0;
+ dpnt->device = NULL;
+ dpnt->capacity = 0;
+ SDp->attached--;
+ sd_template.dev_noticed--;
+ sd_template.nr_dev--;
+ sd_gendisk.nr_real--;
+ return;
+ }
+ return;
+}
- /* If we are disconnecting a disk driver, sync and invalidate everything */
- max_p = sd_gendisk.max_p;
- start = i << sd_gendisk.minor_shift;
- major = MAJOR_NR << 8;
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
- for (i=max_p - 1; i >=0 ; i--) {
- sync_dev(major | start | i);
- invalidate_inodes(major | start | i);
- invalidate_buffers(major | start | i);
- sd_gendisk.part[start+i].start_sect = 0;
- sd_gendisk.part[start+i].nr_sects = 0;
- sd_sizes[start+i] = 0;
- };
-
- dpnt->has_part_table = 0;
- dpnt->device = NULL;
- dpnt->capacity = 0;
- SDp->attached--;
- sd_template.dev_noticed--;
- sd_template.nr_dev--;
- sd_gendisk.nr_real--;
- return;
+char kernel_version[] = UTS_RELEASE;
+
+int init_module(void) {
+ sd_template.usage_count = &mod_use_count_;
+ return scsi_register_module(MODULE_SCSI_DEV, &sd_template);
+}
+
+void cleanup_module( void)
+{
+ struct gendisk * prev_sdgd;
+ struct gendisk * sdgd;
+
+ if (MOD_IN_USE) {
+ printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+ return;
+ }
+ scsi_unregister_module(MODULE_SCSI_DEV, &sd_template);
+ unregister_blkdev(SCSI_GENERIC_MAJOR, "sd");
+ if( rscsi_disks != NULL )
+ {
+ scsi_init_free((char *) rscsi_disks,
+ (sd_template.dev_noticed + SD_EXTRA_DEVS)
+ * sizeof(Scsi_Disk));
+
+ scsi_init_free((char *) sd_sizes, sd_template.dev_max * sizeof(int));
+ scsi_init_free((char *) sd_blocksizes, sd_template.dev_max * sizeof(int));
+ scsi_init_free((char *) sd_hardsizes, sd_template.dev_max * sizeof(int));
+ scsi_init_free((char *) sd,
+ (sd_template.dev_max << 4) * sizeof(struct hd_struct));
+ /*
+ * Now remove sd_gendisk from the linked list
+ */
+ sdgd = gendisk_head;
+ prev_sdgd = NULL;
+ while(sdgd != &sd_gendisk)
+ {
+ prev_sdgd = sdgd;
+ sdgd = sdgd->next;
+ }
+
+ if(sdgd != &sd_gendisk)
+ printk("sd_gendisk not in disk chain.\n");
+ else {
+ if(prev_sdgd != NULL)
+ prev_sdgd->next = sdgd->next;
+ else
+ gendisk_head = sdgd->next;
+ }
}
- return;
+
+ blksize_size[MAJOR_NR] = NULL;
+ blk_dev[MAJOR_NR].request_fn = NULL;
+ blk_size[MAJOR_NR] = NULL;
+ hardsect_size[MAJOR_NR] = NULL;
+ read_ahead[MAJOR_NR] = 0;
+ sd_template.dev_max = 0;
}
+#endif /* MODULE */
/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
* c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
* End:
*/
/*
- * sd.h Copyright (C) 1992 Drew Eckhardt
- * SCSI disk driver header file by
- * Drew Eckhardt
+ * sd.h Copyright (C) 1992 Drew Eckhardt
+ * SCSI disk driver header file by
+ * Drew Eckhardt
*
- * <drew@colorado.edu>
+ * <drew@colorado.edu>
*
* Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
* add scatter-gather, multiple outstanding request, and other
* enhancements.
*/
#ifndef _SD_H
- #define _SD_H
+#define _SD_H
/*
$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/sd.h,v 1.1 1992/07/24 06:27:38 root Exp root $
*/
#endif
/*
- This is an arbitrary constant, and may be changed to whatever
- suits your purposes. Note that smaller will get you a few bytes
- more in kernel space if that is your thing.
-*/
+ * This is an arbitrary constant, and may be changed to whatever
+ * suits your purposes. Note that smaller will get you a few bytes
+ * more in kernel space if that is your thing.
+ */
extern struct hd_struct * sd;
typedef struct scsi_disk {
- unsigned capacity; /* size in blocks */
- unsigned sector_size; /* size in bytes */
- Scsi_Device *device;
- unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */
- unsigned char sector_bit_shift; /* power of 2 sectors per FS block */
- unsigned ten:1; /* support ten byte read / write */
- unsigned remap:1; /* support remapping */
- unsigned has_part_table:1; /* has partition table */
- } Scsi_Disk;
-
+ unsigned capacity; /* size in blocks */
+ unsigned sector_size; /* size in bytes */
+ Scsi_Device *device;
+ unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */
+ unsigned char sector_bit_shift; /* power of 2 sectors per FS block */
+ unsigned ten:1; /* support ten byte read / write */
+ unsigned remap:1; /* support remapping */
+ unsigned has_part_table:1; /* has partition table */
+} Scsi_Disk;
+
extern Scsi_Disk * rscsi_disks;
#endif
+
+/*
+ * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
+
int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
{
- int dev = inode->i_rdev;
- int error;
- struct Scsi_Host * host;
- int diskinfo[4];
- struct hd_geometry *loc = (struct hd_geometry *) arg;
-
- switch (cmd) {
- case HDIO_REQ: /* Return BIOS disk parameters */
- if (!loc) return -EINVAL;
- error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
- if (error)
- return error;
- host = rscsi_disks[MINOR(dev) >> 4].device->host;
- diskinfo[0] = 0;
- diskinfo[1] = 0;
- diskinfo[2] = 0;
- if(host->hostt->bios_param != NULL)
- host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4],
- dev,
- &diskinfo[0]);
- put_user(diskinfo[0], &loc->heads);
- put_user(diskinfo[1], &loc->sectors);
- put_user(diskinfo[2], &loc->cylinders);
- put_user(sd[MINOR(inode->i_rdev)].start_sect, &loc->start);
- return 0;
- case BLKGETSIZE: /* Return device size */
- if (!arg) return -EINVAL;
- error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
- if (error)
- return error;
- put_user(sd[MINOR(inode->i_rdev)].nr_sects,
- (long *) arg);
- return 0;
- case BLKRASET:
- if(!suser()) return -EACCES;
- if(!inode->i_rdev) return -EINVAL;
- if(arg > 0xff) return -EINVAL;
- read_ahead[MAJOR(inode->i_rdev)] = arg;
- return 0;
- case BLKFLSBUF:
- if(!suser()) return -EACCES;
- if(!inode->i_rdev) return -EINVAL;
- fsync_dev(inode->i_rdev);
- invalidate_buffers(inode->i_rdev);
- return 0;
-
- case BLKRRPART: /* Re-read partition tables */
- return revalidate_scsidisk(dev, 1);
- default:
- return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg);
- }
+ int dev = inode->i_rdev;
+ int error;
+ struct Scsi_Host * host;
+ int diskinfo[4];
+ struct hd_geometry *loc = (struct hd_geometry *) arg;
+
+ switch (cmd) {
+ case HDIO_REQ: /* Return BIOS disk parameters */
+ if (!loc) return -EINVAL;
+ error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
+ if (error)
+ return error;
+ host = rscsi_disks[MINOR(dev) >> 4].device->host;
+ diskinfo[0] = 0;
+ diskinfo[1] = 0;
+ diskinfo[2] = 0;
+ if(host->hostt->bios_param != NULL)
+ host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4],
+ dev,
+ &diskinfo[0]);
+ put_user(diskinfo[0], &loc->heads);
+ put_user(diskinfo[1], &loc->sectors);
+ put_user(diskinfo[2], &loc->cylinders);
+ put_user(sd[MINOR(inode->i_rdev)].start_sect, &loc->start);
+ return 0;
+ case BLKGETSIZE: /* Return device size */
+ if (!arg) return -EINVAL;
+ error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long));
+ if (error)
+ return error;
+ put_user(sd[MINOR(inode->i_rdev)].nr_sects,
+ (long *) arg);
+ return 0;
+ case BLKRASET:
+ if(!suser()) return -EACCES;
+ if(!inode->i_rdev) return -EINVAL;
+ if(arg > 0xff) return -EINVAL;
+ read_ahead[MAJOR(inode->i_rdev)] = arg;
+ return 0;
+ case BLKFLSBUF:
+ if(!suser()) return -EACCES;
+ if(!inode->i_rdev) return -EINVAL;
+ fsync_dev(inode->i_rdev);
+ invalidate_buffers(inode->i_rdev);
+ return 0;
+
+ case BLKRRPART: /* Re-read partition tables */
+ return revalidate_scsidisk(dev, 1);
+ default:
+ return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg);
+ }
}
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
* c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
* End:
*/
* transfer rate if handshaking isn't working correctly.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
#include <asm/io.h>
#include <asm/system.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/config.h>
+#include <linux/proc_fs.h>
#include "../block/blk.h"
#include "scsi.h"
}
/* If the user specified the controller type from the command line,
- controller_type will be non-zero, so don't try and detect one */
+ controller_type will be non-zero, so don't try and detect one */
if (!controller_type) {
#ifdef OVERRIDE
#ifdef LINKED
" LINKED"
#endif
- "\n", tpnt->name);
+ "\n", tpnt->name);
return 1;
}
else
const char *seagate_st0x_info(struct Scsi_Host * shpnt) {
static char buffer[64];
- sprintf(buffer, "%s at irq %d, address 0x%05X",
+ sprintf(buffer, "%s at irq %d, address 0x%05X",
(controller_type == SEAGATE) ? ST0X_ID_STR : FD_ID_STR,
irq, (unsigned int)base_address);
- return buffer;
+ return buffer;
}
/*
}
buffer=current_buffer;
- cmnd=current_cmnd; /* WDE add */
- data=current_data; /* WDE add */
- len=current_bufflen; /* WDE add */
+ cmnd=current_cmnd; /* WDE add */
+ data=current_data; /* WDE add */
+ len=current_bufflen; /* WDE add */
nobuffs=current_nobuffs;
/*
#if !defined (ARBITRATE)
while (((STATUS | STATUS | STATUS) &
- (STAT_BSY | STAT_SEL)) &&
+ (STAT_BSY | STAT_SEL)) &&
(!st0x_aborted) && (jiffies < clock));
if (jiffies > clock)
/* Establish current pointers. Take into account scatter / gather */
- if ((nobuffs = SCint->use_sg)) {
+ if ((nobuffs = SCint->use_sg)) {
#if (DEBUG & DEBUG_SG)
{
int i;
}
#endif
- buffer = (struct scatterlist *) SCint->buffer;
- len = buffer->length;
- data = (unsigned char *) buffer->address;
- } else {
+ buffer = (struct scatterlist *) SCint->buffer;
+ len = buffer->length;
+ data = (unsigned char *) buffer->address;
+ } else {
#if (DEBUG & DEBUG_SG)
printk("scsi%d : scatter gather not requested.\n", hostno);
#endif
- buffer = NULL;
- len = SCint->request_bufflen;
- data = (unsigned char *) SCint->request_buffer;
- }
+ buffer = NULL;
+ len = SCint->request_bufflen;
+ data = (unsigned char *) SCint->request_buffer;
+ }
#if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT))
printk("scsi%d : len = %d\n", hostno, len);
#ifdef FAST
if (!len) {
#if 0
- printk("scsi%d: underflow to target %d lun %d \n",
- hostno, target, lun);
- st0x_aborted = DID_ERROR;
- fast = 0;
+ printk("scsi%d: underflow to target %d lun %d \n",
+ hostno, target, lun);
+ st0x_aborted = DID_ERROR;
+ fast = 0;
#endif
- break;
+ break;
}
if (fast && transfersize && !(len % transfersize) && (len >= transfersize)
#endif
) {
#if (DEBUG & DEBUG_FAST)
- printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
- " len = %d, data = %08x\n", hostno, SCint->underflow,
- SCint->transfersize, len, data);
+ printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
+ " len = %d, data = %08x\n", hostno, SCint->underflow,
+ SCint->transfersize, len, data);
#endif
- __asm__("
+ __asm__("
cld;
"
#ifdef FAST32
"
#else
"1: lodsb;
- movb %%al, (%%edi);
+ movb %%al, (%%edi);
"
#endif
" loop 1b;" : :
- /* input */
- "D" (st0x_dr), "S" (data), "c" (SCint->transfersize) :
- /* clobbered */
- "eax", "ecx", "esi" );
+ /* input */
+ "D" (st0x_dr), "S" (data), "c" (SCint->transfersize) :
+ /* clobbered */
+ "eax", "ecx", "esi" );
len -= transfersize;
data += transfersize;
cld
- movl _st0x_cr_sr, %%ebx
- movl _st0x_dr, %%edi
+ movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%ebx
+ movl " SYMBOL_NAME_STR(st0x_dr) ", %%edi
1: movb (%%ebx), %%al\n"
/*
"eax", "ebx", "edi");
}
- if (!len && nobuffs) {
- --nobuffs;
- ++buffer;
- len = buffer->length;
- data = (unsigned char *) buffer->address;
+ if (!len && nobuffs) {
+ --nobuffs;
+ ++buffer;
+ len = buffer->length;
+ data = (unsigned char *) buffer->address;
#if (DEBUG & DEBUG_SG)
printk("scsi%d : next scatter-gather buffer len = %d address = %08x\n",
hostno, len, data);
#endif
- }
+ }
break;
case REQ_DATAIN :
#endif
) {
#if (DEBUG & DEBUG_FAST)
- printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
- " len = %d, data = %08x\n", hostno, SCint->underflow,
- SCint->transfersize, len, data);
+ printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n"
+ " len = %d, data = %08x\n", hostno, SCint->underflow,
+ SCint->transfersize, len, data);
#endif
- __asm__("
+ __asm__("
cld;
"
#ifdef FAST32
"
#else
"1: movb (%%esi), %%al;
- stosb;
+ stosb;
"
#endif
" loop 1b;" : :
- /* input */
- "S" (st0x_dr), "D" (data), "c" (SCint->transfersize) :
- /* clobbered */
- "eax", "ecx", "edi");
+ /* input */
+ "S" (st0x_dr), "D" (data), "c" (SCint->transfersize) :
+ /* clobbered */
+ "eax", "ecx", "edi");
len -= transfersize;
data += transfersize;
jz 2f
cld
- movl _st0x_cr_sr, %%esi
- movl _st0x_dr, %%ebx
+ movl " SYMBOL_NAME_STR(st0x_cr_sr) ", %%esi
+ movl " SYMBOL_NAME_STR(st0x_dr) ", %%ebx
1: movb (%%esi), %%al\n"
/*
#endif
}
- if (!len && nobuffs) {
- --nobuffs;
- ++buffer;
- len = buffer->length;
- data = (unsigned char *) buffer->address;
+ if (!len && nobuffs) {
+ --nobuffs;
+ ++buffer;
+ len = buffer->length;
+ data = (unsigned char *) buffer->address;
#if (DEBUG & DEBUG_SG)
printk("scsi%d : next scatter-gather buffer len = %d address = %08x\n",
hostno, len, data);
#endif
- }
+ }
break;
switch (message = DATA) {
case DISCONNECT :
should_reconnect = 1;
- current_data = data; /* WDE add */
+ current_data = data; /* WDE add */
current_buffer = buffer;
- current_bufflen = len; /* WDE add */
+ current_bufflen = len; /* WDE add */
current_nobuffs = nobuffs;
#ifdef LINKED
linked_connected = 0;
break;
case SAVE_POINTERS :
current_buffer = buffer;
- current_bufflen = len; /* WDE add */
+ current_bufflen = len; /* WDE add */
current_data = data; /* WDE mod */
current_nobuffs = nobuffs;
#if (DEBUG & PHASE_MSGIN)
printk("\n");
#endif
printk("scsi%d : status = ", hostno);
- print_status(status);
+ print_status(status);
printk("message = %02x\n", message);
#endif
return result;
}
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = SEAGATE_ST0X;
+
+#include "scsi_module.c"
+#endif
int seagate_st0x_biosparam(Disk *, int, int*);
-#define SEAGATE_ST0X {NULL, NULL, NULL, seagate_st0x_detect, \
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
+#define SEAGATE_ST0X { NULL, NULL, generic_proc_info, "seagate", \
+ PROC_SCSI_SEAGATE, NULL, seagate_st0x_detect, \
NULL, \
seagate_st0x_info, seagate_st0x_command, \
seagate_st0x_queue_command, seagate_st0x_abort, \
/*
- History:
- Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user
- process control of SCSI devices.
- Development Sponsored by Killy Corp. NY NY
-
- Borrows code from st driver.
-*/
+ * History:
+ * Started: Aug 9 by Lawrence Foard (entropy@world.std.com),
+ * to allow user process control of SCSI devices.
+ * Development Sponsored by Killy Corp. NY NY
+ *
+ * Borrows code from st driver.
+ */
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif /* MODULE */
#include <linux/fs.h>
#include <linux/kernel.h>
static void sg_detach(Scsi_Device *);
-struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", 0xff,
- SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
- sg_detect, sg_init,
- NULL, sg_attach, sg_detach};
+struct Scsi_Device_Template sg_template = {NULL, NULL, "sg", NULL, 0xff,
+ SCSI_GENERIC_MAJOR, 0, 0, 0, 0,
+ sg_detect, sg_init,
+ NULL, sg_attach, sg_detach};
#ifdef SG_BIG_BUFF
-static char *big_buff;
+static char *big_buff = NULL;
static struct wait_queue *big_wait; /* wait for buffer available */
static int big_inuse=0;
#endif
struct scsi_generic
- {
- Scsi_Device *device;
- int users; /* how many people have it open? */
- struct wait_queue *generic_wait; /* wait for device to be available */
- struct wait_queue *read_wait; /* wait for response */
- struct wait_queue *write_wait; /* wait for free buffer */
- int timeout; /* current default value for device */
- int buff_len; /* length of current buffer */
- char *buff; /* the buffer */
- struct sg_header header; /* header of pending command */
- char exclude; /* opened for exclusive access */
- char pending; /* don't accept writes now */
- char complete; /* command complete allow a read */
- };
+{
+ Scsi_Device *device;
+ int users; /* how many people have it open? */
+ struct wait_queue *generic_wait; /* wait for device to be available */
+ struct wait_queue *read_wait; /* wait for response */
+ struct wait_queue *write_wait; /* wait for free buffer */
+ int timeout; /* current default value for device */
+ int buff_len; /* length of current buffer */
+ char *buff; /* the buffer */
+ struct sg_header header; /* header of pending command */
+ char exclude; /* opened for exclusive access */
+ char pending; /* don't accept writes now */
+ char complete; /* command complete allow a read */
+};
static struct scsi_generic *scsi_generics=NULL;
static void sg_free(char *buff,int size);
static int sg_ioctl(struct inode * inode,struct file * file,
- unsigned int cmd_in, unsigned long arg)
- {
- int dev = MINOR(inode->i_rdev);
- if ((dev<0) || (dev>=sg_template.dev_max))
- return -ENXIO;
- switch(cmd_in)
- {
+ unsigned int cmd_in, unsigned long arg)
+{
+ int dev = MINOR(inode->i_rdev);
+ if ((dev<0) || (dev>=sg_template.dev_max))
+ return -ENXIO;
+ switch(cmd_in)
+ {
case SG_SET_TIMEOUT:
- scsi_generics[dev].timeout=get_user((int *) arg);
- return 0;
+ scsi_generics[dev].timeout=get_user((int *) arg);
+ return 0;
case SG_GET_TIMEOUT:
- return scsi_generics[dev].timeout;
+ return scsi_generics[dev].timeout;
default:
- return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
- }
- }
+ return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
+ }
+}
static int sg_open(struct inode * inode, struct file * filp)
- {
- int dev=MINOR(inode->i_rdev);
- int flags=filp->f_flags;
- if (dev>=sg_template.dev_max || !scsi_generics[dev].device)
- return -ENXIO;
- if (O_RDWR!=(flags & O_ACCMODE))
- return -EACCES;
- if (flags & O_EXCL)
- {
- while(scsi_generics[dev].users)
- {
- if (flags & O_NONBLOCK)
- return -EBUSY;
- interruptible_sleep_on(&scsi_generics[dev].generic_wait);
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- }
- scsi_generics[dev].exclude=1;
- }
- else
- while(scsi_generics[dev].exclude)
+{
+ int dev=MINOR(inode->i_rdev);
+ int flags=filp->f_flags;
+ if (dev>=sg_template.dev_max || !scsi_generics[dev].device)
+ return -ENXIO;
+ if (O_RDWR!=(flags & O_ACCMODE))
+ return -EACCES;
+ if (flags & O_EXCL)
{
- if (flags & O_NONBLOCK)
- return -EBUSY;
- interruptible_sleep_on(&scsi_generics[dev].generic_wait);
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
+ while(scsi_generics[dev].users)
+ {
+ if (flags & O_NONBLOCK)
+ return -EBUSY;
+ interruptible_sleep_on(&scsi_generics[dev].generic_wait);
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ }
+ scsi_generics[dev].exclude=1;
}
- if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete)
- {
- if (scsi_generics[dev].buff != NULL)
- sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
- scsi_generics[dev].buff=NULL;
- scsi_generics[dev].pending=0;
- }
- if (!scsi_generics[dev].users)
- scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT;
- if (scsi_generics[dev].device->host->hostt->usage_count)
- (*scsi_generics[dev].device->host->hostt->usage_count)++;
- scsi_generics[dev].users++;
- return 0;
- }
+ else
+ while(scsi_generics[dev].exclude)
+ {
+ if (flags & O_NONBLOCK)
+ return -EBUSY;
+ interruptible_sleep_on(&scsi_generics[dev].generic_wait);
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ }
+ if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete)
+ {
+ if (scsi_generics[dev].buff != NULL)
+ sg_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
+ scsi_generics[dev].buff=NULL;
+ scsi_generics[dev].pending=0;
+ }
+ if (!scsi_generics[dev].users)
+ scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT;
+ if (scsi_generics[dev].device->host->hostt->usage_count)
+ (*scsi_generics[dev].device->host->hostt->usage_count)++;
+ if(sg_template.usage_count) (*sg_template.usage_count)++;
+ scsi_generics[dev].users++;
+ return 0;
+}
static void sg_close(struct inode * inode, struct file * filp)
- {
- int dev=MINOR(inode->i_rdev);
- scsi_generics[dev].users--;
- if (scsi_generics[dev].device->host->hostt->usage_count)
- (*scsi_generics[dev].device->host->hostt->usage_count)--;
- scsi_generics[dev].exclude=0;
- wake_up(&scsi_generics[dev].generic_wait);
- }
+{
+ int dev=MINOR(inode->i_rdev);
+ scsi_generics[dev].users--;
+ if (scsi_generics[dev].device->host->hostt->usage_count)
+ (*scsi_generics[dev].device->host->hostt->usage_count)--;
+ if(sg_template.usage_count) (*sg_template.usage_count)--;
+ scsi_generics[dev].exclude=0;
+ wake_up(&scsi_generics[dev].generic_wait);
+}
static char *sg_malloc(int size)
- {
- if (size<=4096)
- return (char *) scsi_malloc(size);
+{
+ if (size<=4096)
+ return (char *) scsi_malloc(size);
#ifdef SG_BIG_BUFF
- if (size<SG_BIG_BUFF)
- {
- while(big_inuse)
- {
- interruptible_sleep_on(&big_wait);
- if (current->signal & ~current->blocked)
- return NULL;
- }
- big_inuse=1;
- return big_buff;
- }
+ if (size<SG_BIG_BUFF)
+ {
+ while(big_inuse)
+ {
+ interruptible_sleep_on(&big_wait);
+ if (current->signal & ~current->blocked)
+ return NULL;
+ }
+ big_inuse=1;
+ return big_buff;
+ }
#endif
- return NULL;
- }
+ return NULL;
+}
static void sg_free(char *buff,int size)
- {
+{
#ifdef SG_BIG_BUFF
- if (buff==big_buff)
- {
- big_inuse=0;
- wake_up(&big_wait);
- return;
- }
+ if (buff==big_buff)
+ {
+ big_inuse=0;
+ wake_up(&big_wait);
+ return;
+ }
#endif
- scsi_free(buff,size);
- }
+ scsi_free(buff,size);
+}
static int sg_read(struct inode *inode,struct file *filp,char *buf,int count)
- {
- int dev=MINOR(inode->i_rdev);
- int i;
- struct scsi_generic *device=&scsi_generics[dev];
- if ((i=verify_area(VERIFY_WRITE,buf,count)))
- return i;
- while(!device->pending || !device->complete)
- {
- if (filp->f_flags & O_NONBLOCK)
- return -EWOULDBLOCK;
- interruptible_sleep_on(&device->read_wait);
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- }
- device->header.pack_len=device->header.reply_len;
- device->header.result=0;
- if (count>=sizeof(struct sg_header))
- {
- memcpy_tofs(buf,&device->header,sizeof(struct sg_header));
- buf+=sizeof(struct sg_header);
- if (count>device->header.pack_len)
- count=device->header.pack_len;
- if (count > sizeof(struct sg_header)) {
- memcpy_tofs(buf,device->buff,count-sizeof(struct sg_header));
+{
+ int dev=MINOR(inode->i_rdev);
+ int i;
+ struct scsi_generic *device=&scsi_generics[dev];
+ if ((i=verify_area(VERIFY_WRITE,buf,count)))
+ return i;
+ while(!device->pending || !device->complete)
+ {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+ interruptible_sleep_on(&device->read_wait);
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ }
+ device->header.pack_len=device->header.reply_len;
+ device->header.result=0;
+ if (count>=sizeof(struct sg_header))
+ {
+ memcpy_tofs(buf,&device->header,sizeof(struct sg_header));
+ buf+=sizeof(struct sg_header);
+ if (count>device->header.pack_len)
+ count=device->header.pack_len;
+ if (count > sizeof(struct sg_header)) {
+ memcpy_tofs(buf,device->buff,count-sizeof(struct sg_header));
+ }
}
- }
- else
- count=0;
- sg_free(device->buff,device->buff_len);
- device->buff = NULL;
- device->pending=0;
- wake_up(&device->write_wait);
- return count;
- }
+ else
+ count=0;
+ sg_free(device->buff,device->buff_len);
+ device->buff = NULL;
+ device->pending=0;
+ wake_up(&device->write_wait);
+ return count;
+}
static void sg_command_done(Scsi_Cmnd * SCpnt)
- {
- int dev=SCpnt->request.dev;
- struct scsi_generic *device=&scsi_generics[dev];
- if (!device->pending)
- {
- printk("unexpected done for sg %d\n",dev);
+{
+ int dev=SCpnt->request.dev;
+ struct scsi_generic *device=&scsi_generics[dev];
+ if (!device->pending)
+ {
+ printk("unexpected done for sg %d\n",dev);
+ SCpnt->request.dev=-1;
+ return;
+ }
+ memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
+ if (SCpnt->sense_buffer[0])
+ {
+ device->header.result=EIO;
+ }
+ else
+ device->header.result=SCpnt->result;
+ device->complete=1;
SCpnt->request.dev=-1;
- return;
- }
- memcpy(device->header.sense_buffer, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer));
- if (SCpnt->sense_buffer[0])
- {
- device->header.result=EIO;
- }
- else
- device->header.result=SCpnt->result;
- device->complete=1;
- SCpnt->request.dev=-1;
- wake_up(&scsi_generics[dev].read_wait);
- }
+ wake_up(&scsi_generics[dev].read_wait);
+}
static int sg_write(struct inode *inode,struct file *filp,char *buf,int count)
- {
- int dev=MINOR(inode->i_rdev);
- Scsi_Cmnd *SCpnt;
- int bsize,size,amt,i;
- unsigned char opcode;
- unsigned char cmnd[MAX_COMMAND_SIZE];
- struct scsi_generic *device=&scsi_generics[dev];
-
- if ((i=verify_area(VERIFY_READ,buf,count)))
- return i;
- /*
- * The minimum scsi command length is 6 bytes. If we get anything less than this,
- * it is clearly bogus.
- */
- if (count<(sizeof(struct sg_header) + 6))
- return -EIO;
- /* make sure we can fit */
- while(device->pending)
- {
- if (filp->f_flags & O_NONBLOCK)
- return -EWOULDBLOCK;
+{
+ int dev=MINOR(inode->i_rdev);
+ Scsi_Cmnd *SCpnt;
+ int bsize,size,amt,i;
+ unsigned char opcode;
+ unsigned char cmnd[MAX_COMMAND_SIZE];
+ struct scsi_generic *device=&scsi_generics[dev];
+
+ if ((i=verify_area(VERIFY_READ,buf,count)))
+ return i;
+ /*
+ * The minimum scsi command length is 6 bytes. If we get anything less than this,
+ * it is clearly bogus.
+ */
+ if (count<(sizeof(struct sg_header) + 6))
+ return -EIO;
+ /* make sure we can fit */
+ while(device->pending)
+ {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
#ifdef DEBUG
- printk("sg_write: sleeping on pending request\n");
+ printk("sg_write: sleeping on pending request\n");
#endif
- interruptible_sleep_on(&device->write_wait);
- if (current->signal & ~current->blocked)
- return -ERESTARTSYS;
- }
- device->pending=1;
- device->complete=0;
- memcpy_fromfs(&device->header,buf,sizeof(struct sg_header));
- /* fix input size */
- device->header.pack_len=count;
- buf+=sizeof(struct sg_header);
- bsize=(device->header.pack_len>device->header.reply_len) ? device->header.pack_len : device->header.reply_len;
- bsize-=sizeof(struct sg_header);
- amt=bsize;
- if (!bsize)
- bsize++;
- bsize=(bsize+511) & ~511;
- if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize)))
- {
- device->pending=0;
- wake_up(&device->write_wait);
- return -ENOMEM;
- }
+ interruptible_sleep_on(&device->write_wait);
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ }
+ device->pending=1;
+ device->complete=0;
+ memcpy_fromfs(&device->header,buf,sizeof(struct sg_header));
+ /* fix input size */
+ device->header.pack_len=count;
+ buf+=sizeof(struct sg_header);
+ bsize=(device->header.pack_len>device->header.reply_len) ? device->header.pack_len : device->header.reply_len;
+ bsize-=sizeof(struct sg_header);
+ amt=bsize;
+ if (!bsize)
+ bsize++;
+ bsize=(bsize+511) & ~511;
+ if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize)))
+ {
+ device->pending=0;
+ wake_up(&device->write_wait);
+ return -ENOMEM;
+ }
#ifdef DEBUG
- printk("allocating device\n");
+ printk("allocating device\n");
#endif
- if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
- {
- device->pending=0;
- wake_up(&device->write_wait);
- sg_free(device->buff,device->buff_len);
- device->buff = NULL;
- return -EWOULDBLOCK;
- }
+ if (!(SCpnt=allocate_device(NULL,device->device, !(filp->f_flags & O_NONBLOCK))))
+ {
+ device->pending=0;
+ wake_up(&device->write_wait);
+ sg_free(device->buff,device->buff_len);
+ device->buff = NULL;
+ return -EWOULDBLOCK;
+ }
#ifdef DEBUG
- printk("device allocated\n");
+ printk("device allocated\n");
#endif
- /* now issue command */
- SCpnt->request.dev=dev;
- SCpnt->sense_buffer[0]=0;
- opcode = get_user(buf);
- size=COMMAND_SIZE(opcode);
- if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
- SCpnt->cmd_len = size;
- /*
- * Verify that the user has actually passed enough bytes for this command.
- */
- if (count<(sizeof(struct sg_header) + size))
+ /* now issue command */
+ SCpnt->request.dev=dev;
+ SCpnt->sense_buffer[0]=0;
+ opcode = get_user(buf);
+ size=COMMAND_SIZE(opcode);
+ if (opcode >= 0xc0 && device->header.twelve_byte) size = 12;
+ SCpnt->cmd_len = size;
+ amt-=device->header.pack_len>device->header.reply_len ? size : 0;
+ /*
+ * Verify that the user has actually passed enough bytes for this command.
+ */
+ if (count<(sizeof(struct sg_header) + size))
{
- device->pending=0;
- wake_up(&device->write_wait);
- sg_free(device->buff,device->buff_len);
- device->buff = NULL;
- return -EIO;
+ device->pending=0;
+ wake_up(&device->write_wait);
+ sg_free(device->buff,device->buff_len);
+ device->buff = NULL;
+ return -EIO;
}
-
- memcpy_fromfs(cmnd,buf,size);
- buf+=size;
- memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header));
- cmnd[1]=(cmnd[1] & 0x1f) | (device->device->lun<<5);
+
+ memcpy_fromfs(cmnd,buf,size);
+ buf+=size;
+ memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header));
+ cmnd[1]=(cmnd[1] & 0x1f) | (device->device->lun<<5);
#ifdef DEBUG
- printk("do cmd\n");
+ printk("do cmd\n");
#endif
- scsi_do_cmd (SCpnt,(void *) cmnd,
- (void *) device->buff,amt,
- sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
+ scsi_do_cmd (SCpnt,(void *) cmnd,
+ (void *) device->buff,amt,
+ sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
#ifdef DEBUG
- printk("done cmd\n");
+ printk("done cmd\n");
#endif
- return count;
- }
+ return count;
+}
static struct file_operations sg_fops = {
- NULL, /* lseek */
- sg_read, /* read */
- sg_write, /* write */
- NULL, /* readdir */
- NULL, /* select */
- sg_ioctl, /* ioctl */
- NULL, /* mmap */
- sg_open, /* open */
- sg_close, /* release */
- NULL /* fsync */
+ NULL, /* lseek */
+ sg_read, /* read */
+ sg_write, /* write */
+ NULL, /* readdir */
+ NULL, /* select */
+ sg_ioctl, /* ioctl */
+ NULL, /* mmap */
+ sg_open, /* open */
+ sg_close, /* release */
+ NULL /* fsync */
};
static int sg_detect(Scsi_Device * SDp){
- ++sg_template.dev_noticed;
- return 1;
+ ++sg_template.dev_noticed;
+ return 1;
}
/* Driver initialization */
static void sg_init()
- {
- static int sg_registered = 0;
-
- if (sg_template.dev_noticed == 0) return;
-
- if(!sg_registered) {
- if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
- {
- printk("Unable to get major %d for generic SCSI device\n",
- SCSI_GENERIC_MAJOR);
- return;
- }
- sg_registered++;
- }
-
- /* If we have already been through here, return */
- if(scsi_generics) return;
-
+{
+ static int sg_registered = 0;
+
+ if (sg_template.dev_noticed == 0) return;
+
+ if(!sg_registered) {
+ if (register_chrdev(SCSI_GENERIC_MAJOR,"sg",&sg_fops))
+ {
+ printk("Unable to get major %d for generic SCSI device\n",
+ SCSI_GENERIC_MAJOR);
+ return;
+ }
+ sg_registered++;
+ }
+
+ /* If we have already been through here, return */
+ if(scsi_generics) return;
+
#ifdef DEBUG
- printk("sg: Init generic device.\n");
+ printk("sg: Init generic device.\n");
#endif
-
+
#ifdef SG_BIG_BUFF
- big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA);
+ big_buff= (char *) scsi_init_malloc(SG_BIG_BUFF, GFP_ATOMIC | GFP_DMA);
#endif
-
- scsi_generics = (struct scsi_generic *)
- scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS)
- * sizeof(struct scsi_generic), GFP_ATOMIC);
- memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS)
- * sizeof(struct scsi_generic));
-
- sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS;
- }
+
+ scsi_generics = (struct scsi_generic *)
+ scsi_init_malloc((sg_template.dev_noticed + SG_EXTRA_DEVS)
+ * sizeof(struct scsi_generic), GFP_ATOMIC);
+ memset(scsi_generics, 0, (sg_template.dev_noticed + SG_EXTRA_DEVS)
+ * sizeof(struct scsi_generic));
+
+ sg_template.dev_max = sg_template.dev_noticed + SG_EXTRA_DEVS;
+}
static int sg_attach(Scsi_Device * SDp)
- {
- struct scsi_generic * gpnt;
- int i;
-
- if(sg_template.nr_dev >= sg_template.dev_max)
- {
- SDp->attached--;
- return 1;
- }
+{
+ struct scsi_generic * gpnt;
+ int i;
+
+ if(sg_template.nr_dev >= sg_template.dev_max)
+ {
+ SDp->attached--;
+ return 1;
+ }
+
+ for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++)
+ if(!gpnt->device) break;
+
+ if(i >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)");
+
+ scsi_generics[i].device=SDp;
+ scsi_generics[i].users=0;
+ scsi_generics[i].generic_wait=NULL;
+ scsi_generics[i].read_wait=NULL;
+ scsi_generics[i].write_wait=NULL;
+ scsi_generics[i].buff=NULL;
+ scsi_generics[i].exclude=0;
+ scsi_generics[i].pending=0;
+ scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT;
+ sg_template.nr_dev++;
+ return 0;
+};
- for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++)
- if(!gpnt->device) break;
- if(i >= sg_template.dev_max) panic ("scsi_devices corrupt (sg)");
- scsi_generics[i].device=SDp;
- scsi_generics[i].users=0;
- scsi_generics[i].generic_wait=NULL;
- scsi_generics[i].read_wait=NULL;
- scsi_generics[i].write_wait=NULL;
- scsi_generics[i].buff=NULL;
- scsi_generics[i].exclude=0;
- scsi_generics[i].pending=0;
- scsi_generics[i].timeout=SG_DEFAULT_TIMEOUT;
- sg_template.nr_dev++;
- return 0;
- };
+static void sg_detach(Scsi_Device * SDp)
+{
+ struct scsi_generic * gpnt;
+ int i;
+
+ for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++)
+ if(gpnt->device == SDp) {
+ gpnt->device = NULL;
+ SDp->attached--;
+ sg_template.nr_dev--;
+ return;
+ }
+ return;
+}
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+int init_module(void) {
+ sg_template.usage_count = &mod_use_count_;
+ return scsi_register_module(MODULE_SCSI_DEV, &sg_template);
+}
-static void sg_detach(Scsi_Device * SDp)
+void cleanup_module( void)
{
- struct scsi_generic * gpnt;
- int i;
-
- for(gpnt = scsi_generics, i=0; i<sg_template.dev_max; i++, gpnt++)
- if(gpnt->device == SDp) {
- gpnt->device = NULL;
- SDp->attached--;
- sg_template.nr_dev--;
- return;
+ if (MOD_IN_USE) {
+ printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+ return;
+ }
+ scsi_unregister_module(MODULE_SCSI_DEV, &sg_template);
+ unregister_chrdev(SCSI_GENERIC_MAJOR, "sg");
+
+ if(scsi_generics != NULL) {
+ scsi_init_free((char *) scsi_generics,
+ (sg_template.dev_noticed + SG_EXTRA_DEVS)
+ * sizeof(struct scsi_generic));
}
- return;
+ sg_template.dev_max = 0;
+#ifdef SG_BIG_BUFF
+ if(big_buff != NULL)
+ scsi_init_free(big_buff, SG_BIG_BUFF);
+#endif
}
+#endif /* MODULE */
/*
- * Overrides for Emacs so that we follow Linus's tabbing style.
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
* Emacs will notice this stuff at the end of the file and automatically
* adjust the settings for this buffer only. This must remain at the end
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
* c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
* End:
*/
#define SG_DEFAULT_RETRIES 1
#define SG_MAX_QUEUE 4 /* maximum outstanding request, arbitrary, may be
- changed if sufficient DMA buffer room available */
+ changed if sufficient DMA buffer room available */
#define SG_BIG_BUFF 32768
/*
- * sr.c Copyright (C) 1992 David Giller
+ * sr.c Copyright (C) 1992 David Giller
* Copyright (C) 1993, 1994, 1995 Eric Youngdale
*
- * adapted from:
+ * adapted from:
* sd.c Copyright (C) 1992 Drew Eckhardt
* Linux scsi disk driver by
- * Drew Eckhardt
+ * Drew Eckhardt <drew@colorado.edu>
*
- * <drew@colorado.edu>
+ * Modified by Eric Youngdale ericy@cais.com to
+ * add scatter-gather, multiple outstanding request, and other
+ * enhancements.
*
- * Modified by Eric Youngdale ericy@cais.com to
- * add scatter-gather, multiple outstanding request, and other
- * enhancements.
- *
- * Modified by Eric Youngdale eric@aib.com to support loadable
- * low-level scsi drivers.
+ * Modified by Eric Youngdale eric@aib.com to support loadable
+ * low-level scsi drivers.
*/
#include <linux/fs.h>
static int sr_detect(Scsi_Device *);
static void sr_detach(Scsi_Device *);
-struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", TYPE_ROM,
- SCSI_CDROM_MAJOR, 0, 0, 0, 1,
- sr_detect, sr_init,
- sr_finish, sr_attach, sr_detach};
+struct Scsi_Device_Template sr_template = {NULL, "cdrom", "sr", NULL, TYPE_ROM,
+ SCSI_CDROM_MAJOR, 0, 0, 0, 1,
+ sr_detect, sr_init,
+ sr_finish, sr_attach, sr_detach};
-Scsi_CD * scsi_CDs;
+Scsi_CD * scsi_CDs = NULL;
static int * sr_sizes;
static int * sr_blocksizes;
{
sync_dev(inode->i_rdev);
if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count)
- sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+ sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
- (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--;
+ (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)--;
+ if(sr_template.usage_count) (*sr_template.usage_count)--;
}
static struct file_operations sr_fops =
{
NULL, /* lseek - default */
block_read, /* read - general block-dev read */
- block_write, /* write - general block-dev write */
+ block_write, /* write - general block-dev write */
NULL, /* readdir - bad */
NULL, /* select */
sr_ioctl, /* ioctl */
NULL, /* mmap */
- sr_open, /* special open code */
+ sr_open, /* special open code */
sr_release, /* release */
NULL, /* fsync */
NULL, /* fasync */
int retval, target;
struct inode inode;
int flag = 0;
-
+
target = MINOR(full_dev);
-
+
if (target >= sr_template.nr_dev) {
printk("CD-ROM request error: invalid device.\n");
return 0;
};
-
+
inode.i_rdev = full_dev; /* This is all we really need here */
retval = sr_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0);
-
+
if(retval){ /* Unable to test, unit probably not ready. This usually
- means there is no disc in the drive. Mark as changed,
- and we will figure it out later once the drive is
- available again. */
-
- scsi_CDs[target].device->changed = 1;
- return 1; /* This will force a flush, if called from
- check_disk_change */
+ * means there is no disc in the drive. Mark as changed,
+ * and we will figure it out later once the drive is
+ * available again. */
+
+ scsi_CDs[target].device->changed = 1;
+ return 1; /* This will force a flush, if called from
+ * check_disk_change */
};
-
+
retval = scsi_CDs[target].device->changed;
if(!flag) {
- scsi_CDs[target].device->changed = 0;
- /* If the disk changed, the capacity will now be different,
- so we force a re-read of this information */
- if (retval) scsi_CDs[target].needs_sector_size = 1;
+ scsi_CDs[target].device->changed = 0;
+ /* If the disk changed, the capacity will now be different,
+ * so we force a re-read of this information */
+ if (retval) scsi_CDs[target].needs_sector_size = 1;
};
return retval;
}
{
int result = SCpnt->result;
int this_count = SCpnt->this_count;
-
+
#ifdef DEBUG
printk("sr.c done: %x %x\n",result, SCpnt->request.bh->b_data);
#endif
if (!result)
- { /* No error */
- if (SCpnt->use_sg == 0) {
+ { /* No error */
+ if (SCpnt->use_sg == 0) {
if (SCpnt->buffer != SCpnt->request.buffer)
- {
- int offset;
- offset = (SCpnt->request.sector % 4) << 9;
- memcpy((char *)SCpnt->request.buffer,
- (char *)SCpnt->buffer + offset,
- this_count << 9);
- /* Even though we are not using scatter-gather, we look
- ahead and see if there is a linked request for the
- other half of this buffer. If there is, then satisfy
- it. */
- if((offset == 0) && this_count == 2 &&
- SCpnt->request.nr_sectors > this_count &&
- SCpnt->request.bh &&
- SCpnt->request.bh->b_reqnext &&
- SCpnt->request.bh->b_reqnext->b_size == 1024) {
- memcpy((char *)SCpnt->request.bh->b_reqnext->b_data,
- (char *)SCpnt->buffer + 1024,
- 1024);
- this_count += 2;
- };
-
- scsi_free(SCpnt->buffer, 2048);
- }
- } else {
+ {
+ int offset;
+ offset = (SCpnt->request.sector % 4) << 9;
+ memcpy((char *)SCpnt->request.buffer,
+ (char *)SCpnt->buffer + offset,
+ this_count << 9);
+ /* Even though we are not using scatter-gather, we look
+ * ahead and see if there is a linked request for the
+ * other half of this buffer. If there is, then satisfy
+ * it. */
+ if((offset == 0) && this_count == 2 &&
+ SCpnt->request.nr_sectors > this_count &&
+ SCpnt->request.bh &&
+ SCpnt->request.bh->b_reqnext &&
+ SCpnt->request.bh->b_reqnext->b_size == 1024) {
+ memcpy((char *)SCpnt->request.bh->b_reqnext->b_data,
+ (char *)SCpnt->buffer + 1024,
+ 1024);
+ this_count += 2;
+ };
+
+ scsi_free(SCpnt->buffer, 2048);
+ }
+ } else {
struct scatterlist * sgpnt;
int i;
sgpnt = (struct scatterlist *) SCpnt->buffer;
for(i=0; i<SCpnt->use_sg; i++) {
- if (sgpnt[i].alt_address) {
- if (sgpnt[i].alt_address != sgpnt[i].address) {
- memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
- };
- scsi_free(sgpnt[i].address, sgpnt[i].length);
- };
+ if (sgpnt[i].alt_address) {
+ if (sgpnt[i].alt_address != sgpnt[i].address) {
+ memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length);
+ };
+ scsi_free(sgpnt[i].address, sgpnt[i].length);
+ };
};
scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */
if(SCpnt->request.sector % 4) this_count -= 2;
-/* See if there is a padding record at the end that needs to be removed */
+ /* See if there is a padding record at the end that needs to be removed */
if(this_count > SCpnt->request.nr_sectors)
- this_count -= 2;
- };
-
+ this_count -= 2;
+ };
+
#ifdef DEBUG
printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors,
this_count);
#endif
if (SCpnt->request.nr_sectors > this_count)
- {
+ {
SCpnt->request.errors = 0;
if (!SCpnt->request.bh)
panic("sr.c: linked page request (%lx %x)",
- SCpnt->request.sector, this_count);
- }
-
- SCpnt = end_scsi_request(SCpnt, 1, this_count); /* All done */
- requeue_sr_request(SCpnt);
- return;
- } /* Normal completion */
-
+ SCpnt->request.sector, this_count);
+ }
+
+ SCpnt = end_scsi_request(SCpnt, 1, this_count); /* All done */
+ requeue_sr_request(SCpnt);
+ return;
+ } /* Normal completion */
+
/* We only come through here if we have an error of some kind */
-
-/* Free up any indirection buffers we allocated for DMA purposes. */
+
+ /* Free up any indirection buffers we allocated for DMA purposes. */
if (SCpnt->use_sg) {
- struct scatterlist * sgpnt;
- int i;
- sgpnt = (struct scatterlist *) SCpnt->buffer;
- for(i=0; i<SCpnt->use_sg; i++) {
+ struct scatterlist * sgpnt;
+ int i;
+ sgpnt = (struct scatterlist *) SCpnt->buffer;
+ for(i=0; i<SCpnt->use_sg; i++) {
if (sgpnt[i].alt_address) {
- scsi_free(sgpnt[i].address, sgpnt[i].length);
+ scsi_free(sgpnt[i].address, sgpnt[i].length);
};
- };
- scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */
+ };
+ scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */
} else {
- if (SCpnt->buffer != SCpnt->request.buffer)
+ if (SCpnt->buffer != SCpnt->request.buffer)
scsi_free(SCpnt->buffer, SCpnt->bufflen);
};
-
+
if (driver_byte(result) != 0) {
if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) {
if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) {
- /* detected disc change. set a bit and quietly refuse */
- /* further access. */
-
+ /* detected disc change. set a bit and quietly refuse
+ * further access. */
+
scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->changed = 1;
SCpnt = end_scsi_request(SCpnt, 0, this_count);
- requeue_sr_request(SCpnt);
+ requeue_sr_request(SCpnt);
return;
}
}
result = 0;
return;
} else {
- SCpnt = end_scsi_request(SCpnt, 0, this_count);
- requeue_sr_request(SCpnt); /* Do next request */
- return;
+ SCpnt = end_scsi_request(SCpnt, 0, this_count);
+ requeue_sr_request(SCpnt); /* Do next request */
+ return;
}
-
+
}
-
+
if (SCpnt->sense_buffer[2] == NOT_READY) {
printk("CDROM not ready. Make sure you have a disc in the drive.\n");
SCpnt = end_scsi_request(SCpnt, 0, this_count);
requeue_sr_request(SCpnt); /* Do next request */
return;
};
- }
+ }
/* We only get this far if we have an error we have not recognized */
if(result) {
- printk("SCSI CD error : host %d id %d lun %d return code = %03x\n",
- scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->host->host_no,
- scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->id,
- scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->lun,
- result);
+ printk("SCSI CD error : host %d id %d lun %d return code = %03x\n",
+ scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->host->host_no,
+ scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->id,
+ scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->lun,
+ result);
- if (status_byte(result) == CHECK_CONDITION)
- print_sense("sr", SCpnt);
-
- SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
- requeue_sr_request(SCpnt);
- }
+ if (status_byte(result) == CHECK_CONDITION)
+ print_sense("sr", SCpnt);
+
+ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors);
+ requeue_sr_request(SCpnt);
+ }
}
/*
static void sr_photocd(struct inode *inode)
{
- unsigned long sector,min,sec,frame;
- unsigned char buf[40]; /* the buffer for the ioctl */
- unsigned char *cmd; /* the scsi-command */
- unsigned char *send; /* the data we send to the drive ... */
- unsigned char *rec; /* ... and get back */
- int rc,is_xa,no_multi;
-
- if (scsi_CDs[MINOR(inode->i_rdev)].xa_flags & 0x02) {
+ unsigned long sector,min,sec,frame;
+ unsigned char buf[40]; /* the buffer for the ioctl */
+ unsigned char *cmd; /* the scsi-command */
+ unsigned char *send; /* the data we send to the drive ... */
+ unsigned char *rec; /* ... and get back */
+ int rc,is_xa,no_multi;
+
+ if (scsi_CDs[MINOR(inode->i_rdev)].xa_flags & 0x02) {
#ifdef DEBUG
- printk("sr_photocd: CDROM and/or the driver does not support multisession CD's");
+ printk("sr_photocd: CDROM and/or the driver does not support multisession CD's");
#endif
- return;
- }
-
- if (!suser()) {
- /* I'm not the superuser, so SCSI_IOCTL_SEND_COMMAND isn't allowed for me.
- * That's why mpcd_sector will be initialized with zero, because I'm not
- * able to get the right value. Necessary only if access_count is 1, else
- * no disk change happened since the last call of this function and we can
- * keep the old value.
- */
- if (1 == scsi_CDs[MINOR(inode->i_rdev)].device->access_count) {
- scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = 0;
- scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
+ return;
}
- return;
- }
-
- sector = 0;
- is_xa = 0;
- no_multi = 0;
- cmd = rec = &buf[8];
-
- switch(scsi_CDs[MINOR(inode->i_rdev)].device->manufacturer) {
-
- case SCSI_MAN_NEC:
+
+ if (!suser()) {
+ /* I'm not the superuser, so SCSI_IOCTL_SEND_COMMAND isn't allowed for me.
+ * That's why mpcd_sector will be initialized with zero, because I'm not
+ * able to get the right value. Necessary only if access_count is 1, else
+ * no disk change happened since the last call of this function and we can
+ * keep the old value.
+ */
+ if (1 == scsi_CDs[MINOR(inode->i_rdev)].device->access_count) {
+ scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = 0;
+ scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
+ }
+ return;
+ }
+
+ sector = 0;
+ is_xa = 0;
+ no_multi = 0;
+ cmd = rec = &buf[8];
+
+ switch(scsi_CDs[MINOR(inode->i_rdev)].device->manufacturer) {
+
+ case SCSI_MAN_NEC:
#ifdef DEBUG
- printk("sr_photocd: use NEC code\n");
+ printk("sr_photocd: use NEC code\n");
#endif
- memset(buf,0,40);
- *((unsigned long*)buf) = 0x0; /* we send nothing... */
- *((unsigned long*)buf+1) = 0x16; /* and receive 0x16 bytes */
- cmd[0] = 0xde;
- cmd[1] = 0x03;
- cmd[2] = 0xb0;
- rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+ memset(buf,0,40);
+ *((unsigned long*)buf) = 0x0; /* we send nothing... */
+ *((unsigned long*)buf+1) = 0x16; /* and receive 0x16 bytes */
+ cmd[0] = 0xde;
+ cmd[1] = 0x03;
+ cmd[2] = 0xb0;
+ rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
SCSI_IOCTL_SEND_COMMAND, buf);
- if (rc != 0) {
- printk("sr_photocd: ioctl error (NEC): 0x%x\n",rc);
- break;
- }
- if (rec[14] != 0 && rec[14] != 0xb0) {
- printk("sr_photocd: Hmm, seems the CDROM doesn't support multisession CD's\n");
- no_multi = 1;
- break;
- }
- min = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16;
- sec = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16;
- frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16;
- sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
- is_xa = (rec[14] == 0xb0);
+ if (rc != 0) {
+ printk("sr_photocd: ioctl error (NEC): 0x%x\n",rc);
+ break;
+ }
+ if (rec[14] != 0 && rec[14] != 0xb0) {
+ printk("sr_photocd: Hmm, seems the CDROM doesn't support multisession CD's\n");
+ no_multi = 1;
+ break;
+ }
+ min = (unsigned long) rec[15]/16*10 + (unsigned long) rec[15]%16;
+ sec = (unsigned long) rec[16]/16*10 + (unsigned long) rec[16]%16;
+ frame = (unsigned long) rec[17]/16*10 + (unsigned long) rec[17]%16;
+ sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+ is_xa = (rec[14] == 0xb0);
#ifdef DEBUG
- if (sector) {
- printk("sr_photocd: multisession CD detected. start: %lu\n",sector);
- }
+ if (sector) {
+ printk("sr_photocd: multisession CD detected. start: %lu\n",sector);
+ }
#endif
- break;
-
- case SCSI_MAN_TOSHIBA:
+ break;
+
+ case SCSI_MAN_TOSHIBA:
#ifdef DEBUG
- printk("sr_photocd: use TOSHIBA code\n");
+ printk("sr_photocd: use TOSHIBA code\n");
#endif
-
- /* we request some disc information (is it a XA-CD ?,
- where starts the last session ?) */
- memset(buf,0,40);
- *((unsigned long*)buf) = 0;
- *((unsigned long*)buf+1) = 4; /* we receive 4 bytes from the drive */
- cmd[0] = 0xc7;
- cmd[1] = 3;
- rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
- SCSI_IOCTL_SEND_COMMAND, buf);
- if (rc != 0) {
- if (rc == 0x28000002) {
- /* Got a "not ready" - error. No chance to find out if this is
- because there is no CD in the drive or because the drive
- don't knows multisession CD's. So I need to do an extra check... */
- if (kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
- SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
- printk("sr_photocd: drive not ready\n");
- } else {
- printk("sr_photocd: Hmm, seems the CDROM doesn't support multisession CD's\n");
- no_multi = 1;
+
+ /* we request some disc information (is it a XA-CD ?,
+ * where starts the last session ?) */
+ memset(buf,0,40);
+ *((unsigned long*)buf) = 0;
+ *((unsigned long*)buf+1) = 4; /* we receive 4 bytes from the drive */
+ cmd[0] = 0xc7;
+ cmd[1] = 3;
+ rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+ SCSI_IOCTL_SEND_COMMAND, buf);
+ if (rc != 0) {
+ if (rc == 0x28000002) {
+ /* Got a "not ready" - error. No chance to find out if this is
+ * because there is no CD in the drive or because the drive
+ * don't knows multisession CD's. So I need to do an extra check... */
+ if (kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+ SCSI_IOCTL_TEST_UNIT_READY, NULL)) {
+ printk("sr_photocd: drive not ready\n");
+ } else {
+ printk("sr_photocd: Hmm, seems the CDROM doesn't support multisession CD's\n");
+ no_multi = 1;
+ }
+ } else
+ printk("sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
+ break; /* if the first ioctl fails, we don't call the second one */
}
- } else
- printk("sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
- break; /* if the first ioctl fails, we don't call the second one */
- }
- is_xa = (rec[0] == 0x20);
- min = (unsigned long) rec[1]/16*10 + (unsigned long) rec[1]%16;
- sec = (unsigned long) rec[2]/16*10 + (unsigned long) rec[2]%16;
- frame = (unsigned long) rec[3]/16*10 + (unsigned long) rec[3]%16;
- sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
- if (sector) {
- sector -= CD_BLOCK_OFFSET;
+ is_xa = (rec[0] == 0x20);
+ min = (unsigned long) rec[1]/16*10 + (unsigned long) rec[1]%16;
+ sec = (unsigned long) rec[2]/16*10 + (unsigned long) rec[2]%16;
+ frame = (unsigned long) rec[3]/16*10 + (unsigned long) rec[3]%16;
+ sector = min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame;
+ if (sector) {
+ sector -= CD_BLOCK_OFFSET;
#ifdef DEBUG
- printk("sr_photocd: multisession CD detected: start: %lu\n",sector);
+ printk("sr_photocd: multisession CD detected: start: %lu\n",sector);
#endif
- }
-
- /* now we do a get_density... */
- memset(buf,0,40);
- *((unsigned long*)buf) = 0;
- *((unsigned long*)buf+1) = 12;
- cmd[0] = 0x1a;
- cmd[2] = 1;
- cmd[4] = 12;
- rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
- SCSI_IOCTL_SEND_COMMAND, buf);
- if (rc != 0) {
- printk("sr_photocd: ioctl error (TOSHIBA #2): 0x%x\n",rc);
- break;
- }
+ }
+
+ /* now we do a get_density... */
+ memset(buf,0,40);
+ *((unsigned long*)buf) = 0;
+ *((unsigned long*)buf+1) = 12;
+ cmd[0] = 0x1a;
+ cmd[2] = 1;
+ cmd[4] = 12;
+ rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+ SCSI_IOCTL_SEND_COMMAND, buf);
+ if (rc != 0) {
+ printk("sr_photocd: ioctl error (TOSHIBA #2): 0x%x\n",rc);
+ break;
+ }
#ifdef DEBUG
- printk("sr_photocd: get_density: 0x%x\n",rec[4]);
+ printk("sr_photocd: get_density: 0x%x\n",rec[4]);
#endif
-
- /* ...and only if necessary a set_density */
- if ((rec[4] != 0x81 && is_xa) || (rec[4] != 0 && !is_xa)) {
+
+ /* ...and only if necessary a set_density */
+ if ((rec[4] != 0x81 && is_xa) || (rec[4] != 0 && !is_xa)) {
#ifdef DEBUG
- printk("sr_photocd: doing set_density\n");
+ printk("sr_photocd: doing set_density\n");
#endif
- memset(buf,0,40);
- *((unsigned long*)buf) = 12; /* sending 12 bytes... */
- *((unsigned long*)buf+1) = 0;
- cmd[0] = 0x15;
- cmd[1] = (1 << 4);
- cmd[4] = 12;
- send = &cmd[6]; /* this is a 6-Byte command */
- send[ 3] = 0x08; /* the data for the command */
- send[ 4] = (is_xa) ? 0x81 : 0; /* density 0x81 for XA-CD's, 0 else */
- send[10] = 0x08;
- rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
- SCSI_IOCTL_SEND_COMMAND, buf);
- if (rc != 0) {
- printk("sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);
- }
- /* The set_density command may have changed the sector size or capacity. */
- scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
- }
- break;
-
- case SCSI_MAN_NEC_OLDCDR:
- case SCSI_MAN_UNKNOWN:
- default:
- sector = 0;
- no_multi = 1;
- break; }
-
- scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;
- if (is_xa)
- scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x01;
- else
- scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
- if (no_multi)
- scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x02;
- return;
+ memset(buf,0,40);
+ *((unsigned long*)buf) = 12; /* sending 12 bytes... */
+ *((unsigned long*)buf+1) = 0;
+ cmd[0] = 0x15;
+ cmd[1] = (1 << 4);
+ cmd[4] = 12;
+ send = &cmd[6]; /* this is a 6-Byte command */
+ send[ 3] = 0x08; /* the data for the command */
+ send[ 4] = (is_xa) ? 0x81 : 0; /* density 0x81 for XA-CD's, 0 else */
+ send[10] = 0x08;
+ rc = kernel_scsi_ioctl(scsi_CDs[MINOR(inode->i_rdev)].device,
+ SCSI_IOCTL_SEND_COMMAND, buf);
+ if (rc != 0) {
+ printk("sr_photocd: ioctl error (TOSHIBA #3): 0x%x\n",rc);
+ }
+ /* The set_density command may have changed the sector size or capacity. */
+ scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
+ }
+ break;
+
+ case SCSI_MAN_NEC_OLDCDR:
+ case SCSI_MAN_UNKNOWN:
+ default:
+ sector = 0;
+ no_multi = 1;
+ break; }
+
+ scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;
+ if (is_xa)
+ scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x01;
+ else
+ scsi_CDs[MINOR(inode->i_rdev)].xa_flags &= ~0x01;
+ if (no_multi)
+ scsi_CDs[MINOR(inode->i_rdev)].xa_flags |= 0x02;
+ return;
}
static int sr_open(struct inode * inode, struct file * filp)
{
if(MINOR(inode->i_rdev) >= sr_template.nr_dev ||
!scsi_CDs[MINOR(inode->i_rdev)].device) return -ENXIO; /* No such device */
-
+
if (filp->f_mode & 2)
return -EROFS;
-
- check_disk_change(inode->i_rdev);
-
+
+ check_disk_change(inode->i_rdev);
+
if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++)
- sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
+ sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0);
if (scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)
- (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++;
-
+ (*scsi_CDs[MINOR(inode->i_rdev)].device->host->hostt->usage_count)++;
+ if(sr_template.usage_count) (*sr_template.usage_count)++;
+
sr_photocd(inode);
-
+
/* If this device did not have media in the drive at boot time, then
- we would have been unable to get the sector size. Check to see if
- this is the case, and try again.
- */
-
+ * we would have been unable to get the sector size. Check to see if
+ * this is the case, and try again.
+ */
+
if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size)
- get_sectorsize(MINOR(inode->i_rdev));
-
+ get_sectorsize(MINOR(inode->i_rdev));
+
return 0;
}
* do_sr_request() is the request handler function for the sr driver. Its function in life
* is to take block device requests, and translate them to SCSI commands.
*/
-
+
static void do_sr_request (void)
{
- Scsi_Cmnd * SCpnt = NULL;
- struct request * req = NULL;
- unsigned long flags;
- int flag = 0;
-
- while (1==1){
- save_flags(flags);
- cli();
- if (CURRENT != NULL && CURRENT->dev == -1) {
- restore_flags(flags);
- return;
- };
-
- INIT_SCSI_REQUEST;
-
- if (flag++ == 0)
- SCpnt = allocate_device(&CURRENT,
- scsi_CDs[DEVICE_NR(MINOR(CURRENT->dev))].device, 0);
- else SCpnt = NULL;
- restore_flags(flags);
-
-/* This is a performance enhancement. We dig down into the request list and
- try and find a queueable request (i.e. device not busy, and host able to
- accept another command. If we find one, then we queue it. This can
- make a big difference on systems with more than one disk drive. We want
- to have the interrupts off when monkeying with the request list, because
- otherwise the kernel might try and slip in a request in between somewhere. */
-
- if (!SCpnt && sr_template.nr_dev > 1){
- struct request *req1;
- req1 = NULL;
- save_flags(flags);
- cli();
- req = CURRENT;
- while(req){
- SCpnt = request_queueable(req,
- scsi_CDs[DEVICE_NR(MINOR(req->dev))].device);
- if(SCpnt) break;
- req1 = req;
- req = req->next;
- };
- if (SCpnt && req->dev == -1) {
- if (req == CURRENT)
- CURRENT = CURRENT->next;
- else
- req1->next = req->next;
- };
- restore_flags(flags);
- };
+ Scsi_Cmnd * SCpnt = NULL;
+ struct request * req = NULL;
+ unsigned long flags;
+ int flag = 0;
- if (!SCpnt)
- return; /* Could not find anything to do */
-
- wake_up(&wait_for_request);
+ while (1==1){
+ save_flags(flags);
+ cli();
+ if (CURRENT != NULL && CURRENT->dev == -1) {
+ restore_flags(flags);
+ return;
+ };
+
+ INIT_SCSI_REQUEST;
+
+ if (flag++ == 0)
+ SCpnt = allocate_device(&CURRENT,
+ scsi_CDs[DEVICE_NR(MINOR(CURRENT->dev))].device, 0);
+ else SCpnt = NULL;
+ restore_flags(flags);
+
+ /* This is a performance enhancement. We dig down into the request list and
+ * try and find a queueable request (i.e. device not busy, and host able to
+ * accept another command. If we find one, then we queue it. This can
+ * make a big difference on systems with more than one disk drive. We want
+ * to have the interrupts off when monkeying with the request list, because
+ * otherwise the kernel might try and slip in a request in between somewhere. */
+
+ if (!SCpnt && sr_template.nr_dev > 1){
+ struct request *req1;
+ req1 = NULL;
+ save_flags(flags);
+ cli();
+ req = CURRENT;
+ while(req){
+ SCpnt = request_queueable(req,
+ scsi_CDs[DEVICE_NR(MINOR(req->dev))].device);
+ if(SCpnt) break;
+ req1 = req;
+ req = req->next;
+ };
+ if (SCpnt && req->dev == -1) {
+ if (req == CURRENT)
+ CURRENT = CURRENT->next;
+ else
+ req1->next = req->next;
+ };
+ restore_flags(flags);
+ };
+
+ if (!SCpnt)
+ return; /* Could not find anything to do */
+
+ wake_up(&wait_for_request);
-/* Queue command */
- requeue_sr_request(SCpnt);
- }; /* While */
+ /* Queue command */
+ requeue_sr_request(SCpnt);
+ }; /* While */
}
void requeue_sr_request (Scsi_Cmnd * SCpnt)
unsigned int dev, block, realcount;
unsigned char cmd[10], *buffer, tries;
int this_count, start, end_rec;
-
+
tries = 2;
-
- repeat:
+
+ repeat:
if(!SCpnt || SCpnt->request.dev <= 0) {
- do_sr_request();
- return;
+ do_sr_request();
+ return;
}
-
+
dev = MINOR(SCpnt->request.dev);
block = SCpnt->request.sector;
buffer = NULL;
this_count = 0;
-
+
if (dev >= sr_template.nr_dev)
- {
+ {
/* printk("CD-ROM request error: invalid device.\n"); */
SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
tries = 2;
goto repeat;
- }
-
+ }
+
if (!scsi_CDs[dev].use)
- {
+ {
/* printk("CD-ROM request error: device marked not in use.\n"); */
SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
tries = 2;
goto repeat;
- }
-
+ }
+
if (scsi_CDs[dev].device->changed)
- {
-/*
- * quietly refuse to do anything to a changed disc until the changed bit has been reset
- */
+ {
+ /*
+ * quietly refuse to do anything to a changed disc
+ * until the changed bit has been reset
+ */
/* printk("CD-ROM has been changed. Prohibiting further I/O.\n"); */
SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
tries = 2;
goto repeat;
- }
+ }
switch (SCpnt->request.cmd)
- {
- case WRITE:
- SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
- goto repeat;
- break;
- case READ :
- cmd[0] = READ_6;
- break;
- default :
- panic ("Unknown sr command %d\n", SCpnt->request.cmd);
- }
+ {
+ case WRITE:
+ SCpnt = end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors);
+ goto repeat;
+ break;
+ case READ :
+ cmd[0] = READ_6;
+ break;
+ default :
+ panic ("Unknown sr command %d\n", SCpnt->request.cmd);
+ }
cmd[1] = (SCpnt->lun << 5) & 0xe0;
-
-/*
- Now do the grungy work of figuring out which sectors we need, and
- where in memory we are going to put them.
-
- The variables we need are:
-
- this_count= number of 512 byte sectors being read
- block = starting cdrom sector to read.
- realcount = # of cdrom sectors to read
-
- The major difference between a scsi disk and a scsi cdrom
-is that we will always use scatter-gather if we can, because we can
-work around the fact that the buffer cache has a block size of 1024,
-and we have 2048 byte sectors. This code should work for buffers that
-are any multiple of 512 bytes long. */
-
+
+ /*
+ * Now do the grungy work of figuring out which sectors we need, and
+ * where in memory we are going to put them.
+ *
+ * The variables we need are:
+ *
+ * this_count= number of 512 byte sectors being read
+ * block = starting cdrom sector to read.
+ * realcount = # of cdrom sectors to read
+ *
+ * The major difference between a scsi disk and a scsi cdrom
+ * is that we will always use scatter-gather if we can, because we can
+ * work around the fact that the buffer cache has a block size of 1024,
+ * and we have 2048 byte sectors. This code should work for buffers that
+ * are any multiple of 512 bytes long. */
+
SCpnt->use_sg = 0;
-
+
if (SCpnt->host->sg_tablesize > 0 &&
(!need_isa_buffer ||
- dma_free_sectors >= 10)) {
- struct buffer_head * bh;
- struct scatterlist * sgpnt;
- int count, this_count_max;
- bh = SCpnt->request.bh;
- this_count = 0;
- count = 0;
- this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4;
- /* Calculate how many links we can use. First see if we need
- a padding record at the start */
- this_count = SCpnt->request.sector % 4;
- if(this_count) count++;
- while(bh && count < SCpnt->host->sg_tablesize) {
+ dma_free_sectors >= 10)) {
+ struct buffer_head * bh;
+ struct scatterlist * sgpnt;
+ int count, this_count_max;
+ bh = SCpnt->request.bh;
+ this_count = 0;
+ count = 0;
+ this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4;
+ /* Calculate how many links we can use. First see if we need
+ * a padding record at the start */
+ this_count = SCpnt->request.sector % 4;
+ if(this_count) count++;
+ while(bh && count < SCpnt->host->sg_tablesize) {
if ((this_count + (bh->b_size >> 9)) > this_count_max) break;
this_count += (bh->b_size >> 9);
count++;
bh = bh->b_reqnext;
- };
- /* Fix up in case of an odd record at the end */
- end_rec = 0;
- if(this_count % 4) {
+ };
+ /* Fix up in case of an odd record at the end */
+ end_rec = 0;
+ if(this_count % 4) {
if (count < SCpnt->host->sg_tablesize) {
- count++;
- end_rec = (4 - (this_count % 4)) << 9;
- this_count += 4 - (this_count % 4);
+ count++;
+ end_rec = (4 - (this_count % 4)) << 9;
+ this_count += 4 - (this_count % 4);
} else {
- count--;
- this_count -= (this_count % 4);
+ count--;
+ this_count -= (this_count % 4);
};
- };
- SCpnt->use_sg = count; /* Number of chains */
- count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes*/
- while( count < (SCpnt->use_sg * sizeof(struct scatterlist)))
+ };
+ SCpnt->use_sg = count; /* Number of chains */
+ count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes*/
+ while( count < (SCpnt->use_sg * sizeof(struct scatterlist)))
count = count << 1;
- SCpnt->sglist_len = count;
- sgpnt = (struct scatterlist * ) scsi_malloc(count);
- if (!sgpnt) {
+ SCpnt->sglist_len = count;
+ sgpnt = (struct scatterlist * ) scsi_malloc(count);
+ if (!sgpnt) {
printk("Warning - running *really* short on DMA buffers\n");
SCpnt->use_sg = 0; /* No memory left - bail out */
- } else {
+ } else {
buffer = (unsigned char *) sgpnt;
count = 0;
bh = SCpnt->request.bh;
if(SCpnt->request.sector % 4) {
- sgpnt[count].length = (SCpnt->request.sector % 4) << 9;
- sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
- if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
- sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete
- if needed */
- count++;
+ sgpnt[count].length = (SCpnt->request.sector % 4) << 9;
+ sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
+ if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
+ sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete
+ if needed */
+ count++;
};
for(bh = SCpnt->request.bh; count < SCpnt->use_sg;
count++, bh = bh->b_reqnext) {
- if (bh) { /* Need a placeholder at the end of the record? */
- sgpnt[count].address = bh->b_data;
- sgpnt[count].length = bh->b_size;
- sgpnt[count].alt_address = NULL;
- } else {
- sgpnt[count].address = (char *) scsi_malloc(end_rec);
- if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
- sgpnt[count].length = end_rec;
- sgpnt[count].alt_address = sgpnt[count].address;
- if (count+1 != SCpnt->use_sg) panic("Bad sr request list");
- break;
- };
- if (((long) sgpnt[count].address) + sgpnt[count].length >
- ISA_DMA_THRESHOLD & (SCpnt->host->unchecked_isa_dma)) {
- sgpnt[count].alt_address = sgpnt[count].address;
- /* We try and avoid exhausting the DMA pool, since it is easier
- to control usage here. In other places we might have a more
- pressing need, and we would be screwed if we ran out */
- if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
- sgpnt[count].address = NULL;
+ if (bh) { /* Need a placeholder at the end of the record? */
+ sgpnt[count].address = bh->b_data;
+ sgpnt[count].length = bh->b_size;
+ sgpnt[count].alt_address = NULL;
} else {
- sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
+ sgpnt[count].address = (char *) scsi_malloc(end_rec);
+ if(!sgpnt[count].address) panic("SCSI DMA pool exhausted.");
+ sgpnt[count].length = end_rec;
+ sgpnt[count].alt_address = sgpnt[count].address;
+ if (count+1 != SCpnt->use_sg) panic("Bad sr request list");
+ break;
};
-/* If we start running low on DMA buffers, we abort the scatter-gather
- operation, and free all of the memory we have allocated. We want to
- ensure that all scsi operations are able to do at least a non-scatter/gather
- operation */
- if(sgpnt[count].address == NULL){ /* Out of dma memory */
- printk("Warning: Running low on SCSI DMA buffers");
- /* Try switching back to a non scatter-gather operation. */
- while(--count >= 0){
- if(sgpnt[count].alt_address)
- scsi_free(sgpnt[count].address, sgpnt[count].length);
- };
- SCpnt->use_sg = 0;
- scsi_free(buffer, SCpnt->sglist_len);
- break;
- }; /* if address == NULL */
- }; /* if need DMA fixup */
+ if (((long) sgpnt[count].address) + sgpnt[count].length > ISA_DMA_THRESHOLD &&
+ SCpnt->host->unchecked_isa_dma) {
+ sgpnt[count].alt_address = sgpnt[count].address;
+ /* We try and avoid exhausting the DMA pool, since it is easier
+ * to control usage here. In other places we might have a more
+ * pressing need, and we would be screwed if we ran out */
+ if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) {
+ sgpnt[count].address = NULL;
+ } else {
+ sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length);
+ };
+ /* If we start running low on DMA buffers, we abort the scatter-gather
+ * operation, and free all of the memory we have allocated. We want to
+ * ensure that all scsi operations are able to do at least a non-scatter/gather
+ * operation */
+ if(sgpnt[count].address == NULL){ /* Out of dma memory */
+ printk("Warning: Running low on SCSI DMA buffers");
+ /* Try switching back to a non scatter-gather operation. */
+ while(--count >= 0){
+ if(sgpnt[count].alt_address)
+ scsi_free(sgpnt[count].address, sgpnt[count].length);
+ };
+ SCpnt->use_sg = 0;
+ scsi_free(buffer, SCpnt->sglist_len);
+ break;
+ }; /* if address == NULL */
+ }; /* if need DMA fixup */
}; /* for loop to fill list */
#ifdef DEBUG
printk("SR: %d %d %d %d %d *** ",SCpnt->use_sg, SCpnt->request.sector,
SCpnt->request.current_nr_sectors,
SCpnt->request.nr_sectors);
for(count=0; count<SCpnt->use_sg; count++)
- printk("SGlist: %d %x %x %x\n", count,
- sgpnt[count].address,
- sgpnt[count].alt_address,
- sgpnt[count].length);
+ printk("SGlist: %d %x %x %x\n", count,
+ sgpnt[count].address,
+ sgpnt[count].alt_address,
+ sgpnt[count].length);
#endif
- }; /* Able to allocate scatter-gather list */
+ }; /* Able to allocate scatter-gather list */
};
if (SCpnt->use_sg == 0){
- /* We cannot use scatter-gather. Do this the old fashion way */
- if (!SCpnt->request.bh)
+ /* We cannot use scatter-gather. Do this the old fashion way */
+ if (!SCpnt->request.bh)
this_count = SCpnt->request.nr_sectors;
- else
+ else
this_count = (SCpnt->request.bh->b_size >> 9);
-
- start = block % 4;
- if (start)
+
+ start = block % 4;
+ if (start)
{
- this_count = ((this_count > 4 - start) ?
- (4 - start) : (this_count));
- buffer = (unsigned char *) scsi_malloc(2048);
+ this_count = ((this_count > 4 - start) ?
+ (4 - start) : (this_count));
+ buffer = (unsigned char *) scsi_malloc(2048);
}
- else if (this_count < 4)
+ else if (this_count < 4)
{
- buffer = (unsigned char *) scsi_malloc(2048);
+ buffer = (unsigned char *) scsi_malloc(2048);
}
- else
+ else
{
- this_count -= this_count % 4;
- buffer = (unsigned char *) SCpnt->request.buffer;
- if (((long) buffer) + (this_count << 9) > ISA_DMA_THRESHOLD &
- (SCpnt->host->unchecked_isa_dma))
+ this_count -= this_count % 4;
+ buffer = (unsigned char *) SCpnt->request.buffer;
+ if (((long) buffer) + (this_count << 9) > ISA_DMA_THRESHOLD &&
+ SCpnt->host->unchecked_isa_dma)
buffer = (unsigned char *) scsi_malloc(this_count << 9);
}
};
-
+
if (scsi_CDs[dev].sector_size == 2048)
- block = block >> 2; /* These are the sectors that the cdrom uses */
+ block = block >> 2; /* These are the sectors that the cdrom uses */
else
- block = block & 0xfffffffc;
-
+ block = block & 0xfffffffc;
+
realcount = (this_count + 3) / 4;
-
+
if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2;
-
+
if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten)
- {
+ {
if (realcount > 0xffff)
- {
+ {
realcount = 0xffff;
this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
- }
-
+ }
+
cmd[0] += READ_10 - READ_6 ;
cmd[2] = (unsigned char) (block >> 24) & 0xff;
cmd[3] = (unsigned char) (block >> 16) & 0xff;
cmd[6] = cmd[9] = 0;
cmd[7] = (unsigned char) (realcount >> 8) & 0xff;
cmd[8] = (unsigned char) realcount & 0xff;
- }
+ }
else
- {
- if (realcount > 0xff)
- {
- realcount = 0xff;
- this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
- }
-
- cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
- cmd[2] = (unsigned char) ((block >> 8) & 0xff);
- cmd[3] = (unsigned char) block & 0xff;
- cmd[4] = (unsigned char) realcount;
- cmd[5] = 0;
- }
-
+ {
+ if (realcount > 0xff)
+ {
+ realcount = 0xff;
+ this_count = realcount * (scsi_CDs[dev].sector_size >> 9);
+ }
+
+ cmd[1] |= (unsigned char) ((block >> 16) & 0x1f);
+ cmd[2] = (unsigned char) ((block >> 8) & 0xff);
+ cmd[3] = (unsigned char) block & 0xff;
+ cmd[4] = (unsigned char) realcount;
+ cmd[5] = 0;
+ }
+
#ifdef DEBUG
- {
- int i;
- printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count);
- printk("Use sg: %d\n", SCpnt->use_sg);
- printk("Dumping command: ");
- for(i=0; i<12; i++) printk("%2.2x ", cmd[i]);
- printk("\n");
- };
+ {
+ int i;
+ printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count);
+ printk("Use sg: %d\n", SCpnt->use_sg);
+ printk("Dumping command: ");
+ for(i=0; i<12; i++) printk("%2.2x ", cmd[i]);
+ printk("\n");
+ };
#endif
-
-/* Some dumb host adapters can speed transfers by knowing the
- * minimum transfersize in advance.
- *
- * We shouldn't disconnect in the middle of a sector, but the cdrom
- * sector size can be larger than the size of a buffer and the
- * transfer may be split to the size of a buffer. So it's safe to
- * assume that we can at least transfer the minimum of the buffer
- * size (1024) and the sector size between each connect / disconnect.
- */
-
- SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ?
- 1024 : scsi_CDs[dev].sector_size;
-
+
+ /* Some dumb host adapters can speed transfers by knowing the
+ * minimum transfersize in advance.
+ *
+ * We shouldn't disconnect in the middle of a sector, but the cdrom
+ * sector size can be larger than the size of a buffer and the
+ * transfer may be split to the size of a buffer. So it's safe to
+ * assume that we can at least transfer the minimum of the buffer
+ * size (1024) and the sector size between each connect / disconnect.
+ */
+
+ SCpnt->transfersize = (scsi_CDs[dev].sector_size > 1024) ?
+ 1024 : scsi_CDs[dev].sector_size;
+
SCpnt->this_count = this_count;
scsi_do_cmd (SCpnt, (void *) cmd, buffer,
- realcount * scsi_CDs[dev].sector_size,
- rw_intr, SR_TIMEOUT, MAX_RETRIES);
+ realcount * scsi_CDs[dev].sector_size,
+ rw_intr, SR_TIMEOUT, MAX_RETRIES);
}
static int sr_detect(Scsi_Device * SDp){
-
- if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
-
- printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n",
- sr_template.dev_noticed++,
- SDp->host->host_no , SDp->id, SDp->lun);
-
- return 1;
+
+ if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 0;
+
+ printk("Detected scsi CD-ROM sr%d at scsi%d, channel %d, id %d, lun %d\n",
+ sr_template.dev_noticed++,
+ SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
+
+ return 1;
}
static int sr_attach(Scsi_Device * SDp){
- Scsi_CD * cpnt;
- int i;
-
- if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1;
-
- if (sr_template.nr_dev >= sr_template.dev_max)
+ Scsi_CD * cpnt;
+ int i;
+
+ if(SDp->type != TYPE_ROM && SDp->type != TYPE_WORM) return 1;
+
+ if (sr_template.nr_dev >= sr_template.dev_max)
{
SDp->attached--;
return 1;
}
-
- for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
- if(!cpnt->device) break;
-
- if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)");
-
- SDp->scsi_request_fn = do_sr_request;
- scsi_CDs[i].device = SDp;
- sr_template.nr_dev++;
- if(sr_template.nr_dev > sr_template.dev_max)
- panic ("scsi_devices corrupt (sr)");
- return 0;
+
+ for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
+ if(!cpnt->device) break;
+
+ if(i >= sr_template.dev_max) panic ("scsi_devices corrupt (sr)");
+
+ SDp->scsi_request_fn = do_sr_request;
+ scsi_CDs[i].device = SDp;
+ sr_template.nr_dev++;
+ if(sr_template.nr_dev > sr_template.dev_max)
+ panic ("scsi_devices corrupt (sr)");
+ return 0;
}
-
+
static void sr_init_done (Scsi_Cmnd * SCpnt)
{
- struct request * req;
-
- req = &SCpnt->request;
- req->dev = 0xfffe; /* Busy, but indicate request done */
-
- if (req->sem != NULL) {
- up(req->sem);
- }
+ struct request * req;
+
+ req = &SCpnt->request;
+ req->dev = 0xfffe; /* Busy, but indicate request done */
+
+ if (req->sem != NULL) {
+ up(req->sem);
+ }
}
static void get_sectorsize(int i){
- unsigned char cmd[10];
- unsigned char *buffer;
- int the_result, retries;
- Scsi_Cmnd * SCpnt;
-
- buffer = (unsigned char *) scsi_malloc(512);
- SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1);
-
- retries = 3;
- do {
- cmd[0] = READ_CAPACITY;
- cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
- memset ((void *) &cmd[2], 0, 8);
- SCpnt->request.dev = 0xffff; /* Mark as really busy */
- SCpnt->cmd_len = 0;
-
- memset(buffer, 0, 8);
-
- scsi_do_cmd (SCpnt,
- (void *) cmd, (void *) buffer,
- 512, sr_init_done, SR_TIMEOUT,
- MAX_RETRIES);
+ unsigned char cmd[10];
+ unsigned char *buffer;
+ int the_result, retries;
+ Scsi_Cmnd * SCpnt;
- if (current == task[0])
- while(SCpnt->request.dev != 0xfffe) barrier();
- else
- if (SCpnt->request.dev != 0xfffe){
- struct semaphore sem = MUTEX_LOCKED;
- SCpnt->request.sem = &sem;
- down(&sem);
- /* Hmm.. Have to ask about this */
- while (SCpnt->request.dev != 0xfffe) schedule();
- };
-
- the_result = SCpnt->result;
- retries--;
-
- } while(the_result && retries);
-
- SCpnt->request.dev = -1; /* Mark as not busy */
-
- wake_up(&SCpnt->device->device_wait);
-
- if (the_result) {
- scsi_CDs[i].capacity = 0x1fffff;
- scsi_CDs[i].sector_size = 2048; /* A guess, just in case */
- scsi_CDs[i].needs_sector_size = 1;
- } else {
- scsi_CDs[i].capacity = (buffer[0] << 24) |
- (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
- scsi_CDs[i].sector_size = (buffer[4] << 24) |
- (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
- if(scsi_CDs[i].sector_size == 0) scsi_CDs[i].sector_size = 2048;
- if(scsi_CDs[i].sector_size != 2048 &&
- scsi_CDs[i].sector_size != 512) {
- printk ("scd%d : unsupported sector size %d.\n",
- i, scsi_CDs[i].sector_size);
- scsi_CDs[i].capacity = 0;
- scsi_CDs[i].needs_sector_size = 1;
+ buffer = (unsigned char *) scsi_malloc(512);
+ SCpnt = allocate_device(NULL, scsi_CDs[i].device, 1);
+
+ retries = 3;
+ do {
+ cmd[0] = READ_CAPACITY;
+ cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0;
+ memset ((void *) &cmd[2], 0, 8);
+ SCpnt->request.dev = 0xffff; /* Mark as really busy */
+ SCpnt->cmd_len = 0;
+
+ memset(buffer, 0, 8);
+
+ scsi_do_cmd (SCpnt,
+ (void *) cmd, (void *) buffer,
+ 512, sr_init_done, SR_TIMEOUT,
+ MAX_RETRIES);
+
+ if (current->pid == 0)
+ while(SCpnt->request.dev != 0xfffe)
+ barrier();
+ else
+ if (SCpnt->request.dev != 0xfffe){
+ struct semaphore sem = MUTEX_LOCKED;
+ SCpnt->request.sem = &sem;
+ down(&sem);
+ /* Hmm.. Have to ask about this */
+ while (SCpnt->request.dev != 0xfffe) schedule();
+ };
+
+ the_result = SCpnt->result;
+ retries--;
+
+ } while(the_result && retries);
+
+ SCpnt->request.dev = -1; /* Mark as not busy */
+
+ wake_up(&SCpnt->device->device_wait);
+
+ if (the_result) {
+ scsi_CDs[i].capacity = 0x1fffff;
+ scsi_CDs[i].sector_size = 2048; /* A guess, just in case */
+ scsi_CDs[i].needs_sector_size = 1;
+ } else {
+ scsi_CDs[i].capacity = (buffer[0] << 24) |
+ (buffer[1] << 16) | (buffer[2] << 8) | buffer[3];
+ scsi_CDs[i].sector_size = (buffer[4] << 24) |
+ (buffer[5] << 16) | (buffer[6] << 8) | buffer[7];
+ if(scsi_CDs[i].sector_size == 0) scsi_CDs[i].sector_size = 2048;
+ if(scsi_CDs[i].sector_size != 2048 &&
+ scsi_CDs[i].sector_size != 512) {
+ printk ("scd%d : unsupported sector size %d.\n",
+ i, scsi_CDs[i].sector_size);
+ scsi_CDs[i].capacity = 0;
+ scsi_CDs[i].needs_sector_size = 1;
+ };
+ if(scsi_CDs[i].sector_size == 2048)
+ scsi_CDs[i].capacity *= 4;
+ scsi_CDs[i].needs_sector_size = 0;
+ sr_sizes[i] = scsi_CDs[i].capacity;
};
- if(scsi_CDs[i].sector_size == 2048)
- scsi_CDs[i].capacity *= 4;
- scsi_CDs[i].needs_sector_size = 0;
- sr_sizes[i] = scsi_CDs[i].capacity;
- };
- scsi_free(buffer, 512);
+ scsi_free(buffer, 512);
}
static void sr_init()
{
int i;
static int sr_registered = 0;
-
+
if(sr_template.dev_noticed == 0) return;
-
+
if(!sr_registered) {
- if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) {
+ if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) {
printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR);
return;
- }
- sr_registered++;
}
-
+ sr_registered++;
+ }
+
if (scsi_CDs) return;
sr_template.dev_max = sr_template.dev_noticed + SR_EXTRA_DEVS;
scsi_CDs = (Scsi_CD *) scsi_init_malloc(sr_template.dev_max * sizeof(Scsi_CD), GFP_ATOMIC);
memset(scsi_CDs, 0, sr_template.dev_max * sizeof(Scsi_CD));
-
+
sr_sizes = (int *) scsi_init_malloc(sr_template.dev_max * sizeof(int), GFP_ATOMIC);
memset(sr_sizes, 0, sr_template.dev_max * sizeof(int));
-
+
sr_blocksizes = (int *) scsi_init_malloc(sr_template.dev_max *
- sizeof(int), GFP_ATOMIC);
+ sizeof(int), GFP_ATOMIC);
for(i=0;i<sr_template.dev_max;i++) sr_blocksizes[i] = 2048;
blksize_size[MAJOR_NR] = sr_blocksizes;
-
+
}
void sr_finish()
{
- int i;
-
+ int i;
+
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
blk_size[MAJOR_NR] = sr_sizes;
-
+
for (i = 0; i < sr_template.nr_dev; ++i)
- {
- /* If we have already seen this, then skip it. Comes up
- with loadable modules. */
- if (scsi_CDs[i].capacity) continue;
- scsi_CDs[i].capacity = 0x1fffff;
- scsi_CDs[i].sector_size = 2048; /* A guess, just in case */
- scsi_CDs[i].needs_sector_size = 1;
+ {
+ /* If we have already seen this, then skip it. Comes up
+ * with loadable modules. */
+ if (scsi_CDs[i].capacity) continue;
+ scsi_CDs[i].capacity = 0x1fffff;
+ scsi_CDs[i].sector_size = 2048; /* A guess, just in case */
+ scsi_CDs[i].needs_sector_size = 1;
#if 0
- /* seems better to leave this for later */
- get_sectorsize(i);
- printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
+ /* seems better to leave this for later */
+ get_sectorsize(i);
+ printk("Scd sectorsize = %d bytes.\n", scsi_CDs[i].sector_size);
#endif
- scsi_CDs[i].use = 1;
- scsi_CDs[i].ten = 1;
- scsi_CDs[i].remap = 1;
- sr_sizes[i] = scsi_CDs[i].capacity;
- }
-
-
+ scsi_CDs[i].use = 1;
+ scsi_CDs[i].ten = 1;
+ scsi_CDs[i].remap = 1;
+ sr_sizes[i] = scsi_CDs[i].capacity;
+ }
+
+
/* If our host adapter is capable of scatter-gather, then we increase
- the read-ahead to 16 blocks (32 sectors). If not, we use
- a two block (4 sector) read ahead. */
+ * the read-ahead to 16 blocks (32 sectors). If not, we use
+ * a two block (4 sector) read ahead. */
if(scsi_CDs[0].device && scsi_CDs[0].device->host->sg_tablesize)
- read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */
+ read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */
else
- read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
-
+ read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
+
return;
}
static void sr_detach(Scsi_Device * SDp)
{
- Scsi_CD * cpnt;
- int i, major;
-
- major = MAJOR_NR << 8;
+ Scsi_CD * cpnt;
+ int i, major;
+
+ major = MAJOR_NR << 8;
+
+ for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
+ if(cpnt->device == SDp) {
+ /*
+ * Since the cdrom is read-only, no need to sync the device.
+ * We should be kind to our buffer cache, however.
+ */
+ invalidate_inodes(major | i);
+ invalidate_buffers(major | i);
+
+ /*
+ * Reset things back to a sane state so that one can re-load a new
+ * driver (perhaps the same one).
+ */
+ cpnt->device = NULL;
+ cpnt->capacity = 0;
+ SDp->attached--;
+ sr_template.nr_dev--;
+ sr_template.dev_noticed--;
+ sr_sizes[i] = 0;
+ return;
+ }
+ return;
+}
+
+
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
- for(cpnt = scsi_CDs, i=0; i<sr_template.dev_max; i++, cpnt++)
- if(cpnt->device == SDp) {
- /*
- * Since the cdrom is read-only, no need to sync the device.
- * We should be kind to our buffer cache, however.
- */
- invalidate_inodes(major | i);
- invalidate_buffers(major | i);
+char kernel_version[] = UTS_RELEASE;
- /*
- * Reset things back to a sane state so that one can re-load a new
- * driver (perhaps the same one).
- */
- cpnt->device = NULL;
- cpnt->capacity = 0;
- SDp->attached--;
- sr_template.nr_dev--;
- sr_template.dev_noticed--;
- sr_sizes[i] = 0;
- return;
+int init_module(void) {
+ sr_template.usage_count = &mod_use_count_;
+ return scsi_register_module(MODULE_SCSI_DEV, &sr_template);
+}
+
+void cleanup_module( void)
+{
+ int i;
+
+ if (MOD_IN_USE) {
+ printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+ return;
}
- return;
+ scsi_unregister_module(MODULE_SCSI_DEV, &sr_template);
+ unregister_blkdev(SCSI_GENERIC_MAJOR, "sr");
+ if(scsi_CDs != NULL) {
+ scsi_init_free((char *) scsi_CDs,
+ (sr_template.dev_noticed + SR_EXTRA_DEVS)
+ * sizeof(Scsi_CD));
+
+ scsi_init_free((char *) sr_sizes, sr_template.dev_max * sizeof(int));
+ scsi_init_free((char *) sr_blocksizes, sr_template.dev_max * sizeof(int));
+ }
+
+ blksize_size[MAJOR_NR] = NULL;
+ blk_dev[MAJOR_NR].request_fn = NULL;
+ blk_size[MAJOR_NR] = NULL;
+ read_ahead[MAJOR_NR] = 0;
+
+ sr_template.dev_max = 0;
}
+#endif /* MODULE */
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
* c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
* End:
*/
static void sr_ioctl_done(Scsi_Cmnd * SCpnt)
{
- struct request * req;
-
- req = &SCpnt->request;
- req->dev = 0xfffe; /* Busy, but indicate request done */
-
- if (req->sem != NULL) {
- up(req->sem);
- }
+ struct request * req;
+
+ req = &SCpnt->request;
+ req->dev = 0xfffe; /* Busy, but indicate request done */
+
+ if (req->sem != NULL) {
+ up(req->sem);
+ }
}
/* We do our own retries because we want to know what the specific
static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength)
{
- Scsi_Cmnd * SCpnt;
- int result;
-
- SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
- scsi_do_cmd(SCpnt,
- (void *) sr_cmd, buffer, buflength, sr_ioctl_done,
- IOCTL_TIMEOUT, IOCTL_RETRIES);
-
-
- if (SCpnt->request.dev != 0xfffe){
- struct semaphore sem = MUTEX_LOCKED;
- SCpnt->request.sem = &sem;
- down(&sem);
- /* Hmm.. Have to ask about this */
- while (SCpnt->request.dev != 0xfffe) schedule();
- };
-
- result = SCpnt->result;
-
-/* Minimal error checking. Ignore cases we know about, and report the rest. */
- if(driver_byte(result) != 0)
- switch(SCpnt->sense_buffer[2] & 0xf) {
- case UNIT_ATTENTION:
+ Scsi_Cmnd * SCpnt;
+ int result;
+
+ SCpnt = allocate_device(NULL, scsi_CDs[target].device, 1);
+ scsi_do_cmd(SCpnt,
+ (void *) sr_cmd, buffer, buflength, sr_ioctl_done,
+ IOCTL_TIMEOUT, IOCTL_RETRIES);
+
+
+ if (SCpnt->request.dev != 0xfffe){
+ struct semaphore sem = MUTEX_LOCKED;
+ SCpnt->request.sem = &sem;
+ down(&sem);
+ /* Hmm.. Have to ask about this */
+ while (SCpnt->request.dev != 0xfffe) schedule();
+ };
+
+ result = SCpnt->result;
+
+ /* Minimal error checking. Ignore cases we know about, and report the rest. */
+ if(driver_byte(result) != 0)
+ switch(SCpnt->sense_buffer[2] & 0xf) {
+ case UNIT_ATTENTION:
scsi_CDs[target].device->changed = 1;
printk("Disc change detected.\n");
break;
- case NOT_READY: /* This happens if there is no disc in drive */
+ case NOT_READY: /* This happens if there is no disc in drive */
printk("CDROM not ready. Make sure there is a disc in the drive.\n");
break;
- case ILLEGAL_REQUEST:
+ case ILLEGAL_REQUEST:
printk("CDROM (ioctl) reports ILLEGAL REQUEST.\n");
break;
- default:
+ default:
printk("SCSI CD error: host %d id %d lun %d return code = %03x\n",
scsi_CDs[target].device->host->host_no,
scsi_CDs[target].device->id,
SCpnt->sense_buffer[2] & 0xf);
};
-
- result = SCpnt->result;
- SCpnt->request.dev = -1; /* Deallocate */
- wake_up(&SCpnt->device->device_wait);
- /* Wake up a process waiting for device*/
- return result;
+
+ result = SCpnt->result;
+ SCpnt->request.dev = -1; /* Deallocate */
+ wake_up(&SCpnt->device->device_wait);
+ /* Wake up a process waiting for device*/
+ return result;
}
int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
{
- u_char sr_cmd[10];
-
- int dev = inode->i_rdev;
- int result, target, err;
-
- target = MINOR(dev);
-
- if (target >= sr_template.nr_dev ||
- !scsi_CDs[target].device) return -ENXIO;
-
- switch (cmd)
- {
- /* Sun-compatible */
- case CDROMPAUSE:
-
- sr_cmd[0] = SCMD_PAUSE_RESUME;
- sr_cmd[1] = scsi_CDs[target].device->lun << 5;
- sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0;
- sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0;
- sr_cmd[8] = 0;
- sr_cmd[9] = 0;
-
- result = do_ioctl(target, sr_cmd, NULL, 255);
- return result;
-
- case CDROMRESUME:
-
- sr_cmd[0] = SCMD_PAUSE_RESUME;
- sr_cmd[1] = scsi_CDs[target].device->lun << 5;
- sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0;
- sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0;
- sr_cmd[8] = 1;
- sr_cmd[9] = 0;
-
- result = do_ioctl(target, sr_cmd, NULL, 255);
-
- return result;
-
- case CDROMPLAYMSF:
- {
- struct cdrom_msf msf;
- memcpy_fromfs(&msf, (void *) arg, sizeof(msf));
-
- sr_cmd[0] = SCMD_PLAYAUDIO_MSF;
- sr_cmd[1] = scsi_CDs[target].device->lun << 5;
- sr_cmd[2] = 0;
- sr_cmd[3] = msf.cdmsf_min0;
- sr_cmd[4] = msf.cdmsf_sec0;
- sr_cmd[5] = msf.cdmsf_frame0;
- sr_cmd[6] = msf.cdmsf_min1;
- sr_cmd[7] = msf.cdmsf_sec1;
- sr_cmd[8] = msf.cdmsf_frame1;
- sr_cmd[9] = 0;
-
- result = do_ioctl(target, sr_cmd, NULL, 255);
- return result;
- }
-
- case CDROMPLAYTRKIND:
- {
- struct cdrom_ti ti;
- memcpy_fromfs(&ti, (void *) arg, sizeof(ti));
-
- sr_cmd[0] = SCMD_PLAYAUDIO_TI;
- sr_cmd[1] = scsi_CDs[target].device->lun << 5;
- sr_cmd[2] = 0;
- sr_cmd[3] = 0;
- sr_cmd[4] = ti.cdti_trk0;
- sr_cmd[5] = ti.cdti_ind0;
- sr_cmd[6] = 0;
- sr_cmd[7] = ti.cdti_trk1;
- sr_cmd[8] = ti.cdti_ind1;
- sr_cmd[9] = 0;
-
- result = do_ioctl(target, sr_cmd, NULL, 255);
-
- return result;
- }
-
- case CDROMREADTOCHDR:
- {
- struct cdrom_tochdr tochdr;
- char * buffer;
-
- sr_cmd[0] = SCMD_READ_TOC;
- sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */
- sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
- sr_cmd[6] = 0;
- sr_cmd[7] = 0; /* MSB of length (12) */
- sr_cmd[8] = 12; /* LSB of length */
- sr_cmd[9] = 0;
-
- buffer = (unsigned char *) scsi_malloc(512);
- if(!buffer) return -ENOMEM;
-
- result = do_ioctl(target, sr_cmd, buffer, 12);
-
- tochdr.cdth_trk0 = buffer[2];
- tochdr.cdth_trk1 = buffer[3];
-
- scsi_free(buffer, 512);
-
- err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tochdr));
- if (err)
- return err;
- memcpy_tofs ((void *) arg, &tochdr, sizeof (struct cdrom_tochdr));
-
- return result;
- }
-
- case CDROMREADTOCENTRY:
- {
- struct cdrom_tocentry tocentry;
- char * buffer;
-
- verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry));
- memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry));
-
- sr_cmd[0] = SCMD_READ_TOC;
- sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */
- sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
- sr_cmd[6] = tocentry.cdte_track;
- sr_cmd[7] = 0; /* MSB of length (12) */
- sr_cmd[8] = 12; /* LSB of length */
- sr_cmd[9] = 0;
-
- buffer = (unsigned char *) scsi_malloc(512);
- if(!buffer) return -ENOMEM;
-
- result = do_ioctl (target, sr_cmd, buffer, 12);
-
- if (tocentry.cdte_format == CDROM_MSF) {
- tocentry.cdte_addr.msf.minute = buffer[9];
- tocentry.cdte_addr.msf.second = buffer[10];
- tocentry.cdte_addr.msf.frame = buffer[11];
- tocentry.cdte_ctrl = buffer[5] & 0xf;
- }
- else
- tocentry.cdte_addr.lba = (int) buffer[0];
-
- scsi_free(buffer, 512);
-
- err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tocentry));
- if (err)
- return err;
- memcpy_tofs ((void *) arg, &tocentry, sizeof (struct cdrom_tocentry));
-
- return result;
- }
-
- case CDROMSTOP:
- sr_cmd[0] = START_STOP;
- sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
- sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
- sr_cmd[4] = 0;
-
- result = do_ioctl(target, sr_cmd, NULL, 255);
- return result;
-
- case CDROMSTART:
- sr_cmd[0] = START_STOP;
- sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
- sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
- sr_cmd[4] = 1;
-
- result = do_ioctl(target, sr_cmd, NULL, 255);
- return result;
-
- case CDROMEJECT:
- if (scsi_CDs[target].device -> access_count != 1)
- return -EBUSY;
-
- sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
- sr_cmd[0] = START_STOP;
- sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1;
- sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
- sr_cmd[4] = 0x02;
-
- if (!(result = do_ioctl(target, sr_cmd, NULL, 255)))
- scsi_CDs[target].device -> changed = 1;
-
- return result;
-
- case CDROMVOLCTRL:
- {
- char * buffer, * mask;
- struct cdrom_volctrl volctrl;
-
- verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl));
- memcpy_fromfs (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl));
-
- /* First we get the current params so we can just twiddle the volume */
-
- sr_cmd[0] = MODE_SENSE;
- sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
- sr_cmd[2] = 0xe; /* Want mode page 0xe, CDROM audio params */
- sr_cmd[3] = 0;
- sr_cmd[4] = 28;
- sr_cmd[5] = 0;
-
- buffer = (unsigned char *) scsi_malloc(512);
- if(!buffer) return -ENOMEM;
-
- if ((result = do_ioctl (target, sr_cmd, buffer, 28))) {
- printk ("Hosed while obtaining audio mode page\n");
- scsi_free(buffer, 512);
- return result;
- }
-
- sr_cmd[0] = MODE_SENSE;
- sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
- sr_cmd[2] = 0x4e; /* Want the mask for mode page 0xe */
- sr_cmd[3] = 0;
- sr_cmd[4] = 28;
- sr_cmd[5] = 0;
-
- mask = (unsigned char *) scsi_malloc(512);
- if(!mask) {
- scsi_free(buffer, 512);
- return -ENOMEM;
- };
-
- if ((result = do_ioctl (target, sr_cmd, mask, 28))) {
- printk ("Hosed while obtaining mask for audio mode page\n");
- scsi_free(buffer, 512);
- scsi_free(mask, 512);
- return result;
- }
-
- /* Now mask and substitute our own volume and reuse the rest */
- buffer[0] = 0; /* Clear reserved field */
-
- buffer[21] = volctrl.channel0 & mask[21];
- buffer[23] = volctrl.channel1 & mask[23];
- buffer[25] = volctrl.channel2 & mask[25];
- buffer[27] = volctrl.channel3 & mask[27];
-
- sr_cmd[0] = MODE_SELECT;
- sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10; /* Params are SCSI-2 */
- sr_cmd[2] = sr_cmd[3] = 0;
- sr_cmd[4] = 28;
- sr_cmd[5] = 0;
-
- result = do_ioctl (target, sr_cmd, buffer, 28);
- scsi_free(buffer, 512);
- scsi_free(mask, 512);
- return result;
- }
-
- case CDROMSUBCHNL:
- {
- struct cdrom_subchnl subchnl;
- char * buffer;
-
- sr_cmd[0] = SCMD_READ_SUBCHANNEL;
- sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */
- sr_cmd[2] = 0x40; /* I do want the subchannel info */
- sr_cmd[3] = 0x01; /* Give me current position info */
- sr_cmd[4] = sr_cmd[5] = 0;
- sr_cmd[6] = 0;
- sr_cmd[7] = 0;
- sr_cmd[8] = 16;
- sr_cmd[9] = 0;
-
- buffer = (unsigned char*) scsi_malloc(512);
- if(!buffer) return -ENOMEM;
-
- result = do_ioctl(target, sr_cmd, buffer, 16);
-
- subchnl.cdsc_audiostatus = buffer[1];
- subchnl.cdsc_format = CDROM_MSF;
- subchnl.cdsc_ctrl = buffer[5] & 0xf;
- subchnl.cdsc_trk = buffer[6];
- subchnl.cdsc_ind = buffer[7];
-
- subchnl.cdsc_reladdr.msf.minute = buffer[13];
- subchnl.cdsc_reladdr.msf.second = buffer[14];
- subchnl.cdsc_reladdr.msf.frame = buffer[15];
- subchnl.cdsc_absaddr.msf.minute = buffer[9];
- subchnl.cdsc_absaddr.msf.second = buffer[10];
- subchnl.cdsc_absaddr.msf.frame = buffer[11];
-
- scsi_free(buffer, 512);
-
- err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_subchnl));
- if (err)
- return err;
- memcpy_tofs ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
- return result;
- }
-
- case CDROMREADMODE2:
- return -EINVAL;
- case CDROMREADMODE1:
- return -EINVAL;
-
- /* block-copy from ../block/sbpcd.c with some adjustments... */
- case CDROMMULTISESSION: /* tell start-of-last-session to user */
- {
- struct cdrom_multisession ms_info;
- long lba;
-
- err = verify_area(VERIFY_READ, (void *) arg,
- sizeof(struct cdrom_multisession));
- if (err) return (err);
-
- memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
-
- if (ms_info.addr_format==CDROM_MSF) { /* MSF-bin requested */
- lba = scsi_CDs[target].mpcd_sector+CD_BLOCK_OFFSET;
- ms_info.addr.msf.minute = lba / (CD_SECS*CD_FRAMES);
- lba %= CD_SECS*CD_FRAMES;
- ms_info.addr.msf.second = lba / CD_FRAMES;
- ms_info.addr.msf.frame = lba % CD_FRAMES;
- } else if (ms_info.addr_format==CDROM_LBA) /* lba requested */
- ms_info.addr.lba=scsi_CDs[target].mpcd_sector;
- else return (-EINVAL);
-
- ms_info.xa_flag=scsi_CDs[target].xa_flags & 0x01;
-
- err=verify_area(VERIFY_WRITE,(void *) arg,
- sizeof(struct cdrom_multisession));
- if (err) return (err);
-
- memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
- return (0);
- }
+ u_char sr_cmd[10];
+
+ int dev = inode->i_rdev;
+ int result, target, err;
+
+ target = MINOR(dev);
+
+ if (target >= sr_template.nr_dev ||
+ !scsi_CDs[target].device) return -ENXIO;
+
+ switch (cmd)
+ {
+ /* Sun-compatible */
+ case CDROMPAUSE:
+
+ sr_cmd[0] = SCMD_PAUSE_RESUME;
+ sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+ sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0;
+ sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0;
+ sr_cmd[8] = 0;
+ sr_cmd[9] = 0;
+
+ result = do_ioctl(target, sr_cmd, NULL, 255);
+ return result;
+
+ case CDROMRESUME:
+
+ sr_cmd[0] = SCMD_PAUSE_RESUME;
+ sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+ sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0;
+ sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0;
+ sr_cmd[8] = 1;
+ sr_cmd[9] = 0;
+
+ result = do_ioctl(target, sr_cmd, NULL, 255);
+
+ return result;
+
+ case CDROMPLAYMSF:
+ {
+ struct cdrom_msf msf;
+ memcpy_fromfs(&msf, (void *) arg, sizeof(msf));
+
+ sr_cmd[0] = SCMD_PLAYAUDIO_MSF;
+ sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+ sr_cmd[2] = 0;
+ sr_cmd[3] = msf.cdmsf_min0;
+ sr_cmd[4] = msf.cdmsf_sec0;
+ sr_cmd[5] = msf.cdmsf_frame0;
+ sr_cmd[6] = msf.cdmsf_min1;
+ sr_cmd[7] = msf.cdmsf_sec1;
+ sr_cmd[8] = msf.cdmsf_frame1;
+ sr_cmd[9] = 0;
+
+ result = do_ioctl(target, sr_cmd, NULL, 255);
+ return result;
+ }
+
+ case CDROMPLAYTRKIND:
+ {
+ struct cdrom_ti ti;
+ memcpy_fromfs(&ti, (void *) arg, sizeof(ti));
+
+ sr_cmd[0] = SCMD_PLAYAUDIO_TI;
+ sr_cmd[1] = scsi_CDs[target].device->lun << 5;
+ sr_cmd[2] = 0;
+ sr_cmd[3] = 0;
+ sr_cmd[4] = ti.cdti_trk0;
+ sr_cmd[5] = ti.cdti_ind0;
+ sr_cmd[6] = 0;
+ sr_cmd[7] = ti.cdti_trk1;
+ sr_cmd[8] = ti.cdti_ind1;
+ sr_cmd[9] = 0;
+
+ result = do_ioctl(target, sr_cmd, NULL, 255);
+
+ return result;
+ }
+
+ case CDROMREADTOCHDR:
+ {
+ struct cdrom_tochdr tochdr;
+ char * buffer;
+
+ sr_cmd[0] = SCMD_READ_TOC;
+ sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */
+ sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
+ sr_cmd[6] = 0;
+ sr_cmd[7] = 0; /* MSB of length (12) */
+ sr_cmd[8] = 12; /* LSB of length */
+ sr_cmd[9] = 0;
+
+ buffer = (unsigned char *) scsi_malloc(512);
+ if(!buffer) return -ENOMEM;
+
+ result = do_ioctl(target, sr_cmd, buffer, 12);
+
+ tochdr.cdth_trk0 = buffer[2];
+ tochdr.cdth_trk1 = buffer[3];
+
+ scsi_free(buffer, 512);
+
+ err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tochdr));
+ if (err)
+ return err;
+ memcpy_tofs ((void *) arg, &tochdr, sizeof (struct cdrom_tochdr));
+
+ return result;
+ }
+
+ case CDROMREADTOCENTRY:
+ {
+ struct cdrom_tocentry tocentry;
+ char * buffer;
+
+ verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry));
+ memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry));
+
+ sr_cmd[0] = SCMD_READ_TOC;
+ sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */
+ sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0;
+ sr_cmd[6] = tocentry.cdte_track;
+ sr_cmd[7] = 0; /* MSB of length (12) */
+ sr_cmd[8] = 12; /* LSB of length */
+ sr_cmd[9] = 0;
+
+ buffer = (unsigned char *) scsi_malloc(512);
+ if(!buffer) return -ENOMEM;
+
+ result = do_ioctl (target, sr_cmd, buffer, 12);
+
+ if (tocentry.cdte_format == CDROM_MSF) {
+ tocentry.cdte_addr.msf.minute = buffer[9];
+ tocentry.cdte_addr.msf.second = buffer[10];
+ tocentry.cdte_addr.msf.frame = buffer[11];
+ tocentry.cdte_ctrl = buffer[5] & 0xf;
+ }
+ else
+ tocentry.cdte_addr.lba = (int) buffer[0];
+
+ scsi_free(buffer, 512);
+
+ err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tocentry));
+ if (err)
+ return err;
+ memcpy_tofs ((void *) arg, &tocentry, sizeof (struct cdrom_tocentry));
+
+ return result;
+ }
+
+ case CDROMSTOP:
+ sr_cmd[0] = START_STOP;
+ sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
+ sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
+ sr_cmd[4] = 0;
+
+ result = do_ioctl(target, sr_cmd, NULL, 255);
+ return result;
+
+ case CDROMSTART:
+ sr_cmd[0] = START_STOP;
+ sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1;
+ sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
+ sr_cmd[4] = 1;
+
+ result = do_ioctl(target, sr_cmd, NULL, 255);
+ return result;
+
+ case CDROMEJECT:
+ if (scsi_CDs[target].device -> access_count != 1)
+ return -EBUSY;
+
+ sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0);
+ sr_cmd[0] = START_STOP;
+ sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1;
+ sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0;
+ sr_cmd[4] = 0x02;
+
+ if (!(result = do_ioctl(target, sr_cmd, NULL, 255)))
+ scsi_CDs[target].device -> changed = 1;
+
+ return result;
+
+ case CDROMVOLCTRL:
+ {
+ char * buffer, * mask;
+ struct cdrom_volctrl volctrl;
+
+ verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl));
+ memcpy_fromfs (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl));
+
+ /* First we get the current params so we can just twiddle the volume */
+
+ sr_cmd[0] = MODE_SENSE;
+ sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
+ sr_cmd[2] = 0xe; /* Want mode page 0xe, CDROM audio params */
+ sr_cmd[3] = 0;
+ sr_cmd[4] = 28;
+ sr_cmd[5] = 0;
+
+ buffer = (unsigned char *) scsi_malloc(512);
+ if(!buffer) return -ENOMEM;
+
+ if ((result = do_ioctl (target, sr_cmd, buffer, 28))) {
+ printk ("Hosed while obtaining audio mode page\n");
+ scsi_free(buffer, 512);
+ return result;
+ }
+
+ sr_cmd[0] = MODE_SENSE;
+ sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5;
+ sr_cmd[2] = 0x4e; /* Want the mask for mode page 0xe */
+ sr_cmd[3] = 0;
+ sr_cmd[4] = 28;
+ sr_cmd[5] = 0;
+
+ mask = (unsigned char *) scsi_malloc(512);
+ if(!mask) {
+ scsi_free(buffer, 512);
+ return -ENOMEM;
+ };
- case BLKRASET:
- if(!suser()) return -EACCES;
- if(!inode->i_rdev) return -EINVAL;
- if(arg > 0xff) return -EINVAL;
- read_ahead[MAJOR(inode->i_rdev)] = arg;
- return 0;
- RO_IOCTLS(dev,arg);
- default:
- return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
- }
+ if ((result = do_ioctl (target, sr_cmd, mask, 28))) {
+ printk ("Hosed while obtaining mask for audio mode page\n");
+ scsi_free(buffer, 512);
+ scsi_free(mask, 512);
+ return result;
+ }
+
+ /* Now mask and substitute our own volume and reuse the rest */
+ buffer[0] = 0; /* Clear reserved field */
+
+ buffer[21] = volctrl.channel0 & mask[21];
+ buffer[23] = volctrl.channel1 & mask[23];
+ buffer[25] = volctrl.channel2 & mask[25];
+ buffer[27] = volctrl.channel3 & mask[27];
+
+ sr_cmd[0] = MODE_SELECT;
+ sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10; /* Params are SCSI-2 */
+ sr_cmd[2] = sr_cmd[3] = 0;
+ sr_cmd[4] = 28;
+ sr_cmd[5] = 0;
+
+ result = do_ioctl (target, sr_cmd, buffer, 28);
+ scsi_free(buffer, 512);
+ scsi_free(mask, 512);
+ return result;
+ }
+
+ case CDROMSUBCHNL:
+ {
+ struct cdrom_subchnl subchnl;
+ char * buffer;
+
+ sr_cmd[0] = SCMD_READ_SUBCHANNEL;
+ sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */
+ sr_cmd[2] = 0x40; /* I do want the subchannel info */
+ sr_cmd[3] = 0x01; /* Give me current position info */
+ sr_cmd[4] = sr_cmd[5] = 0;
+ sr_cmd[6] = 0;
+ sr_cmd[7] = 0;
+ sr_cmd[8] = 16;
+ sr_cmd[9] = 0;
+
+ buffer = (unsigned char*) scsi_malloc(512);
+ if(!buffer) return -ENOMEM;
+
+ result = do_ioctl(target, sr_cmd, buffer, 16);
+
+ subchnl.cdsc_audiostatus = buffer[1];
+ subchnl.cdsc_format = CDROM_MSF;
+ subchnl.cdsc_ctrl = buffer[5] & 0xf;
+ subchnl.cdsc_trk = buffer[6];
+ subchnl.cdsc_ind = buffer[7];
+
+ subchnl.cdsc_reladdr.msf.minute = buffer[13];
+ subchnl.cdsc_reladdr.msf.second = buffer[14];
+ subchnl.cdsc_reladdr.msf.frame = buffer[15];
+ subchnl.cdsc_absaddr.msf.minute = buffer[9];
+ subchnl.cdsc_absaddr.msf.second = buffer[10];
+ subchnl.cdsc_absaddr.msf.frame = buffer[11];
+
+ scsi_free(buffer, 512);
+
+ err = verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_subchnl));
+ if (err)
+ return err;
+ memcpy_tofs ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
+ return result;
+ }
+
+ case CDROMREADMODE2:
+ return -EINVAL;
+ case CDROMREADMODE1:
+ return -EINVAL;
+
+ /* block-copy from ../block/sbpcd.c with some adjustments... */
+ case CDROMMULTISESSION: /* tell start-of-last-session to user */
+ {
+ struct cdrom_multisession ms_info;
+ long lba;
+
+ err = verify_area(VERIFY_READ, (void *) arg,
+ sizeof(struct cdrom_multisession));
+ if (err) return (err);
+
+ memcpy_fromfs(&ms_info, (void *) arg, sizeof(struct cdrom_multisession));
+
+ if (ms_info.addr_format==CDROM_MSF) { /* MSF-bin requested */
+ lba = scsi_CDs[target].mpcd_sector+CD_BLOCK_OFFSET;
+ ms_info.addr.msf.minute = lba / (CD_SECS*CD_FRAMES);
+ lba %= CD_SECS*CD_FRAMES;
+ ms_info.addr.msf.second = lba / CD_FRAMES;
+ ms_info.addr.msf.frame = lba % CD_FRAMES;
+ } else if (ms_info.addr_format==CDROM_LBA) /* lba requested */
+ ms_info.addr.lba=scsi_CDs[target].mpcd_sector;
+ else return (-EINVAL);
+
+ ms_info.xa_flag=scsi_CDs[target].xa_flags & 0x01;
+
+ err=verify_area(VERIFY_WRITE,(void *) arg,
+ sizeof(struct cdrom_multisession));
+ if (err) return (err);
+
+ memcpy_tofs((void *) arg, &ms_info, sizeof(struct cdrom_multisession));
+ return (0);
+ }
+
+ case BLKRASET:
+ if(!suser()) return -EACCES;
+ if(!inode->i_rdev) return -EINVAL;
+ if(arg > 0xff) return -EINVAL;
+ read_ahead[MAJOR(inode->i_rdev)] = arg;
+ return 0;
+ RO_IOCTLS(dev,arg);
+ default:
+ return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg);
+ }
}
/*
* of the file.
* ---------------------------------------------------------------------------
* Local variables:
- * c-indent-level: 8
+ * c-indent-level: 4
* c-brace-imaginary-offset: 0
- * c-brace-offset: -8
- * c-argdecl-indent: 8
- * c-label-offset: -8
- * c-continued-statement-offset: 8
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
* c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 8
* End:
*/
Last modified: Sat Feb 18 10:51:25 1995 by root@kai.home
*/
+#ifdef MODULE
+#include <linux/module.h>
+#include <linux/version.h>
+#endif /* MODULE */
#include <linux/fs.h>
#include <linux/kernel.h>
static int st_write_threshold = ST_WRITE_THRESHOLD;
static int st_max_buffers = ST_MAX_BUFFERS;
-static Scsi_Tape * scsi_tapes;
+static Scsi_Tape * scsi_tapes = NULL;
static void st_init(void);
static int st_attach(Scsi_Device *);
static int st_detect(Scsi_Device *);
static void st_detach(Scsi_Device *);
-struct Scsi_Device_Template st_template = {NULL, "tape", "st", TYPE_TAPE,
+struct Scsi_Device_Template st_template = {NULL, "tape", "st", NULL, TYPE_TAPE,
SCSI_TAPE_MAJOR, 0, 0, 0, 0,
st_detect, st_init,
NULL, st_attach, st_detach};
cmd[0] = TEST_UNIT_READY;
SCpnt->request.dev = dev;
scsi_do_cmd(SCpnt,
- (void *) cmd, (void *) (STp->buffer)->b_data,
- 0, st_sleep_done, ST_LONG_TIMEOUT,
+ (void *) cmd, (void *) (STp->buffer)->b_data,
+ 0, st_sleep_done, ST_LONG_TIMEOUT,
MAX_READY_RETRIES);
if ((STp->buffer)->last_result_fatal != 0) {
if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 &&
(SCpnt->sense_buffer[2] & 0x0f) == NO_TAPE) {
- (STp->mt_status)->mt_fileno = STp->drv_block = 0 ;
+ (STp->mt_status)->mt_fileno = STp->drv_block = 0 ;
printk("st%d: No tape.\n", dev);
STp->ready = ST_NO_TAPE;
} else {
- (STp->mt_status)->mt_fileno = STp->drv_block = (-1);
+ (STp->mt_status)->mt_fileno = STp->drv_block = (-1);
STp->ready = ST_NOT_READY;
}
SCpnt->request.dev = -1; /* Mark as not busy */
cmd[0] = READ_BLOCK_LIMITS;
SCpnt->request.dev = dev;
scsi_do_cmd(SCpnt,
- (void *) cmd, (void *) (STp->buffer)->b_data,
+ (void *) cmd, (void *) (STp->buffer)->b_data,
6, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
cmd[4] = 12;
SCpnt->request.dev = dev;
scsi_do_cmd(SCpnt,
- (void *) cmd, (void *) (STp->buffer)->b_data,
- 12, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
+ (void *) cmd, (void *) (STp->buffer)->b_data,
+ 12, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES);
/* this must be done with interrupts off */
if (scsi_tapes[dev].device->host->hostt->usage_count)
(*scsi_tapes[dev].device->host->hostt->usage_count)++;
+ if(st_template.usage_count) (*st_template.usage_count)++;
return 0;
}
if (scsi_tapes[dev].device->host->hostt->usage_count)
(*scsi_tapes[dev].device->host->hostt->usage_count)--;
+ if(st_template.usage_count) (*st_template.usage_count)--;
return;
}
(STp->buffer)->buffer_bytes, b_point, do_count);
if (STp->block_size == 0)
- blks = transfer = do_count;
+ blks = transfer = do_count;
else {
blks = ((STp->buffer)->buffer_bytes + do_count) /
STp->block_size;
STp->drv_block = 0;
}
undone = (
- (SCpnt->sense_buffer[3] << 24) +
- (SCpnt->sense_buffer[4] << 16) +
- (SCpnt->sense_buffer[5] << 8) +
- SCpnt->sense_buffer[6] );
+ (SCpnt->sense_buffer[3] << 24) +
+ (SCpnt->sense_buffer[4] << 16) +
+ (SCpnt->sense_buffer[5] << 8) +
+ SCpnt->sense_buffer[6] );
if ( (cmd_in == MTFSF) || (cmd_in == MTFSFM) ) {
if (fileno >= 0)
(STp->mt_status)->mt_fileno = fileno - undone ;
i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(mtc));
if (i)
- return i;
+ return i;
memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop));
{
if(SDp->type != TYPE_TAPE) return 0;
- printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n",
+ printk("Detected scsi tape st%d at scsi%d, channel %d, id %d, lun %d\n",
st_template.dev_noticed++,
- SDp->host->host_no , SDp->id, SDp->lun);
+ SDp->host->host_no, SDp->channel, SDp->id, SDp->lun);
return 1;
}
}
return;
}
+
+
+#ifdef MODULE
+char kernel_version[] = UTS_RELEASE;
+
+int init_module(void) {
+ st_template.usage_count = &mod_use_count_;
+ return scsi_register_module(MODULE_SCSI_DEV, &st_template);
+}
+
+void cleanup_module( void)
+{
+ int i;
+
+ if (MOD_IN_USE) {
+ printk(KERN_INFO __FILE__ ": module is in use, remove rejected\n");
+ return;
+ }
+ scsi_unregister_module(MODULE_SCSI_DEV, &st_template);
+ unregister_chrdev(SCSI_GENERIC_MAJOR, "st");
+ if(scsi_tapes != NULL) {
+ scsi_init_free((char *) scsi_tapes,
+ (st_template.dev_noticed + ST_EXTRA_DEVS)
+ * sizeof(Scsi_Tape));
+
+ for (i=0; i < st_nbr_buffers; i++) {
+ scsi_init_free((char *) st_buffers[i],
+ sizeof(ST_buffer) - 1 + st_buffer_size);
+ }
+
+ scsi_init_free((char *) st_buffers, st_nbr_buffers * sizeof(ST_buffer *));
+ }
+ st_template.dev_max = 0;
+}
+#endif /* MODULE */
#ifdef HOSTS_C
-#define TRANTOR_T128 {NULL, NULL, "Trantor T128/T128F/T228", t128_detect, NULL, \
+#define TRANTOR_T128 {NULL, NULL, generic_proc_info, "t128", PROC_SCSI_T128, \
+ "Trantor T128/T128F/T228", t128_detect, NULL, \
NULL, \
NULL, t128_queue_command, t128_abort, t128_reset, NULL, \
t128_biosparam, \
#include <linux/ioport.h>
#include <asm/io.h>
#include <asm/system.h>
+#include <linux/proc_fs.h>
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
}
static inline int port_detect(ushort *port_base, unsigned int j,
- Scsi_Host_Template * tpnt) {
+ Scsi_Host_Template * tpnt) {
unsigned char irq, dma_channel, subversion;
unsigned char in_byte;
unsigned char heads;
unsigned char sectors;
} mapping_table[4] = {
- { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
- };
+ { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 }
+ };
struct config_1 {
unsigned char bios_segment: 3;
if(check_region(*port_base, REGION_SIZE)) {
printk("%s: address 0x%03x in use, skipping probe.\n",
- name, *port_base);
+ name, *port_base);
return FALSE;
}
if (subversion == ISA && request_dma(dma_channel, driver_name)) {
printk("%s: unable to allocate DMA channel %u, detaching.\n",
- name, dma_channel);
+ name, dma_channel);
free_irq(irq);
return FALSE;
}
HD(j)->board_id[40] = 0;
if (strcmp(&HD(j)->board_id[32], "06000600")) {
- printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
- printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n",
- BN(j), &HD(j)->board_id[32]);
- sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
- sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
- }
+ printk("%s: %s.\n", BN(j), &HD(j)->board_id[8]);
+ printk("%s: firmware %s is outdated, FW PROM should be 28004-006.\n",
+ BN(j), &HD(j)->board_id[32]);
+ sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
+ sh[j]->sg_tablesize = MAX_SAFE_SGLIST;
+ }
}
printk("%s: PORT 0x%03x, BIOS 0x%05x, IRQ %u, DMA %u, SG %d, "\
- "Mbox %d, CmdLun %d, C%d.\n", BN(j), sh[j]->io_port,
- (int)sh[j]->base, sh[j]->irq,
- sh[j]->dma_channel, sh[j]->sg_tablesize,
- sh[j]->can_queue, sh[j]->cmd_per_lun,
- sh[j]->hostt->use_clustering);
+ "Mbox %d, CmdLun %d, C%d.\n", BN(j), sh[j]->io_port,
+ (int)sh[j]->base, sh[j]->irq,
+ sh[j]->dma_channel, sh[j]->sg_tablesize,
+ sh[j]->can_queue, sh[j]->cmd_per_lun,
+ sh[j]->hostt->use_clustering);
return TRUE;
}
if (i >= sh[j]->can_queue) i = 0;
if (HD(j)->cp_stat[i] == FREE) {
- HD(j)->last_cp_used = i;
- break;
- }
+ HD(j)->last_cp_used = i;
+ break;
+ }
}
if (k == sh[j]->can_queue) {
printk("%s: qcomm, no free mailbox, resetting.\n", BN(j));
if (HD(j)->in_reset)
- printk("%s: qcomm, already in reset.\n", BN(j));
+ printk("%s: qcomm, already in reset.\n", BN(j));
else if (u14_34f_reset(SCpnt) == SCSI_RESET_SUCCESS)
- panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
+ panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
SCpnt->result = DID_BUS_BUSY << 16;
SCpnt->host_scribble = NULL;
SCpnt->host_scribble = (unsigned char *) &cpp->index;
if (do_trace) printk("%s: qcomm, mbox %d, target %d, pid %ld.\n",
- BN(j), i, SCpnt->target, SCpnt->pid);
+ BN(j), i, SCpnt->target, SCpnt->pid);
cpp->opcode = OP_SCSI;
cpp->xdir = DTD_SCSI;
SCpnt->result = DID_ERROR << 16;
SCpnt->host_scribble = NULL;
printk("%s: qcomm, target %d, pid %ld, adapter busy, DID_ERROR, done.\n",
- BN(j), SCpnt->target, SCpnt->pid);
+ BN(j), SCpnt->target, SCpnt->pid);
restore_flags(flags);
done(SCpnt);
return 0;
if (SCarg->host_scribble == NULL) {
printk("%s: abort, target %d, pid %ld inactive.\n",
- BN(j), SCarg->target, SCarg->pid);
+ BN(j), SCarg->target, SCarg->pid);
return SCSI_ABORT_NOT_RUNNING;
}
i = *(unsigned int *)SCarg->host_scribble;
printk("%s: abort, mbox %d, target %d, pid %ld.\n",
- BN(j), i, SCarg->target, SCarg->pid);
+ BN(j), i, SCarg->target, SCarg->pid);
if (i >= sh[j]->can_queue)
panic("%s: abort, invalid SCarg->host_scribble.\n", BN(j));
printk("%s: abort, mbox %d is in use.\n", BN(j), i);
if (SCarg != HD(j)->cp[i].SCpnt)
- panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
- BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
+ panic("%s: abort, mbox %d, SCarg %p, cp SCpnt %p.\n",
+ BN(j), i, SCarg, HD(j)->cp[i].SCpnt);
restore_flags(flags);
return SCSI_ABORT_SNOOZE;
cli();
j = ((struct hostdata *) SCarg->host->hostdata)->board_number;
printk("%s: reset, enter, target %d, pid %ld.\n",
- BN(j), SCarg->target, SCarg->pid);
+ BN(j), SCarg->target, SCarg->pid);
if (SCarg->host_scribble == NULL)
printk("%s: reset, pid %ld inactive.\n", BN(j), SCarg->pid);
if (HD(j)->cp_stat[i] == FREE) continue;
if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
- continue;
- }
+ HD(j)->cp_stat[i] = FREE;
+ printk("%s: reset, locked mbox %d forced free.\n", BN(j), i);
+ continue;
+ }
SCpnt = HD(j)->cp[i].SCpnt;
HD(j)->cp_stat[i] = IN_RESET;
printk("%s: reset, mbox %d in reset, pid %ld.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->pid);
if (SCpnt == NULL)
- panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
+ panic("%s: reset, mbox %d, SCpnt == NULL.\n", BN(j), i);
if (SCpnt->host_scribble == NULL)
- panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
+ panic("%s: reset, mbox %d, garbled SCpnt.\n", BN(j), i);
if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
+ panic("%s: reset, mbox %d, index mismatch.\n", BN(j), i);
if (SCpnt->scsi_done == NULL)
- panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
+ panic("%s: reset, mbox %d, SCpnt->scsi_done == NULL.\n", BN(j), i);
if (SCpnt == SCarg) arg_done = TRUE;
}
HD(j)->cp_stat[i] = LOCKED;
printk("%s, reset, mbox %d locked, DID_RESET, pid %ld done.\n",
- BN(j), i, SCpnt->pid);
+ BN(j), i, SCpnt->pid);
restore_flags(flags);
SCpnt->scsi_done(SCpnt);
cli();
}
if (do_trace) printk("%s: ihdlr, enter, irq %d, calls %d.\n",
- driver_name, irq, calls[irq]);
+ driver_name, irq, calls[irq]);
/* Service all the boards configured on this irq */
for (j = 0; sh[j] != NULL; j++) {
/* Loop until all interrupts for a board are serviced */
while (inb(sh[j]->io_port + REG_SYS_INTR) & IRQ_ASSERTED) {
- total_loops++;
- loops++;
-
- if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
- BN(j), HD(j)->iocount);
-
- spp = (struct mscp *)inl(sh[j]->io_port + REG_ICM);
-
- /* Clear interrupt pending flag */
- outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
-
- i = spp - HD(j)->cp;
-
- if (i >= sh[j]->can_queue)
- panic("%s: ihdlr, invalid mscp address.\n", BN(j));
-
- if (HD(j)->cp_stat[i] == IGNORE) {
- HD(j)->cp_stat[i] = FREE;
- continue;
- }
- else if (HD(j)->cp_stat[i] == LOCKED) {
- HD(j)->cp_stat[i] = FREE;
- printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
- BN(j), i, HD(j)->iocount);
- continue;
- }
- else if (HD(j)->cp_stat[i] == FREE) {
- printk("%s: ihdlr, mbox %d is free, count %d.\n",
- BN(j), i, HD(j)->iocount);
- continue;
- }
- else if (HD(j)->cp_stat[i] == IN_RESET)
- printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
- else if (HD(j)->cp_stat[i] != IN_USE)
- panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
-
- HD(j)->cp_stat[i] = FREE;
- SCpnt = spp->SCpnt;
-
- if (SCpnt == NULL)
- panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
-
- if (SCpnt->host_scribble == NULL)
- panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n",
- BN(j), i, SCpnt->pid, SCpnt);
-
- if (*(unsigned int *)SCpnt->host_scribble != i)
- panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d,"\
- " irq %d.\n", BN(j), i, SCpnt->pid,
- *(unsigned int *)SCpnt->host_scribble, irq);
-
- tstatus = status_byte(spp->target_status);
-
- switch (spp->adapter_status) {
- case ASOK: /* status OK */
-
- /* Forces a reset if a disk drive keeps returning BUSY */
- if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
- status = DID_ERROR << 16;
-
- /* If there was a bus reset, redo operation on each target */
- else if (tstatus != GOOD
- && SCpnt->device->type == TYPE_DISK
- && HD(j)->target_reset[SCpnt->target])
- status = DID_BUS_BUSY << 16;
-
- /* Works around a flaw in scsi.c */
- else if (tstatus == CHECK_CONDITION
- && SCpnt->device->type == TYPE_DISK
- && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
- status = DID_BUS_BUSY << 16;
-
- else
- status = DID_OK << 16;
-
- if (tstatus == GOOD)
- HD(j)->target_reset[SCpnt->target] = FALSE;
-
- if (spp->target_status && SCpnt->device->type == TYPE_DISK)
- printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
- "0x%x, sense key 0x%x.\n", BN(j),
- SCpnt->target, SCpnt->lun, SCpnt->pid,
- spp->target_status, SCpnt->sense_buffer[2]);
-
- HD(j)->target_time_out[SCpnt->target] = 0;
-
- break;
- case ASST: /* Selection Time Out */
-
- if (HD(j)->target_time_out[SCpnt->target] > 1)
- status = DID_ERROR << 16;
- else {
- status = DID_TIME_OUT << 16;
- HD(j)->target_time_out[SCpnt->target]++;
- }
-
- break;
- case 0x92: /* Data over/under-run */
- case 0x93: /* Unexpected bus free */
- case 0x94: /* Target bus phase sequence failure */
- case 0x96: /* Illegal SCSI command */
- case 0xa3: /* SCSI bus reset error */
-
- if (SCpnt->device->type != TYPE_TAPE)
- status = DID_BUS_BUSY << 16;
- else
- status = DID_ERROR << 16;
-
- for (k = 0; k < MAX_TARGET; k++)
- HD(j)->target_reset[k] = TRUE;
-
- break;
- case 0x01: /* Invalid command */
- case 0x02: /* Invalid parameters */
- case 0x03: /* Invalid data list */
- case 0x84: /* SCSI bus abort error */
- case 0x9b: /* Auto request sense error */
- case 0x9f: /* Unexpected command complete message error */
- case 0xff: /* Invalid parameter in the S/G list */
- default:
- status = DID_ERROR << 16;
- break;
- }
-
- SCpnt->result = status | spp->target_status;
- HD(j)->iocount++;
-
- if (loops > 1) HD(j)->multicount++;
+ total_loops++;
+ loops++;
+
+ if (do_trace) printk("%s: ihdlr, start service, count %d.\n",
+ BN(j), HD(j)->iocount);
+
+ spp = (struct mscp *)inl(sh[j]->io_port + REG_ICM);
+
+ /* Clear interrupt pending flag */
+ outb(CMD_CLR_INTR, sh[j]->io_port + REG_SYS_INTR);
+
+ i = spp - HD(j)->cp;
+
+ if (i >= sh[j]->can_queue)
+ panic("%s: ihdlr, invalid mscp address.\n", BN(j));
+
+ if (HD(j)->cp_stat[i] == IGNORE) {
+ HD(j)->cp_stat[i] = FREE;
+ continue;
+ }
+ else if (HD(j)->cp_stat[i] == LOCKED) {
+ HD(j)->cp_stat[i] = FREE;
+ printk("%s: ihdlr, mbox %d unlocked, count %d.\n",
+ BN(j), i, HD(j)->iocount);
+ continue;
+ }
+ else if (HD(j)->cp_stat[i] == FREE) {
+ printk("%s: ihdlr, mbox %d is free, count %d.\n",
+ BN(j), i, HD(j)->iocount);
+ continue;
+ }
+ else if (HD(j)->cp_stat[i] == IN_RESET)
+ printk("%s: ihdlr, mbox %d is in reset.\n", BN(j), i);
+ else if (HD(j)->cp_stat[i] != IN_USE)
+ panic("%s: ihdlr, mbox %d, invalid cp_stat.\n", BN(j), i);
+
+ HD(j)->cp_stat[i] = FREE;
+ SCpnt = spp->SCpnt;
+
+ if (SCpnt == NULL)
+ panic("%s: ihdlr, mbox %d, SCpnt == NULL.\n", BN(j), i);
+
+ if (SCpnt->host_scribble == NULL)
+ panic("%s: ihdlr, mbox %d, pid %ld, SCpnt %p garbled.\n",
+ BN(j), i, SCpnt->pid, SCpnt);
+
+ if (*(unsigned int *)SCpnt->host_scribble != i)
+ panic("%s: ihdlr, mbox %d, pid %ld, index mismatch %d,"\
+ " irq %d.\n", BN(j), i, SCpnt->pid,
+ *(unsigned int *)SCpnt->host_scribble, irq);
+
+ tstatus = status_byte(spp->target_status);
+
+ switch (spp->adapter_status) {
+ case ASOK: /* status OK */
+
+ /* Forces a reset if a disk drive keeps returning BUSY */
+ if (tstatus == BUSY && SCpnt->device->type != TYPE_TAPE)
+ status = DID_ERROR << 16;
+
+ /* If there was a bus reset, redo operation on each target */
+ else if (tstatus != GOOD
+ && SCpnt->device->type == TYPE_DISK
+ && HD(j)->target_reset[SCpnt->target])
+ status = DID_BUS_BUSY << 16;
+
+ /* Works around a flaw in scsi.c */
+ else if (tstatus == CHECK_CONDITION
+ && SCpnt->device->type == TYPE_DISK
+ && (SCpnt->sense_buffer[2] & 0xf) == RECOVERED_ERROR)
+ status = DID_BUS_BUSY << 16;
+
+ else
+ status = DID_OK << 16;
+
+ if (tstatus == GOOD)
+ HD(j)->target_reset[SCpnt->target] = FALSE;
+
+ if (spp->target_status && SCpnt->device->type == TYPE_DISK)
+ printk("%s: ihdlr, target %d:%d, pid %ld, target_status "\
+ "0x%x, sense key 0x%x.\n", BN(j),
+ SCpnt->target, SCpnt->lun, SCpnt->pid,
+ spp->target_status, SCpnt->sense_buffer[2]);
+
+ HD(j)->target_time_out[SCpnt->target] = 0;
+
+ break;
+ case ASST: /* Selection Time Out */
+
+ if (HD(j)->target_time_out[SCpnt->target] > 1)
+ status = DID_ERROR << 16;
+ else {
+ status = DID_TIME_OUT << 16;
+ HD(j)->target_time_out[SCpnt->target]++;
+ }
+
+ break;
+ case 0x92: /* Data over/under-run */
+ case 0x93: /* Unexpected bus free */
+ case 0x94: /* Target bus phase sequence failure */
+ case 0x96: /* Illegal SCSI command */
+ case 0xa3: /* SCSI bus reset error */
+
+ if (SCpnt->device->type != TYPE_TAPE)
+ status = DID_BUS_BUSY << 16;
+ else
+ status = DID_ERROR << 16;
+
+ for (k = 0; k < MAX_TARGET; k++)
+ HD(j)->target_reset[k] = TRUE;
+
+ break;
+ case 0x01: /* Invalid command */
+ case 0x02: /* Invalid parameters */
+ case 0x03: /* Invalid data list */
+ case 0x84: /* SCSI bus abort error */
+ case 0x9b: /* Auto request sense error */
+ case 0x9f: /* Unexpected command complete message error */
+ case 0xff: /* Invalid parameter in the S/G list */
+ default:
+ status = DID_ERROR << 16;
+ break;
+ }
+
+ SCpnt->result = status | spp->target_status;
+ HD(j)->iocount++;
+
+ if (loops > 1) HD(j)->multicount++;
#if defined (DEBUG_INTERRUPT)
- if (SCpnt->result || do_trace)
+ if (SCpnt->result || do_trace)
#else
- if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
- (spp->adapter_status != ASOK &&
- spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
- do_trace)
+ if ((spp->adapter_status != ASOK && HD(j)->iocount > 1000) ||
+ (spp->adapter_status != ASOK &&
+ spp->adapter_status != ASST && HD(j)->iocount <= 1000) ||
+ do_trace)
#endif
- printk("%s: ihdlr, mbox %d, err 0x%x:%x,"\
- " target %d:%d, pid %ld, count %d.\n",
- BN(j), i, spp->adapter_status, spp->target_status,
- SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount);
+ printk("%s: ihdlr, mbox %d, err 0x%x:%x,"\
+ " target %d:%d, pid %ld, count %d.\n",
+ BN(j), i, spp->adapter_status, spp->target_status,
+ SCpnt->target, SCpnt->lun, SCpnt->pid, HD(j)->iocount);
- /* Set the command state to inactive */
- SCpnt->host_scribble = NULL;
+ /* Set the command state to inactive */
+ SCpnt->host_scribble = NULL;
- restore_flags(flags);
- SCpnt->scsi_done(SCpnt);
- cli();
+ restore_flags(flags);
+ SCpnt->scsi_done(SCpnt);
+ cli();
- } /* Multiple command loop */
+ } /* Multiple command loop */
} /* Boards loop */
if (total_loops == 0)
printk("%s: ihdlr, irq %d, no command completed, calls %d.\n",
- driver_name, irq, calls[irq]);
+ driver_name, irq, calls[irq]);
if (do_trace) printk("%s: ihdlr, exit, irq %d, calls %d.\n",
- driver_name, irq, calls[irq]);
+ driver_name, irq, calls[irq]);
#if defined (DEBUG_STATISTICS)
if ((calls[irq] % 100000) == 10000)
for (j = 0; sh[j] != NULL; j++)
- printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
- calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
+ printk("%s: ihdlr, calls %d, count %d, multi %d.\n", BN(j),
+ calls[(sh[j]->irq)], HD(j)->iocount, HD(j)->multicount);
#endif
restore_flags(flags);
int u14_34f_reset(Scsi_Cmnd *);
int u14_34f_biosparam(Disk *, int, int *);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
#define U14_34F_VERSION "2.01.00"
#define ULTRASTOR_14_34F { \
- NULL, /* Ptr for modules */ \
- NULL, /* usage count for modules */ \
- "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
- u14_34f_detect, \
- NULL, /* Release */ \
- NULL, \
- NULL, \
- u14_34f_queuecommand, \
- u14_34f_abort, \
- u14_34f_reset, \
- NULL, \
- u14_34f_biosparam, \
+ NULL, /* Ptr for modules */ \
+ NULL, /* usage count for modules */ \
+ generic_proc_info, \
+ "u14_34f", \
+ PROC_SCSI_U14_34F, \
+ "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
+ u14_34f_detect, \
+ NULL, /* Release */ \
+ NULL, \
+ NULL, \
+ u14_34f_queuecommand, \
+ u14_34f_abort, \
+ u14_34f_reset, \
+ NULL, \
+ u14_34f_biosparam, \
0, /* can_queue, reset by detect */ \
- 7, /* this_id, reset by detect */ \
- 0, /* sg_tablesize, reset by detect */ \
- 0, /* cmd_per_lun, reset by detect */ \
+ 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 \
- }
+ 1, /* unchecked isa dma, reset by detect */ \
+ ENABLE_CLUSTERING \
+ }
#endif
* Release ICM slot by clearing first byte on 24F.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <linux/stddef.h>
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/ioport.h>
-
+#include <linux/proc_fs.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/system.h>
printk("USx4F: interrupt: returning\n");
#endif
}
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = ULTRASTOR_14F;
+
+#include "scsi_module.c"
+#endif
int ultrastor_reset(Scsi_Cmnd *);
int ultrastor_biosparam(Disk *, int, int *);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
#define ULTRASTOR_14F_MAX_SG 16
#define ULTRASTOR_24F_MAX_SG 33
#define ULTRASTOR_14F { NULL, NULL, /* Ptr for modules*/ \
+ generic_proc_info, \
+ "ultrastor", \
+ PROC_SCSI_ULTRASTOR, \
"UltraStor 14F/24F/34F", \
ultrastor_detect, \
NULL, /* Release */ \
* J.B. Jan 1994.
*/
+#ifdef MODULE
+#include <linux/module.h>
+#endif
+
#include <stdarg.h>
#include <linux/kernel.h>
#include <linux/head.h>
#include <asm/dma.h>
#include <asm/io.h>
#include <linux/ioport.h>
-
+#include <linux/proc_fs.h>
#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
/* ASC Status Port
*/
-#define INT_IM 0x80 /* Interrupt Image Flag */
-#define CMD_RDY 0x40 /* Command Port Ready */
-#define CMD_REJ 0x20 /* Command Port Byte Rejected */
+#define INT_IM 0x80 /* Interrupt Image Flag */
+#define CMD_RDY 0x40 /* Command Port Ready */
+#define CMD_REJ 0x20 /* Command Port Byte Rejected */
#define ASC_INIT 0x10 /* ASC Initialized Flag */
#define ASC_STATMASK 0xf0 /* The lower 4 Bytes are reserved */
#define HARD_RESET_ACK 6 /* SCSI bus hard reset acknowledge */
#define START_OGMB 0x80 /* start command in OGMB (n) */
#define SCAN_OGMBS 0xc0 /* start multiple commands, signature (n) */
- /* where (n) = lower 6 bits */
+ /* where (n) = lower 6 bits */
/* For INITIALIZATION:
*/
typedef struct initCmd {
/* CONTROL port bits
*/
-#define INT_EN 0x08 /* Interrupt Enable */
-#define DMA_EN 0x04 /* DMA Enable */
+#define INT_EN 0x08 /* Interrupt Enable */
+#define DMA_EN 0x04 /* DMA Enable */
#define SCSI_RES 0x02 /* SCSI Reset */
-#define ASC_RES 0x01 /* ASC Reset */
+#define ASC_RES 0x01 /* ASC Reset */
/*
Driver data structures:
unchar linkptr[3]; /* Next Command Link Pointer */
unchar direc; /* Transfer Direction */
unchar reserved2[6]; /* SCSI Command Descriptor Block */
- /* end of hardware SCB */
+ /* end of hardware SCB */
Scsi_Cmnd *SCpnt; /* Scsi_Cmnd using this SCB */
Sgb sgb[WD7000_SG]; /* Scatter/gather list for this SCB */
Adapter *host; /* host adapter */
#define ICB_OP_RECV_SDATA 0x83 /* receive data with status from init. */
#define ICB_OP_SEND_DATA 0x84 /* send data with status to initiator */
#define ICB_OP_SEND_STAT 0x86 /* send command status to initiator */
- /* 0x87 is reserved */
+ /* 0x87 is reserved */
#define ICB_OP_READ_INIT 0x88 /* read initialization bytes */
#define ICB_OP_READ_ID 0x89 /* read adapter's SCSI ID */
#define ICB_OP_SET_UMASK 0x8A /* set unsolicited interrupt mask */
*/
#undef any2scsi
#define any2scsi(up, p) \
-(up)[0] = (((unsigned long)(p)) >> 16); \
+(up)[0] = (((unsigned long)(p)) >> 16); \
(up)[1] = ((unsigned long)(p)) >> 8; \
(up)[2] = ((unsigned long)(p));
{
WAIT(host->iobase+ASC_STAT,ASC_STATMASK,CMD_RDY,0);
while (len--) {
- do {
+ do {
outb(*cmd, host->iobase+ASC_COMMAND);
WAIT(host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
} while (inb(host->iobase+ASC_STAT) & CMD_REJ);
save_flags(flags);
cli();
while (busy) { /* someone else is allocating */
- sti(); /* Yes this is really needed here */
+ sti(); /* Yes this is really needed here */
now = jiffies; while (jiffies == now) /* wait a jiffy */;
cli();
}
busy = 1; /* not busy now; it's our turn */
while (freescbs < needed) {
- timeout = jiffies + WAITnexttimeout;
+ timeout = jiffies + WAITnexttimeout;
do {
sti(); /* Yes this is really needed here */
now = jiffies; while (jiffies == now) /* wait a jiffy */;
printk(", scb is %x",(unsigned int) scbptr);
#endif
if (i >= OGMB_CNT) {
- /*
+ /*
* Alternatively, we might issue the "interrupt on free OGMB",
* and sleep, but it must be ensured that it isn't the init
* task running. Instead, this version assumes that the caller
* that marks OGMB's free, waiting even with interrupts off
* should work, since they are freed very quickly in most cases.
*/
- #ifdef DEBUG
- printk(", no free OGMBs.\n");
+ #ifdef DEBUG
+ printk(", no free OGMBs.\n");
#endif
return 0;
}
hosterr = DID_BAD_TARGET;
break;
case 80: /* Unexpected Reselection */
- case 81: /* Unexpected Selection */
+ case 81: /* Unexpected Selection */
hosterr = DID_BAD_INTR;
break;
- case 82: /* Abort Command Message */
+ case 82: /* Abort Command Message */
hosterr = DID_ABORT;
break;
case 83: /* SCSI Bus Software Reset */
case 84: /* SCSI Bus Hardware Reset */
hosterr = DID_RESET;
break;
- default: /* Reserved */
+ default: /* Reserved */
hosterr = DID_ERROR;
break;
}
#ifdef DEBUG
if (scsierr||hosterr)
- printk("\nSCSI command error: SCSI %02x host %04x return %d",
+ printk("\nSCSI command error: SCSI %02x host %04x return %d",
scsierr,in_error,hosterr);
#endif
return scsierr | (hosterr << 16);
#endif
if (!(inb(host->iobase+ASC_STAT) & INT_IM)) {
- /* NB: these are _very_ possible if IRQ 15 is being used, since
+ /* NB: these are _very_ possible if IRQ 15 is being used, since
it's the "garbage collector" on the 2nd 8259 PIC. Specifically,
any interrupt signal into the 8259 which can't be identified
comes out as 7 from the 8259, which is 15 to the host. Thus, it
}
if (flag & MB_INTR) {
- /* The interrupt is for a mailbox */
+ /* The interrupt is for a mailbox */
if (!(flag & IMB_INTR)) {
#ifdef DEBUG
printk("wd7000_intr_handle: free outgoing mailbox");
icmb_status = icmbs[icmb].status;
if (icmb_status & 0x80) { /* unsolicited - result in ICMB */
#ifdef DEBUG
- printk("wd7000_intr_handle: unsolicited interrupt %02xh\n",
+ printk("wd7000_intr_handle: unsolicited interrupt %02xh\n",
icmb_status);
#endif
- wd7000_intr_ack(host);
- return;
+ wd7000_intr_ack(host);
+ return;
}
scb = (struct scb *) scsi2int((unchar *)icmbs[icmb].scbptr);
icmbs[icmb].status = 0;
if (!(scb->op & ICB_OP_MASK)) { /* an SCB is done */
- SCpnt = scb->SCpnt;
+ SCpnt = scb->SCpnt;
if (--(SCpnt->SCp.phase) <= 0) { /* all scbs are done */
host_error = scb->vue | (icmb_status << 8);
scsi_error = scb->status;
SCpnt->scsi_done(SCpnt);
}
} else { /* an ICB is done */
- icb = (IcbAny *) scb;
+ icb = (IcbAny *) scb;
icb->status = icmb_status;
icb->phase = 0;
}
scb->host = host;
if (SCpnt->use_sg) {
- struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
- unsigned i;
+ struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer;
+ unsigned i;
- if (SCpnt->host->sg_tablesize == SG_NONE) {
+ if (SCpnt->host->sg_tablesize == SG_NONE) {
panic("wd7000_queuecommand: scatter/gather not supported.\n");
}
#ifdef DEBUG
for (i = 0; i < SCpnt->use_sg; i++) {
any2scsi(sgb[i].ptr, (int) sg[i].address);
any2scsi(sgb[i].len, sg[i].length);
- }
+ }
} else {
scb->op = 0;
any2scsi(scb->dataptr, (int) SCpnt->request_buffer);
barrier(); /* wait for completion */
if (icb.phase) {
- printk("wd7000_diagnostics: timed out.\n");
+ printk("wd7000_diagnostics: timed out.\n");
return 0;
}
if (make_code(icb.vue|(icb.status << 8),0)) {
- printk("wd7000_diagnostics: failed (%02x,%02x)\n",
+ printk("wd7000_diagnostics: failed (%02x,%02x)\n",
icb.vue, icb.status);
return 0;
}
int wd7000_init( Adapter *host )
{
InitCmd init_cmd = {
- INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, 0,0,0, OGMB_CNT, ICMB_CNT
+ INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, 0,0,0, OGMB_CNT, ICMB_CNT
};
int diag;
WAIT(host->iobase+ASC_STAT, ASC_STATMASK, CMD_RDY, 0);
if ((diag = inb(host->iobase+ASC_INTR_STAT)) != 1) {
- printk("wd7000_init: ");
- switch (diag) {
+ printk("wd7000_init: ");
+ switch (diag) {
case 2:
printk("RAM failure.\n");
break;
printk("diagnostic code %02Xh received.\n", diag);
break;
}
- return 0;
+ return 0;
}
/* Clear mailboxes */
WAIT(host->iobase+ASC_STAT, ASC_STATMASK, ASC_INIT, 0);
if (request_irq(host->irq, wd7000_intr_handle, SA_INTERRUPT, "wd7000")) {
- printk("wd7000_init: can't get IRQ %d.\n", host->irq);
+ printk("wd7000_init: can't get IRQ %d.\n", host->irq);
return 0;
}
if (request_dma(host->dma,"wd7000")) {
- printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
+ printk("wd7000_init: can't get DMA channel %d.\n", host->dma);
free_irq(host->irq);
return 0;
}
wd7000_enable_intr(host);
if (!wd7000_diagnostics(host,ICB_DIAG_FULL)) {
- free_dma(host->dma);
- free_irq(host->irq);
- return 0;
+ free_dma(host->dma);
+ free_irq(host->irq);
+ return 0;
}
return 1;
cfg = configs;
for (i = 0; i < NUM_CONFIGS; i++) {
- sig = signatures;
+ sig = signatures;
for (j = 0; j < NUM_SIGNATURES; j++) {
if (!memcmp(cfg->bios+sig->ofs, sig->sig, sig->len)) {
- /* matched this one */
+ /* matched this one */
#ifdef DEBUG
printk("WD-7000 SST BIOS detected at %04X: checking...\n",
(int) cfg->bios);
(int)host);
#endif
memset( host, 0, sizeof(Adapter) );
- host->sh = sh;
+ host->sh = sh;
host->irq = cfg->irq;
host->iobase = cfg->iobase;
host->dma = cfg->dma;
printk("Western Digital WD-7000 (%d.%d) ",
host->rev1, host->rev2);
- printk("using IO %xh IRQ %d DMA %d.\n",
+ printk("using IO %xh IRQ %d DMA %d.\n",
host->iobase, host->irq, host->dma);
request_region(host->iobase, 4,"wd7000"); /* Register our ports */
Adapter *host = (Adapter *) SCpnt->host->hostdata;
if (inb(host->iobase+ASC_STAT) & INT_IM) {
- printk("wd7000_abort: lost interrupt\n");
+ printk("wd7000_abort: lost interrupt\n");
wd7000_intr_handle(host->irq, NULL);
return SCSI_ABORT_SUCCESS;
}
/* if (ip[2] >= 1024) ip[2] = 1024; */
return 0;
}
+
+#ifdef MODULE
+/* Eventually this will go into an include file, but this will be later */
+Scsi_Host_Template driver_template = WD7000;
+
+#include "scsi_module.c"
+#endif
int wd7000_reset(Scsi_Cmnd *);
int wd7000_biosparam(Disk *, int, int*);
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
+
#ifndef NULL
#define NULL 0L
#endif
#define WD7000_Q 16
#define WD7000_SG 16
-#define WD7000 { NULL, NULL, \
+#define WD7000 { NULL, NULL, \
+ generic_proc_info, \
+ "wd7000", \
+ PROC_SCSI_7000FASST, \
"Western Digital WD-7000", \
wd7000_detect, \
NULL, \
- NULL, \
- wd7000_command, \
- wd7000_queuecommand, \
+ NULL, \
+ wd7000_command, \
+ wd7000_queuecommand, \
wd7000_abort, \
wd7000_reset, \
NULL, \
#endif
#include <linux/fs.h>
+#include <linux/stat.h>
#include <linux/sched.h>
#include <linux/mm.h>
#include <linux/mman.h>
#include <linux/malloc.h>
#include <linux/shm.h>
#include <linux/personality.h>
+#include <linux/elfcore.h>
#include <asm/segment.h>
#include <asm/pgtable.h>
static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs);
static int load_elf_library(int fd);
+static int elf_core_dump(long signr, struct pt_regs * regs);
+extern int dump_fpu (elf_fpregset_t *);
struct linux_binfmt elf_format = {
#ifndef MODULE
- NULL, NULL, load_elf_binary, load_elf_library, NULL
+ NULL, NULL, load_elf_binary, load_elf_library, elf_core_dump
#else
- NULL, &mod_use_count_, load_elf_binary, load_elf_library, NULL
+ NULL, &mod_use_count_, load_elf_binary, load_elf_library, elf_core_dump
#endif
};
return 0;
}
+/*
+ * ELF core dumper
+ *
+ * Modelled on fs/exec.c:aout_core_dump()
+ * Jeremy Fitzhardinge <jeremy@sw.oz.au>
+ */
+/*
+ * These are the only things you should do on a core-file: use only these
+ * functions to write out all the necessary info.
+ */
+static int dump_write(struct file *file, void *addr, int nr)
+{
+ return file->f_op->write(file->f_inode, file, addr, nr) == nr;
+}
+
+static int dump_seek(struct file *file, off_t off)
+{
+ if (file->f_op->lseek) {
+ if (file->f_op->lseek(file->f_inode, file, off, 0) != off)
+ return 0;
+ } else
+ file->f_pos = off;
+ return 1;
+}
+
+/*
+ * Decide whether a segment is worth dumping; default is yes to be
+ * sure (missing info is worse than too much; etc).
+ * Personally I'd include everything, and use the coredump limit...
+ *
+ * I think we should skip something. But I am not sure how. H.J.
+ */
+static inline int maydump(struct vm_area_struct *vma)
+{
+#if 1
+ if (vma->vm_flags & (VM_WRITE|VM_GROWSUP|VM_GROWSDOWN))
+ return 1;
+ if (vma->vm_flags & (VM_READ|VM_EXEC|VM_EXECUTABLE|VM_SHARED))
+ return 0;
+#endif
+ return 1;
+}
+
+#define roundup(x, y) ((((x)+((y)-1))/(y))*(y))
+
+/* An ELF note in memory */
+struct memelfnote
+{
+ char *name;
+ int type;
+ unsigned int datasz;
+ void *data;
+};
+
+static int notesize(struct memelfnote *en)
+{
+ int sz;
+
+ sz = sizeof(struct elf_note);
+ sz += roundup(strlen(en->name), 4);
+ sz += roundup(en->datasz, 4);
+
+ return sz;
+}
+
+/* #define DEBUG */
+
+#ifdef DEBUG
+static void dump_regs(const char *str, elf_greg_t *r)
+{
+ int i;
+ static const char *regs[] = { "ebx", "ecx", "edx", "esi", "edi", "ebp",
+ "eax", "ds", "es", "fs", "gs",
+ "orig_eax", "eip", "cs",
+ "efl", "uesp", "ss"};
+ printk("Registers: %s\n", str);
+
+ for(i = 0; i < ELF_NGREG; i++)
+ {
+ unsigned long val = r[i];
+ printk(" %-2d %-5s=%08lx %lu\n", i, regs[i], val, val);
+ }
+}
+#endif
+
+#define DUMP_WRITE(addr, nr) \
+ do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
+#define DUMP_SEEK(off) \
+ do { if (!dump_seek(file, (off))) return 0; } while(0)
+
+static int writenote(struct memelfnote *men, struct file *file)
+{
+ struct elf_note en;
+
+ en.n_namesz = strlen(men->name);
+ en.n_descsz = men->datasz;
+ en.n_type = men->type;
+
+ DUMP_WRITE(&en, sizeof(en));
+ DUMP_WRITE(men->name, en.n_namesz);
+ /* XXX - cast from long long to long to avoid need for libgcc.a */
+ DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
+ DUMP_WRITE(men->data, men->datasz);
+ DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
+
+ return 1;
+}
+#undef DUMP_WRITE
+#undef DUMP_SEEK
+
+#define DUMP_WRITE(addr, nr) \
+ if (!dump_write(&file, (addr), (nr))) \
+ goto close_coredump;
+#define DUMP_SEEK(off) \
+ if (!dump_seek(&file, (off))) \
+ goto close_coredump;
+/*
+ * Actual dumper
+ *
+ * This is a two-pass process; first we find the offsets of the bits,
+ * and then they are actually written out. If we run out of core limit
+ * we just truncate.
+ */
+static int elf_core_dump(long signr, struct pt_regs * regs)
+{
+ int has_dumped = 0;
+ struct file file;
+ struct inode *inode;
+ unsigned short fs;
+ char corefile[6+sizeof(current->comm)];
+ int segs;
+ int i;
+ size_t size;
+ struct vm_area_struct *vma;
+ struct elfhdr elf;
+ off_t offset = 0, dataoff;
+ int limit = current->rlim[RLIMIT_CORE].rlim_cur;
+ int numnote = 4;
+ struct memelfnote notes[4];
+ struct elf_prstatus prstatus; /* NT_PRSTATUS */
+ elf_fpregset_t fpu; /* NT_PRFPREG */
+ struct elf_prpsinfo psinfo; /* NT_PRPSINFO */
+
+ if (!current->dumpable || limit < PAGE_SIZE)
+ return 0;
+ current->dumpable = 0;
+
+#ifndef CONFIG_BINFMT_ELF
+ MOD_INC_USE_COUNT;
+#endif
+
+ /* Count what's needed to dump, up to the limit of coredump size */
+ segs = 0;
+ size = 0;
+ for(vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
+ int sz = vma->vm_end-vma->vm_start;
+
+ if (!maydump(vma))
+ continue;
+
+ if (size+sz > limit)
+ break;
+
+ segs++;
+ size += sz;
+ }
+#ifdef DEBUG
+ printk("elf_core_dump: %d segs taking %d bytes\n", segs, size);
+#endif
+
+ /* Set up header */
+ memcpy(elf.e_ident, ELFMAG, SELFMAG);
+ elf.e_ident[EI_CLASS] = ELFCLASS32;
+ elf.e_ident[EI_DATA] = ELFDATA2LSB;
+ elf.e_ident[EI_VERSION] = EV_CURRENT;
+ memset(elf.e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
+
+ elf.e_type = ET_CORE;
+ elf.e_machine = EM_386;
+ elf.e_version = EV_CURRENT;
+ elf.e_entry = 0;
+ elf.e_phoff = sizeof(elf);
+ elf.e_shoff = 0;
+ elf.e_flags = 0;
+ elf.e_ehsize = sizeof(elf);
+ elf.e_phentsize = sizeof(struct elf_phdr);
+ elf.e_phnum = segs+1; /* Include notes */
+ elf.e_shentsize = 0;
+ elf.e_shnum = 0;
+ elf.e_shstrndx = 0;
+
+ fs = get_fs();
+ set_fs(KERNEL_DS);
+ memcpy(corefile,"core.",5);
+#if 0
+ memcpy(corefile+5,current->comm,sizeof(current->comm));
+#else
+ corefile[4] = '\0';
+#endif
+ if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) {
+ inode = NULL;
+ goto end_coredump;
+ }
+ if (!S_ISREG(inode->i_mode))
+ goto end_coredump;
+ if (!inode->i_op || !inode->i_op->default_file_ops)
+ goto end_coredump;
+ file.f_mode = 3;
+ file.f_flags = 0;
+ file.f_count = 1;
+ file.f_inode = inode;
+ file.f_pos = 0;
+ file.f_reada = 0;
+ file.f_op = inode->i_op->default_file_ops;
+ if (file.f_op->open)
+ if (file.f_op->open(inode,&file))
+ goto end_coredump;
+ if (!file.f_op->write)
+ goto close_coredump;
+ has_dumped = 1;
+
+ DUMP_WRITE(&elf, sizeof(elf));
+ offset += sizeof(elf); /* Elf header */
+ offset += (segs+1) * sizeof(struct elf_phdr); /* Program headers */
+
+ /*
+ * Set up the notes in similar form to SVR4 core dumps made
+ * with info from their /proc.
+ */
+ memset(&psinfo, 0, sizeof(psinfo));
+ memset(&prstatus, 0, sizeof(prstatus));
+
+ notes[0].name = "CORE";
+ notes[0].type = NT_PRSTATUS;
+ notes[0].datasz = sizeof(prstatus);
+ notes[0].data = &prstatus;
+ prstatus.pr_info.si_signo = prstatus.pr_cursig = signr;
+ prstatus.pr_sigpend = current->signal;
+ prstatus.pr_sighold = current->blocked;
+ psinfo.pr_pid = prstatus.pr_pid = current->pid;
+ psinfo.pr_ppid = prstatus.pr_ppid = current->p_pptr->pid;
+ psinfo.pr_pgrp = prstatus.pr_pgrp = current->pgrp;
+ psinfo.pr_sid = prstatus.pr_sid = current->session;
+ prstatus.pr_utime.tv_sec = CT_TO_SECS(current->utime);
+ prstatus.pr_utime.tv_usec = CT_TO_USECS(current->utime);
+ prstatus.pr_stime.tv_sec = CT_TO_SECS(current->stime);
+ prstatus.pr_stime.tv_usec = CT_TO_USECS(current->stime);
+ prstatus.pr_cutime.tv_sec = CT_TO_SECS(current->cutime);
+ prstatus.pr_cutime.tv_usec = CT_TO_USECS(current->cutime);
+ prstatus.pr_cstime.tv_sec = CT_TO_SECS(current->cstime);
+ prstatus.pr_cstime.tv_usec = CT_TO_USECS(current->cstime);
+ if (sizeof(elf_gregset_t) != sizeof(struct pt_regs))
+ {
+ printk("sizeof(elf_gregset_t) (%d) != sizeof(struct pt_regs) (%d)\n",
+ sizeof(elf_gregset_t), sizeof(struct pt_regs));
+ }
+ else
+ *(struct pt_regs *)&prstatus.pr_reg = *regs;
+
+#ifdef DEBUG
+ dump_regs("Passed in regs", (elf_greg_t *)regs);
+ dump_regs("prstatus regs", (elf_greg_t *)&prstatus.pr_reg);
+#endif
+
+ notes[1].name = "CORE";
+ notes[1].type = NT_PRPSINFO;
+ notes[1].datasz = sizeof(psinfo);
+ notes[1].data = &psinfo;
+ psinfo.pr_state = current->state;
+ psinfo.pr_sname = (current->state < 0 || current->state > 5) ? '.' : "RSDZTD"[current->state];
+ psinfo.pr_zomb = psinfo.pr_sname == 'Z';
+ psinfo.pr_nice = current->priority-15;
+ psinfo.pr_flag = current->flags;
+ psinfo.pr_uid = current->uid;
+ psinfo.pr_gid = current->gid;
+ {
+ int i, len;
+
+ set_fs(fs);
+
+ len = current->mm->arg_end - current->mm->arg_start;
+ len = len >= ELF_PRARGSZ ? ELF_PRARGSZ : len;
+ memcpy_fromfs(&psinfo.pr_psargs,
+ (const char *)current->mm->arg_start, len);
+ for(i = 0; i < len; i++)
+ if (psinfo.pr_psargs[i] == 0)
+ psinfo.pr_psargs[i] = ' ';
+ psinfo.pr_psargs[len] = 0;
+
+ set_fs(KERNEL_DS);
+ }
+ strncpy(psinfo.pr_fname, current->comm, sizeof(psinfo.pr_fname));
+
+ notes[2].name = "CORE";
+ notes[2].type = NT_TASKSTRUCT;
+ notes[2].datasz = sizeof(*current);
+ notes[2].data = current;
+
+ /* Try to dump the fpu. */
+ prstatus.pr_fpvalid = dump_fpu (&fpu);
+ if (!prstatus.pr_fpvalid)
+ {
+ numnote--;
+ }
+ else
+ {
+ notes[3].name = "CORE";
+ notes[3].type = NT_PRFPREG;
+ notes[3].datasz = sizeof(fpu);
+ notes[3].data = &fpu;
+ }
+
+ /* Write notes phdr entry */
+ {
+ struct elf_phdr phdr;
+ int sz = 0;
+
+ for(i = 0; i < numnote; i++)
+ sz += notesize(¬es[i]);
+
+ phdr.p_type = PT_NOTE;
+ phdr.p_offset = offset;
+ phdr.p_vaddr = 0;
+ phdr.p_paddr = 0;
+ phdr.p_filesz = sz;
+ phdr.p_memsz = 0;
+ phdr.p_flags = 0;
+ phdr.p_align = 0;
+
+ offset += phdr.p_filesz;
+ DUMP_WRITE(&phdr, sizeof(phdr));
+ }
+
+ /* Page-align dumped data */
+ dataoff = offset = roundup(offset, PAGE_SIZE);
+
+ /* Write program headers for segments dump */
+ for(vma = current->mm->mmap, i = 0;
+ i < segs && vma != NULL; vma = vma->vm_next) {
+ struct elf_phdr phdr;
+ size_t sz;
+
+ if (!maydump(vma))
+ continue;
+ i++;
+
+ sz = vma->vm_end - vma->vm_start;
+
+ phdr.p_type = PT_LOAD;
+ phdr.p_offset = offset;
+ phdr.p_vaddr = vma->vm_start;
+ phdr.p_paddr = 0;
+ phdr.p_filesz = sz;
+ phdr.p_memsz = sz;
+ offset += sz;
+ phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
+ if (vma->vm_flags & VM_WRITE) phdr.p_flags |= PF_W;
+ if (vma->vm_flags & VM_EXEC) phdr.p_flags |= PF_X;
+ phdr.p_align = PAGE_SIZE;
+
+ DUMP_WRITE(&phdr, sizeof(phdr));
+ }
+
+ for(i = 0; i < numnote; i++)
+ if (!writenote(¬es[i], &file))
+ goto close_coredump;
+
+ set_fs(fs);
+
+ DUMP_SEEK(dataoff);
+
+ for(i = 0, vma = current->mm->mmap;
+ i < segs && vma != NULL;
+ vma = vma->vm_next) {
+ unsigned long addr = vma->vm_start;
+ unsigned long len = vma->vm_end - vma->vm_start;
+
+ if (!maydump(vma))
+ continue;
+ i++;
+#ifdef DEBUG
+ printk("elf_core_dump: writing %08lx %lx\n", addr, len);
+#endif
+ DUMP_WRITE((void *)addr, len);
+ }
+
+ if ((off_t) file.f_pos != offset) {
+ /* Sanity check */
+ printk("elf_core_dump: file.f_pos (%ld) != offset (%ld)\n",
+ (off_t) file.f_pos, offset);
+ }
+
+ close_coredump:
+ if (file.f_op->release)
+ file.f_op->release(inode,&file);
+
+ end_coredump:
+ set_fs(fs);
+ iput(inode);
+#ifndef CONFIG_BINFMT_ELF
+ MOD_DEC_USE_COUNT;
+#endif
+ return has_dumped;
+}
+
#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
return 0;
}
+
void cleanup_module( void) {
if (MOD_IN_USE)
if (!fops->check_media_change(dev))
return 0;
- printk("VFS: Disk change detected on device %d/%d\n",
+ printk(KERN_DEBUG "VFS: Disk change detected on device %d/%d\n",
MAJOR(dev), MINOR(dev));
for (i=0 ; i<NR_SUPER ; i++)
if (super_blocks[i].s_dev == dev)
.s.o:
$(AS) -o $*.o $<
-OBJS= inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o
+OBJS= inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o scsi.o
proc.o: $(OBJS)
$(LD) -r -o proc.o $(OBJS)
return;
}
+ if (ino == PROC_SCSI_SCSI) {
+ inode->i_mode = S_IFREG | S_IWUSR;
+ inode->i_op = &proc_scsi_inode_operations;
+ return;
+ }
+ /* files within /proc/scsi */
+ if ((ino > PROC_SCSI_SCSI) && (ino < PROC_SCSI_FILE)) {
+ inode->i_nlink = 2;
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ inode->i_op = &proc_scsi_inode_operations;
+ return;
+ }
+
+ /* files within /proc/scsi/<driver>/ */
+ if ((ino >= PROC_SCSI_FILE) && (ino <= PROC_SCSI_LAST)) {
+ inode->i_mode = S_IFREG | S_IRUGO | S_IWUSR;
+ inode->i_op = &proc_scsi_inode_operations;
+ return;
+ }
+
if (!pid) {
switch (ino) {
case PROC_KMSG:
inode->i_nlink = 2;
inode->i_op = &proc_net_inode_operations;
break;
+ case PROC_SCSI:
+ inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ inode->i_nlink = 2;
+ inode->i_op = &proc_scsi_inode_operations;
+ break;
case PROC_KCORE:
inode->i_mode = S_IFREG | S_IRUSR;
inode->i_op = &proc_kcore_inode_operations;
{ PROC_CPUINFO, 7, "cpuinfo" },
{ PROC_SELF, 4, "self" }, /* will change inode # */
{ PROC_NET, 3, "net" },
+ { PROC_SCSI, 4, "scsi" },
#ifdef CONFIG_DEBUG_MALLOC
{ PROC_MALLOC, 6, "malloc" },
#endif
--- /dev/null
+/*
+ * linux/fs/proc/scsi.c
+ * (c) 1995 Michael Neuffer neuffer@goofy.zdv.uni-mainz.de
+ *
+ * The original version was derived from linux/fs/proc/net.c,
+ * which is Copyright (C) 1991, 1992 Linus Torvalds.
+ * Much has been rewritten, but some of the code still remains.
+ *
+ * /proc/scsi directory handling functions
+ *
+ * last change: 95/06/13
+ *
+ * Initial version: March '95
+ * 95/15/05 Added subdirectories for each driver and show every
+ * registered HBA as a single file.
+ * 95/30/05 Added rudimentary write support for parameter passing
+ *
+ * TODO: Improve support to write to the driver files
+ * Optimize directory handling
+ * Add some more comments
+ */
+#include <linux/autoconf.h>
+#include <asm/segment.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/proc_fs.h>
+#include <linux/stat.h>
+#include <linux/config.h>
+#include <linux/mm.h>
+
+/* forward references */
+static int proc_readscsi(struct inode * inode, struct file * file,
+ char * buf, int count);
+static int proc_writescsi(struct inode * inode, struct file * file,
+ char * buf, int count);
+static int proc_readscsidir(struct inode *, struct file *,
+ void *, filldir_t filldir);
+static int proc_lookupscsi(struct inode *,const char *,int,struct inode **);
+static int proc_scsilseek(struct inode *, struct file *, off_t, int);
+
+extern uint count_templates(void);
+extern void build_proc_dir_hba_entries(uint);
+
+/* the *_get_info() functions are in the respective scsi driver code */
+extern int (* dispatch_scsi_info_ptr)(int, char *, char **, off_t, int, int);
+
+
+static struct file_operations proc_scsi_operations = {
+ proc_scsilseek, /* lseek */
+ proc_readscsi, /* read */
+ proc_writescsi, /* write */
+ proc_readscsidir, /* readdir */
+ NULL, /* select */
+ NULL, /* ioctl */
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ NULL, /* no special release code */
+ NULL /* can't fsync */
+};
+
+/*
+ * proc directories can do almost nothing..
+ */
+struct inode_operations proc_scsi_inode_operations = {
+ &proc_scsi_operations, /* default scsi directory file-ops */
+ NULL, /* create */
+ proc_lookupscsi,/* lookup */
+ NULL, /* link */
+ NULL, /* unlink */
+ NULL, /* symlink */
+ NULL, /* mkdir */
+ NULL, /* rmdir */
+ NULL, /* mknod */
+ NULL, /* rename */
+ NULL, /* readlink */
+ NULL, /* follow_link */
+ NULL, /* bmap */
+ NULL, /* truncate */
+ NULL /* permission */
+};
+
+struct proc_dir_entry scsi_dir[PROC_SCSI_FILE - PROC_SCSI_SCSI + 3];
+struct proc_dir_entry scsi_hba_dir[(PROC_SCSI_LAST - PROC_SCSI_FILE) * 4];
+
+static struct proc_dir_entry scsi_dir2[] = {
+ { PROC_SCSI, 1, "." },
+ { PROC_ROOT_INO, 2, ".." },
+ { PROC_SCSI_NOT_PRESENT, 11, "not.present" },
+ { 0, 0, NULL }
+};
+
+inline static uint count_dir_entries(uint inode)
+{
+ struct proc_dir_entry *dir;
+ uint i = 0;
+
+
+ if(dispatch_scsi_info_ptr)
+ if (inode <= PROC_SCSI_SCSI_DEBUG)
+ dir = scsi_dir;
+ else
+ dir = scsi_hba_dir;
+ else dir = scsi_dir2;
+
+ while(dir[i].low_ino)
+ i++;
+
+ return(i);
+}
+
+static int proc_lookupscsi(struct inode * dir, const char * name, int len,
+ struct inode ** result)
+{
+ struct proc_dir_entry *de = NULL;
+
+ *result = NULL;
+ if (!dir)
+ return(-ENOENT);
+ if (!S_ISDIR(dir->i_mode)) {
+ iput(dir);
+ return(-ENOENT);
+ }
+ if (dispatch_scsi_info_ptr != NULL)
+ if (dir->i_ino <= PROC_SCSI_SCSI)
+ de = scsi_dir;
+ else {
+ de = &scsi_hba_dir[dispatch_scsi_info_ptr(dir->i_ino, 0, 0, 0, 0, 2)];
+ }
+ else
+ de = scsi_dir2;
+
+ for (; de->name ; de++) {
+ if (!proc_match(len, name, de))
+ continue;
+ *result = iget(dir->i_sb, de->low_ino);
+ iput(dir);
+ if (!*result)
+ return(-ENOENT);
+ return(0);
+ }
+ iput(dir);
+ return(-ENOENT);
+}
+
+static int proc_readscsidir(struct inode * inode, struct file * filp,
+ void * dirent, filldir_t filldir)
+{
+ struct proc_dir_entry * de;
+ unsigned int ino;
+
+ if (!inode || !S_ISDIR(inode->i_mode))
+ return(-EBADF);
+ ino = inode->i_ino;
+ while (((unsigned) filp->f_pos) < count_dir_entries(ino)) {
+ if (dispatch_scsi_info_ptr)
+ if (ino <= PROC_SCSI_SCSI)
+ de = scsi_dir + filp->f_pos;
+ else
+ de = scsi_hba_dir + filp->f_pos;
+ else
+ de = scsi_dir2 + filp->f_pos;
+ if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino)<0)
+ break;
+ filp->f_pos++;
+ }
+ return(0);
+}
+
+int get_not_present_info(char *buffer, char **start, off_t offset, int length)
+{
+ int len, pos, begin;
+
+ begin = 0;
+ pos = len = sprintf(buffer,
+ "The scsi core module is currently not present\n");
+ if(pos < offset) {
+ len = 0;
+ begin = pos;
+ }
+
+ *start = buffer + (offset - begin); /* Start of wanted data */
+ len -= (offset - begin);
+ if(len > length)
+ len = length;
+
+ return(len);
+}
+
+#define PROC_BLOCK_SIZE (3*1024) /* 4K page size, but our output routines
+ * use some slack for overruns
+ */
+
+static int proc_readscsi(struct inode * inode, struct file * file,
+ char * buf, int count)
+{
+ uint ino;
+ int length;
+ int bytes = count;
+ int copied = 0;
+ int thistime;
+ char * page;
+ char * start;
+
+ if (count < -1) /* Normally I wouldn't do this, */
+ return(-EINVAL); /* but it saves some redundant code.
+ * Now it is possible to seek to the
+ * end of the file */
+ if (!(page = (char *) __get_free_page(GFP_KERNEL)))
+ return(-ENOMEM);
+ ino = inode->i_ino;
+
+
+ while(bytes > 0 || count == -1)
+ {
+
+ thistime = bytes;
+ if(bytes > PROC_BLOCK_SIZE || count == -1)
+ thistime = PROC_BLOCK_SIZE;
+
+ if(dispatch_scsi_info_ptr)
+ length = dispatch_scsi_info_ptr(ino, page, &start,
+ file->f_pos, thistime, 0);
+ else
+ length = get_not_present_info(page, &start, file->f_pos, thistime);
+ if(length < 0) {
+ free_page((ulong) page);
+ return(length);
+ }
+
+ /*
+ * We have been given a non page aligned block of
+ * the data we asked for + a bit. We have been given
+ * the start pointer and we know the length..
+ */
+ if (length <= 0)
+ break;
+ /*
+ * Copy the bytes, if we're not doing a seek to
+ * the end of the file
+ */
+ if (count != -1)
+ memcpy_tofs(buf + copied, start, length);
+ file->f_pos += length; /* Move down the file */
+ bytes -= length;
+ copied += length;
+
+ if(length < thistime)
+ break; /* End of file */
+
+ }
+
+ free_page((ulong) page);
+ return(copied);
+}
+
+
+static int proc_writescsi(struct inode * inode, struct file * file,
+ char * buf, int count)
+{
+ uint ino;
+ int ret = 0;
+ char * page;
+
+ if (!(page = (char *) __get_free_page(GFP_KERNEL)))
+ return(-ENOMEM);
+
+ if(count > PROC_BLOCK_SIZE) {
+ return(-EOVERFLOW);
+ }
+
+ ino = inode->i_ino;
+
+ if(dispatch_scsi_info_ptr != NULL) {
+ memcpy_fromfs(page, buf, count);
+ ret = dispatch_scsi_info_ptr(ino, page, 0, 0, count, 1);
+ } else {
+ free_page((ulong) page);
+ return(-ENOPKG); /* Nothing here */
+ }
+
+ free_page((ulong) page);
+ return(ret);
+}
+
+
+static int proc_scsilseek(struct inode * inode, struct file * file,
+ off_t offset, int orig)
+{
+ switch (orig) {
+ case 0:
+ file->f_pos = offset;
+ return(file->f_pos);
+ case 1:
+ file->f_pos += offset;
+ return(file->f_pos);
+ case 2: /* This ugly hack allows us to */
+ if (offset) /* to determine the length of the */
+ return(-EINVAL); /* file and then later savely to */
+ proc_readscsi(inode, file, 0, -1); /* seek in it */
+ return(file->f_pos);
+ default:
+ return(-EINVAL);
+ }
+}
+
+/*
+ * Overrides for Emacs so that we almost follow Linus's tabbing style.
+ * Emacs will notice this stuff at the end of the file and automatically
+ * adjust the settings for this buffer only. This must remain at the end
+ * of the file.
+ * ---------------------------------------------------------------------------
+ * Local variables:
+ * c-indent-level: 4
+ * c-brace-imaginary-offset: 0
+ * c-brace-offset: -4
+ * c-argdecl-indent: 4
+ * c-label-offset: -4
+ * c-continued-statement-offset: 4
+ * c-continued-brace-offset: 0
+ * indent-tabs-mode: nil
+ * tab-width: 4
+ * End:
+ */
/*
* Change virtual addresses to physical addresses and vv.
*/
-extern inline unsigned long virt_to_phys(void * address)
+extern inline unsigned long virt_to_phys(volatile void * address)
{
return 0xffffffffUL & (unsigned long) address;
}
#include <asm/jensen.h>
#endif
+/*
+ * String version of IO memory access ops:
+ */
+extern void memcpy_fromio(void *, unsigned long, unsigned long);
+extern void memcpy_toio(unsigned long, void *, unsigned long);
+extern void memset_io(unsigned long, int, unsigned long);
+
+/*
+ * String versions of in/out ops:
+ */
+extern void insb (unsigned long port, void *src, unsigned long count);
+extern void insw (unsigned long port, void *src, unsigned long count);
+extern void insl (unsigned long port, void *src, unsigned long count);
+extern void outsb (unsigned long port, void *dst, unsigned long count);
+extern void outsw (unsigned long port, void *dst, unsigned long count);
+extern void outsl (unsigned long port, void *dst, unsigned long count);
+
#endif
extern void outw(unsigned short b, unsigned long addr);
extern void outl(unsigned int b, unsigned long addr);
-/*
- * String versions of in/out ops:
- */
-extern void insw (unsigned long port, void *src, unsigned long count);
-extern void insl (unsigned long port, void *src, unsigned long count);
-extern void outsw (unsigned long port, void *dst, unsigned long count);
-extern void outsl (unsigned long port, void *dst, unsigned long count);
-
extern unsigned long readb(unsigned long addr);
extern unsigned long readw(unsigned long addr);
* make the kernel segment mapped at 0, we need to do translation
* on the i386 as well)
*/
-extern inline unsigned long virt_to_phys(void * address)
+extern inline unsigned long virt_to_phys(volatile void * address)
{
return (unsigned long) address;
}
* differently. On the x86 architecture, we just read/write the
* memory location directly.
*/
-extern inline unsigned long readb(unsigned long addr)
-{ return *(unsigned char *) addr; }
+#define readb(addr) (*(volatile unsigned char *) (addr))
+#define readw(addr) (*(volatile unsigned short *) (addr))
+#define readl(addr) (*(volatile unsigned int *) (addr))
-extern inline unsigned long readw(unsigned long addr)
-{ return *(unsigned short *) addr; }
-
-extern inline unsigned long readl(unsigned long addr)
-{ return *(unsigned int *) addr; }
-
-extern inline void writeb(unsigned char b, unsigned long addr)
-{ *(unsigned char *) addr = b; }
-
-extern inline void writew(unsigned short b, unsigned long addr)
-{ *(unsigned short *) addr = b; }
-
-extern inline void writel(unsigned int b, unsigned long addr)
-{ *(unsigned int *) addr = b; }
+#define writeb(b,addr) ((*(volatile unsigned char *) (addr)) = (b))
+#define writew(b,addr) ((*(volatile unsigned short *) (addr)) = (b))
+#define writel(b,addr) ((*(volatile unsigned int *) (addr)) = (b))
#define memset_io(a,b,c) memset((void *)(a),(b),(c))
#define memcpy_fromio(a,b,c) memcpy((a),(void *)(b),(c))
"inb $0x21,%al\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
- "1:\torb $" #mask ",_cache_21\n\t" \
- "movb _cache_21,%al\n\t" \
+ "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_21)"\n\t" \
+ "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
"outb %al,$0x21\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
"inb $0xA1,%al\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
- "1:\torb $" #mask ",_cache_A1\n\t" \
- "movb _cache_A1,%al\n\t" \
+ "1:\torb $" #mask ","SYMBOL_NAME_STR(cache_A1)"\n\t" \
+ "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
"outb %al,$0xA1\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
"inb $0x21,%al\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
- "1:\tandb $~(" #mask "),_cache_21\n\t" \
- "movb _cache_21,%al\n\t" \
+ "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_21)"\n\t" \
+ "movb "SYMBOL_NAME_STR(cache_21)",%al\n\t" \
"outb %al,$0x21\n\t"
#define UNBLK_SECOND(mask) \
"inb $0xA1,%al\n\t" \
"jmp 1f\n" \
"1:\tjmp 1f\n" \
- "1:\tandb $~(" #mask "),_cache_A1\n\t" \
- "movb _cache_A1,%al\n\t" \
+ "1:\tandb $~(" #mask "),"SYMBOL_NAME_STR(cache_A1)"\n\t" \
+ "movb "SYMBOL_NAME_STR(cache_A1)",%al\n\t" \
"outb %al,$0xA1\n\t"
#define IRQ_NAME2(nr) nr##_interrupt(void)
asmlinkage void FAST_IRQ_NAME(nr); \
asmlinkage void BAD_IRQ_NAME(nr); \
__asm__( \
-"\n.align 4\n" \
-"_IRQ" #nr "_interrupt:\n\t" \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(IRQ) #nr "_interrupt:\n\t" \
"pushl $-"#nr"-2\n\t" \
SAVE_ALL \
ACK_##chip(mask) \
- "incl _intr_count\n\t"\
+ "incl "SYMBOL_NAME_STR(intr_count)"\n\t"\
"sti\n\t" \
"movl %esp,%ebx\n\t" \
"pushl %ebx\n\t" \
"pushl $" #nr "\n\t" \
- "call _do_IRQ\n\t" \
+ "call "SYMBOL_NAME_STR(do_IRQ)"\n\t" \
"addl $8,%esp\n\t" \
"cli\n\t" \
UNBLK_##chip(mask) \
- "decl _intr_count\n\t" \
+ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
"jmp ret_from_sys_call\n" \
-"\n.align 4\n" \
-"_fast_IRQ" #nr "_interrupt:\n\t" \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(fast_IRQ) #nr "_interrupt:\n\t" \
SAVE_MOST \
ACK_##chip(mask) \
- "incl _intr_count\n\t" \
+ "incl "SYMBOL_NAME_STR(intr_count)"\n\t" \
"pushl $" #nr "\n\t" \
- "call _do_fast_IRQ\n\t" \
+ "call "SYMBOL_NAME_STR(do_fast_IRQ)"\n\t" \
"addl $4,%esp\n\t" \
"cli\n\t" \
UNBLK_##chip(mask) \
- "decl _intr_count\n\t" \
+ "decl "SYMBOL_NAME_STR(intr_count)"\n\t" \
RESTORE_MOST \
-"\n\n.align 4\n" \
-"_bad_IRQ" #nr "_interrupt:\n\t" \
+"\n"__ALIGN_STR"\n" \
+SYMBOL_NAME_STR(bad_IRQ) #nr "_interrupt:\n\t" \
SAVE_MOST \
ACK_##chip(mask) \
RESTORE_MOST);
*/
#define switch_to(tsk) do { \
__asm__("cli\n\t" \
- "xchgl %%ecx,_current\n\t" \
+ "xchgl %%ecx,"SYMBOL_NAME_STR(current)"\n\t" \
"ljmp %0\n\t" \
"sti\n\t" \
- "cmpl %%ecx,_last_task_used_math\n\t" \
+ "cmpl %%ecx,"SYMBOL_NAME_STR(last_task_used_math)"\n\t" \
"jne 1f\n\t" \
"clts\n" \
"1:" \
+++ /dev/null
-#define WHO_COMPILED_ME "someone@somewhere.domain"
+++ /dev/null
-/* wim.h: Defines the layout of the "Window Invalid Register" on
- Version 8 of the Sparc Architecture.
-
- Copyright (C) 1994 David S. Miller (davem@caip.rutgers.edu)
-*/
-
-#ifndef __LINUX_SPARC_WIM_H
-#define __LINUX_SPARC_WIM_H
-
-#ifdef __LINUX_SPARC_V8 /* register doesn't exist on the V9 */
-
-/* The Window Invalid Register %wim, holds a set of which register
- windows are 'valid' at this point in time.
-
- ------------------------------------------------------------
- |W31|W30|W29|W28|W27|W26|W25|W24|W23|....|W5|W4|W3|W2|W1|W0|
- ------------------------------------------------------------
-
- Each register window on the chip gets one bit. If the bit is
- set then the window is currently 'invalid' and hardware will
- trap if that window is entered via a 'save', 'restore', or
- 'rett' instruction. Privileged software is responsible for
- updating this on trap fills/spills etc. Therefore if a 'save'
- instruction is executed and it causes the Current Window
- Pointer to equal a register window which has its bit set in
- %wim we get a 'overflow' trap, a restore into such a register
- invokes a window 'spill' trap.
-*/
-
-#define __LINUX_SPARC_HAS_WIM
-
-/* Macro to fine the %wim bit mask for the current window pointer */
-#define CWP_TO_WIM_MASK(cwp) (1<<(cwp))
-
-/* Assembly version of above macro, 'cwp' and 'wimask' must be registers */
-#define ASM_CWP_TO_WIM_MASK(cwp,wimask) \
- or %g0, 0x1, wimask \
- sll wimask, cwp, wimask
-
-/* Assembly macro to find if the given window is set to invalid in the %wim.
- Again 'window', 'result', and 'scratch' must be in registers. This leaves
- a non-zero value in result if the window is indeed invalid. This routine
- works because we keep exactly one window invalid at all times to maximize
- register utilization, which means both kernel and user windows can be in
- the register file at the same time in certain trap situations.
-*/
-#define ASM_REG_WIN_INVAL(window,result,scratch) \
- rd %wim, result \
- or %g0, 0x1, scratch \
- sll scratch, window, scratch \
- and scratch, result, result
-
-#endif /* !(__LINUX_SPARC_V8) */
-
-#endif /* !(__LINUX_SPARC_WIM_H) */
-
--- /dev/null
+#ifndef _LINUX_ELFCORE_H
+#define _LINUX_ELFCORE_H
+
+#include <linux/types.h>
+#include <linux/signal.h>
+#include <linux/time.h>
+#include <linux/ptrace.h>
+#include <linux/user.h>
+
+struct elf_siginfo
+{
+ int si_signo; /* signal number */
+ int si_code; /* extra code */
+ int si_errno; /* errno */
+};
+
+typedef unsigned long elf_greg_t;
+#define ELF_NGREG (sizeof (struct pt_regs) / sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+typedef struct
+#ifdef __i386__
+ user_i387_struct
+#else
+#error "The FPU in this arch is not supported by ELF core dump.".
+#endif
+elf_fpregset_t;
+
+#ifndef __KERNEL__
+typedef elf_greg_t greg_t;
+typedef elf_gregset_t gregset_t;
+typedef elf_fpregset_t fpregset_t;
+#define NGREG ELF_NGREG
+#endif
+
+/*
+ * Definitons to generate Intel SVR4-like core files.
+ * These mostly have the same names as the SVR4 types with "elf_"
+ * tacked on the front to prevent clashes with linux definitions,
+ * and the typedef forms have been avoided. This is mostly like
+ * the SVR4 structure, but more Linuxy, with things that Linux does
+ * not support and which gdb doesn't really use excluded.
+ * Fields present but not used are marked with "XXX".
+ */
+struct elf_prstatus
+{
+#if 0
+ long pr_flags; /* XXX Process flags */
+ short pr_why; /* XXX Reason for process halt */
+ short pr_what; /* XXX More detailed reason */
+#endif
+ struct elf_siginfo pr_info; /* Info associated with signal */
+ short pr_cursig; /* Current signal */
+ sigset_t pr_sigpend; /* Set of pending signals */
+ sigset_t pr_sighold; /* Set of held signals */
+#if 0
+ struct sigaltstack pr_altstack; /* Alternate stack info */
+ struct sigaction pr_action; /* Signal action for current sig */
+#endif
+ pid_t pr_pid;
+ pid_t pr_ppid;
+ pid_t pr_pgrp;
+ pid_t pr_sid;
+ struct timeval pr_utime; /* User time */
+ struct timeval pr_stime; /* System time */
+ struct timeval pr_cutime; /* Cumulative user time */
+ struct timeval pr_cstime; /* Cumulative system time */
+#if 0
+ long pr_instr; /* Current instruction */
+#endif
+ elf_gregset_t pr_reg; /* GP registers */
+ int pr_fpvalid; /* True if math co-processor being used. */
+};
+
+#define ELF_PRARGSZ (80) /* Number of chars for args */
+
+struct elf_prpsinfo
+{
+ char pr_state; /* numeric process state */
+ char pr_sname; /* char for pr_state */
+ char pr_zomb; /* zombie */
+ char pr_nice; /* nice val */
+ unsigned long pr_flag; /* flags */
+ uid_t pr_uid;
+ gid_t pr_gid;
+ pid_t pr_pid, pr_ppid, pr_pgrp, pr_sid;
+ /* Lots missing */
+ char pr_fname[16]; /* filename of executable */
+ char pr_psargs[ELF_PRARGSZ]; /* initial part of arg list */
+};
+
+#ifndef __KERNEL__
+typedef struct elf_prstatus prstatus_t;
+typedef struct elf_prpsinfo prpsinfo_t;
+#define PRARGSZ ELF_PRARGSZ
+#endif
+
+#endif /* _LINUX_ELFCORE_H */
#define asmlinkage
#endif
+#ifdef __ELF__
+#define SYMBOL_NAME_STR(X) #X
+#define SYMBOL_NAME(X) X
+#ifdef __STDC__
+#define SYMBOL_NAME_LABEL(X) X##:
+#else
+#define SYMBOL_NAME_LABEL(X) X/**/:
+#endif
+#else
+#define SYMBOL_NAME_STR(X) "_"#X
+#ifdef __STDC__
+#define SYMBOL_NAME(X) _##X
+#define SYMBOL_NAME_LABEL(X) _##X##:
+#else
+#define SYMBOL_NAME(X) _/**/X
+#define SYMBOL_NAME_LABEL(X) _/**/X/**/:
+#endif
+#endif
+
+#if !defined(__i486__) && !defined(__i586__)
+#ifdef __ELF__
+#define __ALIGN .align 4,0x90
+#define __ALIGN_STR ".align 4,0x90"
+#else /* __ELF__ */
+#define __ALIGN .align 2,0x90
+#define __ALIGN_STR ".align 2,0x90"
+#endif /* __ELF__ */
+#else /* __i486__/__i586__ */
+#ifdef __ELF__
+#define __ALIGN .align 16,0x90
+#define __ALIGN_STR ".align 16,0x90"
+#else /* __ELF__ */
+#define __ALIGN .align 4,0x90
+#define __ALIGN_STR ".align 4,0x90"
+#endif /* __ELF__ */
+#endif /* __i486__/__i586__ */
+
+#ifdef __ASSEMBLY__
+
+#define ALIGN __ALIGN
+#define ALIGN_STRING __ALIGN_STRING
+
+#define ENTRY(name) \
+ .globl SYMBOL_NAME(name); \
+ ALIGN; \
+ SYMBOL_NAME_LABEL(name)
+
+#endif
+
#endif
#define GFP_DMA 0x80
+#define GFP_LEVEL_MASK 0xf
+
+
/*
* vm_ops not present page codes for shared memory.
*
#define PCI_DEVICE_ID 0x02 /* 16 bits */
#define PCI_COMMAND 0x04 /* 16 bits */
#define PCI_COMMAND_IO 0x1 /* Enable response in I/O space */
-#define PCI_COMMAND_MEMORY 0x2 /* Enable response in I/O space */
+#define PCI_COMMAND_MEMORY 0x2 /* Enable response in Memory space */
#define PCI_COMMAND_MASTER 0x4 /* Enable bus mastering */
#define PCI_COMMAND_SPECIAL 0x8 /* Enable response to special cycles */
#define PCI_COMMAND_INVALIDATE 0x10 /* Use memory write and invalidate */
#define PCI_VENDOR_ID_ADAPTEC 0x9004
#define PCI_DEVICE_ID_ADAPTEC_2940 0x7178
#define PCI_DEVICE_ID_ADAPTEC_294x 0x7078
+#define PCI_DEVICE_ID_ADAPTEC_7850 0x5078
#define PCI_VENDOR_ID_DPT 0x1044
#define PCI_DEVICE_ID_DPT 0xa400
#define PCI_DEVICE_ID_UMC_UM8881F 0x8881
#define PCI_DEVICE_ID_UMC_UM8891A 0x0891
#define PCI_DEVICE_ID_UMC_UM8886F 0x8886
+#define PCI_DEVICE_ID_UMC_UM8886A 0x886a
#define PCI_DEVICE_ID_UMC_UM8673F 0x0101
#define PCI_VENDOR_ID_DEC 0x1011
#define PCI_DEVICE_ID_DEC_TULIP 0x0002
#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
+#define PCI_DEVICE_ID_DEC_TULIP_PLUS 0x0014
#define PCI_DEVICE_ID_DEC_FDDI 0x000F
#define PCI_DEVICE_ID_DEC_BRD 0x0001
#define PCI_DEVICE_ID_CIRRUS_5434_4 0x00A4
#define PCI_DEVICE_ID_CIRRUS_5434_8 0x00A8
#define PCI_DEVICE_ID_CIRRUS_6729 0x1100
+#define PCI_DEVICE_ID_CIRRUS_7542 0x1200
#define PCI_VENDOR_ID_BUSLOGIC 0x104B
#define PCI_DEVICE_ID_BUSLOGIC_946C 0x1040
#define PCI_VENDOR_ID_X 0x1061
#define PCI_DEVICE_ID_X_AGX016 0x0001
+#define PCI_VENDOR_ID_ACC 0x10aa
+
+#define PCI_VENDOR_ID_VORTEX 0x1119
+#define PCI_DEVICE_ID_VORTEX_GDT 0x0001
+
+
/*
* The PCI interface treats multi-function devices as independent
* devices. The slot/function address of each device is encoded
#define _LINUX_PROC_FS_H
#include <linux/config.h>
+#include <linux/fs.h>
/*
* The proc filesystem constants/structures
PROC_PCI,
PROC_SELF, /* will change inode # */
PROC_NET,
+ PROC_SCSI,
#ifdef CONFIG_DEBUG_MALLOC
PROC_MALLOC,
#endif
PROC_NET_LAST
};
+enum scsi_directory_inos {
+ PROC_SCSI_SCSI = 256,
+ PROC_SCSI_EATA,
+ PROC_SCSI_EATA_PIO,
+ PROC_SCSI_AHA152X,
+ PROC_SCSI_AHA1542,
+ PROC_SCSI_AHA1740,
+ PROC_SCSI_AIC7XXX,
+ PROC_SCSI_BUSLOGIC,
+ PROC_SCSI_U14_34F,
+ PROC_SCSI_FUTURE_DOMAIN,
+ PROC_SCSI_GENERIC_NCR5380,
+ PROC_SCSI_IN2000,
+ PROC_SCSI_PAS16,
+ PROC_SCSI_QLOGIC,
+ PROC_SCSI_SEAGATE,
+ PROC_SCSI_T128,
+ PROC_SCSI_NCR53C7xx,
+ PROC_SCSI_ULTRASTOR,
+ PROC_SCSI_7000FASST,
+ PROC_SCSI_SCSI_DEBUG,
+ PROC_SCSI_NOT_PRESENT,
+ PROC_SCSI_FILE, /* I'm asuming here that we */
+ PROC_SCSI_LAST = (PROC_SCSI_FILE + 16) /* won't ever see more than */
+}; /* 16 HBAs in one machine */
+
#define PROC_SUPER_MAGIC 0x9fa0
struct proc_dir_entry {
extern struct inode_operations proc_root_inode_operations;
extern struct inode_operations proc_base_inode_operations;
extern struct inode_operations proc_net_inode_operations;
+extern struct inode_operations proc_scsi_inode_operations;
extern struct inode_operations proc_mem_inode_operations;
extern struct inode_operations proc_array_inode_operations;
extern struct inode_operations proc_arraylong_inode_operations;
+#include <linux/linkage.h>
#ifdef CONFIG_MODVERSIONS /* CONFIG_MODVERSIONS */
#undef _set_ver
#undef X
#ifndef __GENKSYMS__
#ifdef MODULE
-#define _set_ver(sym,ver) { (void *) & sym ## _R ## ver, "_" #sym "_R" #ver }
+#define _set_ver(sym,ver) \
+ { (void *) & sym ## _R ## ver, SYMBOL_NAME_STR(sym) "_R" #ver }
#else /* MODULE */
-#define _set_ver(sym,ver) { (void *) & sym, "_" #sym "_R" #ver }
+#define _set_ver(sym,ver) \
+ { (void *) & sym, SYMBOL_NAME_STR(sym) "_R" #ver }
#endif /* MODULE */
#define X(a) a
#endif /* __GENKSYMS__ */
#else /* CONFIG_MODVERSIONS */
-#define X(sym) { (void *) & sym, "_" #sym }
+#define X(sym) { (void *) & sym, SYMBOL_NAME_STR(sym)}
#endif /* CONFIG_MODVERSIONS */
#define EMPTY {0,0}
0, 0, 0, {
* These are system calls that haven't been implemented yet
* but have an entry in the table for future expansion..
*/
+#ifdef __ELF__
+#define sys_quotactl sys_ni_syscall
+#else
#define _sys_quotactl _sys_ni_syscall
+#endif
#endif
*/
struct timeval time; /* (read only) */
long tick; /* (modified) usecs between clock ticks */
+
+ long ppsfreq; /* pps frequency (scaled ppm) (ro) */
+ long jitter; /* pps jitter (us) (ro) */
+ int shift; /* interval duration (s) (shift) (ro) */
+ long stabil; /* pps stability (scaled ppm) (ro) */
+ long jitcnt; /* jitter limit exceeded (ro) */
+ long calcnt; /* calibration intervals (ro) */
+ long errcnt; /* calibration errors (ro) */
+ long stbcnt; /* stability limit exceeded (ro) */
+
+ int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32; int :32;
+ int :32; int :32; int :32; int :32;
};
/*
#include "../drivers/scsi/scsi.h"
#include "../drivers/scsi/hosts.h"
#include "../drivers/scsi/constants.h"
+
+extern int generic_proc_info(char *, char **, off_t, int, int, int);
#endif
+int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
+ off_t offset, int length,
+ int inode, int func) = 0; /* Dirty hack */
+
extern int sys_tz;
extern int request_dma(unsigned int dmanr, char * deviceID);
extern void free_dma(unsigned int dmanr);
struct symbol_table symbol_table = {
#include <linux/symtab_begin.h>
#ifdef CONFIG_MODVERSIONS
- { (void *)1 /* Version version :-) */, "_Using_Versions" },
+ { (void *)1 /* Version version :-) */,
+ SYMBOL_NAME_STR (Using_Versions) },
#endif
/* stackable module support */
X(rename_module_symbol),
X(close_fp),
X(check_disk_change),
X(invalidate_buffers),
+ X(invalidate_inodes),
X(fsync_dev),
X(permission),
X(inode_setattr),
X(kill_fasync),
#endif
#ifdef CONFIG_SCSI
- /* Supports loadable scsi drivers */
- /*
+ /* Supports loadable scsi drivers
+ * technically some of this stuff could be moved to scsi.c, but
+ * scsi.c is initialized before the memory manager is set up.
+ * So we add it here too. There is a duplicate set in scsi.c
+ * that is used when the entire scsi subsystem is a loadable
+ * module.
+ *
* in_scan_scsis is a hack, and should go away once the new
* memory allocation code is in the NCR driver
*/
X(scsi_register),
X(scsi_unregister),
X(scsicam_bios_param),
- X(scsi_init_malloc),
- X(scsi_init_free),
- X(print_command),
+ X(allocate_device),
+ X(scsi_do_cmd),
+ X(scsi_command_size),
+ X(scsi_init_malloc),
+ X(scsi_init_free),
+ X(scsi_ioctl),
+ X(print_command),
+ X(print_msg),
+ X(print_status),
+ X(print_sense),
+ X(dma_free_sectors),
+ X(kernel_scsi_ioctl),
+ X(need_isa_buffer),
+ X(request_queueable),
+ X(dispatch_scsi_info_ptr),
+ X(generic_proc_info),
+ X(scsi_devices),
+ X(free_pages),
+ X(intr_count),
+ X(mem_map),
X(print_msg),
X(print_status),
#endif
extern void console_print(const char *);
-#define DEFAULT_MESSAGE_LOGLEVEL 7 /* KERN_DEBUG */
+#define DEFAULT_MESSAGE_LOGLEVEL 6 /* KERN_INFO */
#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything more serious than KERN_DEBUG */
unsigned long log_size = 0;
) {
p -= 3;
p[0] = '<';
- p[1] = DEFAULT_MESSAGE_LOGLEVEL - 1 + '0';
+ p[1] = DEFAULT_MESSAGE_LOGLEVEL + '0';
p[2] = '>';
} else
msg += 3;
#include <asm/system.h>
#include <asm/dma.h>
-#define GFP_LEVEL_MASK 0xf
-
/* I want this low enough for a while to catch errors.
I want this number to be increased in the near future:
loadable device drivers should use this function to get memory */
network.a: subdirs $(OBJS)
rm -f $@
- ar rcs $@ $(OBJS) $(SUBOBJS)
+ $(AR) rcs $@ $(OBJS) $(SUBOBJS)
subdirs: dummy
set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done