Commit c04591a2 authored by Linus Torvalds's avatar Linus Torvalds

Import 1.3.59

parent b6e9c719
This document describes the usage and errata of the 3Com "Vortex" device
driver for Linux.
This driver supports the following hardware:
3c590, 3c592, 3c595, 3c597
When loaded as a module the following variables may be set:
name type description
debug int The debug message level, 0 (no messages) to 6 (wordy).
options int[] The media type override and card operation settings
(See list below.)
An example of loading the vortex module is
insmod 3c59x.o debug=1 options=0,,12
This sets the debug message level to minimal messages, sets the first card to
the 10baseT transceiver, the second to the EEPROM-set transceiver, and the
third card to operate in full-duplex mode using its 100baseTx transceiver.
(Note: card ordering is set by the PCI BIOS.)
Possible media type settings
0 10baseT
1 10Mbs AUI
2 undefined
3 10base2 (BNC)
4 100base-TX
5 100base-FX
6 MII (not yet available)
7 <Use default setting>
8 Full-duplex bit
8 10baseT full-duplex
12 100baseTx full-duplex
16 Bus-master enable bit (experimental use only!)
Details of the device driver implementation are at the top of the source file.
VERSION = 1 VERSION = 1
PATCHLEVEL = 3 PATCHLEVEL = 3
SUBLEVEL = 58 SUBLEVEL = 59
ARCH = i386 ARCH = i386
......
...@@ -16,7 +16,7 @@ all: kernel.o head.o ...@@ -16,7 +16,7 @@ all: kernel.o head.o
O_TARGET := kernel.o O_TARGET := kernel.o
O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \ O_OBJS := entry.o traps.o process.o osf_sys.o irq.o signal.o setup.o \
bios32.o ptrace.o time.o apecs.o lca.o ksyms.c bios32.o ptrace.o time.o apecs.o lca.o ksyms.o
all: kernel.o head.o all: kernel.o head.o
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
# Loadable module support # Loadable module support
# #
CONFIG_MODULES=y CONFIG_MODULES=y
CONFIG_MODVERSIONS=y # CONFIG_MODVERSIONS is not set
# CONFIG_KERNELD is not set # CONFIG_KERNELD is not set
# #
...@@ -88,6 +88,7 @@ CONFIG_NET_VENDOR_3COM=y ...@@ -88,6 +88,7 @@ CONFIG_NET_VENDOR_3COM=y
# CONFIG_EL1 is not set # CONFIG_EL1 is not set
# CONFIG_EL2 is not set # CONFIG_EL2 is not set
CONFIG_EL3=y CONFIG_EL3=y
# CONFIG_VORTEX is not set
# CONFIG_NET_ISA is not set # CONFIG_NET_ISA is not set
# CONFIG_NET_EISA is not set # CONFIG_NET_EISA is not set
# CONFIG_NET_POCKET is not set # CONFIG_NET_POCKET is not set
......
...@@ -436,16 +436,19 @@ static void make_request(int major,int rw, struct buffer_head * bh) ...@@ -436,16 +436,19 @@ static void make_request(int major,int rw, struct buffer_head * bh)
add_request(major+blk_dev,req); add_request(major+blk_dev,req);
} }
/*
* Swap partitions are now read via brw_page. ll_rw_page is an
* asynchronous function now --- we must call wait_on_page afterwards
* if synchronous IO is required.
*/
void ll_rw_page(int rw, kdev_t dev, unsigned long page, char * buffer) void ll_rw_page(int rw, kdev_t dev, unsigned long page, char * buffer)
{ {
struct request * req;
unsigned int major = MAJOR(dev); unsigned int major = MAJOR(dev);
unsigned long sector = page * (PAGE_SIZE / 512); int block = page;
struct semaphore sem = MUTEX_LOCKED;
if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) { if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) {
printk("Trying to read nonexistent block-device %s (%ld)\n", printk("Trying to read nonexistent block-device %s (%ld)\n",
kdevname(dev), sector); kdevname(dev), page);
return; return;
} }
switch (rw) { switch (rw) {
...@@ -461,19 +464,10 @@ void ll_rw_page(int rw, kdev_t dev, unsigned long page, char * buffer) ...@@ -461,19 +464,10 @@ void ll_rw_page(int rw, kdev_t dev, unsigned long page, char * buffer)
default: default:
panic("ll_rw_page: bad block dev cmd, must be R/W"); panic("ll_rw_page: bad block dev cmd, must be R/W");
} }
req = get_request_wait(NR_REQUEST, dev); if (mem_map[MAP_NR(buffer)].locked)
/* fill up the request-info, and add it to the queue */ panic ("ll_rw_page: page already locked");
req->cmd = rw; mem_map[MAP_NR(buffer)].locked = 1;
req->errors = 0; brw_page(rw, (unsigned long) buffer, dev, &block, PAGE_SIZE, 0);
req->sector = sector;
req->nr_sectors = PAGE_SIZE / 512;
req->current_nr_sectors = PAGE_SIZE / 512;
req->buffer = buffer;
req->sem = &sem;
req->bh = NULL;
req->next = NULL;
add_request(major+blk_dev,req);
down(&sem);
} }
/* This function can be used to request a number of buffers from a block /* This function can be used to request a number of buffers from a block
......
...@@ -20,6 +20,10 @@ ...@@ -20,6 +20,10 @@
* January 1996, Rik Faith (faith@cs.unc.edu): * January 1996, Rik Faith (faith@cs.unc.edu):
* Make /proc/apm easy to format (bump driver version) * Make /proc/apm easy to format (bump driver version)
* *
* History:
* 0.6b: first version in official kernel, Linux 1.3.46
* 0.7: changed /proc/apm format, Linux 1.3.58
* 0.8: fixed gcc 2.7.[12] compilation problems, Linux 1.3.59
* *
* Reference: * Reference:
* *
...@@ -110,29 +114,40 @@ extern unsigned long get_cmos_time(void); ...@@ -110,29 +114,40 @@ extern unsigned long get_cmos_time(void);
*/ */
/* /*
* define to have debug messages * Define to have debug messages.
*/ */
#undef APM_DEBUG #undef APM_DEBUG
/* /*
* define to always call the APM BIOS busy routine even if the clock was * Define to always call the APM BIOS busy routine even if the clock was
* not slowed by the idle routine * not slowed by the idle routine.
*/ */
#define ALWAYS_CALL_BUSY #define ALWAYS_CALL_BUSY
/* /*
* define to disable interrupts in APM BIOS calls (the CPU Idle BIOS call * Define to disable interrupts in APM BIOS calls (the CPU Idle BIOS call
* should turn interrupts on before it does a 'hlt') * should turn interrupts on before it does a 'hlt').
*/ */
#define APM_NOINTS #define APM_NOINTS
/* /*
* define to make the APM BIOS calls zero all data segment registers (do * Define to make the APM BIOS calls zero all data segment registers (do
* that an incorrect BIOS implementation will cause a kernel panic if it * that if an incorrect BIOS implementation will cause a kernel panic if it
* tries to write to arbitrary memory) * tries to write to arbitrary memory).
*/ */
#define APM_ZERO_SEGS #define APM_ZERO_SEGS
/*
* Define to make all set_limit calls use 64k limits. The APM 1.1 BIOS is
* supposed to provide limit information that it recognizes. Many machines
* do this correctly, but many others do not restrict themselves to their
* claimed limit. When this happens, they will cause a segmentation
* violation in the kernel at boot time. Most BIOS's, however, will
* respect a 64k limit, so we use that. If you want to be pedantic and
* hold your BIOS to its claims, then undefine this.
*/
#define APM_RELAX_SEGMENTS
/* /*
* Need to poll the APM BIOS every second * Need to poll the APM BIOS every second
*/ */
...@@ -193,27 +208,27 @@ extern unsigned long get_cmos_time(void); ...@@ -193,27 +208,27 @@ extern unsigned long get_cmos_time(void);
#define APM_SET_CPU_IDLE(error) \ #define APM_SET_CPU_IDLE(error) \
APM_BIOS_CALL(al) \ APM_BIOS_CALL(al) \
: "=a" (error) \ : "=a" (error) \
: "0" (0x5305) \ : "a" (0x5305) \
APM_BIOS_CALL_END APM_BIOS_CALL_END
#endif #endif
#define APM_SET_CPU_BUSY(error) \ #define APM_SET_CPU_BUSY(error) \
APM_BIOS_CALL(al) \ APM_BIOS_CALL(al) \
: "=a" (error) \ : "=a" (error) \
: "0" (0x5306) \ : "a" (0x5306) \
APM_BIOS_CALL_END APM_BIOS_CALL_END
#define APM_SET_POWER_STATE(state, error) \ #define APM_SET_POWER_STATE(state, error) \
APM_BIOS_CALL(al) \ APM_BIOS_CALL(al) \
: "=a" (error) \ : "=a" (error) \
: "0" (0x5307), "b" (0x0001), "c" (state) \ : "a" (0x5307), "b" (0x0001), "c" (state) \
APM_BIOS_CALL_END APM_BIOS_CALL_END
#ifdef CONFIG_APM_DISPLAY_BLANK #ifdef CONFIG_APM_DISPLAY_BLANK
#define APM_SET_DISPLAY_POWER_STATE(state, error) \ #define APM_SET_DISPLAY_POWER_STATE(state, error) \
APM_BIOS_CALL(al) \ APM_BIOS_CALL(al) \
: "=a" (error) \ : "=a" (error) \
: "0" (0x5307), "b" (0x01ff), "c" (state) \ : "a" (0x5307), "b" (0x01ff), "c" (state) \
APM_BIOS_CALL_END APM_BIOS_CALL_END
#endif #endif
...@@ -221,32 +236,32 @@ extern unsigned long get_cmos_time(void); ...@@ -221,32 +236,32 @@ extern unsigned long get_cmos_time(void);
#define APM_ENABLE_POWER_MANAGEMENT(device, error) \ #define APM_ENABLE_POWER_MANAGEMENT(device, error) \
APM_BIOS_CALL(al) \ APM_BIOS_CALL(al) \
: "=a" (error) \ : "=a" (error) \
: "0" (0x5308), "b" (device), "c" (1) \ : "a" (0x5308), "b" (device), "c" (1) \
APM_BIOS_CALL_END APM_BIOS_CALL_END
#endif #endif
#define APM_GET_POWER_STATUS(bx, cx, dx, error) \ #define APM_GET_POWER_STATUS(bx, cx, dx, error) \
APM_BIOS_CALL(al) \ APM_BIOS_CALL(al) \
: "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx) \ : "=a" (error), "=b" (bx), "=c" (cx), "=d" (dx) \
: "0" (0x530a), "1" (1) \ : "a" (0x530a), "b" (1) \
APM_BIOS_CALL_END APM_BIOS_CALL_END
#define APM_GET_EVENT(event, error) \ #define APM_GET_EVENT(event, error) \
APM_BIOS_CALL(al) \ APM_BIOS_CALL(al) \
: "=a" (error), "=b" (event) \ : "=a" (error), "=b" (event) \
: "0" (0x530b) \ : "a" (0x530b) \
APM_BIOS_CALL_END APM_BIOS_CALL_END
#define APM_DRIVER_VERSION(ver, ax, error) \ #define APM_DRIVER_VERSION(ver, ax, error) \
APM_BIOS_CALL(bl) \ APM_BIOS_CALL(bl) \
: "=a" (ax), "=b" (error) \ : "=a" (ax), "=b" (error) \
: "0" (0x530e), "1" (0), "c" (ver) \ : "a" (0x530e), "b" (0), "c" (ver) \
APM_BIOS_CALL_END APM_BIOS_CALL_END
#define APM_ENGAGE_POWER_MANAGEMENT(device, error) \ #define APM_ENGAGE_POWER_MANAGEMENT(device, error) \
APM_BIOS_CALL(al) \ APM_BIOS_CALL(al) \
: "=a" (error) \ : "=a" (error) \
: "0" (0x530f), "b" (device), "c" (1) \ : "a" (0x530f), "b" (device), "c" (1) \
APM_BIOS_CALL_END APM_BIOS_CALL_END
/* /*
...@@ -292,7 +307,7 @@ static struct apm_bios_struct * user_list = NULL; ...@@ -292,7 +307,7 @@ static struct apm_bios_struct * user_list = NULL;
static struct timer_list apm_timer; static struct timer_list apm_timer;
static char driver_version[] = "0.7";/* no spaces */ static char driver_version[] = "0.8";/* no spaces */
#ifdef APM_DEBUG #ifdef APM_DEBUG
static char * apm_event_name[] = { static char * apm_event_name[] = {
...@@ -1025,13 +1040,18 @@ static int apm_setup(void) ...@@ -1025,13 +1040,18 @@ static int apm_setup(void)
set_limit(gdt[APM_CS_16 >> 3], 64 * 1024); set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
set_limit(gdt[APM_DS >> 3], 64 * 1024); set_limit(gdt[APM_DS >> 3], 64 * 1024);
} else { } else {
set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len); #ifdef APM_RELAX_SEGMENTS
/* This is not clear from the spec, but at least one /* For ASUS motherboard, Award BIOS rev 110 (and others?) */
machine needs CS_16 to be a 64k segment, and the DEC set_limit(gdt[APM_CS >> 3], 64 * 1024);
Hinote Ultra CT475 (and others?) needs DS to be a 64k /* For some unknown machine. */
segment. */
set_limit(gdt[APM_CS_16 >> 3], 64 * 1024); set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
/* For the DEC Hinote Ultra CT475 (and others?) */
set_limit(gdt[APM_DS >> 3], 64 * 1024); set_limit(gdt[APM_DS >> 3], 64 * 1024);
#else
set_limit(gdt[APM_CS >> 3], apm_bios_info.cseg_len);
set_limit(gdt[APM_CS_16 >> 3], 64 * 1024);
set_limit(gdt[APM_DS >> 3], apm_bios_info.dseg_len);
#endif
apm_bios_info.version = 0x0101; apm_bios_info.version = 0x0101;
error = apm_driver_version(&apm_bios_info.version); error = apm_driver_version(&apm_bios_info.version);
if (error != 0) if (error != 0)
......
...@@ -65,7 +65,6 @@ static void mouse_interrupt(int irq, struct pt_regs *regs) ...@@ -65,7 +65,6 @@ static void mouse_interrupt(int irq, struct pt_regs *regs)
char dx, dy; char dx, dy;
unsigned char buttons; unsigned char buttons;
MSE_INT_OFF();
outb(MSE_READ_X_LOW, MSE_CONTROL_PORT); outb(MSE_READ_X_LOW, MSE_CONTROL_PORT);
dx = (inb(MSE_DATA_PORT) & 0xf); dx = (inb(MSE_DATA_PORT) & 0xf);
outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT); outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT);
...@@ -171,6 +170,7 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i ...@@ -171,6 +170,7 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i
int dx; int dx;
int dy; int dy;
unsigned char buttons; unsigned char buttons;
/* long flags; */
if (count < 3) if (count < 3)
return -EINVAL; return -EINVAL;
...@@ -186,7 +186,8 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i ...@@ -186,7 +186,8 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i
* so paging in put_user() does not effect mouse tracking. * so paging in put_user() does not effect mouse tracking.
*/ */
MSE_INT_OFF(); /* save_flags(flags); cli(); */
disable_irq(mouse_irq);
dx = mouse.dx; dx = mouse.dx;
dy = mouse.dy; dy = mouse.dy;
if (dx < -127) if (dx < -127)
...@@ -201,7 +202,8 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i ...@@ -201,7 +202,8 @@ static int read_mouse(struct inode * inode, struct file * file, char * buffer, i
mouse.dx -= dx; mouse.dx -= dx;
mouse.dy -= dy; mouse.dy -= dy;
mouse.ready = 0; mouse.ready = 0;
MSE_INT_ON(); enable_irq(mouse_irq);
/* restore_flags(flags); */
put_user(buttons | 0x80, buffer); put_user(buttons | 0x80, buffer);
put_user((char)dx, buffer + 1); put_user((char)dx, buffer + 1);
......
...@@ -77,12 +77,9 @@ extern unsigned long video_mem_term; ...@@ -77,12 +77,9 @@ extern unsigned long video_mem_term;
* of the VC's backing store, or the "shadow screen" memory where the screen * of the VC's backing store, or the "shadow screen" memory where the screen
* contents are kept, as the TGA frame buffer is *not* char/attr cells. * contents are kept, as the TGA frame buffer is *not* char/attr cells.
* *
* The "(unsigned long) addr < video_mem_term" tests for an Alpha kernel * We must test for an Alpha kernel virtual address that falls within
* virtual address less than the end of the "shadow scrren" memory. This * the "shadow screen" memory. This condition indicates we really want
* indicates we really want to write to the screen, so, we do... :-) * to write to the screen, so, we do... :-)
*
* NOTE: we must guarantee that video_mem_term is less than *any* VC's backing
* store; to do that, we must allocate it earlier than any VC's are done.
* *
* NOTE also: there's only *TWO* operations: to put/get a character/attribute. * NOTE also: there's only *TWO* operations: to put/get a character/attribute.
* All the others needed by VGA support go away, as Not Applicable for TGA. * All the others needed by VGA support go away, as Not Applicable for TGA.
...@@ -94,7 +91,8 @@ static inline void scr_writew(unsigned short val, unsigned short * addr) ...@@ -94,7 +91,8 @@ static inline void scr_writew(unsigned short val, unsigned short * addr)
* if so, then render the char/attr onto the real screen. * if so, then render the char/attr onto the real screen.
*/ */
*addr = val; *addr = val;
if ((unsigned long)addr < video_mem_term) { if ((unsigned long)addr < video_mem_term &&
(unsigned long)addr >= video_mem_base) {
tga_blitc(val, (unsigned long) addr); tga_blitc(val, (unsigned long) addr);
} }
} }
......
This diff is collapsed.
...@@ -29,6 +29,7 @@ if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then ...@@ -29,6 +29,7 @@ if [ "$CONFIG_NET_VENDOR_3COM" = "y" ]; then
tristate '3c507 support' CONFIG_EL16 tristate '3c507 support' CONFIG_EL16
fi fi
tristate '3c509/3c579 support' CONFIG_EL3 tristate '3c509/3c579 support' CONFIG_EL3
tristate '3c590 series (592/595/597) "Vortex" support' CONFIG_VORTEX
fi fi
bool 'Other ISA cards' CONFIG_NET_ISA bool 'Other ISA cards' CONFIG_NET_ISA
if [ "$CONFIG_NET_ISA" = "y" ]; then if [ "$CONFIG_NET_ISA" = "y" ]; then
......
...@@ -226,6 +226,14 @@ else ...@@ -226,6 +226,14 @@ else
endif endif
endif endif
ifeq ($(CONFIG_VORTEX),y)
L_OBJS += 3c59x.o
else
ifeq ($(CONFIG_VORTEX),m)
M_OBJS += 3c59x.o
endif
endif
ifeq ($(CONFIG_EEXPRESS),y) ifeq ($(CONFIG_EEXPRESS),y)
L_OBJS += eexpress.o L_OBJS += eexpress.o
else else
......
...@@ -68,6 +68,7 @@ extern int ni52_probe(struct device *); ...@@ -68,6 +68,7 @@ extern int ni52_probe(struct device *);
extern int ni65_probe(struct device *); extern int ni65_probe(struct device *);
extern int SK_init(struct device *); extern int SK_init(struct device *);
extern int seeq8005_probe(struct device *); extern int seeq8005_probe(struct device *);
extern int tc59x_probe(struct device *);
/* Detachable devices ("pocket adaptors") */ /* Detachable devices ("pocket adaptors") */
extern int atp_init(struct device *); extern int atp_init(struct device *);
...@@ -83,6 +84,9 @@ ethif_probe(struct device *dev) ...@@ -83,6 +84,9 @@ ethif_probe(struct device *dev)
return 1; /* ENXIO */ return 1; /* ENXIO */
if (1 if (1
#if defined(CONFIG_VORTEX)
&& tc59x_probe(dev)
#endif
#if defined(CONFIG_SEEQ8005) #if defined(CONFIG_SEEQ8005)
&& seeq8005_probe(dev) && seeq8005_probe(dev)
#endif #endif
......
...@@ -325,7 +325,7 @@ int tok_probe(struct device *dev) ...@@ -325,7 +325,7 @@ int tok_probe(struct device *dev)
if (intr==2) irq=10; if (intr==2) irq=10;
if (intr==3) irq=11; if (intr==3) irq=11;
while(!(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)); while(!(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN));
ti->sram=(unsigned char *)((unsigned long)(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN) <<12); ti->sram=(unsigned char *)((unsigned long)(*(ti->mmio + ACA_OFFSET + ACA_RW + RRR_EVEN)) <<12);
ti->global_int_enable=PIOaddr+ADAPTINTREL; ti->global_int_enable=PIOaddr+ADAPTINTREL;
break; break;
......
This diff is collapsed.
This diff is collapsed.
...@@ -37,5 +37,6 @@ dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI ...@@ -37,5 +37,6 @@ dep_tristate 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR $CONFIG_SCSI
dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI
dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI
dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI dep_tristate 'NCR53c406a SCSI support' CONFIG_SCSI_NCR53C406A $CONFIG_SCSI
bool 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974
#dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI #dep_tristate 'SCSI debugging host adapter' CONFIG_SCSI_DEBUG $CONFIG_SCSI
endmenu endmenu
...@@ -76,9 +76,9 @@ endif ...@@ -76,9 +76,9 @@ endif
ifeq ($(CONFIG_SCSI_ADVANSYS),y) ifeq ($(CONFIG_SCSI_ADVANSYS),y)
L_OBJS += advansys.o L_OBJS += advansys.o
else else
ifeq ($(CONFIG_SCSI_ADVANSYS),m) ifeq ($(CONFIG_SCSI_ADVANSYS),m)
M_OBJS += advansys.o M_OBJS += advansys.o
endif endif
endif endif
ifeq ($(CONFIG_SCSI_QLOGIC),y) ifeq ($(CONFIG_SCSI_QLOGIC),y)
...@@ -121,6 +121,10 @@ else ...@@ -121,6 +121,10 @@ else
endif endif
endif endif
ifeq ($(CONFIG_SCSI_AM53C974),y)
L_OBJS += AM53C974.o
endif
ifeq ($(CONFIG_SCSI_BUSLOGIC),y) ifeq ($(CONFIG_SCSI_BUSLOGIC),y)
L_OBJS += BusLogic.o L_OBJS += BusLogic.o
else else
......
SUBJECT
-------
AM53/79C974 PC-SCSI Driver
DISCLAIMER
----------
*** THIS SHOULD BE CONSIDERED AS BETA SOFTWARE ***
*** USE AT YOUR OWN RISK! ***
Copyright
---------
The architecture and much of the code of this device driver was
originally developed by Drew Eckhardt for the NCR5380. The
following copyrights apply:
For the architecture and all pieces of code which can also be found
in the NCR5380 device driver:
Copyright 1993, Drew Eckhardt
Visionary Computing
(Unix and Linux consulting and custom programming)
drew@colorado.edu
+1 (303) 666-5836
The AM53C974_nobios_detect code was origininally developed by
Robin Cutshaw (robin@xfree86.org) and is used here in a
slightly modified form.
For the remaining code:
Copyright 1994, D. Frieauff
EMail: fri@rsx42sun0.dofn.de
Phone: x49-7545-8-2256 , x49-7541-42305
Version
-------
AM53/79C974 (PC-SCSI) Linux driver ALPHA release 0.5, 19 November 1995
Changelog
---------
0.1 -> 0.2:
- Extended message handling re-written to eliminate 'invalid message 17' bug
- Parameters of AM53C974_intr adapted
- Debug messages structured
- Spelling improved
0.2 -> 0.3:
- README file updated -- please read this file up to the end!
- Automatic scanning of io_port and irq implemented; no need for BIOS32
anymore
- Improved configuration (now via LILO parameter string)
- Cleanup of probing and initialisation code
- Improved sync. negotiation (can be setup individually for every device)
- Improved/ debugged code for reception of ext. messages
0.3 -> 0.4:
- Improved PCI probing and initialisation code
- Compatibility changes for Linux 1.3.x
0.4 -> 0.5:
- Compatibility changes for Linux 1.3.42
Bugs & Todo
-----------
- Add proc info function
- Support SCSI-2 tagged queuing
- Finalize abort code
Features
--------
This driver supports asynchronous and synchronous SCSI-I and SCSI-II devices.
It is capable of transfer rate and synchronous negotiation (see below).
The driver supportes scatter-gather. Transfers are DMA based, but do not
(yet) make use of the AM53/79C974 MDL mode.
Max. transfer rate is 10MHz (whatever this is in real life). The transfer
rate is negotiated with each device (see dmesg output).
The AM53/79C974 has a 96-byte DMA FIFO to the PCI bus and a 16-byte SCSI
FIFO. It provides active negation and glitch suppression functions.
Burst DMA transfer rate is 132 MBytes/sec.
Configuration
-------------
The following communication characteristics can be set individually for every
SCSI device on the bus:
- enable/disable sync. negotiation
- transfer rate
- asynchronous or synchronous communication
- in case of sync. communication, the sync. offset
The sync. offset specifies the number of bytes that can be sent or
reveived from the SCSI bus without ACK resp. REQ signal.
CAUTION: USING SYNCHRONOUS MODE ON LONG SCSI CABLES MAY CAUSE
COMMUNICATION PROBLEMS LEADING TO LOSS OF DATA.
The default setting of the SCSI communication parameters is as follows:
- no negotiation
- 5.0 MHz transfer rate
- asynchronous mode
- zero offset
The parameters can be modified by passing a string with the following syntax to
the kernel: AM53C974=host-scsi-id,target-scsi-id,max-rate,max-offset
The parameters will be used by the driver as negotiation basis.
The range of the rate parameter is 3 to 10 MHz.
The range of the sync. offset parameter is 0 to 15 bytes. A value of 0 denotes
asynchronous comm. mode.
If the target cannot cope with the specified transfer rate, sync. mode or sync.
offset, the negotiation result will differ from the specified values.
The negotiation result is printed out at the end of the negotiation process
(to read it, use the dmesg program or the appropriate syslog).
The parameter strings (blank separated) can be passed to the kernel at the
LILO prompt, or as part of the LILO configuration file.
For example, the string "AM53C974=7,2,8,15" would be interpreted as follows:
"For communication between the controller with SCSI-ID 7 and the device with
SCSI-ID 2 a transfer rate of 8MHz in synchronous mode with max. 15 bytes offset
should be negotiated".
As an example, here my LILO configuration file:
boot = /dev/sda
compact
#prompt
delay = 50 # optional, for systems that boot very quickly
vga = normal # force sane state
ramdisk = 0 # paranoia setting
root = current # use "current" root
image = /usr/src/linux/arch/i386/boot/zImage
label = linux
append = "AM53C974=7,0,10,0 AM53C974=7,1,10,0 AM53C974=7,2,10,15 AM53C974=7,4,10,0 AM53C974=7,5,10,0"
read-only
other = /dev/sda4
label = os2
other = /dev/sdb3
loader = /boot/any_d.b
table = /dev/sdb
label = setup
The same parameters at the LILO prompt:
LILO boot: linux AM53C974=7,0,10,0 AM53C974=7,1,10,0 AM53C974=7,2,10,15 AM53C974=7,4,10,0 AM53C974=7,5,10,0
You can override parameters specified in the LILO configuration file by
parameters specified on the LILO command line.
BIOS usage
----------
Version 0.4 of the driver will use the BIOS, if available. Otherwise
it will try its internal PCI scan and access routines.
The driver assumes that the controller's SCSI-ID (usually 7) has been
correctly loaded by the BIOS into the controller's register during
system boot. If the driver detects that the controller's SCSI ID is not
'7' it will print out a warning. If this happens to you please correct
seeting of the controller's SCSI-ID. If it is wrong, then edit the
AM53C974_SCSI_ID definition in file AM53C974.h accordingly.
Test environment
----------------
This driver was tested on a Compaq XL566 with the following SCSI configuration:
2 x HP C2247 fixed disk (internal, rate=10MHz, async.)
1 x Micropolis 1624 fixed disk (external, rate=8MHz, sync., offset=15 bytes)
1 x Wangtek W5525ES cartridge streamer (internal, rate=5MHz, async.)
1 x Toshiba XM-3301B CD-ROM (external, rate=5MHz, async.)
Known problems
--------------
- Compaq/Matsushita CD-ROM:
Use of this device with AM53C974 driver version 0.2 caused the kernel to
hang during Linux boot. If you encounter the problem, don't enable sync.
negotiation with the CD-ROM, i.e. simply don't specify comm. parameters
for this device on the LILO commandline or configuration file.
The driver will thus use its default for the CD-ROM, which is 5MHz
transfer rate asynch and no sync. negotiation.
- Some disks cause problems.
What to do if there is a SCSI problem possibly related to the driver
--------------------------------------------------------------------
Read Klaus Liedl's WWW page (http://www-c724.uibk.ac.at/XL/).
In case this does not help:
Send me a complete description of the problem, including your SCSI
configuration plus as much debugging information as possible.
Don't wait until I ask you for this information. To enable the
generation of debugging output, remove the comments from the following
definitions in the AM53C974.h file:
AM53C974_DEBUG
AM53C974_DEBUG_MSG
AM53C974_DEBUG_KEYWAIT
AM53C974_DEBUG_INFO
AM53C974_DEBUG_INTR
With these definitions enabled, the driver will enter single-step mode during
Linux boot. Use the spacebar for stepping.
Take note of at least the last 10 printout sections (marked by dashes) before
the crash/hangup or whatever happens and send me all of this information via
email. If the system can boot, use the syslogd daemon to record the debugging
output. Maybe you can use the ramdisk for this purpose too (if necessary, kindly
ask K. Liedl (Klaus.Liedl@uibk.ac.at) for support, he knows how to do it --
I never tried). Stay in email contact with me. Be aware that the following
weeks/months could be the worst of your life.
Note: If single-stepping takes up too much time, you can try to let the driver
catch the problem by pressing the 'r' key. The driver will automatically enter
single-step mode if it has detected something weird.
Author's Contact Adress
-----------------------
Email: fri@rsx42sun0.dofn.de
Phone: x49-7545-2256 (office), x49-7541-42305 (home)
Home address: D. Frieauff, Stockerholzstr. 27, 88048 Friedrichshafen, Germany
!!!! Important Notice !!!!
-----------------------------
- Klaus Liedl maintains an excellent WWW page about Linux on Compaq XL.
It includes an FAQ, lots of tips & tricks as well as downloadable
boot disk images. The URL is: http://www-c724.uibk.ac.at/XL/
- Volunteer wanted for further maintenance of this driver software. I
don't have the time anymore to do serious support as some of you will know.
Literature
----------
- AMD AM53C974 PC-SCSI Technical Manual, publication #18624B
- Amendment to the AMD AM53C974 PC-SCSI Technical Manual
- AMD AM79C974 PC-NET Datasheet, publication #18681
- Amendment to the AMD AM79C974 PC-NET Datasheet
THANKS to
---------
- Drew Eckhardt, Robin Cutshaw, K. Liedl, Robert J. Pappas, A. Grenier,
Mark Stockton, David C. Niemi, Ben Craft, and many others who have helped
...@@ -20,9 +20,12 @@ ...@@ -20,9 +20,12 @@
* General Public License for more details. * General Public License for more details.
* *
* *
* $Id: aha152x.c,v 1.13 1996/01/09 02:15:53 fischer Exp $ * $Id: aha152x.c,v 1.14 1996/01/17 15:11:20 fischer Exp fischer $
* *
* $Log: aha152x.c,v $ * $Log: aha152x.c,v $
* Revision 1.14 1996/01/17 15:11:20 fischer
* - fixed lockup in MESSAGE IN phase after reconnection
*
* Revision 1.13 1996/01/09 02:15:53 fischer * Revision 1.13 1996/01/09 02:15:53 fischer
* - some cleanups * - some cleanups
* - moved request_irq behind controller initialization * - moved request_irq behind controller initialization
...@@ -1402,8 +1405,6 @@ void aha152x_intr(int irqno, struct pt_regs * regs) ...@@ -1402,8 +1405,6 @@ void aha152x_intr(int irqno, struct pt_regs * regs)
aha152x_panic(shpnt, "unknown lun"); aha152x_panic(shpnt, "unknown lun");
} }
make_acklow(shpnt);
getphase(shpnt);
#if defined(DEBUG_QUEUES) #if defined(DEBUG_QUEUES)
if(HOSTDATA(shpnt)->debug & debug_queues) if(HOSTDATA(shpnt)->debug & debug_queues)
...@@ -1430,6 +1431,8 @@ void aha152x_intr(int irqno, struct pt_regs * regs) ...@@ -1430,6 +1431,8 @@ void aha152x_intr(int irqno, struct pt_regs * regs)
CURRENT_SC->SCp.phase &= ~disconnected; CURRENT_SC->SCp.phase &= ~disconnected;
restore_flags(flags); restore_flags(flags);
make_acklow(shpnt);
if(getphase(shpnt)!=P_MSGI) {
SETPORT(SIMODE0, 0); SETPORT(SIMODE0, 0);
SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE); SETPORT(SIMODE1, ENPHASEMIS|ENBUSFREE);
#if defined(DEBUG_RACE) #if defined(DEBUG_RACE)
...@@ -1438,6 +1441,7 @@ void aha152x_intr(int irqno, struct pt_regs * regs) ...@@ -1438,6 +1441,7 @@ void aha152x_intr(int irqno, struct pt_regs * regs)
SETBITS(DMACNTRL0, INTEN); SETBITS(DMACNTRL0, INTEN);
return; return;
} }
}
/* Check, if we aren't busy with a command */ /* Check, if we aren't busy with a command */
if(!CURRENT_SC) if(!CURRENT_SC)
...@@ -1946,6 +1950,7 @@ void aha152x_intr(int irqno, struct pt_regs * regs) ...@@ -1946,6 +1950,7 @@ void aha152x_intr(int irqno, struct pt_regs * regs)
printk("d+, "); printk("d+, ");
#endif #endif
append_SC(&DISCONNECTED_SC, CURRENT_SC); append_SC(&DISCONNECTED_SC, CURRENT_SC);
CURRENT_SC->SCp.phase |= 1<<16;
CURRENT_SC = NULL; CURRENT_SC = NULL;
restore_flags(flags); restore_flags(flags);
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
#define _AHA152X_H #define _AHA152X_H
/* /*
* $Id: aha152x.h,v 1.13 1995/12/16 12:27:23 fischer Exp $ * $Id: aha152x.h,v 1.14 1996/01/17 15:13:36 fischer Exp fischer $
*/ */
#if defined(__KERNEL__) #if defined(__KERNEL__)
...@@ -23,7 +23,7 @@ int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int ...@@ -23,7 +23,7 @@ int aha152x_proc_info(char *buffer, char **start, off_t offset, int length, int
(unless we support more than 1 cmd_per_lun this should do) */ (unless we support more than 1 cmd_per_lun this should do) */
#define AHA152X_MAXQUEUE 7 #define AHA152X_MAXQUEUE 7
#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.13 $" #define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.14 $"
extern struct proc_dir_entry proc_scsi_aha152x; extern struct proc_dir_entry proc_scsi_aha152x;
......
...@@ -125,6 +125,10 @@ ...@@ -125,6 +125,10 @@
#include "NCR53c406a.h" #include "NCR53c406a.h"
#endif #endif
#ifdef CONFIG_SCSI_AM53C974
#include "AM53C974.h"
#endif
#ifdef CONFIG_SCSI_DEBUG #ifdef CONFIG_SCSI_DEBUG
#include "scsi_debug.h" #include "scsi_debug.h"
#endif #endif
...@@ -226,6 +230,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] = ...@@ -226,6 +230,9 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
#ifdef CONFIG_SCSI_EATA #ifdef CONFIG_SCSI_EATA
EATA, EATA,
#endif #endif
#ifdef CONFIG_SCSI_AM53C974
AM53C974,
#endif
#ifdef CONFIG_SCSI_DEBUG #ifdef CONFIG_SCSI_DEBUG
SCSI_DEBUG, SCSI_DEBUG,
#endif #endif
......
...@@ -410,8 +410,8 @@ sb16_dsp_prepare_for_input (int dev, int bsize, int bcount) ...@@ -410,8 +410,8 @@ sb16_dsp_prepare_for_input (int dev, int bsize, int bcount)
audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8; audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8;
dsp_count = 0; dsp_count = 0;
dsp_cleanup (); dsp_cleanup ();
sb_dsp_command (0xd0); /* Halt DMA until trigger() is called */
trigger_bits = 0; trigger_bits = 0;
sb_dsp_command (0xd4);
return 0; return 0;
} }
...@@ -421,20 +421,14 @@ sb16_dsp_prepare_for_output (int dev, int bsize, int bcount) ...@@ -421,20 +421,14 @@ sb16_dsp_prepare_for_output (int dev, int bsize, int bcount)
audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8; audio_devs[my_dev]->dmachan1 = dsp_16bit ? dma16 : dma8;
dsp_count = 0; dsp_count = 0;
dsp_cleanup (); dsp_cleanup ();
sb_dsp_command (0xd0); /* Halt DMA until trigger() is called */
trigger_bits = 0; trigger_bits = 0;
sb_dsp_command (0xd4);
return 0; return 0;
} }
static void static void
sb16_dsp_trigger (int dev, int bits) sb16_dsp_trigger (int dev, int bits)
{ {
if (bits != 0)
bits = 1;
if (bits == trigger_bits) /* No change */
return;
trigger_bits = bits; trigger_bits = bits;
if (!bits) if (!bits)
......
...@@ -1378,26 +1378,23 @@ Jazz16_set_dma16 (int dma) ...@@ -1378,26 +1378,23 @@ Jazz16_set_dma16 (int dma)
initialize_ProSonic16 (); initialize_ProSonic16 ();
} }
long static void
sb_dsp_init (long mem_start, struct address_info *hw_config) dsp_get_vers (struct address_info *hw_config)
{ {
int i; int i;
int ess_major = 0, ess_minor = 0;
int mixer_type = 0; unsigned long flags;
save_flags (flags);
cli ();
sb_osp = hw_config->osp; sb_osp = hw_config->osp;
sbc_major = sbc_minor = 0; sbc_major = sbc_minor = 0;
sb_dsp_command (0xe1); /* sb_dsp_command (0xe1); /* Get version */
* Get version
*/
for (i = 1000; i; i--) for (i = 100000; i; i--)
{ {
if (inb (DSP_DATA_AVAIL) & 0x80) if (inb (DSP_DATA_AVAIL) & 0x80)
{ /* {
* wait for Data Ready
*/
if (sbc_major == 0) if (sbc_major == 0)
sbc_major = inb (DSP_READ); sbc_major = inb (DSP_READ);
else else
...@@ -1407,10 +1404,28 @@ sb_dsp_init (long mem_start, struct address_info *hw_config) ...@@ -1407,10 +1404,28 @@ sb_dsp_init (long mem_start, struct address_info *hw_config)
} }
} }
} }
restore_flags (flags);
}
long
sb_dsp_init (long mem_start, struct address_info *hw_config)
{
int i;
int ess_major = 0, ess_minor = 0;
int mixer_type = 0;
dsp_get_vers (hw_config);
if (sbc_major == 0)
{
sb_reset_dsp ();
dsp_get_vers (hw_config);
}
if (sbc_major == 0) if (sbc_major == 0)
{ {
printk ("\n\nFailed to get SB version (%x) - possible I/O conflict\n\n", printk ("\n\nFailed to get SB version (%x) - possible I/O conflict?\n\n",
inb (DSP_DATA_AVAIL)); inb (DSP_DATA_AVAIL));
sbc_major = 1; sbc_major = 1;
} }
......
...@@ -998,13 +998,12 @@ static inline void recover_reusable_buffer_heads(void) ...@@ -998,13 +998,12 @@ static inline void recover_reusable_buffer_heads(void)
unsigned long flags; unsigned long flags;
save_flags(flags); save_flags(flags);
cli();
while (reuse_list) { while (reuse_list) {
cli();
bh = reuse_list; bh = reuse_list;
reuse_list = bh->b_next_free; reuse_list = bh->b_next_free;
restore_flags(flags); restore_flags(flags);
put_unused_buffer_head(bh); put_unused_buffer_head(bh);
cli();
} }
} }
...@@ -1062,7 +1061,7 @@ static struct buffer_head * create_buffers(unsigned long page, unsigned long siz ...@@ -1062,7 +1061,7 @@ static struct buffer_head * create_buffers(unsigned long page, unsigned long siz
return NULL; return NULL;
} }
static int bread_page(unsigned long address, kdev_t dev, int b[], int size) int brw_page(int rw, unsigned long address, kdev_t dev, int b[], int size, int bmap)
{ {
struct buffer_head *bh, *prev, *next, *arr[MAX_BUF_PER_PAGE]; struct buffer_head *bh, *prev, *next, *arr[MAX_BUF_PER_PAGE];
int block, nr; int block, nr;
...@@ -1085,35 +1084,55 @@ static int bread_page(unsigned long address, kdev_t dev, int b[], int size) ...@@ -1085,35 +1084,55 @@ static int bread_page(unsigned long address, kdev_t dev, int b[], int size)
next->b_blocknr = block; next->b_blocknr = block;
next->b_count = 1; next->b_count = 1;
next->b_flushtime = 0; next->b_flushtime = 0;
clear_bit(BH_Dirty, &next->b_state);
clear_bit(BH_Req, &next->b_state);
set_bit(BH_Uptodate, &next->b_state); set_bit(BH_Uptodate, &next->b_state);
if (!block) { /* When we use bmap, we define block zero to represent
a hole. ll_rw_page, however, may legitimately
access block zero, and we need to distinguish the
two cases.
*/
if (bmap && !block) {
memset(next->b_data, 0, size); memset(next->b_data, 0, size);
next->b_count--;
continue; continue;
} }
tmp = get_hash_table(dev, block, size); tmp = get_hash_table(dev, block, size);
if (tmp) { if (tmp) {
if (!buffer_uptodate(tmp)) { if (!buffer_uptodate(tmp)) {
ll_rw_block(READ, 1, &tmp); if (rw == READ)
ll_rw_block(READ, 1, &tmp);
wait_on_buffer(tmp); wait_on_buffer(tmp);
} }
memcpy(next->b_data, tmp->b_data, size); if (rw == READ)
memcpy(next->b_data, tmp->b_data, size);
else {
memcpy(tmp->b_data, next->b_data, size);
set_bit(BH_Dirty, &tmp->b_state);
}
brelse(tmp); brelse(tmp);
next->b_count--;
continue; continue;
} }
clear_bit(BH_Uptodate, &next->b_state); if (rw == READ)
clear_bit(BH_Uptodate, &next->b_state);
else
set_bit(BH_Dirty, &next->b_state);
arr[nr++] = next; arr[nr++] = next;
} while (prev = next, (next = next->b_this_page) != NULL); } while (prev = next, (next = next->b_this_page) != NULL);
prev->b_this_page = bh; prev->b_this_page = bh;
if (nr) if (nr)
ll_rw_block(READ, nr, arr); ll_rw_block(rw, nr, arr);
else { else {
page->locked = 0; page->locked = 0;
page->uptodate = 1; page->uptodate = 1;
wake_up(&page->wait); wake_up(&page->wait);
next = bh;
do {
next->b_next_free = reuse_list;
reuse_list = next;
next = next->b_this_page;
} while (next != bh);
} }
++current->maj_flt; ++current->maj_flt;
return 0; return 0;
...@@ -1138,6 +1157,64 @@ void mark_buffer_uptodate(struct buffer_head * bh, int on) ...@@ -1138,6 +1157,64 @@ void mark_buffer_uptodate(struct buffer_head * bh, int on)
clear_bit(BH_Uptodate, &bh->b_state); clear_bit(BH_Uptodate, &bh->b_state);
} }
void unlock_buffer(struct buffer_head * bh)
{
struct buffer_head *tmp;
unsigned long flags;
struct page *page;
clear_bit(BH_Lock, &bh->b_state);
wake_up(&bh->b_wait);
if (!test_bit(BH_FreeOnIO, &bh->b_state))
return;
page = mem_map + MAP_NR(bh->b_data);
if (!page->locked) {
printk ("Whoops: unlock_buffer: "
"async io complete on unlocked page\n");
return;
}
if (bh->b_count != 1) {
printk ("Whoops: unlock_buffer: b_count != 1 on async io.\n");
return;
}
/* Async buffer_heads are here only as labels for IO, and get
thrown away once the IO for this page is complete. IO is
deemed complete once all buffers have been visited
(b_count==0) and are now unlocked. */
bh->b_count--;
for (tmp = bh; tmp=tmp->b_this_page, tmp!=bh; ) {
if (test_bit(BH_Lock, &tmp->b_state) || tmp->b_count)
return;
}
/* OK, go ahead and complete the async IO on this page. */
save_flags(flags);
page->locked = 0;
wake_up(&page->wait);
cli();
tmp = bh;
do {
if (!test_bit(BH_FreeOnIO, &tmp->b_state)) {
printk ("Whoops: unlock_buffer: "
"async IO mismatch on page.\n");
restore_flags(flags);
return;
}
tmp->b_next_free = reuse_list;
reuse_list = tmp;
clear_bit(BH_FreeOnIO, &tmp->b_state);
tmp = tmp->b_this_page;
} while (tmp != bh);
restore_flags(flags);
if (page->free_after) {
extern int nr_async_pages;
nr_async_pages--;
page->free_after = 0;
free_page(page_address(page));
}
}
/* /*
* Generic "readpage" function for block devices that have the normal * Generic "readpage" function for block devices that have the normal
* bmap functionality. This is most of the block device filesystems. * bmap functionality. This is most of the block device filesystems.
...@@ -1167,38 +1244,11 @@ int generic_readpage(struct inode * inode, struct page * page) ...@@ -1167,38 +1244,11 @@ int generic_readpage(struct inode * inode, struct page * page)
/* IO start */ /* IO start */
page->count++; page->count++;
address = page_address(page); address = page_address(page);
bread_page(address, inode->i_dev, nr, inode->i_sb->s_blocksize); brw_page(READ, address, inode->i_dev, nr, inode->i_sb->s_blocksize, 1);
free_page(address); free_page(address);
return 0; return 0;
} }
#if 0
/*
* bwrite_page writes a page out to the buffer cache and/or the physical device.
* It's used for mmap writes (the same way bread_page() is used for mmap reads).
*/
void bwrite_page(unsigned long address, kdev_t dev, int b[], int size)
{
struct buffer_head * bh[MAX_BUF_PER_PAGE];
int i, j;
for (i=0, j=0; j<PAGE_SIZE ; i++, j+= size) {
bh[i] = NULL;
if (b[i])
bh[i] = getblk(dev, b[i], size);
}
for (i=0, j=0; j<PAGE_SIZE ; i++, j += size, address += size) {
if (bh[i]) {
memcpy(bh[i]->b_data, (void *) address, size);
mark_buffer_uptodate(bh[i], 1);
mark_buffer_dirty(bh[i], 0);
brelse(bh[i]);
} else
memset((void *) address, 0, size); /* ???!?!! */
}
}
#endif
/* /*
* Try to increase the number of buffers available: the size argument * Try to increase the number of buffers available: the size argument
* is used to determine what kind of buffers we want. * is used to determine what kind of buffers we want.
......
#include <linux/config.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/proc_fs.h> #include <linux/proc_fs.h>
/*
* This is all required so that if we load all of scsi as a module,
* that the scsi code will be able to talk to the /proc/scsi handling
* in the procfs.
*/
extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
off_t offset, int length, int inout);
extern struct inode_operations proc_scsi_inode_operations;
static struct symbol_table procfs_syms = { static struct symbol_table procfs_syms = {
/* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */ /* Should this be surrounded with "#ifdef CONFIG_MODULES" ? */
#include <linux/symtab_begin.h> #include <linux/symtab_begin.h>
...@@ -12,11 +20,14 @@ static struct symbol_table procfs_syms = { ...@@ -12,11 +20,14 @@ static struct symbol_table procfs_syms = {
X(generate_cluster), X(generate_cluster),
X(proc_net_inode_operations), X(proc_net_inode_operations),
X(proc_net), X(proc_net),
#ifdef CONFIG_SCSI /* Ugh... */
/*
* This is required so that if we load scsi later, that the
* scsi code can attach to /proc/scsi in the correct manner.
*/
X(proc_scsi), X(proc_scsi),
X(proc_scsi_inode_operations), X(proc_scsi_inode_operations),
X(dispatch_scsi_info_ptr), X(dispatch_scsi_info_ptr),
#endif
#include <linux/symtab_end.h> #include <linux/symtab_end.h>
}; };
......
...@@ -297,11 +297,7 @@ void proc_root_init(void) ...@@ -297,11 +297,7 @@ void proc_root_init(void)
64, &proc_self_inode_operations, 64, &proc_self_inode_operations,
}); });
proc_register(&proc_root, &proc_net); proc_register(&proc_root, &proc_net);
#ifdef CONFIG_SCSI
proc_register(&proc_root, &proc_scsi); proc_register(&proc_root, &proc_scsi);
#endif
proc_register(&proc_root, &proc_sys_root); proc_register(&proc_root, &proc_sys_root);
#ifdef CONFIG_DEBUG_MALLOC #ifdef CONFIG_DEBUG_MALLOC
......
...@@ -13,14 +13,14 @@ ...@@ -13,14 +13,14 @@
#define NR_REQUEST 64 #define NR_REQUEST 64
/* /*
* This is used in the elevator algorithm: Note that * This is used in the elevator algorithm. We don't prioritise reads
* reads always go before writes. This is natural: reads * over writes any more --- although reads are more time-critical than
* are much more time-critical than writes. * writes, by treating them equally we increase filesystem throughput.
* This turns out to give better overall performance. -- sct
*/ */
#define IN_ORDER(s1,s2) \ #define IN_ORDER(s1,s2) \
((s1)->cmd < (s2)->cmd || ((s1)->cmd == (s2)->cmd && \
((s1)->rq_dev < (s2)->rq_dev || (((s1)->rq_dev == (s2)->rq_dev && \ ((s1)->rq_dev < (s2)->rq_dev || (((s1)->rq_dev == (s2)->rq_dev && \
(s1)->sector < (s2)->sector))))) (s1)->sector < (s2)->sector)))
/* /*
* These will have to be changed to be aware of different buffer * These will have to be changed to be aware of different buffer
......
...@@ -598,8 +598,8 @@ extern struct buffer_head * breada(kdev_t dev,int block, int size, ...@@ -598,8 +598,8 @@ extern struct buffer_head * breada(kdev_t dev,int block, int size,
extern int generic_readpage(struct inode *, struct page *); extern int generic_readpage(struct inode *, struct page *);
extern int generic_file_read(struct inode *, struct file *, char *, int); extern int generic_file_read(struct inode *, struct file *, char *, int);
extern int generic_mmap(struct inode *, struct file *, struct vm_area_struct *); extern int generic_mmap(struct inode *, struct file *, struct vm_area_struct *);
extern int brw_page(int, unsigned long, kdev_t, int [], int, int);
extern void bwrite_page(unsigned long addr,kdev_t dev,int b[],int size);
extern void put_super(kdev_t dev); extern void put_super(kdev_t dev);
unsigned long generate_cluster(kdev_t dev, int b[], int size); unsigned long generate_cluster(kdev_t dev, int b[], int size);
extern kdev_t ROOT_DEV; extern kdev_t ROOT_DEV;
......
...@@ -4,6 +4,9 @@ ...@@ -4,6 +4,9 @@
#ifndef _LINUX_MM_H #ifndef _LINUX_MM_H
#include <linux/mm.h> #include <linux/mm.h>
#endif #endif
#ifndef _LINUX_PAGEMAP_H
#include <linux/pagemap.h>
#endif
/* /*
* Unlocked, temporary IO buffer_heads gets moved to the reuse_list * Unlocked, temporary IO buffer_heads gets moved to the reuse_list
...@@ -29,39 +32,8 @@ extern inline void lock_buffer(struct buffer_head * bh) ...@@ -29,39 +32,8 @@ extern inline void lock_buffer(struct buffer_head * bh)
__wait_on_buffer(bh); __wait_on_buffer(bh);
} }
extern inline void unlock_buffer(struct buffer_head * bh) void unlock_buffer(struct buffer_head *);
{
struct buffer_head *tmp = bh;
int page_locked = 0;
unsigned long flags;
clear_bit(BH_Lock, &bh->b_state);
wake_up(&bh->b_wait);
do {
if (test_bit(BH_Lock, &tmp->b_state)) {
page_locked = 1;
break;
}
tmp=tmp->b_this_page;
} while (tmp && tmp != bh);
save_flags(flags);
if (!page_locked) {
struct page *page = mem_map + MAP_NR(bh->b_data);
page->locked = 0;
wake_up(&page->wait);
tmp = bh;
cli();
do {
if (test_bit(BH_FreeOnIO, &tmp->b_state)) {
tmp->b_next_free = reuse_list;
reuse_list = tmp;
clear_bit(BH_FreeOnIO, &tmp->b_state);
}
tmp = tmp->b_this_page;
} while (tmp && tmp != bh);
restore_flags(flags);
}
}
/* /*
* super-block locking. Again, interrupts may only unlock * super-block locking. Again, interrupts may only unlock
......
...@@ -122,7 +122,8 @@ typedef struct page { ...@@ -122,7 +122,8 @@ typedef struct page {
error:1, error:1,
referenced:1, referenced:1,
locked:1, locked:1,
unused:3, free_after:1,
unused:2,
reserved:1; reserved:1;
struct wait_queue *wait; struct wait_queue *wait;
struct page *next; struct page *next;
......
...@@ -118,6 +118,7 @@ enum scsi_directory_inos { ...@@ -118,6 +118,7 @@ enum scsi_directory_inos {
PROC_SCSI_ULTRASTOR, PROC_SCSI_ULTRASTOR,
PROC_SCSI_7000FASST, PROC_SCSI_7000FASST,
PROC_SCSI_EATA2X, PROC_SCSI_EATA2X,
PROC_SCSI_AM53C974,
PROC_SCSI_SSC, PROC_SCSI_SSC,
PROC_SCSI_SCSI_DEBUG, PROC_SCSI_SCSI_DEBUG,
PROC_SCSI_NOT_PRESENT, PROC_SCSI_NOT_PRESENT,
......
...@@ -12,6 +12,8 @@ ...@@ -12,6 +12,8 @@
#define SWP_USED 1 #define SWP_USED 1
#define SWP_WRITEOK 3 #define SWP_WRITEOK 3
#define SWAP_CLUSTER_MAX 32
struct swap_info_struct { struct swap_info_struct {
unsigned int flags; unsigned int flags;
kdev_t swap_device; kdev_t swap_device;
...@@ -20,6 +22,8 @@ struct swap_info_struct { ...@@ -20,6 +22,8 @@ struct swap_info_struct {
unsigned char * swap_lockmap; unsigned char * swap_lockmap;
int lowest_bit; int lowest_bit;
int highest_bit; int highest_bit;
int cluster_next;
int cluster_nr;
int prio; /* swap priority */ int prio; /* swap priority */
int pages; int pages;
unsigned long max; unsigned long max;
...@@ -28,6 +32,7 @@ struct swap_info_struct { ...@@ -28,6 +32,7 @@ struct swap_info_struct {
extern int nr_swap_pages; extern int nr_swap_pages;
extern int nr_free_pages; extern int nr_free_pages;
extern int nr_async_pages;
extern int min_free_pages; extern int min_free_pages;
extern int free_pages_low; extern int free_pages_low;
extern int free_pages_high; extern int free_pages_high;
...@@ -40,17 +45,17 @@ struct sysinfo; ...@@ -40,17 +45,17 @@ struct sysinfo;
/* linux/ipc/shm.c */ /* linux/ipc/shm.c */
extern int shm_swap (int, unsigned long); extern int shm_swap (int, unsigned long);
/* linux/mm/swap_clock.c */ /* linux/mm/vmscan.c */
extern int try_to_free_page(int, unsigned long); extern int try_to_free_page(int, unsigned long, int);
/* linux/mm/swap_io.c */ /* linux/mm/page_io.c */
extern void rw_swap_page(int, unsigned long, char *); extern void rw_swap_page(int, unsigned long, char *, int);
#define read_swap_page(nr,buf) \ #define read_swap_page(nr,buf) \
rw_swap_page(READ,(nr),(buf)) rw_swap_page(READ,(nr),(buf),1)
#define write_swap_page(nr,buf) \ #define write_swap_page(nr,buf) \
rw_swap_page(WRITE,(nr),(buf)) rw_swap_page(WRITE,(nr),(buf),1)
/* linux/mm/swap_mman.c */ /* linux/mm/page_alloc.c */
extern void swap_in(struct task_struct *, struct vm_area_struct *, extern void swap_in(struct task_struct *, struct vm_area_struct *,
pte_t *, unsigned long, int); pte_t *, unsigned long, int);
......
...@@ -70,6 +70,7 @@ extern void generic_NCR5380_setup(char *str, int *intr); ...@@ -70,6 +70,7 @@ extern void generic_NCR5380_setup(char *str, int *intr);
extern void aha152x_setup(char *str, int *ints); extern void aha152x_setup(char *str, int *ints);
extern void aha1542_setup(char *str, int *ints); extern void aha1542_setup(char *str, int *ints);
extern void aic7xxx_setup(char *str, int *ints); extern void aic7xxx_setup(char *str, int *ints);
extern void AM53C974_setup(char *str, int *ints);
extern void BusLogic_Setup(char *str, int *ints); extern void BusLogic_Setup(char *str, int *ints);
extern void fdomain_setup(char *str, int *ints); extern void fdomain_setup(char *str, int *ints);
extern void NCR53c406a_setup(char *str, int *ints); extern void NCR53c406a_setup(char *str, int *ints);
...@@ -239,6 +240,9 @@ struct { ...@@ -239,6 +240,9 @@ struct {
#ifdef CONFIG_SCSI_BUSLOGIC #ifdef CONFIG_SCSI_BUSLOGIC
{ "BusLogic=", BusLogic_Setup}, { "BusLogic=", BusLogic_Setup},
#endif #endif
#ifdef CONFIG_SCSI_AM53C974
{ "AM53C974=", AM53C974_setup},
#endif
#ifdef CONFIG_SCSI_NCR53C406A #ifdef CONFIG_SCSI_NCR53C406A
{ "ncr53c406a=", NCR53c406a_setup}, { "ncr53c406a=", NCR53c406a_setup},
#endif #endif
......
...@@ -86,19 +86,6 @@ extern unsigned char aux_device_present, kbd_read_mask; ...@@ -86,19 +86,6 @@ extern unsigned char aux_device_present, kbd_read_mask;
#include <linux/smp.h> #include <linux/smp.h>
#endif #endif
#ifndef CONFIG_SCSI
#if defined(CONFIG_PROC_FS)
/*
* This is all required so that if we load all of scsi as a module,
* that the scsi code will be able to talk to the /proc/scsi handling
* in the procfs.
*/
extern int (* dispatch_scsi_info_ptr) (int ino, char *buffer, char **start,
off_t offset, int length, int inout);
extern struct inode_operations proc_scsi_inode_operations;
#endif
#endif
extern char *get_options(char *str, int *ints); extern char *get_options(char *str, int *ints);
extern void set_device_ro(int dev,int flag); extern void set_device_ro(int dev,int flag);
extern struct file_operations * get_blkfops(unsigned int); extern struct file_operations * get_blkfops(unsigned int);
...@@ -210,6 +197,7 @@ struct symbol_table symbol_table = { ...@@ -210,6 +197,7 @@ struct symbol_table symbol_table = {
X(__bforget), X(__bforget),
X(ll_rw_block), X(ll_rw_block),
X(__wait_on_buffer), X(__wait_on_buffer),
X(unlock_buffer),
X(dcache_lookup), X(dcache_lookup),
X(dcache_add), X(dcache_add),
X(aout_core_dump), X(aout_core_dump),
...@@ -435,14 +423,6 @@ struct symbol_table symbol_table = { ...@@ -435,14 +423,6 @@ struct symbol_table symbol_table = {
*/ */
X(gendisk_head), X(gendisk_head),
X(resetup_one_dev), X(resetup_one_dev),
#if defined(CONFIG_PROC_FS)
/*
* This is required so that if we load scsi later, that the
* scsi code can attach to /proc/scsi in the correct manner.
*/
X(proc_scsi_inode_operations),
X(dispatch_scsi_info_ptr),
#endif
#endif #endif
/* Added to make file system as module */ /* Added to make file system as module */
X(set_writetime), X(set_writetime),
......
...@@ -168,8 +168,7 @@ void update_vm_cache(struct inode * inode, unsigned long pos, const char * buf, ...@@ -168,8 +168,7 @@ void update_vm_cache(struct inode * inode, unsigned long pos, const char * buf,
if (page) { if (page) {
unsigned long addr; unsigned long addr;
if (!page->uptodate) wait_on_page(page);
sleep_on(&page->wait);
addr = page_address(page); addr = page_address(page);
memcpy((void *) ((pos & ~PAGE_MASK) + addr), buf, count); memcpy((void *) ((pos & ~PAGE_MASK) + addr), buf, count);
free_page(addr); free_page(addr);
......
...@@ -181,7 +181,7 @@ unsigned long __get_free_pages(int priority, unsigned long order, unsigned long ...@@ -181,7 +181,7 @@ unsigned long __get_free_pages(int priority, unsigned long order, unsigned long
return 0; return 0;
} }
restore_flags(flags); restore_flags(flags);
if (priority != GFP_BUFFER && try_to_free_page(priority, limit)) if (priority != GFP_BUFFER && try_to_free_page(priority, limit, 1))
goto repeat; goto repeat;
return 0; return 0;
} }
......
...@@ -28,11 +28,12 @@ ...@@ -28,11 +28,12 @@
static struct wait_queue * lock_queue = NULL; static struct wait_queue * lock_queue = NULL;
void rw_swap_page(int rw, unsigned long entry, char * buf) void rw_swap_page(int rw, unsigned long entry, char * buf, int wait)
{ {
unsigned long type, offset; unsigned long type, offset;
struct swap_info_struct * p; struct swap_info_struct * p;
struct page *page;
type = SWP_TYPE(entry); type = SWP_TYPE(entry);
if (type >= nr_swapfiles) { if (type >= nr_swapfiles) {
printk("Internal error: bad swap-device\n"); printk("Internal error: bad swap-device\n");
...@@ -58,8 +59,17 @@ void rw_swap_page(int rw, unsigned long entry, char * buf) ...@@ -58,8 +59,17 @@ void rw_swap_page(int rw, unsigned long entry, char * buf)
kstat.pswpin++; kstat.pswpin++;
else else
kstat.pswpout++; kstat.pswpout++;
page = mem_map + MAP_NR(buf);
wait_on_page(page);
if (p->swap_device) { if (p->swap_device) {
if (!wait) {
page->count++;
page->free_after = 1;
nr_async_pages++;
}
ll_rw_page(rw,p->swap_device,offset,buf); ll_rw_page(rw,p->swap_device,offset,buf);
if (wait)
wait_on_page(page);
} else if (p->swap_file) { } else if (p->swap_file) {
struct inode *swapf = p->swap_file; struct inode *swapf = p->swap_file;
unsigned int zones[PAGE_SIZE/512]; unsigned int zones[PAGE_SIZE/512];
...@@ -105,4 +115,3 @@ void rw_swap_page(int rw, unsigned long entry, char * buf) ...@@ -105,4 +115,3 @@ void rw_swap_page(int rw, unsigned long entry, char * buf)
printk("rw_swap_page: lock already cleared\n"); printk("rw_swap_page: lock already cleared\n");
wake_up(&lock_queue); wake_up(&lock_queue);
} }
...@@ -42,6 +42,10 @@ int min_free_pages = 20; ...@@ -42,6 +42,10 @@ int min_free_pages = 20;
int free_pages_low = 30; int free_pages_low = 30;
int free_pages_high = 40; int free_pages_high = 40;
/* We track the number of pages currently being asynchronously swapped
out, so that we don't try to swap TOO many pages out at once */
int nr_async_pages = 0;
/* /*
* Constants for the page aging mechanism: the maximum age (actually, * Constants for the page aging mechanism: the maximum age (actually,
* the maximum "youthfulness"); the quanta by which pages rejuvinate * the maximum "youthfulness"); the quanta by which pages rejuvinate
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment