diff -u --recursive --new-file v2.1.107/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.107/linux/Documentation/Configure.help Wed Jun 24 22:54:01 1998 +++ linux/Documentation/Configure.help Tue Jun 30 22:37:54 1998 @@ -3219,127 +3219,104 @@ NCR53C8XX SCSI support CONFIG_SCSI_NCR53C8XX - This is the BSD ncr driver adapted to Linux for the NCR53C8XX family + This is the BSD ncr driver adapted to linux for the NCR53C8XX family of PCI-SCSI controllers. This driver supports parity checking, - tagged command queuing, Fast-20 data transfer up to 20 MB/s with - narrow SCSI devices and 40 MB/s with wide SCSI devices. + tagged command queuing and fast synchronous data transfers up to 80 MB/s + with wide FAST-40 LVD devices and controllers. + The NCR53C860 and NCR53C875 support FAST-20 transfers. The NCR53C895 + supports FAST-40 transfers with Ultra2 LVD devices. Please read drivers/scsi/README.ncr53c8xx for more information. - Linux/i386, Linux/Alpha and Linux/PPC are supported by this driver. + Linux/i386 and Linux/Alpha are supported by this driver. synchronous data transfers frequency CONFIG_SCSI_NCR53C8XX_SYNC - SCSI-2 specifications allow SCSI devices to negotiate a synchronous - transfer period of 25 nano-seconds or more. - - The transfer period value is 4 times the agreed transfer period. - So, data can be transferred at a 10 MHz frequency, allowing 10 - MB/second throughput with 8 bits SCSI-2 devices and 20 MB/second - with wide16 devices. This frequency can be used safely with - differential devices but may cause problems with single-ended - devices. - - Specify 0 if you want to only use asynchronous data transfers. - Otherwise, specify a value between 5 and 10. Commercial O/Ses - generally use 5 Mhz frequency for synchronous transfers. It is a - reasonable default value. - - However, a flawless single-ended SCSI bus supports 10 MHz data - transfers. Regardless of the value chosen in the Linux - configuration, the synchronous period can be changed after boot-up - through the /proc/scsi file system. The generic command is: - - echo "setsync #target period" >/proc/scsi/ncr53c8xx/0 - - Use a 25 ns period for 10 Mhz synchronous data transfers. - If you don't know what to do now, go with the default. + The SCSI Parallel Interface-2 Standard defines 4 classes of transfer + rates: FAST-5, FAST-10, FAST-20 and FAST-40. The numbers are respectively + the maximum data transfer rates in mega-transfers per second for each + class. For example, a FAST-20 Wide 16 device is able to transfer data + at up to 40 MB/s. + You may specify 0 if you want to only use asynchronous data transfers. + Otherwise, specify a value between 5 and 40, depending on the capability + of your SCSI controller. Note that 40 should normally be ok since the + driver narrows the value according to controllers capabilities. + This option has no effect for adapters with NVRAM, since the driver will + get this information from the user set-up. It also can be overriden using + a boot setup option, as follow (example): + 'ncr53c8xx=sync:12' will allow the driver to negotiate for FAST-20 + synchronous data transfer (20 mega-transfers per second). + The normal answer therefore is not to go with the default but to select + the maximum value 40 allowing the driver to use the maximum value + supported by each controller. + There is no safe option other than using good cabling, right terminations + and SCSI conformant devices. use normal IO CONFIG_SCSI_NCR53C8XX_IOMAPPED This option allows you to force the driver to use normal IO. - Memory mapped IO has less latency than normal IO and works for most - Intel-based hardware. Under Linux/Alpha and Linux/PPC only normal - IO is currently supported by the driver and so, this option has no - effect. On Linux/PPC MMIO and normal IO are done the same (all IO - is memory mapped) so you lose nothing by using normal IO. The normal - answer therefore is N. Try Y only if you have problems. + Memory mapped IO has less latency than normal IO and works for most + Intel-based hardware. + Under Linux/Alpha only normal IO is currently supported by the + driver and so, this option has no effect. + The normal answer therefore is N. not allow targets to disconnect CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT - This option is only provided for safety if you suspect some SCSI + This option is only provided for safety if you suspect some scsi device of yours to not support properly the target-disconnect feature. In that case, you would say Y here. In general however, to not allow targets to disconnect is not reasonable if there is more - than 1 device on a SCSI bus. The normal answer therefore is N. + than 1 device on a scsi bus. The normal answer therefore is N. -detect and read serial NVRAMs -CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT - Enable support for reading the serial NVRAM data on Symbios and some - Symbios compatible cards, and Tekram DC390W/U/F cards. Useful for - systems with more than one Symbios compatible controller where at - least one has a serial NVRAM, or for a system with a mixture of - Symbios and Tekram cards. Enables setting the boot order of host - adaptors to something other than the default order or "reverse - probe" order. Also enables Symbios and Tekram cards to be - distinguished so that the option "assume boards are SYMBIOS - compatible" (CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT) below may be set - in a system with a mixture of Symbios and Tekram cards so that the - Symbios cards can make use of the full range of Symbios features, - differential, led pin, without causing problems for the Tekram - card(s). Also enables setting host and targets SCSI features as - defined in the user setup for each host using a serial NVRAM. Read - drivers/scsi/README.ncr53c8xx for more information. The default - answer is N, the normal answer should be Y. - -enable tagged command queuing -CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE +default tagged command queue depth +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS This option allows you to enable tagged command queuing support at - Linux start-up. Some SCSI devices do not properly support this - feature. The suggested method is to say N here and to use the - "settags" control command after boot-up to enable this feature: - - echo "settags 2 4" >/proc/scsi/ncr53c8xx/0 - - asks the driver to use up to 4 concurrent tagged commands for target - 2 of controller 0. - - See the file drivers/scsi/README.ncr53c8xx for more information. - WARNING! If you say Y here, then you have to say N to "not allow - targets to disconnect", above. - - The safe answer therefore is N. - The normal answer therefore is Y. + linux start-up and to define the default value for the number of + tags per device. If you donnot want tagged command queuing to be + used by the driver you must enter either 0 or 1 for this option. + The default value is 8 and should be supported by most hard disks. + This option has no effect for adapters with NVRAM, since the driver + will get this information from the user set-up. It also can be + overriden using a boot setup option, as follow (example): + 'ncr53c8xx=tags:4/t2t3q16/t0u2q10' will set default queue depth to 4, + set queue depth to 16 for target 2 and target 3 on controller 0 and + set queue depth to 10 for target 0 / lun 2 on controller 1. + The normal answer therefore is to go with the default 8 and to use + a boot command line option for devices that need to use a different + command queue depth. + There is no safe option other than using good scsi devices. maximum number of queued commands CONFIG_SCSI_NCR53C8XX_MAX_TAGS This option allows you to specify the maximum number of commands - that can be queued to a device, when tagged command queuing is - possible. The default value is 4. Minimum is 2, maximum is 12. The - normal answer therefore is the default one. - + that can be queued to any device, when tagged command queuing is + possible. The default value is 32. Minimum is 2, maximum is 64. + For value less than 32, this option only spares a fiew memory + (8*7*(32-MAXTAGS) bytes), so using less than 32 is'nt worth it. + For value greater than 32, latency on reselection will be increased + of 1 or 2 micro-seconds. So, the normal answer here is to go with the + default value 32 unless you are using very large hard disks with + large cache (>= 1MB) that are able to get advantage of more than + 32 tagged commands. + There is no safe option and the default answer is recommended. + assume boards are SYMBIOS compatible CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT This option allows you to enable some features depending on GPIO wiring. These General Purpose Input/Output pins can be used for vendor specific features or implementation of the standard SYMBIOS features. Genuine SYMBIOS boards use GPIO0 in output for controller - LED and GPIO3 bit as a flag indicating single-ended/differential - interface. - - If all the boards of your system are genuine SYMBIOS boards or use - BIOS and drivers from SYMBIOS, you would want to say Y here. - The driver behaves correctly on my system with this option enabled. - (SDMS 4.0 + Promise SCSI ULTRA 875 rev 0x3 + ASUS SC200 810A rev - 0x12). This option must be set to N if your system has at least one - 53C8XX based SCSI board with a vendor-specific BIOS (example: Tekram - DC-390/U/W/F). - - However, if all your non Symbios compatible boards have NVRAM, - saying Y to "detect and read serial NVRAMs" - (CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT) above allows the driver to - distinguish Symbios compatible boards from other ones; you can then - also answer Y here. - - If unsure, say N. + LED and GPIO3 bit as a flag indicating singled-ended/differential + interface. The Tekram DC-390U/F boards uses a different GPIO wiring. + This option is useless if all your boards have NVRAM, since the driver + is able to detect the board type from the NVRAM format. + +enable profiling statistics gathering +CONFIG_SCSI_NCR53C8XX_PROFILE + This option allows you to enable profiling informations gathering. + This statististics are not very accurate due to the low frequency + of the kernel clock (100 Hz on i386) and have performance impact + on systems that use very fast devices. + The normal answer therefore is N. IBMMCA SCSI support CONFIG_SCSI_IBMMCA diff -u --recursive --new-file v2.1.107/linux/Documentation/filesystems/vfs.txt linux/Documentation/filesystems/vfs.txt --- v2.1.107/linux/Documentation/filesystems/vfs.txt Wed Jun 24 22:54:02 1998 +++ linux/Documentation/filesystems/vfs.txt Sat Jun 27 00:11:52 1998 @@ -1,174 +1,448 @@ -A Brief Overview of the Virtual File System -=========================================== - by Benjamin LaHaise (blah@dot.superaje.com) +/* -*- auto-fill -*- */ -No one else seems to be writing this, so here's a quick description of what -I've learned while writing lofs. + Overview of the Virtual File System -The VFS is relatively simple, but it is nice not to have to browse through -pages of code to determine what is expected when writing a filesystem. -This document is meant to help anyone attempting such a feat, and to clarify -a few important points and dependencies. + Richard Gooch -register_filesystem (struct file_system_type *fstype) -===================================================== + 27-JUN-1998 -All filesystems are created equal, or at least they start out that way. -A filesystem, whether in module form or linked into the kernel, needs to add -itself to the table of filesystems by calling register_filesystem with an -initialized file_system_type structure. Any further functions of the -filesystem are accessed through the following function tables: +Conventions used in this document
+================================= -struct file_system_type -======================= +Each section in this document will have the string "
" at the +right-hand side of the section title. Each subsection will have +"" at the right-hand side. These strings are meant to make +it easier to search through the document. - struct super_block *(*read_super) (struct super_block *sb, void *options, int silent); +NOTE that the master copy of this document is available online at: +http://www.atnf.csiro.au/~rgooch/linux/docs/vfs.txt - This is the entry point of all filesystems. If the filesystem succeeds - in mounting itself, sb should be returned, otherwise NULL. options is - a pointer to a maximum of PAGE_SIZE-1 bytes of options, typically a zero - terminated string passed from mount. This page is freed after read_super - returns, so do not use any pointers into it. - This routine _must_ set the s_op member of sb to point to a valid - super_operations structure. +What is it?
+=========== - const char *name; +The Virtual File System (otherwise known as the Virtual Filesystem +Switch) is the software layer in the kernel that provides the +filesystem interface to userspace programmes. It also provides an +abstraction within the kernel which allows different filesystem +implementations to co-exist. - Name points to a string that the system will know the filesystem by. - int requires_dev; +A Quick Look At How It Works
+============================ - Set this flag to 1 if the filesystem requires a block device to be mounted - on. +In this section I'll briefly describe how things work, before +launching into the details. I'll start with describing what happens +when user programmes open and manipulate files, and then look from the +other view which is how a filesystem is supported and subsequently +mounted. - struct file_system_type * next; +Opening a File +-------------- + +The VFS implements the open(2) system call. The pathname argument is +used by the VFS to search through the directory entry cache (dentry +cache or "dcache"). This provides a very fast lookup mechanism to +translate a pathname (filename) into a specific dentry. + +An individual dentry usually has a pointer to an inode. Inodes are the +things that live on disc drives, and can be regular files (you know: +those things that you write data into), directories, FIFOs and other +beasts. Dentries live in RAM and are never saved to disc: they exist +only for performance. Inodes live on disc and are copied into memory +when required. Later any changes are written back to disc. The inode +that lives in RAM is a VFS inode, and it is this which the dentry +points to. + +The dcache is meant to be a view into your entire filespace. Unlike +Linus, most of us losers can't fit enough dentries into RAM to cover +all of our filespace, so the dcache has bits missing. In order to +resolve your pathname into a dentry, the VFS may have to resort to +creating dentries along the way, and then loading the inode. This is +done by looking up the inode. + +To lookup an inode (usually read from disc) requires that the VFS +calls the lookup() method of the parent directory inode. This method +is installed by the specific filesystem implementation that the inode +lives in. There will be more on this later. + +Once the VFS has the required dentry (and hence the inode), we can do +all those boring things like open(2) the file, or stat(2) it to peek +at the inode data. The stat(2) operation is fairly simple: once the +VFS has the dentry, it peeks at the inode data and passes some of it +back to userspace. + +Opening a file requires another operation: allocation of a file +structure (this is the kernel-side implementation of file +descriptors). The freshly allocated file structure is initialised with +a pointer to the dentry and a set of file operation member +functions. These are taken from the inode data. The open() file method +is then called so the specific filesystem implementation can do it's +work. You can see that this is another switch performed by the VFS. + +The file structure is placed into the file descriptor table for the +process. + +Reading, writing and closing files (and other assorted VFS operations) +is done by using the userspace file descriptor to grab the appropriate +file structure, and then calling the required file structure method +function to do whatever is required. + +For as long as the file is open, it keeps the dentry "open" (in use), +which in turn means that the VFS inode is still in use. + +Registering and Mounting a Filesystem +------------------------------------- + +If you want to support a new kind of filesystem in the kernel, all you +need to do is call register_filesystem(). You pass a structure +describing the filesystem implementation (struct file_system_type) +which is then added to an internal table of supported filesystems. You +can do: - This field points to the next file_system_type that is present in the system, - and should be initialized to NULL. +% cat /proc/filesystems -struct super_operations +to see what filesystems are currently available on your system. + +When a request is made to mount a block device onto a directory in +your filespace the VFS will call the appropriate method for the +specific filesystem. The dentry for the mount point will then be +updated to point to the root inode for the new filesystem. + +It's now time to look at things in more detail. + + +struct file_system_type
======================= -The super_operations structure is found through the s_op member of the -super_block structure. +This describes the filesystem. As of kernel 2.1.99, the following +members are defined: - void (*read_inode) (struct inode *inode); - [optional - doesn't quite make sense] - read_inode is called by the VFS when iget is called requesting an inode - not already present in the inode table. i_ino is set to the number of the - inode requested. - - The i_op member of inode should be set to a valid inode_operations - structure. Typically filesystems have separate inode_operations for - directories, files and symlinks. i_op can be NULL. +struct file_system_type { + const char *name; + int fs_flags; + struct super_block *(*read_super) (struct super_block *, void *, int); + struct file_system_type * next; +}; - int (*notify_change) (struct inode *, struct iattr *); - [optional] - void (*write_inode) (struct inode *); - [optional] + name: the name of the filesystem type, such as "ext2", "iso9660", + "msdos" and so on + + fs_flags: various flags (i.e. if it is a read-only FS) + + read_super: the method to call when a new instance of this + filesystem should be mounted + + next: for internal VFS use: you should initialise this to NULL + +The read_super() method has the following arguments: + + struct super_block *sb: the superblock structure. This is partially + initialised by the VFS and the rest must be initialised by the + read_super() method + + void *data: arbitrary mount options, usually comes as an ASCII + string - int (*put_inode) (struct inode *inode); - [optional] - put_inode is called by the VFS when the last instance of inode is released - with a call to iput. The only special consideration that should be made - is that iget may reuse inode without calling read_inode unless clear_inode - is called. put_inode MUST return 1 if it called clear_inode on the inode, - otherwise zero. + int silent: whether or not to be silent on error +The read_super() method must determine if the block device specified +in the superblock contains a filesystem of the type the method +supports. On success the method returns the superblock pointer, on +failure it returns NULL. + +The most interesting member of the superblock structure that the +read_super() method fills in is the "s_op" field. This is a pointer to +a "struct super_operations" which describes the next level of the +filesystem implementation. + + +struct super_operations
+======================= + +This describes how the VFS can manipulate the superblock of your +filesystem. As of kernel 2.1.99, the following members are defined: + +struct super_operations { + void (*read_inode) (struct inode *); + void (*write_inode) (struct inode *); + void (*put_inode) (struct inode *); + void (*delete_inode) (struct inode *); + int (*notify_change) (struct dentry *, struct iattr *); void (*put_super) (struct super_block *); - [optional] void (*write_super) (struct super_block *); - [optional] - void (*statfs) (struct super_block *, struct statfs *, int); - [optional] + int (*statfs) (struct super_block *, struct statfs *, int); int (*remount_fs) (struct super_block *, int *, char *); - [optional] + void (*clear_inode) (struct inode *); +}; + +All methods are called without any locks being held, unless otherwise +noted. This means that most methods can block safely. All methods are +only called from a process context (i.e. not from an interrupt handler +or bottom half). + + read_inode: this method is called to read a specific inode from the + mounted filesystem. The "i_ino" member in the "struct inode" + will be initialised by the VFS to indicate which inode to + read. Other members are filled in by this method + + write_inode: this method is called when the VFS needs to write an + inode to disc + + put_inode: called when the VFS inode is removed from the inode + cache. This method is optional + + delete_inode: called when the VFS wants to delete an inode + + notify_change: called when VFS inode attributes are changed. If this + is NULL the VFS falls back to the write_inode() method. This + is called with the kernel lock held + put_super: called when the VFS wishes to free the superblock + (i.e. unmount). This is called with the superblock lock held -struct inode_operations + write_super: called when the VFS superblock needs to be written to + disc. This method is optional + + statfs: called when the VFS needs to get filesystem statistics. This + is called with the kernel lock held + + remount_fs: called when the filesystem is remounted. This is called + with the kernel lock held + + clear_inode: called then the VFS clears the inode. Optional + +The read_inode() method is responsible for filling in the "i_op" +field. This is a pointer to a "struct inode_operations" which +describes the methods that can be performed on individual inodes. + + +struct inode_operations
======================= - struct file_operations * default_file_ops; - [mandatory] - All inode_operations structures must have default_file_ops pointing to - a valid file_operations structure. - - int (*create) (struct inode *,const char *,int,int,struct inode **); - [optional] - - int (*lookup) (struct inode *dir, const char *name, int len, struct inode **result); - [optional] - lookup is called when the VFS wishes to have the filesystem resolve a name - into an inode. Dir is a directory on the filesystem that--we hope--contains - the zero-terminated string name (length len). A return value of zero indicates - that there is a valid inode stored in *result. - -*** Note: lofs assumes that any filesystem returns an inode within the filesystem - for all directory inodes. Therefore, __iget(sb,ino,0) should be used to fetch - the inode in a filesystem's lookup routine. - - int (*link) (struct inode *,struct inode *,const char *,int); - [optional] - int (*unlink) (struct inode *,const char *,int); - [optional] - int (*symlink) (struct inode *,const char *,int,const char *); - [optional] - int (*mkdir) (struct inode *,const char *,int,int); - [optional] - int (*rmdir) (struct inode *,const char *,int); - [optional] - int (*mknod) (struct inode *,const char *,int,int,int); - [optional] - int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int, int); - [optional] - - int (*readlink) (struct inode *inode, char *buf, int len); - [optional] - readlink is called by the VFS to read the contents of a symbolic link. - inode is an inode that meets the S_ISLNK test, and buf points to a buffer - of len bytes. - - int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **); - [optional] - follow_link must be implemented if readlink is implemented. - Note that follow_link can return a different inode than a - lookup_dentry() on the result of readlink() would return. - The proc filesystem, in particular, uses this feature heavily. - For most user filesystems, however, follow_link() and readlink() - should return consistent results. - - int (*readpage) (struct inode *, struct page *); [optional] - int (*writepage) (struct inode *, struct page *); [mandatory with readpage] - - In order for files to be mmap'd, readpage and writepage are required. - A filesystem can use generic_readpage/writepage if it supports the bmap - function. Otherwise, a custom version must be written. +This describes how the VFS can manipulate an inode in your +filesystem. As of kernel 2.1.99, the following members are defined: +struct inode_operations { + struct file_operations * default_file_ops; + int (*create) (struct inode *,struct dentry *,int); + int (*lookup) (struct inode *,struct dentry *); + int (*link) (struct dentry *,struct inode *,struct dentry *); + int (*unlink) (struct inode *,struct dentry *); + int (*symlink) (struct inode *,struct dentry *,const char *); + int (*mkdir) (struct inode *,struct dentry *,int); + int (*rmdir) (struct inode *,struct dentry *); + int (*mknod) (struct inode *,struct dentry *,int,int); + int (*rename) (struct inode *, struct dentry *, + struct inode *, struct dentry *); + int (*readlink) (struct dentry *, char *,int); + struct dentry * (*follow_link) (struct dentry *, struct dentry *); + int (*readpage) (struct file *, struct page *); + int (*writepage) (struct file *, struct page *); int (*bmap) (struct inode *,int); - [optional] void (*truncate) (struct inode *); - [optional] int (*permission) (struct inode *, int); - [optional] int (*smap) (struct inode *,int); - [optional] + int (*updatepage) (struct file *, struct page *, const char *, + unsigned long, unsigned int, int); + int (*revalidate) (struct dentry *); +}; + + default_file_ops: this is a pointer to a "struct file_operations" + which describes how to manipulate open files + + create: called by the open(2) and creat(2) system calls. Only + required if you want to support regular files. The dentry you + get should not have an inode (i.e. it should be a negative + dentry). Here you will probably call d_instantiate() with the + dentry and the newly created inode + + lookup: called when the VFS needs to lookup an inode in a parent + directory. The name to look for is found in the dentry. This + method must call d_add() to insert the found inode into the + dentry. The "i_count" field in the inode structure should be + incremented. If the named inode does not exist a NULL inode + should be inserted into the dentry (this is called a negative + dentry). Returning an error code from this routine must only + be done on a real error, otherwise creating inodes with system + calls like create(2), mknod(2), mkdir(2) and so on will fail. + If you wish to overload the dentry methods then you should + initialise the "d_dop" field in the dentry; this is a pointer + to a struct "dentry_operations". + This method is called with the directory semaphore held + + link: called by the link(2) system call. Only required if you want + to support hard links. You will probably need to call + d_instantiate() just as you would in the create() method + + unlink: called by the unlink(2) system call. Only required if you + want to support deleting inodes + + symlink: called by the symlink(2) system call. Only required if you + want to support symlinks. You will probably need to call + d_instantiate() just as you would in the create() method + + mkdir: called by the mkdir(2) system call. Only required if you want + to support creating subdirectories. You will probably need to + call d_instantiate() just as you would in the create() method + + rmdir: called by the rmdir(2) system call. Only required if you want + to support deleting subdirectories + + mknod: called by the mknod(2) system call to create a device (char, + block) inode or a named pipe (FIFO) or socket. Only required + if you want to support creating these types of inodes. You + will probably need to call d_instantiate() just as you would + in the create() method + + readlink: called by the readlink(2) system call. Only required if + you want to support reading symbolic links + + follow_link: called by the VFS to follow a symbolic link to the + inode it points to. Only required if you want to support + symbolic links + -struct file_operations +struct file_operations
====================== - int (*lseek) (struct inode *, struct file *, off_t, int); - int (*read) (struct inode *, struct file *, char *, int); - int (*write) (struct inode *, struct file *, const char *, int); - int (*readdir) (struct inode *, struct file *, void *, filldir_t); - unsigned int (*poll) (struct file *, poll_table *); +This describes how the VFS can manipulate an open file. As of kernel +2.1.99, the following members are defined: + +struct file_operations { + loff_t (*llseek) (struct file *, loff_t, int); + ssize_t (*read) (struct file *, char *, size_t, loff_t *); + ssize_t (*write) (struct file *, const char *, size_t, loff_t *); + int (*readdir) (struct file *, void *, filldir_t); + unsigned int (*poll) (struct file *, struct poll_table_struct *); int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); - int (*mmap) (struct inode *, struct file *, struct vm_area_struct *); + int (*mmap) (struct file *, struct vm_area_struct *); int (*open) (struct inode *, struct file *); - void (*release) (struct inode *, struct file *); - int (*fsync) (struct inode *, struct file *); - int (*fasync) (struct inode *, struct file *, int); + int (*release) (struct inode *, struct file *); + int (*fsync) (struct file *, struct dentry *); + int (*fasync) (struct file *, int); int (*check_media_change) (kdev_t dev); int (*revalidate) (kdev_t dev); + int (*lock) (struct file *, int, struct file_lock *); +}; + + llseek: called when the VFS needs to move the file position index + + read: called by the read(2) system call + + write: called by the write(2) system call + readdir: called when the VFS needs to read the directory contents + + poll: called by the VFS when a process wants to check if there is + activity on this file and (optionally) go to sleep until there + is activity + + ioctl: called by the ioctl(2) system call + + mmap: called by the mmap(2) system call + + open: called by the VFS when an inode should be opened. When the VFS + opens a file, it creates a new "struct file" and initialises + the "f_op" file operations member with the "default_file_ops" + field in the inode structure. It then calls the open method + for the newly allocated file structure. You might think that + the open method really belongs in "struct inode_operations", + and you may be right. I think it's done the way it is because + it makes filesystems simpler to implement. The open() method + is a good place to initialise the "private_data" member in the + file structure if you want to point to a device structure + + release: called when the last reference to an open file is closed + + fsync: called by the fsync(2) system call + + fasync: called by the fcntl(2) system call when asynchronous + (non-blocking) mode is enabled for a file + +Note that the file operations are implemented by the specific +filesystem in which the inode resides. When opening a device node +(character or block special) most filesystems will call special +support routines in the VFS which will locate the required device +driver information. These support routines replace the filesystem file +operations with those for the device driver, and then proceed to call +the new open() method for the file. This is how opening a device file +in the filesystem eventually ends up calling the device driver open() +method. Note the devfs (the Device FileSystem) has a more direct path +from device node to device driver (this is an unofficial kernel +patch). + + +struct dentry_operations
+======================== + +This describes how a filesystem can overload the standard dentry +operations. Dentries and the dcache are the domain of the VFS and the +individual filesystem implementations. Device drivers have no business +here. As of kernel 2.1.99, the following members are defined: + +struct dentry_operations { + int (*d_revalidate)(struct dentry *); + int (*d_hash) (struct dentry *, struct qstr *); + int (*d_compare) (struct dentry *, struct qstr *, struct qstr *); + void (*d_delete)(struct dentry *); + void (*d_release)(struct dentry *); + void (*d_iput)(struct dentry *, struct inode *); +}; + + d_revalidate: called when the VFS needs to revalidate a dentry + + d_hash: called when the VFS adds a dentry to the hash table + + d_compare: called when a dentry should be compared with another + + d_delete: called when the last reference to a dentry is + deleted. This means no-one is using the dentry, however it is + still valid and in the dcache + + d_release: called when a dentry is deallocated + + d_iput: called when a dentry looses its inode (just prior to its + being deallocated). The default when this is NULL is that the + VFS calls iput(). If you define this method, you must call + iput() yourself + +Each dentry has a pointer to its parent dentry, as well as a hash list +of child dentries. Child dentries are basically like files in a +directory. + +There are a number of functions defined which permit a filesystem to +manipulate dentries: + + dget: open a new handle for an existing dentry (this just increments + the usage count) + + dput: close a handle for a dentry (decrements the usage count). If + the usage count drops to 0, the "d_delete" method is called + and the dentry is placed on the unused list if the dentry is + still in its parents hash list. Putting the dentry on the + unused list just means that if the system needs some RAM, it + goes through the unused list of dentries and deallocates them. + If the dentry has already been unhashed and the usage count + drops to 0, in this case the dentry is deallocated after the + "d_delete" method is called + + d_drop: this unhashes a dentry from its parents hash list. A + subsequent call to dput() will dellocate the dentry if its + usage count drops to 0 + + d_delete: delete a dentry. If there are no other open references to + the dentry then the dentry is turned into a negative dentry + (the d_iput() method is called). If there are other + references, then d_drop() is called instead + + d_add: add a dentry to its parents hash list and then calls + d_instantiate() + + d_instantiate: add a dentry to the alias hash list for the inode and + updates the "d_inode" member. The "i_count" member in the + inode structure should be set/incremented. If the inode + pointer is NULL, the dentry is called a "negative + dentry". This function is commonly called when an inode is + created for an existing negative dentry diff -u --recursive --new-file v2.1.107/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.107/linux/MAINTAINERS Tue Jun 23 10:01:19 1998 +++ linux/MAINTAINERS Sun Jun 28 16:00:41 1998 @@ -509,10 +509,8 @@ S: Maintained SCSI SUBSYSTEM -P: Leonard N. Zubkoff -M: Leonard N. Zubkoff L: linux-scsi@vger.rutgers.edu -S: Maintained +S: Unmaintained SCSI TAPE DRIVER P: Kai Mdkisara diff -u --recursive --new-file v2.1.107/linux/Makefile linux/Makefile --- v2.1.107/linux/Makefile Wed Jun 24 22:54:02 1998 +++ linux/Makefile Wed Jun 24 22:27:38 1998 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 107 +SUBLEVEL = 108 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/ -e s/arm.*/arm/ -e s/sa110/arm/) diff -u --recursive --new-file v2.1.107/linux/arch/alpha/config.in linux/arch/alpha/config.in --- v2.1.107/linux/arch/alpha/config.in Wed Jun 24 22:54:02 1998 +++ linux/arch/alpha/config.in Sun Jun 28 00:56:39 1998 @@ -4,15 +4,6 @@ # mainmenu_name "Kernel configuration of Linux for Alpha machines" -# clear all implied options (don't want default values for those): -unset CONFIG_CROSSCOMPILE CONFIG_NATIVE -unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 -unset CONFIG_PCI CONFIG_ALPHA_EISA -unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA -unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS -unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA -unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION - mainmenu_option next_comment comment 'Code maturity level options' bool 'Prompt for development and/or incomplete code/drivers' CONFIG_EXPERIMENTAL @@ -31,6 +22,8 @@ mainmenu_option next_comment comment 'General setup' +unset CONFIG_CROSSCOMPILE CONFIG_NATIVE + if [ "`uname`" != "Linux" ]; then define_bool CONFIG_CROSSCOMPILE y else @@ -62,6 +55,14 @@ AlphaBook1 CONFIG_ALPHA_BOOK1 \ Ruffian CONFIG_ALPHA_RUFFIAN \ Platform2000 CONFIG_ALPHA_P2K" Cabriolet + +# clear all implied options (don't want default values for those): +unset CONFIG_ALPHA_EV4 CONFIG_ALPHA_EV5 CONFIG_ALPHA_EV6 +unset CONFIG_PCI CONFIG_ALPHA_EISA +unset CONFIG_ALPHA_LCA CONFIG_ALPHA_APECS CONFIG_ALPHA_CIA +unset CONFIG_ALPHA_T2 CONFIG_ALPHA_PYXIS +unset CONFIG_ALPHA_TSUNAMI CONFIG_ALPHA_MCPCIA +unset CONFIG_ALPHA_NEED_ROUNDING_EMULATION if [ "$CONFIG_ALPHA_BOOK1" = "y" ] then diff -u --recursive --new-file v2.1.107/linux/arch/alpha/kernel/setup.c linux/arch/alpha/kernel/setup.c --- v2.1.107/linux/arch/alpha/kernel/setup.c Wed Jun 24 22:54:03 1998 +++ linux/arch/alpha/kernel/setup.c Sat Jun 27 10:42:46 1998 @@ -388,11 +388,11 @@ &systype_name, &sysvariation_name); return sprintf(buffer, - "CPU\t\t\t: Alpha\n" - "CPU model\t\t: %s\n" - "CPU variation\t\t: %ld\n" - "CPU revision\t\t: %ld\n" - "CPU serial number\t: %s\n" + "cpu\t\t\t: Alpha\n" + "cpu model\t\t: %s\n" + "cpu variation\t\t: %ld\n" + "cpu revision\t\t: %ld\n" + "cpu serial number\t: %s\n" "system type\t\t: %s\n" "system variation\t: %s\n" "system revision\t\t: %ld\n" diff -u --recursive --new-file v2.1.107/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- v2.1.107/linux/arch/i386/kernel/bios32.c Sun Jun 7 11:16:27 1998 +++ linux/arch/i386/kernel/bios32.c Tue Jun 30 23:58:15 1998 @@ -1,7 +1,7 @@ /* * bios32.c - Low-Level PCI Access * - * $Id: bios32.c,v 1.33 1998/05/12 07:30:11 mj Exp $ + * $Id: bios32.c,v 1.37 1998/06/19 17:11:37 mj Exp $ * * Copyright 1993, 1994 Drew Eckhardt * Visionary Computing @@ -62,6 +62,9 @@ * Feb 6, 1998 : No longer using BIOS to find devices and device classes. [mj] * * May 1, 1998 : Support for peer host bridges. [mj] + * + * Jun 19, 1998 : Changed to use spinlocks, so that PCI configuration space + * can be accessed from interrupts even on SMP systems. [mj] */ #include @@ -71,16 +74,15 @@ #include #include #include +#include #include #include #include #include - -#include #include -#include #include +#include #include "irq.h" @@ -93,6 +95,13 @@ #endif /* + * This interrupt-safe spinlock protects all accesses to PCI + * configuration space. + */ + +spinlock_t pci_lock = SPIN_LOCK_UNLOCKED; + +/* * Generic PCI access -- indirect calls according to detected HW. */ @@ -128,41 +137,28 @@ return access_pci->pci_present; } -int pcibios_read_config_byte (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned char *value) -{ - return access_pci->read_config_byte(bus, device_fn, where, value); -} - -int pcibios_read_config_word (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned short *value) -{ - return access_pci->read_config_word(bus, device_fn, where, value); -} - -int pcibios_read_config_dword (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned int *value) -{ - return access_pci->read_config_dword(bus, device_fn, where, value); -} - -int pcibios_write_config_byte (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned char value) -{ - return access_pci->write_config_byte(bus, device_fn, where, value); -} - -int pcibios_write_config_word (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned short value) -{ - return access_pci->write_config_word(bus, device_fn, where, value); -} - -int pcibios_write_config_dword (unsigned char bus, - unsigned char device_fn, unsigned char where, unsigned int value) -{ - return access_pci->write_config_dword(bus, device_fn, where, value); -} +#define PCI_byte_BAD 0 +#define PCI_word_BAD (pos & 1) +#define PCI_dword_BAD (pos & 3) + +#define PCI_STUB(rw,size,type) \ +int pcibios_##rw##_config_##size (u8 bus, u8 dfn, u8 pos, type value) \ +{ \ + int res; \ + unsigned long flags; \ + if (PCI_##size##_BAD) return PCIBIOS_BAD_REGISTER_NUMBER; \ + spin_lock_irqsave(&pci_lock, flags); \ + res = access_pci->rw##_config_##size(bus, dfn, pos, value); \ + spin_unlock_irqrestore(&pci_lock, flags); \ + return res; \ +} + +PCI_STUB(read, byte, u8 *) +PCI_STUB(read, word, u16 *) +PCI_STUB(read, dword, u32 *) +PCI_STUB(write, byte, u8) +PCI_STUB(write, word, u16) +PCI_STUB(write, dword, u32) #define PCI_PROBE_BIOS 1 #define PCI_PROBE_CONF1 2 @@ -187,76 +183,48 @@ static int pci_conf1_read_config_byte(unsigned char bus, unsigned char device_fn, unsigned char where, unsigned char *value) { - unsigned long flags; - - save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inb(0xCFC + (where&3)); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } static int pci_conf1_read_config_word (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned short *value) { - unsigned long flags; - - if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER; - save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inw(0xCFC + (where&2)); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } static int pci_conf1_read_config_dword (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned int *value) { - unsigned long flags; - - if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; - save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inl(0xCFC); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } static int pci_conf1_write_config_byte (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned char value) { - unsigned long flags; - - save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outb(value, 0xCFC + (where&3)); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } static int pci_conf1_write_config_word (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned short value) { - unsigned long flags; - - if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER; - save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outw(value, 0xCFC + (where&2)); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } static int pci_conf1_write_config_dword (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned int value) { - unsigned long flags; - - if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; - save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outl(value, 0xCFC); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } @@ -282,90 +250,72 @@ static int pci_conf2_read_config_byte(unsigned char bus, unsigned char device_fn, unsigned char where, unsigned char *value) { - unsigned long flags; - if (device_fn & 0x80) return PCIBIOS_DEVICE_NOT_FOUND; - save_flags(flags); cli(); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); *value = inb(IOADDR(device_fn,where)); outb (0, 0xCF8); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } static int pci_conf2_read_config_word (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned short *value) { - unsigned long flags; - if (device_fn & 0x80) return PCIBIOS_DEVICE_NOT_FOUND; - save_flags(flags); cli(); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); *value = inw(IOADDR(device_fn,where)); outb (0, 0xCF8); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } static int pci_conf2_read_config_dword (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned int *value) { - unsigned long flags; - if (device_fn & 0x80) return PCIBIOS_DEVICE_NOT_FOUND; - save_flags(flags); cli(); outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); *value = inl (IOADDR(device_fn,where)); outb (0, 0xCF8); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } static int pci_conf2_write_config_byte (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned char value) { - unsigned long flags; - - save_flags(flags); cli(); + if (device_fn & 0x80) + return PCIBIOS_DEVICE_NOT_FOUND; outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); outb (value, IOADDR(device_fn,where)); outb (0, 0xCF8); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } static int pci_conf2_write_config_word (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned short value) { - unsigned long flags; - - save_flags(flags); cli(); + if (device_fn & 0x80) + return PCIBIOS_DEVICE_NOT_FOUND; outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); outw (value, IOADDR(device_fn,where)); outb (0, 0xCF8); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } static int pci_conf2_write_config_dword (unsigned char bus, unsigned char device_fn, unsigned char where, unsigned int value) { - unsigned long flags; - - save_flags(flags); cli(); + if (device_fn & 0x80) + return PCIBIOS_DEVICE_NOT_FOUND; outb (FUNC(device_fn), 0xCF8); outb (bus, 0xCFA); outl (value, IOADDR(device_fn,where)); outb (0, 0xCF8); - restore_flags(flags); return PCIBIOS_SUCCESSFUL; } @@ -387,7 +337,7 @@ unsigned int tmp; unsigned long flags; - save_flags(flags); cli(); + __save_flags(flags); __cli(); /* * Check if configuration type 1 works. @@ -398,7 +348,7 @@ outl (0x80000000, 0xCF8); if (inl (0xCF8) == 0x80000000) { outl (tmp, 0xCF8); - restore_flags(flags); + __restore_flags(flags); printk("PCI: Using configuration type 1\n"); return &pci_direct_conf1; } @@ -413,13 +363,13 @@ outb (0x00, 0xCF8); outb (0x00, 0xCFA); if (inb (0xCF8) == 0x00 && inb (0xCFA) == 0x00) { - restore_flags(flags); + __restore_flags(flags); printk("PCI: Using configuration type 2\n"); return &pci_direct_conf2; } } - restore_flags(flags); + __restore_flags(flags); return NULL; } @@ -504,7 +454,7 @@ unsigned long entry; /* %edx */ unsigned long flags; - save_flags(flags); cli(); + spin_lock_irqsave(&pci_lock, flags); __asm__("lcall (%%edi)" : "=a" (return_code), "=b" (address), @@ -513,7 +463,7 @@ : "0" (service), "1" (0), "D" (&bios32_indirect)); - restore_flags(flags); + spin_unlock_irqrestore(&pci_lock, flags); switch (return_code) { case 0: @@ -542,8 +492,8 @@ if ((pcibios_entry = bios32_service(PCI_SERVICE))) { pci_indirect.address = pcibios_entry + PAGE_OFFSET; - save_flags(flags); cli(); - __asm__ __volatile__( + __save_flags(flags); __cli(); + __asm__( "lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -555,7 +505,7 @@ : "1" (PCIBIOS_PCI_BIOS_PRESENT), "D" (&pci_indirect) : "memory"); - restore_flags(flags); + __restore_flags(flags); status = (eax >> 8) & 0xff; hw_mech = eax & 0xff; @@ -589,9 +539,7 @@ { unsigned long bx; unsigned long ret; - unsigned long flags; - save_flags(flags); cli(); __asm__ ("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -602,7 +550,6 @@ "c" (class_code), "S" ((int) index), "D" (&pci_indirect)); - restore_flags(flags); *bus = (bx >> 8) & 0xff; *device_fn = bx & 0xff; return (int) (ret & 0xff00) >> 8; @@ -615,9 +562,7 @@ { unsigned short bx; unsigned short ret; - unsigned long flags; - save_flags(flags); cli(); __asm__("lcall (%%edi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -629,7 +574,6 @@ "d" (vendor), "S" ((int) index), "D" (&pci_indirect)); - restore_flags(flags); *bus = (bx >> 8) & 0xff; *device_fn = bx & 0xff; return (int) (ret & 0xff00) >> 8; @@ -640,9 +584,7 @@ { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -653,7 +595,6 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); - restore_flags(flags); return (int) (ret & 0xff00) >> 8; } @@ -662,9 +603,7 @@ { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -675,7 +614,6 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); - restore_flags(flags); return (int) (ret & 0xff00) >> 8; } @@ -684,9 +622,7 @@ { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -697,7 +633,6 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); - restore_flags(flags); return (int) (ret & 0xff00) >> 8; } @@ -706,9 +641,7 @@ { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -719,7 +652,6 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); - restore_flags(flags); return (int) (ret & 0xff00) >> 8; } @@ -728,9 +660,7 @@ { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -741,7 +671,6 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); - restore_flags(flags); return (int) (ret & 0xff00) >> 8; } @@ -750,9 +679,7 @@ { unsigned long ret; unsigned long bx = (bus << 8) | device_fn; - unsigned long flags; - save_flags(flags); cli(); __asm__("lcall (%%esi)\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" @@ -763,7 +690,6 @@ "b" (bx), "D" ((long) where), "S" (&pci_indirect)); - restore_flags(flags); return (int) (ret & 0xff00) >> 8; } @@ -860,8 +786,14 @@ break; } } - if (!d) + if (!d) { printk("PCI: BIOS reporting unknown device %02x:%02x\n", bus, devfn); + /* + * We must not continue scanning as several buggy BIOSes + * return garbage after the last device. Grr. + */ + break; + } } if (!idx) { printk("PCI: Device %02x:%02x not found by BIOS\n", diff -u --recursive --new-file v2.1.107/linux/arch/i386/kernel/entry.S linux/arch/i386/kernel/entry.S --- v2.1.107/linux/arch/i386/kernel/entry.S Tue Jun 23 10:01:19 1998 +++ linux/arch/i386/kernel/entry.S Fri Jun 26 02:28:38 1998 @@ -547,7 +547,8 @@ .long SYMBOL_NAME(sys_capget) .long SYMBOL_NAME(sys_capset) /* 185 */ .long SYMBOL_NAME(sys_sigaltstack) + .long SYMBOL_NAME(sys_sendfile) - .rept NR_syscalls-186 + .rept NR_syscalls-187 .long SYMBOL_NAME(sys_ni_syscall) .endr diff -u --recursive --new-file v2.1.107/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.1.107/linux/arch/i386/kernel/setup.c Wed Jun 24 22:54:03 1998 +++ linux/arch/i386/kernel/setup.c Thu Jun 25 11:01:17 1998 @@ -466,7 +466,7 @@ continue; #endif p += sprintf(p, "processor\t: %d\n" - "CPU family\t: %c\n" + "cpu family\t: %c\n" "model\t\t: %s\n" "vendor_id\t: %s\n", n, @@ -512,9 +512,9 @@ "hlt_bug\t\t: %s\n" "sep_bug\t\t: %s\n" "f00f_bug\t: %s\n" - "FPU\t\t: %s\n" - "FPU_exception\t: %s\n" - "CPUID level\t: %d\n" + "fpu\t\t: %s\n" + "fpu_exception\t: %s\n" + "cpuid level\t: %d\n" "wp\t\t: %s\n" "flags\t\t:", c->fdiv_bug ? "yes" : "no", diff -u --recursive --new-file v2.1.107/linux/arch/m68k/hp300/ints.c linux/arch/m68k/hp300/ints.c --- v2.1.107/linux/arch/m68k/hp300/ints.c Tue Jun 23 10:01:20 1998 +++ linux/arch/m68k/hp300/ints.c Thu Jun 25 11:03:42 1998 @@ -8,7 +8,6 @@ * moment everything difficult is handled by the generic code. */ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/arch/m68k/hp300/time.c linux/arch/m68k/hp300/time.c --- v2.1.107/linux/arch/m68k/hp300/time.c Tue Jun 23 10:01:20 1998 +++ linux/arch/m68k/hp300/time.c Thu Jun 25 11:03:42 1998 @@ -6,7 +6,6 @@ * This file contains the HP300-specific time handling code. */ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/arch/m68k/kernel/m68k_ksyms.c linux/arch/m68k/kernel/m68k_ksyms.c --- v2.1.107/linux/arch/m68k/kernel/m68k_ksyms.c Tue Jun 23 10:01:21 1998 +++ linux/arch/m68k/kernel/m68k_ksyms.c Thu Jun 25 11:03:42 1998 @@ -1,4 +1,3 @@ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/arch/m68k/mac/macints.c linux/arch/m68k/mac/macints.c --- v2.1.107/linux/arch/m68k/mac/macints.c Tue Jun 23 10:01:21 1998 +++ linux/arch/m68k/mac/macints.c Thu Jun 25 11:03:42 1998 @@ -69,6 +69,7 @@ * - */ +#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/arch/m68k/mac/via6522.c linux/arch/m68k/mac/via6522.c --- v2.1.107/linux/arch/m68k/mac/via6522.c Tue Jun 23 10:01:21 1998 +++ linux/arch/m68k/mac/via6522.c Thu Jun 25 11:03:42 1998 @@ -5,7 +5,6 @@ * via them as are assorted bits and bobs - eg rtc, adb. */ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/arch/ppc/chrp_defconfig linux/arch/ppc/chrp_defconfig --- v2.1.107/linux/arch/ppc/chrp_defconfig Fri May 8 23:14:44 1998 +++ linux/arch/ppc/chrp_defconfig Thu Jun 25 11:04:25 1998 @@ -21,7 +21,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_MODULES=y # CONFIG_MODVERSIONS is not set -CONFIG_KERNELD=y +CONFIG_KMOD=y CONFIG_PCI=y CONFIG_PCI_OLD_PROC=y CONFIG_NET=y diff -u --recursive --new-file v2.1.107/linux/arch/ppc/common_defconfig linux/arch/ppc/common_defconfig --- v2.1.107/linux/arch/ppc/common_defconfig Fri May 8 23:14:44 1998 +++ linux/arch/ppc/common_defconfig Thu Jun 25 11:04:25 1998 @@ -20,7 +20,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_MODULES=y CONFIG_MODVERSIONS=y -CONFIG_KERNELD=y +CONFIG_KMOD=y CONFIG_PCI=y CONFIG_PCI_OLD_PROC=y CONFIG_NET=y diff -u --recursive --new-file v2.1.107/linux/arch/ppc/prep_defconfig linux/arch/ppc/prep_defconfig --- v2.1.107/linux/arch/ppc/prep_defconfig Fri May 8 23:14:45 1998 +++ linux/arch/ppc/prep_defconfig Thu Jun 25 11:04:25 1998 @@ -21,7 +21,7 @@ CONFIG_EXPERIMENTAL=y CONFIG_MODULES=y CONFIG_MODVERSIONS=y -CONFIG_KERNELD=y +CONFIG_KMOD=y CONFIG_PCI=y # CONFIG_PCI_OPTIMIZE is not set CONFIG_PCI_OLD_PROC=y diff -u --recursive --new-file v2.1.107/linux/drivers/block/Config.in linux/drivers/block/Config.in --- v2.1.107/linux/drivers/block/Config.in Wed Jun 24 22:54:04 1998 +++ linux/drivers/block/Config.in Tue Jun 30 12:27:48 1998 @@ -16,7 +16,7 @@ dep_tristate ' Include IDE/ATAPI TAPE support' CONFIG_BLK_DEV_IDETAPE $CONFIG_BLK_DEV_IDE dep_tristate ' Include IDE/ATAPI FLOPPY support' CONFIG_BLK_DEV_IDEFLOPPY $CONFIG_BLK_DEV_IDE dep_tristate ' SCSI emulation support' CONFIG_BLK_DEV_IDESCSI $CONFIG_BLK_DEV_IDE - if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then + if [ "$CONFIG_BLK_DEV_IDE" != "n" ]; then bool ' CMD640 chipset bugfix/support' CONFIG_BLK_DEV_CMD640 if [ "$CONFIG_BLK_DEV_CMD640" = "y" ]; then bool ' CMD640 enhanced support' CONFIG_BLK_DEV_CMD640_ENHANCED @@ -48,7 +48,9 @@ bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 bool ' UMC-8672 support' CONFIG_BLK_DEV_UMC8672 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + if [ "$CONFIG_BLK_DEV_IDE" = "y" ]; then bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PDC4030 + fi fi fi fi diff -u --recursive --new-file v2.1.107/linux/drivers/block/Makefile linux/drivers/block/Makefile --- v2.1.107/linux/drivers/block/Makefile Fri May 8 23:14:47 1998 +++ linux/drivers/block/Makefile Tue Jun 30 12:27:48 1998 @@ -98,85 +98,86 @@ L_OBJS += hd.o endif -ifeq ($(CONFIG_BLK_DEV_IDE),y) - LX_OBJS += ide.o - ifeq ($(CONFIG_PROC_FS),y) - L_OBJS += ide-proc.o - endif - L_OBJS += ide-probe.o -else - ifeq ($(CONFIG_BLK_DEV_IDE),m) - MIX_OBJS += ide.o - # ide-mod includes ide-proc - M_OBJS += ide-mod.o - MX_OBJS += ide-probe.o - endif -endif - ifeq ($(CONFIG_BLK_DEV_RZ1000),y) -L_OBJS += rz1000.o +IDE_OBJS += rz1000.o endif ifeq ($(CONFIG_BLK_DEV_CMD640),y) -L_OBJS += cmd640.o +IDE_OBJS += cmd640.o endif ifeq ($(CONFIG_BLK_DEV_IDEPCI),y) -L_OBJS += ide-pci.o +IDE_OBJS += ide-pci.o endif ifeq ($(CONFIG_BLK_DEV_IDEDMA),y) -L_OBJS += ide-dma.o -endif - -ifeq ($(CONFIG_BLK_DEV_PS2),y) -L_OBJS += ps2esdi.o +IDE_OBJS += ide-dma.o endif ifeq ($(CONFIG_BLK_DEV_DTC2278),y) -L_OBJS += dtc2278.o +IDE_OBJS += dtc2278.o endif ifeq ($(CONFIG_BLK_DEV_HT6560B),y) -L_OBJS += ht6560b.o +IDE_OBJS += ht6560b.o endif ifeq ($(CONFIG_BLK_DEV_QD6580),y) -L_OBJS += qd6580.o +IDE_OBJS += qd6580.o endif ifeq ($(CONFIG_BLK_DEV_UMC8672),y) -L_OBJS += umc8672.o +IDE_OBJS += umc8672.o endif ifeq ($(CONFIG_BLK_DEV_ALI14XX),y) -L_OBJS += ali14xx.o +IDE_OBJS += ali14xx.o endif ifeq ($(CONFIG_BLK_DEV_PDC4030),y) -L_OBJS += pdc4030.o +IDE_OBJS += pdc4030.o endif ifeq ($(CONFIG_BLK_DEV_TRM290),y) -L_OBJS += trm290.o +IDE_OBJS += trm290.o endif ifeq ($(CONFIG_BLK_DEV_OPTI621),y) -L_OBJS += opti621.o +IDE_OBJS += opti621.o endif ifeq ($(CONFIG_BLK_DEV_NS87415),y) -L_OBJS += ns87415.o +IDE_OBJS += ns87415.o endif ifeq ($(CONFIG_BLK_DEV_CMD646),y) -L_OBJS += cmd646.o +IDE_OBJS += cmd646.o endif ifeq ($(CONFIG_BLK_DEV_SL82C105),y) -L_OBJS += sl82c105.o +IDE_OBJS += sl82c105.o endif +### if CONFIG_BLK_DEV_IDE is n, IDE_OBJS will be ignored + +ifeq ($(CONFIG_PROC_FS),y) +IDE_OBJS += ide-proc.o +endif + +###Collect + +ifeq ($(CONFIG_BLK_DEV_IDE),y) + LX_OBJS += ide.o + L_OBJS += ide-probe.o $(IDE_OBJS) +else + ifeq ($(CONFIG_BLK_DEV_IDE),m) + MIX_OBJS += ide.o $(IDE_OBJS) + M_OBJS += ide-mod.o ide-probe.o + endif +endif + +############ + ifeq ($(CONFIG_BLK_DEV_IDEDISK),y) L_OBJS += ide-disk.o else @@ -209,6 +210,10 @@ endif endif +ifeq ($(CONFIG_BLK_DEV_PS2),y) +L_OBJS += ps2esdi.o +endif + ifeq ($(CONFIG_BLK_DEV_XD),y) L_OBJS += xd.o else @@ -273,5 +278,5 @@ include $(TOPDIR)/Rules.make -ide-mod.o: ide.o ide-proc.o - $(LD) $(LD_RFLAG) -r -o $@ ide.o ide-proc.o +ide-mod.o: ide.o $(IDE_OBJS) + $(LD) $(LD_RFLAG) -r -o $@ ide.o $(IDE_OBJS) diff -u --recursive --new-file v2.1.107/linux/drivers/block/ide.c linux/drivers/block/ide.c --- v2.1.107/linux/drivers/block/ide.c Wed May 20 19:10:38 1998 +++ linux/drivers/block/ide.c Tue Jun 30 12:27:48 1998 @@ -1,5 +1,5 @@ /* - * linux/drivers/block/ide.c Version 6.13 March 29, 1998 + * linux/drivers/block/ide.c Version 6.17 March 29, 1998 * * Copyright (C) 1994-1998 Linus Torvalds & authors (see below) */ @@ -88,6 +88,7 @@ * Version 6.14 fixed IRQ sharing among PCI devices * Version 6.15 added SMP awareness to IDE drivers * Version 6.16 fixed various bugs; even more SMP friendly + * Version 6.17 fix for newest EZ-Drive problem * * Some additional driver compile-time options are in ide.h * @@ -2560,7 +2561,7 @@ printk("%s ", msg); - if (xparm == -1 && drive->bios_cyl < 1024) + if (xparm == -1 && (drive->bios_cyl * drive->bios_head * drive->bios_sect) < (1024 * 16 * 63)) return 0; /* small disk: no translation needed */ if (drive->id) { diff -u --recursive --new-file v2.1.107/linux/drivers/char/conmakehash.c linux/drivers/char/conmakehash.c --- v2.1.107/linux/drivers/char/conmakehash.c Thu Feb 12 20:56:05 1998 +++ linux/drivers/char/conmakehash.c Thu Jun 25 12:24:28 1998 @@ -52,7 +52,6 @@ void addpair(int fp, int un) { int i; - unicode hu; if ( un <= 0xfffe ) { diff -u --recursive --new-file v2.1.107/linux/drivers/char/fbmem.c linux/drivers/char/fbmem.c --- v2.1.107/linux/drivers/char/fbmem.c Wed Jun 24 22:54:05 1998 +++ linux/drivers/char/fbmem.c Thu Jun 25 11:04:25 1998 @@ -23,8 +23,8 @@ #ifdef CONFIG_PROC_FS #include #endif -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif #ifdef __mc68000__ @@ -262,7 +262,7 @@ } } -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD static void try_to_load(int fb) { char modname[16]; @@ -337,7 +337,7 @@ return -EINVAL; if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) return -EINVAL; -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (!registered_fb[con2fb.framebuffer]) try_to_load(con2fb.framebuffer); #endif @@ -419,7 +419,7 @@ int fbidx = GET_FB_IDX(inode->i_rdev); struct fb_info *info; -#ifdef CONFIG_KERNELD +#ifdef CONFIG_KMOD if (!(info = registered_fb[fbidx])) try_to_load(fbidx); #endif diff -u --recursive --new-file v2.1.107/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.107/linux/drivers/char/lp.c Tue Jun 9 11:57:29 1998 +++ linux/drivers/char/lp.c Sat Jun 27 10:13:17 1998 @@ -74,9 +74,9 @@ * BUSY _________ _______ * |____________| * - * I discovered this using the printer scanner: + * I discovered this using the printer scanner that you can find at: * - * http://www.cs.unibo.it/~arcangel/pscan/pscan-0.4.tar.gz + * ftp://e-mind.com/pub/linux/pscan/ * * 11 May 98, Andrea Arcangeli */ @@ -326,8 +326,7 @@ lp_table[minor].irq_detected = 0; lp_table[minor].irq_missed = 0; - if (!LP_POLLED(minor)) - w_ctr(minor, LP_PSELECP | LP_PINITP | LP_PINTEN); + w_ctr(minor, LP_PSELECP | LP_PINITP); do { bytes_written = 0; @@ -335,7 +334,7 @@ if (copy_from_user(lp->lp_buffer, buf, copy_size)) { - w_ctr(minor, LP_PINITP); + w_ctr(minor, LP_PSELECP | LP_PINITP); return -EFAULT; } @@ -357,7 +356,7 @@ if (signal_pending(current)) { - w_ctr(minor, LP_PINITP); + w_ctr(minor, LP_PSELECP | LP_PINITP); if (total_bytes_written + bytes_written) return total_bytes_written + bytes_written; else @@ -370,7 +369,7 @@ if (lp_check_status(minor)) { - w_ctr(minor, LP_PINITP); + w_ctr(minor, LP_PSELECP | LP_PINITP); return rc ? rc : -EIO; } @@ -414,7 +413,7 @@ } while (count > 0); - w_ctr(minor, LP_PINITP); + w_ctr(minor, LP_PSELECP | LP_PINITP); return total_bytes_written; } diff -u --recursive --new-file v2.1.107/linux/drivers/char/serial.c linux/drivers/char/serial.c --- v2.1.107/linux/drivers/char/serial.c Sun Jun 7 11:16:30 1998 +++ linux/drivers/char/serial.c Tue Jun 30 22:27:48 1998 @@ -62,7 +62,7 @@ * ever possible. */ -#define SERIAL_PARANOIA_CHECK +#undef SERIAL_PARANOIA_CHECK #define CONFIG_SERIAL_NOPAUSE_IO #define SERIAL_DO_RESTART @@ -1661,11 +1661,15 @@ if ((new_serial.irq >= NR_IRQS) || (new_serial.port > 0xffff) || (new_serial.type < PORT_UNKNOWN) || - (new_serial.type > PORT_MAX) || - (new_serial.xmit_fifo_size == 0)) { + (new_serial.type > PORT_MAX)) { return -EINVAL; } + if ((new_serial.type != state->type) || + (new_serial.xmit_fifo_size <= 0)) + new_serial.xmit_fifo_size = + uart_config[state->type].dfl_xmit_fifo_size; + /* Make sure address is not already in use */ if (new_serial.type) { for (i = 0 ; i < NR_PORTS; i++) @@ -1714,9 +1718,6 @@ check_and_exit: if (!state->port || !state->type) return 0; - if (state->type != old_state.type) - info->xmit_fifo_size = state->xmit_fifo_size = - uart_config[state->type].dfl_xmit_fifo_size; if (state->flags & ASYNC_INITIALIZED) { if (((old_state.flags & ASYNC_SPD_MASK) != (state->flags & ASYNC_SPD_MASK)) || @@ -2566,12 +2567,15 @@ int retval, line; unsigned long page; + MOD_INC_USE_COUNT; line = MINOR(tty->device) - tty->driver.minor_start; if ((line < 0) || (line >= NR_PORTS)) return -ENODEV; retval = get_async_struct(line, &info); if (retval) return retval; + tty->driver_data = info; + info->tty = tty; if (serial_paranoia_check(info, tty->device, "rs_open")) return -ENODEV; @@ -2579,8 +2583,6 @@ printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, info->state->count); #endif - tty->driver_data = info; - info->tty = tty; info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0; if (!tmp_buf) { @@ -2615,7 +2617,6 @@ if (retval) return retval; - MOD_INC_USE_COUNT; retval = block_til_ready(tty, filp, info); if (retval) { #ifdef SERIAL_DEBUG_OPEN diff -u --recursive --new-file v2.1.107/linux/drivers/char/vc_screen.c linux/drivers/char/vc_screen.c --- v2.1.107/linux/drivers/char/vc_screen.c Wed Jun 24 22:54:05 1998 +++ linux/drivers/char/vc_screen.c Thu Jun 25 11:03:42 1998 @@ -20,8 +20,6 @@ * - making it shorter - scr_readw are macros which expand in PRETTY long code */ -#include - #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/macintosh/chips.c linux/drivers/macintosh/chips.c --- v2.1.107/linux/drivers/macintosh/chips.c Wed Jun 24 22:54:05 1998 +++ linux/drivers/macintosh/chips.c Thu Jun 25 11:03:42 1998 @@ -8,7 +8,6 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/net/7990.c linux/drivers/net/7990.c --- v2.1.107/linux/drivers/net/7990.c Tue Jun 23 10:01:23 1998 +++ linux/drivers/net/7990.c Thu Jun 25 11:03:42 1998 @@ -12,9 +12,7 @@ * most of a2025 and sunlance with the aim of merging them, so the * common code was pretty obvious. */ -#include #include - #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/net/hamradio/baycom_epp.c linux/drivers/net/hamradio/baycom_epp.c --- v2.1.107/linux/drivers/net/hamradio/baycom_epp.c Tue Jun 9 11:57:29 1998 +++ linux/drivers/net/hamradio/baycom_epp.c Thu Jun 25 11:03:42 1998 @@ -35,6 +35,7 @@ /*****************************************************************************/ +#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/net/hamradio/soundmodem/gentbl.c linux/drivers/net/hamradio/soundmodem/gentbl.c --- v2.1.107/linux/drivers/net/hamradio/soundmodem/gentbl.c Wed Apr 8 19:36:27 1998 +++ linux/drivers/net/hamradio/soundmodem/gentbl.c Thu Jun 25 12:25:16 1998 @@ -438,7 +438,7 @@ { int i, j, k, l; float s; - float c[40]; + float c[44]; float min, max; fprintf(f, "\n/*\n * hapn4800 specific tables\n */\n\n"); diff -u --recursive --new-file v2.1.107/linux/drivers/net/hplance.c linux/drivers/net/hplance.c --- v2.1.107/linux/drivers/net/hplance.c Tue Jun 23 10:01:23 1998 +++ linux/drivers/net/hplance.c Thu Jun 25 11:03:42 1998 @@ -5,9 +5,7 @@ * Uses the generic 7990.c LANCE code. */ -#include #include - #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/net/sktr.c linux/drivers/net/sktr.c --- v2.1.107/linux/drivers/net/sktr.c Wed Jun 24 22:54:07 1998 +++ linux/drivers/net/sktr.c Thu Jun 25 11:03:43 1998 @@ -42,7 +42,6 @@ static const char *version = "sktr.c: v1.01 08/29/97 by Christoph Goos\n"; -#include #ifdef MODULE #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/ChangeLog.ncr53c8xx linux/drivers/scsi/ChangeLog.ncr53c8xx --- v2.1.107/linux/drivers/scsi/ChangeLog.ncr53c8xx Sun Jun 7 11:16:33 1998 +++ linux/drivers/scsi/ChangeLog.ncr53c8xx Tue Jun 30 22:37:53 1998 @@ -1,5 +1,174 @@ -Fri Jan 2 18:00 1998 Gerard Roudier (groudier@club-internet.fr) - * Revision 2.5f +Sun Jun 28 12:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 3.0e + - Some cleanup, spelling fixes, version checks, documentations + changes, etc ... + +Sat Jun 20 20:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 3.0c + - Add a boot setup option that allows to set up device queue depths + at boot-up. This option is very usefull since Linux does not + allow to change scsi device queue depth once the system has been + booted up. + +Sun Jun 15 23:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 3.0a + - Support for up to 64 TAGS per LUN. + - Rewrite the TARGET vs LUN capabilities management. + CmdQueue is now handled as a LUN capability as it shall be. + This also fixes a bug triggered when disabling tagged command + queuing for a device that had this feature enabled. + - Remove the ncr_opennings() stuff that was useless under Linux + and hard to understand to me. + - Add "setverbose" procfs driver command. It allows to tune + verbose level after boot-up. Setting this level to zero, for + example avoid flooding the syslog file. + - Add KERN_XXX to some printk's. + +Tue Jun 10 23:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 3.0 + - Linux config changes for 2.0.34: + Remove NVRAM detection config option. This option is now enabled + by default but can be disabled by editing the driver header file. + Add a PROFILE config option. + - Update Configure.help + - Add calls to new function mdelay() for milli-seconds delay if + kernel version >= 2.1.105. + - Replace all printf(s) by printk(s). After all, the ncr53c8xx is + a driver for Linux. + - Perform auto-sense on COMMAND TERMINATED. Not sure it is usefull. + - Some other minor changes. + +Tue Jun 4 23:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 2.6n + - Code cleanup and simplification: + Remove kernel 1.2.X and 1.3.X support. + Remove the _old_ target capabilities table. + Remove the error recovery code that have'nt been really usefull. + Use a single alignment boundary (CACHE_LINE_SIZE) for data + structures. + - Several aggressive SCRIPTS optimizations and changes: + Reselect SCRIPTS code rewritten. + Support for selection/reselection without ATN. + And some others. + - Miscallaneous changes in the C code: + Count actual number of CCB queued to the controller (future use). + Lots of other minor changes. + +Wed May 13 20:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 2.6m + - Problem of missed SCSI bus reset with the 53C895 fixed by + Richard Waltham. The 53C895 needs about 650 us for the bus + mode to settle. Delays used while resetting the controller + and the bus have been adjusted. Thanks Richard! + - Some simplification for 64 bit arch done ccb address testing. + - Add a check of the MSG_OUT phase after Selection with ATN. + - The new tagged queue stuff seems ok, so some informationnal + message have been conditionned by verbose >= 3. + - Donnot reset if a SBMC interrupt reports the same bus mode. + - Print out the whole driver set-up. Some options were missing and + the print statement was misplaced for modules. + - Ignore a SCSI parity interrupt if the chip is not connected to + the SCSI bus. + +Sat May 1 16:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 2.6l + - Add CCB done queue support for Alpha and perhaps some other + architectures. + - Add some barriers to enforce memory ordering for x86 and + Alpha architectures. + - Fix something that looks like an old bug in the nego SIR + interrupt code in case of negotiation failure. + +Sat Apr 25 21:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 2.6k + - Remove all accesses to the on-chip RAM from the C code: + Use SCRIPTS to load the on-chip RAM. + Use SCRIPTS to repair the start queue on selection timeout. + Use the copy of script in main memory to calculate the chip + context on phase mismatch. + - The above allows now to use the on-chip RAM without requiring + to get access to the on-chip RAM from the C code. This makes + on-chip RAM useable for linux-1.2.13 and for Linux-Alpha for + instance. + - Some simplifications and cleanups in the SCRIPTS and C code. + - Buglet fixed in parity error recovery SCRIPTS (never tested). + - Minor updates in README.ncr53c8xx. + +Wed Apr 15 21:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 2.6j + - Incorporate changes from linux-2.1.95 ncr53c8xx driver version. + - Add SMP support for linux-2.1.95 and above. + - Fix a bug when QUEUE FULL is returned and no commands are + disconnected. This happens with Atlas I / L912 and may happen + with Atlas II / LXY4. + - Nail another one on CHECK condition when requeuing the command + for auto-sense. + - Call scsi_done() for all completed commands after interrupt + handling. + - Increase the done queue to 24 entries. + +Sat Apr 4 20:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 2.6i + - CTEST0 is used by the 53C885 for Power Management and + priority setting between the 2 functions. + Use SDID instead as actual target number. Just have had to + overwrite it with SSID on reselection. + - Split DATA_IN and DATA_OUT scripts into 2 sub-scripts. + 64 segments are moved from on-chip RAM scripts. + If more segments, a script in main memory is used for the + additionnal segments. + - Since the SCRIPTS processor continues SCRIPTS execution after + having won arbitration, do some stuff prior to testing any SCSI + phase on reselection. This should have the vertue to process + scripts in parallel with the SCSI core performing selection. + - Increase the done queue to 12 entries. + +Sun Mar 29 12:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 2.6h + - Some fixes. + +Tue Mar 26 23:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 2.6g + - New done queue. 8 entries by default (6 always useable). + Can be increased if needed. + - Resources management using doubly linked queues. + - New auto-sense and QUEUE FULL handling that does not need to + stall the NCR queue any more. + - New CCB starvation avoiding algorithm. + - Prepare CCBs for SCSI commands that cannot be queued, instead of + inserting these commands into the waiting list. The waiting list + is now only used while resetting and when memory for CCBs is not + yet available? + +Sun Feb 8 22:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 2.6f + - Some fixes in order to really support the 53C895, at least with + FAST-20 devices. + - Heavy changes in the target/lun resources management to allow + the scripts to jump directly to the CCB on reselection instead + of walking on the lun CCBs list. Up to 32 tags per lun are now + supported without script processor and PCI traffic overhead. + +Sun Jan 11 22:00 1998 Gerard Roudier (groudier@club-internet.fr) + * revision 2.6d + - new (different ?) implementation of the start queue: + Use a simple CALL to a launch script in the CCB. + - implement a minimal done queue (1 entry :-) ). + this avoid scanning all CCBs on INT FLY (Only scan all CCBs, on + overflow). Hit ratio is better than 99.9 % on my system, so no + need to have a larger done queue. + - generalization of the restart of CCB on special condition as + Abort, QUEUE FULL, CHECK CONDITION. + This has been called 'silly scheduler'. + - make all the profiling code conditionned by a config option. + This spare some PCI traffic and C code when this feature is not + needed. + - handle more cleanly the situation where direction is unknown. + The pointers patching is now performed by the SCRIPTS processor. + - remove some useless scripts instructions. + + Ported from driver 2.5 series: + ------------------------------ - Use FAST-5 instead of SLOW for slow scsi devices according to new SPI-2 draft. - Make some changes in order to accomodate with 875 rev <= 3 @@ -10,1136 +179,13 @@ . Memory Read Line is not enabled for 875 and 875-like chips. . Programmed burst length set to 64 DWORDS (instead of 128). (Note: SYMBIOS uses 32 DWORDS for the SDMS BIOS) - -Sun Oct 26 12:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.5e - Add 'buschk' boot option. This option enables checking of SCSI BUS data lines after SCSI RESET (set by default). (Submitted by Richard Waltham). - Update the README file. - -Sat Oct 4 18:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.5d - Dispatch CONDITION MET and RESERVATION CONFLICT scsi status as OK driver status. - Update the README file and the Symbios NVRAM format definition with removable media flags values (available with SDMS 4.09). - -Sat Sep 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.5c - Several PCI configuration registers fix-ups for powerpc. (Patch sent by Cort). - -Thu Aug 28 10:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.5b - - Add 'ncr53c8xx' char pointer variable. This variable allows to - pass a boot command to the driver when it is loaded as a module. - Option separator is ' ' instead of ','. Example: - insmod /ncr53c8xx.o ncr53c8xx='verb:2 sync:0 specf:n' - - Always use 'driver_setup.settle_delay' for internal resets. - 2 seconds hardcoded is sometimes too short. Suggested by Richard W. - This delay may be shortenned in order to avoid spurious timeouts. - - Fix release module stuff that failed for more than 1 controller. - - For linux versions > 1.3.70, trust the 'dev_id' parameter passed - to the interrupt handler (dev_id = struct ncb *). - - Fix up in 'ncr_log_hard_error()' when the DSP points outside scripts. - Suggested by Stefan Esser. - -Tue Aug 23 23:43 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.5a - - Update Configure.help for inclusion in linux-2.1.51/2/3 - - Use BASE_2 address from PCI config space instead of some - IO register for getting the on-board SRAM bus address. - - Remove error testing of pcibios_read/write functions. - These functions are intended to be used for successfully - detected PCI devices. Expecting error condition from them - is nothing but paranoia. - -Thu Aug 21 23:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.5 - - 53C860 chip support fix. - - Move the 'host_status' to the last DWORD of the CCB header. - This header is copied back by the script processor. This - guarantees that the header is entirely copied back over - the PCI when the CPU completes a CCB. - - (re)read ISTAT prior to scanning CCBs for completion. This - ensure that any posted buffer are flushed prior CCBs scan. - - Support for BIG ENDIAN cpu. Added by Cort . - Initial patch did'nt support disconnections and tagged commands. - I've completed the patch and it seems that all is ok now. - Only some powerpc under 2.1.X is supported for the moment. - - Misc. trivial fixes and cleanups. - -Sat July 26 18:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.4 - Several clean-ups: - - Asynchronous pre-scaler calculation. - Synchronous divisor calculation. - - Use FE_ as feature identifier prefix instead of _F_. - - Change 'ns_sync' identifier to "minsync". - - Some others. - Apply some SPI2-R12 recommendations. - - Use Slow, Fast-10, Fast-20, Fast-40 SCSI instead of SCSI-2, - FAST SCSI-2, ULTRA, ULTRA-2. - - Reset the SCSI on bus mode change. - -Wed July 02 22:58 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.3c - - Add define SCSI_NCR_PCI_FIX_UP_SUPPORT for conditionnal compilation - of the corresponding pci fix-up code when a small driver is needed. - - Use "ncr53c8xx" as driver name for both request_irq() and - request_region(). Using different names confused 'lsdev'. - (Suggestion sent by Henrik Storner). - -Wed June 24 22:08 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.3b - - Print an error message on unexpected boot command line option. - - Switch to asynchronous data transfer mode after SCSI wide - negotiation. - -Wed June 14 22:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.3a - - Add PCI LATENCY TIMER fixup code. - Increase it if necessary according to burst size. - Boot option bit : 'pcifix:4' - - On phase mismatch, calculate residual data size for all OUTPUT - phases. That's only required for interrupted DATA OUT phase, but - this information is usefull for problem solving. - - Add KERN_INFO to some messages printed to the log. - (Patch sent by Wolfram Kleff). - -Tue June 02 22:30 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.3 - - NvRAM support code slightly improved (I think): - Use IO or MMIO according to driver setup for reading the NvRAM. - Use structures for NvRAM data instead of raw data. - - Prevent from queuing more than 1 command to the scsi SCRIPT with - negotiation attached when tagged command queueing is enabled. - - Fix-up for old 53C8XX chips that support PCI READ LINE but not - CACHE LINE SIZE. If the cache line size is unknown, set burst - to 8 dwords and disable READ LINE, otherwise set burst max to - the cache line size value. - -Sat May 24 12:30 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.2c (for linux-2.1.40) - - Remove reference to 'x86' symbol when MODULE is defined, since this - symbol is not exported for module loading. - The value of 'x86' is used for fixing up the PCI CACHE LINE SIZE - configuration register. - - Bytes/words read one bit at a time from the serial NVRAM were'nt - initialized with zero. - - Some comments added. Minor cosmetic changes. - -Mon May 19 20:30 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.2b - - Patch for NVRAM support by Richard Waltham applied. - The code detects Symbios NVRAM format and Tekram NVRAM format. - This enhancement allows to get hosts and devices user set up - from the NVRAM. - - Use the NVRAM contents when present to initialize user definable - target parameters. - - Update the README file. - -Sun May 11 22:30 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.1b - - Cosmetic changes. - - Some heavy testings under pre-linux-2.1.37-6 - -Sun May 4 22:30 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.1a - - PFEN wrongly used for PREFETCH feature bit testing. - Changed to _F_PFEN. - - 2 SCR_COPY that need NO FLUSH bit to be removed had been missed - in tp->getscr[] script (loads SXFER and SCNTL3 on reselection). - -Sat May 3 22:30 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.1 - - Use the NO FLUSH option for MOVE MEMORY (COPY) each time it is - possible. More than 100 COPY with NO FLUSH and 6 with FLUSH for - my configuration (max queued command / device = 8). - This option bit is removed from the script instance for chips - that donnot support prefetching. - - Rewrite the ncr_exception() routine more simple (I think) and - remove useless code. - - Change the data_in and data_out script management. - Use the bottom part of these scripts instead of the beginning. - That avoids to zero the scatter/gather array when a command is - queued (1k) and to deal with some weird IID on MOVE 0 bytes when - a target wants to transfer more bytes than expected. - - Misc. improvements in the init code. - - Remove IOMAPPED/MMIO automatic switching option. - Was useless and reported not reliable. - - Fix a double read of DSTAT and remove DFE testing in the - Phase mismatch service routine. - - Etc... - -Fri Apr 26 20:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.0a - - Add support if the Diamond FirePort 40 (SYM53C875J chip) - -Mon Apr 22 22:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 2.0 - - incorporate __initdata and __initfunc directives in order to - allow 'init' to free unused memory after driver initialisations. - Patch sent by Roberto Fichera. - - rewrite the init code of the driver. Now a feature descriptor - is used for each real chip types. The code is a lot more clean, - since the driver uses device and revision ids only in the - detection procedure. - - add 'pcifix' boot command line. This command allows to fix up PCI - config space for new chips which support features based on the - cache line size and 'write and invalidate'. - - incorporate in the driver, the code used for error recovery - testing. This code is normally not compiled; have to define - SCSI_NCR_DEBUG_ERROR_RECOVERY in order to compile it. - - take into account actual SCSI bus mode for 53C895 LVD/SE controller. - In single ended mode only fast20 is supported. - (Just to not be late since such controllers are not yet available) - - -Sat Apr 20 21:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 1.18f - - fix an old bug included in the initial port (version 0.0). - The driver allocated 10 bytes of static data and uses 12 bytes. - No danger, since data are generally aligned on 4 bytes boundary - and so byte 10 and 11 are free (I hope ...) - -Wed Apr 16 12:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 1.18e - - reset all when an unexpected data cycle is detected while - disconnecting. - - make changes to abort() ans reset() functions according to - Leonard's documentation. - - small fix in some message for hard errors. - -Sat Apr 5 13:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 1.18d - - Probe NCR pci device ids in reverse order if asked by user from - the boot command line. Suggested by Richard Waltham. - - Make a separate function that prints out verbose information on - severe error (assumed from hardware). - - Add the transfer period factor and the max commands per lun value - to the proc info data. If debug flags are set or verbosity is - greater than 1, debug flags and verbosity are returned in proc - info data. - - Update the documentation. - -Thu Mar 20 23:00 1997 Gerard Roudier (groudier@club-internet.fr) - * revision 1.18c - - Add special features support for NCR53C885 and NCR53C896 chip. - Quite obvious, but untested, and based on the fact that: - The 885 supports same features as the 875. - The 896 is a 64 bits PCI version of the 895. - - Improve recovery from SCSI GROSS ERRORS. - I can get such errors by making the driver negotiate offset 8 with - a disk and setting the ncr chip to a lower offset value. - I got bunches of errors that have been gracefully recovered by - the driver. - The driver now uses its timer handler in order to wait 2 sec. for - devices to settle after SCSI reset and so does not uselessly freeze - the system with interrupt masked for seconds. - - Enable 'burst op code fetch' and 'read line' for 815 chips. - - Use a 2 commands queue depth instead of 1 for devices that does - not support tagged command queuing. - - The ULTRA timing flag setting was based on the output resulting - period factor of the ncr and not on the negotiated one. - This flag setting was wrong only for 24 ns negotiated period factor. - - Some other minor changes and cleanups. - -Thu Feb 27 23:00 1997 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c ncr53c8xx.h revision 1.18b - - 'On paper' support of the NCR53C895 Ultra-2 chip. - (Clock quadrupler + 7 clock divisors) - - Load the main part of the script into the on-board RAM. - - 810A rev. 0x11 PCI problem fixed. - This chip is now supported with all PCI features enabled and - 16 dwords burst transfers. - - Align on 32 boundary some internal structures. - That fixes the 810A problem and allows cache line bursting when - moving the global header (64 bytes) from/to CCBs to/from NCB. - - Synchronous parameters calculation rewritten. The driver - now uses all available clock divisors and will be able to support - clock frequencies that are not multiple of 40 Mhz if necessary. - -Sat Feb 8 22:00 1997 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - revision 1.17a - - IRQ mode set up from boot setup command. - irqm:0 open drain (default) - irqm:1 preserve initial setting (assumed from BIOS) - irqm:2 totem pole - - DIFF mode set up from boot setup command. - Suggested by Richard Waltham. - diff:0 never set up diff mode (default) - diff:1 set up diff mode according to initial setting (BIOS?) - diff:2 always set up diff mode - diff:3 set up diff mode if GPIO3 is zero (SYMBIOS boards) - - Change CONFIG option for LED support. - CONFIG_SCSI_NCR53C8XX_SYMBIOS_COMPAT allows LED support and - DIFF support for SYMBIOS boards and compatibles (clones?). - - Set 16 DWORD bursts for 810A rev. >= 0x12 since my SC200 with - such a chip have no problem with it (MB with Triton 2 HX). - 810A rev. 0x11 are set to 8 DWORD bursts since they may give - problems with PCI read multiple and Triton 2 HX. - Thanks to Stefan for this information. - -Sat Jan 25 22:00 1997 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - revision 1.17 - - Controller LED support. - Only works with LED pin wired to GPIO_FETCHN, so probably with - all boards using SMDS BIOS. - This option can be enabled only if CONFIG_EXPERIMENTAL is set. - - Assume clock doubler for 875 chip when clock frequency measurement - result is 40 MHz. May help when some old stuff as SDMS BIOS 3.0 - or some old driver has broken the normal BIOS settings. - - Add wide negotiation control from boot setup command. - May be usefull with systems using a 875 based board connected to - a wide device through a 50 pins to 68 pins converter. - - Add a "boot fail safe option" to the boot setup command line. - - Rewrite the "reset_command" routine. - Low-level driver are responsible to keep the involved command - alive. The new code seems to behave correctly. - - Change some variables used by the script from u_long to u_int32. - - Remove some useless code. - -Sun Jan 12 12:00 1997 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - revision 1.16e - - Add support of PCI burst length control from boot setup command. - burst:0 disable burst - burst:255 get burst from initial settings (BIOS settings?) - burst:#x set burst transfers to 1<<#x - - Only check xfer direction for common op-codes. - For all device specific / vendor specific opcodes the driver - now uses the xfer direction decided by the target. - -Sun Jan 05 12:00 1997 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - revision 1.16d - - The driver is now able to process scsi commands without - knowledge of xfer data direction. - Stefan agreed with this change for Linux. This change is - not needed under FreeBSD since low-level drivers receive - the expected data direction for each scsi request. - - Save ctest5 features bits at start-up and restore them at - module release step. - Avoid side effects when a ncr driver which trusts bios - settings is reloaded (could be the ncr53c8xx itself). - - -Wed Jan 01 23:30 1997 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - revision 1.16c - - Bad decision about 20MHz for 13 ns period factor. - Was wrong, so I restore the previous algorithm. - - Burst length 128 not correctly set in dmode. - -Thu Dec 26 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c ncr53c8xx.h README.ncr53c8xx - revision 1.16b - - Remove useless code. - - Try to improve error recovery in case of abort and reset. - - Remove DEBUG_NEGO by default. - - Add boot setup command support. - Now, all experimental config options can be removed. - - Update README file. - - -Mon Dec 23 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c ncr53c8xx.h - revision 1.16a - New display for speed ##.# MB/s (From Stefan) - - I add "WIDE" qualifier after ULTRA and FAST - - I get "FAST WIDE SCSI-2 20 MB/s" with my Atlas. That's nice. - - Richard Waltham reports SYMBIOS set the 875 to 20 MB/s for 13 ns - period factor. I decide to trust SYMBIOS. 20 MB/s output speed - instead of 19.2 MB/s should not cause problem. The ncr is only able - to use 16.67 MB/s when 20 MB/s is not possible. - - Fix from Markus Kossman: "Ultra SCSI enabled" wrongly printed - when not enabled. - - Set DEBUG_NEGO by default in order to get reports about sync nego. - Will remove it in the next patch. - -Thu Dec 19 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c ncr53c8xx.h README.ncr53c8xx - revision 1.16 - Incorporate new definitions in ncr53c8xx.h (From Stefan). - Check changes against Stefan's current version of the driver. - All seems ok. - -Sat Nov 30 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c ncr53c8xx.h - Make changes in order to support: - - Clock doubler and so 80 Mhz scsi clock for 875 chips. - - Sync transfers below 7.5 MB/sec. - Use Clock/2 between 5 and 10 Mega-transfers/s and Clock/4 below 5. - - Ultra SCSI data transfers. - - Offset 16. - - Works with my configuration. However I cannot test Ultra transfers, - since my disks are only fast scsi-2. - -Tue Nov 28 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - I received yesterday my Promise SCSI Ultra board. - NCR53C875 rev. 3 with clock doubler. - Add the code to support some bus features, the large 536 dma fifo and - burst 128. Works. - -Mon Nov 4 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c ncr53c8xx.h - revision 1.14c - Severall control command improvements: - - - Allow to specify "all" to commands that apply to #target. - For example: "setsync all 255" sets asynchronous data - transfers for all targets on a bus. - - - Allow to control disconnection privilege per device, as follow: - "setflag #target no_sync" disables disconnection for #target. - "setflag #target" with no flag specified reenables it. - - Obviously #target may be specified as "all" in order to control - disconnection for all targets with a single control command. - - - README file updated and some hints about SCSI problems solving added. - -Sun Oct 27 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c ncr53c8xx.h - revision 1.14b - Add the following config parameters: - - - CONFIG_SCSI_NCR53C8XX_MAX_TAGS - Max number of queued tagged commands. - Allow from 2 to 12, default 4. - - - CONFIG_SCSI_NCR53C8XX_SYNC - Synchronous transfers frequency in MHz. - Allow from 5 to 10, default 5, 0 means asynchronous. - (And so remove CONFIG_SCSI_NCR53C8XX_FORCE_ASYNCHRONOUS) - -Sun Oct 20 16:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - ncr_scatter() rewritten. - remove "ncr dead" detection. - -Sun Oct 13 19:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c ncr53c8xx.h - revision 1.14a - Enabling some special features makes problems with some hardware. - So, disable them by default. - Add SCSI_NCR_SPECIAL_FEATURES define to play with. - -Sun Oct 13 14:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c ncr53c8xx.h - Incorporate Stefan's patch for clock frequency detection. - (Committed in FreeBSD/ncr.c rev. 1.81). - The driver then does about the following: - Assume 40 MHz clock for all ncr chips except: - - NCR53C860 chips: - Assume 80 Mhz clock. - - NCR53C875 chips: - If clock doubler enabled, disable it and assume 40 Mhz clock. - Else if (scntl3&7)=0 measure scsi clock frequency. - Else trust bios setting of scntl3&7 (3=40 Mhz, 5=80Mhz). - -Wed Oct 9 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - release 1.14 - For now, just change the clock detection as follow: - - If clock doubler selected by BIOS, assume 40 MHz clock since - clock doubler will be disabled by chip reset. - - Else if NCR53C860 assume 80 MHz clock. - - Else trust BIOS setting if (scntl3&7 >= 3) - - Else assume 40 MHz clock. - -Sat Oct 05 17:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Stefan sent me a patch that improves the clock frequency detection - of the driver. Stefan uses the general timer register stime1 in - order to measure as accurately as possible the scsi clock. - Works ok with my 825, but needs still testing. So will be - released later. - -Sun Sep 29 17:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Preserve dcntl/dmode/ctest3/ctest4 features bits at start-up. - Add the define option SCSI_NCR_TRUST_BIOS_SETTING. - - If this option is defined, the driver will preserve the - corresponding bits of io registers. - - Else, the driver will set features bits according to chip - and revision ids. - -Sun Sep 22 17:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Remove useless fields and code and so spare cpu: - - profile data are accumulated in jiffies ticks and converted - to milli-seconds when read through proc fs. - - when IOMAPPED is not defined, try only MMIO. - (avoid testing a value in order to choose between IO and MMIO) - -Sun Sep 01 20:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.h, ncr53c8xx.c - Version 1.13 - Adaptation of the tagged command queuing depth control of the - FreeBSD driver to Linux. Now, tagged command queueing can be - disabled at run time by a "settags N 0" control command. - Add the following heuristic in order to manage intelligently (perhaps) - QUEUE_FULL status: - - Each time a QUEUE FULL status is returned by a device, disable tagged - command queuing for that device. - - Every 100 successfully complete commands, increment the maximum - queuable commands (up to the allowed limit). - -Fri Aug 30 10:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Version 1.12c - Incorporate the changes of FreeBSD/ncr.c revision 1.76. - The changes add support for the 53c860 and 53c875, - but without taking advantage of the new features. - Those chips are used exactly as the old 53c810. - -Sun Jul 21 00:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, README.ncr53c8xx - Add the ncr53c8xx_select_queue_depths() function. - Set queue_depth to SCSI_NCR_MAX_TAGS (4 by default) for devices that - support tagged command queueing. - For other devices, set queue_depth to 1. No need to queue a command - to the driver if this command cannot be sent to the device. - Each time the driver hide io requests from the kernel and/or from the - driver, it may break a little (or a lot) optimization algorithms that - try to increase throughput by reordering io requests. - It is better to enable the disk write caching to reduce latencies for - write operations, and to trust asynchronous read ahead from the device - and from the kernel that can reduce latencies for read operations, - even when tagged command queuing is not supported or enabled. - -Sat Jul 20 20:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Minor changes: - - Problem of "CCB address mismatch" that happens with the 3 versions - of the driver. The CCB is correct and Stefan Esser suggests a little - patch that seems to be a bypass. - Stefan says he will change that in a future version of the BSD driver. - - Set burst transfers to 8 for 815 chips. - -Sun Jul 14 15:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, Configure.help - Memory mapped io donnot work under linux/Alpha for the driver. - For the moment it is better to not support this feature for this - architecture. - -Tue Jul 09 20:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Garbage printed out with the following command (fixed): - - cat /proc/scsi/ncr53c8xx/0 - -Sun Jul 07 20:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Tagged command queueing cannot be disabled at run time. - I probably never try that because I felt the risk. - Shortest patch sent to Linus. I have to plan something better. - -Wed Jul 03 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - Release 1.12a - Tested linux releases: 1.2.13, 2.0.0, 2.0.1 - -Mon Jul 01 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - ncr53c8xx.h, ncr53c8xx.c - Add "clearprof" user command that clear the profile counters. - Automatically clear profile counters when num_kbytes=1000000000 - in order to avoid ugly overflow. - Donnot compile user command code and profile data with 1.2.13. - -Wed Jun 29 20:38 1996 Gerard Roudier (groudier@club-internet.fr) - Matthew Geier reported to me a weird problem of unexpected - disconnection while asynchronous negotiation. - The message sent by the driver is 1-3-1-ff-00. I sent a patch to - Matthew that change the message to 1-3-1-00-00. - The sync msgout was correct however some devices might be to happy - with ff. - -Wed Jun 26 22:57 1996 Gerard Roudier (groudier@club-internet.fr) - Patch no 4 sent to Harald. - The drived used "wtime" for timeouts adn time measurements. - I change for jiffies. - Work with my P133. - -Mon Jun 24 23:05 1996 Gerard Roudier (groudier@club-internet.fr) - Patch no 3 sent to Harald. - -Sun Jun 23 22:29 1996 Gerard Roudier (groudier@club-internet.fr) - Patch no 2 sent to Harald. - I think that the driver have some chance to work. - -Sun Jun 23 15:00 1996 Gerard Roudier (groudier@club-internet.fr) - Harald Koenig is interested in the adaptation of the driver to - Linux/Alpha. - I have prepared a patch and sent it to Harald. - -Sun Jun 16 19:00 1996 Gerard Roudier (groudier@club-internet.fr) - Release 1.11 - Tested linux releases: 1.2.13, 2.0.0 - -Sat Jun 15 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.h, Configure.help, scsi/Config.in - Add CONFIG_SCSI_NCR53C8XX_IOMAPPED config option. - Prepare the 2.0.0 with the new version of the driver. - -Wed Jun 12 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - Rewrite the README file. - Add some documentations of the proc file system support. - -Sun Jun 9 18:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Add proc filesystem support of the driver. - Read operations returns profile information. - Write operations send control commands to the host adapter driver. - -Wed Jun 5 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - Change xfer direction for SCAN command to write. - Was bogus. - -Tue May 30 18:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Set the DMA FIFO to 88 for 825A and 875 boards. - The previous value of 536 is bogus since the script only read 7 - bits for the fifo size (thanks to Stefan). - -Mon May 27 18:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Correct the xfer direction guessing for scanner SCAN command (write). - -Mon May 27 18:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Add the following config options: - SCSI_NCR_DISABLE_MPARITY_CHECK : disable master parity checking. - SCSI_NCR_DISABLE_PARITY_CHECK : disable scsi parity checking. - SCSI_NCR_FORCE_SYNC_NEGO : force sync nego for all scsi 2 devices. - -Sat May 25 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - Release 1.10 - Tested linux releases: 1.2.13, 1.3.45, 1.3.71, 1.3.90, 1.3.100 - 1.99.6, 1.99.7 - Switch between Drew's driver and Bsd driver tested for 1.99.7. - Both driver was made as modules. - -Sat May 25 16:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Some weird problems happen with multi-lun configurations and HDs. - SDTR seems to be sent with TEST UNIT READY of lun 1. - Tagged Queue cannot be enabled. It seems that inqdata are - filled with garbage probably due to some INQUIRY command to - lun 1. - I have fixed the problem as follow: - - negotiation are initiated only with a command to lun 0. - - inquiry data are store only for lun 0. - -Wed May 22 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, ncr53c8xx.h - Have prepared the patch that allow to install the driver in the - kernel tree, without moving Drew's one. - Seems to work. However, I have to check that nothing has been - broken for 1.2.13 and 1.3.45 to 1.3.100. - -Sun May 4 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.h - Adapt the source to some modifications of the linux tree of 1.3.98. - (include/linux/scsicam.h moved to include/scsi/scsicam.h) - -Thu Apr 25 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.h, ncr53c8xx.c - Release 1.9 - Prepare conditionnal compilations for the future Linux version(s). - Assume that these versions will be nicely compatible with current - one. - 1.3.255, 1.4.0 or 2.0.0 ? - I suggest 3.0.0 for some obvious reason. - -Wed Apr 24 23:15 1996 Gerard Roudier (groudier@club-internet.fr) - * Install.ncr53c8xx - Add Patch-Current.ncr53c8xx to the distribution. - This patch is applied to the scsi Makefile at installation time for - Linux release V.P.S (V*1000000000+P*100000000+S > 1300000094). - Each time it'll be necessary I will send the patch corresponding to - the current Linux release to the linux-scsi@vger.rutgers.edu. - -Sun Apr 21 19:00 1996 Gerard Roudier (groudier@club-internet.fr) - * README.ncr53c8xx - Update Bonnie results of linux-1.3.92 + prepatch read-ahead 1.3.93. - Results are so good that I must remove FreeBSD-2.0.5 results from the - README file, otherwise I should cause trouble for myself. - -Sun Apr 07 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.h - Define SCSI_NCR_MAX_LUN (8) inconditionaly. - Previous releases did not work for multi-lun devices. - This definition was wrongly conditionned: - (SCSI_CONFIG_MULTI_LUN instead of CONFIG_SCSI_MULTI_LUN). - No luck, since I donnot have multi-lun devices and could'nt - test it. - Some tests under linux-1.3.84 with an experimental patch that - try to do asynchronous read-ahead. - -Wed Apr 03 23:15 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.h, ncr53c8xx.c - Change some wrong "assert (target == cmd->target & 7)" to - "assert (target == (cmd->target & 0xf)". - Remove NCR_TIMEOUT_ALERT from ncr53c8xx.c - Add SCSI_NCR_TIMEOUT_ALERT to ncr53c8xx.h - -Sun Mar 24 21:15 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.h - During "make dep" of linux-1.2.13, LINUX_VERSION_CODE is undefined. - Have to assume 1.2.13 in such situation. - Release 1.8 - -Sun Mar 24 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * README.ncr53c8xx - Make changes according to the new uninstallation procedure. - -Sun Mar 24 20:00 1996 Gerard Roudier (groudier@club-internet.fr) - * Uninstall.ncr53c8xx - Add an uninstallation script to the distribution. - This shell script restore the standard driver. - Very usefull for people who prefers to use a driver that - does not support: - - Master parity check - - Tagged command queuing - - Fast Wide Scsi-2 features (up to 20 MB/sec) - and that would be capable to reject a Wide Negotiation that it had - previously initiated. - -Sat Mar 23 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * README.ncr53c8xx - Make changes according to the new installation procedure. - -Fri Mar 22 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - * Install.ncr53c8xx - Add an installation script to the distribution. - 3 differents patches are necessary: - - linux-1.2.13 - - linux-1.3.45 to linux-1.3.49 - - linux-1.3.50 to linux-1.3.77 - -Wed Mar 13 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, ncr53c8xx.h - Add share irq support. - This facility appears with linux-1.3.70. It seems that the - corresponding code of the kernel was questionnable before 1.3.72. - I decide to support this options from linux-1.3.72 and above. - (Add define option SCSI_NCR_SHARE_IRQ) - Release 1.7 - -Tue Mar 12 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Download BSD ncr.c 1.67 and apply the correction of negotiations order. - Now the Wide and Sync negotiation are done in the proper order. - (Problem reported by Johannes Plass). - Round up correctly the announced speed in MB/sec. - -Tue Mar 05 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * README.ncr53c8xx - Have to upload release 1.6 for users of linux-1.3.70-71 - -Mon Mar 04 16:00 1996 Gerard Roudier (groudier@club-internet.fr) - * README.ncr53c8xx - Add some Bonnie results to the README file. - -Sun Mar 03 20:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Make changes for linux-1.3.70 according to the new specification of - irq services interface (request_irq(), free_irq()). - With 26 letters, "_", and 10 digits we can build about: - 53x62**9 C names of 10 characters. - Why to use SAME function names with DIFFERENT parameters ? - -Sat Mar 02 22:30 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Using SIMPLE QUEUE TAG for all operations is good for performances, - but may be bad for assumed timeout values. - Under heavy disk load (Bonnie), the drive may start IO process of a - command, then disconnect, then execute lots of other commands - before completing the interrupted command. - The standard value of SD_TIMEOUT (6 sec or 7 sec) seems (is) too short. - I fix the problem by forcing an ORDERED QUEUE TAG for the next - command when I found some "old" pending command. - "Old" means that they might be timeouted in a few seconds. - Add NCR_TIMEOUT_ALERT and set it to 3 seconds. - -Fri Mar 01 22:30 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.h, ncr53c8xx.c - Add define SCSI_NCR_SEGMENT_SIZE and set it by default to 512. - If undefined, the driver use the scatter list given by the upper - scsi driver, else it tries to split segments into shorter one - according to the value of SCSI_NCR_SEGMENT_SIZE. - -Tue Feb 27 21:30 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.h - Set sg_tablesize to 127 = SCSI_NCR_MAX_SCATTER-1. - (was 64 = SCSI_NCR_MAX_SCATTER/2). - May increase the speed (about 20%) for linear read/write operations. - Bonnie results may be better, but I prefered the previous - value. - -Tue Feb 27 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr54c8xx.c, ncr53c8xx.h - Tagged command queueing seems to affect linux-1.3.XY kernels. - I decide to disable tagged queue by default and to provide a command - tool to enable it per device after boot-up. - Add scsitag.c to the distribution. - Usage: scsitag device - Examples: scsitag /dev/sda - scsitag /dev/sdb - -Sun Feb 25 14:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, ncr53c8xx.h - Add INQ7_Default definition and set the target capabilities to this - value by default. - Add some code to reject a synchronous negotiation request from a target - that is defined as not capable of Sync in the table of capabilities. - -Sat Feb 24 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Add some code to fill some write-only host instance fields: - - base - - io_port - - n_io_port - - dma_channel - This fields may be used with some "standard" drivers that do not - process correctly the release function. - -Fri Feb 23 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - I receive a mail from Jason Duerstock. - A new bug in ncrBsd2Linux which is probably outside the driver code - and inside Linux kernel code. - The kernel memory is quite corrupted and we cannot get any information - by looking into the messages about the crash. However Linus see a bug in - ncrBsd2Linux because it is a "non standard" driver. - I think too that ncrBsd2Linux is not a standard driver of Linux kernel, - because it has no bugs enough to become standard for Linux. - Drew's driver is quite standard. - -Wed Feb 21 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, ncr53c8xx.h - I incorporate the differences between FreeBSD ncr.c revision 1.62 and - revision 1.64. - - Some cosmetic changes. - - Use M_SIMPLE_TAG by default (even for write operations). - I seems to me that SIMPLE TAG is safe only if the flag "queue - algorithm modifier" is set to zero. - I will ask some questions to Stefan Esser about this. - Add option SCSI_NCR_ALWAYS_SIMPLE_TAG in ncr53c8xx.h. - -Fri Feb 16 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - I have found the bug. It is a recursion in __get_free_pages(). - I will send a mail to Linus about this. - -Sat Feb 10 20:00 1996 Gerard Roudier (groudier@club-internet.fr) - I am sure that the kernel stack overflow is due to a severe bug in - the Linux kernel. - I decide to try to find the bug by myself. - -Fri Feb 09 20:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, ncr53c8xx.h - Limit commands per lun to 2 for linux-1.3.XY. - The patch-1.3.60 does not correct the kernel stack overflow problem. - I decide to make some tests with Drew's driver and Bsd2Linux with same - working conditions (3 commands per lun, FAST SCSI, no command queueing). - I get the stack overflow problem with the 2 drivers at the same - frequency. - With only 2 commands per lun, I don't have the problem with any driver. - It seems that the madness of recursion and the recent introduction of - the silly generic read function have broken performance and reliability - of scsi drivers. - -Thu Feb 08 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, ncr_attach() - Release memory mapped region and io port if initialisation - does not succeed. - -Thu Feb 08 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, ncr53c8xx.c - Try to spare some CPU time in queue_command() function and interrupt - handler: - Add SCSI_NCR_PARANOIA define option in ncr53c8xx.h. - Add SCSI_NCR_PROFILE define option in ncr53c8xx.h. - Avoid useless code and function calls. - -Tue Feb 06 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, ncr53c8xx.h, ncr_timeout() - Add SCSI_NCR_BROKEN_INTR define option in ncr53c8xx.h. - If this option is set, the timeout handler polls the interrupt status - register every tick (10 ms). So, boards with broken interrupt can work. - -Mon Feb 05 21:30 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Print the correct speed, for devices with successfull wide negotiation. - For same period, such devices are two times faster then narrow ones. - -Mon Feb 05 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.h, ncr53c8xx.c, ncr_attach() - Add define SCSI_NCR_SETTLE_TIME in header file and set it by default - to 2 seconds. - -Sat Jan 27 14:00 1996 Gerard Roudier (groudier@club-internet.fr) - Upload release 1.3 - -Wed Jan 24 24:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Update from ncr Bsd 1.60 (Stefan Esser): - The handshake timeout is disabled, since - a few devices will delay ACK for more than a - second: Scanner, CDROM writer and a few old hard - disk drives. - -Wed Jan 24 22:30 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Set the selection timeout to 0.4 sec, since 0.25 sec - is recommended for scsi-1 devices. - Note that the Bsd ncr driver sets this timeout to 0.1 sec - and the linux standard ncr driver sets it to 0.8 sec. - -Wed Jan 24 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Add a 5 seconds delay after chip initialization, - waiting for scsi devices to settle their stomach, - as FreeBSD generic scsi driver does. - -Tue Jan 23 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Set burst length value according to chip type. - The original Bsd ncr driver sets burst length to 16 for - all chip types. - -Tue Jan 16 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c, ncr53c8xx.h - Add comments to linux specific glue code. - -Mon Jan 15 22:00 1996 Gerard Roudier (groudier@club-internet.fr) - io mapped versus memory mapped. - * ncr53c8xx.c - Add some code to dynamicaly switch to io mapped if memory mapped - does not work. - No more need to reconfigure, compile and link the kernel if - memory mapped is not possible. - -Sun Jan 14 18:00 1996 Gerard Roudier (groudier@club-internet.fr) - Patch sent to ncr mailing list by Jason Duerstock - - I have omitted to provide the proc_dir_entry to the middle - scsi driver. - * ncr53c8xxx.c - Add the declaration of the ncr53c8xx proc_dir_entry and return - the pointer to middle scsi driver. - -Sat Jan 13 01:00 1996 Gerard Roudier (groudier@club-internet.fr) - ncrBsd2Linux 1.1 is ready. - Upload to sunsite immediatly. - -Fri Jan 12 23:45 1996 Gerard Roudier (groudier@club-internet.fr) - It seems that scsi-2 devices too may cause problems because they - have flawes in the firmware. - * ncr53c8xx.h - I add a table of capabilities per target. - This table contains one byte per target. The value of this byte - is anded with byte 7 of INQUIRY data. - Edit ncr53c8xx.h and read the corresponding comments for more - details. - -Wed Jan 10 22:35 1996 Gerard Roudier (groudier@club-internet.fr) - I have some time to read the scsi-1 specifications. - Some very old scsi devices may cause problems with the ncr Bsd driver - for the following raisons: - The Synchronous Negotiation protocol was optional. - The standardized INQUIRY data does not include the byte 7 of - the scsi-2 specifications which contains the capabilities of - the device. - I think that negotiation with such devices are very questionnable. - * ncr53c8xx.c - ncrBsd2Linux 1.1 does not negotiate with scsi-1 devices. - -Sat Jan 06 21:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c function ncr_attach() - Disable chip interrupt before soft reset in attach procedure. - When loadlin is used to boot the system, the state of the NCR chip - is unpredicable. This modification avoid unexpected interrupts. - -Thu Jan 04 23:45 1996 Gerard Roudier (groudier@club-internet.fr) - ncrBsd2Linux 1.0 is ready. - Upload to sunsite immediatly. - -Tue Jan 02 23:00 1996 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Add a waiting list for Scsi Commands than can be inserted - into the start queue immediatly. - When a command complete, the waiting commands are requeued by calling - the queuecommand() function. - -Sun Dec 31 23:59 1995 Gerard Roudier (groudier@club-internet.fr) - * ncr53c8xx.c - Use kmalloc()/kfree() for internal data structures allocation to - avoid scsi memory pool shortage. - -Sat Dec 30 23:00 1995 Gerard Roudier (groudier@club-internet.fr) - ncrBsd2Linux can now use memory mapped IO. - Works fine. - * ncr53c8xx.c - Call vremap() from ncr_attach() to map the physical page which - contains the memory IO window. - Call vfree() from ncr_detach() (release module). - -Fri Dec 29 23:45 1995 Gerard Roudier (groudier@club-internet.fr) - ncrBsd2Linux can now be configured as a module. - Works fine. - * ncr53c8xx.c: add new functions ncr53c8xx_release() and ncr_detach() - Add the code to (per host): - Stop the timer. - Stop the chip. - Free allocated memory. - -Fri Dec 29 23:00 1995 Gerard Roudier (groudier@club-internet.fr) - Problem: detection routine returns 0 and can detect only one host. - * ncr53c8xx.c function ncr_attach() - ncr_attach() now returns 0 on success and -1 on error. - ncr53c8xx_detect() returns the number of detected hosts. - -Thu Dec 28 22:00 1995 Gerard Roudier (groudier@club-internet.fr) - I must upload the new version which corrects the severe problem with - WRITE_10 command. - Release 0.5 - Known or probable problems with this ncr driver release: - -------------------------------------------------------- - Same as the previous release. - -Wed Dec 27 23:00 1995 Gerard Roudier (groudier@club-internet.fr) - Problem: - System CRASH or scsi ERROR "extra data disgarded" on WRITE(10) - command. - * ncr53c8xx.c function guess_xfer_direction() - I add the WRITE(10) (0x2A) into the list of Data Out scsi commands. - It was a big mistake. - This BUG was introduced in the release 0.3 and is obvious present in - the release 0.4. - -Wed Dec 27 22:00 1995 Gerard Roudier (groudier@club-internet.fr) - Problem: - When I was testing tagged command queueing and disconnections - with one hard disk at a time (IBM S12), the script process hung - every 5 minutes with a non empty stall queue. - * ncr53c8xx.c function ncr_exception() - I replace "OUTB (nc_istat, INTF)" by - "OUTB (nc_istat, (istat & SIGP) | INTF)". - This statement cleared the INTF condition, but cleared the SIGP flag too. - (This bug is in the original FreeBSD ncr driver). - -Mon Dec 25 22:00 1995 Gerard Roudier (groudier@club-internet.fr) - Release 0.4 - Known or probable problems with this ncr driver release: - -------------------------------------------------------- - Hardware (or software) conflicts with some ethernet cards. - See release 0.2 above. - Crash with Intel saturn chipset with write-back cache enabled. - The SCSI SCRIPT access the internal registers of - the NCR chip by memory addressing. - Ensure that the memory area of the NCR chip is not cacheable. - Use scanpci to get the base memory address of the ncr chip. - The 128 bytes following this address must not be cached. - -Sat Dec 23 22:00 1995 Gerard Roudier (groudier@club-internet.fr) - Problem: - FreeBSD driver important comments - --------------------------------- - We try to reduce the number of interrupts caused - by unexpected phase changes due to disconnects. - A typical harddisk may disconnect before ANY block. - If we wanted to avoid unexpected phase changes at all - we had to use a break point every 512 bytes. - Of course the number of scatter/gather blocks is - limited. - * ncr53c8xx.c function ncr_scatter() - This function has been rewritten according to the above comments. - The Linux scatter list is scanned, and blocks are broken as possible - into 512 bytes chunks. - -Wed Dec 22 22:00 1995 Gerard Roudier (groudier@club-internet.fr) - Problem: ensure that there are enough allocated Command Control Blocks - for each unit to enqueue commands according to cmd_per_lun. - * ncr53c8xx.c function ncr_allocate_ccb() - Allocate all required ccb(s) instead of one at a time. - -Mon Dec 18 23:00 1995 Gerard Roudier (groudier@club-internet.fr) - Problem: A copy of the system time is used to compute timeouts. - When the system time is changed , we can get spurious timeouts - if scsi commands are pending. - * ncr53c8xx.c function ncr_timeout() - In FreeBSD the kernel time (volatile struct timeval time) is not - affected by settimeofday() or other change time functions. - For Linux, I replace "time" by "xtime". But "xtime" is the system time, - and is affected by change time functions. - If we detect a change <=-1s or >1s we assume system time has been changed. - For all active ccb(s), we recompute tlimit. - We set heartbeat to thistime to prevent spurious chip reset. - -Sun Dec 17 23:00 1995 Gerard Roudier (groudier@club-internet.fr) - Release 0.3. - -Sun Dec 17 11:00 1995 Gerard Roudier (groudier@club-internet.fr) - - Problem: Linux middle-level scsi driver does not provide the - direction of transfert in scsi command parameters. - FreeBSD ncr driver need this information to patch the SCSI script - for SAVE DATA POINTER and to check actual data transfer direction. - * ncr53c8xx.c - I add the function guess_xfer_direction(int opcode) which try to - guess the transfer direction. - Unfortunately my documentation about SCSI-II standard is very old. - It does not contain PHOTO-CD command specifications. - I assume input transfer direction, for unknown command. (not perfect) - -Wed Dec 15 23:00 1995 Gerard Roudier (groudier@club-internet.fr) - - It's time to schedule the release 0.2 - Known or probable problems with this ncr driver release: - -------------------------------------------------------- - Scsi tapes do not work. - scsi-config-1.5 does not work too. - Hardware (or software) conflicts with some ethernet cards. - The linux native ncr53c810 scsi driver does'not use memory - mapped IO at all. - The BSD driver can use memory mapped IO. - Under Linux, i seems to be difficult (or impossible) to map - a PCI memory area. So I decide to use normal IO in the code of - the ported driver. - However, the SCSI SCRIPT access the internal registers of - the NCR chip by memory addressing. - EThernet cards use a memory area to communicate with the system. - I think that this memory area conflicts with the memory area - used by the NCR chip. - The configuration diskette of your ethernet card can help you - to fix the problem (try sofware configurations). - -Wed Dec 15 22:00 1995 Gerard Roudier (groudier@club-internet.fr) - - Problem: detection of CD change did not work. - * ncr53c8xx.c - Signal a CHECK_CONDITION (S_CHECK_COND) to the middle-level - scsi drivers when the scsi completion status = S_SENSE|S_GOOD. - - Problem: System hang with status <4/82> after mounting the root - partition. System disk is a QUANTUM EMPIRE 1080 S. - Submitted by rwilhelm@Physik.TU-Muenchen.DE (Robert Wilhelm) - Thu, 14 Dec 1995 10:18:43 +0100 (MET) - * ncr53c8xx.c - Signal a CHECK_CONDITION (S_CHECK_COND) to the middle-level - scsi drivers when the scsi completion status = S_SENSE|S_CHECK_COND. - (HS_COMPLETE=4, S_SENSE|S_CHECK_COND=x82). - I can't test this fix. I think that it should work. - -Thu Dec 14 22:00 1995 Gerard Roudier (groudier@club-internet.fr) - - Problem submitted by Bill Dyess Tue 12 Dec 1995 - Only one lun detected on a Pioneer DRM-602X 6-disk CD-ROM changer. - * ncr53c8xx.h, ncr53c8xx.c - Define NCR_SCSI_MAX_LUN to 8 if the Linux configuration flag - SCSI_CONFIG_MULTI_LUN is set. - My CD device has only one lun. I can't test multi-lun device, - but I think that it should work. - - * ncr53c8xx.c - Write the ncr_abort_command() and ncr_reset_command() functions. - I intend to test these functions next week. - -Sun Dec 10 22:00 1995 Gerard Roudier (groudier@club-internet.fr) - * Release 0.1 - Works fine with hard disks under Linux 1.2.13 and Linux 1.3.45. diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/Config.in linux/drivers/scsi/Config.in --- v2.1.107/linux/drivers/scsi/Config.in Tue Jun 23 10:01:23 1998 +++ linux/drivers/scsi/Config.in Tue Jun 30 22:37:53 1998 @@ -68,12 +68,12 @@ if [ "$CONFIG_PCI" = "y" -a "$CONFIG_SCSI_NCR53C7xx" != "y" ]; then dep_tristate 'NCR53C8XX SCSI support' CONFIG_SCSI_NCR53C8XX $CONFIG_SCSI if [ "$CONFIG_SCSI_NCR53C8XX" != "n" ]; then - bool ' detect and read serial NVRAMs' CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT - bool ' enable tagged command queueing' CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE + int ' default tagged command queue depth' CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS 8 + int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 32 + int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 20 + bool ' enable profiling' CONFIG_SCSI_NCR53C8XX_PROFILE bool ' use normal IO' CONFIG_SCSI_NCR53C8XX_IOMAPPED - int ' maximum number of queued commands' CONFIG_SCSI_NCR53C8XX_MAX_TAGS 4 - int ' synchronous transfers frequency in MHz' CONFIG_SCSI_NCR53C8XX_SYNC 5 - if [ "$CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE" != "y" ]; then + if [ "$CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS" = "0" ]; then bool ' not allow targets to disconnect' CONFIG_SCSI_NCR53C8XX_NO_DISCONNECT fi if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/NCR53C9x.h linux/drivers/scsi/NCR53C9x.h --- v2.1.107/linux/drivers/scsi/NCR53C9x.h Tue Jun 23 10:01:23 1998 +++ linux/drivers/scsi/NCR53C9x.h Thu Jun 25 11:03:43 1998 @@ -11,6 +11,8 @@ #ifndef NCR53C9X_H #define NCR53C9X_H +#include + /* Macros for debugging messages */ /* #define DEBUG_ESP */ diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/README.ncr53c8xx linux/drivers/scsi/README.ncr53c8xx --- v2.1.107/linux/drivers/scsi/README.ncr53c8xx Tue Mar 10 10:03:32 1998 +++ linux/drivers/scsi/README.ncr53c8xx Tue Jun 30 22:37:53 1998 @@ -4,7 +4,7 @@ 21 Rue Carnot 95170 DEUIL LA BARRE - FRANCE -2 January 1998 +27 June 1998 =============================================================================== 1. Introduction @@ -22,7 +22,7 @@ 8.5 Set debug mode 8.6 Clear profile counters 8.7 Set flag (no_sync) - 8.8 Debug error recovery + 8.8 Set verbose level 9. Configuration parameters 10. Boot setup commands 10.1 Syntax @@ -33,9 +33,7 @@ 10.6 SCSI BUS checking boot option 11. Some constants and flags of the ncr53c8xx.h header file 12. Installation - 12.1 Provided files - 12.2 Installation procedure -13. Control commands under linux-1.2.13 +13. Architecture dependant features 14. Known problems 14.1 Tagged commands with Iomega Jaz device 14.2 Device names change when another controller is added @@ -93,7 +91,7 @@ Latest driver version and patches are available at: - ftp://linux.wauug.org/pub/roudier + ftp://ftp.tux.org/pub/people/gerard-roudier I am not a native speaker of English and there are probably lots of mistakes in this README file. Any help will be welcome. @@ -112,19 +110,19 @@ "Wide negotiation" is supported for chips that allow it. The following table shows some characteristics of NCR 8xx family chips: - On board Supported by Tested with -Chip SDMS BIOS Wide Ultra SCSI the driver the driver ----- --------- ---- ---------- ------------ ----------- -810 N N N Y Y -810A N N N Y Y -815 Y N N Y Y -825 Y Y N Y Y -825A Y Y N Y Y -860 N N Y Y Y -875 Y Y Y Y Y -895 Y Y Y(1) Y not yet + On board Supported by +Chip SDMS BIOS Wide SCSI std. Max. sync the driver +---- --------- ---- --------- ---------- ------------ +810 N N FAST10 10 MB/s Y +810A N N FAST10 10 MB/s Y +815 Y N FAST10 10 MB/s Y +825 Y Y FAST10 20 MB/s Y +825A Y Y FAST10 20 MB/s Y +860 N N FAST20 20 MB/s Y +875 Y Y FAST20 40 MB/s Y +876 Y Y FAST20 40 MB/s Y +895 Y Y FAST40 80 MB/s Y -(1) The 895 chip is supported 'on paper'. 3. Summary of other supported features. @@ -152,49 +150,88 @@ 5. Tagged command queueing -Some SCSI devices do not properly support tagged command queuing. A -safe configuration is to not enable tagged command queuing support at -boot-up, and to enable support of it with the control command -"settags" described further in this text. - -Once you are sure that all your devices properly support tagged -command queuing, you can enable it by default with the -CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE configuration option. +Queuing more than 1 command at a time to a device allows it to perform +optimizations based on actual head positions and its mechanical +characteristics. This feature may also reduce average command latency. +In order to really gain advantage of this feature, devices must have +a reasonnable cache size (No miracle is to be expected for a low-end +hard disk with 128 KB or less). +Some kown SCSI devices do not properly support tagged command queuing. +Generally, firmware revisions that fix this kind of problems are available +at respective vendor web/ftp sites. +All I can say is that the hard disks I use on my machines behave well with +this driver with tagged command queuing enabled: + +- IBM S12 0662 +- Conner 1080S +- Quantum Atlas I +- Quantum Atlas II + +If your controller has NVRAM, you can configure this feature per target +from the user setup tool. The Tekram Setup program allows to tune the +maximum number of queued commands up to 32. The Symbios Setup only allows +to enable or disable this feature. The maximum number of simultaneous tagged commands queued to a device -is currently set to 4 by default. It is defined in the file -ncr53c8xx.h by SCSI_NCR_MAX_TAGS. This value is suitable for most SCSI -disks. With large SCSI disks (> 2GB, cache > 512KB average seek time -< 10 ms), 8 tagged commands may give better performance. +is currently set to 8 by default. This value is suitable for most SCSI +disks. With large SCSI disks (>= 2GB, cache >= 512KB, average seek time +<= 10 ms), using a larger value may give better performances. +The driver supports up to 64 commands per device, but using more than +32 is generally not worth it, unless you are using a very large disk +or disk array. + +If your controller does not have NVRAM or if it is managed by the SDMS +BIOS/SETUP, you can configure tagged queueing feature and device queue +depths from the boot command-line. For example: + + ncr53c8xx=tags:4/t2t3q15-t4q7/t1u0q32 + +will set tagged commands queue depths as follow: + +- target 2 all luns on controller 0 --> 15 +- target 3 all luns on controller 0 --> 15 +- target 4 all luns on controller 0 --> 7 +- target 1 lun 0 on controller 1 --> 32 +- all other target/lun --> 4 In some special conditions, some SCSI disk firmwares may return a QUEUE FULL status for a SCSI command. This behaviour is managed by the -driver by the following heuristic: +driver using the following heuristic: -- Each time a QUEUE FULL status is returned, tagged command queueing is - temporarily disabled. +- Each time a QUEUE FULL status is returned, tagged queue depth is reduced + to the actual number of disconnected commands. -- Every 100 successfully completed SCSI commands, if allowed by the - current limit, the maximum number of queueable commands is - incremented and tagged command queueing is reenabled. +- Every 1000 successfully completed SCSI commands, if allowed by the + current limit, the maximum number of queueable commands is incremented. +Since QUEUE FULL status reception and handling is resource wasting, the +driver notifies by default this problem to user by indicating the actual +number of commands used and their status, as well as its decision on the +device queue depth change. +The heuristic used by the driver in handling QUEUE FULL ensures that the +impact on performances is not too bad. You can get rid of the messages by +setting verbose level to zero, as follow: + +1st method: boot your system using 'ncr53c8xx=verb:0' option. +2nd method: apply "setverbose 0" control command to the proc fs entry + corresponding to your controller after boot-up. 6. Parity checking The driver supports SCSI parity checking and PCI bus master parity checking. These features must be enabled in order to ensure safe data transfers. However, some flawed devices or mother boards will have -problems with parity. You can disable parity by choosing first -"CONFIG_EXPERIMENTAL". Then, "make config" will allow to set the -following configuration options: - - CONFIG_SCSI_NCR53C8XX_DISABLE_PARITY_CHECK (disable SCSI parity checking) - CONFIG_SCSI_NCR53C8XX_DISABLE_MPARITY_CHECK (disable master parity checking) - +problems with parity. You can disable either PCI parity or SCSI parity +checking by entering appropriate options from the boot command line. +(See 10: Boot setup commands). 7. Profiling information Profiling information is available through the proc SCSI file system. +Since gathering profiling information may impact performances, this +feature is disabled by default and requires a compilation configuration +option to be set to Y. + The device associated with a host has the following pathname: /proc/scsi/ncr53c8xx/N (N=0,1,2 ....) @@ -346,7 +383,7 @@ target: target number tags: number of concurrent tagged commands - must not be greater than SCSI_NCR_MAX_TAGS (default: 4) + must not be greater than SCSI_NCR_MAX_TAGS (default: 8) 8.4 Set order type for tagged command @@ -404,26 +441,12 @@ will allow disconnection for all devices on the SCSI bus. -8.8 Debug error recovery +8.8 Set verbose level - debug_error_recovery + setverbose #level - Available error type to trigger: - sge: SCSI gross error - abort: abort command from the middle-level driver - reset: reset command from the middle-level driver - parity: scsi parity detected in DATA IN phase - none: restore driver normal behaviour - - The code corresponding to this feature is normally not compiled. - Its purpose is driver testing only. In order to compile the code - that allows to trigger error recovery you must define at compile time - SCSI_NCR_DEBUG_ERROR_RECOVERY. - If you have compiled the driver with this option, nothing will happen - as long as you donnot use the control command 'debug_error_recovery' - with sge, abort, reset or parity as argument. - If you select an error type, it will be triggered by the driver every - 30 seconds. + The driver default verbose level is 1. This command allows to change + th driver verbose level after boot-up. 9. Configuration parameters @@ -433,6 +456,11 @@ support by the driver of this feature at linux start-up and enable this feature after boot-up only for devices that support it safely. +CONFIG_SCSI_NCR53C8XX_PROFILE_SUPPORT (default answer: n) + This option must be set for profiling information to be gathered + and printed out through the proc file system. This features may + impact performances. + CONFIG_SCSI_NCR53C8XX_IOMAPPED (default answer: n) Answer "y" if you suspect your mother board to not allow memory mapped I/O. May slow down performance a little. This option is required by @@ -440,13 +468,12 @@ suffers no performance loss with this option since all IO is memory mapped anyway. -CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE (default answer: n) - Answer "y" if you are sure that all your SCSI devices that are able to - accept tagged commands will proceed safely. +CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS (default answer: 8) + Default tagged command queue depth. -CONFIG_SCSI_NCR53C8XX_MAX_TAGS (default answer: 4) +CONFIG_SCSI_NCR53C8XX_MAX_TAGS (default answer: 8) This option allows you to specify the maximum number of tagged commands - that can be queued to a device. + that can be queued to a device. The maximum supported value is 32. CONFIG_SCSI_NCR53C8XX_SYNC (default answer: 5) This option allows you to specify the frequency in MHz the driver @@ -535,8 +562,8 @@ disc:n disabled Special features - Only apply to 810A, 825A, 860 and 875 controllers. - Have no effect with normal 810 and 825. + Only apply to 810A, 825A, 860, 875 and 895 controllers. + Have no effect with other ones. specf:y (or 1) enabled specf:n (or 0) disabled specf:3 enabled except Memory Write And Invalidate @@ -545,17 +572,25 @@ Invalidate. Ultra SCSI support - Only apply to 860 and 875 controllers. + Only apply to 860, 875 and 895 controllers. Have no effect with other ones. - ultra:y enabled + ultra:2 Ultra2 enabled + ultra:1 Ultra enabled ultra:n disabled -Number of tagged commands +Default number of tagged commands tags:0 (or tags:1 ) tagged command queuing disabled tags:#tags (#tags > 1) tagged command queuing enabled #tags will be truncated to the max queued commands configuration parameter. - If the driver is configured with a maximum of 4 queued commands, tags:4 is - the right argument to specify. + This option also allows to specify a command queue depth for each device + that support tagged command queueing. + Example: + ncr53c8xx=tags:10/t2t3q16-t5q24/t1u2q32 + will set devices queue depth as follow: + - controller #0 target #2 and target #3 -> 16 commands, + - controller #0 target #5 -> 24 commands, + - controller #1 target #1 logical unit #2 -> 32 commands, + - all other logical units (all targets, all controllers) -> 10 commands. Default synchronous period factor sync:255 disabled (asynchronous transfer mode) @@ -692,7 +727,7 @@ If the driver has been configured with default options, the equivalent boot setup is: - ncr53c8xx=mpar:y,spar:y,disc:y,specf:3,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\ + ncr53c8xx=mpar:y,spar:y,disc:y,specf:3,fsn:n,ultra:2,fsn:n,revprob:n,verb:1\ tags:0,sync:50,debug:0,burst:7,led:0,wide:1,settle:2,diff:0,irqm:0 For an installation diskette or a safe but not fast system, @@ -705,8 +740,8 @@ My personnal system works flawlessly with the following equivalent setup: - ncr53c8xx=mpar:y,spar:y,disc:y,specf:1,fsn:n,ultra:y,fsn:n,revprob:n,verb:1\ - tags:8,sync:12,debug:0,burst:7,led:1,wide:1,settle:2,diff:0,irqm:0 + ncr53c8xx=mpar:y,spar:y,disc:y,specf:1,fsn:n,ultra:2,fsn:n,revprob:n,verb:1\ + tags:32,sync:12,debug:0,burst:7,led:1,wide:1,settle:2,diff:0,irqm:0 The driver prints its actual setup when verbosity level is 2. You can try "ncr53c8xx=verb:2" to get the "static" setup of the driver, or add "verb:2" @@ -723,8 +758,8 @@ Use 'pcifix:3' in order to allow the driver to fix both PCI features. -These options only apply to new SYMBIOS chips 810A, 825A, 860 and 875 -and are only supported for Pentium and 486 class processors. +These options only apply to new SYMBIOS chips 810A, 825A, 860, 875 +and 895 and are only supported for Pentium and 486 class processors. Recent SYMBIOS 53C8XX scsi processors are able to use PCI read multiple and PCI write and invalidate commands. These features require the cache line size register to be properly set in the PCI configuration @@ -737,7 +772,7 @@ Optimized PCI accesses may be broken for some PCI/memory controllers or make problems with some PCI boards. -This fix-up works flawlessly on my system. +This fix-up worked flawlessly on my previous system. (MB Triton HX / 53C875 / 53C810A) I use these options at my own risks as you will do if you decide to use them too. @@ -812,17 +847,12 @@ change other "defines", you must edit the header file. Do that only if you know what you are doing. -SCSI_NCR_SETUP_ULTRA_SUPPORT (default: defined) - Ultra SCSI support. - Can be changed by the following boot setup command: - ncr53c8xx=ultra:n - SCSI_NCR_SETUP_SPECIAL_FEATURES (default: defined) If defined, the driver will enable some special features according to chip and revision id. - For 810A, 860, 825A and 875 scsi chips, this option enables support - of features that reduce load of PCI bus and memory accesses during - scsi transfer processing: burst op-code fetch, read multiple, + For 810A, 860, 825A, 875 and 895 scsi chips, this option enables + support of features that reduce load of PCI bus and memory accesses + during scsi transfer processing: burst op-code fetch, read multiple, read line, prefetch, cache line line, write and invalidate, burst 128 (875 only), large dma fifo (875 only), offset 16 (875 only). Can be changed by the following boot setup command: @@ -834,7 +864,7 @@ SCSI_NCR_SHARE_IRQ (default: defined) If defined, request shared IRQ. -SCSI_NCR_MAX_TAGS (default: 4) +SCSI_NCR_MAX_TAGS (default: 8) Maximum number of simultaneous tagged commands to a device. Can be changed by "settags " @@ -843,7 +873,7 @@ negotiation. 0 means asynchronous. Can be changed by "setsync " -SCSI_NCR_SETUP_DEFAULT_TAGS (default: 4) +SCSI_NCR_SETUP_DEFAULT_TAGS (default: 8) Default number of simultaneous tagged commands to a device. < 1 means tagged command queuing disabled at start-up. @@ -864,7 +894,7 @@ SCSI_NCR_SETUP_MASTER_PARITY (default: defined) If defined, SCSI parity checking is enabled. -SCSI_NCR_PROFILE (default: defined) +SCSI_NCR_PROFILE_SUPPORT (default: not defined) If defined, profiling information is gathered. SCSI_NCR_MAX_SCATTER (default: 128) @@ -899,67 +929,28 @@ 12. Installation -12.1 Provided files +This driver is part of the linux kernel distribution. +Driver files are located in the sub-directory "drivers/scsi" of the +kernel source tree. -Driver and common files: +Driver files: README.ncr53c8xx : this file ChangeLog.ncr53c8xx : change log - ConfigHelp.ncr53c8xx : Part of Configure.help about the driver ncr53c8xx.h : definitions ncr53c8xx.c : the driver code - scsitag.c : command tool to enable tagged queue - conf.modules : sample of /etc/conf.modules - - Install.ncr53c8xx : installation script - - Patch-1.2.13.ncr53c8xx : patch for linux-1.2.13 - Patch-2.0.29.ncr53c8xx : patch for linux-2.0.29 - -You must untar the distribution with the following command: - - tar zxvf ncrBsd2Linux-2.2b-src.tar.gz - -The sub-directory ncr53c8xx-2.2b will be created. Change to this directory. - - -12.2 Installation procedure - -This install script has been tested with linux-1.2.13 and 2.0.29. - -This procedure copies the new driver files to the kernel tree and -applies a patch to some files of the kernel tree. - - If your linux directory is at the standard location - "/usr/src/linux", just enter: - Install.ncr53c8xx - - Else enter: - Install.ncr53c8xx - - Make the kernel: - Change to linux source directory - Configure with NCR53C7,8XX support = N - Configure with NCR53C8XX support = Y (or m) - Make dependencies - Make the kernel (use make zdisk first) - Make and install modules if you have configured with 'm' - - -13. Control commands under linux-1.2.13 -Profiling data and control commands using the proc SCSI file system -are not available for linux-1.2.13. The only control command -available is "scsitag" which allows you to enable tagged command -queuing support after linux boot-up. +New driver versions are made available separately in order to allow testing +changes and new features prior to including them into the linux kernel +distribution. The following URL provides informations on latest avalaible +patches: -Tagged command queueing is disabled by default at system startup. + ftp://ftp.tux.org/pub/people/gerard-roudier/README -You can enable tagged queue per device with the following command: - scsitag device_name (ex: scsitag /dev/sda) +13. Architecture dependant features. -Use "cc -o scsitag scsitag.c" to create the "scsitag" executable. + 14. Known problems @@ -1079,7 +1070,7 @@ Will reset flags (no_sync) for target 3, and so will allow it to disconnect the SCSI Bus. -- echo "settags 3 4" >/proc/scsi/ncr53c8xx/0 +- echo "settags 3 8" >/proc/scsi/ncr53c8xx/0 Will enable tagged command queuing for target 3 if that device supports it. Once you have found the device and the feature that cause problems, just @@ -1100,12 +1091,14 @@ 1 Mega-transfers/second means 1 MB/s with 8 bits SCSI and 2 MB/s with Wide16 SCSI. -16.1 Synchronous timings for 53C875 and 53C860 Ultra-SCSI controllers +16.1 Synchronous timings for 53C895, 53C875 and 53C860 SCSI controllers ---------------------------------------------- Negotiated NCR settings Factor Period Speed Period Speed ------ ------ ------ ------ ------ + 10 25 40.000 25 40.000 (53C895 only) + 11 30.2 33.112 31.25 32.000 (53C895 only) 12 50 20.000 50 20.000 13 52 19.230 62 16.000 14 56 17.857 62 16.000 diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/hosts.c linux/drivers/scsi/hosts.c --- v2.1.107/linux/drivers/scsi/hosts.c Tue Jun 23 10:01:24 1998 +++ linux/drivers/scsi/hosts.c Sun Jun 28 16:00:41 1998 @@ -501,7 +501,7 @@ /* If we are removing the last host registered, it is safe to reuse * its host number (this avoids "holes" at boot time) (DB) */ - if (max_scsi_hosts == next_scsi_host && !scsi_loadable_module_flag) + if (max_scsi_hosts == next_scsi_host) max_scsi_hosts--; next_scsi_host--; diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/ncr53c8xx.c linux/drivers/scsi/ncr53c8xx.c --- v2.1.107/linux/drivers/scsi/ncr53c8xx.c Tue Jun 23 10:01:24 1998 +++ linux/drivers/scsi/ncr53c8xx.c Tue Jun 30 22:37:53 1998 @@ -63,11 +63,17 @@ ** August 18 1997 by Cort : ** Support for Power/PC (Big Endian). ** +** June 20 1998 by Gerard Roudier : +** Support for up to 64 tags per lun. +** O(1) everywhere (C and SCRIPTS) for normal cases. +** Low PCI traffic for command handling when on-chip RAM is present. +** Aggressive SCSI SCRIPTS optimizations. +** ******************************************************************************* */ /* -** 2 January 1998, version 2.5f +** 28 June 1998, version 3.0e ** ** Supported SCSI-II features: ** Synchronous negotiation @@ -92,9 +98,7 @@ ** Shared IRQ (since linux-1.3.72) */ -#define SCSI_NCR_DEBUG_FLAGS (0) - -#define NCR_GETCC_WITHMSG +#define SCSI_NCR_DEBUG_FLAGS (0) /*========================================================== ** @@ -112,7 +116,9 @@ #include #include #include +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) #include +#endif #include #include #include @@ -127,16 +133,11 @@ #include #include -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) #include -#else -#include "../block/blk.h" -#endif #if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,35) #include #else -#include #ifndef __initdata #define __initdata #endif @@ -145,6 +146,10 @@ #endif #endif +#if LINUX_VERSION_CODE <= LinuxVersionCode(2,1,92) +#include +#endif + #include "scsi.h" #include "hosts.h" #include "constants.h" @@ -161,6 +166,159 @@ /*========================================================== ** +** A la VMS/CAM-3 queue management. +** Implemented from linux list management. +** +**========================================================== +*/ + +typedef struct xpt_quehead { + struct xpt_quehead *flink; /* Forward pointer */ + struct xpt_quehead *blink; /* Backward pointer */ +} XPT_QUEHEAD; + +#define xpt_que_init(ptr) do { \ + (ptr)->flink = (ptr); (ptr)->blink = (ptr); \ +} while (0) + +static inline void __xpt_que_add(struct xpt_quehead * new, + struct xpt_quehead * blink, + struct xpt_quehead * flink) +{ + flink->blink = new; + new->flink = flink; + new->blink = blink; + blink->flink = new; +} + +static inline void __xpt_que_del(struct xpt_quehead * blink, + struct xpt_quehead * flink) +{ + flink->blink = blink; + blink->flink = flink; +} + +static inline int xpt_que_empty(struct xpt_quehead *head) +{ + return head->flink == head; +} + +static inline void xpt_que_splice(struct xpt_quehead *list, + struct xpt_quehead *head) +{ + struct xpt_quehead *first = list->flink; + + if (first != list) { + struct xpt_quehead *last = list->blink; + struct xpt_quehead *at = head->flink; + + first->blink = head; + head->flink = first; + + last->flink = at; + at->blink = last; + } +} + +#define xpt_que_entry(ptr, type, member) \ + ((type *)((char *)(ptr)-(unsigned long)(&((type *)0)->member))) + + +#define xpt_insque(new, pos) __xpt_que_add(new, pos, (pos)->flink) + +#define xpt_remque(el) __xpt_que_del((el)->blink, (el)->flink) + +#define xpt_insque_head(new, head) __xpt_que_add(new, head, (head)->flink) + +static inline struct xpt_quehead *xpt_remque_head(struct xpt_quehead *head) +{ + struct xpt_quehead *elem = head->flink; + + if (elem != head) + __xpt_que_del(head, elem->flink); + else + elem = 0; + return elem; +} + +#define xpt_insque_tail(new, head) __xpt_que_add(new, (head)->blink, head) + +static inline struct xpt_quehead *xpt_remque_tail(struct xpt_quehead *head) +{ + struct xpt_quehead *elem = head->blink; + + if (elem != head) + __xpt_que_del(elem->blink, head); + else + elem = 0; + return elem; +} + +/*========================================================== +** +** The CCB done queue uses an array of CCB virtual +** addresses. Empty entries are flagged using the bogus +** virtual address 0xffffffff. +** +** Since PCI ensures that only aligned DWORDs are accessed +** atomically, 64 bit little-endian architecture requires +** to test the high order DWORD of the entry to determine +** if it is empty or valid. +** +** BTW, I will make things differently as soon as I will +** have a better idea, but this is simple and should work. +** +**========================================================== +*/ + +#define SCSI_NCR_CCB_DONE_SUPPORT +#ifdef SCSI_NCR_CCB_DONE_SUPPORT + +#define MAX_DONE 24 +#define CCB_DONE_EMPTY 0xffffffffUL + +/* All 32 bit architectures */ +#if (~0UL) == 0xffffffffUL +#define CCB_DONE_VALID(cp) (((u_long) cp) != CCB_DONE_EMPTY) + +/* All > 32 bit (64 bit) architectures regardless endian-ness */ +#else +#define CCB_DONE_VALID(cp) \ + ((((u_long) cp) & 0xffffffff00000000ul) && \ + (((u_long) cp) & 0xfffffffful) != CCB_DONE_EMPTY) +#endif + +#endif /* SCSI_NCR_CCB_DONE_SUPPORT */ + +/*========================================================== +** +** On x86 architecture, write buffers management does +** not reorder writes to memory. So, using compiler +** optimization barriers is enough to guarantee some +** ordering when the CPU is writing data accessed by +** the NCR. +** On Alpha architecture, explicit memory barriers have +** to be used. +** Other architectures are defaulted to mb() macro if +** defined, otherwise use compiler barrier. +** +**========================================================== +*/ + +#if defined(__i386__) +#define MEMORY_BARRIER() barrier() +#elif defined(__alpha__) +#define MEMORY_BARRIER() mb() +#else +# ifdef mb +# define MEMORY_BARRIER() mb() +# else +# define MEMORY_BARRIER() barrier() +# endif +#endif + +/*========================================================== +** ** Configuration and Debugging ** **========================================================== @@ -182,13 +340,44 @@ */ #ifndef SCSI_NCR_MAX_TAGS -#define SCSI_NCR_MAX_TAGS (4) +#define SCSI_NCR_MAX_TAGS (8) +#endif + +/* +** TAGS are actually limited to 64 tags/lun. +** We need to deal with power of 2, for alignment constraints. +*/ +#if SCSI_NCR_MAX_TAGS > 64 +#undef SCSI_NCR_MAX_TAGS +#define SCSI_NCR_MAX_TAGS (64) +#endif + +#define NO_TAG (255) + +/* +** For more than 32 TAGS support, we do some address calculation +** from the SCRIPTS using 2 additionnal SCR_COPY's and a fiew +** bit handling on 64 bit integers. For these reasons, support for +** 32 up to 64 TAGS is compiled conditionnaly. +*/ + +#if SCSI_NCR_MAX_TAGS <= 32 +struct nlink { + ncrcmd l_cmd; + ncrcmd l_paddr; +}; +#else +struct nlink { + ncrcmd l_paddr; +}; +typedef u64 u_int64; #endif + /* ** Number of targets supported by the driver. ** n permits target numbers 0..n-1. -** Default is 7, meaning targets #0..#6. +** Default is 16, meaning targets #0..#15. ** #7 .. is myself. */ @@ -234,10 +423,23 @@ /* ** The maximum number of segments a transfer is split into. +** We support up to 127 segments for both read and write. +** The data scripts are broken into 2 sub-scripts. +** 80 (MAX_SCATTERL) segments are moved from a sub-script +** in on-chip RAM. This makes data transfers shorter than +** 80k (assuming 1k fs) as fast as possible. */ #define MAX_SCATTER (SCSI_NCR_MAX_SCATTER) +#if (MAX_SCATTER > 80) +#define MAX_SCATTERL 80 +#define MAX_SCATTERH (MAX_SCATTER - MAX_SCATTERL) +#else +#define MAX_SCATTERL (MAX_SCATTER-1) +#define MAX_SCATTERH 1 +#endif + /* ** Io mapped or memory mapped. */ @@ -267,7 +469,6 @@ ** Obvious definitions */ -#define printf printk #define u_char unsigned char #define u_short unsigned short #define u_int unsigned int @@ -282,25 +483,77 @@ #ifndef bzero #define bzero(d, n) memset((d), 0, (n)) #endif - + #ifndef offsetof #define offsetof(t, m) ((size_t) (&((t *)0)->m)) #endif /* +** SMP threading. +** +** Assuming that SMP systems are generally high end systems and may +** use several SCSI adapters, we are using one lock per controller +** instead of some global one. For the moment (linux-2.1.95), driver's +** entry points are called with the 'io_request_lock' lock held, so: +** - We are uselessly loosing a couple of micro-seconds to lock the +** controller data structure. +** - But the driver is not broken by design for SMP and so can be +** more resistant to bugs or bad changes in the IO sub-system code. +** - A small advantage could be that the interrupt code is grained as +** wished (e.g.: threaded by controller). +*/ + +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) + +#if 0 /* not yet needed */ +static spinlock_t driver_lock; +#define NCR_LOCK_DRIVER(flags) spin_lock_irqsave(&driver_lock, flags) +#define NCR_UNLOCK_DRIVER(flags) spin_unlock_irqrestore(&driver_lock, flags) +#endif + +#define NCR_INIT_LOCK_NCB(np) spin_lock_init(&np->smp_lock); +#define NCR_LOCK_NCB(np, flags) spin_lock_irqsave(&np->smp_lock, flags) +#define NCR_UNLOCK_NCB(np, flags) spin_unlock_irqrestore(&np->smp_lock, flags) + +# if LINUX_VERSION_CODE < LinuxVersionCode(2,3,99) + +# define NCR_LOCK_SCSI_DONE(np, flags) \ + spin_lock_irqsave(&io_request_lock, flags) +# define NCR_UNLOCK_SCSI_DONE(np, flags) \ + spin_unlock_irqrestore(&io_request_lock, flags) + +# else + +# define NCR_LOCK_SCSI_DONE(np, flags) do {;} while (0) +# define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0) + +# endif + +#else + +#if 0 /* not yet needed */ +#define NCR_LOCK_DRIVER(flags) do {;} while (0) +#define NCR_UNLOCK_DRIVER(flags) do {;} while (0) +#endif + +#define NCR_INIT_LOCK_NCB(np) do { } while (0) +#define NCR_LOCK_NCB(np, flags) do { save_flags(flags); cli(); } while (0) +#define NCR_UNLOCK_NCB(np, flags) do { restore_flags(flags); } while (0) + +#define NCR_LOCK_SCSI_DONE(np, flags) do {;} while (0) +#define NCR_UNLOCK_SCSI_DONE(np, flags) do {;} while (0) + +#endif + +/* ** Address translation ** -** On Linux 1.3.X, virt_to_bus() must be used to translate -** virtual memory addresses of the kernel data segment into -** IO bus adresses. -** On i386 architecture, IO bus addresses match the physical -** addresses. But on other architectures they can be different. -** In the original Bsd driver, vtophys() is called to translate -** data addresses to IO bus addresses. In order to minimize -** change, I decide to define vtophys() as virt_to_bus(). +** The driver has to provide physical memory addresses to +** the script processor. Because some architectures use +** different physical addresses from the PCI BUS, we must +** use virt_to_bus instead of virt_to_phys. */ -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) #define vtophys(p) virt_to_bus(p) /* @@ -314,12 +567,18 @@ ** architecture. */ +#if LINUX_VERSION_CODE < LinuxVersionCode(2,1,0) +#define ioremap vremap +#define iounmap vfree +#endif + #ifdef __sparc__ #define remap_pci_mem(base, size) ((vm_offset_t) __va(base)) #define unmap_pci_mem(vaddr, size) #define pcivtophys(p) ((p) & pci_dvma_mask) #else /* __sparc__ */ #define pcivtophys(p) (p) + #ifndef NCR_IOMAPPED __initfunc( static vm_offset_t remap_pci_mem(u_long base, u_long size) @@ -327,13 +586,9 @@ { u_long page_base = ((u_long) base) & PAGE_MASK; u_long page_offs = ((u_long) base) - page_base; -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) u_long page_remapped = (u_long) ioremap(page_base, page_offs+size); -#else - u_long page_remapped = (u_long) vremap(page_base, page_offs+size); -#endif - return (vm_offset_t) (page_remapped ? (page_remapped + page_offs) : 0UL); + return (vm_offset_t) (page_remapped? (page_remapped + page_offs) : 0UL); } __initfunc( @@ -341,52 +596,41 @@ ) { if (vaddr) -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,0) iounmap((void *) (vaddr & PAGE_MASK)); -#else - vfree((void *) (vaddr & PAGE_MASK)); -#endif } #endif /* !NCR_IOMAPPED */ #endif /* __sparc__ */ -#else /* linux-1.2.13 */ - /* -** Linux 1.2.X assumes that addresses (virtual, physical, bus) -** are the same. -** -** I have not found how to do MMIO. It seems that only processes can -** map high physical pages to virtual (Xservers can do MMIO). +** Insert a delay in micro-seconds and milli-seconds. +** ------------------------------------------------- +** Under Linux, udelay() is restricted to delay < 1 milli-second. +** In fact, it generally works for up to 1 second delay. +** Since 2.1.105, the mdelay() function is provided for delays +** in milli-seconds. +** Under 2.0 kernels, udelay() is an inline function that is very +** inaccurate on Pentium processors. */ -#define vtophys(p) ((u_long) (p)) +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,105) +#define UDELAY udelay +#define MDELAY mdelay +#else +static void UDELAY(long us) { udelay(us); } +static void MDELAY(long ms) { while (ms--) UDELAY(1000); } #endif /* -** Insert a delay in micro-seconds. -*/ - -static void DELAY(long us) -{ - for (;us>1000;us-=1000) udelay(1000); - if (us) udelay(us); -} - -/* ** Internal data structure allocation. ** ** Linux scsi memory poor pool is adjusted for the need of ** middle-level scsi driver. ** We allocate our control blocks in the kernel memory pool ** to avoid scsi pool shortage. -** I notice that kmalloc() returns NULL during host attach under -** Linux 1.2.13. But this ncr driver is reliable enough to -** accomodate with this joke. ** -** kmalloc() only ensure 8 bytes boundary alignment. +** kmalloc() only ensures 8 bytes boundary alignment. ** The NCR need better alignment for cache line bursting. -** The global header is moved betewen the NCB and CCBs and need +** The global header is moved between the NCB and CCBs and needs ** origin and destination addresses to have same lower four bits. ** ** We use 32 boundary alignment for NCB and CCBs and offset multiple @@ -396,17 +640,9 @@ #define ALIGN_SIZE(shift) (1UL << shift) #define ALIGN_MASK(shift) (~(ALIGN_SIZE(shift)-1)) -#define NCB_ALIGN_SHIFT 5 -#define CCB_ALIGN_SHIFT 5 -#define LCB_ALIGN_SHIFT 5 -#define SCR_ALIGN_SHIFT 5 - -#define NCB_ALIGN_SIZE ALIGN_SIZE(NCB_ALIGN_SHIFT) -#define NCB_ALIGN_MASK ALIGN_MASK(NCB_ALIGN_SHIFT) -#define CCB_ALIGN_SIZE ALIGN_SIZE(CCB_ALIGN_SHIFT) -#define CCB_ALIGN_MASK ALIGN_MASK(CCB_ALIGN_SHIFT) -#define SCR_ALIGN_SIZE ALIGN_SIZE(SCR_ALIGN_SHIFT) -#define SCR_ALIGN_MASK ALIGN_MASK(SCR_ALIGN_SHIFT) +#define CACHE_LINE_SHIFT 5 +#define CACHE_LINE_SIZE ALIGN_SIZE(CACHE_LINE_SHIFT) +#define CACHE_LINE_MASK ALIGN_MASK(CACHE_LINE_SHIFT) static void *m_alloc(int size, int a_shift) { @@ -460,11 +696,8 @@ ** be able to transfer data in the direction choosen by the target. */ -#define XferNone 0 -#define XferIn 1 -#define XferOut 2 -#define XferBoth 3 -static int guess_xfer_direction(int opcode); +#define XFER_IN (1) +#define XFER_OUT (2) /* ** Head of list of NCR boards @@ -482,45 +715,30 @@ ** /proc directory entry and proc_info function */ -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) struct proc_dir_entry proc_scsi_ncr53c8xx = { PROC_SCSI_NCR53C8XX, 9, "ncr53c8xx", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -# ifdef SCSI_NCR_PROC_INFO_SUPPORT +#ifdef SCSI_NCR_PROC_INFO_SUPPORT int ncr53c8xx_proc_info(char *buffer, char **start, off_t offset, int length, int hostno, int func); -# endif #endif /* -** Table of target capabilities. -** -** This bitmap is anded with the byte 7 of inquiry data on completion of -** INQUIRY command. -** The driver never see zeroed bits and will ignore the corresponding -** capabilities of the target. -*/ - -static struct { - unsigned char and_map[MAX_TARGET]; -} target_capabilities[SCSI_NCR_MAX_HOST] = { NCR53C8XX_TARGET_CAPABILITIES }; - -/* ** Driver setup. ** ** This structure is initialized from linux config options. ** It can be overridden at boot-up by the boot command line. */ struct ncr_driver_setup { - unsigned master_parity : 1; - unsigned scsi_parity : 1; - unsigned disconnection : 1; - unsigned special_features : 2; - unsigned ultra_scsi : 2; - unsigned force_sync_nego: 1; - unsigned reverse_probe: 1; - unsigned pci_fix_up: 4; + u_char master_parity; + u_char scsi_parity; + u_char disconnection; + u_char special_features; + u_char ultra_scsi; + u_char force_sync_nego; + u_char reverse_probe; + u_char pci_fix_up; u_char use_nvram; u_char verbose; u_char default_tags; @@ -533,6 +751,7 @@ u_char diff_support; u_char irqm; u_char bus_check; + char tag_ctrl[100]; }; static struct ncr_driver_setup @@ -552,17 +771,9 @@ #define ScsiResult(host_code, scsi_code) (((host_code) << 16) + ((scsi_code) & 0x7f)) -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0) -static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist); -#endif - -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) +static void ncr53c8xx_select_queue_depths( + struct Scsi_Host *host, struct scsi_device *devlist); static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); -static void do_ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs); -#else -static void ncr53c8xx_intr(int irq, struct pt_regs * regs); -#endif - static void ncr53c8xx_timeout(unsigned long np); #define initverbose (driver_setup.verbose) @@ -589,6 +800,7 @@ #define SYMBIOS_SCAM_ENABLE (1) #define SYMBIOS_PARITY_ENABLE (1<<1) #define SYMBIOS_VERBOSE_MSGS (1<<2) +#define SYMBIOS_CHS_MAPPING (1<<3) u_short flags1; #define SYMBIOS_SCAN_HI_LO (1) u_short word10; /* 0x00 */ @@ -685,7 +897,7 @@ int irq; /* port and reg fields to use INB, OUTB macros */ u_long port; - volatile struct ncr_reg *reg; + volatile struct ncr_reg *reg; } ncr_slot; typedef struct { @@ -758,7 +970,7 @@ #define assert(expression) { \ if (!(expression)) { \ - (void)printf(\ + (void)printk(KERN_ERR \ "assertion \"%s\" failed: file \"%s\", line %d\n", \ #expression, \ __FILE__, __LINE__); \ @@ -821,7 +1033,12 @@ ** ** Access to the controller chip. ** -** If NCR_IOMAPPED is defined, only IO are used by the driver. +** If NCR_IOMAPPED is defined, the driver will use +** normal IOs instead of the MEMORY MAPPED IO method +** recommended by PCI specifications. +** If all PCI bridges, host brigdes and architectures +** would have been correctly designed for PCI, this +** option would be useless. ** **========================================================== */ @@ -941,15 +1158,31 @@ #define HS_NEGOTIATE (2) /* sync/wide data transfer*/ #define HS_DISCONNECT (3) /* Disconnected by target */ -#define HS_COMPLETE (4) -#define HS_SEL_TIMEOUT (5) /* Selection timeout */ -#define HS_RESET (6) /* SCSI reset */ -#define HS_ABORTED (7) /* Transfer aborted */ -#define HS_TIMEOUT (8) /* Software timeout */ -#define HS_FAIL (9) /* SCSI or PCI bus errors */ -#define HS_UNEXPECTED (10) /* Unexpected disconnect */ +#define HS_DONEMASK (0x80) +#define HS_COMPLETE (4|HS_DONEMASK) +#define HS_SEL_TIMEOUT (5|HS_DONEMASK) /* Selection timeout */ +#define HS_RESET (6|HS_DONEMASK) /* SCSI reset */ +#define HS_ABORTED (7|HS_DONEMASK) /* Transfer aborted */ +#define HS_TIMEOUT (8|HS_DONEMASK) /* Software timeout */ +#define HS_FAIL (9|HS_DONEMASK) /* SCSI or PCI bus errors */ +#define HS_UNEXPECTED (10|HS_DONEMASK)/* Unexpected disconnect */ + +/* +** Invalid host status values used by the SCRIPTS processor +** when the nexus is not fully identified. +** Shall never appear in a CCB. +*/ -#define HS_DONEMASK (0xfc) +#define HS_INVALMASK (0x40) +#define HS_SELECTING (0|HS_INVALMASK) +#define HS_IN_RESELECT (1|HS_INVALMASK) +#define HS_STARTING (2|HS_INVALMASK) + +/* +** Flags set by the SCRIPT processor for commands +** that have been skipped. +*/ +#define HS_SKIPMASK (0x20) /*========================================================== ** @@ -958,21 +1191,24 @@ **========================================================== */ -#define SIR_SENSE_RESTART (1) -#define SIR_SENSE_FAILED (2) -#define SIR_STALL_RESTART (3) -#define SIR_STALL_QUEUE (4) -#define SIR_NEGO_SYNC (5) -#define SIR_NEGO_WIDE (6) -#define SIR_NEGO_FAILED (7) -#define SIR_NEGO_PROTO (8) -#define SIR_REJECT_RECEIVED (9) -#define SIR_REJECT_SENT (10) -#define SIR_IGN_RESIDUE (11) -#define SIR_MISSING_SAVE (12) -#define SIR_DATA_IO_IS_OUT (13) -#define SIR_DATA_IO_IS_IN (14) -#define SIR_MAX (14) +#define SIR_BAD_STATUS (1) +#define SIR_XXXXXXXXXX (2) +#define SIR_NEGO_SYNC (3) +#define SIR_NEGO_WIDE (4) +#define SIR_NEGO_FAILED (5) +#define SIR_NEGO_PROTO (6) +#define SIR_REJECT_RECEIVED (7) +#define SIR_REJECT_SENT (8) +#define SIR_IGN_RESIDUE (9) +#define SIR_MISSING_SAVE (10) +#define SIR_RESEL_NO_MSG_IN (11) +#define SIR_RESEL_NO_IDENTIFY (12) +#define SIR_RESEL_BAD_LUN (13) +#define SIR_RESEL_BAD_TARGET (14) +#define SIR_RESEL_BAD_I_T_L (15) +#define SIR_RESEL_BAD_I_T_L_Q (16) +#define SIR_DONE_OVERFLOW (17) +#define SIR_MAX (17) /*========================================================== ** @@ -1010,7 +1246,6 @@ #define QUIRK_NOMSG (0x02) #define QUIRK_NOSYNC (0x10) #define QUIRK_NOWIDE16 (0x20) -#define QUIRK_UPDATE (0x80) /*========================================================== ** @@ -1069,10 +1304,7 @@ #define UC_SETWIDE 14 #define UC_SETFLAG 15 #define UC_CLEARPROF 16 - -#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT -#define UC_DEBUG_ERROR_RECOVERY 17 -#endif +#define UC_SETVERBOSE 17 #define UF_TRACE (0x01) #define UF_NODISC (0x02) @@ -1085,10 +1317,11 @@ **--------------------------------------- */ +#ifdef SCSI_NCR_PROFILE_SUPPORT + struct tstamp { u_long start; u_long end; - u_long select; u_long command; u_long status; u_long disconnect; @@ -1112,263 +1345,262 @@ u_long ms_disc; u_long ms_post; }; +#endif -/*========================================================== +/*======================================================================== ** ** Declaration of structs: target control block ** -**========================================================== +**======================================================================== */ - struct tcb { - /* - ** during reselection the ncr jumps to this point - ** with SFBR set to the encoded target number - ** with bit 7 set. + /*---------------------------------------------------------------- + ** During reselection the ncr jumps to this point with SFBR + ** set to the encoded target number with bit 7 set. ** if it's not this target, jump to the next. ** - ** JUMP IF (SFBR != #target#) - ** @(next tcb) + ** JUMP IF (SFBR != #target#), @(next tcb) + **---------------------------------------------------------------- */ - struct link jump_tcb; - /* - ** load the actual values for the sxfer and the scntl3 + /*---------------------------------------------------------------- + ** Load the actual values for the sxfer and the scntl3 ** register (sync/wide mode). ** - ** SCR_COPY (1); - ** @(sval field of this tcb) - ** @(sxfer register) - ** SCR_COPY (1); - ** @(wval field of this tcb) - ** @(scntl3 register) + ** SCR_COPY (1), @(sval field of this tcb), @(sxfer register) + ** SCR_COPY (1), @(wval field of this tcb), @(scntl3 register) + **---------------------------------------------------------------- */ - ncrcmd getscr[6]; - /* - ** if next message is "identify" - ** then load the message to SFBR, - ** else load 0 to SFBR. + /*---------------------------------------------------------------- + ** Get the IDENTIFY message and load the LUN to SFBR. ** - ** CALL - ** + ** CALL, + **---------------------------------------------------------------- */ - struct link call_lun; - /* - ** now look for the right lun. + /*---------------------------------------------------------------- + ** Now look for the right lun. ** - ** JUMP - ** @(first ccb of this lun) - */ - - struct link jump_lcb; - - /* - ** pointer to interrupted getcc ccb - */ - - ccb_p hold_cp; - - /* - ** pointer to ccb used for negotiating. - ** Avoid to start a nego for all queued commands + ** For i = 0 to 3 + ** SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(first lcb mod. i) + ** + ** Recent chips will prefetch the 4 JUMPS using only 1 burst. + ** It is kind of hashcoding. + **---------------------------------------------------------------- + */ + struct link jump_lcb[4]; /* JUMPs for reselection */ + lcb_p lp[MAX_LUN]; /* The lcb's of this tcb */ + u_char inq_done; /* Target capabilities received */ + u_char inq_byte7; /* Contains these capabilities */ + + /*---------------------------------------------------------------- + ** Pointer to the ccb used for negotiation. + ** Prevent from starting a negotiation for all queued commands ** when tagged command queuing is enabled. + **---------------------------------------------------------------- */ - ccb_p nego_cp; - /* + /*---------------------------------------------------------------- ** statistical data + **---------------------------------------------------------------- */ - u_long transfers; u_long bytes; - /* - ** user settable limits for sync transfer - ** and tagged commands. - ** These limits are read from the NVRAM if present. - */ - - u_char usrsync; - u_char usrwide; - u_char usrtags; - u_char usrflag; - - u_char numtags; - u_char maxtags; - u_short num_good; - - /* - ** negotiation of wide and synch transfer. - ** device quirks. + /*---------------------------------------------------------------- + ** negotiation of wide and synch transfer and device quirks. + **---------------------------------------------------------------- */ - /*0*/ u_char minsync; /*1*/ u_char sval; /*2*/ u_short period; /*0*/ u_char maxoffs; - /*1*/ u_char quirks; - /*2*/ u_char widedone; /*3*/ u_char wval; - /* - ** inquire data - */ -#define MAX_INQUIRE 36 - u_char inqdata[MAX_INQUIRE]; - /* - ** the lcb's of this tcb + /*---------------------------------------------------------------- + ** User settable limits and options. + ** These limits are read from the NVRAM if present. + **---------------------------------------------------------------- */ - - lcb_p lp[MAX_LUN]; + u_char usrsync; + u_char usrwide; + u_char usrtags; + u_char usrflag; }; -/*========================================================== +/*======================================================================== ** ** Declaration of structs: lun control block ** -**========================================================== +**======================================================================== */ - struct lcb { - /* - ** during reselection the ncr jumps to this point + /*---------------------------------------------------------------- + ** During reselection the ncr jumps to this point ** with SFBR set to the "Identify" message. ** if it's not this lun, jump to the next. ** - ** JUMP IF (SFBR != #lun#) - ** @(next lcb of this target) - */ - - struct link jump_lcb; - - /* - ** if next message is "simple tag", - ** then load the tag to SFBR, - ** else load 0 to SFBR. + ** JUMP IF (SFBR != #lun#), @(next lcb of this target) ** - ** CALL - ** - */ - - struct link call_tag; - - /* - ** now look for the right ccb. + ** It is this lun. Load TEMP with the nexus jumps table + ** address and jump to RESEL_TAG (or RESEL_NOTAG). ** - ** JUMP - ** @(first ccb of this lun) - */ - - struct link jump_ccb; - - /* - ** start of the ccb chain - */ - - ccb_p next_ccb; - - /* - ** Control of tagged queueing - */ - - u_char reqccbs; - u_char actccbs; - u_char reqlink; - u_char actlink; - u_char usetags; - u_char lasttag; - - /* - ** Linux specific fields: - ** Number of active commands and current credit. - ** Should be managed by the generic scsi driver + ** SCR_COPY (4), p_jump_ccb, TEMP, + ** SCR_JUMP, + **---------------------------------------------------------------- */ + struct link jump_lcb; + ncrcmd load_jump_ccb[3]; + struct link jump_tag; + ncrcmd p_jump_ccb; /* Jump table bus address */ + + /*---------------------------------------------------------------- + ** Jump table used by the script processor to directly jump + ** to the CCB corresponding to the reselected nexus. + ** Address is allocated on 256 bytes boundary in order to + ** allow 8 bit calculation of the tag jump entry for up to + ** 64 possible tags. + **---------------------------------------------------------------- + */ + struct nlink jump_ccb_0; /* Default table if no tags */ + struct nlink *jump_ccb; /* Virtual address */ + + /*---------------------------------------------------------------- + ** CCB queue management. + **---------------------------------------------------------------- + */ + XPT_QUEHEAD free_ccbq; /* Queue of available CCBs */ + XPT_QUEHEAD busy_ccbq; /* Queue of busy CCBs */ + XPT_QUEHEAD wait_ccbq; /* Queue of waiting for IO CCBs */ + XPT_QUEHEAD skip_ccbq; /* Queue of skipped CCBs */ + u_char actccbs; /* Number of allocated CCBs */ + u_char busyccbs; /* CCBs busy for this lun */ + u_char queuedccbs; /* CCBs queued to the controller*/ + u_char queuedepth; /* Queue depth for this lun */ + u_char scdev_depth; /* SCSI device queue depth */ + u_char maxnxs; /* Max possible nexuses */ + + /*---------------------------------------------------------------- + ** Control of tagged command queuing. + ** Tags allocation is performed using a circular buffer. + ** This avoids using a loop for tag allocation. + **---------------------------------------------------------------- + */ + u_char ia_tag; /* Allocation index */ + u_char if_tag; /* Freeing index */ +#if SCSI_NCR_MAX_TAGS <= 32 + u_char cb_tags[32]; /* Circular tags buffer */ +#else + u_char cb_tags[64]; /* Circular tags buffer */ +#endif + u_char usetags; /* Command queuing is active */ + u_char maxtags; /* Max nr of tags asked by user */ + u_char numtags; /* Current number of tags */ + u_char inq_byte7; /* Store unit CmdQ capabitility */ + + /*---------------------------------------------------------------- + ** QUEUE FULL control and ORDERED tag control. + **---------------------------------------------------------------- + */ + u_short num_good; /* Nr of GOOD since QUEUE FULL */ +#if SCSI_NCR_MAX_TAGS <= 32 + u_int tags_umap; /* Used tags bitmap */ + u_int tags_smap; /* Tags in use at 'tag_stime' */ +#else + u_int64 tags_umap; /* Used tags bitmap */ + u_int64 tags_smap; /* Tags in use at 'tag_stime' */ +#endif + u_long tags_stime; /* Last time we set smap=umap */ + ccb_p held_ccb; /* CCB held for QUEUE FULL */ +}; - u_char active; - u_char opennings; - - /*----------------------------------------------- - ** Flag to force M_ORDERED_TAG on next command - ** in order to avoid spurious timeout when - ** M_SIMPLE_TAG is used for all operations. - **----------------------------------------------- +/*======================================================================== +** +** Declaration of structs: the launch script. +** +**======================================================================== +** +** It is part of the CCB and is called by the scripts processor to +** start or restart the data structure (nexus). +** This 6 DWORDs mini script makes use of prefetching. +** +**------------------------------------------------------------------------ +*/ +struct launch { + /*---------------------------------------------------------------- + ** SCR_COPY(4), @(p_phys), @(dsa register) + ** SCR_JUMP, @(scheduler_point) + **---------------------------------------------------------------- */ - u_char force_ordered_tag; -#define NCR_TIMEOUT_INCREASE (5*HZ) + ncrcmd setup_dsa[3]; /* Copy 'phys' address to dsa */ + struct link schedule; /* Jump to scheduler point */ + ncrcmd p_phys; /* 'phys' header bus address */ }; -/*========================================================== +/*======================================================================== ** -** Declaration of structs: COMMAND control block +** Declaration of structs: global HEADER. ** -**========================================================== +**======================================================================== ** -** This substructure is copied from the ccb to a -** global address after selection (or reselection) -** and copied back before disconnect. +** This substructure is copied from the ccb to a global address after +** selection (or reselection) and copied back before disconnect. ** ** These fields are accessible to the script processor. ** -**---------------------------------------------------------- +**------------------------------------------------------------------------ */ struct head { - /* - ** Execution of a ccb starts at this point. - ** It's a jump to the "SELECT" label - ** of the script. - ** - ** After successful selection the script - ** processor overwrites it with a jump to - ** the IDLE label of the script. - */ - - struct link launch; - - /* + /*---------------------------------------------------------------- ** Saved data pointer. - ** Points to the position in the script - ** responsible for the actual transfer - ** of data. - ** It's written after reception of a - ** "SAVE_DATA_POINTER" message. - ** The goalpointer points after - ** the last transfer command. + ** Points to the position in the script responsible for the + ** actual transfer transfer of data. + ** It's written after reception of a SAVE_DATA_POINTER message. + ** The goalpointer points after the last transfer command. + **---------------------------------------------------------------- */ - u_int32 savep; u_int32 lastp; u_int32 goalp; - /* - ** The virtual address of the ccb - ** containing this header. + /*---------------------------------------------------------------- + ** Alternate data pointer. + ** They are copied back to savep/lastp/goalp by the SCRIPTS + ** when the direction is unknown and the device claims data out. + **---------------------------------------------------------------- + */ + u_int32 wlastp; + u_int32 wgoalp; + + /*---------------------------------------------------------------- + ** The virtual address of the ccb containing this header. + **---------------------------------------------------------------- */ - ccb_p cp; - /* - ** space for some timestamps to gather - ** profiling data about devices and this driver. +#ifdef SCSI_NCR_PROFILE_SUPPORT + /*---------------------------------------------------------------- + ** Space for some timestamps to gather profiling data. + **---------------------------------------------------------------- */ - struct tstamp stamp; +#endif - /* - ** status fields. - */ - - u_char scr_st[4]; /* script status */ - u_char status[4]; /* host status. Must be the last */ - /* DWORD of the CCB header */ + /*---------------------------------------------------------------- + ** Status fields. + **---------------------------------------------------------------- + */ + u_char scr_st[4]; /* script status */ + u_char status[4]; /* host status. must be the */ + /* last DWORD of the header. */ }; /* @@ -1401,6 +1633,7 @@ #define HS_REG scr1 #define HS_PRT nc_scr1 #define SS_REG scr2 +#define SS_PRT nc_scr2 #define PS_REG scr3 /* @@ -1423,9 +1656,12 @@ ** First four bytes (host) */ #define xerr_status phys.xerr_st -#define sync_status phys.sync_st #define nego_status phys.nego_st + +#if 0 +#define sync_status phys.sync_st #define wide_status phys.wide_st +#endif /*========================================================== ** @@ -1447,9 +1683,6 @@ /* ** Header. - ** Has to be the first entry, - ** because it's jumped to by the - ** script processor */ struct head header; @@ -1460,403 +1693,276 @@ struct scr_tblsel select; struct scr_tblmove smsg ; - struct scr_tblmove smsg2 ; struct scr_tblmove cmd ; - struct scr_tblmove scmd ; struct scr_tblmove sense ; struct scr_tblmove data [MAX_SCATTER]; }; -/*========================================================== + +/*======================================================================== ** ** Declaration of structs: Command control block. ** -**========================================================== -** -** During execution of a ccb by the script processor, -** the DSA (data structure address) register points -** to this substructure of the ccb. -** This substructure contains the header with -** the script-processor-changable data and then -** data blocks for the indirect move commands. -** -**---------------------------------------------------------- +**======================================================================== */ - - struct ccb { - /* - ** This field forces 32 bytes alignement for phys.header, - ** in order to use cache line bursting when copying it - ** to the ncb. - */ - - struct link filler[2]; - - /* - ** during reselection the ncr jumps to this point. - ** If a "SIMPLE_TAG" message was received, - ** then SFBR is set to the tag. - ** else SFBR is set to 0 - ** If looking for another tag, jump to the next ccb. - ** - ** JUMP IF (SFBR != #TAG#) - ** @(next ccb of this lun) - */ - - struct link jump_ccb; - - /* - ** After execution of this call, the return address - ** (in the TEMP register) points to the following - ** data structure block. - ** So copy it to the DSA register, and start - ** processing of this data structure. - ** - ** CALL - ** - */ - - struct link call_tmp; - - /* - ** This is the data structure which is - ** to be executed by the script processor. + /*---------------------------------------------------------------- + ** This is the data structure which is pointed by the DSA + ** register when it is executed by the script processor. + ** It must be the first entry because it contains the header + ** as first entry that must be cache line aligned. + **---------------------------------------------------------------- + */ + struct dsb phys; + + /*---------------------------------------------------------------- + ** Mini-script used at CCB execution start-up. + ** Load the DSA with the data structure address (phys) and + ** jump to SELECT. Jump to CANCEL if CCB is to be canceled. + **---------------------------------------------------------------- + */ + struct launch start; + + /*---------------------------------------------------------------- + ** Mini-script used at CCB relection to restart the nexus. + ** Load the DSA with the data structure address (phys) and + ** jump to RESEL_DSA. Jump to ABORT if CCB is to be aborted. + **---------------------------------------------------------------- */ + struct launch restart; - struct dsb phys; - - /* + /*---------------------------------------------------------------- ** If a data transfer phase is terminated too early ** (after reception of a message (i.e. DISCONNECT)), ** we have to prepare a mini script to transfer ** the rest of the data. + **---------------------------------------------------------------- */ + ncrcmd patch[8]; - ncrcmd patch[8]; - - /* + /*---------------------------------------------------------------- ** The general SCSI driver provides a ** pointer to a control block. + **---------------------------------------------------------------- */ - - Scsi_Cmnd *cmd; - int data_len; - - /* - ** We prepare a message to be sent after selection, - ** and a second one to be sent after getcc selection. + Scsi_Cmnd *cmd; /* SCSI command */ + u_long tlimit; /* Deadline for this job */ + int data_len; /* Total data length */ + + /*---------------------------------------------------------------- + ** Message areas. + ** We prepare a message to be sent after selection. + ** We may use a second one if the command is rescheduled + ** due to GETCC or QFULL. ** Contents are IDENTIFY and SIMPLE_TAG. ** While negotiating sync or wide transfer, - ** a SDTM or WDTM message is appended. - */ - - u_char scsi_smsg [8]; - u_char scsi_smsg2[8]; - - /* - ** Lock this ccb. - ** Flag is used while looking for a free ccb. - */ - - u_long magic; - - /* - ** Physical address of this instance of ccb - */ - - u_long p_ccb; - - /* - ** Completion time out for this job. - ** It's set to time of start + allowed number of seconds. - */ - - u_long tlimit; - - /* - ** All ccbs of one hostadapter are chained. - */ - - ccb_p link_ccb; - - /* - ** All ccbs of one target/lun are chained. - */ - - ccb_p next_ccb; - - /* - ** Sense command - */ - - u_char sensecmd[6]; - - /* - ** Tag for this transfer. - ** It's patched into jump_ccb. - ** If it's not zero, a SIMPLE_TAG - ** message is included in smsg. + ** a SDTR or WDTR message is appended. + **---------------------------------------------------------------- */ + u_char scsi_smsg [8]; + u_char scsi_smsg2[8]; - u_char tag; - - /* - ** Number of segments of the scatter list. - ** Used for recalculation of savep/goalp/lastp on - ** SIR_DATA_IO_IS_OUT interrupt. - */ - - u_char segments; + /*---------------------------------------------------------------- + ** Other fields. + **---------------------------------------------------------------- + */ + u_long p_ccb; /* BUS address of this CCB */ + u_char sensecmd[6]; /* Sense command */ + u_char tag; /* Tag for this transfer */ + /* 255 means no tag */ + u_char target; + u_char lun; + u_char queued; + u_char auto_sense; + ccb_p link_ccb; /* Host adapter CCB chain */ + XPT_QUEHEAD link_ccbq; /* Link to unit CCB queue */ + u_int32 startp; /* Initial data pointer */ + u_long magic; /* Free / busy CCB flag */ }; #define CCB_PHYS(cp,lbl) (cp->p_ccb + offsetof(struct ccb, lbl)) -/*========================================================== + +/*======================================================================== ** ** Declaration of structs: NCR device descriptor ** -**========================================================== +**======================================================================== */ - struct ncb { - /* + /*---------------------------------------------------------------- ** The global header. - ** Accessible to both the host and the - ** script-processor. - ** Is 32 bytes aligned since ncb is, in order to - ** allow cache line bursting when copying it from or - ** to ccbs. + ** It is accessible to both the host and the script processor. + ** Must be cache line size aligned (32 for x86) in order to + ** allow cache line bursting when it is copied to/from CCB. + **---------------------------------------------------------------- */ struct head header; - /*----------------------------------------------- - ** Specific Linux fields - **----------------------------------------------- - */ - int unit; /* Unit number */ - char chip_name[8]; /* Chip name */ - char inst_name[16]; /* Instance name */ - struct timer_list timer; /* Timer link header */ - int ncr_cache; /* Cache test variable */ - Scsi_Cmnd *waiting_list; /* Waiting list header for commands */ - /* that we can't put into the squeue */ - u_long settle_time; /* Reset in progess */ - u_char release_stage; /* Synchronisation stage on release */ - u_char verbose; /* Boot verbosity for this controller*/ -#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT - u_char debug_error_recovery; - u_char stalling; - u_char assert_atn; -#endif - - /*----------------------------------------------- - ** Added field to support differences - ** between ncr chips. - ** sv_xxx are some io register bit value at start-up and - ** so assumed to have been set by the sdms bios. - ** rv_xxx are the bit fields of io register that will keep - ** the features used by the driver. - **----------------------------------------------- - */ - u_short device_id; - u_char revision_id; - - u_char sv_scntl0; - u_char sv_scntl3; - u_char sv_dmode; - u_char sv_dcntl; - u_char sv_ctest3; - u_char sv_ctest4; - u_char sv_ctest5; - u_char sv_gpcntl; - u_char sv_stest2; - u_char sv_stest4; - - u_char rv_scntl0; - u_char rv_scntl3; - u_char rv_dmode; - u_char rv_dcntl; - u_char rv_ctest3; - u_char rv_ctest4; - u_char rv_ctest5; - u_char rv_stest2; - - u_char scsi_mode; - - /*----------------------------------------------- - ** Scripts .. - **----------------------------------------------- - ** - ** During reselection the ncr jumps to this point. + /*---------------------------------------------------------------- + ** CCBs management queues. + **---------------------------------------------------------------- + */ + Scsi_Cmnd *waiting_list; /* Commands waiting for a CCB */ + /* when lcb is not allocated. */ + Scsi_Cmnd *done_list; /* Commands waiting for done() */ + /* callback to be invoked. */ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,93) + spinlock_t smp_lock; /* Lock for SMP threading */ +#endif + + /*---------------------------------------------------------------- + ** Chip and controller indentification. + **---------------------------------------------------------------- + */ + int unit; /* Unit number */ + char chip_name[8]; /* Chip name */ + char inst_name[16]; /* ncb instance name */ + + /*---------------------------------------------------------------- + ** Initial value of some IO register bits. + ** These values are assumed to have been set by BIOS, and may + ** be used for probing adapter implementation differences. + **---------------------------------------------------------------- + */ + u_char sv_scntl0, sv_scntl3, sv_dmode, sv_dcntl, sv_ctest3, sv_ctest4, + sv_ctest5, sv_gpcntl, sv_stest2, sv_stest4; + + /*---------------------------------------------------------------- + ** Actual initial value of IO register bits used by the + ** driver. They are loaded at initialisation according to + ** features that are to be enabled. + **---------------------------------------------------------------- + */ + u_char rv_scntl0, rv_scntl3, rv_dmode, rv_dcntl, rv_ctest3, rv_ctest4, + rv_ctest5, rv_stest2; + + /*---------------------------------------------------------------- + ** Targets management. + ** During reselection the ncr jumps to jump_tcb. ** The SFBR register is loaded with the encoded target id. + ** For i = 0 to 3 + ** SCR_JUMP ^ IFTRUE(MASK(i, 3)), @(next tcb mod. i) ** - ** Jump to the first target. - ** - ** JUMP - ** @(next tcb) - */ - struct link jump_tcb; - - /*----------------------------------------------- - ** Configuration .. - **----------------------------------------------- - ** - ** virtual and physical addresses - ** of the 53c810 chip. - */ - vm_offset_t vaddr; - vm_offset_t paddr; - - vm_offset_t vaddr2; - vm_offset_t paddr2; - - /* - ** pointer to the chip's registers. - */ - volatile - struct ncr_reg* reg; - - /* - ** A copy of the scripts, relocated for this ncb. - */ - struct script *script0; - struct scripth *scripth0; - - /* - ** Scripts instance virtual address. - */ - struct script *script; - struct scripth *scripth; - - /* - ** Scripts instance physical address. - */ - u_long p_script; - u_long p_scripth; - - /* - ** The SCSI address of the host adapter. - */ - u_char myaddr; - - /* - ** Max dwords burst supported by the adapter. - */ + ** Recent chips will prefetch the 4 JUMPS using only 1 burst. + ** It is kind of hashcoding. + **---------------------------------------------------------------- + */ + struct link jump_tcb[4]; /* JUMPs for reselection */ + struct tcb target[MAX_TARGET]; /* Target data */ + + /*---------------------------------------------------------------- + ** Virtual and physical bus addresses of the chip. + **---------------------------------------------------------------- + */ + vm_offset_t vaddr; /* Virtual and bus address of */ + vm_offset_t paddr; /* chip's IO registers. */ + vm_offset_t paddr2; /* On-chip RAM bus address. */ + volatile /* Pointer to volatile for */ + struct ncr_reg *reg; /* memory mapped IO. */ + + /*---------------------------------------------------------------- + ** SCRIPTS virtual and physical bus addresses. + ** 'script' is loaded in the on-chip RAM if present. + ** 'scripth' stays in main memory. + **---------------------------------------------------------------- + */ + struct script *script0; /* Copies of script and scripth */ + struct scripth *scripth0; /* relocated for this ncb. */ + struct scripth *scripth; /* Actual scripth virt. address */ + u_long p_script; /* Actual script and scripth */ + u_long p_scripth; /* bus addresses. */ + + /*---------------------------------------------------------------- + ** General controller parameters and configuration. + **---------------------------------------------------------------- + */ + u_short device_id; /* PCI device id */ + u_char revision_id; /* PCI device revision id */ + u_long port; /* IO space base address */ + u_int irq; /* IRQ level */ + u_int features; /* Chip features map */ + u_char myaddr; /* SCSI id of the adapter */ u_char maxburst; /* log base 2 of dwords burst */ - - /* - ** timing parameters - */ + u_char maxwide; /* Maximum transfer width */ u_char minsync; /* Minimum sync period factor */ u_char maxsync; /* Maximum sync period factor */ u_char maxoffs; /* Max scsi offset */ u_char multiplier; /* Clock multiplier (1,2,4) */ u_char clock_divn; /* Number of clock divisors */ u_long clock_khz; /* SCSI clock frequency in KHz */ - u_int features; /* Chip features map */ - - - /*----------------------------------------------- - ** Link to the generic SCSI driver - **----------------------------------------------- - */ - - /* struct scsi_link sc_link; */ - - /*----------------------------------------------- - ** Job control - **----------------------------------------------- - ** - ** Commands from user - */ - struct usrcmd user; - u_char order; - - /* - ** Target data - */ - struct tcb target[MAX_TARGET]; - /* - ** Start queue. - */ - u_int32 squeue [MAX_START]; - u_short squeueput; - u_short actccbs; - - /* - ** Timeout handler + /*---------------------------------------------------------------- + ** Start queue management. + ** It is filled up by the host processor and accessed by the + ** SCRIPTS processor in order to start SCSI commands. + **---------------------------------------------------------------- + */ + u_short squeueput; /* Next free slot of the queue */ + u_short actccbs; /* Number of allocated CCBs */ + u_short queuedccbs; /* Number of CCBs in start queue*/ + u_short queuedepth; /* Start queue depth */ + + /*---------------------------------------------------------------- + ** Timeout handler. + **---------------------------------------------------------------- */ -#if 0 - u_long heartbeat; - u_short ticks; - u_short latetime; -#endif + struct timer_list timer; /* Timer handler link header */ u_long lasttime; + u_long settle_time; /* Resetting the SCSI BUS */ - /*----------------------------------------------- - ** Debug and profiling - **----------------------------------------------- - ** - ** register dump - */ - struct ncr_reg regdump; - u_long regtime; - - /* - ** Profiling data + /*---------------------------------------------------------------- + ** Debugging and profiling. + **---------------------------------------------------------------- */ - struct profile profile; - u_int disc_phys; + struct ncr_reg regdump; /* Register dump */ + u_long regtime; /* Time it has been done */ +#ifdef SCSI_NCR_PROFILE_SUPPORT + struct profile profile; /* Profiling data */ + u_int disc_phys; /* Disconnection counters */ u_int disc_ref; +#endif - /* - ** The global control block. - ** It's used only during the configuration phase. - ** A target control block will be created - ** after the first successful transfer. - */ - struct ccb *ccb; - - /* - ** message buffers. - ** Should be longword aligned, - ** because they're written with a - ** COPY script command. - */ - u_char msgout[8]; - u_char msgin [8]; - u_int32 lastmsg; - - /* - ** Buffer for STATUS_IN phase. - */ - u_char scratch; - - /* - ** controller chip dependent maximal transfer width. - */ - u_char maxwide; - - /* - ** option for M_IDENTIFY message: enables disconnecting - */ - u_char disc; - - /* - ** address of the ncr control registers in io space - */ - u_long port; - - /* - ** irq level - */ - u_int irq; + /*---------------------------------------------------------------- + ** Miscellaneous buffers accessed by the scripts-processor. + ** They shall be DWORD aligned, because they may be read or + ** written with a SCR_COPY script command. + **---------------------------------------------------------------- + */ + u_char msgout[8]; /* Buffer for MESSAGE OUT */ + u_char msgin [8]; /* Buffer for MESSAGE IN */ + u_int32 lastmsg; /* Last SCSI message sent */ + u_char scratch; /* Scratch for SCSI receive */ + + /*---------------------------------------------------------------- + ** Miscellaneous configuration and status parameters. + **---------------------------------------------------------------- + */ + u_char disc; /* Diconnection allowed */ + u_char scsi_mode; /* Current SCSI BUS mode */ + u_char order; /* Tag order to use */ + u_char verbose; /* Verbosity for this controller*/ + int ncr_cache; /* Used for cache test at init. */ + + /*---------------------------------------------------------------- + ** Command completion handling. + **---------------------------------------------------------------- + */ +#ifdef SCSI_NCR_CCB_DONE_SUPPORT + struct ccb *(ccb_done[MAX_DONE]); + int ccb_done_ic; +#endif + /*---------------------------------------------------------------- + ** Fields that should be removed or changed. + **---------------------------------------------------------------- + */ + struct ccb *ccb; /* Global CCB */ + struct usrcmd user; /* Command from user */ + u_char release_stage; /* Synchronisation stage on release */ }; #define NCB_SCRIPT_PHYS(np,lbl) (np->p_script + offsetof (struct script, lbl)) -#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth, lbl)) +#define NCB_SCRIPTH_PHYS(np,lbl) (np->p_scripth + offsetof (struct scripth,lbl)) /*========================================================== ** @@ -1874,84 +1980,137 @@ ** we reach them (for forward jumps). ** Therefore we declare a struct here. ** If you make changes inside the script, -** DON'T FORGET TO CHANGE THE LENGTHS HERE! +** DONT FORGET TO CHANGE THE LENGTHS HERE! ** **---------------------------------------------------------- */ /* -** Script fragments which are loaded into the on-board RAM +** Script fragments which are loaded into the on-chip RAM ** of 825A, 875 and 895 chips. */ struct script { - ncrcmd start [ 4]; - ncrcmd start0 [ 2]; - ncrcmd start1 [ 3]; + ncrcmd start [ 5]; ncrcmd startpos [ 1]; - ncrcmd trysel [ 8]; - ncrcmd skip [ 8]; - ncrcmd skip2 [ 3]; - ncrcmd idle [ 2]; - ncrcmd select [ 22]; - ncrcmd prepare [ 4]; - ncrcmd loadpos [ 14]; - ncrcmd prepare2 [ 24]; - ncrcmd setmsg [ 5]; - ncrcmd clrack [ 2]; - ncrcmd dispatch [ 38]; + ncrcmd select [ 6]; + ncrcmd select2 [ 7]; + ncrcmd loadpos [ 4]; + ncrcmd send_ident [ 7]; + ncrcmd prepare [ 6]; + ncrcmd prepare2 [ 7]; +#ifdef SCSI_NCR_PROFILE_SUPPORT + ncrcmd command [ 9]; +#else + ncrcmd command [ 6]; +#endif + ncrcmd dispatch [ 32]; + ncrcmd clrack [ 4]; ncrcmd no_data [ 17]; - ncrcmd checkatn [ 10]; - ncrcmd command [ 15]; - ncrcmd status [ 27]; - ncrcmd msg_in [ 26]; - ncrcmd msg_bad [ 6]; - ncrcmd complete [ 13]; - ncrcmd cleanup [ 12]; - ncrcmd cleanup0 [ 11]; - ncrcmd signal [ 10]; - ncrcmd save_dp [ 5]; +#ifdef SCSI_NCR_PROFILE_SUPPORT + ncrcmd status [ 11]; +#else + ncrcmd status [ 8]; +#endif + ncrcmd msg_in [ 2]; + ncrcmd msg_in2 [ 16]; + ncrcmd msg_bad [ 4]; + ncrcmd setmsg [ 7]; + ncrcmd cleanup [ 6]; + ncrcmd complete [ 9]; + ncrcmd cleanup_ok [ 8]; + ncrcmd cleanup0 [ 1]; +#ifndef SCSI_NCR_CCB_DONE_SUPPORT + ncrcmd signal [ 12]; +#else + ncrcmd signal [ 9]; + ncrcmd done_pos [ 1]; + ncrcmd done_plug [ 2]; + ncrcmd done_end [ 7]; +#endif + ncrcmd save_dp [ 7]; ncrcmd restore_dp [ 5]; - ncrcmd disconnect [ 12]; - ncrcmd disconnect0 [ 5]; - ncrcmd disconnect1 [ 23]; +#ifdef SCSI_NCR_PROFILE_SUPPORT + ncrcmd disconnect [ 28]; +#else + ncrcmd disconnect [ 17]; +#endif ncrcmd msg_out [ 9]; ncrcmd msg_out_done [ 7]; - ncrcmd badgetcc [ 6]; + ncrcmd idle [ 2]; ncrcmd reselect [ 8]; - ncrcmd reselect1 [ 8]; - ncrcmd reselect2 [ 8]; - ncrcmd resel_tmp [ 5]; - ncrcmd resel_lun [ 18]; - ncrcmd resel_tag [ 24]; - ncrcmd data_io [ 6]; - ncrcmd data_in [MAX_SCATTER * 4 + 4]; + ncrcmd reselected [ 8]; + ncrcmd resel_dsa [ 6]; +#ifdef SCSI_NCR_PROFILE_SUPPORT + ncrcmd loadpos1 [ 7]; +#else + ncrcmd loadpos1 [ 4]; +#endif + ncrcmd resel_lun [ 6]; +#if SCSI_NCR_MAX_TAGS <= 32 + ncrcmd resel_tag [ 8]; +#else + ncrcmd resel_tag [ 6]; + ncrcmd jump_to_nexus [ 4]; + ncrcmd nexus_indirect [ 4]; +#endif +#if SCSI_NCR_MAX_TAGS <= 32 + ncrcmd resel_notag [ 4]; +#else + ncrcmd resel_notag [ 4]; +#endif + ncrcmd data_in [MAX_SCATTERL * 4]; + ncrcmd data_in2 [ 4]; + ncrcmd data_out [MAX_SCATTERL * 4]; + ncrcmd data_out2 [ 4]; }; /* ** Script fragments which stay in main memory for all chips. */ struct scripth { - ncrcmd tryloop [MAX_START*5+2]; - ncrcmd msg_parity [ 6]; + ncrcmd tryloop [MAX_START*2]; + ncrcmd tryloop2 [ 2]; +#ifdef SCSI_NCR_CCB_DONE_SUPPORT + ncrcmd done_queue [MAX_DONE*5]; + ncrcmd done_queue2 [ 2]; +#endif + ncrcmd select_no_atn [ 8]; + ncrcmd cancel [ 4]; + ncrcmd skip [ 9]; + ncrcmd skip2 [ 19]; + ncrcmd par_err_data_in [ 6]; + ncrcmd par_err_other [ 4]; ncrcmd msg_reject [ 8]; - ncrcmd msg_ign_residue [ 32]; - ncrcmd msg_extended [ 18]; - ncrcmd msg_ext_2 [ 18]; - ncrcmd msg_wdtr [ 27]; - ncrcmd msg_ext_3 [ 18]; - ncrcmd msg_sdtr [ 27]; + ncrcmd msg_ign_residue [ 24]; + ncrcmd msg_extended [ 10]; + ncrcmd msg_ext_2 [ 10]; + ncrcmd msg_wdtr [ 14]; + ncrcmd send_wdtr [ 7]; + ncrcmd msg_ext_3 [ 10]; + ncrcmd msg_sdtr [ 14]; + ncrcmd send_sdtr [ 7]; ncrcmd msg_out_abort [ 10]; - ncrcmd getcc [ 4]; - ncrcmd getcc1 [ 5]; -#ifdef NCR_GETCC_WITHMSG - ncrcmd getcc2 [ 33]; -#else - ncrcmd getcc2 [ 14]; -#endif - ncrcmd getcc3 [ 10]; - ncrcmd data_out [MAX_SCATTER * 4 + 4]; + ncrcmd hdata_in [MAX_SCATTERH * 4]; + ncrcmd hdata_in2 [ 2]; + ncrcmd hdata_out [MAX_SCATTERH * 4]; + ncrcmd hdata_out2 [ 2]; + ncrcmd reset [ 4]; ncrcmd aborttag [ 4]; - ncrcmd abort [ 22]; + ncrcmd abort [ 2]; + ncrcmd abort_resel [ 20]; + ncrcmd resend_ident [ 4]; + ncrcmd clratn_go_on [ 3]; + ncrcmd nxtdsp_go_on [ 1]; + ncrcmd sdata_in [ 8]; + ncrcmd data_io [ 18]; + ncrcmd bad_identify [ 12]; + ncrcmd bad_i_t_l [ 4]; + ncrcmd bad_i_t_l_q [ 4]; + ncrcmd bad_target [ 8]; + ncrcmd bad_status [ 8]; + ncrcmd start_ram [ 4]; + ncrcmd start_ram0 [ 4]; + ncrcmd sto_restart [ 5]; ncrcmd snooptest [ 9]; ncrcmd snoopend [ 2]; }; @@ -1965,14 +2124,19 @@ **========================================================== */ -static void ncr_alloc_ccb (ncb_p np, u_long t, u_long l); +static void ncr_alloc_ccb (ncb_p np, u_char tn, u_char ln); static void ncr_complete (ncb_p np, ccb_p cp); static void ncr_exception (ncb_p np); -static void ncr_free_ccb (ncb_p np, ccb_p cp, u_long t, u_long l); +static void ncr_free_ccb (ncb_p np, ccb_p cp); +static void ncr_init_ccb (ncb_p np, ccb_p cp); +static void ncr_init_tcb (ncb_p np, u_char tn); +static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln); +static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, + u_char *inq_data); static void ncr_getclock (ncb_p np, int mult); static void ncr_selectclock (ncb_p np, u_char scntl3); -static ccb_p ncr_get_ccb (ncb_p np, u_long t,u_long l); -static void ncr_init (ncb_p np, char * msg, u_long code); +static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln); +static void ncr_init (ncb_p np, int reset, char * msg, u_long code); static int ncr_int_sbmc (ncb_p np); static int ncr_int_par (ncb_p np); static void ncr_int_ma (ncb_p np); @@ -1980,7 +2144,6 @@ static void ncr_int_sto (ncb_p np); static u_long ncr_lookup (char* id); static void ncr_negotiate (struct ncb* np, struct tcb* tp); -static void ncr_opennings (ncb_p np, lcb_p lp, Scsi_Cmnd * xp); #ifdef SCSI_NCR_PROFILE_SUPPORT static void ncb_profile (ncb_p np, ccb_p cp); @@ -1993,13 +2156,16 @@ static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long numtags); static void ncr_getsync (ncb_p np, u_char sfac, u_char *fakp, u_char *scntl3p); static void ncr_setsync (ncb_p np, ccb_p cp, u_char scntl3, u_char sxfer); -static void ncr_settags (tcb_p tp, lcb_p lp); +static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln); static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack); static int ncr_show_msg (u_char * msg); static int ncr_snooptest (ncb_p np); static void ncr_timeout (ncb_p np); static void ncr_wakeup (ncb_p np, u_long code); -static void ncr_start_reset (ncb_p np, int settle_delay); +static void ncr_wakeup_done (ncb_p np); +static void ncr_start_next_ccb (ncb_p np, lcb_p lp, int maxn); +static void ncr_put_start_queue(ncb_p np, ccb_p cp); +static void ncr_start_reset (ncb_p np); static int ncr_reset_scsi_bus (ncb_p np, int enab_int, int settle_delay); #ifdef SCSI_NCR_USER_COMMAND_SUPPORT @@ -2088,38 +2254,17 @@ static struct script script0 __initdata = { /*--------------------------< START >-----------------------*/ { -#if 0 /* - ** Claim to be still alive ... + ** This NOP will be patched with LED ON + ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) */ - SCR_COPY (sizeof (((struct ncb *)0)->heartbeat)), - KVAR(SCRIPT_KVAR_JIFFIES), - NADDR (heartbeat), -#endif + SCR_NO_OP, + 0, /* - ** Make data structure address invalid. - ** clear SIGP. + ** Clear SIGP. */ - SCR_LOAD_REG (dsa, 0xff), - 0, SCR_FROM_REG (ctest2), 0, -}/*-------------------------< START0 >----------------------*/,{ - /* - ** Hook for interrupted GetConditionCode. - ** Will be patched to ... IFTRUE by - ** the interrupt handler. - */ - SCR_INT ^ IFFALSE (0), - SIR_SENSE_RESTART, - -}/*-------------------------< START1 >----------------------*/,{ - /* - ** Hook for stalled start queue. - ** Will be patched to IFTRUE by the interrupt handler. - */ - SCR_INT ^ IFFALSE (0), - SIR_STALL_RESTART, /* ** Then jump to a certain point in tryloop. ** Due to the lack of indirect addressing the code @@ -2128,76 +2273,6 @@ SCR_JUMP, }/*-------------------------< STARTPOS >--------------------*/,{ PADDRH(tryloop), -}/*-------------------------< TRYSEL >----------------------*/,{ - /* - ** Now: - ** DSA: Address of a Data Structure - ** or Address of the IDLE-Label. - ** - ** TEMP: Address of a script, which tries to - ** start the NEXT entry. - ** - ** Save the TEMP register into the SCRATCHA register. - ** Then copy the DSA to TEMP and RETURN. - ** This is kind of an indirect jump. - ** (The script processor has NO stack, so the - ** CALL is actually a jump and link, and the - ** RETURN is an indirect jump.) - ** - ** If the slot was empty, DSA contains the address - ** of the IDLE part of this script. The processor - ** jumps to IDLE and waits for a reselect. - ** It will wake up and try the same slot again - ** after the SIGP bit becomes set by the host. - ** - ** If the slot was not empty, DSA contains - ** the address of the phys-part of a ccb. - ** The processor jumps to this address. - ** phys starts with head, - ** head starts with launch, - ** so actually the processor jumps to - ** the lauch part. - ** If the entry is scheduled for execution, - ** then launch contains a jump to SELECT. - ** If it's not scheduled, it contains a jump to IDLE. - */ - SCR_COPY (4), - RADDR (temp), - RADDR (scratcha), - SCR_COPY (4), - RADDR (dsa), - RADDR (temp), - SCR_RETURN, - 0 - -}/*-------------------------< SKIP >------------------------*/,{ - /* - ** This entry has been canceled. - ** Next time use the next slot. - */ - SCR_COPY (4), - RADDR (scratcha), - PADDR (startpos), - /* - ** patch the launch field. - ** should look like an idle process. - */ - SCR_COPY_F (4), - RADDR (dsa), - PADDR (skip2), - SCR_COPY (8), - PADDR (idle), -}/*-------------------------< SKIP2 >-----------------------*/,{ - 0, - SCR_JUMP, - PADDR(start), -}/*-------------------------< IDLE >------------------------*/,{ - /* - ** Nothing to do? - ** Wait for reselect. - */ - SCR_JUMP, - PADDR(reselect), }/*-------------------------< SELECT >----------------------*/,{ /* @@ -2214,7 +2289,7 @@ SCR_CLR (SCR_TRG), 0, - SCR_LOAD_REG (HS_REG, 0xff), + SCR_LOAD_REG (HS_REG, HS_SELECTING), 0, /* @@ -2223,6 +2298,7 @@ SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select), PADDR (reselect), +}/*-------------------------< SELECT2 >----------------------*/,{ /* ** Now there are 4 possibilities: ** @@ -2235,50 +2311,22 @@ ** Then the script processor takes the jump ** to the RESELECT label. ** - ** (3) The ncr completes the selection. - ** Then it will execute the next statement. - ** - ** (4) There is a selection timeout. - ** Then the ncr should interrupt the host and stop. - ** Unfortunately, it seems to continue execution - ** of the script. But it will fail with an - ** IID-interrupt on the next WHEN. + ** (3) The ncr wins arbitration. + ** Then it will execute SCRIPTS instruction until + ** the next instruction that checks SCSI phase. + ** Then will stop and wait for selection to be + ** complete or selection time-out to occur. + ** As a result the SCRIPTS instructions until + ** LOADPOS + 2 should be executed in parallel with + ** the SCSI core performing selection. */ - SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)), - 0, - - /* - ** Save target id to ctest0 register - */ - - SCR_FROM_REG (sdid), - 0, - SCR_TO_REG (ctest0), - 0, - /* - ** Send the IDENTIFY and SIMPLE_TAG messages - ** (and the M_X_SYNC_REQ message) - */ - SCR_MOVE_TBL ^ SCR_MSG_OUT, - offsetof (struct dsb, smsg), -#ifdef undef /* XXX better fail than try to deal with this ... */ - SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_OUT)), - -16, -#endif - SCR_CLR (SCR_ATN), - 0, - SCR_COPY (1), - RADDR (sfbr), - NADDR (lastmsg), /* - ** Selection complete. ** Next time use the next slot. */ SCR_COPY (4), - RADDR (scratcha), + RADDR (temp), PADDR (startpos), -}/*-------------------------< PREPARE >----------------------*/,{ /* ** The ncr doesn't have an indirect load ** or store command. So we have to @@ -2298,22 +2346,30 @@ /* ** continued after the next label ... */ - }/*-------------------------< LOADPOS >---------------------*/,{ 0, NADDR (header), /* - ** Mark this ccb as not scheduled. + ** Wait for the next phase or the selection + ** to complete or time-out. */ - SCR_COPY (8), - PADDR (idle), - NADDR (header.launch), + SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_OUT)), + PADDR (prepare), + +}/*-------------------------< SEND_IDENT >----------------------*/,{ /* - ** Set a time stamp for this selection + ** Selection complete. + ** Send the IDENTIFY and SIMPLE_TAG messages + ** (and the M_X_SYNC_REQ message) */ - SCR_COPY (sizeof (u_long)), - KVAR(SCRIPT_KVAR_JIFFIES), - NADDR (header.stamp.select), + SCR_MOVE_TBL ^ SCR_MSG_OUT, + offsetof (struct dsb, smsg), + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_OUT)), + PADDRH (resend_ident), + SCR_COPY (1), + RADDR (sfbr), + NADDR (lastmsg), +}/*-------------------------< PREPARE >----------------------*/,{ /* ** load the savep (saved pointer) into ** the TEMP register (actual pointer) @@ -2327,74 +2383,61 @@ SCR_COPY (4), NADDR (header.status), RADDR (scr0), - }/*-------------------------< PREPARE2 >---------------------*/,{ /* - ** Load the synchronous mode register - */ - SCR_COPY (1), - NADDR (sync_st), - RADDR (sxfer), - /* - ** Load the wide mode and timing register - */ - SCR_COPY (1), - NADDR (wide_st), - RADDR (scntl3), - /* - ** Initialize the msgout buffer with a NOOP message. + ** Initialize the msgout buffer with a NOOP message. */ SCR_LOAD_REG (scratcha, M_NOOP), 0, SCR_COPY (1), RADDR (scratcha), NADDR (msgout), +#if 0 SCR_COPY (1), RADDR (scratcha), NADDR (msgin), +#endif /* - ** Message in phase ? + ** Anticipate the COMMAND phase. + ** This is the normal case for initial selection. */ - SCR_JUMP ^ IFFALSE (WHEN (SCR_MSG_IN)), + SCR_JUMP ^ IFFALSE (WHEN (SCR_COMMAND)), PADDR (dispatch), + +}/*-------------------------< COMMAND >--------------------*/,{ +#ifdef SCSI_NCR_PROFILE_SUPPORT /* - ** Extended or reject message ? + ** ... set a timestamp ... */ - SCR_FROM_REG (sbdl), - 0, - SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), - PADDR (msg_in), - SCR_JUMP ^ IFTRUE (DATA (M_REJECT)), - PADDRH (msg_reject), + SCR_COPY (sizeof (u_long)), + KVAR(SCRIPT_KVAR_JIFFIES), + NADDR (header.stamp.command), +#endif /* - ** normal processing + ** ... and send the command */ - SCR_JUMP, - PADDR (dispatch), -}/*-------------------------< SETMSG >----------------------*/,{ - SCR_COPY (1), - RADDR (scratcha), - NADDR (msgout), - SCR_SET (SCR_ATN), - 0, -}/*-------------------------< CLRACK >----------------------*/,{ + SCR_MOVE_TBL ^ SCR_COMMAND, + offsetof (struct dsb, cmd), /* - ** Terminate possible pending message phase. + ** If status is still HS_NEGOTIATE, negotiation failed. + ** We check this here, since we want to do that + ** only once. */ - SCR_CLR (SCR_ACK), - 0, - -}/*-----------------------< DISPATCH >----------------------*/,{ SCR_FROM_REG (HS_REG), 0, SCR_INT ^ IFTRUE (DATA (HS_NEGOTIATE)), SIR_NEGO_FAILED, + +}/*-----------------------< DISPATCH >----------------------*/,{ /* - ** remove bogus output signals + ** MSG_IN is the only phase that shall be + ** entered at least once for each (re)selection. + ** So we test it first. */ - SCR_REG_REG (socl, SCR_AND, CACK|CATN), - 0, - SCR_RETURN ^ IFTRUE (WHEN (SCR_DATA_OUT)), + SCR_JUMP ^ IFTRUE (WHEN (SCR_MSG_IN)), + PADDR (msg_in), + + SCR_RETURN ^ IFTRUE (IF (SCR_DATA_OUT)), 0, /* ** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 4. @@ -2409,16 +2452,13 @@ RADDR (scratcha), RADDR (scratcha), SCR_RETURN, - 0, - - SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), - PADDR (msg_out), - SCR_JUMP ^ IFTRUE (IF (SCR_MSG_IN)), - PADDR (msg_in), - SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)), - PADDR (command), + 0, SCR_JUMP ^ IFTRUE (IF (SCR_STATUS)), PADDR (status), + SCR_JUMP ^ IFTRUE (IF (SCR_COMMAND)), + PADDR (command), + SCR_JUMP ^ IFTRUE (IF (SCR_MSG_OUT)), + PADDR (msg_out), /* ** Discard one illegal phase byte, if required. */ @@ -2438,6 +2478,15 @@ SCR_JUMP, PADDR (dispatch), +}/*-------------------------< CLRACK >----------------------*/,{ + /* + ** Terminate possible pending message phase. + */ + SCR_CLR (SCR_ACK), + 0, + SCR_JUMP, + PADDR (dispatch), + }/*-------------------------< NO_DATA >--------------------*/,{ /* ** The target wants to tranfer too much data @@ -2467,116 +2516,31 @@ PADDR (dispatch), SCR_JUMP, PADDR (no_data), -}/*-------------------------< CHECKATN >--------------------*/,{ - /* - ** If AAP (bit 1 of scntl0 register) is set - ** and a parity error is detected, - ** the script processor asserts ATN. - ** - ** The target should switch to a MSG_OUT phase - ** to get the message. - */ - SCR_FROM_REG (socl), - 0, - SCR_JUMP ^ IFFALSE (MASK (CATN, CATN)), - PADDR (dispatch), - /* - ** count it - */ - SCR_REG_REG (PS_REG, SCR_ADD, 1), - 0, - /* - ** Prepare a M_ID_ERROR message - ** (initiator detected error). - ** The target should retry the transfer. - */ - SCR_LOAD_REG (scratcha, M_ID_ERROR), - 0, - SCR_JUMP, - PADDR (setmsg), - -}/*-------------------------< COMMAND >--------------------*/,{ - /* - ** If this is not a GETCC transfer ... - */ - SCR_FROM_REG (SS_REG), - 0, -/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (S_CHECK_COND)), - 28, - /* - ** ... set a timestamp ... - */ - SCR_COPY (sizeof (u_long)), - KVAR(SCRIPT_KVAR_JIFFIES), - NADDR (header.stamp.command), - /* - ** ... and send the command - */ - SCR_MOVE_TBL ^ SCR_COMMAND, - offsetof (struct dsb, cmd), - SCR_JUMP, - PADDR (dispatch), - /* - ** Send the GETCC command - */ -/*>>>*/ SCR_MOVE_TBL ^ SCR_COMMAND, - offsetof (struct dsb, scmd), - SCR_JUMP, - PADDR (dispatch), }/*-------------------------< STATUS >--------------------*/,{ +#ifdef SCSI_NCR_PROFILE_SUPPORT /* ** set the timestamp. */ SCR_COPY (sizeof (u_long)), KVAR(SCRIPT_KVAR_JIFFIES), NADDR (header.stamp.status), - /* - ** If this is a GETCC transfer, - */ - SCR_FROM_REG (SS_REG), - 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (S_CHECK_COND)), - 40, +#endif /* ** get the status */ SCR_MOVE_ABS (1) ^ SCR_STATUS, NADDR (scratch), /* - ** Save status to scsi_status. - ** Mark as complete. - ** And wait for disconnect. - */ - SCR_TO_REG (SS_REG), - 0, - SCR_REG_REG (SS_REG, SCR_OR, S_SENSE), - 0, - SCR_LOAD_REG (HS_REG, HS_COMPLETE), - 0, - SCR_JUMP, - PADDR (checkatn), - /* - ** If it was no GETCC transfer, - ** save the status to scsi_status. + ** save status to scsi_status. + ** mark as complete. */ -/*>>>*/ SCR_MOVE_ABS (1) ^ SCR_STATUS, - NADDR (scratch), SCR_TO_REG (SS_REG), 0, - /* - ** if it was no check condition ... - */ - SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)), - PADDR (checkatn), - /* - ** ... mark as complete. - */ SCR_LOAD_REG (HS_REG, HS_COMPLETE), 0, SCR_JUMP, - PADDR (checkatn), - + PADDR (dispatch), }/*-------------------------< MSG_IN >--------------------*/,{ /* ** Get the first byte of the message @@ -2587,28 +2551,18 @@ */ SCR_MOVE_ABS (1) ^ SCR_MSG_IN, NADDR (msgin[0]), +}/*-------------------------< MSG_IN2 >--------------------*/,{ /* - ** Check for message parity error. - */ - SCR_TO_REG (scratcha), - 0, - SCR_FROM_REG (socl), - 0, - SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDRH (msg_parity), - SCR_FROM_REG (scratcha), - 0, - /* - ** Parity was ok, handle this message. + ** Handle this message. */ SCR_JUMP ^ IFTRUE (DATA (M_COMPLETE)), PADDR (complete), + SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)), + PADDR (disconnect), SCR_JUMP ^ IFTRUE (DATA (M_SAVE_DP)), PADDR (save_dp), SCR_JUMP ^ IFTRUE (DATA (M_RESTORE_DP)), PADDR (restore_dp), - SCR_JUMP ^ IFTRUE (DATA (M_DISCONNECT)), - PADDR (disconnect), SCR_JUMP ^ IFTRUE (DATA (M_EXTENDED)), PADDRH (msg_extended), SCR_JUMP ^ IFTRUE (DATA (M_NOOP)), @@ -2632,24 +2586,42 @@ SIR_REJECT_SENT, SCR_LOAD_REG (scratcha, M_REJECT), 0, +}/*-------------------------< SETMSG >----------------------*/,{ + SCR_COPY (1), + RADDR (scratcha), + NADDR (msgout), + SCR_SET (SCR_ATN), + 0, + SCR_JUMP, + PADDR (clrack), +}/*-------------------------< CLEANUP >-------------------*/,{ + /* + ** dsa: Pointer to ccb + ** or xxxxxxFF (no ccb) + ** + ** HS_REG: Host-Status (<>0!) + */ + SCR_FROM_REG (dsa), + 0, + SCR_JUMP ^ IFTRUE (DATA (0xff)), + PADDR (start), + /* + ** dsa is valid. + ** complete the cleanup. + */ SCR_JUMP, - PADDR (setmsg), + PADDR (cleanup_ok), }/*-------------------------< COMPLETE >-----------------*/,{ /* ** Complete message. ** - ** If it's not the get condition code, - ** copy TEMP register to LASTP in header. + ** Copy TEMP register to LASTP in header. */ - SCR_FROM_REG (SS_REG), - 0, -/*<<<*/ SCR_JUMPR ^ IFTRUE (MASK (S_SENSE, S_SENSE)), - 12, SCR_COPY (4), RADDR (temp), NADDR (header.lastp), -/*>>>*/ /* + /* ** When we terminate the cycle by clearing ACK, ** the target may disconnect immediately. ** @@ -2669,20 +2641,9 @@ */ SCR_WAIT_DISC, 0, -}/*-------------------------< CLEANUP >-------------------*/,{ - /* - ** dsa: Pointer to ccb - ** or xxxxxxFF (no ccb) - ** - ** HS_REG: Host-Status (<>0!) - */ - SCR_FROM_REG (dsa), - 0, - SCR_JUMP ^ IFTRUE (DATA (0xff)), - PADDR (signal), +}/*-------------------------< CLEANUP_OK >----------------*/,{ /* - ** dsa is valid. - ** save the status registers + ** Save host status to header. */ SCR_COPY (4), RADDR (scr0), @@ -2697,43 +2658,32 @@ NADDR (header), }/*-------------------------< CLEANUP0 >--------------------*/,{ 0, - +}/*-------------------------< SIGNAL >----------------------*/,{ /* - ** If command resulted in "check condition" - ** status and is not yet completed, - ** try to get the condition code. + ** if job not completed ... */ SCR_FROM_REG (HS_REG), 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)), - 16, - SCR_FROM_REG (SS_REG), - 0, - SCR_JUMP ^ IFTRUE (DATA (S_CHECK_COND)), - PADDRH(getcc2), /* - ** And make the DSA register invalid. + ** ... start the next command. */ -/*>>>*/ SCR_LOAD_REG (dsa, 0xff), /* invalid */ - 0, -}/*-------------------------< SIGNAL >----------------------*/,{ + SCR_JUMP ^ IFTRUE (MASK (0, (HS_DONEMASK|HS_SKIPMASK))), + PADDR(start), /* - ** if status = queue full, - ** reinsert in startqueue and stall queue. + ** If command resulted in not GOOD status, + ** call the C code if needed. */ SCR_FROM_REG (SS_REG), 0, - SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)), - SIR_STALL_QUEUE, - /* - ** if job completed ... - */ - SCR_FROM_REG (HS_REG), - 0, + SCR_CALL ^ IFFALSE (DATA (S_GOOD)), + PADDRH (bad_status), + +#ifndef SCSI_NCR_CCB_DONE_SUPPORT + /* ** ... signal completion to the host */ - SCR_INT_FLY ^ IFFALSE (MASK (0, HS_DONEMASK)), + SCR_INT_FLY, 0, /* ** Auf zu neuen Schandtaten! @@ -2741,6 +2691,28 @@ SCR_JUMP, PADDR(start), +#else /* defined SCSI_NCR_CCB_DONE_SUPPORT */ + + /* + ** ... signal completion to the host + */ + SCR_JUMP, +}/*------------------------< DONE_POS >---------------------*/,{ + PADDRH (done_queue), +}/*------------------------< DONE_PLUG >--------------------*/,{ + SCR_INT, + SIR_DONE_OVERFLOW, +}/*------------------------< DONE_END >---------------------*/,{ + SCR_INT_FLY, + 0, + SCR_COPY (4), + RADDR (temp), + PADDR (done_pos), + SCR_JUMP, + PADDR (start), + +#endif /* SCSI_NCR_CCB_DONE_SUPPORT */ + }/*-------------------------< SAVE_DP >------------------*/,{ /* ** SAVE_DP message: @@ -2749,8 +2721,10 @@ SCR_COPY (4), RADDR (temp), NADDR (header.savep), + SCR_CLR (SCR_ACK), + 0, SCR_JUMP, - PADDR (clrack), + PADDR (dispatch), }/*-------------------------< RESTORE_DP >---------------*/,{ /* ** RESTORE_DP message: @@ -2764,56 +2738,6 @@ }/*-------------------------< DISCONNECT >---------------*/,{ /* - ** If QUIRK_AUTOSAVE is set, - ** do an "save pointer" operation. - */ - SCR_FROM_REG (QU_REG), - 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)), - 12, - /* - ** like SAVE_DP message: - ** Copy TEMP register to SAVEP in header. - */ - SCR_COPY (4), - RADDR (temp), - NADDR (header.savep), -/*>>>*/ /* - ** Check if temp==savep or temp==goalp: - ** if not, log a missing save pointer message. - ** In fact, it's a comparison mod 256. - ** - ** Hmmm, I hadn't thought that I would be urged to - ** write this kind of ugly self modifying code. - ** - ** It's unbelievable, but the ncr53c8xx isn't able - ** to subtract one register from another. - */ - SCR_FROM_REG (temp), - 0, - /* - ** You are not expected to understand this .. - ** - ** CAUTION: only little endian architectures supported! XXX - */ - SCR_COPY_F (1), - NADDR (header.savep), - PADDR (disconnect0), -}/*-------------------------< DISCONNECT0 >--------------*/,{ -/*<<<*/ SCR_JUMPR ^ IFTRUE (DATA (1)), - 20, - /* - ** neither this - */ - SCR_COPY_F (1), - NADDR (header.goalp), - PADDR (disconnect1), -}/*-------------------------< DISCONNECT1 >--------------*/,{ - SCR_INT ^ IFFALSE (DATA (1)), - SIR_MISSING_SAVE, -/*>>>*/ - - /* ** DISCONNECTing ... ** ** disable the "unexpected disconnect" feature, @@ -2828,6 +2752,7 @@ */ SCR_WAIT_DISC, 0, +#ifdef SCSI_NCR_PROFILE_SUPPORT /* ** Profiling: ** Set a time stamp, @@ -2838,19 +2763,35 @@ NADDR (header.stamp.disconnect), SCR_COPY (4), NADDR (disc_phys), - RADDR (temp), - SCR_REG_REG (temp, SCR_ADD, 0x01), + RADDR (scratcha), + SCR_REG_REG (scratcha, SCR_ADD, 0x01), 0, SCR_COPY (4), - RADDR (temp), + RADDR (scratcha), NADDR (disc_phys), +#endif /* ** Status is: DISCONNECTED. */ SCR_LOAD_REG (HS_REG, HS_DISCONNECT), 0, + /* + ** If QUIRK_AUTOSAVE is set, + ** do an "save pointer" operation. + */ + SCR_FROM_REG (QU_REG), + 0, + SCR_JUMP ^ IFFALSE (MASK (QUIRK_AUTOSAVE, QUIRK_AUTOSAVE)), + PADDR (cleanup_ok), + /* + ** like SAVE_DP message: + ** Copy TEMP register to SAVEP in header. + */ + SCR_COPY (4), + RADDR (temp), + NADDR (header.savep), SCR_JUMP, - PADDR (cleanup), + PADDR (cleanup_ok), }/*-------------------------< MSG_OUT >-------------------*/,{ /* @@ -2886,23 +2827,16 @@ */ SCR_JUMP, PADDR (dispatch), -}/*------------------------< BADGETCC >---------------------*/,{ - /* - ** If SIGP was set, clear it and try again. - */ - SCR_FROM_REG (ctest2), - 0, - SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)), - PADDRH (getcc2), - SCR_INT, - SIR_SENSE_FAILED, -}/*-------------------------< RESELECT >--------------------*/,{ +}/*-------------------------< IDLE >------------------------*/,{ /* + ** Nothing to do? + ** Wait for reselect. ** This NOP will be patched with LED OFF ** SCR_REG_REG (gpreg, SCR_OR, 0x01) */ SCR_NO_OP, 0, +}/*-------------------------< RESELECT >--------------------*/,{ /* ** make the DSA invalid. */ @@ -2910,6 +2844,8 @@ 0, SCR_CLR (SCR_TRG), 0, + SCR_LOAD_REG (HS_REG, HS_IN_RESELECT), + 0, /* ** Sleep waiting for a reselection. ** If SIGP is set, special treatment. @@ -2917,8 +2853,8 @@ ** Zu allem bereit .. */ SCR_WAIT_RESEL, - PADDR(reselect2), -}/*-------------------------< RESELECT1 >--------------------*/,{ + PADDR(start), +}/*-------------------------< RESELECTED >------------------*/,{ /* ** This NOP will be patched with LED ON ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) @@ -2940,38 +2876,51 @@ */ SCR_REG_SFBR (ssid, SCR_AND, 0x8F), 0, - SCR_TO_REG (ctest0), + SCR_TO_REG (sdid), 0, SCR_JUMP, NADDR (jump_tcb), -}/*-------------------------< RESELECT2 >-------------------*/,{ + +}/*-------------------------< RESEL_DSA >-------------------*/,{ /* - ** This NOP will be patched with LED ON - ** SCR_REG_REG (gpreg, SCR_AND, 0xfe) + ** Ack the IDENTIFY or TAG previously received. */ - SCR_NO_OP, + SCR_CLR (SCR_ACK), 0, /* - ** If it's not connected :( - ** -> interrupted by SIGP bit. - ** Jump to start. + ** The ncr doesn't have an indirect load + ** or store command. So we have to + ** copy part of the control block to a + ** fixed place, where we can access it. + ** + ** We patch the address part of a + ** COPY command with the DSA-register. + */ + SCR_COPY_F (4), + RADDR (dsa), + PADDR (loadpos1), + /* + ** then we do the actual copy. + */ + SCR_COPY (sizeof (struct head)), + /* + ** continued after the next label ... */ - SCR_FROM_REG (ctest2), - 0, - SCR_JUMP ^ IFTRUE (MASK (CSIGP,CSIGP)), - PADDR (start), - SCR_JUMP, - PADDR (reselect), -}/*-------------------------< RESEL_TMP >-------------------*/,{ +}/*-------------------------< LOADPOS1 >-------------------*/,{ + 0, + NADDR (header), +#ifdef SCSI_NCR_PROFILE_SUPPORT /* - ** The return address in TEMP - ** is in fact the data structure address, - ** so copy it to the DSA register. + ** Set a time stamp for this reselection + */ + SCR_COPY (sizeof (u_long)), + KVAR(SCRIPT_KVAR_JIFFIES), + NADDR (header.stamp.reselect), +#endif + /* + ** The DSA contains the data structure address. */ - SCR_COPY (4), - RADDR (temp), - RADDR (dsa), SCR_JUMP, PADDR (prepare), @@ -2981,133 +2930,123 @@ ** to get an IDENTIFY message ** Wait for a msg_in phase. */ -/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), - 48, + SCR_INT ^ IFFALSE (WHEN (SCR_MSG_IN)), + SIR_RESEL_NO_MSG_IN, /* - ** message phase - ** It's not a sony, it's a trick: - ** read the data without acknowledging it. + ** message phase. + ** Read the data directly from the BUS DATA lines. + ** This helps to support very old SCSI devices that + ** may reselect without sending an IDENTIFY. */ SCR_FROM_REG (sbdl), 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (M_IDENTIFY, 0x98)), - 32, /* - ** It WAS an Identify message. - ** get it and ack it! + ** It should be an Identify message. */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), - SCR_CLR (SCR_ACK), - 0, - /* - ** Mask out the lun. - */ - SCR_REG_REG (sfbr, SCR_AND, 0x07), - 0, - SCR_RETURN, - 0, - /* - ** No message phase or no IDENTIFY message: - ** return 0. - */ -/*>>>*/ SCR_LOAD_SFBR (0), - 0, SCR_RETURN, 0, - }/*-------------------------< RESEL_TAG >-------------------*/,{ /* - ** come back to this point - ** to get a SIMPLE_TAG message - ** Wait for a MSG_IN phase. + ** Read IDENTIFY + SIMPLE + TAG using a single MOVE. + ** Agressive optimization, is'nt it? + ** No need to test the SIMPLE TAG message, since the + ** driver only supports conformant devices for tags. ;-) */ -/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), - 64, + SCR_MOVE_ABS (3) ^ SCR_MSG_IN, + NADDR (msgin), /* - ** message phase - ** It's a trick - read the data - ** without acknowledging it. + ** Read the TAG from the SIDL. + ** Still an aggressive optimization. ;-) */ - SCR_FROM_REG (sbdl), + SCR_FROM_REG (sidl), 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (M_SIMPLE_TAG)), - 48, /* - ** It WAS a SIMPLE_TAG message. - ** get it and ack it! + ** JUMP indirectly to the restart point of the CCB. */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), - SCR_CLR (SCR_ACK), +#if SCSI_NCR_MAX_TAGS <= 32 + SCR_SFBR_REG (temp, SCR_AND, 0xf8), 0, - /* - ** Wait for the second byte (the tag) - */ -/*<<<*/ SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), - 24, - /* - ** Get it and ack it! - */ - SCR_MOVE_ABS (1) ^ SCR_MSG_IN, - NADDR (msgin), - SCR_CLR (SCR_ACK|SCR_CARRY), + SCR_RETURN, + 0, +#else + SCR_SFBR_REG (temp, SCR_AND, 0xfc), + 0, +}/*-------------------------< JUMP_TO_NEXUS >-------------------*/,{ + SCR_COPY_F (4), + RADDR (temp), + PADDR (nexus_indirect), + SCR_COPY (4), +}/*-------------------------< NEXUS_INDIRECT >-------------------*/,{ 0, + RADDR (temp), SCR_RETURN, 0, +#endif +}/*-------------------------< RESEL_NOTAG >-------------------*/,{ /* - ** No message phase or no SIMPLE_TAG message - ** or no second byte: return 0. + ** No tag expected. + ** Read an throw away the IDENTIFY. */ -/*>>>*/ SCR_LOAD_SFBR (0), - 0, - SCR_SET (SCR_CARRY), - 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), +#if SCSI_NCR_MAX_TAGS <= 32 SCR_RETURN, 0, - -}/*-------------------------< DATA_IO >--------------------*/,{ -/* -** Because Linux does not provide xfer data direction -** to low-level scsi drivers, we must trust the target -** for actual data direction when we cannot guess it. -** The programmed interrupt patches savep, lastp, goalp, -** etc.., and restarts the scsi script at data_out/in. -*/ - SCR_INT ^ IFTRUE (WHEN (SCR_DATA_OUT)), - SIR_DATA_IO_IS_OUT, - SCR_INT ^ IFTRUE (WHEN (SCR_DATA_IN)), - SIR_DATA_IO_IS_IN, +#else SCR_JUMP, - PADDR (no_data), - + PADDR (jump_to_nexus), +#endif }/*-------------------------< DATA_IN >--------------------*/,{ /* ** Because the size depends on the -** #define MAX_SCATTER parameter, +** #define MAX_SCATTERL parameter, ** it is filled in at runtime. ** -** ##===========< i=0; i========= +** ##===========< i=0; i========= ** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), -** || PADDR (checkatn), +** || PADDR (dispatch), ** || SCR_MOVE_TBL ^ SCR_DATA_IN, ** || offsetof (struct dsb, data[ i]), ** ##========================================== ** -** SCR_CALL, -** PADDR (checkatn), -** SCR_JUMP, -** PADDR (no_data), +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< DATA_IN2 >-------------------*/,{ + SCR_CALL, + PADDR (dispatch), + SCR_JUMP, + PADDR (no_data), +}/*-------------------------< DATA_OUT >--------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTERL parameter, +** it is filled in at runtime. +** +** ##===========< i=0; i========= +** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)), +** || PADDR (dispatch), +** || SCR_MOVE_TBL ^ SCR_DATA_OUT, +** || offsetof (struct dsb, data[ i]), +** ##========================================== +** +**--------------------------------------------------------- */ 0 +}/*-------------------------< DATA_OUT2 >-------------------*/,{ + SCR_CALL, + PADDR (dispatch), + SCR_JUMP, + PADDR (no_data), }/*--------------------------------------------------------*/ }; static struct scripth scripth0 __initdata = { /*-------------------------< TRYLOOP >---------------------*/{ /* -** Load an entry of the start queue into dsa -** and try to start it by jumping to TRYSEL. +** Start the next entry. +** Called addresses point to the launch script in the CCB. +** They are patched by the main processor. ** ** Because the size depends on the ** #define MAX_START parameter, it is filled @@ -3116,32 +3055,142 @@ **----------------------------------------------------------- ** ** ##===========< I=0; i=========== -** || SCR_COPY (4), -** || NADDR (squeue[i]), -** || RADDR (dsa), ** || SCR_CALL, -** || PADDR (trysel), +** || PADDR (idle), ** ##========================================== ** -** SCR_JUMP, -** PADDRH(tryloop), +**----------------------------------------------------------- +*/ +0 +}/*------------------------< TRYLOOP2 >---------------------*/,{ + SCR_JUMP, + PADDRH(tryloop), + +#ifdef SCSI_NCR_CCB_DONE_SUPPORT + +}/*------------------------< DONE_QUEUE >-------------------*/,{ +/* +** Copy the CCB address to the next done entry. +** Because the size depends on the +** #define MAX_DONE parameter, it is filled +** in at runtime. +** +**----------------------------------------------------------- +** +** ##===========< I=0; i=========== +** || SCR_COPY (sizeof(ccb_p)), +** || NADDR (header.cp), +** || NADDR (ccb_done[i]), +** || SCR_CALL, +** || PADDR (done_end), +** ##========================================== ** **----------------------------------------------------------- */ 0 -},/*-------------------------< MSG_PARITY >---------------*/{ +}/*------------------------< DONE_QUEUE2 >------------------*/,{ + SCR_JUMP, + PADDRH (done_queue), + +#endif /* SCSI_NCR_CCB_DONE_SUPPORT */ +}/*------------------------< SELECT_NO_ATN >-----------------*/,{ /* - ** count it + ** Set Initiator mode. + ** And try to select this target without ATN. */ - SCR_REG_REG (PS_REG, SCR_ADD, 0x01), + + SCR_CLR (SCR_TRG), + 0, + SCR_LOAD_REG (HS_REG, HS_SELECTING), + 0, + SCR_SEL_TBL ^ offsetof (struct dsb, select), + PADDR (reselect), + SCR_JUMP, + PADDR (select2), + +}/*-------------------------< CANCEL >------------------------*/,{ + + SCR_LOAD_REG (scratcha, HS_ABORTED), + 0, + SCR_JUMPR, + 8, +}/*-------------------------< SKIP >------------------------*/,{ + SCR_LOAD_REG (scratcha, 0), 0, /* - ** send a "message parity error" message. + ** This entry has been canceled. + ** Next time use the next slot. */ - SCR_LOAD_REG (scratcha, M_PARITY), + SCR_COPY (4), + RADDR (temp), + PADDR (startpos), + /* + ** The ncr doesn't have an indirect load + ** or store command. So we have to + ** copy part of the control block to a + ** fixed place, where we can access it. + ** + ** We patch the address part of a + ** COPY command with the DSA-register. + */ + SCR_COPY_F (4), + RADDR (dsa), + PADDRH (skip2), + /* + ** then we do the actual copy. + */ + SCR_COPY (sizeof (struct head)), + /* + ** continued after the next label ... + */ +}/*-------------------------< SKIP2 >---------------------*/,{ 0, + NADDR (header), + /* + ** Initialize the status registers + */ + SCR_COPY (4), + NADDR (header.status), + RADDR (scr0), + /* + ** Force host status. + */ + SCR_FROM_REG (scratcha), + 0, + SCR_JUMPR ^ IFFALSE (MASK (0, HS_DONEMASK)), + 16, + SCR_REG_REG (HS_REG, SCR_OR, HS_SKIPMASK), + 0, + SCR_JUMPR, + 8, + SCR_TO_REG (HS_REG), + 0, + SCR_LOAD_REG (SS_REG, S_GOOD), + 0, + SCR_JUMP, + PADDR (cleanup_ok), + +},/*-------------------------< PAR_ERR_DATA_IN >---------------*/{ + /* + ** Ignore all data in byte, until next phase + */ + SCR_JUMP ^ IFFALSE (WHEN (SCR_DATA_IN)), + PADDRH (par_err_other), + SCR_MOVE_ABS (1) ^ SCR_DATA_IN, + NADDR (scratch), + SCR_JUMPR, + -24, +},/*-------------------------< PAR_ERR_OTHER >------------------*/{ + /* + ** count it. + */ + SCR_REG_REG (PS_REG, SCR_ADD, 0x01), + 0, + /* + ** jump to dispatcher. + */ SCR_JUMP, - PADDR (setmsg), + PADDR (dispatch), }/*-------------------------< MSG_REJECT >---------------*/,{ /* ** If a negotiation was in progress, @@ -3173,17 +3222,6 @@ SCR_MOVE_ABS (1) ^ SCR_MSG_IN, NADDR (msgin[1]), /* - ** Check for message parity error. - */ - SCR_TO_REG (scratcha), - 0, - SCR_FROM_REG (socl), - 0, - SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDRH (msg_parity), - SCR_FROM_REG (scratcha), - 0, - /* ** Size is 0 .. ignore message. */ SCR_JUMP ^ IFTRUE (DATA (0)), @@ -3191,14 +3229,14 @@ /* ** Size is not 1 .. have to interrupt. */ -/*<<<*/ SCR_JUMPR ^ IFFALSE (DATA (1)), + SCR_JUMPR ^ IFFALSE (DATA (1)), 40, /* ** Check for residue byte in swide register */ SCR_FROM_REG (scntl2), 0, -/*<<<*/ SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), + SCR_JUMPR ^ IFFALSE (MASK (WSR, WSR)), 16, /* ** There IS data in the swide register. @@ -3211,9 +3249,9 @@ /* ** Load again the size to the sfbr register. */ -/*>>>*/ SCR_FROM_REG (scratcha), + SCR_FROM_REG (scratcha), 0, -/*>>>*/ SCR_INT, + SCR_INT, SIR_IGN_RESIDUE, SCR_JUMP, PADDR (clrack), @@ -3232,17 +3270,6 @@ SCR_MOVE_ABS (1) ^ SCR_MSG_IN, NADDR (msgin[1]), /* - ** Check for message parity error. - */ - SCR_TO_REG (scratcha), - 0, - SCR_FROM_REG (socl), - 0, - SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDRH (msg_parity), - SCR_FROM_REG (scratcha), - 0, - /* */ SCR_JUMP ^ IFTRUE (DATA (3)), PADDRH (msg_ext_3), @@ -3258,17 +3285,6 @@ */ SCR_MOVE_ABS (1) ^ SCR_MSG_IN, NADDR (msgin[2]), - /* - ** Check for message parity error. - */ - SCR_TO_REG (scratcha), - 0, - SCR_FROM_REG (socl), - 0, - SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDRH (msg_parity), - SCR_FROM_REG (scratcha), - 0, SCR_JUMP ^ IFTRUE (DATA (M_X_WIDE_REQ)), PADDRH (msg_wdtr), /* @@ -3286,10 +3302,6 @@ */ SCR_MOVE_ABS (1) ^ SCR_MSG_IN, NADDR (msgin[3]), - SCR_FROM_REG (socl), - 0, - SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDRH (msg_parity), /* ** let the host do the real work. */ @@ -3303,15 +3315,15 @@ SCR_CLR (SCR_ACK), 0, +/* CHECK THE SOURCE FOR 'send_wdtr' IF YOU INTEND TO CHANGE SOMETHING HERE */ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), SIR_NEGO_PROTO, +}/*-------------------------< SEND_WDTR >----------------*/,{ /* ** Send the M_X_WIDE_REQ */ SCR_MOVE_ABS (4) ^ SCR_MSG_OUT, NADDR (msgout), - SCR_CLR (SCR_ATN), - 0, SCR_COPY (1), RADDR (sfbr), NADDR (lastmsg), @@ -3328,17 +3340,6 @@ */ SCR_MOVE_ABS (1) ^ SCR_MSG_IN, NADDR (msgin[2]), - /* - ** Check for message parity error. - */ - SCR_TO_REG (scratcha), - 0, - SCR_FROM_REG (socl), - 0, - SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDRH (msg_parity), - SCR_FROM_REG (scratcha), - 0, SCR_JUMP ^ IFTRUE (DATA (M_X_SYNC_REQ)), PADDRH (msg_sdtr), /* @@ -3357,10 +3358,6 @@ */ SCR_MOVE_ABS (2) ^ SCR_MSG_IN, NADDR (msgin[3]), - SCR_FROM_REG (socl), - 0, - SCR_JUMP ^ IFTRUE (MASK (CATN, CATN)), - PADDRH (msg_parity), /* ** let the host do the real work. */ @@ -3374,15 +3371,15 @@ SCR_CLR (SCR_ACK), 0, +/* CHECK THE SOURCE FOR 'send_sdtr' IF YOU INTEND TO CHANGE SOMETHING HERE */ SCR_INT ^ IFFALSE (WHEN (SCR_MSG_OUT)), SIR_NEGO_PROTO, +}/*-------------------------< SEND_SDTR >-------------*/,{ /* ** Send the M_X_SYNC_REQ */ SCR_MOVE_ABS (5) ^ SCR_MSG_OUT, NADDR (msgout), - SCR_CLR (SCR_ATN), - 0, SCR_COPY (1), RADDR (sfbr), NADDR (lastmsg), @@ -3409,203 +3406,259 @@ SCR_JUMP, PADDR (cleanup), -}/*-------------------------< GETCC >-----------------------*/,{ +}/*-------------------------< HDATA_IN >-------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTERH parameter, +** it is filled in at runtime. +** +** ##==< i=MAX_SCATTERL; i== +** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), +** || PADDR (dispatch), +** || SCR_MOVE_TBL ^ SCR_DATA_IN, +** || offsetof (struct dsb, data[ i]), +** ##=================================================== +** +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< HDATA_IN2 >------------------*/,{ + SCR_JUMP, + PADDR (data_in), + +}/*-------------------------< HDATA_OUT >-------------------*/,{ +/* +** Because the size depends on the +** #define MAX_SCATTERH parameter, +** it is filled in at runtime. +** +** ##==< i=MAX_SCATTERL; i== +** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)), +** || PADDR (dispatch), +** || SCR_MOVE_TBL ^ SCR_DATA_OUT, +** || offsetof (struct dsb, data[ i]), +** ##=================================================== +** +**--------------------------------------------------------- +*/ +0 +}/*-------------------------< HDATA_OUT2 >------------------*/,{ + SCR_JUMP, + PADDR (data_out), + +}/*-------------------------< RESET >----------------------*/,{ /* - ** The ncr doesn't have an indirect load - ** or store command. So we have to - ** copy part of the control block to a - ** fixed place, where we can modify it. - ** - ** We patch the address part of a COPY command - ** with the address of the dsa register ... + ** Send a M_RESET message if bad IDENTIFY + ** received on reselection. */ - SCR_COPY_F (4), - RADDR (dsa), - PADDRH (getcc1), + SCR_LOAD_REG (scratcha, M_ABORT_TAG), + 0, + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< ABORTTAG >-------------------*/,{ /* - ** ... then we do the actual copy. + ** Abort a wrong tag received on reselection. */ - SCR_COPY (sizeof (struct head)), -}/*-------------------------< GETCC1 >----------------------*/,{ + SCR_LOAD_REG (scratcha, M_ABORT_TAG), 0, - NADDR (header), + SCR_JUMP, + PADDRH (abort_resel), +}/*-------------------------< ABORT >----------------------*/,{ /* - ** Initialize the status registers + ** Abort a reselection when no active CCB. */ - SCR_COPY (4), - NADDR (header.status), - RADDR (scr0), -}/*-------------------------< GETCC2 >----------------------*/,{ + SCR_LOAD_REG (scratcha, M_ABORT), + 0, +}/*-------------------------< ABORT_RESEL >----------------*/,{ + SCR_COPY (1), + RADDR (scratcha), + NADDR (msgout), + SCR_SET (SCR_ATN), + 0, + SCR_CLR (SCR_ACK), + 0, /* - ** Get the condition code from a target. - ** - ** DSA points to a data structure. - ** Set TEMP to the script location - ** that receives the condition code. - ** - ** Because there is no script command - ** to load a longword into a register, - ** we use a CALL command. + ** and send it. + ** we expect an immediate disconnect */ -/*<<<*/ SCR_CALLR, - 24, + SCR_REG_REG (scntl2, SCR_AND, 0x7f), + 0, + SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, + NADDR (msgout), + SCR_COPY (1), + RADDR (sfbr), + NADDR (lastmsg), + SCR_CLR (SCR_ACK|SCR_ATN), + 0, + SCR_WAIT_DISC, + 0, + SCR_JUMP, + PADDR (start), +}/*-------------------------< RESEND_IDENT >-------------------*/,{ /* - ** Get the condition code. + ** The target stays in MSG OUT phase after having acked + ** Identify [+ Tag [+ Extended message ]]. Targets shall + ** behave this way on parity error. + ** We must send it again all the messages. */ + SCR_SET (SCR_ATN), /* Shall be asserted 2 deskew delays before the */ + 0, /* 1rst ACK = 90 ns. Hope the NCR is'nt too fast */ + SCR_JUMP, + PADDR (send_ident), +}/*-------------------------< CLRATN_GO_ON >-------------------*/,{ + SCR_CLR (SCR_ATN), + 0, + SCR_JUMP, +}/*-------------------------< NXTDSP_GO_ON >-------------------*/,{ + 0, +}/*-------------------------< SDATA_IN >-------------------*/,{ + SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_IN)), + PADDR (dispatch), SCR_MOVE_TBL ^ SCR_DATA_IN, offsetof (struct dsb, sense), - /* - ** No data phase may follow! - */ SCR_CALL, - PADDR (checkatn), + PADDR (dispatch), SCR_JUMP, PADDR (no_data), -/*>>>*/ - +}/*-------------------------< DATA_IO >--------------------*/,{ /* - ** The CALL jumps to this point. - ** Prepare for a RESTORE_POINTER message. - ** Save the TEMP register into the saved pointer. + ** We jump here if the data direction was unknown at the + ** time we had to queue the command to the scripts processor. + ** Pointers had been set as follow in this situation: + ** savep --> DATA_IO + ** lastp --> start pointer when DATA_IN + ** goalp --> goal pointer when DATA_IN + ** wlastp --> start pointer when DATA_OUT + ** wgoalp --> goal pointer when DATA_OUT + ** This script sets savep/lastp/goalp according to the + ** direction chosen by the target. */ - SCR_COPY (4), - RADDR (temp), - NADDR (header.savep), + SCR_JUMPR ^ IFTRUE (WHEN (SCR_DATA_OUT)), + 32, /* - ** Load scratcha, because in case of a selection timeout, - ** the host will expect a new value for startpos in - ** the scratcha register. + ** Direction is DATA IN. + ** Warning: we jump here, even when phase is DATA OUT. */ SCR_COPY (4), - PADDR (startpos), - RADDR (scratcha), -#ifdef NCR_GETCC_WITHMSG - /* - ** If QUIRK_NOMSG is set, select without ATN. - ** and don't send a message. - */ - SCR_FROM_REG (QU_REG), - 0, - SCR_JUMP ^ IFTRUE (MASK (QUIRK_NOMSG, QUIRK_NOMSG)), - PADDRH(getcc3), - /* - ** Then try to connect to the target. - ** If we are reselected, special treatment - ** of the current job is required before - ** accepting the reselection. - */ - SCR_SEL_TBL_ATN ^ offsetof (struct dsb, select), - PADDR(badgetcc), - /* - ** save target id. - */ - SCR_FROM_REG (sdid), - 0, - SCR_TO_REG (ctest0), - 0, + NADDR (header.lastp), + NADDR (header.savep), + /* - ** Send the IDENTIFY message. - ** In case of short transfer, remove ATN. + ** Jump to the SCRIPTS according to actual direction. */ - SCR_MOVE_TBL ^ SCR_MSG_OUT, - offsetof (struct dsb, smsg2), - SCR_CLR (SCR_ATN), + SCR_COPY (4), + NADDR (header.savep), + RADDR (temp), + SCR_RETURN, 0, /* - ** save the first byte of the message. + ** Direction is DATA OUT. */ - SCR_COPY (1), - RADDR (sfbr), - NADDR (lastmsg), + SCR_COPY (4), + NADDR (header.wlastp), + NADDR (header.lastp), + SCR_COPY (4), + NADDR (header.wgoalp), + NADDR (header.goalp), + SCR_JUMPR, + -64, +}/*-------------------------< BAD_IDENTIFY >---------------*/,{ + /* + ** If message phase but not an IDENTIFY, + ** get some help from the C code. + ** Old SCSI device may behave so. + */ + SCR_JUMPR ^ IFTRUE (MASK (0x80, 0x80)), + 16, + SCR_INT, + SIR_RESEL_NO_IDENTIFY, SCR_JUMP, - PADDR (prepare2), - -#endif -}/*-------------------------< GETCC3 >----------------------*/,{ + PADDRH (reset), /* - ** Try to connect to the target. - ** If we are reselected, special treatment - ** of the current job is required before - ** accepting the reselection. - ** - ** Silly target won't accept a message. - ** Select without ATN. + ** Message is an IDENTIFY, but lun is unknown. + ** Read the message, since we got it directly + ** from the SCSI BUS data lines. + ** Signal problem to C code for logging the event. + ** Send a M_ABORT to clear all pending tasks. */ - SCR_SEL_TBL ^ offsetof (struct dsb, select), - PADDR(badgetcc), + SCR_INT, + SIR_RESEL_BAD_LUN, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), + SCR_JUMP, + PADDRH (abort), +}/*-------------------------< BAD_I_T_L >------------------*/,{ /* - ** save target id. + ** We donnot have a task for that I_T_L. + ** Signal problem to C code for logging the event. + ** Send a M_ABORT message. */ - SCR_FROM_REG (sdid), - 0, - SCR_TO_REG (ctest0), - 0, + SCR_INT, + SIR_RESEL_BAD_I_T_L, + SCR_JUMP, + PADDRH (abort), +}/*-------------------------< BAD_I_T_L_Q >----------------*/,{ /* - ** Force error if selection timeout + ** We donnot have a task that matches the tag. + ** Signal problem to C code for logging the event. + ** Send a M_ABORTTAG message. */ - SCR_JUMPR ^ IFTRUE (WHEN (SCR_MSG_IN)), - 0, + SCR_INT, + SIR_RESEL_BAD_I_T_L_Q, + SCR_JUMP, + PADDRH (aborttag), +}/*-------------------------< BAD_TARGET >-----------------*/,{ /* - ** don't negotiate. + ** We donnot know the target that reselected us. + ** Grab the first message if any (IDENTIFY). + ** Signal problem to C code for logging the event. + ** M_RESET message. */ + SCR_INT, + SIR_RESEL_BAD_TARGET, + SCR_JUMPR ^ IFFALSE (WHEN (SCR_MSG_IN)), + 8, + SCR_MOVE_ABS (1) ^ SCR_MSG_IN, + NADDR (msgin), SCR_JUMP, - PADDR (prepare2), - -}/*-------------------------< DATA_OUT >-------------------*/,{ -/* -** Because the size depends on the -** #define MAX_SCATTER parameter, -** it is filled in at runtime. -** -** ##===========< i=0; i========= -** || SCR_CALL ^ IFFALSE (WHEN (SCR_DATA_OUT)), -** || PADDR (dispatch), -** || SCR_MOVE_TBL ^ SCR_DATA_OUT, -** || offsetof (struct dsb, data[ i]), -** ##========================================== -** -** SCR_CALL, -** PADDR (dispatch), -** SCR_JUMP, -** PADDR (no_data), -** -**--------------------------------------------------------- -*/ -0 -}/*-------------------------< ABORTTAG >-------------------*/,{ + PADDRH (reset), +}/*-------------------------< BAD_STATUS >-----------------*/,{ /* - ** Abort a bad reselection. - ** Set the message to ABORT vs. ABORT_TAG + ** If command resulted in either QUEUE FULL, + ** CHECK CONDITION or COMMAND TERMINATED, + ** call the C code. */ - SCR_LOAD_REG (scratcha, M_ABORT_TAG), - 0, - SCR_JUMPR ^ IFFALSE (CARRYSET), - 8, -}/*-------------------------< ABORT >----------------------*/,{ - SCR_LOAD_REG (scratcha, M_ABORT), + SCR_INT ^ IFTRUE (DATA (S_QUEUE_FULL)), + SIR_BAD_STATUS, + SCR_INT ^ IFTRUE (DATA (S_CHECK_COND)), + SIR_BAD_STATUS, + SCR_INT ^ IFTRUE (DATA (S_TERMINATED)), + SIR_BAD_STATUS, + SCR_RETURN, 0, - SCR_COPY (1), +}/*-------------------------< START_RAM >-------------------*/,{ + /* + ** Load the script into on-chip RAM, + ** and jump to start point. + */ + SCR_COPY_F (4), RADDR (scratcha), - NADDR (msgout), - SCR_SET (SCR_ATN), - 0, - SCR_CLR (SCR_ACK), + PADDRH (start_ram0), + SCR_COPY (sizeof (struct script)), +}/*-------------------------< START_RAM0 >--------------------*/,{ 0, + PADDR (start), + SCR_JUMP, + PADDR (start), +}/*-------------------------< STO_RESTART >-------------------*/,{ /* - ** and send it. - ** we expect an immediate disconnect + ** + ** Repair start queue (e.g. next time use the next slot) + ** and jump to start point. */ - SCR_REG_REG (scntl2, SCR_AND, 0x7f), - 0, - SCR_MOVE_ABS (1) ^ SCR_MSG_OUT, - NADDR (msgout), - SCR_COPY (1), - RADDR (sfbr), - NADDR (lastmsg), - SCR_CLR (SCR_ACK|SCR_ATN), - 0, - SCR_WAIT_DISC, - 0, + SCR_COPY (4), + RADDR (temp), + PADDR (startpos), SCR_JUMP, PADDR (start), }/*-------------------------< SNOOPTEST >-------------------*/,{ @@ -3654,48 +3707,63 @@ p = scrh->tryloop; for (i=0; itryloop + sizeof (scrh->tryloop)); - p = scr->data_in; +#ifdef SCSI_NCR_CCB_DONE_SUPPORT + + p = scrh->done_queue; + for (i = 0; idone_queue+sizeof(scrh->done_queue)); - for (i=0; ihdata_in; + for (i=0; ihdata_in + sizeof (scrh->hdata_in)); - *p++ =SCR_CALL; - *p++ =PADDR (checkatn); - *p++ =SCR_JUMP; - *p++ =PADDR (no_data); - + p = scr->data_in; + for (i=MAX_SCATTERH; idata_in + sizeof (scr->data_in)); - p = scrh->data_out; - - for (i=0; ihdata_out; + for (i=0; ihdata_out + sizeof (scrh->hdata_out)); - *p++ =SCR_CALL; - *p++ =PADDR (dispatch); - *p++ =SCR_JUMP; - *p++ =PADDR (no_data); + p = scr->data_out; + for (i=MAX_SCATTERH; idata_out + sizeof (scrh->data_out)); + assert ((u_long)p == (u_long)&scr->data_out + sizeof (scr->data_out)); } /*========================================================== @@ -3732,13 +3800,13 @@ */ if (opcode == 0) { - printf ("%s: ERROR0 IN SCRIPT at %d.\n", + printk (KERN_ERR "%s: ERROR0 IN SCRIPT at %d.\n", ncr_name(np), (int) (src-start-1)); - DELAY (1000000); + MDELAY (1000); }; if (DEBUG_FLAGS & DEBUG_SCRIPT) - printf ("%p: <%x>\n", + printk (KERN_DEBUG "%p: <%x>\n", (src-1), (unsigned)opcode); /* @@ -3758,9 +3826,9 @@ if ((tmp2 & RELOC_MASK) == RELOC_KVAR) tmp2 = 0; if ((tmp1 ^ tmp2) & 3) { - printf ("%s: ERROR1 IN SCRIPT at %d.\n", + printk (KERN_ERR"%s: ERROR1 IN SCRIPT at %d.\n", ncr_name(np), (int) (src-start-1)); - DELAY (1000000); + MDELAY (1000); } /* ** If PREFETCH feature not enabled, remove @@ -3782,7 +3850,7 @@ case 0x8: /* ** JUMP / CALL - ** don't relocate if relative :-) + ** dont't relocate if relative :-) */ if (opcode & 0x00800000) relocs = 0; @@ -3847,9 +3915,6 @@ *dst++ = cpu_to_scr(*src++); }; - if (bootverbose > 1 && opchanged) - printf("%s: NO FLUSH bit removed from %d script instructions\n", - ncr_name(np), opchanged); } /*========================================================== @@ -3872,31 +3937,37 @@ struct host_data { struct ncb *ncb; - char ncb_align[NCB_ALIGN_SIZE-1]; /* Filler for alignment */ + char ncb_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */ struct ncb _ncb_data; - char ccb_align[CCB_ALIGN_SIZE-1]; /* Filler for alignment */ + char ccb_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */ struct ccb _ccb_data; - char scr_align[SCR_ALIGN_SIZE-1]; /* Filler for alignment */ + char scr_align[CACHE_LINE_SIZE-1]; /* Filler for alignment */ struct script script_data; struct scripth scripth_data; }; /* -** Print something which allow to retrieve the controler type, unit, +** Print something which allows to retrieve the controler type, unit, ** target, lun concerned by a kernel message. */ -#define PRINT_LUN(np, target, lun) \ -printf(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), (int) (target), (int) (lun)) +static void PRINT_TARGET(ncb_p np, int target) +{ + printk(KERN_INFO "%s-<%d,*>: ", ncr_name(np), target); +} + +static void PRINT_LUN(ncb_p np, int target, int lun) +{ + printk(KERN_INFO "%s-<%d,%d>: ", ncr_name(np), target, lun); +} static void PRINT_ADDR(Scsi_Cmnd *cmd) { struct host_data *host_data = (struct host_data *) cmd->host->hostdata; - ncb_p np = host_data->ncb; - if (np) PRINT_LUN(np, cmd->target, cmd->lun); + PRINT_LUN(host_data->ncb, cmd->target, cmd->lun); } /*========================================================== @@ -4003,8 +4074,6 @@ if (tn->flags & TEKRAM_TAGGED_COMMANDS) { tp->usrtags = 2 << nvram->max_tags_index; - if (tp->usrtags > SCSI_NCR_MAX_TAGS) - tp->usrtags = SCSI_NCR_MAX_TAGS; } if (!(tn->flags & TEKRAM_DISCONNECT_ENABLE)) @@ -4067,8 +4136,7 @@ * Divisor to be used for async (timer pre-scaler). */ i = np->clock_divn - 1; - while (i >= 0) { - --i; + while (--i >= 0) { if (10ul * SCSI_NCR_MIN_ASYNC * np->clock_khz > div_10M[i]) { ++i; break; @@ -4271,7 +4339,7 @@ */ i = nvram ? nvram->type : 0; - printf(KERN_INFO "%s: %sID %d, Fast-%d%s%s\n", ncr_name(np), + printk(KERN_INFO "%s: %sID %d, Fast-%d%s%s\n", ncr_name(np), i == SCSI_NCR_SYMBIOS_NVRAM ? "Symbios format NVRAM, " : (i == SCSI_NCR_TEKRAM_NVRAM ? "Tekram format NVRAM, " : ""), np->myaddr, @@ -4280,19 +4348,19 @@ (np->rv_stest2 & 0x20) ? ", Differential" : ""); if (bootverbose > 1) { - printf ("%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " + printk (KERN_INFO "%s: initial SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", ncr_name(np), np->sv_scntl3, np->sv_dmode, np->sv_dcntl, np->sv_ctest3, np->sv_ctest4, np->sv_ctest5); - printf ("%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " + printk (KERN_INFO "%s: final SCNTL3/DMODE/DCNTL/CTEST3/4/5 = " "(hex) %02x/%02x/%02x/%02x/%02x/%02x\n", ncr_name(np), np->rv_scntl3, np->rv_dmode, np->rv_dcntl, np->rv_ctest3, np->rv_ctest4, np->rv_ctest5); } if (bootverbose && np->paddr2) - printf (KERN_INFO "%s: on-board RAM at 0x%lx\n", + printk (KERN_INFO "%s: on-chip RAM at 0x%lx\n", ncr_name(np), np->paddr2); return 0; @@ -4308,17 +4376,18 @@ int i; /* display Symbios nvram host data */ - printf("%s: HOST ID=%d%s%s%s%s\n", + printk(KERN_DEBUG "%s: HOST ID=%d%s%s%s%s%s\n", ncr_name(np), nvram->host_id & 0x0f, (nvram->flags & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", (nvram->flags & SYMBIOS_PARITY_ENABLE) ? " PARITY" :"", - (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERSBOSE" :"", + (nvram->flags & SYMBIOS_VERBOSE_MSGS) ? " VERBOSE" :"", + (nvram->flags & SYMBIOS_CHS_MAPPING) ? " CHS_ALT" :"", (nvram->flags1 & SYMBIOS_SCAN_HI_LO) ? " HI_LO" :""); /* display Symbios nvram drive data */ for (i = 0 ; i < 15 ; i++) { struct Symbios_target *tn = &nvram->target[i]; - printf("%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", + printk(KERN_DEBUG "%s-%d:%s%s%s%s WIDTH=%d SYNC=%d TMO=%d\n", ncr_name(np), i, (tn->flags & SYMBIOS_DISCONNECT_ENABLE) ? " DISC" : "", (tn->flags & SYMBIOS_SCAN_AT_BOOT_TIME) ? " SCAN_BOOT" : "", @@ -4351,7 +4420,8 @@ case 2: rem = " REMOVABLE=all"; break; } - printf("%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", + printk(KERN_DEBUG + "%s: HOST ID=%d%s%s%s%s%s%s%s%s%s BOOT DELAY=%d tags=%d\n", ncr_name(np), nvram->host_id & 0x0f, (nvram->flags1 & SYMBIOS_SCAM_ENABLE) ? " SCAM" :"", (nvram->flags & TEKRAM_MORE_THAN_2_DRIVES) ? " >2DRIVES" :"", @@ -4369,7 +4439,7 @@ struct Tekram_target *tn = &nvram->target[i]; j = tn->sync_index & 0xf; sync = j < 12 ? Tekram_sync[j] : 255; - printf("%s-%d:%s%s%s%s%s%s PERIOD=%d\n", + printk(KERN_DEBUG "%s-%d:%s%s%s%s%s%s PERIOD=%d\n", ncr_name(np), i, (tn->flags & TEKRAM_PARITY_CHECK) ? " PARITY" : "", (tn->flags & TEKRAM_SYNC_NEGO) ? " SYNC" : "", @@ -4401,17 +4471,18 @@ struct Scsi_Host *instance = 0; u_long flags = 0; ncr_nvram *nvram = device->nvram; + int i; #ifdef __sparc__ -printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=0x%x\n", +printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=0x%x\n", device->chip.name, unit, device->chip.revision_id, device->slot.base, device->slot.io_port, device->slot.irq); #else -printf(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n", +printk(KERN_INFO "ncr53c%s-%d: rev=0x%02x, base=0x%lx, io_port=0x%lx, irq=%d\n", device->chip.name, unit, device->chip.revision_id, device->slot.base, device->slot.io_port, device->slot.irq); #endif - + /* ** Allocate host_data structure */ @@ -4422,17 +4493,16 @@ ** Initialize structure. */ host_data = (struct host_data *) instance->hostdata; + bzero (host_data, sizeof(*host_data)); /* ** Align np and first ccb to 32 boundary for cache line ** bursting when copying the global header. */ - np = (ncb_p) (((u_long) &host_data->_ncb_data) & NCB_ALIGN_MASK); + np = (ncb_p) (((u_long) &host_data->_ncb_data) & CACHE_LINE_MASK); + NCR_INIT_LOCK_NCB(np); host_data->ncb = np; - bzero (np, sizeof (*np)); - - np->ccb = (ccb_p) (((u_long) &host_data->_ccb_data) & CCB_ALIGN_MASK); - bzero (np->ccb, sizeof (*np->ccb)); + np->ccb = (ccb_p) (((u_long) &host_data->_ccb_data) & CACHE_LINE_MASK); /* ** Store input informations in the host data structure. @@ -4448,8 +4518,8 @@ np->maxoffs = device->chip.offset_max; np->maxburst = device->chip.burst_max; - np->script0 = - (struct script *) (((u_long) &host_data->script_data) & SCR_ALIGN_MASK); + np->script0 = (struct script *) + (((u_long) &host_data->script_data) & CACHE_LINE_MASK); np->scripth0 = &host_data->scripth_data; /* @@ -4471,12 +4541,14 @@ #ifndef NCR_IOMAPPED np->vaddr = remap_pci_mem((u_long) np->paddr, (u_long) 128); if (!np->vaddr) { - printf("%s: can't map memory mapped IO region\n", ncr_name(np)); + printk(KERN_ERR + "%s: can't map memory mapped IO region\n",ncr_name(np)); goto attach_error; } else if (bootverbose > 1) - printf("%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr); + printk(KERN_INFO + "%s: using memory mapped IO at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr); /* ** Make the controller's registers available. @@ -4511,7 +4583,7 @@ default: nvram = 0; #ifdef SCSI_NCR_DEBUG_NVRAM - printf("%s: NVRAM: None or invalid data.\n", ncr_name(np)); + printk(KERN_DEBUG "%s: NVRAM: None or invalid data.\n", ncr_name(np)); #endif } } @@ -4522,37 +4594,27 @@ */ (void)ncr_prepare_setting(np, nvram); -#ifndef NCR_IOMAPPED - if (np->paddr2 && sizeof(struct script) <= 4096) { - np->vaddr2 = remap_pci_mem((u_long) np->paddr2, (u_long) 4096); - if (!np->vaddr2) { - printf("%s: can't map memory mapped IO region\n", ncr_name(np)); - goto attach_error; - } - else - if (bootverbose > 1) - printf("%s: on-board ram mapped at virtual address 0x%lx\n", ncr_name(np), (u_long) np->vaddr2); + if (np->paddr2 && sizeof(struct script) > 4096) { + np->paddr2 = 0; + printk(KERN_WARNING "%s: script too large, NOT using on chip RAM.\n", + ncr_name(np)); } -#endif /* !defined NCR_IOMAPPED */ /* ** Fill Linux host instance structure */ -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) instance->max_channel = 0; instance->max_id = np->maxwide ? 16 : 8; instance->max_lun = SCSI_NCR_MAX_LUN; -#endif #ifndef NCR_IOMAPPED instance->base = (char *) np->reg; #endif instance->irq = device->slot.irq; + instance->unique_id = device->slot.io_port; instance->io_port = device->slot.io_port; instance->n_io_port = 128; instance->dma_channel = 0; -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0) instance->select_queue_depths = ncr53c8xx_select_queue_depths; -#endif /* ** Patch script to physical addresses @@ -4562,8 +4624,7 @@ np->scripth = np->scripth0; np->p_scripth = vtophys(np->scripth); - np->script = (np->vaddr2) ? (struct script *) np->vaddr2 : np->script0; - np->p_script = (np->vaddr2) ? pcivtophys(np->paddr2) : vtophys(np->script0); + np->p_script = (np->paddr2) ? pcivtophys(np->paddr2) : vtophys(np->script0); ncr_script_copy_and_bind (np, (ncrcmd *) &script0, (ncrcmd *) np->script0, sizeof(struct script)); ncr_script_copy_and_bind (np, (ncrcmd *) &scripth0, (ncrcmd *) np->scripth0, sizeof(struct scripth)); @@ -4574,27 +4635,32 @@ */ if (np->features & FE_LED0) { - np->script0->reselect[0] = + np->script0->idle[0] = cpu_to_scr(SCR_REG_REG(gpreg, SCR_OR, 0x01)); - np->script0->reselect1[0] = + np->script0->reselected[0] = cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); - np->script0->reselect2[0] = + np->script0->start[0] = cpu_to_scr(SCR_REG_REG(gpreg, SCR_AND, 0xfe)); } /* - ** init data structure - */ - - np->jump_tcb.l_cmd = cpu_to_scr(SCR_JUMP); - np->jump_tcb.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort)); + ** Look for the target control block of this nexus. + ** For i = 0 to 3 + ** JUMP ^ IFTRUE (MASK (i, 3)), @(next_lcb) + */ + for (i = 0 ; i < 4 ; i++) { + np->jump_tcb[i].l_cmd = + cpu_to_scr((SCR_JUMP ^ IFTRUE (MASK (i, 3)))); + np->jump_tcb[i].l_paddr = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_target)); + } /* ** Reset chip. */ OUTB (nc_istat, SRST); - DELAY (1000); + UDELAY (100); OUTB (nc_istat, 0 ); /* @@ -4602,34 +4668,35 @@ */ if (ncr_snooptest (np)) { - printf ("CACHE INCORRECTLY CONFIGURED.\n"); + printk (KERN_ERR "CACHE INCORRECTLY CONFIGURED.\n"); goto attach_error; }; /* ** Install the interrupt handler. */ -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) -#ifdef SCSI_NCR_SHARE_IRQ +#ifdef SCSI_NCR_SHARE_IRQ +#define NCR_SA_INTERRUPT_FLAGS (SA_INTERRUPT | SA_SHIRQ) if (bootverbose > 1) - printf("%s: requesting shared irq %d (dev_id=0x%lx)\n", + printk(KERN_INFO "%s: requesting shared irq %d (dev_id=0x%lx)\n", ncr_name(np), device->slot.irq, (u_long) np); - if (request_irq(device->slot.irq, do_ncr53c8xx_intr, - SA_INTERRUPT|SA_SHIRQ, "ncr53c8xx", np)) { #else - if (request_irq(device->slot.irq, do_ncr53c8xx_intr, - SA_INTERRUPT, "ncr53c8xx", np)) { +#define NCR_SA_INTERRUPT_FLAGS SA_INTERRUPT #endif -#else if (request_irq(device->slot.irq, ncr53c8xx_intr, - SA_INTERRUPT, "ncr53c8xx")) { -#endif - printf("%s: request irq %d failure\n", ncr_name(np), device->slot.irq); + NCR_SA_INTERRUPT_FLAGS, "ncr53c8xx", np)) { + printk(KERN_ERR "%s: request irq %d failure\n", + ncr_name(np), device->slot.irq); goto attach_error; } np->irq = device->slot.irq; /* + ** Initialize the fixed part of the default ccb. + */ + ncr_init_ccb(np, np->ccb); + + /* ** After SCSI devices have been opened, we cannot ** reset the bus safely, so we do it here. ** Interrupt handler does the real work. @@ -4637,41 +4704,26 @@ ** if interrupts are not enabled yet. ** Then enable disconnects. */ - save_flags(flags); cli(); - do { - if (ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay) != 0) { - printf("%s: FATAL ERROR: CHECK SCSI BUS - CABLES, " - "TERMINATION, DEVICE POWER etc.!\n", - ncr_name(np)); - restore_flags(flags); - goto attach_error; - } + NCR_LOCK_NCB(np, flags); + if (ncr_reset_scsi_bus(np, 0, driver_setup.settle_delay) != 0) { + printk(KERN_ERR "%s: FATAL ERROR: CHECK SCSI BUS - CABLES, TERMINATION, DEVICE POWER etc.!\n", ncr_name(np)); - /* - ** On Ultra/AXi, the NCR53C876 sometimes does not get the - ** RST bit set in SIST the first time, so retry resetting - ** the SCSI bus until the chip is properly initialized. - */ - np->disc = 1; - ncr_exception (np); - if (np->disc) { - printk("%s: Chip not responding to CRST, retrying\n", - ncr_name(np)); - } - } while (np->disc); - restore_flags(flags); + NCR_UNLOCK_NCB(np, flags); + goto attach_error; + } + ncr_exception (np); np->disc = 1; /* ** The middle-level SCSI driver does not - ** wait devices to settle. + ** wait for devices to settle. ** Wait synchronously if more than 2 seconds. */ if (driver_setup.settle_delay > 2) { - printf("%s: waiting %d seconds for scsi devices to settle...\n", + printk(KERN_INFO "%s: waiting %d seconds for scsi devices to settle...\n", ncr_name(np), driver_setup.settle_delay); - DELAY(1000000UL * driver_setup.settle_delay); + MDELAY (1000 * driver_setup.settle_delay); } /* @@ -4700,46 +4752,80 @@ first_host = instance; } + NCR_UNLOCK_NCB(np, flags); + return 0; attach_error: if (!instance) return -1; - printf("%s: detaching...\n", ncr_name(np)); + printk(KERN_INFO "%s: detaching...\n", ncr_name(np)); #ifndef NCR_IOMAPPED if (np->vaddr) { #ifdef DEBUG_NCR53C8XX - printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128); + printk(KERN_DEBUG "%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128); #endif unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128); } - if (np->vaddr2) { -#ifdef DEBUG_NCR53C8XX - printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096); -#endif - unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096); - } -#endif +#endif /* !NCR_IOMAPPED */ if (np->port) { #ifdef DEBUG_NCR53C8XX - printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128); + printk(KERN_DEBUG "%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128); #endif release_region(np->port, 128); } if (np->irq) { #ifdef DEBUG_NCR53C8XX - printf("%s: freeing irq %d\n", ncr_name(np), np->irq); -#endif -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) - free_irq(np->irq, np); +#ifdef __sparc__ + printk(KERN_INFO "%s: freeing irq 0x%x\n", ncr_name(np), np->irq); #else - free_irq(np->irq); + printk(KERN_INFO "%s: freeing irq %d\n", ncr_name(np), np->irq); +#endif #endif + free_irq(np->irq, np); } scsi_unregister(instance); return -1; } + +/*========================================================== +** +** +** Done SCSI commands list management. +** +** We donnot enter the scsi_done() callback immediately +** after a command has been seen as completed but we +** insert it into a list which is flushed outside any kind +** of driver critical section. +** This allows to do minimal stuff under interrupt and +** inside critical sections and to also avoid locking up +** on recursive calls to driver entry points under SMP. +** In fact, the only kernel point which is entered by the +** driver with a driver lock set is kmalloc(GFP_ATOMIC) +** that shall not reenter the driver under any circumstances, +** AFAIK. +** +**========================================================== +*/ +static inline void ncr_queue_done_cmd(ncb_p np, Scsi_Cmnd *cmd) +{ + cmd->host_scribble = (char *) np->done_list; + np->done_list = cmd; +} + +static inline void ncr_flush_done_cmds(Scsi_Cmnd *lcmd) +{ + Scsi_Cmnd *cmd; + + while (lcmd) { + cmd = lcmd; + lcmd = (Scsi_Cmnd *) cmd->host_scribble; + cmd->scsi_done(cmd); + } +} + + /*========================================================== ** ** @@ -4749,27 +4835,18 @@ ** **========================================================== */ -int ncr_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) +int ncr_queue_command (ncb_p np, Scsi_Cmnd *cmd) { - struct Scsi_Host *host = cmd->host; /* Scsi_Device *device = cmd->device; */ - struct host_data *host_data = (struct host_data *) host->hostdata; - ncb_p np = host_data->ncb; tcb_p tp = &np->target[cmd->target]; - + lcb_p lp = tp->lp[cmd->lun]; ccb_p cp; - lcb_p lp; int segments; - u_char qidx, nego, idmsg, *msgptr; - u_int msglen, msglen2; - u_long flags; - int xfer_direction; - - cmd->scsi_done = done; - cmd->host_scribble = NULL; - cmd->SCp.ptr = NULL; - cmd->SCp.buffer = NULL; + u_char nego, idmsg, *msgptr; + u_int msglen; + int direction; + u_int32 lastp, goalp; /*--------------------------------------------- ** @@ -4799,7 +4876,7 @@ if (DEBUG_FLAGS & DEBUG_TINY) { PRINT_ADDR(cmd); - printf ("CMD=%x ", cmd->cmnd[0]); + printk ("CMD=%x ", cmd->cmnd[0]); } /*--------------------------------------------------- @@ -4812,8 +4889,6 @@ ** **---------------------------------------------------- */ - save_flags(flags); cli(); - if (np->settle_time && cmd->timeout_per_command >= HZ && np->settle_time > jiffies + cmd->timeout_per_command - HZ) { np->settle_time = jiffies + cmd->timeout_per_command - HZ; @@ -4821,7 +4896,6 @@ if (np->settle_time || !(cp=ncr_get_ccb (np, cmd->target, cmd->lun))) { insert_into_waiting_list(np, cmd); - restore_flags(flags); return(DID_OK); } cp->cmd = cmd; @@ -4832,10 +4906,12 @@ ** **---------------------------------------------------- */ - if (!tp->usrtags && cmd->device && cmd->device->tagged_queue) { - tp->usrtags = SCSI_NCR_MAX_TAGS; - ncr_setmaxtags (np, tp, SCSI_NCR_MAX_TAGS); +#if 0 /* This stuff was only usefull for linux-1.2.13 */ + if (lp && !lp->numtags && cmd->device && cmd->device->tagged_queue) { + lp->numtags = tp->usrtags; + ncr_setup_tags (np, cmd->target, cmd->lun); } +#endif /*--------------------------------------------------- ** @@ -4848,47 +4924,23 @@ cp->phys.header.stamp.start = jiffies; #endif - /*---------------------------------------------------- - ** - ** Get device quirks from a speciality table. - ** - ** @GENSCSI@ - ** This should be a part of the device table - ** in "scsi_conf.c". - ** - **---------------------------------------------------- - */ - if (tp->quirks & QUIRK_UPDATE) { - tp->quirks = ncr_lookup ((char*) &tp->inqdata[0]); -#ifndef NCR_GETCC_WITHMSG - if (tp->quirks) { - PRINT_ADDR(cmd); - printf ("quirks=%x.\n", tp->quirks); - } -#endif - } - /*--------------------------------------------------- ** ** negotiation required? ** - ** Only SCSI-II devices. - ** To negotiate with SCSI-I devices is dangerous, since - ** Synchronous Negotiation protocol is optional, and - ** INQUIRY data do not contains capabilities in byte 7. - **---------------------------------------------------- + **--------------------------------------------------- */ nego = 0; - if (cmd->lun == 0 && !tp->nego_cp && - (tp->inqdata[2] & 0x7) >= 2 && tp->inqdata[7]) { + if ((!tp->widedone || !tp->period) && !tp->nego_cp && tp->inq_done) { + /* ** negotiate wide transfers ? */ if (!tp->widedone) { - if (tp->inqdata[7] & INQ7_WIDE16) { + if (tp->inq_byte7 & INQ7_WIDE16) { nego = NS_WIDE; } else tp->widedone=1; @@ -4899,17 +4951,13 @@ */ if (!nego && !tp->period) { - if ( 1 -#if defined (CDROM_ASYNC) - && ((tp->inqdata[0] & 0x1f) != 5) -#endif - && (tp->inqdata[7] & INQ7_SYNC)) { + if (tp->inq_byte7 & INQ7_SYNC) { nego = NS_SYNC; } else { tp->period =0xffff; tp->sval = 0xe0; - PRINT_ADDR(cmd); - printf ("asynchronous.\n"); + PRINT_TARGET(np, cmd->target); + printk ("SYNC transfers not supported.\n"); }; }; @@ -4923,33 +4971,6 @@ tp->nego_cp = cp; }; - /*--------------------------------------------------- - ** - ** choose a new tag ... - ** - **---------------------------------------------------- - */ - - if ((lp = tp->lp[cmd->lun]) && (lp->usetags)) { - /* - ** assign a tag to this ccb! - */ - while (!cp->tag) { - ccb_p cp2 = lp->next_ccb; - lp->lasttag = lp->lasttag % 255 + 1; - while (cp2 && cp2->tag != lp->lasttag) - cp2 = cp2->next_ccb; - if (cp2) continue; - cp->tag=lp->lasttag; - if (DEBUG_FLAGS & DEBUG_TAGS) { - PRINT_ADDR(cmd); - printf ("using tag #%d.\n", cp->tag); - } - } - } else { - cp->tag=0; - } - /*---------------------------------------------------- ** ** Build the identify / tag / sdtr message @@ -4959,44 +4980,54 @@ idmsg = M_IDENTIFY | cmd->lun; - if (cp != np->ccb && ((np->disc && !(tp->usrflag & UF_NODISC)) || cp->tag)) + if (cp ->tag != NO_TAG || + (cp != np->ccb && np->disc && !(tp->usrflag & UF_NODISC))) idmsg |= 0x40; msgptr = cp->scsi_smsg; msglen = 0; msgptr[msglen++] = idmsg; - if (cp->tag) { - char tag; + if (cp->tag != NO_TAG) { + char order = np->order; - tag = np->order; - if (tag == 0) { /* - ** Ordered write ops, unordered read ops. + ** Force ordered tag if necessary to avoid timeouts + ** and to preserve interactivity. */ - switch (cmd->cmnd[0]) { - case 0x08: /* READ_SMALL (6) */ - case 0x28: /* READ_BIG (10) */ - case 0xa8: /* READ_HUGE (12) */ - tag = M_SIMPLE_TAG; - break; - default: - tag = M_ORDERED_TAG; + if (lp && lp->tags_stime + (3*HZ) <= jiffies) { + if (lp->tags_smap) { + order = M_ORDERED_TAG; + if ((DEBUG_FLAGS & DEBUG_TAGS)||bootverbose>2){ + PRINT_ADDR(cmd); + printk("ordered tag forced.\n"); + } + } + lp->tags_stime = jiffies; + lp->tags_smap = lp->tags_umap; } - } - /* - ** Have to force ordered tag to avoid timeouts - */ - if ((lp = tp->lp[cmd->lun]) && (lp->force_ordered_tag)) { - tag = M_ORDERED_TAG; - lp->force_ordered_tag = 0; - if (DEBUG_FLAGS & DEBUG_TAGS) { - PRINT_ADDR(cmd); - printf ("Ordered Queue Tag forced\n"); + + if (order == 0) { + /* + ** Ordered write ops, unordered read ops. + */ + switch (cmd->cmnd[0]) { + case 0x08: /* READ_SMALL (6) */ + case 0x28: /* READ_BIG (10) */ + case 0xa8: /* READ_HUGE (12) */ + order = M_SIMPLE_TAG; + break; + default: + order = M_ORDERED_TAG; + } } - } - msgptr[msglen++] = tag; - msgptr[msglen++] = cp -> tag; + msgptr[msglen++] = order; +#if SCSI_NCR_MAX_TAGS <= 32 + msgptr[msglen++] = (cp->tag << 3) + 1; +#else + msgptr[msglen++] = (cp->tag << 2) + 1; +#endif + } switch (nego) { @@ -5008,9 +5039,9 @@ msgptr[msglen++] = tp->maxoffs; if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); - printf ("sync msgout: "); + printk ("sync msgout: "); ncr_show_msg (&cp->scsi_smsg [msglen-5]); - printf (".\n"); + printk (".\n"); }; break; case NS_WIDE: @@ -5020,25 +5051,15 @@ msgptr[msglen++] = tp->usrwide; if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); - printf ("wide msgout: "); + printk ("wide msgout: "); ncr_show_msg (&cp->scsi_smsg [msglen-4]); - printf (".\n"); + printk (".\n"); }; break; }; /*---------------------------------------------------- ** - ** Build the identify message for getcc. - ** - **---------------------------------------------------- - */ - - cp -> scsi_smsg2 [0] = idmsg; - msglen2 = 1; - - /*---------------------------------------------------- - ** ** Build the data descriptors ** **---------------------------------------------------- @@ -5047,8 +5068,7 @@ segments = ncr_scatter (cp, cp->cmd); if (segments < 0) { - ncr_free_ccb(np, cp, cmd->target, cmd->lun); - restore_flags(flags); + ncr_free_ccb(np, cp); return(DID_ERROR); } @@ -5059,20 +5079,24 @@ ** **---------------------------------------------------- */ - switch((int) cmd->cmnd[0]) { - case 0x08: /* READ(6) 08 */ - case 0x28: /* READ(10) 28 */ - case 0xA8: /* READ(12) A8 */ - xfer_direction = XferIn; - break; - case 0x0A: /* WRITE(6) 0A */ - case 0x2A: /* WRITE(10) 2A */ - case 0xAA: /* WRITE(12) AA */ - xfer_direction = XferOut; - break; - default: - xfer_direction = guess_xfer_direction((int) cmd->cmnd[0]); - break; + if (!cp->data_len) + direction = 0; + else { + switch((int) cmd->cmnd[0]) { + case 0x08: /* READ(6) 08 */ + case 0x28: /* READ(10) 28 */ + case 0xA8: /* READ(12) A8 */ + direction = XFER_IN; + break; + case 0x0A: /* WRITE(6) 0A */ + case 0x2A: /* WRITE(10) 2A */ + case 0xAA: /* WRITE(12) AA */ + direction = XFER_OUT; + break; + default: + direction = (XFER_IN|XFER_OUT); + break; + } } /*---------------------------------------------------- @@ -5082,36 +5106,64 @@ **---------------------------------------------------- */ - cp->segments = segments; - if (!cp->data_len) - xfer_direction = XferNone; + /* + ** Default to no data transfer. + */ + lastp = goalp = NCB_SCRIPT_PHYS (np, no_data); - switch (xfer_direction) { - u_long endp; - default: - case XferBoth: - cp->phys.header.savep = - cpu_to_scr(NCB_SCRIPT_PHYS (np, data_io)); - cp->phys.header.goalp = cp->phys.header.savep; - break; - case XferIn: - endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16; - cp->phys.header.goalp = cpu_to_scr(endp + 8); - cp->phys.header.savep = cpu_to_scr(endp - segments*16); - break; - case XferOut: - endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16; - cp->phys.header.goalp = cpu_to_scr(endp + 8); - cp->phys.header.savep = cpu_to_scr(endp - segments*16); - break; - case XferNone: - cp->phys.header.savep = - cpu_to_scr(NCB_SCRIPT_PHYS (np, no_data)); - cp->phys.header.goalp = cp->phys.header.savep; - break; + /* + ** Compute data out pointers, if needed. + */ + if (direction & XFER_OUT) { + goalp = NCB_SCRIPT_PHYS (np, data_out2) + 8; + if (segments <= MAX_SCATTERL) + lastp = goalp - 8 - (segments * 16); + else { + lastp = NCB_SCRIPTH_PHYS (np, hdata_out2); + lastp -= (segments - MAX_SCATTERL) * 16; + } + /* + ** If actual data direction is unknown, save pointers + ** in header. The SCRIPTS will swap them to current + ** if target decision will be data out. + */ + if (direction & XFER_IN) { + cp->phys.header.wgoalp = cpu_to_scr(goalp); + cp->phys.header.wlastp = cpu_to_scr(lastp); + } + } + + /* + ** Compute data in pointers, if needed. + */ + if (direction & XFER_IN) { + goalp = NCB_SCRIPT_PHYS (np, data_in2) + 8; + if (segments <= MAX_SCATTERL) + lastp = goalp - 8 - (segments * 16); + else { + lastp = NCB_SCRIPTH_PHYS (np, hdata_in2); + lastp -= (segments - MAX_SCATTERL) * 16; + } } - cp->phys.header.lastp = cp->phys.header.savep; + /* + ** Set all pointers values needed by SCRIPTS. + ** If direction is unknown, start at data_io. + */ + cp->phys.header.lastp = cpu_to_scr(lastp); + cp->phys.header.goalp = cpu_to_scr(goalp); + + if ((direction & (XFER_IN|XFER_OUT)) == (XFER_IN|XFER_OUT)) + cp->phys.header.savep = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, data_io)); + else + cp->phys.header.savep= cpu_to_scr(lastp); + + /* + ** Save the initial data pointer in order to be able + ** to redo the command. + */ + cp->startp = cp->phys.header.savep; /*---------------------------------------------------- ** @@ -5123,13 +5175,12 @@ ** physical -> virtual backlink ** Generic SCSI command */ - cp->phys.header.cp = cp; + /* ** Startqueue */ - cp->phys.header.launch.l_paddr = - cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); - cp->phys.header.launch.l_cmd = cpu_to_scr(SCR_JUMP); + cp->start.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); + cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_dsa)); /* ** select */ @@ -5142,30 +5193,12 @@ cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg)); cp->phys.smsg.size = cpu_to_scr(msglen); - cp->phys.smsg2.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg2)); - cp->phys.smsg2.size = cpu_to_scr(msglen2); /* ** command */ cp->phys.cmd.addr = cpu_to_scr(vtophys (&cmd->cmnd[0])); cp->phys.cmd.size = cpu_to_scr(cmd->cmd_len); - /* - ** sense command - */ - cp->phys.scmd.addr = cpu_to_scr(CCB_PHYS (cp, sensecmd)); - cp->phys.scmd.size = cpu_to_scr(6); - /* - ** patch requested size into sense command - */ - cp->sensecmd[0] = 0x03; - cp->sensecmd[1] = cmd->lun << 5; - cp->sensecmd[4] = sizeof(cmd->sense_buffer); - /* - ** sense data - */ - cp->phys.sense.addr = - cpu_to_scr(vtophys (&cmd->sense_buffer[0])); - cp->phys.sense.size = cpu_to_scr(sizeof(cmd->sense_buffer)); + /* ** status */ @@ -5175,9 +5208,11 @@ cp->parity_status = 0; cp->xerr_status = XE_OK; - cp->sync_status = tp->sval; cp->nego_status = nego; +#if 0 + cp->sync_status = tp->sval; cp->wide_status = tp->wval; +#endif /*---------------------------------------------------- ** @@ -5187,56 +5222,96 @@ */ /* - ** reselect pattern and activate this job. + ** activate this job. */ - cp->jump_ccb.l_cmd = - cpu_to_scr((SCR_JUMP ^ IFFALSE (DATA (cp->tag)))); - /* Compute a time limit greater than the middle-level driver one */ if (cmd->timeout_per_command > 0) - cp->tlimit = jiffies + cmd->timeout_per_command + NCR_TIMEOUT_INCREASE; + cp->tlimit = jiffies + cmd->timeout_per_command + HZ; else - cp->tlimit = jiffies + 3600 * HZ; /* No timeout=one hour */ + cp->tlimit = jiffies + 86400 * HZ;/* No timeout=24 hours */ cp->magic = CCB_MAGIC; /* + ** insert next CCBs into start queue. + ** 2 max at a time is enough to flush the CCB wait queue. + */ + cp->auto_sense = 0; + if (lp) + ncr_start_next_ccb(np, lp, 2); + else + ncr_put_start_queue(np, cp); + + /* + ** Command is successfully queued. + */ + + return(DID_OK); +} + + +/*========================================================== +** +** +** Insert a CCB into the start queue and wake up the +** SCRIPTS processor. +** +** +**========================================================== +*/ + +static void ncr_start_next_ccb(ncb_p np, lcb_p lp, int maxn) +{ + XPT_QUEHEAD *qp; + ccb_p cp; + + if (lp->held_ccb) + return; + + while (maxn-- && lp->queuedccbs < lp->queuedepth) { + qp = xpt_remque_head(&lp->wait_ccbq); + if (!qp) + break; + ++lp->queuedccbs; + cp = xpt_que_entry(qp, struct ccb, link_ccbq); + xpt_insque_tail(qp, &lp->busy_ccbq); + lp->jump_ccb[cp->tag == NO_TAG ? 0 : cp->tag].l_paddr = + cpu_to_scr(cp->p_ccb + offsetof(struct ccb, restart)); + ncr_put_start_queue(np, cp); + } +} + +static void ncr_put_start_queue(ncb_p np, ccb_p cp) +{ + u_short qidx; + + /* ** insert into start queue. */ + if (!np->squeueput) np->squeueput = 1; + qidx = np->squeueput + 2; + if (qidx >= MAX_START + MAX_START) qidx = 1; + + np->scripth->tryloop [qidx] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + MEMORY_BARRIER(); + np->scripth->tryloop [np->squeueput] = cpu_to_scr(CCB_PHYS (cp, start)); - qidx = np->squeueput + 1; - if (qidx >= MAX_START) qidx=0; - np->squeue [qidx ] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); - np->squeue [np->squeueput] = cpu_to_scr(CCB_PHYS (cp, phys)); np->squeueput = qidx; + ++np->queuedccbs; + cp->queued = 1; - if(DEBUG_FLAGS & DEBUG_QUEUE) - printf ("%s: queuepos=%d tryoffset=%d.\n", ncr_name (np), - np->squeueput, - (unsigned)(scr_to_cpu(np->script->startpos[0]) - - (NCB_SCRIPTH_PHYS (np, tryloop)))); + if (DEBUG_FLAGS & DEBUG_QUEUE) + printk ("%s: queuepos=%d.\n", ncr_name (np), np->squeueput); /* ** Script processor may be waiting for reselect. ** Wake it up. */ -#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT - if (!np->stalling) -#endif + MEMORY_BARRIER(); OUTB (nc_istat, SIGP); - - /* - ** and reenable interrupts - */ - restore_flags(flags); - - /* - ** Command is successfully queued. - */ - - return(DID_OK); } + /*========================================================== ** ** @@ -5249,18 +5324,13 @@ ** **========================================================== */ -static void ncr_start_reset(ncb_p np, int settle_delay) +static void ncr_start_reset(ncb_p np) { - u_long flags; - - save_flags(flags); cli(); - if (!np->settle_time) { - (void) ncr_reset_scsi_bus(np, 1, settle_delay); - } - restore_flags(flags); -} - + (void) ncr_reset_scsi_bus(np, 1, driver_setup.settle_delay); + } + } + static int ncr_reset_scsi_bus(ncb_p np, int enab_int, int settle_delay) { u_int32 term; @@ -5269,17 +5339,24 @@ np->settle_time = jiffies + settle_delay * HZ; if (bootverbose > 1) - printf("%s: resetting, " + printk("%s: resetting, " "command processing suspended for %d seconds\n", ncr_name(np), settle_delay); OUTB (nc_istat, SRST); - DELAY (1000); + UDELAY (100); OUTB (nc_istat, 0); + UDELAY (2000); /* The 895 needs time for the bus mode to settle */ if (enab_int) OUTW (nc_sien, RST); + /* + ** Enable Tolerant, reset IRQD if present and + ** properly set IRQ mode, prior to resetting the bus. + */ + OUTB (nc_stest3, TE); + OUTB (nc_dcntl, (np->rv_dcntl & IRQM)); OUTB (nc_scntl1, CRST); - DELAY (100); + UDELAY (200); if (!driver_setup.bus_check) goto out; @@ -5299,9 +5376,9 @@ term &= 0x3ffff; if (term != (2<<7)) { - printf("%s: suspicious SCSI data while resetting the BUS.\n", + printk("%s: suspicious SCSI data while resetting the BUS.\n", ncr_name(np)); - printf("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = " + printk("%s: %sdp0,d7-0,rst,req,ack,bsy,sel,atn,msg,c/d,i/o = " "0x%lx, expecting 0x%lx\n", ncr_name(np), (np->features & FE_WIDE) ? "dp1,d15-8," : "", @@ -5323,27 +5400,16 @@ ** **========================================================== */ -int ncr_reset_bus (Scsi_Cmnd *cmd, int sync_reset) +int ncr_reset_bus (ncb_p np, Scsi_Cmnd *cmd, int sync_reset) { - struct Scsi_Host *host = cmd->host; /* Scsi_Device *device = cmd->device; */ - struct host_data *host_data = (struct host_data *) host->hostdata; - ncb_p np = host_data->ncb; ccb_p cp; - u_long flags; int found; -#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT - if (np->stalling) - np->stalling = 0; -#endif - - save_flags(flags); cli(); /* * Return immediately if reset is in progress. */ if (np->settle_time) { - restore_flags(flags); return SCSI_RESET_PUNT; } /* @@ -5352,7 +5418,7 @@ * Commands will now be queued in the waiting list until a settle * delay of 2 seconds will be completed. */ - ncr_start_reset(np, driver_setup.settle_delay); + ncr_start_reset(np); /* * First, look in the wakeup list */ @@ -5387,11 +5453,9 @@ */ if (!found && sync_reset && !retrieve_from_waiting_list(0, np, cmd)) { cmd->result = ScsiResult(DID_RESET, 0); - cmd->scsi_done(cmd); + ncr_queue_done_cmd(np, cmd); } - restore_flags(flags); - return SCSI_RESET_SUCCESS; } @@ -5404,30 +5468,19 @@ ** **========================================================== */ -static int ncr_abort_command (Scsi_Cmnd *cmd) +static int ncr_abort_command (ncb_p np, Scsi_Cmnd *cmd) { - struct Scsi_Host *host = cmd->host; /* Scsi_Device *device = cmd->device; */ - struct host_data *host_data = (struct host_data *) host->hostdata; - ncb_p np = host_data->ncb; ccb_p cp; - u_long flags; int found; int retv; -#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT - if (np->stalling == 2) - np->stalling = 0; -#endif - - save_flags(flags); cli(); /* * First, look for the scsi command in the waiting list */ if (remove_from_waiting_list(np, cmd)) { cmd->result = ScsiResult(DID_ABORT, 0); - cmd->scsi_done(cmd); - restore_flags(flags); + ncr_queue_done_cmd(np, cmd); return SCSI_ABORT_SUCCESS; } @@ -5446,45 +5499,45 @@ } if (!found) { - restore_flags(flags); return SCSI_ABORT_NOT_RUNNING; } if (np->settle_time) { - restore_flags(flags); return SCSI_ABORT_SNOOZE; } /* - ** Disable reselect. - ** Remove it from startqueue. - ** Set cp->tlimit to 0. The ncr_timeout() handler will use - ** this condition in order to complete the canceled command - ** after the script skipped the ccb, if necessary. - */ - cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP); - if (cp->phys.header.launch.l_paddr == - cpu_to_scr(NCB_SCRIPT_PHYS (np, select))) { - printf ("%s: abort ccb=%p (skip)\n", ncr_name (np), cp); - cp->phys.header.launch.l_paddr = - cpu_to_scr(NCB_SCRIPT_PHYS (np, skip)); - } + ** If the CCB is active, patch schedule jumps for the + ** script to abort the command. + */ cp->tlimit = 0; - retv = SCSI_ABORT_PENDING; + switch(cp->host_status) { + case HS_BUSY: + case HS_NEGOTIATE: + printk ("%s: abort ccb=%p (cancel)\n", ncr_name (np), cp); + cp->start.schedule.l_paddr = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, cancel)); + retv = SCSI_ABORT_PENDING; + break; + case HS_DISCONNECT: + cp->restart.schedule.l_paddr = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort)); + retv = SCSI_ABORT_PENDING; + break; + default: + retv = SCSI_ABORT_NOT_RUNNING; + break; + + } /* ** If there are no requests, the script ** processor will sleep on SEL_WAIT_RESEL. ** Let's wake it up, since it may have to work. */ -#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT - if (!np->stalling) -#endif OUTB (nc_istat, SIGP); - restore_flags(flags); - return retv; } @@ -5508,7 +5561,7 @@ int target, lun; int i; - printf("%s: releasing host resources\n", ncr_name(np)); + printk("%s: releasing host resources\n", ncr_name(np)); /* ** Stop the ncr_timeout process @@ -5516,12 +5569,12 @@ */ #ifdef DEBUG_NCR53C8XX - printf("%s: stopping the timer\n", ncr_name(np)); + printk("%s: stopping the timer\n", ncr_name(np)); #endif np->release_stage = 1; - for (i = 50 ; i && np->release_stage != 2 ; i--) DELAY(100000); + for (i = 50 ; i && np->release_stage != 2 ; i--) MDELAY (100); if (np->release_stage != 2) - printf("%s: the timer seems to be already stopped\n", ncr_name(np)); + printk("%s: the timer seems to be already stopped\n", ncr_name(np)); else np->release_stage = 2; /* @@ -5529,7 +5582,7 @@ */ #ifdef DEBUG_NCR53C8XX - printf("%s: disabling chip interrupts\n", ncr_name(np)); + printk("%s: disabling chip interrupts\n", ncr_name(np)); #endif OUTW (nc_sien , 0); OUTB (nc_dien , 0); @@ -5539,26 +5592,18 @@ */ #ifdef DEBUG_NCR53C8XX -#ifdef __sparc__ - printf("%s: freeing irq 0x%x\n", ncr_name(np), np->irq); -#else - printf("%s: freeing irq %d\n", ncr_name(np), np->irq); -#endif + printk("%s: freeing irq %d\n", ncr_name(np), np->irq); #endif -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) free_irq(np->irq, np); -#else - free_irq(np->irq); -#endif /* ** Reset NCR chip ** Restore bios setting for automatic clock detection. */ - printf("%s: resetting chip\n", ncr_name(np)); + printk("%s: resetting chip\n", ncr_name(np)); OUTB (nc_istat, SRST); - DELAY (1000); + UDELAY (100); OUTB (nc_istat, 0 ); OUTB(nc_dmode, np->sv_dmode); @@ -5577,17 +5622,13 @@ #ifndef NCR_IOMAPPED #ifdef DEBUG_NCR53C8XX - printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128); + printk("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr, 128); #endif unmap_pci_mem((vm_offset_t) np->vaddr, (u_long) 128); -#ifdef DEBUG_NCR53C8XX - printf("%s: releasing memory mapped IO region %lx[%d]\n", ncr_name(np), (u_long) np->vaddr2, 4096); -#endif - unmap_pci_mem((vm_offset_t) np->vaddr2, (u_long) 4096); -#endif +#endif /* !NCR_IOMAPPED */ #ifdef DEBUG_NCR53C8XX - printf("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128); + printk("%s: releasing IO region %x[%d]\n", ncr_name(np), np->port, 128); #endif release_region(np->port, 128); @@ -5598,11 +5639,11 @@ while ((cp=np->ccb->link_ccb) != NULL) { np->ccb->link_ccb = cp->link_ccb; if (cp->host_status) { - printf("%s: shall free an active ccb (host_status=%d)\n", + printk("%s: shall free an active ccb (host_status=%d)\n", ncr_name(np), cp->host_status); } #ifdef DEBUG_NCR53C8XX - printf("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp); + printk("%s: freeing ccb (%lx)\n", ncr_name(np), (u_long) cp); #endif m_free(cp, sizeof(*cp)); } @@ -5617,14 +5658,16 @@ lp = tp->lp[lun]; if (lp) { #ifdef DEBUG_NCR53C8XX - printf("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp); + printk("%s: freeing lp (%lx)\n", ncr_name(np), (u_long) lp); #endif + if (lp->maxnxs > 1) + m_free(lp->jump_ccb, 256); m_free(lp, sizeof(*lp)); } } } - printf("%s: host resources successfully released\n", ncr_name(np)); + printk("%s: host resources successfully released\n", ncr_name(np)); return 1; } @@ -5650,20 +5693,8 @@ ** Sanity check */ - if (!cp || (cp->magic!=CCB_MAGIC) || !cp->cmd) return; - cp->magic = 1; - cp->tlimit= 0; - cmd = cp->cmd; - - /* - ** No Reselect anymore. - */ - cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP); - - /* - ** No starting. - */ - cp->phys.header.launch.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + if (!cp || cp->magic != CCB_MAGIC || !cp->cmd) + return; /* ** timestamp @@ -5674,9 +5705,13 @@ #endif if (DEBUG_FLAGS & DEBUG_TINY) - printf ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff, + printk ("CCB=%lx STAT=%x/%x\n", (unsigned long)cp & 0xfff, cp->host_status,cp->scsi_status); + /* + ** Get command, target and lun pointers. + */ + cmd = cp->cmd; cp->cmd = NULL; tp = &np->target[cmd->target]; @@ -5692,17 +5727,32 @@ tp->nego_cp = 0; /* + ** If auto-sense performed, change scsi status. + */ + if (cp->auto_sense) { + cp->scsi_status = cp->auto_sense; + } + + /* + ** If we were recovering from queue full or performing + ** auto-sense, requeue skipped CCBs to the wait queue. + */ + + if (lp && lp->held_ccb) { + if (cp == lp->held_ccb) { + xpt_que_splice(&lp->skip_ccbq, &lp->wait_ccbq); + xpt_que_init(&lp->skip_ccbq); + lp->held_ccb = 0; + } + } + + /* ** Check for parity errors. */ - if (cp->parity_status) { + if (cp->parity_status > 1) { PRINT_ADDR(cmd); - printf ("%d parity error(s), fallback.\n", cp->parity_status); - /* - ** fallback to asynch transfer. - */ - tp->usrsync=255; - tp->period = 0; + printk ("%d parity error(s).\n",cp->parity_status); } /* @@ -5713,13 +5763,13 @@ PRINT_ADDR(cmd); switch (cp->xerr_status) { case XE_EXTRA_DATA: - printf ("extraneous data discarded.\n"); + printk ("extraneous data discarded.\n"); break; case XE_BAD_PHASE: - printf ("illegal scsi phase (4/5).\n"); + printk ("illegal scsi phase (4/5).\n"); break; default: - printf ("extended error %d.\n", cp->xerr_status); + printk ("extended error %d.\n", cp->xerr_status); break; } if (cp->host_status==HS_COMPLETE) @@ -5727,95 +5777,69 @@ } /* + ** Print out any error for debugging purpose. + */ + if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { + if (cp->host_status!=HS_COMPLETE || cp->scsi_status!=S_GOOD) { + PRINT_ADDR(cmd); + printk ("ERROR: cmd=%x host_status=%x scsi_status=%x\n", + cmd->cmnd[0], cp->host_status, cp->scsi_status); + } + } + + /* ** Check the status. */ if ( (cp->host_status == HS_COMPLETE) && (cp->scsi_status == S_GOOD || cp->scsi_status == S_COND_MET)) { - /* + /* ** All went well (GOOD status). ** CONDITION MET status is returned on - ** `Pre-Fetch' or `Search data' success. - */ + ** `Pre-Fetch' or `Search data' success. + */ cmd->result = ScsiResult(DID_OK, cp->scsi_status); /* - ** if (cp->phys.header.lastp != cp->phys.header.goalp)... - ** ** @RESID@ ** Could dig out the correct value for resid, ** but it would be quite complicated. - ** - ** The ah1542.c driver sets it to 0 too ... */ + /* if (cp->phys.header.lastp != cp->phys.header.goalp) */ /* - ** Try to assign a ccb to this nexus + ** Allocate the lcb if not yet. */ - ncr_alloc_ccb (np, cmd->target, cmd->lun); + if (!lp) + ncr_alloc_lcb (np, cmd->target, cmd->lun); /* - ** On inquire cmd (0x12) save some data. - ** Clear questionnable capacities. + ** On standard INQUIRY response (EVPD and CmDt + ** not set), setup logical unit according to + ** announced capabilities. */ - if (cmd->lun == 0 && cmd->cmnd[0] == 0x12) { - if (np->unit < SCSI_NCR_MAX_HOST) { - if (driver_setup.force_sync_nego) - ((char *) cmd->request_buffer)[7] |= INQ7_SYNC; - else - ((char *) cmd->request_buffer)[7] &= - (target_capabilities[np->unit].and_map[cmd->target]); - } - bcopy ( cmd->request_buffer, - &tp->inqdata, - sizeof (tp->inqdata)); - - /* - ** set number of tags - */ - ncr_setmaxtags (np, tp, driver_setup.default_tags); - /* - ** prepare negotiation of synch and wide. - */ - ncr_negotiate (np, tp); - - /* - ** force quirks update before next command start - */ - tp->quirks |= QUIRK_UPDATE; + if (cmd->cmnd[0] == 0x12 && !(cmd->cmnd[1] & 0x3)) { + ncr_setup_lcb (np, cmd->target, cmd->lun, + (char *) cmd->request_buffer); } - /* - ** Announce changes to the generic driver. - */ - if (lp) { - ncr_settags (tp, lp); - if (lp->reqlink != lp->actlink) - ncr_opennings (np, lp, cmd); - }; - tp->bytes += cp->data_len; tp->transfers ++; /* ** If tags was reduced due to queue full, - ** increase tags if 100 good status received. + ** increase tags if 1000 good status received. */ - if (tp->numtags < tp->maxtags) { - ++tp->num_good; - if (tp->num_good >= 100) { - tp->num_good = 0; - ++tp->numtags; - if (tp->numtags == 1) { - PRINT_ADDR(cmd); - printf("tagged command queueing resumed\n"); - } + if (lp && lp->numtags < lp->maxtags) { + ++lp->num_good; + if (lp->num_good >= 1000) { + lp->num_good = 0; + ++lp->numtags; + ncr_setup_tags (np, cmd->target, cmd->lun); } } } else if ((cp->host_status == HS_COMPLETE) - && (cp->scsi_status == (S_SENSE|S_GOOD) || - cp->scsi_status == (S_SENSE|S_CHECK_COND))) { - + && (cp->scsi_status == S_CHECK_COND)) { /* ** Check condition code */ @@ -5824,49 +5848,20 @@ if (DEBUG_FLAGS & (DEBUG_RESULT|DEBUG_TINY)) { u_char * p = (u_char*) & cmd->sense_buffer; int i; - printf ("\n%s: sense data:", ncr_name (np)); - for (i=0; i<14; i++) printf (" %x", *p++); - printf (".\n"); + printk ("\n%s: sense data:", ncr_name (np)); + for (i=0; i<14; i++) printk (" %x", *p++); + printk (".\n"); } } else if ((cp->host_status == HS_COMPLETE) && (cp->scsi_status == S_BUSY || - cp->scsi_status == S_CONFLICT)) { + cp->scsi_status == S_QUEUE_FULL)) { /* ** Target is busy. */ cmd->result = ScsiResult(DID_OK, cp->scsi_status); - } else if ((cp->host_status == HS_COMPLETE) - && (cp->scsi_status == S_QUEUE_FULL)) { - - /* - ** Target is stuffed. - */ - cmd->result = ScsiResult(DID_OK, cp->scsi_status); - - /* - ** Suspend tagged queuing and start good status counter. - ** Announce changes to the generic driver. - */ - if (tp->numtags) { - /* - * Decrease tp->maxtags (ecd, 980110) - */ - tp->maxtags = tp->numtags - 1; - - PRINT_ADDR(cmd); - printf("QUEUE FULL! suspending tagged command queueing (setting maxtags to %d)\n", tp->maxtags); - - tp->numtags = 0; - tp->num_good = 0; - if (lp) { - ncr_settags (tp, lp); - if (lp->reqlink != lp->actlink) - ncr_opennings (np, lp, cmd); - }; - } } else if ((cp->host_status == HS_SEL_TIMEOUT) || (cp->host_status == HS_TIMEOUT)) { @@ -5895,7 +5890,7 @@ ** Other protocol messes */ PRINT_ADDR(cmd); - printf ("COMMAND FAILED (%x %x) @%p.\n", + printk ("COMMAND FAILED (%x %x) @%p.\n", cp->host_status, cp->scsi_status, cp); cmd->result = ScsiResult(DID_ERROR, cp->scsi_status); @@ -5909,43 +5904,51 @@ u_char * p; int i; PRINT_ADDR(cmd); - printf (" CMD:"); + printk (" CMD:"); p = (u_char*) &cmd->cmnd[0]; - for (i=0; icmd_len; i++) printf (" %x", *p++); + for (i=0; icmd_len; i++) printk (" %x", *p++); if (cp->host_status==HS_COMPLETE) { switch (cp->scsi_status) { case S_GOOD: - printf (" GOOD"); + printk (" GOOD"); break; case S_CHECK_COND: - printf (" SENSE:"); + printk (" SENSE:"); p = (u_char*) &cmd->sense_buffer; for (i=0; i<14; i++) - printf (" %x", *p++); + printk (" %x", *p++); break; default: - printf (" STAT: %x\n", cp->scsi_status); + printk (" STAT: %x\n", cp->scsi_status); break; } - } else printf (" HOSTERROR: %x", cp->host_status); - printf ("\n"); + } else printk (" HOSTERROR: %x", cp->host_status); + printk ("\n"); } /* ** Free this ccb */ - ncr_free_ccb (np, cp, cmd->target, cmd->lun); + ncr_free_ccb (np, cp); + + /* + ** requeue awaiting scsi commands for this lun. + */ + if (lp && lp->queuedccbs < lp->queuedepth && + !xpt_que_empty(&lp->wait_ccbq)) + ncr_start_next_ccb(np, lp, 2); /* - ** requeue awaiting scsi commands + ** requeue awaiting scsi commands for this controller. */ - if (np->waiting_list) requeue_waiting_list(np); + if (np->waiting_list) + requeue_waiting_list(np); /* ** signal completion to generic driver. */ - cmd->scsi_done (cmd); + ncr_queue_done_cmd(np, cmd); } /*========================================================== @@ -5957,41 +5960,92 @@ **========================================================== */ -void ncr_wakeup (ncb_p np, u_long code) +/* +** This CCB has been skipped by the NCR. +** Queue it in the correponding unit queue. +*/ +void ncr_ccb_skipped(ncb_p np, ccb_p cp) { - /* - ** Starting at the default ccb and following - ** the links, complete all jobs with a - ** host_status greater than "disconnect". - ** - ** If the "code" parameter is not zero, - ** complete all jobs that are not IDLE. - */ + tcb_p tp = &np->target[cp->target]; + lcb_p lp = tp->lp[cp->lun]; - ccb_p cp = np->ccb; - while (cp) { - switch (cp->host_status) { + if (lp && cp != np->ccb) { + cp->host_status &= ~HS_SKIPMASK; + cp->start.schedule.l_paddr = + cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); + xpt_remque(&cp->link_ccbq); + xpt_insque_tail(&cp->link_ccbq, &lp->skip_ccbq); + if (cp->queued) { + --lp->queuedccbs; + } + } + if (cp->queued) { + --np->queuedccbs; + cp->queued = 0; + } +} + +/* +** The NCR has completed CCBs. +** Look at the DONE QUEUE if enabled, otherwise scan all CCBs +*/ +void ncr_wakeup_done (ncb_p np) +{ + ccb_p cp; +#ifdef SCSI_NCR_CCB_DONE_SUPPORT + int i, j; + + i = np->ccb_done_ic; + while (1) { + j = i+1; + if (j >= MAX_DONE) + j = 0; - case HS_IDLE: + cp = np->ccb_done[j]; + if (!CCB_DONE_VALID(cp)) break; - case HS_DISCONNECT: - if(DEBUG_FLAGS & DEBUG_TINY) printf ("D"); - /* fall through */ - - case HS_BUSY: - case HS_NEGOTIATE: - if (!code) break; - cp->host_status = code; + np->ccb_done[j] = (ccb_p) CCB_DONE_EMPTY; + np->scripth->done_queue[5*j + 4] = + cpu_to_scr(NCB_SCRIPT_PHYS (np, done_plug)); + MEMORY_BARRIER(); + np->scripth->done_queue[5*i + 4] = + cpu_to_scr(NCB_SCRIPT_PHYS (np, done_end)); - /* fall through */ + if (cp->host_status & HS_DONEMASK) + ncr_complete (np, cp); + else if (cp->host_status & HS_SKIPMASK) + ncr_ccb_skipped (np, cp); - default: + i = j; + } + np->ccb_done_ic = i; +#else + cp = np->ccb; + while (cp) { + if (cp->host_status & HS_DONEMASK) ncr_complete (np, cp); - break; - }; - cp = cp -> link_ccb; - }; + else if (cp->host_status & HS_SKIPMASK) + ncr_ccb_skipped (np, cp); + cp = cp->link_ccb; + } +#endif +} + +/* +** Complete all active CCBs. +*/ +void ncr_wakeup (ncb_p np, u_long code) +{ + ccb_p cp = np->ccb; + + while (cp) { + if (cp->host_status != HS_IDLE) { + cp->host_status = code; + ncr_complete (np, cp); + } + cp = cp->link_ccb; + } } /*========================================================== @@ -6003,35 +6057,59 @@ **========================================================== */ -void ncr_init (ncb_p np, char * msg, u_long code) +void ncr_init (ncb_p np, int reset, char * msg, u_long code) { - int i; - - /* - ** Reset chip. - */ + int i; - OUTB (nc_istat, SRST); - DELAY (10000); + /* + ** Reset chip if asked, otherwise just clear fifos. + */ + if (reset) { + OUTB (nc_istat, SRST); + UDELAY (100); + } + else { + OUTB (nc_stest3, TE|CSF); + OUTONB (nc_ctest3, CLF); + } + /* ** Message. */ - if (msg) printf (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg); + if (msg) printk (KERN_INFO "%s: restart (%s).\n", ncr_name (np), msg); /* ** Clear Start Queue */ - for (i=0;i squeue [i] = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + np->queuedepth = MAX_START - 1; /* 1 entry needed as end marker */ + for (i = 1; i < MAX_START + MAX_START; i += 2) + np->scripth0->tryloop[i] = + cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); /* ** Start at first entry. */ np->squeueput = 0; np->script0->startpos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np, tryloop)); - np->script0->start0 [0] = cpu_to_scr(SCR_INT ^ IFFALSE (0)); + + /* + ** Clear Done Queue + */ + for (i = 0; i < MAX_DONE; i++) { + np->ccb_done[i] = (ccb_p) CCB_DONE_EMPTY; + np->scripth0->done_queue[5*i + 4] = + cpu_to_scr(NCB_SCRIPT_PHYS (np, done_end)); + } + + /* + ** Start at first entry. + */ + np->script0->done_pos[0] = cpu_to_scr(NCB_SCRIPTH_PHYS (np,done_queue)); + np->ccb_done_ic = MAX_DONE-1; + np->scripth0->done_queue[5*(MAX_DONE-1) + 4] = + cpu_to_scr(NCB_SCRIPT_PHYS (np, done_plug)); /* ** Wakeup all pending jobs. @@ -6043,6 +6121,8 @@ */ OUTB (nc_istat, 0x00 ); /* Remove Reset, abort */ + UDELAY (2000); /* The 895 needs time for the bus mode to settle */ + OUTB (nc_scntl0, np->rv_scntl0 | 0xc0); /* full arb., ena parity, par->ATN */ OUTB (nc_scntl1, 0x00); /* odd parity, and remove CRST!! */ @@ -6061,7 +6141,7 @@ OUTB (nc_stest2, EXT|np->rv_stest2); /* Extended Sreq/Sack filtering */ OUTB (nc_stest3, TE); /* TolerANT enable */ - OUTB (nc_stime0, 0x0d ); /* HTH disabled STO 0.4 sec. */ + OUTB (nc_stime0, 0x0c ); /* HTH disabled STO 0.25 sec */ /* ** Disable disconnects. @@ -6078,23 +6158,10 @@ } /* - ** Upload the script into on-board RAM - */ - if (np->vaddr2) { - if (bootverbose) - printf ("%s: copying script fragments into the on-board RAM ...\n", ncr_name(np)); -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0) - memcpy_toio(np->script, np->script0, sizeof(struct script)); -#else - memcpy(np->script, np->script0, sizeof(struct script)); -#endif - } - - /* ** enable ints */ - OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST); + OUTW (nc_sien , STO|HTH|MA|SGE|UDC|RST|PAR); OUTB (nc_dien , MDPE|BF|ABRT|SSI|SIR|IID); /* @@ -6137,8 +6204,16 @@ /* ** Start script processor. */ - - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); + MEMORY_BARRIER(); + if (np->paddr2) { + if (bootverbose) + printk ("%s: Downloading SCSI SCRIPTS.\n", + ncr_name(np)); + OUTL (nc_scratcha, vtophys(np->script0)); + OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, start_ram)); + } + else + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); } /*========================================================== @@ -6166,14 +6241,6 @@ } /* - ** if not scsi 2 - ** don't believe FAST! - */ - - if ((minsync < 50) && (tp->inqdata[2] & 0x0f) < 2) - minsync=50; - - /* ** our limit .. */ @@ -6249,7 +6316,7 @@ /* ** Why not to try the immediate lower divisor and to choose ** the one that allows the fastest output speed ? - ** We don't want input speed too much greater than output speed. + ** We dont want input speed too much greater than output speed. */ if (div >= 1 && fak < 8) { u_long fak2, per2; @@ -6300,8 +6367,12 @@ for (cp = np->ccb; cp; cp = cp->link_ccb) { if (!cp->cmd) continue; if (cp->cmd->target != target) continue; +#if 0 cp->sync_status = tp->sval; cp->wide_status = tp->wval; +#endif + cp->phys.select.sel_scntl3 = tp->wval; + cp->phys.select.sel_sxfer = tp->sval; }; } @@ -6316,15 +6387,15 @@ { Scsi_Cmnd *cmd; tcb_p tp; - u_char target = INB (nc_ctest0) & 0x0f; + u_char target = INB (nc_sdid) & 0x0f; u_char idiv; - assert (cp); + assert (cp && cp->cmd); if (!cp) return; cmd = cp->cmd; - assert (cmd); if (!cmd) return; + assert (target == (cmd->target & 0xf)); tp = &np->target[target]; @@ -6354,7 +6425,7 @@ /* ** Bells and whistles ;-) */ - PRINT_ADDR(cmd); + PRINT_TARGET(np, target); if (sxfer & 0x01f) { unsigned f10 = 100000 << (tp->widedone ? tp->widedone -1 : 0); unsigned mb10 = (f10 + tp->period/2) / tp->period; @@ -6373,11 +6444,11 @@ else if (tp->period < 2000) scsi = "FAST-10"; else scsi = "FAST-5"; - printf ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi, + printk ("%s %sSCSI %d.%d MB/s (%d ns, offset %d)\n", scsi, tp->widedone > 1 ? "WIDE " : "", mb10 / 10, mb10 % 10, tp->period / 10, sxfer & 0x1f); } else - printf ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); + printk ("%sasynchronous.\n", tp->widedone > 1 ? "wide " : ""); /* ** set actual value and sync_status @@ -6399,17 +6470,17 @@ static void ncr_setwide (ncb_p np, ccb_p cp, u_char wide, u_char ack) { Scsi_Cmnd *cmd; - u_short target = INB (nc_ctest0) & 0x0f; + u_short target = INB (nc_sdid) & 0x0f; tcb_p tp; u_char scntl3; u_char sxfer; - assert (cp); + assert (cp && cp->cmd); if (!cp) return; cmd = cp->cmd; - assert (cmd); if (!cmd) return; + assert (target == (cmd->target & 0xf)); tp = &np->target[target]; @@ -6429,11 +6500,11 @@ ** Bells and whistles ;-) */ if (bootverbose >= 2) { - PRINT_ADDR(cmd); + PRINT_TARGET(np, target); if (scntl3 & EWS) - printf ("WIDE SCSI (16 bit) enabled.\n"); + printk ("WIDE SCSI (16 bit) enabled.\n"); else - printf ("WIDE SCSI disabled.\n"); + printk ("WIDE SCSI disabled.\n"); } /* @@ -6452,71 +6523,107 @@ static void ncr_setmaxtags (ncb_p np, tcb_p tp, u_long numtags) { - int l; if (numtags > tp->usrtags) numtags = tp->usrtags; - tp->numtags = numtags; - tp->maxtags = numtags; - for (l=0; llp[ln]; - if (!tp) break; - lp=tp->lp[l]; - if (!lp) continue; - - wastags = lp->usetags; - ncr_settags (tp, lp); - - if (numtags > 1 && lp->reqccbs > 1) { - PRINT_LUN(np, tp - np->target, l); - printf("using tagged command queueing, up to %ld cmds/lun\n", numtags); - } - else if (numtags <= 1 && wastags) { - PRINT_LUN(np, tp - np->target, l); - printf("disabling tagged command queueing\n"); + if (!lp) + continue; + lp->maxtags = lp->numtags = numtags; + ncr_setup_tags (np, (tp - np->target), ln); } - }; + } } -static void ncr_settags (tcb_p tp, lcb_p lp) +static void ncr_setup_tags (ncb_p np, u_char tn, u_char ln) { - u_char reqtags, tmp; + tcb_p tp = &np->target[tn]; + lcb_p lp = tp->lp[ln]; + u_char reqtags, maxdepth; + + /* + ** Just in case ... + */ + if ((!tp) || (!lp)) + return; + + /* + ** If SCSI device queue depth is not yet set, leave here. + */ + if (!lp->scdev_depth) + return; - if ((!tp) || (!lp)) return; + /* + ** Donnot allow more tags than the SCSI driver can queue + ** for this device. + ** Donnot allow more tags than we can handle. + */ + maxdepth = lp->scdev_depth; + if (maxdepth > lp->maxnxs) maxdepth = lp->maxnxs; + if (lp->maxtags > maxdepth) lp->maxtags = maxdepth; + if (lp->numtags > maxdepth) lp->numtags = maxdepth; /* ** only devices conformant to ANSI Version >= 2 - ** only devices capable of tagges commands - ** only disk devices + ** only devices capable of tagged commands ** only if enabled by user .. */ - if (( tp->inqdata[2] & 0x7) >= 2 && - ( tp->inqdata[7] & INQ7_QUEUE) && ((tp->inqdata[0] & 0x1f)==0x00) - && tp->numtags > 1) { - reqtags = tp->numtags; - if (lp->actlink <= 1) - lp->usetags=reqtags; + if ((lp->inq_byte7 & INQ7_QUEUE) && lp->numtags > 1) { + reqtags = lp->numtags; } else { reqtags = 1; - if (lp->actlink <= 1) - lp->usetags=0; }; /* - ** don't announce more than available. + ** Update max number of tags + */ + lp->numtags = reqtags; + if (lp->numtags > lp->maxtags) + lp->maxtags = lp->numtags; + + /* + ** If we want to switch tag mode, we must wait + ** for no CCB to be active. + */ + if (reqtags > 1 && lp->usetags) { /* Stay in tagged mode */ + if (lp->queuedepth == reqtags) /* Already announced */ + return; + lp->queuedepth = reqtags; + } + else if (reqtags <= 1 && !lp->usetags) { /* Stay in untagged mode */ + lp->queuedepth = reqtags; + return; + } + else { /* Want to switch tag mode */ + if (lp->busyccbs) /* If not yet safe, return */ + return; + lp->queuedepth = reqtags; + lp->usetags = reqtags > 1 ? 1 : 0; + } + + /* + ** Patch the lun mini-script, according to tag mode. */ - tmp = lp->actccbs; - if (tmp > reqtags) tmp = reqtags; - lp->reqlink = tmp; + lp->jump_tag.l_paddr = lp->usetags? + cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_tag)) : + cpu_to_scr(NCB_SCRIPT_PHYS(np, resel_notag)); /* - ** don't discard if announced. + ** Announce change to user. */ - tmp = lp->actlink; - if (tmp < reqtags) tmp = reqtags; - lp->reqccbs = tmp; + if (bootverbose) { + PRINT_LUN(np, tn, ln); + if (lp->usetags) { + printk("tagged command queue depth set to %d\n", reqtags); + } + else { + printk("tagged command queueing disabled\n"); + } + } } /*---------------------------------------------------- @@ -6547,8 +6654,6 @@ break; case UC_SETTAGS: - if (np->user.data > SCSI_NCR_MAX_TAGS) - np->user.data = SCSI_NCR_MAX_TAGS; for (t=0; tuser.target>>t)&1)) continue; np->target[t].usrtags = np->user.data; @@ -6566,6 +6671,10 @@ np->order = np->user.data; break; + case UC_SETVERBOSE: + np->verbose = np->user.data; + break; + case UC_SETWIDE: for (t=0; tprofile, sizeof(np->profile)); break; -#ifdef UC_DEBUG_ERROR_RECOVERY - case UC_DEBUG_ERROR_RECOVERY: - np->debug_error_recovery = np->user.data; - break; #endif } np->user.cmd=0; } #endif - -/*===================================================================== -** -** Embedded error recovery debugging code. -** -**===================================================================== -** -** This code is conditionned by SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT. -** It only can be enabled after boot-up with a control command. -** -** Every 30 seconds the timer handler of the driver decides to -** change the behaviour of the driver in order to trigger errors. -** -** If last command was "debug_error_recovery sge", the driver -** sets sync offset of all targets that use sync transfers to 2, -** and so hopes a SCSI gross error at the next read operation. -** -** If last command was "debug_error_recovery abort", the driver -** does not signal new scsi commands to the script processor, until -** it is asked to abort or reset a command by the mid-level driver. -** -** If last command was "debug_error_recovery reset", the driver -** does not signal new scsi commands to the script processor, until -** it is asked to reset a command by the mid-level driver. -** -** If last command was "debug_error_recovery parity", the driver -** will assert ATN on the next DATA IN phase mismatch, and so will -** behave as if a parity error had been detected. -** -** The command "debug_error_recovery none" makes the driver behave -** normaly. -** -**===================================================================== -*/ - -#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT -static void ncr_trigger_errors (ncb_p np) -{ - /* - ** If np->debug_error_recovery is not zero, we want to - ** simulate common errors in order to test error recovery. - */ - do { - static u_long last = 0l; - - if (!np->debug_error_recovery) - break; - if (!last) - last = jiffies; - else if (jiffies < last + 30*HZ) - break; - last = jiffies; - /* - * This one triggers SCSI gross errors. - */ - if (np->debug_error_recovery == 1) { - int i; - printf("%s: testing error recovery from SCSI gross error...\n", ncr_name(np)); - for (i = 0 ; i < MAX_TARGET ; i++) { - if (np->target[i].sval & 0x1f) { - np->target[i].sval &= ~0x1f; - np->target[i].sval += 2; - } - } - } - /* - * This one triggers abort from the mid-level driver. - */ - else if (np->debug_error_recovery == 2) { - printf("%s: testing error recovery from mid-level driver abort()...\n", ncr_name(np)); - np->stalling = 2; - } - /* - * This one triggers reset from the mid-level driver. - */ - else if (np->debug_error_recovery == 3) { - printf("%s: testing error recovery from mid-level driver reset()...\n", ncr_name(np)); - np->stalling = 3; - } - /* - * This one set ATN on phase mismatch in DATA IN phase and so - * will behave as on scsi parity error detected. - */ - else if (np->debug_error_recovery == 4) { - printf("%s: testing data in parity error...\n", ncr_name(np)); - np->assert_atn = 1; - } - } while (0); -} -#endif - /*========================================================== ** ** @@ -6707,9 +6722,6 @@ static void ncr_timeout (ncb_p np) { u_long thistime = jiffies; - u_long count = 0; - ccb_p cp; - u_long flags; /* ** If release process in progress, let's go @@ -6722,18 +6734,9 @@ return; } - np->timer.expires = -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) - jiffies + -#endif - SCSI_NCR_TIMER_INTERVAL; - + np->timer.expires = jiffies + SCSI_NCR_TIMER_INTERVAL; add_timer(&np->timer); -#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT - ncr_trigger_errors (np); -#endif - /* ** If we are resetting the ncr, wait for settle_time before ** clearing it. Then command processing will be resumed. @@ -6741,12 +6744,10 @@ if (np->settle_time) { if (np->settle_time <= thistime) { if (bootverbose > 1) - printf("%s: command processing resumed\n", ncr_name(np)); - save_flags(flags); cli(); + printk("%s: command processing resumed\n", ncr_name(np)); np->settle_time = 0; np->disc = 1; requeue_waiting_list(np); - restore_flags(flags); } return; } @@ -6756,99 +6757,20 @@ ** to perform abort of a command, we must look at ccbs about ** every 0.25 second. */ - if (np->lasttime + (HZ>>2) <= thistime) { + if (np->lasttime + 4*HZ < thistime) { /* ** block ncr interrupts */ - save_flags(flags); cli(); - np->lasttime = thistime; +#ifdef SCSI_NCR_PROFILE_SUPPORT /* ** Reset profile data to avoid ugly overflow ** (Limited to 1024 GB for 32 bit architecture) */ if (np->profile.num_kbytes > (~0UL >> 2)) bzero(&np->profile, sizeof(np->profile)); - - /*---------------------------------------------------- - ** - ** handle ncr chip timeouts - ** - ** Assumption: - ** We have a chance to arbitrate for the - ** SCSI bus at least every 10 seconds. - ** - **---------------------------------------------------- - */ -#if 0 - if (thistime < np->heartbeat + HZ + HZ) - np->latetime = 0; - else - np->latetime++; -#endif - - /*---------------------------------------------------- - ** - ** handle ccb timeouts - ** - **---------------------------------------------------- - */ - - for (cp=np->ccb; cp; cp=cp->link_ccb) { - /* - ** look for timed out ccbs. - */ - if (!cp->host_status) continue; - count++; - /* - ** Have to force ordered tag to avoid timeouts - */ - if (cp->cmd && cp->tlimit && cp->tlimit <= - thistime + NCR_TIMEOUT_INCREASE + SCSI_NCR_TIMEOUT_ALERT) { - lcb_p lp; - lp = np->target[cp->cmd->target].lp[cp->cmd->lun]; - if (lp && !lp->force_ordered_tag) { - lp->force_ordered_tag = 1; - } - } - /* - ** ncr_abort_command() cannot complete canceled - ** commands immediately. It sets tlimit to zero - ** and ask the script to skip the scsi process if - ** necessary. We have to complete this work here. - */ - - if (cp->tlimit) continue; - - switch (cp->host_status) { - - case HS_BUSY: - case HS_NEGOTIATE: - /* - ** still in start queue ? - */ - if (cp->phys.header.launch.l_paddr == - cpu_to_scr(NCB_SCRIPT_PHYS (np, skip))) - continue; - - /* fall through */ - case HS_DISCONNECT: - cp->host_status=HS_ABORTED; - }; - cp->tag = 0; - - /* - ** wakeup this ccb. - */ - ncr_complete (np, cp); - -#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT - if (!np->stalling) #endif - OUTB (nc_istat, SIGP); - } - restore_flags(flags); } #ifdef SCSI_NCR_BROKEN_INTR @@ -6857,11 +6779,9 @@ /* ** Process pending interrupts. */ - save_flags(flags); cli(); - if (DEBUG_FLAGS & DEBUG_TINY) printf ("{"); + if (DEBUG_FLAGS & DEBUG_TINY) printk ("{"); ncr_exception (np); - if (DEBUG_FLAGS & DEBUG_TINY) printf ("}"); - restore_flags(flags); + if (DEBUG_FLAGS & DEBUG_TINY) printk ("}"); } #endif /* SCSI_NCR_BROKEN_INTR */ } @@ -6910,14 +6830,14 @@ if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) { script_ofs = dsp - np->p_script; script_size = sizeof(struct script); - script_base = (u_char *) np->script; + script_base = (u_char *) np->script0; script_name = "script"; } else if (np->p_scripth < dsp && dsp <= np->p_scripth + sizeof(struct scripth)) { script_ofs = dsp - np->p_scripth; script_size = sizeof(struct scripth); - script_base = (u_char *) np->scripth; + script_base = (u_char *) np->scripth0; script_name = "scripth"; } else { script_ofs = dsp; @@ -6926,22 +6846,22 @@ script_name = "mem"; } - printf ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n", - ncr_name (np), (unsigned)INB (nc_ctest0)&0x0f, dstat, sist, + printk ("%s:%d: ERROR (%x:%x) (%x-%x-%x) (%x/%x) @ (%s %x:%08x).\n", + ncr_name (np), (unsigned)INB (nc_sdid)&0x0f, dstat, sist, (unsigned)INB (nc_socl), (unsigned)INB (nc_sbcl), (unsigned)INB (nc_sbdl), (unsigned)INB (nc_sxfer),(unsigned)INB (nc_scntl3), script_name, script_ofs, (unsigned)INL (nc_dbc)); if (((script_ofs & 3) == 0) && (unsigned)script_ofs < script_size) { - printf ("%s: script cmd = %08x\n", ncr_name(np), + printk ("%s: script cmd = %08x\n", ncr_name(np), (int) *(ncrcmd *)(script_base + script_ofs)); } - printf ("%s: regdump:", ncr_name(np)); + printk ("%s: regdump:", ncr_name(np)); for (i=0; i<16;i++) - printf (" %02x", (unsigned)INB_OFF(i)); - printf (".\n"); + printk (" %02x", (unsigned)INB_OFF(i)); + printk (".\n"); } /*============================================================ @@ -6987,23 +6907,25 @@ ** Since the global header may be copied back to a CCB ** using a posted PCI memory write, the last operation on ** the istat register is a READ in order to flush posted - ** PCI commands (Btw, the 'do' loop is probably useless). + ** PCI write commands. */ istat = INB (nc_istat); if (istat & INTF) { - do { - OUTB (nc_istat, (istat & SIGP) | INTF); - istat = INB (nc_istat); - } while (istat & INTF); - if (DEBUG_FLAGS & DEBUG_TINY) printf ("F "); + OUTB (nc_istat, (istat & SIGP) | INTF); + istat = INB (nc_istat); + if (DEBUG_FLAGS & DEBUG_TINY) printk ("F "); +#ifdef SCSI_NCR_PROFILE_SUPPORT np->profile.num_fly++; - ncr_wakeup (np, 0); +#endif + ncr_wakeup_done (np); }; if (!(istat & (SIP|DIP))) return; +#ifdef SCSI_NCR_PROFILE_SUPPORT np->profile.num_int++; +#endif if (istat & CABRT) OUTB (nc_istat, CABRT); @@ -7017,7 +6939,7 @@ dstat = (istat & DIP) ? INB (nc_dstat) : 0; if (DEBUG_FLAGS & DEBUG_TINY) - printf ("<%d|%x:%x|%x:%x>", + printk ("<%d|%x:%x|%x:%x>", (int)INB(nc_scr0), dstat,sist, (unsigned)INL(nc_dsp), @@ -7054,12 +6976,11 @@ ** DEL 397 - 53C875 Rev 3 - Part Number 609-0392410 - ITEM 2. */ if (!(sist & (SBMC|PAR)) && !(dstat & SSI)) { - printf( "%s: unknown interrupt(s) ignored, " + printk( "%s: unknown interrupt(s) ignored, " "ISTAT=%x DSTAT=%x SIST=%x\n", ncr_name(np), istat, dstat, sist); return; } - OUTONB (nc_dcntl, (STD|NOCOM)); return; }; @@ -7080,7 +7001,7 @@ */ if (sist & RST) { - ncr_init (np, bootverbose ? "scsi reset" : NULL, HS_RESET); + ncr_init (np, 1, bootverbose ? "scsi reset" : NULL, HS_RESET); return; }; @@ -7117,29 +7038,26 @@ ncr_log_hard_error(np, sist, dstat); - printf ("%s: have to clear fifos.\n", ncr_name (np)); + printk ("%s: have to clear fifos.\n", ncr_name (np)); OUTB (nc_stest3, TE|CSF); OUTONB (nc_ctest3, CLF); if ((sist & (SGE)) || (dstat & (MDPE|BF|ABORT|IID))) { - ncr_start_reset(np, driver_setup.settle_delay); + ncr_start_reset(np); return; }; if (sist & HTH) { - printf ("%s: handshake timeout\n", ncr_name(np)); - ncr_start_reset(np, driver_setup.settle_delay); + printk ("%s: handshake timeout\n", ncr_name(np)); + ncr_start_reset(np); return; }; if (sist & UDC) { - printf ("%s: unexpected disconnect\n", ncr_name(np)); - if (INB (nc_scr1) != 0xff) { - OUTB (nc_scr1, HS_UNEXPECTED); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup)); - }; - ncr_start_reset(np, driver_setup.settle_delay); + printk ("%s: unexpected disconnect\n", ncr_name(np)); + OUTB (HS_PRT, HS_UNEXPECTED); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, cleanup)); return; }; @@ -7148,7 +7066,7 @@ ** Print a message. The timeout will do the real work. **========================================================= */ - printf ("%s: unknown interrupt\n", ncr_name(np)); + printk ("%s: unknown interrupt\n", ncr_name(np)); } /*========================================================== @@ -7169,9 +7087,9 @@ void ncr_int_sto (ncb_p np) { - u_long dsa, scratcha, diff; + u_long dsa; ccb_p cp; - if (DEBUG_FLAGS & DEBUG_TINY) printf ("T"); + if (DEBUG_FLAGS & DEBUG_TINY) printk ("T"); /* ** look for ccb and set the status. @@ -7188,21 +7106,11 @@ }; /* - ** repair start queue + ** repair start queue and jump to start point. */ - scratcha = INL (nc_scratcha); - diff = scratcha - NCB_SCRIPTH_PHYS (np, tryloop); - -/* assert ((diff <= MAX_START * 20) && !(diff % 20));*/ - - if ((diff <= MAX_START * 20) && !(diff % 20)) { - np->script->startpos[0] = cpu_to_scr(scratcha); - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); - return; - }; - ncr_init (np, "selection timeout", HS_FAIL); - np->disc = 1; + OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, sto_restart)); + return; } /*========================================================== @@ -7226,13 +7134,22 @@ { u_char scsi_mode = INB (nc_stest4) & SMODE; - printf("%s: SCSI bus mode change from %x to %x, resetting ...\n", - ncr_name(np), np->scsi_mode, scsi_mode); + if (scsi_mode != np->scsi_mode) { + printk("%s: SCSI bus mode change from %x to %x.\n", + ncr_name(np), np->scsi_mode, scsi_mode); - np->scsi_mode = scsi_mode; - ncr_start_reset(np, driver_setup.settle_delay); + np->scsi_mode = scsi_mode; - return 1; + + /* + ** Suspend command processing for 1 second and + ** reinitialize all except the chip. + */ + np->settle_time = jiffies + HZ; + ncr_init (np, 0, bootverbose ? "scsi mode change" : NULL, HS_RESET); + return 1; + } + return 0; } /*========================================================== @@ -7241,16 +7158,73 @@ ** **========================================================== ** -** SCSI parity errors are handled by the SCSI script. -** So, we just print some message. ** **---------------------------------------------------------- */ static int ncr_int_par (ncb_p np) { - printf("%s: SCSI parity error detected\n", ncr_name(np)); - return 0; + u_char hsts = INB (HS_PRT); + u_int32 dbc = INL (nc_dbc); + u_char sstat1 = INB (nc_sstat1); + int phase = -1; + int msg = -1; + u_int32 jmp; + + printk("%s: SCSI parity error detected: SCR1=%d DBC=%x SSTAT1=%x\n", + ncr_name(np), hsts, dbc, sstat1); + + /* + * Ignore the interrupt if the NCR is not connected + * to the SCSI bus, since the right work should have + * been done on unexpected disconnection handling. + */ + if (!(INB (nc_scntl1) & ISCON)) + return 0; + + /* + * If the nexus is not clearly identified, reset the bus. + * We will try to do better later. + */ + if (hsts & HS_INVALMASK) + goto reset_all; + + /* + * If the SCSI parity error occurs in MSG IN phase, prepare a + * MSG PARITY message. Otherwise, prepare a INITIATOR DETECTED + * ERROR message and let the device decide to retry the command + * or to terminate with check condition. If we were in MSG IN + * phase waiting for the response of a negotiation, we will + * get SIR_NEGO_FAILED at dispatch. + */ + if (!(dbc & 0xc0000000)) + phase = (dbc >> 24) & 7; + if (phase == 7) + msg = M_PARITY; + else + msg = M_ID_ERROR; + + /* + * If the NCR stopped on a MOVE ^ DATA_IN, we jump to a + * script that will ignore all data in bytes until phase + * change, since we are not sure the chip will wait the phase + * change prior to delivering the interrupt. + */ + if (phase == 1) + jmp = NCB_SCRIPTH_PHYS (np, par_err_data_in); + else + jmp = NCB_SCRIPTH_PHYS (np, par_err_other); + + OUTONB (nc_ctest3, CLF ); /* clear dma fifo */ + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ + + np->msgout[0] = msg; + OUTL (nc_dsp, jmp); + return 1; + +reset_all: + ncr_start_reset(np); + return 1; } /*========================================================== @@ -7320,72 +7294,89 @@ if (ss2 & ORF1) rest++; }; - OUTONB (nc_ctest3, CLF ); /* clear dma fifo */ - OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ - if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) - printf ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7, + printk ("P%x%x RL=%d D=%d SS0=%x ", cmd&7, sbcl&7, (unsigned) rest, (unsigned) delta, ss0); } else { if (DEBUG_FLAGS & (DEBUG_TINY|DEBUG_PHASE)) - printf ("P%x%x RL=%d ", cmd&7, sbcl&7, rest); - if ((cmd & 7) != 1) { - OUTONB (nc_ctest3, CLF ); - OUTB (nc_stest3, TE|CSF); - } + printk ("P%x%x RL=%d ", cmd&7, sbcl&7, rest); } /* - ** locate matching cp + ** Clear fifos. */ - dsa = INL (nc_dsa); - cp = np->ccb; - while (cp && (CCB_PHYS (cp, phys) != dsa)) - cp = cp->link_ccb; + OUTONB (nc_ctest3, CLF ); /* clear dma fifo */ + OUTB (nc_stest3, TE|CSF); /* clear scsi fifo */ - if (!cp) { - printf ("%s: SCSI phase error fixup: CCB already dequeued (0x%08lx)\n", - ncr_name (np), (u_long) np->header.cp); - return; - } - if (cp != np->header.cp) { - printf ("%s: SCSI phase error fixup: CCB address mismatch (0x%08lx != 0x%08lx)\n", - ncr_name (np), (u_long) cp, (u_long) np->header.cp); -/* return;*/ + /* + ** locate matching cp. + ** if the interrupted phase is DATA IN or DATA OUT, + ** trust the global header. + */ + dsa = INL (nc_dsa); + if (!(cmd & 6)) { + cp = np->header.cp; + if (CCB_PHYS(cp, phys) != dsa) + cp = 0; + } else { + cp = np->ccb; + while (cp && (CCB_PHYS (cp, phys) != dsa)) + cp = cp->link_ccb; } /* - ** find the interrupted script command, + ** try to find the interrupted script command, ** and the address at which to continue. */ - - if (dsp == vtophys (&cp->patch[2])) { - vdsp = &cp->patch[0]; - nxtdsp = scr_to_cpu(vdsp[3]); - } else if (dsp == vtophys (&cp->patch[6])) { - vdsp = &cp->patch[4]; - nxtdsp = scr_to_cpu(vdsp[3]); - } else if (dsp > np->p_script && dsp <= np->p_script + sizeof(struct script)) { - vdsp = (u_int32 *) ((char*)np->script - np->p_script + dsp -8); + vdsp = 0; + nxtdsp = 0; + if (dsp > np->p_script && + dsp <= np->p_script + sizeof(struct script)) { + vdsp = (u_int32 *)((char*)np->script0 + (dsp-np->p_script-8)); nxtdsp = dsp; - } else { - vdsp = (u_int32 *) ((char*)np->scripth - np->p_scripth + dsp -8); + } + else if (dsp > np->p_scripth && + dsp <= np->p_scripth + sizeof(struct scripth)) { + vdsp = (u_int32 *)((char*)np->scripth0 + (dsp-np->p_scripth-8)); nxtdsp = dsp; - }; + } + else if (cp) { + if (dsp == vtophys (&cp->patch[2])) { + vdsp = &cp->patch[0]; + nxtdsp = scr_to_cpu(vdsp[3]); + } + else if (dsp == vtophys (&cp->patch[6])) { + vdsp = &cp->patch[4]; + nxtdsp = scr_to_cpu(vdsp[3]); + } + } /* ** log the information */ if (DEBUG_FLAGS & DEBUG_PHASE) { - printf ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", + printk ("\nCP=%p CP2=%p DSP=%x NXT=%x VDSP=%p CMD=%x ", cp, np->header.cp, (unsigned)dsp, (unsigned)nxtdsp, vdsp, cmd); }; /* + ** cp=0 means that the DSA does not point to a valid control + ** block. This should not happen since we donnot use multi-byte + ** move while we are being reselected ot after command complete. + ** We are not able to recover from such a phase error. + */ + if (!cp) { + printk ("%s: SCSI phase error fixup: " + "CCB already dequeued (0x%08lx)\n", + ncr_name (np), (u_long) np->header.cp); + goto reset_all; + } + + /* ** get old startaddress and old length. */ @@ -7401,7 +7392,7 @@ }; if (DEBUG_FLAGS & DEBUG_PHASE) { - printf ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", + printk ("OCMD=%x\nTBLP=%p OLEN=%x OADR=%x\n", (unsigned) (scr_to_cpu(vdsp[0]) >> 24), tblp, (unsigned) olen, @@ -7414,71 +7405,285 @@ if (cmd != (scr_to_cpu(vdsp[0]) >> 24)) { PRINT_ADDR(cp->cmd); - printf ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", + printk ("internal error: cmd=%02x != %02x=(vdsp[0] >> 24)\n", (unsigned)cmd, (unsigned)scr_to_cpu(vdsp[0]) >> 24); - + + goto reset_all; + } + + /* + ** cp != np->header.cp means that the header of the CCB + ** currently being processed has not yet been copied to + ** the global header area. That may happen if the device did + ** not accept all our messages after having been selected. + */ + if (cp != np->header.cp) { + printk ("%s: SCSI phase error fixup: " + "CCB address mismatch (0x%08lx != 0x%08lx)\n", + ncr_name (np), (u_long) cp, (u_long) np->header.cp); + } + + /* + ** if old phase not dataphase, leave here. + */ + + if (cmd & 0x06) { + PRINT_ADDR(cp->cmd); + printk ("phase change %x-%x %d@%08x resid=%d.\n", + cmd&7, sbcl&7, (unsigned)olen, + (unsigned)oadr, (unsigned)rest); + goto unexpected_phase; + }; + + /* + ** choose the correct patch area. + ** if savep points to one, choose the other. + */ + + newcmd = cp->patch; + if (cp->phys.header.savep == cpu_to_scr(vtophys (newcmd))) newcmd+=4; + + /* + ** fillin the commands + */ + + newcmd[0] = cpu_to_scr(((cmd & 0x0f) << 24) | rest); + newcmd[1] = cpu_to_scr(oadr + olen - rest); + newcmd[2] = cpu_to_scr(SCR_JUMP); + newcmd[3] = cpu_to_scr(nxtdsp); + + if (DEBUG_FLAGS & DEBUG_PHASE) { + PRINT_ADDR(cp->cmd); + printk ("newcmd[%d] %x %x %x %x.\n", + (int) (newcmd - cp->patch), + (unsigned)scr_to_cpu(newcmd[0]), + (unsigned)scr_to_cpu(newcmd[1]), + (unsigned)scr_to_cpu(newcmd[2]), + (unsigned)scr_to_cpu(newcmd[3])); + } + /* + ** fake the return address (to the patch). + ** and restart script processor at dispatcher. + */ +#ifdef SCSI_NCR_PROFILE_SUPPORT + np->profile.num_break++; +#endif + OUTL (nc_temp, vtophys (newcmd)); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch)); + return; + + /* + ** Unexpected phase changes that occurs when the current phase + ** is not a DATA IN or DATA OUT phase are due to error conditions. + ** Such event may only happen when the SCRIPTS is using a + ** multibyte SCSI MOVE. + ** + ** Phase change Some possible cause + ** + ** COMMAND --> MSG IN SCSI parity error detected by target. + ** COMMAND --> STATUS Bad command or refused by target. + ** MSG OUT --> MSG IN Message rejected by target. + ** MSG OUT --> COMMAND Bogus target that discards extended + ** negotiation messages. + ** + ** The code below does not care of the new phase and so + ** trusts the target. Why to annoy it ? + ** If the interrupted phase is COMMAND phase, we restart at + ** dispatcher. + ** If a target does not get all the messages after selection, + ** the code assumes blindly that the target discards extended + ** messages and clears the negotiation status. + ** If the target does not want all our response to negotiation, + ** we force a SIR_NEGO_PROTO interrupt (it is a hack that avoids + ** bloat for such a should_not_happen situation). + ** In all other situation, we reset the BUS. + ** Are these assumptions reasonnable ? (Wait and see ...) + */ +unexpected_phase: + dsp -= 8; + nxtdsp = 0; + + switch (cmd & 7) { + case 2: /* COMMAND phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); + break; +#if 0 + case 3: /* STATUS phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, dispatch); + break; +#endif + case 6: /* MSG OUT phase */ + np->scripth->nxtdsp_go_on[0] = cpu_to_scr(dsp + 8); + if (dsp == NCB_SCRIPT_PHYS (np, send_ident)) { + cp->host_status = HS_BUSY; + nxtdsp = NCB_SCRIPTH_PHYS (np, clratn_go_on); + } + else if (dsp == NCB_SCRIPTH_PHYS (np, send_wdtr) || + dsp == NCB_SCRIPTH_PHYS (np, send_sdtr)) { + nxtdsp = dsp - 8; /* Should raise SIR_NEGO_PROTO */ + } + break; +#if 0 + case 7: /* MSG IN phase */ + nxtdsp = NCB_SCRIPT_PHYS (np, clrack); + break; +#endif + } + + if (nxtdsp) { + OUTL (nc_dsp, nxtdsp); return; } -#ifdef SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT - if ((cmd & 7) == 1 && np->assert_atn) { - np->assert_atn = 0; - OUTONB(nc_socl, CATN); - } -#endif +reset_all: + ncr_start_reset(np); +} + + +static void ncr_sir_to_redo(ncb_p np, int num, ccb_p cp) +{ + Scsi_Cmnd *cmd = cp->cmd; + tcb_p tp = &np->target[cmd->target]; + lcb_p lp = tp->lp[cmd->lun]; + XPT_QUEHEAD *qp; + ccb_p cp2; + int disc_cnt = 0; + int busy_cnt = 0; + u_int32 startp; + u_char s_status = INB (SS_PRT); + + /* + ** Let the SCRIPTS processor skip all not yet started CCBs, + ** and count disconnected CCBs. Since the busy queue is in + ** the same order as the chip start queue, disconnected CCBs + ** are before cp and busy ones after. + */ + if (lp) { + qp = lp->busy_ccbq.blink; + while (qp != &lp->busy_ccbq) { + cp2 = xpt_que_entry(qp, struct ccb, link_ccbq); + qp = qp->blink; + ++busy_cnt; + if (cp2 == cp) + break; + cp2->start.schedule.l_paddr = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, skip)); + } + lp->held_ccb = cp; /* Requeue when this one completes */ + disc_cnt = lp->queuedccbs - busy_cnt; + } + + switch(s_status) { + default: /* Just for safety, should never happen */ + case S_QUEUE_FULL: + /* + ** Decrease number of tags to the number of + ** disconnected commands. + */ + if (!lp) + goto out; + if (bootverbose >= 1) { + PRINT_ADDR(cmd); + printk ("QUEUE FULL! %d busy, %d disconnected CCBs\n", + busy_cnt, disc_cnt); + } + if (disc_cnt < lp->numtags) { + lp->numtags = disc_cnt > 2 ? disc_cnt : 2; + lp->num_good = 0; + ncr_setup_tags (np, cmd->target, cmd->lun); + } + /* + ** Requeue the command to the start queue. + ** If any disconnected commands, + ** Clear SIGP. + ** Jump to reselect. + */ + cp->phys.header.savep = cp->startp; + cp->host_status = HS_BUSY; + cp->scsi_status = S_ILLEGAL; + + ncr_put_start_queue(np, cp); + if (disc_cnt) + INB (nc_ctest2); /* Clear SIGP */ + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, reselect)); + return; + case S_TERMINATED: + case S_CHECK_COND: + /* + ** If we were requesting sense, give up. + */ + if (cp->auto_sense) + goto out; + + /* + ** Device returned CHECK CONDITION status. + ** Prepare all needed data strutures for getting + ** sense data. + ** + ** identify message + */ + cp->scsi_smsg2[0] = M_IDENTIFY | cmd->lun; + cp->phys.smsg.addr = cpu_to_scr(CCB_PHYS (cp, scsi_smsg2)); + cp->phys.smsg.size = cpu_to_scr(1); + + /* + ** sense command + */ + cp->phys.cmd.addr = cpu_to_scr(CCB_PHYS (cp, sensecmd)); + cp->phys.cmd.size = cpu_to_scr(6); + + /* + ** patch requested size into sense command + */ + cp->sensecmd[0] = 0x03; + cp->sensecmd[1] = cmd->lun << 5; + cp->sensecmd[4] = sizeof(cmd->sense_buffer); - /* - ** if old phase not dataphase, leave here. - */ + /* + ** sense data + */ + cp->phys.sense.addr = + cpu_to_scr(vtophys (&cmd->sense_buffer[0])); + cp->phys.sense.size = + cpu_to_scr(sizeof(cmd->sense_buffer)); - if (cmd & 0x06) { - PRINT_ADDR(cp->cmd); - printf ("phase change %x-%x %d@%08x resid=%d.\n", - cmd&7, sbcl&7, (unsigned)olen, - (unsigned)oadr, (unsigned)rest); + /* + ** requeue the command. + */ + startp = cpu_to_scr(NCB_SCRIPTH_PHYS (np, sdata_in)); - OUTONB (nc_dcntl, (STD|NOCOM)); - return; - }; + cp->phys.header.savep = startp; + cp->phys.header.goalp = startp + 24; + cp->phys.header.lastp = startp; + cp->phys.header.wgoalp = startp + 24; + cp->phys.header.wlastp = startp; - /* - ** choose the correct patch area. - ** if savep points to one, choose the other. - */ + cp->host_status = HS_BUSY; + cp->scsi_status = S_ILLEGAL; + cp->auto_sense = s_status; - newcmd = cp->patch; - if (cp->phys.header.savep == cpu_to_scr(vtophys (newcmd))) newcmd+=4; + cp->start.schedule.l_paddr = + cpu_to_scr(NCB_SCRIPT_PHYS (np, select)); - /* - ** fillin the commands - */ + /* + ** Select without ATN for quirky devices. + */ + if (tp->quirks & QUIRK_NOMSG) + cp->start.schedule.l_paddr = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, select_no_atn)); - newcmd[0] = cpu_to_scr(((cmd & 0x0f) << 24) | rest); - newcmd[1] = cpu_to_scr(oadr + olen - rest); - newcmd[2] = cpu_to_scr(SCR_JUMP); - newcmd[3] = cpu_to_scr(nxtdsp); + ncr_put_start_queue(np, cp); - if (DEBUG_FLAGS & DEBUG_PHASE) { - PRINT_ADDR(cp->cmd); - printf ("newcmd[%d] %x %x %x %x.\n", - (int) (newcmd - cp->patch), - (unsigned)scr_to_cpu(newcmd[0]), - (unsigned)scr_to_cpu(newcmd[1]), - (unsigned)scr_to_cpu(newcmd[2]), - (unsigned)scr_to_cpu(newcmd[3])); + OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, start)); + return; } - /* - ** fake the return address (to the patch). - ** and restart script processor at dispatcher. - */ - np->profile.num_break++; - OUTL (nc_temp, vtophys (newcmd)); - if ((cmd & 7) == 0) - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch)); - else - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, checkatn)); + +out: + OUTONB (nc_dcntl, (STD|NOCOM)); + return; } + /*========================================================== ** ** @@ -7491,159 +7696,79 @@ static int ncr_show_msg (u_char * msg) { u_char i; - printf ("%x",*msg); + printk ("%x",*msg); if (*msg==M_EXTENDED) { for (i=1;i<8;i++) { if (i-1>msg[1]) break; - printf ("-%x",msg[i]); + printk ("-%x",msg[i]); }; return (i+1); } else if ((*msg & 0xf0) == 0x20) { - printf ("-%x",msg[1]); + printk ("-%x",msg[1]); return (2); }; return (1); } + void ncr_int_sir (ncb_p np) { u_char scntl3; u_char chg, ofs, per, fak, wide; u_char num = INB (nc_dsps); ccb_p cp=0; - u_long dsa; - u_char target = INB (nc_ctest0) & 0x0f; + u_long dsa = INL (nc_dsa); + u_char target = INB (nc_sdid) & 0x0f; tcb_p tp = &np->target[target]; - int i; - if (DEBUG_FLAGS & DEBUG_TINY) printf ("I#%d", num); + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("I#%d", num); switch (num) { - case SIR_SENSE_RESTART: - case SIR_STALL_RESTART: - break; - case SIR_STALL_QUEUE: /* Ignore, just restart the script */ + case SIR_RESEL_NO_MSG_IN: + case SIR_RESEL_NO_IDENTIFY: + /* + ** If devices reselecting without sending an IDENTIFY + ** message still exist, this should help. + ** We just assume lun=0, 1 CCB, no tag. + */ + if (tp->lp[0]) { + OUTL (nc_dsp, tp->lp[0]->jump_ccb[0].l_paddr); + return; + } + case SIR_RESEL_BAD_TARGET: /* Will send a TARGET RESET message */ + case SIR_RESEL_BAD_LUN: /* Will send a TARGET RESET message */ + case SIR_RESEL_BAD_I_T_L_Q: /* Will send an ABORT TAG message */ + case SIR_RESEL_BAD_I_T_L: /* Will send an ABORT message */ + printk ("%s:%d: SIR %d, " + "incorrect nexus identification on reselection\n", + ncr_name (np), target, num); goto out; - + case SIR_DONE_OVERFLOW: + printk ("%s:%d: SIR %d, " + "CCB done queue overflow\n", + ncr_name (np), target, num); + goto out; + case SIR_BAD_STATUS: + cp = np->header.cp; + if (!cp || CCB_PHYS (cp, phys) != dsa) + goto out; + ncr_sir_to_redo(np, num, cp); + return; default: /* ** lookup the ccb */ - dsa = INL (nc_dsa); cp = np->ccb; while (cp && (CCB_PHYS (cp, phys) != dsa)) cp = cp->link_ccb; - assert (cp); - if (!cp) - goto out; - assert (cp == np->header.cp); - if (cp != np->header.cp) + assert (cp && cp == np->header.cp); + + if (!cp || cp != np->header.cp) goto out; } switch (num) { - u_long endp; - case SIR_DATA_IO_IS_OUT: - case SIR_DATA_IO_IS_IN: -/* -** We did not guess the direction of transfer. We have to wait for -** actual data direction driven by the target before setting -** pointers. We must patch the global header too. -*/ - if (num == SIR_DATA_IO_IS_OUT) { - endp = NCB_SCRIPTH_PHYS (np, data_out) + MAX_SCATTER*16; - cp->phys.header.goalp = cpu_to_scr(endp + 8); - cp->phys.header.savep = - cpu_to_scr(endp - cp->segments*16); - } else { - endp = NCB_SCRIPT_PHYS (np, data_in) + MAX_SCATTER*16; - cp->phys.header.goalp = cpu_to_scr(endp + 8); - cp->phys.header.savep = - cpu_to_scr(endp - cp->segments*16); - } - - cp->phys.header.lastp = cp->phys.header.savep; - np->header.savep = cp->phys.header.savep; - np->header.goalp = cp->phys.header.goalp; - np->header.lastp = cp->phys.header.lastp; - - OUTL (nc_temp, scr_to_cpu(np->header.savep)); - OUTL (nc_dsp, scr_to_cpu(np->header.savep)); - return; - /* break; */ - -/*-------------------------------------------------------------------- -** -** Processing of interrupted getcc selects -** -**-------------------------------------------------------------------- -*/ - - case SIR_SENSE_RESTART: - /*------------------------------------------ - ** Script processor is idle. - ** Look for interrupted "check cond" - **------------------------------------------ - */ - - if (DEBUG_FLAGS & DEBUG_RESTART) - printf ("%s: int#%d",ncr_name (np),num); - cp = (ccb_p) 0; - for (i=0; itarget[i]; - if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+"); - cp = tp->hold_cp; - if (!cp) continue; - if (DEBUG_FLAGS & DEBUG_RESTART) printf ("+"); - if ((cp->host_status==HS_BUSY) && - (cp->scsi_status==S_CHECK_COND)) - break; - if (DEBUG_FLAGS & DEBUG_RESTART) printf ("- (remove)"); - tp->hold_cp = cp = (ccb_p) 0; - }; - - if (cp) { - if (DEBUG_FLAGS & DEBUG_RESTART) - printf ("+ restart job ..\n"); - OUTL (nc_dsa, CCB_PHYS (cp, phys)); - OUTL (nc_dsp, NCB_SCRIPTH_PHYS (np, getcc)); - return; - }; - - /* - ** no job, resume normal processing - */ - if (DEBUG_FLAGS & DEBUG_RESTART) printf (" -- remove trap\n"); - np->script->start0[0] = cpu_to_scr(SCR_INT ^ IFFALSE (0)); - break; - - case SIR_SENSE_FAILED: - /*------------------------------------------- - ** While trying to select for - ** getting the condition code, - ** a target reselected us. - **------------------------------------------- - */ - if (DEBUG_FLAGS & DEBUG_RESTART) { - PRINT_ADDR(cp->cmd); - printf ("in getcc reselect by t%d.\n", - (int)INB(nc_ssid) & 0x0f); - } - - /* - ** Mark this job - */ - cp->host_status = HS_BUSY; - cp->scsi_status = S_CHECK_COND; - np->target[cp->cmd->target].hold_cp = cp; - - /* - ** And patch code to restart it. - */ - np->script->start0[0] = cpu_to_scr(SCR_INT); - break; - /*----------------------------------------------------------------------------- ** ** Was Sie schon immer ueber transfermode negotiation wissen wollten ... @@ -7727,7 +7852,7 @@ if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); - printf ("negotiation failed sir=%x status=%x.\n", + printk ("negotiation failed sir=%x status=%x.\n", num, cp->nego_status); }; @@ -7750,7 +7875,8 @@ np->msgout[0] = M_NOOP; cp->nego_status = 0; OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, dispatch)); - break; + return; +/* break; */ case SIR_NEGO_SYNC: /* @@ -7759,9 +7885,9 @@ if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); - printf ("sync msgin: "); + printk ("sync msgin: "); (void) ncr_show_msg (np->msgin); - printf (".\n"); + printk (".\n"); }; /* @@ -7779,7 +7905,7 @@ */ if (ofs) - tp->inqdata[7] |= INQ7_SYNC; + tp->inq_byte7 |= INQ7_SYNC; /* ** check values against driver limits. @@ -7813,7 +7939,7 @@ if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); - printf ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n", + printk ("sync: per=%d scntl3=0x%x ofs=%d fak=%d chg=%d.\n", per, scntl3, ofs, fak, chg); } @@ -7847,20 +7973,6 @@ }; /* - ** It was a request. - ** Check against the table of target capabilities. - ** If target not capable force M_REJECT and asynchronous. - */ - if (np->unit < SCSI_NCR_MAX_HOST) { - tp->inqdata[7] &= - (target_capabilities[np->unit].and_map[target]); - if (!(tp->inqdata[7] & INQ7_SYNC)) { - ofs = 0; - fak = 7; - } - } - - /* ** It was a request. Set value and ** prepare an answer message */ @@ -7877,9 +7989,9 @@ if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); - printf ("sync msgout: "); + printk ("sync msgout: "); (void) ncr_show_msg (np->msgout); - printf (".\n"); + printk (".\n"); } if (!ofs) { @@ -7896,9 +8008,9 @@ */ if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); - printf ("wide msgin: "); + printk ("wide msgin: "); (void) ncr_show_msg (np->msgin); - printf (".\n"); + printk (".\n"); }; /* @@ -7914,7 +8026,7 @@ */ if (wide) - tp->inqdata[7] |= INQ7_WIDE16; + tp->inq_byte7 |= INQ7_WIDE16; /* ** check values against driver limits. @@ -7925,7 +8037,7 @@ if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); - printf ("wide: wide=%d chg=%d.\n", wide, chg); + printk ("wide: wide=%d chg=%d.\n", wide, chg); } if (INB (HS_PRT) == HS_NEGOTIATE) { @@ -7975,9 +8087,9 @@ if (DEBUG_FLAGS & DEBUG_NEGO) { PRINT_ADDR(cp->cmd); - printf ("wide msgout: "); + printk ("wide msgout: "); (void) ncr_show_msg (np->msgin); - printf (".\n"); + printk (".\n"); } break; @@ -7997,7 +8109,7 @@ */ PRINT_ADDR(cp->cmd); - printf ("M_REJECT received (%x:%x).\n", + printk ("M_REJECT received (%x:%x).\n", (unsigned)scr_to_cpu(np->lastmsg), np->msgout[0]); break; @@ -8010,9 +8122,9 @@ */ PRINT_ADDR(cp->cmd); - printf ("M_REJECT sent for "); + printk ("M_REJECT sent for "); (void) ncr_show_msg (np->msgin); - printf (".\n"); + printk (".\n"); break; /*-------------------------------------------------------------------- @@ -8032,9 +8144,9 @@ */ PRINT_ADDR(cp->cmd); - printf ("M_IGN_RESIDUE received, but not yet implemented.\n"); + printk ("M_IGN_RESIDUE received, but not yet implemented.\n"); break; - +#if 0 case SIR_MISSING_SAVE: /*----------------------------------------------- ** @@ -8045,92 +8157,13 @@ */ PRINT_ADDR(cp->cmd); - printf ("M_DISCONNECT received, but datapointer not saved: " + printk ("M_DISCONNECT received, but datapointer not saved: " "data=%x save=%x goal=%x.\n", (unsigned) INL (nc_temp), (unsigned) scr_to_cpu(np->header.savep), (unsigned) scr_to_cpu(np->header.goalp)); break; - -#if 0 /* This stuff does not work */ -/*-------------------------------------------------------------------- -** -** Processing of a "S_QUEUE_FULL" status. -** -** The current command has been rejected, -** because there are too many in the command queue. -** We have started too many commands for that target. -** -** If possible, reinsert at head of queue. -** Stall queue until there are no disconnected jobs -** (ncr is REALLY idle). Then restart processing. -** -** We should restart the current job after the controller -** has become idle. But this is not yet implemented. -** -**-------------------------------------------------------------------- -*/ - case SIR_STALL_QUEUE: - /*----------------------------------------------- - ** - ** Stall the start queue. - ** - **----------------------------------------------- - */ - PRINT_ADDR(cp->cmd); - printf ("queue full.\n"); - - np->script->start1[0] = cpu_to_scr(SCR_INT); - - /* - ** Try to disable tagged transfers. - */ - ncr_setmaxtags (np, &np->target[target], 0); - - /* - ** @QUEUE@ - ** - ** Should update the launch field of the - ** current job to be able to restart it. - ** Then prepend it to the start queue. - */ - - /* fall through */ - - case SIR_STALL_RESTART: - /*----------------------------------------------- - ** - ** Enable selecting again, - ** if NO disconnected jobs. - ** - **----------------------------------------------- - */ - /* - ** Look for a disconnected job. - */ - cp = np->ccb; - while (cp && cp->host_status != HS_DISCONNECT) - cp = cp->link_ccb; - - /* - ** if there is one, ... - */ - if (cp) { - /* - ** wait for reselection - */ - OUTL (nc_dsp, NCB_SCRIPT_PHYS (np, reselect)); - return; - }; - - /* - ** else remove the interrupt. - */ - - printf ("%s: queue empty.\n", ncr_name (np)); - np->script->start1[0] = cpu_to_scr(SCR_INT ^ IFFALSE (0)); - break; -#endif /* This stuff does not work */ +#endif }; out: @@ -8146,48 +8179,65 @@ **========================================================== */ -static ccb_p ncr_get_ccb - (ncb_p np, u_long target, u_long lun) +static ccb_p ncr_get_ccb (ncb_p np, u_char tn, u_char ln) { - lcb_p lp; + tcb_p tp = &np->target[tn]; + lcb_p lp = tp->lp[ln]; + u_char tag = NO_TAG; ccb_p cp = (ccb_p) 0; /* ** Lun structure available ? */ + if (lp) { + XPT_QUEHEAD *qp; + /* + ** Allocate a new CCB if needed. + */ + if (xpt_que_empty(&lp->free_ccbq)) + ncr_alloc_ccb(np, tn, ln); - lp = np->target[target].lp[lun]; - - if (lp && lp->opennings && (!lp->active || lp->active < lp->reqlink)) { - - cp = lp->next_ccb; - + /* + ** Tune tag mode if asked by user. + */ + if (lp->queuedepth != lp->numtags) { + ncr_setup_tags(np, tn, ln); + } + /* ** Look for free CCB */ - - while (cp && cp->magic) cp = cp->next_ccb; + qp = xpt_remque_head(&lp->free_ccbq); + if (qp) { + cp = xpt_que_entry(qp, struct ccb, link_ccbq); + if (cp->magic) { + PRINT_LUN(np, tn, ln); + printk ("ccb free list corrupted (@%p)\n", cp); + cp = 0; + } + else { + xpt_insque_tail(qp, &lp->wait_ccbq); + ++lp->busyccbs; + } + } /* - ** Increment active commands and decrement credit. + ** If a CCB is available, + ** Get a tag for this nexus if required. */ - if (cp) { - ++lp->active; - --lp->opennings; + if (lp->usetags) + tag = lp->cb_tags[lp->ia_tag]; } + else if (lp->actccbs > 0) + return (ccb_p) 0; } /* ** if nothing available, take the default. - ** DANGEROUS, because this ccb is not suitable for - ** reselection. - ** If lp->actccbs > 0 wait for a suitable ccb to be free. */ - if ((!cp) && lp && lp->actccbs > 0) - return ((ccb_p) 0); - - if (!cp) cp = np->ccb; + if (!cp) + cp = np->ccb; /* ** Wait until available. @@ -8204,7 +8254,40 @@ return ((ccb_p) 0); cp->magic = 1; - return (cp); + + /* + ** Move to next available tag if tag used. + */ + if (lp) { + if (tag != NO_TAG) { + ++lp->ia_tag; +#if SCSI_NCR_MAX_TAGS <= 32 + if (lp->ia_tag == 32) +#else + if (lp->ia_tag == 64) +#endif + lp->ia_tag = 0; +#if SCSI_NCR_MAX_TAGS <= 32 + lp->tags_umap |= (1u << tag); +#else + lp->tags_umap |= (((u_int64) 1) << tag); +#endif + } + } + + /* + ** Remember all informations needed to free this CCB. + */ + cp->tag = tag; + cp->target = tn; + cp->lun = ln; + + if (DEBUG_FLAGS & DEBUG_TAGS) { + PRINT_LUN(np, tn, ln); + printk ("ccb @%p using tag %d.\n", cp, tag); + } + + return cp; } /*========================================================== @@ -8216,32 +8299,154 @@ **========================================================== */ -void ncr_free_ccb (ncb_p np, ccb_p cp, u_long target, u_long lun) +static void ncr_free_ccb (ncb_p np, ccb_p cp) { - lcb_p lp; + tcb_p tp = &np->target[cp->target]; + lcb_p lp = tp->lp[cp->lun]; + + if (DEBUG_FLAGS & DEBUG_TAGS) { + PRINT_LUN(np, cp->target, cp->lun); + printk ("ccb @%p freeing tag %d.\n", cp, cp->tag); + } + + /* + ** If lun control block available, + ** decrement active commands and increment credit, + ** free the tag if any and remove the JUMP for reselect. + */ + if (lp) { + if (cp->tag != NO_TAG) { + lp->cb_tags[lp->if_tag++] = cp->tag; +#if SCSI_NCR_MAX_TAGS <= 32 + if (lp->if_tag == 32) +#else + if (lp->if_tag == 64) +#endif + lp->if_tag = 0; +#if SCSI_NCR_MAX_TAGS <= 32 + lp->tags_umap &= ~(1u << cp->tag); +#else + lp->tags_umap &= ~(((u_int64) 1) << cp->tag); +#endif + lp->tags_smap &= lp->tags_umap; + lp->jump_ccb[cp->tag].l_paddr = + cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l_q)); + } else { + lp->jump_ccb[0].l_paddr = + cpu_to_scr(NCB_SCRIPTH_PHYS(np, bad_i_t_l)); + } + } + + /* + ** Make this CCB available. + */ + + if (lp) { + if (cp != np->ccb) { + xpt_remque(&cp->link_ccbq); + xpt_insque_head(&cp->link_ccbq, &lp->free_ccbq); + } + --lp->busyccbs; + if (cp->queued) { + --lp->queuedccbs; + } + } + cp -> host_status = HS_IDLE; + cp -> magic = 0; + if (cp->queued) { + --np->queuedccbs; + cp->queued = 0; + } + +#if 0 + if (cp == np->ccb) + wakeup ((caddr_t) cp); +#endif +} + + +#define ncr_reg_bus_addr(r) \ + (pcivtophys(np->paddr) + offsetof (struct ncr_reg, r)) + +/*------------------------------------------------------------------------ +** Initialize the fixed part of a CCB structure. +**------------------------------------------------------------------------ +**------------------------------------------------------------------------ +*/ +static void ncr_init_ccb(ncb_p np, ccb_p cp) +{ + ncrcmd copy_4 = np->features & FE_PFEN ? SCR_COPY(4) : SCR_COPY_F(4); + + /* + ** Remember virtual and bus address of this ccb. + */ + cp->p_ccb = vtophys(cp); + cp->phys.header.cp = cp; + + /* + ** This allows xpt_remque to work for the default ccb. + */ + xpt_que_init(&cp->link_ccbq); + + /* + ** Initialyze the start and restart launch script. + ** + ** COPY(4) @(...p_phys), @(dsa) + ** JUMP @(sched_point) + */ + cp->start.setup_dsa[0] = cpu_to_scr(copy_4); + cp->start.setup_dsa[1] = cpu_to_scr(vtophys(&cp->start.p_phys)); + cp->start.setup_dsa[2] = cpu_to_scr(ncr_reg_bus_addr(nc_dsa)); + cp->start.schedule.l_cmd = cpu_to_scr(SCR_JUMP); + cp->start.p_phys = vtophys(&cp->phys); + + bcopy(&cp->start, &cp->restart, sizeof(cp->restart)); + + cp->start.schedule.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, idle)); + cp->restart.schedule.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort)); +} + + +/*------------------------------------------------------------------------ +** Allocate a CCB and initialize its fixed part. +**------------------------------------------------------------------------ +**------------------------------------------------------------------------ +*/ +static void ncr_alloc_ccb(ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = tp->lp[ln]; + ccb_p cp = 0; + + /* + ** Allocate memory for this CCB. + */ + cp = m_alloc(sizeof(struct ccb), 5); + if (!cp) + return; + + if (DEBUG_FLAGS & DEBUG_ALLOC) { + PRINT_LUN(np, tn, ln); + printk ("new ccb @%p.\n", cp); + } /* - ** sanity + ** Count it and initialyze it. */ - - assert (cp != NULL); + lp->actccbs++; + np->actccbs++; + bzero (cp, sizeof (*cp)); + ncr_init_ccb(np, cp); /* - ** Decrement active commands and increment credit. + ** Chain into wakeup list and free ccb queue and take it + ** into account for tagged commands. */ + cp->link_ccb = np->ccb->link_ccb; + np->ccb->link_ccb = cp; - lp = np->target[target].lp[lun]; - if (lp) { - --lp->active; - ++lp->opennings; - } - - cp -> host_status = HS_IDLE; - cp -> magic = 0; -#if 0 - if (cp == np->ccb) - wakeup ((caddr_t) cp); -#endif + xpt_insque_head(&cp->link_ccbq, &lp->free_ccbq); + ncr_setup_tags (np, tn, ln); } /*========================================================== @@ -8253,215 +8458,279 @@ **========================================================== */ -static void ncr_alloc_ccb (ncb_p np, u_long target, u_long lun) -{ - tcb_p tp; - lcb_p lp; - ccb_p cp; - - assert (np != NULL); - - if (target>=MAX_TARGET) return; - if (lun >=MAX_LUN ) return; - - tp=&np->target[target]; - if (!tp->jump_tcb.l_cmd) { - /* - ** initialize it. - */ - tp->jump_tcb.l_cmd = - cpu_to_scr((SCR_JUMP^IFFALSE (DATA (0x80 + target)))); - tp->jump_tcb.l_paddr = np->jump_tcb.l_paddr; - - tp->getscr[0] = (np->features & FE_PFEN) ? - cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1)); - tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval)); - tp->getscr[2] = - cpu_to_scr(pcivtophys(np->paddr) + offsetof (struct ncr_reg, nc_sxfer)); +/*------------------------------------------------------------------------ +** Target control block initialisation. +**------------------------------------------------------------------------ +** This data structure is fully initialized after a SCSI command +** has been successfully completed for this target. +** It contains a SCRIPT that is called on target reselection. +**------------------------------------------------------------------------ +*/ +static void ncr_init_tcb (ncb_p np, u_char tn) +{ + tcb_p tp = &np->target[tn]; + ncrcmd copy_1 = np->features & FE_PFEN ? SCR_COPY(1) : SCR_COPY_F(1); + int th = tn & 3; + int i; - tp->getscr[3] = (np->features & FE_PFEN) ? - cpu_to_scr(SCR_COPY(1)):cpu_to_scr(SCR_COPY_F(1)); - tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval)); - tp->getscr[5] = - cpu_to_scr(pcivtophys(np->paddr) + offsetof (struct ncr_reg, nc_scntl3)); + /* + ** Jump to next tcb if SFBR does not match this target. + ** JUMP IF (SFBR != #target#), @(next tcb) + */ + tp->jump_tcb.l_cmd = + cpu_to_scr((SCR_JUMP ^ IFFALSE (DATA (0x80 + tn)))); + tp->jump_tcb.l_paddr = np->jump_tcb[th].l_paddr; - assert (( (offsetof(struct ncr_reg, nc_sxfer) ^ - offsetof(struct tcb , sval )) &3) == 0); - assert (( (offsetof(struct ncr_reg, nc_scntl3) ^ - offsetof(struct tcb , wval )) &3) == 0); + /* + ** Load the synchronous transfer register. + ** COPY @(tp->sval), @(sxfer) + */ + tp->getscr[0] = cpu_to_scr(copy_1); + tp->getscr[1] = cpu_to_scr(vtophys (&tp->sval)); + tp->getscr[2] = cpu_to_scr(ncr_reg_bus_addr(nc_sxfer)); + + /* + ** Load the timing register. + ** COPY @(tp->wval), @(scntl3) + */ + tp->getscr[3] = cpu_to_scr(copy_1); + tp->getscr[4] = cpu_to_scr(vtophys (&tp->wval)); + tp->getscr[5] = cpu_to_scr(ncr_reg_bus_addr(nc_scntl3)); - tp->call_lun.l_cmd = cpu_to_scr(SCR_CALL); - tp->call_lun.l_paddr = - cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_lun)); + /* + ** Get the IDENTIFY message and the lun. + ** CALL @script(resel_lun) + */ + tp->call_lun.l_cmd = cpu_to_scr(SCR_CALL); + tp->call_lun.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_lun)); - tp->jump_lcb.l_cmd = cpu_to_scr(SCR_JUMP); - tp->jump_lcb.l_paddr = cpu_to_scr(NCB_SCRIPTH_PHYS (np, abort)); - np->jump_tcb.l_paddr = cpu_to_scr(vtophys (&tp->jump_tcb)); + /* + ** Look for the lun control block of this nexus. + ** For i = 0 to 3 + ** JUMP ^ IFTRUE (MASK (i, 3)), @(next_lcb) + */ + for (i = 0 ; i < 4 ; i++) { + tp->jump_lcb[i].l_cmd = + cpu_to_scr((SCR_JUMP ^ IFTRUE (MASK (i, 3)))); + tp->jump_lcb[i].l_paddr = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_identify)); } /* - ** Logic unit control block + ** Link this target control block to the JUMP chain. */ - lp = tp->lp[lun]; - if (!lp) { - /* - ** Allocate a lcb - */ - lp = (lcb_p) m_alloc (sizeof (struct lcb), LCB_ALIGN_SHIFT); - if (!lp) return; + np->jump_tcb[th].l_paddr = cpu_to_scr(vtophys (&tp->jump_tcb)); - if (DEBUG_FLAGS & DEBUG_ALLOC) { - PRINT_LUN(np, target, lun); - printf ("new lcb @%p.\n", lp); - } - - /* - ** Initialize it - */ - bzero (lp, sizeof (*lp)); - lp->jump_lcb.l_cmd = - cpu_to_scr(SCR_JUMP ^ IFFALSE (DATA (lun))); - lp->jump_lcb.l_paddr = tp->jump_lcb.l_paddr; - - lp->call_tag.l_cmd = cpu_to_scr(SCR_CALL); - lp->call_tag.l_paddr = - cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_tag)); - - lp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP); - lp->jump_ccb.l_paddr = - cpu_to_scr(NCB_SCRIPTH_PHYS (np, aborttag)); - - lp->actlink = 1; + /* + ** These assert's should be moved at driver initialisations. + */ + assert (( (offsetof(struct ncr_reg, nc_sxfer) ^ + offsetof(struct tcb , sval )) &3) == 0); + assert (( (offsetof(struct ncr_reg, nc_scntl3) ^ + offsetof(struct tcb , wval )) &3) == 0); +} - lp->active = 1; - /* - ** Chain into LUN list - */ - tp->jump_lcb.l_paddr = cpu_to_scr(vtophys (&lp->jump_lcb)); - tp->lp[lun] = lp; +/*------------------------------------------------------------------------ +** Reselection JUMP table initialisation. +**------------------------------------------------------------------------ +** The SCRIPTS processor jumps on reselection to the entry +** corresponding to the CCB using the tag as offset. +**------------------------------------------------------------------------ +*/ +static void ncr_setup_jump_ccb(ncb_p np, lcb_p lp) +{ + int i; - ncr_setmaxtags (np, tp, driver_setup.default_tags); + lp->p_jump_ccb = vtophys(lp->jump_ccb); + for (i = 0 ; i < lp->maxnxs ; i++) { +#if SCSI_NCR_MAX_TAGS <= 32 + lp->jump_ccb[i].l_cmd = cpu_to_scr(SCR_JUMP); +#endif + lp->jump_ccb[i].l_paddr = + cpu_to_scr(NCB_SCRIPTH_PHYS (np, bad_i_t_l_q)); + lp->cb_tags[i] = i; } +} - /* - ** Allocate ccbs up to lp->reqccbs. - */ +/*------------------------------------------------------------------------ +** Lun control block allocation and initialization. +**------------------------------------------------------------------------ +** This data structure is allocated and initialized after a SCSI +** command has been successfully completed for this target/lun. +**------------------------------------------------------------------------ +*/ +static lcb_p ncr_alloc_lcb (ncb_p np, u_char tn, u_char ln) +{ + tcb_p tp = &np->target[tn]; + lcb_p lp = tp->lp[ln]; + ncrcmd copy_4 = np->features & FE_PFEN ? SCR_COPY(4) : SCR_COPY_F(4); + int lh = ln & 3; /* - ** Limit possible number of ccbs. - ** - ** If tagged command queueing is enabled, - ** can use more than one ccb. + ** Already done, return. */ - if (np->actccbs >= MAX_START-2) return; - if (lp->actccbs && (lp->actccbs >= lp->reqccbs)) - return; + if (lp) + return lp; /* - ** Allocate a ccb + ** Allocate the lcb. */ - cp = (ccb_p) m_alloc (sizeof (struct ccb), CCB_ALIGN_SHIFT); - if (!cp) - return; + lp = m_alloc(sizeof(struct lcb), 3); + if (!lp) + goto fail; + bzero(lp, sizeof(*lp)); + tp->lp[ln] = lp; if (DEBUG_FLAGS & DEBUG_ALLOC) { - PRINT_LUN(np, target, lun); - printf ("new ccb @%p.\n", cp); + PRINT_LUN(np, tn, ln); + printk ("new lcb @%p.\n", lp); } /* - ** Count it + ** Initialize the target control block if not yet. */ - lp->actccbs++; - np->actccbs++; + if (!tp->jump_tcb.l_cmd) + ncr_init_tcb(np, tn); /* - ** Initialize it + ** Initialize the CCB queue headers. */ - bzero (cp, sizeof (*cp)); + xpt_que_init(&lp->free_ccbq); + xpt_que_init(&lp->busy_ccbq); + xpt_que_init(&lp->wait_ccbq); + xpt_que_init(&lp->skip_ccbq); /* - ** Fill in physical addresses + ** Set max CCBs to 1 and use the default jump table + ** by default. */ - - cp->p_ccb = vtophys (cp); + lp->maxnxs = 1; + lp->jump_ccb = &lp->jump_ccb_0; + ncr_setup_jump_ccb(np, lp); /* - ** Chain into reselect list + ** Initilialyze the reselect script: + ** + ** Jump to next lcb if SFBR does not match this lun. + ** Load TEMP with the CCB direct jump table bus address. + ** Get the SIMPLE TAG message and the tag. + ** + ** JUMP IF (SFBR != #lun#), @(next lcb) + ** COPY @(lp->p_jump_ccb), @(temp) + ** JUMP @script(resel_notag) */ - cp->jump_ccb.l_cmd = cpu_to_scr(SCR_JUMP); - cp->jump_ccb.l_paddr = lp->jump_ccb.l_paddr; - lp->jump_ccb.l_paddr = cpu_to_scr(CCB_PHYS (cp, jump_ccb)); - cp->call_tmp.l_cmd = cpu_to_scr(SCR_CALL); - cp->call_tmp.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_tmp)); + lp->jump_lcb.l_cmd = + cpu_to_scr((SCR_JUMP ^ IFFALSE (MASK (0x80+ln, 0xff)))); + lp->jump_lcb.l_paddr = tp->jump_lcb[lh].l_paddr; + + lp->load_jump_ccb[0] = cpu_to_scr(copy_4); + lp->load_jump_ccb[1] = cpu_to_scr(vtophys (&lp->p_jump_ccb)); + lp->load_jump_ccb[2] = cpu_to_scr(ncr_reg_bus_addr(nc_temp)); + + lp->jump_tag.l_cmd = cpu_to_scr(SCR_JUMP); + lp->jump_tag.l_paddr = cpu_to_scr(NCB_SCRIPT_PHYS (np, resel_notag)); /* - ** Chain into wakeup list + ** Link this lun control block to the JUMP chain. */ - cp->link_ccb = np->ccb->link_ccb; - np->ccb->link_ccb = cp; + tp->jump_lcb[lh].l_paddr = cpu_to_scr(vtophys (&lp->jump_lcb)); /* - ** Chain into CCB list + ** Initialize command queuing control. */ - cp->next_ccb = lp->next_ccb; - lp->next_ccb = cp; + lp->busyccbs = 1; + lp->queuedccbs = 1; + lp->queuedepth = 1; +fail: + return lp; } -/*========================================================== -** -** -** Announce the number of ccbs/tags to the scsi driver. -** -** -**========================================================== -*/ -static void ncr_opennings (ncb_p np, lcb_p lp, Scsi_Cmnd * cmd) +/*------------------------------------------------------------------------ +** Lun control block setup on INQUIRY data received. +**------------------------------------------------------------------------ +** We only support WIDE, SYNC for targets and CMDQ for logical units. +** This setup is done on each INQUIRY since we are expecting user +** will play with CHANGE DEFINITION commands. :-) +**------------------------------------------------------------------------ +*/ +static lcb_p ncr_setup_lcb (ncb_p np, u_char tn, u_char ln, u_char *inq_data) { + tcb_p tp = &np->target[tn]; + lcb_p lp = tp->lp[ln]; + u_char inq_byte7; + /* - ** want to reduce the number ... + ** If no lcb, try to allocate it. */ - if (lp->actlink > lp->reqlink) { + if (!lp && !(lp = ncr_alloc_lcb(np, tn, ln))) + goto fail; - /* - ** Try to reduce the count. - ** We assume to run at splbio .. - */ - u_char diff = lp->actlink - lp->reqlink; - - if (!diff) return; + /* + ** Get device quirks from a speciality table. + */ + tp->quirks = ncr_lookup (inq_data); + if (tp->quirks && bootverbose) { + PRINT_LUN(np, tn, ln); + printk ("quirks=%x.\n", tp->quirks); + } - if (diff > lp->opennings) - diff = lp->opennings; + /* + ** Evaluate trustable target/unit capabilities. + ** We only believe device version >= SCSI-2 that + ** use appropriate response data format. + */ + inq_byte7 = 0; + if ((inq_data[2] & 0x7) >= 2 && (inq_data[3] & 0x7) >= 2) + inq_byte7 = inq_data[7]; - lp->opennings -= diff; + /* + ** If user is wanting SYNC, force this feature. + */ + if (driver_setup.force_sync_nego) + inq_byte7 |= INQ7_SYNC; - lp->actlink -= diff; - if (DEBUG_FLAGS & DEBUG_TAGS) - printf ("%s: actlink: diff=%d, new=%d, req=%d\n", - ncr_name(np), diff, lp->actlink, lp->reqlink); - return; - }; + /* + ** Prepare negotiation if SIP capabilities have changed. + */ + tp->inq_done = 1; + if ((inq_byte7 ^ tp->inq_byte7) & (INQ7_SYNC | INQ7_WIDE16)) { + tp->inq_byte7 = inq_byte7; + ncr_negotiate(np, tp); + } /* - ** want to increase the number ? + ** If unit supports tagged commands, allocate the + ** CCB JUMP table if not yet. */ - if (lp->reqlink > lp->actlink) { - u_char diff = lp->reqlink - lp->actlink; + if ((inq_byte7 & INQ7_QUEUE) && lp->maxnxs < 2) { + struct nlink *jumps; + jumps = m_alloc(256, 8); + if (!jumps) + goto fail; +#if SCSI_NCR_MAX_TAGS <= 32 + lp->maxnxs = 32; +#else + lp->maxnxs = 64; +#endif + lp->jump_ccb = jumps; + ncr_setup_jump_ccb(np, lp); + lp->tags_stime = jiffies; + } - lp->opennings += diff; + /* + ** Adjust tagged queueing status if needed. + */ + if ((inq_byte7 ^ lp->inq_byte7) & INQ7_QUEUE) { + lp->inq_byte7 = inq_byte7; + lp->numtags = tp->usrtags; + ncr_setup_tags (np, tn, ln); + } - lp->actlink += diff; -#if 0 - wakeup ((caddr_t) xp->sc_link); -#endif - if (DEBUG_FLAGS & DEBUG_TAGS) - printf ("%s: actlink: diff=%d, new=%d, req=%d\n", - ncr_name(np), diff, lp->actlink, lp->reqlink); - }; +fail: + return lp; } /*========================================================== @@ -8499,9 +8768,6 @@ int segment = 0; int use_sg = (int) cmd->use_sg; -#if 0 - bzero (cp->phys.data, sizeof (cp->phys.data)); -#endif data = cp->phys.data; cp->data_len = 0; @@ -8550,7 +8816,7 @@ static int ncr_regtest (struct ncb* np) ) { - register volatile u_long data; + register volatile u_int32 data; /* ** ncr registers may NOT be cached. ** write 0xffffffff to a read only register area, @@ -8564,7 +8830,7 @@ #else if ((data & 0xe2f0fffd) != 0x02000080) { #endif - printf ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", + printk ("CACHE TEST FAILED: reg dstat-sstat2 readback %x.\n", (unsigned) data); return (0x10); }; @@ -8576,8 +8842,8 @@ static int ncr_snooptest (struct ncb* np) ) { - u_long ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc, err=0; - int i; + u_int32 ncr_rd, ncr_wr, ncr_bk, host_rd, host_wr, pc; + int i, err=0; #ifndef NCR_IOMAPPED if (np->reg) { err |= ncr_regtest (np); @@ -8619,22 +8885,22 @@ ** Reset ncr chip */ OUTB (nc_istat, SRST); - DELAY (1000); + UDELAY (100); OUTB (nc_istat, 0 ); /* ** check for timeout */ if (i>=NCR_SNOOP_TIMEOUT) { - printf ("CACHE TEST FAILED: timeout.\n"); + printk ("CACHE TEST FAILED: timeout.\n"); return (0x20); }; /* ** Check termination position. */ if (pc != NCB_SCRIPTH_PHYS (np, snoopend)+8) { - printf ("CACHE TEST FAILED: script execution failed.\n"); - printf ("start=%08lx, pc=%08lx, end=%08lx\n", - (u_long) NCB_SCRIPTH_PHYS (np, snooptest), pc, + printk ("CACHE TEST FAILED: script execution failed.\n"); + printk ("start=%08lx, pc=%08lx, end=%08lx\n", + (u_long) NCB_SCRIPTH_PHYS (np, snooptest), (u_long) pc, (u_long) NCB_SCRIPTH_PHYS (np, snoopend) +8); return (0x40); }; @@ -8642,17 +8908,17 @@ ** Show results. */ if (host_wr != ncr_rd) { - printf ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n", + printk ("CACHE TEST FAILED: host wrote %d, ncr read %d.\n", (int) host_wr, (int) ncr_rd); err |= 1; }; if (host_rd != ncr_wr) { - printf ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n", + printk ("CACHE TEST FAILED: ncr wrote %d, host read %d.\n", (int) ncr_wr, (int) host_rd); err |= 2; }; if (ncr_bk != ncr_wr) { - printf ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n", + printk ("CACHE TEST FAILED: ncr wrote %d, read back %d.\n", (int) ncr_wr, (int) ncr_bk); err |= 4; }; @@ -8680,7 +8946,7 @@ #define PROFILE cp->phys.header.stamp static void ncb_profile (ncb_p np, ccb_p cp) { - long co, st, en, di, se, post, work, disc; + long co, st, en, di, re, post, work, disc; u_int diff; PROFILE.end = jiffies; @@ -8693,14 +8959,14 @@ en = ncr_delta (PROFILE.start,PROFILE.end), di = ncr_delta (PROFILE.start,PROFILE.disconnect), - se = ncr_delta (PROFILE.start,PROFILE.select); + re = ncr_delta (PROFILE.start,PROFILE.reselect); post = en - st; /* ** @PROFILE@ Disconnect time invalid if multiple disconnects */ - if (di>=0) disc = se-di; else disc = 0; + if (di>=0) disc = re - di; else disc = 0; work = (st - co) - disc; @@ -8746,13 +9012,13 @@ static struct table_entry device_tab[] = { -#ifdef NCR_GETCC_WITHMSG +#if 0 {"", "", "", QUIRK_NOMSG}, +#endif {"SONY", "SDT-5000", "3.17", QUIRK_NOMSG}, {"WangDAT", "Model 2600", "01.7", QUIRK_NOMSG}, {"WangDAT", "Model 3200", "02.2", QUIRK_NOMSG}, {"WangDAT", "Model 1300", "02.4", QUIRK_NOMSG}, -#endif {"", "", "", 0} /* catch all: must be last entry. */ }; @@ -8816,17 +9082,17 @@ } if (bootverbose >= 2) - printf ("%s: enabling clock multiplier\n", ncr_name(np)); + printk ("%s: enabling clock multiplier\n", ncr_name(np)); OUTB(nc_stest1, DBLEN); /* Enable clock multiplier */ if (np->multiplier > 2) { /* Poll bit 5 of stest4 for quadrupler */ int i = 20; while (!(INB(nc_stest4) & LCKFRQ) && --i > 0) - DELAY(20); + UDELAY (20); if (!i) - printf("%s: the chip cannot lock the frequency\n", ncr_name(np)); + printk("%s: the chip cannot lock the frequency\n", ncr_name(np)); } else /* Wait 20 micro-seconds for doubler */ - DELAY(20); + UDELAY (20); OUTB(nc_stest3, HSC); /* Halt the scsi clock */ OUTB(nc_scntl3, scntl3); OUTB(nc_stest1, (DBLEN|DBLSEL));/* Select clock multiplier */ @@ -8867,7 +9133,7 @@ OUTB (nc_stime1, 0); /* disable general purpose timer */ OUTB (nc_stime1, gen); /* set to nominal delay of 1<= 2) - printf ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms); + printk ("%s: Delay (GEN=%d): %u msec\n", ncr_name(np), gen, ms); /* * adjust for prescaler, and convert into KHz */ @@ -8903,7 +9169,7 @@ */ if (mult > 1 && (stest1 & (DBLEN+DBLSEL)) == DBLEN+DBLSEL) { if (bootverbose >= 2) - printf ("%s: clock multiplier found\n", ncr_name(np)); + printk ("%s: clock multiplier found\n", ncr_name(np)); np->multiplier = mult; } @@ -8915,14 +9181,14 @@ if (np->multiplier != mult || (scntl3 & 7) < 3 || !(scntl3 & 1)) { unsigned f2; - OUTB(nc_istat, SRST); DELAY(5); OUTB(nc_istat, 0); + OUTB(nc_istat, SRST); UDELAY (5); OUTB(nc_istat, 0); (void) ncrgetfreq (np, 11); /* throw away first result */ f1 = ncrgetfreq (np, 11); f2 = ncrgetfreq (np, 11); if (bootverbose) - printf ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2); + printk ("%s: NCR clock is %uKHz, %uKHz\n", ncr_name(np), f1, f2); if (f1 > f2) f1 = f2; /* trust lower result */ @@ -8932,7 +9198,7 @@ if (f1 < 80000 && mult > 1) { if (bootverbose >= 2) - printf ("%s: clock multiplier assumed\n", ncr_name(np)); + printk ("%s: clock multiplier assumed\n", ncr_name(np)); np->multiplier = mult; } } else { @@ -8971,6 +9237,12 @@ ** --------------------------------------------------------------------- */ +#ifdef MODULE +#define ARG_SEP ' ' +#else +#define ARG_SEP ',' +#endif + __initfunc( void ncr53c8xx_setup(char *str, int *ints) ) @@ -8983,33 +9255,33 @@ int c; while (cur != NULL && (pc = strchr(cur, ':')) != NULL) { + char *pe; + val = 0; pv = pc; c = *++pv; + if (c == 'n') val = 0; else if (c == 'y') val = 1; else { base = 0; -#if 0 - if (c == '0') { - c = *pv++; - base = 8; - } - if (c == 'x') { - ++pv; - base = 16; + val = (int) simple_strtoul(pv, &pe, base); + } + if (!strncmp(cur, "tags:", 5)) { + int i; + driver_setup.default_tags = val; + if (pe && *pe == '/') { + i = 0; + while (*pe && *pe != ARG_SEP && + i < sizeof(driver_setup.tag_ctrl)-1) { + driver_setup.tag_ctrl[i++] = *pe++; + } + driver_setup.tag_ctrl[i] = '\0'; } - else if (c >= '0' && c <= '9') - base = 10; - else - break; -#endif - val = (int) simple_strtoul(pv, NULL, base); } - - if (!strncmp(cur, "mpar:", 5)) + else if (!strncmp(cur, "mpar:", 5)) driver_setup.master_parity = val; else if (!strncmp(cur, "spar:", 5)) driver_setup.scsi_parity = val; @@ -9023,11 +9295,6 @@ driver_setup.force_sync_nego = val; else if (!strncmp(cur, "revprob:", 8)) driver_setup.reverse_probe = val; - else if (!strncmp(cur, "tags:", 5)) { - if (val > SCSI_NCR_MAX_TAGS) - val = SCSI_NCR_MAX_TAGS; - driver_setup.default_tags = val; - } else if (!strncmp(cur, "sync:", 5)) driver_setup.default_sync = val; else if (!strncmp(cur, "verb:", 5)) @@ -9058,13 +9325,9 @@ else if (!strncmp(cur, "safe:", 5) && val) memcpy(&driver_setup, &driver_safe_setup, sizeof(driver_setup)); else - printf("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur); + printk("ncr53c8xx_setup: unexpected boot option '%.*s' ignored\n", (int)(pc-cur+1), cur); -#ifdef MODULE - if ((cur = strchr(cur, ' ')) != NULL) -#else - if ((cur = strchr(cur, ',')) != NULL) -#endif + if ((cur = strchr(cur, ARG_SEP)) != NULL) ++cur; } #endif /* SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT */ @@ -9093,24 +9356,31 @@ ) { #define YesNo(y) y ? 'y' : 'n' - printk("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%c,tags:%d,sync:%d,burst:%d,wide:%c,diff:%d\n", - YesNo(driver_setup.disconnection), - driver_setup.special_features, - YesNo(driver_setup.ultra_scsi), - driver_setup.default_tags, - driver_setup.default_sync, - driver_setup.burst_max, - YesNo(driver_setup.max_wide), - driver_setup.diff_support); - printk("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x,led:%c,settle:%d,irqm:%d\n", - YesNo(driver_setup.master_parity), - YesNo(driver_setup.scsi_parity), - YesNo(driver_setup.force_sync_nego), - driver_setup.verbose, - driver_setup.debug, - YesNo(driver_setup.led_pin), - driver_setup.settle_delay, - driver_setup.irqm); + printk ("ncr53c8xx: setup=disc:%c,specf:%d,ultra:%d,tags:%d,sync:%d," + "burst:%d,wide:%c,diff:%d,revprob:%c,buschk:0x%x\n", + YesNo(driver_setup.disconnection), + driver_setup.special_features, + driver_setup.ultra_scsi, + driver_setup.default_tags, + driver_setup.default_sync, + driver_setup.burst_max, + YesNo(driver_setup.max_wide), + driver_setup.diff_support, + YesNo(driver_setup.reverse_probe), + driver_setup.bus_check); + + printk ("ncr53c8xx: setup=mpar:%c,spar:%c,fsn=%c,verb:%d,debug:0x%x," + "led:%c,settle:%d,irqm:%d,nvram:0x%x,pcifix:0x%x\n", + YesNo(driver_setup.master_parity), + YesNo(driver_setup.scsi_parity), + YesNo(driver_setup.force_sync_nego), + driver_setup.verbose, + driver_setup.debug, + YesNo(driver_setup.led_pin), + driver_setup.settle_delay, + driver_setup.irqm, + driver_setup.use_nvram, + driver_setup.pci_fix_up); #undef YesNo } @@ -9145,13 +9415,13 @@ if (nvram_index == -1) nvram_index = i; #ifdef SCSI_NCR_DEBUG_NVRAM - printf("ncr53c8xx: NVRAM: Symbios format Boot Block, 53c%s, PCI bus %d, device %d, function %d\n", + printk("ncr53c8xx: NVRAM: Symbios format Boot Block, 53c%s, PCI bus %d, device %d, function %d\n", devp->chip.name, devp->slot.bus, (int) (devp->slot.device_fn & 0xf8) >> 3, (int) devp->slot.device_fn & 7); for (j = 0 ; j < 4 ; j++) { Symbios_host *h = &nvram->data.Symbios.host[j]; - printf("ncr53c8xx: BOOT[%d] device_id=%04x vendor_id=%04x device_fn=%02x io_port=%04x %s\n", + printk("ncr53c8xx: BOOT[%d] device_id=%04x vendor_id=%04x device_fn=%02x io_port=%04x %s\n", j, h->device_id, h->vendor_id, h->device_fn, h->io_port, (h->flags & SYMBIOS_INIT_SCAN_AT_BOOT) ? "SCAN AT BOOT" : ""); @@ -9159,7 +9429,7 @@ } else if (nvram->type == SCSI_NCR_TEKRAM_NVRAM) { /* display Tekram nvram data */ - printf("ncr53c8xx: NVRAM: Tekram format data, 53c%s, PCI bus %d, device %d, function %d\n", + printk("ncr53c8xx: NVRAM: Tekram format data, 53c%s, PCI bus %d, device %d, function %d\n", devp->chip.name, devp->slot.bus, (int) (devp->slot.device_fn & 0xf8) >> 3, (int) devp->slot.device_fn & 7); @@ -9226,18 +9496,14 @@ #ifdef SCSI_NCR_NVRAM_SUPPORT int nvram_index = 0; #endif - if (initverbose >= 2) - ncr_print_driver_setup(); #ifdef SCSI_NCR_DEBUG_INFO_SUPPORT ncr_debug = driver_setup.debug; #endif -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) tpnt->proc_dir = &proc_scsi_ncr53c8xx; -# ifdef SCSI_NCR_PROC_INFO_SUPPORT +#ifdef SCSI_NCR_PROC_INFO_SUPPORT tpnt->proc_info = ncr53c8xx_proc_info; -# endif #endif #if defined(SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT) && defined(MODULE) @@ -9245,6 +9511,9 @@ ncr53c8xx_setup(ncr53c8xx, (int *) 0); #endif + if (initverbose >= 2) + ncr_print_driver_setup(); + /* ** Detect all 53c8xx hosts and then attach them. ** @@ -9256,7 +9525,11 @@ ** the order they are detected. */ +#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,92) if (!pci_present()) +#else + if (!pcibios_present()) +#endif return 0; chips = sizeof(ncr_chip_ids) / sizeof(ncr_chip_ids[0]); @@ -9304,7 +9577,7 @@ } } #endif - printf(KERN_INFO "ncr53c8xx: 53c%s detected %s\n", + printk(KERN_INFO "ncr53c8xx: 53c%s detected %s\n", device[count].chip.name, msg); ++count; } @@ -9320,7 +9593,7 @@ for (i= 0; i < count; i++) { if (!device[i].attach_done && !ncr_attach (tpnt, attach_count, &device[i])) { - attach_count++; + attach_count++; } } @@ -9341,16 +9614,13 @@ ushort vendor_id, device_id, command; uchar cache_line_size, latency_timer; uchar revision; -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,85) +#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) struct pci_dev *pdev; ulong base, base_2, io_port; uint irq; -#elif LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) - uchar irq; - uint base, base_2, io_port; #else uchar irq; - ulong base, base_2, io_port; + uint base, base_2, io_port; #endif int i; @@ -9374,7 +9644,7 @@ PCI_DEVICE_ID, &device_id); (void) pcibios_read_config_word(bus, device_fn, PCI_COMMAND, &command); -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,1,85) +#if LINUX_VERSION_CODE > LinuxVersionCode(2,1,92) pdev = pci_find_slot(bus, device_fn); io_port = pdev->base_address[0]; base = pdev->base_address[1]; @@ -9417,6 +9687,10 @@ } #ifdef __powerpc__ + /* + * Several fix-up for power/pc. + * Should not be performed by the driver. + */ if (!(command & PCI_COMMAND_MASTER)) { printk("ncr53c8xx: attempting to force PCI_COMMAND_MASTER..."); command |= PCI_COMMAND_MASTER; @@ -9470,7 +9744,8 @@ pcibios_write_config_dword(bus, device_fn, PCI_BASE_ADDRESS_2, base_2); } } -#endif +#endif /* __powerpc__ */ + #ifdef __sparc__ /* * Severall fix-ups for sparc. @@ -9517,7 +9792,7 @@ pcibios_read_config_byte(bus, device_fn, PCI_LATENCY_TIMER, &latency_timer); } -#endif +#endif /* __sparc__ */ /* * Check availability of IO space, memory space and master capability. @@ -9603,6 +9878,7 @@ switch(boot_cpu_data.x86) { #endif case 4: cache_line_size = 4; break; + case 6: case 5: cache_line_size = 8; break; } if (cache_line_size) @@ -9738,35 +10014,106 @@ return 0; } -#if LINUX_VERSION_CODE >= LinuxVersionCode(2,0,0) /* ** Linux select queue depths function */ + +#define DEF_DEPTH (driver_setup.default_tags) +#define ALL_TARGETS -2 +#define NO_TARGET -1 +#define ALL_LUNS -2 +#define NO_LUN -1 + +static int device_queue_depth(ncb_p np, int target, int lun) +{ + int c, h, t, u, v; + char *p = driver_setup.tag_ctrl; + char *ep; + + h = -1; + t = NO_TARGET; + u = NO_LUN; + while ((c = *p++) != 0) { + v = simple_strtoul(p, &ep, 0); + switch(c) { + case '/': + ++h; + t = ALL_TARGETS; + u = ALL_LUNS; + break; + case 't': + if (t != target) + t = (target == v) ? v : NO_TARGET; + u = ALL_LUNS; + break; + case 'u': + if (u != lun) + u = (lun == v) ? v : NO_LUN; + break; + case 'q': + if (h == np->unit && + (t == ALL_TARGETS || t == target) && + (u == ALL_LUNS || u == lun)) + return v; + break; + case '-': + t = ALL_TARGETS; + u = ALL_LUNS; + break; + default: + break; + } + p = ep; + } + return DEF_DEPTH; +} + static void ncr53c8xx_select_queue_depths(struct Scsi_Host *host, struct scsi_device *devlist) { struct scsi_device *device; for (device = devlist; device; device = device->next) { - if (device->host == host) { -#if SCSI_NCR_MAX_TAGS > 1 - if (device->tagged_supported) { - device->queue_depth = SCSI_NCR_MAX_TAGS; - } - else { - device->queue_depth = 2; - } -#else - device->queue_depth = 1; -#endif + ncb_p np; + tcb_p tp; + lcb_p lp; + + if (device->host != host) + continue; + + np = ((struct host_data *) host->hostdata)->ncb; + tp = &np->target[device->id]; + lp = tp->lp[device->lun]; + + /* + ** Donnot use more than our maximum. + ** Select queue depth from driver setup. + ** Donnot use more than configured by user. + ** Use 2 for devices that donnot support tags. + ** Use at least 2. + */ + device->queue_depth = SCSI_NCR_MAX_TAGS; + device->queue_depth = + device_queue_depth(np, device->id, device->lun); + if (device->queue_depth > tp->usrtags) + device->queue_depth = tp->usrtags; + if (!device->tagged_supported || device->queue_depth < 2) + device->queue_depth = 2; + + /* + ** Since the queue depth is not tunable under Linux, + ** we need to know this value in order not to + ** announce stupid things to user. + */ + if (lp) + lp->scdev_depth = device->queue_depth; + ncr_setup_tags (np, device->id, device->lun); #ifdef DEBUG_NCR53C8XX -printk("ncr53c8xx_select_queue_depth: id=%d, lun=%d, queue_depth=%d\n", - device->id, device->lun, device->queue_depth); +printk("ncr53c8xx_select_queue_depth: host=%d, id=%d, lun=%d, depth=%d\n", + np->unit, device->id, device->lun, device->queue_depth); #endif - } } } -#endif /* ** Linux entry point of queuecommand() function @@ -9774,78 +10121,96 @@ int ncr53c8xx_queue_command (Scsi_Cmnd *cmd, void (* done)(Scsi_Cmnd *)) { + ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; + unsigned long flags; int sts; + #ifdef DEBUG_NCR53C8XX printk("ncr53c8xx_queue_command\n"); #endif - if ((sts = ncr_queue_command(cmd, done)) != DID_OK) { + cmd->scsi_done = done; + cmd->host_scribble = NULL; + cmd->SCp.ptr = NULL; + cmd->SCp.buffer = NULL; + + NCR_LOCK_NCB(np, flags); + + if ((sts = ncr_queue_command(np, cmd)) != DID_OK) { cmd->result = ScsiResult(sts, 0); - done(cmd); #ifdef DEBUG_NCR53C8XX printk("ncr53c8xx : command not queued - result=%d\n", sts); #endif - return sts; } #ifdef DEBUG_NCR53C8XX + else printk("ncr53c8xx : command successfully queued\n"); #endif + + NCR_UNLOCK_NCB(np, flags); + + if (sts != DID_OK) + done(cmd); + return sts; } /* ** Linux entry point of the interrupt handler. -** Fort linux versions > 1.3.70, we trust the kernel for +** Since linux versions > 1.3.70, we trust the kernel for ** passing the internal host descriptor as 'dev_id'. ** Otherwise, we scan the host list and call the interrupt ** routine for each host that uses this IRQ. */ -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,70) static void ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs * regs) { + unsigned long flags; + ncb_p np = (ncb_p) dev_id; + Scsi_Cmnd *done_list; + #ifdef DEBUG_NCR53C8XX printk("ncr53c8xx : interrupt received\n"); #endif - if (DEBUG_FLAGS & DEBUG_TINY) printf ("["); - ncr_exception((ncb_p) dev_id); - if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n"); -} - -static void do_ncr53c8xx_intr(int irq, void *dev_id, struct pt_regs *regs) -{ - unsigned long flags; - - spin_lock_irqsave(&io_request_lock, flags); - ncr53c8xx_intr(irq, dev_id, regs); - spin_unlock_irqrestore(&io_request_lock, flags); -} - -#else -static void ncr53c8xx_intr(int irq, struct pt_regs * regs) -{ - struct Scsi_Host *host; - struct host_data *host_data; + if (DEBUG_FLAGS & DEBUG_TINY) printk ("["); - for (host = first_host; host; host = host->next) { - if (host->hostt == the_template && host->irq == irq) { - host_data = (struct host_data *) host->hostdata; - if (DEBUG_FLAGS & DEBUG_TINY) printf ("["); - ncr_exception(host_data->ncb); - if (DEBUG_FLAGS & DEBUG_TINY) printf ("]\n"); - } + NCR_LOCK_NCB(np, flags); + ncr_exception(np); + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + if (DEBUG_FLAGS & DEBUG_TINY) printk ("]\n"); + + if (done_list) { + NCR_LOCK_SCSI_DONE(np, flags); + ncr_flush_done_cmds(done_list); + NCR_UNLOCK_SCSI_DONE(np, flags); } } -#endif /* ** Linux entry point of the timer handler */ -static void ncr53c8xx_timeout(unsigned long np) +static void ncr53c8xx_timeout(unsigned long npref) { + ncb_p np = (ncb_p) npref; + unsigned long flags; + Scsi_Cmnd *done_list; + + NCR_LOCK_NCB(np, flags); ncr_timeout((ncb_p) np); + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + if (done_list) { + NCR_LOCK_SCSI_DONE(np, flags); + ncr_flush_done_cmds(done_list); + NCR_UNLOCK_SCSI_DONE(np, flags); + } } /* @@ -9853,16 +10218,24 @@ */ #if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS - int ncr53c8xx_reset(Scsi_Cmnd *cmd, unsigned int reset_flags) +#else +int ncr53c8xx_reset(Scsi_Cmnd *cmd) +#endif { + ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; int sts; unsigned long flags; + Scsi_Cmnd *done_list; +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS printk("ncr53c8xx_reset: pid=%lu reset_flags=%x serial_number=%ld serial_number_at_timeout=%ld\n", cmd->pid, reset_flags, cmd->serial_number, cmd->serial_number_at_timeout); +#else + printk("ncr53c8xx_reset: command pid %lu\n", cmd->pid); +#endif - save_flags(flags); cli(); + NCR_LOCK_NCB(np, flags); /* * We have to just ignore reset requests in some situations. @@ -9880,8 +10253,13 @@ * before returning SCSI_RESET_SUCCESS. */ - sts = ncr_reset_bus(cmd, +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS + sts = ncr_reset_bus(np, cmd, (reset_flags & (SCSI_RESET_SYNCHRONOUS | SCSI_RESET_ASYNCHRONOUS)) == SCSI_RESET_SYNCHRONOUS); +#else + sts = ncr_reset_bus(np, cmd, 0); +#endif + /* * Since we always reset the controller, when we return success, * we add this information to the return code. @@ -9892,33 +10270,36 @@ #endif out: - restore_flags(flags); + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + ncr_flush_done_cmds(done_list); + return sts; } -#else -int ncr53c8xx_reset(Scsi_Cmnd *cmd) -{ - printk("ncr53c8xx_reset: command pid %lu\n", cmd->pid); - return ncr_reset_bus(cmd, 1); -} -#endif /* ** Linux entry point of abort() function */ -#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS - int ncr53c8xx_abort(Scsi_Cmnd *cmd) { + ncb_p np = ((struct host_data *) cmd->host->hostdata)->ncb; int sts; unsigned long flags; + Scsi_Cmnd *done_list; +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS printk("ncr53c8xx_abort: pid=%lu serial_number=%ld serial_number_at_timeout=%ld\n", cmd->pid, cmd->serial_number, cmd->serial_number_at_timeout); +#else + printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid); +#endif - save_flags(flags); cli(); + NCR_LOCK_NCB(np, flags); +#if defined SCSI_RESET_SYNCHRONOUS && defined SCSI_RESET_ASYNCHRONOUS /* * We have to just ignore abort requests in some situations. */ @@ -9926,19 +10307,19 @@ sts = SCSI_ABORT_NOT_RUNNING; goto out; } +#endif - sts = ncr_abort_command(cmd); + sts = ncr_abort_command(np, cmd); out: - restore_flags(flags); + done_list = np->done_list; + np->done_list = 0; + NCR_UNLOCK_NCB(np, flags); + + ncr_flush_done_cmds(done_list); + return sts; } -#else -int ncr53c8xx_abort(Scsi_Cmnd *cmd) -{ - printk("ncr53c8xx_abort: command pid %lu\n", cmd->pid); - return ncr_abort_command(cmd); -} -#endif + #ifdef MODULE int ncr53c8xx_release(struct Scsi_Host *host) @@ -9973,7 +10354,7 @@ Scsi_Cmnd *wcmd; #ifdef DEBUG_WAITING_LIST - printf("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd); + printk("%s: cmd %lx inserted into waiting list\n", ncr_name(np), (u_long) cmd); #endif cmd->next_wcmd = 0; if (!(wcmd = np->waiting_list)) np->waiting_list = cmd; @@ -9996,7 +10377,7 @@ cmd->next_wcmd = 0; } #ifdef DEBUG_WAITING_LIST - printf("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd); + printk("%s: cmd %lx retrieved from waiting list\n", ncr_name(np), (u_long) cmd); #endif return cmd; } @@ -10012,70 +10393,29 @@ np->waiting_list = 0; #ifdef DEBUG_WAITING_LIST - if (waiting_list) printf("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts); + if (waiting_list) printk("%s: waiting_list=%lx processing sts=%d\n", ncr_name(np), (u_long) waiting_list, sts); #endif while ((wcmd = waiting_list) != 0) { waiting_list = (Scsi_Cmnd *) wcmd->next_wcmd; wcmd->next_wcmd = 0; if (sts == DID_OK) { #ifdef DEBUG_WAITING_LIST - printf("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd); + printk("%s: cmd %lx trying to requeue\n", ncr_name(np), (u_long) wcmd); #endif - sts = ncr_queue_command(wcmd, wcmd->scsi_done); + sts = ncr_queue_command(np, wcmd); } if (sts != DID_OK) { #ifdef DEBUG_WAITING_LIST - printf("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts); + printk("%s: cmd %lx done forced sts=%d\n", ncr_name(np), (u_long) wcmd, sts); #endif wcmd->result = ScsiResult(sts, 0); - wcmd->scsi_done(wcmd); + ncr_queue_done_cmd(np, wcmd); } } } #undef next_wcmd -/* -** Returns data transfer direction for common op-codes. -*/ - -static int guess_xfer_direction(int opcode) -{ - int d; - - switch(opcode) { - case 0x12: /* INQUIRY 12 */ - case 0x4D: /* LOG SENSE 4D */ - case 0x5A: /* MODE SENSE(10) 5A */ - case 0x1A: /* MODE SENSE(6) 1A */ - case 0x3C: /* READ BUFFER 3C */ - case 0x1C: /* RECEIVE DIAGNOSTIC RESULTS 1C */ - case 0x03: /* REQUEST SENSE 03 */ - d = XferIn; - break; - case 0x39: /* COMPARE 39 */ - case 0x3A: /* COPY AND VERIFY 3A */ - case 0x18: /* COPY 18 */ - case 0x4C: /* LOG SELECT 4C */ - case 0x55: /* MODE SELECT(10) 55 */ - case 0x3B: /* WRITE BUFFER 3B */ - case 0x1D: /* SEND DIAGNOSTIC 1D */ - case 0x40: /* CHANGE DEFINITION 40 */ - case 0x15: /* MODE SELECT(6) 15 */ - d = XferOut; - break; - case 0x00: /* TEST UNIT READY 00 */ - d = XferNone; - break; - default: - d = XferBoth; - break; - } - - return d; -} - - #ifdef SCSI_NCR_PROC_INFO_SUPPORT /*========================================================================= @@ -10163,6 +10503,8 @@ uc->cmd = UC_SETTAGS; else if ((arg_len = is_keyword(ptr, len, "setorder")) != 0) uc->cmd = UC_SETORDER; + else if ((arg_len = is_keyword(ptr, len, "setverbose")) != 0) + uc->cmd = UC_SETVERBOSE; else if ((arg_len = is_keyword(ptr, len, "setwide")) != 0) uc->cmd = UC_SETWIDE; else if ((arg_len = is_keyword(ptr, len, "setdebug")) != 0) @@ -10171,15 +10513,11 @@ uc->cmd = UC_SETFLAG; else if ((arg_len = is_keyword(ptr, len, "clearprof")) != 0) uc->cmd = UC_CLEARPROF; -#ifdef UC_DEBUG_ERROR_RECOVERY - else if ((arg_len = is_keyword(ptr, len, "debug_error_recovery")) != 0) - uc->cmd = UC_DEBUG_ERROR_RECOVERY; -#endif else arg_len = 0; #ifdef DEBUG_PROC_INFO -printf("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd); +printk("ncr_user_command: arg_len=%d, cmd=%ld\n", arg_len, uc->cmd); #endif if (!arg_len) @@ -10199,20 +10537,21 @@ GET_INT_ARG(target); uc->target = (1<cmd) { + case UC_SETVERBOSE: case UC_SETSYNC: case UC_SETTAGS: case UC_SETWIDE: SKIP_SPACES(1); GET_INT_ARG(uc->data); #ifdef DEBUG_PROC_INFO -printf("ncr_user_command: data=%ld\n", uc->data); +printk("ncr_user_command: data=%ld\n", uc->data); #endif break; case UC_SETORDER: @@ -10260,7 +10599,7 @@ ptr += arg_len; len -= arg_len; } #ifdef DEBUG_PROC_INFO -printf("ncr_user_command: data=%ld\n", uc->data); +printk("ncr_user_command: data=%ld\n", uc->data); #endif break; case UC_SETFLAG: @@ -10275,24 +10614,6 @@ ptr += arg_len; len -= arg_len; } break; -#ifdef UC_DEBUG_ERROR_RECOVERY - case UC_DEBUG_ERROR_RECOVERY: - SKIP_SPACES(1); - if ((arg_len = is_keyword(ptr, len, "sge"))) - uc->data = 1; - else if ((arg_len = is_keyword(ptr, len, "abort"))) - uc->data = 2; - else if ((arg_len = is_keyword(ptr, len, "reset"))) - uc->data = 3; - else if ((arg_len = is_keyword(ptr, len, "parity"))) - uc->data = 4; - else if ((arg_len = is_keyword(ptr, len, "none"))) - uc->data = 0; - else - return -EINVAL; - ptr += arg_len; len -= arg_len; - break; -#endif default: break; } @@ -10302,9 +10623,9 @@ else { long flags; - save_flags(flags); cli(); + NCR_LOCK_NCB(np, flags); ncr_usercmd (np); - restore_flags(flags); + NCR_UNLOCK_NCB(np, flags); } return length; } @@ -10425,7 +10746,7 @@ int retv; #ifdef DEBUG_PROC_INFO -printf("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func); +printk("ncr53c8xx_proc_info: hostno=%d, func=%d\n", hostno, func); #endif for (host = first_host; host; host = host->next) { @@ -10563,7 +10884,7 @@ nvram_stop(np, &gpreg); #ifdef SCSI_NCR_DEBUG_NVRAM -printf("ncr53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n", +printk("ncr53c8xx: NvRAM marker=%x trailer=%x %x %x %x %x %x byte_count=%d/%d checksum=%x/%x\n", nvram->start_marker, nvram->trailer[0], nvram->trailer[1], nvram->trailer[2], nvram->trailer[3], nvram->trailer[4], nvram->trailer[5], @@ -10713,7 +11034,7 @@ static void nvram_setBit(ncr_slot *np, u_char write_bit, u_char *gpreg, int bit_mode) ) { - DELAY(5); + UDELAY (5); switch (bit_mode){ case SET_BIT: *gpreg |= write_bit; @@ -10730,7 +11051,7 @@ } OUTB (nc_gpreg, *gpreg); - DELAY(5); + UDELAY (5); } #undef SET_BIT 0 @@ -10867,7 +11188,7 @@ static void Tnvram_Read_Bit(ncr_slot *np, u_char *read_bit, u_char *gpreg) ) { - DELAY(2); + UDELAY (2); Tnvram_Clk(np, gpreg); *read_bit = INB (nc_gpreg); } @@ -10887,7 +11208,7 @@ *gpreg |= 0x10; OUTB (nc_gpreg, *gpreg); - DELAY(2); + UDELAY (2); Tnvram_Clk(np, gpreg); } @@ -10901,7 +11222,7 @@ { *gpreg &= 0xef; OUTB (nc_gpreg, *gpreg); - DELAY(2); + UDELAY (2); Tnvram_Clk(np, gpreg); } @@ -10914,7 +11235,7 @@ ) { OUTB (nc_gpreg, *gpreg | 0x04); - DELAY(2); + UDELAY (2); OUTB (nc_gpreg, *gpreg); } diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/ncr53c8xx.h linux/drivers/scsi/ncr53c8xx.h --- v2.1.107/linux/drivers/scsi/ncr53c8xx.h Mon Apr 6 17:41:00 1998 +++ linux/drivers/scsi/ncr53c8xx.h Wed Jul 1 00:29:27 1998 @@ -42,10 +42,18 @@ #ifndef NCR53C8XX_H #define NCR53C8XX_H +#if 0 +#define CONFIG_SCSI_NCR53C8XX_PROFILE +#endif + +#ifndef CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT +#define CONFIG_SCSI_NCR53C8XX_NVRAM_DETECT +#endif + /* ** Name and revision of the driver */ -#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 2.5f" +#define SCSI_NCR_DRIVER_NAME "ncr53c8xx - revision 3.0e" /* ** Check supported Linux versions @@ -56,51 +64,27 @@ #endif #include -/* -** During make dep of linux-1.2.13, LINUX_VERSION_CODE is undefined -** Under linux-1.3.X, all seems to be OK. -** So, we have only to define it under 1.2.13 -*/ - #define LinuxVersionCode(v, p, s) (((v)<<16)+((p)<<8)+(s)) -#if !defined(LINUX_VERSION_CODE) -#define LINUX_VERSION_CODE LinuxVersionCode(1,2,13) -#endif - /* -** Normal IO or memory mapped IO. -** -** Memory mapped IO only works with linux-1.3.X -** If your motherboard does not work with memory mapped IO, -** define SCSI_NCR_IOMAPPED for PATCHLEVEL 3 too. +** These options are'nt tunable from 'make config' */ - -#if LINUX_VERSION_CODE < LinuxVersionCode(1,3,0) -# define SCSI_NCR_IOMAPPED -#endif - -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) -# define SCSI_NCR_PROC_INFO_SUPPORT -#endif - -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,72) -# define SCSI_NCR_SHARE_IRQ -#endif +#define SCSI_NCR_PROC_INFO_SUPPORT +#define SCSI_NCR_SHARE_IRQ /* ** If you want a driver as small as possible, donnot define the ** following options. */ - #define SCSI_NCR_BOOT_COMMAND_LINE_SUPPORT #define SCSI_NCR_DEBUG_INFO_SUPPORT #define SCSI_NCR_PCI_FIX_UP_SUPPORT #ifdef SCSI_NCR_PROC_INFO_SUPPORT -# define SCSI_NCR_PROFILE_SUPPORT +# ifdef CONFIG_SCSI_NCR53C8XX_PROFILE +# define SCSI_NCR_PROFILE_SUPPORT +# endif # define SCSI_NCR_USER_COMMAND_SUPPORT # define SCSI_NCR_USER_INFO_SUPPORT -/* # define SCSI_NCR_DEBUG_ERROR_RECOVERY_SUPPORT */ #endif /*========================================================== @@ -130,25 +114,27 @@ #define SCSI_NCR_MAX_SYNC (40) /* - * Allow tags from 2 to 12, default 4 + * Allow tags from 2 to 64, default 8 */ #ifdef CONFIG_SCSI_NCR53C8XX_MAX_TAGS #if CONFIG_SCSI_NCR53C8XX_MAX_TAGS < 2 #define SCSI_NCR_MAX_TAGS (2) -#elif CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 12 -#define SCSI_NCR_MAX_TAGS (12) +#elif CONFIG_SCSI_NCR53C8XX_MAX_TAGS > 64 +#define SCSI_NCR_MAX_TAGS (64) #else #define SCSI_NCR_MAX_TAGS CONFIG_SCSI_NCR53C8XX_MAX_TAGS #endif #else -#define SCSI_NCR_MAX_TAGS (4) +#define SCSI_NCR_MAX_TAGS (8) #endif /* * Allow tagged command queuing support if configured with default number * of tags set to max (see above). */ -#ifdef CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE +#ifdef CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS +#define SCSI_NCR_SETUP_DEFAULT_TAGS CONFIG_SCSI_NCR53C8XX_DEFAULT_TAGS +#elif defined CONFIG_SCSI_NCR53C8XX_TAGGED_QUEUE #define SCSI_NCR_SETUP_DEFAULT_TAGS SCSI_NCR_MAX_TAGS #else #define SCSI_NCR_SETUP_DEFAULT_TAGS (0) @@ -167,12 +153,13 @@ /* * Sync transfer frequency at startup. - * Allow from 5Mhz to 40Mhz default 10 Mhz. + * Allow from 5Mhz to 40Mhz default 20 Mhz. */ #ifndef CONFIG_SCSI_NCR53C8XX_SYNC -#define CONFIG_SCSI_NCR53C8XX_SYNC (5) +#define CONFIG_SCSI_NCR53C8XX_SYNC (20) #elif CONFIG_SCSI_NCR53C8XX_SYNC > SCSI_NCR_MAX_SYNC -#define SCSI_NCR_SETUP_DEFAULT_SYNC SCSI_NCR_MAX_SYNC +#undef CONFIG_SCSI_NCR53C8XX_SYNC +#define CONFIG_SCSI_NCR53C8XX_SYNC SCSI_NCR_MAX_SYNC #endif #if CONFIG_SCSI_NCR53C8XX_SYNC == 0 @@ -247,14 +234,18 @@ #define SCSI_NCR_ALWAYS_SIMPLE_TAG #define SCSI_NCR_MAX_SCATTER (127) #define SCSI_NCR_MAX_TARGET (16) -#define SCSI_NCR_MAX_HOST (2) -#define SCSI_NCR_TIMEOUT_ALERT (3*HZ) +/* No need to use a too large adapter queue */ +#if SCSI_NCR_MAX_TAGS <= 32 #define SCSI_NCR_CAN_QUEUE (7*SCSI_NCR_MAX_TAGS) +#else +#define SCSI_NCR_CAN_QUEUE (250) +#endif + #define SCSI_NCR_CMD_PER_LUN (SCSI_NCR_MAX_TAGS) #define SCSI_NCR_SG_TABLESIZE (SCSI_NCR_MAX_SCATTER) -#define SCSI_NCR_TIMER_INTERVAL ((HZ+5-1)/5) +#define SCSI_NCR_TIMER_INTERVAL (HZ) #if 1 /* defined CONFIG_SCSI_MULTI_LUN */ #define SCSI_NCR_MAX_LUN (8) @@ -270,21 +261,12 @@ #if defined(HOSTS_C) || defined(MODULE) -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98) #include -#else -#include -#endif int ncr53c8xx_abort(Scsi_Cmnd *); int ncr53c8xx_detect(Scsi_Host_Template *tpnt); int ncr53c8xx_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); - -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,98) int ncr53c8xx_reset(Scsi_Cmnd *, unsigned int); -#else -int ncr53c8xx_reset(Scsi_Cmnd *); -#endif #ifdef MODULE int ncr53c8xx_release(struct Scsi_Host *); @@ -306,34 +288,22 @@ sg_tablesize: SCSI_NCR_SG_TABLESIZE, \ cmd_per_lun: SCSI_NCR_CMD_PER_LUN, \ use_clustering: DISABLE_CLUSTERING} - -#elif LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) - -#define NCR53C8XX { NULL, NULL, NULL, NULL, \ - SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect, \ - ncr53c8xx_release, NULL, NULL, \ - ncr53c8xx_queue_command,ncr53c8xx_abort, \ - ncr53c8xx_reset, NULL, scsicam_bios_param, \ - SCSI_NCR_CAN_QUEUE, 7, \ - SCSI_NCR_SG_TABLESIZE, SCSI_NCR_CMD_PER_LUN, \ - 0, 0, DISABLE_CLUSTERING} #else -#define NCR53C8XX { NULL, NULL, \ +#define NCR53C8XX { NULL, NULL, NULL, NULL, \ SCSI_NCR_DRIVER_NAME, ncr53c8xx_detect, \ - ncr53c8xx_release, NULL, NULL, \ + ncr53c8xx_release, NULL, NULL, \ ncr53c8xx_queue_command,ncr53c8xx_abort, \ ncr53c8xx_reset, NULL, scsicam_bios_param, \ SCSI_NCR_CAN_QUEUE, 7, \ SCSI_NCR_SG_TABLESIZE, SCSI_NCR_CMD_PER_LUN, \ 0, 0, DISABLE_CLUSTERING} - + #endif /* LINUX_VERSION_CODE */ #endif /* defined(HOSTS_C) || defined(MODULE) */ - #ifndef HOSTS_C /* @@ -589,94 +559,6 @@ 1 \ } -/* -** Define the table of target capabilities by host and target -** -** If you have problems with a scsi device, note the host unit and the -** corresponding target number. -** -** Edit the corresponding entry of the table below and try successively: -** NQ7_Questionnable -** NQ7_IdeLike -** -** This bitmap is anded with the byte 7 of inquiry data on completion of -** INQUIRY command. -** The driver never see the zeroed bits and will ignore the corresponding -** capabilities of the target. -*/ - -#define INQ7_SftRe 1 -#define INQ7_CmdQueue (1<<1) /* Tagged Command */ -#define INQ7_Reserved (1<<2) -#define INQ7_Linked (1<<3) -#define INQ7_Sync (1<<4) /* Synchronous Negotiation */ -#define INQ7_WBus16 (1<<5) -#define INQ7_WBus32 (1<<6) -#define INQ7_RelAdr (1<<7) - -#define INQ7_IdeLike 0 -#define INQ7_Scsi1Like INQ7_IdeLike -#define INQ7_Perfect 0xff -#define INQ7_Questionnable ~(INQ7_CmdQueue|INQ7_Sync) -#define INQ7_VeryQuestionnable \ - ~(INQ7_CmdQueue|INQ7_Sync|INQ7_WBus16|INQ7_WBus32) - -#define INQ7_Default INQ7_Perfect - -#define NCR53C8XX_TARGET_CAPABILITIES \ -/* Host 0 */ \ -{ \ - { \ - /* Target 0 */ INQ7_Default, \ - /* Target 1 */ INQ7_Default, \ - /* Target 2 */ INQ7_Default, \ - /* Target 3 */ INQ7_Default, \ - /* Target 4 */ INQ7_Default, \ - /* Target 5 */ INQ7_Default, \ - /* Target 6 */ INQ7_Default, \ - /* Target 7 */ INQ7_Default, \ - /* Target 8 */ INQ7_Default, \ - /* Target 9 */ INQ7_Default, \ - /* Target 10 */ INQ7_Default, \ - /* Target 11 */ INQ7_Default, \ - /* Target 12 */ INQ7_Default, \ - /* Target 13 */ INQ7_Default, \ - /* Target 14 */ INQ7_Default, \ - /* Target 15 */ INQ7_Default, \ - } \ -}, \ -/* Host 1 */ \ -{ \ - { \ - /* Target 0 */ INQ7_Default, \ - /* Target 1 */ INQ7_Default, \ - /* Target 2 */ INQ7_Default, \ - /* Target 3 */ INQ7_Default, \ - /* Target 4 */ INQ7_Default, \ - /* Target 5 */ INQ7_Default, \ - /* Target 6 */ INQ7_Default, \ - /* Target 7 */ INQ7_Default, \ - /* Target 8 */ INQ7_Default, \ - /* Target 9 */ INQ7_Default, \ - /* Target 10 */ INQ7_Default, \ - /* Target 11 */ INQ7_Default, \ - /* Target 12 */ INQ7_Default, \ - /* Target 13 */ INQ7_Default, \ - /* Target 14 */ INQ7_Default, \ - /* Target 15 */ INQ7_Default, \ - } \ -} - -/* -** Replace the proc_dir_entry of the standard ncr driver. -*/ - -#if LINUX_VERSION_CODE >= LinuxVersionCode(1,3,0) -#if defined(CONFIG_SCSI_NCR53C7xx) || !defined(CONFIG_SCSI_NCR53C8XX) -#define PROC_SCSI_NCR53C8XX PROC_SCSI_NCR53C7xx -#endif -#endif - /**************** ORIGINAL CONTENT of ncrreg.h from FreeBSD ******************/ /*----------------------------------------------------------------- @@ -801,7 +683,11 @@ /*28*/ u_int32 nc_dnad; /* ### Next command register */ /*2c*/ u_int32 nc_dsp; /* --> Script Pointer */ /*30*/ u_int32 nc_dsps; /* --> Script pointer save/opcode#2 */ -/*34*/ u_int32 nc_scratcha; /* ??? Temporary register a */ + +/*34*/ u_char nc_scratcha; /* Temporary register a */ +/*35*/ u_char nc_scratcha1; +/*36*/ u_char nc_scratcha2; +/*37*/ u_char nc_scratcha3; /*38*/ u_char nc_dmode; #define BL_2 0x80 /* mod: burst length shift value +2 */ @@ -1080,10 +966,10 @@ /*----------------------------------------------------------- ** -** FROM_REG (reg) reg = SFBR +** FROM_REG (reg) SFBR = reg ** << 0 >> ** -** TO_REG (reg) SFBR = reg +** TO_REG (reg) reg = SFBR ** << 0 >> ** ** LOAD_REG (reg, data) reg = @@ -1109,6 +995,42 @@ /*----------------------------------------------------------- ** +** LOAD from memory to register. +** STORE from register to memory. +** +**----------------------------------------------------------- +** +** LOAD_ABS (LEN) +** <> +** +** LOAD_REL (LEN) (DSA relative) +** <> +** +**----------------------------------------------------------- +*/ + +#define SCR_NO_FLUSH2 0x02000000 +#define SCR_DSA_REL2 0x10000000 + +#define SCR_LOAD_R(reg, how, n) \ + (0xe1000000 | how | (SCR_REG_OFS(REG(reg))) | (n)) + +#define SCR_STORE_R(reg, how, n) \ + (0xe0000000 | how | (SCR_REG_OFS(REG(reg))) | (n)) + +#define SCR_LOAD_ABS(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2, n) +#define SCR_LOAD_REL(reg, n) SCR_LOAD_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2, n) +#define SCR_LOAD_ABS_F(reg, n) SCR_LOAD_R(reg, 0, n) +#define SCR_LOAD_REL_F(reg, n) SCR_LOAD_R(reg, SCR_DSA_REL2, n) + +#define SCR_STORE_ABS(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2, n) +#define SCR_STORE_REL(reg, n) SCR_STORE_R(reg, SCR_NO_FLUSH2|SCR_DSA_REL2,n) +#define SCR_STORE_ABS_F(reg, n) SCR_STORE_R(reg, 0, n) +#define SCR_STORE_REL_F(reg, n) SCR_STORE_R(reg, SCR_DSA_REL2, n) + + +/*----------------------------------------------------------- +** ** Waiting for Disconnect or Reselect ** **----------------------------------------------------------- @@ -1143,7 +1065,7 @@ **----------------------------------------------------------- */ -#define SCR_NO_OP 0x80000000 +#define SCR_NO_OP 0x80000000 #define SCR_JUMP 0x80080000 #define SCR_JUMPR 0x80880000 #define SCR_CALL 0x88080000 diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/pluto.c linux/drivers/scsi/pluto.c --- v2.1.107/linux/drivers/scsi/pluto.c Thu Apr 23 20:21:35 1998 +++ linux/drivers/scsi/pluto.c Thu Jun 25 11:04:26 1998 @@ -14,8 +14,8 @@ #include #include #include -#ifdef CONFIG_KERNELD -#include +#ifdef CONFIG_KMOD +#include #endif #include @@ -104,7 +104,7 @@ fcscount++; PLND(("%d channels online\n", fcscount)) if (!fcscount) { -#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KERNELD) +#if defined(MODULE) && defined(CONFIG_FC4_SOC_MODULE) && defined(CONFIG_KMOD) request_module("soc"); for_each_online_fc_channel(fc) diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.107/linux/drivers/scsi/scsi.c Sun Jun 7 11:16:34 1998 +++ linux/drivers/scsi/scsi.c Sun Jun 28 16:00:41 1998 @@ -274,6 +274,7 @@ {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"NRC","MBR-7.4","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"NAKAMICH","MJ-4.8S","*", BLIST_FORCELUN | BLIST_SINGLELUN}, +{"PIONEER","CD-ROM DRM-600","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"EMULEX","MD21/S2 ESDI","*", BLIST_SINGLELUN}, diff -u --recursive --new-file v2.1.107/linux/drivers/scsi/scsi_obsolete.c linux/drivers/scsi/scsi_obsolete.c --- v2.1.107/linux/drivers/scsi/scsi_obsolete.c Tue Jun 23 10:01:24 1998 +++ linux/drivers/scsi/scsi_obsolete.c Sun Jun 28 16:00:41 1998 @@ -180,7 +180,8 @@ scsi_reset (SCpnt, SCSI_RESET_ASYNCHRONOUS | SCSI_RESET_SUGGEST_BUS_RESET); break; - case (IN_ABORT | IN_RESET | IN_RESET2): + case IN_RESET2: + case (IN_ABORT | IN_RESET2): /* Obviously the bus reset didn't work. * Let's try even harder and call for an HBA reset. * Maybe the HBA itself crashed and this will shake it loose. diff -u --recursive --new-file v2.1.107/linux/drivers/sound/msnd.c linux/drivers/sound/msnd.c --- v2.1.107/linux/drivers/sound/msnd.c Tue Jun 23 10:01:24 1998 +++ linux/drivers/sound/msnd.c Thu Jun 25 11:03:43 1998 @@ -24,7 +24,6 @@ * ********************************************************************/ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/sound/msnd_classic.c linux/drivers/sound/msnd_classic.c --- v2.1.107/linux/drivers/sound/msnd_classic.c Tue Jun 23 10:01:24 1998 +++ linux/drivers/sound/msnd_classic.c Thu Jun 25 11:03:43 1998 @@ -24,7 +24,6 @@ * ********************************************************************/ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/sound/msnd_classic.h linux/drivers/sound/msnd_classic.h --- v2.1.107/linux/drivers/sound/msnd_classic.h Tue Jun 23 10:01:24 1998 +++ linux/drivers/sound/msnd_classic.h Thu Jun 25 11:03:43 1998 @@ -30,6 +30,8 @@ #ifndef __MSND_CLASSIC_H #define __MSND_CLASSIC_H +#include + #define DSP_NUMIO 0x10 #define HP_MEMM 0x08 diff -u --recursive --new-file v2.1.107/linux/drivers/sound/msnd_pinnacle.c linux/drivers/sound/msnd_pinnacle.c --- v2.1.107/linux/drivers/sound/msnd_pinnacle.c Tue Jun 23 10:01:24 1998 +++ linux/drivers/sound/msnd_pinnacle.c Thu Jun 25 11:03:43 1998 @@ -24,7 +24,6 @@ * ********************************************************************/ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/sound/msnd_pinnacle.h linux/drivers/sound/msnd_pinnacle.h --- v2.1.107/linux/drivers/sound/msnd_pinnacle.h Tue Jun 23 10:01:24 1998 +++ linux/drivers/sound/msnd_pinnacle.h Thu Jun 25 11:03:43 1998 @@ -30,6 +30,8 @@ #ifndef __MSND_PINNACLE_H #define __MSND_PINNACLE_H +#include + #define DSP_NUMIO 0x08 #define HP_DSPR 0x04 diff -u --recursive --new-file v2.1.107/linux/drivers/sound/sound_core.c linux/drivers/sound/sound_core.c --- v2.1.107/linux/drivers/sound/sound_core.c Tue Jun 9 11:57:30 1998 +++ linux/drivers/sound/sound_core.c Thu Jun 25 11:03:43 1998 @@ -34,7 +34,6 @@ * locking at some point in 2.3.x. */ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/video/S3triofb.c linux/drivers/video/S3triofb.c --- v2.1.107/linux/drivers/video/S3triofb.c Wed Jun 24 22:54:07 1998 +++ linux/drivers/video/S3triofb.c Thu Jun 25 11:03:43 1998 @@ -23,6 +23,7 @@ */ +#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/video/fbcon-ilbm.c linux/drivers/video/fbcon-ilbm.c --- v2.1.107/linux/drivers/video/fbcon-ilbm.c Wed Jun 24 22:54:07 1998 +++ linux/drivers/video/fbcon-ilbm.c Thu Jun 25 22:37:36 1998 @@ -201,7 +201,7 @@ #if defined(__BIG_ENDIAN) d = *cdat1++<<24 | *cdat2++<<16 | *cdat3++<<8 | *cdat4++; #elif defined(__LITTLE_ENDIAN) - d = *cdat1++ | *cdat2++<<8 | *cdat3++<<16 | *cdat4++<<32); + d = *cdat1++ | *cdat2++<<8 | *cdat3++<<16 | *cdat4++<<24; #else #error FIXME: No endianness?? #endif diff -u --recursive --new-file v2.1.107/linux/drivers/video/fbcon-iplan2p2.c linux/drivers/video/fbcon-iplan2p2.c --- v2.1.107/linux/drivers/video/fbcon-iplan2p2.c Wed Jun 24 22:54:07 1998 +++ linux/drivers/video/fbcon-iplan2p2.c Thu Jun 25 11:03:43 1998 @@ -10,6 +10,7 @@ * more details. */ +#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/video/fbcon-iplan2p4.c linux/drivers/video/fbcon-iplan2p4.c --- v2.1.107/linux/drivers/video/fbcon-iplan2p4.c Wed Jun 24 22:54:07 1998 +++ linux/drivers/video/fbcon-iplan2p4.c Thu Jun 25 11:03:43 1998 @@ -10,6 +10,7 @@ * more details. */ +#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/video/fbcon-iplan2p8.c linux/drivers/video/fbcon-iplan2p8.c --- v2.1.107/linux/drivers/video/fbcon-iplan2p8.c Wed Jun 24 22:54:07 1998 +++ linux/drivers/video/fbcon-iplan2p8.c Thu Jun 25 11:03:43 1998 @@ -10,6 +10,7 @@ * more details. */ +#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/drivers/video/hpfb.c linux/drivers/video/hpfb.c --- v2.1.107/linux/drivers/video/hpfb.c Wed Jun 24 22:54:07 1998 +++ linux/drivers/video/hpfb.c Thu Jun 25 11:03:43 1998 @@ -6,7 +6,6 @@ * No! -- Jes */ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/fs/coda/stats.c linux/fs/coda/stats.c --- v2.1.107/linux/fs/coda/stats.c Sun Jun 7 11:16:36 1998 +++ linux/fs/coda/stats.c Thu Jun 25 11:03:43 1998 @@ -7,7 +7,6 @@ * */ -#include #include #include #include diff -u --recursive --new-file v2.1.107/linux/fs/fcntl.c linux/fs/fcntl.c --- v2.1.107/linux/fs/fcntl.c Sun Jun 7 11:16:36 1998 +++ linux/fs/fcntl.c Mon Jun 29 23:22:29 1998 @@ -191,7 +191,7 @@ match = -p->pgrp; if (pid != match) continue; - if (!euid && + if ((euid != 0) && (euid ^ p->suid) && (euid ^ p->uid) && (uid ^ p->suid) && (uid ^ p->uid)) continue; diff -u --recursive --new-file v2.1.107/linux/fs/proc/array.c linux/fs/proc/array.c --- v2.1.107/linux/fs/proc/array.c Wed Jun 24 22:54:10 1998 +++ linux/fs/proc/array.c Fri Jun 26 09:45:54 1998 @@ -232,7 +232,7 @@ #ifdef __SMP__ len = sprintf(buffer, - "CPU %u %u %u %lu\n", + "cpu %u %u %u %lu\n", kstat.cpu_user, kstat.cpu_nice, kstat.cpu_system, diff -u --recursive --new-file v2.1.107/linux/fs/select.c linux/fs/select.c --- v2.1.107/linux/fs/select.c Thu Mar 26 15:57:05 1998 +++ linux/fs/select.c Thu Jun 25 10:39:32 1998 @@ -297,21 +297,25 @@ current->state = TASK_INTERRUPTIBLE; for (fdpnt = fds, j = 0; j < nfds; j++, fdpnt++) { + int fd; unsigned int mask; - struct file * file; - mask = POLLNVAL; - /* poll_wait increments f_count if needed */ - file = fcheck(fdpnt->fd); - if (file != NULL) { - mask = DEFAULT_POLLMASK; - if (file->f_op && file->f_op->poll) - mask = file->f_op->poll(file, wait); - mask &= fdpnt->events | POLLERR | POLLHUP; - } - if (mask) { - wait = NULL; - count++; + mask = 0; + fd = fdpnt->fd; + if (fd >= 0) { + /* poll_wait increments f_count if needed */ + struct file * file = fcheck(fd); + mask = POLLNVAL; + if (file != NULL) { + mask = DEFAULT_POLLMASK; + if (file->f_op && file->f_op->poll) + mask = file->f_op->poll(file, wait); + mask &= fdpnt->events | POLLERR | POLLHUP; + } + if (mask) { + wait = NULL; + count++; + } } fdpnt->revents = mask; } diff -u --recursive --new-file v2.1.107/linux/fs/sysv/CHANGES linux/fs/sysv/CHANGES --- v2.1.107/linux/fs/sysv/CHANGES Thu Feb 12 20:56:12 1998 +++ linux/fs/sysv/CHANGES Thu Jun 25 10:57:35 1998 @@ -3,7 +3,7 @@ Fri Jan 23 1998 Krzysztof G. Baranowski * inode.c: corrected 1 track offset setting (in sb->sv_block_base). - Originally it was overriden (by setting to zero) + Originally it was overridden (by setting to zero) in detected_[xenix,sysv4,sysv2,coherent]. Thanks to Andrzej Krzysztofowicz for identifying the problem. diff -u --recursive --new-file v2.1.107/linux/fs/sysv/Makefile linux/fs/sysv/Makefile --- v2.1.107/linux/fs/sysv/Makefile Tue Aug 15 05:07:02 1995 +++ linux/fs/sysv/Makefile Thu Jun 25 10:57:35 1998 @@ -1,11 +1,11 @@ # -# Makefile for the Linux SystemV/Coherent-filesystem routines. +# Makefile for the Linux SystemV/Coherent filesystem routines. # # Note! Dependencies are done automagically by 'make dep', which also # removes any old dependencies. DON'T put your own dependencies here -# unless it's something special (ie not a .c file). +# unless it's something special (not a .c file). # -# Note 2! The CFLAGS definitions are now in the main makefile... +# Note 2! The CFLAGS definitions are now in the main makefile. O_TARGET := sysv.o O_OBJS := ialloc.o balloc.o inode.o file.o dir.o symlink.o namei.o \ diff -u --recursive --new-file v2.1.107/linux/fs/sysv/file.c linux/fs/sysv/file.c --- v2.1.107/linux/fs/sysv/file.c Tue Oct 21 08:57:30 1997 +++ linux/fs/sysv/file.c Thu Jun 25 10:57:35 1998 @@ -36,7 +36,7 @@ static ssize_t sysv_file_write(struct file *, const char *, size_t, loff_t *); /* - * We have mostly NULL's here: the current defaults are ok for + * We have mostly NULLs here: the current defaults are OK for * the coh filesystem. */ static struct file_operations sysv_file_operations = { @@ -220,7 +220,7 @@ return -EINVAL; } /* - * ok, append may not work when many processes are writing at the same time + * OK, append may not work when many processes are writing at the same time * but so what. That way leads to madness anyway. * But we need to protect against simultaneous truncate as we may end up * writing our data into blocks that have meanwhile been incorporated into diff -u --recursive --new-file v2.1.107/linux/fs/sysv/truncate.c linux/fs/sysv/truncate.c --- v2.1.107/linux/fs/sysv/truncate.c Sun Sep 7 13:06:08 1997 +++ linux/fs/sysv/truncate.c Thu Jun 25 10:57:35 1998 @@ -24,7 +24,7 @@ /* * Truncate has the most races in the whole filesystem: coding it is - * a pain in the a**. Especially as I don't do any locking... + * a pain in the a**, especially as I don't do any locking. * * The code may look a bit weird, but that's just because I've tried to * handle things like file-size changes in a somewhat graceful manner. diff -u --recursive --new-file v2.1.107/linux/include/asm-i386/unistd.h linux/include/asm-i386/unistd.h --- v2.1.107/linux/include/asm-i386/unistd.h Tue Jun 23 10:01:27 1998 +++ linux/include/asm-i386/unistd.h Fri Jun 26 02:28:38 1998 @@ -192,6 +192,7 @@ #define __NR_capget 184 #define __NR_capset 185 #define __NR_sigaltstack 186 +#define __NR_sendfile 187 /* user-visible error numbers are in the range -1 - -122: see */ diff -u --recursive --new-file v2.1.107/linux/include/asm-m68k/pgtable.h linux/include/asm-m68k/pgtable.h --- v2.1.107/linux/include/asm-m68k/pgtable.h Tue Jun 23 10:01:28 1998 +++ linux/include/asm-m68k/pgtable.h Thu Jun 25 11:03:43 1998 @@ -1,6 +1,7 @@ #ifndef _M68K_PGTABLE_H #define _M68K_PGTABLE_H +#include #include #ifndef __ASSEMBLY__ diff -u --recursive --new-file v2.1.107/linux/include/linux/console_compat.h linux/include/linux/console_compat.h --- v2.1.107/linux/include/linux/console_compat.h Wed Jun 24 22:54:11 1998 +++ linux/include/linux/console_compat.h Thu Jun 25 11:03:43 1998 @@ -11,6 +11,8 @@ #ifndef _LINUX_CONSOLE_COMPAT_H_ #define _LINUX_CONSOLE_COMPAT_H_ +#include + #undef video_num_columns #undef video_num_lines #undef video_size_row diff -u --recursive --new-file v2.1.107/linux/include/linux/console_struct.h linux/include/linux/console_struct.h --- v2.1.107/linux/include/linux/console_struct.h Wed Jun 24 22:54:11 1998 +++ linux/include/linux/console_struct.h Thu Jun 25 11:03:43 1998 @@ -10,8 +10,6 @@ */ #define CUR_DEFAULT CUR_UNDERLINE -#include - #define NPAR 16 struct vc_data { diff -u --recursive --new-file v2.1.107/linux/include/linux/mm.h linux/include/linux/mm.h --- v2.1.107/linux/include/linux/mm.h Wed Jun 24 22:54:11 1998 +++ linux/include/linux/mm.h Wed Jul 1 08:29:56 1998 @@ -281,7 +281,6 @@ extern void free_page_tables(struct mm_struct * mm); extern void clear_page_tables(struct task_struct * tsk); extern int new_page_tables(struct task_struct * tsk); -extern int copy_page_tables(struct task_struct * to); extern void zap_page_range(struct mm_struct *mm, unsigned long address, unsigned long size); extern int copy_page_range(struct mm_struct *dst, struct mm_struct *src, struct vm_area_struct *vma); @@ -291,6 +290,7 @@ extern void vmtruncate(struct inode * inode, unsigned long offset); extern void handle_mm_fault(struct task_struct *tsk,struct vm_area_struct *vma, unsigned long address, int write_access); extern void check_pgt_cache(void); +extern void make_pages_present(unsigned long addr, unsigned long end); extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem); extern void mem_init(unsigned long start_mem, unsigned long end_mem); diff -u --recursive --new-file v2.1.107/linux/include/linux/selection.h linux/include/linux/selection.h --- v2.1.107/linux/include/linux/selection.h Wed Jun 24 22:54:11 1998 +++ linux/include/linux/selection.h Thu Jun 25 11:03:43 1998 @@ -4,8 +4,6 @@ * Interface between console.c, tty_io.c, vt.c, vc_screen.c and selection.c */ -#include - extern int sel_cons; extern void clear_selection(void); @@ -59,8 +57,6 @@ /* how to access screen memory */ - -#include static inline void scr_writew(unsigned short val, unsigned short *addr) { diff -u --recursive --new-file v2.1.107/linux/mm/filemap.c linux/mm/filemap.c --- v2.1.107/linux/mm/filemap.c Wed Jun 24 22:54:12 1998 +++ linux/mm/filemap.c Fri Jun 26 16:13:34 1998 @@ -567,6 +567,23 @@ return page_cache; } +/* + * "descriptor" for what we're up to with a read. + * This allows us to use the same read code yet + * have multiple different users of the data that + * we read from a file. + * + * The simplest case just copies the data to user + * mode. + */ +typedef struct { + size_t written; + size_t count; + char * buf; + int error; +} read_descriptor_t; + +typedef int (*read_actor_t)(read_descriptor_t *, const char *, unsigned long); /* * This is a generic file read routine, and uses the @@ -576,23 +593,14 @@ * This is really ugly. But the goto's actually try to clarify some * of the logic when it comes to error handling etc. */ - -ssize_t generic_file_read(struct file * filp, char * buf, - size_t count, loff_t *ppos) +static void do_generic_file_read(struct file * filp, loff_t *ppos, read_descriptor_t * desc, read_actor_t actor) { struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; - ssize_t error, read; size_t pos, pgpos, page_cache; int reada_ok; int max_readahead = get_max_readahead(inode); - if (!access_ok(VERIFY_WRITE, buf, count)) - return -EFAULT; - if (!count) - return 0; - error = 0; - read = 0; page_cache = 0; pos = *ppos; @@ -620,12 +628,12 @@ * Then, at least MIN_READAHEAD if read ahead is ok, * and at most MAX_READAHEAD in all cases. */ - if (pos + count <= (PAGE_SIZE >> 1)) { + if (pos + desc->count <= (PAGE_SIZE >> 1)) { filp->f_ramax = 0; } else { unsigned long needed; - needed = ((pos + count) & PAGE_MASK) - pgpos; + needed = ((pos + desc->count) & PAGE_MASK) - pgpos; if (filp->f_ramax < needed) filp->f_ramax = needed; @@ -678,20 +686,20 @@ offset = pos & ~PAGE_MASK; nr = PAGE_SIZE - offset; - if (nr > count) - nr = count; if (nr > inode->i_size - pos) nr = inode->i_size - pos; - nr -= copy_to_user(buf, (void *) (page_address(page) + offset), nr); - release_page(page); - error = -EFAULT; - if (!nr) - break; - buf += nr; + + /* + * The actor routine returns how many bytes were actually used.. + * NOTE! This may not be the same as how much of a user buffer + * we filled up (we may be padding etc), so we can only update + * "pos" here (the actor routine has to update the user buffer + * pointers and the remaining count). + */ + nr = actor(desc, (const char *) (page_address(page) + offset), nr); pos += nr; - read += nr; - count -= nr; - if (count) + release_page(page); + if (nr && desc->count) continue; break; } @@ -709,7 +717,7 @@ */ if (page_cache) continue; - error = -ENOMEM; + desc->error = -ENOMEM; break; } @@ -738,11 +746,14 @@ if (reada_ok && filp->f_ramax > MIN_READAHEAD) filp->f_ramax = MIN_READAHEAD; - error = inode->i_op->readpage(filp, page); - if (!error) - goto found_page; - release_page(page); - break; + { + int error = inode->i_op->readpage(filp, page); + if (!error) + goto found_page; + desc->error = error; + release_page(page); + break; + } page_read_error: /* @@ -750,15 +761,18 @@ * Try to re-read it _once_. We do this synchronously, * because this happens only if there were errors. */ - error = inode->i_op->readpage(filp, page); - if (!error) { - wait_on_page(page); - if (PageUptodate(page) && !PageError(page)) - goto success; - error = -EIO; /* Some unspecified error occurred.. */ + { + int error = inode->i_op->readpage(filp, page); + if (!error) { + wait_on_page(page); + if (PageUptodate(page) && !PageError(page)) + goto success; + error = -EIO; /* Some unspecified error occurred.. */ + } + desc->error = error; + release_page(page); + break; } - release_page(page); - break; } *ppos = pos; @@ -766,9 +780,146 @@ if (page_cache) free_page(page_cache); UPDATE_ATIME(inode); - if (!read) - read = error; - return read; +} + +static int file_read_actor(read_descriptor_t * desc, const char *area, unsigned long size) +{ + unsigned long left; + unsigned long count = desc->count; + + if (size > count) + size = count; + left = __copy_to_user(desc->buf, area, size); + if (left) { + size -= left; + desc->error = -EFAULT; + } + desc->count = count - size; + desc->written += size; + desc->buf += size; + return size; +} + +/* + * This is the "read()" routine for all filesystems + * that can use the page cache directly. + */ +ssize_t generic_file_read(struct file * filp, char * buf, size_t count, loff_t *ppos) +{ + ssize_t retval; + + retval = -EFAULT; + if (access_ok(VERIFY_WRITE, buf, count)) { + retval = 0; + if (count) { + read_descriptor_t desc; + + desc.written = 0; + desc.count = count; + desc.buf = buf; + desc.error = 0; + do_generic_file_read(filp, ppos, &desc, file_read_actor); + + retval = desc.written; + if (!retval) + retval = desc.error; + } + } + return retval; +} + +static int file_send_actor(read_descriptor_t * desc, const char *area, unsigned long size) +{ + ssize_t written; + unsigned long count = desc->count; + struct file *file = (struct file *) desc->buf; + struct inode *inode = file->f_dentry->d_inode; + + if (size > count) + size = count; + down(&inode->i_sem); + set_fs(KERNEL_DS); + written = file->f_op->write(file, area, size, &file->f_pos); + set_fs(USER_DS); + up(&inode->i_sem); + if (written < 0) { + desc->error = written; + written = 0; + } + desc->count = count - written; + desc->written += written; + return written; +} + +asmlinkage ssize_t sys_sendfile(int out_fd, int in_fd, size_t count) +{ + ssize_t retval; + struct file * in_file, * out_file; + struct inode * in_inode, * out_inode; + + lock_kernel(); + + /* + * Get input file, and verify that it is ok.. + */ + retval = -EBADF; + in_file = fget(in_fd); + if (!in_file) + goto out; + if (!(in_file->f_mode & FMODE_READ)) + goto fput_in; + retval = -EINVAL; + in_inode = in_file->f_dentry->d_inode; + if (!in_inode) + goto fput_in; + if (!in_inode->i_op || !in_inode->i_op->readpage) + goto fput_in; + retval = locks_verify_area(FLOCK_VERIFY_READ, in_inode, in_file, in_file->f_pos, count); + if (retval) + goto fput_in; + + /* + * Get output file, and verify that it is ok.. + */ + retval = -EBADF; + out_file = fget(out_fd); + if (!out_file) + goto fput_in; + if (!(out_file->f_mode & FMODE_WRITE)) + goto fput_out; + retval = -EINVAL; + if (!out_file->f_op || !out_file->f_op->write) + goto fput_out; + out_inode = out_file->f_dentry->d_inode; + if (!out_inode) + goto fput_out; + retval = locks_verify_area(FLOCK_VERIFY_WRITE, out_inode, out_file, out_file->f_pos, count); + if (retval) + goto fput_out; + + retval = 0; + if (count) { + read_descriptor_t desc; + + desc.written = 0; + desc.count = count; + desc.buf = (char *) out_file; + desc.error = 0; + do_generic_file_read(in_file, &in_file->f_pos, &desc, file_send_actor); + + retval = desc.written; + if (!retval) + retval = desc.error; + } + + +fput_out: + fput(out_file); +fput_in: + fput(in_file); +out: + unlock_kernel(); + return retval; } /* diff -u --recursive --new-file v2.1.107/linux/mm/memory.c linux/mm/memory.c --- v2.1.107/linux/mm/memory.c Tue Jun 23 10:01:30 1998 +++ linux/mm/memory.c Tue Jun 30 12:42:50 1998 @@ -918,6 +918,22 @@ oom(tsk); } +/* + * Simplistic page force-in.. + */ +void make_pages_present(unsigned long addr, unsigned long end) +{ + int write; + struct vm_area_struct * vma; + + vma = find_vma(current->mm, addr); + write = (vma->vm_flags & VM_WRITE) != 0; + while (addr < end) { + handle_mm_fault(current, vma, addr, write); + addr += PAGE_SIZE; + } +} + /* Low and high watermarks for page table cache. The system should try to have pgt_water[0] <= cache elements <= pgt_water[1] */ diff -u --recursive --new-file v2.1.107/linux/mm/mlock.c linux/mm/mlock.c --- v2.1.107/linux/mm/mlock.c Tue Jun 23 10:01:30 1998 +++ linux/mm/mlock.c Tue Jun 30 12:38:39 1998 @@ -126,26 +126,7 @@ if (!(newflags & VM_LOCKED)) pages = -pages; vma->vm_mm->locked_vm += pages; - -#if 0 -/* - * This is horribly broken. See the comment on the same - * brokenness in mm/mmap.c (essentially, this doesn't - * work anyway for PROT_NONE and writable pages, and now - * that we properly get the mmap semaphore it would just - * lock up on us). - * - * Fix the same way. - */ - if (newflags & VM_LOCKED) { - while (start < end) { - int c; - get_user(c,(int *) start); - __asm__ __volatile__("": :"r" (c)); - start += PAGE_SIZE; - } - } -#endif + make_pages_present(start, end); } return retval; } diff -u --recursive --new-file v2.1.107/linux/mm/mmap.c linux/mm/mmap.c --- v2.1.107/linux/mm/mmap.c Tue Jun 23 10:01:30 1998 +++ linux/mm/mmap.c Tue Jun 30 12:38:39 1998 @@ -51,7 +51,7 @@ /* Check that a process has enough memory to allocate a * new virtual mapping. */ -static inline int vm_enough_memory(long pages) +int vm_enough_memory(long pages) { /* Stupid algorithm to decide if we have enough memory: while * simple, it hopefully works in most obvious cases.. Easy to @@ -318,27 +318,7 @@ mm->total_vm += len >> PAGE_SHIFT; if (flags & VM_LOCKED) { mm->locked_vm += len >> PAGE_SHIFT; - -/* - * This used to be just slightly broken, now it's just completely - * buggered. We can't take a page fault here, because we already - * hold the mm semaphore (as is proper). We should do this by hand - * by calling the appropriate fault-in routine. - * - * That would also fix this routine wrt writes and PROT_NONE - * areas, both of which can't be handled by the page fault - * approach anyway. - */ -#if 0 - unsigned long start = addr; - do { - char c; - get_user(c,(char *) start); - len -= PAGE_SIZE; - start += PAGE_SIZE; - __asm__ __volatile__("": :"r" (c)); - } while (len > 0); -#endif + make_pages_present(addr, addr + len); } return addr; diff -u --recursive --new-file v2.1.107/linux/mm/mremap.c linux/mm/mremap.c --- v2.1.107/linux/mm/mremap.c Tue Jun 23 10:01:30 1998 +++ linux/mm/mremap.c Sat Jun 27 09:44:15 1998 @@ -21,6 +21,8 @@ #include #include +extern int vm_enough_memory(long pages); + static inline pte_t *get_one_pte(struct mm_struct *mm, unsigned long addr) { pgd_t * pgd; @@ -179,7 +181,7 @@ * the unnecessary pages.. */ ret = addr; - if (old_len > new_len) { + if (old_len >= new_len) { do_munmap(addr+new_len, old_len - new_len); goto out; } @@ -204,6 +206,11 @@ ret = -ENOMEM; if ((current->mm->total_vm << PAGE_SHIFT) + (new_len - old_len) > current->rlim[RLIMIT_AS].rlim_cur) + goto out; + /* Private writable mapping? Check memory availability.. */ + if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE && + !(flags & MAP_NORESERVE) && + !vm_enough_memory((new_len - old_len) >> PAGE_SHIFT)) goto out; /* old_len exactly to the end of the area.. */