N: Hannu Savolainen
E: hannu@voxware.pp.fi
D: Kernel sound drivers
-S: Pallaksentie 4 A 2
-S: 00970 Helsinki
+S: Hiekkalaiturintie 3 A 8
+S: 00980 Helsinki
S: Finland
N: Peter De Schrijver
VERSION = 1
PATCHLEVEL = 1
-SUBLEVEL = 89
+SUBLEVEL = 90
ARCH = i386
\
ls *.o > .allmods; \
echo $$MODULES | tr ' ' '\n' | sort | comm -23 .allmods - > .misc; \
- inst_mod .misc misc; \
+ if [ -s .misc ]; then inst_mod .misc misc; fi; \
rm -f .misc .allmods; \
)
if [ "$CONFIG_INET" = "y" ]; then
bool 'NFS filesystem support' CONFIG_NFS_FS y
fi
-if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" ]; then
+if [ "$CONFIG_BLK_DEV_SR" = "y" -o "$CONFIG_CDU31A" = "y" -o "$CONFIG_MCD" = "y" -o "$CONFIG_SBPCD" = "y" -o "$CONFIG_BLK_DEV_IDECD" = "y" -o "$CONFIG_AZTCD" = "y" ]; then
bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS y
else
bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
if (task[i] == current) {
if (!(current->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE)))
return -ENOMEM;
+ memset(current->ldt, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES);
load_ldt(i);
}
}
regs->esp = (unsigned long) frame;
regs->eip = eip; /* "return" to the first handler */
+ regs->eflags &= ~TF_MASK;
current->tss.trap_no = current->tss.error_code = 0;
return 1;
}
asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
{
- int signr = SIGSEGV;
-
if (regs->eflags & VM_MASK) {
handle_vm86_fault((struct vm86_regs *) regs, error_code);
return;
}
die_if_kernel("general protection",regs,error_code);
- switch (get_seg_byte(regs->cs, (char *)regs->eip)) {
- case 0xCD: /* INT */
- case 0xF4: /* HLT */
- case 0xFA: /* CLI */
- case 0xFB: /* STI */
- signr = SIGILL;
- }
current->tss.error_code = error_code;
current->tss.trap_no = 13;
- send_sig(signr, current, 1);
+ send_sig(SIGSEGV, current, 1);
}
asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
/* ioport.c: I/O access on the Sparc. Work in progress.. Most of the things
* in this file are for the sole purpose of getting the kernel
- * throught the compiler. :-)
+ * through the compiler. :-)
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
*/
* unmaps the bootup page table (as we're now in KSEG, so we don't need it).
*
* The bootup sequence put the virtual page table into high memory: that
- * means that we cah change the L1 page table by just using VL1p below.
+ * means that we can change the L1 page table by just using VL1p below.
*/
unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
Sets the bitmask of allowed drives to <mask>. By default, only units
0 and 1 of each floppy controller are allowed. This is done because
certain non-standard hardware (ASUS PCI motherboards) mess up the
- keyboard when accessing units 2 or 3.
+ keyboard when accessing units 2 or 3. This option is somewhat
+ obsoleted by the cmos option.
+
+ floppy=all_drives
+ Sets the bitmask of allowed drives to all drives. Use this if you have
+ more than two drives connected to a floppy controller.
+
+ floppy=asus_pci
+ Sets the bitmask to allow only units 0 and 1. (The default)
+
+ floppy=daring
+ Tells the floppy driver that you have a well behaved floppy controller.
+ This allows more efficient and smoother operation, but may fail on
+ certain controllers. This may speed up certain operations.
+
+ floppy=0,daring
+ Tells the floppy driver that your floppy controller should be used
+ with caution.
+
+ floppy=one_fdc
+ Tells the floppy driver that you have only floppy controller (default)
floppy=two_fdc
+ floppy=<address>,two_fdc
Tells the floppy driver that you have two floppy controllers. The
- second floppy controller is assumed to be at io address 0x370.
+ second floppy controller is assumed to be at <address>. If <address>
+ is not given, 0x370 is assumed.
floppy=thinkpad
Tells the floppy driver that you have a Thinkpad. Thinkpads use an
inverted convention for the disk change line.
+ floppy=0,thinkpad
+ Tells the floppy driver that you don't have a Thinkpad.
+
+ floppy=<drive>,<type>,cmos
+ Sets the cmos type of <drive> to <type>. Additionnaly, this drive is
+ allowed in the bitmask. This is useful if you have more than two
+ floppy drives (only two can be described in the physical cmos), or if
+ your BIOS uses non-standard CMOS types. The CMOS types are:
+ 0 - unknown or not installed
+ 1 - 5 1/4 DD
+ 2 - 5 1/4 HD
+ 3 - 3 1/2 DD
+ 4 - 3 1/2 HD
+ 5 - 3 1/2 ED
+ 6 - 3 1/2 ED
+ (Note: there are two valid types for ED drives. This is because 5 was
+ initially chosen to represent floppy *tapes*, and 6 for ED drives.
+ AMI ignored this, and used 5 for ED drives. That's why the floppy
+ driver handles both)
+ Setting the CMOS to 0 for the first two drives (default) makes the
+ floppy driver read the physical cmos for those drives.
+
+ floppy=unexpected_interrupts
+ Print a warning message when an unexpected interrupt is received
+ (default behaviour)
+
+ floppy=no_unexpected_interrupts
+ floppy=L40SX
+ Don't print a message when an unexpected interrupt is received. This
+ is needed on IBM L40SX laptops in certain video modes. (There seems
+ to be an interaction between video and floppy. The unexpected interrupts
+ only affect performance, and can safely be ignored.)
Supporting utilities and additional documentation:
break;
case CDROMVOLCTRL: /* Volume control
* With my Aztech CD268-01A volume control does not work, I can only
- turn the cannels on (any value !=0) or off (value==0). Maybe it
+ turn the channels on (any value !=0) or off (value==0). Maybe it
works better with your drive */
st=verify_area(VERIFY_READ,(void *) arg, sizeof(volctrl));
if (st) return (st);
*/
#define CONFIG_FLOPPY_SANITY
-#define CONFIG_FLOPPY_2_FDC
#undef CONFIG_FLOPPY_SILENT_DCL_CLEAR
#define REALLY_SLOW_IO
#include <linux/config.h>
+/* do print messages for unexpected interupts */
+static int print_unex=1;
+
#ifndef FD_MODULE
/* the following is the mask of allowed drives. By default units 2 and
* 3 of both floppy controllers are disabled, because switching on the
#define FLOPPY1_TYPE 0
#endif
-
-#ifdef CONFIG_FLOPPY_2_FDC
#define N_FDC 2
#define N_DRIVE 8
-#else
-#define N_FDC 1
-#define N_DRIVE 4
-#endif
#define TYPE(x) ( ((x)>>2) & 0x1f )
#define DRIVE(x) ( ((x)&0x03) | (((x)&0x80 ) >> 5))
#define USETF(x) (set_bit(x##_BIT, &UDRS->flags))
#define UTESTF(x) (test_bit(x##_BIT, &UDRS->flags))
-#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive);
+#define DPRINT(x) printk(DEVICE_NAME "%d: " x,current_drive)
#define DPRINT1(x,x1) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1))
#define DPRINT2(x,x1,x2) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2))
#define DPRINT3(x,x1,x2,x3) \
-printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3));
+printk(DEVICE_NAME "%d: " x,current_drive,(x1),(x2),(x3))
/* read/write */
#define COMMAND raw_cmd.cmd[0]
/* Auto-detection: Disk type used until the next media change occurs. */
struct floppy_struct *current_type[N_DRIVE] = {
+ NULL, NULL, NULL, NULL,
NULL, NULL, NULL, NULL
-#ifdef CONFIG_FLOPPY_2_FDC
- ,
- NULL, NULL, NULL, NULL
-#endif
};
/*
current_drive = drive;
}
set_dor(fdc,~0,8);
-#ifdef CONFIG_FLOPPY_2_FDC
set_dor(1-fdc, ~8, 0);
-#endif
if ( FDCS->rawcmd == 2 )
reset_fdc_info(1);
if( inb_p(FD_STATUS) != STATUS_READY )
{ NULL, NULL, 0, 0, motor_off_callback },
{ NULL, NULL, 0, 1, motor_off_callback },
{ NULL, NULL, 0, 2, motor_off_callback },
- { NULL, NULL, 0, 3, motor_off_callback }
-#ifdef CONFIG_FLOPPY_2_FDC
- ,
+ { NULL, NULL, 0, 3, motor_off_callback },
{ NULL, NULL, 0, 4, motor_off_callback },
{ NULL, NULL, 0, 5, motor_off_callback },
{ NULL, NULL, 0, 6, motor_off_callback },
{ NULL, NULL, 0, 7, motor_off_callback }
-#endif
};
/* schedules motor off */
int i;
if ( initialising )
return;
- DPRINT("unexpected interrupt\n");
- if ( inr >= 0 )
- for(i=0; i<inr; i++)
- printk("%d %x\n", i, reply_buffer[i] );
+ if(print_unex){
+ DPRINT("unexpected interrupt\n");
+ if ( inr >= 0 )
+ for(i=0; i<inr; i++)
+ printk("%d %x\n", i, reply_buffer[i] );
+ }
while(1){
output_byte(FD_SENSEI);
inr=result();
if ( inr != 2 )
break;
- printk("sensei\n");
- for(i=0; i<inr; i++)
- printk("%d %x\n", i, reply_buffer[i] );
+ if(print_unex){
+ printk("sensei\n");
+ for(i=0; i<inr; i++)
+ printk("%d %x\n", i, reply_buffer[i] );
+ }
}
FDCS->reset = 1;
}
cnt < (type << 2 ) + 4 ;
cnt++)
floppy_sizes[cnt]=
-#ifdef CONFIG_FLOPPY_2_FDC
floppy_sizes[cnt+0x80]=
-#endif
floppy_type[type].size>>1;
process_fd_request();
for ( cnt = 0; cnt < N_DRIVE; cnt++){
#undef IOCTL_ALLOWED
}
-static void set_base_type(int drive,int code)
-{
- if (code > 0 && code <= NUMBER(default_drive_params)) {
- memcpy((char *) UDP,
- (char *) (&default_drive_params[code].params),
- sizeof( struct floppy_drive_params ));
- printk("fd%d is %s", drive, default_drive_params[code].name);
- return;
- } else if (!code)
- printk("fd%d is not installed", drive);
- else
- printk("fd%d is unknown type %d",drive,code);
-}
-
static void config_types(void)
{
+ int first=1;
int drive;
- for (drive=0; drive<N_DRIVE ; drive++){
- /* default type for unidentifiable drives */
- memcpy((char *) UDP, (char *) (&default_drive_params->params),
- sizeof( struct floppy_drive_params ));
- }
- printk("Floppy drive(s): ");
- set_base_type(0, FLOPPY0_TYPE);
- if (FLOPPY1_TYPE) {
- printk(", ");
- set_base_type(1, FLOPPY1_TYPE);
+ /* read drive info out of physical cmos */
+ drive=0;
+ if (!UDP->cmos )
+ UDP->cmos= FLOPPY0_TYPE;
+ drive=1;
+ if (!UDP->cmos && FLOPPY1_TYPE)
+ UDP->cmos = FLOPPY1_TYPE;
+
+ /* XXX */
+ /* additional physical CMOS drive detection should go here */
+
+ for (drive=0; drive < N_DRIVE; drive++){
+ if (UDP->cmos >= 0 && UDP->cmos <= NUMBER(default_drive_params))
+ memcpy((char *) UDP,
+ (char *) (&default_drive_params[(int)UDP->cmos].params),
+ sizeof(struct floppy_drive_params));
+ if (UDP->cmos){
+ if (first)
+ printk("Floppy drive(s): ");
+ else
+ printk(", ");
+ first=0;
+ if (UDP->cmos > 0 ){
+ ALLOWED_DRIVE_MASK |= 1 << drive;
+ printk("fd%d is %s", drive,
+ default_drive_params[(int)UDP->cmos].name);
+ } else
+ printk("fd%d is unknown type %d",drive,
+ UDP->cmos);
+ }
}
- printk("\n");
+ if(!first)
+ printk("\n");
}
static int floppy_read(struct inode * inode, struct file * filp,
} /* get_fdc_version */
/* lilo configuration */
-static void invert_dcl(int *ints)
+
+/* we make the invert_dcl function global. One day, somebody might
+want to centralize all thinkpad related options into one lilo option,
+there are just so many thinpad related quirks! */
+void floppy_invert_dcl(int *ints,int param)
{
int i;
- for (i=0; i < ARRAY_SIZE(default_drive_params); i++)
- default_drive_params[i].params.flags |= 0x80;
+ for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
+ if (param)
+ default_drive_params[i].params.flags |= 0x80;
+ else
+ default_drive_params[i].params.flags &= ~0x80;
+ }
DPRINT("Configuring drives for inverted dcl\n");
}
-static void allow_drives(int *ints)
+static void daring(int *ints,int param)
{
- if (ints[1] >= 1 ){
- ALLOWED_DRIVE_MASK=ints[1];
- DPRINT1("setting allowed_drive_mask to 0x%x\n", ints[1]);
- } else
- DPRINT("allowed_drive_mask needs a parameter\n");
+ int i;
+
+ for (i=0; i < ARRAY_SIZE(default_drive_params); i++){
+ if (param){
+ default_drive_params[i].params.select_delay = 0;
+ default_drive_params[i].params.flags |= FD_SILENT_DCL_CLEAR;
+ } else {
+ default_drive_params[i].params.select_delay = 2;
+ default_drive_params[i].params.flags &= ~FD_SILENT_DCL_CLEAR;
+ }
+ }
+ DPRINT1("Assuming %s floppy hardware\n", param ? "standard" : "broken");
}
-#ifdef CONFIG_FLOPPY_2_FDC
-static void twofdc(int *ints)
+static void allow_drives(int *ints, int param)
{
- FDC2 = 0x370;
- DPRINT("enabling second fdc at address 0x370\n");
+ ALLOWED_DRIVE_MASK=param;
+ DPRINT1("setting allowed_drive_mask to 0x%x\n", param);
}
-#endif
+static void fdc2_adr(int *ints, int param)
+{
+ FDC2 = param;
+ if(param)
+ DPRINT1("enabling second fdc at address 0x%3x\n", FDC2);
+ else
+ DPRINT("disabling second fdc\n");
+}
+
+static void unex(int *ints,int param)
+{
+ print_unex = param;
+ DPRINT1("%sprinting messages for unexpected interrupts\n",
+ param ? "" : "not ");
+}
+
+static void set_cmos(int *ints, int dummy)
+{
+ int current_drive=0;
+
+ if ( ints[0] != 2 ){
+ DPRINT("wrong number of parameter for cmos\n");
+ return;
+ }
+ current_drive = ints[1];
+ if (current_drive < 0 || current_drive >= 8 ){
+ DPRINT("bad drive for set_cmos\n");
+ return;
+ }
+ if(ints[2] <= 0 || ints[2] >= NUMBER(default_drive_params)){
+ DPRINT1("bad cmos code %d\n", ints[2]);
+ return;
+ }
+ DP->cmos = ints[2];
+ DPRINT1("setting cmos code to %d\n", ints[2]);
+}
+
static struct param_table {
char *name;
- void (*fn)(int *ints);
+ void (*fn)(int *ints, int param);
+ int def_param;
} config_params[]={
-{ "allowed_drive_mask", allow_drives },
-#ifdef CONFIG_FLOPPY_2_FDC
-{ "two_fdc", twofdc },
-#endif
-{ "thinkpad", invert_dcl } };
+{ "allowed_drive_mask", allow_drives, 0xff },
+{ "all_drives", allow_drives, 0xff },
+{ "asus_pci", allow_drives, 0x33 },
+
+{ "daring", daring, 1},
+
+{ "two_fdc", fdc2_adr, 0x370 },
+{ "one_fdc", fdc2_adr, 0 },
+{ "thinkpad", floppy_invert_dcl, 1 },
+
+{ "cmos", set_cmos, 0 },
+
+{ "unexpected_interrupts", unex, 1 },
+{ "no_unexpected_interrupts", unex, 0 },
+{ "L40SX", unex, 0 } };
+
+#define FLOPPY_SETUP
void floppy_setup(char *str, int *ints)
{
int i;
+ int param;
if(!str)
return;
for(i=0; i< ARRAY_SIZE(config_params); i++){
if (strcmp(str,config_params[i].name) == 0 ){
- config_params[i].fn(ints);
+ if (ints[0] )
+ param = ints[1];
+ else
+ param = config_params[i].def_param;
+ config_params[i].fn(ints,param);
return;
}
}
- printk("unknown floppy parameter %s\n", str);
+ DPRINT1("unknown floppy option %s\n", str);
+ DPRINT("allowed options are:");
+ for(i=0; i< ARRAY_SIZE(config_params); i++)
+ printk(" %s",config_params[i].name);
+ printk("\n");
+ DPRINT("Read linux/drivers/block/README.fd\n");
}
-#define FLOPPY_SETUP
#ifdef FD_MODULE
static
-Thu Jan 26 09:02:49 1995 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (rs_init, set_serial_info, get_serial_info, rs_close):
- Support close_wait and close_wait2 in the serial driver.
- This is helpful for slow devices (like serial plotters) so
- that their outputs don't get flushed upon device close.
- This has to be configurable because normally we don't want
- ports to be hung up for long periods of time during a
- close when they are not connected to a device, or the
- device is powered off.
-
- The default is to wait 30 seconds after shutting down the
- receiver (to prevent echo wars). This is done by setting
- close_wait=ASYNC_CLOSE_WAIT_NONE, close_wait2 = 3000. If
- XON/XOFF handshaking is used, then the 30 second timeout
- should happen before the receiver is shutdown; this is
- done by reversing the values of close_wait and
- close_wait2. In the case of a very slow device, the
- timeouts for close_wait or close_wait2 should be lengthened.
- If either value is set to 0, the kernel will wait forever
- for all of the data to be transmitted.
-
-Thu Jan 17 01:17:20 1995 Theodore Y. Ts'o (tytso@rt-11)
-
- * serial.c (startup, change_speed, rs_init): Add support to detect
- the StarTech 16650 chip. Treat it as a 16450 for now,
- because of its FIFO bugs.
-
Thu Jan 5 21:21:57 1995 <dhinds@allegro.stanford.edu>
* serial.c: (receive_char): Added counter to prevent infinite loop
ret_val = tty_check_change(tty);
if (ret_val)
return ret_val;
- wait_until_sent(tty,0);
+ tty_wait_until_sent(tty,0);
if (!arg)
send_break(info, HZ/4); /* 1/4 second */
break;
ret_val = tty_check_change(tty);
if (ret_val)
return ret_val;
- wait_until_sent(tty,0);
+ tty_wait_until_sent(tty,0);
send_break(info, arg ? arg*(HZ/10) : HZ/4);
break;
case TIOCMBIS:
if (info->flags & ASYNC_CALLOUT_ACTIVE)
info->callout_termios = *tty->termios;
if (info->flags & ASYNC_INITIALIZED)
- wait_until_sent(tty, 3000); /* 30 seconds timeout */
+ tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
shutdown(info);
if (tty->driver.flush_buffer)
tty->driver.flush_buffer(tty);
{
int i;
- for (i=0; i<0x10000; i++)
+ for (i=0; i<0x100000; i++)
if ((inb_p(0x64) & 0x02) == 0)
- break;
+ return;
+ printk("Keyboard timed out\n");
}
static inline void send_cmd(unsigned char c)
bh_base[KEYBOARD_BH].routine = kbd_bh;
request_irq(KEYBOARD_IRQ, keyboard_interrupt, 0, "keyboard");
#ifdef __alpha__
- /* enable keyboard interrupts */
- outb(0x60,0x64);
- while (inb(0x64) & 2)
- /* nothing */;
- outb(0x1,0x60);
- while (inb(0x64) & 2)
- /* nothing */;
- if (!send_data(0xf0) || !send_data(0x01))
- printk("Scanmode 1 change failed\n");
+ /* enable keyboard interrupts, PC/AT mode */
+ kb_wait();
+ outb(0x60,0x64); /* write PS/2 Mode Register */
+ kb_wait();
+ outb(0x41,0x60); /* KCC | EKI */
+ kb_wait();
+ if (!send_data(0xf0) || !send_data(0x02))
+ printk("Scanmode 2 change failed\n");
#endif
mark_bh(KEYBOARD_BH);
enable_bh(KEYBOARD_BH);
static void n_tty_close(struct tty_struct *tty)
{
- wait_until_sent(tty, 0);
+ tty_wait_until_sent(tty, 0);
n_tty_flush_buffer(tty);
if (tty->read_buf) {
free_page((unsigned long) tty->read_buf);
* Clear the FIFO buffers and disable them
* (they will be reenabled in change_speed())
*/
- if (info->type == PORT_16650) {
- serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
- UART_FCR_CLEAR_XMIT));
-#if 0
- info->xmit_fifo_size = 32;
-#else
- info->xmit_fifo_size = 1;
-#endif
- } else if (info->type == PORT_16550A) {
+ if (info->type == PORT_16550A) {
serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR |
UART_FCR_CLEAR_XMIT));
info->xmit_fifo_size = 16;
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1;
else
fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8;
- } else if (info->type == PORT_16650) {
- /*
- * On the 16650, we disable the FIFOs altogether
- * because of a design bug in how the implement
- * things. We could support it by completely changing
- * how we handle the interrupt driver, but not today....
- *
- * N.B. Because there's no way to set a FIFO trigger
- * at 1 char, we'd probably disable at speed below
- * 2400 baud anyway...
- */
- fcr = 0;
} else
fcr = 0;
tmp.flags = info->flags;
tmp.baud_base = info->baud_base;
tmp.close_delay = info->close_delay;
- tmp.closing_wait = info->closing_wait;
- tmp.closing_wait2 = info->closing_wait2;
tmp.custom_divisor = info->custom_divisor;
tmp.hub6 = info->hub6;
memcpy_tofs(retinfo,&tmp,sizeof(*retinfo));
info->custom_divisor = new_serial.custom_divisor;
info->type = new_serial.type;
info->close_delay = new_serial.close_delay;
- info->closing_wait = new_serial.closing_wait;
- info->closing_wait2 = new_serial.closing_wait2;
release_region(info->port,8);
if (change_port || change_irq) {
retval = tty_check_change(tty);
if (retval)
return retval;
- wait_until_sent(tty, 0);
+ tty_wait_until_sent(tty, 0);
if (!arg)
send_break(info, HZ/4); /* 1/4 second */
return 0;
retval = tty_check_change(tty);
if (retval)
return retval;
- wait_until_sent(tty, 0);
+ tty_wait_until_sent(tty, 0);
send_break(info, arg ? arg*(HZ/10) : HZ/4);
return 0;
case TIOCGSOFTCAR:
info->normal_termios = *tty->termios;
if (info->flags & ASYNC_CALLOUT_ACTIVE)
info->callout_termios = *tty->termios;
- if (info->closing_wait != ASYNC_CLOSING_WAIT_NONE)
- wait_until_sent(tty, info->closing_wait);
/*
* At this point we stop accepting input. To do this, we
* disable the receive line status interrupts, and tell the
info->read_status_mask &= ~UART_LSR_DR;
if (info->flags & ASYNC_INITIALIZED) {
serial_out(info, UART_IER, info->IER);
- wait_until_sent(tty, info->closing_wait2);
+ tty_wait_until_sent(tty, 3000); /* 30 seconds timeout */
/*
* Before we drop DTR, make sure the UART transmitter
* has completely drained; this is especially
if (info->flags & ASYNC_AUTO_IRQ)
info->irq = do_auto_irq(info);
- scratch2 = serial_in(info, UART_LCR);
- serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
- serial_outp(info, UART_EFR, 0); /* EFR is the same as FCR */
- serial_outp(info, UART_LCR, scratch2);
serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO);
scratch = serial_in(info, UART_IIR) >> 6;
info->xmit_fifo_size = 1;
info->type = PORT_16550;
break;
case 3:
- serial_outp(info, UART_LCR, scratch2 | UART_LCR_DLAB);
- if (serial_in(info, UART_EFR) == 0) {
- info->type = PORT_16650;
- info->xmit_fifo_size = 32;
- } else {
- info->type = PORT_16550A;
- info->xmit_fifo_size = 16;
- }
- serial_outp(info, UART_LCR, scratch2);
+ info->type = PORT_16550A;
+ info->xmit_fifo_size = 16;
break;
}
if (info->type == PORT_16450) {
info->type = PORT_UNKNOWN;
info->custom_divisor = 0;
info->close_delay = 50;
- info->closing_wait = ASYNC_CLOSING_WAIT_NONE;
- info->closing_wait2 = 3000;
info->x_char = 0;
info->event = 0;
info->count = 0;
case PORT_16550A:
printk(" is a 16550A\n");
break;
- case PORT_16650:
- printk(" is a 16650\n");
- break;
default:
printk("\n");
break;
#define TERMIOS_WAIT 2
#define TERMIOS_TERMIO 4
-void wait_until_sent(struct tty_struct * tty, int timeout)
+void tty_wait_until_sent(struct tty_struct * tty, int timeout)
{
struct wait_queue wait = { current, NULL };
tty->ldisc.flush_buffer(tty);
if (opt & TERMIOS_WAIT)
- wait_until_sent(tty, 0);
+ tty_wait_until_sent(tty, 0);
cli();
*tty->termios = tmp_termios;
retval = tty_check_change(tty);
if (retval)
return retval;
- wait_until_sent(tty, 0);
+ tty_wait_until_sent(tty, 0);
if (!tty->driver.ioctl)
return 0;
tty->driver.ioctl(tty, file, cmd, arg);
in group 224.0.0.1 and you will therefore be listening to all multicasts.
One nv conference running over that ethernet and you can give up.
+ 2/8/95 (invid@msen.com)
+
+ Removed calls to init_etherdev since they are no longer needed, and
+ cleaned up modularization just a bit. The driver still allows only
+ the default address for cards when loaded as a module, but that's
+ really less braindead than anyone using a 3c501 board. :)
*/
static char *version =
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
#endif
#include <linux/kernel.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
-extern struct device *init_etherdev(struct device *dev, int sizeof_private,
- unsigned long *mem_startp);
-
/* A zero-terminated list of I/O addresses to be probed.
The 3c501 can be at many locations, but here are the popular ones. */
static unsigned int netcard_portlist[] =
static int
el1_probe1(struct device *dev, int ioaddr)
{
+ #ifndef MODULE
+
char *mname; /* Vendor name */
unsigned char station_addr[6];
int autoirq = 0;
/* Grab the region so we can find the another board if autoIRQ fails. */
request_region(ioaddr, EL1_IO_EXTENT,"3c501");
- if (dev == NULL)
- dev = init_etherdev(0, sizeof(struct net_local), 0);
-
/* We auto-IRQ by shutting off the interrupt line and letting it float
high. */
if (dev->irq < 2) {
/* Setup the generic properties */
ether_setup(dev);
+#endif /* !MODULE */
return 0;
}
dev->start = 1;
outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */
-#ifdef MODULE
MOD_INC_USE_COUNT;
-#endif
return 0;
}
outb(AX_RESET, AX_CMD); /* Reset the chip */
irq2dev_map[dev->irq] = 0;
-#ifdef MODULE
MOD_DEC_USE_COUNT;
-#endif
return 0;
}
#ifdef CONFIG_EWRK3 /* DEC EtherWORKS 3 */
&& ewrk3_probe(dev)
#endif
-#ifdef CONFIG_DE4X5 /* DEC DE425, DE434, DE435 adapters */
+#ifdef CONFIG_DE4x5 /* DEC DE425, DE434, DE435 adapters */
&& de4x5_probe(dev)
#endif
#ifdef CONFIG_APRICOT /* Apricot I82596 */
return ENODEV;
}
+#if 0 /* Not yet */
if (check_region(DE600_IO, 3)) {
printk(", port 0x%x busy\n", DE600_IO);
return EBUSY;
}
+#endif
request_region(DE600_IO, 3, "de600");
printk(", Ethernet Address: %02X", dev->dev_addr[0]);
void
cleanup_module(void)
{
- if (MOD_IN_USE)
- printk("de600: device busy, remove delayed\n");
- else
- unregister_netdev(&de600_dev);
+ unregister_netdev(&de600_dev);
release_region(DE600_IO, 3);
}
#endif /* MODULE */
return ENODEV;
}
+#if 0 /* Not yet */
if (check_region(DE620_IO, 3)) {
printk(", port 0x%x busy\n", DE620_IO);
return EBUSY;
}
+#endif
request_region(DE620_IO, 3, "de620");
/* else, got it! */
void
cleanup_module(void)
{
- if (MOD_IN_USE)
- printk("de620: device busy, remove delayed\n");
- else
- unregister_netdev(&de620_dev);
+ unregister_netdev(&de620_dev);
release_region(DE620_IO, 3);
}
#endif /* MODULE */
* CAN YOU PLEASE REPORT ME YOUR PERFORMANCE EXPERIENCES !!.
*
* If you find a bug, please report me:
- * The kernelpanic output and any kmsg from the ni52 driver
+ * The kernel panic output and any kmsg from the ni52 driver
* the ni5210-driver-version and the linux-kernel version
* how many shared memory (memsize) on the netcard,
* bootprom: yes/no, base_addr, mem_start
*
* 19.Sep.94: Added Multicast support (not tested yet) (MH)
*
- * 18.Sep.94: Workarround for 'EL-Bug'. Removed flexible RBD-handling.
+ * 18.Sep.94: Workaround for 'EL-Bug'. Removed flexible RBD-handling.
* Now, every RFD has exact one RBD. (MH)
*
- * 14.Sep.94: added promiscous mode, a few cleanups (MH)
+ * 14.Sep.94: added promiscuous mode, a few cleanups (MH)
*
* 19.Aug.94: changed request_irq() parameter (MH)
*
* IMPORTANT NOTE: if you configure only one NUM_XMIT_BUFFS, the driver works
* --------------- in a different (more stable?) mode. Only in this mode it's
- * possbile to configure the driver with 'NO_NOPCOMMANDS'
+ * possible to configure the driver with 'NO_NOPCOMMANDS'
sizeof(scp)=12; sizeof(scb)=16; sizeof(iscp)=8;
sizeof(scp)+sizeof(iscp)+sizeof(scb) = 36 = INIT
ni_attn586();
DELAY(2); /* wait a while... */
- if(p->iscp->busy) /* i82586 clears 'busy' after succesful init */
+ if(p->iscp->busy) /* i82586 clears 'busy' after successful init */
return 0;
}
return 1;
if(len < num_addrs)
{
num_addrs = len;
- printk("%s: Sorry, can only apply %d MC-Addresse(s).\n",dev->name,num_addrs);
+ printk("%s: Sorry, can only apply %d MC-Address(es).\n",dev->name,num_addrs);
}
mc_cmd = (struct mcsetup_cmd_struct *) ptr;
mc_cmd->cmd_status = 0;
p->stats.rx_errors++;
WAIT_4_SCB_CMD(); /* wait for the last cmd */
- p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no ressource'-state .. abort it now. */
+ p->scb->cmd = RUC_ABORT; /* usually the RU is in the 'no resource'-state .. abort it now. */
ni_attn586();
WAIT_4_SCB_CMD(); /* wait for accept cmd. */
{
if(!dev->start && !num_addrs)
{
- printk("%s: Can't apply promiscous/multicastmode to a not running interface.\n",dev->name);
+ printk("%s: Can't apply promiscuous/multicastmode to a not running interface.\n",dev->name);
return;
}
-/* $Id: plip.c,v 1.7 1994/12/16 06:20:02 gniibe Exp $ */
-/* plip.c: A parallel port "network" driver for linux. */
+/* $Id: plip.c,v 1.10 1995/02/08 05:47:12 gniibe Exp $ */
+/* PLIP: A parallel port "network" driver for Linux. */
/* This driver is for parallel port with 5-bit cable (LapLink (R) cable). */
/*
* Authors: Donald Becker, <becker@super.org>
* Peter Bauer, <100136.3530@compuserve.com>
* Niibe Yutaka, <gniibe@mri.co.jp>
*
- * This is the all improved state based PLIP that Niibe Yutaka has contributed.
- *
- * Modularization by Alan Cox. I also added the plipconfig program to tune the timeouts
- * and ifmap support for funny serial port settings or setting odd values using the
- * modular plip. I also took the panic() calls out. I don't like panic - especially when
- * it can be avoided.
+ * Modularization and ifreq/ifmap support by Alan Cox.
+ * Rewritten by Niibe Yutaka.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
/*
* Original version and the name 'PLIP' from Donald Becker <becker@super.org>
* inspired by Russ Nelson's parallel port packet driver.
+ *
+ * NOTE:
+ * Tanabe Hiroyasu had changed the protocol, and it was in Linux v1.0.
+ * Because of the necessity to communicate to DOS machines with the
+ * Crynwr packet driver, Peter Bauer changed the protocol again
+ * back to original protocol.
+ *
+ * This version follows original PLIP protocol.
+ * So, this PLIP can't communicate the PLIP of Linux v1.0.
*/
-static char *version =
- "NET3 "
-#ifdef MODULE
- "MODULAR "
-#endif
- "PLIP $Revision: 1.7 $ gniibe@mri.co.jp\n";
+static char *version = "NET3 PLIP version 2.0 gniibe@mri.co.jp\n";
/*
Sources:
"parallel.asm" parallel port packet driver.
The "Crynwr" parallel port standard specifies the following protocol:
- send header nibble '8'
- count-low octet
- count-high octet
- ... data octets
- checksum octet
+ Trigger by sending '0x08' (this cause interrupt on other end)
+ count-low octet
+ count-high octet
+ ... data octets
+ checksum octet
Each octet is sent as <wait for rx. '0x1?'> <send 0x10+(octet&0x0F)>
<wait for rx. '0x0?'> <send 0x00+((octet>>4)&0x0F)>
-The cable used is a de facto standard parallel null cable -- sold as
-a "LapLink" cable by various places. You'll need a 10-conductor cable to
-make one yourself. The wiring is:
+ The packet is encapsulated as if it were ethernet.
+
+ The cable used is a de facto standard parallel null cable -- sold as
+ a "LapLink" cable by various places. You'll need a 12-conductor cable to
+ make one yourself. The wiring is:
SLCTIN 17 - 17
GROUND 25 - 25
D0->ERROR 2 - 15 15 - 2
#ifdef MODULE
#include <linux/module.h>
#include <linux/version.h>
+#else
+#define MOD_INC_USE_COUNT
+#define MOD_DEC_USE_COUNT
#endif
#include <linux/kernel.h>
#include <asm/bitops.h>
#include <asm/irq.h>
-/* use 0 for production, 1 for verification, >2 for debug */
+/* Use 0 for production, 1 for verification, >2 for debug */
#ifndef NET_DEBUG
-#define NET_DEBUG 3
+#define NET_DEBUG 1
#endif
static unsigned int net_debug = NET_DEBUG;
#define PLIP_TRIGGER_WAIT 500
/* Nibble time out = PLIP_NIBBLE_WAIT * PLIP_DELAY_UNIT usec */
-#define PLIP_NIBBLE_WAIT 5000
+#define PLIP_NIBBLE_WAIT 3000
+#define PAR_INTR_ON (LP_PINITP|LP_PSELECP|LP_PINTEN)
+#define PAR_INTR_OFF (LP_PINITP|LP_PSELECP)
#define PAR_DATA(dev) ((dev)->base_addr+0)
#define PAR_STATUS(dev) ((dev)->base_addr+1)
#define PAR_CONTROL(dev) ((dev)->base_addr+2)
-/* Index to functions, as function prototypes. */
+/* Bottom halfs */
+static void plip_kick_bh(struct device *dev);
+static void plip_bh(struct device *dev);
+
+/* Interrupt handler */
+static void plip_interrupt(int irq, struct pt_regs *regs);
+
+/* Functions for DEV methods */
+static int plip_rebuild_header(void *buff, struct device *dev,
+ unsigned long raddr, struct sk_buff *skb);
static int plip_tx_packet(struct sk_buff *skb, struct device *dev);
static int plip_open(struct device *dev);
static int plip_close(struct device *dev);
static struct enet_statistics *plip_get_stats(struct device *dev);
-static int plip_rebuild_header(void *buff, struct device *dev,
- unsigned long raddr, struct sk_buff *skb);
-static void plip_kick_bh(struct device *dev);
-static void plip_bh(struct device *dev);
+static int plip_config(struct device *dev, struct ifmap *map);
+static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
\f
enum plip_connection_state {
- PLIP_CN_NONE=0,
- PLIP_CN_RECEIVE,
- PLIP_CN_SEND,
- PLIP_CN_CLOSING,
- PLIP_CN_ERROR
+ PLIP_CN_NONE=0,
+ PLIP_CN_RECEIVE,
+ PLIP_CN_SEND,
+ PLIP_CN_CLOSING,
+ PLIP_CN_ERROR
};
enum plip_packet_state {
- PLIP_PK_DONE=0,
- PLIP_PK_TRIGGER,
- PLIP_PK_LENGTH_LSB,
- PLIP_PK_LENGTH_MSB,
- PLIP_PK_DATA,
- PLIP_PK_CHECKSUM
+ PLIP_PK_DONE=0,
+ PLIP_PK_TRIGGER,
+ PLIP_PK_LENGTH_LSB,
+ PLIP_PK_LENGTH_MSB,
+ PLIP_PK_DATA,
+ PLIP_PK_CHECKSUM
};
enum plip_nibble_state {
- PLIP_NB_BEGIN,
- PLIP_NB_1,
- PLIP_NB_2,
+ PLIP_NB_BEGIN,
+ PLIP_NB_1,
+ PLIP_NB_2,
};
-#define PLIP_STATE_STRING(x) \
- (((x) == PLIP_PK_DONE)?"0":\
- ((x) == PLIP_PK_TRIGGER)?"t":\
- ((x) == PLIP_PK_LENGTH_LSB)?"l":\
- ((x) == PLIP_PK_LENGTH_MSB)?"m":\
- ((x) == PLIP_PK_DATA)?"d":\
- ((x) == PLIP_PK_CHECKSUM)?"s":"B")
-
struct plip_local {
- enum plip_packet_state state;
- enum plip_nibble_state nibble;
- unsigned short length;
- unsigned short byte;
- unsigned char checksum;
- unsigned char data;
- struct sk_buff *skb;
+ enum plip_packet_state state;
+ enum plip_nibble_state nibble;
+ unsigned short length;
+ unsigned short byte;
+ unsigned char checksum;
+ unsigned char data;
+ struct sk_buff *skb;
};
struct net_local {
- struct enet_statistics e;
- struct tq_struct immediate;
- struct tq_struct deferred;
- struct plip_local snd_data;
- struct plip_local rcv_data;
- unsigned long trigger_us;
- unsigned long nibble_us;
- unsigned long unit_us;
- enum plip_connection_state connection;
- unsigned short timeout_count;
+ struct enet_statistics enet_stats;
+ struct tq_struct immediate;
+ struct tq_struct deferred;
+ struct plip_local snd_data;
+ struct plip_local rcv_data;
+ unsigned long trigger;
+ unsigned long nibble;
+ unsigned long unit;
+ enum plip_connection_state connection;
+ unsigned short timeout_count;
+ char is_deferred;
};
-
-/* Routines used internally. */
-static void plip_device_clear(struct device *dev);
-static void plip_interrupt(int irq, struct pt_regs *regs);
-
-static int plip_error(struct device *dev);
-static int plip_receive_packet(struct device *dev);
-static int plip_send_packet(struct device *dev);
-static int plip_ioctl(struct device *dev, struct ifreq *ifr, int cmd);
-static int plip_config(struct device *dev, struct ifmap *map);
\f
+/* Entry point of PLIP driver.
+ Probe the hardware, and register/initialize the driver. */
int
plip_init(struct device *dev)
{
- struct net_local *nl;
+ struct net_local *nl;
- /* Check that there is something at base_addr. */
- outb(LP_PINITP, PAR_CONTROL(dev));
- outb(0x00, PAR_DATA(dev));
- if (inb(PAR_DATA(dev)) != 0x00)
- return -ENODEV;
+ /* Check region before the probe */
+ if (check_region(PAR_DATA(dev), 3) < 0)
+ return -ENODEV;
- /* Alpha testers must have the version number to report bugs. */
- if (net_debug)
- printk(version);
+ /* Check that there is something at base_addr. */
+ outb(0, PAR_DATA(dev));
+ udelay(1000);
+ if (inb(PAR_DATA(dev)) != 0)
+ return -ENODEV;
- if (dev->irq) {
- printk("%s: configured for parallel port at %#3x, IRQ %d.\n",
- dev->name, dev->base_addr, dev->irq);
- } else {
- printk("%s: configured for parallel port at %#3x",
- dev->name, dev->base_addr);
+ printk(version);
+ printk("%s: Parallel port at %#3lx, ", dev->name, dev->base_addr);
+ if (dev->irq) {
+ printk("using assigned IRQ %d.\n", dev->irq);
+ } else {
+ int irq = 0;
#ifdef MODULE
- /* autoirq doesn't work :(, but we can set it by ifconfig */
+ /* dev->irq==0 means autoprobe, but we don't try to do so
+ with module. We can change it by ifconfig */
#else
- autoirq_setup(0);
- outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
- outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
- outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
- dev->irq = autoirq_report(1);
+ unsigned int irqs = probe_irq_on();
+
+ outb(0x00, PAR_CONTROL(dev));
+ udelay(1000);
+ outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+ outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+ udelay(1000);
+ irq = probe_irq_off(irqs);
#endif
- if (dev->irq)
- printk(", probed IRQ %d.\n", dev->irq);
- else {
- printk(", failed to detect IRQ line.\n");
- return -ENODEV;
+ if (irq > 0) {
+ dev->irq = irq;
+ printk("using probed IRQ %d.\n", dev->irq);
+ } else
+ printk("failed to detect IRQ(%d) --"
+ " Please set IRQ by ifconfig.\n", irq);
}
- }
-
- request_region(PAR_DATA(dev), 3,"plip");
-
- /* Fill in the generic fields of the device structure. */
- ether_setup(dev);
-
- /* And, override parts of it */
- dev->rebuild_header = plip_rebuild_header;
- dev->hard_start_xmit = plip_tx_packet;
- dev->open = plip_open;
- dev->stop = plip_close;
- dev->get_stats = plip_get_stats;
- dev->set_config = plip_config;
- dev->do_ioctl = plip_ioctl;
- dev->flags = IFF_POINTOPOINT;
-
- /* Set private structure */
- dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(struct net_local));
- nl = (struct net_local *) dev->priv;
-
- /* initialize constants */
- nl->trigger_us = PLIP_TRIGGER_WAIT;
- nl->nibble_us = PLIP_NIBBLE_WAIT;
- nl->unit_us = PLIP_DELAY_UNIT;
-
- /* initialize task queue structures */
- nl->immediate.next = &tq_last;
- nl->immediate.sync = 0;
- nl->immediate.routine = (void *)(void *)plip_bh;
- nl->immediate.data = dev;
-
- nl->deferred.next = &tq_last;
- nl->deferred.sync = 0;
- nl->deferred.routine = (void *)(void *)plip_kick_bh;
- nl->deferred.data = dev;
-
- return 0;
+
+ request_region(PAR_DATA(dev), 3, dev->name);
+
+ /* Fill in the generic fields of the device structure. */
+ ether_setup(dev);
+
+ /* Then, override parts of it */
+ dev->rebuild_header = plip_rebuild_header;
+ dev->hard_start_xmit = plip_tx_packet;
+ dev->open = plip_open;
+ dev->stop = plip_close;
+ dev->get_stats = plip_get_stats;
+ dev->set_config = plip_config;
+ dev->do_ioctl = plip_ioctl;
+ dev->flags = IFF_POINTOPOINT;
+
+ /* Set the private structure */
+ dev->priv = kmalloc(sizeof (struct net_local), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct net_local));
+ nl = (struct net_local *) dev->priv;
+
+ /* Initialize constants */
+ nl->trigger = PLIP_TRIGGER_WAIT;
+ nl->nibble = PLIP_NIBBLE_WAIT;
+ nl->unit = PLIP_DELAY_UNIT;
+
+ /* Initialize task queue structures */
+ nl->immediate.next = &tq_last;
+ nl->immediate.sync = 0;
+ nl->immediate.routine = (void *)(void *)plip_bh;
+ nl->immediate.data = dev;
+
+ nl->deferred.next = &tq_last;
+ nl->deferred.sync = 0;
+ nl->deferred.routine = (void *)(void *)plip_kick_bh;
+ nl->deferred.data = dev;
+
+ return 0;
}
\f
+/* Bottom half handler for the delayed request.
+ This routine is kicked by do_timer().
+ Request `plip_bh' to be invoked. */
static void
plip_kick_bh(struct device *dev)
{
- struct net_local *nl = (struct net_local *)dev->priv;
+ struct net_local *nl = (struct net_local *)dev->priv;
- if (nl->connection == PLIP_CN_NONE)
- return;
- queue_task(&nl->immediate, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- return;
+ if (nl->is_deferred) {
+ queue_task(&nl->immediate, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
}
+/* Forward declarations of internal routines */
+static int plip_none(struct device *, struct net_local *,
+ struct plip_local *, struct plip_local *);
+static int plip_receive_packet(struct device *, struct net_local *,
+ struct plip_local *, struct plip_local *);
+static int plip_send_packet(struct device *, struct net_local *,
+ struct plip_local *, struct plip_local *);
+static int plip_connection_close(struct device *, struct net_local *,
+ struct plip_local *, struct plip_local *);
+static int plip_error(struct device *, struct net_local *,
+ struct plip_local *, struct plip_local *);
+static int plip_bh_timeout_error(struct device *dev, struct net_local *nl,
+ struct plip_local *snd,
+ struct plip_local *rcv,
+ int error);
+
+#define OK 0
+#define TIMEOUT 1
+#define ERROR 2
+
+typedef int (*plip_func)(struct device *dev, struct net_local *nl,
+ struct plip_local *snd, struct plip_local *rcv);
+
+static plip_func connection_state_table[] =
+{
+ plip_none,
+ plip_receive_packet,
+ plip_send_packet,
+ plip_connection_close,
+ plip_error
+};
+
+/* Bottom half handler of PLIP. */
static void
plip_bh(struct device *dev)
{
- struct net_local *nl = (struct net_local *)dev->priv;
- struct enet_statistics *stats = (struct enet_statistics *) dev->priv;
- struct plip_local *rcv = &nl->rcv_data;
- struct plip_local *snd = &nl->snd_data;
- int result, timeout=0;
- unsigned char *s;
- unsigned char c0;
- struct sk_buff *skb;
-
- while (!timeout) {
- cli();
- switch (nl->connection) {
- case PLIP_CN_NONE:
- sti();
- return;
-
- case PLIP_CN_RECEIVE:
- sti();
- disable_irq(dev->irq);
- outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
- outb(0x01, PAR_DATA(dev)); /* send ACK */
- dev->interrupt = 0;
- result = plip_receive_packet(dev);
- if (result == 0) { /* success */
- outb (0x00, PAR_DATA(dev));
- skb = rcv->skb;
- rcv->skb = NULL;
- stats->rx_packets++;
- netif_rx(skb);
- if (snd->state != PLIP_PK_DONE) {
- nl->connection = PLIP_CN_SEND;
- outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- } else {
- nl->connection = PLIP_CN_NONE;
- outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- return;
- }
- } else if (result == -1) { /* failure */
- outb(0x00, PAR_DATA(dev));
- if (rcv->skb)
- dev_kfree_skb(rcv->skb, FREE_WRITE);
- rcv->state = PLIP_PK_DONE;
- rcv->skb = NULL;
- if (snd->skb)
- dev_kfree_skb(snd->skb, FREE_WRITE);
- snd->state = PLIP_PK_DONE;
- snd->skb = NULL;
- dev->tbusy = 1;
- nl->connection = PLIP_CN_ERROR;
- } else
- timeout = 1;
- break;
-
- case PLIP_CN_SEND:
- sti();
- result = plip_send_packet(dev);
- if (result == -1) /* interrupted */
- break;
- if (result == 0) { /* success */
- outb (0x00, PAR_DATA(dev));
- snd->state = PLIP_PK_DONE;
- snd->skb = NULL;
- nl->connection = PLIP_CN_CLOSING;
- queue_task(&nl->deferred, &tq_timer);
- outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- return;
- } else
- timeout = 1;
- break;
-
- case PLIP_CN_CLOSING:
- sti();
- nl->connection = PLIP_CN_NONE;
- mark_bh(NET_BH);
- dev->tbusy = 0;
- return;
-
- case PLIP_CN_ERROR:
- sti();
- result = plip_error(dev);
- if (result == 0) {
- nl->connection = PLIP_CN_NONE;
- dev->tbusy = 0;
- outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
- enable_irq(dev->irq);
- return;
- } else {
+ struct net_local *nl = (struct net_local *)dev->priv;
+ struct plip_local *snd = &nl->snd_data;
+ struct plip_local *rcv = &nl->rcv_data;
+ plip_func f;
+ int r;
+
+ nl->is_deferred = 0;
+ f = connection_state_table[nl->connection];
+ if ((r = (*f)(dev, nl, snd, rcv)) != OK
+ && (r = plip_bh_timeout_error(dev, nl, snd, rcv, r)) != OK) {
+ nl->is_deferred = 1;
queue_task(&nl->deferred, &tq_timer);
- return;
- }
- break;
}
- }
+}
- /* timeout */
- if (++nl->timeout_count > 3) { /* cable problem? */
- c0 = inb(PAR_STATUS(dev));
+static int
+plip_bh_timeout_error(struct device *dev, struct net_local *nl,
+ struct plip_local *snd, struct plip_local *rcv,
+ int error)
+{
+ unsigned char c0;
+ cli();
if (nl->connection == PLIP_CN_SEND) {
- stats->tx_errors++;
- stats->tx_aborted_errors++;
- s = PLIP_STATE_STRING(snd->state);
- if (net_debug > 1)
- printk("%s: transmit timeout(%s,%02x)... reset interface.\n",
- dev->name, s, (unsigned int)c0);
- if (snd->skb)
- dev_kfree_skb(snd->skb, FREE_WRITE);
+
+ if (error != ERROR) { /* Timeout */
+ nl->timeout_count++;
+ if ((snd->state == PLIP_PK_TRIGGER
+ && nl->timeout_count <= 10)
+ || nl->timeout_count <= 3) {
+ sti();
+ /* Try again later */
+ return TIMEOUT;
+ }
+ c0 = inb(PAR_STATUS(dev));
+ printk("%s: transmit timeout(%d,%02x)\n",
+ dev->name, snd->state, c0);
+ }
+ nl->enet_stats.tx_errors++;
+ nl->enet_stats.tx_aborted_errors++;
} else if (nl->connection == PLIP_CN_RECEIVE) {
- stats->rx_dropped++;
- s = PLIP_STATE_STRING(rcv->state);
- if (net_debug > 1)
- printk("%s: receive timeout(%s,%02x)... reset interface.\n",
- dev->name, s, (unsigned int)c0);
- if (rcv->skb)
- dev_kfree_skb(rcv->skb, FREE_WRITE);
+ if (rcv->state == PLIP_PK_TRIGGER) {
+ /* Transmission was interrupted. */
+ sti();
+ return OK;
+ }
+ if (error != ERROR) { /* Timeout */
+ if (++nl->timeout_count <= 3) {
+ sti();
+ /* Try again later */
+ return TIMEOUT;
+ }
+ c0 = inb(PAR_STATUS(dev));
+ printk("%s: receive timeout(%d,%02x)\n",
+ dev->name, rcv->state, c0);
+ }
+ nl->enet_stats.rx_dropped++;
+ }
+ rcv->state = PLIP_PK_DONE;
+ if (rcv->skb) {
+ rcv->skb->free = 1;
+ kfree_skb(rcv->skb, FREE_READ);
+ rcv->skb = NULL;
+ }
+ snd->state = PLIP_PK_DONE;
+ if (snd->skb) {
+ dev_kfree_skb(snd->skb, FREE_WRITE);
+ snd->skb = NULL;
}
disable_irq(dev->irq);
- outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
+ outb(PAR_INTR_OFF, PAR_CONTROL(dev));
dev->tbusy = 1;
nl->connection = PLIP_CN_ERROR;
outb(0x00, PAR_DATA(dev));
- }
+ sti();
- queue_task(&nl->deferred, &tq_timer);
- return;
+ return TIMEOUT;
}
\f
static int
-plip_tx_packet(struct sk_buff *skb, struct device *dev)
+plip_none(struct device *dev, struct net_local *nl,
+ struct plip_local *snd, struct plip_local *rcv)
{
- struct net_local *nl = (struct net_local *)dev->priv;
- struct plip_local *snd = &nl->snd_data;
-
- if (dev->tbusy)
- return 1;
-
- /* If some higher layer thinks we've missed an tx-done interrupt
- we are passed NULL. Caution: dev_tint() handles the cli()/sti()
- itself. */
- if (skb == NULL) {
- dev_tint(dev);
- return 0;
- }
+ return OK;
+}
- if (set_bit(0, (void*)&dev->tbusy) != 0) {
- printk("%s: Transmitter access conflict.\n", dev->name);
- return 1;
- }
+/* PLIP_RECEIVE --- receive a byte(two nibbles)
+ Returns OK on success, TIMEOUT on timeout */
+inline static int
+plip_receive(unsigned short nibble_timeout, unsigned short unit,
+ unsigned short status_addr, unsigned short data_addr,
+ enum plip_nibble_state *ns_p, unsigned char *data_p)
+{
+ unsigned char c0, c1;
+ unsigned int cx;
+
+ switch (*ns_p) {
+ case PLIP_NB_BEGIN:
+ cx = nibble_timeout;
+ while (1) {
+ c0 = inb(status_addr);
+ udelay(unit);
+ if ((c0 & 0x80) == 0) {
+ c1 = inb(status_addr);
+ if (c0 == c1)
+ break;
+ }
+ if (--cx == 0)
+ return TIMEOUT;
+ }
+ *data_p = (c0 >> 3) & 0x0f;
+ outb(0x10, data_addr); /* send ACK */
+ *ns_p = PLIP_NB_1;
+
+ case PLIP_NB_1:
+ cx = nibble_timeout;
+ while (1) {
+ c0 = inb(status_addr);
+ udelay(unit);
+ if (c0 & 0x80) {
+ c1 = inb(status_addr);
+ if (c0 == c1)
+ break;
+ }
+ if (--cx == 0)
+ return TIMEOUT;
+ }
+ *data_p |= (c0 << 1) & 0xf0;
+ outb(0x00, data_addr); /* send ACK */
+ *ns_p = PLIP_NB_BEGIN;
+ return OK;
- if (skb->len > dev->mtu) {
- printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
- dev->tbusy = 0;
- return 0;
- }
+ case PLIP_NB_2:
+ }
+}
- snd->state = PLIP_PK_TRIGGER;
- dev->trans_start = jiffies;
+/* PLIP_RECEIVE_PACKET --- receive a packet */
+static int
+plip_receive_packet(struct device *dev, struct net_local *nl,
+ struct plip_local *snd, struct plip_local *rcv)
+{
+ unsigned short data_addr = PAR_DATA(dev),
+ status_addr = PAR_STATUS(dev);
+ unsigned short nibble_timeout = nl->nibble, unit = nl->unit;
+ unsigned char *lbuf;
- snd->skb = skb;
- snd->length = skb->len;
+ switch (rcv->state) {
+ case PLIP_PK_TRIGGER:
+ disable_irq(dev->irq);
+ outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+ dev->interrupt = 0;
+ outb(0x01, PAR_DATA(dev)); /* send ACK */
+ if (net_debug > 2)
+ printk("%s: receive start\n", dev->name);
+ rcv->state = PLIP_PK_LENGTH_LSB;
+ rcv->nibble = PLIP_NB_BEGIN;
+
+ case PLIP_PK_LENGTH_LSB:
+ if (snd->state != PLIP_PK_DONE) {
+ if (plip_receive(nl->trigger, unit,
+ status_addr, data_addr, &rcv->nibble,
+ (unsigned char *)&rcv->length)) {
+ /* collision, here dev->tbusy == 1 */
+ rcv->state = PLIP_PK_DONE;
+ nl->is_deferred = 1;
+ nl->connection = PLIP_CN_SEND;
+ queue_task(&nl->deferred, &tq_timer);
+ outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_irq(dev->irq);
+ return OK;
+ }
+ } else {
+ if (plip_receive(nibble_timeout, unit,
+ status_addr, data_addr, &rcv->nibble,
+ (unsigned char *)&rcv->length))
+ return TIMEOUT;
+ }
+ rcv->state = PLIP_PK_LENGTH_MSB;
+
+ case PLIP_PK_LENGTH_MSB:
+ if (plip_receive(nibble_timeout, unit,
+ status_addr, data_addr, &rcv->nibble,
+ (unsigned char *)&rcv->length+1))
+ return TIMEOUT;
+ if (rcv->length > dev->mtu || rcv->length < 8) {
+ printk("%s: bogus packet size %d.\n", dev->name, rcv->length);
+ return ERROR;
+ }
+ /* Malloc up new buffer. */
+ rcv->skb = alloc_skb(rcv->length, GFP_ATOMIC);
+ if (rcv->skb == NULL) {
+ printk("%s: Memory squeeze.\n", dev->name);
+ return ERROR;
+ }
+ rcv->skb->len = rcv->length;
+ rcv->skb->dev = dev;
+ rcv->state = PLIP_PK_DATA;
+ rcv->byte = 0;
+ rcv->checksum = 0;
+
+ case PLIP_PK_DATA:
+ lbuf = rcv->skb->data;
+ do {
+ if (plip_receive(nibble_timeout, unit,
+ status_addr, data_addr,
+ &rcv->nibble, &lbuf[rcv->byte]))
+ return TIMEOUT;
+ rcv->checksum += lbuf[rcv->byte];
+ } while (++rcv->byte < rcv->length);
+ rcv->state = PLIP_PK_CHECKSUM;
+
+ case PLIP_PK_CHECKSUM:
+ if (plip_receive(nibble_timeout, unit, status_addr,
+ data_addr, &rcv->nibble, &rcv->data))
+ return TIMEOUT;
+ if (rcv->data != rcv->checksum) {
+ nl->enet_stats.rx_crc_errors++;
+ if (net_debug)
+ printk("%s: checksum error\n", dev->name);
+ return ERROR;
+ }
+ rcv->state = PLIP_PK_DONE;
- cli();
- if (nl->connection == PLIP_CN_NONE) {
- nl->connection = PLIP_CN_SEND;
- nl->timeout_count = 0;
- }
- sti();
- queue_task(&nl->immediate, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
+ case PLIP_PK_DONE:
+ /* Inform the upper layer for the arrival of a packet. */
+ netif_rx(rcv->skb);
+ nl->enet_stats.rx_packets++;
+ rcv->skb = NULL;
+ if (net_debug > 2)
+ printk("%s: receive end\n", dev->name);
- return 0;
+ /* Close the connection. */
+ outb (0x00, PAR_DATA(dev));
+ cli();
+ if (snd->state != PLIP_PK_DONE) {
+ nl->connection = PLIP_CN_SEND;
+ sti();
+ queue_task(&nl->immediate, &tq_immediate);
+ outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_irq(dev->irq);
+ return OK;
+ } else {
+ nl->connection = PLIP_CN_NONE;
+ sti();
+ outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_irq(dev->irq);
+ return OK;
+ }
+ }
+ return OK;
}
-/* Open/initialize the board. This is called (in the current kernel)
- sometime after booting when the 'ifconfig' program is run.
-
- This routine gets exclusive access to the parallel port by allocating
- its IRQ line.
- */
-static int
-plip_open(struct device *dev)
+/* PLIP_SEND --- send a byte (two nibbles)
+ Returns OK on success, TIMEOUT when timeout */
+inline static int
+plip_send(unsigned short nibble_timeout, unsigned short unit,
+ unsigned short status_addr, unsigned short data_addr,
+ enum plip_nibble_state *ns_p, unsigned char data)
{
- int i;
-
- cli();
- if (request_irq(dev->irq , plip_interrupt, 0, "plip") != 0) {
- sti();
- printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
- return -EAGAIN;
- }
- irq2dev_map[dev->irq] = dev;
- sti();
- /* enable rx interrupt. */
- outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
- plip_device_clear(dev);
-
- /* Fill in the MAC-level header. */
- for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
- dev->dev_addr[i] = 0xfc;
- memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(unsigned long));
-
- dev->start = 1;
-#ifdef MODULE
- MOD_INC_USE_COUNT;
-#endif
- return 0;
+ unsigned char c0;
+ unsigned int cx;
+
+ switch (*ns_p) {
+ case PLIP_NB_BEGIN:
+ outb((data & 0x0f), data_addr);
+ *ns_p = PLIP_NB_1;
+
+ case PLIP_NB_1:
+ outb(0x10 | (data & 0x0f), data_addr);
+ cx = nibble_timeout;
+ while (1) {
+ c0 = inb(status_addr);
+ if ((c0 & 0x80) == 0)
+ break;
+ if (--cx == 0)
+ return TIMEOUT;
+ udelay(unit);
+ }
+ outb(0x10 | (data >> 4), data_addr);
+ *ns_p = PLIP_NB_2;
+
+ case PLIP_NB_2:
+ outb((data >> 4), data_addr);
+ cx = nibble_timeout;
+ while (1) {
+ c0 = inb(status_addr);
+ if (c0 & 0x80)
+ break;
+ if (--cx == 0)
+ return TIMEOUT;
+ udelay(unit);
+ }
+ *ns_p = PLIP_NB_BEGIN;
+ return OK;
+ }
}
-/* The inverse routine to plip_open (). */
+/* PLIP_SEND_PACKET --- send a packet */
static int
-plip_close(struct device *dev)
+plip_send_packet(struct device *dev, struct net_local *nl,
+ struct plip_local *snd, struct plip_local *rcv)
{
- dev->tbusy = 1;
- dev->start = 0;
- cli();
- free_irq(dev->irq);
- irq2dev_map[dev->irq] = NULL;
- sti();
- outb(0x00, PAR_DATA(dev));
- /* release the interrupt. */
- outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
-#ifdef MODULE
- MOD_DEC_USE_COUNT;
-#endif
- return 0;
+ unsigned short data_addr = PAR_DATA(dev),
+ status_addr = PAR_STATUS(dev);
+ unsigned short nibble_timeout = nl->nibble, unit = nl->unit;
+ unsigned char *lbuf;
+ unsigned char c0;
+ unsigned int cx;
+
+ if (snd->skb == NULL || (lbuf = snd->skb->data) == NULL) {
+ printk("%s: send skb lost\n", dev->name);
+ snd->state = PLIP_PK_DONE;
+ snd->skb = NULL;
+ return ERROR;
+ }
+
+ switch (snd->state) {
+ case PLIP_PK_TRIGGER:
+ /* Trigger remote rx interrupt. */
+ outb(0x08, PAR_DATA(dev));
+ cx = nl->trigger;
+ while (1) {
+ udelay(nl->unit);
+ cli();
+ if (nl->connection == PLIP_CN_RECEIVE) {
+ sti();
+ /* interrupted */
+ nl->enet_stats.collisions++;
+ if (net_debug > 1)
+ printk("%s: collision.\n", dev->name);
+ return OK;
+ }
+ c0 = inb(PAR_STATUS(dev));
+ if (c0 & 0x08) {
+ disable_irq(dev->irq);
+ outb(PAR_INTR_OFF, PAR_CONTROL(dev));
+ if (net_debug > 2)
+ printk("%s: send start\n", dev->name);
+ snd->state = PLIP_PK_LENGTH_LSB;
+ snd->nibble = PLIP_NB_BEGIN;
+ nl->timeout_count = 0;
+ sti();
+ break;
+ }
+ sti();
+ if (--cx == 0) {
+ outb(0x00, PAR_DATA(dev));
+ return TIMEOUT;
+ }
+ }
+
+ case PLIP_PK_LENGTH_LSB:
+ if (plip_send(nibble_timeout, unit, status_addr, data_addr,
+ &snd->nibble, snd->length & 0xff))
+ return TIMEOUT;
+ snd->state = PLIP_PK_LENGTH_MSB;
+
+ case PLIP_PK_LENGTH_MSB:
+ if (plip_send(nibble_timeout, unit, status_addr, data_addr,
+ &snd->nibble, snd->length >> 8))
+ return TIMEOUT;
+ snd->state = PLIP_PK_DATA;
+ snd->byte = 0;
+ snd->checksum = 0;
+
+ case PLIP_PK_DATA:
+ do {
+ if (plip_send(nibble_timeout, unit,
+ status_addr, data_addr,
+ &snd->nibble, lbuf[snd->byte]))
+ return TIMEOUT;
+ snd->checksum += lbuf[snd->byte];
+ } while (++snd->byte < snd->length);
+ snd->state = PLIP_PK_CHECKSUM;
+
+ case PLIP_PK_CHECKSUM:
+ if (plip_send(nibble_timeout, unit, status_addr, data_addr,
+ &snd->nibble, snd->checksum))
+ return TIMEOUT;
+
+ dev_kfree_skb(snd->skb, FREE_WRITE);
+ nl->enet_stats.tx_packets++;
+ snd->state = PLIP_PK_DONE;
+
+ case PLIP_PK_DONE:
+ /* Close the connection */
+ outb (0x00, PAR_DATA(dev));
+ snd->skb = NULL;
+ if (net_debug > 2)
+ printk("%s: send end\n", dev->name);
+ nl->connection = PLIP_CN_CLOSING;
+ nl->is_deferred = 1;
+ queue_task(&nl->deferred, &tq_timer);
+ outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_irq(dev->irq);
+ return OK;
+ }
+ return OK;
}
-static struct enet_statistics *
-plip_get_stats(struct device *dev)
+static int
+plip_connection_close(struct device *dev, struct net_local *nl,
+ struct plip_local *snd, struct plip_local *rcv)
{
- struct enet_statistics *localstats = (struct enet_statistics*)dev->priv;
- return localstats;
+ cli();
+ if (nl->connection == PLIP_CN_CLOSING) {
+ nl->connection = PLIP_CN_NONE;
+ dev->tbusy = 0;
+ mark_bh(NET_BH);
+ }
+ sti();
+ return OK;
}
-/* We don't need to send arp, for plip is point-to-point. */
+/* PLIP_ERROR --- wait till other end settled */
static int
-plip_rebuild_header(void *buff, struct device *dev, unsigned long dst,
- struct sk_buff *skb)
+plip_error(struct device *dev, struct net_local *nl,
+ struct plip_local *snd, struct plip_local *rcv)
{
- struct ethhdr *eth = (struct ethhdr *)buff;
- int i;
+ unsigned char status;
- if (eth->h_proto != htons(ETH_P_IP)) {
- printk("plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
- return 0;
- }
+ status = inb(PAR_STATUS(dev));
+ if ((status & 0xf8) == 0x80) {
+ if (net_debug > 2)
+ printk("%s: reset interface.\n", dev->name);
+ nl->connection = PLIP_CN_NONE;
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ outb(PAR_INTR_ON, PAR_CONTROL(dev));
+ enable_irq(dev->irq);
+ mark_bh(NET_BH);
+ } else {
+ nl->is_deferred = 1;
+ queue_task(&nl->deferred, &tq_timer);
+ }
- for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
- eth->h_dest[i] = 0xfc;
- memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long));
- return 0;
+ return OK;
}
\f
+/* Handle the parallel port interrupts. */
static void
-plip_device_clear(struct device *dev)
+plip_interrupt(int irq, struct pt_regs * regs)
{
- struct net_local *nl = (struct net_local *)dev->priv;
-
- outb (0x00, PAR_DATA(dev));
- nl->rcv_data.state = PLIP_PK_DONE;
- nl->snd_data.state = PLIP_PK_DONE;
- nl->rcv_data.skb = NULL;
- nl->snd_data.skb = NULL;
- nl->connection = PLIP_CN_NONE;
- cli();
- dev->tbusy = 0;
- sti();
- outb(LP_PINITP|LP_PSELECP|LP_PINTEN, PAR_CONTROL(dev));
- enable_irq(dev->irq);
-}
+ struct device *dev = (struct device *) irq2dev_map[irq];
+ struct net_local *nl = (struct net_local *)dev->priv;
+ struct plip_local *rcv = &nl->rcv_data;
+ unsigned char c0;
-/* PLIP_ERROR --- wait till other end settled */
-static int
-plip_error(struct device *dev)
-{
- unsigned char status;
+ if (dev == NULL) {
+ printk ("plip_interrupt: irq %d for unknown device.\n", irq);
+ return;
+ }
- status = inb(PAR_STATUS(dev));
- if ((status & 0xf8) == 0x80)
- return 0;
- return 1;
+ if (dev->interrupt)
+ return;
+
+ c0 = inb(PAR_STATUS(dev));
+ if ((c0 & 0xf8) != 0xc0) {
+ if (net_debug > 1)
+ printk("%s: spurious interrupt\n", dev->name);
+ return;
+ }
+ dev->interrupt = 1;
+ if (net_debug > 3)
+ printk("%s: interrupt.\n", dev->name);
+
+ cli();
+ switch (nl->connection) {
+ case PLIP_CN_CLOSING:
+ dev->tbusy = 0;
+ case PLIP_CN_NONE:
+ case PLIP_CN_SEND:
+ dev->last_rx = jiffies;
+ rcv->state = PLIP_PK_TRIGGER;
+ nl->connection = PLIP_CN_RECEIVE;
+ nl->timeout_count = 0;
+ queue_task(&nl->immediate, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ sti();
+ break;
+
+ case PLIP_CN_RECEIVE:
+ sti();
+ printk("%s: receive interrupt when receiving packet\n", dev->name);
+ break;
+
+ case PLIP_CN_ERROR:
+ sti();
+ printk("%s: receive interrupt in error state\n", dev->name);
+ break;
+ }
}
\f
-/* PLIP_RECEIVE --- receive a byte(two nibbles)
- Returns 0 on success, 1 on failure */
-inline static int
-plip_receive(unsigned short nibble_timeout, unsigned short unit_us,
- unsigned short status_addr, unsigned short data_addr,
- enum plip_nibble_state *ns_p, unsigned char *data_p)
+/* We don't need to send arp, for plip is point-to-point. */
+static int
+plip_rebuild_header(void *buff, struct device *dev, unsigned long dst,
+ struct sk_buff *skb)
{
- unsigned char c0, c1;
- unsigned int cx;
-
- switch (*ns_p) {
- case PLIP_NB_BEGIN:
- cx = nibble_timeout;
- while (1) {
- c0 = inb(status_addr);
- udelay(unit_us);
- if ((c0 & 0x80) == 0) {
- c1 = inb(status_addr);
- if (c0 == c1)
- break;
- }
- if (--cx == 0)
- return 1;
- }
- *data_p = (c0 >> 3) & 0x0f;
- outb(0x10, data_addr); /* send ACK */
- *ns_p = PLIP_NB_1;
-
- case PLIP_NB_1:
- cx = nibble_timeout;
- while (1) {
- c0 = inb(status_addr);
- udelay(unit_us);
- if (c0 & 0x80) {
- c1 = inb(status_addr);
- if (c0 == c1)
- break;
- }
- if (--cx == 0)
- return 1;
+ struct ethhdr *eth = (struct ethhdr *)buff;
+ int i;
+
+ if (eth->h_proto != htons(ETH_P_IP)) {
+ printk("plip_rebuild_header: Don't know how to resolve type %d addresses?\n", (int)eth->h_proto);
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ return 0;
}
- *data_p |= (c0 << 1) & 0xf0;
- outb(0x00, data_addr); /* send ACK */
- *ns_p = PLIP_NB_BEGIN;
- return 0;
- case PLIP_NB_2:
- }
+ for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
+ eth->h_dest[i] = 0xfc;
+ memcpy(&(eth->h_dest[i]), &dst, sizeof(unsigned long));
+ return 0;
}
-/* PLIP_RECEIVE_PACKET --- receive a packet
- Returns 0 on success, 1 when timeout, -1 on failure */
static int
-plip_receive_packet(struct device *dev)
+plip_tx_packet(struct sk_buff *skb, struct device *dev)
{
- unsigned short data_addr = PAR_DATA(dev), status_addr = PAR_STATUS(dev);
- struct net_local *nl = (struct net_local *)dev->priv;
- unsigned short nibble_timeout = nl->nibble_us, unit_us = nl->unit_us;
- struct plip_local *rcv = &nl->rcv_data;
- unsigned char *lbuf;
- struct enet_statistics *stats = (struct enet_statistics *) dev->priv;
-
- switch (rcv->state) {
- case PLIP_PK_TRIGGER:
- rcv->state = PLIP_PK_LENGTH_LSB;
- rcv->nibble = PLIP_NB_BEGIN;
-
- case PLIP_PK_LENGTH_LSB:
- if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
- &rcv->nibble, (unsigned char *)&rcv->length))
- return 1;
- rcv->state = PLIP_PK_LENGTH_MSB;
-
- case PLIP_PK_LENGTH_MSB:
- if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
- &rcv->nibble, (unsigned char *)&rcv->length+1))
- return 1;
- if (rcv->length > dev->mtu || rcv->length < 8) {
- printk("%s: bogus packet size %d.\n", dev->name, rcv->length);
- return -1;
- }
- /* Malloc up new buffer. */
- rcv->skb = alloc_skb(rcv->length, GFP_ATOMIC);
- if (rcv->skb == NULL) {
- printk("%s: Memory squeeze.\n", dev->name);
- return -1;
+ struct net_local *nl = (struct net_local *)dev->priv;
+ struct plip_local *snd = &nl->snd_data;
+
+ if (dev->tbusy)
+ return 1;
+
+ /* If some higher layer thinks we've missed an tx-done interrupt
+ we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+ itself. */
+ if (skb == NULL) {
+ dev_tint(dev);
+ return 0;
}
- rcv->skb->len = rcv->length;
- rcv->skb->dev = dev;
- rcv->state = PLIP_PK_DATA;
- rcv->byte = 0;
- rcv->checksum = 0;
-
- case PLIP_PK_DATA:
- lbuf = rcv->skb->data;
- do {
- if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
- &rcv->nibble, &lbuf[rcv->byte]))
+
+ if (set_bit(0, (void*)&dev->tbusy) != 0) {
+ printk("%s: Transmitter access conflict.\n", dev->name);
return 1;
- rcv->checksum += lbuf[rcv->byte];
- } while (++rcv->byte < rcv->length);
- rcv->state = PLIP_PK_CHECKSUM;
-
- case PLIP_PK_CHECKSUM:
- if (plip_receive(nibble_timeout, unit_us, status_addr, data_addr,
- &rcv->nibble, &rcv->data))
- return 1;
- if (rcv->data != rcv->checksum) {
- stats->rx_crc_errors++;
- if (net_debug)
- printk("%s: checksum error\n", dev->name);
- return -1;
}
- rcv->state = PLIP_PK_DONE;
- case PLIP_PK_DONE:
- }
- return 0;
-}
+ if (skb->len > dev->mtu) {
+ printk("%s: packet too big, %d.\n", dev->name, (int)skb->len);
+ dev->tbusy = 0;
+ return 0;
+ }
-/* Handle the parallel port interrupts. */
-static void
-plip_interrupt(int irq, struct pt_regs * regs)
-{
- struct device *dev = (struct device *) irq2dev_map[irq];
- struct net_local *nl = (struct net_local *)dev->priv;
- struct plip_local *rcv = &nl->rcv_data;
- unsigned char c0;
-
- if (dev == NULL) {
- if (net_debug)
- printk ("plip_interrupt: irq %d for unknown device.\n", irq);
- return;
- }
-
- if (dev->interrupt)
- return;
-
- c0 = inb(PAR_STATUS(dev));
- if ((c0 & 0xf8) != 0xc0) {
- if (net_debug > 3)
- printk("plip: spurious interrupt\n");
- return;
- }
- dev->interrupt = 1;
- if (net_debug > 3)
- printk("%s: interrupt.\n", dev->name);
-
- cli();
- switch (nl->connection) {
- case PLIP_CN_CLOSING:
- dev->tbusy = 0;
- case PLIP_CN_NONE:
- case PLIP_CN_SEND:
- sti();
- dev->last_rx = jiffies;
- rcv->state = PLIP_PK_TRIGGER;
- nl->connection = PLIP_CN_RECEIVE;
- nl->timeout_count = 0;
+ if (net_debug > 2)
+ printk("%s: send request\n", dev->name);
+
+ cli();
+ dev->trans_start = jiffies;
+ snd->skb = skb;
+ snd->length = skb->len;
+ snd->state = PLIP_PK_TRIGGER;
+ if (nl->connection == PLIP_CN_NONE) {
+ nl->connection = PLIP_CN_SEND;
+ nl->timeout_count = 0;
+ }
queue_task(&nl->immediate, &tq_immediate);
mark_bh(IMMEDIATE_BH);
- break;
-
- case PLIP_CN_RECEIVE:
sti();
- printk("%s: receive interrupt when receiving packet\n", dev->name);
- break;
- case PLIP_CN_ERROR:
- sti();
- printk("%s: receive interrupt in error state\n", dev->name);
- break;
- }
+ return 0;
}
-\f
-/* PLIP_SEND --- send a byte (two nibbles)
- Returns 0 on success, 1 on failure */
-inline static int
-plip_send(unsigned short nibble_timeout, unsigned short unit_us,
- unsigned short status_addr, unsigned short data_addr,
- enum plip_nibble_state *ns_p, unsigned char data)
+
+/* Open/initialize the board. This is called (in the current kernel)
+ sometime after booting when the 'ifconfig' program is run.
+
+ This routine gets exclusive access to the parallel port by allocating
+ its IRQ line.
+ */
+static int
+plip_open(struct device *dev)
{
- unsigned char c0;
- unsigned int cx;
-
- switch (*ns_p) {
- case PLIP_NB_BEGIN:
- outb((data & 0x0f), data_addr);
- *ns_p = PLIP_NB_1;
-
- case PLIP_NB_1:
- outb(0x10 | (data & 0x0f), data_addr);
- cx = nibble_timeout;
- while (1) {
- c0 = inb(status_addr);
- if ((c0 & 0x80) == 0)
- break;
- if (--cx == 0) /* time out */
- return 1;
- udelay(unit_us);
+ struct net_local *nl = (struct net_local *)dev->priv;
+ int i;
+
+ if (dev->irq == 0) {
+ printk("%s: IRQ is not set. Please set it by ifconfig.\n", dev->name);
+ return -EAGAIN;
}
- outb(0x10 | (data >> 4), data_addr);
- *ns_p = PLIP_NB_2;
-
- case PLIP_NB_2:
- outb((data >> 4), data_addr);
- cx = nibble_timeout;
- while (1) {
- c0 = inb(status_addr);
- if (c0 & 0x80)
- break;
- if (--cx == 0) /* time out */
- return 1;
- udelay(unit_us);
+ cli();
+ if (request_irq(dev->irq , plip_interrupt, 0, dev->name) != 0) {
+ sti();
+ printk("%s: couldn't get IRQ %d.\n", dev->name, dev->irq);
+ return -EAGAIN;
}
- *ns_p = PLIP_NB_BEGIN;
+ irq2dev_map[dev->irq] = dev;
+ sti();
+
+ /* Clear the data port. */
+ outb (0x00, PAR_DATA(dev));
+
+ /* Enable rx interrupt. */
+ outb(PAR_INTR_ON, PAR_CONTROL(dev));
+
+ /* Initialize the state machine. */
+ nl->rcv_data.state = nl->snd_data.state = PLIP_PK_DONE;
+ nl->rcv_data.skb = nl->snd_data.skb = NULL;
+ nl->connection = PLIP_CN_NONE;
+ nl->is_deferred = 0;
+
+ /* Fill in the MAC-level header. */
+ for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++)
+ dev->dev_addr[i] = 0xfc;
+ memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(unsigned long));
+
+ dev->interrupt = 0;
+ dev->start = 1;
+ dev->tbusy = 0;
+ MOD_INC_USE_COUNT;
return 0;
- }
}
-/* PLIP_SEND_PACKET --- send a packet
- Returns 0 on success, 1 when timeout, -1 when interrupted */
+/* The inverse routine to plip_open (). */
static int
-plip_send_packet(struct device *dev)
+plip_close(struct device *dev)
{
- unsigned short data_addr = PAR_DATA(dev), status_addr = PAR_STATUS(dev);
- struct net_local *nl = (struct net_local *)dev->priv;
- unsigned short nibble_timeout = nl->nibble_us, unit_us = nl->unit_us;
- struct plip_local *snd = &nl->snd_data;
- unsigned char *lbuf = snd->skb->data;
- unsigned char c0;
- unsigned int cx;
- struct enet_statistics *stats = (struct enet_statistics *) dev->priv;
-
- switch (snd->state) {
- case PLIP_PK_TRIGGER:
- /* Trigger remote rx interrupt. */
- outb(0x08, PAR_DATA(dev));
- cx = nl->trigger_us;
- while (1) {
- if (nl->connection == PLIP_CN_RECEIVE) { /* interrupted */
- stats->collisions++;
- if (net_debug > 3)
- printk("%s: collision.\n", dev->name);
- return -1;
- }
- cli();
- c0 = inb(PAR_STATUS(dev));
- if (c0 & 0x08) {
- disable_irq(dev->irq);
- outb(LP_PINITP|LP_PSELECP, PAR_CONTROL(dev));
- if (net_debug > 3)
- printk("+");
- /* OK, connection established! */
- snd->state = PLIP_PK_LENGTH_LSB;
- snd->nibble = PLIP_NB_BEGIN;
- nl->timeout_count = 0;
- sti();
- break;
- }
- sti();
- udelay(nl->unit_us);
- if (--cx == 0) {
- outb(0x00, PAR_DATA(dev));
- return 1;
- }
- }
+ struct net_local *nl = (struct net_local *)dev->priv;
+ struct plip_local *snd = &nl->snd_data;
+ struct plip_local *rcv = &nl->rcv_data;
- case PLIP_PK_LENGTH_LSB:
- if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
- &snd->nibble, snd->length & 0xff)) /* timeout */
- return 1;
- snd->state = PLIP_PK_LENGTH_MSB;
-
- case PLIP_PK_LENGTH_MSB:
- if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
- &snd->nibble, snd->length >> 8)) /* timeout */
- return 1;
- snd->state = PLIP_PK_DATA;
- snd->byte = 0;
- snd->checksum = 0;
-
- case PLIP_PK_DATA:
- do {
- if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
- &snd->nibble, lbuf[snd->byte])) /* timeout */
- return 1;
- snd->checksum += lbuf[snd->byte];
- } while (++snd->byte < snd->length);
- snd->state = PLIP_PK_CHECKSUM;
+ dev->tbusy = 1;
+ dev->start = 0;
+ cli();
+ free_irq(dev->irq);
+ irq2dev_map[dev->irq] = NULL;
+ nl->is_deferred = 0;
+ nl->connection = PLIP_CN_NONE;
+ sti();
+ outb(0x00, PAR_DATA(dev));
+
+ snd->state = PLIP_PK_DONE;
+ if (snd->skb) {
+ dev_kfree_skb(snd->skb, FREE_WRITE);
+ snd->skb = NULL;
+ }
+ rcv->state = PLIP_PK_DONE;
+ if (rcv->skb) {
+ rcv->skb->free = 1;
+ kfree_skb(rcv->skb, FREE_READ);
+ rcv->skb = NULL;
+ }
- case PLIP_PK_CHECKSUM:
- if (plip_send(nibble_timeout, unit_us, status_addr, data_addr,
- &snd->nibble, snd->checksum)) /* timeout */
- return 1;
+ /* Reset. */
+ outb(0x00, PAR_CONTROL(dev));
+ MOD_DEC_USE_COUNT;
+ return 0;
+}
- dev_kfree_skb(snd->skb, FREE_WRITE);
- stats->tx_packets++;
+static struct enet_statistics *
+plip_get_stats(struct device *dev)
+{
+ struct net_local *nl = (struct net_local *)dev->priv;
+ struct enet_statistics *r = &nl->enet_stats;
- case PLIP_PK_DONE:
- }
- return 0;
+ return r;
}
-\f
-static int plip_config(struct device *dev, struct ifmap *map)
+
+static int
+plip_config(struct device *dev, struct ifmap *map)
{
- if(dev->flags&IFF_UP)
+ if (dev->flags & IFF_UP)
return -EBUSY;
-/*
- * We could probe this for verification, but since they told us
- * to do it then they can suffer.
- */
- if(map->base_addr!= (unsigned short)-1)
- dev->base_addr=map->base_addr;
- if(map->irq!= (unsigned char)-1)
- dev->irq= map->irq;
+
+ if (map->base_addr != (unsigned long)-1
+ && map->base_addr != dev->base_addr)
+ printk("%s: You cannot change base_addr of this interface (ignored).\n", dev->name);
+
+ if (map->irq != (unsigned char)-1)
+ dev->irq = map->irq;
return 0;
}
-static int plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
+static int
+plip_ioctl(struct device *dev, struct ifreq *rq, int cmd)
{
struct net_local *nl = (struct net_local *) dev->priv;
struct plipconf *pc = (struct plipconf *) &rq->ifr_data;
- switch(pc->pcmd)
- {
- case PLIP_GET_TIMEOUT:
- pc->trigger=nl->trigger_us;
- pc->nibble=nl->nibble_us;
- pc->unit=nl->unit_us;
- break;
- case PLIP_SET_TIMEOUT:
- nl->trigger_us=pc->trigger;
- nl->nibble_us=pc->nibble;
- nl->unit_us=pc->unit;
- break;
- default:
- return -EOPNOTSUPP;
+ switch(pc->pcmd) {
+ case PLIP_GET_TIMEOUT:
+ pc->trigger = nl->trigger;
+ pc->nibble = nl->nibble;
+ pc->unit = nl->unit;
+ break;
+ case PLIP_SET_TIMEOUT:
+ nl->trigger = pc->trigger;
+ nl->nibble = pc->nibble;
+ nl->unit = pc->unit;
+ break;
+ default:
+ return -EOPNOTSUPP;
}
return 0;
}
-
\f
#ifdef MODULE
char kernel_version[] = UTS_RELEASE;
int
init_module(void)
{
- int devices=0;
-
- if (register_netdev(&dev_plip0) != 0)
- devices++;
- if (register_netdev(&dev_plip1) != 0)
- devices++;
- if (register_netdev(&dev_plip2) != 0)
- devices++;
- if (devices == 0)
- return -EIO;
- return 0;
+ int devices=0;
+
+ if (register_netdev(&dev_plip0) != 0)
+ devices++;
+ if (register_netdev(&dev_plip1) != 0)
+ devices++;
+ if (register_netdev(&dev_plip2) != 0)
+ devices++;
+ if (devices == 0)
+ return -EIO;
+ return 0;
}
void
cleanup_module(void)
{
- if (MOD_IN_USE)
- printk("plip: device busy, remove delayed\n");
- else {
if (dev_plip0.priv) {
- unregister_netdev(&dev_plip0);
- release_region(PAR_DATA(&dev_plip0), 3);
- kfree_s(dev_plip0.priv, sizeof(struct net_local));
- dev_plip0.priv = NULL;
+ unregister_netdev(&dev_plip0);
+ release_region(PAR_DATA(&dev_plip0), 3);
+ kfree_s(dev_plip0.priv, sizeof(struct net_local));
+ dev_plip0.priv = NULL;
}
if (dev_plip1.priv) {
- unregister_netdev(&dev_plip1);
- release_region(PAR_DATA(&dev_plip1), 3);
- kfree_s(dev_plip1.priv, sizeof(struct net_local));
- dev_plip1.priv = NULL;
+ unregister_netdev(&dev_plip1);
+ release_region(PAR_DATA(&dev_plip1), 3);
+ kfree_s(dev_plip1.priv, sizeof(struct net_local));
+ dev_plip1.priv = NULL;
}
if (dev_plip2.priv) {
- unregister_netdev(&dev_plip2);
- release_region(PAR_DATA(&dev_plip2), 3);
- kfree_s(dev_plip2.priv, sizeof(struct net_local));
- dev_plip2.priv = NULL;
+ unregister_netdev(&dev_plip2);
+ release_region(PAR_DATA(&dev_plip2), 3);
+ kfree_s(dev_plip2.priv, sizeof(struct net_local));
+ dev_plip2.priv = NULL;
}
- }
}
#endif /* MODULE */
\f
/*
* Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe -m486 -I../../net/inet -c plip.c"
- * c-indent-level: 4
- * c-continued-statement-offset: 4
- * c-brace-offset: -4
- * c-argdecl-indent: 4
- * c-label-offset: -4
- * version-control: t
- * kept-new-versions: 10
+ * compile-command: "gcc -DMODULE -DCONFIG_MODVERSIONS -D__KERNEL__ -Wall -Wstrict-prototypes -O2 -g -fomit-frame-pointer -pipe -m486 -c plip.c"
* End:
*/
/*
* eata.c - Low-level driver for EATA/DMA SCSI host adapters.
*
+ * 8 Feb 1995 rev. 1.15 for linux 1.1.89
+ * Cleared target_time_out counter while preforming a reset.
+ * All external symbols renamed to avoid possible name conflicts.
+ *
* 28 Jan 1995 rev. 1.14 for linux 1.1.86
* Added module support.
* Log and do a retry when a disk drive returns a target status
* This driver is based on the CAM (Common Access Method Committee)
* EATA (Enhanced AT Bus Attachment) rev. 2.0A, using DMA protocol.
*
- * Released by Dario Ballabio (Dario_Ballabio@milano.europe.dg.com)
+ * Copyright (C) 1994, 1995 Dario Ballabio (dario@milano.europe.dg.com)
*
*/
#if defined(MODULE)
#include <linux/module.h>
+#include <linux/version.h>
#endif
#include <linux/string.h>
#define HD(board) ((struct hostdata *) &sh[board]->hostdata)
#define BN(board) (HD(board)->board_name)
-static void eata_interrupt_handler(int, struct pt_regs *);
+static void eata2x_interrupt_handler(int, struct pt_regs *);
static int do_trace = FALSE;
static inline unchar wait_on_busy(ushort iobase) {
/* Board detected, allocate its IRQ if not already done */
if ((irq >= MAX_IRQ) || ((irqlist[irq] == NO_IRQ) && request_irq
- (irq, eata_interrupt_handler, SA_INTERRUPT, driver_name))) {
+ (irq, eata2x_interrupt_handler, SA_INTERRUPT, driver_name))) {
printk("%s: unable to allocate IRQ %u, detaching.\n", name, irq);
return FALSE;
}
if (HD(j)->subversion == ESA)
sh[j]->unchecked_isa_dma = FALSE;
else {
-
-#if !defined(MODULE)
- /* The module code does not checkin/checkout in the blocking list yet */
sh[j]->block = sh[j];
-#endif
-
sh[j]->unchecked_isa_dma = TRUE;
disable_dma(dma_channel);
clear_dma_ff(dma_channel);
return TRUE;
}
-int eata_detect (Scsi_Host_Template * tpnt) {
+int eata2x_detect (Scsi_Host_Template * tpnt) {
unsigned int j = 0, k, flags;
ushort io_port[] = {
port_base++;
}
+ if (j > 0)
+ printk("EATA/DMA 2.0x: Copyright (C) 1994, 1995 Dario Ballabio.\n");
+
restore_flags(flags);
return j;
}
cpp->data_len = htonl((SCpnt->use_sg * sizeof(struct sg_list)));
}
-int eata_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
+int eata2x_queuecommand (Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *)) {
unsigned int i, j, k, flags;
struct mscp *cpp;
struct mssp *spp;
if (HD(j)->in_reset)
printk("%s: qcomm, already in reset.\n", BN(j));
- else if (eata_reset(SCpnt) == SCSI_RESET_SUCCESS)
+ else if (eata2x_reset(SCpnt) == SCSI_RESET_SUCCESS)
panic("%s: qcomm, SCSI_RESET_SUCCESS.\n", BN(j));
SCpnt->result = DID_BUS_BUSY << 16;
return 0;
}
-int eata_abort (Scsi_Cmnd *SCarg) {
+int eata2x_abort (Scsi_Cmnd *SCarg) {
unsigned int i, j, flags;
save_flags(flags);
panic("%s: abort, mbox %d, invalid cp_stat.\n", BN(j), i);
}
-int eata_reset (Scsi_Cmnd *SCarg) {
+int eata2x_reset (Scsi_Cmnd *SCarg) {
unsigned int i, j, flags, time, k, limit = 0;
int arg_done = FALSE;
Scsi_Cmnd *SCpnt;
for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE;
+ for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0;
+
for (i = 0; i < sh[j]->can_queue; i++) {
if (HD(j)->cp_stat[i] == FREE) continue;
HD(j)->in_reset = TRUE;
sti();
time = jiffies;
- while (jiffies < (time + 200) && limit++ < 100000000) sti();
+ while (jiffies < (time + 100) && limit++ < 100000000);
cli();
printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
}
}
-static void eata_interrupt_handler(int irq, struct pt_regs * regs) {
+static void eata2x_interrupt_handler(int irq, struct pt_regs * regs) {
Scsi_Cmnd *SCpnt;
unsigned int i, j, k, flags, status, tstatus, loops, total_loops = 0;
struct mssp *spp;
status = DID_BUS_BUSY << 16;
else if (tstatus == CHECK_CONDITION
- && (SCpnt->device->type == TYPE_DISK
- || SCpnt->device->type == TYPE_ROM)
+ && SCpnt->device->type == TYPE_DISK
&& (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION)
status = DID_ERROR << 16;
if (tstatus == GOOD)
HD(j)->target_reset[SCpnt->target] = FALSE;
- if (spp->target_status && (SCpnt->device->type == TYPE_DISK
- || SCpnt->device->type == TYPE_ROM))
+ 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,
#include <linux/scsicam.h>
-#define EATA_VERSION "1.14.03"
+#define EATA_VERSION "1.15.00"
-int eata_detect(Scsi_Host_Template *);
-int eata_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
-int eata_abort(Scsi_Cmnd *);
-int eata_reset(Scsi_Cmnd *);
+int eata2x_detect(Scsi_Host_Template *);
+int eata2x_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int eata2x_abort(Scsi_Cmnd *);
+int eata2x_reset(Scsi_Cmnd *);
-#define EATA { NULL, /* Ptr for modules */ \
+#define EATA { \
+ NULL, /* Ptr for modules */ \
NULL, /* usage count for modules */ \
- "EATA/DMA 2.0 rev. " EATA_VERSION " by " \
- "Dario_Ballabio@milano.europe.dg.com.", \
- eata_detect, \
+ "EATA/DMA 2.0x rev. " EATA_VERSION " ", \
+ eata2x_detect, \
NULL, /* Release */ \
NULL, \
NULL, \
- eata_queuecommand, \
- eata_abort, \
- eata_reset, \
+ eata2x_queuecommand, \
+ eata2x_abort, \
+ eata2x_reset, \
NULL, \
scsicam_bios_param, \
0, /* can_queue, reset by detect */ \
#define C_P_L_DIV 4 /* 1 <= C_P_L_DIV <= 8
* You can use this parameter to fine-tune
* the driver. Depending on the number of
- * devices and their ablilty to queue commands
+ * devices and their 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 tents
j = sh->extra_bytes;
if(scsi_hostlist == sh)
- scsi_hostlist = NULL;
+ scsi_hostlist = sh->next;
else {
shpnt = scsi_hostlist;
while(shpnt->next != sh) shpnt = shpnt->next;
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 = next_scsi_host++;
+ 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;
printk ("scsi : %d host%s.\n", next_scsi_host,
(next_scsi_host == 1) ? "" : "s");
- {
- int block_count = 0, index;
- struct Scsi_Host * sh[128], * shpnt;
-
- for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
- if (shpnt->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);
- }
-
- }
+ scsi_make_blocked_list();
/* Now attach the high level drivers */
#ifdef CONFIG_BLK_DEV_SD
scsi_register_device(&sg_template);
#endif
+#if 0
max_scsi_hosts = next_scsi_host;
+#endif
return 0;
}
$conditional = $1;
print STDERR "$0 : parsed ATN\n" if ($debug);
} elsif ($conditional =~ /^($phase)\s*(.*)/i) {
- $1 = "\U$1\E";
- $p = $scsi_phases{$1};
+ $phase_index = "\U$1\E";
+ $p = $scsi_phases{$phase_index};
$code[$address] |= $p | 0x00_02_00_00;
$conditional = $2;
- print STDERR "$0 : parsed phase $1\n" if ($debug);
+ print STDERR "$0 : parsed phase $phase_index\n" if ($debug);
} else {
$other = '';
$need_data = 1;
$rest = $2;
foreach $rest (split (/\s*,\s*/, $rest)) {
if ($rest =~ /^($identifier)\s*=\s*($constant)\s*$/) {
- if ($symbol_values{$1} eq undef) {
- $symbol_values{$1} = eval $2;
- delete $forward{$1};
+ local ($id, $cnst) = ($1, $2);
+ if ($symbol_values{$id} eq undef) {
+ $symbol_values{$id} = eval $cnst;
+ delete $forward{$id};
if ($is_absolute =~ /ABSOLUTE/i) {
- push (@absolute , $1);
+ push (@absolute , $id);
} else {
- push (@relative, $1);
+ push (@relative, $id);
}
} else {
- die "$0 : redefinition of symbol $1 in line $lineno : $_\n";
+ die "$0 : redefinition of symbol $id in line $lineno : $_\n";
}
} else {
die
/*
- * scsi.c Copyright (C) 1992 Drew Eckhardt
+ * scsi.c Copyright (C) 1992 Drew Eckhardt
* Copyright (C) 1993, 1994, 1995 Eric Youngdale
*
* generic mid-level SCSI driver
- * Initial versions: Drew Eckhardt
+ * Initial versions: Drew Eckhardt
* Subsequent revisions: Eric Youngdale
*
* <drew@colorado.edu>
*
- * Bug correction thanks go to :
+ * 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.
static int time_start;
static int time_elapsed;
-static int scsi_maybe_deadlocked = 0;
-static int max_active = 0;
-static struct Scsi_Host * host_active = NULL;
-static struct Scsi_Host * host_next = NULL;
+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))
#define MAX_SCSI_DEVICE_CODE 10
const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
/*
- global variables :
- scsi_devices an array of these specifying the address for each
+ global variables :
+ scsi_devices an array of these specifying the address for each
(host, id, LUN)
*/
Scsi_Cmnd * last_cmnd = NULL;
/*
- * As the scsi do command functions are intelligent, and may need to
- * redo a command, we need to keep track of the last command
+ * 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_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
+ * 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.
*
#define SENSE_TIMEOUT 50
#define RESET_TIMEOUT 50
#define ABORT_TIMEOUT 50
- #define MIN_RESET_DELAY 100
#endif
+#define MIN_RESET_DELAY 100
+
+/* Do not call reset on error if we just did a reset within 10 sec. */
+#define MIN_RESET_PERIOD 1000
+
/* 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. */
char * revision; /* Latest revision known to be bad. Not used yet */
};
-static struct blist blacklist[] =
+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 */
{"HP", "C1750A", "3226"}, /* scanjet iic */
{"HP", "C1790A", ""}, /* scanjet iip */
{"HP", "C2500A", ""}, /* scanjet iicx */
- {NULL, NULL, NULL}};
+ {NULL, NULL, NULL}};
static int blacklisted(unsigned char * response_data){
int i = 0;
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
+ * 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;
-static void restart_all(void) {
- /*
- * If we might have deadlocked, get things started again. Only
- * for block devices. Character devices should never deadlock.
- */
- struct Scsi_Device_Template * sdtpnt;
+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 "block" field in the Scsi_Host structure set to any value
+ * different from NULL.
+ * If there is only one host such that host->block != NULL, the list is
+ * empty and host->block is reset to NULL.
+ * 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)
+ */
- for (sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
+ 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->block = shpnt;
+#endif
- if (sdtpnt->blk && blk_dev[sdtpnt->major].request_fn)
- (*blk_dev[sdtpnt->major].request_fn)();
+ if (shpnt->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);
+ }
+
+ restore_flags(flags);
}
static void scan_scsis_done (Scsi_Cmnd * SCpnt)
{
-
+
#ifdef DEBUG
printk ("scan_scsis_done(%d, %06x)\n", SCpnt->host, SCpnt->result);
-#endif
+#endif
SCpnt->request.dev = 0xfffe;
if (SCpnt->request.sem != NULL)
#endif
void scsi_luns_setup(char *str, int *ints) {
- if (ints[0] != 1)
+ if (ints[0] != 1)
printk("scsi_luns_setup : usage max_scsi_luns=n (n should be between 1 and 8)\n");
else
- max_scsi_luns = ints[1];
+ max_scsi_luns = ints[1];
}
/*
- * 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
+ * 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.
*/
Scsi_Device * SDpnt, *SDtail;
struct Scsi_Device_Template * sdtpnt;
Scsi_Cmnd SCmd;
-
+
++in_scan_scsis;
lun = 0;
type = -1;
}
/* Make sure we have something that is valid for DMA purposes */
- scsi_result = ((current == task[0] || !shpnt->unchecked_isa_dma)
+ scsi_result = ((current == task[0] || !shpnt->unchecked_isa_dma)
? &scsi_result0[0] : scsi_malloc(512));
-
+
shpnt->host_queue = &SCmd; /* We need this so that
commands can time out */
SDpnt->next = NULL;
SDpnt->attached = 0;
/*
- * Assume that the device will have handshaking problems, and then
+ * 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[5] = 0;
scsi_cmd[4] = 0;
-
+
SCmd.host = shpnt;
SCmd.target = dev;
SCmd.lun = lun;
SCmd.old_use_sg = 0;
SCmd.transfersize = 0;
SCmd.underflow = 0;
-
+
scsi_do_cmd (&SCmd,
- (void *) scsi_cmd, (void *)
- scsi_result, 256, scan_scsis_done,
+ (void *) scsi_cmd, (void *)
+ scsi_result, 256, scan_scsis_done,
SCSI_TIMEOUT + 400, 5);
-
+
/* Wait for command to finish. Use simple wait if we are booting, else
do it right and use a mutex */
printk("scsi: scan SCSIS id %d lun %d\n", dev, lun);
printk("scsi: return code %08x\n", SCmd.result);
#endif
-
-
+
+
if(SCmd.result) {
if ((driver_byte(SCmd.result) & DRIVER_SENSE) &&
((SCmd.sense_buffer[0] & 0x70) >> 4) == 7) {
else
break;
};
-
+
#if defined (DEBUG) || defined(DEBUG_INIT)
printk("scsi: performing INQUIRY\n");
#endif
-
+
/*
- * Build an INQUIRY command block.
+ * 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;
-
+
SCmd.request.dev = 0xffff; /* Mark not busy */
SCmd.cmd_len = 0;
-
+
scsi_do_cmd (&SCmd,
- (void *) scsi_cmd, (void *)
- scsi_result, 256, scan_scsis_done,
+ (void *) scsi_cmd, (void *)
+ scsi_result, 256, scan_scsis_done,
SCSI_TIMEOUT, 3);
-
+
if (current == task[0]){
while (SCmd.request.dev != 0xfffe);
} else {
}
the_result = SCmd.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;
-
+
+ if(the_result) break;
+
/* skip other luns on this device */
-
+
if (!the_result)
{
/* It would seem some TOSHIBA CD-ROM gets things wrong */
scsi_result[1] |= 0x80; /* removable */
}
-/*
- * Unfortunately the Toshiba CD-ROM XM-3401TA doesn't
- * understand the vendor specific mode select/sense
- * commands which are used by the photo cd routines in
- * sr.c.
- */
-
SDpnt->manufacturer = SCSI_MAN_UNKNOWN;
if (!strncmp(scsi_result+8,"NEC",3))
SDpnt->manufacturer = SCSI_MAN_NEC;
- if (!strncmp(scsi_result+8,"TOSHIBA",7) &&
- strncmp(scsi_result+16,"CD-ROM XM-3401TA",16) &&
- strncmp(scsi_result+32,"3593",4))
+ if (!strncmp(scsi_result+8,"TOSHIBA",7))
SDpnt->manufacturer = SCSI_MAN_TOSHIBA;
- SDpnt->removable = (0x80 &
+ 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
+ * all random devices disk, with the appropriate read only
* flags set for ROM / WORM treated as RO.
- */
+ */
switch (type = (scsi_result[0] & 0x1f))
{
type = -1;
#endif
}
-
- SDpnt->soft_reset =
+
+ 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);
(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.
/*
* 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
+ * 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
-/*
+ 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.
#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 &&
scsi_cmd[3] = 0;
scsi_cmd[4] = 0x2a;
scsi_cmd[5] = 0;
-
+
SCmd.request.dev = 0xffff; /* Mark not busy */
SCmd.cmd_len = 0;
-
+
scsi_do_cmd (&SCmd,
- (void *) scsi_cmd, (void *)
- scsi_result, 0x2a, scan_scsis_done,
+ (void *) scsi_cmd, (void *)
+ scsi_result, 0x2a, scan_scsis_done,
SCSI_TIMEOUT, 3);
-
+
if (current == task[0]){
while (SCmd.request.dev != 0xfffe);
} else {
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 &&
+ 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));
-
+
/* If we allocated a buffer so we could do DMA, free it now */
if (scsi_result != &scsi_result0[0]) scsi_free(scsi_result, 512);
} /* 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
+ 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))
+
+ switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET))
{
case NORMAL_TIMEOUT:
if (!in_scan_scsis) {
scsi_dump_status();
#endif
}
-
+
if (!scsi_abort (SCpnt, DID_TIME_OUT, pid))
- return;
+ return;
case IN_ABORT:
printk("SCSI host %d abort() timed out - resetting\n",
SCpnt->host->host_no);
- if (!scsi_reset (SCpnt))
+ if (!scsi_reset (SCpnt))
return;
case IN_RESET:
case (IN_ABORT | IN_RESET):
default:
INTERNAL_ERROR;
}
-
+
}
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 &&
if (!SCpnt) return NULL;
- if (device->host->can_queue &&
- ((device->host->block && host_active && device->host != host_active) ||
- (device->host->block && host_next && device->host != host_next) ||
- device->host->host_busy >= device->host->can_queue)) {
-
- if (device->host->block && !host_next && host_active
- && device->host != host_active)
- host_next = device->host;
-
- return NULL;
- }
+ if (SCSI_BLOCK(device->host)) return NULL;
if (req) {
memcpy(&SCpnt->request, req, sizeof(struct request));
} else {
req->dev = -1;
wake_up(&wait_for_request);
- };
+ };
} else {
SCpnt->request.dev = 0xffff; /* Busy, but no request */
SCpnt->request.sem = NULL; /* And no one is waiting for the device either */
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 && host->can_queue &&
- ((host->block && host_active && host != host_active) ||
- (host->block && host_next && host != host_next) ||
- host->host_busy >= host->can_queue)) {
- scsi_maybe_deadlocked = 1;
-
- if (host->block && !host_next && host_active && host != host_active)
- host_next = host;
+ host = device->host;
- return NULL;
- }
+ if (intr_count && SCSI_BLOCK(host)) return NULL;
while (1==1){
SCpnt = host->host_queue;
device->id ,device->lun);
panic("No device found in allocate_device\n");
};
- SCSI_SLEEP(&device->device_wait,
+ SCSI_SLEEP(&device->device_wait,
(SCwait->request.dev > 0));
} else {
if (req) {
req->buffer = bh->b_data;
SCpnt->request.sem = NULL; /* Wait until whole thing done */
}
- else
+ else
{
req->dev = -1;
*reqp = req->next;
/*
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;
-#ifdef DEBUG_DELAY
+ unsigned int flags;
+#ifdef DEBUG_DELAY
int clock;
#endif
host = SCpnt->host;
/*
- We will wait MIN_RESET_DELAY clock ticks after the last reset so
+ We will wait MIN_RESET_DELAY clock ticks after the last reset so
we can avoid the drive not being ready.
-*/
-temp = host->last_reset;
+*/
+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.
+ queuing and calling of completion function ourselves.
*/
#ifdef DEBUG
printk("internal_cmnd (host = %d, target = %d, command = %08x, buffer = %08x, \n"
"bufflen = %d, done = %08x)\n", SCpnt->host->host_no, 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 %08x\n",
+ printk("queuecommand : routine at %08x\n",
host->hostt->queuecommand);
#endif
/* This locking tries to prevent all sorts of races between
if(!intr_count && SCpnt->host->irq)
disable_irq(SCpnt->host->irq);
- host->hostt->queuecommand (SCpnt, scsi_done);
+ host->hostt->queuecommand (SCpnt, scsi_done);
if(!intr_count && SCpnt->host->irq)
enable_irq(SCpnt->host->irq);
printk("command() : routine at %08x\n", host->hostt->command);
#endif
temp=host->hostt->command (SCpnt);
- SCpnt->result = temp;
+ SCpnt->result = temp;
#ifdef DEBUG_DELAY
clock = jiffies + 400;
while (jiffies < clock);
printk("done(host = %d, result = %04x) : routine at %08x\n", host->host_no, temp, done);
#endif
- scsi_done(SCpnt);
- }
+ scsi_done(SCpnt);
+ }
#ifdef DEBUG
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[1] = SCpnt->lun << 5;
SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer);
SCpnt->request_buffer = &SCpnt->sense_buffer;
/*
- 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
+ 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 scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *),
- int timeout, int retries
+ int timeout, int retries
)
- {
+ {
unsigned long flags;
struct Scsi_Host * host = SCpnt->host;
#ifdef DEBUG
{
- int i;
+ int i;
int target = SCpnt->target;
printk ("scsi_do_cmd (host = %d, target = %d, buffer =%08x, "
"bufflen = %d, done = %08x, timeout = %d, retries = %d)\n"
"command : " , host->host_no, 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.
+ 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.
*/
- SCpnt->pid = scsi_pid++;
+ save_flags(flags);
+ cli();
+ SCpnt->pid = scsi_pid++;
+
+ while (SCSI_BLOCK(host)) {
+ restore_flags(flags);
+ SCSI_SLEEP(&host->host_wait, SCSI_BLOCK(host));
+ cli();
+ }
- for(;;) {
+ if (host->block) host_active = host;
+
+ host->host_busy++;
+ restore_flags(flags);
- save_flags(flags);
- cli();
-
- if (host->can_queue &&
- ((host->block && host_active && host != host_active) ||
- (host->block && host_next && host != host_next) ||
- host->host_busy >= host->can_queue)) {
-
- if (intr_count)
- panic("scsi: queueing to inactive host while in interrupt.\n");
-
- if (host->block && !host_next && host_active
- && host != host_active)
- host_next = host;
-
- restore_flags(flags);
- SCSI_SLEEP(&host->host_wait,
- ((host->block && host_active && host != host_active) ||
- (host->block && host_next && host != host_next) ||
- host->host_busy >= host->can_queue));
- }
-
- else {
- host->host_busy++;
-
- if (host->block) {
-
- if (!host_active) {
- max_active = 0;
- host_active = host;
- host_next = NULL;
- }
- else if (max_active > 7 && !host_next)
- host_next = host->block;
-
- max_active++;
- }
-
- restore_flags(flags);
- break;
- }
- }
/*
- 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
+ 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.
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. */
#ifdef DEBUG
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
+ 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.
*/
#ifdef DEBUG
printk("scsi: reset(%d)\n", SCpnt->host->host_no);
#endif
-
+
SCpnt->flags |= (WAS_RESET | IS_RESETTING);
scsi_reset(SCpnt);
-
+
#ifdef DEBUG
printk("performing request sense\n");
#endif
-
+
#if 0 /* FIXME - remove this when done */
if(SCpnt->flags & NEEDS_JUMPSTART) {
SCpnt->flags &= ~NEEDS_JUMPSTART;
};
#endif
}
-
-
+
+
static int check_sense (Scsi_Cmnd * SCpnt)
{
else
return SUGGEST_RETRY;
}
-
+
SCpnt->flags &= ~ASKED_FOR_SENSE;
#ifdef DEBUG_INIT
print_sense("", SCpnt);
printk("\n");
#endif
- if (SCpnt->sense_buffer[2] &0xe0)
+ if (SCpnt->sense_buffer[2] &0xe0)
return SUGGEST_ABORT;
switch (SCpnt->sense_buffer[2] & 0xf)
return SUGGEST_IS_OK;
case ABORTED_COMMAND:
- return SUGGEST_RETRY;
+ return SUGGEST_RETRY;
case NOT_READY:
case UNIT_ATTENTION:
return SUGGEST_ABORT;
- /* these three are not supported */
+ /* these three are not supported */
case COPY_ABORTED:
case VOLUME_OVERFLOW:
case MISCOMPARE:
-
+
case MEDIUM_ERROR:
return SUGGEST_REMAP;
case BLANK_CHECK:
/* 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->result = result = (result & 0xff00ffff) |
(SCpnt->abort_reason << 16);
SCpnt->cmd_len = SCpnt->old_cmd_len;
}
- switch (host_byte(result))
+ switch (host_byte(result))
{
case DID_OK:
if (status_byte(result) && (SCpnt->flags & WAS_SENSE))
if (!(SCpnt->flags & WAS_RESET))
{
- printk("scsi%d : target %d lun %d request sense failed, performing reset.\n",
+ printk("scsi%d : target %d lun %d request sense failed, performing reset.\n",
SCpnt->host->host_no, SCpnt->target, SCpnt->lun);
reset(SCpnt);
return;
SCpnt->flags &= ~WAS_SENSE;
SCpnt->internal_timeout &= ~SENSE_TIMEOUT;
-
+
switch (checked = check_sense(SCpnt))
{
case SUGGEST_SENSE:
- case 0:
+ case 0:
#ifdef DEBUG
printk("NO SENSE. status = REDO\n");
#endif
update_timeout(SCpnt, oldto);
status = REDO;
break;
- case SUGGEST_IS_OK:
+ case SUGGEST_IS_OK:
break;
- case SUGGEST_REMAP:
- case SUGGEST_RETRY:
+ case SUGGEST_REMAP:
+ case SUGGEST_RETRY:
#ifdef DEBUG
printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n");
#endif
exit = DRIVER_SENSE | SUGGEST_ABORT;
break;
default:
- printk ("Internal error %s %d \n", __FILE__,
+ printk ("Internal error %s %d \n", __FILE__,
__LINE__);
- }
- }
+ }
+ }
else
{
#ifdef DEBUG
exit = DRIVER_OK;
status = FINISHED;
}
- break;
+ break;
case CHECK_CONDITION:
switch (check_sense(SCpnt))
{
- case 0:
+ case 0:
update_timeout(SCpnt, oldto);
status = REDO;
break;
- case SUGGEST_REMAP:
+ case SUGGEST_REMAP:
case SUGGEST_RETRY:
status = MAYREDO;
exit = DRIVER_SENSE | SUGGEST_RETRY;
case SUGGEST_SENSE:
scsi_request_sense (SCpnt);
status = PENDING;
- break;
+ break;
}
- 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",
+ printk("scsi%d : RESERVATION CONFLICT performing reset.\n",
SCpnt->host->host_no);
reset(SCpnt);
return;
#endif
default:
printk ("Internal error %s %d \n"
- "status byte = %d \n", __FILE__,
+ "status byte = %d \n", __FILE__,
__LINE__, status_byte(result));
-
+
}
break;
default:
- panic("scsi: unsupported message byte %d received\n", msg_byte(result));
+ panic("scsi: unsupported message byte %d received\n", msg_byte(result));
}
break;
- case DID_TIME_OUT:
+ case DID_TIME_OUT:
#ifdef DEBUG
printk("Host returned DID_TIME_OUT - ");
#endif
{
#ifdef DEBUG
printk("Aborting\n");
-#endif
+#endif
exit = (DRIVER_TIMEOUT | SUGGEST_ABORT);
- }
- else
+ }
+ else
{
#ifdef DEBUG
printk ("Retrying.\n");
#endif
exit = (DRIVER_HARD | SUGGEST_ABORT);
break;
- case DID_ERROR:
+ 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:
+ break;
+ case DID_RESET:
if (SCpnt->flags & IS_RESETTING)
{
SCpnt->flags &= ~IS_RESETTING;
break;
}
- if(msg_byte(result) == GOOD &&
- status_byte(result) == CHECK_CONDITION) {
+ if(msg_byte(result) == GOOD &&
+ status_byte(result) == CHECK_CONDITION) {
switch (check_sense(SCpnt)) {
- case 0:
+ case 0:
update_timeout(SCpnt, oldto);
status = REDO;
break;
- case SUGGEST_REMAP:
+ case SUGGEST_REMAP:
case SUGGEST_RETRY:
status = MAYREDO;
exit = DRIVER_SENSE | SUGGEST_RETRY;
exit = DRIVER_SENSE | SUGGEST_ABORT;
break;
case SUGGEST_SENSE:
- scsi_request_sense (SCpnt);
- status = PENDING;
- break;
+ scsi_request_sense (SCpnt);
+ status = PENDING;
+ break;
}
} else {
- status=REDO;
- exit = SUGGEST_RETRY;
+ status=REDO;
+ exit = SUGGEST_RETRY;
}
- break;
- default :
+ break;
+ default :
exit = (DRIVER_ERROR | SUGGEST_DIE);
}
- switch (status)
+ switch (status)
{
case FINISHED:
case PENDING:
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
case REDO:
- if (host->block) scsi_maybe_deadlocked = 1;
-
- if (SCpnt->flags & WAS_SENSE)
- scsi_request_sense(SCpnt);
- else
+ if (SCpnt->flags & WAS_SENSE)
+ scsi_request_sense(SCpnt);
+ else
{
memcpy ((void *) SCpnt->cmnd,
- (void*) SCpnt->data_cmnd,
+ (void*) SCpnt->data_cmnd,
sizeof(SCpnt->data_cmnd));
SCpnt->request_buffer = SCpnt->buffer;
SCpnt->request_bufflen = SCpnt->bufflen;
SCpnt->cmd_len = SCpnt->old_cmd_len;
internal_cmnd (SCpnt);
};
- break;
- default:
+ break;
+ default:
INTERNAL_ERROR;
}
host->host_busy--; /* Indicate that we are free */
if (host->block && host->host_busy == 0) {
- struct Scsi_Host * block;
-
- block = host_next;
- host_active = NULL;
+ host_active = NULL;
- if (block) wake_up(&block->host_wait);
+ /* 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 (block = host->block; block != host; block = block->block)
- wake_up(&block->host_wait);
+ for (next = host->block; next != host; next = next->block)
+ wake_up(&next->host_wait);
+ }
- host_next = NULL;
-
- if (scsi_maybe_deadlocked) {
- scsi_maybe_deadlocked = 0;
- restart_all();
- }
-
- }
+ }
- wake_up(&host->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);
+ SCpnt->done (SCpnt);
}
#undef FINISHED
/*
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
+ 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
int oldto;
unsigned long flags;
struct Scsi_Host * host = SCpnt->host;
-
- while(1)
+
+ while(1)
{
save_flags(flags);
cli();
return 0;
}
- if (SCpnt->internal_timeout & IN_ABORT)
+ if (SCpnt->internal_timeout & IN_ABORT)
{
restore_flags(flags);
while (SCpnt->internal_timeout & IN_ABORT);
}
else
- {
+ {
SCpnt->internal_timeout |= IN_ABORT;
oldto = update_timeout(SCpnt, ABORT_TIMEOUT);
- if ((SCpnt->flags & IS_RESETTING) &&
+ 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);
}
-
+
restore_flags(flags);
if (!host->host_busy) {
SCpnt->internal_timeout &= ~IN_ABORT;
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->pid, SCpnt->host->host_no, (int) SCpnt->target, (int)
SCpnt->lun);
print_command (SCpnt->cmnd);
if (SCpnt->request.dev == -1 || pid != SCpnt->pid)
return 1;
}
}
- }
+ }
}
-
+
int scsi_reset (Scsi_Cmnd * SCpnt)
{
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);
#endif
else
{
SCpnt->internal_timeout |= IN_RESET;
- oldto = update_timeout(SCpnt, RESET_TIMEOUT);
-
+ 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) &&
+#if 0
+ if (!(SCpnt1->flags & IS_RESETTING) &&
!(SCpnt1->internal_timeout & IN_ABORT))
scsi_abort(SCpnt1, DID_RESET, SCpnt->pid);
#endif
SCpnt1 = SCpnt1->next;
};
- temp = host->hostt->reset(SCpnt);
- }
+ host->last_reset = jiffies;
+ temp = host->hostt->reset(SCpnt);
+ host->last_reset = jiffies;
+ }
else
{
- host->host_busy++;
-
- if (host->block) {
- host_active = host;
- host_next = NULL;
- }
-
+ if (!host->block) host->host_busy++;
restore_flags(flags);
+ host->last_reset = jiffies;
temp = host->hostt->reset(SCpnt);
host->last_reset = jiffies;
- host->host_busy--;
-
+ if (!host->block) host->host_busy--;
}
- if (host->block && host->host_busy == 0) {
- host_active = NULL;
- host_next = NULL;
- restart_all();
- }
-
-
#ifdef DEBUG
printk("scsi reset function returned %d\n", temp);
#endif
SCpnt->internal_timeout &= ~IN_RESET;
scsi_request_sense (SCpnt);
return 0;
- case SCSI_RESET_SNOOZE:
+ 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
default:
return 1;
}
-
- return temp;
+
+ return temp;
}
}
}
-
+
static void scsi_main_timeout(void)
{
struct Scsi_Host * host;
Scsi_Cmnd * SCpnt = NULL;
- do {
+ do {
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)
pid = SCpnt->pid;
restore_flags(flags);
scsi_times_out(SCpnt, pid);
- ++timed_out;
+ ++timed_out;
save_flags(flags);
cli();
}
};
- } while (timed_out);
+ } 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.
+ 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;
save_flags(flags);
cli();
-/*
- Figure out how much time has passed since the last time the timeouts
- were updated
+/*
+ Figure out how much time has passed since the last time the timeouts
+ were updated
*/
used = (time_start) ? (jiffies - time_start) : 0;
/*
Find out what is due to timeout soonest, and adjust all timeouts for
- the amount of time that has passed since the last time we called
- update_timeout.
+ the amount of time that has passed since the last time we called
+ update_timeout.
*/
-
+
oldto = 0;
if(SCset){
};
/*
- If something is due to timeout again, then we will set the next 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;
+ 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;
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){
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 ((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");
}
/*
- scsi_dev_init() is our initialization routine, which in turn calls host
- initialization, bus scanning, and sd/st initialization routines. It
+ 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().
*/
int i;
#ifdef FOO_ON_YOU
return;
-#endif
+#endif
/* Init a few things so we can "malloc" memory. */
scsi_loadable_module_flag = 0;
timer_table[SCSI_TIMER].expires = 0;
/* initialize all hosts */
- scsi_init();
-
+ scsi_init();
+
scsi_devices = (Scsi_Device *) NULL;
for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
printk("%d SCSI %s%s ", sdtpnt->dev_noticed, sdtpnt->name,
(sdtpnt->dev_noticed != 1) ? "s" : "");
printk("total.\n");
-
+
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->init && sdtpnt->dev_noticed) (*sdtpnt->init)();
SCpnt->old_use_sg = 0;
SCpnt->old_cmd_len = 0;
SCpnt->timeout = 0;
- SCpnt->underflow = 0;
- SCpnt->transfersize = 0;
+ SCpnt->underflow = 0;
+ SCpnt->transfersize = 0;
SCpnt->host_scribble = NULL;
host = SDpnt->host;
if(host->host_queue)
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) *
+ 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) {
dma_sectors = (dma_sectors + 15) & 0xfff0;
dma_free_sectors = dma_sectors; /* This must be a multiple of 16 */
- dma_malloc_freelist = (unsigned char *)
+ 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);
+ 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
for(sdtpnt = scsi_devicelist; sdtpnt; sdtpnt = sdtpnt->next)
if(sdtpnt->finish && sdtpnt->nr_dev)
(*sdtpnt->finish)();
-
+
scsi_loadable_module_flag = 1;
return scsi_init_memory_start;
}
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(" ");
- }
+ {
+ 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(" ");
- }
+ {
+ 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(" ");
- }
+ {
+ if (data[i] >= 0x20 && i < data[4] + 5)
+ printk("%c", data[i]);
+ else
+ printk(" ");
+ }
printk("\n");
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 */
+ Scsi_Devices entries */
for(shpnt=scsi_hostlist; shpnt; shpnt = shpnt->next)
if(shpnt->hostt == tpnt) scan_scsis(shpnt);
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) {
host = SDpnt->host;
-
+
if(SDpnt->type != TYPE_TAPE)
- new_dma_sectors += ((host->sg_tablesize *
- sizeof(struct scatterlist) + 511) >> 9) *
+ 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_need_isa_buffer++;
};
};
-
+
new_dma_sectors = (new_dma_sectors + 15) & 0xfff0;
- new_dma_malloc_freelist = (unsigned char *)
+ 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 **)
+
+ 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 *)
+ 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 */
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->finish)();
+ if(sdtpnt->finish && sdtpnt->nr_dev)
+ (*sdtpnt->finish)();
}
return 0;
}
* is trying to remove a low level scsi driver from the system.
*/
static void scsi_unregister_host(Scsi_Host_Template * tpnt)
-{
+{
Scsi_Host_Template * SHT, *SHTp;
Scsi_Device *sdpnt, * sdppnt, * sdpnt1;
Scsi_Cmnd * SCpnt;
return;
}
}
-
+
/* Next we free up the Scsi_Cmnd structures for this host */
for(sdpnt = scsi_devices; sdpnt; sdpnt = sdpnt->next)
sdpnt->host->host_queue = SCpnt;
if (SCpnt) SCpnt->prev = NULL;
}
-
+
/* Next free up the Scsi_Device structures for this host */
sdppnt = NULL;
that were detected */
shpnt = scsi_hostlist;
- while(shpnt) {
+ while(shpnt) {
sh1 = shpnt->next;
if(shpnt->hostt == tpnt) {
if(shpnt->loaded_as_module) {
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)
+ 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);
shpnt = sh1;
}
+ printk ("scsi : %d host%s.\n", next_scsi_host,
+ (next_scsi_host == 1) ? "" : "s");
+
+ 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;
}
#ifdef DEBUG_TIMEOUT
-static void
+static void
scsi_dump_status(void)
{
int i;
#define MODE_SELECT_10 0x55
#define MODE_SENSE_10 0x5a
+extern void scsi_make_blocked_list(void);
extern volatile int in_scan_scsis;
extern const unsigned char scsi_command_size[8];
#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7]
extern int max_scsi_hosts;
#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;
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);
if (CONDITION) { \
struct wait_queue wait = { current, NULL}; \
add_wait_queue(QUEUE, &wait); \
-sleep_repeat: \
+ for(;;) { \
current->state = TASK_UNINTERRUPTIBLE; \
if (CONDITION) { \
- schedule(); \
- goto sleep_repeat; \
+ 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; \
*
* - TOSHIBA: setting density is done here now, mounting PhotoCD's should
* work now without running the program "set_density"
- * People reported that it is necessary to eject and reinsert
- * the CD after the set-density call to get this working for
- * old drives.
- * And some very new drives don't need this call any more...
* Multisession CD's are supported too.
*
- * Dec 1994: completely rewritten, uses kernel_scsi_ioctl() now
- *
* kraxel@cs.tu-berlin.de (Gerd Knorr)
*/
-#define DEBUG
-
static void sr_photocd(struct inode *inode)
{
unsigned long sector,min,sec,frame;
if (rc != 0) {
printk("sr_photocd: ioctl error (NEC): 0x%x\n",rc);
sector = 0;
+ is_xa = 0;
} else {
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;
/* if rec[14] isn't 0xb0, the drive does not support multisession CD's, use zero */
sector = (0xb0 == rec[14]) ? min*CD_SECS*CD_FRAMES + sec*CD_FRAMES + frame : 0;
+ is_xa = (rec[14] == 0xb0);
#ifdef DEBUG
printk("NEC: (%2x) %2li:%02li:%02li = %li\n",buf[8+14],min,sec,frame,sector);
if (sector) {
if (rc != 0) {
printk("sr_photocd: ioctl error (TOSHIBA #1): 0x%x\n",rc);
sector = 0;
+ is_xa = 0;
break; /* if the first ioctl fails, we don't call the second one */
}
is_xa = (rec[0] == 0x20);
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;
printk("sr_photocd: unknown drive, no special multisession code\n");
#endif
sector = 0;
+ is_xa = 0;
break; }
scsi_CDs[MINOR(inode->i_rdev)].mpcd_sector = sector;
- /* The code above may have changed the sector size or capacity. */
- scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size = 1;
+ scsi_CDs[MINOR(inode->i_rdev)].is_xa = is_xa;
return;
}
-#undef DEBUG
-
static int sr_open(struct inode * inode, struct file * filp)
{
if(MINOR(inode->i_rdev) >= sr_template.nr_dev ||
unsigned sector_size; /* size in bytes */
Scsi_Device *device;
unsigned long mpcd_sector; /* for reading multisession-CD's */
+ char is_xa; /* is it an XA-CD ? */
unsigned char sector_bit_size; /* sector size = 2^sector_bit_size */
unsigned char sector_bit_shift; /* sectors/FS block = 2^sector_bit_shift*/
unsigned needs_sector_size:1; /* needs to get sector size */
ms_info.addr.lba=scsi_CDs[target].mpcd_sector;
else return (-EINVAL);
- if (scsi_CDs[target].mpcd_sector)
- ms_info.xa_flag=1; /* valid redirection address */
- else
- ms_info.xa_flag=0; /* invalid redirection address */
-
+ ms_info.xa_flag=scsi_CDs[target].is_xa;
+
err=verify_area(VERIFY_WRITE,(void *) arg,
sizeof(struct cdrom_multisession));
if (err) return (err);
/*
* u14-34f.c - Low-level driver for UltraStor 14F/34F SCSI host adapters.
*
+ * 8 Feb 1995 rev. 1.15 for linux 1.1.89
+ * Cleared target_time_out counter while preforming a reset.
+ *
* 28 Jan 1995 rev. 1.14 for linux 1.1.86
* Added module support.
* Log and do a retry when a disk drive returns a target status
*
* Multiple U14F and/or U34F host adapters are supported.
*
- * Released by Dario Ballabio (Dario_Ballabio@milano.europe.dg.com)
+ * Copyright (C) 1994, 1995 Dario Ballabio (dario@milano.europe.dg.com)
*
* WARNING: if your 14F board has an old firmware revision (see below)
* you must change "#undef" into "#define" in the following
#if defined(MODULE)
#include <linux/module.h>
+#include <linux/version.h>
#endif
#include <linux/string.h>
sti();
time = jiffies;
- while (jiffies < (time + 100) && limit++ < 100000000) sti();
+ while (jiffies < (time + 100) && limit++ < 100000000);
cli();
if (cpp->adapter_status || HD(j)->cp_stat[0] != FREE) {
sprintf(BN(j), "U34F%d", j);
}
else {
-
-#if !defined(MODULE)
- /* The module code does not checkin/checkout in the blocking list yet */
sh[j]->block = sh[j];
-#endif
#if defined (HAVE_OLD_U14F_FIRMWARE)
sh[j]->hostt->use_clustering = DISABLE_CLUSTERING;
port_base++;
}
+ if (j > 0)
+ printk("UltraStor 14F/34F: Copyright (C) 1994, 1995 Dario Ballabio.\n");
+
restore_flags(flags);
return j;
}
for (k = 0; k < MAX_TARGET; k++) HD(j)->target_reset[k] = TRUE;
+ for (k = 0; k < MAX_TARGET; k++) HD(j)->target_time_out[k] = 0;
+
for (i = 0; i < sh[j]->can_queue; i++) {
if (HD(j)->cp_stat[i] == FREE) continue;
HD(j)->in_reset = TRUE;
sti();
time = jiffies;
- while (jiffies < (time + 200) && limit++ < 100000000) sti();
+ while (jiffies < (time + 100) && limit++ < 100000000);
cli();
printk("%s: reset, interrupts disabled, loops %d.\n", BN(j), limit);
status = DID_BUS_BUSY << 16;
else if (tstatus == CHECK_CONDITION
- && (SCpnt->device->type == TYPE_DISK
- || SCpnt->device->type == TYPE_ROM)
+ && SCpnt->device->type == TYPE_DISK
&& (SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION)
status = DID_ERROR << 16;
if (tstatus == GOOD)
HD(j)->target_reset[SCpnt->target] = FALSE;
- if (spp->target_status && (SCpnt->device->type == TYPE_DISK
- || SCpnt->device->type == TYPE_ROM))
+ 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,
int u14_34f_reset(Scsi_Cmnd *);
int u14_34f_biosparam(Disk *, int, int *);
-#define U14_34F_VERSION "1.14.05"
+#define U14_34F_VERSION "1.15.00"
#define ULTRASTOR_14_34F { \
- NULL, \
- NULL, \
- "UltraStor 14F/34F rev. " U14_34F_VERSION " by " \
- "Dario_Ballabio@milano.europe.dg.com.", \
+ NULL, /* Ptr for modules */ \
+ NULL, /* usage count for modules */ \
+ "UltraStor 14F/34F rev. " U14_34F_VERSION " ", \
u14_34f_detect, \
- NULL, \
+ NULL, /* Release */ \
NULL, \
NULL, \
u14_34f_queuecommand, \
hannu@voxware.pp.fi
Snail mail: Hannu Savolainen
- Pallaksentie 4 A 2
- 00970 Helsinki
+ Hiekkalaiturintie 3 A 8
+ 00980 Helsinki
Finland
-FAX: +358 0 395 1968 (usually not connected)
+FAX: +358 0 341 6272 (answers if I have my machine (mgetty) on).
+
+NOTE! I propably don't answer to Snail mail or FAX messages. Sending answer
+ to each of them is simply too expensive and time consuming. However I
+ try to reply every email message I get (within a week). If you don't
+ get response, please check how your address is written in the message
+ header. I can't answer if I don't have a valid reply address.
return 1;
}
+
+static unsigned int isofs_get_last_session(int dev)
+{
+ struct cdrom_multisession ms_info;
+ unsigned int vol_desc_start;
+ struct inode inode_fake;
+ extern struct file_operations * get_blkfops(unsigned int);
+ int i;
+
+ /*
+ * look if the driver can tell the multi session redirection value
+ * <emoenke@gwdg.de>
+ */
+ vol_desc_start=0;
+ if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
+ {
+ inode_fake.i_rdev=dev;
+ ms_info.addr_format=CDROM_LBA;
+ set_fs(KERNEL_DS);
+ i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
+ NULL,
+ CDROMMULTISESSION,
+ (unsigned long) &ms_info);
+ set_fs(USER_DS);
+#if 0
+ printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
+ if (i==0)
+ {
+ printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
+ printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
+ }
+#endif 0
+ if ((i==0)&&(ms_info.xa_flag)) vol_desc_start=ms_info.addr.lba;
+ }
+ return vol_desc_start;
+}
+
struct super_block *isofs_read_super(struct super_block *s,void *data,
int silent)
{
unsigned int blocksize_bits;
int high_sierra;
int dev=s->s_dev;
- int i;
- struct cdrom_multisession ms_info;
unsigned int vol_desc_start;
- struct inode inode_fake;
- extern struct file_operations * get_blkfops(unsigned int);
+
struct iso_volume_descriptor *vdp;
struct hs_volume_descriptor *hdp;
s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */
- /*
- * look if the driver can tell the multi session redirection value
- * <emoenke@gwdg.de>
- */
- vol_desc_start=0;
- if (get_blkfops(MAJOR(dev))->ioctl!=NULL)
- {
- inode_fake.i_rdev=dev;
- ms_info.addr_format=CDROM_LBA;
- set_fs(KERNEL_DS);
- i=get_blkfops(MAJOR(dev))->ioctl(&inode_fake,
- NULL,
- CDROMMULTISESSION,
- (unsigned long) &ms_info);
- set_fs(USER_DS);
-#if 0
- printk("isofs.inode: CDROMMULTISESSION: rc=%d\n",i);
- if (i==0)
- {
- printk("isofs.inode: XA disk: %s\n", ms_info.xa_flag ? "yes":"no");
- printk("isofs.inode: vol_desc_start = %d\n", ms_info.addr.lba);
- }
-#endif 0
- if ((i==0)&&(ms_info.xa_flag)) vol_desc_start=ms_info.addr.lba;
- }
+ vol_desc_start = isofs_get_last_session(dev);
+
for (iso_blknum = vol_desc_start+16; iso_blknum < vol_desc_start+100; iso_blknum++) {
#if 0
- printk("isofs.inode: iso_blknum=%d\n", iso_blknum);
+ printk("isofs.inode: iso_blknum=%d\n", iso_blknum);
#endif 0
if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), opt.blocksize))) {
s->s_dev=0;
* ***FIXME*** should probably put this in nfs_fs.h */
#define NFS_SLACK_SPACE 1024
-
-extern struct socket *socki_lookup(struct inode *inode);
-
#define _S(nr) (1<<((nr)-1))
/*
file = server->file;
inode = file->f_inode;
select = file->f_op->select;
- sock = socki_lookup(inode);
+ sock = &inode->u.socket_i;
if (!sock) {
printk("nfs_rpc_call: socki_lookup failed\n");
return -EBADF;
return;
}
- printk("Ok, FDIV bug i%c86 system\n", '0'+x86);
+ printk("Hmm, FDIV bug i%c86 system\n", '0'+x86);
}
static void check_hlt(void)
/* cprefix.h: This file is included by assembly source which needs
* to know what the c-label prefixes are. The newer versions
* of cpp that come with gcc predefine such things to help
- * us out. The reason this stuff is neaded is to make
+ * us out. The reason this stuff is needed is to make
* solaris compiles of the kernel work.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
#define PCI_DEVICE_ID_DEC_TULIP 0x0002
#define PCI_DEVICE_ID_DEC_TULIP_FAST 0x0009
#define PCI_DEVICE_ID_DEC_FDDI 0x000F
+#define PCI_DEVICE_ID_DEC_BRD 0x0001
#define PCI_VENDOR_ID_MATROX 0x102B
+#define PCI_DEVICE_ID_MATROX_2plus 0x0518
#define PCI_VENDOR_ID_INTEL 0x8086
#define PCI_DEVICE_ID_INTEL_82378 0x0484
#define PCI_DEVICE_ID_AI_M1435 0x1435
#define PCI_VENDOR_ID_AL 0x10b9
-#define PCI_DEVICE_ID_AL_M1449 0x4449
+#define PCI_DEVICE_ID_AL_M1449 0x1449
#define PCI_DEVICE_ID_AL_M1451 0x1451
#define PCI_VENDOR_ID_TSENG 0x100c
#define PCI_DEVICE_ID_TSENG_W32P_2 0x3202
#define PCI_DEVICE_ID_TSENG_W32P_b 0x3205
-#define PCI_DEVICE_ID_TSENG_W32P_a 0x3207
+#define PCI_DEVICE_ID_TSENG_W32P_c 0x3207
#define PCI_VENDOR_ID_CMD 0x1095
#define PCI_DEVICE_ID_CMD_640 0x0640
#define PCI_VENDOR_ID_TRIDENT 0x1023
#define PCI_DEVICE_ID_TRIDENT_9420 0x9420
+#define PCI_DEVICE_ID_TRIDENT_9440 0x9440
#define PCI_VENDOR_ID_CONTAQ 0x1080
#define PCI_DEVICE_ID_CONTAQ_82C599 0x0600
#define PCI_DEVICE_ID_VIA_82C505 0x0505
#define PCI_VENDOR_ID_SI 0x1039
-#define PCI_DEVICE_ID_SI_MG1936 0x0406
-#define PCI_DEVICE_ID_SI_MG1938 0x0008
+#define PCI_DEVICE_ID_SI_496 0x0496
+#define PCI_DEVICE_ID_SI_501 0x0406
+#define PCI_DEVICE_ID_SI_503 0x0008
#define PCI_VENDOR_ID_LEADTEK 0x107d
#define PCI_DEVICE_ID_LEADTEK_805 0x0000
+#define PCI_VENDOR_ID_IMS 0x10e0
+#define PCI_DEVICE_ID_IMS_8849 0x8849
+
+#define PCI_VENDOR_ID_ZEINET 0x1193
+#define PCI_DEVICE_ID_ZEINET_1221 0x0001
+
+#define PCI_VENDOR_ID_EF 0x111a
+#define PCI_DEVICE_ID_EF_ATM 0x0000
+
+
struct pci_vendor_type {
unsigned short vendor_id;
char *vendor_name;
};
-#define PCI_VENDOR_NUM 30
+#define PCI_VENDOR_NUM 33
#define PCI_VENDOR_TYPE { \
{PCI_VENDOR_ID_NCR, "NCR"}, \
{PCI_VENDOR_ID_ADAPTEC, "Adaptec"}, \
{PCI_VENDOR_ID_NS, "NS"}, \
{PCI_VENDOR_ID_VIA, "VIA Technologies"}, \
{PCI_VENDOR_ID_SI, "Silicon Integrated"}, \
- {PCI_VENDOR_ID_LEADTEK, "Leadtek Research"} \
+ {PCI_VENDOR_ID_LEADTEK, "Leadtek Research"}, \
+ {PCI_VENDOR_ID_IMS, "IMS"}, \
+ {PCI_VENDOR_ID_ZEINET, "ZeiNet"}, \
+ {PCI_VENDOR_ID_EF, "Efficient Networks"} \
}
char *device_name;
};
-#define PCI_DEVICE_NUM 54
+#define PCI_DEVICE_NUM 61
#define PCI_DEVICE_TYPE { \
{0xff, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C810, "53c810"}, \
{0xff, PCI_VENDOR_ID_NCR, PCI_DEVICE_ID_NCR_53C815, "53c815"}, \
{0xff, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP, "DC21040"}, \
{0xff, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_TULIP_FAST, "DC21040"}, \
{0xff, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_FDDI, "DEFPA"}, \
+ {0xff, PCI_VENDOR_ID_DEC, PCI_DEVICE_ID_DEC_BRD, "DC21050"}, \
+ {0xff, PCI_VENDOR_ID_MATROX, PCI_DEVICE_ID_MATROX_2plus, "MGA/2+"}, \
{0xff, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82378, "82378IB"}, \
{0x00, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82424, "82424ZX Saturn"}, \
{0xff, PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82375, "82375EB"}, \
{0xff, PCI_VENDOR_ID_AL, PCI_DEVICE_ID_AL_M1451, "M1451"}, \
{0xff, PCI_VENDOR_ID_TSENG, PCI_DEVICE_ID_TSENG_W32P_2, "ET4000W32P"}, \
{0xff, PCI_VENDOR_ID_TSENG, PCI_DEVICE_ID_TSENG_W32P_b, "ET4000W32P rev B"}, \
- {0xff, PCI_VENDOR_ID_TSENG, PCI_DEVICE_ID_TSENG_W32P_a, "ET4000W32P rev A"}, \
+ {0xff, PCI_VENDOR_ID_TSENG, PCI_DEVICE_ID_TSENG_W32P_c, "ET4000W32P rev C"}, \
{0xff, PCI_VENDOR_ID_CMD, PCI_DEVICE_ID_CMD_640, "640A"}, \
{0xff, PCI_VENDOR_ID_VISION, PCI_DEVICE_ID_VISION_QD8500, "QD-8500PCI"}, \
{0xff, PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_LANCE, "79C970"}, \
{0xff, PCI_VENDOR_ID_ADL, PCI_DEVICE_ID_ADL_2301, "2301"}, \
{0xff, PCI_VENDOR_ID_SYMPHONY, PCI_DEVICE_ID_SYMPHONY_101, "82C101"}, \
{0xff, PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_9420, "TG 9420"}, \
+ {0xff, PCI_VENDOR_ID_TRIDENT, PCI_DEVICE_ID_TRIDENT_9440, "TG 9440"}, \
{0xff, PCI_VENDOR_ID_CONTAQ, PCI_DEVICE_ID_CONTAQ_82C599, "82C599"}, \
{0xff, PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C505, "VT 82C505"}, \
- {0xff, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_MG1936, "MG1936 ??"}, \
- {0xff, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_MG1938, "MG1938 ??"}, \
- {0xff, PCI_VENDOR_ID_LEADTEK, PCI_DEVICE_ID_LEADTEK_805, "S3 805"} \
+ {0xff, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_496, "85C496"}, \
+ {0xff, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_501, "85C501"}, \
+ {0xff, PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503, "85C503"}, \
+ {0xff, PCI_VENDOR_ID_LEADTEK, PCI_DEVICE_ID_LEADTEK_805, "S3 805"}, \
+ {0xff, PCI_VENDOR_ID_IMS, PCI_DEVICE_ID_IMS_8849, "8849"}, \
+ {0xff, PCI_VENDOR_ID_ZEINET, PCI_DEVICE_ID_ZEINET_1221, "1221"}, \
+ {0xff, PCI_VENDOR_ID_EF, PCI_DEVICE_ID_EF_ATM, "155P-MF1"} \
}
/* An item of this structure has the following meaning */
unsigned short close_delay;
char reserved_char[2];
int hub6;
- unsigned short closing_wait; /* time to wait before rcvr shutdown */
- unsigned short closing_wait2; /* time to wait after rcvr shutdown */
- int reserved[4];
+ int reserved[5];
};
-/*
- * For the close wait times, 0 means wait forever for serial port to
- * flush its output. 65535 means don't wait at all.
- */
-#define ASYNC_CLOSING_WAIT_INF 0
-#define ASYNC_CLOSING_WAIT_NONE 65535
-
/*
* These are the supported serial types.
*/
#define PORT_16450 2
#define PORT_16550 3
#define PORT_16550A 4
-#define PORT_CIRRUS 5 /* Hey! Who put this there? */
-#define PORT_16650 6
-#define PORT_MAX 6
+#define PORT_CIRRUS 5
+#define PORT_MAX 5
/*
* Definitions for async_struct (and serial_struct) flags field
int custom_divisor;
int x_char; /* xon/xoff character */
int close_delay;
- unsigned short closing_wait;
- unsigned short closing_wait2;
int IER; /* Interrupt Enable Register */
int MCR; /* Modem control register */
int MCR_noint; /* MCR with interrupts off */
#define UART_IER 1 /* Out: Interrupt Enable Register */
#define UART_IIR 2 /* In: Interrupt ID Register */
#define UART_FCR 2 /* Out: FIFO Control Register */
-#define UART_EFR 2 /* I/O: Extended Features Register */
- /* (DLAB=1, 16C660 only) */
#define UART_LCR 3 /* Out: Line Control Register */
#define UART_MCR 4 /* Out: Modem Control Register */
#define UART_LSR 5 /* In: Line Status Register */
/*
* These are the definitions for the FIFO Control Register
- * (16650 only)
*/
#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */
#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */
#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */
#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */
#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */
-/* 16650 redefinitions */
-#define UART_FCR6_R_TRIGGER_8 0x00 /* Mask for receive trigger set at 1 */
-#define UART_FCR6_R_TRIGGER_16 0x40 /* Mask for receive trigger set at 4 */
-#define UART_FCR6_R_TRIGGER_24 0x80 /* Mask for receive trigger set at 8 */
-#define UART_FCR6_R_TRIGGER_28 0xC0 /* Mask for receive trigger set at 14 */
-#define UART_FCR6_T_TRIGGER_16 0x00 /* Mask for transmit trigger set at 16 */
-#define UART_FCR6_T_TRIGGER_8 0x10 /* Mask for transmit trigger set at 8 */
-#define UART_FCR6_T_TRIGGER_24 0x20 /* Mask for transmit trigger set at 24 */
-#define UART_FCR6_T_TRIGGER_30 0x30 /* Mask for transmit trigger set at 30 */
/*
* These are the definitions for the Line Control Register
#define UART_MSR_DCTS 0x01 /* Delta CTS */
#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */
-/*
- * These are the definitions for the Extended Features Register
- * (StarTech 16C660 only, when DLAB=1)
- */
-#define UART_EFR_CTS 0x80 /* CTS flow control */
-#define UART_EFR_RTS 0x40 /* RTS flow control */
-#define UART_EFR_SCD 0x20 /* Special character detect */
-#define UART_EFR_ENI 0x10 /* Enhanced Interrupt */
-/*
- * the low four bits control software flow control
- */
-
#endif /* _LINUX_SERIAL_REG_H */
const char *routine);
extern char *_tty_name(struct tty_struct *tty, char *buf);
extern char *tty_name(struct tty_struct *tty);
-extern void wait_until_sent(struct tty_struct * tty, int timeout);
+extern void tty_wait_until_sent(struct tty_struct * tty, int timeout);
extern int tty_check_change(struct tty_struct * tty);
extern void stop_tty(struct tty_struct * tty);
extern void start_tty(struct tty_struct * tty);
* wake up processes that were waiting for semval to go to 0 if the
* value went to 0 and was then incremented rapidly enough. In solving
* this problem I have also modified the implementation so that it
- * processes pending operations in a FIFO manner, thus give a guarentee
+ * processes pending operations in a FIFO manner, thus give a guarantee
* that processes waiting for a lock on the semaphore won't starve
* unless another locking process fails to unlock.
* In addition the following two changes in behavior have been introduced:
* have read permissions. The implementation now returns 0
* on success as stated in the manual page.
* - There is some confusion over whether the set of undo adjustments
- * to be peformed at exit should be done in an atomic manner.
+ * to be performed at exit should be done in an atomic manner.
* That is, if we are attempting to decrement the semval should we queue
* up and wait until we can do so legally?
* The original implementation attempted to do this.
X(register_serial),
X(unregister_serial),
+ /* tty routines */
+ X(tty_hangup),
+ X(tty_wait_until_sent),
+ X(tty_check_change),
+ X(tty_hung_up_p),
+
/* filesystem registration */
X(register_filesystem),
X(unregister_filesystem),
return 0;
}
+static inline void forget_pte(pte_t page)
+{
+ if (pte_none(page))
+ return;
+ if (pte_present(page)) {
+ free_page(pte_page(page));
+ if (mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED)
+ return;
+ if (current->mm->rss <= 0)
+ return;
+ current->mm->rss--;
+ return;
+ }
+ swap_free(pte_val(page));
+}
+
+static inline void unmap_pte_range(pmd_t * pmd, unsigned long address, unsigned long size)
+{
+ pte_t * pte;
+ unsigned long end;
+
+ if (pmd_none(*pmd))
+ return;
+ if (pmd_bad(*pmd)) {
+ printk("unmap_pte_range: bad pmd (%08lx)\n", pmd_val(*pmd));
+ pmd_clear(pmd);
+ return;
+ }
+ pte = pte_offset(pmd, address);
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end >= PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ pte_t page = *pte;
+ pte_clear(pte);
+ forget_pte(page);
+ address += PAGE_SIZE;
+ pte++;
+ } while (address < end);
+}
+
+static inline void unmap_pmd_range(pgd_t * dir, unsigned long address, unsigned long size)
+{
+ pmd_t * pmd;
+ unsigned long end;
+
+ if (pgd_none(*dir))
+ return;
+ if (pgd_bad(*dir)) {
+ printk("unmap_pmd_range: bad pgd (%08lx)\n", pgd_val(*dir));
+ pgd_clear(dir);
+ return;
+ }
+ pmd = pmd_offset(dir, address);
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ do {
+ unmap_pte_range(pmd, address, end - address);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+}
+
/*
* a more complete version of free_page_tables which performs with page
* granularity.
*/
-int unmap_page_range(unsigned long from, unsigned long size)
+int unmap_page_range(unsigned long address, unsigned long size)
{
- pgd_t page_dir, * dir;
- pte_t page, * page_table;
- unsigned long poff, pcnt, pc;
-
- if (from & ~PAGE_MASK) {
- printk("unmap_page_range called with wrong alignment\n");
- return -EINVAL;
- }
- size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
- dir = PAGE_DIR_OFFSET(current,from);
- poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
- if ((pcnt = PTRS_PER_PAGE - poff) > size)
- pcnt = size;
+ pgd_t * dir;
+ unsigned long end = address + size;
- for ( ; size > 0; ++dir, size -= pcnt,
- pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) {
- page_dir = *dir;
- if (pgd_none(page_dir)) {
- poff = 0;
- continue;
- }
- if (pgd_bad(page_dir)) {
- printk("unmap_page_range: bad page directory.");
- continue;
- }
- page_table = (pte_t *) pgd_page(page_dir);
- if (poff) {
- page_table += poff;
- poff = 0;
- }
- for (pc = pcnt; pc--; page_table++) {
- page = *page_table;
- if (!pte_none(page)) {
- pte_clear(page_table);
- if (pte_present(page)) {
- if (!(mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED))
- if (current->mm->rss > 0)
- --current->mm->rss;
- free_page(pte_page(page));
- } else
- swap_free(pte_val(page));
- }
- }
- if (pcnt == PTRS_PER_PAGE) {
- pgd_clear(dir);
- free_page(pgd_page(page_dir));
- }
+ dir = pgd_offset(current, address);
+ while (address < end) {
+ unmap_pmd_range(dir, address, end - address);
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
}
invalidate();
return 0;
}
-int zeromap_page_range(unsigned long from, unsigned long size, pgprot_t prot)
+static inline void zeromap_pte_range(pte_t * pte, unsigned long address, unsigned long size, pte_t zero_pte)
+{
+ unsigned long end;
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ do {
+ pte_t oldpage = *pte;
+ *pte = zero_pte;
+ forget_pte(oldpage);
+ address += PAGE_SIZE;
+ pte++;
+ } while (address < end);
+}
+
+static inline int zeromap_pmd_range(pmd_t * pmd, unsigned long address, unsigned long size, pte_t zero_pte)
{
+ unsigned long end;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ do {
+ pte_t * pte = pte_alloc(pmd, address);
+ if (!pte)
+ return -ENOMEM;
+ zeromap_pte_range(pte, address, end - address, zero_pte);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address < end);
+ return 0;
+}
+
+int zeromap_page_range(unsigned long address, unsigned long size, pgprot_t prot)
+{
+ int error = 0;
pgd_t * dir;
- pte_t * page_table;
- unsigned long poff, pcnt;
+ unsigned long end = address + size;
pte_t zero_pte;
- if (from & ~PAGE_MASK) {
- printk("zeromap_page_range: from = %08lx\n",from);
- return -EINVAL;
- }
zero_pte = pte_wrprotect(mk_pte(ZERO_PAGE, prot));
- dir = PAGE_DIR_OFFSET(current,from);
- size = (size + ~PAGE_MASK) >> PAGE_SHIFT;
- poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
- if ((pcnt = PTRS_PER_PAGE - poff) > size)
- pcnt = size;
-
- while (size > 0) {
- if (!pgd_present(*dir)) {
- if (!(page_table = (pte_t *) get_free_page(GFP_KERNEL))) {
- invalidate();
- return -ENOMEM;
- }
- if (pgd_present(*dir)) {
- free_page((unsigned long) page_table);
- page_table = (pte_t *) pgd_page(*dir);
- } else
- pgd_set(dir, page_table);
- } else
- page_table = (pte_t *) pgd_page(*dir);
+ dir = pgd_offset(current, address);
+ while (address < end) {
+ pmd_t *pmd = pmd_alloc(dir, address);
+ error = -ENOMEM;
+ if (!pmd)
+ break;
+ error = zeromap_pmd_range(pmd, address, end - address, zero_pte);
+ if (error)
+ break;
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
- page_table += poff;
- poff = 0;
- for (size -= pcnt; pcnt-- ;) {
- pte_t page = *page_table;
- if (!pte_none(page)) {
- pte_clear(page_table);
- if (pte_present(page)) {
- if (!(mem_map[MAP_NR(pte_page(page))] & MAP_PAGE_RESERVED))
- if (current->mm->rss > 0)
- --current->mm->rss;
- free_page(pte_page(page));
- } else
- swap_free(pte_val(page));
- }
- *page_table++ = zero_pte;
- }
- pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size);
}
invalidate();
- return 0;
+ return error;
}
/*
* Add better route to host.
* But first check that the redirect
* comes from the old gateway..
+ * And make sure it's an ok host address
+ * (not some confused thing sending our
+ * address)
*/
rt = ip_rt_route(ip, NULL, NULL);
if (!rt)
break;
- if (rt->rt_gateway != source)
+ if (rt->rt_gateway != source || ip_chk_addr(icmph->un.gateway))
break;
printk("redirect from %s\n", in_ntoa(source));
ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY),
} /* End of whole function */
#endif /* CONFIG_IP_ACCT */
-#ifdef CONFIG_IP_ACCT
+#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
static void zero_fw_chain(struct ip_fw *chainptr)
{
}
}
-#endif
-
-#if defined(CONFIG_IP_ACCT) || defined(CONFIG_IP_FIREWALL)
-
static void free_fw_chain(struct ip_fw *volatile* chainptr)
{
unsigned long flags;
{
struct sk_buff *skb;
- while ((skb = skb_dequeue(&sk->receive_queue)) != NULL) {
+ while ((skb = skb_dequeue(&sk->receive_queue)) != NULL)
+ {
+ skb->sk->dead=1;
tcp_close(skb->sk, 0);
kfree_skb(skb, FREE_READ);
}
{
sk->err = ETIMEDOUT;
sk->error_report(sk);
+ del_timer(&sk->retransmit_timer);
/*
* Time wait the socket
*/
- if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING)
+ if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 || sk->state == TCP_CLOSING )
{
tcp_set_state(sk,TCP_TIME_WAIT);
reset_msl_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN);
{
sk->err = -ENOMEM;
newsk->dead = 1;
+ newsk->state = TCP_CLOSE;
+ /* And this will destroy it */
release_sock(newsk);
kfree_skb(skb, FREE_READ);
tcp_statistics.TcpAttemptFails++;
buff->free = 1;
kfree_skb(buff,FREE_WRITE);
newsk->dead = 1;
+ newsk->state = TCP_CLOSE;
release_sock(newsk);
skb->sk = sk;
kfree_skb(skb, FREE_READ);
tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk);
newsk->prot->queue_xmit(newsk, ndev, buff, 0);
- reset_xmit_timer(newsk, TIME_WRITE, newsk->rto);
-
reset_xmit_timer(newsk, TIME_WRITE , TCP_TIMEOUT_INIT);
skb->sk = newsk;