diff -u --recursive --new-file v1.1.24/linux/Makefile linux/Makefile --- v1.1.24/linux/Makefile Thu Jul 7 21:37:11 1994 +++ linux/Makefile Thu Jul 7 14:59:35 1994 @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 1 -SUBLEVEL = 24 +SUBLEVEL = 25 all: Version zImage @@ -39,6 +39,12 @@ ROOT_DEV = CURRENT # +# INSTALL_PATH specifies where to place the updated kernel and system map +# images. Uncomment if you want to place them anywhere other than root. + +#INSTALL_PATH=/boot + +# # If you want to preset the SVGA mode, uncomment the next line and # set SVGA_MODE to whatever number you want. # Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. @@ -188,10 +194,10 @@ dd bs=8192 if=zImage of=/dev/fd0 zlilo: $(CONFIGURE) zImage - if [ -f /vmlinuz ]; then mv /vmlinuz /vmlinuz.old; fi - if [ -f /zSystem.map ]; then mv /zSystem.map /zSystem.old; fi - cat zImage > /vmlinuz - cp zSystem.map / + if [ -f $(INSTALL_PATH)/vmlinuz ]; then mv $(INSTALL_PATH)/vmlinuz $(INSTALL_PATH)/vmlinuz.old; fi + if [ -f $(INSTALL_PATH)/zSystem.map ]; then mv $(INSTALL_PATH)/zSystem.map $(INSTALL_PATH)/zSystem.old; fi + cat zImage > $(INSTALL_PATH)/vmlinuz + cp zSystem.map $(INSTALL_PATH)/ if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs diff -u --recursive --new-file v1.1.24/linux/config.in linux/config.in --- v1.1.24/linux/config.in Mon Jun 27 16:46:57 1994 +++ linux/config.in Thu Jul 7 19:11:44 1994 @@ -80,6 +80,8 @@ # bool ' SLIP debugging on' SL_DUMP y fi bool 'PPP (point-to-point) support' CONFIG_PPP n +bool 'PLIP (parallel port) support' CONFIG_PLIP n +bool 'SK_G16 support' CONFIG_SK_G16 n bool 'Load balancing support (experimental)' CONFIG_SLAVE_BALANCING n bool 'Do you want to be offered ALPHA test drivers' CONFIG_NET_ALPHA n bool 'Western Digital/SMC cards' CONFIG_NET_VENDOR_SMC n @@ -104,15 +106,14 @@ bool 'DEPCA support' CONFIG_DEPCA n if [ "$CONFIG_NET_ALPHA" = "y" ]; then bool 'EtherExpress support' CONFIG_EEXPRESS n + bool 'AT1700 support' CONFIG_AT1700 n fi bool 'HP PCLAN support' CONFIG_HPLAN n bool 'NE2000/NE1000 support' CONFIG_NE2000 n fi -bool 'PLIP (parallel port) support' CONFIG_PLIP n bool 'EISA and on board controllers' CONFIG_NET_EISA n if [ "$CONFIG_NET_ALPHA" = "y" ]; then bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n - bool 'AT1700 support' CONFIG_AT1700 n fi bool 'Apricot Xen-II on board ethernet' CONFIG_APRICOT n #bool 'NI52EE support' CONFIG_NI52 n diff -u --recursive --new-file v1.1.24/linux/drivers/block/cdu31a.c linux/drivers/block/cdu31a.c --- v1.1.24/linux/drivers/block/cdu31a.c Tue Jun 21 14:16:19 1994 +++ linux/drivers/block/cdu31a.c Thu Jul 7 18:22:08 1994 @@ -64,6 +64,58 @@ * */ +/* + * + * Setting up the Sony CDU31A/CDU33A drive interface card. If + * You have another card, you are on your own. + * + * +----------+-----------------+----------------------+ + * | JP1 | 34 Pin Conn | | + * | JP2 +-----------------+ | + * | JP3 | + * | JP4 | + * | +--+ + * | | +-+ + * | | | | External + * | | | | Connector + * | | | | + * | | +-+ + * | +--+ + * | | + * | +--------+ + * | | + * +------------------------------------------+ + * + * JP1 sets the Base Address, using the following settings: + * + * Address Pin 1 Pin 2 + * ------- ----- ----- + * 0x320 Short Short + * 0x330 Short Open + * 0x340 Open Short + * 0x360 Open Open + * + * JP2 and JP3 configure the DMA channel; they must be set the same. + * + * DMA Pin 1 Pin 2 Pin 3 + * --- ----- ----- ----- + * 1 On Off On + * 2 Off On Off + * 3 Off Off On + * + * JP4 Configures the IRQ: + * + * IRQ Pin 1 Pin 2 Pin 3 Pin 4 + * --- ----- ----- ----- ----- + * 3 Off Off On Off + * 4 Off Off* Off On + * 5 On Off Off Off + * 6 Off On Off Off + * + * * The documentation states to set this for interrupt + * 4, but I think that is a mistake. + */ + #include #include #include @@ -110,6 +162,8 @@ { 0x360, -1, 0 }, /* Secondary standard Sony Interface */ { 0x320, -1, 0 }, /* Secondary standard Sony Interface */ { 0x330, -1, 0 }, /* Secondary standard Sony Interface */ + { 0x634, -1, 0 }, /* Sound FX SC400 */ + { 0x654, -1, 0 }, /* Sound FX SC400 */ { 0 } }; @@ -201,6 +255,8 @@ static int curr_control_reg = 0; /* Current value of the control register */ +#if 1 /* This will go away as soon as the isofs code is fixed + to use the fops struct. */ /* * This routine returns 1 if the disk has been changed since the last * check or 0 if it hasn't. Setting flag to 0 resets the changed flag. @@ -226,6 +282,30 @@ return retval; } +#endif + +/* + * This routine returns 1 if the disk has been changed since the last + * check or 0 if it hasn't. Setting flag to 0 resets the changed flag. + */ +static int +scd_disk_change(dev_t full_dev) +{ + int retval, target; + + + target = MINOR(full_dev); + + if (target > 0) { + printk("Sony CD-ROM request error: invalid device.\n"); + return 0; + } + + retval = sony_disc_changed; + sony_disc_changed = 0; + + return retval; +} static inline void enable_interrupts(void) @@ -1823,7 +1903,10 @@ NULL, /* mmap */ scd_open, /* open */ scd_release, /* release */ - NULL /* fsync */ + NULL, /* fsync */ + NULL, /* fasync */ + scd_disk_change, /* media_change */ + NULL /* revalidate */ }; diff -u --recursive --new-file v1.1.24/linux/drivers/block/floppy.c linux/drivers/block/floppy.c --- v1.1.24/linux/drivers/block/floppy.c Thu Jul 7 21:37:11 1994 +++ linux/drivers/block/floppy.c Thu Jul 7 19:09:36 1994 @@ -74,6 +74,8 @@ #define FLOPPY_DMA 2 #define FDC_FIFO_UNTESTED /* -bb */ +#define FDC_FIFO_BUG + #include #include #include @@ -287,8 +289,8 @@ static void floppy_ready(void); static void recalibrate_floppy(void); -static int floppy_grab_irq_and_dma(void); -static void floppy_release_irq_and_dma(void); +int floppy_grab_irq_and_dma(void); +void floppy_release_irq_and_dma(void); /* * These are global variables, as that's the easiest way to give @@ -506,6 +508,32 @@ printk("Unable to send byte to FDC\n"); } +#ifdef FDC_FIFO_BUG + +static void output_byte_force(char byte) +{ + int counter; + unsigned char status; + + if (reset) + return; + for (counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS); + if ((status & (STATUS_READY | STATUS_DIR)) == STATUS_READY) { + outb(byte,FD_DATA); + return; + } + if ((status & (STATUS_READY | STATUS_BUSY)) == (STATUS_READY | STATUS_BUSY)) { + outb(byte,FD_DATA); + return; + } + } + current_track = NO_TRACK; + reset = 1; + printk("Unable to send byte to FDC\n"); +} +#endif /* FDC_FIFO_BUG */ + static int result(void) { int i = 0, counter, status; @@ -565,15 +593,27 @@ if (rate & 0x40) { unsigned char r = rate & 0x03; if (r == 0) +#ifndef FDC_FIFO_BUG output_byte(2); /* perpendicular, 500 kbps */ +#else + output_byte_force(2); /* perpendicular, 500 kbps */ +#endif else if (r == 3) +#ifndef FDC_FIFO_BUG output_byte(3); /* perpendicular, 1Mbps */ +#else + output_byte_force(3); /* perpendicular, 1Mbps */ +#endif else { printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n"); reset = 1; } } else +#ifndef FDC_FIFO_BUG output_byte(0); /* conventional mode */ +#else + output_byte_force(0); /* conventional mode */ +#endif } else { if (rate & 0x40) { printk(DEVICE_NAME ": perpendicular mode not supported by this FDC.\n"); @@ -594,9 +634,17 @@ if (need_configure && (fdc_version == FDC_TYPE_82077)) { /* Enhanced version with FIFO & vertical recording. */ output_byte(FD_CONFIGURE); +#ifndef FDC_FIFO_BUG output_byte(0); +#else + output_byte_force(0); +#endif output_byte(0x1A); /* FIFO on, polling off, 10 byte threshold */ +#ifndef FDC_FIFO_BUG output_byte(0); /* precompensation from track 0 upwards */ +#else + output_byte_force(0); /* precompensation from track 0 upwards */ +#endif need_configure = 0; printk(DEVICE_NAME ": FIFO enabled\n"); } @@ -1403,7 +1451,7 @@ static int usage_count = 0; -static int floppy_grab_irq_and_dma(void) +int floppy_grab_irq_and_dma(void) { if (usage_count++) return 0; @@ -1420,7 +1468,7 @@ return 0; } -static void floppy_release_irq_and_dma(void) +void floppy_release_irq_and_dma(void) { if (--usage_count) return; diff -u --recursive --new-file v1.1.24/linux/drivers/block/mcd.c linux/drivers/block/mcd.c --- v1.1.24/linux/drivers/block/mcd.c Tue May 24 08:47:06 1994 +++ linux/drivers/block/mcd.c Thu Jul 7 21:26:20 1994 @@ -30,6 +30,13 @@ (Jon Tombs ) 0.3.3 Added more #defines and mcd_setup() (Jon Tombs ) + + October 1993 Bernd Huebner and Ruediger Helsch, Unifix Software GmbH, + Braunschweig, Germany: Total rework to speed up data read operation. + Also enabled definition of irq and address from bootstrap, using the + environment. linux/init/main.c must be patched to export the env. + November 93 added code for FX001 S,D (single & double speed). + February 94 added code for broken M 5/6 series of 16-bit single speed. */ @@ -41,6 +48,8 @@ #include #include #include +#include +#include /* #define REALLY_SLOW_IO */ #include @@ -57,8 +66,53 @@ static int mcdPresent = 0; -static char mcd_buf[2048]; /* buffer for block size conversion */ -static int mcd_bn = -1; +#if 0 +#define TEST1 /* */ +#define TEST2 /* do_mcd_req */ +#define TEST3 */ /* MCD_S_state */ +#define TEST4 /* QUICK_LOOP-counter */ +#define TEST5 */ /* port(1) state */ +#endif + +#if 1 +#define QUICK_LOOP_DELAY udelay(45) /* use udelay */ +#define QUICK_LOOP_COUNT 20 +#else +#define QUICK_LOOP_DELAY +#define QUICK_LOOP_COUNT 140 /* better wait constant time */ +#endif +/* #define DOUBLE_QUICK_ONLY */ + +#define CURRENT_VALID \ + (CURRENT && MAJOR(CURRENT -> dev) == MAJOR_NR && CURRENT -> cmd == READ \ + && CURRENT -> sector != -1) +#define MFL_STATUSorDATA (MFL_STATUS | MFL_DATA) +#define MCD_BUF_SIZ 16 +static volatile int mcd_transfer_is_active; +static char mcd_buf[2048*MCD_BUF_SIZ]; /* buffer for block size conversion */ +static volatile int mcd_buf_bn[MCD_BUF_SIZ], mcd_next_bn; +static volatile int mcd_buf_in, mcd_buf_out = -1; +static volatile int mcd_error; +static int mcd_open_count; +enum mcd_state_e { + MCD_S_IDLE, /* 0 */ + MCD_S_START, /* 1 */ + MCD_S_MODE, /* 2 */ + MCD_S_READ, /* 3 */ + MCD_S_DATA, /* 4 */ + MCD_S_STOP, /* 5 */ + MCD_S_STOPPING /* 6 */ +}; +static volatile enum mcd_state_e mcd_state = MCD_S_IDLE; +static int mcd_mode = -1; +static int MCMD_DATA_READ= MCMD_PLAY_READ; +#define READ_TIMEOUT 3000 +#define WORK_AROUND_MITSUMI_BUG_92 +#define WORK_AROUND_MITSUMI_BUG_93 +#ifdef WORK_AROUND_MITSUMI_BUG_93 +int mitsumi_bug_93_wait = 0; +#endif /* WORK_AROUND_MITSUMI_BUG_93 */ + static short mcd_port = MCD_BASE_ADDR; static int mcd_irq = MCD_INTR_NR; @@ -75,10 +129,8 @@ static char mcdVersion; static void mcd_transfer(void); -static void mcd_start(void); -static void mcd_status(void); -static void mcd_read_cmd(void); -static void mcd_data(void); +static void mcd_poll(void); +static void mcd_invalidate_buffers(void); static void do_mcd_request(void); static void hsg2msf(long hsg, struct msf *msf); static void bin2bcd(unsigned char *p); @@ -99,6 +151,10 @@ mcd_port = ints[1]; if (ints[0] > 1) mcd_irq = ints[2]; +#ifdef WORK_AROUND_MITSUMI_BUG_93 + if (ints[0] > 2) + mitsumi_bug_93_wait = ints[3]; +#endif /* WORK_AROUND_MITSUMI_BUG_93 */ } @@ -507,16 +563,34 @@ static void mcd_transfer(void) { - long offs; - - while (CURRENT -> nr_sectors > 0 && mcd_bn == CURRENT -> sector / 4) - { - offs = (CURRENT -> sector & 3) * 512; - memcpy(CURRENT -> buffer, mcd_buf + offs, 512); - CURRENT -> nr_sectors--; - CURRENT -> sector++; - CURRENT -> buffer += 512; - } + if (CURRENT_VALID) { + while (CURRENT -> nr_sectors) { + int bn = CURRENT -> sector / 4; + int i; + for (i = 0; i < MCD_BUF_SIZ && mcd_buf_bn[i] != bn; ++i) + ; + if (i < MCD_BUF_SIZ) { + int offs = (i * 4 + (CURRENT -> sector & 3)) * 512; + int nr_sectors = 4 - (CURRENT -> sector & 3); + if (mcd_buf_out != i) { + mcd_buf_out = i; + if (mcd_buf_bn[i] != bn) { + mcd_buf_out = -1; + continue; + } + } + if (nr_sectors > CURRENT -> nr_sectors) + nr_sectors = CURRENT -> nr_sectors; + memcpy(CURRENT -> buffer, mcd_buf + offs, nr_sectors * 512); + CURRENT -> nr_sectors -= nr_sectors; + CURRENT -> sector += nr_sectors; + CURRENT -> buffer += nr_sectors * 512; + } else { + mcd_buf_out = -1; + break; + } + } + } } @@ -531,220 +605,419 @@ int st; st = inb(MCDPORT(1)) & 0xFF; - if (st != 0xFF) +#ifdef TEST1 + printk("", st); +#endif + if (!(st & MFL_STATUS)) { st = inb(MCDPORT(0)) & 0xFF; -#if 0 - printk("", st); +#ifdef TEST1 + printk("", st); #endif + if ((st & 0xFF) != 0xFF) + mcd_error = st ? st & 0xFF : -1; } } -/* - * I/O request routine called from Linux kernel. - */ - static void do_mcd_request(void) { - unsigned int block,dev; - unsigned int nsect; +#ifdef TEST2 + printk(" do_mcd_request(%ld+%ld)\n", CURRENT -> sector, CURRENT -> nr_sectors); +#endif + mcd_transfer_is_active = 1; + while (CURRENT_VALID) { + if (CURRENT->bh) { + if (!CURRENT->bh->b_lock) + panic(DEVICE_NAME ": block not locked"); + } + mcd_transfer(); + if (CURRENT -> nr_sectors == 0) { + end_request(1); + } else { + mcd_buf_out = -1; /* Want to read a block not in buffer */ + if (mcd_state == MCD_S_IDLE) { + if (!tocUpToDate) { + if (updateToc() < 0) { + while (CURRENT_VALID) + end_request(0); + break; + } + } + mcd_state = MCD_S_START; + McdTries = 5; + SET_TIMER(mcd_poll, 1); + } + break; + } + } + mcd_transfer_is_active = 0; +#ifdef TEST2 + printk(" do_mcd_request ends\n"); +#endif +} -repeat: - if (!(CURRENT) || CURRENT->dev < 0) return; - INIT_REQUEST; - dev = MINOR(CURRENT->dev); - block = CURRENT->sector; - nsect = CURRENT->nr_sectors; - if (CURRENT == NULL || CURRENT -> sector == -1) - return; - if (CURRENT -> cmd != READ) - { - printk("mcd: bad cmd %d\n", CURRENT -> cmd); - end_request(0); - goto repeat; +static void +mcd_poll(void) +{ + int st; + + + if (mcd_error) { + if (mcd_error & 0xA5) { + printk("mcd: I/O error 0x%02x", mcd_error); + if (mcd_error & 0x80) + printk(" (Door open)"); + if (mcd_error & 0x20) + printk(" (Disk changed)"); + if (mcd_error & 0x04) + printk(" (Read error)"); + printk("\n"); + mcd_invalidate_buffers(); +#ifdef WARN_IF_READ_FAILURE + if (McdTries == 5) + printk("mcd: read of block %d failed\n", mcd_next_bn); +#endif + if (!McdTries--) { + printk("mcd: read of block %d failed, giving up\n", mcd_next_bn); + if (mcd_transfer_is_active) { + McdTries = 0; + goto ret; } + if (CURRENT_VALID) + end_request(0); + McdTries = 5; + } + } + mcd_error = 0; + mcd_state = MCD_S_STOP; + } - mcd_transfer(); - /* if we satisfied the request from the buffer, we're done. */ - if (CURRENT -> nr_sectors == 0) - { - end_request(1); - goto repeat; - } + immediatly: + switch (mcd_state) { - McdTries = MCD_RETRY_ATTEMPTS; - mcd_start(); -} -/* - * Start the I/O for the cdrom. Handle retry count. - */ + case MCD_S_IDLE: +#ifdef TEST3 + printk("MCD_S_IDLE\n"); +#endif + return; -static void -mcd_start() -{ - if (McdTries == 0) - { - printk("mcd: read failed after %d tries\n", MCD_RETRY_ATTEMPTS); - end_request(0); - SET_TIMER(do_mcd_request, 1); /* wait a bit, try again */ - return; - } - McdTries--; - outb(0x40, MCDPORT(0)); /* get status */ - McdTimeout = MCD_STATUS_DELAY; - SET_TIMER(mcd_status, 1); -} + case MCD_S_START: +#ifdef TEST3 + printk("MCD_S_START\n"); +#endif -/* - * Called from the timer to check the results of the get-status cmd. - * On success, send the set-mode command. - */ + outb(MCMD_GET_STATUS, MCDPORT(0)); + mcd_state = mcd_mode == 1 ? MCD_S_READ : MCD_S_MODE; + McdTimeout = 3000; + break; -static void -mcd_status() -{ - int st; - McdTimeout--; - st = mcdStatus(); - if (st == -1) - { - if (McdTimeout == 0) - { - printk("mcd: status timed out\n"); - SET_TIMER(mcd_start, 1); /* wait a bit, try again */ - return; - } - SET_TIMER(mcd_status, 1); - return; - } + case MCD_S_MODE: +#ifdef TEST3 + printk("MCD_S_MODE\n"); +#endif - if (st & MST_DSK_CHG) - { - mcdDiskChanged = 1; - } - - if ((st & MST_READY) == 0) - { - printk("mcd: disk removed\n"); - mcdDiskChanged = 1; - end_request(0); - do_mcd_request(); - return; - } + if ((st = mcdStatus()) != -1) { - outb(0x50, MCDPORT(0)); /* set mode */ - outb(0x01, MCDPORT(0)); /* mode = cooked data */ - McdTimeout = 100; - SET_TIMER(mcd_read_cmd, 1); -} + if (st & MST_DSK_CHG) { + mcdDiskChanged = 1; + tocUpToDate = 0; + mcd_invalidate_buffers(); + } + + set_mode_immediatly: + + if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) { + mcdDiskChanged = 1; + tocUpToDate = 0; + if (mcd_transfer_is_active) { + mcd_state = MCD_S_START; + goto immediatly; + } + printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n"); + mcd_state = MCD_S_IDLE; + while (CURRENT_VALID) + end_request(0); + return; + } + + outb(MCMD_SET_MODE, MCDPORT(0)); + outb(1, MCDPORT(0)); + mcd_mode = 1; + mcd_state = MCD_S_READ; + McdTimeout = 3000; + + } + break; -/* - * Check the result of the set-mode command. On success, send the - * read-data command. - */ -static void -mcd_read_cmd() -{ - int st; - long block; - struct mcd_Play_msf mcdcmd; + case MCD_S_READ: +#ifdef TEST3 + printk("MCD_S_READ\n"); +#endif - McdTimeout--; - st = mcdStatus(); + if ((st = mcdStatus()) != -1) { - if (st & MST_DSK_CHG) - { - mcdDiskChanged = 1; - } - - if (st == -1) - { - if (McdTimeout == 0) - { - printk("mcd: set mode timed out\n"); - SET_TIMER(mcd_start, 1); /* wait a bit, try again */ - return; - } + if (st & MST_DSK_CHG) { + mcdDiskChanged = 1; + tocUpToDate = 0; + mcd_invalidate_buffers(); + } + + read_immediatly: + + if ((st & MST_DOOR_OPEN) || !(st & MST_READY)) { + mcdDiskChanged = 1; + tocUpToDate = 0; + if (mcd_transfer_is_active) { + mcd_state = MCD_S_START; + goto immediatly; + } + printk((st & MST_DOOR_OPEN) ? "mcd: door open\n" : "mcd: disk removed\n"); + mcd_state = MCD_S_IDLE; + while (CURRENT_VALID) + end_request(0); + return; + } + + if (CURRENT_VALID) { + struct mcd_Play_msf msf; + mcd_next_bn = CURRENT -> sector / 4; + hsg2msf(mcd_next_bn, &msf.start); + msf.end.min = ~0; + msf.end.sec = ~0; + msf.end.frame = ~0; + sendMcdCmd(MCMD_DATA_READ, &msf); + mcd_state = MCD_S_DATA; + McdTimeout = READ_TIMEOUT; + } else { + mcd_state = MCD_S_STOP; + goto immediatly; + } + + } + break; + + + case MCD_S_DATA: +#ifdef TEST3 + printk("MCD_S_DATA\n"); +#endif - SET_TIMER(mcd_read_cmd, 1); - return; - } + st = inb(MCDPORT(1)) & (MFL_STATUSorDATA); + data_immediatly: +#ifdef TEST5 + printk("Status %02x\n",st); +#endif + switch (st) { - mcd_bn = -1; /* purge our buffer */ - block = CURRENT -> sector / 4; - hsg2msf(block, &mcdcmd.start); /* cvt to msf format */ - - mcdcmd.end.min = 0; - mcdcmd.end.sec = 0; - mcdcmd.end.frame = 1; - - sendMcdCmd(MCMD_PLAY_READ, &mcdcmd); /* read command */ - McdTimeout = 200; - SET_TIMER(mcd_data, 1); -} + case MFL_DATA: +#ifdef WARN_IF_READ_FAILURE + if (McdTries == 5) + printk("mcd: read of block %d failed\n", mcd_next_bn); +#endif + if (!McdTries--) { + printk("mcd: read of block %d failed, giving up\n", mcd_next_bn); + if (mcd_transfer_is_active) { + McdTries = 0; + break; + } + if (CURRENT_VALID) + end_request(0); + McdTries = 5; + } + mcd_state = MCD_S_START; + McdTimeout = READ_TIMEOUT; + goto immediatly; + + case MFL_STATUSorDATA: + break; + + default: + McdTries = 5; + if (!CURRENT_VALID && mcd_buf_in == mcd_buf_out) { + mcd_state = MCD_S_STOP; + goto immediatly; + } + mcd_buf_bn[mcd_buf_in] = -1; + READ_DATA(MCDPORT(0), mcd_buf + 2048 * mcd_buf_in, 2048); + mcd_buf_bn[mcd_buf_in] = mcd_next_bn++; + if (mcd_buf_out == -1) + mcd_buf_out = mcd_buf_in; + mcd_buf_in = mcd_buf_in + 1 == MCD_BUF_SIZ ? 0 : mcd_buf_in + 1; + if (!mcd_transfer_is_active) { + while (CURRENT_VALID) { + mcd_transfer(); + if (CURRENT -> nr_sectors == 0) + end_request(1); + else + break; + } + } + + if (CURRENT_VALID + && (CURRENT -> sector / 4 < mcd_next_bn || + CURRENT -> sector / 4 > mcd_next_bn + 16)) { + mcd_state = MCD_S_STOP; + goto immediatly; + } + McdTimeout = READ_TIMEOUT; +#ifdef DOUBLE_QUICK_ONLY + if (MCMD_DATA_READ != MCMD_PLAY_READ) +#endif + { + int count= QUICK_LOOP_COUNT; + while (count--) { + QUICK_LOOP_DELAY; + if ((st = (inb(MCDPORT(1))) & (MFL_STATUSorDATA)) != (MFL_STATUSorDATA)) { +# ifdef TEST4 +/* printk("Quickloop success at %d\n",QUICK_LOOP_COUNT-count); */ + printk(" %d ",QUICK_LOOP_COUNT-count); +# endif + goto data_immediatly; + } + } +# ifdef TEST4 +/* printk("Quickloop ended at %d\n",QUICK_LOOP_COUNT); */ + printk("ended "); +# endif + } + break; + } + break; -/* - * Check the completion of the read-data command. On success, read - * the 2048 bytes of data from the disk into our buffer. - */ -static void -mcd_data() -{ - int i; + case MCD_S_STOP: +#ifdef TEST3 + printk("MCD_S_STOP\n"); +#endif - McdTimeout--; - cli(); - i =inb(MCDPORT(1)) & (MFL_STATUS | MFL_DATA); - if (i == MFL_DATA) - { - printk("mcd: read failed\n"); -#ifdef MCD_DEBUG - printk("got 0xB %02X\n", inb(MCDPORT(0)) & 0xFF); +#ifdef WORK_AROUND_MITSUMI_BUG_93 + if (!mitsumi_bug_93_wait) + goto do_not_work_around_mitsumi_bug_93_1; + + McdTimeout = mitsumi_bug_93_wait; + mcd_state = 9+3+1; + break; + + case 9+3+1: + if (McdTimeout) + break; + + do_not_work_around_mitsumi_bug_93_1: +#endif /* WORK_AROUND_MITSUMI_BUG_93 */ + + outb(MCMD_STOP, MCDPORT(0)); + +#ifdef WORK_AROUND_MITSUMI_BUG_92 + if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) { + int i = 4096; + do { + inb(MCDPORT(0)); + } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i); + outb(MCMD_STOP, MCDPORT(0)); + if ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS) { + i = 4096; + do { + inb(MCDPORT(0)); + } while ((inb(MCDPORT(1)) & MFL_STATUSorDATA) == MFL_STATUS && --i); + outb(MCMD_STOP, MCDPORT(0)); + } + } +#endif /* WORK_AROUND_MITSUMI_BUG_92 */ + + mcd_state = MCD_S_STOPPING; + McdTimeout = 1000; + break; + + case MCD_S_STOPPING: +#ifdef TEST3 + printk("MCD_S_STOPPING\n"); #endif - SET_TIMER(mcd_start, 1); - sti(); - return; - } - - if (i == (MFL_STATUS | MFL_DATA)) - { - if (McdTimeout == 0) - { - printk("mcd: data timeout, retrying\n"); - SET_TIMER(mcd_start, 1); - } - - else - SET_TIMER(mcd_data, 1); - - sti(); - return; - } + + if ((st = mcdStatus()) == -1 && McdTimeout) + break; + + if ((st != -1) && (st & MST_DSK_CHG)) { + mcdDiskChanged = 1; + tocUpToDate = 0; + mcd_invalidate_buffers(); + } + +#ifdef WORK_AROUND_MITSUMI_BUG_93 + if (!mitsumi_bug_93_wait) + goto do_not_work_around_mitsumi_bug_93_2; + + McdTimeout = mitsumi_bug_93_wait; + mcd_state = 9+3+2; + break; + + case 9+3+2: + if (McdTimeout) + break; + + st = -1; + + do_not_work_around_mitsumi_bug_93_2: +#endif /* WORK_AROUND_MITSUMI_BUG_93 */ + +#ifdef TEST3 + printk("CURRENT_VALID %d mcd_mode %d\n", + CURRENT_VALID, mcd_mode); +#endif + + if (CURRENT_VALID) { + if (st != -1) { + if (mcd_mode == 1) + goto read_immediatly; + else + goto set_mode_immediatly; + } else { + mcd_state = MCD_S_START; + McdTimeout = 1; + } + } else { + mcd_state = MCD_S_IDLE; + return; + } + break; + + default: + printk("mcd: invalid state %d\n", mcd_state); + return; + } + + ret: + if (!McdTimeout--) { + printk("mcd: timeout in state %d\n", mcd_state); + mcd_state = MCD_S_STOP; + } + + SET_TIMER(mcd_poll, 1); +} + - CLEAR_TIMER; - READ_DATA(MCDPORT(0), &mcd_buf[0], 2048); - sti(); - - mcd_bn = CURRENT -> sector / 4; - mcd_transfer(); - end_request(1); - SET_TIMER(do_mcd_request, 1); + +static void +mcd_invalidate_buffers(void) +{ + int i; + for (i = 0; i < MCD_BUF_SIZ; ++i) + mcd_buf_bn[i] = -1; + mcd_buf_out = -1; } @@ -760,6 +1033,10 @@ if (mcdPresent == 0) return -ENXIO; /* no hardware */ + if (!mcd_open_count && mcd_state == MCD_S_IDLE) { + + mcd_invalidate_buffers(); + st = statusCmd(); /* check drive status */ if (st == -1) return -EIO; /* drive doesn't respond */ @@ -773,6 +1050,9 @@ if (updateToc() < 0) return -EIO; + } + ++mcd_open_count; + return 0; } @@ -784,9 +1064,11 @@ static void mcd_release(struct inode * inode, struct file * file) { - mcd_bn = -1; + if (!--mcd_open_count) { + mcd_invalidate_buffers(); sync_dev(inode->i_rdev); invalidate_buffers(inode -> i_rdev); + } } @@ -799,7 +1081,8 @@ mcd_ioctl, /* ioctl */ NULL, /* mmap */ mcd_open, /* open */ - mcd_release /* release */ + mcd_release, /* release */ + NULL /* fsync */ }; @@ -825,15 +1108,22 @@ int count; unsigned char result[3]; + if (mcd_port <= 0 || mcd_irq <= 0) { + printk("skip mcd_init\n"); + return mem_start; + } + + printk("mcd=0x%x,%d: ", mcd_port, mcd_irq); + if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0) { - printk("mcd: Unable to get major %d for Mitsumi CD-ROM\n", + printk("Unable to get major %d for Mitsumi CD-ROM\n", MAJOR_NR); return mem_start; } if (check_region(mcd_port, 4)) { - printk("mcd: Init failed, I/O port (%X) already in use\n", + printk("Init failed, I/O port (%X) already in use\n", mcd_port); return mem_start; } @@ -844,16 +1134,16 @@ /* check for card */ outb(0, MCDPORT(1)); /* send reset */ - for (count = 0; count < 1000000; count++) + for (count = 0; count < 2000000; count++) (void) inb(MCDPORT(1)); /* delay a bit */ outb(0x40, MCDPORT(0)); /* send get-stat cmd */ - for (count = 0; count < 1000000; count++) + for (count = 0; count < 2000000; count++) if (!(inb(MCDPORT(1)) & MFL_STATUS)) break; - if (count >= 1000000) { - printk("mcd: Init failed. No mcd device at 0x%x irq %d\n", + if (count >= 2000000) { + printk("Init failed. No mcd device at 0x%x irq %d\n", mcd_port, mcd_irq); return mem_start; } @@ -862,7 +1152,7 @@ outb(MCMD_GET_VERSION,MCDPORT(0)); for(count=0;count<3;count++) if(getValue(result+count)) { - printk("mcd: mitsumi get version failed at 0x%d\n", + printk("mitsumi get version failed at 0x%d\n", mcd_port); return mem_start; } @@ -870,9 +1160,10 @@ if (result[0] == result[1] && result[1] == result[2]) return mem_start; - printk("mcd: Mitsumi version : %02X %c %x\n", + printk("Mitsumi status, type and version : %02X %c %x\n", result[0],result[1],result[2]); + if (result[1] == 'D') MCMD_DATA_READ= 0xC1; mcdVersion=result[2]; @@ -883,13 +1174,24 @@ if (irqaction(mcd_irq, &mcd_sigaction)) { - printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq); + printk("Unable to get IRQ%d for Mitsumi CD-ROM\n", mcd_irq); return mem_start; } snarf_region(mcd_port, 4); + + outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); + outb(0x02,MCDPORT(0)); + outb(0x00,MCDPORT(0)); + getValue(result); + + outb(MCMD_CONFIG_DRIVE, MCDPORT(0)); + outb(0x10,MCDPORT(0)); + outb(0x04,MCDPORT(0)); + getValue(result); + + mcd_invalidate_buffers(); mcdPresent = 1; - printk("mcd: Mitsumi CD-ROM Drive present at addr %x, irq %d\n", - mcd_port, mcd_irq); + printk("\n"); return mem_start; } @@ -1189,6 +1491,7 @@ { outb(MCMD_SET_MODE, MCDPORT(0)); outb(0x05, MCDPORT(0)); /* mode: toc */ + mcd_mode = 0x05; if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } @@ -1219,6 +1522,7 @@ { outb(MCMD_SET_MODE, MCDPORT(0)); outb(0x01, MCDPORT(0)); + mcd_mode = 1; if (getMcdStatus(MCD_STATUS_DELAY) != -1) break; } diff -u --recursive --new-file v1.1.24/linux/drivers/block/ramdisk.c linux/drivers/block/ramdisk.c --- v1.1.24/linux/drivers/block/ramdisk.c Tue Apr 19 10:52:42 1994 +++ linux/drivers/block/ramdisk.c Thu Jul 7 19:09:36 1994 @@ -94,12 +94,7 @@ return(length); } -/* - * If the root device is the RAM disk, try to load it. - * In order to do this, the root device is originally set to the - * floppy, and we later change it to be RAM disk. - */ -void rd_load(void) +static void do_load(void) { struct buffer_head *bh; struct minix_super_block s; @@ -108,14 +103,6 @@ int nblocks; char *cp; - /* If no RAM disk specified, give up early. */ - if (!rd_length) return; - printk("RAMDISK: %d bytes, starting at 0x%x\n", - rd_length, (int) rd_start); - - /* If we are doing a diskette boot, we might have to pre-load it. */ - if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return; - /* * Check for a super block on the diskette. * The old-style boot/root diskettes had their RAM image @@ -175,4 +162,33 @@ ROOT_DEV = ((MEM_MAJOR << 8) | RAMDISK_MINOR); return; } +} + +int floppy_grab_irq_and_dma(void); +void floppy_release_irq_and_dma(void); + +/* + * If the root device is the RAM disk, try to load it. + * In order to do this, the root device is originally set to the + * floppy, and we later change it to be RAM disk. + */ +void rd_load(void) +{ + /* If no RAM disk specified, give up early. */ + if (!rd_length) + return; + printk("RAMDISK: %d bytes, starting at 0x%x\n", + rd_length, (int) rd_start); + + /* If we are doing a diskette boot, we might have to pre-load it. */ + if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) + return; + +/* ugly, ugly */ + if (floppy_grab_irq_and_dma()) { + printk("Unable to gram floppy IRQ/DMA for loading ramdisk image\n"); + return; + } + do_load(); + floppy_release_irq_and_dma(); } diff -u --recursive --new-file v1.1.24/linux/drivers/net/3c505.c linux/drivers/net/3c505.c --- v1.1.24/linux/drivers/net/3c505.c Mon Jun 27 16:46:58 1994 +++ linux/drivers/net/3c505.c Thu Jul 7 18:28:21 1994 @@ -2,16 +2,20 @@ * Linux ethernet device driver for the 3Com Etherlink Plus (3C505) * By Craig Southeren * - * 3c505.c This module implements an interface to the 3Com + * elplus.c This module implements an interface to the 3Com * Etherlink Plus (3c505) ethernet card. Linux device * driver interface reverse engineered from the Linux 3C509 * device drivers. Vital 3C505 information gleaned from * the Crynwr packet driver * - * Version: @(#)3c505.c 0.1 23/09/93 + * Version: @(#)elplus.c 0.5 11-Jun-94 * * Authors: Linux 3c505 device driver by: * Craig Southeren, + * Final debugging by: + * Andrew Tridgell, + * Auto irq, auto detect, cleanup and v1.1.4+ kernel mods by: + * Juha Laiho, * Linux 3C509 driver by: * Donald Becker, * Crynwr packet driver by @@ -22,10 +26,36 @@ * modified by Warren Van Houten and krus@diku.dk. * 3C505 technical information provided by * Terry Murphy, of 3Com Network Adapter Division - * Special thanks to Juha Laiho, * */ + +/********************************************************* + * + * set ELP_KERNEL_TYPE to the following values depending upon + * the kernel type: + * 0 = 0.99pl14 or earlier + * 1 = 0.99pl15 through 1.1.3 + * 2 = 1.1.4 through 1.1.11 + * 3 = 1.1.12 through 1.1.19 + * 4 = 1.1.20 + * + *********************************************************/ + +#define ELP_KERNEL_TYPE 4 + +/********************************************************* + * + * set ELP_NEED_HARD_RESET to 1, if having problems with + * "warm resets" from DOS. Bootup will then take some more + * time, as the adapter will perform self-test upon hard + * reset. This misbehaviour is reported to happen at least + * after use of Windows real-mode NDIS drivers. + * + *********************************************************/ + +#define ELP_NEED_HARD_RESET 0 + #include #include #include @@ -34,23 +64,80 @@ #include #include #include +#include +#include +#include #include -#ifndef port_read -#include "iow.h" -#endif +#if (ELP_KERNEL_TYPE < 2) +#include "dev.h" +#include "eth.h" +#include "skbuff.h" +#include "arp.h" +#else #include #include #include +#endif + +#ifndef port_read +#include "iow.h" +#endif #include "3c505.h" -#ifdef ELP_DEBUG -static int elp_debug = ELP_DEBUG; +#define ELPLUS_DEBUG 0 + +/********************************************************* + * + * define debug messages here as common strings to reduce space + * + *********************************************************/ + +static char * filename = __FILE__; + +static char * null_msg = "*** NULL at %s(%d) ***\n"; +#define CHECK_NULL(p) if (!p) printk(null_msg, filename, __LINE__) + +static char * timeout_msg = "*** timeout at %s(%d) ***\n"; +#define TIMEOUT_MSG() printk(timeout_msg, filename,__LINE__) + +static char * invalid_pcb_msg = "*** invalid pcb length %d at %s(%d) ***\n"; + +static char * search_msg = "%s: Looking for 3c505 adapter at address 0x%x..."; + +static char * stilllooking_msg = "still looking..."; + +static char * found_msg = "found.\n"; + +static char * notfound_msg = "not found (reason = %d)\n"; + +static char * couldnot_msg = "%s: 3c505 not found\n"; + +/********************************************************* + * + * various other debug stuff + * + *********************************************************/ + +#ifdef ELPLUS_DEBUG +static int elp_debug = ELPLUS_DEBUG; #else static int elp_debug = 0; #endif +#if (ELP_KERNEL_TYPE < 2) +extern void skb_check(struct sk_buff *skb,int, char *); +#ifndef IS_SKB +#define IS_SKB(skb) skb_check((skb),__LINE__,filename) +#endif +#else +#ifndef IS_SKB +#define IS_SKB(skb) skb_check((skb),0,__LINE__,filename) +#endif +#endif + + /* * 0 = no messages * 1 = messages when high level commands performed @@ -58,9 +145,7 @@ * 3 = messages when interrupts received */ -#define ELP_VERSION "0.1.0" - -extern struct device *irq2dev_map[16]; +#define ELPLUS_VERSION "0.4.0" /***************************************************************** * @@ -68,8 +153,27 @@ * *****************************************************************/ -#define INB(port) inb((unsigned short)port) -#define OUTB(val,port) outb((unsigned char)val,(unsigned short)port); +/* + * kernels before pl15 used an unobvious method for accessing + * the skb data area + */ +#if (ELP_KERNEL_TYPE < 1) +#define SKB_DATA (skb+1) +#else +#define SKB_DATA (skb->data) +#endif + +/* + * not all kernels before 1.1.4 had an alloc_skb function (apparently!!) + */ +#if (ELP_KERNEL_TYPE < 2) +#ifndef HAVE_ALLOC_SKB +#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority) +#endif +#endif + +#define INB(port) inb((unsigned short)(port)) +#define OUTB(val,port) outb((unsigned char)(val),(unsigned short)(port)); #ifndef TRUE #define TRUE 1 @@ -82,16 +186,19 @@ /***************************************************************** * + * List of I/O-addresses we try to auto-sense + * Last element MUST BE 0! + *****************************************************************/ + +const int addr_list[]={0x300,0x280,0x310,0}; + +/***************************************************************** + * * PCB structure * *****************************************************************/ -typedef struct { - unsigned char command; /* PCB command code */ - unsigned char length; /* PCB data length */ - unsigned char data[MAX_PCB_DATA]; /* PCB data */ -} pcb_struct; - +#include "3c505dta.h" /***************************************************************** * @@ -101,7 +208,8 @@ typedef struct { int io_addr; /* base I/O address */ - short got_configure; /* set to TRUE when configure response received */ + char * name; /* used for debug output */ + short got[NUM_TRANSMIT_CMDS]; /* flags for command completion */ pcb_struct tx_pcb; /* PCB for foreground sending */ pcb_struct rx_pcb; /* PCB for foreground receiving */ pcb_struct itx_pcb; /* PCB for background sending */ @@ -127,10 +235,13 @@ static int get_status (elp_device * adapter) { + int timeout = jiffies + TIMEOUT; register int stat1; do { stat1 = INB(adapter->io_addr+PORT_STATUS); - } while (stat1 != INB(adapter->io_addr+PORT_STATUS)); + } while (stat1 != INB(adapter->io_addr+PORT_STATUS) && jiffies < timeout); + if (jiffies >= timeout) + TIMEOUT_MSG(); return stat1; } @@ -153,8 +264,8 @@ while(((INB(adapter->io_addr+PORT_STATUS)&STATUS_HCRE)==0) && (jiffies <= timeout)) ; - if (jiffies > timeout) { - printk("elp0: timeout waiting for HCRE\n"); + if (jiffies >= timeout) { + TIMEOUT_MSG(); return FALSE; } return TRUE; @@ -183,6 +294,12 @@ int retry = 0; int timeout; + CHECK_NULL(pcb); + CHECK_NULL(adapter); + + if (pcb->length > MAX_PCB_DATA) + printk(invalid_pcb_msg, pcb->length, filename, __LINE__); + while (1) { cont = 1; @@ -195,7 +312,6 @@ SET_HSF(0); OUTB(pcb->command, (adapter->io_addr)+PORT_COMMAND); cont = WAIT_HCRE(5); - /* SET_HSF(0); */ if (cont) { OUTB(pcb->length, (adapter->io_addr)+PORT_COMMAND); @@ -203,7 +319,7 @@ } for (i = 0; cont && (i < pcb->length); i++) { - OUTB(pcb->data[i], (adapter->io_addr)+PORT_COMMAND); + OUTB(pcb->data.raw[i], (adapter->io_addr)+PORT_COMMAND); cont = WAIT_HCRE(2); } @@ -220,12 +336,16 @@ (i == ASF_PCB_NAK)) break; } + + if (jiffies >= timeout) + TIMEOUT_MSG(); + if (i == ASF_PCB_ACK) { SET_HSF(0); return TRUE; - } else if (i = ASF_PCB_NAK) { + } else if (i == ASF_PCB_NAK) { SET_HSF(0); - printk("elp0: PCB send was NAKed\n"); + printk("%s: PCB send was NAKed\n", adapter->name); { int to = jiffies + 5; while (jiffies < to) @@ -234,11 +354,13 @@ } } - if (elp_debug >= 6) - printk("elp0: NAK/timeout on send PCB\n"); + if (elp_debug >= 2) + printk("%s: NAK/timeout on send PCB\n", adapter->name); if ((retry++ & 7) == 0) - printk("elp0: retry #%i on send PCB\n", retry); + printk("%s: retry #%i on send PCB\n", adapter->name, retry); } + + return FALSE; } /***************************************************************** @@ -260,38 +382,60 @@ int i; int total_length; int stat; + int timeout; + + CHECK_NULL(pcb); + CHECK_NULL(adapter); /* get the command code */ - while (((stat = GET_STATUS())&STATUS_ACRF) == 0) + timeout = jiffies + TIMEOUT; + while (((stat = GET_STATUS())&STATUS_ACRF) == 0 && jiffies < timeout) ; + if (jiffies >= timeout) + TIMEOUT_MSG(); + SET_HSF(0); pcb->command = INB(adapter->io_addr+PORT_COMMAND); if ((stat & ASF_PCB_MASK) != ASF_PCB_END) { /* read the data length */ - while (((stat = GET_STATUS())&STATUS_ACRF) == 0) + timeout = jiffies + TIMEOUT; + while (((stat = GET_STATUS())&STATUS_ACRF) == 0 && jiffies < timeout) ; + if (jiffies >= timeout) + TIMEOUT_MSG(); pcb->length = INB(adapter->io_addr+PORT_COMMAND); + + if (pcb->length > MAX_PCB_DATA) + printk(invalid_pcb_msg, pcb->length, filename,__LINE__); + if ((stat & ASF_PCB_MASK) != ASF_PCB_END) { /* read the data */ i = 0; + timeout = jiffies + TIMEOUT; do { - while (((stat = GET_STATUS())&STATUS_ACRF) == 0) + while (((stat = GET_STATUS())&STATUS_ACRF) == 0 && jiffies < timeout) ; - pcb->data[i++] = INB(adapter->io_addr+PORT_COMMAND); - } while ((stat & ASF_PCB_MASK) != ASF_PCB_END); - + pcb->data.raw[i++] = INB(adapter->io_addr+PORT_COMMAND); + if (i > MAX_PCB_DATA) + printk(invalid_pcb_msg, i, filename, __LINE__); + } while ((stat & ASF_PCB_MASK) != ASF_PCB_END && jiffies < timeout); + + if (jiffies >= timeout) + TIMEOUT_MSG(); + /* woops, the last "data" byte was really the length! */ - total_length = pcb->data[--i]; + total_length = pcb->data.raw[--i]; /* safety check total length vs data length */ if (total_length != (pcb->length + 2)) { - if (elp_debug >= 6) - printk("elp0: mangled PCB received\n"); + if (elp_debug >= 2) + printk("%s: mangled PCB received\n", adapter->name); SET_HSF(HSF_PCB_NAK); return FALSE; } + SET_HSF(HSF_PCB_ACK); return TRUE; } @@ -301,11 +445,15 @@ return FALSE; } +#if ELP_NEED_HARD_RESET + static void adapter_hard_reset(elp_device * adapter) { int timeout; + CHECK_NULL(adapter); + /* * take FLSH and ATTN high */ @@ -336,11 +484,14 @@ break; } -static void adapter_reset(elp_device * adapter) +#endif /* ELP_NEED_HARD_RESET */ +static void adapter_reset(elp_device * adapter) { int timeout; + CHECK_NULL(adapter); + cli(); OUTB(CONTROL_ATTN|INB(adapter->io_addr+PORT_CONTROL), adapter->io_addr+PORT_CONTROL); sti(); @@ -350,10 +501,11 @@ */ for (timeout = jiffies + 20; jiffies <= timeout; ) ; - + cli(); OUTB(INB(adapter->io_addr+PORT_CONTROL)&~(CONTROL_ATTN), adapter->io_addr+PORT_CONTROL); sti(); + } /****************************************************** @@ -366,14 +518,16 @@ static int start_receive(elp_device * adapter, pcb_struct * tx_pcb) { - if (elp_debug > 3) - printk("elp0: restarting receiver\n"); + CHECK_NULL(adapter); + CHECK_NULL(tx_pcb); + + if (elp_debug >= 3) + printk("%s: restarting receiver\n", adapter->name); tx_pcb->command = CMD_RECEIVE_PACKET; - tx_pcb->length = 8; - tx_pcb->data[4] = 1600 & 0xff; - tx_pcb->data[5] = 1600 >> 8; - tx_pcb->data[6] = 0; /* set timeout to zero */ - tx_pcb->data[7] = 0; + tx_pcb->length = sizeof(struct Rcv_pkt); + tx_pcb->data.rcv_pkt.buf_seg = tx_pcb->data.rcv_pkt.buf_ofs = 0; /* Unused */ + tx_pcb->data.rcv_pkt.buf_len = 1600; + tx_pcb->data.rcv_pkt.timeout = 0; /* set timeout to zero */ return send_pcb(adapter, tx_pcb); } @@ -394,13 +548,33 @@ register int i; unsigned short * ptr; short d; + int timeout; + int rlen; + struct sk_buff *skb; /* * allocate a buffer to put the packet into. + * (for kernels prior to 1.1.4 only) */ - struct sk_buff *skb; - skb = alloc_skb(len+3, GFP_ATOMIC); +#if (ELP_KERNEL_TYPE < 2) + int sksize = sizeof(struct sk_buff) + len + 4; +#endif + + CHECK_NULL(dev); + CHECK_NULL(adapter); + + if (len <= 0 || ((len & ~1) != len)) + if (elp_debug >= 3) + printk("*** bad packet len %d at %s(%d)\n",len,filename,__LINE__); + rlen = (len+1) & ~1; + +#if (ELP_KERNEL_TYPE < 2) + skb = alloc_skb(sksize, GFP_ATOMIC); +#else + skb = alloc_skb(rlen, GFP_ATOMIC); +#endif + /* * make sure the data register is going the right way */ @@ -410,23 +584,52 @@ * if buffer could not be allocated, swallow it */ if (skb == NULL) { - for (i = 0; i < (len/2); i++) { - while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0) + for (i = 0; i < (rlen/2); i++) { + timeout = jiffies + TIMEOUT; + while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0 && + jiffies < timeout) ; + if (jiffies >= timeout) + TIMEOUT_MSG(); + d = inw(adapter->io_addr+PORT_DATA); } adapter->stats.rx_dropped++; } else { + skb->lock = 0; + skb->len = rlen; + skb->dev = dev; +/* + * for kernels before 1.1.4, the driver allocated the buffer + */ +#if (ELP_KERNEL_TYPE < 2) + skb->mem_len = sksize; + skb->mem_addr = skb; +#endif + /* * now read the data from the adapter */ - ptr = (unsigned short *)(skb->data); - for (i = 0; i < (len/2); i++) { - while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0) { - ; - } + ptr = (unsigned short *)SKB_DATA; + for (i = 0; i < (rlen/2); i++) { + timeout = jiffies + TIMEOUT; + while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0 && + jiffies < timeout) + ; + if (jiffies >= timeout) + { + printk("*** timeout at %s(%d) reading word %d of %d ***\n", + filename,__LINE__, i, rlen/2); +#if (ELP_KERNEL_TYPE < 2) + kfree_s(skb, sksize); +#else + kfree_s(skb, rlen); +#endif + return; + } + *ptr = inw(adapter->io_addr+PORT_DATA); ptr++; } @@ -436,10 +639,21 @@ * protocol chain. If it returns 0, we can assume the packet was * swallowed up. If not, then we are responsible for freeing memory */ - if (dev_rint((unsigned char *)skb, len, IN_SKBUFF, dev) != 0) { + + IS_SKB(skb); + +/* + * for kernels before 1.1.4, the driver allocated the buffer, so it had + * to free it + */ +#if (ELP_KERNEL_TYPE < 2) + if (dev_rint((unsigned char *)skb, rlen, IN_SKBUFF, dev) != 0) { printk("%s: receive buffers full.\n", dev->name); - kfree_skb(skb, FREE_READ); + kfree_s(skb, sksize); } +#else + netif_rx(skb); +#endif } OUTB(INB(adapter->io_addr+PORT_CONTROL)&(~CONTROL_DIR), adapter->io_addr+PORT_CONTROL); @@ -460,27 +674,34 @@ int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); struct device *dev; elp_device * adapter; + int timeout; if (irq < 0 || irq > 15) { - printk ("elp0: illegal IRQ number found in interrupt routine (%i)\n", irq); + printk ("elp_interrupt(): illegal IRQ number found in interrupt routine (%i)\n", irq); return; } - if (irq != 0xc) { - printk ("elp0: warning - interrupt routine has incorrect IRQ of %i\n", irq); +/* FIXME: How do I do this kind of check without a fixed IRQ? */ +#if 0 + if (irq != ELP_IRQ) { + printk ("elp_interrupt(): - interrupt routine has incorrect IRQ of %i\n", irq); return; } +#endif dev = irq2dev_map[irq]; - adapter = (elp_device *) dev->priv; if (dev == NULL) { printk ("elp_interrupt(): irq %d for unknown device.\n", irq); return; } + adapter = (elp_device *) dev->priv; + + CHECK_NULL(adapter); + if (dev->interrupt) - if (elp_debug >= 3) + if (elp_debug >= 2) printk("%s: Re-entering the interrupt handler.\n", dev->name); dev->interrupt = 1; @@ -492,7 +713,9 @@ /* * receive a PCB from the adapter */ - while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0) { + timeout = jiffies + TIMEOUT; + while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0 && + jiffies < timeout) { if (receive_pcb(adapter, &adapter->irx_pcb)) { @@ -502,18 +725,66 @@ * 82586 configured correctly */ case CMD_CONFIGURE_82586_RESPONSE: - adapter->got_configure = 1; + adapter->got[CMD_CONFIGURE_82586] = 1; if (elp_debug >= 3) printk("%s: interrupt - configure response received\n", dev->name); break; + /* + * Adapter memory configuration + */ + case CMD_CONFIGURE_ADAPTER_RESPONSE: + adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 1; + if (elp_debug >= 3) + printk("%s: Adapter memory configuration %s.",dev->name, + adapter->irx_pcb.data.failed?"failed":"succeeded"); + break; + + /* + * Multicast list loading + */ + case CMD_LOAD_MULTICAST_RESPONSE: + adapter->got[CMD_LOAD_MULTICAST_LIST] = 1; + if (elp_debug >= 3) + printk("%s: Multicast address list loading %s.",dev->name, + adapter->irx_pcb.data.failed?"failed":"succeeded"); + break; + + /* + * Station address setting + */ + case CMD_SET_ADDRESS_RESPONSE: + adapter->got[CMD_SET_STATION_ADDRESS] = 1; + if (elp_debug >= 3) + printk("%s: Ethernet address setting %s.",dev->name, + adapter->irx_pcb.data.failed?"failed":"succeeded"); + break; + + + /* + * received board statistics + */ + case CMD_NETWORK_STATISTICS_RESPONSE: + adapter->stats.rx_packets += adapter->irx_pcb.data.netstat.tot_recv; + adapter->stats.tx_packets += adapter->irx_pcb.data.netstat.tot_xmit; + adapter->stats.rx_crc_errors += adapter->irx_pcb.data.netstat.err_CRC; + adapter->stats.rx_frame_errors += adapter->irx_pcb.data.netstat.err_align; + adapter->stats.rx_fifo_errors += adapter->irx_pcb.data.netstat.err_ovrrun; + adapter->got[CMD_NETWORK_STATISTICS] = 1; + if (elp_debug >= 3) + printk("%s: interrupt - statistics response received\n", dev->name); + break; + /* * received a packet */ case CMD_RECEIVE_PACKET_COMPLETE: - len = adapter->irx_pcb.data[6] + (adapter->irx_pcb.data[7] << 8); - dlen = adapter->irx_pcb.data[4] + (adapter->irx_pcb.data[5] << 8); - if (adapter->irx_pcb.data[8] != 0) { + /* if the device isn't open, don't pass packets up the stack */ + if (dev->start == 0) + break; + len = adapter->irx_pcb.data.rcv_resp.pkt_len; + dlen = adapter->irx_pcb.data.rcv_resp.buf_len; + if (adapter->irx_pcb.data.rcv_resp.timeout != 0) { printk("%s: interrupt - packet not received correctly\n", dev->name); } else { if (elp_debug >= 3) @@ -521,7 +792,6 @@ receive_packet(dev, adapter, dlen); if (elp_debug >= 3) printk("%s: packet received\n", dev->name); - adapter->stats.rx_packets++; } if (dev->start && !start_receive(adapter, &adapter->itx_pcb)) if (elp_debug >= 2) @@ -537,13 +807,18 @@ case CMD_TRANSMIT_PACKET_COMPLETE: if (elp_debug >= 3) printk("%s: interrupt - packet sent\n", dev->name); - if (adapter->irx_pcb.data[4] != 0) + if (dev->start == 0) + break; + if (adapter->irx_pcb.data.xmit_resp.c_stat != 0) if (elp_debug >= 2) - printk("%s: interrupt - error sending packet %4.4x\n", dev->name, - adapter->irx_pcb.data[4] + (adapter->irx_pcb.data[5] << 8)); + printk("%s: interrupt - error sending packet %4.4x\n", + dev->name, adapter->irx_pcb.data.xmit_resp.c_stat); dev->tbusy = 0; +#if (ELP_KERNEL_TYPE < 3) mark_bh(INET_BH); - adapter->stats.tx_packets++; +#else + mark_bh(NET_BH); +#endif break; /* @@ -556,6 +831,8 @@ } else printk("%s: failed to read PCB on interrupt\n", dev->name); } + if (jiffies >= timeout) + TIMEOUT_MSG(); /* * indicate no longer in interrupt routine @@ -575,7 +852,9 @@ { elp_device * adapter = (elp_device *) dev->priv; - if (elp_debug >= 1) + CHECK_NULL(dev); + + if (elp_debug >= 3) printk("%s: request to open device\n", dev->name); /* @@ -587,6 +866,16 @@ } /* + * disable interrupts on the board + */ + OUTB(0x00, adapter->io_addr+PORT_CONTROL); + + /* + * clear any pending interrupts + */ + INB(adapter->io_addr+PORT_COMMAND); + + /* * interrupt routine not entered */ dev->interrupt = 0; @@ -618,74 +907,60 @@ dev->start = 1; /* + * configure adapter memory: we need 10 multicast addresses, default==0 + */ + if (elp_debug >= 3) + printk("%s: sending 3c505 memory configuration command\n", dev->name); + adapter->tx_pcb.command = CMD_CONFIGURE_ADAPTER_MEMORY; + adapter->tx_pcb.data.memconf.cmd_q = 10; + adapter->tx_pcb.data.memconf.rcv_q = 20; + adapter->tx_pcb.data.memconf.mcast = 10; + adapter->tx_pcb.data.memconf.frame = 20; + adapter->tx_pcb.data.memconf.rcv_b = 20; + adapter->tx_pcb.data.memconf.progs = 0; + adapter->tx_pcb.length = sizeof(struct Memconf); + adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] = 0; + if (!send_pcb(adapter, &adapter->tx_pcb)) + printk("%s: couldn't send memory configuration command\n", dev->name); + else { + int timeout = jiffies + TIMEOUT; + while (adapter->got[CMD_CONFIGURE_ADAPTER_MEMORY] == 0 && jiffies < timeout) + ; + if (jiffies >= timeout) + TIMEOUT_MSG(); + } + + + /* * configure adapter to receive broadcast messages and wait for response */ - if (elp_debug >= 2) + if (elp_debug >= 3) printk("%s: sending 82586 configure command\n", dev->name); adapter->tx_pcb.command = CMD_CONFIGURE_82586; - adapter->tx_pcb.data[0] = 1; - adapter->tx_pcb.data[1] = 0; + adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD; adapter->tx_pcb.length = 2; - adapter->got_configure = 0; + adapter->got[CMD_CONFIGURE_82586] = 0; if (!send_pcb(adapter, &adapter->tx_pcb)) printk("%s: couldn't send 82586 configure command\n", dev->name); - else - while (adapter->got_configure == 0) + else { + int timeout = jiffies + TIMEOUT; + while (adapter->got[CMD_CONFIGURE_82586] == 0 && jiffies < timeout) ; + if (jiffies >= timeout) + TIMEOUT_MSG(); + } /* - * queue a receive command to start things rolling + * queue receive commands to provide buffering */ if (!start_receive(adapter, &adapter->tx_pcb)) printk("%s: start receive command failed \n", dev->name); - if (elp_debug >= 2) + if (elp_debug >= 3) printk("%s: start receive command sent\n", dev->name); return 0; /* Always succeed */ } -/****************************************************** - * - * close the board - * - ******************************************************/ - -static int elp_close (struct device *dev) - -{ - elp_device * adapter = (elp_device *) dev->priv; - - if (elp_debug >= 1) - printk("%s: request to close device\n", dev->name); - - /* - * disable interrupts on the board - */ - OUTB(0x00, adapter->io_addr+PORT_CONTROL); - - /* - * flag transmitter as busy (i.e. not available) - */ - dev->tbusy = 1; - - /* - * indicate device is closed - */ - dev->start = 0; - - /* - * release the IRQ - */ - free_irq(dev->irq); - - /* - * and we no longer have to map irq to dev either - */ - irq2dev_map[dev->irq] = 0; - - return 0; -} - /****************************************************** * @@ -703,14 +978,20 @@ */ unsigned int nlen = (((len < 60) ? 60 : len) + 1) & (~1); + CHECK_NULL(adapter); + CHECK_NULL(ptr); + + if (nlen < len) + printk("Warning, bad length nlen=%d len=%d %s(%d)\n",nlen,len,filename,__LINE__); + /* * send the adapter a transmit packet command. Ignore segment and offset * and make sure the length is even */ adapter->tx_pcb.command = CMD_TRANSMIT_PACKET; - adapter->tx_pcb.length = 6; - adapter->tx_pcb.data[4] = nlen & 0xff; - adapter->tx_pcb.data[5] = nlen >> 8; + adapter->tx_pcb.length = sizeof(struct Xmit_pkt); + adapter->tx_pcb.data.xmit_pkt.buf_ofs = adapter->tx_pcb.data.xmit_pkt.buf_seg = 0; /* Unused */ + adapter->tx_pcb.data.xmit_pkt.pkt_len = nlen; if (!send_pcb(adapter, &adapter->tx_pcb)) return FALSE; @@ -725,8 +1006,15 @@ * write data to the adapter */ for (i = 0; i < (nlen/2);i++) { - while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0) + int timeout = jiffies + TIMEOUT; + while ((INB(adapter->io_addr+PORT_STATUS)&STATUS_HRDY) == 0 && jiffies < timeout) ; + if (jiffies >= timeout) { + printk("*** timeout at %s(%d) writing word %d of %d ***\n", + filename,__LINE__, i, nlen/2); + return FALSE; + } + outw(*(short *)ptr, adapter->io_addr+PORT_DATA); ptr +=2; } @@ -746,8 +1034,10 @@ { elp_device * adapter = (elp_device *) dev->priv; + CHECK_NULL(dev); + /* - * not sure what this does, but the 3c609 driver does it, so... + * not sure what this does, but the 3c509 driver does it, so... */ if (skb == NULL) { dev_tint(dev); @@ -755,20 +1045,34 @@ } /* + * Fill in the ethernet header + * (for kernels prior to 1.1.4 only) + */ +#if (ELP_KERNEL_TYPE < 2) + IS_SKB(skb); + if (!skb->arp && dev->rebuild_header(SKB_DATA, dev)) { + skb->dev = dev; + IS_SKB(skb); + arp_queue (skb); + return 0; + } +#endif + + /* * if we ended up with a munged length, don't send it */ if (skb->len <= 0) return 0; - if (elp_debug >= 1) - printk("%s: request to send packet of length %i\n", dev->name, skb->len); + if (elp_debug >= 3) + printk("%s: request to send packet of length %d\n", dev->name, (int)skb->len); /* * if the transmitter is still busy, we have a transmit timeout... */ if (dev->tbusy) { int tickssofar = jiffies - dev->trans_start; - if (tickssofar < 500) + if (tickssofar < 200) /* was 500, AJT */ return 1; printk("%s: transmit timed out, resetting adapter\n", dev->name); if ((INB(adapter->io_addr+PORT_STATUS)&STATUS_ACRF) != 0) @@ -779,15 +1083,15 @@ } /* - * send the packet at (void *)(skb+1) for skb->len + * send the packet at skb->data for skb->len */ - if (!send_packet(adapter, (unsigned char *)(skb->data), skb->len)) { + if (!send_packet(adapter, (unsigned char *)SKB_DATA, skb->len)) { printk("%s: send packet PCB failed\n", dev->name); return 1; } - if (elp_debug >= 2) - printk("%s: packet of length %i sent\n", dev->name, skb->len); + if (elp_debug >= 3) + printk("%s: packet of length %d sent\n", dev->name, (int)skb->len); /* @@ -803,7 +1107,15 @@ /* * if we have been asked to free the buffer, do so */ +#if (ELP_KERNEL_TYPE < 4) + if (skb->free) + { + IS_SKB(skb); + kfree_skb(skb, FREE_WRITE); + } +#else dev_kfree_skb(skb, FREE_WRITE); +#endif return 0; } @@ -817,30 +1129,174 @@ static struct enet_statistics * elp_get_stats(struct device *dev) { - if (elp_debug >= 1) + elp_device *adapter = (elp_device *) dev->priv; + + if (elp_debug >= 3) printk("%s: request for stats\n", dev->name); - elp_device * adapter = (elp_device *) dev->priv; + /* If the device is closed, just return the latest stats we have, + - we cannot ask from the adapter without interrupts */ + if (!dev->start) + return &adapter->stats; + + /* send a get statistics command to the board */ + adapter->tx_pcb.command = CMD_NETWORK_STATISTICS; + adapter->tx_pcb.length = 0; + adapter->got[CMD_NETWORK_STATISTICS] = 0; + if (!send_pcb(adapter, &adapter->tx_pcb)) + printk("%s: couldn't send get statistics command\n", dev->name); + else + { + int timeout = jiffies + TIMEOUT; + while (adapter->got[CMD_NETWORK_STATISTICS] == 0 && jiffies < timeout) + ; + if (jiffies >= timeout) { + TIMEOUT_MSG(); + return &adapter->stats; + } + } + + /* statistics are now up to date */ return &adapter->stats; } /****************************************************** * - * initialise Etherlink Pus board + * close the board * ******************************************************/ -static void elp_init(struct device *dev) +static int elp_close (struct device *dev) + +{ + elp_device * adapter = (elp_device *) dev->priv; + + CHECK_NULL(dev); + CHECK_NULL(adapter); + + if (elp_debug >= 3) + printk("%s: request to close device\n", dev->name); + + /* Someone may request the device statistic information even when + * the interface is closed. The following will update the statistics + * structure in the driver, so we'll be able to give current statistics. + */ + (void) elp_get_stats(dev); + + /* + * disable interrupts on the board + */ + OUTB(0x00, adapter->io_addr+PORT_CONTROL); + + /* + * flag transmitter as busy (i.e. not available) + */ + dev->tbusy = 1; + + /* + * indicate device is closed + */ + dev->start = 0; + + /* + * release the IRQ + */ + free_irq(dev->irq); + + /* + * and we no longer have to map irq to dev either + */ + irq2dev_map[dev->irq] = 0; + + return 0; +} + + +/************************************************************ + * + * Set multicast list + * num_addrs==0: clear mc_list + * num_addrs==-1: set promiscuous mode + * num_addrs>0: set mc_list + * + ************************************************************/ +static void elp_set_mc_list(struct device *dev, int num_addrs, void *addrs) { + elp_device *adapter = (elp_device *) dev->priv; int i; + + if (elp_debug >= 3) + printk("%s: request to set multicast list\n", dev->name); + + if (num_addrs != -1) { + /* send a "load multicast list" command to the board, max 10 addrs/cmd */ + /* if num_addrs==0 the list will be cleared */ + adapter->tx_pcb.command = CMD_LOAD_MULTICAST_LIST; + adapter->tx_pcb.length = 6*num_addrs; + for (i=0;itx_pcb.data.multicast[i], addrs+6*i,6); + adapter->got[CMD_LOAD_MULTICAST_LIST] = 0; + if (!send_pcb(adapter, &adapter->tx_pcb)) + printk("%s: couldn't send set_multicast command\n", dev->name); + else { + int timeout = jiffies + TIMEOUT; + while (adapter->got[CMD_LOAD_MULTICAST_LIST] == 0 && jiffies < timeout) + ; + if (jiffies >= timeout) { + TIMEOUT_MSG(); + } + } + if (num_addrs) + adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD | RECV_MULTI; + else /* num_addrs == 0 */ + adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_BROAD; + } else /* num_addrs == -1 */ + adapter->tx_pcb.data.configure = NO_LOOPBACK | RECV_ALL; + /* + * configure adapter to receive messages (as specified above) + * and wait for response + */ + if (elp_debug >= 3) + printk("%s: sending 82586 configure command\n", dev->name); + adapter->tx_pcb.command = CMD_CONFIGURE_82586; + adapter->tx_pcb.length = 2; + adapter->got[CMD_CONFIGURE_82586] = 0; + if (!send_pcb(adapter, &adapter->tx_pcb)) + printk("%s: couldn't send 82586 configure command\n", dev->name); + else { + int timeout = jiffies + TIMEOUT; + while (adapter->got[CMD_CONFIGURE_82586] == 0 && jiffies < timeout) + ; + if (jiffies >= timeout) + TIMEOUT_MSG(); + } +} + +/****************************************************** + * + * initialise Etherlink Plus board + * + ******************************************************/ + +static void elp_init(struct device *dev) + +{ elp_device * adapter; + CHECK_NULL(dev); + /* * NULL out buffer pointers + * (kernels prior to 1.1.4 only) */ - for (i = 0; i < DEV_NUMBUFFS; i++) - dev->buffs[i] = NULL; +#if (ELP_KERNEL_TYPE < 2) + { + int i; + for (i = 0; i < DEV_NUMBUFFS; i++) + dev->buffs[i] = NULL; + } +#endif /* * set ptrs to various functions @@ -849,31 +1305,43 @@ dev->stop = elp_close; /* local */ dev->get_stats = elp_get_stats; /* local */ dev->hard_start_xmit = elp_start_xmit; /* local */ + dev->set_multicast_list = elp_set_mc_list; /* local */ +#if (ELP_KERNEL_TYPE < 2) dev->hard_header = eth_header; /* eth.c */ dev->add_arp = eth_add_arp; /* eth.c */ dev->rebuild_header = eth_rebuild_header; /* eth.c */ dev->type_trans = eth_type_trans; /* eth.c */ - dev->queue_xmit = dev_queue_xmit; /* dev.c */ +#else + /* Setup the generic properties */ + ether_setup(dev); +#endif /* * setup ptr to adapter specific information */ adapter = (elp_device *)(dev->priv = kmalloc(sizeof(elp_device), GFP_KERNEL)); + CHECK_NULL(adapter); adapter->io_addr = dev->base_addr; + adapter->name = dev->name; memset(&(adapter->stats), 0, sizeof(struct enet_statistics)); /* * Ethernet information + * (for kernels prior to 1.1.4 only) */ +#if (ELP_KERNEL_TYPE < 2) dev->type = ARPHRD_ETHER; dev->hard_header_len = ETH_HLEN; dev->mtu = 1500; /* eth_mtu */ dev->addr_len = ETH_ALEN; - for (i = 0; i < dev->addr_len; i++) - dev->broadcast[i] = 0xff; + { + int i; + for (i = 0; i < dev->addr_len; i++) + dev->broadcast[i] = 0xff; + } /* * New-style flags. @@ -884,41 +1352,139 @@ dev->pa_brdaddr = 0; dev->pa_mask = 0; dev->pa_alen = sizeof(unsigned long); +#endif /* * memory information */ dev->mem_start = dev->mem_end = dev->rmem_end = dev->mem_start = 0; + +#if ELP_NEED_HARD_RESET + adapter_hard_reset(adapter); +#else + adapter_reset(adapter); +#endif +} + +/************************************************************ + * + * A couple of tests to see if there's 3C505 or not + * Called only by elp_autodetect + ************************************************************/ + +static int elp_sense(int addr) +{ + int timeout; + byte orig_HCR=INB(addr+PORT_CONTROL), + orig_HSR=INB(addr+PORT_STATUS); + + if (((orig_HCR==0xff) && (orig_HSR==0xff)) || + ( (orig_HCR & CONTROL_DIR) != (orig_HSR & STATUS_DIR) ) ) + return 1; /* It can't be 3c505 if HCR.DIR != HSR.DIR */ + + /* Wait for a while; the adapter may still be booting up */ + if (elp_debug > 0) + printk(stilllooking_msg); + for (timeout = jiffies + (100 * 15); jiffies <= timeout; ) + if ((INB(addr+PORT_STATUS) & ASF_PCB_MASK) != ASF_PCB_END) + break; + + if (orig_HCR & CONTROL_DIR) { + /* If HCR.DIR is up, we pull it down. HSR.DIR should follow. */ + OUTB(orig_HCR & ~CONTROL_DIR,addr+PORT_CONTROL); + timeout = jiffies+30; + while (jiffies < timeout) + ; + if (INB(addr+PORT_STATUS) & STATUS_DIR) { + OUTB(orig_HCR,addr+PORT_CONTROL); + return 2; + } + } else { + /* If HCR.DIR is down, we pull it up. HSR.DIR should follow. */ + OUTB(orig_HCR | CONTROL_DIR,addr+PORT_CONTROL); + timeout = jiffies+300; + while (jiffies < timeout) + ; + if (!(INB(addr+PORT_STATUS) & STATUS_DIR)) { + OUTB(orig_HCR,addr+PORT_CONTROL); + return 3; + } + } + return 0; /* It certainly looks like a 3c505. */ } +/************************************************************* + * + * Search through addr_list[] and try to find a 3C505 + * Called only by eplus_probe + *************************************************************/ + +static int elp_autodetect(struct device * dev) +{ + int idx=0, addr; + + /* if base address set, then only check that address + otherwise, run through the table */ + if ( (addr=dev->base_addr) ) { /* dev->base_addr == 0 ==> plain autodetect */ + if (elp_debug > 0) + printk(search_msg, dev->name, addr); + if (elp_sense(addr) == 0) + { + if (elp_debug > 0) + printk(found_msg); + return addr; + } else if (elp_debug > 0) + printk(notfound_msg); + } else while ( (addr=addr_list[idx++]) ) { + if (elp_debug > 0) + printk(search_msg, dev->name, addr); + if (elp_sense(addr) == 0) { + if (elp_debug > 0) + printk(found_msg); + return addr; + } else if (elp_debug > 0) + printk(notfound_msg); + } + + /* could not find an adapter */ + if (elp_debug == 0) + printk(couldnot_msg, dev->name); + return 0; /* Because of this, the layer above will return -ENODEV */ +} /****************************************************** * * probe for an Etherlink Plus board at the specified address - * by attempting to get the ethernet address. * ******************************************************/ -int elp_probe(struct device *dev) +int elplus_probe(struct device *dev) { elp_device adapter; int i; + CHECK_NULL(dev); + /* * setup adapter structure */ - adapter.io_addr = dev->base_addr; - printk ("%s: probing for 3c505...", dev->name); + adapter.io_addr = dev->base_addr = elp_autodetect(dev); + if ( !adapter.io_addr ) + return -ENODEV; /* - * get the adapter's undivided attention (if it's there!) + * As we enter here from bootup, the adapter should have IRQs enabled, + * but we can as well enable them anyway. */ - adapter_hard_reset(&adapter); + OUTB(INB(dev->base_addr+PORT_CONTROL) | CONTROL_CMDE, + dev->base_addr+PORT_CONTROL); + autoirq_setup(0); /* * use ethernet address command to probe for board in polled mode + * (this also makes us the IRQ that we need for automatic detection) */ adapter.tx_pcb.command = CMD_STATION_ADDRESS; adapter.tx_pcb.length = 0; @@ -926,16 +1492,59 @@ !receive_pcb(&adapter, &adapter.rx_pcb) || (adapter.rx_pcb.command != CMD_ADDRESS_RESPONSE) || (adapter.rx_pcb.length != 6)) { - printk("not found\n"); + printk("%s: not responding to first PCB\n", dev->name); return -ENODEV; } - + if (dev->irq) { /* Is there a preset IRQ? */ + if (dev->irq != autoirq_report(0)) { + printk("%s: Detected IRQ doesn't match user-defined one.\n",dev->name); + return -ENODEV; + } + /* if dev->irq == autoirq_report(0), all is well */ + } else /* No preset IRQ; just use what we can detect */ + dev->irq=autoirq_report(0); + switch (dev->irq) { /* Legal, sane? */ + case 0: printk("%s: No IRQ reported by autoirq_report().\n",dev->name); + printk("%s: Check the jumpers of your 3c505 board.\n",dev->name); + return -ENODEV; + case 1: + case 6: + case 8: + case 13: + printk("%s: Impossible IRQ %d reported by autoirq_report().\n", + dev->name, + dev->irq); + return -ENODEV; + } + /* + * Now we have the IRQ number so we can disable the interrupts from + * the board until the board is opened. + */ + OUTB(INB(dev->base_addr+PORT_CONTROL) & ~CONTROL_CMDE, + dev->base_addr+PORT_CONTROL); + + /* + * copy ethernet address into structure + */ for (i = 0; i < 6; i++) - dev->dev_addr[i] = adapter.rx_pcb.data[i]; + dev->dev_addr[i] = adapter.rx_pcb.data.eth_addr[i]; - printk("found at port 0x%x, address = %s\n", dev->base_addr, eth_print(dev->dev_addr)); + /* + * print remainder of startup message + */ +#if (ELP_KERNEL_TYPE < 2) + printk("%s: 3c505 card found at I/O 0x%x using IRQ%d has address %s\n", + dev->name, dev->base_addr, dev->irq, eth_print(dev->dev_addr)); +#else + printk("%s: 3c505 card found at I/O 0x%x using IRQ%d has address %02x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, dev->base_addr, dev->irq, + dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); +#endif + /* + * initialise the device + */ elp_init(dev); return 0; } - diff -u --recursive --new-file v1.1.24/linux/drivers/net/3c505.h linux/drivers/net/3c505.h --- v1.1.24/linux/drivers/net/3c505.h Mon Jun 27 16:46:59 1994 +++ linux/drivers/net/3c505.h Thu Jul 7 18:28:28 1994 @@ -72,7 +72,7 @@ * *****************************************************************/ -#define TIMEOUT 10000 +#define TIMEOUT 300 /***************************************************************** * @@ -101,6 +101,7 @@ CMD_SELF_TEST = 0x0f, CMD_SET_STATION_ADDRESS = 0x10, CMD_ADAPTER_INFO = 0x11, + NUM_TRANSMIT_CMDS, /* * adapter PCB commands diff -u --recursive --new-file v1.1.24/linux/drivers/net/3c505dta.h linux/drivers/net/3c505dta.h --- v1.1.24/linux/drivers/net/3c505dta.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/3c505dta.h Thu Jul 7 18:28:28 1994 @@ -0,0 +1,119 @@ +/* This header file defines some data structures used by the 3c505 driver */ + +/* Data units */ +typedef unsigned char byte; +typedef unsigned short int word; +typedef unsigned long int dword; + + +/* Data structures */ +struct Memconf { + word cmd_q, + rcv_q, + mcast, + frame, + rcv_b, + progs; +}; + +struct Rcv_pkt { + word buf_ofs, + buf_seg, + buf_len, + timeout; +}; + +struct Xmit_pkt { + word buf_ofs, + buf_seg, + pkt_len; +}; + +struct Rcv_resp { + word buf_ofs, + buf_seg, + buf_len, + pkt_len, + timeout, + status; + dword timetag; +}; + +struct Xmit_resp { + word buf_ofs, + buf_seg, + c_stat, + status; +}; + + +struct Netstat { + dword tot_recv, + tot_xmit; + word err_CRC, + err_align, + err_res, + err_ovrrun; +}; + + +struct Selftest { + word error; + union { + word ROM_cksum; + struct { + word ofs, seg; + } RAM; + word i82586; + } failure; +}; + +struct Info { + byte minor_vers, + major_vers; + word ROM_cksum, + RAM_sz, + free_ofs, + free_seg; +}; + +struct Memdump { + word size, + off, + seg; +}; + +/* +Primary Command Block. The most important data structure. All communication +between the host and the adapter is done with these. (Except for the ethernet +data, which has different packaging.) +*/ +typedef struct { + byte command; + byte length; + union { + struct Memconf memconf; + word configure; + struct Rcv_pkt rcv_pkt; + struct Xmit_pkt xmit_pkt; + byte multicast[10][6]; + byte eth_addr[6]; + byte failed; + struct Rcv_resp rcv_resp; + struct Xmit_resp xmit_resp; + struct Netstat netstat; + struct Selftest selftest; + struct Info info; + struct Memdump memdump; + byte raw[62]; + } data; +} pcb_struct; + +/* These defines for 'configure' */ +#define RECV_STATION 0x00 +#define RECV_BROAD 0x01 +#define RECV_MULTI 0x02 +#define RECV_ALL 0x04 +#define NO_LOOPBACK 0x00 +#define INT_LOOPBACK 0x08 +#define EXT_LOOPBACK 0x10 diff -u --recursive --new-file v1.1.24/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v1.1.24/linux/drivers/net/Makefile Wed Jun 22 14:57:08 1994 +++ linux/drivers/net/Makefile Thu Jul 7 18:05:15 1994 @@ -20,6 +20,10 @@ net_init.o: ../../include/linux/autoconf.h +ifdef CONFIG_SK_G16 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(sk_g16.o) +endif + ifdef CONFIG_WD80x3 NETDRV_OBJS := $(NETDRV_OBJS) net.a(wd.o) CONFIG_8390 = CONFIG_8390 @@ -46,6 +50,11 @@ CONFIG_8390 = CONFIG_8390 hp.o: hp.c CONFIG $(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c $< +endif + +ifdef CONFIG_HPLAN_PLUS +NETDRV_OBJS := $(NETDRV_OBJS) net.a(hp-plus.o) +CONFIG_8390 = CONFIG_8390 endif ifdef CONFIG_ULTRA diff -u --recursive --new-file v1.1.24/linux/drivers/net/README.3c505 linux/drivers/net/README.3c505 --- v1.1.24/linux/drivers/net/README.3c505 Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/README.3c505 Thu Jul 7 18:28:28 1994 @@ -0,0 +1,35 @@ +The address and IRQ used by the 3c505 driver can be configured at boot +time by typing 'ether=eth0,15,0x300' (replace IRQ and base address with +ones that tell how your adapter is jumpered). + +If no base address is given at the boot time, the driver will look for +a 3c505 adapter at addresses 0x300, 0x280 and 0x310 in this order, +possibly messing up any other hardware residing in these addresses. +If a base address is given, it will be verified. + +There's two #defines one may need to change in the 3c505 driver: +ELP_KERNEL_TYPE + this exists just to adapt the driver with pretty wide range of kernels. + See 3c505.c for exact information. + +ELP_NEED_HARD_RESET + some DOS drivers seem to get the adapter to some irrecoverable state + if the machine is "warm booted" from DOS to Linux. If you experience + problems when warm booting, but "cold boot" works, #defining this + to 1 may help. + + +Known problems: + when 'ifconfig up' is run for the first time after bootup, the driver + complains: +elp_interrupt(): irq 15 for unknown device. + ^^ + There should be the IRQ the ELPlus adapter is using. IF the IRQ doesn't + match, something is seriously wrong. + +Authors: + The driver is mainly written by Craig Southeren, email c/o + . + Parts of the driver (adapting the driver to 1.1.4+ kernels, + IRQ/address detection, minor changes) and this (lousy) 'readme' + by Juha Laiho . diff -u --recursive --new-file v1.1.24/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v1.1.24/linux/drivers/net/Space.c Wed Jun 22 14:57:08 1994 +++ linux/drivers/net/Space.c Thu Jul 7 18:05:15 1994 @@ -42,6 +42,7 @@ extern int el2_probe(struct device *dev); extern int ne_probe(struct device *dev); extern int hp_probe(struct device *dev); +extern int hp_plus_probe(struct device *dev); extern int znet_probe(struct device *); extern int express_probe(struct device *); extern int el3_probe(struct device *); @@ -53,6 +54,7 @@ extern int elplus_probe(struct device *); extern int ac3200_probe(struct device *); extern int e2100_probe(struct device *); +extern int SK_init(struct device *dev); /* Detachable devices ("pocket adaptors" and special PCMCIA drivers). */ extern int atp_init(struct device *); @@ -83,6 +85,9 @@ #if defined(CONFIG_HPLAN) || defined(HPLAN) && hp_probe(dev) #endif +#if defined(CONFIG_HPLAN_PLUS) + && hp_plus_probe(dev) +#endif #ifdef CONFIG_AT1500 && at1500_probe(dev) #endif @@ -121,6 +126,9 @@ #endif #ifdef CONFIG_DE620 /* D-Link DE-620 adapter */ && de620_probe(dev) +#endif +#if defined(CONFIG_SK_G16) + && SK_init(dev) #endif && 1 ) { return 1; /* -ENODEV or -EAGAIN would be more accurate. */ diff -u --recursive --new-file v1.1.24/linux/drivers/net/ac3200.c linux/drivers/net/ac3200.c --- v1.1.24/linux/drivers/net/ac3200.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/ac3200.c Thu Jul 7 18:05:43 1994 @@ -0,0 +1,275 @@ +/* ac3200.c: A driver for the Ansel Communications EISA ethernet adaptor. */ +/* + Written 1993, 1994 by Donald Becker. + Copyright 1993 United States Government as represented by the Director, + National Security Agency. This software may only be used and distributed + according to the terms of the GNU Public License as modified by SRC, + incorporated herein by reference. + + The author may be reached as becker@cesdis.gsfc.nasa.gov, or + C/O Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + This is driver for the Ansel Communications Model 3200 EISA Ethernet LAN + Adapter. The programming information is from the users manual, as related + by glee@ardnassak.math.clemson.edu. + */ + +static char *version = + "ac3200.c:v1.01 7/1/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; + +#include +#include +#include +#include +#include +#include +#include + +#include +#include "8390.h" + +/* Offsets from the base address. */ +#define AC_NIC_BASE 0x00 +#define AC_SA_PROM 0x16 /* The station address PROM. */ +#define AC_ADDR0 0x00 /* Prefix station address values. */ +#define AC_ADDR1 0x40 /* !!!!These are just guesses!!!! */ +#define AC_ADDR2 0x90 +#define AC_ID_PORT 0xC80 +#define AC_EISA_ID 0x0110d305 +#define AC_RESET_PORT 0xC84 +#define AC_RESET 0x00 +#define AC_ENABLE 0x01 +#define AC_CONFIG 0xC90 /* The configuration port. */ + +/* Decoding of the configuration register. */ +static unsigned char config2irqmap[8] = {15, 12, 11, 10, 9, 7, 5, 3}; +static int addrmap[8] = +{0xFF0000, 0xFE0000, 0xFD0000, 0xFFF0000, 0xFFE0000, 0xFFC0000, 0xD0000, 0 }; +static char *port_name[4] = { "10baseT", "invalid", "AUI", "10base2"}; + +#define config2irq(configval) config2irqmap[((configval) >> 3) & 7] +#define config2mem(configval) addrmap[(configval) & 7] +#define config2name(configval) port_name[((configval) >> 6) & 3] + +/* First and last 8390 pages. */ +#define AC_START_PG 0x00 /* First page of 8390 TX buffer */ +#define AC_STOP_PG 0x80 /* Last page +1 of the 8390 RX ring */ + +int ac3200_probe(struct device *dev); +static int ac_probe1(int ioaddr, struct device *dev); + +static int ac_open(struct device *dev); +static void ac_reset_8390(struct device *dev); +static int ac_block_input(struct device *dev, int count, + char *buf, int ring_offset); +static void ac_block_output(struct device *dev, const int count, + const unsigned char *buf, const int start_page); +static int ac_close_card(struct device *dev); + + +/* Probe for the AC3200. + + The AC3200 can be identified by either the EISA configuration registers, + or the unique value in the station address PROM. + */ + +int ac3200_probe(struct device *dev) +{ + unsigned short ioaddr = dev->base_addr; + + if (ioaddr > 0x1ff) /* Check a single specified location. */ + return ac_probe1(ioaddr, dev); + else if (ioaddr > 0) /* Don't probe at all. */ + return ENXIO; + + /* If you have a pre-pl15 machine you should delete this line. */ + if ( ! EISA_bus) + return ENXIO; + + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) + if (ac_probe1(ioaddr, dev) == 0) + return 0; + + return ENODEV; +} + +static int ac_probe1(int ioaddr, struct device *dev) +{ + int i; + +#ifndef final_version + printk("AC3200 ethercard probe at %#3x:", ioaddr); + + for(i = 0; i < 6; i++) + printk(" %02x", inb(ioaddr + AC_SA_PROM + i)); +#endif + + /* !!!!The values of AC_ADDRn (see above) should be corrected when we + find out the correct station address prefix!!!! */ + if (inb(ioaddr + AC_SA_PROM + 0) != AC_ADDR0 + || inb(ioaddr + AC_SA_PROM + 1) != AC_ADDR1 + || inb(ioaddr + AC_SA_PROM + 2) != AC_ADDR2 ) { +#ifndef final_version + printk(" not found (invalid prefix).\n"); +#endif + return ENODEV; + } + + /* The correct probe method is to check the EISA ID. */ + for (i = 0; i < 4; i++) + if (inl(ioaddr + AC_ID_PORT) != AC_EISA_ID) { + printk("EISA ID mismatch, %8x vs %8x.\n", + inl(ioaddr + AC_EISA_ID), AC_EISA_ID); + return ENODEV; + } + + for(i = 0; i < ETHER_ADDR_LEN; i++) + dev->dev_addr[i] = inb(ioaddr + AC_SA_PROM + i); + +#ifndef final_version + printk("\nAC3200 ethercard configuration register is %#02x," + " EISA ID %02x %02x %02x %02x.\n", inb(ioaddr + AC_CONFIG), + inb(ioaddr + AC_ID_PORT + 0), inb(ioaddr + AC_ID_PORT + 1), + inb(ioaddr + AC_ID_PORT + 2), inb(ioaddr + AC_ID_PORT + 3)); +#endif + + /* Assign and snarf the interrupt now. */ + if (dev->irq == 0) + dev->irq = config2irq(inb(ioaddr + AC_CONFIG)); + else if (dev->irq == 2) + dev->irq = 9; + + if (irqaction (dev->irq, &ei_sigaction)) { + printk (" unable to get IRQ %d.\n", dev->irq); + return 0; + } + + dev->base_addr = ioaddr; + +#ifdef notyet + if (dev->mem_start) { /* Override the value from the board. */ + for (i = 0; i < 7; i++) + if (addrmap[i] == dev->mem_start) + break; + if (i >= 7) + i = 0; + outb((inb(ioaddr + AC_CONFIG) & ~7) | i, ioaddr + AC_CONFIG); + } +#endif + + dev->if_port = inb(ioaddr + AC_CONFIG) >> 6; + dev->mem_start = config2mem(inb(ioaddr + AC_CONFIG)); + dev->rmem_start = dev->mem_start + TX_PAGES*256; + dev->mem_end = dev->rmem_end = dev->mem_start + + (AC_STOP_PG - AC_START_PG)*256; + + ethdev_init(dev); + + ei_status.name = "AC3200"; + ei_status.tx_start_page = AC_START_PG; + ei_status.rx_start_page = AC_START_PG + TX_PAGES; + ei_status.stop_page = AC_STOP_PG; + ei_status.word16 = 1; + + printk("\n%s: AC3200 at %#x, IRQ %d, %s port, shared memory %#lx-%#lx.\n", + dev->name, ioaddr, dev->irq, port_name[dev->if_port], + dev->mem_start, dev->mem_end-1); + + if (ei_debug > 0) + printk(version); + + ei_status.reset_8390 = &ac_reset_8390; + ei_status.block_input = &ac_block_input; + ei_status.block_output = &ac_block_output; + + dev->open = &ac_open; + dev->stop = &ac_close_card; + NS8390_init(dev, 0); + return 0; +} + +static int ac_open(struct device *dev) +{ +#ifdef notyet + /* Someday we may enable the IRQ and shared memory here. */ + int ioaddr = dev->base_addr; + + if (irqaction(dev->irq, &ei_sigaction)) + return -EAGAIN; +#endif + + return ei_open(dev); +} + +static void ac_reset_8390(struct device *dev) +{ + ushort ioaddr = dev->base_addr; + + outb(AC_RESET, ioaddr + AC_RESET_PORT); + if (ei_debug > 1) printk("resetting AC3200, t=%ld...", jiffies); + + ei_status.txing = 0; + outb(AC_ENABLE, ioaddr + AC_RESET_PORT); + if (ei_debug > 1) printk("reset done\n"); + + return; +} + +/* Block input and output are easy on shared memory ethercards, the only + complication is when the ring buffer wraps. */ + +static int ac_block_input(struct device *dev, int count, char *buf, + int ring_offset) +{ + long xfer_start = dev->mem_start + ring_offset - (AC_START_PG<<8); + + if (xfer_start + count > dev->rmem_end) { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + memcpy(buf, (char*)xfer_start, semi_count); + count -= semi_count; + memcpy(buf + semi_count, (char *)dev->rmem_start, count); + return dev->rmem_start + count; + } + memcpy(buf, (char*)xfer_start, count); + + return ring_offset + count; +} + +static void ac_block_output(struct device *dev, int count, + const unsigned char *buf, int start_page) +{ + long shmem = dev->mem_start + ((start_page - AC_START_PG)<<8); + + memcpy((unsigned char *)shmem, buf, count); +} + +static int ac_close_card(struct device *dev) +{ + dev->start = 0; + dev->tbusy = 1; + + if (ei_debug > 1) + printk("%s: Shutting down ethercard.\n", dev->name); + +#ifdef notyet + /* We should someday disable shared memory and interrupts. */ + outb(0x00, ioaddr + 6); /* Disable interrupts. */ + free_irq(dev->irq); + irq2dev_map[dev->irq] = 0; +#endif + + NS8390_init(dev, 0); + + return 0; +} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c ac3200.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ Only in v1.1.24/linux/drivers/net: ac32000.c diff -u --recursive --new-file v1.1.24/linux/drivers/net/hp-plus.c linux/drivers/net/hp-plus.c --- v1.1.24/linux/drivers/net/hp-plus.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/hp-plus.c Thu Jul 7 18:03:36 1994 @@ -0,0 +1,366 @@ +/* hp-plus.c: A HP PCLAN/plus ethernet driver for linux. */ +/* + Written 1994 by Donald Becker. + + This driver is for the Hewlett Packard PC LAN (27***) plus ethercards. + These cards are sold under several model numbers, usually 2724*. + + This software may be used and distributed according to the terms + of the GNU Public License, incorporated herein by reference. + + The author may be reached as becker@CESDIS.gsfc.nasa.gov, or C/O + + Center of Excellence in Space Data and Information Sciences + Code 930.5, Goddard Space Flight Center, Greenbelt MD 20771 + + As is often the case, a great deal of credit is owed to Russ Nelson. + The Crynwr packet driver was my primary source of HP-specific + programming information. +*/ + +static char *version = +"hp-plus.c:v0.04 6/16/94 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; + +#include +#include /* Important -- this inlines word moves. */ +#include +#include +#include +#include +#include +#include + +#ifdef start_bh_atomic /* This checks for kernels >= 1.1.0. */ +#include +#include +#else +#include "dev.h" +#endif + +#include "8390.h" + +/* + The HP EtherTwist chip implementation is a fairly routine DP8390 + implementation. It allows both shared memory and programmed-I/O buffer + access, using a custom interface for both. The programed-I/O mode is + entirely implemented in the HP EtherTwist chip, bypassing the problem + ridden built-in 8390 facilities used on NE2000 designs. The shared + memory mode is likewise special, with an offset register used to make + packets appear at the shared memory base. Both modes use a base and bounds + page register to hide the Rx ring buffer wrap -- a packet that spans the + end of physical buffer memory appears continuous to the driver. (c.f. the + 3c503 and Cabletron E2100) + + A special note: the internal buffer of the board is only 8 bits wide. + This lays several nasty traps for the unaware: + - the 8390 must be programmed for byte-wide operations + - all I/O and memory operations must work on whole words (the access + latches are serially preloaded and have no byte-swapping ability). + + This board is laid out in I/O space much like the earlier HP boards: + the first 16 locations are for the board registers, and the second 16 are + for the 8390. The board is easy to identify, with both a dedicated 16 bit + ID register and a constant 0x530* value in the upper bits of the paging + register. +*/ + +#define HPP_PROBE_LIST {0x200, 0x240, 0x280, 0x2C0, 0x300, 0x320, 0x340, 0} + +#define HP_IO_EXTENT 32 + +#define HP_ID 0x00 /* ID register, always 0x4850. */ +#define HP_PAGING 0x02 /* Registers visible @ 8-f, see PageName. */ +#define HPP_OPTION 0x04 /* Bitmapped options, see HP_Option. */ +#define HPP_OUT_ADDR 0x08 /* I/O output location in Perf_Page. */ +#define HPP_IN_ADDR 0x0A /* I/O input location in Perf_Page. */ +#define HP_DATAPORT 0x0c /* I/O data transfer in Perf_Page. */ +#define NIC_OFFSET 0x10 /* Offset to the 8390 registers. */ + +#define HP_START_PG 0x00 /* First page of TX buffer */ +#define HP_STOP_PG 0x80 /* Last page +1 of RX ring */ + +/* The register set selected in HP_PAGING. */ +enum PageName { + Perf_Page = 0, /* Normal operation. */ + MAC_Page = 1, /* The ethernet address (+checksum). */ + HW_Page = 2, /* EEPROM-loaded hardware parameters. */ + LAN_Page = 4, /* Transceiver selection, testing, etc. */ + ID_Page = 6 }; + +/* The bit definitions for the HPP_OPTION register. */ +enum HP_Option { + NICReset = 1, ChipReset = 2, /* Active low, really UNreset. */ + EnableIRQ = 4, FakeIntr = 8, BootROMEnb = 0x10, IOEnb = 0x20, + MemEnable = 0x40, ZeroWait = 0x80, MemDisable = 0x1000, }; + +int hpplus_probe(struct device *dev); +int hpp_probe1(struct device *dev, int ioaddr); + +static void hpp_reset_8390(struct device *dev); +static int hpp_open(struct device *dev); +static int hpp_close(struct device *dev); +static int hpp_mem_block_input(struct device *dev, int count, + char *buf, int ring_offset); +static void hpp_mem_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page); +static int hpp_io_block_input(struct device *dev, int count, + char *buf, int ring_offset); +static void hpp_io_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page); + + +/* Probe a list of addresses for an HP LAN+ adaptor. + This routine is almost boilerplate. */ + +int hp_plus_probe(struct device *dev) +{ + int *port, ports[] = HPP_PROBE_LIST; + short ioaddr = dev->base_addr; + + if (ioaddr > 0x1ff) /* Check a single specified location. */ + return hpp_probe1(dev, ioaddr); + else if (ioaddr > 0) /* Don't probe at all. */ + return ENXIO; + + for (port = &ports[0]; *port; port++) { + if (check_region(*port, HP_IO_EXTENT)) + continue; + if (hpp_probe1(dev, *port) == 0) { + return 0; + } + } + return ENODEV; +} + +/* Do the interesting part of the probe at a single address. */ +int hpp_probe1(struct device *dev, int ioaddr) +{ + int i; + unsigned char checksum = 0; + char *name = "HP-PC-LAN+"; + unsigned char *station_addr = dev->dev_addr; + int mem_start; + + /* Check for the HP+ signature, 50 48 0x 53. */ + if (inw(ioaddr + HP_ID) != 0x4850 + || (inw(ioaddr + HP_PAGING) & 0xfff0) != 0x5300) + return ENODEV; + + /* OK, we think that we have it. Get and checksum the physical address. */ + printk("%s: %s at %#3x,", dev->name, name, ioaddr); + + /* Retrieve and checksum the station address. */ + outw(MAC_Page, ioaddr + HP_PAGING); + + for(i = 0; i < ETHER_ADDR_LEN; i++) { + unsigned char inval = inb(ioaddr + 8 + i); + station_addr[i] = inval; + checksum += inval; + printk(" %2.2x", inval); + } + checksum += inb(ioaddr + 14); + + if (checksum != 0xff) { + printk(" bad checksum %2.2x.\n", checksum); + return ENODEV; + } else { + /* Point at the Software Configuration Flags. */ + outw(ID_Page, ioaddr + HP_PAGING); + printk(" ID %4.4x", inw(ioaddr + 12)); + } + + /* Grab the region so we can find another board if something fails. */ + snarf_region(ioaddr, HP_IO_EXTENT); + + /* Read the IRQ line. */ + outw(HW_Page, ioaddr + HP_PAGING); + { + int irq = inb(ioaddr + 13) & 0x0f; + int option = inw(ioaddr + HPP_OPTION); + + dev->irq = irq; + if (option & MemEnable) { + mem_start = inw(ioaddr + 9) << 8; + printk(", IRQ %d, memory address %#x.\n", irq, mem_start); + } else { + mem_start = 0; + printk(", IRQ %d, programmed-I/O mode.\n", irq); + } + } + + printk( "%s%s", KERN_INFO, version); + + /* Set the wrap registers for string I/O reads. */ + outw((HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8), ioaddr + 14); + + /* Set the base address to point to the NIC, not the "real" base! */ + dev->base_addr = ioaddr + NIC_OFFSET; + + ethdev_init(dev); + + dev->open = &hpp_open; + dev->stop = &hpp_close; + + ei_status.name = name; + ei_status.word16 = 0; /* Agggghhhhh! Debug time: 2 days! */ + ei_status.tx_start_page = HP_START_PG; + ei_status.rx_start_page = HP_START_PG + TX_2X_PAGES; + ei_status.stop_page = HP_STOP_PG; + + ei_status.reset_8390 = &hpp_reset_8390; + ei_status.block_input = &hpp_io_block_input; + ei_status.block_output = &hpp_io_block_output; + + /* Check if the memory_enable flag is set in the option register. */ + if (mem_start) { + ei_status.block_input = &hpp_mem_block_input; + ei_status.block_output = &hpp_mem_block_output; + dev->mem_start = mem_start; + dev->rmem_start = dev->mem_start + TX_2X_PAGES*256; + dev->mem_end = dev->rmem_end + = dev->mem_start + (HP_STOP_PG - HP_START_PG)*256; + } + + outw(Perf_Page, ioaddr + HP_PAGING); + NS8390_init(dev, 0); + /* Leave the 8390 and HP chip reset. */ + outw(inw(ioaddr + HPP_OPTION) & ~EnableIRQ, ioaddr + HPP_OPTION); + + return 0; +} + +static int +hpp_open(struct device *dev) +{ + int ioaddr = dev->base_addr - NIC_OFFSET; + int option_reg; + + if (request_irq(dev->irq, &ei_interrupt)) { + return -EAGAIN; + } + + /* Reset the 8390 and HP chip. */ + option_reg = inw(ioaddr + HPP_OPTION); + outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION); + SLOW_DOWN_IO; SLOW_DOWN_IO; + /* Unreset the board and enable interrupts. */ + outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION); + + /* Set the wrap registers for programmed-I/O operation. */ + outw(HW_Page, ioaddr + HP_PAGING); + outw((HP_START_PG + TX_2X_PAGES) | ((HP_STOP_PG - 1) << 8), ioaddr + 14); + + /* Select the operational page. */ + outw(Perf_Page, ioaddr + HP_PAGING); + + return ei_open(dev); +} + +static int +hpp_close(struct device *dev) +{ + int ioaddr = dev->base_addr - NIC_OFFSET; + int option_reg = inw(ioaddr + HPP_OPTION); + + free_irq(dev->irq); + irq2dev_map[dev->irq] = NULL; + NS8390_init(dev, 0); + outw((option_reg & ~EnableIRQ) | MemDisable | NICReset | ChipReset, + ioaddr + HPP_OPTION); + + return 0; +} + +static void +hpp_reset_8390(struct device *dev) +{ + int ioaddr = dev->base_addr - NIC_OFFSET; + int option_reg = inw(ioaddr + HPP_OPTION); + + if (ei_debug > 1) printk("resetting the 8390 time=%ld...", jiffies); + + outw(option_reg & ~(NICReset + ChipReset), ioaddr + HPP_OPTION); + /* Pause a few cycles for the hardware reset to take place. */ + SLOW_DOWN_IO; + SLOW_DOWN_IO; + ei_status.txing = 0; + outw(option_reg | (EnableIRQ + NICReset + ChipReset), ioaddr + HPP_OPTION); + + SLOW_DOWN_IO; SLOW_DOWN_IO; + + + if ((inb_p(ioaddr+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0) + printk("%s: hp_reset_8390() did not complete.\n", dev->name); + + if (ei_debug > 1) printk("8390 reset done (%ld).", jiffies); + return; +} + +/* Block input and output, similar to the Crynwr packet driver. + Note that transfer with the EtherTwist+ must be on word boundaries. */ + +static int +hpp_io_block_input(struct device *dev, int count, char *buf, int ring_offset) +{ + int ioaddr = dev->base_addr - NIC_OFFSET; + + outw(ring_offset, ioaddr + HPP_IN_ADDR); + insw(ioaddr + HP_DATAPORT, buf, count>>1); + if (count & 0x01) + buf[count-1] = inw(ioaddr + HP_DATAPORT); + return ring_offset + count; +} + +static int +hpp_mem_block_input(struct device *dev, int count, char *buf, int ring_offset) +{ + int ioaddr = dev->base_addr - NIC_OFFSET; + int option_reg = inw(ioaddr + HPP_OPTION); + + outw(ring_offset, ioaddr + HPP_IN_ADDR); + + outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION); + /* Caution: this relies on 8390.c rounding up allocations! */ + memcpy(buf, (char*)dev->mem_start, (count + 3) & ~3); + outw(option_reg, ioaddr + HPP_OPTION); + + return ring_offset + count; +} + +/* A special note: we *must* always transfer >=16 bit words. + It's always safe to round up, so we do. */ +static void +hpp_io_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page) +{ + int ioaddr = dev->base_addr - NIC_OFFSET; + outw(start_page << 8, ioaddr + HPP_OUT_ADDR); + outsl(ioaddr + HP_DATAPORT, buf, (count+3)>>2); + return; +} + +static void +hpp_mem_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page) +{ + int ioaddr = dev->base_addr - NIC_OFFSET; + int option_reg = inw(ioaddr + HPP_OPTION); + + outw(start_page << 8, ioaddr + HPP_OUT_ADDR); + outw(option_reg & ~(MemDisable + BootROMEnb), ioaddr + HPP_OPTION); + memcpy((char *)dev->mem_start, buf, (count + 3) & ~3); + outw(option_reg, ioaddr + HPP_OPTION); + + return; +} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp-plus.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * c-indent-level: 4 + * End: + */ diff -u --recursive --new-file v1.1.24/linux/drivers/net/sk_g16.c linux/drivers/net/sk_g16.c --- v1.1.24/linux/drivers/net/sk_g16.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/sk_g16.c Thu Jul 7 17:56:36 1994 @@ -0,0 +1,2119 @@ +/*- + * Copyright (C) 1994 by PJD Weichmann & SWS Bern, Switzerland + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * Module : sk_g16.c + * + * Version : $Revision: 1.1 $ + * + * Author : Patrick J.D. Weichmann + * + * Date Created : 94/05/26 + * Last Updated : $Date: 1994/06/30 16:25:15 $ + * + * Description : Schneider & Koch G16 Ethernet Device Driver for + * Linux Kernel >= 1.1.22 + * Update History : + * +-*/ + +static char *rcsid = "$Id: sk_g16.c,v 1.1 1994/06/30 16:25:15 root Exp $"; + +/* + * The Schneider & Koch (SK) G16 Network device driver is based + * on the 'ni6510' driver from Michael Hipp which can be found at + * ftp://sunsite.unc.edu/pub/Linux/system/Network/drivers/nidrivers.tar.gz + * + * Sources: 1) ni6510.c by M. Hipp + * 2) depca.c by D.C. Davies + * 3) skeleton.c by D. Becker + * 4) Am7990 Local Area Network Controller for Ethernet (LANCE), + * AMD, Pub. #05698, June 1989 + * + * Many Thanks for helping me to get things working to: + * + * A. Cox (A.Cox@swansea.ac.uk) + * M. Hipp (mhipp@student.uni-tuebingen.de) + * R. Bolz (Schneider & Koch, Germany) + * + * See README.sk_g16 for details about limitations and bugs for the + * current version. + * + * To Do: + * - Support of SK_G8 and other SK Network Cards. + * - Autoset memory mapped RAM. Check for free memory and then + * configure RAM correctly. + * - SK_close should really set card in to initial state. + * - Test if IRQ 3 is not switched off. Use autoirq() functionality. + * (as in /drivers/net/skeleton.c) + * - Implement Multicast addressing. At minimum something like + * in depca.c. + * - Redo the statistics part. + * - Try to find out if the board is in 8 Bit or 16 Bit slot. + * If in 8 Bit mode don't use IRQ 11. + * - (Try to make it slightly faster.) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "sk_g16.h" + +/* + * Schneider & Koch Card Definitions + * ================================= + */ + +#define SK_NAME "SK_G16" + +/* + * SK_G16 Configuration + * -------------------- + */ + +/* + * Abbreviations + * ------------- + * + * RAM - used for the 16KB shared memory + * Boot_ROM, ROM - are used for referencing the BootEPROM + * + * SK_BOOT_ROM and SK_ADDR are symbolic constants used to configure + * the behaviour of the driver and the SK_G16. + * + * ! See sk_g16.install on how to install and configure the driver ! + * + * SK_BOOT_ROM defines if the Boot_ROM should be switched off or not. + * + * SK_ADDR defines the address where the RAM will be mapped into the real + * host memory. + * valid addresses are from 0xa0000 to 0xfc000 in 16Kbyte steps. + */ + +#define SK_BOOT_ROM 1 /* 1=BootROM on 0=off */ + +#define SK_ADDR 0xcc000 + +/* + * In POS3 are bits A14-A19 of the address bus. These bits can be set + * to choose the RAM address. Thats why we only can choose the RAM address + * in 16KB steps. + */ + +#define POS_ADDR (rom_addr>>14) /* Do not change this line */ + +/* + * SK_G16 I/O PORT's + IRQ's + Boot_ROM locations + * ---------------------------------------------- + */ + +/* + * As nearly every card has also SK_G16 a specified I/O Port region and + * only a few possible IRQ's. + * In the Installation Guide from Schneider & Koch is listed a possible + * Interrupt IRQ2. IRQ2 is always IRQ9 in boards with two cascaded interrupt + * controllers. So we use in SK_IRQS IRQ9. + */ + +/* Don't touch any of the following #defines. */ + +#define SK_IO_PORTS { 0x100, 0x180, 0x208, 0x220, 0x288, 0x320, 0x328, 0x390, 0 } + +#define SK_IRQS { 3, 5, 9, 11, 0 } + +#define SK_BOOT_ROM_LOCATIONS { 0xc0000, 0xc4000, 0xc8000, 0xcc000, 0xd0000, 0xd4000, 0xd8000, 0xdc000, 0 } + +#define SK_BOOT_ROM_ID { 0x55, 0xaa, 0x10, 0x50, 0x06, 0x33 } + +/* + * SK_G16 POS REGISTERS + * -------------------- + */ + +/* + * SK_G16 has a Programmable Option Select (POS) Register. + * The POS is composed of 8 separate registers (POS0-7) which + * are I/O mapped on an address set by the W1 switch. + * + */ + +#define SK_POS_SIZE 8 /* 8 I/O Ports are used by SK_G16 */ + +#define SK_POS0 ioaddr /* Card-ID Low (R) */ +#define SK_POS1 ioaddr+1 /* Card-ID High (R) */ +#define SK_POS2 ioaddr+2 /* Card-Enable, Boot-ROM Disable (RW) */ +#define SK_POS3 ioaddr+3 /* Base address of RAM */ +#define SK_POS4 ioaddr+4 /* IRQ */ + +/* POS5 - POS7 are unused */ + +/* + * SK_G16 MAC PREFIX + * ----------------- + */ + +/* + * Scheider & Koch manufactorer code (00:00:a5). + * This must be checked, that we are sure it is a SK card. + */ + +#define SK_MAC0 0x00 +#define SK_MAC1 0x00 +#define SK_MAC2 0x5a + +/* + * SK_G16 ID + * --------- + */ + +/* + * If POS0,POS1 contain the following ID, then we know + * at which I/O Port Address we are. + */ + +#define SK_IDLOW 0xfd +#define SK_IDHIGH 0x6a + + +/* + * LANCE POS Bit definitions + * ------------------------- + */ + +#define SK_ROM_RAM_ON (POS2_CARD) +#define SK_ROM_RAM_OFF (POS2_EPROM) +#define SK_ROM_ON (inb(SK_POS2) & POS2_CARD) +#define SK_ROM_OFF (inb(SK_POS2) | POS2_EPROM) +#define SK_RAM_ON (inb(SK_POS2) | POS2_CARD) +#define SK_RAM_OFF (inb(SK_POS2) & POS2_EPROM) + +#define POS2_CARD 0x0001 /* 1 = SK_G16 on 0 = off */ +#define POS2_EPROM 0x0002 /* 1 = Boot EPROM off 0 = on */ + +/* + * SK_G16 Memory mapped Registers + * ------------------------------ + * + */ + +#define SK_IOREG (board->ioreg) /* LANCE data registers. */ +#define SK_PORT (board->port) /* Control, Status register */ +#define SK_IOCOM (board->iocom) /* I/O Command */ + +/* + * SK_G16 Status/Control Register bits + * ----------------------------------- + * + * (C) Controlreg (S) Statusreg + */ + +/* + * Register transfer: 0 = no transfer + * 1 = transfering data between LANCE and I/O reg + */ +#define SK_IORUN 0x20 + +/* + * LANCE interrupt: 0 = LANCE interrupt occured + * 1 = no LANCE interrupt occured + */ +#define SK_IRQ 0x10 + +#define SK_RESET 0x08 /* Reset SK_CARD: 0 = RESET 1 = normal */ +#define SK_RW 0x02 /* 0 = write to 1 = read from */ +#define SK_ADR 0x01 /* 0 = REG DataPort 1 = RAP Reg addr port */ + + +#define SK_RREG SK_RW /* Transferdirection to read from lance */ +#define SK_WREG 0 /* Transferdirection to write to lance */ +#define SK_RAP SK_ADR /* Destination Register RAP */ +#define SK_RDATA 0 /* Destination Register REG DataPort */ + +/* + * SK_G16 I/O Command + * ------------------ + */ + +/* + * Any bitcombination sets the internal I/O bit (transfer will start) + * when written to I/O Command + */ + +#define SK_DOIO 0x80 /* Do Transfer */ + +/* + * LANCE RAP (Register Adress Port). + * --------------------------------- + */ + +/* + * The LANCE internal registers are selected through the RAP. + * The Registers are: + * + * CSR0 - Status and Control flags + * CSR1 - Low order bits of initialize block (bits 15:00) + * CSR2 - High order bits of initialize block (bits 07:00, 15:08 are reserved) + * CSR3 - Allows redifinition of the Bus Master Interface. + * This register must be set to 0x0002, which means BSWAP = 0, + * ACON = 1, BCON = 0; + * + */ + +#define CSR0 0x00 +#define CSR1 0x01 +#define CSR2 0x02 +#define CSR3 0x03 + +/* + * General Definitions + * =================== + */ + +/* + * Set the number of Tx and Rx buffers, using Log_2(# buffers). + * We have 16KB RAM which can be accessed by the LANCE. In the + * memory are not only the buffers but also the ring descriptors and + * the initialize block. + * Don't change anything unless you really know what you do. + */ + +#define LC_LOG_TX_BUFFERS 1 /* (2 == 2^^1) 2 Transmit buffers */ +#define LC_LOG_RX_BUFFERS 3 /* (8 == 2^^3) 8 Receive buffers */ + +/* Descriptor ring sizes */ + +#define TMDNUM (1 << (LC_LOG_TX_BUFFERS)) /* 2 Transmit descriptor rings */ +#define RMDNUM (1 << (LC_LOG_RX_BUFFERS)) /* 8 Receive Buffers */ + +/* Define Mask for setting RMD, TMD length in the LANCE init_block */ + +#define TMDNUMMASK (LC_LOG_TX_BUFFERS << 29) +#define RMDNUMMASK (LC_LOG_RX_BUFFERS << 29) + +/* + * Data Buffer size is set to maximum packet length. + */ + +#define PKT_BUF_SZ 1518 + +/* + * The number of low I/O ports used by the ethercard. + */ + +#define ETHERCARD_TOTAL_SIZE SK_POS_SIZE + +/* + * Portreserve is there to mark the Card I/O Port region as used. + * Check_region is to check if the region at ioaddr with the size "size" + * is free or not. + * Snarf_region allocates the I/O Port region. + */ + +#ifndef HAVE_PORTRESERVE + +#define check_region(ioaddr, size) 0 +#define snarf_region(ioaddr, size); do ; while (0) + +#endif + +/* + * SK_DEBUG + * + * Here you can choose what level of debugging wanted. + * + * If SK_DEBUG and SK_DEBUG2 are undefined, then only the + * necessary messages will be printed. + * + * If SK_DEBUG is defined, there will be many debugging prints + * which can help to find some mistakes in configuration or even + * in the driver code. + * + * If SK_DEBUG2 is defined, many many messages will be printed + * which normally you don't need. I used this to check the interrupt + * routine. + * + * (If you define only SK_DEBUG2 then only the messages for + * checking interrupts will be printed!) + * + * Normal way of live is: + * + * For the whole thing get going let both symbolic constants + * undefined. If you face any problems and you know whats going + * on (you know something about the card and you can interpret some + * hex LANCE register output) then define SK_DEBUG + * + */ + +#undef SK_DEBUG /* debugging */ +#undef SK_DEBUG2 /* debugging with more verbose report */ + +#ifdef SK_DEBUG +#define PRINTK(x) printk x +#else +#define PRINTK(x) /**/ +#endif + +#ifdef SK_DEBUG2 +#define PRINTK2(x) printk x +#else +#define PRINTK2(x) /**/ +#endif + +/* + * SK_G16 RAM + * + * The components are memory mapped and can be set in a region from + * 0x00000 through 0xfc000 in 16KB steps. + * + * The Network components are: dual ported RAM, Prom, I/O Reg, Status-, + * Controlregister and I/O Command. + * + * dual ported RAM: This is the only memory region which the LANCE chip + * has access to. From the Lance it is addressed from 0x0000 to + * 0x3fbf. The host accesses it normaly. + * + * PROM: The PROM obtains the ETHERNET-MAC-Address. It is realised as a + * 8-Bit PROM, this means only the 16 even addresses are used of the + * 32 Byte Address region. Access to a odd address results in invalid + * data. + * + * LANCE I/O Reg: The I/O Reg is build of 4 single Registers, Low-Byte Write, + * Hi-Byte Write, Low-Byte Read, Hi-Byte Read. + * Transfer from or to the LANCE is always in 16Bit so Low and High + * registers are always relevant. + * + * The Data from the Readregister is not the data in the Writeregister!! + * + * Port: Status- and Controlregister. + * Two different registers which share the same address, Status is + * read-only, Control is write-only. + * + * I/O Command: + * Any bitcombination written in here starts the transmission between + * Host and LANCE. + */ + +typedef struct +{ + unsigned char ram[0x3fc0]; /* 16KB dual ported ram */ + unsigned char rom[0x0020]; /* 32Byte PROM containing 6Byte MAC */ + unsigned char res1[0x0010]; /* reserved */ + unsigned volatile short ioreg;/* LANCE I/O Register */ + unsigned volatile char port; /* Statusregister and Controlregister */ + unsigned char iocom; /* I/O Command Register */ +} SK_RAM; + +/* struct */ + +/* + * This is the structure for the dual ported ram. We + * have exactly 16 320 Bytes. In here there must be: + * + * - Initialize Block (starting at a word boundary) + * - Receive and Transmit Descriptor Rings (quadword boundary) + * - Data Buffers (arbitrary boundary) + * + * This is because LANCE has on SK_G16 only access to the dual ported + * RAM and nowhere else. + */ + +struct SK_ram +{ + struct init_block ib; + struct tmd tmde[TMDNUM]; + struct rmd rmde[RMDNUM]; + char tmdbuf[TMDNUM][PKT_BUF_SZ]; + char rmdbuf[RMDNUM][PKT_BUF_SZ]; +}; + +/* + * Structure where all necessary information is for ring buffer + * management and statistics. + */ + +struct priv +{ + struct SK_ram *ram; /* dual ported ram structure */ + struct rmd *rmdhead; /* start of receive ring descriptors */ + struct tmd *tmdhead; /* start of transmit ring descriptors */ + int rmdnum; /* actual used ring descriptor */ + int tmdnum; /* actual transmit descriptor for transmitting data */ + int tmdlast; /* last sent descriptor used for error handling, etc */ + void *rmdbufs[RMDNUM]; /* pointer to the receive buffers */ + void *tmdbufs[TMDNUM]; /* pointer to the transmit buffers */ + struct enet_statistics stats; /* Device driver statistics */ +}; + +/* global variable declaration */ + +/* IRQ map used to reserve a IRQ (see SK_open()) */ + +extern void *irq2dev_map[16]; + +/* static variables */ + +static SK_RAM *board; /* pointer to our memory mapped board components */ + +/* Macros */ + + +/* Function Prototypes */ + +/* + * Device Driver functions + * ----------------------- + * See for short explanation of each function its definitions header. + */ + +int SK_init(struct device *dev); +static int SK_probe(struct device *dev, short ioaddr); + +static int SK_open(struct device *dev); +static int SK_send_packet(struct sk_buff *skb, struct device *dev); +static void SK_interrupt(int reg_ptr); +static void SK_rxintr(struct device *dev); +static void SK_txintr(struct device *dev); +static int SK_close(struct device *dev); + +static struct enet_statistics *SK_get_stats(struct device *dev); + +unsigned int SK_rom_addr(void); + +#ifdef HAVE_MULTICAST +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +#endif + +/* + * LANCE Functions + * --------------- + */ + +static int SK_lance_init(struct device *dev, unsigned short mode); +void SK_reset_board(void); +void SK_set_RAP(int reg_number); +int SK_read_reg(int reg_number); +int SK_rread_reg(void); +void SK_write_reg(int reg_number, int value); + +/* + * Debuging functions + * ------------------ + */ + +void SK_print_pos(struct device *dev, char *text); +void SK_print_dev(struct device *dev, char *text); +void SK_print_ram(struct device *dev); + + +/*- + * Function : SK_init + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/26 + * + * Description : Check for a SK_G16 network adaptor and initialize it. + * This function gets called by dev_init which initializes + * all Network devices. + * + * Parameters : I : struct device *dev - structure preconfigured + * from Space.c + * Return Value : 0 = Driver Found and initialized + * Errors : ENODEV - no device found + * ENXIO - not probed + * Globals : None + * Update History : + * YY/MM/DD uid Description +-*/ + +/* + * Check for a network adaptor of this type, and return '0' if one exists. + * If dev->base_addr == 0, probe all likely locations. + * If dev->base_addr == 1, always return failure. + * If dev->base_addr == 2, alloate space for the device and return success + * (detachable devices only). + */ + +int SK_init(struct device *dev) +{ + int ioaddr = 0; /* I/O port address used for POS regs */ + int *port, ports[] = SK_IO_PORTS; /* SK_G16 supported ports */ + + /* get preconfigured base_addr from dev which is done in Space.c */ + int base_addr = dev->base_addr; + + PRINTK(("%s: %s", SK_NAME, rcsid)); + rcsid = NULL; /* We do not want to use this further */ + + if (base_addr > 0x0ff) /* Check a single specified address */ + { + /* Check if on specified address is a SK_G16 */ + + if ( (inb(SK_POS0) == SK_IDLOW) || + (inb(SK_POS1) == SK_IDHIGH) ) + { + return SK_probe(dev, base_addr); + } + + return ENODEV; /* Sorry, but on specified address NO SK_G16 */ + } + else if (base_addr > 0) /* Don't probe at all */ + { + return ENXIO; + } + + /* Autoprobe base_addr */ + + for (port = &ports[0]; *port; port++) + { + ioaddr = *port; /* we need ioaddr for accessing POS regs */ + + /* Check if I/O Port region is used by another board */ + + if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE)) + { + continue; /* Try next Port address */ + } + + /* Check if at ioaddr is a SK_G16 */ + + if ( !(inb(SK_POS0) == SK_IDLOW) || + !(inb(SK_POS1) == SK_IDHIGH) ) + { + continue; /* Try next Port address */ + } + + dev->base_addr = ioaddr; /* Set I/O Port Address */ + + if (SK_probe(dev, ioaddr) == 0) + { + return 0; /* Card found and initialized */ + } + } + + dev->base_addr = base_addr; /* Write back original base_addr */ + + return ENODEV; /* Failed to find or init driver */ + +} /* End of SK_init */ + + +/*- + * Function : SK_probe + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/26 + * + * Description : This function is called by SK_init and + * does the main part of initialization. + * + * Parameters : I : struct device *dev - SK_G16 device structure + * I : short ioaddr - I/O Port address where POS is. + * Return Value : 0 = Initilization done + * Errors : ENODEV - No SK_G16 found + * -1 - Configuration problem + * Globals : irq2dev_map - Which device uses which IRQ + * : board - pointer to SK_RAM + * Update History : + * YY/MM/DD uid Description + * 94/06/30 pwe SK_ADDR now checked and at the correct place +-*/ + +int SK_probe(struct device *dev, short ioaddr) +{ + int i,j; /* Counters */ + int sk_addr_flag = 0; /* SK ADDR correct? 1 - no, 0 - yes */ + unsigned int rom_addr; /* used to store RAM address used for POS_ADDR */ + + struct priv *p; /* SK_G16 private structure */ + + if (SK_ADDR & 0x3fff || SK_ADDR < 0xa0000) + { + + sk_addr_flag = 1; + + /* + * Now here we could use a routine which searches for a free + * place in the ram and set SK_ADDR if found. TODO. + */ + } + + if (SK_BOOT_ROM) /* Shall we keep Boot_ROM on ? */ + { + PRINTK(("## %s: SK_BOOT_ROM is set.\n", SK_NAME)); + + rom_addr = SK_rom_addr(); + + if (rom_addr == 0) /* No Boot_ROM found */ + { + if (sk_addr_flag) /* No or Invalid SK_ADDR is defined */ + { + printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n", + dev->name, SK_ADDR); + return -1; + } + + rom_addr = SK_ADDR; /* assign predefined address */ + + PRINTK(("## %s: NO Bootrom found \n", SK_NAME)); + + outb(SK_ROM_RAM_OFF, SK_POS2); /* Boot_ROM + RAM off */ + outb(POS_ADDR, SK_POS3); /* Set RAM address */ + outb(SK_RAM_ON, SK_POS2); /* enable RAM */ + } + else if (rom_addr == SK_ADDR) + { + printk("%s: RAM + ROM are set to the same address %#08x\n" + " Check configuration. Now switching off Boot_ROM\n", + SK_NAME, rom_addr); + + outb(SK_ROM_RAM_OFF, SK_POS2); /* Boot_ROM + RAM off*/ + outb(POS_ADDR, SK_POS3); /* Set RAM address */ + outb(SK_RAM_ON, SK_POS2); /* enable RAM */ + } + else + { + PRINTK(("## %s: Found ROM at %#08x\n", SK_NAME, rom_addr)); + PRINTK(("## %s: Keeping Boot_ROM on\n", SK_NAME)); + + if (sk_addr_flag) /* No or Invalid SK_ADDR is defined */ + { + printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n", + dev->name, SK_ADDR); + return -1; + } + + rom_addr = SK_ADDR; + + outb(SK_ROM_RAM_OFF, SK_POS2); /* Boot_ROM + RAM off */ + outb(POS_ADDR, SK_POS3); /* Set RAM address */ + outb(SK_ROM_RAM_ON, SK_POS2); /* RAM on, BOOT_ROM on */ + } + } + else /* Don't keep Boot_ROM */ + { + PRINTK(("## %s: SK_BOOT_ROM is not set.\n", SK_NAME)); + + if (sk_addr_flag) /* No or Invalid SK_ADDR is defined */ + { + printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n", + dev->name, SK_ADDR); + return -1; + } + + rom_addr = SK_rom_addr(); /* Try to find a Boot_ROM */ + + /* IF we find a Boot_ROM disable it */ + + outb(SK_ROM_RAM_OFF, SK_POS2); /* Boot_ROM + RAM off */ + + /* We found a Boot_ROM and its gone. Set RAM address on + * Boot_ROM address. + */ + + if (rom_addr) + { + printk("%s: We found Boot_ROM at %#08x. Now setting RAM on" + "that address\n", SK_NAME, rom_addr); + + outb(POS_ADDR, SK_POS3); /* Set RAM on Boot_ROM address */ + } + else /* We did not find a Boot_ROM, use predefined SK_ADDR for ram */ + { + if (sk_addr_flag) /* No or Invalid SK_ADDR is defined */ + { + printk("%s: SK_ADDR %#08x is not valid. Check configuration.\n", + dev->name, SK_ADDR); + return -1; + } + + rom_addr = SK_ADDR; + + outb(POS_ADDR, SK_POS3); /* Set RAM address */ + } + outb(SK_RAM_ON, SK_POS2); /* enable RAM */ + } + +#ifdef SK_DEBUG + SK_print_pos(dev, "POS registers after ROM, RAM config"); +#endif + + board = (SK_RAM *) rom_addr; + + /* Read in station address */ + for (i = 0, j = 0; i < ETH_ALEN; i++, j+=2) + { + dev->dev_addr[i] = board->rom[j]; + } + + /* Check for manufactorer code */ + if (!(dev->dev_addr[0] == SK_MAC0 && + dev->dev_addr[1] == SK_MAC1 && + dev->dev_addr[2] == SK_MAC2) ) + { + PRINTK(("## %s: We did not find SK_G16 at RAM location.\n", + SK_NAME)); + return ENODEV; /* NO SK_G16 found */ + } + + printk("%s: %s found at %#3x, HW addr: %#04x:%02x:%02x:%02x:%02x:%02x\n", + dev->name, + "Schneider & Koch Netcard", + (unsigned int) dev->base_addr, + dev->dev_addr[0], + dev->dev_addr[1], + dev->dev_addr[2], + dev->dev_addr[3], + dev->dev_addr[4], + dev->dev_addr[5]); + + /* Grap the I/O Port region */ + snarf_region(ioaddr, ETHERCARD_TOTAL_SIZE); + + /* Initialize device structure */ + + /* Allocate memory for private structure */ + p = dev->priv = (void *) kmalloc(sizeof(struct priv), GFP_KERNEL); + memset((char *) dev->priv, 0, sizeof(struct priv)); /* clear memory */ + + /* Assign our Device Driver functions */ + + dev->open = &SK_open; + dev->stop = &SK_close; + dev->hard_start_xmit = &SK_send_packet; + dev->get_stats = &SK_get_stats; + +#ifdef HAVE_MULTICAST + dev->set_multicast_list = &set_multicast_list; +#endif + + + /* Set the generic fields of the device structure */ + + ether_setup(dev); + + /* Initialize private structure */ + + p->ram = (struct SK_ram *) rom_addr; /* Set dual ported RAM addr */ + p->tmdhead = &(p->ram)->tmde[0]; /* Set TMD head */ + p->rmdhead = &(p->ram)->rmde[0]; /* Set RMD head */ + + /* Initialize buffer pointers */ + + for (i = 0; i < TMDNUM; i++) + { + p->tmdbufs[i] = &(p->ram)->tmdbuf[i]; + } + + for (i = 0; i < RMDNUM; i++) + { + p->rmdbufs[i] = &(p->ram)->rmdbuf[i]; + } + +#ifdef SK_DEBUG + SK_print_pos(dev, "End of SK_probe"); + SK_print_ram(dev); +#endif + + return 0; /* Initialization done */ + +} /* End of SK_probe() */ + + +/*- + * Function : SK_open + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/26 + * + * Description : This function is called sometimes after booting + * when ifconfig programm is run. + * + * This function requests an IRQ, sets the correct + * IRQ in the card. Then calls SK_lance_init() to + * init and start the LANCE chip. Then if everthing is + * ok returns with 0 (OK), which means SK_G16 is now + * opened and operational. + * + * (Called by dev_open() /net/inet/dev.c) + * + * Parameters : I : struct device *dev - SK_G16 device structure + * Return Value : 0 - Device opened + * Errors : -EAGAIN - Open failed + * Globals : irq2dev_map - which device uses which irq + * Side Effects : None + * Update History : + * YY/MM/DD uid Description +-*/ + +static int SK_open(struct device *dev) +{ + int i = 0; + int irqval = 0; + int ioaddr = dev->base_addr; + + int irqtab[] = SK_IRQS; + + struct priv *p = (struct priv *)dev->priv; + + PRINTK(("## %s: At beginning of SK_open(). CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0))); + + if (dev->irq == 0) /* Autoirq */ + { + i = 0; + + /* + * Check if one IRQ out of SK_IRQS is free and install + * interrupt handler. + * Most done by request_irq(). + * irqval: 0 - interrupt handler installed for IRQ irqtab[i] + * -EBUSY - interrupt busy + * -EINVAL - irq > 15 or handler = NULL + */ + + do + { + irqval = request_irq(irqtab[i], &SK_interrupt); + i++; + } while (irqval && irqtab[i]); + + if (irqval) /* We tried every possible IRQ but no success */ + { + printk("%s: unable to get an IRQ\n", dev->name); + return -EAGAIN; + } + + dev->irq = irqtab[--i]; + + outb(i<<2, SK_POS4); /* Set Card on probed IRQ */ + + } + else if (dev->irq == 2) /* IRQ2 is always IRQ9 */ + { + if (request_irq(9, &SK_interrupt)) + { + printk("%s: unable to get IRQ 9\n", dev->name); + return -EAGAIN; + } + dev->irq = 9; + + /* + * Now we set card on IRQ2. + * This can be confusing, but remember that IRQ2 on the network + * card is in reality IRQ9 + */ + outb(0x08, SK_POS4); /* set card to IRQ2 */ + + } + else /* Check IRQ as defined in Space.c */ + { + int i = 0; + + /* check if IRQ free and valid. Then install Interrupt handler */ + + if (request_irq(dev->irq, &SK_interrupt)) + { + printk("%s: unable to get selected IRQ\n", dev->name); + return -EAGAIN; + } + + switch(dev->irq) + { + case 3: i = 0; + break; + case 5: i = 1; + break; + case 2: i = 2; + break; + case 11:i = 3; + break; + default: + printk("%s: Preselected IRQ %d is invalid for %s boards", + dev->name, + dev->irq, + SK_NAME); + return -EAGAIN; + } + + outb(i<<2, SK_POS4); /* Set IRQ on card */ + } + + irq2dev_map[dev->irq] = dev; /* Set IRQ as used by us */ + + printk("%s: Schneider & Koch G16 at %#3x, IRQ %d, shared mem at %#08x\n", + dev->name, (unsigned int)dev->base_addr, + (int) dev->irq, (unsigned int) p->ram); + + if (!(i = SK_lance_init(dev, 0))) /* LANCE init OK? */ + { + + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + +#ifdef SK_DEBUG + + /* + * This debug block tries to stop LANCE, + * reinit LANCE with transmitter and receiver disabled, + * then stop again and reinit with NORMAL_MODE + */ + + printk("## %s: After lance init. CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0)); + SK_write_reg(CSR0, CSR0_STOP); + printk("## %s: LANCE stopped. CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0)); + SK_lance_init(dev, MODE_DTX | MODE_DRX); + printk("## %s: Reinit with DTX + DRX off. CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0)); + SK_write_reg(CSR0, CSR0_STOP); + printk("## %s: LANCE stopped. CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0)); + SK_lance_init(dev, MODE_NORMAL); + printk("## %s: LANCE back to normal mode. CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0)); + SK_print_pos(dev, "POS regs before returning OK"); + +#endif /* SK_DEBUG */ + + return 0; /* SK_open() is successful */ + } + else /* LANCE init failed */ + { + + PRINTK(("## %s: LANCE init failed: CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0))); + + dev->start = 0; /* Device not ready */ + return -EAGAIN; + } + +} /* End of SK_open() */ + + +/*- + * Function : SK_lance_init + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/26 + * + * Description : Reset LANCE chip, fill RMD, TMD structures with + * start values and Start LANCE. + * + * Parameters : I : struct device *dev - SK_G16 device structure + * I : int mode - put LANCE into "mode" see data-sheet for + * more info. + * Return Value : 0 - Init done + * Errors : -1 - Init failed + * Update History : + * YY/MM/DD uid Description +-*/ + +static int SK_lance_init(struct device *dev, unsigned short mode) +{ + int i; + struct priv *p = (struct priv *) dev->priv; + struct tmd *tmdp; + struct rmd *rmdp; + + PRINTK(("## %s: At beginning of LANCE init. CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0))); + + /* Reset LANCE */ + SK_reset_board(); + + /* Initialize TMD's with start values */ + p->tmdnum = 0; /* First descriptor for transmitting */ + p->tmdlast = 0; /* First descriptor for reading stats */ + + for (i = 0; i < TMDNUM; i++) /* Init all TMD's */ + { + tmdp = p->tmdhead + i; + + tmdp->u.buffer = (unsigned long) p->tmdbufs[i]; /* assign buffer */ + + /* Mark TMD as start and end of packet */ + tmdp->u.s.status = TX_STP | TX_ENP; + } + + + /* Initialize RMD's with start values */ + + p->rmdnum = 0; /* First RMD which will be used */ + + for (i = 0; i < RMDNUM; i++) /* Init all RMD's */ + { + rmdp = p->rmdhead + i; + + + rmdp->u.buffer = (unsigned long) p->rmdbufs[i]; /* assign buffer */ + + /* + * LANCE must be owner at beginning so that he can fill in + * receiving packets, set status and release RMD + */ + + rmdp->u.s.status = RX_OWN; + + rmdp->blen = -PKT_BUF_SZ; /* Buffer Size in a two's comliment */ + + rmdp->mlen = 0; /* init message length */ + + } + + /* Fill LANCE Initialize Block */ + + (p->ram)->ib.mode = mode; /* Set operation mode */ + + for (i = 0; i < ETH_ALEN; i++) /* Set physical address */ + { + (p->ram)->ib.paddr[i] = dev->dev_addr[i]; + } + + for (i = 0; i < 8; i++) /* Set multicast, logical adress */ + { + (p->ram)->ib.laddr[i] = 0; /* We do not use logical addressing */ + } + + /* Set ring descriptor pointers and set number of descriptors */ + + (p->ram)->ib.rdrp = (int) p->rmdhead | RMDNUMMASK; + (p->ram)->ib.tdrp = (int) p->tmdhead | TMDNUMMASK; + + /* Prepare LANCE Controll and Status Registers */ + + cli(); + + SK_write_reg(CSR3, CSR3_ACON); /* Ale Control !!!THIS MUST BE SET!!!! */ + + /* + * LANCE addresses the RAM from 0x0000 to 0x3fbf and has no access to + * PC Memory locations. + * + * In structure SK_ram is defined that the first thing in ram + * is the initalization block. So his address is for LANCE always + * 0x0000 + * + * CSR1 contains low order bits 15:0 of initialization block address + * CSR2 is built of: + * 7:0 High order bits 23:16 of initialization block address + * 15:8 reserved, must be 0 + */ + + /* Set initialization block address (must be on word boundary) */ + SK_write_reg(CSR1, 0); /* Set low order bits 15:0 */ + SK_write_reg(CSR2, 0); /* Set high order bits 23:16 */ + + + PRINTK(("## %s: After setting CSR1-3. CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0))); + + /* Initialize LANCE */ + + /* + * INIT = Initialize, when set, cuases the LANCE to begin the + * initialization procedure and access the Init Block. + */ + + SK_write_reg(CSR0, CSR0_INIT); + + sti(); + + /* Wait until LANCE finished initialization */ + + SK_set_RAP(CSR0); /* Register Address Pointer to CSR0 */ + + for (i = 0; (i < 100) && !(SK_rread_reg() & CSR0_IDON); i++) + ; /* Wait until init done or go ahead if problems (i>=100) */ + + if (i >= 100) /* Something is wrong ! */ + { + printk("%s: can't init am7990, status: %04x " + "init_block: %#08x\n", + dev->name, (int) SK_read_reg(CSR0), + (unsigned int) &(p->ram)->ib); + +#ifdef SK_DEBUG + SK_print_pos(dev, "LANCE INIT failed"); + SK_print_dev(dev,"Device Structure:"); +#endif + + return -1; /* LANCE init failed */ + } + + PRINTK(("## %s: init done after %d ticks\n", SK_NAME, i)); + + /* Clear Initialize done, enable Interrupts, start LANCE */ + + SK_write_reg(CSR0, CSR0_IDON | CSR0_INEA | CSR0_STRT); + + PRINTK(("## %s: LANCE started. CSR0: %#06x\n", SK_NAME, + SK_read_reg(CSR0))); + + return 0; /* LANCE is up and running */ + +} /* End of SK_lance_init() */ + + + +/*- + * Function : SK_send_packet + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/27 + * + * Description : Writes an socket buffer into a transmit descriptor + * and starts transmission. + * + * Parameters : I : struct sk_buff *skb - packet to transfer + * I : struct device *dev - SK_G16 device structure + * Return Value : 0 - OK + * 1 - Could not transmit (dev_queue_xmit will queue it) + * and try to sent it later + * Globals : None + * Side Effects : None + * Update History : + * YY/MM/DD uid Description +-*/ + +static int SK_send_packet(struct sk_buff *skb, struct device *dev) +{ + struct priv *p = (struct priv *) dev->priv; + struct tmd *tmdp; + + if (dev->tbusy) + { + /* if Transmitter more than 150ms busy -> time_out */ + + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 15) + { + return 1; /* We have to try transmit later */ + } + + printk("%s: xmitter timed out, try to restart!\n", dev->name); + + SK_lance_init(dev, MODE_NORMAL); /* Reinit LANCE */ + + dev->tbusy = 0; /* Clear Transmitter flag */ + + dev->trans_start = jiffies; /* Mark Start of transmission */ + + } + + /* + * If some upper Layer thinks we missed a transmit done interrupt + * we are passed NULL. + * (dev_queue_xmit net/inet/dev.c + */ + + if (skb == NULL) + { + /* + * Dequeue packets from transmit queue and send them. + */ + dev_tint(dev); + + return 0; + } + + PRINTK2(("## %s: SK_send_packet() called, CSR0 %#04x.\n", + SK_NAME, SK_read_reg(CSR0))); + + + /* + * Block a timer-based transmit from overlapping. + * This means check if we are already in. + */ + + if (set_bit(0, (void *) &dev->tbusy) != 0) /* dev->tbusy already set ? */ + { + printk("%s: Transmitter access conflict.\n", dev->name); + } + else + { + /* Evaluate Packet length */ + short len = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + + tmdp = p->tmdhead + p->tmdnum; /* Which descriptor for transmitting */ + + /* Fill in Transmit Message Descriptor */ + + /* Copy data into dual ported ram */ + + memcpy((char *) (tmdp->u.buffer & 0x00ffffff), (char *)skb->data, + skb->len); + + tmdp->blen = -len; /* set length to transmit */ + + /* + * Packet start and end is always set because we use the maximum + * packet length as buffer length. + * Relinquish ownership to LANCE + */ + + tmdp->u.s.status = TX_OWN | TX_STP | TX_ENP; + + /* Start Demand Transmission */ + SK_write_reg(CSR0, CSR0_TDMD | CSR0_INEA); + + dev->trans_start = jiffies; /* Mark start of transmission */ + + /* Set pointer to next transmit buffer */ + p->tmdnum++; + p->tmdnum &= TMDNUM-1; + + /* Do we own the next transmit buffer ? */ + if (! ((p->tmdhead + p->tmdnum)->u.s.status & TX_OWN) ) + { + /* + * We own next buffer and are ready to transmit, so + * clear busy flag + */ + dev->tbusy = 0; + } + } + dev_kfree_skb(skb, FREE_WRITE); + return 0; +} /* End of SK_send_packet */ + + +/*- + * Function : SK_interrupt + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/27 + * + * Description : SK_G16 interrupt handler which checks for LANCE + * Errors, handles transmit and receive interrupts + * + * Parameters : I : int reg_ptr - + * Return Value : None + * Errors : None + * Globals : None + * Side Effects : None + * Update History : + * YY/MM/DD uid Description +-*/ + +static void SK_interrupt(int reg_ptr) +{ + int irq = - (((struct pt_regs *)reg_ptr)->orig_eax+2); + int csr0; + struct device *dev = (struct device *) irq2dev_map[irq]; + struct priv *p = (struct priv *) dev->priv; + + + PRINTK2(("## %s: SK_interrupt(). status: %#06x\n", + SK_NAME, SK_read_reg(CSR0))); + + if (dev == NULL) + { + printk("SK_interrupt(): IRQ %d for unknown device.\n", irq); + } + + + if (dev->interrupt) + { + printk("%s: Re-entering the interrupt handler.\n", dev->name); + } + + csr0 = SK_read_reg(CSR0); /* store register for checking */ + + dev->interrupt = 1; /* We are handling an interrupt */ + + /* + * Acknowledge all of the current interrupt sources, disable + * Interrupts (INEA = 0) + */ + + SK_write_reg(CSR0, csr0 & CSR0_CLRALL); + + if (csr0 & CSR0_ERR) /* LANCE Error */ + { + printk("%s: error: %04x\n", dev->name, csr0); + + if (csr0 & CSR0_MISS) /* No place to store packet ? */ + { + p->stats.rx_dropped++; + } + } + + if (csr0 & CSR0_RINT) /* Receive Interrupt (packet arrived) */ + { + SK_rxintr(dev); + } + + if (csr0 & CSR0_TINT) /* Transmit interrupt (packet sent) */ + { + SK_txintr(dev); + } + + SK_write_reg(CSR0, CSR0_INEA); /* Enable Interrupts */ + + dev->interrupt = 0; /* We are out */ +} /* End of SK_interrupt() */ + + +/*- + * Function : SK_txintr + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/27 + * + * Description : After sending a packet we check status, update + * statistics and relinquish ownership of transmit + * descriptor ring. + * + * Parameters : I : struct device *dev - SK_G16 device structure + * Return Value : None + * Errors : None + * Globals : None + * Update History : + * YY/MM/DD uid Description +-*/ + +static void SK_txintr(struct device *dev) +{ + int tmdstat; + struct tmd *tmdp; + struct priv *p = (struct priv *) dev->priv; + + + PRINTK2(("## %s: SK_txintr() status: %#06x\n", + SK_NAME, SK_read_reg(CSR0))); + + tmdp = p->tmdhead + p->tmdlast; /* Which buffer we sent at last ? */ + + /* Set next buffer */ + p->tmdlast++; + p->tmdlast &= TMDNUM-1; + + tmdstat = tmdp->u.s.status & 0xff00; /* filter out status bits 15:08 */ + + /* + * We check status of transmitted packet. + * see LANCE data-sheet for error explanation + */ + if (tmdstat & TX_ERR) /* Error occured */ + { + printk("%s: TX error: %04x %04x\n", dev->name, (int) tmdstat, + (int) tmdp->status2); + + if (tmdp->status2 & TX_TDR) /* TDR problems? */ + { + printk("%s: tdr-problems \n", dev->name); + } + + if (tmdp->status2 & TX_RTRY) /* Failed in 16 attempts to transmit ? */ + p->stats.tx_aborted_errors++; + if (tmdp->status2 & TX_LCOL) /* Late collision ? */ + p->stats.tx_window_errors++; + if (tmdp->status2 & TX_LCAR) /* Loss of Carrier ? */ + p->stats.tx_carrier_errors++; + if (tmdp->status2 & TX_UFLO) /* Underflow error ? */ + { + p->stats.tx_fifo_errors++; + + /* + * If UFLO error occurs it will turn tranmitter of. + * So we must reinit LANCE + */ + + SK_lance_init(dev, MODE_NORMAL); + } + + p->stats.tx_errors++; + + tmdp->status2 = 0; /* Clear error flags */ + } + else if (tmdstat & TX_MORE) /* Collisions occured ? */ + { + /* + * Here I have a problem. + * I only know that there must be one or up to 15 collisions. + * Thats why TX_MORE is set, because after 16 attempts TX_RTRY + * will be set which means couldn't send packet aborted transfer. + * + * First I did not have this in but then I thought at minimum + * we see that something was not ok. + * If anyone knows something better than this to handle this + * please report it. (see Email addresses in the README file) + */ + + p->stats.collisions++; + } + else /* Packet sent without any problems */ + { + p->stats.tx_packets++; + } + + /* + * We mark transmitter not busy anymore, because now we have a free + * transmit descriptor which can be filled by SK_send_packet and + * afterwards sent by the LANCE + */ + + dev->tbusy = 0; + + /* + * mark_bh(NET_BH); + * This will cause net_bh() to run after this interrupt handler. + * + * The function which do handle slow IRQ parts is do_bottom_half() + * which runs at normal kernel priority, that means all interrupt are + * enabled. (see kernel/irq.c) + * + * net_bh does something like this: + * - check if already in net_bh + * - try to transmit something from the send queue + * - if something is in the receive queue send it up to higher + * levels if it is a known protocol + * - try to transmit something from the send queue + */ + + mark_bh(NET_BH); + +} /* End of SK_txintr() */ + + +/*- + * Function : SK_rxintr + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/27 + * + * Description : Buffer sent, check for errors, relinquish ownership + * of the receive message descriptor. + * + * Parameters : I : SK_G16 device structure + * Return Value : None + * Globals : None + * Update History : + * YY/MM/DD uid Description +-*/ + +static void SK_rxintr(struct device *dev) +{ + + struct rmd *rmdp; + int rmdstat; + struct priv *p = (struct priv *) dev->priv; + + PRINTK2(("## %s: SK_rxintr(). CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0))); + + rmdp = p->rmdhead + p->rmdnum; + + /* As long as we own the next entry, check status and send + * it up to higher layer + */ + + while (!( (rmdstat = rmdp->u.s.status) & RX_OWN)) + { + /* + * Start and end of packet must be set, because we use + * the ethernet maximum packet length (1518) as buffer size. + * + * Because our buffers are at maximum OFLO and BUFF errors are + * not to be concerned (see Data sheet) + */ + + if (rmdstat & (RX_STP | RX_ENP) != (RX_STP | RX_ENP)) + { + /* Start of a frame > 1518 Bytes ? */ + + if (rmdstat & RX_STP) + { + p->stats.rx_errors++; /* bad packet received */ + p->stats.rx_length_errors++; /* packet to long */ + + printk("%s: packet too long\n", dev->name); + } + + /* + * All other packets will be ignored until a new frame with + * start (RX_STP) set follows. + * + * What we do is just give descriptor free for new incoming + * packets. + */ + + rmdp->u.s.status = RX_OWN; /* Relinquish ownership to LANCE */ + + } + else if (rmdstat & RX_ERR) /* Receive Error ? */ + { + printk("%s: RX error: %04x\n", dev->name, (int) rmdstat); + + p->stats.rx_errors++; + + if (rmdstat & RX_FRAM) p->stats.rx_frame_errors++; + if (rmdstat & RX_CRC) p->stats.rx_crc_errors++; + + rmdp->u.s.status = RX_OWN; /* Relinquish ownership to LANCE */ + + } + else /* We have a packet which can be queued for the upper layers */ + { + + int len = (rmdp->mlen & 0x0fff); /* extract message length from receive buffer */ + struct sk_buff *skb; + + skb = alloc_skb(len, GFP_ATOMIC); /* allocate socket buffer */ + + if (skb == NULL) /* Could not get mem ? */ + { + + /* + * Couldn't allocate sk_buffer so we give descriptor back + * to Lance, update statistics and go ahead. + */ + + rmdp->u.s.status = RX_OWN; /* Reliquish ownershipt to LANCE */ + printk("%s: Couldn't allocate sk_buff, deferring packet.\n", + dev->name); + p->stats.rx_dropped++; + + break; /* Jump out */ + } + + /* Prepare sk_buff to queue for upper layers */ + + skb->len = len; + skb->dev = dev; + + /* + * Copy data out of our receive descriptor into sk_buff. + * + * (rmdp->u.buffer & 0x00ffffff) -> get address of buffer and + * ignore status fields) + */ + + memcpy(skb->data, (unsigned char *) (rmdp->u.buffer & 0x00ffffff), + len); + + + /* + * Notify the upper protocol layers that there is another packet + * to handle + * + * netif_rx() always succeeds. see /net/inet/dev.c for more. + */ + + netif_rx(skb); /* queue packet and mark it for processing */ + + /* + * Packet is queued and marked for processing so we + * free our descriptor and update statistics + */ + + rmdp->u.s.status = RX_OWN; + p->stats.rx_packets++; + + + p->rmdnum++; + p->rmdnum %= RMDNUM; + + rmdp = p->rmdhead + p->rmdnum; + } + } +} /* End of SK_rxintr() */ + + +/*- + * Function : SK_close + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/26 + * + * Description : close gets called from dev_close() and should + * deinstall the card (free_irq, mem etc). + * + * Parameters : I : struct device *dev - our device structure + * Return Value : 0 - closed device driver + * Errors : None + * Globals : None + * Update History : + * YY/MM/DD uid Description +-*/ + +/* I have tried to set BOOT_ROM on and RAM off but then, after a 'ifconfig + * down' the system stops. So I don't shut set card to init state. + */ + +static int SK_close(struct device *dev) +{ + + PRINTK(("## %s: SK_close(). CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0))); + + dev->tbusy = 1; /* Transmitter busy */ + dev->start = 0; /* Card down */ + + printk("%s: Shuting %s down CSR0 %#06x\n", dev->name, SK_NAME, + (int) SK_read_reg(CSR0)); + + SK_write_reg(CSR0, CSR0_STOP); /* STOP the LANCE */ + + free_irq(dev->irq); /* Free IRQ */ + irq2dev_map[dev->irq] = 0; /* Mark IRQ as unused */ + + return 0; /* always succed */ + +} /* End of SK_close() */ + + +/*- + * Function : SK_get_stats + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/26 + * + * Description : Return current status structure to upper layers. + * It is called by sprintf_stats (dev.c). + * + * Parameters : I : struct device *dev - our device structure + * Return Value : struct enet_statistics * - our current statistics + * Errors : None + * Side Effects : None + * Update History : + * YY/MM/DD uid Description +-*/ + +static struct enet_statistics *SK_get_stats(struct device *dev) +{ + + struct priv *p = (struct priv *) dev->priv; + + PRINTK(("## %s: SK_get_stats(). CSR0: %#06x\n", + SK_NAME, SK_read_reg(CSR0))); + + return &p->stats; /* Return Device status */ + +} /* End of SK_get_stats() */ + +#ifdef HAVE_MULTICAST + +/*- + * Function : set_multicast_list + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/26 + * + * Description : This function gets called when a programm performs + * a SIOCSIFFLAGS call. Ifconfig does this if you call + * 'ifconfig [-]allmultie' which enables or disables the + * Promiscous mode. + * Promiscous mode is when the Network card accepts all + * packets, not only the packets which match our MAC + * Address. It is useful for writing a network monitor, + * but it is also a security problem. You have to remeber + * that all information on the net is not encrypted. + * + * Parameters : I : struct device *dev - SK_G16 device Structure + * I : int num_addrs - explanation further down + * I : void *addrs - + * Return Value : None + * Errors : None + * Globals : None + * Update History : + * YY/MM/DD uid Description +-*/ + + +/* Set or clear the multicast filter for SK_G16. + * + * num_addrs == -1 Promiscous mode, receive all packets + * num_addrs == 0 Normal mode, clear multicast list + * num_addrs > 0 Multicast mode, receive normal and MC packets + */ + +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) +{ + + if (num_addrs == -1) + { + /* Reinitialize LANCE with MODE_PROM set */ + SK_lance_init(dev, MODE_PROM); + } + else if (num_addrs == 0) + { + /* Reinitialize LANCE without MODE_PROM */ + SK_lance_init(dev, MODE_NORMAL); + } + else + { + /* Multicast with logical address filter on */ + + /* Not implemented yet. */ + } +} /* End of set_multicast_list() */ + +#endif + + + +/*- + * Function : SK_rom_addr + * Author : Patrick J.D. Weichmann + * Date Created : 94/06/01 + * + * Description : Try to find a Boot_ROM at all possible locations + * + * Parameters : None + * Return Value : Address where Boot_ROM is + * Errors : 0 - Did not find Boot_ROM + * Globals : None + * Update History : + * YY/MM/DD uid Description +-*/ + +unsigned int SK_rom_addr(void) +{ + int i,j; + int rom_found = 0; + unsigned int rom_location[] = SK_BOOT_ROM_LOCATIONS; + unsigned char rom_id[] = SK_BOOT_ROM_ID; + unsigned char *test_byte; + + /* Autodetect Boot_ROM */ + PRINTK(("## %s: Autodetection of Boot_ROM\n", SK_NAME)); + + for (i = 0; (rom_location[i] != 0) && (rom_found == 0); i++) + { + + PRINTK(("## Trying ROM location %#08x", rom_location[i])); + + rom_found = 1; + for (j = 0; j < 6; j++) + { + test_byte = (unsigned char *) (rom_location[i]+j); + PRINTK((" %02x ", *test_byte)); + + if(!(*test_byte == rom_id[j])) + { + rom_found = 0; + } + } + PRINTK(("\n")); + } + + if (rom_found == 1) + { + PRINTK(("## %s: Boot_ROM found at %#08x\n", + SK_NAME, rom_location[(i-1)])); + + return (rom_location[--i]); + } + else + { + PRINTK(("%s: No Boot_ROM found\n", SK_NAME)); + return 0; + } +} /* End of SK_rom_addr() */ + + + +/* LANCE access functions + * + * ! CSR1-3 can only be accessed when in CSR0 the STOP bit is set ! + */ + + +/*- + * Function : SK_reset_board + * + * Author : Patrick J.D. Weichmann + * + * Date Created : 94/05/25 + * + * Description : This function resets SK_G16 and all components, but + * POS registers are not changed + * + * Parameters : None + * Return Value : None + * Errors : None + * Globals : SK_RAM *board - SK_RAM structure pointer + * + * Update History : + * YY/MM/DD uid Description +-*/ + +void SK_reset_board(void) +{ + int i; + + SK_PORT = 0x00; /* Reset aktiv */ + for (i = 0; i < 10 ; i++) /* Delay min 5ms */ + ; + SK_PORT = SK_RESET; /* Set back to normal operation */ + +} /* End of SK_reset_board() */ + + +/*- + * Function : SK_set_RAP + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/25 + * + * Description : Set LANCE Register Address Port to register + * for later data trasfer. + * + * Parameters : I : reg_number - which CSR to read/write from/to + * Return Value : None + * Errors : None + * Globals : SK_RAM *board - SK_RAM structure pointer + * Update History : + * YY/MM/DD uid Description +-*/ + +void SK_set_RAP(int reg_number) +{ + SK_IOREG = reg_number; + SK_PORT = SK_RESET | SK_RAP | SK_WREG; + SK_IOCOM = SK_DOIO; + + while (SK_PORT & SK_IORUN) + ; +} /* End of SK_set_RAP() */ + + +/*- + * Function : SK_read_reg + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/25 + * + * Description : Set RAP and read data from a LANCE CSR register + * + * Parameters : I : reg_number - which CSR to read from + * Return Value : Register contents + * Errors : None + * Globals : SK_RAM *board - SK_RAM structure pointer + * Update History : + * YY/MM/DD uid Description +-*/ + +int SK_read_reg(int reg_number) +{ + SK_set_RAP(reg_number); + + SK_PORT = SK_RESET | SK_RDATA | SK_RREG; + SK_IOCOM = SK_DOIO; + + while (SK_PORT & SK_IORUN) + ; + return (SK_IOREG); + +} /* End of SK_read_reg() */ + + +/*- + * Function : SK_rread_reg + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/28 + * + * Description : Read data from preseted register. + * This function requires that you know which + * Register is actually set. Be aware that CSR1-3 + * can only be accessed when in CSR0 STOP is set. + * + * Return Value : Register contents + * Errors : None + * Globals : SK_RAM *board - SK_RAM structure pointer + * Update History : + * YY/MM/DD uid Description +-*/ + +int SK_rread_reg(void) +{ + SK_PORT = SK_RESET | SK_RDATA | SK_RREG; + + SK_IOCOM = SK_DOIO; + + while (SK_PORT & SK_IORUN) + ; + return (SK_IOREG); + +} /* End of SK_rread_reg() */ + + +/*- + * Function : SK_write_reg + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/25 + * + * Description : This function sets the RAP then fills in the + * LANCE I/O Reg and starts Transfer to LANCE. + * It waits until transfer has ended which is max. 7 ms + * and then it returns. + * + * Parameters : I : reg_number - which CSR to write to + * I : value - what value to fill into register + * Return Value : None + * Errors : None + * Globals : SK_RAM *board - SK_RAM structure pointer + * Update History : + * YY/MM/DD uid Description +-*/ + +void SK_write_reg(int reg_number, int value) +{ + SK_set_RAP(reg_number); + + SK_IOREG = value; + SK_PORT = SK_RESET | SK_RDATA | SK_WREG; + SK_IOCOM = SK_DOIO; + + while (SK_PORT & SK_IORUN) + ; +} /* End of SK_write_reg */ + + + +/* + * Debugging functions + * ------------------- + */ + +/*- + * Function : SK_print_pos + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/25 + * + * Description : This function prints out the 4 POS (Programmable + * Option Select) Registers. Used mainly to debug operation. + * + * Parameters : I : struct device *dev - SK_G16 device structure + * I : char * - Text which will be printed as title + * Return Value : None + * Errors : None + * Update History : + * YY/MM/DD uid Description +-*/ + +void SK_print_pos(struct device *dev, char *text) +{ + int ioaddr = dev->base_addr; + + unsigned char pos0 = inb(SK_POS0), + pos1 = inb(SK_POS1), + pos2 = inb(SK_POS2), + pos3 = inb(SK_POS3), + pos4 = inb(SK_POS4); + + + printk("## %s: %s.\n" + "## pos0=%#4x pos1=%#4x pos2=%#04x pos3=%#08x pos4=%#04x\n", + SK_NAME, text, pos0, pos1, pos2, (pos3<<14), pos4); + +} /* End of SK_print_pos() */ + + + +/*- + * Function : SK_print_dev + * Author : Patrick J.D. Weichmann + * Date Created : 94/05/25 + * + * Description : This function simply prints out the important fields + * of the device structure. + * + * Parameters : I : struct device *dev - SK_G16 device structure + * I : char *text - Title for printing + * Return Value : None + * Errors : None + * Update History : + * YY/MM/DD uid Description +-*/ + +void SK_print_dev(struct device *dev, char *text) +{ + if (dev == NULL) + { + printk("## %s: Device Structure. %s\n", SK_NAME, text); + printk("## DEVICE == NULL\n"); + } + else + { + printk("## %s: Device Structure. %s\n", SK_NAME, text); + printk("## Device Name: %s Base Address: %#06x IRQ: %d\n", + dev->name, dev->base_addr, dev->irq); + + printk("## FLAGS: start: %d tbusy: %d int: %d\n", + dev->start, dev->tbusy, dev->interrupt); + + printk("## next device: %#08x init function: %#08x\n", + (int) dev->next, (int) dev->init); + } + +} /* End of SK_print_dev() */ + + + +/*- + * Function : SK_print_ram + * Author : Patrick J.D. Weichmann + * Date Created : 94/06/02 + * + * Description : This function is used to check how are things set up + * in the 16KB RAM. Also the pointers to the receive and + * transmit descriptor rings and rx und tx buffers locations. + * It contains a minor bug in printing, but has no effect to the values + * only newlines are not correct. + * + * Parameters : I : struct device *dev - SK_G16 device structure + * Return Value : None + * Errors : None + * Globals : None + * Update History : + * YY/MM/DD uid Description +-*/ + +void SK_print_ram(struct device *dev) +{ + + int i; + struct priv *p = (struct priv *) dev->priv; + + printk("## %s: RAM Details.\n" + "## RAM at %#08x tmdhead: %#08x rmdhead: %#08x initblock: %#08x\n", + SK_NAME, + (unsigned int) p->ram, + (unsigned int) p->tmdhead, + (unsigned int) p->rmdhead, + (unsigned int) &(p->ram)->ib); + + printk("## "); + + for(i = 0; i < TMDNUM; i++) + { + if (!(i % 3)) /* Every third line do a newline */ + { + printk("\n## "); + } + printk("tmdbufs%d: %#08x ", (i+1), (int) p->tmdbufs[i]); + } + printk("## "); + + for(i = 0; i < RMDNUM; i++) + { + if (!(i % 3)) /* Every third line do a newline */ + { + printk("\n## "); + } + printk("rmdbufs%d: %#08x ", (i+1), (int) p->rmdbufs[i]); + } + printk("\n"); + +} /* End of SK_print_ram() */ + diff -u --recursive --new-file v1.1.24/linux/drivers/net/sk_g16.h linux/drivers/net/sk_g16.h --- v1.1.24/linux/drivers/net/sk_g16.h Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/sk_g16.h Thu Jul 7 17:56:36 1994 @@ -0,0 +1,165 @@ +/*- + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + * Module : sk_g16.h + * Version : $Revision$ + * + * Author : M.Hipp (mhipp@student.uni-tuebingen.de) + * changes by : Patrick J.D. Weichmann + * + * Date Created : 94/05/25 + * + * Description : In here are all necessary definitions of + * the am7990 (LANCE) chip used for writing a + * network device driver which uses this chip + * + * $Log$ +-*/ + +#ifndef SK_G16_H + +#define SK_G16_H + + +/* + * Control and Status Register 0 (CSR0) bit definitions + * + * (R=Readable) (W=Writeable) (S=Set on write) (C-Clear on write) + * + */ + +#define CSR0_ERR 0x8000 /* Error summary (R) */ +#define CSR0_BABL 0x4000 /* Babble transmitter timeout error (RC) */ +#define CSR0_CERR 0x2000 /* Collision Error (RC) */ +#define CSR0_MISS 0x1000 /* Missed packet (RC) */ +#define CSR0_MERR 0x0800 /* Memory Error (RC) */ +#define CSR0_RINT 0x0400 /* Reciever Interrupt (RC) */ +#define CSR0_TINT 0x0200 /* Transmit Interrupt (RC) */ +#define CSR0_IDON 0x0100 /* Initialization Done (RC) */ +#define CSR0_INTR 0x0080 /* Interrupt Flag (R) */ +#define CSR0_INEA 0x0040 /* Interrupt Enable (RW) */ +#define CSR0_RXON 0x0020 /* Receiver on (R) */ +#define CSR0_TXON 0x0010 /* Transmitter on (R) */ +#define CSR0_TDMD 0x0008 /* Transmit Demand (RS) */ +#define CSR0_STOP 0x0004 /* Stop (RS) */ +#define CSR0_STRT 0x0002 /* Start (RS) */ +#define CSR0_INIT 0x0001 /* Initialize (RS) */ + +#define CSR0_CLRALL 0x7f00 /* mask for all clearable bits */ + +/* + * Control and Status Register 3 (CSR3) bit definitions + * + */ + +#define CSR3_BSWAP 0x0004 /* Byte Swap (RW) */ +#define CSR3_ACON 0x0002 /* ALE Control (RW) */ +#define CSR3_BCON 0x0001 /* Byte Control (RW) */ + +/* + * Initialization Block Mode operation Bit Definitions. + */ + +#define MODE_PROM 0x8000 /* Promiscuous Mode */ +#define MODE_INTL 0x0040 /* Internal Loopback */ +#define MODE_DRTY 0x0020 /* Disable Retry */ +#define MODE_COLL 0x0010 /* Force Collision */ +#define MODE_DTCR 0x0008 /* Disable Transmit CRC) */ +#define MODE_LOOP 0x0004 /* Loopback */ +#define MODE_DTX 0x0002 /* Disable the Transmitter */ +#define MODE_DRX 0x0001 /* Disable the Reciever */ + +#define MODE_NORMAL 0x0000 /* Normal operation mode */ + +/* + * Receive message descriptor status bit definitions. + */ + +#define RX_OWN 0x80 /* Owner bit 0 = host, 1 = lance */ +#define RX_ERR 0x40 /* Error Summary */ +#define RX_FRAM 0x20 /* Framing Error */ +#define RX_OFLO 0x10 /* Overflow Error */ +#define RX_CRC 0x08 /* CRC Error */ +#define RX_BUFF 0x04 /* Buffer Error */ +#define RX_STP 0x02 /* Start of Packet */ +#define RX_ENP 0x01 /* End of Packet */ + + +/* + * Transmit message descriptor status bit definitions. + */ + +#define TX_OWN 0x80 /* Owner bit 0 = host, 1 = lance */ +#define TX_ERR 0x40 /* Error Summary */ +#define TX_MORE 0x10 /* More the 1 retry needed to Xmit */ +#define TX_ONE 0x08 /* One retry needed to Xmit */ +#define TX_DEF 0x04 /* Deferred */ +#define TX_STP 0x02 /* Start of Packet */ +#define TX_ENP 0x01 /* End of Packet */ + +/* + * Transmit status (2) (valid if TX_ERR == 1) + */ + +#define TX_BUFF 0x8000 /* Buffering error (no ENP) */ +#define TX_UFLO 0x4000 /* Underflow (late memory) */ +#define TX_LCOL 0x1000 /* Late collision */ +#define TX_LCAR 0x0400 /* Loss of Carrier */ +#define TX_RTRY 0x0200 /* Failed after 16 retransmissions */ +#define TX_TDR 0x003f /* Time-domain-reflectometer-value */ + + +/* + * Structures used for Communication with the LANCE + */ + +/* LANCE Initialize Block */ + +struct init_block +{ + unsigned short mode; /* Mode Register */ + unsigned char paddr[6]; /* Physical Address (MAC) */ + unsigned char laddr[8]; /* Logical Filter Address (not used) */ + unsigned int rdrp; /* Receive Descriptor Ring pointer */ + unsigned int tdrp; /* Transmit Descriptor Ring pointer */ +}; + + +/* Receive Message Descriptor Entry */ + +struct rmd +{ + union + { + unsigned long buffer; /* Address of buffer */ + struct + { + unsigned char unused[3]; + unsigned volatile char status; /* Status Bits */ + } s; + } u; + volatile short blen; /* Buffer Length (two's complement) */ + unsigned short mlen; /* Message Byte Count */ +}; + + +/* Transmit Message Descriptor Entry */ + +struct tmd +{ + union + { + unsigned long buffer; /* Address of buffer */ + struct + { + unsigned char unused[3]; + unsigned volatile char status; /* Status Bits */ + } s; + } u; + unsigned short blen; /* Buffer Length (two's complement) */ + unsigned volatile short status2; /* Error Status Bits */ +}; + +#endif /* End of SK_G16_H */ diff -u --recursive --new-file v1.1.24/linux/drivers/net/slhc.c linux/drivers/net/slhc.c --- v1.1.24/linux/drivers/net/slhc.c Tue May 24 00:34:52 1994 +++ linux/drivers/net/slhc.c Thu Jul 7 18:28:48 1994 @@ -36,6 +36,8 @@ * allow zero or one slots * separate routines * status display + * - Jul 1994 Dmitry Gorodchanin + * Fixes for memory leaks. * * * This module is a difficult issue. Its clearly inet code but its also clearly @@ -101,7 +103,10 @@ (struct cstate *)kmalloc(rslots * sizeof(struct cstate), GFP_KERNEL); if (! comp->rstate) + { + kfree((unsigned char *)comp); return NULL; + } memset(comp->rstate, 0, rslots * sizeof(struct cstate)); comp->rslot_limit = rslots - 1; } @@ -111,7 +116,11 @@ (struct cstate *)kmalloc(tslots * sizeof(struct cstate), GFP_KERNEL); if (! comp->tstate) + { + kfree((unsigned char *)comp->rstate); + kfree((unsigned char *)comp); return NULL; + } memset(comp->tstate, 0, rslots * sizeof(struct cstate)); comp->tslot_limit = tslots - 1; } diff -u --recursive --new-file v1.1.24/linux/drivers/net/slip.c linux/drivers/net/slip.c --- v1.1.24/linux/drivers/net/slip.c Wed Jun 22 14:57:10 1994 +++ linux/drivers/net/slip.c Thu Jul 7 18:28:41 1994 @@ -23,6 +23,8 @@ * Alan Cox : Corrected non-IP cases of the above. * Alan Cox : Now uses hardware type as per FvK. * Alan Cox : Default to 192.168.0.0 (RFC 1597) + * A.N.Kuznetsov : dev_tint() recursion fix. + * Dmitry Gorodchanin : SLIP memory leaks * * * FIXME: This driver still makes some IP'ish assumptions. It should build cleanly KISS TNC only without @@ -379,7 +381,7 @@ actual = sl->tty->driver.write(sl->tty, 0, sl->xbuff, count); if (actual == count) { sl_unlock(sl); - dev_tint(sl->dev); + mark_bh(NET_BH); } else { sl->xhead = sl->xbuff + count; sl->xtail = sl->xbuff + actual; @@ -420,7 +422,7 @@ tty->flags &= ~TTY_DO_WRITE_WAKEUP; sl_unlock(sl); - dev_tint(sl->dev); + mark_bh(NET_BH); } else { sl->xtail += answer; } @@ -566,7 +568,7 @@ p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); if (p == NULL) { - kfree_s((void *)sl->dev->mem_start,l+4); + kfree((unsigned char *)sl->dev->mem_start); return(-ENOMEM); } sl->dev->rmem_start = (unsigned long) p; @@ -584,6 +586,7 @@ p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); if (p == NULL) { kfree((unsigned char *)sl->dev->mem_start); + kfree((unsigned char *)sl->dev->rmem_start); return(-ENOMEM); } sl->cbuff = p; @@ -592,7 +595,7 @@ if (sl->slcomp == NULL) { kfree((unsigned char *)sl->dev->mem_start); kfree((unsigned char *)sl->dev->rmem_start); - kfree(sl->cbuff); + kfree((unsigned char *)sl->cbuff); return(-ENOMEM); } #endif diff -u --recursive --new-file v1.1.24/linux/drivers/net/znet.c linux/drivers/net/znet.c --- v1.1.24/linux/drivers/net/znet.c Thu Jan 1 02:00:00 1970 +++ linux/drivers/net/znet.c Thu Jul 7 18:03:34 1994 @@ -0,0 +1,767 @@ +/* znet.c: An Zenith Z-Note ethernet driver for linux. */ + +static char *version = "znet.c:v1.01 7/1/94 becker@cesdis.gsfc.nasa.gov\n"; + +/* + Written by Donald Becker. + + The author may be reached as becker@cesdis.gsfc.nasa.gov. + This driver is based on the Linux skeleton driver. The copyright of the + skeleton driver is held by the United States Government, as represented + by DIRNSA, and it is released under the GPL. + + Thanks to Mike Hollick for alpha testing and suggestions. + + References: + The Crynwr packet driver. + + "82593 CSMA/CD Core LAN Controller" Intel datasheet, 1992 + Intel Microcommunications Databook, Vol. 1, 1990. + As usual with Intel, the documentation is incomplete and inaccurate. + I had to read the Crynwr packet driver to figure out how to actually + use the i82593, and guess at what register bits matched the loosely + related i82586. + + Theory of Operation + + The i82593 used in the Zenith Z-Note series operates using two(!) slave + DMA channels, one interrupt, and one 8-bit I/O port. + + While there several ways to configure '593 DMA system, I chose the one + that seemed commesurate with the highest system performance in the face + of moderate interrupt latency: Both DMA channels are configued as + recirculating ring buffers, with one channel (#0) dedicated to Rx and + the other channel (#1) to Tx and configuration. (Note that this is + different than the Crynwr driver, where the Tx DMA channel is initialized + before each operation. That approach simplifies operation and Tx error + recovery, but requires additional I/O in normal operation and precludes + transmit buffer chaining.) + + Both rings are set to 8192 bytes using {TX,RX}_RING_SIZE. This provides + a reasonable ring size for Rx, while simplifying DMA buffer allocation -- + DMA buffers must not cross a 128K boundary. (In truth the size selection + was influenced by my lack of '593 documentation. I thus was constrained + to use the Crynwr '593 initialization table, which sets the Rx ring size + to 8K.) + + Despite my usual low opinion about Intel-designed parts, I must admit + that the bulk data handling of the i82593 is a good design for + an integrated system, like a laptop, where using two slave DMA channels + doesn't pose a problem. I still take issue with using only a single I/O + port. In the same controlled environment there are essentially no + limitations on I/O space, and using multiple locations would eliminate + the need for multiple operations when looking at status registers, + setting the Rx ring boundary, or switching to promiscuous mode. + + I also question Zenith's selection of the '593: one of the advertised + advantages of earlier Intel parts was that if you figured out the magic + initialization incantation you could use the same part on many different + network types. Zenith's use of the "FriendlyNet" (sic) connector rather + than an on-board transceiver leads me to believe that they were planning + to take advantage of this. But, uhmmm, the '593 omits all but ethernet + functionality from the serial subsystem. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#ifndef ZNET_DEBUG +#define ZNET_DEBUG 3 +#endif +static unsigned int znet_debug = ZNET_DEBUG; + +/* The DMA modes we need aren't in . */ +#define DMA_RX_MODE 0x14 /* Auto init, I/O to mem, ++, demand. */ +#define DMA_TX_MODE 0x18 /* Auto init, Mem to I/O, ++, demand. */ +#define dma_page_eq(ptr1, ptr2) ((long)(ptr1)>>17 == (long)(ptr2)>>17) +#define DMA_BUF_SIZE 8192 +#define RX_BUF_SIZE 8192 +#define TX_BUF_SIZE 8192 + +/* Commands to the i82593 channel 0. */ +#define CMD0_CHNL_0 0x00 +#define CMD0_CHNL_1 0x10 /* Switch to channel 1. */ +#define CMD0_NOP (CMD0_CHNL_0) +#define CMD0_PORT_1 CMD0_CHNL_1 +#define CMD1_PORT_0 1 +#define CMD0_IA_SETUP 1 +#define CMD0_CONFIGURE 2 +#define CMD0_MULTICAST_LIST 3 +#define CMD0_TRANSMIT 4 +#define CMD0_DUMP 6 +#define CMD0_DIAGNOSE 7 +#define CMD0_Rx_ENABLE 8 +#define CMD0_Rx_DISABLE 10 +#define CMD0_Rx_STOP 11 +#define CMD0_RETRANSMIT 12 +#define CMD0_ABORT 13 +#define CMD0_RESET 14 + +#define CMD0_ACK 0x80 + +#define CMD0_STAT0 (0 << 5) +#define CMD0_STAT1 (1 << 5) +#define CMD0_STAT2 (2 << 5) +#define CMD0_STAT3 (3 << 5) + +#define net_local znet_private +struct znet_private { + int rx_dma, tx_dma; + struct enet_statistics stats; + /* The starting, current, and end pointers for the packet buffers. */ + ushort *rx_start, *rx_cur, *rx_end; + ushort *tx_start, *tx_cur, *tx_end; + ushort tx_buf_len; /* Tx buffer lenght, in words. */ +}; + +/* Only one can be built-in;-> */ +static struct znet_private zn; +static ushort dma_buffer1[DMA_BUF_SIZE/2]; +static ushort dma_buffer2[DMA_BUF_SIZE/2]; +static ushort dma_buffer3[DMA_BUF_SIZE/2 + 8]; + +/* The configuration block. What an undocumented nightmare. The first + set of values are those suggested (without explaination) for ethernet + in the Intel 82586 databook. The rest appear to be completely undocumented, + except for cryptic notes in the Crynwr packet driver. This driver uses + the Crynwr values verbatim. */ + +static unsigned char i593_init[] = { + 0xAA, /* 0: 16-byte input & 80-byte output FIFO. */ + /* threshhold, 96-byte FIFO, 82593 mode. */ + 0x88, /* 1: Continuous w/interrupts, 128-clock DMA.*/ + 0x2E, /* 2: 8-byte preamble, NO address insertion, */ + /* 6-byte Ethernet address, loopback off.*/ + 0x00, /* 3: Default priorities & backoff methods. */ + 0x60, /* 4: 96-bit interframe spacing. */ + 0x00, /* 5: 512-bit slot time (low-order). */ + 0xF2, /* 6: Slot time (high-order), 15 COLL retries. */ + 0x00, /* 7: Promisc-off, broadcast-on, default CRC. */ + 0x00, /* 8: Default carrier-sense, collision-detect. */ + 0x40, /* 9: 64-byte minimum frame length. */ + 0x5F, /* A: Type/length checks OFF, no CRC input, + "jabber" termination, etc. */ + 0x00, /* B: Full-duplex disabled. */ + 0x3F, /* C: Default multicast addresses & backoff. */ + 0x07, /* D: Default IFS retriggering. */ + 0x31, /* E: Internal retransmit, drop "runt" packets, + synchr. DRQ deassertion, 6 status bytes. */ + 0x22, /* F: Receive ring-buffer size (8K), + receive-stop register enable. */ +}; + +struct netidblk { + char magic[8]; /* The magic number (string) "NETIDBLK" */ + unsigned char netid[8]; /* The physical station address */ + char nettype, globalopt; + char vendor[8]; /* The machine vendor and product name. */ + char product[8]; + char irq1, irq2; /* Interrupts, only one is currently used. */ + char dma1, dma2; + short dma_mem_misc[8]; /* DMA buffer locations (unused in Linux). */ + short iobase1, iosize1; + short iobase2, iosize2; /* Second iobase unused. */ + char driver_options; /* Misc. bits */ + char pad; +}; + +int znet_probe(struct device *dev); +static int znet_open(struct device *dev); +static int znet_send_packet(struct sk_buff *skb, struct device *dev); +static void znet_interrupt(int reg_ptr); +static void znet_rx(struct device *dev); +static int znet_close(struct device *dev); +static struct enet_statistics *net_get_stats(struct device *dev); +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +static void hardware_init(struct device *dev); +static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset); + +#ifdef notdef +static struct sigaction znet_sigaction = { &znet_interrupt, 0, 0, NULL, }; +#endif + + +/* The Z-Note probe is pretty easy. The NETIDBLK exists in the safe-to-probe + BIOS area. We just scan for the signature, and pull the vital parameters + out of the structure. */ + +int znet_probe(struct device *dev) +{ + int i; + struct netidblk *netinfo; + char *p; + + /* This code scans the region 0xf0000 to 0xfffff for a "NETIDBLK". */ + for(p = (char *)0xf0000; p < (char *)0x100000; p++) + if (*p == 'N' && strncmp(p, "NETIDBLK", 8) == 0) + break; + + if (p >= (char *)0x100000) { + if (znet_debug > 1) + printk(KERN_INFO "No Z-Note ethernet adaptor found.\n"); + return ENODEV; + } + netinfo = (struct netidblk *)p; + dev->base_addr = netinfo->iobase1; + dev->irq = netinfo->irq1; + + printk(KERN_INFO "%s: ZNET at %#3x,", dev->name, dev->base_addr); + + /* The station address is in the "netidblk" at 0x0f0000. */ + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = netinfo->netid[i]); + + printk(", using IRQ %d DMA %d and %d.\n", dev->irq, netinfo->dma1, + netinfo->dma2); + + if (znet_debug > 1) { + printk(KERN_INFO "%s: vendor '%16.16s' IRQ1 %d IRQ2 %d DMA1 %d DMA2 %d.\n", + dev->name, netinfo->vendor, + netinfo->irq1, netinfo->irq2, + netinfo->dma1, netinfo->dma2); + printk(KERN_INFO "%s: iobase1 %#x size %d iobase2 %#x size %d net type %2.2x.\n", + dev->name, netinfo->iobase1, netinfo->iosize1, + netinfo->iobase2, netinfo->iosize2, netinfo->nettype); + } + + if (znet_debug > 0) + printk("%s%s", KERN_INFO, version); + + dev->priv = (void *) &zn; + zn.rx_dma = netinfo->dma1; + zn.tx_dma = netinfo->dma2; + + /* These should never fail. You can't add devices to a sealed box! */ + if (request_irq(dev->irq, &znet_interrupt) + || request_dma(zn.rx_dma) + || request_dma(zn.tx_dma)) { + printk(KERN_WARNING "%s: Not opened -- resource busy?!?\n", dev->name); + return EBUSY; + } + irq2dev_map[dev->irq] = dev; + + /* Allocate buffer memory. We can cross a 128K boundary, so we + must be careful about the allocation. It's easiest to waste 8K. */ + if (dma_page_eq(dma_buffer1, &dma_buffer1[RX_BUF_SIZE/2-1])) + zn.rx_start = dma_buffer1; + else + zn.rx_start = dma_buffer2; + + if (dma_page_eq(dma_buffer3, &dma_buffer3[RX_BUF_SIZE/2-1])) + zn.tx_start = dma_buffer3; + else + zn.tx_start = dma_buffer2; + zn.rx_end = zn.rx_start + RX_BUF_SIZE/2; + zn.tx_buf_len = TX_BUF_SIZE/2; + zn.tx_end = zn.tx_start + zn.tx_buf_len; + + /* The ZNET-specific entries in the device structure. */ + dev->open = &znet_open; + dev->hard_start_xmit = &znet_send_packet; + dev->stop = &znet_close; + dev->get_stats = net_get_stats; + dev->set_multicast_list = &set_multicast_list; + + /* Fill in the 'dev' with ethernet-generic values. */ + ether_setup(dev); + + return 0; +} + + +static int znet_open(struct device *dev) +{ + int ioaddr = dev->base_addr; + + if (znet_debug > 2) + printk(KERN_DEBUG "%s: znet_open() called.\n", dev->name); + + /* Turn on the 82501 SIA, using zenith-specific magic. */ + outb(0x10, 0xe6); /* Select LAN control register */ + outb(inb(0xe7) | 0x84, 0xe7); /* Turn on LAN power (bit 2). */ + /* According to the Crynwr driver we should wait 50 msec. for the + LAN clock to stabilize. My experiments indicates that the '593 can + be initialized immediately. The delay is probably needed for the + DC-to-DC converter to come up to full voltage, and for the oscillator + to be spot-on at 20Mhz before transmitting. + Until this proves to be a problem we rely on the higher layers for the + delay and save allocating a timer entry. */ + + /* This follows the packet driver's lead, and checks for success. */ + if (inb(ioaddr) != 0x10 && inb(ioaddr) != 0x00) + printk(KERN_WARNING "%s: Problem turning on the transceiver power.\n", + dev->name); + + dev->tbusy = 0; + dev->interrupt = 0; + hardware_init(dev); + dev->start = 1; + + return 0; +} + +static int znet_send_packet(struct sk_buff *skb, struct device *dev) +{ + int ioaddr = dev->base_addr; + + if (znet_debug > 4) + printk(KERN_DEBUG "%s: ZNet_send_packet(%d).\n", dev->name, dev->tbusy); + + /* Transmitter timeout, likely just recovery after suspending the machine. */ + if (dev->tbusy) { + ushort event, tx_status, rx_offset, state; + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 10) + return 1; + outb(CMD0_STAT0, ioaddr); event = inb(ioaddr); + outb(CMD0_STAT1, ioaddr); tx_status = inw(ioaddr); + outb(CMD0_STAT2, ioaddr); rx_offset = inw(ioaddr); + outb(CMD0_STAT3, ioaddr); state = inb(ioaddr); + printk(KERN_WARNING "%s: transmit timed out, status %02x %04x %04x %02x," + " resetting.\n", dev->name, event, tx_status, rx_offset, state); + if (tx_status == 0x0400) + printk(KERN_WARNING "%s: Tx carrier error, check transceiver cable.\n", + dev->name); + outb(CMD0_RESET, ioaddr); + hardware_init(dev); + } + + if (skb == NULL) { + dev_tint(dev); + return 0; + } + + /* Check that the part hasn't reset itself, probably from suspend. */ + outb(CMD0_STAT0, ioaddr); + if (inw(ioaddr) == 0x0010 + && inw(ioaddr) == 0x0000 + && inw(ioaddr) == 0x0010) + hardware_init(dev); + + /* Block a timer-based transmit from overlapping. This could better be + done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */ + if (set_bit(0, (void*)&dev->tbusy) != 0) + printk(KERN_WARNING "%s: Transmitter access conflict.\n", dev->name); + else { + short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN; + unsigned char *buf = (void *)(skb+1); + ushort *tx_link = zn.tx_cur - 1; + ushort rnd_len = (length + 1)>>1; + + { + short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE; + unsigned addr = inb(dma_port); + addr |= inb(dma_port) << 8; + addr <<= 1; + if (((int)zn.tx_cur & 0x1ffff) != addr) + printk(KERN_WARNING "Address mismatch at Tx: %#x vs %#x.\n", + (int)zn.tx_cur & 0xffff, addr); + zn.tx_cur = (ushort *)(((int)zn.tx_cur & 0xfe0000) | addr); + } + + if (zn.tx_cur >= zn.tx_end) + zn.tx_cur = zn.tx_start; + *zn.tx_cur++ = length; + if (zn.tx_cur + rnd_len + 1 > zn.tx_end) { + int semi_cnt = (zn.tx_end - zn.tx_cur)<<1; /* Cvrt to byte cnt. */ + memcpy(zn.tx_cur, buf, semi_cnt); + rnd_len -= semi_cnt>>1; + memcpy(zn.tx_start, buf + semi_cnt, length - semi_cnt); + zn.tx_cur = zn.tx_start + rnd_len; + } else { + memcpy(zn.tx_cur, buf, skb->len); + zn.tx_cur += rnd_len; + } + *zn.tx_cur++ = 0; + cli(); { + *tx_link = CMD0_TRANSMIT + CMD0_CHNL_1; + /* Is this always safe to do? */ + outb(CMD0_TRANSMIT + CMD0_CHNL_1,ioaddr); + } sti(); + + dev->trans_start = jiffies; + if (znet_debug > 4) + printk(KERN_DEBUG "%s: Transmitter queued, length %d.\n", dev->name, length); + } + dev_kfree_skb(skb, FREE_WRITE); + return 0; +} + +/* The ZNET interrupt handler. */ +static void znet_interrupt(int reg_ptr) +{ + int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); + struct device *dev = irq2dev_map[irq]; + int ioaddr; + int boguscnt = 20; + + if (dev == NULL) { + printk(KERN_WARNING "znet_interrupt(): IRQ %d for unknown device.\n", irq); + return; + } + + dev->interrupt = 1; + ioaddr = dev->base_addr; + + outb(CMD0_STAT0, ioaddr); + do { + ushort status = inb(ioaddr); + if (znet_debug > 5) { + ushort result, rx_ptr, running; + outb(CMD0_STAT1, ioaddr); + result = inw(ioaddr); + outb(CMD0_STAT2, ioaddr); + rx_ptr = inw(ioaddr); + outb(CMD0_STAT3, ioaddr); + running = inb(ioaddr); + printk(KERN_DEBUG "%s: interrupt, status %02x, %04x %04x %02x serial %d.\n", + dev->name, status, result, rx_ptr, running, boguscnt); + } + if ((status & 0x80) == 0) + break; + + if ((status & 0x0F) == 4) { /* Transmit done. */ + struct net_local *lp = (struct net_local *)dev->priv; + int tx_status; + outb(CMD0_STAT1, ioaddr); + tx_status = inw(ioaddr); + /* It's undocumented, but tx_status seems to match the i82586. */ + if (tx_status & 0x2000) { + lp->stats.tx_packets++; + lp->stats.collisions += tx_status & 0xf; + } else { + if (tx_status & 0x0600) lp->stats.tx_carrier_errors++; + if (tx_status & 0x0100) lp->stats.tx_fifo_errors++; + if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++; + if (tx_status & 0x0020) lp->stats.tx_aborted_errors++; + /* ...and the catch-all. */ + if (tx_status | 0x0760 != 0x0760) + lp->stats.tx_errors++; + } + dev->tbusy = 0; + mark_bh(NET_BH); /* Inform upper layers. */ + } + + if ((status & 0x40) + || (status & 0x0f) == 11) { + znet_rx(dev); + } + /* Clear the interrupts we've handled. */ + outb(CMD0_ACK,ioaddr); + } while (boguscnt--); + + dev->interrupt = 0; + return; +} + +static void znet_rx(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + int boguscount = 1; + short next_frame_end_offset = 0; /* Offset of next frame start. */ + short *cur_frame_end; + short cur_frame_end_offset; + + outb(CMD0_STAT2, ioaddr); + cur_frame_end_offset = inw(ioaddr); + + if (cur_frame_end_offset == zn.rx_cur - zn.rx_start) { + printk(KERN_WARNING "%s: Interrupted, but nothing to receive, offset %03x.\n", + dev->name, cur_frame_end_offset); + return; + } + + /* Use same method as the Crynwr driver: construct a forward list in + the same area of the backwards links we now have. This allows us to + pass packets to the upper layers in the order they were received -- + important for fast-path sequential operations. */ + while (zn.rx_start + cur_frame_end_offset != zn.rx_cur + && ++boguscount < 5) { + unsigned short hi_cnt, lo_cnt, hi_status, lo_status; + int count, status; + + if (cur_frame_end_offset < 4) { + /* Oh no, we have a special case: the frame trailer wraps around + the end of the ring buffer. We've saved space at the end of + the ring buffer for just this problem. */ + memcpy(zn.rx_end, zn.rx_start, 8); + cur_frame_end_offset += (RX_BUF_SIZE/2); + } + cur_frame_end = zn.rx_start + cur_frame_end_offset - 4; + + lo_status = *cur_frame_end++; + hi_status = *cur_frame_end++; + status = ((hi_status & 0xff) << 8) + (lo_status & 0xff); + lo_cnt = *cur_frame_end++; + hi_cnt = *cur_frame_end++; + count = ((hi_cnt & 0xff) << 8) + (lo_cnt & 0xff); + + if (znet_debug > 5) + printk(KERN_DEBUG "Constructing trailer at location %03x, %04x %04x %04x %04x" + " count %#x status %04x.\n", + cur_frame_end_offset<<1, lo_status, hi_status, lo_cnt, hi_cnt, + count, status); + cur_frame_end[-4] = status; + cur_frame_end[-3] = next_frame_end_offset; + cur_frame_end[-2] = count; + next_frame_end_offset = cur_frame_end_offset; + cur_frame_end_offset -= ((count + 1)>>1) + 3; + if (cur_frame_end_offset < 0) + cur_frame_end_offset += RX_BUF_SIZE/2; + }; + + /* Now step forward through the list. */ + do { + ushort *this_rfp_ptr = zn.rx_start + next_frame_end_offset; + int status = this_rfp_ptr[-4]; + int pkt_len = this_rfp_ptr[-2]; + + if (znet_debug > 5) + printk(KERN_DEBUG "Looking at trailer ending at %04x status %04x length %03x" + " next %04x.\n", next_frame_end_offset<<1, status, pkt_len, + this_rfp_ptr[-3]<<1); + /* Once again we must assume that the i82586 docs apply. */ + if ( ! (status & 0x2000)) { /* There was an error. */ + lp->stats.rx_errors++; + if (status & 0x0800) lp->stats.rx_crc_errors++; + if (status & 0x0400) lp->stats.rx_frame_errors++; + if (status & 0x0200) lp->stats.rx_over_errors++; /* Wrong. */ + if (status & 0x0100) lp->stats.rx_fifo_errors++; + if (status & 0x0080) lp->stats.rx_length_errors++; + } else if (pkt_len > 1536) { + lp->stats.rx_length_errors++; + } else { + /* Malloc up new buffer. */ + int sksize = sizeof(struct sk_buff) + pkt_len; + struct sk_buff *skb; + + skb = alloc_skb(sksize, GFP_ATOMIC); + if (skb == NULL) { + if (znet_debug) + printk(KERN_WARNING "%s: Memory squeeze, dropping packet.\n", dev->name); + lp->stats.rx_dropped++; + break; + } + skb->mem_len = sksize; + skb->mem_addr = skb; + skb->len = pkt_len; + skb->dev = dev; + + if (&zn.rx_cur[(pkt_len+1)>>1] > zn.rx_end) { + int semi_cnt = (zn.rx_end - zn.rx_cur)<<1; + memcpy((unsigned char *) (skb + 1), zn.rx_cur, semi_cnt); + memcpy((unsigned char *) (skb + 1) + semi_cnt, zn.rx_start, + pkt_len - semi_cnt); + } else { + memcpy((unsigned char *) (skb + 1), zn.rx_cur, pkt_len); + if (znet_debug > 6) { + unsigned int *packet = (unsigned int *) (skb + 1); + printk(KERN_DEBUG "Packet data is %08x %08x %08x %08x.\n", packet[0], + packet[1], packet[2], packet[3]); + } + } + +#ifdef HAVE_NETIF_RX + netif_rx(skb); +#else + skb->lock = 0; + if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { + kfree_s(skb, sksize); + lp->stats.rx_dropped++; + break; + } +#endif + lp->stats.rx_packets++; + } + zn.rx_cur = this_rfp_ptr; + if (zn.rx_cur >= zn.rx_end) + zn.rx_cur -= RX_BUF_SIZE/2; + update_stop_hit(ioaddr, (zn.rx_cur - zn.rx_start)<<1); + next_frame_end_offset = this_rfp_ptr[-3]; + if (next_frame_end_offset == 0) /* Read all the frames? */ + break; /* Done for now */ + this_rfp_ptr = zn.rx_start + next_frame_end_offset; + } while (--boguscount); + + /* If any worth-while packets have been received, dev_rint() + has done a mark_bh(INET_BH) for us and will work on them + when we get to the bottom-half routine. */ + return; +} + +/* The inverse routine to znet_open(). */ +static int znet_close(struct device *dev) +{ + int ioaddr = dev->base_addr; + + dev->tbusy = 1; + dev->start = 0; + + outb(CMD0_RESET, ioaddr); /* CMD0_RESET */ + + disable_dma(zn.rx_dma); + disable_dma(zn.tx_dma); + + free_irq(dev->irq); + + if (znet_debug > 1) + printk(KERN_DEBUG "%s: Shutting down ethercard.\n", dev->name); + /* Turn off transceiver power. */ + outb(0x10, 0xe6); /* Select LAN control register */ + outb(inb(0xe7) & ~0x84, 0xe7); /* Turn on LAN power (bit 2). */ + + return 0; +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct enet_statistics *net_get_stats(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + + return &lp->stats; +} + +#ifdef HAVE_MULTICAST +/* Set or clear the multicast filter for this adaptor. + num_addrs == -1 Promiscuous mode, receive all packets + num_addrs == 0 Normal mode, clear multicast list + num_addrs > 0 Multicast mode, receive normal and MC packets, and do + best-effort filtering. + As a side effect this routine must also initialize the device parameters. + This is taken advantage of in open(). + + N.B. that we change i593_init[] in place. This (properly) makes the + mode change persistent, but must be changed if this code is moved to + a multiple adaptor environment. + */ +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs) +{ + short ioaddr = dev->base_addr; + + if (num_addrs < 0) { + /* Enable promiscuous mode */ + i593_init[7] &= ~3; i593_init[7] |= 1; + i593_init[13] &= ~8; i593_init[13] |= 8; + } else if (num_addrs > 0) { + /* Enable accept-all-multicast mode */ + i593_init[7] &= ~3; i593_init[7] |= 0; + i593_init[13] &= ~8; i593_init[13] |= 8; + } else { /* Enable normal mode. */ + i593_init[7] &= ~3; i593_init[7] |= 0; + i593_init[13] &= ~8; i593_init[13] |= 0; + } + *zn.tx_cur++ = sizeof(i593_init); + memcpy(zn.tx_cur, i593_init, sizeof(i593_init)); + zn.tx_cur += sizeof(i593_init)/2; + outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr); +#ifdef not_tested + if (num_addrs > 0) { + int addrs_len = 6*num_addrs; + *zn.tx_cur++ = addrs_len; + memcpy(zn.tx_cur, addrs, addrs_len); + outb(CMD0_MULTICAST_LIST+CMD0_CHNL_1, ioaddr); + zn.tx_cur += addrs_len>>1; + } +#endif +} +#endif + +void show_dma(void) +{ + short dma_port = ((zn.tx_dma&3)<<2) + IO_DMA2_BASE; + unsigned addr = inb(dma_port); + addr |= inb(dma_port) << 8; + printk("Addr: %04x cnt:%3x...", addr<<1, get_dma_residue(zn.tx_dma)); +} + +/* Initialize the hardware. We have to do this when the board is open()ed + or when we come out of suspend mode. */ +static void hardware_init(struct device *dev) +{ + short ioaddr = dev->base_addr; + + zn.rx_cur = zn.rx_start; + zn.tx_cur = zn.tx_start; + + /* Reset the chip, and start it up. */ + outb(CMD0_RESET, ioaddr); + + cli(); { /* Protect against a DMA flip-flop */ + disable_dma(zn.rx_dma); /* reset by an interrupting task. */ + clear_dma_ff(zn.rx_dma); + set_dma_mode(zn.rx_dma, DMA_RX_MODE); + set_dma_addr(zn.rx_dma, (unsigned int) zn.rx_start); + set_dma_count(zn.rx_dma, RX_BUF_SIZE); + enable_dma(zn.rx_dma); + /* Now set up the Tx channel. */ + disable_dma(zn.tx_dma); + clear_dma_ff(zn.tx_dma); + set_dma_mode(zn.tx_dma, DMA_TX_MODE); + set_dma_addr(zn.tx_dma, (unsigned int) zn.tx_start); + set_dma_count(zn.tx_dma, zn.tx_buf_len<<1); + enable_dma(zn.tx_dma); + } sti(); + + if (znet_debug > 1) + printk(KERN_DEBUG "%s: Initializing the i82593, tx buf %p... ", dev->name, + zn.tx_start); + /* Do an empty configure command, just like the Crynwr driver. This + resets to chip to its default values. */ + *zn.tx_cur++ = 0; + *zn.tx_cur++ = 0; + printk("stat:%02x ", inb(ioaddr)); show_dma(); + outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr); + *zn.tx_cur++ = sizeof(i593_init); + memcpy(zn.tx_cur, i593_init, sizeof(i593_init)); + zn.tx_cur += sizeof(i593_init)/2; + printk("stat:%02x ", inb(ioaddr)); show_dma(); + outb(CMD0_CONFIGURE+CMD0_CHNL_1, ioaddr); + *zn.tx_cur++ = 6; + memcpy(zn.tx_cur, dev->dev_addr, 6); + zn.tx_cur += 3; + printk("stat:%02x ", inb(ioaddr)); show_dma(); + outb(CMD0_IA_SETUP + CMD0_CHNL_1, ioaddr); + printk("stat:%02x ", inb(ioaddr)); show_dma(); + + update_stop_hit(ioaddr, 8192); + if (znet_debug > 1) printk("enabling Rx.\n"); + outb(CMD0_Rx_ENABLE+CMD0_CHNL_0, ioaddr); + dev->tbusy = 0; +} + +static void update_stop_hit(short ioaddr, unsigned short rx_stop_offset) +{ + outb(CMD0_PORT_1, ioaddr); + if (znet_debug > 5) + printk(KERN_DEBUG "Updating stop hit with value %02x.\n", + (rx_stop_offset >> 6) | 0x80); + outb((rx_stop_offset >> 6) | 0x80, ioaddr); + outb(CMD1_PORT_0, ioaddr); +} + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c znet.c" + * version-control: t + * kept-new-versions: 5 + * c-indent-level: 4 + * tab-width: 4 + * End: + */ Only in v1.1.24/linux/drivers/net: znote.c diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/ChangeLog linux/drivers/scsi/ChangeLog --- v1.1.24/linux/drivers/scsi/ChangeLog Fri Jun 17 15:20:05 1994 +++ linux/drivers/scsi/ChangeLog Thu Jul 7 18:45:08 1994 @@ -1,4 +1,45 @@ +Wed Jul 6 05:45:02 1994 Eric Youngdale (eric@esp22) + + * Linux 1.1.25 released. + + * sd.c, sr.c: Use new check_media_change and revalidate + file_operations fields. + + * st.c, st.h: Add changes from Kai Makisara, dated Jun 22. + + * hosts.h: Change SG_ALL back to 0xff. Apparently soft error + in /dev/brain resulted in having this bumped up. + Change first parameter in bios_param function to be Disk * instead + of index into rscsi_disks. + + * sd_ioctl.c: Pass pointer to rscsi_disks element instead of index + to array. + + * sd.h: Add struct name "scsi_disk" to typedef for Scsi_Disk. + + * scsi.c: Remove redundant Maxtor XT8760S from blacklist. + In scsi_reset, add printk when DEBUG defined. + + * All low level drivers: Modify definitions of bios_param in + appropriate way. + +Thu Jun 16 10:31:59 1994 Eric Youngdale (eric@esp22) + + * Linux 1.1.20 released. + + * scsi_ioctl.c: Only pass down the actual number of characters + required to scsi_do_cmd, not the one rounded up to a even number + of sectors. + + * ultrastor.c: Changes from Caleb Epstein for 24f cards. Support + larger SG lists. + + * ultrastor.c: Changes from me - use scsi_register to register + host. Add some consistency checking, + Wed Jun 1 21:12:13 1994 Eric Youngdale (eric@esp22) + + * Linux 1.1.19 released. * scsi.h: Add new return code for reset() function: SCSI_RESET_PUNT. diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/README.st linux/drivers/scsi/README.st --- v1.1.24/linux/drivers/scsi/README.st Mon May 23 12:14:22 1994 +++ linux/drivers/scsi/README.st Thu Jul 7 18:45:05 1994 @@ -1,5 +1,5 @@ This file contains brief information about the SCSI tape driver. -Last modified: Thu May 5 00:13:24 1994 by root@kai.home +Last modified: Wed Jun 22 23:38:47 1994 by root@kai.home BASICS @@ -10,6 +10,9 @@ (minor equals device number) and non-rewind devices (minor is 128 + device number) are implemented. +By default the driver writes one filemark when the device is closed after +writing. Two filemarks can be optionally written. In both cases end +of data is signified by returning zero bytes for two consecutive reads. BUFFERING @@ -78,12 +81,13 @@ MTWEOF Write count filemarks. MTREW Rewind tape. MTOFFL Set device off line (often rewind plus eject). -MTNOP Do nothing. +MTNOP Do nothing except flush the buffers. MTRETEN Retension tape. MTEOM Space to end of recorded data. MTERASE Erase tape. MTSEEK Seek to tape block count. Uses Tandberg-compatible seek (QFA) - for SCSI-1 drives and SCSI-2 seek for SCSI-2 drives. + for SCSI-1 drives and SCSI-2 seek for SCSI-2 drives. The file and + block numbers in the status are not valid after a seek. MTSETBLK Set the drive block size. Setting to zero sets the drive into variable block mode (if applicable). MTSETDENSITY Sets the drive density code to arg. See drive @@ -99,8 +103,9 @@ Sets the buffering options. The bits are the new states (enabled/disabled) of the write buffering (MT_ST_BUFFER_WRITES), asynchronous writes (MT_ST_ASYNC_WRITES), read ahead - (MT_ST_READ_AHEAD) and debugging (MT_ST_DEBUGGING; - (debugging must be compiled into the driver). + (MT_ST_READ_AHEAD), writing of two filemark (ST_TWO_FM), and + debugging (MT_ST_DEBUGGING ; debugging must be compiled into the + driver). MT_ST_WRITE_THRESHOLD Sets the write threshold for this device to kilobytes specified by the lowest bits. @@ -120,6 +125,8 @@ The current block size and the density code are stored in the field mt_dsreg (shifts for the subfields are MT_ST_BLKSIZE_SHIFT and MT_ST_DENSITY_SHIFT). + The write protect bit in mt_gstat is set if the tape is write + protected. The other fields are empty. diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha152x.c linux/drivers/scsi/aha152x.c --- v1.1.24/linux/drivers/scsi/aha152x.c Fri May 27 10:49:07 1994 +++ linux/drivers/scsi/aha152x.c Thu Jul 7 18:45:06 1994 @@ -20,10 +20,19 @@ * General Public License for more details. * - * $Id: aha152x.c,v 1.0 1994/03/25 12:52:00 root Exp $ + * $Id: aha152x.c,v 1.2 1994/07/03 12:56:36 root Exp $ * * $Log: aha152x.c,v $ + * Revision 1.2 1994/07/03 12:56:36 root + * - cleaned up debugging code + * - more tweaking on reset delays + * - updated abort/reset code (pretty untested...) + * + * Revision 1.1 1994/05/28 21:18:49 root + * - update for mid-level interface change (abort-reset) + * - delays after resets adjusted for some slow devices + * * Revision 1.0 1994/03/25 12:52:00 root * - Fixed "more data than expected" problem * - added new BIOS signatures @@ -162,12 +171,11 @@ **************************************************************************/ -#include "aha152x.h" - #include #include #include "../block/blk.h" #include "scsi.h" +#include "sd.h" /* Reqd for biosparam definition */ #include "hosts.h" #include "constants.h" #include @@ -176,6 +184,8 @@ #include #include +#include "aha152x.h" + /* DEFINES */ @@ -500,10 +510,6 @@ struct sigaction sa; int interrupt_level; -#if defined(DEBUG_RACE) - enter_driver("detect"); -#endif - if(setup_called) { printk("aha152x: processing commandline: "); @@ -568,13 +574,8 @@ (int) signatures[j].sig_length); if(!ok) - { -#if defined(DEBUG_RACE) - leave_driver("(1) detect"); -#endif - printk("failed\n"); - return 0; - } + return 0; + printk("aha152x: BIOS test: passed, "); #else printk("aha152x: "); @@ -588,9 +589,6 @@ if(i==PORT_COUNT) { printk("failed\n"); -#if defined(DEBUG_RACE) - leave_driver("(2) detect"); -#endif return 0; } else @@ -662,9 +660,9 @@ /* RESET OUT */ SETBITS(SCSISEQ, SCSIRSTO ); - do_pause(5); + do_pause(30); CLRBITS(SCSISEQ, SCSIRSTO ); - do_pause(10); + do_pause(60); aha152x_reset(NULL); @@ -677,10 +675,6 @@ SETPORT(SIMODE0, 0); SETPORT(SIMODE1, 0); -#if defined(DEBUG_RACE) - leave_driver("(3) detect"); -#endif - SETBITS( DMACNTRL0, INTEN); return 1; } @@ -765,6 +759,10 @@ } sti(); +#if defined(DEBUG_RACE) + leave_driver("queue"); +#endif + return 0; } @@ -791,7 +789,9 @@ printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned int) SCpnt ); #endif +#if defined(DEBUG_ABORT) show_queues(); +#endif /* look for command in issue queue */ for( ptr=issue_SC, prev=NULL; @@ -814,12 +814,21 @@ return SCSI_ABORT_SUCCESS; } - /* Fail abortion, if we're on the bus */ if (current_SC) - { + if( TESTLO(SSTAT1, BUSFREE) ) { + /* fail abortion, if current command is on the bus */ sti(); return SCSI_ABORT_BUSY; } + else + { + /* target entered bus free before COMMAND COMPLETE, nothing to abort */ + sti(); + current_SC->result = DID_ERROR << 16; + current_SC->done(current_SC); + current_SC = (Scsi_Cmnd *) NULL; + return SCSI_ABORT_SUCCESS; + } /* look for command in disconnected queue */ for( ptr=disconnected_SC, prev=NULL; @@ -836,7 +845,7 @@ if(prev) prev->host_scribble = ptr->host_scribble; else - issue_SC = (Scsi_Cmnd *) ptr->host_scribble; + disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble; /* set command current and initiate selection, let the interrupt routine take care of the abortion */ @@ -903,11 +912,11 @@ /* * Reset registers, reset a hanging bus and - * kill active and disconnected commands + * kill active and disconnected commands for target w/o soft reset */ int aha152x_reset(Scsi_Cmnd * __unused) { - Scsi_Cmnd *ptr; + Scsi_Cmnd *ptr, *prev, *next; aha152x_reset_ports(); @@ -920,13 +929,11 @@ printk("aha152x: reset(), bus not free: SCSI RESET OUT\n"); #endif +#if defined( DEBUG_RESET ) show_queues(); - - /* FIXME - if the device implements soft resets, the command will still - be running after the bus reset. In this case we should do nothing - and let the command continue. -ERY */ +#endif - if(current_SC) + if(current_SC && !current_SC->device->soft_reset) { current_SC->host_scribble = NULL; current_SC->result = DID_RESET << 16; @@ -934,22 +941,45 @@ current_SC=NULL; } - while(disconnected_SC) - { - ptr = disconnected_SC; - disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble; - ptr->host_scribble = NULL; - ptr->result = DID_RESET << 16; - ptr->done(ptr); - } + cli(); + prev=NULL; ptr=disconnected_SC; + while(ptr) + { + if(!ptr->device->soft_reset) + { + if(prev) + prev->host_scribble = ptr->host_scribble; + else + disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble; + + next = (Scsi_Cmnd *) ptr->host_scribble; + + ptr->host_scribble = NULL; + ptr->result = DID_RESET << 16; + ptr->done(ptr); + + ptr = next; + } + else + { + prev=ptr; + ptr = (Scsi_Cmnd *) ptr->host_scribble; + } + } + sti(); + +#if defined( DEBUG_RESET ) + printk("commands on targets w/ soft-resets:\n"); + show_queues(); +#endif /* RESET OUT */ SETPORT(SCSISEQ, SCSIRSTO); - do_pause(5); + do_pause(30); SETPORT(SCSISEQ, 0); - do_pause(10); + do_pause(60); - SETPORT(SIMODE0, 0 ); + SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 ); SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0); SETPORT( DMACNTRL0, INTEN ); @@ -961,8 +991,9 @@ /* * Return the "logical geometry" */ -int aha152x_biosparam( int size, int dev, int *info_array ) +int aha152x_biosparam(Scsi_Disk * disk, int dev, int *info_array ) { + int size = disk->capacity; #if defined(DEBUG_BIOSPARAM) printk("aha152x_biosparam: dev=%x, size=%d, ", dev, size); #endif diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha152x.h linux/drivers/scsi/aha152x.h --- v1.1.24/linux/drivers/scsi/aha152x.h Fri May 27 10:49:07 1994 +++ linux/drivers/scsi/aha152x.h Thu Jul 7 18:45:07 1994 @@ -2,7 +2,7 @@ #define _AHA152X_H /* - * $Id: aha152x.h,v 1.0 1994/03/25 12:52:00 root Exp $ + * $Id: aha152x.h,v 1.2 1994/07/03 13:01:47 root Exp $ */ #include "../block/blk.h" @@ -16,13 +16,13 @@ int aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int aha152x_abort(Scsi_Cmnd *); int aha152x_reset(Scsi_Cmnd *); -int aha152x_biosparam(int, int, int*); +int aha152x_biosparam(Disk *, int, int*); /* number of queueable commands (unless we support more than 1 cmd_per_lun this should do) */ #define AHA152X_MAXQUEUE 7 -#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.0 $" +#define AHA152X_REVID "Adaptec 152x SCSI driver; $Revision: 1.2 $" /* Initial value of Scsi_Host entry */ #define AHA152X { /* name */ AHA152X_REVID, \ diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha1542.c linux/drivers/scsi/aha1542.c --- v1.1.24/linux/drivers/scsi/aha1542.c Fri Jun 17 15:20:06 1994 +++ linux/drivers/scsi/aha1542.c Thu Jul 7 18:45:06 1994 @@ -17,7 +17,6 @@ #include #include #include -#include #include #include @@ -1063,18 +1062,14 @@ return SCSI_RESET_PUNT; } -#ifdef CONFIG_BLK_DEV_SD #include "sd.h" -#endif -int aha1542_biosparam(int size, int dev, int * ip) +int aha1542_biosparam(Scsi_Disk * disk, int dev, int * ip) { int translation_algorithm; -#ifdef CONFIG_BLK_DEV_SD - Scsi_Device *disk; + int size = disk->capacity; - disk = rscsi_disks[MINOR(dev) >> 4].device; - translation_algorithm = HOSTDATA(disk->host)->bios_translation; + translation_algorithm = HOSTDATA(disk->device->host)->bios_translation; /* Should this be > 1024, or >= 1024? Enquiring minds want to know. */ if((size>>11) > 1024 && translation_algorithm == 2) { /* Please verify that this is the same as what DOS returns */ @@ -1087,6 +1082,5 @@ ip[2] = size >> 11; }; /* if (ip[2] >= 1024) ip[2] = 1024; */ -#endif return 0; } diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha1542.h linux/drivers/scsi/aha1542.h --- v1.1.24/linux/drivers/scsi/aha1542.h Fri May 27 10:49:07 1994 +++ linux/drivers/scsi/aha1542.h Thu Jul 7 18:45:08 1994 @@ -134,7 +134,7 @@ int aha1542_abort(Scsi_Cmnd *); const char *aha1542_info(void); int aha1542_reset(Scsi_Cmnd *); -int aha1542_biosparam(int, int, int*); +int aha1542_biosparam(Disk *, int, int*); #define AHA1542_MAILBOXES 8 #define AHA1542_SCATTER 16 diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha1740.c linux/drivers/scsi/aha1740.c --- v1.1.24/linux/drivers/scsi/aha1740.c Fri Jun 17 15:20:06 1994 +++ linux/drivers/scsi/aha1740.c Thu Jul 7 18:45:06 1994 @@ -31,6 +31,7 @@ #include "../block/blk.h" #include "scsi.h" #include "hosts.h" +#include "sd.h" #include "aha1740.h" @@ -489,8 +490,9 @@ return SCSI_RESET_PUNT; } -int aha1740_biosparam(int size, int dev, int* ip) +int aha1740_biosparam(Disk * disk, int dev, int* ip) { + int size = disk->capacity; DEB(printk("aha1740_biosparam\n")); ip[0] = 64; ip[1] = 32; diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/aha1740.h linux/drivers/scsi/aha1740.h --- v1.1.24/linux/drivers/scsi/aha1740.h Fri May 27 10:49:08 1994 +++ linux/drivers/scsi/aha1740.h Thu Jul 7 18:45:08 1994 @@ -158,7 +158,7 @@ int aha1740_abort(Scsi_Cmnd *); const char *aha1740_info(void); int aha1740_reset(Scsi_Cmnd *); -int aha1740_biosparam(int, int, int*); +int aha1740_biosparam(Disk *, int, int*); #define AHA1740_ECBS 32 #define AHA1740_SCATTER 16 diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/buslogic.c linux/drivers/scsi/buslogic.c --- v1.1.24/linux/drivers/scsi/buslogic.c Fri Jun 17 15:20:06 1994 +++ linux/drivers/scsi/buslogic.c Thu Jul 7 18:45:06 1994 @@ -59,7 +59,6 @@ * unfinished, questionable, or wrong. */ -#include #include #include #include @@ -74,9 +73,7 @@ #include "../block/blk.h" #include "scsi.h" #include "hosts.h" -#ifdef CONFIG_BLK_DEV_SD # include "sd.h" -#endif #define BUSLOGIC_PRIVATE_H /* Get the "private" stuff */ #include "buslogic.h" @@ -1181,17 +1178,17 @@ return SCSI_RESET_PUNT; } -int buslogic_biosparam(int size, int dev, int *ip) +int buslogic_biosparam(Disk * disk, int dev, int *ip) { - /* ??? This is wrong if disk is configured for > 1G mapping. - Unfortunately, unlike UltraStor, I see know way of determining whether - > 1G mapping has been enabled. */ -#ifdef CONFIG_BLK_DEV_SD - int translation_algorithm; - Scsi_Device *disk; + int size = disk->capacity; + int translation_algorithm; + + /* ??? This is wrong if disk is configured for > 1G mapping. + Unfortunately, unlike UltraStor, I see know way of determining whether + > 1G mapping has been enabled. */ - disk = rscsi_disks[MINOR(dev) >> 4].device; - translation_algorithm = HOSTDATA(disk->host)->bios_translation; + + translation_algorithm = HOSTDATA(disk->device->host)->bios_translation; /* ??? Should this be > 1024, or >= 1024? Enquiring minds want to know. */ if ((size >> 11) > 1024 && translation_algorithm == BIOS_TRANSLATION_25563) { @@ -1206,6 +1203,5 @@ } /* if (ip[2] > 1024) ip[2] = 1024; */ -#endif return 0; } diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/buslogic.h linux/drivers/scsi/buslogic.h --- v1.1.24/linux/drivers/scsi/buslogic.h Fri May 27 10:49:08 1994 +++ linux/drivers/scsi/buslogic.h Thu Jul 7 18:45:08 1994 @@ -17,7 +17,7 @@ int buslogic_abort(Scsi_Cmnd *); const char *buslogic_info(void); int buslogic_reset(Scsi_Cmnd *); -int buslogic_biosparam(int, int, int *); +int buslogic_biosparam(Disk *, int, int *); #define BUSLOGIC_CMDLUN 1 /* ??? */ diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/fdomain.c linux/drivers/scsi/fdomain.c --- v1.1.24/linux/drivers/scsi/fdomain.c Fri May 27 10:49:09 1994 +++ linux/drivers/scsi/fdomain.c Thu Jul 7 18:45:07 1994 @@ -156,7 +156,6 @@ **************************************************************************/ -#include #include #include #include "../block/blk.h" @@ -1456,20 +1455,18 @@ return SCSI_RESET_WAKEUP; } -#ifdef CONFIG_BLK_DEV_SD - #include "sd.h" #include "scsi_ioctl.h" -int fdomain_16x0_biosparam( int size, int dev, int *info_array ) +int fdomain_16x0_biosparam(Scsi_Disk * disk, int dev, int *info_array ) { int drive; + int size = disk->capacity; unsigned char buf[512 + sizeof( int ) * 2]; int *sizes = (int *)buf; unsigned char *data = (unsigned char *)(sizes + 2); unsigned char do_read[] = { READ_6, 0, 0, 0, 1, 0 }; int retcode; - Scsi_Device *disk; struct drive_info { unsigned short cylinders; unsigned char heads; @@ -1509,7 +1506,6 @@ */ drive = MINOR(dev) / 16; - disk = rscsi_disks[ drive ].device; if (bios_major == 2) { i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 ); @@ -1527,7 +1523,7 @@ sizes[0] = 0; /* zero bytes out */ sizes[1] = 512; /* one sector in */ memcpy( data, do_read, sizeof( do_read ) ); - retcode = kernel_scsi_ioctl( disk, + retcode = kernel_scsi_ioctl( disk->device, SCSI_IOCTL_SEND_COMMAND, (void *)buf ); if (!retcode /* SCSI command ok */ @@ -1588,5 +1584,3 @@ return 0; } - -#endif /* CONFIG_BLK_DEV_SD */ diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/fdomain.h linux/drivers/scsi/fdomain.h --- v1.1.24/linux/drivers/scsi/fdomain.h Fri May 27 10:49:09 1994 +++ linux/drivers/scsi/fdomain.h Thu Jul 7 18:45:07 1994 @@ -32,11 +32,7 @@ int fdomain_16x0_reset( Scsi_Cmnd * ); int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) ); -#ifdef CONFIG_BLK_DEV_SD -int fdomain_16x0_biosparam( int, int, int * ); -#else -#define fdomain_16x0_biosparam NULL -#endif +int fdomain_16x0_biosparam(Disk *, int, int * ); #define FDOMAIN_16X0 { "Future Domain TMC-16x0", \ fdomain_16x0_detect, \ diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/hosts.h linux/drivers/scsi/hosts.h --- v1.1.24/linux/drivers/scsi/hosts.h Fri May 27 10:49:09 1994 +++ linux/drivers/scsi/hosts.h Thu Jul 7 18:45:05 1994 @@ -21,8 +21,10 @@ */ +/* It is senseless to set SG_ALL any higher than this - the performance + does not get any better, and it wastes memory */ #define SG_NONE 0 -#define SG_ALL 0x7fff +#define SG_ALL 0xff #define DISABLE_CLUSTERING 0 #define ENABLE_CLUSTERING 1 @@ -42,6 +44,8 @@ type of host adapter that is supported on the system. */ +typedef struct scsi_disk Disk; + typedef struct { /* @@ -144,7 +148,7 @@ size, device number, list (heads, sectors, cylinders) */ - int (* bios_param)(int, int, int []); + int (* bios_param)(Disk *, int, int []); /* This determines if we will use a non-interrupt driven diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/pas16.c linux/drivers/scsi/pas16.c --- v1.1.24/linux/drivers/scsi/pas16.c Wed Dec 1 14:44:16 1993 +++ linux/drivers/scsi/pas16.c Thu Jul 7 18:45:06 1994 @@ -91,9 +91,9 @@ #define AUTOPROBE_IRQ #include "NCR5380.h" #include "constants.h" +#include "sd.h" - int scsi_irq_translate[] = { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 }; @@ -374,7 +374,7 @@ } /* - * Function : int pas16_biosparam(int size, int dev, int *ip) + * Function : int pas16_biosparam(Disk *disk, int dev, int *ip) * * Purpose : Generates a BIOS / DOS compatable H-C-S mapping for * the specified device / size. @@ -393,8 +393,9 @@ * and matching the H_C_S coordinates to what DOS uses. */ -int pas16_biosparam(int size, int dev, int * ip) +int pas16_biosparam(Disk * disk, int dev, int * ip) { + int size = disk->capacity; ip[0] = 64; ip[1] = 32; ip[2] = size >> 11; diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/pas16.h linux/drivers/scsi/pas16.h --- v1.1.24/linux/drivers/scsi/pas16.h Fri May 27 10:49:09 1994 +++ linux/drivers/scsi/pas16.h Thu Jul 7 18:45:08 1994 @@ -115,7 +115,7 @@ #ifndef ASM int pas16_abort(Scsi_Cmnd *); -int pas16_biosparam(int, int, int*); +int pas16_biosparam(Disk *, int, int*); int pas16_detect(int); const char *pas16_info(void); int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v1.1.24/linux/drivers/scsi/scsi.c Mon Jun 27 16:47:01 1994 +++ linux/drivers/scsi/scsi.c Thu Jul 7 18:45:06 1994 @@ -142,7 +142,6 @@ {"MAXTOR","XT-4380S","B3C"}, /* Locks-up when LUN>0 polled. */ {"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN > 0 polled */ {"MAXTOR","XT-4170S","B5A"}, /* Locks-up sometimes when LUN>0 polled. */ - {"MAXTOR","XT-8760S","B6B"}, /* Locks-up when LUN > 0 is polled */ {"MAXTOR","XT-8760S","B7B"}, /* guess what? */ {"NEC","CD-ROM DRIVE:841","1.0"}, /* Locks-up when LUN>0 polled. */ {"RODIME","RO3000S","2.33"}, /* Locks up if polled for lun != 0 */ @@ -1493,6 +1492,9 @@ host->host_busy--; } +#ifdef DEBUG + printk("scsi reset function returned %d\n", temp); +#endif switch(temp) { case SCSI_RESET_SUCCESS: cli(); diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/scsi_debug.c linux/drivers/scsi/scsi_debug.c --- v1.1.24/linux/drivers/scsi/scsi_debug.c Fri May 27 10:49:10 1994 +++ linux/drivers/scsi/scsi_debug.c Thu Jul 7 18:45:07 1994 @@ -22,6 +22,8 @@ #include "scsi.h" #include "hosts.h" +#include "sd.h" + /* A few options that we want selected */ /* Do not attempt to use a timer to simulate a real disk with latency */ @@ -541,7 +543,8 @@ return 0; } -int scsi_debug_biosparam(int size, int dev, int* info){ +int scsi_debug_biosparam(Disk * disk, int dev, int* info){ + int size = disk->capacity; info[0] = 32; info[1] = 64; info[2] = (size + 2047) >> 11; diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/scsi_debug.h linux/drivers/scsi/scsi_debug.h --- v1.1.24/linux/drivers/scsi/scsi_debug.h Fri May 27 10:49:10 1994 +++ linux/drivers/scsi/scsi_debug.h Thu Jul 7 18:45:08 1994 @@ -6,7 +6,7 @@ int scsi_debug_command(Scsi_Cmnd *); int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int scsi_debug_abort(Scsi_Cmnd *, int); -int scsi_debug_biosparam(int, int, int[]); +int scsi_debug_biosparam(Disk *, int, int[]); const char *scsi_debug_info(void); int scsi_debug_reset(Scsi_Cmnd *); diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/sd.c linux/drivers/scsi/sd.c --- v1.1.24/linux/drivers/scsi/sd.c Fri May 27 10:49:11 1994 +++ linux/drivers/scsi/sd.c Thu Jul 7 18:45:05 1994 @@ -54,6 +54,9 @@ extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +static int check_scsidisk_media_change(dev_t); +static int fop_revalidate_scsidisk(dev_t); + static sd_init_onedisk(int); static void requeue_sd_request (Scsi_Cmnd * SCpnt); @@ -108,7 +111,10 @@ NULL, /* mmap */ sd_open, /* open code */ sd_release, /* release */ - block_fsync /* fsync */ + block_fsync, /* fsync */ + NULL, /* fasync */ + check_scsidisk_media_change, /* Disk change */ + fop_revalidate_scsidisk /* revalidate */ }; static struct gendisk sd_gendisk = { @@ -733,10 +739,11 @@ MAX_RETRIES); } -int check_scsidisk_media_change(int full_dev, int flag){ +static int check_scsidisk_media_change(dev_t full_dev){ int retval; int target; struct inode inode; + int flag = 0; target = DEVICE_NR(MINOR(full_dev)); @@ -1089,5 +1096,9 @@ DEVICE_BUSY = 0; return 0; +} + +static int fop_revalidate_scsidisk(dev_t dev){ + return revalidate_scsidisk(dev, 0); } diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/sd.h linux/drivers/scsi/sd.h --- v1.1.24/linux/drivers/scsi/sd.h Wed Dec 1 14:44:16 1993 +++ linux/drivers/scsi/sd.h Thu Jul 7 18:45:07 1994 @@ -31,7 +31,7 @@ extern struct hd_struct * sd; -typedef struct { +typedef struct scsi_disk { unsigned capacity; /* size in blocks */ unsigned sector_size; /* size in bytes */ Scsi_Device *device; diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/sd_ioctl.c linux/drivers/scsi/sd_ioctl.c --- v1.1.24/linux/drivers/scsi/sd_ioctl.c Tue Apr 19 10:52:49 1994 +++ linux/drivers/scsi/sd_ioctl.c Thu Jul 7 18:45:08 1994 @@ -33,7 +33,7 @@ diskinfo[1] = 0; diskinfo[2] = 0; if(host->hostt->bios_param != NULL) - host->hostt->bios_param(rscsi_disks[MINOR(dev) >> 4].capacity, + host->hostt->bios_param(&rscsi_disks[MINOR(dev) >> 4], dev, &diskinfo[0]); put_fs_byte(diskinfo[0], diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/seagate.c linux/drivers/scsi/seagate.c --- v1.1.24/linux/drivers/scsi/seagate.c Fri May 27 10:49:11 1994 +++ linux/drivers/scsi/seagate.c Thu Jul 7 18:45:07 1994 @@ -1590,34 +1590,28 @@ return SCSI_RESET_PENDING; } -#ifdef CONFIG_BLK_DEV_SD - #include #include "sd.h" #include "scsi_ioctl.h" -int seagate_st0x_biosparam(int size, int dev, int* ip) { +int seagate_st0x_biosparam(Disk * disk, int dev, int* ip) { unsigned char buf[256 + sizeof(int) * 2], cmd[6], *data, *page; int *sizes, result, formatted_sectors, total_sectors; int cylinders, heads, sectors; - Scsi_Device *disk; - - disk = rscsi_disks[MINOR(dev) >> 4].device; - /* * Only SCSI-I CCS drives and later implement the necessary mode sense * pages. */ - if (disk->scsi_level < 2) + if (disk->device->scsi_level < 2) return -1; sizes = (int *) buf; data = (unsigned char *) (sizes + 2); cmd[0] = MODE_SENSE; - cmd[1] = (disk->lun << 5) & 0xe5; + cmd[1] = (disk->device->lun << 5) & 0xe5; cmd[2] = 0x04; /* Read page 4, rigid disk geometry page current values */ cmd[3] = 0; cmd[4] = 255; @@ -1633,7 +1627,7 @@ memcpy (data, cmd, 6); - if (!(result = kernel_scsi_ioctl (disk, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) { + if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) { /* * The mode page lies beyond the MODE SENSE header, with length 4, and * the BLOCK DESCRIPTOR, with length header[3]. @@ -1646,7 +1640,7 @@ cmd[2] = 0x03; /* Read page 3, format page current values */ memcpy (data, cmd, 6); - if (!(result = kernel_scsi_ioctl (disk, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) { + if (!(result = kernel_scsi_ioctl (disk->device, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) { page = data + 4 + data[3]; sectors = (page[10] << 8) | page[11]; @@ -1701,7 +1695,5 @@ return result; } -#endif /* CONFIG_BLK_DEV_SD */ - #endif /* defined(CONFIG_SCSI_SEGATE) */ diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/seagate.h linux/drivers/scsi/seagate.h --- v1.1.24/linux/drivers/scsi/seagate.h Fri May 27 10:49:11 1994 +++ linux/drivers/scsi/seagate.h Thu Jul 7 18:45:07 1994 @@ -24,11 +24,7 @@ #define NULL 0 #endif -#ifdef CONFIG_BLK_DEV_SD -int seagate_st0x_biosparam(int, int, int*); -#else -#define seagate_st0x_biosparam NULL -#endif +int seagate_st0x_biosparam(Disk *, int, int*); #define SEAGATE_ST0X {"Seagate ST-01/ST-02", seagate_st0x_detect, \ seagate_st0x_info, seagate_st0x_command, \ diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/sr.c linux/drivers/scsi/sr.c --- v1.1.24/linux/drivers/scsi/sr.c Fri May 27 10:49:11 1994 +++ linux/drivers/scsi/sr.c Thu Jul 7 18:45:05 1994 @@ -45,6 +45,7 @@ extern int sr_ioctl(struct inode *, struct file *, unsigned int, unsigned long); void requeue_sr_request (Scsi_Cmnd * SCpnt); +static int check_cdrom_media_change(dev_t); static void sr_release(struct inode * inode, struct file * file) { @@ -62,9 +63,12 @@ NULL, /* select */ sr_ioctl, /* ioctl */ NULL, /* mmap */ - sr_open, /* no special open code */ + sr_open, /* special open code */ sr_release, /* release */ - NULL /* fsync */ + NULL, /* fsync */ + NULL, /* fasync */ + check_cdrom_media_change, /* Disk change */ + NULL /* revalidate */ }; /* @@ -77,9 +81,10 @@ * an inode for that to work, and we do not always have one. */ -int check_cdrom_media_change(int full_dev, int flag){ +int check_cdrom_media_change(dev_t full_dev){ int retval, target; struct inode inode; + int flag = 0; target = MINOR(full_dev); diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/st.c linux/drivers/scsi/st.c --- v1.1.24/linux/drivers/scsi/st.c Mon May 23 12:14:23 1994 +++ linux/drivers/scsi/st.c Thu Jul 7 18:45:05 1994 @@ -11,7 +11,7 @@ Copyright 1992, 1993, 1994 Kai Makisara email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi - Last modified: Wed May 4 20:29:42 1994 by root@kai.home + Last modified: Wed Jun 22 23:37:10 1994 by root@kai.home */ #include @@ -40,6 +40,8 @@ /* #define ST_RECOVERED_WRITE_FATAL */ +#define ST_TWO_FM 0 + #define ST_BUFFER_WRITES 1 #define ST_ASYNC_WRITES 1 @@ -71,7 +73,7 @@ #define MAX_READY_RETRIES 5 #define NO_TAPE NOT_READY -#define ST_TIMEOUT 9000 +#define ST_TIMEOUT 27000 #define ST_LONG_TIMEOUT 200000 static int st_nbr_buffers; @@ -237,6 +239,11 @@ if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); SCpnt->request.dev = -1; + if ((STp->buffer)->last_result != 0) { + printk("st%d: Backing over filemark failed.\n", dev); + (STp->mt_status)->mt_fileno += 1; + (STp->mt_status)->mt_blkno = 0; + } return (STp->buffer)->last_result_fatal; } @@ -551,7 +558,8 @@ (STp->buffer)->buffer_blocks); #endif - if ((STp->buffer)->b_data[2] & 0x80) { + STp->drv_write_prot = ((STp->buffer)->b_data[2] & 0x80) != 0; + if (STp->drv_write_prot) { STp->write_prot = 1; #ifdef DEBUG if (debugging) @@ -594,7 +602,7 @@ SCpnt->sense_buffer[0] = 0; memset(cmd, 0, 10); cmd[0] = WRITE_FILEMARKS; - cmd[4] = 1; + cmd[4] = 1 + STp->two_fm; SCpnt->request.dev = dev; scsi_do_cmd( SCpnt, (void *) cmd, (void *) (STp->buffer)->b_data, @@ -602,19 +610,23 @@ if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); - if ((STp->buffer)->last_result_fatal != 0) + if ((STp->buffer)->last_result_fatal != 0) { + SCpnt->request.dev = -1; /* Mark as not busy */ printk("st%d: Error on write filemark.\n", dev); + } else { + SCpnt->request.dev = -1; /* Mark as not busy */ (STp->mt_status)->mt_fileno++ ; STp->drv_block = 0; + if (STp->two_fm) + back_over_eof(dev); } - SCpnt->request.dev = -1; /* Mark as not busy */ } #ifdef DEBUG if (debugging) - printk("st%d: Buffer flushed, EOF written\n", dev); + printk("st%d: Buffer flushed, %d EOF(s) written\n", dev, cmd[4]); #endif } else if (!rewind) { @@ -670,6 +682,9 @@ STp->rw = ST_WRITING; } + if (STp->moves_after_eof < 255) + STp->moves_after_eof++; + if ((STp->buffer)->writing) { write_behind_check(dev); if ((STp->buffer)->last_result_fatal) { @@ -896,6 +911,8 @@ return transfer; STp->rw = ST_READING; } + if (STp->moves_after_eof < 255) + STp->moves_after_eof++; #ifdef DEBUG if (debugging && STp->eof != ST_NOEOF) @@ -1010,8 +1027,8 @@ "st%d: EOF detected (%d bytes read, transferred %d bytes).\n", dev, (STp->buffer)->buffer_bytes, total); #endif - } /* end of EOF, EOM, ILI test */ - } + } + } /* end of EOF, EOM, ILI test */ else { /* nonzero sense key */ #ifdef DEBUG if (debugging) @@ -1021,16 +1038,25 @@ STp->drv_block = (-1); if (total) return total; + else if (STp->moves_after_eof == 1 && + (SCpnt->sense_buffer[2] & 0x0f) == BLANK_CHECK) { +#ifdef DEBUG + if (debugging) + printk("st%d: Zero returned for first BLANK CHECK after EOF.\n", + dev); +#endif + return 0; /* First BLANK_CHECK after EOF */ + } else return -EIO; } - } + } /* End of extended sense test */ else { transfer = (STp->buffer)->last_result_fatal; SCpnt->request.dev = -1; /* Mark as not busy */ return transfer; } - } + } /* End of error handling */ else /* Read successful */ (STp->buffer)->buffer_bytes = bytes; @@ -1066,6 +1092,8 @@ if (total == 0 && STp->eof == ST_FM) { STp->eof = 0; STp->drv_block = 0; + if (STp->moves_after_eof > 1) + STp->moves_after_eof = 0; (STp->mt_status)->mt_fileno++; } if (total == 0 && STp->eof == ST_EOM_OK) @@ -1098,13 +1126,15 @@ STp->do_buffer_writes = (options & MT_ST_BUFFER_WRITES) != 0; STp->do_async_writes = (options & MT_ST_ASYNC_WRITES) != 0; STp->do_read_ahead = (options & MT_ST_READ_AHEAD) != 0; + STp->two_fm = (options & MT_ST_TWO_FM) != 0; #ifdef DEBUG debugging = (options & MT_ST_DEBUGGING) != 0; printk( "st%d: options: buffer writes: %d, async writes: %d, read ahead: %d\n", dev, STp->do_buffer_writes, STp->do_async_writes, STp->do_read_ahead); - printk(" debugging: %d\n", debugging); + printk(" two FMs: %d, debugging: %d\n", STp->two_fm, + debugging); #endif } else if ((options & MT_ST_OPTIONS) == MT_ST_WRITE_THRESHOLD) { @@ -1397,8 +1427,16 @@ SCpnt->request.dev = -1; /* Mark as not busy */ if (!ioctl_result) { - STp->drv_block = blkno; - (STp->mt_status)->mt_fileno = fileno; + if (cmd_in != MTSEEK) { + STp->drv_block = blkno; + (STp->mt_status)->mt_fileno = fileno; + } + else + STp->drv_block = (STp->mt_status)->mt_fileno = (-1); + if (cmd_in == MTFSF) + STp->moves_after_eof = 0; + else + STp->moves_after_eof = 1; if (cmd_in == MTBSFM) ioctl_result = st_int_ioctl(inode, file, MTFSF, 1); else if (cmd_in == MTFSFM) @@ -1419,10 +1457,10 @@ (STp->buffer)->read_pointer = 0; } else if (cmd_in == MTSETDRVBUFFER) - STp->drv_buffer = arg; + STp->drv_buffer = (arg & 7); else if (cmd_in == MTSETDENSITY) STp->density = arg; - else if (cmd_in == MTEOM || cmd_in == MTWEOF) { + else if (cmd_in == MTEOM) { STp->eof = ST_EOM_OK; STp->eof_hit = 0; } @@ -1498,7 +1536,7 @@ memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop)); - i = flush_buffer(inode, file, mtc.mt_op == MTSEEK || + i = flush_buffer(inode, file, mtc.mt_op == MTNOP || mtc.mt_op == MTSEEK || mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM); if (i < 0) @@ -1530,6 +1568,9 @@ (STp->mt_status)->mt_blkno -= ((STp->buffer)->buffer_bytes + STp->block_size - 1) / STp->block_size; } + (STp->mt_status)->mt_gstat = 0; + if (STp->drv_write_prot) + (STp->mt_status)->mt_gstat |= GMT_WR_PROT(0xffffffff); memcpy_tofs((char *)arg, (char *)(STp->mt_status), sizeof(struct mtget)); @@ -1677,8 +1718,10 @@ STp->do_buffer_writes = ST_BUFFER_WRITES; STp->do_async_writes = ST_ASYNC_WRITES; STp->do_read_ahead = ST_READ_AHEAD; + STp->two_fm = ST_TWO_FM; STp->write_threshold = st_write_threshold; STp->drv_block = 0; + STp->moves_after_eof = 1; STp->mt_status = (struct mtget *) mem_start; mem_start += sizeof(struct mtget); /* Initialize status */ diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/st.h linux/drivers/scsi/st.h --- v1.1.24/linux/drivers/scsi/st.h Mon May 23 12:14:23 1994 +++ linux/drivers/scsi/st.h Thu Jul 7 18:45:05 1994 @@ -25,16 +25,18 @@ unsigned capacity; struct wait_queue * waiting; Scsi_Device* device; - unsigned dirty:1; - unsigned rw:2; - unsigned eof:2; - unsigned write_prot:1; - unsigned in_use:1; - unsigned eof_hit:1; - unsigned drv_buffer:3; - unsigned do_buffer_writes:1; - unsigned do_async_writes:1; - unsigned do_read_ahead:1; + unsigned char dirty; + unsigned char rw; + unsigned char eof; + unsigned char write_prot; + unsigned char drv_write_prot; + unsigned char in_use; + unsigned char eof_hit; + unsigned char drv_buffer; + unsigned char do_buffer_writes; + unsigned char do_async_writes; + unsigned char do_read_ahead; + unsigned char two_fm; unsigned char density; ST_buffer * buffer; int block_size; @@ -43,6 +45,7 @@ int write_threshold; int recover_count; int drv_block; /* The block where the drive head is */ + unsigned char moves_after_eof; struct mtget * mt_status; Scsi_Cmnd SCpnt; } Scsi_Tape; diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/t128.c linux/drivers/scsi/t128.c --- v1.1.24/linux/drivers/scsi/t128.c Wed Dec 1 14:44:16 1993 +++ linux/drivers/scsi/t128.c Thu Jul 7 18:45:07 1994 @@ -116,10 +116,10 @@ #define AUTOPROBE_IRQ #include "NCR5380.h" #include "constants.h" +#include "sd.h" - static struct override { unsigned char *address; int irq; @@ -273,7 +273,7 @@ } /* - * Function : int t128_biosparam(int size, int dev, int *ip) + * Function : int t128_biosparam(Disk * disk, int dev, int *ip) * * Purpose : Generates a BIOS / DOS compatable H-C-S mapping for * the specified device / size. @@ -292,8 +292,9 @@ * and matching the H_C_S coordinates to what DOS uses. */ -int t128_biosparam(int size, int dev, int * ip) +int t128_biosparam(Disk * disk, int dev, int * ip) { + int size = disk->capacity; ip[0] = 64; ip[1] = 32; ip[2] = size >> 11; diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/t128.h linux/drivers/scsi/t128.h --- v1.1.24/linux/drivers/scsi/t128.h Fri May 27 10:49:11 1994 +++ linux/drivers/scsi/t128.h Thu Jul 7 18:45:08 1994 @@ -92,7 +92,7 @@ #ifndef ASM int t128_abort(Scsi_Cmnd *); -int t128_biosparam(int, int, int*); +int t128_biosparam(Disk *, int, int*); int t128_detect(int); const char *t128_info(void); int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/ultrastor.c linux/drivers/scsi/ultrastor.c --- v1.1.24/linux/drivers/scsi/ultrastor.c Tue Jun 21 14:16:23 1994 +++ linux/drivers/scsi/ultrastor.c Thu Jul 7 18:45:07 1994 @@ -140,6 +140,7 @@ #include "scsi.h" #include "hosts.h" #include "ultrastor.h" +#include "sd.h" #define FALSE 0 #define TRUE 1 @@ -996,8 +997,9 @@ } -int ultrastor_biosparam(int size, int dev, int * dkinfo) +int ultrastor_biosparam(Disk * disk, int dev, int * dkinfo) { + int size = disk->capacity; unsigned int s = config.heads * config.sectors; dkinfo[0] = config.heads; diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/ultrastor.h linux/drivers/scsi/ultrastor.h --- v1.1.24/linux/drivers/scsi/ultrastor.h Tue Jun 21 14:16:23 1994 +++ linux/drivers/scsi/ultrastor.h Thu Jul 7 18:45:08 1994 @@ -18,7 +18,7 @@ int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int ultrastor_abort(Scsi_Cmnd *); int ultrastor_reset(Scsi_Cmnd *); -int ultrastor_biosparam(int, int, int *); +int ultrastor_biosparam(Disk *, int, int *); #define ULTRASTOR_14F_MAX_SG 16 #define ULTRASTOR_24F_MAX_SG 33 diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/wd7000.c linux/drivers/scsi/wd7000.c --- v1.1.24/linux/drivers/scsi/wd7000.c Fri Jun 17 15:20:07 1994 +++ linux/drivers/scsi/wd7000.c Thu Jul 7 18:45:07 1994 @@ -115,6 +115,7 @@ #include "../block/blk.h" #include "scsi.h" #include "hosts.h" +#include "sd.h" #define ANY2SCSI_INLINE /* undef this to use old macros */ #undef DEBUG @@ -1225,8 +1226,9 @@ * this way, so I think it will work OK. Someone who is ambitious can * borrow a newer or more complete version from another driver. */ -int wd7000_biosparam(int size, int dev, int* ip) +int wd7000_biosparam(Disk * disk, int dev, int* ip) { + int size = disk->capacity; ip[0] = 64; ip[1] = 32; ip[2] = size >> 11; diff -u --recursive --new-file v1.1.24/linux/drivers/scsi/wd7000.h linux/drivers/scsi/wd7000.h --- v1.1.24/linux/drivers/scsi/wd7000.h Fri May 27 10:49:12 1994 +++ linux/drivers/scsi/wd7000.h Thu Jul 7 18:45:08 1994 @@ -18,7 +18,7 @@ int wd7000_abort(Scsi_Cmnd *); const char *wd7000_info(void); int wd7000_reset(Scsi_Cmnd *); -int wd7000_biosparam(int, int, int*); +int wd7000_biosparam(Disk *, int, int*); #ifndef NULL #define NULL 0L diff -u --recursive --new-file v1.1.24/linux/fs/buffer.c linux/fs/buffer.c --- v1.1.24/linux/fs/buffer.c Thu Jul 7 21:37:12 1994 +++ linux/fs/buffer.c Thu Jul 7 18:45:04 1994 @@ -479,7 +479,7 @@ wait_on_buffer(bh); if (bh->b_dev == dev && bh->b_size != size) { - bh->b_uptodate = bh->b_dirt = + bh->b_uptodate = bh->b_dirt = bh->b_req = bh->b_flushtime = 0; }; remove_from_hash_queue(bh); diff -u --recursive --new-file v1.1.24/linux/fs/devices.c linux/fs/devices.c --- v1.1.24/linux/fs/devices.c Thu Jul 7 21:37:12 1994 +++ linux/fs/devices.c Thu Jul 7 18:47:46 1994 @@ -15,22 +15,12 @@ #include #include +#include + /* * Ugly. We'll fix this once all the drivers use the f_ops->check_media_change() * stuff instead.. */ -#ifdef CONFIG_SCSI -#ifdef CONFIG_BLK_DEV_SR -extern int check_cdrom_media_change(int, int); -#endif -#ifdef CONFIG_BLK_DEV_SD -extern int check_scsidisk_media_change(int, int); -extern int revalidate_scsidisk(int, int); -#endif -#endif -#ifdef CONFIG_CDU31A -extern int check_cdu31a_media_change(int, int); -#endif #ifdef CONFIG_MCD extern int check_mcd_media_change(int, int); #endif @@ -142,57 +132,37 @@ * People changing diskettes in the middle of an operation deserve * to loose :-) */ -void check_disk_change(dev_t dev) +int check_disk_change(dev_t dev) { int i; struct file_operations * fops; i = MAJOR(dev); if (i >= MAX_BLKDEV || (fops = blkdevs[i].fops) == NULL) - return; + return 0; if (fops->check_media_change != NULL) { if (!fops->check_media_change(dev)) - return; + return 0; } #if 1 /* this will go soon.. */ else switch(MAJOR(dev)){ -#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI) - case SCSI_DISK_MAJOR: - if (!check_scsidisk_media_change(dev, 0)) - return; - break; -#endif - -#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI) - case SCSI_CDROM_MAJOR: - if (!check_cdrom_media_change(dev, 0)) - return; - break; -#endif - -#if defined(CONFIG_CDU31A) - case CDU31A_CDROM_MAJOR: - if (!check_cdu31a_media_change(dev, 0)) - return; - break; -#endif #if defined(CONFIG_MCD) case MITSUMI_CDROM_MAJOR: if (!check_mcd_media_change(dev, 0)) - return; + return 0; break; #endif #if defined(CONFIG_SBPCD) case MATSUSHITA_CDROM_MAJOR: if (!check_sbpcd_media_change(dev, 0)) - return; + return 0; break; #endif default: - return; + return 0; } #endif /* will go away */ @@ -206,13 +176,7 @@ if (fops->revalidate) fops->revalidate(dev); - -#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI) -/* This is trickier for a removable hardisk, because we have to invalidate - all of the partitions that lie on the disk. */ - if (MAJOR(dev) == SCSI_DISK_MAJOR) - revalidate_scsidisk(dev, 0); -#endif + return 1; } /* diff -u --recursive --new-file v1.1.24/linux/fs/isofs/inode.c linux/fs/isofs/inode.c --- v1.1.24/linux/fs/isofs/inode.c Tue Jun 21 14:16:23 1994 +++ linux/fs/isofs/inode.c Thu Jul 7 18:45:04 1994 @@ -305,35 +305,8 @@ printk("get root inode failed\n"); return NULL; } -#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI) - if (MAJOR(s->s_dev) == SCSI_CDROM_MAJOR) { - /* Check this one more time. */ - if(check_cdrom_media_change(s->s_dev, 0)) - goto out; - } -#endif -#if defined(CONFIG_CDU31A) - if (MAJOR(s->s_dev) == CDU31A_CDROM_MAJOR) { - /* Check this one more time. */ - if(check_cdu31a_media_change(s->s_dev, 0)) - goto out; - } -#endif -#if defined(CONFIG_MCD) - if (MAJOR(s->s_dev) == MITSUMI_CDROM_MAJOR) { - /* Check this one more time. */ - if(check_mcd_media_change(s->s_dev, 0)) - goto out; - } -#endif -#if defined(CONFIG_SBPCD) - if (MAJOR(s->s_dev) == MATSUSHITA_CDROM_MAJOR) { - if (check_sbpcd_media_change(s->s_dev,0)) - goto out; - }; -#endif CONFIG_SBPCD - return s; + if(!check_disk_change(s->s_dev)) return s; out: /* Kick out for various error conditions */ brelse(bh); s->s_dev = 0; diff -u --recursive --new-file v1.1.24/linux/fs/locks.c linux/fs/locks.c --- v1.1.24/linux/fs/locks.c Sat May 7 14:54:07 1994 +++ linux/fs/locks.c Thu Jul 7 15:08:56 1994 @@ -200,8 +200,6 @@ if (!filp->f_inode) /* just in case */ return 0; - if (!S_ISREG(filp->f_inode->i_mode)) - return 0; if (l->l_type != F_UNLCK && l->l_type != F_RDLCK && l->l_type != F_WRLCK && l->l_type != F_SHLCK && l->l_type != F_EXLCK) return 0; @@ -378,7 +376,7 @@ if (! added) { if (caller->fl_type == F_UNLCK) - return -EINVAL; + return 0; if (! (caller = alloc_lock(before, caller, fd))) return -ENOLCK; } diff -u --recursive --new-file v1.1.24/linux/fs/nfs/sock.c linux/fs/nfs/sock.c --- v1.1.24/linux/fs/nfs/sock.c Tue Mar 1 08:03:41 1994 +++ linux/fs/nfs/sock.c Thu Jul 7 18:28:55 1994 @@ -4,6 +4,13 @@ * Copyright (C) 1992, 1993 Rick Sladkey * * low-level nfs remote procedure call interface + * + * FIXES + * + * 2/7/94 James Bottomley and Jon Peatfield DAMTP, Cambridge University + * + * An xid mismatch no longer causes the request to be trashed. + * */ #include @@ -15,8 +22,14 @@ #include #include #include +#include +/* JEJB/JSP 2/7/94 + * this must match the value of NFS_SLACK_SPACE in linux/fs/nfs/proc.c + * ***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)) @@ -51,6 +64,9 @@ int n; int addrlen; unsigned long old_mask; + /* JEJB/JSP 2/7/94 + * This is for a 4 byte recv of the xid only */ + int recv_xid; xid = start[0]; len = ((char *) end) - ((char *) start); @@ -92,8 +108,14 @@ current->state = TASK_INTERRUPTIBLE; if (!select(inode, file, SEL_IN, &wait_table) && !select(inode, file, SEL_IN, NULL)) { - if (timeout > max_timeout) - timeout = max_timeout; + if (timeout > max_timeout) { + /* JEJB/JSP 2/7/94 + * This is useful to see if the system is + * hanging */ + printk("NFS max timeout reached on %s\n", + server_name); + timeout = max_timeout; + } current->timeout = jiffies + timeout; schedule(); remove_wait_queue(entry.wait_address, &entry.wait); @@ -116,8 +138,8 @@ timeout = init_timeout; init_timeout <<= 1; if (!major_timeout_seen) { - printk("NFS server %s not responding, " - "still trying\n", server_name); + printk("NFS server %s not responding, " + "still trying\n", server_name); } major_timeout_seen = 1; continue; @@ -129,8 +151,13 @@ remove_wait_queue(entry.wait_address, &entry.wait); current->state = TASK_RUNNING; addrlen = 0; - result = sock->ops->recvfrom(sock, (void *) start, PAGE_SIZE, 1, 0, - NULL, &addrlen); + /* JEJB/JSP 2/7/94 + * Get the xid from the next packet using a peek, so keep it + * on the recv queue. If it is wrong, it will be some reply + * we don't now need, so discard it */ + result = sock->ops->recvfrom(sock, (void *)&recv_xid, + sizeof(recv_xid), 1, MSG_PEEK, + NULL, &addrlen); if (result < 0) { if (result == -EAGAIN) { #if 0 @@ -150,15 +177,41 @@ } break; } - if (*start == xid) { + if (recv_xid == xid) { if (major_timeout_seen) printk("NFS server %s OK\n", server_name); break; } + /* JEJB/JSP 2/7/94 + * we have xid mismatch, so discard the packet and start + * again. What a hack! but I can't call recvfrom with + * a null buffer yet. */ + (void)sock->ops->recvfrom(sock, (void *)&recv_xid, + sizeof(recv_xid), 1, 0, NULL, + &addrlen); #if 0 printk("nfs_rpc_call: XID mismatch\n"); #endif } + /* JEJB/JSP 2/7/94 + * + * we have the correct xid, so read into the correct place and + * return it + * + * Here we need to know the size given to alloc, server->wsize for + * writes or server->rsize for reads. In practice these are the + * same. + * + * If they are not the same then a reply to a write request will be + * a small acknowledgement, so even if wsize < rsize we should never + * cause data to be written past the end of the buffer (unless some + * brain damaged implementation sends out a large write acknowledge). + * + * FIXME: I should really know how big a packet was alloc'd -- + * should pass it to do_nfs_rpc. */ + result=sock->ops->recvfrom(sock, (void *)start, + server->rsize + NFS_SLACK_SPACE, 1, 0, NULL, + &addrlen); current->blocked = old_mask; set_fs(fs); return result; diff -u --recursive --new-file v1.1.24/linux/fs/open.c linux/fs/open.c --- v1.1.24/linux/fs/open.c Tue May 24 00:34:53 1994 +++ linux/fs/open.c Thu Jul 7 15:08:57 1994 @@ -448,7 +448,7 @@ return 0; } inode = filp->f_inode; - if (inode && S_ISREG(inode->i_mode)) + if (inode) fcntl_remove_locks(current, filp, fd); if (filp->f_count > 1) { filp->f_count--; diff -u --recursive --new-file v1.1.24/linux/include/linux/fs.h linux/include/linux/fs.h --- v1.1.24/linux/include/linux/fs.h Thu Jul 7 21:37:13 1994 +++ linux/include/linux/fs.h Thu Jul 7 18:45:04 1994 @@ -413,7 +413,7 @@ } -extern void check_disk_change(dev_t dev); +extern int check_disk_change(dev_t dev); extern void invalidate_inodes(dev_t dev); extern void invalidate_buffers(dev_t dev); extern void sync_inodes(dev_t dev); diff -u --recursive --new-file v1.1.24/linux/include/linux/mcd.h linux/include/linux/mcd.h --- v1.1.24/linux/include/linux/mcd.h Thu Jul 7 21:37:13 1994 +++ linux/include/linux/mcd.h Thu Jul 7 21:26:55 1994 @@ -28,7 +28,7 @@ #define MCD_INTR_NR 10 /* Increase this if you get lots of timeouts */ -#define MCD_STATUS_DELAY 100 +#define MCD_STATUS_DELAY 200 /* number of times to retry a command before giving up */ #define MCD_RETRY_ATTEMPTS 5 diff -u --recursive --new-file v1.1.24/linux/include/linux/mtio.h linux/include/linux/mtio.h --- v1.1.24/linux/include/linux/mtio.h Wed Jun 22 14:57:10 1994 +++ linux/include/linux/mtio.h Thu Jul 7 18:45:05 1994 @@ -203,6 +203,7 @@ #define MT_ST_ASYNC_WRITES 0x2 #define MT_ST_READ_AHEAD 0x4 #define MT_ST_DEBUGGING 0x8 +#define MT_ST_TWO_FM 0x10 #endif /* _LINUX_MTIO_H */ diff -u --recursive --new-file v1.1.24/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v1.1.24/linux/kernel/ksyms.c Tue Jun 28 22:30:28 1994 +++ linux/kernel/ksyms.c Thu Jul 7 19:32:15 1994 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include #include @@ -122,6 +123,8 @@ X(disable_irq), X(bh_active), X(bh_mask), + X(add_timer), + X(del_timer), /* dma handling */ X(request_dma), @@ -136,6 +139,7 @@ X(xtime), /* misc */ + X(panic), X(printk), X(sprintf), X(vsprintf), diff -u --recursive --new-file v1.1.24/linux/net/inet/af_inet.c linux/net/inet/af_inet.c --- v1.1.24/linux/net/inet/af_inet.c Mon Jun 27 16:47:02 1994 +++ linux/net/inet/af_inet.c Thu Jul 7 18:29:06 1994 @@ -12,6 +12,10 @@ * Florian La Roche, * Alan Cox, * + * Changes (see also sock.c) + * + * A.N.Kuznetsov : Socket death error in accept(). + * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version @@ -975,6 +979,7 @@ { err = -sk2->err; sk2->err=0; + sk2->dead=1; /* ANK */ destroy_sock(sk2); newsock->data = NULL; return(err); diff -u --recursive --new-file v1.1.24/linux/net/inet/icmp.c linux/net/inet/icmp.c --- v1.1.24/linux/net/inet/icmp.c Mon Jun 27 16:47:02 1994 +++ linux/net/inet/icmp.c Thu Jul 7 18:31:00 1994 @@ -370,7 +370,7 @@ skb2->free = 1; /* Build Layer 2-3 headers for message back to source */ - offset = ip_build_header(skb2, daddr, saddr, &ndev, + offset = ip_build_header(skb2, daddr, dev->pa_addr, &ndev, IPPROTO_ICMP, opt, len, skb->ip_hdr->tos,255); if (offset < 0) { @@ -586,12 +586,6 @@ icmp_statistics.IcmpInMsgs++; - if (ip_chk_addr(daddr) == IS_BROADCAST) - { - icmp_statistics.IcmpInErrors++; - kfree_skb(skb1, FREE_READ); - return(0); - } /* * Grab the packet as an icmp object @@ -616,6 +610,13 @@ /* * Parse the ICMP message */ + + if (ip_chk_addr(daddr) == IS_BROADCAST && icmph->type != ICMP_ECHO) + { + icmp_statistics.IcmpInErrors++; + kfree_skb(skb1, FREE_READ); + return(0); + } switch(icmph->type) {