diff -u --recursive --new-file v2.1.45/linux/Makefile linux/Makefile --- v2.1.45/linux/Makefile Thu Jul 17 10:06:03 1997 +++ linux/Makefile Fri Jul 18 17:00:24 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 45 +SUBLEVEL = 46 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.45/linux/drivers/scsi/README.in2000 linux/drivers/scsi/README.in2000 --- v2.1.45/linux/drivers/scsi/README.in2000 Mon Oct 14 23:39:48 1996 +++ linux/drivers/scsi/README.in2000 Thu Jul 17 20:24:38 1997 @@ -1,4 +1,16 @@ +UPDATE NEWS: version 1.31 - 6 Jul 97 + + Fixed a bug that caused incorrect SCSI status bytes to be + returned from commands sent to LUN's greater than 0. This + means that CDROM changers work now! Fixed a bug in the + handling of command-line arguments when loaded as a module. + Also put all the header data in in2000.h where it belongs. + There are no longer any differences between this driver in + the 2.1.xx source tree and the 2.0.xx tree, as of 2.0.31 + and 2.1.45 (or is it .46?) - this makes things much easier + for me... + UPDATE NEWS: version 1.30 - 14 Oct 96 Fixed a bug in the code that sets the transfer direction @@ -105,15 +117,10 @@ There's also a define called 'DEFAULT_SX_PER'; this sets the data transfer speed for the asynchronous mode. I've put it at 500 ns despite the fact that the card could handle settings of 376 or -252, because I'm not really sure if certain devices or maybe bad -cables might have trouble at higher speeds. I couldn't find any -info in my various SCSI references that talk about this in language -I could understand, so decided to compromise with 500. This is still -faster than the old driver was set at (I think). Can someone explain -the significance of the bus transfer speed setting? Do devices on -the bus ever care what it is? Is cable quality a factor here? -Regardless, you can choose your own default through the command- -line with the 'period' keyword. +252, because higher speeds may be a problem with poor quality +cables or improper termination; 500 ns is a compromise. You can +choose your own default through the command-line with the +'period' keyword. ------------------------------------------------ diff -u --recursive --new-file v2.1.45/linux/drivers/scsi/in2000.c linux/drivers/scsi/in2000.c --- v2.1.45/linux/drivers/scsi/in2000.c Fri Apr 4 08:52:23 1997 +++ linux/drivers/scsi/in2000.c Thu Jul 17 20:24:38 1997 @@ -104,7 +104,7 @@ * */ - +#include #include #include @@ -115,46 +115,44 @@ #include #include +#include +#include + #include "scsi.h" #include "sd.h" #include "hosts.h" -#include "in2000.h" -#include -#include - -#ifdef MODULE -#include -#endif -#define uchar unsigned char +#define IN2000_VERSION "1.31" +#define IN2000_DATE "06/July/1997" -#define IN2000_VERSION "1.30" -#define IN2000_DATE "14/Oct/1996" +/* + * Note - the following defines have been moved to 'in2000.h': + * + * PROC_INTERFACE + * PROC_STATISTICS + * SYNC_DEBUG + * DEBUGGING_ON + * DEBUG_DEFAULTS + * FAST_READ_IO + * FAST_WRITE_IO + * + */ -#define PROC_INTERFACE /* add code for /proc/scsi/in2000/xxx interface */ -#define SYNC_DEBUG /* extra info on sync negotiation printed */ -#define DEBUGGING_ON /* enable command-line debugging bitmask */ -#define DEBUG_DEFAULTS 0 /* default bitmask - change from command-line */ -#define FAST_READ_IO /* No problems with these on my machine */ -#define FAST_WRITE_IO +#include "in2000.h" -#ifdef DEBUGGING_ON -#define DB(f,a) if (hostdata->args & (f)) a; -#define CHECK_NULL(p,s) /* if (!(p)) {printk("\n"); while (1) printk("NP:%s\r",(s));} */ -#else -#define DB(f,a) -#define CHECK_NULL(p,s) -#endif /* - * setup_strings is an array of strings that define some of the operating - * parameters and settings for this driver. It is used unless a LILO - * or insmod command line has been specified, in which case those settings - * are combined with the ones here. The driver recognizes the following - * keywords (lower case required) and arguments: + * 'setup_strings' is a single string used to pass operating parameters and + * settings from the kernel/module command-line to the driver. 'setup_args[]' + * is an array of strings that define the compile-time default values for + * these settings. If Linux boots with a LILO or insmod command-line, those + * settings are combined with 'setup_args[]'. Note that LILO command-lines + * are prefixed with "in2000=" while insmod uses a "setup_strings=" prefix. + * The driver recognizes the following keywords (lower case required) and + * arguments: * * - ioport:addr -Where addr is IO address of a (usually ROM-less) card. * - noreset -No optional args. Prevents SCSI bus reset at boot time. @@ -179,13 +177,11 @@ * _must_ be a colon between a keyword and its numeric argument, with no * spaces. * - Keywords are separated by commas, no spaces, in the standard kernel - * command-line manner, except in the case of 'setup_strings[]' (see - * below), which is simply a C array of pointers to char. Each element - * in the array is a string comprising one keyword & argument. + * command-line manner. * - A keyword in the 'nth' comma-separated command-line member will overwrite - * the 'nth' element of setup_strings[]. A blank command-line member (in + * the 'nth' element of setup_args[]. A blank command-line member (in * other words, a comma with no preceding keyword) will _not_ overwrite - * the corresponding setup_strings[] element. + * the corresponding setup_args[] element. * * A few LILO examples (for insmod, use 'setup_strings' instead of 'in2000'): * - in2000=ioport:0x220,noreset @@ -194,334 +190,20 @@ * - in2000=proc:3 */ -static char *setup_strings[] = - {"","","","","","","","","","","",""}; +/* Normally, no defaults are specified... */ +static char *setup_args[] = + {"","","","","","","","",""}; -static struct Scsi_Host *instance_list = 0; +/* filled in by 'insmod' */ +static char *setup_strings = 0; -#ifdef PROC_INTERFACE -static unsigned long disc_allowed_total; -static unsigned long disc_taken_total; +#ifdef MODULE_PARM +MODULE_PARM(setup_strings, "s"); #endif -/* IN2000 io_port offsets */ -#define IO_WD_ASR 0x00 /* R - 3393 auxstat reg */ -#define ASR_INT 0x80 -#define ASR_LCI 0x40 -#define ASR_BSY 0x20 -#define ASR_CIP 0x10 -#define ASR_PE 0x02 -#define ASR_DBR 0x01 -#define IO_WD_ADDR 0x00 /* W - 3393 address reg */ -#define IO_WD_DATA 0x01 /* R/W - rest of 3393 regs */ -#define IO_FIFO 0x02 /* R/W - in2000 dual-port fifo (16 bits) */ -#define IN2000_FIFO_SIZE 2048 /* fifo capacity in bytes */ -#define IO_CARD_RESET 0x03 /* W - in2000 start master reset */ -#define IO_FIFO_COUNT 0x04 /* R - in2000 fifo counter */ -#define IO_FIFO_WRITE 0x05 /* W - clear fifo counter, start write */ -#define IO_FIFO_READ 0x07 /* W - start fifo read */ -#define IO_LED_OFF 0x08 /* W - turn off in2000 activity LED */ -#define IO_SWITCHES 0x08 /* R - read in2000 dip switch */ -#define SW_ADDR0 0x01 /* bit 0 = bit 0 of index to io addr */ -#define SW_ADDR1 0x02 /* bit 1 = bit 1 of index io addr */ -#define SW_DISINT 0x04 /* bit 2 true if ints disabled */ -#define SW_INT0 0x08 /* bit 3 = bit 0 of index to interrupt */ -#define SW_INT1 0x10 /* bit 4 = bit 1 of index to interrupt */ -#define SW_INT_SHIFT 3 /* shift right this amount to right justify int bits */ -#define SW_SYNC_DOS5 0x20 /* bit 5 used by Always BIOS */ -#define SW_FLOPPY 0x40 /* bit 6 true if floppy enabled */ -#define SW_BIT7 0x80 /* bit 7 hardwired true (ground) */ -#define IO_LED_ON 0x09 /* W - turn on in2000 activity LED */ -#define IO_HARDWARE 0x0a /* R - read in2000 hardware rev, stop reset */ -#define IO_INTR_MASK 0x0c /* W - in2000 interrupt mask reg */ -#define IMASK_WD 0x01 /* WD33c93 interrupt mask */ -#define IMASK_FIFO 0x02 /* FIFO interrupt mask */ - -/* wd register names */ -#define WD_OWN_ID 0x00 -#define WD_CONTROL 0x01 -#define WD_TIMEOUT_PERIOD 0x02 -#define WD_CDB_1 0x03 -#define WD_CDB_2 0x04 -#define WD_CDB_3 0x05 -#define WD_CDB_4 0x06 -#define WD_CDB_5 0x07 -#define WD_CDB_6 0x08 -#define WD_CDB_7 0x09 -#define WD_CDB_8 0x0a -#define WD_CDB_9 0x0b -#define WD_CDB_10 0x0c -#define WD_CDB_11 0x0d -#define WD_CDB_12 0x0e -#define WD_TARGET_LUN 0x0f -#define WD_COMMAND_PHASE 0x10 -#define WD_SYNCHRONOUS_TRANSFER 0x11 -#define WD_TRANSFER_COUNT_MSB 0x12 -#define WD_TRANSFER_COUNT 0x13 -#define WD_TRANSFER_COUNT_LSB 0x14 -#define WD_DESTINATION_ID 0x15 -#define WD_SOURCE_ID 0x16 -#define WD_SCSI_STATUS 0x17 -#define WD_COMMAND 0x18 -#define WD_DATA 0x19 -#define WD_QUEUE_TAG 0x1a -#define WD_AUXILIARY_STATUS 0x1f - -/* WD commands */ -#define WD_CMD_RESET 0x00 -#define WD_CMD_ABORT 0x01 -#define WD_CMD_ASSERT_ATN 0x02 -#define WD_CMD_NEGATE_ACK 0x03 -#define WD_CMD_DISCONNECT 0x04 -#define WD_CMD_RESELECT 0x05 -#define WD_CMD_SEL_ATN 0x06 -#define WD_CMD_SEL 0x07 -#define WD_CMD_SEL_ATN_XFER 0x08 -#define WD_CMD_SEL_XFER 0x09 -#define WD_CMD_RESEL_RECEIVE 0x0a -#define WD_CMD_RESEL_SEND 0x0b -#define WD_CMD_WAIT_SEL_RECEIVE 0x0c -#define WD_CMD_TRANS_ADDR 0x18 -#define WD_CMD_TRANS_INFO 0x20 -#define WD_CMD_TRANSFER_PAD 0x21 -#define WD_CMD_SBT_MODE 0x80 - -/* SCSI Bus Phases */ -#define PHS_DATA_OUT 0x00 -#define PHS_DATA_IN 0x01 -#define PHS_COMMAND 0x02 -#define PHS_STATUS 0x03 -#define PHS_MESS_OUT 0x06 -#define PHS_MESS_IN 0x07 - -/* Command Status Register definitions */ - - /* reset state interrupts */ -#define CSR_RESET 0x00 -#define CSR_RESET_AF 0x01 - - /* successful completion interrupts */ -#define CSR_RESELECT 0x10 -#define CSR_SELECT 0x11 -#define CSR_SEL_XFER_DONE 0x16 -#define CSR_XFER_DONE 0x18 - - /* paused or aborted interrupts */ -#define CSR_MSGIN 0x20 -#define CSR_SDP 0x21 -#define CSR_SEL_ABORT 0x22 -#define CSR_RESEL_ABORT 0x25 -#define CSR_RESEL_ABORT_AM 0x27 -#define CSR_ABORT 0x28 - - /* terminated interrupts */ -#define CSR_INVALID 0x40 -#define CSR_UNEXP_DISC 0x41 -#define CSR_TIMEOUT 0x42 -#define CSR_PARITY 0x43 -#define CSR_PARITY_ATN 0x44 -#define CSR_BAD_STATUS 0x45 -#define CSR_UNEXP 0x48 - - /* service required interrupts */ -#define CSR_RESEL 0x80 -#define CSR_RESEL_AM 0x81 -#define CSR_DISC 0x85 -#define CSR_SRV_REQ 0x88 - - /* Own ID/CDB Size register */ -#define OWNID_EAF 0x08 -#define OWNID_EHP 0x10 -#define OWNID_RAF 0x20 -#define OWNID_FS_8 0x00 -#define OWNID_FS_12 0x40 -#define OWNID_FS_16 0x80 - - /* Control register */ -#define CTRL_HSP 0x01 -#define CTRL_HA 0x02 -#define CTRL_IDI 0x04 -#define CTRL_EDI 0x08 -#define CTRL_HHP 0x10 -#define CTRL_POLLED 0x00 -#define CTRL_BURST 0x20 -#define CTRL_BUS 0x40 -#define CTRL_DMA 0x80 - - /* Timeout Period register */ -#define TIMEOUT_PERIOD_VALUE 20 /* results in 200 ms. */ - - /* Synchronous Transfer Register */ -#define STR_FSS 0x80 - - /* Destination ID register */ -#define DSTID_DPD 0x40 -#define DATA_OUT_DIR 0 -#define DATA_IN_DIR 1 -#define DSTID_SCC 0x80 - - /* Source ID register */ -#define SRCID_MASK 0x07 -#define SRCID_SIV 0x08 -#define SRCID_DSP 0x20 -#define SRCID_ES 0x40 -#define SRCID_ER 0x80 - - - -#define DEFAULT_SX_PER 500 /* (ns) fairly safe */ -#define DEFAULT_SX_OFF 0 /* aka async */ - -#define OPTIMUM_SX_PER 252 /* (ns) best we can do (mult-of-4) */ -#define OPTIMUM_SX_OFF 12 /* size of in2000 fifo */ - - -/* defines for hostdata->chip */ - -#define C_WD33C93 0 -#define C_WD33C93A 1 -#define C_WD33C93B 2 -#define C_UNKNOWN_CHIP 100 - -/* defines for hostdata->state */ - -#define S_UNCONNECTED 0 -#define S_SELECTING 1 -#define S_RUNNING_LEVEL2 2 -#define S_CONNECTED 3 -#define S_PRE_TMP_DISC 4 -#define S_PRE_CMP_DISC 5 - -/* defines for hostdata->fifo */ - -#define FI_FIFO_UNUSED 0 -#define FI_FIFO_READING 1 -#define FI_FIFO_WRITING 2 - -/* defines for hostdata->level2 */ -/* NOTE: only the first 3 are trustworthy at this point - - * having trouble when more than 1 device is reading/writing - * at the same time... - */ - -#define L2_NONE 0 /* no combination commands - we get lots of ints */ -#define L2_SELECT 1 /* start with SEL_ATN_XFER, but never resume it */ -#define L2_BASIC 2 /* resume after STATUS ints & RDP messages */ -#define L2_DATA 3 /* resume after DATA_IN/OUT ints */ -#define L2_MOST 4 /* resume after anything except a RESELECT int */ -#define L2_RESELECT 5 /* resume after everything, including RESELECT ints */ -#define L2_ALL 6 /* always resume */ - -/* defines for hostdata->disconnect */ - -#define DIS_NEVER 0 -#define DIS_ADAPTIVE 1 -#define DIS_ALWAYS 2 - -/* defines for hostdata->args */ - -#define DB_TEST 1<<0 -#define DB_FIFO 1<<1 -#define DB_QUEUE_COMMAND 1<<2 -#define DB_EXECUTE 1<<3 -#define DB_INTR 1<<4 -#define DB_TRANSFER 1<<5 -#define DB_MASK 0x3f - -#define A_NO_SCSI_RESET 1<<15 - - -/* defines for hostdata->sync_xfer[] */ - -#define SS_UNSET 0 -#define SS_FIRST 1 -#define SS_WAITING 2 -#define SS_SET 3 - -/* defines for hostdata->proc */ - -#define PR_VERSION 1<<0 -#define PR_INFO 1<<1 -#define PR_TOTALS 1<<2 -#define PR_CONNECTED 1<<3 -#define PR_INPUTQ 1<<4 -#define PR_DISCQ 1<<5 -#define PR_TEST 1<<6 -#define PR_STOP 1<<7 - - -#define read1_io(a) (inb(hostdata->io_base+(a))) -#define read2_io(a) (inw(hostdata->io_base+(a))) -#define write1_io(b,a) (outb((b),hostdata->io_base+(a))) -#define write2_io(w,a) (outw((w),hostdata->io_base+(a))) - - -struct sx_period { - unsigned int period_ns; - uchar reg_value; - }; +static struct Scsi_Host *instance_list = 0; -struct IN2000_hostdata { - struct Scsi_Host *next; - uchar chip; /* what kind of wd33c93 chip? */ - uchar microcode; /* microcode rev if 'B' */ - unsigned short io_base; /* IO port base */ - unsigned int dip_switch; /* dip switch settings */ - unsigned int hrev; /* hardware revision of card */ - volatile uchar busy[8]; /* index = target, bit = lun */ - volatile Scsi_Cmnd *input_Q; /* commands waiting to be started */ - volatile Scsi_Cmnd *selecting; /* trying to select this command */ - volatile Scsi_Cmnd *connected; /* currently connected command */ - volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */ - uchar state; /* what we are currently doing */ - uchar fifo; /* what the FIFO is up to */ - uchar level2; /* extent to which Level-2 commands are used */ - uchar disconnect; /* disconnect/reselect policy */ - unsigned int args; /* set from command-line argument */ - uchar incoming_msg[8]; /* filled during message_in phase */ - int incoming_ptr; /* mainly used with EXTENDED messages */ - uchar outgoing_msg[8]; /* send this during next message_out */ - int outgoing_len; /* length of outgoing message */ - unsigned int default_sx_per; /* default transfer period for SCSI bus */ - uchar sync_xfer[8]; /* sync_xfer reg settings per target */ - uchar sync_stat[8]; /* status of sync negotiation per target */ - uchar sync_off; /* bit mask: don't use sync with these targets */ - uchar proc; /* bit mask: what's in proc output */ - }; - -/* These inline assembly defines are derived from a patch - * sent to me by Bill Earnest. He's done a lot of very - * valuable thinking, testing, and coding during his effort - * to squeeze more speed out of this driver. I really think - * that we are doing IO at close to the maximum now with - * the fifo. (And yes, insw uses 'edi' while outsw uses - * 'esi'. Thanks Bill!) - */ - -#define FAST_READ2_IO() \ - __asm__ __volatile__ ("\n \ - cld \n \ - orl %%ecx, %%ecx \n \ - jz 1f \n \ - rep \n \ - insw %%dx \n \ -1: " \ - : "=D" (sp) /* output */ \ - : "d" (f), "D" (sp), "c" (i) /* input */ \ - : "edx", "ecx", "edi" ) /* trashed */ - -#define FAST_WRITE2_IO() \ - __asm__ __volatile__ ("\n \ - cld \n \ - orl %%ecx, %%ecx \n \ - jz 1f \n \ - rep \n \ - outsw %%dx \n \ -1: " \ - : "=S" (sp) /* output */ \ - : "d" (f), "S" (sp), "c" (i) /* input */ \ - : "edx", "ecx", "esi" ) /* trashed */ static inline uchar read_3393(struct IN2000_hostdata *hostdata, uchar reg_num) @@ -596,10 +278,10 @@ switch (cmd->cmnd[0]) { case WRITE_6: case WRITE_10: case WRITE_12: case WRITE_LONG: case WRITE_SAME: case WRITE_BUFFER: - case WRITE_VERIFY: case WRITE_VERIFY_12: + case WRITE_VERIFY: case WRITE_VERIFY_12: case COMPARE: case COPY: case COPY_VERIFY: case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: - case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: + case SEARCH_EQUAL_12: case SEARCH_HIGH_12: case SEARCH_LOW_12: case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: case MODE_SELECT: case MODE_SELECT_10: case LOG_SELECT: case SEND_DIAGNOSTIC: case CHANGE_DEFINITION: case UPDATE_BLOCK: @@ -624,7 +306,7 @@ {1000,0x00}, {0, 0} }; -int round_period(unsigned int period) +static int round_period(unsigned int period) { int x; @@ -657,7 +339,6 @@ Scsi_Cmnd *tmp; unsigned long flags; - hostdata = (struct IN2000_hostdata *)cmd->host->hostdata; DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld(",cmd->target,cmd->cmnd[0],cmd->pid)) @@ -675,7 +356,7 @@ /* We use the Scsi_Pointer structure that's included with each command * as a scratchpad (as it's intended to be used!). The handy thing about * the SCp.xxx fields is that they're always associated with a given - * cmd, and are preserved across disconnect-reconnect. This means we + * cmd, and are preserved across disconnect-reselect. This means we * can pretty much ignore SAVE_POINTERS and RESTORE_POINTERS messages * if we keep all the critical pointers and counters in SCp: * - SCp.ptr is the pointer into the RAM buffer @@ -703,9 +384,24 @@ /* We don't set SCp.phase here - that's done in in2000_execute() */ -/* Preset the command status to GOOD, since that's the normal case */ +/* WD docs state that at the conclusion of a "LEVEL2" command, the + * status byte can be retrieved from the LUN register. Apparently, + * this is the case only for *uninterrupted* LEVEL2 commands! If + * there are any unexpected phases entered, even if they are 100% + * legal (different devices may choose to do things differently), + * the LEVEL2 command sequence is exited. This often occurs prior + * to receiving the status byte, in which case the driver does a + * status phase interrupt and gets the status byte on its own. + * While such a command can then be "resumed" (ie restarted to + * finish up as a LEVEL2 command), the LUN register will NOT be + * a valid status byte at the command's conclusion, and we must + * use the byte obtained during the earlier interrupt. Here, we + * preset SCp.Status to an illegal value (0xff) so that when + * this command finally completes, we can tell where the actual + * status byte is stored. + */ - cmd->SCp.Status = GOOD; + cmd->SCp.Status = ILLEGAL_STATUS_BYTE; save_flags(flags); cli(); @@ -803,6 +499,10 @@ else hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble; +#ifdef PROC_STATISTICS + hostdata->cmd_cnt[cmd->target]++; +#endif + /* * Start the selection process */ @@ -860,8 +560,8 @@ yes: cmd->SCp.phase = 1; -#ifdef PROC_INTERFACE - disc_allowed_total++; +#ifdef PROC_STATISTICS + hostdata->disc_allowed_cnt[cmd->target]++; #endif no: @@ -1094,7 +794,8 @@ if (data_in_dir) { write1_io(0,IO_FIFO_READ); - if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) { + if ((hostdata->level2 >= L2_DATA) || + (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) { write_3393(hostdata,WD_COMMAND_PHASE,0x45); write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER); hostdata->state = S_RUNNING_LEVEL2; @@ -1111,7 +812,8 @@ * write any bytes that don't make it at this stage. */ - if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) { + if ((hostdata->level2 >= L2_DATA) || + (hostdata->level2 == L2_BASIC && cmd->SCp.phase == 0)) { write_3393(hostdata,WD_COMMAND_PHASE,0x45); write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER); hostdata->state = S_RUNNING_LEVEL2; @@ -1177,6 +879,10 @@ save_flags(flags); sti(); +#ifdef PROC_STATISTICS + hostdata->int_cnt++; +#endif + /* The IN2000 card has 2 interrupt sources OR'ed onto its IRQ line - the * WD3393 chip and the 2k fifo (which is actually a dual-port RAM combined * with a big logic array, so it's a little different than what you might @@ -1484,9 +1190,10 @@ case CSR_XFER_DONE|PHS_STATUS: case CSR_UNEXP |PHS_STATUS: case CSR_SRV_REQ |PHS_STATUS: -DB(DB_INTR,printk("STATUS")) +DB(DB_INTR,printk("STATUS=")) cmd->SCp.Status = read_1_byte(hostdata); +DB(DB_INTR,printk("%02x",cmd->SCp.Status)) if (hostdata->level2 >= L2_BASIC) { sr = read_3393(hostdata,WD_SCSI_STATUS); /* clear interrupt */ hostdata->state = S_RUNNING_LEVEL2; @@ -1494,7 +1201,6 @@ write_3393_cmd(hostdata,WD_CMD_SEL_ATN_XFER); } else { -DB(DB_INTR,printk("=%02x",cmd->SCp.Status)) hostdata->state = S_CONNECTED; } break; @@ -1665,15 +1371,16 @@ DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid)) cmd->SCp.Message = COMMAND_COMPLETE; lun = read_3393(hostdata,WD_TARGET_LUN); - if (cmd->SCp.Status == GOOD) - cmd->SCp.Status = lun; +DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun)) hostdata->connected = NULL; - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (cmd->SCp.Status != GOOD) - cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->state = S_UNCONNECTED; + if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE) + cmd->SCp.Status = lun; + if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + else + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); cmd->scsi_done(cmd); /* We are no longer connected to a target - check to see if @@ -1755,10 +1462,10 @@ hostdata->connected = NULL; hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->state = S_UNCONNECTED; - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (cmd->SCp.Status != GOOD) + if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + else + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); cmd->scsi_done(cmd); /* We are no longer connected to a target - check to see if @@ -1788,10 +1495,11 @@ hostdata->connected = NULL; hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->state = S_UNCONNECTED; - if (cmd->cmnd[0] != REQUEST_SENSE) - cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); - else if (cmd->SCp.Status != GOOD) +DB(DB_INTR,printk(":%d",cmd->SCp.Status)) + if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + else + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); cmd->scsi_done(cmd); break; case S_PRE_TMP_DISC: @@ -1801,8 +1509,8 @@ hostdata->connected = NULL; hostdata->state = S_UNCONNECTED; -#ifdef PROC_INTERFACE - disc_taken_total++; +#ifdef PROC_STATISTICS + hostdata->disc_done_cnt[cmd->target]++; #endif break; @@ -2158,10 +1866,11 @@ #define MAX_IN2000_HOSTS 3 -#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *)) +#define MAX_SETUP_ARGS (sizeof(setup_args) / sizeof(char *)) #define SETUP_BUFFER_SIZE 200 static char setup_buffer[SETUP_BUFFER_SIZE]; -static char setup_used[MAX_SETUP_STRINGS]; +static char setup_used[MAX_SETUP_ARGS]; +static int done_setup = 0; void in2000_setup (char *str, int *ints) { @@ -2172,43 +1881,44 @@ setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0'; p1 = setup_buffer; i = 0; - while (*p1 && (i < MAX_SETUP_STRINGS)) { + while (*p1 && (i < MAX_SETUP_ARGS)) { p2 = strchr(p1, ','); if (p2) { *p2 = '\0'; if (p1 != p2) - setup_strings[i] = p1; + setup_args[i] = p1; p1 = p2 + 1; i++; } else { - setup_strings[i] = p1; + setup_args[i] = p1; break; } } - for (i=0; ibusy[x] = 0; hostdata->sync_xfer[x] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF); hostdata->sync_stat[x] = SS_UNSET; /* using default sync values */ +#ifdef PROC_STATISTICS + hostdata->cmd_cnt[x] = 0; + hostdata->disc_allowed_cnt[x] = 0; + hostdata->disc_done_cnt[x] = 0; +#endif } hostdata->input_Q = NULL; hostdata->selecting = NULL; @@ -2395,36 +2109,42 @@ else hostdata->sync_off = 0xff; /* sync defaults to off */ - hostdata->proc = PR_VERSION|PR_INFO|PR_TOTALS| +#ifdef PROC_INTERFACE + hostdata->proc = PR_VERSION|PR_INFO|PR_STATISTICS| PR_CONNECTED|PR_INPUTQ|PR_DISCQ| PR_STOP; - -#ifdef PROC_INTERFACE - disc_allowed_total = 0; - disc_taken_total = 0; +#ifdef PROC_STATISTICS + hostdata->int_cnt = 0; +#endif #endif - if (check_setup_strings("nosync",&flags,&val,buf)) + if (check_setup_args("nosync",&flags,&val,buf)) hostdata->sync_off = val; - if (check_setup_strings("period",&flags,&val,buf)) + if (check_setup_args("period",&flags,&val,buf)) hostdata->default_sx_per = sx_table[round_period((unsigned int)val)].period_ns; - if (check_setup_strings("disconnect",&flags,&val,buf)) { + if (check_setup_args("disconnect",&flags,&val,buf)) { if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS)) hostdata->disconnect = val; else hostdata->disconnect = DIS_ADAPTIVE; } - if (check_setup_strings("noreset",&flags,&val,buf)) + if (check_setup_args("noreset",&flags,&val,buf)) hostdata->args ^= A_NO_SCSI_RESET; - if (check_setup_strings("debug",&flags,&val,buf)) + if (check_setup_args("level2",&flags,&val,buf)) + hostdata->level2 = val; + + if (check_setup_args("debug",&flags,&val,buf)) hostdata->args = (val & DB_MASK); - if (check_setup_strings("proc",&flags,&val,buf)) +#ifdef PROC_INTERFACE + if (check_setup_args("proc",&flags,&val,buf)) hostdata->proc = val; +#endif + x = reset_hardware(instance,(hostdata->args & A_NO_SCSI_RESET)?RESET_CARD:RESET_CARD_AND_BUS); @@ -2450,9 +2170,9 @@ (hostdata->chip==C_WD33C93B)?"WD33c93B":"unknown", hostdata->microcode); #ifdef DEBUGGING_ON - printk("setup_strings = "); - for (x=0; x<8; x++) - printk("%s,",setup_strings[x]); + printk("setup_args = "); + for (x=0; xsync_off == 0xff) @@ -2496,23 +2216,18 @@ iinfo[0] = 255; iinfo[1] = 63; iinfo[2] = disk->capacity / (iinfo[0] * iinfo[1]); - -/* This next little bit of code was intended to prevent the number of - * tracks from exceeding 1023. As Andries Brouwer (aeb@cwi.nl) pointed - * out in his "Large Disk HOWTO" (June 1996), this kind of DOS - * compatibility is pointless. And wasteful on disks larger than 8 gigs. - */ - -#if 0 - if (iinfo[2] > 1023) - iinfo[2] = 1023; -#endif - } return 0; } + +struct proc_dir_entry proc_scsi_in2000 = { + PROC_SCSI_IN2000, 6, "in2000", + S_IFDIR | S_IRUGO | S_IXUGO, 2 + }; + + int in2000_proc_info(char *buf, char **start, off_t off, int len, int hn, int in) { @@ -2576,6 +2291,10 @@ bp += 5; hd->proc = simple_strtoul(bp,NULL,0); } + else if (!strncmp(bp,"level2:",7)) { + bp += 7; + hd->level2 = simple_strtoul(bp,NULL,0); + } return len; } @@ -2594,12 +2313,38 @@ (hd->dip_switch & 0x40)?"Yes":"No", (hd->dip_switch & 0x20)?"Yes":"No"); strcat(bp,tbuf); - } - if (hd->proc & PR_TOTALS) { - sprintf(tbuf,"\n%ld disc_allowed, %ld disc_taken", - disc_allowed_total,disc_taken_total); + strcat(bp,"\nsync_xfer[] = "); + for (x=0; x<7; x++) { + sprintf(tbuf,"\t%02x",hd->sync_xfer[x]); + strcat(bp,tbuf); + } + strcat(bp,"\nsync_stat[] = "); + for (x=0; x<7; x++) { + sprintf(tbuf,"\t%02x",hd->sync_stat[x]); + strcat(bp,tbuf); + } + } +#ifdef PROC_STATISTICS + if (hd->proc & PR_STATISTICS) { + strcat(bp,"\ncommands issued: "); + for (x=0; x<7; x++) { + sprintf(tbuf,"\t%ld",hd->cmd_cnt[x]); + strcat(bp,tbuf); + } + strcat(bp,"\ndisconnects allowed:"); + for (x=0; x<7; x++) { + sprintf(tbuf,"\t%ld",hd->disc_allowed_cnt[x]); + strcat(bp,tbuf); + } + strcat(bp,"\ndisconnects done: "); + for (x=0; x<7; x++) { + sprintf(tbuf,"\t%ld",hd->disc_done_cnt[x]); + strcat(bp,tbuf); + } + sprintf(tbuf,"\ninterrupts: \t%ld",hd->int_cnt); strcat(bp,tbuf); } +#endif if (hd->proc & PR_CONNECTED) { strcat(bp,"\nconnected: "); if (hd->connected) { diff -u --recursive --new-file v2.1.45/linux/drivers/scsi/in2000.h linux/drivers/scsi/in2000.h --- v2.1.45/linux/drivers/scsi/in2000.h Fri Apr 4 08:52:23 1997 +++ linux/drivers/scsi/in2000.h Sat Jul 19 12:50:44 1997 @@ -2,7 +2,7 @@ * in2000.h - Linux device driver definitions for the * Always IN2000 ISA SCSI card. * - * IMPORTANT: This file is for version 1.30 - 14/Oct/1996 + * IMPORTANT: This file is for version 1.31 - 06/Jul/1997 * * Copyright (c) 1996 John Shifflett, GeoLog Consulting * john@geolog.com @@ -23,13 +23,366 @@ #ifndef IN2000_H #define IN2000_H -extern struct proc_dir_entry proc_scsi_in2000; +#include + +#define PROC_INTERFACE /* add code for /proc/scsi/in2000/xxx interface */ +#ifdef PROC_INTERFACE +#define PROC_STATISTICS /* add code for keeping various real time stats */ +#endif + +#define SYNC_DEBUG /* extra info on sync negotiation printed */ +#define DEBUGGING_ON /* enable command-line debugging bitmask */ +#define DEBUG_DEFAULTS 0 /* default bitmask - change from command-line */ + +#define FAST_READ_IO /* No problems with these on my machine */ +#define FAST_WRITE_IO + +#ifdef DEBUGGING_ON +#define DB(f,a) if (hostdata->args & (f)) a; +#define CHECK_NULL(p,s) /* if (!(p)) {printk("\n"); while (1) printk("NP:%s\r",(s));} */ +#else +#define DB(f,a) +#define CHECK_NULL(p,s) +#endif + +#define uchar unsigned char + +#define read1_io(a) (inb(hostdata->io_base+(a))) +#define read2_io(a) (inw(hostdata->io_base+(a))) +#define write1_io(b,a) (outb((b),hostdata->io_base+(a))) +#define write2_io(w,a) (outw((w),hostdata->io_base+(a))) + +/* These inline assembly defines are derived from a patch + * sent to me by Bill Earnest. He's done a lot of very + * valuable thinking, testing, and coding during his effort + * to squeeze more speed out of this driver. I really think + * that we are doing IO at close to the maximum now with + * the fifo. (And yes, insw uses 'edi' while outsw uses + * 'esi'. Thanks Bill!) + */ + +#define FAST_READ2_IO() \ + __asm__ __volatile__ ("\n \ + cld \n \ + orl %%ecx, %%ecx \n \ + jz 1f \n \ + rep \n \ + insw %%dx \n \ +1: " \ + : "=D" (sp) /* output */ \ + : "d" (f), "D" (sp), "c" (i) /* input */ \ + : "edx", "ecx", "edi" ) /* trashed */ + +#define FAST_WRITE2_IO() \ + __asm__ __volatile__ ("\n \ + cld \n \ + orl %%ecx, %%ecx \n \ + jz 1f \n \ + rep \n \ + outsw %%dx \n \ +1: " \ + : "=S" (sp) /* output */ \ + : "d" (f), "S" (sp), "c" (i) /* input */ \ + : "edx", "ecx", "esi" ) /* trashed */ + + +/* IN2000 io_port offsets */ +#define IO_WD_ASR 0x00 /* R - 3393 auxstat reg */ +#define ASR_INT 0x80 +#define ASR_LCI 0x40 +#define ASR_BSY 0x20 +#define ASR_CIP 0x10 +#define ASR_PE 0x02 +#define ASR_DBR 0x01 +#define IO_WD_ADDR 0x00 /* W - 3393 address reg */ +#define IO_WD_DATA 0x01 /* R/W - rest of 3393 regs */ +#define IO_FIFO 0x02 /* R/W - in2000 dual-port fifo (16 bits) */ +#define IN2000_FIFO_SIZE 2048 /* fifo capacity in bytes */ +#define IO_CARD_RESET 0x03 /* W - in2000 start master reset */ +#define IO_FIFO_COUNT 0x04 /* R - in2000 fifo counter */ +#define IO_FIFO_WRITE 0x05 /* W - clear fifo counter, start write */ +#define IO_FIFO_READ 0x07 /* W - start fifo read */ +#define IO_LED_OFF 0x08 /* W - turn off in2000 activity LED */ +#define IO_SWITCHES 0x08 /* R - read in2000 dip switch */ +#define SW_ADDR0 0x01 /* bit 0 = bit 0 of index to io addr */ +#define SW_ADDR1 0x02 /* bit 1 = bit 1 of index io addr */ +#define SW_DISINT 0x04 /* bit 2 true if ints disabled */ +#define SW_INT0 0x08 /* bit 3 = bit 0 of index to interrupt */ +#define SW_INT1 0x10 /* bit 4 = bit 1 of index to interrupt */ +#define SW_INT_SHIFT 3 /* shift right this amount to right justify int bits */ +#define SW_SYNC_DOS5 0x20 /* bit 5 used by Always BIOS */ +#define SW_FLOPPY 0x40 /* bit 6 true if floppy enabled */ +#define SW_BIT7 0x80 /* bit 7 hardwired true (ground) */ +#define IO_LED_ON 0x09 /* W - turn on in2000 activity LED */ +#define IO_HARDWARE 0x0a /* R - read in2000 hardware rev, stop reset */ +#define IO_INTR_MASK 0x0c /* W - in2000 interrupt mask reg */ +#define IMASK_WD 0x01 /* WD33c93 interrupt mask */ +#define IMASK_FIFO 0x02 /* FIFO interrupt mask */ + +/* wd register names */ +#define WD_OWN_ID 0x00 +#define WD_CONTROL 0x01 +#define WD_TIMEOUT_PERIOD 0x02 +#define WD_CDB_1 0x03 +#define WD_CDB_2 0x04 +#define WD_CDB_3 0x05 +#define WD_CDB_4 0x06 +#define WD_CDB_5 0x07 +#define WD_CDB_6 0x08 +#define WD_CDB_7 0x09 +#define WD_CDB_8 0x0a +#define WD_CDB_9 0x0b +#define WD_CDB_10 0x0c +#define WD_CDB_11 0x0d +#define WD_CDB_12 0x0e +#define WD_TARGET_LUN 0x0f +#define WD_COMMAND_PHASE 0x10 +#define WD_SYNCHRONOUS_TRANSFER 0x11 +#define WD_TRANSFER_COUNT_MSB 0x12 +#define WD_TRANSFER_COUNT 0x13 +#define WD_TRANSFER_COUNT_LSB 0x14 +#define WD_DESTINATION_ID 0x15 +#define WD_SOURCE_ID 0x16 +#define WD_SCSI_STATUS 0x17 +#define WD_COMMAND 0x18 +#define WD_DATA 0x19 +#define WD_QUEUE_TAG 0x1a +#define WD_AUXILIARY_STATUS 0x1f + +/* WD commands */ +#define WD_CMD_RESET 0x00 +#define WD_CMD_ABORT 0x01 +#define WD_CMD_ASSERT_ATN 0x02 +#define WD_CMD_NEGATE_ACK 0x03 +#define WD_CMD_DISCONNECT 0x04 +#define WD_CMD_RESELECT 0x05 +#define WD_CMD_SEL_ATN 0x06 +#define WD_CMD_SEL 0x07 +#define WD_CMD_SEL_ATN_XFER 0x08 +#define WD_CMD_SEL_XFER 0x09 +#define WD_CMD_RESEL_RECEIVE 0x0a +#define WD_CMD_RESEL_SEND 0x0b +#define WD_CMD_WAIT_SEL_RECEIVE 0x0c +#define WD_CMD_TRANS_ADDR 0x18 +#define WD_CMD_TRANS_INFO 0x20 +#define WD_CMD_TRANSFER_PAD 0x21 +#define WD_CMD_SBT_MODE 0x80 + +/* SCSI Bus Phases */ +#define PHS_DATA_OUT 0x00 +#define PHS_DATA_IN 0x01 +#define PHS_COMMAND 0x02 +#define PHS_STATUS 0x03 +#define PHS_MESS_OUT 0x06 +#define PHS_MESS_IN 0x07 + +/* Command Status Register definitions */ + + /* reset state interrupts */ +#define CSR_RESET 0x00 +#define CSR_RESET_AF 0x01 + + /* successful completion interrupts */ +#define CSR_RESELECT 0x10 +#define CSR_SELECT 0x11 +#define CSR_SEL_XFER_DONE 0x16 +#define CSR_XFER_DONE 0x18 + + /* paused or aborted interrupts */ +#define CSR_MSGIN 0x20 +#define CSR_SDP 0x21 +#define CSR_SEL_ABORT 0x22 +#define CSR_RESEL_ABORT 0x25 +#define CSR_RESEL_ABORT_AM 0x27 +#define CSR_ABORT 0x28 + + /* terminated interrupts */ +#define CSR_INVALID 0x40 +#define CSR_UNEXP_DISC 0x41 +#define CSR_TIMEOUT 0x42 +#define CSR_PARITY 0x43 +#define CSR_PARITY_ATN 0x44 +#define CSR_BAD_STATUS 0x45 +#define CSR_UNEXP 0x48 + + /* service required interrupts */ +#define CSR_RESEL 0x80 +#define CSR_RESEL_AM 0x81 +#define CSR_DISC 0x85 +#define CSR_SRV_REQ 0x88 + + /* Own ID/CDB Size register */ +#define OWNID_EAF 0x08 +#define OWNID_EHP 0x10 +#define OWNID_RAF 0x20 +#define OWNID_FS_8 0x00 +#define OWNID_FS_12 0x40 +#define OWNID_FS_16 0x80 + + /* Control register */ +#define CTRL_HSP 0x01 +#define CTRL_HA 0x02 +#define CTRL_IDI 0x04 +#define CTRL_EDI 0x08 +#define CTRL_HHP 0x10 +#define CTRL_POLLED 0x00 +#define CTRL_BURST 0x20 +#define CTRL_BUS 0x40 +#define CTRL_DMA 0x80 + + /* Timeout Period register */ +#define TIMEOUT_PERIOD_VALUE 20 /* results in 200 ms. */ + + /* Synchronous Transfer Register */ +#define STR_FSS 0x80 + + /* Destination ID register */ +#define DSTID_DPD 0x40 +#define DATA_OUT_DIR 0 +#define DATA_IN_DIR 1 +#define DSTID_SCC 0x80 + + /* Source ID register */ +#define SRCID_MASK 0x07 +#define SRCID_SIV 0x08 +#define SRCID_DSP 0x20 +#define SRCID_ES 0x40 +#define SRCID_ER 0x80 + + + +#define ILLEGAL_STATUS_BYTE 0xff + + +#define DEFAULT_SX_PER 500 /* (ns) fairly safe */ +#define DEFAULT_SX_OFF 0 /* aka async */ + +#define OPTIMUM_SX_PER 252 /* (ns) best we can do (mult-of-4) */ +#define OPTIMUM_SX_OFF 12 /* size of in2000 fifo */ + +struct sx_period { + unsigned int period_ns; + uchar reg_value; + }; + + +struct IN2000_hostdata { + struct Scsi_Host *next; + uchar chip; /* what kind of wd33c93 chip? */ + uchar microcode; /* microcode rev if 'B' */ + unsigned short io_base; /* IO port base */ + unsigned int dip_switch; /* dip switch settings */ + unsigned int hrev; /* hardware revision of card */ + volatile uchar busy[8]; /* index = target, bit = lun */ + volatile Scsi_Cmnd *input_Q; /* commands waiting to be started */ + volatile Scsi_Cmnd *selecting; /* trying to select this command */ + volatile Scsi_Cmnd *connected; /* currently connected command */ + volatile Scsi_Cmnd *disconnected_Q;/* commands waiting for reconnect */ + uchar state; /* what we are currently doing */ + uchar fifo; /* what the FIFO is up to */ + uchar level2; /* extent to which Level-2 commands are used */ + uchar disconnect; /* disconnect/reselect policy */ + unsigned int args; /* set from command-line argument */ + uchar incoming_msg[8]; /* filled during message_in phase */ + int incoming_ptr; /* mainly used with EXTENDED messages */ + uchar outgoing_msg[8]; /* send this during next message_out */ + int outgoing_len; /* length of outgoing message */ + unsigned int default_sx_per; /* default transfer period for SCSI bus */ + uchar sync_xfer[8]; /* sync_xfer reg settings per target */ + uchar sync_stat[8]; /* status of sync negotiation per target */ + uchar sync_off; /* bit mask: don't use sync with these targets */ +#ifdef PROC_INTERFACE + uchar proc; /* bit mask: what's in proc output */ +#ifdef PROC_STATISTICS + unsigned long cmd_cnt[8]; /* # of commands issued per target */ + unsigned long int_cnt; /* # of interrupts serviced */ + unsigned long disc_allowed_cnt[8]; /* # of disconnects allowed per target */ + unsigned long disc_done_cnt[8]; /* # of disconnects done per target*/ +#endif +#endif + }; + + +/* defines for hostdata->chip */ + +#define C_WD33C93 0 +#define C_WD33C93A 1 +#define C_WD33C93B 2 +#define C_UNKNOWN_CHIP 100 + +/* defines for hostdata->state */ + +#define S_UNCONNECTED 0 +#define S_SELECTING 1 +#define S_RUNNING_LEVEL2 2 +#define S_CONNECTED 3 +#define S_PRE_TMP_DISC 4 +#define S_PRE_CMP_DISC 5 + +/* defines for hostdata->fifo */ + +#define FI_FIFO_UNUSED 0 +#define FI_FIFO_READING 1 +#define FI_FIFO_WRITING 2 + +/* defines for hostdata->level2 */ +/* NOTE: only the first 3 are trustworthy at this point - + * having trouble when more than 1 device is reading/writing + * at the same time... + */ + +#define L2_NONE 0 /* no combination commands - we get lots of ints */ +#define L2_SELECT 1 /* start with SEL_ATN_XFER, but never resume it */ +#define L2_BASIC 2 /* resume after STATUS ints & RDP messages */ +#define L2_DATA 3 /* resume after DATA_IN/OUT ints */ +#define L2_MOST 4 /* resume after anything except a RESELECT int */ +#define L2_RESELECT 5 /* resume after everything, including RESELECT ints */ +#define L2_ALL 6 /* always resume */ + +/* defines for hostdata->disconnect */ + +#define DIS_NEVER 0 +#define DIS_ADAPTIVE 1 +#define DIS_ALWAYS 2 + +/* defines for hostdata->args */ + +#define DB_TEST 1<<0 +#define DB_FIFO 1<<1 +#define DB_QUEUE_COMMAND 1<<2 +#define DB_EXECUTE 1<<3 +#define DB_INTR 1<<4 +#define DB_TRANSFER 1<<5 +#define DB_MASK 0x3f + +#define A_NO_SCSI_RESET 1<<15 + + +/* defines for hostdata->sync_xfer[] */ + +#define SS_UNSET 0 +#define SS_FIRST 1 +#define SS_WAITING 2 +#define SS_SET 3 + +/* defines for hostdata->proc */ + +#define PR_VERSION 1<<0 +#define PR_INFO 1<<1 +#define PR_STATISTICS 1<<2 +#define PR_CONNECTED 1<<3 +#define PR_INPUTQ 1<<4 +#define PR_DISCQ 1<<5 +#define PR_TEST 1<<6 +#define PR_STOP 1<<7 + int in2000_detect(Scsi_Host_Template *); int in2000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int in2000_abort(Scsi_Cmnd *); void in2000_setup(char *, int *); int in2000_proc_info(char *, char **, off_t, int, int, int); +struct proc_dir_entry proc_scsi_in2000; int in2000_biosparam(struct scsi_disk *, kdev_t, int *); int in2000_reset(Scsi_Cmnd *, unsigned int); @@ -40,7 +393,7 @@ #define IN2000_HOST_ID 7 #define IN2000 { NULL, /* link pointer for modules */ \ - NULL, /* module pointer for modules */ \ + NULL, /* usage_count for modules */ \ &proc_scsi_in2000, /* pointer to /proc/scsi directory entry */ \ in2000_proc_info, /* pointer to proc info function */ \ "Always IN2000", /* device name */ \ diff -u --recursive --new-file v2.1.45/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c --- v2.1.45/linux/fs/binfmt_aout.c Thu Jul 17 10:06:06 1997 +++ linux/fs/binfmt_aout.c Sat Jul 19 11:29:59 1997 @@ -127,16 +127,8 @@ goto end_coredump; if (get_write_access(inode)) goto end_coredump; - file.f_mode = 3; - file.f_flags = 0; - file.f_count = 1; - file.f_dentry = dentry; - file.f_pos = 0; - file.f_reada = 0; - file.f_op = inode->i_op->default_file_ops; - if (file.f_op->open) - if (file.f_op->open(inode,&file)) - goto done_coredump; + if (init_private_file(&file, dentry, 3)) + goto end_coredump; if (!file.f_op->write) goto close_coredump; has_dumped = 1; diff -u --recursive --new-file v2.1.45/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.1.45/linux/fs/binfmt_elf.c Thu Jul 17 10:06:06 1997 +++ linux/fs/binfmt_elf.c Sat Jul 19 11:29:59 1997 @@ -1091,16 +1091,8 @@ goto end_coredump; if (!inode->i_op || !inode->i_op->default_file_ops) goto end_coredump; - file.f_mode = 3; - file.f_flags = 0; - file.f_count = 1; - file.f_dentry = dentry; - file.f_pos = 0; - file.f_reada = 0; - file.f_op = inode->i_op->default_file_ops; - if (file.f_op->open) - if (file.f_op->open(inode,&file)) - goto end_coredump; + if (init_private_file(&file, dentry, 3)) + goto end_coredump; if (!file.f_op->write) goto close_coredump; has_dumped = 1; diff -u --recursive --new-file v2.1.45/linux/fs/exec.c linux/fs/exec.c --- v2.1.45/linux/fs/exec.c Thu Jul 17 10:06:06 1997 +++ linux/fs/exec.c Sat Jul 19 11:29:59 1997 @@ -352,17 +352,9 @@ if (!inode->i_op || !inode->i_op->default_file_ops) goto end_readexec; - file.f_mode = 1; - file.f_flags = 0; - file.f_count = 1; - file.f_dentry = dentry; - file.f_pos = 0; - file.f_reada = 0; - file.f_op = inode->i_op->default_file_ops; - if (file.f_op->open) - if (file.f_op->open(inode,&file)) - goto end_readexec; - if (!file.f_op || !file.f_op->read) + if (init_private_file(&file, dentry, 1)) + goto end_readexec; + if (!file.f_op->read) goto close_readexec; if (file.f_op->llseek) { if (file.f_op->llseek(inode,&file,offset,0) != offset) diff -u --recursive --new-file v2.1.45/linux/fs/ext2/ialloc.c linux/fs/ext2/ialloc.c --- v2.1.45/linux/fs/ext2/ialloc.c Thu Jul 17 10:06:06 1997 +++ linux/fs/ext2/ialloc.c Fri Jul 18 11:25:38 1997 @@ -154,8 +154,26 @@ return 0; } +/* + * NOTE! When we get the inode, we're the only people + * that have access to it, and as such there are no + * race conditions we have to worry about. The inode + * is not on the hash-lists, and it cannot be reached + * through the filesystem because the directory entry + * has been deleted earlier. + * + * HOWEVER: we must make sure that we get no aliases, + * which means that we have to call "clear_inode()" + * _before_ we mark the inode not in use in the inode + * bitmaps. Otherwise a newly created file might use + * the same inode number (not actually the same pointer + * though), and then we'd have two inodes sharing the + * same inode number and space on the harddisk. + */ void ext2_free_inode (struct inode * inode) { + int is_directory; + unsigned long ino; struct super_block * sb; struct buffer_head * bh; struct buffer_head * bh2; @@ -185,30 +203,40 @@ return; } - ext2_debug ("freeing inode %lu\n", inode->i_ino); + ino = inode->i_ino; + ext2_debug ("freeing inode %lu\n", ino); sb = inode->i_sb; lock_super (sb); - if (inode->i_ino < EXT2_FIRST_INO(sb) || - inode->i_ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) { + if (ino < EXT2_FIRST_INO(sb) || + ino > le32_to_cpu(sb->u.ext2_sb.s_es->s_inodes_count)) { ext2_error (sb, "free_inode", "reserved inode or nonexistent inode"); unlock_super (sb); return; } es = sb->u.ext2_sb.s_es; - block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb); - bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb); + block_group = (ino - 1) / EXT2_INODES_PER_GROUP(sb); + bit = (ino - 1) % EXT2_INODES_PER_GROUP(sb); bitmap_nr = load_inode_bitmap (sb, block_group); bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; + + is_directory = S_ISDIR(inode->i_mode); + + /* Do this BEFORE marking the inode not in use */ + if (sb->dq_op) + sb->dq_op->free_inode (inode, 1); + clear_inode (inode); + + /* Ok, now we can actually update the inode bitmaps.. */ if (!ext2_clear_bit (bit, bh->b_data)) ext2_warning (sb, "ext2_free_inode", - "bit already cleared for inode %lu", inode->i_ino); + "bit already cleared for inode %lu", ino); else { gdp = get_group_desc (sb, block_group, &bh2); gdp->bg_free_inodes_count = cpu_to_le16(le16_to_cpu(gdp->bg_free_inodes_count) + 1); - if (S_ISDIR(inode->i_mode)) + if (is_directory) gdp->bg_used_dirs_count = cpu_to_le16(le16_to_cpu(gdp->bg_used_dirs_count) - 1); mark_buffer_dirty(bh2, 1); @@ -221,10 +249,7 @@ ll_rw_block (WRITE, 1, &bh); wait_on_buffer (bh); } - if (sb->dq_op) - sb->dq_op->free_inode (inode, 1); sb->s_dirt = 1; - clear_inode (inode); unlock_super (sb); } diff -u --recursive --new-file v2.1.45/linux/fs/file_table.c linux/fs/file_table.c --- v2.1.45/linux/fs/file_table.c Thu Jul 17 10:06:07 1997 +++ linux/fs/file_table.c Sat Jul 19 11:29:59 1997 @@ -102,6 +102,24 @@ return f; } +/* + * Clear and initialize a (private) struct file for the given dentry, + * and call the open function (if any). The caller must verify that + * inode->i_op and inode->i_op->default_file_ops are not NULL. + */ +int init_private_file(struct file *filp, struct dentry *dentry, int mode) +{ + memset(filp, 0, sizeof(*filp)); + filp->f_mode = mode; + filp->f_count = 1; + filp->f_dentry = dentry; + filp->f_op = dentry->d_inode->i_op->default_file_ops; + if (filp->f_op->open) + return filp->f_op->open(dentry->d_inode, filp); + else + return 0; +} + #ifdef CONFIG_QUOTA void add_dquot_ref(kdev_t dev, short type) diff -u --recursive --new-file v2.1.45/linux/fs/inode.c linux/fs/inode.c --- v2.1.45/linux/fs/inode.c Thu Jul 17 10:06:07 1997 +++ linux/fs/inode.c Fri Jul 18 12:54:33 1997 @@ -296,7 +296,7 @@ memset(&inode->u, 0, sizeof(inode->u)); inode->i_sock = 0; inode->i_op = NULL; - inode->i_nlink = 0; + inode->i_nlink = 1; inode->i_writecount = 0; inode->i_size = 0; memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); @@ -438,6 +438,8 @@ if (!inode->i_nlink) { list_del(&inode->i_hash); INIT_LIST_HEAD(&inode->i_hash); + list_del(&inode->i_list); + INIT_LIST_HEAD(&inode->i_list); if (op && op->delete_inode) { void (*delete)(struct inode *) = op->delete_inode; spin_unlock(&inode_lock); diff -u --recursive --new-file v2.1.45/linux/fs/minix/inode.c linux/fs/minix/inode.c --- v2.1.45/linux/fs/minix/inode.c Thu Jul 17 10:06:07 1997 +++ linux/fs/minix/inode.c Fri Jul 18 12:42:29 1997 @@ -24,10 +24,8 @@ #include #include -void minix_put_inode(struct inode *inode) +static void minix_delete_inode(struct inode *inode) { - if (inode->i_nlink) - return; inode->i_size = 0; minix_truncate(inode); minix_free_inode(inode); @@ -77,9 +75,10 @@ static struct super_operations minix_sops = { minix_read_inode, - NULL, minix_write_inode, - minix_put_inode, + NULL, /* put_inode */ + minix_delete_inode, + NULL, /* notify_change */ minix_put_super, minix_write_super, minix_statfs, diff -u --recursive --new-file v2.1.45/linux/fs/minix/namei.c linux/fs/minix/namei.c --- v2.1.45/linux/fs/minix/namei.c Thu Jul 17 10:06:07 1997 +++ linux/fs/minix/namei.c Fri Jul 18 12:45:54 1997 @@ -47,9 +47,6 @@ *offset += info->s_dirsize; if (!de->inode || len > info->s_namelen) return 0; - /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ - if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) - return 1; return namecompare(len,info->s_namelen,name,de->name); } @@ -104,24 +101,22 @@ return NULL; } -int minix_lookup(struct inode * dir, struct qstr *name, - struct inode ** result) +int minix_lookup(struct inode * dir, struct dentry *dentry) { - int ino; + struct inode * inode = NULL; struct minix_dir_entry * de; struct buffer_head * bh; - *result = NULL; - if (!dir) - return -ENOENT; - if (!S_ISDIR(dir->i_mode)) - return -ENOENT; - if (!(bh = minix_find_entry(dir, name->name, name->len, &de))) - return -ENOENT; - ino = de->inode; - brelse(bh); - if (!(*result = iget(dir->i_sb,ino))) - return -EACCES; + bh = minix_find_entry(dir, dentry->d_name.name, dentry->d_name.len, &de); + if (bh) { + unsigned long ino = le32_to_cpu(de->inode); + brelse (bh); + inode = iget(dir->i_sb, ino); + + if (!inode) + return -EACCES; + } + d_add(dentry, inode); return 0; } @@ -602,29 +597,21 @@ return 0; } -static int subdir(struct inode * new_inode, struct inode * old_inode) +static int subdir(struct dentry * new_dentry, struct dentry * old_dentry) { - int ino; - int result; + int result = 0; - new_inode->i_count++; - result = 0; for (;;) { - if (new_inode == old_inode) { - result = 1; - break; + if (new_dentry != old_dentry) { + struct dentry * parent = new_dentry->d_parent; + if (parent == new_dentry) + break; + new_dentry = parent; + continue; } - if (new_inode->i_dev != old_inode->i_dev) - break; - ino = new_inode->i_ino; - if (minix_lookup(new_inode, - &(struct qstr) { "..", 2, 0 }, - &new_inode)) - break; - if (new_inode->i_ino == ino) - break; + result = 1; + break; } - iput(new_inode); return result; } @@ -690,7 +677,7 @@ if (!S_ISDIR(old_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir, old_inode)) + if (subdir(new_dentry, old_dentry)) goto end_rename; retval = -ENOTEMPTY; if (!empty_dir(new_inode)) @@ -709,7 +696,7 @@ if (new_inode && !S_ISDIR(new_inode->i_mode)) goto end_rename; retval = -EINVAL; - if (subdir(new_dir, old_inode)) + if (subdir(new_dentry, old_dentry)) goto end_rename; retval = -EIO; dir_bh = minix_bread(old_inode,0,0); diff -u --recursive --new-file v2.1.45/linux/fs/namei.c linux/fs/namei.c --- v2.1.45/linux/fs/namei.c Thu Jul 17 10:06:07 1997 +++ linux/fs/namei.c Sat Jul 19 11:34:29 1997 @@ -255,7 +255,6 @@ } up(&dir->i_sem); } - up(&dir->i_sem); return result; } @@ -380,7 +379,7 @@ } if (!*name) - return base; + goto return_base; /* At this point we know we have a real path component. */ for(;;) { @@ -422,9 +421,10 @@ break; base = do_follow_link(base, dentry); - if (c) + if (c && !IS_ERR(base)) continue; +return_base: return base; } dput(base); @@ -742,7 +742,7 @@ struct inode *dir; struct dentry *dentry; - dentry = lookup_dentry(name, NULL, 1); + dentry = lookup_dentry(name, NULL, 0); error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto exit; @@ -1051,13 +1051,13 @@ struct inode * old_dir, * new_dir; struct dentry * old_dentry, *new_dentry; - old_dentry = lookup_dentry(oldname, NULL, 1); + old_dentry = lookup_dentry(oldname, NULL, 0); error = PTR_ERR(old_dentry); if (IS_ERR(old_dentry)) goto exit; - new_dentry = lookup_dentry(newname, NULL, 1); + new_dentry = lookup_dentry(newname, NULL, 0); error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) diff -u --recursive --new-file v2.1.45/linux/fs/open.c linux/fs/open.c --- v2.1.45/linux/fs/open.c Thu Jul 17 10:06:07 1997 +++ linux/fs/open.c Sat Jul 19 11:34:29 1997 @@ -487,22 +487,17 @@ return error; } -asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group) +static int chown_common(struct dentry * dentry, uid_t user, gid_t group) { struct inode * inode; - struct dentry * dentry; - struct file * file; struct iattr newattrs; - int error = -EBADF; + int error; - lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - goto out; error = -ENOENT; - if (!(dentry = file->f_dentry)) - goto out; - if (!(inode = dentry->d_inode)) + if (!(inode = dentry->d_inode)) { + printk("chown_common: NULL inode\n"); goto out; + } error = -EROFS; if (IS_RDONLY(inode)) goto out; @@ -545,16 +540,33 @@ } else error = notify_change(inode, &newattrs); out: - unlock_kernel(); return error; } +asmlinkage int sys_lchown(const char * filename, uid_t user, gid_t group) +{ + struct dentry * dentry; + int error; + + lock_kernel(); + dentry = lnamei(filename); + + error = PTR_ERR(dentry); + if (IS_ERR(dentry)) + goto out; + + error = chown_common(dentry, user, group); + + dput(dentry); +out: + unlock_kernel(); + return(error); +} + asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group) { struct dentry * dentry; - struct inode * inode; int error; - struct iattr newattrs; lock_kernel(); dentry = namei(filename); @@ -562,56 +574,33 @@ error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto out; - inode = dentry->d_inode; - - error = -EROFS; - if (IS_RDONLY(inode)) - goto dput_and_out; - error = -EPERM; - if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) - goto dput_and_out; + error = chown_common(dentry, user, group); - if (user == (uid_t) -1) - user = inode->i_uid; - if (group == (gid_t) -1) - group = inode->i_gid; - newattrs.ia_mode = inode->i_mode; - newattrs.ia_uid = user; - newattrs.ia_gid = group; - newattrs.ia_valid = ATTR_UID | ATTR_GID | ATTR_CTIME; - /* - * If the owner has been changed, remove the setuid bit - */ - if (inode->i_mode & S_ISUID) { - newattrs.ia_mode &= ~S_ISUID; - newattrs.ia_valid |= ATTR_MODE; - } - /* - * If the group has been changed, remove the setgid bit - * - * Don't remove the setgid bit if no group execute bit. - * This is a file marked for mandatory locking. - */ - if (((inode->i_mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) { - newattrs.ia_mode &= ~S_ISGID; - newattrs.ia_valid |= ATTR_MODE; - } - if (inode->i_sb->dq_op) { - inode->i_sb->dq_op->initialize(inode, -1); - error = -EDQUOT; - if (inode->i_sb->dq_op->transfer(inode, &newattrs, 0)) - goto dput_and_out; - error = notify_change(inode, &newattrs); - if (error) - inode->i_sb->dq_op->transfer(inode, &newattrs, 1); - } else - error = notify_change(inode, &newattrs); -dput_and_out: dput(dentry); out: unlock_kernel(); return(error); +} + +asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group) +{ + struct dentry * dentry; + struct file * file; + int error = -EBADF; + + lock_kernel(); + if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + goto out; + error = -ENOENT; + if (!(dentry = file->f_dentry)) + goto out; + + error = chown_common(dentry, user, group); + +out: + unlock_kernel(); + return error; } /* diff -u --recursive --new-file v2.1.45/linux/fs/pipe.c linux/fs/pipe.c --- v2.1.45/linux/fs/pipe.c Thu Jul 17 10:06:07 1997 +++ linux/fs/pipe.c Thu Jul 17 10:24:24 1997 @@ -391,7 +391,6 @@ } else { PIPE_BASE(*inode) = (char *) page; inode->i_op = &pipe_inode_operations; - inode->i_count = 1; PIPE_WAIT(*inode) = NULL; PIPE_START(*inode) = PIPE_LEN(*inode) = 0; PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0; @@ -404,7 +403,7 @@ * that it already _is_ on the dirty list. */ inode->i_state = 1 << I_DIRTY; - inode->i_mode |= S_IFIFO | S_IRUSR | S_IWUSR; + inode->i_mode = S_IFIFO | S_IRUSR | S_IWUSR; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; diff -u --recursive --new-file v2.1.45/linux/include/linux/fs.h linux/include/linux/fs.h --- v2.1.45/linux/include/linux/fs.h Thu Jul 17 10:06:08 1997 +++ linux/include/linux/fs.h Sat Jul 19 12:49:58 1997 @@ -385,6 +385,8 @@ void *private_data; }; +extern int init_private_file(struct file *, struct dentry *, int); + #define FL_POSIX 1 #define FL_FLOCK 2 #define FL_BROKEN 4 /* broken flock() emulation */ diff -u --recursive --new-file v2.1.45/linux/include/linux/minix_fs.h linux/include/linux/minix_fs.h --- v2.1.45/linux/include/linux/minix_fs.h Thu Jul 17 10:06:08 1997 +++ linux/include/linux/minix_fs.h Fri Jul 18 12:43:40 1997 @@ -88,8 +88,7 @@ #ifdef __KERNEL__ -extern int minix_lookup(struct inode * dir, struct qstr *name, - struct inode ** result); +extern int minix_lookup(struct inode * dir, struct dentry *dentry); extern int minix_create(struct inode * dir, struct dentry *dentry, int mode); extern int minix_mkdir(struct inode * dir, struct dentry *dentry, int mode); extern int minix_rmdir(struct inode * dir, struct dentry *dentry); @@ -120,7 +119,6 @@ extern int minix_remount (struct super_block * sb, int * flags, char * data); extern void minix_read_inode(struct inode *); extern void minix_write_inode(struct inode *); -extern void minix_put_inode(struct inode *); extern int minix_statfs(struct super_block *, struct statfs *, int); extern int minix_sync_inode(struct inode *); extern int minix_sync_file(struct inode *, struct file *); diff -u --recursive --new-file v2.1.45/linux/kernel/ksyms.c linux/kernel/ksyms.c --- v2.1.45/linux/kernel/ksyms.c Thu Jul 17 10:06:09 1997 +++ linux/kernel/ksyms.c Fri Jul 18 12:40:13 1997 @@ -150,6 +150,10 @@ EXPORT_SYMBOL(close_fp); EXPORT_SYMBOL(d_alloc_root); EXPORT_SYMBOL(d_delete); +EXPORT_SYMBOL(d_add); +EXPORT_SYMBOL(d_move); +EXPORT_SYMBOL(d_instantiate); +EXPORT_SYMBOL(__mark_inode_dirty); EXPORT_SYMBOL(insert_file_free); EXPORT_SYMBOL(check_disk_change); EXPORT_SYMBOL(invalidate_buffers); diff -u --recursive --new-file v2.1.45/linux/net/appletalk/sysctl_net_atalk.c linux/net/appletalk/sysctl_net_atalk.c --- v2.1.45/linux/net/appletalk/sysctl_net_atalk.c Thu Jul 17 10:06:09 1997 +++ linux/net/appletalk/sysctl_net_atalk.c Fri Jul 18 16:10:12 1997 @@ -6,6 +6,7 @@ * Dynamic registration, added aarp entries. (5/30/97 Chris Horn) */ +#include #include #include diff -u --recursive --new-file v2.1.45/linux/net/socket.c linux/net/socket.c --- v2.1.45/linux/net/socket.c Thu Jul 17 10:06:09 1997 +++ linux/net/socket.c Thu Jul 17 15:56:33 1997 @@ -227,7 +227,6 @@ file->f_op = &socket_file_ops; file->f_mode = 3; file->f_flags = O_RDWR; - file->f_dentry = d_alloc_root(inode, NULL); file->f_pos = 0; } return fd;