Say Y here if you would like to use hard disks under Linux which
were partitioned on a Macintosh.
+Windows' Logical Disk Manager (Dynamic Disk) support (EXPERIMENTAL)
+CONFIG_LDM_PARTITION
+ Say Y here if you would like to use hard disks under Linux which
+ were partitioned using Windows 2000's or XP's Logical Disk Manager.
+ They are also known as "Dynamic Disks".
+
+ Windows 2000 introduced the concept of Dynamic Disks to get around
+ the limitations of the PC's partitioning scheme. The Logical Disk
+ Manager allows the user to repartion a disk and create spanned,
+ mirrored, striped or RAID volumes, all without the need for
+ rebooting.
+
+ Normal partitions are now called Basic Disks under Windows 2000 and XP.
+
+ Technical documentation to accompany this driver is available from:
+ <http://linux-ntfs.sf.net/ldm>
+
+ If unsure, say N.
+
+Windows' LDM extra logging
+CONFIG_LDM_DEBUG
+ Say Y here if you would like LDM to log verbosely. This could be
+ helpful if the driver doesn't work as expected and you'd like to
+ report a bug.
+
+ If unsure, say N.
+
PC BIOS (MSDOS partition tables) support
CONFIG_MSDOS_PARTITION
Say Y here if you would like to use hard disks under Linux which
--- /dev/null
+S/390 common I/O-Layer - command line parameters and /proc entries
+==================================================================
+
+Command line parameters
+-----------------------
+
+* cio_msg = yes | no
+
+ Determines whether information on found devices and sensed device
+ characteristics should be shown during startup, i. e. messages of the types
+ "Detected device 4711 on subchannel 42" and "SenseID: Device 4711 reports: ...".
+
+ Default is off.
+
+
+* cio_notoper_msg = yes | no
+
+ Determines whether messages of the type "Device 4711 became 'not operational'"
+ should be shown during startup; after startup, they will always be shown.
+
+ Default is on.
+
+
+* cio_ignore = <range of device numbers>, <range of device numbers>, ...
+
+ The given device numbers will be ignored by the common I/O-layer; no detection
+ and device sensing will be done on any of those devices. The subchannel to
+ which the device in question is attached will be treated as if no device was
+ attached.
+
+ An ignored device can be un-ignored later; see the "/proc entries"-section for
+ details.
+
+ The device numbers must be given hexadecimal.
+
+ For example,
+ cio_ignore=0x23-0x42,0x4711
+ will ignore all devices with device numbers ranging from 23 to 42 and the
+ device with device number 4711, if detected.
+
+ By default, no devices are ignored.
+
+
+* cio_proc_devinfo = yes | no
+
+ Determines whether the entries under /proc/deviceinfo/ (see below) should be
+ created. Since there are problems with systems with many devices attached, I
+ made it configurable.
+
+ Until the problems are dealt with, default is off.
+
+
+/proc entries
+-------------
+
+* /proc/subchannels
+
+ Shows for each subchannel
+ - device number
+ - device type/model and if applicable control unit type/model
+ - whether the device is in use
+ - path installed mask, path available mask, path operational mask and last
+ path used mask
+ - the channel path IDs (chpids)
+
+
+* /proc/deviceinfo/
+
+ Shows in subdirectories for each device some characteristics:
+ - /proc/deviceinfo/<devno>/chpids:
+ the channel path IDs
+ - /proc/deviceinfo/<devno>/in_use:
+ whether the device is in use
+ - /proc/deviceinfo/<devno>/sensedata:
+ the device type/model and if applicable control unit type/model of the
+ device
+
+ NOTE: Since the number of inodes which can be dynamically allocated by procfs
+ is limited, device entries will only be created up to a magic number of
+ devices. The kernel will utter a warning that not all entries can be
+ created. In this case, you shouldn't use "cio_proc_devinfo=yes" (see
+ above).
+
+* /proc/cio_ignore
+
+ Lists the ranges of device numbers which are ignored by common I/O.
+
+ You can un-ignore certain or all devices by piping to /proc/cio_ignore.
+ "free all" will un-ignore all ignored devices,
+ "free <devnorange>, <devnorange>, ..." will un-ignore the specified devices.
+
+ For example, if devices 23 to 42 and 4711 are ignored,
+ - echo free 0x30-0x32 > /proc/cio_ignore
+ will un-ignore devices 30 to 32 and will leave devices 23 to 2F, 33 to 42
+ and 4711 ignored;
+ - echo free 0x41 > /proc/cio_ignore will furthermore un-ignore device 41;
+ - echo free all > /proc/cio_ignore will un-ignore all remaining ignored
+ devices.
+
+ When a device is un-ignored, device recognition and sensing is performed and
+ the device driver will be notified if possible, so the device will become
+ available to the system.
+
+
+* /proc/s390dbf/cio_*/ (S/390 debug feature)
+
+ Some views generated by the debug feature to hold various debug outputs.
+
+ - /proc/s390dbf/cio_crw/sprintf
+ Messages from the processing of pending channel report words (machine check
+ handling), which will also show when CONFIG_DEBUG_CRW is defined.
+
+ - /proc/s390dbf/cio_msg/sprintf
+ Various debug messages from the common I/O-layer; generally, messages which
+ will also show when CONFIG_DEBUG_IO is defined.
+
+ - /proc/s390dbf/cio_trace/hex_ascii
+ Logs the calling of functions in the common I/O-layer and, if applicable,
+ which subchannel they were called for.
+
+ The level of logging can be changed to be more or less verbose by piping to
+ /proc/s390dbf/cio_*/level a number between 0 and 6; see the documentation on
+ the S/390 debug feature (Documentation/s390/s390dbf.txt) for details.
+
- Debugging on Linux for s/390 & zSeries
+ Debugging on Linux for s/390 & z/Architecture
by
Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com)
Copyright (C) 2000-2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
Overview of Document:
=====================
This document is intended to give an good overview of how to debug
-Linux for s/390 & zSeries it isn't intended as a complete reference & not a
+Linux for s/390 & z/Architecture it isn't intended as a complete reference & not a
tutorial on the fundamentals of C & assembly, it dosen't go into
390 IO in any detail. It is intended to compliment the documents in the
reference section below & any other worthwhile references you get.
========
Register Set
Address Spaces on Intel Linux
-Address Spaces on Linux for s/390 & zSeries
-The Linux for s/390 & zSeries Kernel Task Structure
-Register Usage & Stackframes on Linux for s/390 & zSeries
+Address Spaces on Linux for s/390 & z/Architecture
+The Linux for s/390 & z/Architecture Kernel Task Structure
+Register Usage & Stackframes on Linux for s/390 & z/Architecture
A sample program with comments
-Compiling programs for debugging on Linux for s/390 & zSeries
+Compiling programs for debugging on Linux for s/390 & z/Architecture
Figuring out gcc compile errors
Debugging Tools
objdump
strace
Performance Debugging
Debugging under VM
-s/390 & zSeries IO Overview
-Debugging IO on s/390 & zSeries under VM
-GDB on s/390 & zSeries
+s/390 & z/Architecture IO Overview
+Debugging IO on s/390 & z/Architecture under VM
+GDB on s/390 & z/Architecture
Stack chaining in gdb by hand
Examining core dumps
ldd
Debugging modules
The proc file system
Starting points for debugging scripting languages etc.
-Tools soon to be available
SysRq
References
+Special Thanks
Register Set
============
The current architectures have the following registers.
-16 General propose registers, 32 bit on s/390 64 bit on zSeries, r0-r15 or gpr0-gpr15 used for arithmetic & addressing.
+16 General propose registers, 32 bit on s/390 64 bit on z/Architecture, r0-r15 or gpr0-gpr15 used for arithmetic & addressing.
-16 Control registers, 32 bit on s/390 64 bit on zSeries, ( cr0-cr15 kernel usage only ) used for memory managment,
+16 Control registers, 32 bit on s/390 64 bit on z/Architecture, ( cr0-cr15 kernel usage only ) used for memory managment,
interrupt control,debugging control etc.
-16 Access registers ( ar0-ar15 ) 32 bit on s/390 & zSeries
+16 Access registers ( ar0-ar15 ) 32 bit on s/390 & z/Architecture
not used by normal programs but potentially could
be used as temporary storage. Their main purpose is their 1 to 1
association with general purpose registers and are used in
the kernel for copying data between kernel & user address spaces.
-Access register 0 ( & access register 1 on z/Series ( needs 64 bit pointer ) )
-is currently used by the pthread library as a pointer to
+Access register 0 ( & access register 1 on z/Architecture ( needs 64 bit
+pointer ) ) is currently used by the pthread library as a pointer to
the current running threads private area.
16 64 bit floating point registers (fp0-fp15 ) IEEE & HFP floating
The PSW is the most important register on the machine it
-is 64 bit on s/390 & 128 bit on zSeries & serves the roles of
+is 64 bit on s/390 & 128 bit on z/Architecture & serves the roles of
a program counter (pc), condition code register,memory space designator.
In IBM standard notation I am counting bit 0 as the MSB.
It has several advantages over a normal program counter
currently running at.
Bit Value
-s/390 zSeries
+s/390 z/Architecture
0 0 Reserved ( must be 0 ) otherwise specification exception occurs.
1 1 Program Event Recording 1 PER enabled,
8-11 8-11 PSW Key used for complex memory protection mechanism not used under linux
-12 12 1 on s/390 0 on zSeries
+12 12 1 on s/390 0 on z/Architecture
13 13 Machine Check Mask 1=enable machine check interrupts
compatible.
-Prefix Page
------------
+Prefix Page(s)
+--------------
This per cpu memory area is too intimately tied to the processor not to mention.
-It exists between the real addresses 0-4096 on the processor & is exchanged
-with a page in absolute storage by the set prefix instruction in linux'es startup.
-This page different on each processor.
-Bytes 0-512 ( 200 hex ) are used by the processor itself for holding such
-information as exception indications & entry points for exceptions.
-Bytes after 0xc00 hex are used by linux for per processor globals.
+It exists between the real addresses 0-4096 on s/390 & 0-8192 z/Architecture & is exchanged
+with a 1 page on s/390 or 2 pages on z/Architecture in absolute storage by the set
+prefix instruction in linux'es startup.
+This page is mapped to a different prefix for each processor in an SMP configuration
+( assuming the os designer is sane of course :-) ).
+Bytes 0-512 ( 200 hex ) on s/390 & 0-512,4096-4544,4604-5119 currently on z/Architecture
+are used by the processor itself for holding such information as exception indications &
+entry points for exceptions.
+Bytes after 0xc00 hex are used by linux for per processor globals on s/390 & z/Architecture
+( there is a gap on z/Architecure too currently between 0xc00 & 1000 which linux uses ).
The closest thing to this on traditional architectures is the interrupt
vector table. This is a good thing & does simplify some of the kernel coding
however it means that we now cannot catch stray NULL pointers in the
If using the virtual machine ( VM ) as a debugger it is quite difficult to
know which user process is running as the address space you are looking at
could be from any process in the run queue.
-Thankfully you normally get lucky as address spaces don't overlap that &
-you can recognise the code at by cross referencing with a dump made by objdump
-( more about that later ).
The limitation of Intels addressing technique is that the linux
kernel uses a very simple real address to virtual addressing technique
of our 32 bit addresses,however, we use entirely separate address
spaces for the user & kernel.
-This means we can support 2GB of non Extended RAM, & more
-with the Extended memory managment swap device & 64 Bit
-when it comes along.
+This means we can support 2GB of non Extended RAM on s/390, & more
+with the Extended memory managment swap device &
+currently 4TB of physical memory currently on z/Architecture.
-Address Spaces on Linux for S390
-================================
+Address Spaces on Linux for s/390 & z/Architecture
+==================================================
Our addressing scheme is as follows
-Himem 0x7fffffff 2GB on s/390 ***************** ****************
-2^64 bytes on zSeries * User Stack * * *
- ***************** * *
- * Shared Libs * * *
- ***************** * *
- * * * Kernel *
- * User Program * * *
- * Data BSS * * *
- * Text * * *
- * Sections * * *
-0x00000000 ***************** ****************
+Himem 0x7fffffff 2GB on s/390 ***************** ****************
+currently 0x3ffffffffff (2^42)-1 * User Stack * * *
+on z/Architecture. ***************** * *
+ * Shared Libs * * *
+ ***************** * *
+ * * * Kernel *
+ * User Program * * *
+ * Data BSS * * *
+ * Text * * *
+ * Sections * * *
+0x00000000 ***************** ****************
This also means that we need to look at the PSW problem state bit
or the addressing mode to decide whether we are looking at
-user or kernel space.
+user or kernel space.
+
+Virtual Addresses on s/390 & z/Architecture
+===========================================
+
+A virtual address on s/390 is made up of 3 parts
+The SX ( segment index, roughly corresponding to the PGD & PMD in linux terminology )
+being bits 1-11.
+The PX ( page index, corresponding to the page table entry (pte) in linux terminology )
+being bits 12-19.
+The remaining bits BX (the byte index are the offset in the page )
+i.e. bits 20 to 31.
+
+On z/Architecture in linux we currently make up an address from 4 parts.
+The region index bits (RX) 0-32 we currently use bits 22-32
+The segment index (SX) being bits 33-43
+The page index (PX) being bits 44-51
+The byte index (BX) being bits 52-63
+
+Notes:
+1) s/390 has no PMD so the PMD is really the PGD also.
+A lot of this stuff is defined in pgtable.h.
+
+2) Also seeing as s/390's page indexes are only 1k in size
+(bits 12-19 x 4 bytes per pte ) we use 1 ( page 4k )
+to make the best use of memory by updating 4 segment indices
+entries each time we mess with a PMD & use offsets
+0,1024,2048 & 3072 in this page as for our segment indexes.
+On z/Architecture our page indexes are now 2k in size
+( bits 12-19 x 8 bytes per pte ) we do a similar trick
+but only mess with 2 segment indices each time we mess with
+a PMD.
+
+3) As z/Architecture supports upto a massive 5-level page table lookup we
+can only use 3 currently on Linux ( as this is all the generic kernel
+currently supports ) however this may change in future
+this allows us to access ( according to my sums )
+4TB of virtual storage per process i.e.
+4096*512(PTES)*1024(PMDS)*2048(PGD) = 4398046511104 bytes,
+enough for another 2 or 3 of years I think :-).
+to do this we use a region-third-table designation type in
+our address space control registers.
+
-The Linux for s/390 & zSeries Kernel Task Structure
-===================================================
+The Linux for s/390 & z/Architecture Kernel Task Structure
+==========================================================
Each process/thread under Linux for S390 has its own kernel task_struct
defined in linux/include/linux/sched.h
The S390 on initialisation & resuming of a process on a cpu sets
* ( 4K ) *
8K aligned ************************
- zSeries
+ z/Architecture
************************
* 2 page kernel stack *
* ( 8K ) *
What this means is that we don't need to dedicate any register or global variable
to point to the current running process & can retrieve it with the following
-very simple construct for s/390 & one very similar for zSeries.
+very simple construct for s/390 & one very similar for z/Architecture.
static inline struct task_struct * get_current(void)
{
-Register Usage & Stackframes on Linux for s/390 & zSeries
-=========================================================
+Register Usage & Stackframes on Linux for s/390 & z/Architecture
+=================================================================
Overview:
---------
This is the code that gcc produces at the top & the bottom of
limited knowledge of one assembly language.
It should be noted that there are some differences between the
-s/390 & zSeries stack layouts as the zSeries stack layout didn't have
+s/390 & z/Architecture stack layouts as the z/Architecture stack layout didn't have
to maintain compatibility with older linkage formats.
Glossary:
The code generated by the compiler to return to the caller.
frameless-function
-A frameless function in Linux for s390 & zSeries is one which doesn't need
-more than the register save area ( 96 bytes on s/390, 160 on zSeries )
+A frameless function in Linux for s390 & z/Architecture is one which doesn't
+need more than the register save area ( 96 bytes on s/390, 160 on z/Architecture )
given to it by the caller.
A frameless function never:
1) Sets up a back chain.
}
-s/390 & zSeries Register usage
-==============================
+s/390 & z/Architecture Register usage
+=====================================
r0 used by syscalls/assembly call-clobbered
r1 used by syscalls/assembly call-clobbered
r2 argument 0 / return value 0 call-clobbered
f0 argument 0 / return value ( float/double ) call-clobbered
f2 argument 1 call-clobbered
-f4 zSeries argument 2 saved
-f6 zSeries argument 3 saved
+f4 z/Architecture argument 2 saved
+f6 z/Architecture argument 3 saved
The remaining floating points
f1,f3,f5 f7-f15 are call-clobbered.
area if crossing this boundary.
6) Floating point parameters are mixed with outgoing args
on the outgoing args area in the order the are passed in as parameters.
-7) Floating point arguments 2 & 3 are saved in the outgoing args area for zSeries
+7) Floating point arguments 2 & 3 are saved in the outgoing args area for
+z/Architecture
Stack Frame Layout
------------------
-s/390 zSeries
+s/390 z/Architecture
0 0 back chain ( a 0 here signifies end of back chain )
4 8 eos ( end of stack, not used on Linux for S390 used in other linkage formats )
8 16 glue used in other s/390 linkage formats for saved routine descriptors etc.
stack backchain in optimised code as this also causes pipeline stalls, you
have been warned.
-64 bit zSeries code disassembly
--------------------------------
+64 bit z/Architecture code disassembly
+--------------------------------------
If you understand the stuff above you'll understand the stuff
below too so I'll avoid repeating myself & just say that
-Compiling programs for debugging on Linux for s/390 & zSeries
-=============================================================
--gdwarf2 now works & normal -g debugging works much better now
+Compiling programs for debugging on Linux for s/390 & z/Architecture
+====================================================================
+-gdwarf-2 now works it should be considered the default debugging
+format for s/390 & z/Architecture as it is more reliable for debugging
+shared libraries, normal -g debugging works much better now
Thanks to the IBM java compiler developers bug reports.
-This is typically done adding/appending the flags -g to the
+This is typically done adding/appending the flags -g or -gdwarf-2 to the
CFLAGS & LDFLAGS variables Makefile of the program concerned.
If using gdb & you would like accurate displays of registers &
--------------------------------
D G will display all the gprs
Adding a extra G to all the commands is neccessary to access the full 64 bit
-content in VM on zSeries obviously this isn't required for access registers
+content in VM on z/Architecture obviously this isn't required for access registers
as these are still 32 bit.
e.g. DGG instead of DG
D X will display all the control registers
tr i pswa <address of main>
Start the program, if VM drops to CP on what looks like the entry
point of the main function this is most likely the process you wish to debug.
-Now do a D X13 or D XG13 on zSeries.
+Now do a D X13 or D XG13 on z/Architecture.
On 31 bit the STD is bits 1-19 ( the STO segment table origin )
& 25-31 ( the STL segment table length ) of CR13.
now type
TR I R STD 8F32E1FF 0.7fffffff
Another very useful variation is
TR STORE INTO STD <CR13's value> <address range>
-
+for finding out when a particular variable changes.
+
+An alternative way of finding the STD of a currently running process
+is to do the following, ( this method is more complex but
+could be quite convient if you aren't updating the kernel much &
+so your kernel structures will stay constant for a reasonable period of
+time ).
+
+grep task /proc/<pid>/status
+from this you should see something like
+task: 0f160000 ksp: 0f161de8 pt_regs: 0f161f68
+This now gives you a pointer to the task structure.
+Now make CC:="s390-gcc -g" kernel/sched.s
+To get the task_struct stabinfo.
+( task_struct is defined in include/linux/sched.h ).
+Now we want to look at
+task->active_mm->pgd
+on my machine the active_mm in the task structure stab is
+active_mm:(4,12),672,32
+its offset is 672/8=84=0x54
+the pgd member in the mm_struct stab is
+pgd:(4,6)=*(29,5),96,32
+so its offset is 96/8=12=0xc
+
+so we'll
+hexdump -s 0xf160054 /dev/mem | more
+i.e. task_struct+active_mm offset
+to look at the active_mm member
+f160054 0fee cc60 0019 e334 0000 0000 0000 0011
+hexdump -s 0x0feecc6c /dev/mem | more
+i.e. active_mm+pgd offset
+feecc6c 0f2c 0000 0000 0001 0000 0001 0000 0010
+we get something like
+now do
+TR I R STD <pgd|0x7f> 0.7fffffff
+i.e. the 0x7f is added because the pgd only
+gives the page table origin & we need to set the low bits
+to the maximum possible segment table length.
+TR I R STD 0f2c007f 0.7fffffff
+on z/Architecture you'll probably need to do
+TR I R STD <pgd|0x7> 0.ffffffffffffffff
+to set the TableType to 0x1 & the Table length to 3.
Help for displaying ascii textstrings
-------------------------------------
-As textstrings are cannot be displayed in ASCII under the VM debugger ( I love EBDIC too ) I have
-written this little program which will convert a command line of hex digits to ascii text
-which can be compiled under linux & you can copy the hex digits from your x3270 terminal to
-your xterm if you are debugging from a linuxbox.
+On the very latest VM Nucleus'es VM can now display ascii
+( thanks Neale for the hint ) by doing
+D TX<lowaddr>.<len>
+e.g.
+D TX0.100
+
+Alternatively
+=============
+Under older VM debuggers ( I love EBDIC too ) you can use this little program I wrote which
+will convert a command line of hex digits to ascii text which can be compiled under linux &
+you can copy the hex digits from your x3270 terminal to your xterm if you are debugging
+from a linuxbox.
This is quite useful when looking at a parameter passed in as a text string
under VM ( unless you are good at decoding ASCII in your head ).
-s/390 & zSeries IO Overview
-===========================
+s/390 & z/Architecture IO Overview
+==================================
I am not going to give a course in 390 IO architecture as this would take me quite a
while & I'm no expert. Instead I'll give a 390 IO architecture summary for Dummies if you have
between 2 machines. We use 2 cables under linux to do a bi-directional serial link.
-Debugging IO on s/390 & zSeries under VM
-=========================================
+Debugging IO on s/390 & z/Architecture under VM
+===============================================
Now we are ready to go on with IO tracing commands under VM
A few self explanatory queries:
Q OSA
Q CTC
-Q DISK
+Q DISK ( This command is CMS specific )
Q DASD
This is done using a the same trick described for VM
p/x (*($sp+56))&0x7fffffff get the first backchain.
-For zSeries do
-p/x *($sp+112) i.e. replace 56 with 112 & ignore the &0x7fffffff
-in the macros below.
+For z/Architecture
+Replace 56 with 112 & ignore the &0x7fffffff
+in the macros below & do nasty casts to longs like the following
+as gdb unfortunately deals with printed arguments as ints which
+messes up everything.
+i.e. here is a 3rd backchain dereference
+p/x *(long *)(***(long ***)$sp+112)
+
this outputs
$5 = 0x528f18
Some driver debugging techniques
================================
+debug feature
+-------------
+Some of our drivers now support a "debug feature" in
+/proc/s390dbf see s390dbf.txt in the linux/Documentation directory
+for more info.
+e.g.
+to switch on the lcs "debug feature"
+echo 5 > /proc/s390dbf/lcs/level
+& then after the error occured.
+cat /proc/s390dbf/lcs/sprintf >/logfile
+the logfile now contains some information which may help
+tech support resolve a problem in the field.
+
+
+
high level debugging network drivers
------------------------------------
ifconfig is a quite useful command
& type ? in the debugger for help.
-Debugging Drivers
-=================
-Some of our drivers now support a debug logging feature in
-/proc/s390dbf see s390dbf.txt in the linux/Documentation directory
-for more info.
-e.g.
-to switch on lcs debugging
-echo 5 > /proc/s390dbf/lcs/level
-& then after the error occured.
-cat /proc/s390dbf/lcs/sprintf >/logfile
-the logfile now contains some information which may help
-tech support resolve a problem in the field.
-
-If you have VM look at the chapter Debugging IO on S390 under VM.
-
-
-
-
-Tools soon to be available
-==========================
-
-Dumptool & Lcrash
------------------
-Michael Holzheu & others here at IBM have a fairly mature port of
-SGI's lcrash tool which allows one to look at kernel structures in a
-running kernel.
-
-It also complements a tool called dumptool which dumps all the kernels
-memory pages & registers to either a tape or a disk.
-This can be used by tech support or an ambitous end user do
-post mortem debugging of a machine like gdb core dumps.
-
-Going into how to use this tool in detail will be explained
-in other documentation supplied by IBM & the lcrash homepage
-http://oss.sgi.com/projects/lkcd/.
-
-How they work
--------------
-Lcrash is a perfectly normal application
-however it requires an additional file.
-It is built using a patch to the kernel source base.
-
-
-Debugging a live system it uses /dev/mem
-alternatively for post mortem debugging it uses the data
-collected by dumptool.
-
-
-Ltrace
-------
-We also have a tool called ltrace in our CVS repository
-no plans on a delivery date yet.
-ltrace is a superset of strace in that it also allows
-tracing of shared libraries calls as well as system calls,
-man ltrace for more info.
SysRq
=====
-This is now supported by linux for s/390 & zSeries.
+This is now supported by linux for s/390 & z/Architecture.
To enable it do compile the kernel with
Kernel Hacking -> Magic SysRq Key Enabled
echo "1" > /proc/sys/kernel/sysrq.
Various info & man pages.
CMS Help on tracing commands.
Linux for s/390 Elf Application Binary Interface
-Linux for zSeries Elf Application Binary Interface ( Both Highly Recommended )
+Linux for z/Series Elf Application Binary Interface ( Both Highly Recommended )
z/Architecture Principles of Operation SA22-7832-00
Enterprise Systems Architecture/390 Reference Summary SA22-7209-01 & the
Enterprise Systems Architecture/390 Principles of Operation SA22-7201-05
-
-
-
-
-
+Special Thanks
+==============
+Special thanks to Neale Ferguson who maintains a much
+prettier HTML version of this page at
+http://penguinvm.princeton.edu/notes.html#Debug390
- ensure the tape is at the beginning
mt -f /dev/ntibm0 rewind
-- set the blocksize of the character driver. The blocksizes 512, 1024
- and 2048 bytes are supported by ISO9660. 1024 is the default, u
- which will be used here.
- mt -f /dev/ntibm0 setblk 1024
+- set the blocksize of the character driver. The blocksize 2048 bytes
+ is commonly used on ISO9660 CD-Roms
+ mt -f /dev/ntibm0 setblk 2048
- write the filesystem to the character device driver
mkisofs -o /dev/ntibm0 somedir
mt -f /dev/ntibm0 rewind
- Now you can mount your new filesystem as a block device:
- mount -t iso9660 -o ro,block=1024 /dev/btibm0 /mnt
+ mount -t iso9660 -o ro,block=2048 /dev/btibm0 /mnt
TODO List
-- The backend code has to be enhanced to support error-recovery actions.
-
-- The seeking algorithm of the block device has to be improved to speed
- things up
+ - Driver has to be stabelized still
BUGS
-There are lots of weaknesses still in the code. This is why it is EXPERIMENTAL.
+This driver is considered BETA, which means some weaknesses may still
+be in it.
If an error occurs which cannot be handled by the code you will get a
sense-data dump.In that case please do the following:
.SH SYNOPSIS
The channel device layer is a layer to provide a consistent interface for
configuration & default machine check (devices appearing & disappearing )
-handling Linux for zSeries channel devices.
+handling on Linux for s/390 & z/Series channel devices.
-These include among others
+
+s/390 & z/Series channel devices include among others
.Bl -item
.It
lcs ( the most common ethernet/token ring/fddi standard on zSeries )
.It
-ctc/escon hi speed like serial link standard on zSeries.
+ctc/escon hi speed like serial link standard on s/390 & z/Series.
.It
claw used to talk to cisco routers.
.It
qeth gigabit ethernet.
-.El
-
+.It
+osad used by osa/sf to configure osa devices, e.g. to share a osa card between 2 or more vm guests. osad is just added to the channel device layer for completeness, there are no plans at the current time to write a driver to exploit this under linux.
+.It
These devices use two channels one read & one write for configuration &
-or communication.
-The motivation behind producing this layer was that there is a lot of
-duplicate code among the drivers for configuration so the lcs & ctc drivers
-tended to fight over 3088/08's & 3088/1F's which could be either 2216/3172
-lcs compatible devices or escons/ctc's & to resolve this fight
-both device drivers had to be reconfigured rather than doing the
-configuration in a single place.
+or communication ( & a third channel the data channel in the case of gigabit ethernet ).
+The motivation behind developing this layer was that there was a lot of
+duplicate code among the channel device drivers for configuration.
+Also the lcs & ctc drivers tended to fight over 3088/08's & 3088/1F's which could
+be either 2216/3172 channel attached lcs compatible devices or escon/ctc pipes
+between guests & to resolve this fight both device drivers had to be configured
+separately, this is now simplified by doing the configuration in a single place
+( the channel device layer ).
+
+This layer isn't invasive & it is quite okay to use channel drivers
+which don't use the channel device layer in conjunction with
+drivers which do.
+.El
.SH DESCRIPTION
The current setup can be read from /proc/chandev
.Bl -enum
.It
Piping to /proc/chandev.
+e.g. echo reprobe >/proc/chandev
+will cause uninitialised channel devices to be probed.
.It
-Entering them into /etc/chandev.conf comments are prefixed #.
+Entering them into /etc/chandev.conf comments are prefixed with #.
.It
Or from the boot command line using the 'chandev=' keyword
+e.g. chandev=noauto,0x0,0x480d;noauto,0x4810,0xffff
+will allow only devno's 0x480e & 0x480f to be autodetected.
.El
.Bl -item
.It
-Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. The script /bin/chandev will be called automatically on startup or a machine check of a device as follows.
-/bin/chandev <start starting_devnames> <machine_check (devnames pre_recovery_action_status) (post_recovery_action_status)>.
-The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script.
+Multiple options can be passed separated by semicolons but no spaces are allowed between parameters. To be consistent with other hotpluggable architectures the script pointed to /proc/sys/kernel/hotplug (normally /sbin/hotplug) will be called automatically on startup or a machine check of a device as follows.
+/sbin/hotplug chandev <start starting_devnames> <machine_check (devname last/pre_recovery_status) (current/post_recovery_status)>.
+The chandev layer doesn't open stdin stdout or stderr so it is advisable that you add the following lines to the start of your script, here is a sample script which starts devices as they become available.
.It
#!/bin/bash
.It
exec >/dev/console 2>&1 0>&1
+.It
+# Uncomment line below for debugging.
+.It
+# echo $*
+.It
+if [ "$1" = "chandev" ] && [ "$2" = "start" ]
+.It
+then
+.It
+ shift 2
+.It
+ while [ "$1" != "" ] && [ "$1" != "machine_check" ]
+.It
+ do
+.It
+ isup=`ifconfig $1 2>/dev/null | grep UP`
+.It
+ if [ "$isup" = "" ]
+.It
+ then
+.It
+ ifup $1
+.It
+ fi
+.It
+ shift
+.It
+ done
+.It
+fi
+.It
+.It
+e.g. if tr0 & ctc0 were starting up & eth0 & eth1 devices disappeared & eth2 got a revalidate machine check ( which is normally fully recoverable ) nearly simultainously the parameters would be.
+.It
+/sbin/hotplug chandev start tr0 ctc0 machine_check eth0 gone gone eth1 gone gone eth2 revalidate good
+.It
+This can be used for example to call /etc/rc.d/init.d/network start when a device appears & make the ipldelay kernel boot parameter obselete on native machines or recover from bad machine checks where the default machine check handling isn't adequete. The machine checks that can be presented as parameters are good not_operational no_path revalidate device_gone. Normally you wouldn't want to do anything like stop networking when a device disappears as this is hopefully temporary, I just added it to be complete. The chandev layer waits a few seconds for machine checks to settle before running /sbin/hotplug because several machine checks usually happen at once & the forked scripts would possibly race against each other to shutdown & start resources at the same time & behave rather stupidly.
.El
-e.g. if tr0 & ctc0 were starting up & eth0 & eth1 didn't recover from a gone machine check at the same instant the parameters would be.
-
-
-/bin/chandev start tr0 ctc0 machine_check eth0 gone gone eth1 gone gone
-This can be used for example to call /etc/rc.d/init.d/network start when a device appears & make the ipldelay kernel boot parameter obselete on native machines or recover from bad machine checks where the default machine check handling isn't adequete. The machine checks that can be presented as parameters are good not_operational no_path revalidate device_gone.
-
valid chandev arguments are <> indicate optional parameters, | indicate a choice.
.B glossary
.It
.Bl -item
-
.It
-.B (ctc|escon|lcs|osad|qeth|claw)<devif_num>,
-read_devno, write_devno, <port_no/protocol_no>, <checksum_received_ip_pkts>, <use_hw_stats>
+.B (ctc|escon|lcs|osad|qeth)<devif_num>,
+read_devno,write_devno,<data_devno,memory_usage_in_k,port_no/protocol_no,checksum_received_ip_pkts,use_hw_stats>
+.It
+devif_num of -1 indicates you don't care what device interface number is chosen, omitting it indicates this is a range of devices for which you want to force to be detected as a particular type.
+The data_devno field is only valid for qeth devices when not forcing a range of devices.
+all parameters after & including memory_usage_in_k can be set optionally if not set they
+go to default values. memory_usage_in_k ( 0 the default ) means let the driver choose,checksum_received_ip_pkts & use_hw_stats are set to false
+.It
+e.g. ctc0,0x7c00,0x7c01
.It
-e.g. ctc0,0x7c00,0x7c01,0,0,0
+Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( default 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter. This can be used for instance to force a device if it presents bad sense data to the IO layer & thus autodetection fails.
.It
-Tells the channel layer to force ctc0 if detected to use cuu's 7c00 & 7c01 port,port_no is the relative adapter no on lcs, on ctc/escon this field is the ctc/escon protocol number ( normally 0 ), don't do checksumming on received ip packets & as ctc doesn't have hardware stats so it ignores this parameter.
+qeth,0x7c00,0x7d00,-1,4096
+All devices between 0x7c00 & 7d00 should be detected as gigabit ethernet, let the driver use 4096k for each instance, don't care what port relative adapter number is chosen, don't checksum received ip packets & use hw stats .
+.It
+qeth1,0x7c00,0x7c01,0x7c02
+.It
+devif_num=1,read=0x7c00,write=0x7c01,data=0x7c02, don't checksum received ip packets & use hw stats.
.El
.It
-
+.Bl -item
+.B claw devif_num,
+read_devno,write_devno<,memory_usage_in_k,checksum_received_ip_pkts,use_hw_stats,>
+host_name,adapter_name,api_type
+.It
+CLAW currently is not autodetected as the host_name,adapter_name & api_type
+need to be set up, possibly some convention for setting these automatically
+may be contrived in the future & auto detection may be done but currently there isn't any.
+The names host_name,adapter_name,api_type may be 8 upto characters in length,
+host_name is the name of this host, adapter_name is the name of the adjacent host,
+api_type may be name 1 to 8 chars in length API & TCPIP are common values.
+The remainder of the parameters are the same as the description for other ctc escon etc.
+.It
+A typical setup may be
+.It
+claw0,0xe00,0xe01,linuxa,rs6k,TCPIP
+.It
+.El
.Bl -item
.It
.B add_parms
-,chan_type,<string>
+,chan_type,<lo_devno,hi_devno,>string
.It
chan_type bitfield
.It
.It
This is for device driver specific options passed as a string to the driver
not dealt with by the channel device layer it can't contain spaces.
+low_devno & hi_devno are optional parameters to specify a range.
+The channel device layer doesn't concatenate strings if device ranges overlap,
+before passing to a device driver.
.El
.It
.Bl -item
.It
.B del_parms
-<,chan_type,exact_match>
+<,chan_type,exact_match,lo_devno>
.It
This deletes some or all device driver specific options not specifying chan_type causes it to delete all the strings. exact_match=1 specifies only to remove driver parms where chan_type is exactly equal exact_match=0 specifies to remove parms where any bit matches chan_type.
+lo_devno is an optional parameter the delete to only happen if lo_devno matches a lo_devno in one of the ranges.
.El
.It
.Bl -item
.It
.B noauto
-,<lo_devno>-<hi_devno>
+<,lo_devno,hi_devno>
.It
Don't probe a range of device numbers for channel devices.
.El
.It
e.g. a token ring read channel 0x7c00 would have an interface called tr0x7c00 this avoids name collisions on devices.
.El
-.El
.B power user options
.It
.B add_model
,chan_type, cu_type, cu_model, dev_type, dev_model, max_port_no, automatic_machine_check_handling
-
.It
Tells the channel layer to probe for the device described, -1 for any of the parameters other than chan_type & automatic_machine_check_handling is a wildcard.
Set max_port_no to 0 for non lcs devices.
chan_type bitfield
.It
ctc=0x1, escon=0x2, lcs=0x4, osad=0x8, qeth=0x10, claw=0x20
-
-.It
+.El
.Bl -item
.It
.B del_model
,cu_type,cu_model,dev_type,dev_model
.It
--1 for any parameter is a wildcard,
+-1 for any parameter is a wildcard.
.El
+
+.Bl -item
.It
.B del_all_models
+.It
+should be obvious.
+.El
+.Bl -item
+.It
+.B non_cautious_auto_detect
.It
+Tells the channel device layer to attempt to auto detect devices even if their type/model pairs don't unambigously identify the device, e.g. 3088/1F's can either be escon CTC's or channel attached 3172 lcs compatible devices. If the wrong device driver attempts to probe these channels there may be big delays on startup or even a kernel lockup, use this option with caution.
+.El
+.Bl -item
+.It
+.B cautious_auto_detect
+.It
+ See non_cautious_auto_detect this is the default.
+.El
.Bl -item
.It
.B auto_msck
.It
.Bl -item
.It
+.B unregister_probe <probefunc_addr>
+.It
+unregisters a single probe function or all of them.
+.El
+.Bl -item
+.It
+.B unregister_probe_by_chan_type
+.It
+unregisters all probe functions which match the chan_type bitfield exactly,
+useful if you want a configuration to survice a kernel upgrade.
+.El
+.Bl -item
+.It
.B read_conf
.It
Read instructions from /etc/chandev.conf.
.It
Don't automatically read /etc/chandev.conf on boot.
.El
+.Bl -item
+.It
+.B persist
+,chan_type
+.It
+Force drivers modules to stay loaded even if no device is found,
+this is useful for debugging & one wishes to examine debug entries in
+/proc/s390dbf/ to find out why a module failed to load.
+.El
+
.It
e.g the following sequence of commands should be roughly equivalent
to rebooting for channel devices.
.B /proc/chandev
.It
cat /proc/chandev to see current options chosen.
-.Iy
-echo <command> >proc/chandev to enter a new command
+.It
+echo <command> >/proc/chandev to enter a new command
.It
.B /etc/chandev.conf
.It
.B 'chandev='
keyword.
.It
-.B /bin/chandev
+.B /sbin/hotplug
.It
A user script/executable which is run when devices come online "appear"
or go offline "disappear".
VERSION = 2
PATCHLEVEL = 4
-SUBLEVEL = 7
-EXTRAVERSION =
+SUBLEVEL = 8
+EXTRAVERSION =-pre1
KERNELRELEASE=$(VERSION).$(PATCHLEVEL).$(SUBLEVEL)$(EXTRAVERSION)
mov $30,$17
br $1,do_switch_stack
mov $30,$18
+ subq $30,16,$30
+ stq $26,0($30)
jsr $26,do_sigsuspend
- lda $30,SWITCH_STACK_SIZE($30)
- br ret_from_sys_call
+ ldq $26,0($30)
+ lda $30,SWITCH_STACK_SIZE+16($30)
+ ret $31,($26),1
.end sys_sigsuspend
.align 3
mov $30,$18
br $1,do_switch_stack
mov $30,$19
+ subq $30,16,$30
+ stq $26,0($30)
jsr $26,do_rt_sigsuspend
- lda $30,SWITCH_STACK_SIZE($30)
- br ret_from_sys_call
+ ldq $26,0($30)
+ lda $30,SWITCH_STACK_SIZE+16($30)
+ ret $31,($26),1
.end sys_rt_sigsuspend
.data
-# $Id: Makefile,v 1.19 2001/06/11 12:06:40 bjornw Exp $
+# $Id: Makefile,v 1.20 2001/07/05 10:07:58 jonashg Exp $
# cris/Makefile
#
# This file is included by the global makefile so that you can add your own
# each others config options
SUBDIRS += arch/cris/boot/rescue
endif
-CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o arch/cris/drivers/drivers.o
+CORE_FILES += arch/cris/kernel/kernel.o arch/cris/mm/mm.o
+DRIVERS += arch/cris/drivers/drivers.o
LIBGCC = $(shell $(CC) $(CFLAGS) -print-file-name=libgcc.a)
LIBS := $(TOPDIR)/arch/cris/lib/lib.a $(LIBS) $(TOPDIR)/arch/cris/lib/lib.a $(LIBGCC)
_stext = . ;
*(.text)
*(.rodata)
- *(.rodata.*)
_etext = . ;
} > dram
.data :
int 'DRAM size (dec, in MB)' CONFIG_ETRAX_DRAM_SIZE 8
int 'Buswidth of flash in bytes' CONFIG_ETRAX_FLASH_BUSWIDTH 2
+bool 'Use flash mirroring (for cramfs)' CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS
+if [ "$CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS" = "y" ]; then
+ int ' Individual flash chip size (in MB)' CONFIG_ETRAX_FLASH_SIZE 2
+fi
choice 'Product LED port' \
"Port-PA-LEDs CONFIG_ETRAX_PA_LEDS \
int ' First red LED bit' CONFIG_ETRAX_LED1R 3
int ' Second green LED bit' CONFIG_ETRAX_LED2G 4
int ' Second red LED bit' CONFIG_ETRAX_LED2R 5
- int ' Third green LED bit' CONFIG_ETRAX_LED3R 2
- int ' Third red LED bit' CONFIG_ETRAX_LED3G 2
+ int ' Third green LED bit' CONFIG_ETRAX_LED3G 2
+ int ' Third red LED bit' CONFIG_ETRAX_LED3R 2
fi
if [ "$CONFIG_ETRAX_CSP0_LEDS" = "y" ]; then
source drivers/ieee1394/Config.in
-source drivers/message/i2o/Config.in
+source drivers/i2o/Config.in
if [ "$CONFIG_NET" = "y" ]; then
mainmenu_option next_comment
*(.fixup)
*(.text.__*)
*(.rodata)
- *(.rodata.*)
+ *(.rodata.__*)
}
. = ALIGN(4); /* Exception table */
___setup_start = .;
.setup.init : { *(.setup.init) }
___setup_end = .;
- ___initcall_start = .;
- .initcall.init : { *(.initcall.init) }
- ___initcall_end = .;
+ .initcall.init : {
+ ___initcall_start = .;
+ *(.initcall.init);
+ ___initcall_end = .;
+
+ /* We fill to the next page, so we can discard all init
+ pages without needing to consider what payload might be
+ appended to the kernel image. */
+ FILL (0);
+ . = ALIGN (8192);
+ }
__vmlinux_end = .; /* last address of the physical file */
- . = ALIGN(8192);
___init_end = .;
__data_end = . ; /* Move to _edata ? */
*! in the spin-lock.
*!
*! $Log: eeprom.c,v $
+*! Revision 1.8 2001/06/15 13:24:29 jonashg
+*! * Added verification of pointers from userspace in read and write.
+*! * Made busy counter volatile.
+*! * Added define for inital write delay.
+*! * Removed warnings by using loff_t instead of unsigned long.
+*!
+*! Revision 1.7 2001/06/14 15:26:54 jonashg
+*! Removed test because condition is always true.
+*!
+*! Revision 1.6 2001/06/14 15:18:20 jonashg
+*! Kb -> kB (makes quite a difference if you don't know if you have 2k or 16k).
+*!
*! Revision 1.5 2001/06/14 14:39:51 jonashg
*! Forgot to use name when registering the driver.
*!
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/delay.h>
+#include <asm/uaccess.h>
#include "i2c.h"
#define D(x)
#define EEPROM_MAJOR_NR 122 /* use a LOCAL/EXPERIMENTAL major for now */
#define EEPROM_MINOR_NR 0
+/* Empirical sane initial value of the delay, the value will be adapted to
+ * what the chip needs when using EEPROM_ADAPTIVE_TIMING.
+ */
+#define INITIAL_WRITEDELAY_US 4000
#define MAX_WRITEDELAY_US 10000 /* 10 ms according to spec for 2KB EEPROM */
/* This one defines how many times to try when eeprom fails. */
/* this one is to keep the read/write operations atomic */
wait_queue_head_t wait_q;
- int busy;
+ volatile int busy;
int retry_cnt_addr; /* Used to keep track of number of retries for
adaptive timing adjustments */
int retry_cnt_read;
static int eeprom_address(unsigned long addr);
static int read_from_eeprom(char * buf, int count);
-static int eeprom_write_buf(unsigned long addr, const char * buf, int count);
-static int eeprom_read_buf(unsigned long addr,
- char * buf, int count);
+static int eeprom_write_buf(loff_t addr, const char * buf, int count);
+static int eeprom_read_buf(loff_t addr, char * buf, int count);
static void eeprom_disable_write_protect(void);
/*
* Note: Most of this probing method was taken from the printserver (5470e)
- * codebase. It did not contain a way of finding the 16Kb chips
+ * codebase. It did not contain a way of finding the 16kB chips
* (M24128 or variants). The method used here might not work
* for all models. If you encounter problems the easiest way
* is probably to define your model within #ifdef's, and hard-
*/
eeprom.size = 0;
- eeprom.usec_delay_writecycles = 4000;/*MAX_WRITEDELAY_US / EEPROM_RETRIES;*/
+ eeprom.usec_delay_writecycles = INITIAL_WRITEDELAY_US;
eeprom.usec_delay_step = 128;
eeprom.adapt_state = 0;
unsigned char buf_2k_start[16];
/* Im not sure this will work... :) */
- /* assume 2Kb, if failure go for 16Kb */
+ /* assume 2kB, if failure go for 16kB */
/* Test with 16kB settings.. */
/* If it's a 2kB EEPROM and we address it outside it's range
* it will mirror the address space:
switch(eeprom.size)
{
case (EEPROM_2KB):
- printk("%s: " EETEXT " i2c compatible 2Kb eeprom.\n", eeprom_name);
+ printk("%s: " EETEXT " i2c compatible 2kB eeprom.\n", eeprom_name);
eeprom.sequential_write_pagesize = 16;
eeprom.select_cmd = 0xA0;
break;
case (EEPROM_8KB):
- printk("%s: " EETEXT " i2c compatible 8Kb eeprom.\n", eeprom_name);
+ printk("%s: " EETEXT " i2c compatible 8kB eeprom.\n", eeprom_name);
eeprom.sequential_write_pagesize = 16;
eeprom.select_cmd = 0x80;
break;
case (EEPROM_16KB):
- printk("%s: " EETEXT " i2c compatible 16Kb eeprom.\n", eeprom_name);
+ printk("%s: " EETEXT " i2c compatible 16kB eeprom.\n", eeprom_name);
eeprom.sequential_write_pagesize = 64;
eeprom.select_cmd = 0xA0;
break;
/* Reads data from eeprom. */
-static int eeprom_read_buf(unsigned long addr,
- char * buf, int count)
+static int eeprom_read_buf(loff_t addr, char * buf, int count)
{
struct file f;
/* Writes data to eeprom. */
-static int eeprom_write_buf(unsigned long addr, const char * buf, int count)
+static int eeprom_write_buf(loff_t addr, const char * buf, int count)
{
struct file f;
int i, written, restart=1;
unsigned long p;
+ if (verify_area(VERIFY_READ, buf, count))
+ {
+ return -EFAULT;
+ }
+
while(eeprom.busy)
{
interruptible_sleep_on(&eeprom.wait_q);
/* To High before */
if (eeprom.usec_delay_step > 1)
{
- if (eeprom.usec_delay_step > 0)
- {
- eeprom.usec_delay_step *= 2;
- eeprom.usec_delay_step--;
- }
+ eeprom.usec_delay_step *= 2;
+ eeprom.usec_delay_step--;
if (eeprom.usec_delay_writecycles > eeprom.usec_delay_step)
{
while( (read < count))
{
- buf[read++] = i2c_inbyte();
+ if (put_user(i2c_inbyte(), &buf[read++]))
+ {
+ i2c_stop();
+
+ return -EFAULT;
+ }
/*
* make sure we don't ack last byte or you will get very strange
- ;; $Id: e100lpslave.S,v 1.2 2001/06/11 12:50:01 olof Exp $
+ ;; $Id: e100lpslave.S,v 1.3 2001/06/21 16:55:26 olof Exp $
;;
;; Etrax100 slave network<->parport forwarder
;;
move.d r0, [R_PAR1_CONFIG]
- moveq IO_FIELD(R_PAR1_DELAY, setup, 1), r0 ; setup time of value * 160 + 20
+ moveq IO_FIELD(R_PAR1_DELAY, setup, 0), r0 ; setup time of value * 160 + 20 == 20 ns
move.d r0, [R_PAR1_DELAY]
;; we got four descriptors, that can be active at the same time:
-/* $Id: e100lpslavenet.c,v 1.2 2001/06/11 15:39:52 olof Exp $
+/* $Id: e100lpslavenet.c,v 1.4 2001/06/21 16:55:26 olof Exp $
*
* e100lpslavenet.c: A network driver for the ETRAX 100LX slave controller.
*
* The outline of this driver comes from skeleton.c.
*
* $Log: e100lpslavenet.c,v $
+ * Revision 1.4 2001/06/21 16:55:26 olof
+ * Minimized par port setup time to gain bandwidth
+ *
+ * Revision 1.3 2001/06/21 15:49:02 olof
+ * Removed setting of default MAC address
+ *
* Revision 1.2 2001/06/11 15:39:52 olof
* Clean up and sync with ethernet.c rev 1.16. Increased reset time of slave.
*
dev->get_stats = e100_get_stats;
dev->set_multicast_list = set_multicast_list;
dev->set_mac_address = e100_set_mac_address;
-
- /* set the default MAC address */
-
- e100_set_mac_address(dev, &default_mac);
/* Initialise the list of Etrax DMA-descriptors */
/* We want ECP forward mode since PAR1 is TX */
IO_STATE(R_PAR1_CONFIG, mode, ecp_fwd);
- /* Setup time of value * 160 + 20 ns == 180 ns below */
- *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 1);
+ /* Setup time of value * 160 + 20 ns == 20 ns below */
+ *R_PAR1_DELAY = IO_FIELD(R_PAR1_DELAY, setup, 0);
*R_PAR1_CTRL = 0;
TxDescList[1].ctrl = d_eol | d_int;
TxDescList[1].buf = virt_to_phys(code);
- /*TxDescList[1].buf = code;*/
TxDescList[1].next = 0;
/* setup the dma channel and start it */
-/* $Id: parport.c,v 1.5 2001/05/09 12:38:42 johana Exp $
+/* $Id: parport.c,v 1.7 2001/06/25 16:17:30 jonashg Exp $
*
* Elinux parallel port driver
* NOTE!
* Par0 in : DMA3
* Par1 out : DMA4
* Par1 in : DMA5
- * NOTE! par0 is hared with ser2 and par1 is shared with ser3 regarding
+ * NOTE! par0 is shared with ser2 and par1 is shared with ser3 regarding
* DMA and DMA irq
*/
volatile char *iclrintradr; /* adr to R_DMA_CHx_CLR_INTR, input */
volatile u32 *ifirstadr; /* adr to R_DMA_CHx_FIRST, input */
volatile char *icmdadr; /* adr to R_DMA_CHx_CMD, input */
- const volatile u8 *istatusadr; /* adr to R_DMA_CHx_STATUS, input */
- volatile u32 *ihwswadr; /* adr to R_DMA_CHx_HWSW, input */
/* Non DMA interrupt stuff */
unsigned long int_irq; /* R_VECT_MASK_RD */
/* ----- end of fields initialised in port_table[] below ----- */
- // struct etrax_dma_descr tr_descr;
- // unsigned char tr_buf[LP_BUFFER_SIZE];
- // const unsigned char *tr_buf_curr; /* current char sent */
- // const unsigned char *tr_buf_last; /* last char in buf */
-
- // int fifo_magic; /* fifo amount - bytes left in dma buffer */
- // unsigned char fifo_didmagic; /* a fifo eop has been forced */
- // volatile int tr_running; /* 1 if output is running */
-
struct parport *port;
/* Shadow registers */
R_DMA_CH3_CLR_INTR,
R_DMA_CH3_FIRST,
R_DMA_CH3_CMD,
- R_DMA_CH3_STATUS,
- R_DMA_CH3_HWSW,
/* Non DMA interrupt stuff */
IO_BITNR(R_VECT_MASK_RD, par0),
R_IRQ_MASK0_RD,
R_DMA_CH5_CLR_INTR,
R_DMA_CH5_FIRST,
R_DMA_CH5_CMD,
- R_DMA_CH5_STATUS,
- R_DMA_CH5_HWSW,
/* Non DMA interrupt stuff */
IO_BITNR(R_VECT_MASK_RD, par1),
R_IRQ_MASK1_RD,
/* ----------- Initialisation code --------------------------------- */
-static void
+static void __init
parport_etrax_show_parallel_version(void)
{
printk("ETRAX 100LX parallel port driver v1.0, (c) 2001 Axis Communications AB\n");
#define PAR1_USE_DMA 0
#endif
-static void
+static void __init
parport_etrax_init_registers(void)
{
struct etrax100par_struct *info;
int i;
- /* The different times below will be (value*160 + 20) ns, */
- /* i.e. 20ns-4.98us. E.g. if setup is set to 00110 (0x6), */
- /* the setup time will be (6*160+20) = 980ns. */
-
for (i = 0, info = port_table; i < 2; i++, info++) {
#ifndef CONFIG_ETRAX_PARALLEL_PORT0
if (i == 0)
-# $Id: Makefile,v 1.5 2001/05/15 05:10:00 hp Exp $
+# $Id: Makefile,v 1.7 2001/07/05 01:11:48 hp Exp $
#
# Makefile for the linux kernel.
#
#
# Note 2! The CFLAGS definitions are now in the main makefile...
+# These assembly files can't be assembld with -traditional, so we
+# need another build rule than the one in the toplevel Makefile.
.S.o:
- $(CC) $(AFLAGS) -traditional -c $< -o $*.o
+ $(CC) $(AFLAGS) -c $< -o $*.o
all: kernel.o head.o
obj-$(CONFIG_ETRAX_KGDB) += kgdb.o
+# This dependency isn't caught by mkdep. See entry.S.
entry.o: entryoffsets.s
entryoffsets.s: entryoffsets.c
-/* $Id: entry.S,v 1.27 2001/05/29 11:25:27 markusl Exp $
+/* $Id: entry.S,v 1.31 2001/07/25 16:07:42 bjornw Exp $
*
* linux/arch/cris/entry.S
*
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: entry.S,v $
+ * Revision 1.31 2001/07/25 16:07:42 bjornw
+ * softirq_active/mask -> softirq_pending only
+ *
+ * Revision 1.30 2001/07/05 01:03:32 hp
+ * - include asm/errno.h to get ENOSYS.
+ * - Use ENOSYS, not local constant LENOSYS; tweak comments.
+ * - Explain why .include, not #include is used.
+ * - Make oops-register-dump if watchdog bits and it's not expected.
+ * - Don't jsr, use jump _hard_reset_now, and skip spurious nop.
+ * - Use correct section attribute for section .rodata.
+ * - Adjust sys_ni_syscall fill number.
+ *
+ * Revision 1.29 2001/06/25 14:07:00 hp
+ * Fix review comment.
+ * * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
+ * magic numbers. Add comment that -traditional must not be used.
+ * * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
+ * Correct and update comment.
+ * * Makefile (.S.o): Don't use -traditional. Add comment why the
+ * toplevel rule can't be used (now that there's a reason).
+ *
+ * Revision 1.28 2001/06/21 02:00:40 hp
+ * * entry.S: Include asm/unistd.h.
+ * (_sys_call_table): Use section .rodata, not .data.
+ * (_kernel_thread): Move from...
+ * * process.c: ... here.
+ * * entryoffsets.c (VAL): Break out from...
+ * (OF): Use VAL.
+ * (LCLONE_VM): New asmified value from CLONE_VM.
+ *
* Revision 1.27 2001/05/29 11:25:27 markusl
* In case of "spurious_interrupt", do hard_reset instead of hanging system in a loop...
*
#include <linux/config.h>
#include <linux/linkage.h>
#include <linux/sys.h>
+#include <asm/unistd.h>
#include <asm/sv_addr_ag.h>
+#include <asm/errno.h>
;; functions exported from this file
.globl _sys_call_table
- ;; syscall error codes
-
-LENOSYS = 38
-
- ;; Get offsets into various structs.
+ ;; Get values and offsets into various structs. The file isn't
+ ;; suitable for consumption by the preprocessor, so don't use
+ ;; #include.
.include "entryoffsets.s"
;; process bits for ptrace. FIXME: Should be in a header file.
push r10 ; push orig_r10
clear.d [sp=sp-4] ; frametype == 0, normal stackframe
- movs.w -LENOSYS,r0
+ movs.w -ENOSYS,r0
move.d r0,[sp+LR10] ; put the default return value in r10 in the frame
;; check if this process is syscall-traced
;; check if any bottom halves need service
- move.d _irq_stat,r10
- move.d [r10+],r0 ; softirq_active
- and.d [r10],r0 ; softirq_mask
+ test.d [_irq_stat] ; softirq_pending
bne handle_softirq
nop
tracesys:
;; this first invocation of syscall_trace _requires_ that
- ;; LR10 in the frame contains -LENOSYS (as is set in the beginning
- ;; of system_call
+ ;; LR10 in the frame contains -ENOSYS (as is set in the beginning
+ ;; of system_call).
jsr _syscall_trace
;; check for sanity in the requested syscall number
move.d [sp+LR9], r9
- movs.w -LENOSYS, r10
+ movs.w -ENOSYS, r10
cmpu.w NR_syscalls,r9
bcc 1f
lslq 2,r9 ; multiply by 4, in the delay slot
;; restore r10, r11, r12, r13, mof and srp into the needed registers
- move.d [sp+LORIG_R10], r10 ; LR10 is already filled with -LENOSYS
+ move.d [sp+LORIG_R10], r10 ; LR10 is already filled with -ENOSYS.
move.d [sp+LR11], r11
move.d [sp+LR12], r12
move.d [sp+LR13], r13
#endif
_IRQ1_interrupt:
-_spurious_interrupt:
+
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+;; If we receive a watchdog interrupt while it is not expected, then set
+;; up a canonical frame and dump register contents before dying.
+
+ ;; this prologue MUST match the one in irq.h and the struct in ptregs.h!!!
+ move brp,[sp=sp-16] ; instruction pointer and room for a fake SBFS frame
+ push srp
+ push dccr
+ push mof
di
- jsr _hard_reset_now
+ subq 14*4,sp
+ movem r13,[sp]
+ push r10 ; push orig_r10
+ clear.d [sp=sp-4] ; frametype == 0, normal frame
+
+;; We don't check that we actually were bit by the watchdog as opposed to
+;; an external NMI, since there is currently no handler for external NMI.
+
+;; We'll see this in ksymoops dumps.
+Watchdog_bite:
+
+;; We need to extend the 3.3ms after the NMI at watchdog bite, so we have
+;; time for an oops-dump over a 115k2 serial wire. Another 100ms should do.
+
+;; Change the watchdog key to an arbitrary 3-bit value and restart the
+;; watchdog.
+#define WD_INIT 2
+ moveq IO_FIELD (R_WATCHDOG, key, WD_INIT), r10
+ move.d R_WATCHDOG, r11
+
+ move.d r10,[r11]
+ moveq IO_FIELD (R_WATCHDOG, key, \
+ IO_EXTRACT (R_WATCHDOG, key, \
+ IO_MASK (R_WATCHDOG, key)) \
+ ^ WD_INIT) \
+ | IO_STATE (R_WATCHDOG, enable, start),r10
+ move.d r10,[r11]
+
+;; Note that we don't do "setf m" here (or after two necessary NOPs),
+;; since *not* doing that saves us from re-entrancy checks. We don't want
+;; to get here again due to possible subsequent NMIs; we want the watchdog
+;; to reset us.
+
+ move.d watchdogmsg,r10
+ jsr _printk
+
+ move.d sp,r10
+ jsr _show_registers
+
+;; This nop is here so we see the "Watchdog_bite" label in ksymoops dumps
+;; rather than "_spurious_interrupt".
nop
+;; At this point we drop down into _spurious_interrupt, which will do a
+;; hard reset.
+
+ .section .rodata,"a"
+watchdogmsg:
+ .ascii "Oops: bitten by watchdog\n\0"
+ .previous
+
+#endif /* CONFIG_ETRAX_WATCHDOG and not CONFIG_SVINTO_SIM */
+
+_spurious_interrupt:
+ di
+ jump _hard_reset_now
;; this handles the case when multiple interrupts arrive at the same time
;; we jump to the first set interrupt bit in a priority fashion
_hw_bp_trig_ptr:
.dword _hw_bp_trigs
-/* Because we compile this file with -traditional, we need to redefine
- token-concatenation to the traditional trick, using an empty comment.
- Normally (in other files, with ISO C as in gcc default) this is done
- with the ## preprocessor operator. */
+/*
+ * This is the mechanism for creating a new kernel thread.
+ *
+ * NOTE! Only a kernel-only process (i.e. the swapper or direct descendants
+ * who haven't done an "execve()") should use this: it will work within
+ * a system call from a "real" process, but the process memory space will
+ * not be free'd until both the parent and the child have exited.
+ *
+ * This *can* be done in C with an single-asm-wrapped-in-a-function, but you
+ * get more or less gross code. The safer you make the asm-constraints,
+ * the grosser the code, at least with the gcc version in cris-dist-1.13.
+ */
+
+/* int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) */
+/* r10 r11 r12 */
+
+ .text
+ .global _kernel_thread
+_kernel_thread:
+
+ /* Save ARG for later. */
+ move.d r11,r13
+
+ /* r11 is argument 2 to clone, the flags */
+ move.d r12,r11
+ or.w LCLONE_VM,r11
+
+ /* Save FN for later. */
+ move.d r10,r12
+
+ /* r9 contains syscall number, to sys_clone */
+ movu.w __NR_clone,r9
+
+ /* r10 is argument 1 to clone */
+ clear.d r10
+
+ /* call sys_clone, this will fork */
+ break 13
+
+ /* parent or child? child returns 0 here. */
+ test.d r10
+
+ /* jump if parent */
+ bne 1f
+ nop /* delay slot */
+
+ /* set argument to function to call */
+ move.d r13,r10
+
+ /* call specified function */
+ jsr r12
+ /* If we ever return from the function, something bad has happened. */
+
+ /* r9 is sys_exit syscall number */
+ movu.w __NR_exit,r9
+
+ /* Give a really bad exit-value */
+ moveq -1,r10
+
+ /* call sys_exit, killing the child */
+ break 13
+1:
+ ret
+ nop /* delay slot */
+
+
+/* The file include/linux/linkage.h is wrong for compiling the
+ Linux/CRIS kernel. We currently have C symbols in the kernel (only
+ the kernel) prefixed with _, hence, we need to redefine SYMBOL_NAME. */
#undef SYMBOL_NAME
-#define SYMBOL_NAME(X) _/**/X
-
+#define SYMBOL_NAME(X) _##X
+
+ .section .rodata,"a"
_sys_call_table:
.long SYMBOL_NAME(sys_ni_syscall) /* 0 - old "setup()" system call*/
.long SYMBOL_NAME(sys_exit)
* been shrunk every time we add a new system call.
*/
- .rept NR_syscalls-221
+ .rept NR_syscalls-222
.long SYMBOL_NAME(sys_ni_syscall)
.endr
#include <asm/processor.h>
/* Exclude everything except the assembly by wrapping it in ".if 0". */
-#undef OF
-#define OF(NAME, TYPE, MEMBER) \
+#undef VAL
+#define VAL(NAME, VALUE) \
void NAME ## _fun (void) \
{ \
__asm__ (".endif \n" \
#NAME " = %0 \n" \
".if 0\n" \
- : : "i" (offsetof (TYPE, MEMBER))); \
+ : : "i" (VALUE)); \
}
+#undef OF
+#define OF(NAME, TYPE, MEMBER) \
+ VAL (NAME, offsetof (TYPE, MEMBER))
+
/* task_struct offsets. */
OF (LTASK_SIGPENDING, struct task_struct, sigpending)
OF (LTASK_NEEDRESCHED, struct task_struct, need_resched)
OF (LTHREAD_USP, struct thread_struct, usp)
OF (LTHREAD_DCCR, struct thread_struct, dccr)
+/* linux/sched.h values - doesn't have an #ifdef __ASSEMBLY__ for these. */
+VAL (LCLONE_VM, CLONE_VM)
+
__asm__ (".endif");
-/* $Id: head.S,v 1.34 2001/05/15 07:08:14 hp Exp $
+/* $Id: head.S,v 1.36 2001/06/29 12:39:31 pkj Exp $
*
* Head of the kernel - alter with care
*
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: head.S,v $
+ * Revision 1.36 2001/06/29 12:39:31 pkj
+ * Added support for mirroring the first flash to just below the
+ * second one, to make them look consecutive to cramfs.
+ *
+ * Revision 1.35 2001/06/25 14:07:00 hp
+ * Fix review comment.
+ * * head.S: Use IO_STATE, IO_FIELD and IO_MASK constructs instead of
+ * magic numbers. Add comment that -traditional must not be used.
+ * * entry.S (SYMBOL_NAME): Change redefinition to use ## concatenation.
+ * Correct and update comment.
+ * * Makefile (.S.o): Don't use -traditional. Add comment why the
+ * toplevel rule can't be used (now that there's a reason).
+ *
* Revision 1.34 2001/05/15 07:08:14 hp
* Tweak "notice" to reflect that both r8 r9 are used
*
#include <linux/config.h>
#define ASSEMBLER_MACROS_ONLY
+/* The IO_* macros use the ## token concatenation operator, so
+ -traditional must not be used when assembling this file. */
#include <asm/sv_addr_ag.h>
#define CRAMFS_MAGIC 0x28cd3d45
;; 1G per process with CONFIG_CRIS_LOW_MAP.
#ifdef CONFIG_CRIS_LOW_MAP
- move.d 0x0004b098, r0 ; kseg mappings, temporary map of 0xc0->0x40
+ ; kseg mappings, temporary map of 0xc0->0x40
+ move.d IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \
+ | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb) \
+ | IO_FIELD (R_MMU_KBASE_HI, base_9, 9) \
+ | IO_FIELD (R_MMU_KBASE_HI, base_8, 8), r0
move.d r0, [R_MMU_KBASE_HI]
- move.d 0x04040000, r0 ; temporary map of 0x40->0x40 and 0x00->0x00
+ ; temporary map of 0x40->0x40 and 0x60->0x40
+ move.d IO_FIELD (R_MMU_KBASE_LO, base_6, 4) \
+ | IO_FIELD (R_MMU_KBASE_LO, base_4, 4), r0
move.d r0, [R_MMU_KBASE_LO]
- move.d 0x80075c71, r0 ; mmu enable, segs c,b,9,8,6,5,4,0 segment mapped
+ ; mmu enable, segs e,c,b,a,6,5,4,0 segment mapped
+ move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \
+ | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \
+ | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \
+ | IO_STATE (R_MMU_CONFIG, we_excp, enable) \
+ | IO_STATE (R_MMU_CONFIG, seg_f, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_e, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_d, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_c, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_b, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_a, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_9, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_8, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_7, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_6, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_5, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_4, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_3, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_2, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_1, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_0, seg), r0
move.d r0, [R_MMU_CONFIG]
#else
- move.d 0x0804b000, r0 ; kseg mappings
+ ; kseg mappings
+ move.d IO_FIELD (R_MMU_KBASE_HI, base_e, 8) \
+ | IO_FIELD (R_MMU_KBASE_HI, base_c, 4) \
+ | IO_FIELD (R_MMU_KBASE_HI, base_b, 0xb), r0
move.d r0, [R_MMU_KBASE_HI]
- move.d 0x00040000, r0 ; temporary map of 0x40->0x40 and 0x00->0x00
+ ; temporary map of 0x40->0x40 and 0x00->0x00
+ move.d IO_FIELD (R_MMU_KBASE_LO, base_4, 4), r0
move.d r0, [R_MMU_KBASE_LO]
- move.d 0x8007d811, r0 ; mmu enable, segs f,e,c,b,4,0 segment mapped
+ ; mmu enable, segs f,e,c,b,4,0 segment mapped
+ move.d IO_STATE (R_MMU_CONFIG, mmu_enable, enable) \
+ | IO_STATE (R_MMU_CONFIG, inv_excp, enable) \
+ | IO_STATE (R_MMU_CONFIG, acc_excp, enable) \
+ | IO_STATE (R_MMU_CONFIG, we_excp, enable) \
+ | IO_STATE (R_MMU_CONFIG, seg_f, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_e, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_d, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_c, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_b, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_a, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_9, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_8, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_7, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_6, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_5, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_4, seg) \
+ | IO_STATE (R_MMU_CONFIG, seg_3, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_2, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_1, page) \
+ | IO_STATE (R_MMU_CONFIG, seg_0, seg), r0
move.d r0, [R_MMU_CONFIG]
#endif
add.d 0x50000000, r9 ; add flash start in virtual memory (cached)
#else
add.d 0xf0000000, r9 ; add flash start in virtual memory (cached)
+#endif
+#ifdef CONFIG_ETRAX_FLASH_MIRRORING_FOR_CRAMFS
+ add.d MEM_CSE1_START-CONFIG_ETRAX_FLASH_SIZE*0x100000, r9 ; move flash start to upper mirror
#endif
move.d r9, [_romfs_start]
moveq 0,r0
move.d r0,[R_EXT_DMA_0_ADDR]
- move.d 0x860000,r0 ; cnt enable, word size, output, stop, size 0
+ ; cnt enable, word size, output, stop, size 0
+ move.d IO_STATE (R_EXT_DMA_0_CMD, cnt, enable) \
+ | IO_STATE (R_EXT_DMA_0_CMD, rqpol, ahigh) \
+ | IO_STATE (R_EXT_DMA_0_CMD, apol, ahigh) \
+ | IO_STATE (R_EXT_DMA_0_CMD, rq_ack, burst) \
+ | IO_STATE (R_EXT_DMA_0_CMD, wid, word) \
+ | IO_STATE (R_EXT_DMA_0_CMD, dir, output) \
+ | IO_STATE (R_EXT_DMA_0_CMD, run, stop) \
+ | IO_FIELD (R_EXT_DMA_0_CMD, trf_count, 0),r0
move.d r0,[R_EXT_DMA_0_CMD]
;; reset dma4 and wait for completion
- moveq 4,r0
+ moveq IO_STATE (R_DMA_CH4_CMD, cmd, reset),r0
move.b r0,[R_DMA_CH4_CMD]
w4u: move.b [R_DMA_CH4_CMD],r0
- and.b 7,r0
- cmp.b 4,r0
+ and.b IO_MASK (R_DMA_CH4_CMD, cmd),r0
+ cmp.b IO_STATE (R_DMA_CH4_CMD, cmd, reset),r0
beq w4u
nop
;; reset dma5 and wait for completion
- moveq 4,r0
+ moveq IO_STATE (R_DMA_CH5_CMD, cmd, reset),r0
move.b r0,[R_DMA_CH5_CMD]
w5u: move.b [R_DMA_CH5_CMD],r0
- and.b 7,r0
- cmp.b 4,r0
+ and.b IO_MASK (R_DMA_CH5_CMD, cmd),r0
+ cmp.b IO_STATE (R_DMA_CH5_CMD, cmd, reset),r0
beq w5u
nop
#endif
moveq 0,r0
#if !defined(CONFIG_ETRAX_KGDB) && !defined(CONFIG_DMA_MEMCPY)
- or.d 0x140000,r0 ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
+ ; DMA channels 6 and 7 to ser0, kgdb doesnt want DMA
+ or.d IO_STATE (R_GEN_CONFIG, dma7, serial0) \
+ | IO_STATE (R_GEN_CONFIG, dma6, serial0),r0
#endif
#if !defined(CONFIG_ETRAX_KGDB) || !defined(CONFIG_ETRAX_DEBUG_PORT1)
- or.d 0xc00000,r0 ; DMA channels 8 and 9 to ser1, kgdb doesnt want DMA
+ or.d IO_STATE (R_GEN_CONFIG, dma9, serial1) \
+ | IO_STATE (R_GEN_CONFIG, dma8, serial1),r0
#endif
#ifdef CONFIG_DMA_MEMCPY
- or.d 0x003c0000,r0 ; 6/7 memory-memory DMA
+ ; 6/7 memory-memory DMA
+ or.d IO_STATE (R_GEN_CONFIG, dma7, intdma6) \
+ | IO_STATE (R_GEN_CONFIG, dma6, intdma7),r0
#endif
#ifdef CONFIG_ETRAX_SERIAL_PORT2
- or.d 0x2808,r0 ; DMA channels 2 and 3 to serport 2, port 2 enabled
+ ; DMA channels 2 and 3 to serport 2, port 2 enabled
+ or.d IO_STATE (R_GEN_CONFIG, dma3, serial2) \
+ | IO_STATE (R_GEN_CONFIG, dma2, serial2) \
+ | IO_STATE (R_GEN_CONFIG, ser2, select),r0
#endif
#if defined(CONFIG_ETRAX_SERIAL_PORT3) || defined(CONFIG_ETRAX_SYNCHRONOUS_SERIAL_PORT1)
- or.d 0x28100,r0 ; DMA channels 4 and 5 to serport 3, port 3 enabled
+ ; DMA channels 4 and 5 to serport 3, port 3 enabled
+ or.d IO_STATE (R_GEN_CONFIG, dma5, serial3) \
+ | IO_STATE (R_GEN_CONFIG, dma4, serial3) \
+ | IO_STATE (R_GEN_CONFIG, ser3, select),r0
#endif
#if defined(CONFIG_ETRAX_PARALLEL_PORT0) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
- or.w 0x4,r0 ; parport 0 enabled using DMA 2/3
+ ; parport 0 enabled using DMA 2/3
+ or.w IO_STATE (R_GEN_CONFIG, par0, select),r0
#endif
#if defined(CONFIG_ETRAX_PARALLEL_PORT1) || defined(CONFIG_ETRAX_ETHERNET_LPSLAVE)
- or.w 0x80,r0 ; parport 1 enabled using DMA 4/5
+ ; parport 1 enabled using DMA 4/5
+ or.w IO_STATE (R_GEN_CONFIG, par1, select),r0
#endif
#ifdef CONFIG_ETRAX_IDE
- or.d 0x3c02,r0 ; DMA channels 2 and 3 to ATA, ATA enabled
+ ; DMA channels 2 and 3 to ATA, ATA enabled
+ or.d IO_STATE (R_GEN_CONFIG, dma3, ata) \
+ | IO_STATE (R_GEN_CONFIG, dma2, ata) \
+ | IO_STATE (R_GEN_CONFIG, ata, select),r0
#endif
#ifdef CONFIG_ETRAX_USB_HOST_PORT1
- or.d 0x20000000,r0 ; Set the USB port 1 enable bit
+ ; Set the USB port 1 enable bit
+ or.d IO_STATE (R_GEN_CONFIG, usb1, select),r0
#endif
#ifdef CONFIG_ETRAX_USB_HOST_PORT2
- or.d 0x40000000,r0 ; Set the USB port 2 enable bit
+ ; Set the USB port 2 enable bit
+ or.d IO_STATE (R_GEN_CONFIG, usb2, select),r0
#endif
#ifdef CONFIG_ETRAX_USB_HOST
- and.d 0xff3fffff,r0 ; Connect DMA channels 8 and 9 to USB
+ ; Connect DMA channels 8 and 9 to USB
+ and.d (~(IO_MASK (R_GEN_CONFIG, dma9) \
+ | IO_MASK (R_GEN_CONFIG, dma8))) \
+ | IO_STATE (R_GEN_CONFIG, dma9, usb) \
+ | IO_STATE (R_GEN_CONFIG, dma8, usb),r0
#endif
#ifdef CONFIG_JULIETTE
- or.d 0x3c000,r0 ; DMA channels 4 and 5 to EXTDMA0, for Juliette
+ ; DMA channels 4 and 5 to EXTDMA0, for Juliette
+ or.d IO_STATE (R_GEN_CONFIG, dma5, extdma0) \
+ | IO_STATE (R_GEN_CONFIG, dma4, extdma0),r0
#endif
move.d r0,[_genconfig_shadow] ; init a shadow register of R_GEN_CONFIG
nop
#endif
- moveq 4,r0
+ moveq IO_STATE (R_DMA_CH8_CMD, cmd, reset),r0
move.b r0,[R_DMA_CH8_CMD] ; reset (ser1 dma out)
move.b r0,[R_DMA_CH9_CMD] ; reset (ser1 dma in)
w81: move.b [R_DMA_CH8_CMD],r0 ; wait for reset cycle to finish
- and.b 7,r0
- cmp.b 4,r0
+ and.b IO_MASK (R_DMA_CH8_CMD, cmd),r0
+ cmp.b IO_STATE (R_DMA_CH8_CMD, cmd, reset),r0
beq w81
nop
w91: move.b [R_DMA_CH9_CMD],r0 ; wait for reset cycle to finish
- and.b 7,r0
- cmp.b 4,r0
+ and.b IO_MASK (R_DMA_CH9_CMD, cmd),r0
+ cmp.b IO_STATE (R_DMA_CH9_CMD, cmd, reset),r0
beq w91
nop
;; setup the serial port 0 at 115200 baud for debug purposes
- moveq 0,r0
+ moveq IO_STATE (R_SERIAL0_XOFF, tx_stop, enable) \
+ | IO_STATE (R_SERIAL0_XOFF, auto_xoff, disable) \
+ | IO_FIELD (R_SERIAL0_XOFF, xoff_char, 0),r0
move.d r0,[R_SERIAL0_XOFF]
- move.b 0x99,r0
- move.b r0,[R_SERIAL0_BAUD] ; 115.2kbaud for both transmit and receive
-
- move.b 0x40,r0 ; rec enable
+ ; 115.2kbaud for both transmit and receive
+ move.b IO_STATE (R_SERIAL0_BAUD, tr_baud, c115k2Hz) \
+ | IO_STATE (R_SERIAL0_BAUD, rec_baud, c115k2Hz),r0
+ move.b r0,[R_SERIAL0_BAUD]
+
+ ; Set up and enable the serial0 receiver.
+ move.b IO_STATE (R_SERIAL0_REC_CTRL, dma_err, stop) \
+ | IO_STATE (R_SERIAL0_REC_CTRL, rec_enable, enable) \
+ | IO_STATE (R_SERIAL0_REC_CTRL, rts_, active) \
+ | IO_STATE (R_SERIAL0_REC_CTRL, sampling, middle) \
+ | IO_STATE (R_SERIAL0_REC_CTRL, rec_stick_par, normal) \
+ | IO_STATE (R_SERIAL0_REC_CTRL, rec_par, even) \
+ | IO_STATE (R_SERIAL0_REC_CTRL, rec_par_en, disable) \
+ | IO_STATE (R_SERIAL0_REC_CTRL, rec_bitnr, rec_8bit),r0
move.b r0,[R_SERIAL0_REC_CTRL]
- move.b 0x40,r0 ; tr enable
+ ; Set up and enable the serial0 transmitter.
+ move.b IO_FIELD (R_SERIAL0_TR_CTRL, txd, 0) \
+ | IO_STATE (R_SERIAL0_TR_CTRL, tr_enable, enable) \
+ | IO_STATE (R_SERIAL0_TR_CTRL, auto_cts, disabled) \
+ | IO_STATE (R_SERIAL0_TR_CTRL, stop_bits, one_bit) \
+ | IO_STATE (R_SERIAL0_TR_CTRL, tr_stick_par, normal) \
+ | IO_STATE (R_SERIAL0_TR_CTRL, tr_par, even) \
+ | IO_STATE (R_SERIAL0_TR_CTRL, tr_par_en, disable) \
+ | IO_STATE (R_SERIAL0_TR_CTRL, tr_bitnr, tr_8bit),r0
move.b r0,[R_SERIAL0_TR_CTRL]
;; setup the serial port 1 at 115200 baud for debug purposes
- moveq 0,r0
+ moveq IO_STATE (R_SERIAL1_XOFF, tx_stop, enable) \
+ | IO_STATE (R_SERIAL1_XOFF, auto_xoff, disable) \
+ | IO_FIELD (R_SERIAL1_XOFF, xoff_char, 0),r0
move.d r0,[R_SERIAL1_XOFF]
- move.b 0x99,r0
- move.b r0,[R_SERIAL1_BAUD] ; 115.2kbaud for both transmit and receive
-
- move.b 0x40,r0 ; rec enable
+ ; 115.2kbaud for both transmit and receive
+ move.b IO_STATE (R_SERIAL1_BAUD, tr_baud, c115k2Hz) \
+ | IO_STATE (R_SERIAL1_BAUD, rec_baud, c115k2Hz),r0
+ move.b r0,[R_SERIAL1_BAUD]
+
+ ; Set up and enable the serial1 receiver.
+ move.b IO_STATE (R_SERIAL1_REC_CTRL, dma_err, stop) \
+ | IO_STATE (R_SERIAL1_REC_CTRL, rec_enable, enable) \
+ | IO_STATE (R_SERIAL1_REC_CTRL, rts_, active) \
+ | IO_STATE (R_SERIAL1_REC_CTRL, sampling, middle) \
+ | IO_STATE (R_SERIAL1_REC_CTRL, rec_stick_par, normal) \
+ | IO_STATE (R_SERIAL1_REC_CTRL, rec_par, even) \
+ | IO_STATE (R_SERIAL1_REC_CTRL, rec_par_en, disable) \
+ | IO_STATE (R_SERIAL1_REC_CTRL, rec_bitnr, rec_8bit),r0
move.b r0,[R_SERIAL1_REC_CTRL]
- move.b 0x40,r0 ; tr enable
+ ; Set up and enable the serial1 transmitter.
+ move.b IO_FIELD (R_SERIAL1_TR_CTRL, txd, 0) \
+ | IO_STATE (R_SERIAL1_TR_CTRL, tr_enable, enable) \
+ | IO_STATE (R_SERIAL1_TR_CTRL, auto_cts, disabled) \
+ | IO_STATE (R_SERIAL1_TR_CTRL, stop_bits, one_bit) \
+ | IO_STATE (R_SERIAL1_TR_CTRL, tr_stick_par, normal) \
+ | IO_STATE (R_SERIAL1_TR_CTRL, tr_par, even) \
+ | IO_STATE (R_SERIAL1_TR_CTRL, tr_par_en, disable) \
+ | IO_STATE (R_SERIAL1_TR_CTRL, tr_bitnr, tr_8bit),r0
move.b r0,[R_SERIAL1_TR_CTRL]
#ifdef CONFIG_ETRAX_SERIAL_PORT3
;; setup the serial port 3 at 115200 baud for debug purposes
- moveq 0,r0
+ moveq IO_STATE (R_SERIAL3_XOFF, tx_stop, enable) \
+ | IO_STATE (R_SERIAL3_XOFF, auto_xoff, disable) \
+ | IO_FIELD (R_SERIAL3_XOFF, xoff_char, 0),r0
move.d r0,[R_SERIAL3_XOFF]
- move.b 0x99,r0
- move.b r0,[R_SERIAL3_BAUD] ; 115.2kbaud for both transmit and receive
-
- move.b 0x40,r0 ; rec enable
+ ; 115.2kbaud for both transmit and receive
+ move.b IO_STATE (R_SERIAL3_BAUD, tr_baud, c115k2Hz) \
+ | IO_STATE (R_SERIAL3_BAUD, rec_baud, c115k2Hz),r0
+ move.b r0,[R_SERIAL3_BAUD]
+
+ ; Set up and enable the serial3 receiver.
+ move.b IO_STATE (R_SERIAL3_REC_CTRL, dma_err, stop) \
+ | IO_STATE (R_SERIAL3_REC_CTRL, rec_enable, enable) \
+ | IO_STATE (R_SERIAL3_REC_CTRL, rts_, active) \
+ | IO_STATE (R_SERIAL3_REC_CTRL, sampling, middle) \
+ | IO_STATE (R_SERIAL3_REC_CTRL, rec_stick_par, normal) \
+ | IO_STATE (R_SERIAL3_REC_CTRL, rec_par, even) \
+ | IO_STATE (R_SERIAL3_REC_CTRL, rec_par_en, disable) \
+ | IO_STATE (R_SERIAL3_REC_CTRL, rec_bitnr, rec_8bit),r0
move.b r0,[R_SERIAL3_REC_CTRL]
- move.b 0x40,r0 ; tr enable
+ ; Set up and enable the serial3 transmitter.
+ move.b IO_FIELD (R_SERIAL3_TR_CTRL, txd, 0) \
+ | IO_STATE (R_SERIAL3_TR_CTRL, tr_enable, enable) \
+ | IO_STATE (R_SERIAL3_TR_CTRL, auto_cts, disabled) \
+ | IO_STATE (R_SERIAL3_TR_CTRL, stop_bits, one_bit) \
+ | IO_STATE (R_SERIAL3_TR_CTRL, tr_stick_par, normal) \
+ | IO_STATE (R_SERIAL3_TR_CTRL, tr_par, even) \
+ | IO_STATE (R_SERIAL3_TR_CTRL, tr_par_en, disable) \
+ | IO_STATE (R_SERIAL3_TR_CTRL, tr_bitnr, tr_8bit),r0
move.b r0,[R_SERIAL3_TR_CTRL]
#endif
-/* $Id: irq.c,v 1.15 2001/06/10 11:18:46 bjornw Exp $
+/* $Id: irq.c,v 1.17 2001/07/25 16:08:01 bjornw Exp $
*
* linux/arch/cris/kernel/irq.c
*
#include <linux/timex.h>
#include <linux/slab.h>
#include <linux/random.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/io.h>
}
irq_exit(cpu);
- if (softirq_active(cpu) & softirq_mask(cpu))
+ if (softirq_pending(cpu))
do_softirq();
/* unmasking and bottom half handling is done magically for us. */
void do_sigtrap(void); /* from entry.S */
void gdb_handle_breakpoint(void); /* from entry.S */
-void init_IRQ(void)
+void __init
+init_IRQ(void)
{
int i;
#if defined(CONFIG_PROC_FS) && defined(CONFIG_SYSCTL)
/* Used by other archs to show/control IRQ steering during SMP */
-void init_irq_proc(void)
+void __init
+init_irq_proc(void)
{
}
#endif
-/* $Id: process.c,v 1.14 2001/05/29 11:27:59 markusl Exp $
+/* $Id: process.c,v 1.16 2001/06/21 02:00:40 hp Exp $
*
* linux/arch/cris/kernel/process.c
*
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: process.c,v $
+ * Revision 1.16 2001/06/21 02:00:40 hp
+ * * entry.S: Include asm/unistd.h.
+ * (_sys_call_table): Use section .rodata, not .data.
+ * (_kernel_thread): Move from...
+ * * process.c: ... here.
+ * * entryoffsets.c (VAL): Break out from...
+ * (OF): Use VAL.
+ * (LCLONE_VM): New asmified value from CLONE_VM.
+ *
+ * Revision 1.15 2001/06/20 16:31:57 hp
+ * Add comments to describe empty functions according to review.
+ *
* Revision 1.14 2001/05/29 11:27:59 markusl
* Fixed so that hard_reset_now will do reset even if watchdog wasn't enabled
*
__attribute__((__section__(".data.init_task"))) =
{ INIT_TASK(init_task_union.task) };
+/*
+ * The hlt_counter, disable_hlt and enable_hlt is just here as a hook if
+ * there would ever be a halt sequence (for power save when idle) with
+ * some largish delay when halting or resuming *and* a driver that can't
+ * afford that delay. The hlt_counter would then be checked before
+ * executing the halt sequence, and the driver marks the unhaltable
+ * region by enable_hlt/disable_hlt.
+ */
+
static int hlt_counter=0;
void disable_hlt(void)
hard_reset_now();
}
-/* can't do much here... */
+/*
+ * Similar to machine_power_off, but don't shut off power. Add code
+ * here to freeze the system for e.g. post-mortem debug purpose when
+ * possible. This halt has nothing to do with the idle halt.
+ */
void machine_halt(void)
{
}
+/* If or when software power-off is implemented, add code here. */
+
void machine_power_off(void)
{
}
/*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be free'd until both the parent and the child have exited.
+ * When a process does an "exec", machine state like FPU and debug
+ * registers need to be reset. This is a hook function for that.
+ * Currently we don't have any such state to reset, so this is empty.
*/
-int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags)
-{
- register long __a __asm__ ("r10");
-
- __asm__ __volatile__
- ("movu.w %1,r9\n\t" /* r9 contains syscall number, to sys_clone */
- "clear.d r10\n\t" /* r10 is argument 1 to clone */
- "move.d %2,r11\n\t" /* r11 is argument 2 to clone, the flags */
- "break 13\n\t" /* call sys_clone, this will fork */
- "test.d r10\n\t" /* parent or child? child returns 0 here. */
- "bne 1f\n\t" /* jump if parent */
- "nop\n\t" /* delay slot */
- "move.d %4,r10\n\t" /* set argument to function to call */
- "jsr %5\n\t" /* call specified function */
- "movu.w %3,r9\n\t" /* r9 is sys_exit syscall number */
- "moveq -1,r10\n\t" /* Give a really bad exit-value */
- "break 13\n\t" /* call sys_exit, killing the child */
- "1:\n\t"
- : "=r" (__a)
- : "g" (__NR_clone), "r" (flags | CLONE_VM), "g" (__NR_exit),
- "r" (arg), "r" (fn)
- : "r10", "r11", "r9");
-
- return __a;
-}
-
-
-
void flush_thread(void)
{
}
* Authors: Bjorn Wesen
*
* $Log: ptrace.c,v $
+ * Revision 1.6 2001/07/25 16:08:47 bjornw
+ * PTRACE_ATTACH bulk moved into arch-independant code in 2.4.7
+ *
* Revision 1.5 2001/03/26 14:24:28 orjanf
* * Changed loop condition.
* * Added comment documenting non-standard ptrace behaviour.
-/* $Id: setup.c,v 1.16 2001/05/15 01:23:13 hp Exp $
+/* $Id: setup.c,v 1.18 2001/06/28 04:47:16 hp Exp $
*
* linux/arch/cris/kernel/setup.c
*
paging_init();
- /* we dont use a command line yet, so just let it be an empty string
- to start with */
-
+ /* We dont use a command line yet, so just re-initialize it without
+ saving anything that might be there. */
+
*cmdline_p = command_line;
strcpy(command_line, "root=/dev/rom"); /* use the appended romdisk as root */
cpu_info[revision].flags & HAS_SCSI ? "yes" : "no",
cpu_info[revision].flags & HAS_ATA ? "yes" : "no",
cpu_info[revision].flags & HAS_USB ? "yes" : "no",
- (loops_per_jiffy * HZ + 500) / 100000,
- ((loops_per_jiffy * HZ + 500) / 1000) % 100);
+ (loops_per_jiffy * HZ + 500) / 500000,
+ ((loops_per_jiffy * HZ + 500) / 5000) % 100);
}
#endif /* CONFIG_PROC_FS */
-/* $Id: sys_cris.c,v 1.9 2001/05/30 06:20:26 markusl Exp $
+/* $Id: sys_cris.c,v 1.10 2001/06/27 21:16:15 hp Exp $
*
* linux/arch/cris/kernel/sys_cris.c
*
return error;
}
-/* sys_mmap used to take a ptr to a buffer instead containing the args
- * but we support syscalls with 6 arguments now
- */
-
-asmlinkage unsigned long sys_mmap(unsigned long addr, size_t len,
- unsigned long prot, unsigned long flags,
- unsigned long fd, off_t offset)
-{
- struct file * file = NULL;
- int ret = -EBADF;
-
- lock_kernel();
- if (!(flags & MAP_ANONYMOUS)) {
- if (!(file = fget(fd)))
- goto out;
- }
-
- flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
- down_write(¤t->mm->mmap_sem);
- ret = do_mmap(file, addr, len, prot, flags, offset);
- up_write(¤t->mm->mmap_sem);
- if (file)
- fput(file);
- out:
- unlock_kernel();
- return ret;
-}
-
/* common code for old and new mmaps */
static inline long
do_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
-/* $Id: time.c,v 1.6 2001/05/29 11:29:42 markusl Exp $
+/* $Id: time.c,v 1.8 2001/07/18 14:01:03 bjornw Exp $
*
* linux/arch/cris/kernel/time.c
*
* Copyright (C) 1991, 1992, 1995 Linus Torvalds
- * Copyright (C) 1999, 2000 Axis Communications AB
+ * Copyright (C) 1999, 2000, 2001 Axis Communications AB
*
* 1994-07-02 Alan Modra
* fixed set_rtc_mmss, fixed time.year for >= 2000, new mktime
#define WATCHDOG_MIN_FREE_PAGES 8
-static inline void
+void
reset_watchdog(void)
{
#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
#endif
}
+/* stop the watchdog - we still need the correct key */
+
+void
+stop_watchdog(void)
+{
+#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
+ watchdog_key ^= 0x7; /* invert key, which is 3 bits */
+ *R_WATCHDOG = IO_FIELD(R_WATCHDOG, key, watchdog_key) |
+ IO_STATE(R_WATCHDOG, enable, stop);
+#endif
+}
+
/* last time the cmos clock got updated */
static long last_rtc_update = 0;
#if defined(CONFIG_ETRAX_WATCHDOG) && !defined(CONFIG_SVINTO_SIM)
printk("Enabling watchdog...\n");
start_watchdog();
-#endif
+ /* If we use the hardware watchdog, we want to trap it as an NMI
+ and dump registers before it resets us. For this to happen, we
+ must set the "m" NMI enable flag (which once set, is unset only
+ when an NMI is taken).
+
+ The same goes for the external NMI, but that doesn't have any
+ driver or infrastructure support yet. */
+ asm ("setf m");
+
+ *R_IRQ_MASK0_SET =
+ IO_STATE(R_IRQ_MASK0_SET, watchdog_nmi, set);
+ *R_VECT_MASK_SET =
+ IO_STATE(R_VECT_MASK_SET, nmi, set);
+#endif
}
-/* $Id: traps.c,v 1.12 2001/05/15 15:46:40 bjornw Exp $
+/* $Id: traps.c,v 1.15 2001/07/18 14:02:37 bjornw Exp $
*
* linux/arch/cris/traps.c
*
* Copyright (C) 2000,2001 Axis Communications AB
*
* Authors: Bjorn Wesen
+ * Hans-Peter Nilsson
*
*/
#include <linux/ptrace.h>
#include <linux/timer.h>
#include <linux/mm.h>
+#include <asm/uaccess.h>
#include <asm/system.h>
#include <asm/segment.h>
#define MODULE_RANGE (8*1024*1024)
+/*
+ * The output (format, strings and order) is adjusted to be usable with
+ * ksymoops-2.4.1 with some necessary CRIS-specific patches. Please don't
+ * change it unless you're serious about adjusting ksymoops and syncing
+ * with the ksymoops maintainer.
+ */
+
void
show_stack(unsigned long *sp)
{
int i;
extern char _stext, _etext;
- /*
- * debugging aid: "show_stack(NULL);" prints the
- * back trace for this cpu.
- */
+ /*
+ * debugging aid: "show_stack(NULL);" prints a
+ * back trace.
+ */
if(sp == NULL)
sp = (unsigned long*)rdsp();
stack = sp;
+ printk("\nStack from %08lx:\n ", stack);
for(i = 0; i < kstack_depth_to_print; i++) {
if (((long) stack & (THREAD_SIZE-1)) == 0)
break;
if (i && ((i % 8) == 0))
printk("\n ");
- printk("%08lx ", *stack++);
+ if (__get_user (addr, stack)) {
+ /* This message matches "failing address" marked
+ s390 in ksymoops, so lines containing it will
+ not be filtered out by ksymoops. */
+ printk ("Failing address 0x%lx\n", stack);
+ break;
+ }
+ stack++;
+ printk("%08lx ", addr);
}
printk("\nCall Trace: ");
module_start = VMALLOC_START;
module_end = VMALLOC_END;
while (((long) stack & (THREAD_SIZE-1)) != 0) {
- addr = *stack++;
+ if (__get_user (addr, stack)) {
+ /* This message matches "failing address" marked
+ s390 in ksymoops, so lines containing it will
+ not be filtered out by ksymoops. */
+ printk ("Failing address 0x%lx\n", stack);
+ break;
+ }
+ stack++;
+
/*
* If the address is either in the text segment of the
* kernel, or in the region which contains vmalloc'ed
void
show_registers(struct pt_regs * regs)
{
+ /* We either use rdusp() - the USP register, which might not
+ correspond to the current process for all cases we're called,
+ or we use the current->thread.usp, which is not up to date for
+ the current process. Experience shows we want the USP
+ register. */
unsigned long usp = rdusp();
- printk("IRP: %08lx SRP: %08lx CCR: %08lx USP: %08lx MOF: %08lx\n",
+ printk("IRP: %08lx SRP: %08lx DCCR: %08lx USP: %08lx MOF: %08lx\n",
regs->irp, regs->srp, regs->dccr, usp, regs->mof );
- printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
+ printk(" r0: %08lx r1: %08lx r2: %08lx r3: %08lx\n",
regs->r0, regs->r1, regs->r2, regs->r3);
- printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
+ printk(" r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
regs->r4, regs->r5, regs->r6, regs->r7);
- printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
+ printk(" r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
regs->r8, regs->r9, regs->r10, regs->r11);
printk("r12: %08lx r13: %08lx oR10: %08lx\n",
regs->r12, regs->r13, regs->orig_r10);
+ printk("R_MMU_CAUSE: %08lx\n", *R_MMU_CAUSE);
printk("Process %s (pid: %d, stackpage=%08lx)\n",
current->comm, current->pid, (unsigned long)current);
- /* TODO, fix in_kernel detection */
-
-#if 0
/*
* When in-kernel, we also print out the stack and code at the
* time of the fault..
*/
- if (1) {
-
- printk("\nStack: ");
+ if (! user_mode(regs)) {
+ int i;
+
show_stack((unsigned long*)usp);
+ /* Dump kernel stack if the previous dump wasn't one. */
+ if (usp != 0)
+ show_stack (NULL);
+
printk("\nCode: ");
if(regs->irp < PAGE_OFFSET)
goto bad;
- for(i = 0; i < 20; i++)
+ /* Often enough the value at regs->irp does not point to
+ the interesting instruction, which is most often the
+ _previous_ instruction. So we dump at an offset large
+ enough that instruction decoding should be in sync at
+ the interesting point, but small enough to fit on a row
+ (sort of). We point out the regs->irp location in a
+ ksymoops-friendly way by wrapping the byte for that
+ address in parentheses. */
+ for(i = -12; i < 12; i++)
{
unsigned char c;
if(__get_user(c, &((unsigned char*)regs->irp)[i])) {
printk(" Bad IP value.");
break;
}
- printk("%02x ", c);
+
+ if (i == 0)
+ printk("(%02x) ", c);
+ else
+ printk("%02x ", c);
}
+ printk("\n");
}
- printk("\n");
-#endif
}
void
if(user_mode(regs))
return;
+ stop_watchdog();
+
printk("%s: %04lx\n", str, err & 0xffff);
show_registers(regs);
- show_stack(NULL); /* print backtrace for kernel stack on this CPU */
+
+ reset_watchdog();
do_exit(SIGSEGV);
}
$(CC) -D__ASSEMBLY__ $(AFLAGS) -traditional -c $< -o $*.o
L_TARGET = lib.a
-obj-y = checksum.o checksumcopy.o string.o usercopy.o memset.o
+obj-y = checksum.o checksumcopy.o string.o usercopy.o memset.o csumcpfruser.o
include $(TOPDIR)/Rules.make
-/* $Id: checksumcopy.S,v 1.5 2001/05/29 11:40:14 markusl Exp $
+/* $Id: checksumcopy.S,v 1.6 2001/06/28 03:57:16 hp Exp $
* A fast checksum+copy routine using movem
* Copyright (c) 1998, 2001 Axis Communications AB
*
subq 10*4,r12 ; update length for the first loop
mloop: movem [r10+],r9 ; read 10 longwords
+1: ;; A failing userspace access will have this as PC.
movem r9,[r11+] ; write 10 longwords
;; perform dword checksumming on the 10 longwords
subq 2,r12
wloop: move.w [r10+],r9
+2: ;; A failing userspace access will have this as PC.
addu.w r9,r13
subq 2,r12
bge wloop
do_byte:
;; copy and checksum the last byte
move.b [r10],r9
+3: ;; A failing userspace access will have this as PC.
addu.b r9,r13
move.b r9,[r11]
ret
move.d r13, r10
-
-
--- /dev/null
+/*
+ * Add-on to transform csum_partial_copy_nocheck in checksumcopy.S into
+ * csum_partial_copy_from_user by adding exception records.
+ *
+ * Copyright (C) 2001 Axis Communications AB.
+ *
+ * Author: Hans-Peter Nilsson.
+ */
+
+#include <asm/errno.h>
+
+/* Same function body, but a different name. If we just added exception
+ records to _csum_partial_copy_nocheck and made it generic, we wouldn't
+ know a user fault from a kernel fault and we would have overhead in
+ each kernel caller for the error-pointer argument.
+
+ unsigned int csum_partial_copy_from_user
+ (const char *src, char *dst, int len, unsigned int sum, int *errptr);
+
+ Note that the errptr argument is only set if we encounter an error.
+ It is conveniently located on the stack, so the normal function body
+ does not have to handle it. */
+
+#define _csum_partial_copy_nocheck _csum_partial_copy_from_user
+
+/* There are local labels numbered 1, 2 and 3 present to mark the
+ different from-user accesses. */
+#include "checksumcopy.S"
+
+ .section .fixup,"ax"
+
+;; Here from the movem loop; restore stack.
+4:
+ movem [sp+],r8
+;; r12 is already decremented. Add back chunk_size-2.
+ addq 40-2,r12
+
+;; Here from the word loop; r12 is off by 2; add it back.
+5:
+ addq 2,r12
+
+;; Here from a failing single byte.
+6:
+
+;; Signal in *errptr that we had a failing access.
+ moveq -EFAULT,r9
+ move.d r9,[[sp]]
+
+;; Clear the rest of the destination area using memset. Preserve the
+;; checksum for the readable bytes.
+ push srp
+ push r13
+ move.d r11,r10
+ clear.d r11
+ jsr _memset
+ pop r10
+ jump [sp+]
+
+ .previous
+ .section __ex_table,"a"
+ .dword 1b,4b
+ .dword 2b,5b
+ .dword 3b,6b
+ .previous
* Authors: Bjorn Wesen
*
* $Log: fault.c,v $
+ * Revision 1.18 2001/07/18 22:14:32 bjornw
+ * Enable interrupts in the bulk of do_page_fault
+ *
+ * Revision 1.17 2001/07/18 13:07:23 bjornw
+ * * Detect non-existant PTE's in vmalloc pmd synchronization
+ * * Remove comment about fast-paths for VMALLOC_START etc, because all that
+ * was totally bogus anyway it turned out :)
+ * * Fix detection of vmalloc-area synchronization
+ * * Add some comments
+ *
* Revision 1.16 2001/06/13 00:06:08 bjornw
* current_pgd should be volatile
*
volatile pgd_t *current_pgd;
-/* fast TLB-fill fault handler */
+/* fast TLB-fill fault handler
+ * this is called from entry.S with interrupts disabled
+ */
void
handle_mmu_bus_fault(struct pt_regs *regs)
int index;
int page_id;
int miss, we, acc, inv;
- struct mm_struct *mm = current->active_mm;
pmd_t *pmd;
pte_t pte;
- int errcode = 0;
+ int errcode;
unsigned long address;
cause = *R_MMU_CAUSE;
miss = IO_EXTRACT(R_MMU_CAUSE, miss_excp, cause);
we = IO_EXTRACT(R_MMU_CAUSE, we_excp, cause);
+ /* Note: the reason we don't set errcode's r/w flag here
+ * using the 'we' flag, is because the latter is only given
+ * if there is a write-protection exception, not given as a
+ * general r/w access mode flag. It is currently not possible
+ * to get this from the MMU (TODO: check if this is the case
+ * for LXv2).
+ *
+ * The page-fault code won't care, but there will be two page-
+ * faults instead of one for the case of a write to a non-tabled
+ * page (miss, then write-protection).
+ */
+
+ errcode = 0;
+
D(printk("bus_fault from IRP 0x%x: addr 0x%x, miss %d, inv %d, we %d, acc %d, "
"idx %d pid %d\n",
regs->irp, address, miss, inv, we, acc, index, page_id));
* the write to R_TLB_LO also writes the vpn and page_id fields from
* R_MMU_CAUSE, which we in this case obviously want to keep
*/
-
+
*R_TLB_LO = pte_val(pte);
return;
}
- errcode = 0x01 | (we << 1);
-
+ errcode = 1 | (we << 1);
+
dofault:
/* leave it to the MM system fault handler below */
D(printk("do_page_fault %p errcode %d\n", address, errcode));
* NOTE2: This is done so that, when updating the vmalloc
* mappings we don't have to walk all processes pgdirs and
* add the high mappings all at once. Instead we do it as they
- * are used.
+ * are used. However vmalloc'ed page entries have the PAGE_GLOBAL
+ * bit set so sometimes the TLB can use a lingering entry.
*
- * TODO: On CRIS, we have a PTE Global bit which should be set in
- * all the PTE's related to vmalloc in all processes - that means if
- * we switch process and a vmalloc PTE is still in the TLB, it won't
- * need to be reloaded. It's an optimization.
- *
- * Linux/CRIS's kernel is not page-mapped, so the comparision below
- * should really be >= VMALLOC_START, however, kernel fixup errors
- * will be handled more quickly by going through vmalloc_fault and then
- * into bad_area_nosemaphore than falling through the find_vma user-mode
- * tests. As an aside can be mentioned that the difference in
- * compiled code is neglibible; the instruction is the same, just a
- * comparison with a different address of the same size.
+ * This verifies that the fault happens in kernel space
+ * and that the fault was not a protection error (error_code & 1).
*/
- if (address >= TASK_SIZE)
+ if (address >= VMALLOC_START &&
+ !(error_code & 1) &&
+ !user_mode(regs))
goto vmalloc_fault;
+ /* we can and should enable interrupts at this point */
+ sti();
+
mm = tsk->mm;
writeaccess = error_code & 2;
info.si_code = SEGV_MAPERR;
* Use current_pgd instead of tsk->active_mm->pgd
* since the latter might be unavailable if this
* code is executed in a misfortunately run irq
+ * (like inside schedule() between switch_mm and
+ * switch_to...).
*/
int offset = pgd_index(address);
pgd_t *pgd, *pgd_k;
pmd_t *pmd, *pmd_k;
+ pte_t *pte_k;
pgd = current_pgd + offset;
pgd_k = init_mm.pgd + offset;
- if (!pgd_present(*pgd)) {
- if (!pgd_present(*pgd_k))
- goto bad_area_nosemaphore;
- set_pgd(pgd, *pgd_k);
- return;
- }
+ /* Since we're two-level, we don't need to do both
+ * set_pgd and set_pmd (they do the same thing). If
+ * we go three-level at some point, do the right thing
+ * with pgd_present and set_pgd here.
+ *
+ * Also, since the vmalloc area is global, we don't
+ * need to copy individual PTE's, it is enough to
+ * copy the pgd pointer into the pte page of the
+ * root task. If that is there, we'll find our pte if
+ * it exists.
+ */
pmd = pmd_offset(pgd, address);
pmd_k = pmd_offset(pgd_k, address);
if (!pmd_present(*pmd_k))
goto bad_area_nosemaphore;
+
set_pmd(pmd, *pmd_k);
+
+ /* Make sure the actual PTE exists as well to
+ * catch kernel vmalloc-area accesses to non-mapped
+ * addresses. If we don't do this, this will just
+ * silently loop forever.
+ */
+
+ pte_k = pte_offset(pmd_k, address);
+ if (!pte_present(*pte_k))
+ goto no_context;
+
return;
}
-
}
* Authors: Bjorn Wesen (bjornw@axis.com)
*
* $Log: init.c,v $
+ * Revision 1.29 2001/07/25 16:09:50 bjornw
+ * val->sharedram will stay 0
+ *
+ * Revision 1.28 2001/06/28 16:30:17 bjornw
+ * Oops. This needs to wait until 2.4.6 is merged
+ *
+ * Revision 1.27 2001/06/28 14:04:07 bjornw
+ * Fill in sharedram
+ *
+ * Revision 1.26 2001/06/18 06:36:02 hp
+ * Enable free_initmem of __init-type pages
+ *
* Revision 1.25 2001/06/13 00:02:23 bjornw
* Use a separate variable to store the current pgd to avoid races in schedule
*
void
free_initmem(void)
{
-#if 0
- /* currently this is a bad idea since the cramfs image is catted onto
- * the vmlinux image, and the end of that image is not page-padded so
- * part of the cramfs image will be freed here
- */
unsigned long addr;
addr = (unsigned long)(&__init_begin);
}
printk ("Freeing unused kernel memory: %dk freed\n",
(&__init_end - &__init_begin) >> 10);
-#endif
}
void
i = max_mapnr;
val->totalram = 0;
- val->sharedram = atomic_read(&shmem_nrpages);
+ val->sharedram = 0;
val->freeram = nr_free_pages();
val->bufferram = atomic_read(&buffermem_pages);
while (i-- > 0) {
*
* The last page_id is never running - it is used as an invalid page_id
* so we can make TLB entries that will never match.
+ *
+ * Notice that we need to make the flushes atomic, otherwise an interrupt
+ * handler that uses vmalloced memory might cause a TLB load in the middle
+ * of a flush causing.
*/
struct mm_struct *page_id_map[NUM_PAGEID];
/* invalidate all TLB entries */
void
-flush_tlb_all()
+flush_tlb_all(void)
{
int i;
+ unsigned long flags;
/* the vpn of i & 0xf is so we dont write similar TLB entries
* in the same 4-way entry group. details..
*/
+ save_and_cli(flags); /* flush needs to be atomic */
for(i = 0; i < NUM_TLB_ENTRIES; i++) {
*R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
-
*R_TLB_HI = ( IO_FIELD(R_TLB_HI, page_id, INVALID_PAGEID ) |
IO_FIELD(R_TLB_HI, vpn, i & 0xf ) );
IO_STATE(R_TLB_LO, we, no ) |
IO_FIELD(R_TLB_LO, pfn, 0 ) );
}
+ restore_flags(flags);
D(printk("tlb: flushed all\n"));
}
{
int i;
int page_id = mm->context;
+ unsigned long flags;
D(printk("tlb: flush mm context %d (%p)\n", page_id, mm));
* global pages. is it worth the extra I/O ?
*/
+ save_and_cli(flags); /* flush needs to be atomic */
for(i = 0; i < NUM_TLB_ENTRIES; i++) {
*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
if (IO_EXTRACT(R_TLB_HI, page_id, *R_TLB_HI) == page_id) {
IO_FIELD(R_TLB_LO, pfn, 0 ) );
}
}
+ restore_flags(flags);
}
/* invalidate a single page */
struct mm_struct *mm = vma->vm_mm;
int page_id = mm->context;
int i;
+ unsigned long flags;
D(printk("tlb: flush page %p in context %d (%p)\n", addr, page_id, mm));
* and the virtual address requested
*/
+ save_and_cli(flags); /* flush needs to be atomic */
for(i = 0; i < NUM_TLB_ENTRIES; i++) {
unsigned long tlb_hi;
*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
IO_FIELD(R_TLB_LO, pfn, 0 ) );
}
}
+ restore_flags(flags);
}
/* invalidate a page range */
{
int page_id = mm->context;
int i;
+ unsigned long flags;
D(printk("tlb: flush range %p<->%p in context %d (%p)\n",
start, end, page_id, mm));
* and the virtual address range
*/
+ save_and_cli(flags); /* flush needs to be atomic */
for(i = 0; i < NUM_TLB_ENTRIES; i++) {
unsigned long tlb_hi, vpn;
*R_TLB_SELECT = IO_FIELD(R_TLB_SELECT, index, i);
IO_FIELD(R_TLB_LO, pfn, 0 ) );
}
}
+ restore_flags(flags);
+}
+
+/* dump the entire TLB for debug purposes */
+
+#if 0
+void
+dump_tlb_all(void)
+{
+ int i;
+ unsigned long flags;
+
+ printk("TLB dump. LO is: pfn | reserved | global | valid | kernel | we |\n");
+
+ save_and_cli(flags);
+ for(i = 0; i < NUM_TLB_ENTRIES; i++) {
+ *R_TLB_SELECT = ( IO_FIELD(R_TLB_SELECT, index, i) );
+ printk("Entry %d: HI 0x%08lx, LO 0x%08lx\n",
+ i, *R_TLB_HI, *R_TLB_LO);
+ }
+ restore_flags(flags);
}
+#endif
/*
* Initialize the context related info for a new mm_struct
map_replace_ptr++;
if(map_replace_ptr == INVALID_PAGEID)
- map_replace_ptr = 0; /* wrap around */
-
+ map_replace_ptr = 0; /* wrap around */
}
/*
cpuid(cmd->reg, &cmd->data[0], &cmd->data[1], &cmd->data[2], &cmd->data[3]);
}
-extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
+static inline void do_cpuid(int cpu, u32 reg, u32 *data)
{
struct cpuid_command cmd;
}
#else /* ! CONFIG_SMP */
-extern inline void do_cpuid(int cpu, u32 reg, u32 *data)
+static inline void do_cpuid(int cpu, u32 reg, u32 *data)
{
cpuid(reg, &data[0], &data[1], &data[2], &data[3]);
}
};
#define dmi_printk(x)
-//#define dmi_printk(x) printk(x)
+//#define dmi_printk(x) printk x
static char * __init dmi_string(struct dmi_header *dm, u8 s)
{
u8 *bp=(u8 *)dm;
bp+=dm->length;
+ if(!s)
+ return "";
s--;
while(s>0)
{
}
/*
- * Horrible dependencies! Try to get rid of this. This is wrong,
- * as it only reloads the ldt for the first process with this
- * mm. The implications are that you should really make sure that
- * you have a ldt before you do the first clone(), otherwise
- * you get strange behaviour (the kernel is safe, it's just user
- * space strangeness).
- *
- * we have two choices: either we preallocate the LDT descriptor
- * and can do a shared modify_ldt(), or we postallocate it and do
- * an smp message pass to update it. Currently we are a bit
- * un-nice to user-space and reload the LDT only on the next
- * schedule. (only an issue on SMP)
- *
* the GDT index of the LDT is allocated dynamically, and is
* limited by MAX_LDT_DESCRIPTORS.
*/
down_write(&mm->mmap_sem);
if (!mm->context.segments) {
+ void * segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
error = -ENOMEM;
- mm->context.segments = vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE);
- if (!mm->context.segments)
+ if (!segments)
goto out_unlock;
- memset(mm->context.segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
-
- /*
- * Possibly do an SMP cross-call to other CPUs to reload
- * their LDTs?
- */
+ memset(segments, 0, LDT_ENTRIES*LDT_ENTRY_SIZE);
+ wmb();
+ mm->context.segments = segments;
+ mm->context.cpuvalid = 1UL << smp_processor_id();
load_LDT(mm);
}
/* Note: "err" is handled in a funny way below. Otherwise one version
of gcc or another breaks. */
-extern inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
+static inline int wrmsr_eio(u32 reg, u32 eax, u32 edx)
{
int err;
return err;
}
-extern inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
+static inline int rdmsr_eio(u32 reg, u32 *eax, u32 *edx)
{
int err;
cmd->err = rdmsr_eio(cmd->reg, &cmd->data[0], &cmd->data[1]);
}
-extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
{
struct msr_command cmd;
}
}
-extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
{
struct msr_command cmd;
#else /* ! CONFIG_SMP */
-extern inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
+static inline int do_wrmsr(int cpu, u32 reg, u32 eax, u32 edx)
{
return wrmsr_eio(reg, eax, edx);
}
-extern inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
+static inline int do_rdmsr(int cpu, u32 reg, u32 *eax, u32 *edx)
{
return rdmsr_eio(reg, eax, edx);
}
memcpy(ldt, old_ldt, LDT_ENTRIES*LDT_ENTRY_SIZE);
}
new_mm->context.segments = ldt;
+ new_mm->context.cpuvalid = ~0UL; /* valid on all CPU's - they can't have stale data */
}
/*
/* Some versions of gcc make it difficult to stop eax from being clobbered.
Merely specifying that it is used doesn't work...
*/
-extern inline unsigned long mul_32_32(const unsigned long arg1,
+static inline unsigned long mul_32_32(const unsigned long arg1,
const unsigned long arg2)
{
int retval;
/* Add the 12 byte Xsig x2 to Xsig dest, with no checks for overflow. */
-extern inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2)
+static inline void add_Xsig_Xsig(Xsig *dest, const Xsig *x2)
{
asm volatile ("movl %1,%%edi; movl %2,%%esi;
movl (%%esi),%%eax; addl %%eax,(%%edi);
/* Note: the constraints in the asm statement didn't always work properly
with gcc 2.5.8. Changing from using edi to using ecx got around the
problem, but keep fingers crossed! */
-extern inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
+static inline void add_two_Xsig(Xsig *dest, const Xsig *x2, long int *exp)
{
asm volatile ("movl %2,%%ecx; movl %3,%%esi;
movl (%%esi),%%eax; addl %%eax,(%%ecx);
/* Negate (subtract from 1.0) the 12 byte Xsig */
/* This is faster in a loop on my 386 than using the "neg" instruction. */
-extern inline void negate_Xsig(Xsig *x)
+static inline void negate_Xsig(Xsig *x)
{
asm volatile("movl %1,%%esi; "
"xorl %%ecx,%%ecx; "
_GLOBAL(_set_HID0)
sync
mtspr HID0, r3
- SYNC /* Handle erratas in some cases */
+ SYNC /* Handle errata in some cases */
blr
_GLOBAL(_get_ICTC)
CPP=$(CC) -E
OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
LDFLAGS=-e start
+ifeq ($(CONFIG_SHARED_KERNEL),y)
+LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux-shared.lds $(LDFLAGS)
+else
LINKFLAGS =-T $(TOPDIR)/arch/s390/vmlinux.lds $(LDFLAGS)
+endif
CFLAGS_PIPE := -pipe
CFLAGS_NSR := -fno-strength-reduce
SUBDIRS := $(SUBDIRS) arch/s390/mm arch/s390/kernel arch/s390/lib \
drivers/s390 arch/s390/math-emu
-CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES) \
- drivers/s390/io.o
+CORE_FILES := arch/s390/mm/mm.o arch/s390/kernel/kernel.o $(CORE_FILES)
+DRIVERS := $(DRIVERS) drivers/s390/io.o
LIBS := $(TOPDIR)/arch/s390/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390/lib/lib.a
ifeq ($(CONFIG_MATHEMU),y)
#
-# Makefile for the linux s390-specific parts of the memory manager.
+# arch/s390/boot/Makefile
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
+bool 'Pseudo page fault support' CONFIG_PFAULT
+bool 'VM shared kernel support' CONFIG_SHARED_KERNEL
endmenu
source drivers/s390/Config.in
# CONFIG_EISA is not set
# CONFIG_MCA is not set
CONFIG_UID16=y
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
CONFIG_ARCH_S390=y
#
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_PROCESS_DEBUG is not set
+CONFIG_PFAULT=y
+# CONFIG_SHARED_KERNEL is not set
#
# Block device drivers
#
# S/390 character device drivers
#
-CONFIG_3215=y
-CONFIG_3215_CONSOLE=y
+CONFIG_TN3270=y
+CONFIG_TN3270_CONSOLE=y
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
CONFIG_HWC=y
CONFIG_HWC_CONSOLE=y
+CONFIG_HWC_CPI=m
CONFIG_S390_TAPE=m
#
#
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
CONFIG_NET_ETHERNET=y
CONFIG_TR=y
# CONFIG_FDDI is not set
#
# S/390 network device drivers
#
-# CONFIG_CHANDEV is not set
+CONFIG_CHANDEV=y
+CONFIG_HOTPLUG=y
CONFIG_CTC=m
CONFIG_IUCV=m
# CONFIG_IP_MROUTE is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_NETLINK is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
# CONFIG_RAMFS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_NTFS_RW is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
# CONFIG_DEVFS_DEBUG is not set
# CONFIG_DEVPTS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
#
# Kernel hacking
#
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/version.h>
#include <asm/uaccess.h>
#include <linux/sys.h>
#include <linux/linkage.h>
#include <linux/config.h>
+#include <asm/cache.h>
#include <asm/lowcore.h>
#include <asm/errno.h>
#include <asm/smp.h>
#
# check, if bottom-half has to be done
#
- l %r0,__LC_IRQ_STAT # get softirq_active
- n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask
+ l %r1,processor(%r9) # get cpu number from task struture
+ sll %r1,L1_CACHE_SHIFT
+ al %r1,BASED(.Lirq_stat) # get address of irq_stat
+ icm %r0,15,0(%r1) # test irq_stat[#cpu].__softirq_pending
bnz BASED(sysc_handle_bottom_half)
#
# check, if reschedule is needed
lh %r7,__LC_PGM_ILC # load instruction length
GET_CURRENT
pgm_no_sv:
+ la %r3,0x7f
lh %r8,__LC_PGM_INT_CODE # N.B. saved int code used later KEEP it
- lr %r3,%r8
- la %r0,0x7f
- nr %r3,%r0 # clear per-event-bit
+ nr %r3,%r8 # reload & clear per-event-bit
be BASED(pgm_dn) # none of Martins exceptions occurred bypass
l %r1,BASED(.Ljump_table)
sll %r3,2
be BASED(pgm_go) # if yes then don't reenable interrupts
stosm 24(%r15),0x03 # reenable interrupts
pgm_go: basr %r14,%r1 # branch to interrupt-handler
-pgm_dn: la %r0,0x80
- nr %r8,%r0 # check for per exception
+pgm_dn: n %r8,BASED(.Lc128) # check for per excepton
be BASED(pgm_return)
la %r2,SP_PTREGS(15) # address of register-save area
l %r1,BASED(.Lhandle_per) # load adr. of per handler
#
# check, if bottom-half has to be done
#
- l %r0,__LC_IRQ_STAT # get softirq_active
- n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask
+ l %r1,processor(%r9) # get cpu number from task struture
+ sll %r1,L1_CACHE_SHIFT
+ al %r1,BASED(.Lirq_stat) # get address of irq_stat
+ icm %r0,15,0(%r1) # test irq_stat[#cpu].__softirq_pending
bnz BASED(io_handle_bottom_half)
io_return_bh:
#
.Lc0x2401: .long 0x2401
.Lc0x4000: .long 0x4000
.Lc0xff: .long 0xff
+.Lc128: .long 128
/*
* Symbol constants
.Lentry_base: .long entry_base
.Lext_hash: .long ext_int_hash
.Lhandle_per: .long handle_per_exception
+.Lirq_stat: .long irq_stat
.Ljump_table: .long pgm_check_table
.Lschedule: .long schedule
.Lclone: .long sys_clone
.org 0x10000
startup:basr %r13,0 # get base
.LPG1: lctl %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
- l %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area
+ la %r12,parmarea-.LPG1(%r13) # pointer to parameter area
# move IPL device to lowcore
mvc __LC_IPLDEV(4),IPL_DEVICE-PARMAREA(%r12)
# find out if we have an IEEE fpu
#
mvc __LC_PGM_NEW_PSW(8),.Lpcfpu-.LPG1(%r13)
- ld %f0,.Lflt0-.LPG1(%r13) # load (float) 0.0
- ldr %f2,%f0
- adbr %f0,%f2 # test IEEE add instruction
+ efpc %r0,0 # test IEEE extract fpc instruction
oi 3(%r12),2 # set IEEE fpu flag
.Lchkfpu:
mvc __LC_PGM_NEW_PSW(8),.Lpccsp-.LPG1(%r13)
la %r0,0
lr %r1,%r0
- la %r2,.Lflt0-.LPG1(%r13)
+ la %r2,4
csp %r0,%r2 # Test CSP instruction
oi 3(%r12),8 # set CSP flag
.Lchkcsp:
.Lpcfpu:.long 0x00080000,0x80000000 + .Lchkfpu
.Lpccsp:.long 0x00080000,0x80000000 + .Lchkcsp
.Lpcmvpg:.long 0x00080000,0x80000000 + .Lchkmvpg
-.Lflt0: .double 0
-.Lparm1:.long PARMAREA
.L4malign:.long 0xffc00000
-.Lbigmem:.long 0x04000000
-.Lrdstart:.long 0x02000000
-.Lmaxchunk:.long 0x00ffffff
.Lmemsize:.long memory_size
.Lmflags:.long machine_flags
# params at 10400 (setup.h)
#
.org PARMAREA
+parmarea:
.long 0,0 # IPL_DEVICE
.long 0,RAMDISK_ORIGIN # INITRD_START
.long 0,0x800000 # INITRD_SIZE
#
# startup-code, running in virtual mode
#
+#ifdef CONFIG_SHARED_KERNEL
+ .org 0x100000
+#else
.org 0x10800
+#endif
.globl _stext
_stext: basr %r13,0 # get base
.LPG2:
jo .-4 # branch back, if not finish
# check control registers
stctl %c0,%c15,0(%r15)
- oc 2(1,%r15),.Locbits+5-.LPG2(%r13) # enable sigp external ints.
- oc 0(1,%r15),.Locbits+4-.LPG2(%r13) # low addresss proctection
+ oi 2(%r15),0x20 # enable sigp external interrupts
+ oi 0(%r15),0x10 # switch on low address protection
lctl %c0,%c15,0(%r15)
#
basr %r13,0
lpsw .Ldw-.(%r13) # load disabled wait psw
#
-.Lstart: .long start_kernel
.align 8
+.Ldw: .long 0x000a0000,0x00000000
.Lprefix: .long init_S390_lowcore
.Linittu: .long init_task_union
+.Lstart: .long start_kernel
.Lbss_bgn: .long __bss_start
.Lbss_end: .long _end
-.Locbits: .long 0x01020408,0x10204080
- .align 4
.Laregs: .long 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
- .align 8
-.Ldw: .long 0x000a0000,0x00000000
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/string.h>
#include <linux/random.h>
#include <linux/smp.h>
*/
#ifdef CONFIG_SMP
atomic_t global_irq_holder = ATOMIC_INIT(NO_PROC_ID);
-atomic_t global_irq_lock;
+atomic_t global_irq_lock = ATOMIC_INIT(0);
atomic_t global_irq_count = ATOMIC_INIT(0);
atomic_t global_bh_count;
}
/* Duh, we have to loop. Release the lock to avoid deadlocks */
- clear_bit(0,&global_irq_lock);
+ atomic_set(&global_irq_lock, 0);
for (;;) {
if (!--count) {
if (!local_bh_count(cpu)
&& atomic_read(&global_bh_count))
continue;
- /* this works even though global_irq_lock not
- a long, but is arch-specific --RR */
- if (!test_and_set_bit(0,&global_irq_lock))
- break;
+ if (!atomic_compare_and_swap(0, 1, &global_irq_lock))
+ break;
}
}
}
static inline void get_irqlock(int cpu)
{
- /* this works even though global_irq_lock not a long, but is
- arch-specific --RR */
- if (test_and_set_bit(0,&global_irq_lock)) {
+ if (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0) {
/* do we already hold the lock? */
if ( cpu == atomic_read(&global_irq_holder))
return;
/* Uhhuh.. Somebody else got it. Wait.. */
do {
- do {
- check_smp_invalidate(cpu);
- } while (test_bit(0,&global_irq_lock));
- } while (test_and_set_bit(0,&global_irq_lock));
+ check_smp_invalidate(cpu);
+ } while (atomic_compare_and_swap(0, 1, &global_irq_lock) != 0);
}
/*
* We also to make sure that nobody else is running
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_irq_count);
+EXPORT_SYMBOL(global_bh_count);
#endif
EXPORT_SYMBOL(global_bh_lock);
wait_psw.mask = _WAIT_PSW_MASK;
wait_psw.addr = (unsigned long) &&idle_wakeup | 0x80000000L;
while(1) {
- if (softirq_active(smp_processor_id()) &
- softirq_mask(smp_processor_id())) {
+ if (softirq_pending(smp_processor_id())) {
do_softirq();
__sti();
if (!current->need_resched)
frame = (struct stack_frame *) (2*PAGE_SIZE + (unsigned long) p) -1;
frame = (struct stack_frame *) (((unsigned long) frame)&-8L);
- p->thread.regs = &frame->childregs;
+ p->thread.regs = (struct pt_regs *)&frame->childregs;
p->thread.ksp = (unsigned long) frame;
- frame->childregs = *regs;
+ memcpy(&frame->childregs,regs,sizeof(struct pt_regs));
frame->childregs.gprs[15] = new_stackp;
- frame->eos = 0;
+ frame->back_chain = frame->eos = 0;
/* new return point is ret_from_sys_call */
frame->gprs[8] = ((unsigned long) &ret_from_fork) | 0x80000000;
#undef last_sched
#undef first_sched
-/*
- * This should be safe even if called from tq_scheduler
- * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0.
- *
- */
-void s390_daemonize(char *name,unsigned long mask,int use_init_fs)
-{
- struct fs_struct *fs;
- extern struct task_struct *child_reaper;
- struct task_struct *this_process=current;
-
- /*
- * If we were started as result of loading a module, close all of the
- * user space pages. We don't need them, and if we didn't close them
- * they would be locked into memory.
- */
- exit_mm(current);
-
- this_process->session = 1;
- this_process->pgrp = 1;
- if(name)
- {
- strncpy(current->comm,name,15);
- current->comm[15]=0;
- }
- else
- current->comm[0]=0;
- /* set signal mask to what we want to respond */
- siginitsetinv(¤t->blocked,mask);
- /* exit_signal isn't set up */
- /* if we inherit from cpu idle */
- this_process->exit_signal=SIGCHLD;
- /* if priority=0 schedule can go into a tight loop */
- this_process->policy= SCHED_OTHER;
- /* nice goes priority=20-nice; */
- this_process->nice=10;
- if(use_init_fs)
- {
- exit_fs(this_process); /* current->fs->count--; */
- fs = init_task.fs;
- current->fs = fs;
- atomic_inc(&fs->count);
- exit_files(current);
- }
- write_lock_irq(&tasklist_lock);
- /* We want init as our parent */
- REMOVE_LINKS(this_process);
- this_process->p_opptr=this_process->p_pptr=child_reaper;
- SET_LINKS(this_process);
- write_unlock_irq(&tasklist_lock);
-}
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/lowcore.h>
#include <asm/s390_ext.h>
* Simple hash strategy: index = code & 0xff;
* ext_int_hash[index] is the start of the list for all external interrupts
* that hash to this index. With the current set of external interrupts
- * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
- * iucv) this is always the first element.
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
+ * iucv and 0x2603 pfault) this is always the first element.
*/
ext_int_info_t *ext_int_hash[256] = { 0, };
ext_int_info_t ext_int_info_timer;
ext_int_info_t ext_int_info_hwc;
+ext_int_info_t ext_int_pfault;
int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
ext_int_info_t *p;
p = &ext_int_info_timer;
else if (code == 0x2401) /* hwc_init is done too early too */
p = &ext_int_info_hwc;
- else
+ else if (code == 0x2603) /* pfault_init is done too early too */
+ p = &ext_int_pfault;
+ else
p = (ext_int_info_t *)
kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
if (p == NULL)
q->next = p->next;
else
ext_int_hash[index] = p->next;
- if (code != 0x1004 && code != 0x2401)
+ if (code != 0x1004 && code != 0x2401 && code != 0x2603)
kfree(p);
return 0;
}
EXPORT_SYMBOL_NOVERS(strncpy);
EXPORT_SYMBOL_NOVERS(strnlen);
EXPORT_SYMBOL_NOVERS(strrchr);
+EXPORT_SYMBOL_NOVERS(strstr);
EXPORT_SYMBOL_NOVERS(strtok);
EXPORT_SYMBOL_NOVERS(strpbrk);
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(kernel_thread);
EXPORT_SYMBOL(csum_fold);
+EXPORT_SYMBOL(console_mode);
+EXPORT_SYMBOL(console_device);
#if CONFIG_IP_MULTICAST
/* Required for lcs gigabit ethernet multicast support */
/*
* Machine setup..
*/
+unsigned int console_mode = 0;
+unsigned int console_device = -1;
unsigned long memory_size = 0;
unsigned long machine_flags = 0;
__u16 boot_cpu_addr;
__setup("vmpoff=", vmpoff_setup);
+/*
+ * condev= and conmode= setup parameter.
+ */
+
+static int __init condev_setup(char *str)
+{
+ int vdev;
+
+ vdev = simple_strtoul(str, &str, 0);
+ if (vdev >= 0 && vdev < 65536)
+ console_device = vdev;
+ return 1;
+}
+
+__setup("condev=", condev_setup);
+
+static int __init conmode_setup(char *str)
+{
+#if defined(CONFIG_HWC_CONSOLE)
+ if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+ SET_CONSOLE_HWC;
+#endif
+#if defined(CONFIG_TN3215_CONSOLE)
+ if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+ SET_CONSOLE_3215;
+#endif
+#if defined(CONFIG_TN3270_CONSOLE)
+ if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+ SET_CONSOLE_3270;
+#endif
+ return 1;
+}
+
+__setup("conmode=", conmode_setup);
+
+static void __init conmode_default(void)
+{
+ char query_buffer[1024];
+ char *ptr;
+
+ if (MACHINE_IS_VM) {
+ cpcmd("QUERY TERM", query_buffer, 1024);
+ ptr = strstr(query_buffer, "CONMODE");
+ /*
+ * Set the conmode to 3215 so that the device recognition
+ * will set the cu_type of the console to 3215. If the
+ * conmode is 3270 and we don't set it back then both
+ * 3215 and the 3270 driver will try to access the console
+ * device (3215 as console and 3270 as normal tty).
+ */
+ cpcmd("TERM CONMODE 3215", NULL, 0);
+ if (ptr == NULL) {
+#if defined(CONFIG_HWC_CONSOLE)
+ SET_CONSOLE_HWC;
+#endif
+ return;
+ }
+ if (strncmp(ptr + 8, "3270", 4) == 0) {
+#if defined(CONFIG_TN3270_CONSOLE)
+ SET_CONSOLE_3270;
+#elif defined(CONFIG_TN3215_CONSOLE)
+ SET_CONSOLE_3215;
+#elif defined(CONFIG_HWC_CONSOLE)
+ SET_CONSOLE_HWC;
+#endif
+ } else if (strncmp(ptr + 8, "3215", 4) == 0) {
+#if defined(CONFIG_TN3215_CONSOLE)
+ SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+ SET_CONSOLE_3270;
+#elif defined(CONFIG_HWC_CONSOLE)
+ SET_CONSOLE_HWC;
+#endif
+ }
+ } else if (MACHINE_IS_P390) {
+#if defined(CONFIG_TN3215_CONSOLE)
+ SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+ SET_CONSOLE_3270;
+#endif
+ } else {
+#if defined(CONFIG_HWC_CONSOLE)
+ SET_CONSOLE_HWC;
+#endif
+ }
+}
+
/*
* Reboot, halt and power_off routines for non SMP.
*/
return;
smptrap=1;
- printk("Command line is: %s\n", COMMAND_LINE);
-
/*
* Setup lowcore information for boot cpu
*/
* "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
*/
if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
- if (to != command_line) to--;
delay = simple_strtoul(from+9, &from, 0);
if (*from == 's' || *from == 'S') {
delay = delay*1000000;
delay = delay*60*1000000;
from++;
}
- /* now wait for the requestedn amount of time */
+ /* now wait for the requested amount of time */
udelay(delay);
}
cn = *(from++);
break;
if (cn == '\n')
cn = ' '; /* replace newlines with space */
+ if (cn == 0x0d)
+ cn = ' '; /* replace 0x0d with space */
if (cn == ' ' && c == ' ')
continue; /* remove additional spaces */
c = cn;
request_resource(&iomem_resource, res);
request_resource(res, &code_resource);
request_resource(res, &data_resource);
+
+ /* Setup default console */
+ conmode_default();
}
void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
/* Set up registers for signal handler */
regs->gprs[15] = (addr_t)frame;
regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+ regs->psw.mask = _USER_PSW_MASK;
}
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
#endif
/* Martin wants this for pthreads */
regs->gprs[3] = (addr_t)&frame->sc;
+
+ /* We forgot to include these in the sigcontext.
+ To avoid breaking binary compatibility, they are passed as args. */
+ regs->gprs[4] = current->thread.trap_no;
+ regs->gprs[5] = current->thread.prot_addr;
return;
give_sigsegv:
siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
{
/* Are we from a system call? */
- if (regs->orig_gpr2 >= 0) {
+ if (regs->trap == __LC_SVC_OLD_PSW) {
/* If so, check system call restarting.. */
switch (regs->gprs[2]) {
case -ERESTARTNOHAND:
/* FALLTHRU */
default:
- lock_kernel();
sigaddset(¤t->pending.signal, signr);
recalc_sigpending(current);
current->flags |= PF_SIGNALED;
* Activate a secondary processor.
*/
extern void init_100hz_timer(void);
+extern int pfault_token(void);
int __init start_secondary(void *cpuvoid)
{
/* nothing */ ;
/* init per CPU 100 hz timer */
init_100hz_timer();
+#ifdef CONFIG_PFAULT
+ /* Enable pfault pseudo page faults on this cpu. */
+ pfault_init();
+#endif
/* cpu_idle will call schedule for us */
return cpu_idle(NULL);
}
{
unsigned long flags;
unsigned long usec, sec;
- unsigned long lost_ticks = jiffies - wall_jiffies;
+ unsigned long lost_ticks;
read_lock_irqsave(&xtime_lock, flags);
+ lost_ticks = jiffies - wall_jiffies;
usec = do_gettimeoffset();
if (lost_ticks)
usec +=(USECS_PER_JIFFY*lost_ticks);
#include <asm/gdb-stub.h>
#endif
#include <asm/cpcmd.h>
+#include <asm/s390_ext.h>
/* Called from entry.S only */
extern void handle_per_exception(struct pt_regs *regs);
extern pgm_check_handler_t do_page_fault;
extern pgm_check_handler_t do_pseudo_page_fault;
+#ifdef CONFIG_PFAULT
+extern int pfault_init(void);
+extern void pfault_fini(void);
+extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+#endif
spinlock_t die_lock;
DO_ERROR(SIGILL, "privileged operation", privileged_op)
DO_ERROR(SIGILL, "execute exception", execute_exception)
DO_ERROR(SIGSEGV, "addressing exception", addressing_exception)
-DO_ERROR(SIGILL, "fixpoint divide exception", divide_exception)
+DO_ERROR(SIGFPE, "fixpoint divide exception", divide_exception)
DO_ERROR(SIGILL, "translation exception", translation_exception)
DO_ERROR(SIGILL, "special operand exception", special_op_exception)
DO_ERROR(SIGILL, "operand exception", operand_exception)
int signal = 0;
int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE);
- lock_kernel();
location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
if(problem_state)
get_user(*((__u16 *) opcode), location);
} else if (signal)
do_trap(interruption_code, signal,
"illegal operation", regs, NULL);
- unlock_kernel();
}
__u16 *location;
int signal = 0;
- lock_kernel();
if (regs->psw.mask & PSW_PROBLEM_STATE) {
location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
get_user(*((__u16 *) opcode), location);
} else if (signal)
do_trap(interruption_code, signal,
"specification exception", regs, NULL);
- unlock_kernel();
}
#else
DO_ERROR(SIGILL, "specification exception", specification_exception)
__u16 *location;
int signal = 0;
- lock_kernel();
location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
if (MACHINE_HAS_IEEE)
__asm__ volatile ("stfpc %0\n\t"
} else if (signal)
do_trap(interruption_code, signal,
"data exception", regs, NULL);
- unlock_kernel();
}
pgm_check_table[0x14] = &do_pseudo_page_fault;
pgm_check_table[0x15] = &operand_exception;
pgm_check_table[0x1C] = &privileged_op;
+#ifdef CONFIG_PFAULT
+ if (MACHINE_IS_VM) {
+ /* request the 0x2603 external interrupt */
+ if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+ panic("Couldn't request external interrupt 0x2603");
+ /*
+ * First try to get pfault pseudo page faults going.
+ * If this isn't available turn on pagex page faults.
+ */
+ if (pfault_init() != 0) {
+ /* Tough luck, no pfault. */
+ unregister_external_interrupt(0x2603,
+ pfault_interrupt);
+ cpcmd("SET PAGEX ON", NULL, 0);
+ }
+ }
+#else
if (MACHINE_IS_VM)
- cpcmd("SET PAGEX ON", NULL, 0);
+ cpcmd("SET PAGEX ON", NULL, 0);
+#endif
}
#
-# Makefile for the linux i386-specific parts of the memory manager.
+# Makefile for the linux s390-specific parts of the memory manager.
#
# Note! Dependencies are done automagically by 'make dep', which also
# removes any old dependencies. DON'T put your own dependencies here
#include <linux/smp.h>
#include <linux/smp_lock.h>
#include <linux/compatmac.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
unsigned long address;
unsigned long fixup;
int write;
- unsigned long psw_mask;
- unsigned long psw_addr;
int si_code = SEGV_MAPERR;
int kernel_address = 0;
- /*
- * get psw mask of Program old psw to find out,
- * if user or kernel mode
- */
-
- psw_mask = S390_lowcore.program_old_psw.mask;
- psw_addr = S390_lowcore.program_old_psw.addr;
-
/*
* get the failing address
* more specific the segment and page table portion of
* the address
*/
-
address = S390_lowcore.trans_exc_code&0x7ffff000;
tsk = current;
up_read(&mm->mmap_sem);
/* User mode accesses just cause a SIGSEGV */
- if (psw_mask & PSW_PROBLEM_STATE) {
+ if (regs->psw.mask & PSW_PROBLEM_STATE) {
struct siginfo si;
tsk->thread.prot_addr = address;
tsk->thread.trap_no = error_code;
out_of_memory:
up_read(&mm->mmap_sem);
printk("VM: killing process %s\n", tsk->comm);
- if (psw_mask & PSW_PROBLEM_STATE)
+ if (regs->psw.mask & PSW_PROBLEM_STATE)
do_exit(SIGKILL);
goto no_context;
force_sig(SIGBUS, tsk);
/* Kernel mode? Handle exceptions or die */
- if (!(psw_mask & PSW_PROBLEM_STATE))
+ if (!(regs->psw.mask & PSW_PROBLEM_STATE))
goto no_context;
}
static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */
/*
- * This routine handles pseudo page faults.
+ * This routine handles 'pagex' pseudo page faults.
*/
asmlinkage void
do_pseudo_page_fault(struct pt_regs *regs, unsigned long error_code)
{
- DECLARE_WAITQUEUE(wait, current);
pseudo_wait_t wait_struct;
pseudo_wait_t *ptr, *last, *next;
- unsigned long psw_mask;
unsigned long address;
int kernel_address;
- /*
- * get psw mask of Program old psw to find out,
- * if user or kernel mode
- */
- psw_mask = S390_lowcore.program_old_psw.mask;
-
/*
* get the failing address
* more specific the segment and page table portion of
spin_unlock(&pseudo_wait_spinlock);
} else {
/* Pseudo page faults in kernel mode is a bad idea */
- if (!(psw_mask & PSW_PROBLEM_STATE)) {
+ if (!(regs->psw.mask & PSW_PROBLEM_STATE)) {
/*
* VM presents pseudo page faults if the interrupted
* state was not disabled for interrupts. So we can
wait_event(wait_struct.queue, wait_struct.resolved);
}
}
-
+
+#ifdef CONFIG_PFAULT
+/*
+ * 'pfault' pseudo page faults routines.
+ */
+static int pfault_disable = 0;
+
+static int __init nopfault(char *str)
+{
+ pfault_disable = 1;
+ return 1;
+}
+
+__setup("nopfault", nopfault);
+
+typedef struct {
+ __u16 refdiagc;
+ __u16 reffcode;
+ __u16 refdwlen;
+ __u16 refversn;
+ __u64 refgaddr;
+ __u64 refselmk;
+ __u64 refcmpmk;
+ __u64 reserved;
+} __attribute__ ((packed)) pfault_refbk_t;
+
+int pfault_init(void)
+{
+ pfault_refbk_t refbk =
+ { 0x258, 0, 5, 2, __LC_KERNEL_STACK, 1ULL << 48, 1ULL << 48, 0ULL };
+ int rc;
+
+ if (pfault_disable)
+ return -1;
+ __asm__ __volatile__(
+ " diag %1,%0,0x258\n"
+ "0: j 2f\n"
+ "1: la %0,8\n"
+ "2:\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 0b,1b\n"
+ ".previous"
+ : "=d" (rc) : "a" (&refbk) : "cc" );
+ __ctl_set_bit(0, 9);
+ return rc;
+}
+
+void pfault_fini(void)
+{
+ pfault_refbk_t refbk =
+ { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
+
+ if (pfault_disable)
+ return;
+ __ctl_clear_bit(0,9);
+ __asm__ __volatile__(
+ " diag %0,0,0x258\n"
+ "0:\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .long 0b,0b\n"
+ ".previous"
+ : : "a" (&refbk) : "cc" );
+}
+
+asmlinkage void
+pfault_interrupt(struct pt_regs *regs, __u16 error_code)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct task_struct *tsk;
+ wait_queue_head_t queue;
+ wait_queue_head_t *qp;
+ __u16 subcode;
+
+ /*
+ * Get the external interruption subcode & pfault
+ * initial/completion signal bit. VM stores this
+ * in the 'cpu address' field associated with the
+ * external interrupt.
+ */
+ subcode = S390_lowcore.cpu_addr;
+ if ((subcode & 0xff00) != 0x06)
+ return;
+
+ /*
+ * Get the token (= address of kernel stack of affected task).
+ */
+ tsk = (struct task_struct *)
+ (*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE);
+
+ if (subcode & 0x0080) {
+ /* signal bit is set -> a page has been swapped in by VM */
+ qp = (wait_queue_head_t *)
+ xchg(&tsk->thread.pfault_wait, -1);
+ if (qp != NULL) {
+ /* Initial interrupt was faster than the completion
+ * interrupt. pfault_wait is valid. Set pfault_wait
+ * back to zero and wake up the process. This can
+ * safely be done because the task is still sleeping
+ * and can't procude new pfaults. */
+ tsk->thread.pfault_wait = 0ULL;
+ wake_up(qp);
+ }
+ } else {
+ /* signal bit not set -> a real page is missing. */
+ init_waitqueue_head (&queue);
+ qp = (wait_queue_head_t *)
+ xchg(&tsk->thread.pfault_wait, (addr_t) &queue);
+ if (qp != NULL) {
+ /* Completion interrupt was faster than the initial
+ * interrupt (swapped in a -1 for pfault_wait). Set
+ * pfault_wait back to zero and exit. This can be
+ * done safely because tsk is running in kernel
+ * mode and can't produce new pfaults. */
+ tsk->thread.pfault_wait = 0ULL;
+ }
+
+ /* go to sleep */
+ wait_event(queue, tsk->thread.pfault_wait == 0ULL);
+ }
+}
+#endif
+
+++ /dev/null
-all: dasdfmt
-
-dasdfmt: dasdfmt.c
- $(CC) -o $@ $^
- $(STRIP) $@
-
-clean:
- rm -f dasdfmt
-
+++ /dev/null
-.TH DASDFMT 8 "Tue Jan 25 2000"
-.UC 4
-.SH NAME
-dasdfmt \- formatting of DSAD (ECKD) disk drives.
-.SH SYNOPSIS
-\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
-.SH DESCRIPTION
-\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
-for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
-\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.
-
-.SH OPTIONS
-.TP
-\fB-t\fR
-Disables any modification of the disk drive. \fBdasdfmt\fR just prints
-out, what it \fBwould\fR do.
-
-.TP
-\fB-v\fR
-Increases verbosity.
-
-.TP
-\fB-y\fR
-Start formatting without further user-confirmation.
-
-.TP
-\fB-L\fR
-Omit the writing of a disk label after formatting.
-
-.TP
-\fB-V\fR
-Print version number and exit.
-
-.TP
-\fB-b\fR \fIblockSize\fR
-Specify blocksize to be used. \fIblocksize\fR must be a positive integer
-and always be a power of two. Due due some limitations in the driver,
-it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
-
-.TP
-\fB-l\fR \fIdiskLabel\fR
-Specify the label to be written to disk after formatting. If no label is
-specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
-ASCII string and is automatically converted to EBCDIC.
-
-.TP
-\fIdiskSpec\fR
-This parameter specified the device to be formatted. It also can be
-given in two variants:
-.sp
- \fB-f\fR \fB/dev/dasd\fR\fIX\fR
-.br
-or
-.br
- \fB-n\fR \fIdevnum\fR
-.sp
-The first form uses the commonly used
-.SM UNIX
-device notation where \fIX\fR is a single lowercase letter.
-The second form uses simply the device number.
-
-.SH BUGS
-None so far ;-)
-
-.SH AUTHOR
-.nf
-This man-page was written by Fritz Elfert <felfert@to.com>
-.fi
+++ /dev/null
-/*
- *
- * dasdfmt.c
- *
- * S390 version
- * Copyright (C) 1999,2000 IBM Corporation
- * Author(s): Utz Bacher, <utz.bacher@de.ibm.com>
- *
- * Device-in-use-checks by Fritz Elfert, <felfert@to.com>
- * Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com>
- *
- * Still to do:
- * detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them
- */
-
-/* #define _LINUX_BLKDEV_H */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <mntent.h>
-#define __KERNEL__ /* we want to use kdev_t and not have to define it */
-#include <linux/kdev_t.h>
-#undef __KERNEL__
-
-#include <linux/fs.h>
-#include <asm/dasd.h>
-#include <linux/hdreg.h>
-
-#define EXIT_MISUSE 1
-#define EXIT_BUSY 2
-#define TEMPFILENAME "/tmp/ddfXXXXXX"
-#define TEMPFILENAMECHARS 8 /* 8 characters are fixed in all temp filenames */
-#define SLASHDEV "/dev/"
-#define PROC_DASD_DEVICES "/proc/dasd/devices"
-/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */
-#define PROC_MOUNTS _PATH_MOUNTED
-#define PROC_SWAPS "/proc/swaps"
-#define DASD_DRIVER_NAME "dasd"
-#define LABEL_LENGTH 10
-#define PROC_LINE_LENGTH 80
-#define ERR_LENGTH 80
-
-#define MAX_FILELEN NAME_MAX+PATH_MAX
-
-#define GIVEN_DEVNO 1
-#define GIVEN_MAJOR 2
-#define GIVEN_MINOR 4
-
-#define CHECK_START 1
-#define CHECK_END 2
-#define CHECK_BLKSIZE 4
-#define CHECK_ALL ~0
-
-#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
-#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);}
-
-#define CHECK_SPEC_MAX_ONCE(i,str) \
- {if (i>1) \
- ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
- "can only be specified once\n",prog_name);}
-
-#define PARSE_PARAM_INTO(x,param,base,str) \
- {x=(int)strtol(param,&endptr,base); \
- if (*endptr) \
- ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
- "is in invalid format\n",prog_name);}
-
-char *prog_name;/*="dasdfmt";*/
-char tempfilename[]=TEMPFILENAME;
-
-__u8 _ascebc[256] =
-{
- /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
- 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
- /*08 BS HT LF VT FF CR SO SI */
- /* ->NL */
- 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
- 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
- /*18 CAN EM SUB ESC FS GS RS US */
- /* ->IGS ->IRS ->IUS */
- 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
- /*20 SP ! " # $ % & ' */
- 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
- /*28 ( ) * + , - . / */
- 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
- /*30 0 1 2 3 4 5 6 7 */
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
- /*38 8 9 : ; < = > ? */
- 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
- /*40 @ A B C D E F G */
- 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
- /*48 H I J K L M N O */
- 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
- /*50 P Q R S T U V W */
- 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
- /*58 X Y Z [ \ ] ^ _ */
- 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
- /*60 ` a b c d e f g */
- 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- /*68 h i j k l m n o */
- 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
- /*70 p q r s t u v w */
- 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
- /*78 x y z { | } ~ DL */
- 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
- /*80*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*88*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*90*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*98*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*A0*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*A8*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*B0*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*B8*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*C0*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*C8*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*D0*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*D8*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*E0 sz */
- 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*E8*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*F0*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*F8*/
- 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
-};
-
-void convert_label(char *str)
-{
- int i;
- for (i=0;i<LABEL_LENGTH;i++) str[i]=_ascebc[str[i]];
-}
-
-void
-exit_usage(int exitcode)
-{
-#ifdef RANGE_FORMATTING
- printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \
- "<diskspec>\n\n",prog_name);
-#else /* RANGE_FORMATTING */
- printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \
- "<diskspec>\n\n",prog_name);
-#endif /* RANGE_FORMATTING */
- printf(" -t means testmode\n");
- printf(" -v means verbose mode\n");
- printf(" -C means format compatible disk layout\n");
- printf(" -V means print version\n");
- printf(" -L means don't write disk label\n");
- printf(" <label> is a label which is converted to EBCDIC and " \
- "written to disk\n");
- printf(" <blocksize> has to be power of 2 and at least 512\n");
-#ifdef RANGE_FORMATTING
- printf(" <range> is either\n");
- printf(" -s <start_track> -e <end_track>\n");
- printf(" or\n");
- printf(" -r <start_track>-<end_track>\n");
-#endif /* RANGE_FORMATTING */
- printf(" and <diskspec> is either\n");
- printf(" -f /dev/dasdX\n");
- printf(" or\n");
- printf(" -n <s390-devnr>\n");
- exit(exitcode);
-}
-
-void
-get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode)
-{
- FILE *file;
- int d,rc;
- kdev_t mi,ma;
- int mi_i,ma_i; /* for scanf :-( */
- char line[PROC_LINE_LENGTH];
-
- file=fopen(PROC_DASD_DEVICES,"r");
- if (file==NULL)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to open " \
- PROC_DASD_DEVICES ": %s (do you have the /proc " \
- "filesystem enabled?)\n",prog_name,strerror(errno));
-
- /* fgets(line,sizeof(line),file); omit first line */
- while (fgets(line,sizeof(line),file)!=NULL) {
- rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i);
- ma=ma_i;
- mi=mi_i;
- if ( (rc==3) &&
- !((d!=*devno)&&(mode&GIVEN_DEVNO)) &&
- !((ma!=*major_no)&&(mode&GIVEN_MAJOR)) &&
- !((mi!=*minor_no)&&(mode&GIVEN_MINOR)) ) {
- *devno=d;
- *major_no=ma;
- *minor_no=mi;
- /* yes, this is a quick exit, but the easiest way */
- fclose(file);
- return;
- }
- }
- fclose(file);
-
- ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \
- "filesystem (are you sure to have the right parameter " \
- "dasd=xxx?)\n",
- prog_name);
-}
-
-char *
-get_devname_from_devno(int devno,int verbosity)
-{
- kdev_t major_no,minor_no;
- kdev_t file_major,file_minor;
- struct stat stat_buf;
- int rc;
- int found;
- char *devname;
- char tmpname[MAX_FILELEN];
-
- DIR *dp;
- struct dirent *direntp;
-
- /**** get minor number ****/
- get_xno_from_xno(&devno,&major_no,&minor_no,GIVEN_DEVNO);
-
- /**** get device file ****/
- if ((dp=opendir(SLASHDEV)) == NULL)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: unable to read " SLASHDEV \
- "\n",prog_name);
- found=0;
- while ((direntp=readdir(dp)) != NULL) {
- strcpy(tmpname,SLASHDEV);
- strcat(tmpname,direntp->d_name);
- rc=stat(tmpname,&stat_buf);
- if (!rc) {
- file_major=MAJOR(stat_buf.st_rdev);
- file_minor=MINOR(stat_buf.st_rdev);
- if ((file_major==major_no) && (file_minor==minor_no)) {
- found=1;
- break;
- }
- }
- }
- if (found) {
- devname=malloc(strlen(direntp->d_name));
- strcpy(devname,tmpname);
- }
- rc=closedir(dp);
- if (rc<0) ERRMSG("%s: unable to close directory " SLASHDEV \
- "; continuing\n",prog_name);
- if (found)
- return devname;
-
- if (verbosity>=1)
- printf("I didn't find device node in " SLASHDEV \
- "; trying to create a temporary node\n");
-
- /**** get temp file and create device node *****/
- rc=mkstemp(tempfilename);
- if (rc==-1)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to get temporary " \
- "filename: %s\n",prog_name,strerror(errno));
- close(rc);
- rc=unlink(tempfilename);
-
- rc=mknod(tempfilename,S_IFBLK|0600,MKDEV(major_no,minor_no));
- if (rc)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to create temporary " \
- "device node %s: %s\n",prog_name,tempfilename,
- strerror(errno));
- return tempfilename;
-}
-
-char *
-check_param(int mode,format_data_t data)
-{
- char *s;
-
- if (NULL==(s=malloc(ERR_LENGTH)))
- ERRMSG_EXIT(EXIT_FAILURE,"%s: not enough memory.\n",prog_name);
-
- if ((mode&CHECK_START)&&(data.start_unit<0)) {
- strcpy(s,"start track must be greater than zero");
- goto exit;
- }
- if ((mode&CHECK_END)&&(data.stop_unit<-1)) {
- strcpy(s,"end track must be -1 or greater than zero");
- goto exit;
- }
- if ((mode&CHECK_END)&&(data.start_unit>data.stop_unit)&&
- (data.stop_unit!=-1)) {
- strcpy(s,"end track must be higher than start track");
- goto exit;
- }
-
- if ((mode&CHECK_BLKSIZE)&&(data.blksize<1)) {
- strcpy(s,"blocksize must be a positive integer");
- goto exit;
- }
- if (mode&CHECK_BLKSIZE) while (data.blksize>0) {
- if ((data.blksize%2)&&(data.blksize!=1)) {
- strcpy(s,"blocksize must be a power of 2");
- goto exit;
- }
- data.blksize/=2;
- }
-
- free(s);
- return NULL;
-exit:
- return s;
-}
-
-#define ASK_PRINTOUT printf("Please enter %s",output)
-#define ASK_GETBUFFER fgets(buffer,sizeof(buffer),stdin)
-#define ASK_SCANFORNUMBER(var) rc=sscanf(buffer,"%d%c",&var,&c)
-#define ASK_COMPLAIN_FORMAT if ((rc==2)&&(c=='\n')) rc=1; \
- if (rc==-1) rc=1; /* this happens, if enter is pressed */ \
- if (rc!=1) printf(" -- wrong input, try again.\n")
-#define ASK_CHECK_PARAM(mode) str=check_param(mode,params); \
- if (str!=NULL) { printf(" -- %s\n",str); rc=0; free(str); }
-
-format_data_t
-ask_user_for_data(format_data_t params)
-{
- char buffer[20]; /* should be enough for inputing track numbers */
- char c;
- int i,rc;
- char *str;
- char output[60],o2[12];
-
-#ifdef RANGE_FORMATTING
- i=params.start_unit;
- do {
- params.start_unit=i;
- sprintf(output,"the start track of the range to format " \
- "[%d]: ",i);
- ASK_PRINTOUT;
- ASK_GETBUFFER;
- ASK_SCANFORNUMBER(params.start_unit);
- ASK_COMPLAIN_FORMAT;
- ASK_CHECK_PARAM(CHECK_START);
- } while (rc!=1);
-
- i=params.stop_unit;
- do {
- params.stop_unit=i;
- sprintf(output,"the end track of the range to format [");
- if (i==-1) sprintf(o2,"END]: "); else
- sprintf(o2,"%d]: ",i);
- strcat(output,o2);
- ASK_PRINTOUT;
- ASK_GETBUFFER;
- if ( (!strcasecmp(buffer,"end")) ||
- (!strcasecmp(buffer,"end\n")) ) {
- rc=1;
- params.stop_unit=-1;
- } else {
- ASK_SCANFORNUMBER(params.stop_unit);
- ASK_COMPLAIN_FORMAT;
- ASK_CHECK_PARAM(CHECK_END);
- }
- } while (rc!=1);
-#endif /* RANGE_FORMATTING */
-
- i=params.blksize;
- do {
- params.blksize=i;
- sprintf(output,"the blocksize of the formatting [%d]: ",i);
- ASK_PRINTOUT;
- ASK_GETBUFFER;
- ASK_SCANFORNUMBER(params.blksize);
- ASK_COMPLAIN_FORMAT;
- ASK_CHECK_PARAM(CHECK_BLKSIZE);
- } while (rc!=1);
-
- return params;
-}
-
-/* Check if the device we are going to format is mounted.
- * If true, complain and exit.
- */
-void
-check_mounted(int major, int minor)
-{
- FILE *f;
- int ishift = 0;
- struct mntent *ment;
- struct stat stbuf;
- char line[128];
-
- /* If whole disk to be formatted ... */
- if ((minor % (1U << DASD_PARTN_BITS)) == 0) {
- /* ... ignore partition-selector */
- minor >>= DASD_PARTN_BITS;
- ishift = DASD_PARTN_BITS;
- }
- /*
- * first, check filesystems
- */
- if (!(f = fopen(PROC_MOUNTS, "r")))
- ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", PROC_MOUNTS,
- strerror(errno));
- while ((ment = getmntent(f))) {
- if (stat(ment->mnt_fsname, &stbuf) == 0)
- if ((major == MAJOR(stbuf.st_rdev)) &&
- (minor == (MINOR(stbuf.st_rdev)>>ishift))) {
- ERRMSG("%s: device is mounted on %s!!\n",
- prog_name,ment->mnt_dir);
- ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
- "format it, please unmount it.\n");
- }
- }
- fclose(f);
- /*
- * second, check active swap spaces
- */
- if (!(f = fopen(PROC_SWAPS, "r")))
- ERRMSG_EXIT(EXIT_FAILURE, PROC_SWAPS " %s", strerror(errno));
- /*
- * skip header line
- */
- fgets(line, sizeof(line), f);
- while (fgets(line, sizeof(line), f)) {
- char *p;
- for (p = line; *p && (!isspace(*p)); p++) ;
- *p = '\0';
- if (stat(line, &stbuf) == 0)
- if ((major == MAJOR(stbuf.st_rdev)) &&
- (minor == (MINOR(stbuf.st_rdev)>>ishift))) {
- ERRMSG("%s: the device is in use for "
- "swapping!!\n",prog_name);
- ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
- "format it, please use swapoff %s.\n",
- line);
- }
- }
- fclose(f);
-}
-
-void
-do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
- int verbosity,int writenolabel,int labelspec,
- char *label,int withoutprompt,int devno)
-{
- int fd,rc;
- struct stat stat_buf;
- kdev_t minor_no,major_no;
- int new_blksize;
- unsigned int label_position;
- struct hd_geometry new_geometry;
- char inp_buffer[5]; /* to contain yes */
-
- fd=open(dev_name,O_RDWR);
- if (fd==-1)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: error opening device %s: " \
- "%s\n",prog_name,dev_name,strerror(errno));
-
- if (verbosity>=1) {
- }
-
- rc=stat(dev_name,&stat_buf);
- if (rc) {
- ERRMSG_EXIT(EXIT_FAILURE,"%s: error occurred during stat: " \
- "%s\n",prog_name,strerror(errno));
- } else {
- if (!S_ISBLK(stat_buf.st_mode))
- ERRMSG_EXIT(EXIT_FAILURE,"%s: file is not a " \
- "blockdevice.\n",prog_name);
- major_no=MAJOR(stat_buf.st_rdev);
- minor_no=MINOR(stat_buf.st_rdev);
- }
- check_mounted(major_no, minor_no);
-
- get_xno_from_xno(&devno,&major_no,&minor_no,
- GIVEN_MAJOR|GIVEN_MINOR);
- if ((!writenolabel) && (!labelspec)) {
- sprintf(label,"LNX1 x%04x",devno);
- }
-
- if ( ((withoutprompt)&&(verbosity>=1)) ||
- (!withoutprompt) ) {
- printf("\nI am going to format the device %s in the " \
- "following way:\n",dev_name);
- printf(" Device number of device : 0x%x\n",devno);
- printf(" Major number of device : %u\n",major_no);
- printf(" Minor number of device : %u\n",minor_no);
- printf(" Labelling device : %s\n",(writenolabel)?
- "no":"yes");
- if (!writenolabel)
- printf(" Disk label : %s\n",label);
- if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY)
- printf(" Compatible Disk Layout : %s\n",(format_params.intensity&0x08)?
- "yes":"no");
-#ifdef RANGE_FORMATTING
- printf(" Start track : %d\n" \
- ,format_params.start_unit);
- printf(" End track : ");
- if (format_params.stop_unit==-1)
- printf("last track of disk\n");
- else
- printf("%d\n",format_params.stop_unit);
-#endif /* RANGE_FORMATTING */
- printf(" Blocksize : %d\n" \
- ,format_params.blksize);
- if (testmode) printf("Test mode active, omitting ioctl.\n");
- }
-
- while (!testmode) {
- if (!withoutprompt) {
- printf("\n--->> ATTENTION! <<---\n");
- printf("All data in the specified range of that " \
- "device will be lost.\nType \"yes\" to " \
- "continue, no will leave the disk untouched: ");
- fgets(inp_buffer,sizeof(inp_buffer),stdin);
- if (strcasecmp(inp_buffer,"yes") &&
- strcasecmp(inp_buffer,"yes\n")) {
- printf("Omitting ioctl call (disk will " \
- "NOT be formatted).\n");
- break;
- }
- }
-
- if ( !( (withoutprompt)&&(verbosity<1) ))
- printf("Formatting the device. This may take a " \
- "while (get yourself a coffee).\n");
- rc=ioctl(fd,BIODASDFORMAT,format_params);
- if (rc)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \
- "returned with the following error " \
- "message:\n%s\n",prog_name,strerror(errno));
- printf("Finished formatting the device.\n");
-
- if (!writenolabel) {
- if (verbosity>0)
- printf("Retrieving disk geometry... ");
-
- rc=ioctl(fd,HDIO_GETGEO,&new_geometry);
- if (rc) {
- ERRMSG("%s: the ioctl call to get geometry " \
- "returned with the following error " \
- "message:\n%s\n",prog_name,
- strerror(errno));
- goto reread;
- }
-
-
- rc=ioctl(fd,BLKSSZGET,&new_blksize);
- if (rc) {
- ERRMSG("%s: the ioctl call to get blocksize " \
- "returned with the following error " \
- "message:\n%s\n",prog_name,
- strerror(errno));
- goto reread;
- }
-
- if (verbosity>0) printf("done\n");
-
- label_position=new_geometry.start*new_blksize;
-
- if (verbosity>0) printf("Writing label... ");
- convert_label(label);
- rc=lseek(fd,label_position,SEEK_SET);
- if (rc!=label_position) {
- ERRMSG("%s: lseek on the device to %i " \
- "failed with the following error " \
- "message:\n%s\n",prog_name,
- label_position,strerror(errno));
- goto reread;
- }
- rc=write(fd,label,LABEL_LENGTH);
- if (rc!=LABEL_LENGTH) {
- ERRMSG("%s: writing the label only wrote %d " \
- "bytes.\n",prog_name,rc);
- goto reread;
- }
-
- sync();
- sync();
-
- if (verbosity>0) printf("done\n");
- }
- reread:
- printf("Rereading the partition table... ");
- rc=ioctl(fd,BLKRRPART,NULL);
- if (rc) {
- ERRMSG("%s: error during rereading the partition " \
- "table: %s.\n",prog_name,strerror(errno));
- } else printf("done.\n");
-
- break;
- }
-
- rc=close(fd);
- if (rc)
- ERRMSG("%s: error during close: " \
- "%s; continuing.\n",prog_name,strerror(errno));
-}
-
-
-
-int main(int argc,char *argv[]) {
- int verbosity;
- int testmode;
- int withoutprompt;
- int writenolabel,labelspec;
-
- char *dev_name;
- int devno;
- char *dev_filename,*devno_param_str,*range_param_str;
- char *start_param_str,*end_param_str,*blksize_param_str;
- char label[LABEL_LENGTH+1];
-
- format_data_t format_params;
-
- int rc;
- int oc;
- char *endptr;
-
- char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
- int i,i1,i2;
- char *str;
-
- int start_specified,end_specified,blksize_specified;
- int devfile_specified,devno_specified,range_specified;
-
- /******************* initialization ********************/
- prog_name=argv[0];
-
- endptr=NULL;
-
- /* set default values */
- format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
- format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
- format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
- format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
- testmode=0;
- verbosity=0;
- withoutprompt=0;
- writenolabel=0;
- labelspec=0;
- for (i=0;i<LABEL_LENGTH;i++) label[i]=' ';
- label[LABEL_LENGTH]=0;
-
- start_specified=end_specified=blksize_specified=0;
- devfile_specified=devno_specified=range_specified=0;
-
- /*************** parse parameters **********************/
-
- /* avoid error message generated by getopt */
- opterr=0;
-
-#ifdef RANGE_FORMATTING
- while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) {
-#endif /* RANGE_FORMATTING */
- while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) {
- switch (oc) {
- case 'y':
- withoutprompt=1;
- break;
-
- case 't':
- testmode=1;
- break;
-
- case 'v':
- verbosity++;
- break;
-
- case '?': /* fall-through */
- case ':':
- exit_usage(EXIT_MISUSE);
-
- case 'h':
- exit_usage(0);
- case 'C':
- format_params.intensity&=0x08;
- break;
-
- case 'V':
- printf("%s version 0.99\n",prog_name);
- exit(0);
-
- case 'l':
- strncpy(label,optarg,LABEL_LENGTH);
- if (strlen(optarg)<LABEL_LENGTH)
- label[strlen(optarg)]=' ';
- labelspec++;
- break;
-
- case 'L':
- writenolabel++;
- break;
-
-#ifdef RANGE_FORMATTING
- case 's' :
- start_param_str=optarg;
- start_specified++;
- break;
-
- case 'e' :
- end_param_str=optarg;
- end_specified++;
- break;
-
- case 'r' :
- range_param_str=optarg;
- range_specified++;
- break;
-#endif /* RANGE_FORMATTING */
-
- case 'b' :
- blksize_param_str=optarg;
- blksize_specified++;
- break;
-
- case 'n' :
- devno_param_str=optarg;
- devno_specified++;
- break;
-
- case 'f' :
- dev_filename=optarg;
- devfile_specified++;
- break;
- }
- }
-
- /******************** checking of parameters **************/
-
- /* convert range into -s and -e */
- CHECK_SPEC_MAX_ONCE(range_specified,"formatting range");
-
- while (range_specified) {
- start_specified++;
- end_specified++;
-
- /* scan for 1 or 2 integers, separated by a dash */
- rc=sscanf(range_param_str,"%d%c%d%c",&i1,&c1,&i2,&c2);
- if ((rc==3)&&(c1=='-')) {
- format_params.start_unit=i1;
- format_params.stop_unit=i2;
- break;
- }
- if (rc==1) {
- format_params.start_unit=i1;
- break;
- }
-
- /* scan for integer and -END */
- rc=sscanf(range_param_str,"%d%s",&i1,cbuffer);
- if ((rc==2)&&(!strcasecmp(cbuffer,"-END"))) {
- format_params.start_unit=i1;
- format_params.stop_unit=-1;
- break;
- }
- ERRMSG_EXIT(EXIT_MISUSE,"%s: specified range " \
- "is in invalid format\n",prog_name);
- }
-
- if ((!devfile_specified)&&(!devno_specified))
- ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
- "not specified\n",prog_name);
-
- if ((devfile_specified+devno_specified)>1)
- ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
- "can only be specified once\n",prog_name);
-
- if ((!start_specified)&&(!end_specified)&&(!range_specified)&&
- (!blksize_specified)) {
- format_params=ask_user_for_data(format_params);
- }
-
- CHECK_SPEC_MAX_ONCE(start_specified,"start track");
- CHECK_SPEC_MAX_ONCE(end_specified,"end track");
- CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize");
- CHECK_SPEC_MAX_ONCE(labelspec,"label");
- CHECK_SPEC_MAX_ONCE(writenolabel,"omit-label-writing flag");
-
- if (devno_specified)
- PARSE_PARAM_INTO(devno,devno_param_str,16,"device number");
- if (start_specified&&!range_specified)
- PARSE_PARAM_INTO(format_params.start_unit,start_param_str,10,
- "start track");
- if (end_specified&&!range_specified)
- PARSE_PARAM_INTO(format_params.stop_unit,end_param_str,10,
- "end track");
- if (blksize_specified)
- PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10,
- "blocksize");
-
- /***********get dev_name *********************/
- dev_name=(devno_specified)?
- get_devname_from_devno(devno,verbosity):
- dev_filename;
-
- /*** range checking *********/
- str=check_param(CHECK_ALL,format_params);
- if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str);
-
- /******* issue the real command and reread part table *******/
- do_format_dasd(dev_name,format_params,testmode,verbosity,
- writenolabel,labelspec,label,withoutprompt,devno);
-
- /*************** cleanup ********************************/
- if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
- rc=unlink(dev_name);
- if ((rc)&&(verbosity>=1))
- ERRMSG("%s: temporary device node %s could not be " \
- "removed: %s\n",prog_name,dev_name,
- strerror(errno));
- } else {
- if (devno_specified) {
- /* so we have allocated space for the filename */
- free(dev_name);
- }
- }
-
- return 0;
-}
+++ /dev/null
-all: silo
-
-silo.o: silo.c
- $(CC) -c -o silo.o -O2 silo.c
-
-cfg.o: cfg.c
- $(CC) -c -o cfg.o -O2 cfg.c
-
-silo: silo.o cfg.o
- $(CC) -o $@ $^
- $(STRIP) $@
-
-clean:
- rm -f *.o silo
-
+++ /dev/null
-/* cfg.c - Configuration file parser */
-
-/* Copyright 1992-1997 Werner Almesberger. See file COPYING for details. */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-
-#include "cfg.h"
-
-#define MAX_TOKEN 200
-#define MAX_VAR_NAME MAX_TOKEN
-
-static FILE *file;
-static char flag_set;
-static char *last_token = NULL,*last_item = NULL,*last_value = NULL;
-static int line_num;
-static char *file_name = NULL;
-static int back = 0; /* can go back by one char */
-
-
-void pdie(char *msg)
-{
- fflush(stdout);
- perror(msg);
- exit(1);
-}
-
-
-void die(char *fmt,...)
-{
- va_list ap;
-
- fflush(stdout);
- va_start(ap,fmt);
- vfprintf(stderr,fmt,ap);
- va_end(ap);
- fputc('\n',stderr);
- exit(1);
-}
-
-char *pstrdup(const char *str)
-{
- char *this;
-
- if ((this = strdup(str)) == NULL) pdie("Out of memory");
- return this;
-}
-
-int cfg_open(char *name)
-{
- if (!strcmp(name,"-")) file = stdin;
- else if (!(file = fopen(file_name = name,"r"))) pdie(name);
- line_num = 1;
- return fileno(file);
-}
-
-void cfg_error(char *msg,...)
-{
- va_list ap;
-
- fflush(stdout);
- va_start(ap,msg);
- vfprintf(stderr,msg,ap);
- va_end(ap);
- if (!file_name) fputc('\n',stderr);
- else fprintf(stderr," near line %d in file %s\n",line_num,file_name);
- exit(1);
-}
-
-
-static int next_raw(void)
-{
- int ch;
-
- if (!back) return getc(file);
- ch = back;
- back = 0;
- return ch;
-}
-
-
-static int next(void)
-{
- static char *var;
- char buffer[MAX_VAR_NAME+1];
- int ch,braced;
- char *put;
-
- if (back) {
- ch = back;
- back = 0;
- return ch;
- }
- if (var && *var) return *var++;
- ch = getc(file);
- if (ch == '\\') {
- ch = getc(file);
- if (ch == '$') return ch;
- ungetc(ch,file);
- return '\\';
- }
- if (ch != '$') return ch;
- ch = getc(file);
- braced = ch == '{';
- put = buffer;
- if (!braced) *put++ = ch;
- while (1) {
- ch = getc(file);
-#if 0
- if (!braced && ch < ' ') {
- ungetc(ch,file);
- break;
- }
-#endif
- if (ch == EOF) cfg_error("EOF in variable name");
- if (ch < ' ') cfg_error("control character in variable name");
- if (braced && ch == '}') break;
- if (!braced && !isalpha(ch) && !isdigit(ch) && ch != '_') {
- ungetc(ch,file);
- break;
- }
- if (put-buffer == MAX_VAR_NAME) cfg_error("variable name too long");
- *put++ = ch;
- }
- *put = 0;
- if (!(var = getenv(buffer))) cfg_error("unknown variable \"%s\"",buffer);
- return next();
-}
-
-
-static void again(int ch)
-{
- if (back) die("internal error: again invoked twice");
- back = ch;
-}
-
-
-static char *cfg_get_token(void)
-{
- char buf[MAX_TOKEN+1];
- char *here;
- int ch,escaped;
-
- if (last_token) {
- here = last_token;
- last_token = NULL;
- return here;
- }
- while (1) {
- while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n')
- if (ch == '\n') line_num++;
- if (ch == EOF) return NULL;
- if (ch != '#') break;
- while ((ch = next_raw()), ch != '\n')
- if (ch == EOF) return NULL;
- line_num++;
- }
- if (ch == '=') return pstrdup("=");
- if (ch == '"') {
- here = buf;
- while (here-buf < MAX_TOKEN) {
- if ((ch = next()) == EOF) cfg_error("EOF in quoted string");
- if (ch == '"') {
- *here = 0;
- return pstrdup(buf);
- }
- if (ch == '\\') {
- ch = next();
- if (ch != '"' && ch != '\\' && ch != '\n')
- cfg_error("Bad use of \\ in quoted string");
- if (ch == '\n') {
- while ((ch = next()), ch == ' ' || ch == '\t');
- if (!ch) continue;
- again(ch);
- ch = ' ';
- }
- }
- if (ch == '\n' || ch == '\t')
- cfg_error("\\n and \\t are not allowed in quoted strings");
- *here++ = ch;
- }
- cfg_error("Quoted string is too long");
- return 0; /* not reached */
- }
- here = buf;
- escaped = 0;
- while (here-buf < MAX_TOKEN) {
- if (escaped) {
- if (ch == EOF) cfg_error("\\ precedes EOF");
- if (ch == '\n') line_num++;
- else *here++ = ch == '\t' ? ' ' : ch;
- escaped = 0;
- }
- else {
- if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
- ch == '=' || ch == EOF) {
- again(ch);
- *here = 0;
- return pstrdup(buf);
- }
- if (!(escaped = (ch == '\\'))) *here++ = ch;
- }
- ch = next();
- }
- cfg_error("Token is too long");
- return 0; /* not reached */
-}
-
-
-static void cfg_return_token(char *token)
-{
- last_token = token;
-}
-
-
-static int cfg_next(char **item,char **value)
-{
- char *this;
-
- if (last_item) {
- *item = last_item;
- *value = last_value;
- last_item = NULL;
- return 1;
- }
- *value = NULL;
- if (!(*item = cfg_get_token())) return 0;
- if (!strcmp(*item,"=")) cfg_error("Syntax error");
- if (!(this = cfg_get_token())) return 1;
- if (strcmp(this,"=")) {
- cfg_return_token(this);
- return 1;
- }
- if (!(*value = cfg_get_token())) cfg_error("Value expected at EOF");
- if (!strcmp(*value,"=")) cfg_error("Syntax error after %s",*item);
- return 1;
-}
-
-
-static void cfg_return(char *item,char *value)
-{
- last_item = item;
- last_value = value;
-}
-
-
-void cfg_init(CONFIG *table)
-{
- while (table->type != cft_end) {
- switch (table->type) {
- case cft_strg:
- if (table->data) free(table->data);
- case cft_flag:
- table->data = NULL;
- break;
- case cft_link:
- table = ((CONFIG *) table->action)-1;
- break;
- default:
- die("Unknown syntax code %d",table->type);
- }
- table++;
- }
-}
-
-
-static int cfg_do_set(CONFIG *table,char *item,char *value,int copy,
- void *context)
-{
- CONFIG *walk;
-
- for (walk = table; walk->type != cft_end; walk++) {
- if (walk->name && !strcasecmp(walk->name,item)) {
- if (value && walk->type != cft_strg)
- cfg_error("'%s' doesn't have a value",walk->name);
- if (!value && walk->type == cft_strg)
- cfg_error("Value expected for '%s'",walk->name);
- if (walk->data) {
- if (walk->context == context)
- cfg_error("Duplicate entry '%s'",walk->name);
- else {
- fprintf(stderr,"Ignoring entry '%s'\n",walk->name);
- if (!copy) free(value);
- return 1;
- }
- }
- if (walk->type == cft_flag) walk->data = &flag_set;
- else if (walk->type == cft_strg) {
- if (copy) walk->data = pstrdup(value);
- else walk->data = value;
- }
- walk->context = context;
- if (walk->action) ((void (*)(void)) walk->action)();
- break;
- }
- if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
- }
- if (walk->type != cft_end) return 1;
- cfg_return(item,value);
- return 0;
-}
-
-
-void cfg_set(CONFIG *table,char *item,char *value,void *context)
-{
- if (!cfg_do_set(table,item,value,1,context))
- cfg_error("cfg_set: Can't set %s",item);
-}
-
-
-void cfg_unset(CONFIG *table,char *item)
-{
- CONFIG *walk;
-
- for (walk = table; walk->type != cft_end; walk++)
- if (walk->name && !strcasecmp(walk->name,item)) {
- if (!walk->data) die("internal error (cfg_unset %s, unset)",item);
- if (walk->type == cft_strg) free(walk->data);
- walk->data = NULL;
- return;
- }
- die("internal error (cfg_unset %s, unknown",item);
-}
-
-
-int cfg_parse(CONFIG *table)
-{
- char *item,*value;
-
- while (1) {
- if (!cfg_next(&item,&value)) return 0;
- if (!cfg_do_set(table,item,value,0,table)) return 1;
- free(item);
- }
-}
-
-
-int cfg_get_flag(CONFIG *table,char *item)
-{
- CONFIG *walk;
-
- for (walk = table; walk->type != cft_end; walk++) {
- if (walk->name && !strcasecmp(walk->name,item)) {
- if (walk->type != cft_flag)
- die("cfg_get_flag: operating on non-flag %s",item);
- return !!walk->data;
- }
- if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
- }
- die("cfg_get_flag: unknown item %s",item);
- return 0; /* not reached */
-}
-
-
-char *cfg_get_strg(CONFIG *table,char *item)
-{
- CONFIG *walk;
-
- for (walk = table; walk->type != cft_end; walk++) {
- if (walk->name && !strcasecmp(walk->name,item)) {
- if (walk->type != cft_strg)
- die("cfg_get_strg: operating on non-string %s",item);
- return walk->data;
- }
- if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
- }
- die("cfg_get_strg: unknown item %s",item);
- return 0; /* not reached */
-}
+++ /dev/null
-/* cfg.h - Configuration file parser */
-
-/* Copyright 1992-1996 Werner Almesberger. See file COPYING for details. */
-
-
-#ifndef CFG_H
-#define CFG_H
-
-typedef enum { cft_strg, cft_flag, cft_link, cft_end } CFG_TYPE;
-
-typedef struct {
- CFG_TYPE type;
- char *name;
- void *action;
- void *data;
- void *context;
-} CONFIG;
-
-extern int cfg_open(char *name);
-
-/* Opens the configuration file. Returns the file descriptor of the open
- file. */
-
-extern void cfg_error(char *msg,...);
-
-/* Signals an error while parsing the configuration file and terminates the
- program. */
-
-extern void cfg_init(CONFIG *table);
-
-/* Initializes the specified table. */
-
-extern void cfg_set(CONFIG *table,char *item,char *value,void *context);
-
-/* Sets the specified variable in table. If the variable has already been set
- since the last call to cfg_init, a warning message is issued if the context
- keys don't match or a fatal error is reported if they do. */
-
-extern void cfg_unset(CONFIG *table,char *item);
-
-/* Unsets the specified variable in table. It is a fatal error if the variable
- was not set. */
-
-extern int cfg_parse(CONFIG *table);
-
-/* Parses the configuration file for variables contained in table. A non-zero
- value is returned if a variable not found in table has been met. Zero is
- returned if EOF has been reached. */
-
-extern int cfg_get_flag(CONFIG *table,char *item);
-
-/* Returns one if the specified variable is set, zero if it isn't. */
-
-extern char *cfg_get_strg(CONFIG *table,char *item);
-
-/* Returns the value of the specified variable if it is set, NULL otherwise. */
-
-#endif
+++ /dev/null
-/*
- * arch/s390/boot/silo.c
- *
- * S390 version
- * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *
- * Report bugs to: <linux390@de.ibm.com>
- *
- * Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Fritz Elfert <felfert@to.com> contributed support for
- * /etc/silo.conf based on Intel's lilo
- * Changes :
- * 01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * adapted to deal with devices and bootsects of various sizes
- */
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <dirent.h>
-#include <linux/fs.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <asm/ioctl.h>
-
-#include "cfg.h"
-
-CONFIG cf_options[] = {
- { cft_strg, "append", NULL, NULL,NULL },
- { cft_strg, "image", NULL, NULL,NULL },
- { cft_strg, "ipldevice", NULL, NULL,NULL },
- { cft_strg, "bootsect", NULL, NULL,NULL },
- { cft_strg, "map", NULL, NULL,NULL },
- { cft_strg, "parmfile", NULL, NULL,NULL },
- { cft_strg, "ramdisk", NULL, NULL,NULL },
- { cft_strg, "root", NULL, NULL,NULL },
- { cft_flag, "readonly", NULL, NULL,NULL },
- { cft_strg, "verbose", NULL, NULL,NULL },
- { cft_strg, "testlevel", NULL, NULL,NULL },
- { cft_end, NULL, NULL, NULL,NULL }
-};
-
-/* from dasd.h */
-#define DASD_PARTN_BITS 2
-#define BIODASDRWTB _IOWR('D',0,int)
-/* end */
-
-#define SILO_CFG "/etc/silo.conf"
-#define SILO_IMAGE "./image"
-#define SILO_BOOTMAP "./boot.map"
-#define SILO_PARMFILE "./parmfile"
-#define SILO_BOOTSECT "/boot/ipleckd.boot"
-
-#define PRINT_LEVEL(x,y...) if ( silo_options.verbosity >= x ) printf(y)
-#define ERROR_LEVEL(x,y...) if ( silo_options.verbosity >= x ) fprintf(stderr,y)
-#define TOGGLE(x) ((x)=((x)?(0):(1)))
-#define GETARG(x) {int len=strlen(optarg);x=malloc(len);strncpy(x,optarg,len);PRINT_LEVEL(1,"%s set to %s\n",#x,optarg);}
-
-#define ITRY(x) if ( (x) == -1 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
-#define NTRY(x) if ( (x) == 0 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
-
-#define MAX_CLUSTERS 256
-#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
-
-#define SILO_VERSION "1.1"
-
-struct silo_options
- {
- short int verbosity;
- short int testlevel;
- char *image;
- char *ipldevice;
- char *parmfile;
- char *ramdisk;
- char *bootsect;
- char *conffile;
- char *bootmap;
- }
-silo_options =
-{
- 1, /* verbosity */
- 2, /* testlevel */
- SILO_IMAGE, /* image */
- NULL, /* ipldevice */
- SILO_PARMFILE, /* parmfile */
- NULL, /* initrd */
- SILO_BOOTSECT, /* bootsector */
- SILO_CFG, /* silo.conf file */
- SILO_BOOTMAP, /* boot.map */
-};
-
-struct blockdesc
- {
- unsigned long off;
- unsigned short ct;
- unsigned long addr;
- };
-
-struct blocklist
- {
- struct blockdesc blk[MAX_CLUSTERS];
- unsigned short ix;
- };
-
-void
-usage (void)
-{
- printf ("Usage:\n");
- printf ("silo -d ipldevice [additional options]\n");
- printf ("-d /dev/node : set ipldevice to /dev/node\n");
- printf ("-f image : set image to image\n");
- printf ("-F conffile : specify configuration file (/etc/silo.conf)\n");
- printf ("-p parmfile : set parameter file to parmfile\n");
- printf ("-b bootsect : set bootsector to bootsect\n");
- printf ("Additional options\n");
- printf ("-B bootmap:\n");
- printf ("-v: increase verbosity level\n");
- printf ("-v#: set verbosity level to #\n");
- printf ("-t: decrease testing level\n");
- printf ("-h: print this message\n");
- printf ("-?: print this message\n");
- printf ("-V: print version\n");
-}
-
-int
-read_cfg(struct silo_options *o)
-{
- char *tmp;
- if (access(o->conffile, R_OK) && (errno == ENOENT))
- return 0;
- /* If errno != ENOENT, let cfg_open report an error */
- cfg_open(o->conffile);
- cfg_parse(cf_options);
- tmp = cfg_get_strg(cf_options, "ipldevice");
- if ( ! o->ipldevice && tmp )
- o->ipldevice = tmp;
- tmp = cfg_get_strg(cf_options, "image");
- if ( ! strncmp(o-> image,SILO_IMAGE,strlen(SILO_IMAGE)) && tmp )
- o->image = tmp;
- tmp = cfg_get_strg(cf_options, "parmfile");
- if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp)
- o->parmfile = tmp;
- if ( ! o -> ramdisk )
- o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
- tmp = cfg_get_strg(cf_options, "bootsect");
- if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp)
- o->bootsect = tmp;
- tmp = cfg_get_strg(cf_options, "map") ;
- if ( !strncmp(o -> bootmap,SILO_BOOTMAP,strlen(SILO_BOOTMAP)) && tmp)
- o->bootmap = tmp;
- tmp = cfg_get_strg(cf_options, "verbose");
- if ( tmp ) {
- unsigned short v;
- sscanf (tmp, "%hu", &v);
- o->verbosity = v;
- }
- tmp = cfg_get_strg(cf_options, "testlevel");
- if ( tmp ) {
- unsigned short t;
- sscanf (tmp, "%hu", &t);
- o->testlevel += t;
- }
- return 1;
-}
-
-char *
-gen_tmpparm( char *pfile )
-{
- char *append = cfg_get_strg(cf_options, "append");
- char *root = cfg_get_strg(cf_options, "root");
- int ro = cfg_get_flag(cf_options, "readonly");
- FILE *f,*of;
- char *fn;
- char c;
- char *tmpdir=NULL,*save=NULL;
-
- if (!append && !root && !ro)
- return pfile;
- of = fopen(pfile, "r");
- if ( of ) {
- NTRY( fn = tempnam(NULL,"parm."));
- } else {
- fn = pfile;
- }
- NTRY( f = fopen(fn, "a+"));
- if ( of ) {
- while ( ! feof (of) ) {
- c=fgetc(of);
- fputc(c,f);
- }
- }
- if (root)
- fprintf(f, " root=%s", root);
- if (ro)
- fprintf(f, " ro");
- if (append)
- fprintf(f, " %s", append);
- fprintf(f, "\n");
- fclose(f);
- fclose(of);
- printf ("tempfile is %s\n",fn);
- return strdup(fn);
-}
-
-int
-parse_options (struct silo_options *o, int argc, char *argv[])
-{
- int rc = 0;
- int oc;
-
- while ((oc = getopt (argc, argv, "Vf:F:d:p:r:b:B:h?v::t::")) != -1)
- {
- switch (oc)
- {
- case 'V':
- printf("silo version: %s\n",SILO_VERSION);
- exit(0);
- case 'v':
- {
- unsigned short v;
- if (optarg && sscanf (optarg, "%hu", &v))
- o->verbosity = v;
- else
- o->verbosity++;
- PRINT_LEVEL (1, "Verbosity value is now %hu\n", o->verbosity);
- break;
- }
- case 't':
- {
- unsigned short t;
- if (optarg && sscanf (optarg, "%hu", &t))
- o->testlevel -= t;
- else
- o->testlevel--;
- PRINT_LEVEL (1, "Testonly flag is now %d\n", o->testlevel);
- break;
- }
- case 'h':
- case '?':
- usage ();
- exit(0);
- case 'd':
- GETARG (o->ipldevice);
- break;
- case 'f':
- GETARG (o->image);
- break;
- case 'F':
- GETARG (o->conffile);
- break;
- case 'p':
- GETARG (o->parmfile);
- break;
- case 'r':
- GETARG (o->ramdisk);
- break;
- case 'b':
- GETARG (o->bootsect);
- break;
- case 'B':
- GETARG (o->bootmap);
- default:
- rc = EINVAL;
- break;
- }
- }
- read_cfg(o);
- return rc;
-}
-
-int
-verify_device (char *name)
-{
- int rc = 0;
- struct stat dst;
- struct stat st;
- ITRY (stat (name, &dst));
- if (S_ISBLK (dst.st_mode))
- {
- if (!(MINOR (dst.st_rdev) & PARTN_MASK))
- {
- rc = dst.st_rdev;
- }
- else
- /* invalid MINOR & PARTN_MASK */
- {
- ERROR_LEVEL (1, "Cannot boot from partition %d %d %d",
- (int) PARTN_MASK, (int) MINOR (dst.st_rdev), (int) (PARTN_MASK & MINOR (dst.st_rdev)));
- rc = -1;
- errno = EINVAL;
- }
- }
- else
- /* error S_ISBLK */
- {
- ERROR_LEVEL (1, "%s is no block device\n", name);
- rc = -1;
- errno = EINVAL;
- }
- return rc;
-}
-
-int
-verify_file (char *name, int dev)
-{
- int rc = 0;
- struct stat dst;
- struct stat st;
- int bs = 1024;
- int l;
-
- ITRY(stat ( name, &dst ));
- if (S_ISREG (dst.st_mode))
- {
- if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK))
- {
- /* whatever to do if all is ok... */
- }
- else
- /* devicenumber doesn't match */
- {
- ERROR_LEVEL (1, "%s is not on device (%d/%d) but on (%d/%d)\n", name, (unsigned) MAJOR (dev), (unsigned) MINOR (dev), (unsigned) MAJOR (dst.st_dev), (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK));
- rc = -1;
- errno = EINVAL;
- }
- }
- else
- /* error S_ISREG */
- {
- ERROR_LEVEL (1, "%s is neither regular file nor linkto one\n", name);
- rc = -1;
- errno = EINVAL;
- }
- return rc;
-}
-
-int
-verify_options (struct silo_options *o)
-{
- int rc = 0;
- int dev = 0;
- int crc = 0;
- if (!o->ipldevice || !o->image || !o->bootsect)
- {
- if (!o->ipldevice)
- fprintf(stderr,"ipldevice\n");
- if (!o->image)
- fprintf(stderr,"image\n");
- if (!o->bootsect)
- fprintf(stderr,"bootsect\n");
-
- usage ();
- exit (1);
- }
- PRINT_LEVEL (1, "Testlevel is set to %d\n",o->testlevel);
-
- PRINT_LEVEL (1, "IPL device is: '%s'", o->ipldevice);
- ITRY (dev = verify_device (o->ipldevice));
- PRINT_LEVEL (2, "...ok...(%d/%d)", (unsigned short) MAJOR (dev), (unsigned short) MINOR (dev));
- PRINT_LEVEL (1, "\n");
-
- PRINT_LEVEL (0, "bootsector is: '%s'", o->bootsect);
- ITRY (verify_file (o->bootsect, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
-
- if ( o -> testlevel > 0 &&
- ! strncmp( o->bootmap, SILO_BOOTMAP,strlen(SILO_BOOTMAP) )) {
- NTRY( o -> bootmap = tempnam(NULL,"boot."));
- }
- PRINT_LEVEL (0, "bootmap is set to: '%s'", o->bootmap);
- if ( access ( o->bootmap, O_RDWR ) == -1 ) {
- if ( errno == ENOENT ) {
- ITRY (creat ( o-> bootmap, O_RDWR ));
- } else {
- PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap,
- strerror(errno));
- }
- }
- ITRY (verify_file (o->bootmap, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
-
- PRINT_LEVEL (0, "Kernel image is: '%s'", o->image);
- ITRY (verify_file (o->image, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
-
- PRINT_LEVEL (0, "original parameterfile is: '%s'", o->parmfile);
- ITRY (verify_file (o->parmfile, dev));
- PRINT_LEVEL (1, "...ok...");
- o->parmfile = gen_tmpparm(o->parmfile);
- PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile);
- ITRY (verify_file (o->parmfile, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
-
- if (o->ramdisk)
- {
- PRINT_LEVEL (0, "initialramdisk is: '%s'", o->ramdisk);
- ITRY (verify_file (o->ramdisk, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
- }
-
- return crc;
-}
-
-
-int
-add_file_to_blocklist (char *name, struct blocklist *lst, long addr)
-{
- int fd;
- int devfd;
- struct stat fst;
- int i;
- int blk;
- int bs;
- int blocks;
-
- int rc = 0;
-
- ITRY (fd = open (name, O_RDONLY));
- ITRY (fstat (fd, &fst));
- ITRY (mknod ("/tmp/silodev", S_IFBLK | S_IRUSR | S_IWUSR, fst.st_dev));
- ITRY (devfd = open ("/tmp/silodev", O_RDONLY));
- ITRY (ioctl (fd, FIGETBSZ, &bs));
- blocks = (fst.st_size + bs - 1) / bs;
- for (i = 0; i < blocks; i++)
- {
- blk = i;
- ITRY (ioctl (fd, FIBMAP, &blk));
- if (blk)
- {
- int oldblk = blk;
- ITRY (ioctl (devfd, BIODASDRWTB, &blk));
- if (blk <= 0)
- {
- ERROR_LEVEL (0, "BIODASDRWTB on blk %d returned %d\n", oldblk, blk);
- break;
- }
- }
- else
- {
- PRINT_LEVEL (1, "Filled hole on blk %d\n", i);
- }
- if (lst->ix == 0 || i == 0 ||
- lst->blk[lst->ix - 1].ct >= 128 ||
- (lst->blk[lst->ix - 1].off + lst->blk[lst->ix - 1].ct != blk &&
- !(lst->blk[lst->ix - 1].off == 0 && blk == 0)))
- {
- if (lst->ix >= MAX_CLUSTERS)
- {
- rc = 1;
- errno = ENOMEM;
- break;
- }
- lst->blk[lst->ix].off = blk;
- lst->blk[lst->ix].ct = 1;
- lst->blk[lst->ix].addr = addr + i * bs;
- lst->ix++;
- }
- else
- {
- lst->blk[lst->ix - 1].ct++;
- }
- }
- ITRY(unlink("/tmp/silodev"));
- return rc;
-}
-
-int
-write_bootsect (struct silo_options *o, struct blocklist *blklst)
-{
- int i;
- int s_fd, d_fd, b_fd, bd_fd;
- struct stat s_st, d_st, b_st;
- int rc=0;
- int bs, boots;
- char *tmpdev;
- char buffer[4096]={0,};
- int blocksize, sectsize;
- ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC));
- ITRY (fstat (d_fd, &d_st));
- ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC));
- ITRY (verify_file (o->bootsect, d_st.st_rdev));
- for (i = 0; i < blklst->ix; i++)
- {
- int offset = blklst->blk[i].off;
- int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff);
- PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr);
- if ( o->testlevel <= 1 ) {
- NTRY (write (s_fd, &offset, sizeof (int)));
- NTRY (write (s_fd, &addrct, sizeof (int)));
- }
- }
- ITRY (ioctl (s_fd,FIGETBSZ, &bs));
- ITRY (stat (o->bootmap, &s_st));
- if (s_st.st_size > bs )
- {
- ERROR_LEVEL (0,"%s is larger than one block\n", o->bootmap);
- rc = -1;
- errno = EINVAL;
- }
- boots=0;
- NTRY ( tmpdev = tmpnam(NULL) );
- ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
- ITRY (bd_fd = open (tmpdev, O_RDONLY));
- ITRY (ioctl(bd_fd,BLKSSZGET,&blocksize));
- ITRY (ioctl(s_fd,FIBMAP,&boots));
- ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
- PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
- close (bd_fd);
- close(s_fd);
- ITRY (unlink(tmpdev));
- /* Now patch the bootsector */
- ITRY (stat (o->bootsect, &b_st));
- if ((sectsize = b_st.st_size) > blocksize )
- {
- ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize);
- rc = -1;
- errno = EINVAL;
- }
- ITRY (b_fd = open (o->bootsect, O_RDONLY));
- ITRY (read (b_fd, buffer, sectsize));
- memset (buffer + 0xe0, 0, 8);
- *(int *) (buffer + 0xe0) = boots;
- if ( o -> testlevel <= 0 ) {
- ITRY (write (d_fd, buffer, sectsize));
- ITRY (lseek (d_fd, blocksize, SEEK_SET));
- ITRY (write (d_fd, buffer, sectsize));
- }
- close (b_fd);
- close (d_fd);
- return rc;
-}
-
-int
-do_silo (struct silo_options *o)
-{
- int rc = 0;
-
- int device_fd;
- int image_fd;
- struct blocklist blklist;
- memset (&blklist, 0, sizeof (struct blocklist));
- ITRY (add_file_to_blocklist (o->image, &blklist, 0x00000000));
- if (o->parmfile)
- {
- ITRY (add_file_to_blocklist (o->parmfile, &blklist, 0x00008000));
- }
- if (o->ramdisk)
- {
- ITRY (add_file_to_blocklist (o->ramdisk, &blklist, 0x00800000));
- }
- ITRY (write_bootsect (o, &blklist));
- return rc;
-}
-
-int
-main (int argct, char *argv[])
-{
- int rc = 0;
- char *save=NULL;
- char *tmpdir=getenv("TMPDIR");
- if (tmpdir) {
- NTRY( save=(char*)malloc(strlen(tmpdir)));
- NTRY( strncpy(save,tmpdir,strlen(tmpdir)));
- }
- ITRY( setenv("TMPDIR",".",1));
- ITRY (parse_options (&silo_options, argct, argv));
- ITRY (verify_options (&silo_options));
- if ( silo_options.testlevel > 0 ) {
- printf ("WARNING: silo does not modify your volume. Use -t2 to change IPL records\n");
- }
- ITRY (do_silo (&silo_options));
- if ( save )
- ITRY( setenv("TMPDIR",save,1));
- return rc;
-}
+++ /dev/null
-ipldevice = /dev/dasda
-image = /boot/image
-bootsect = /boot/ipleckd.boot
-map = /boot/boot.map
-root = /dev/dasd01
-readonly
-append = "dasd=200-20f noinitrd"
CPP=$(CC) -E
OBJCOPY=$(CROSS_COMPILE)objcopy -O binary -R .note -R .comment -S
LDFLAGS=-e start
+ifeq ($(CONFIG_SHARED_KERNEL),y)
+LINKFLAGS =-T $(TOPDIR)/arch/s390x/vmlinux-shared.lds $(LDFLAGS)
+else
LINKFLAGS =-T $(TOPDIR)/arch/s390x/vmlinux.lds $(LDFLAGS)
+endif
MODFLAGS += -fpic
CFLAGS_PIPE := -pipe
SUBDIRS := $(SUBDIRS) arch/s390x/mm arch/s390x/kernel arch/s390x/lib \
drivers/s390
-CORE_FILES := arch/s390x/mm/mm.o arch/s390x/kernel/kernel.o $(CORE_FILES) \
- drivers/s390/io.o
+CORE_FILES := arch/s390x/mm/mm.o arch/s390x/kernel/kernel.o $(CORE_FILES)
+DRIVERS := $(DRIVERS) drivers/s390/io.o
LIBS := $(TOPDIR)/arch/s390x/lib/lib.a $(LIBS) $(TOPDIR)/arch/s390x/lib/lib.a
all: image listing
tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF
tristate 'Kernel support for MISC binaries' CONFIG_BINFMT_MISC
bool 'Show crashed user process info' CONFIG_PROCESS_DEBUG
+bool 'Pseudo page fault support' CONFIG_PFAULT
+bool 'VM shared kernel support' CONFIG_SHARED_KERNEL
endmenu
# CONFIG_ISA is not set
# CONFIG_EISA is not set
# CONFIG_MCA is not set
+CONFIG_RWSEM_GENERIC_SPINLOCK=y
+# CONFIG_RWSEM_XCHGADD_ALGORITHM is not set
CONFIG_ARCH_S390=y
CONFIG_ARCH_S390X=y
CONFIG_BINFMT_ELF=y
# CONFIG_BINFMT_MISC is not set
# CONFIG_PROCESS_DEBUG is not set
+CONFIG_PFAULT=y
+# CONFIG_SHARED_KERNEL is not set
#
# Block device drivers
CONFIG_DASD=y
CONFIG_DASD_ECKD=y
CONFIG_DASD_FBA=y
-# CONFIG_DASD_DIAG is not set
#
# Multi-device support (RAID and LVM)
#
# S/390 character device drivers
#
-CONFIG_3215=y
-CONFIG_3215_CONSOLE=y
+CONFIG_TN3270=y
+CONFIG_TN3270_CONSOLE=y
+CONFIG_TN3215=y
+CONFIG_TN3215_CONSOLE=y
CONFIG_HWC=y
CONFIG_HWC_CONSOLE=y
+CONFIG_HWC_CPI=m
CONFIG_S390_TAPE=m
#
#
CONFIG_NETDEVICES=y
# CONFIG_DUMMY is not set
+# CONFIG_BONDING is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
CONFIG_NET_ETHERNET=y
CONFIG_TR=y
# CONFIG_FDDI is not set
#
# S/390 network device drivers
#
-# CONFIG_CHANDEV is not set
+CONFIG_CHANDEV=y
+CONFIG_HOTPLUG=y
CONFIG_CTC=m
CONFIG_IUCV=m
# CONFIG_IP_MROUTE is not set
# CONFIG_INET_ECN is not set
# CONFIG_SYN_COOKIES is not set
-# CONFIG_IPV6 is not set
+CONFIG_IPV6=m
+# CONFIG_IPV6_NETLINK is not set
# CONFIG_KHTTPD is not set
# CONFIG_ATM is not set
# CONFIG_EFS_FS is not set
# CONFIG_JFFS_FS is not set
# CONFIG_CRAMFS is not set
+# CONFIG_TMPFS is not set
# CONFIG_RAMFS is not set
# CONFIG_ISO9660_FS is not set
# CONFIG_JOLIET is not set
# CONFIG_MINIX_FS is not set
+# CONFIG_VXFS_FS is not set
# CONFIG_NTFS_FS is not set
# CONFIG_NTFS_RW is not set
# CONFIG_HPFS_FS is not set
CONFIG_PROC_FS=y
-# CONFIG_DEVFS_FS is not set
-# CONFIG_DEVFS_MOUNT is not set
+CONFIG_DEVFS_FS=y
+CONFIG_DEVFS_MOUNT=y
# CONFIG_DEVFS_DEBUG is not set
# CONFIG_DEVPTS_FS is not set
# CONFIG_QNX4FS_FS is not set
# CONFIG_ROMFS_FS is not set
CONFIG_EXT2_FS=y
# CONFIG_SYSV_FS is not set
-# CONFIG_SYSV_FS_WRITE is not set
# CONFIG_UDF_FS is not set
# CONFIG_UDF_RW is not set
# CONFIG_UFS_FS is not set
#
# Kernel hacking
#
-# CONFIG_MAGIC_SYSRQ is not set
+CONFIG_MAGIC_SYSRQ=y
#include <linux/stddef.h>
#include <linux/kernel.h>
#include <linux/errno.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/ctype.h>
#include <linux/version.h>
#include <asm/uaccess.h>
#include <linux/sys.h>
#include <linux/linkage.h>
#include <linux/config.h>
+#include <asm/cache.h>
#include <asm/lowcore.h>
#include <asm/errno.h>
#include <asm/smp.h>
sigpending = 16
need_resched = 32
tsk_ptrace = 40
-processor = 100
+processor = 92
/*
* Register usage in interrupt handlers:
#
# check, if bottom-half has to be done
#
- l %r0,__LC_IRQ_STAT # get softirq_active
- n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask
+ lgf %r1,processor(%r9) # get cpu number from task struture
+ larl %r2,irq_stat
+ sll %r1,L1_CACHE_SHIFT
+ la %r1,0(%r1,%r2)
+ icm %r0,15,0(%r1) # test irq_stat[#cpu].__softirq_pending
jnz sysc_handle_bottom_half
#
# check, if reschedule is needed
.long SYSCALL(sys_pivot_root,sys32_pivot_root_wrapper)
.long SYSCALL(sys_mincore,sys32_mincore_wrapper)
.long SYSCALL(sys_madvise,sys32_madvise_wrapper)
- .long SYSCALL(sys_ni_syscall,sys32_getdents64_wrapper)/* 220 */
+ .long SYSCALL(sys_getdents64,sys32_getdents64_wrapper)/* 220 */
.long SYSCALL(sys_ni_syscall,sys32_fcntl64_wrapper)
.rept 255-221
.long SYSCALL(sys_ni_syscall,sys_ni_syscall)
#
# check, if bottom-half has to be done
#
- l %r0,__LC_IRQ_STAT # get softirq_active
- n %r0,__LC_IRQ_STAT+4 # and it with softirq_mask
+ lgf %r1,processor(%r9) # get cpu number from task struture
+ larl %r2,irq_stat
+ sll %r1,L1_CACHE_SHIFT
+ la %r1,0(%r1,%r2)
+ icm %r0,15,0(%r1) # test irq_stat[#cpu].__softirq_pending
jnz io_handle_bottom_half
io_return_bh:
#
l %r1,0xb8 # load ipl subchannel number
la %r2,IPL_BS # load start address
bas %r14,.Lloader # load rest of ipl image
- l %r12,.Lparm # pointer to parameter area
+ larl %r12,parmarea # pointer to parameter area
st %r1,IPL_DEVICE+4-PARMAREA(%r12) # store ipl device number
#
slr %r0,%r0
b .Lcntlp
.Ldelspc:
- ic %r0,0(%r3)
ic %r0,0(%r2,%r3)
chi %r0,0x20 # is it a space ?
be .Lcntlp
l %r1,.Lstartup
br %r1
-.Lparm: .long PARMAREA
.Lstartup: .long startup
.Lcvtab:.long _ebcasc # ebcdic to ascii table
.Lreset:.byte 0xc3,0xc8,0xc1,0xd5,0xc7,0xc5,0x40,0xd9,0xc4,0xd9,0x40
#
.org 0x10000
startup:basr %r13,0 # get base
-.LPG1: n %r13,.Lhighoff-.LPG1(%r13) # remove high order bit
+.LPG1: sll %r13,1 # remove high order bit
+ srl %r13,1
lhi %r1,1 # mode 1 = esame
slr %r0,%r0 # set cpuid to zero
sigp %r1,%r0,0x12 # switch to esame mode
sam64 # switch to 64 bit mode
lctlg %c0,%c15,.Lctl-.LPG1(%r13) # load control registers
- lg %r12,.Lparm1-.LPG1(%r13) # pointer to parameter area
+ larl %r12,parmarea # pointer to parameter area
# move IPL device to lowcore
mvc __LC_IPLDEV(4),IPL_DEVICE+4-PARMAREA(%r12)
+ # set program check new psw mask
+ mvc __LC_PGM_NEW_PSW(8),.Lpcmsk-.LPG1(%r13)
+
#
# find out memory size.
#
- mvc 0x1d0(16),.Lpcmem-.LPG1(%r13) # setup program check handler
+ la %r1,1f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
lghi %r2,1
sllg %r2,%r2,17 # test in increments of 128KB
lgr %r1,%r2
aghi %r1,-8 # test last word in the segment
-.Lloop:
- lg %r0,0(%r1) # test 128KB segment
+0: lg %r0,0(%r1) # test 128KB segment
+ stg %r0,0(%r1)
+ algr %r1,%r2 # add 128KB
+ bc 12,0b-.LPG1(%r13) # r1 < 2^64 -> loop
+1: ng %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M
+ larl %r3,memory_size-.
+ stg %r1,0(%r3) # store memory size
+#
+# find out memory size part 2. Running native the HSA is located at
+# 2GB and we will get an addressing exception trying to access it.
+# We have to restart the scan at 2GB to find out if the machine has
+# more than 2GB of storage.
+#
+ la %r1,1f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ lg %r1,.Lscan2g-.LPG1(%r13) # restart scanning @ 2GB + 128K - 8
+0: lg %r0,0(%r1) # test 128KB segment
stg %r0,0(%r1)
- agr %r1,%r2 # add 128KB
- bno .Lloop-.LPG1(%r13) # r1 < 0x80000000 -> loop
-.Lchkmem:
+ algr %r1,%r2 # add 128 KB
+ bc 12,0b-.LPG1(%r13) # r1 < 2^64 -> loop
+1: clg %r1,.Lscan2g-.LPG1(%r13) # program check @ 2GB + 128K - 8 ?
+ be 2f-.LPG1(%r13)
ng %r1,.L4malign-.LPG1(%r13) # align to multiples of 4M
- lg %r2,.Lmemsize-.LPG1(%r13) # address of variable memory_size
- stg %r1,0(%r2) # store memory size
+ larl %r3,memory_size-.
+ stg %r1,0(%r3) # store memory size
+2:
- lg %r12,.Lmflags-.LPG1(%r13) # get address of machine_flags
+ larl %r12,machine_flags-.
#
# find out if we are running under VM
#
stidp __LC_CPUID # store cpuid
tm __LC_CPUID,0xff # running under VM ?
- bno .Lnovm-.LPG1(%r13)
+ bno 0f-.LPG1(%r13)
oi 7(%r12),1 # set VM flag
-.Lnovm:
- lh %r0,__LC_CPUID+4 # get cpu version
+0: lh %r0,__LC_CPUID+4 # get cpu version
chi %r0,0x7490 # running on a P/390 ?
- bne .Lnop390-.LPG1(%r13)
+ bne 1f-.LPG1(%r13)
oi 7(%r12),4 # set P/390 flag
-.Lnop390:
+1:
#
# find out if we have the MVPG instruction
#
- mvc __LC_PGM_NEW_PSW(16),.Lpcmvpg-.LPG1(%r13)
- sgr %r0,%r0
- lghi %r1,0
- lghi %r2,0
- mvpg %r1,%r2 # Test CSP instruction
- oi 7(%r12),16 # set MVPG flag
-.Lchkmvpg:
+ la %r1,0f-.LPG1(%r13) # set program check address
+ stg %r1,__LC_PGM_NEW_PSW+8
+ sgr %r0,%r0
+ lghi %r1,0
+ lghi %r2,0
+ mvpg %r1,%r2 # test MVPG instruction
+ oi 7(%r12),16 # set MVPG flag
+0:
lpswe .Lentry-.LPG1(13) # jump to _stext in primary-space,
# virtual and never return ...
.quad 0 # cr13: home space segment table
.quad 0xc0000000 # cr14: machine check handling off
.quad 0 # cr15: linkage stack operations
-.Lpcmem:.quad 0x0000000180000000,.Lchkmem
-.Lpcmvpg:.quad 0x0000000180000000,.Lchkmvpg
-.Lflt0: .double 0
-.Lparm1:.quad PARMAREA
-.Lhighoff:.long 0x7fffffff
+.Lpcmsk:.quad 0x0000000180000000
.L4malign:.quad 0xffffffffffc00000
-.Lbigmem:.quad 0x04000000
-.Lmaxchunk:.quad 0x00ffffff
-.Lmemsize:.quad memory_size
-.Lmflags:.quad machine_flags
+.Lscan2g:.quad 0x80000000 + 0x20000 - 8 # 2GB + 128K - 8
#
# params at 10400 (setup.h)
#
.org PARMAREA
+parmarea:
.quad 0 # IPL_DEVICE
.quad RAMDISK_ORIGIN # INITRD_START
.quad RAMDISK_SIZE # INITRD_SIZE
#
# startup-code, running in virtual mode
#
+#ifdef CONFIG_SHARED_KERNEL
+ .org 0x100000
+#else
.org 0x10800
+#endif
.globl _stext
_stext: basr %r13,0 # get base
.LPG2:
l %r1,__LC_IPLDEV # load ipl device number
spx .Lprefix-.LPG2(%r13) # set prefix to linux lowcore
st %r1,__LC_IPLDEV # store ipl device number
- lg %r15,.Linittu-.LPG2(%r13)
+ larl %r15,init_task_union
aghi %r15,16384 # init_task_union + 16384
stg %r15,__LC_KERNEL_STACK # set end of kernel stack
aghi %r15,-160
#
# clear bss memory
#
- lg %r2,.Lbss_bgn-.LPG2(%r13) # start of bss
- lg %r3,.Lbss_end-.LPG2(%r13) # end of bss
+ larl %r2,__bss_start # start of bss segment
+ larl %r3,_end # end of bss segment
sgr %r3,%r2 # length of bss
sgr %r4,%r4 #
sgr %r5,%r5 # set src,length and pad to zero
jo .-4 # branch back, if not finish
# check control registers
stctg %c0,%c15,0(%r15)
- oc 6(1,%r15),.Locbits+5-.LPG2(%r13) # enable sigp external ints.
- oc 4(1,%r15),.Locbits+4-.LPG2(%r13) # low addresss proctection
+ oi 6(%r15),0x20 # enable sigp external interrupts
+ oi 4(%r15),0x10 # switch on low address proctection
lctlg %c0,%c15,0(%r15)
#
basr %r13,0
lpswe .Ldw-.(%r13) # load disabled wait psw
#
-.Lstart: .quad start_kernel
.align 8
+.Ldw: .quad 0x0002000180000000,0x0000000000000000
.Lprefix: .long init_S390_lowcore
-.Linittu: .quad init_task_union
-.Lbss_bgn: .quad __bss_start
-.Lbss_end: .quad _end
-.Locbits: .quad 0x0102040810204080
- .align 4
.Laregs: .long 0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0
- .align 8
-.Ldw: .quad 0x0002000180000000,0x0000000000000000
#include <linux/ioport.h>
#include <linux/interrupt.h>
#include <linux/timex.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/string.h>
#include <linux/random.h>
#include <linux/smp.h>
EXPORT_SYMBOL(__global_sti);
EXPORT_SYMBOL(__global_save_flags);
EXPORT_SYMBOL(__global_restore_flags);
+EXPORT_SYMBOL(global_irq_holder);
+EXPORT_SYMBOL(global_irq_lock);
+EXPORT_SYMBOL(global_irq_count);
+EXPORT_SYMBOL(global_bh_count);
#endif
EXPORT_SYMBOL(global_bh_lock);
#include <linux/sem.h>
#include <linux/msg.h>
#include <linux/shm.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/uio.h>
#include <linux/nfs_fs.h>
#include <linux/smb_fs.h>
unsigned long prot, unsigned long flags,
unsigned long fd, unsigned long pgoff)
{
- int error = -EBADF;
struct file * file = NULL;
+ unsigned long error = -EBADF;
flags &= ~(MAP_EXECUTABLE | MAP_DENYWRITE);
if (!(flags & MAP_ANONYMOUS)) {
down_write(¤t->mm->mmap_sem);
error = do_mmap_pgoff(file, addr, len, prot, flags, pgoff);
+ if (!IS_ERR((void *) error) && error + len >= 0x80000000ULL) {
+ /* Result is out of bounds. */
+ do_munmap(current->mm, addr, len);
+ error = -ENOMEM;
+ }
up_write(¤t->mm->mmap_sem);
if (file)
wait_psw.mask = _WAIT_PSW_MASK;
wait_psw.addr = (unsigned long) &&idle_wakeup;
while(1) {
- if (softirq_active(smp_processor_id()) &
- softirq_mask(smp_processor_id())) {
+ if (softirq_pending(smp_processor_id())) {
do_softirq();
__sti();
if (!current->need_resched)
p->thread.ksp = (unsigned long) frame;
frame->childregs = *regs;
frame->childregs.gprs[15] = new_stackp;
- frame->eos = 0;
+ frame->back_chain = frame->eos = 0;
/* new return point is ret_from_sys_call */
frame->gprs[8] = (unsigned long) &ret_from_fork;
#undef last_sched
#undef first_sched
-/*
- * This should be safe even if called from tq_scheduler
- * A typical mask would be sigmask(SIGKILL)|sigmask(SIGINT)|sigmask(SIGTERM) or 0.
- *
- */
-void s390_daemonize(char *name,unsigned long mask,int use_init_fs)
-{
- struct fs_struct *fs;
- extern struct task_struct *child_reaper;
- struct task_struct *this_process=current;
-
- /*
- * If we were started as result of loading a module, close all of the
- * user space pages. We don't need them, and if we didn't close them
- * they would be locked into memory.
- */
- exit_mm(current);
-
- this_process->session = 1;
- this_process->pgrp = 1;
- if(name)
- {
- strncpy(current->comm,name,15);
- current->comm[15]=0;
- }
- else
- current->comm[0]=0;
- /* set signal mask to what we want to respond */
- siginitsetinv(¤t->blocked,mask);
- /* exit_signal isn't set up */
- /* if we inherit from cpu idle */
- this_process->exit_signal=SIGCHLD;
- /* if priority=0 schedule can go into a tight loop */
- this_process->policy= SCHED_OTHER;
- /* nice goes priority=20-nice; */
- this_process->nice=10;
- if(use_init_fs)
- {
- exit_fs(this_process); /* current->fs->count--; */
- fs = init_task.fs;
- current->fs = fs;
- atomic_inc(&fs->count);
- exit_files(current);
- }
- write_lock_irq(&tasklist_lock);
- /* We want init as our parent */
- REMOVE_LINKS(this_process);
- this_process->p_opptr=this_process->p_pptr=child_reaper;
- SET_LINKS(this_process);
- write_unlock_irq(&tasklist_lock);
-}
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/lowcore.h>
#include <asm/s390_ext.h>
* Simple hash strategy: index = code & 0xff;
* ext_int_hash[index] is the start of the list for all external interrupts
* that hash to this index. With the current set of external interrupts
- * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console and 0x4000
- * iucv) this is always the first element.
+ * (0x1202 external call, 0x1004 cpu timer, 0x2401 hwc console, 0x4000
+ * iucv and 0x2603 pfault) this is always the first element.
*/
ext_int_info_t *ext_int_hash[256] = { 0, };
ext_int_info_t ext_int_info_timer;
ext_int_info_t ext_int_info_hwc;
+ext_int_info_t ext_int_pfault;
int register_external_interrupt(__u16 code, ext_int_handler_t handler) {
ext_int_info_t *p;
p = &ext_int_info_timer;
else if (code == 0x2401) /* hwc_init is done too early too */
p = &ext_int_info_hwc;
+ else if (code == 0x2603) /* pfault_init is done too early too */
+ p = &ext_int_pfault;
else
p = (ext_int_info_t *)
kmalloc(sizeof(ext_int_info_t), GFP_ATOMIC);
q->next = p->next;
else
ext_int_hash[index] = p->next;
- if (code != 0x1004 && code != 0x2401)
+ if (code != 0x1004 && code != 0x2401 && code != 0x2603)
kfree(p);
return 0;
}
EXPORT_SYMBOL(machine_flags);
EXPORT_SYMBOL(__udelay);
EXPORT_SYMBOL(kernel_thread);
+EXPORT_SYMBOL(console_mode);
+EXPORT_SYMBOL(console_device);
#if CONFIG_IP_MULTICAST
/* Required for lcs gigibit ethernet multicast support */
/*
* Machine setup..
*/
+unsigned int console_mode = 0;
+unsigned int console_device = -1;
unsigned long memory_size = 0;
unsigned long machine_flags = 0;
__u16 boot_cpu_addr;
__setup("vmpoff=", vmpoff_setup);
+/*
+ * condev= and conmode= setup parameter.
+ */
+
+static int __init condev_setup(char *str)
+{
+ int vdev;
+
+ vdev = simple_strtoul(str, &str, 0);
+ if (vdev >= 0 && vdev < 65536)
+ console_device = vdev;
+ return 1;
+}
+
+__setup("condev=", condev_setup);
+
+static int __init conmode_setup(char *str)
+{
+#if defined(CONFIG_HWC_CONSOLE)
+ if (strncmp(str, "hwc", 4) == 0 && !MACHINE_IS_P390)
+ SET_CONSOLE_HWC;
+#endif
+#if defined(CONFIG_TN3215_CONSOLE)
+ if (strncmp(str, "3215", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+ SET_CONSOLE_3215;
+#endif
+#if defined(CONFIG_TN3270_CONSOLE)
+ if (strncmp(str, "3270", 5) == 0 && (MACHINE_IS_VM || MACHINE_IS_P390))
+ SET_CONSOLE_3270;
+#endif
+ return 1;
+}
+
+__setup("conmode=", conmode_setup);
+
+static void __init conmode_default(void)
+{
+ char query_buffer[1024];
+ char *ptr;
+
+ if (MACHINE_IS_VM) {
+ cpcmd("QUERY TERM", query_buffer, 1024);
+ ptr = strstr(query_buffer, "CONMODE");
+ /*
+ * Set the conmode to 3215 so that the device recognition
+ * will set the cu_type of the console to 3215. If the
+ * conmode is 3270 and we don't set it back then both
+ * 3215 and the 3270 driver will try to access the console
+ * device (3215 as console and 3270 as normal tty).
+ */
+ cpcmd("TERM CONMODE 3215", NULL, 0);
+ if (ptr == NULL) {
+#if defined(CONFIG_HWC_CONSOLE)
+ SET_CONSOLE_HWC;
+#endif
+ return;
+ }
+ if (strncmp(ptr + 8, "3270", 4) == 0) {
+#if defined(CONFIG_TN3270_CONSOLE)
+ SET_CONSOLE_3270;
+#elif defined(CONFIG_TN3215_CONSOLE)
+ SET_CONSOLE_3215;
+#elif defined(CONFIG_HWC_CONSOLE)
+ SET_CONSOLE_HWC;
+#endif
+ } else if (strncmp(ptr + 8, "3215", 4) == 0) {
+#if defined(CONFIG_TN3215_CONSOLE)
+ SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+ SET_CONSOLE_3270;
+#elif defined(CONFIG_HWC_CONSOLE)
+ SET_CONSOLE_HWC;
+#endif
+ }
+ } else if (MACHINE_IS_P390) {
+#if defined(CONFIG_TN3215_CONSOLE)
+ SET_CONSOLE_3215;
+#elif defined(CONFIG_TN3270_CONSOLE)
+ SET_CONSOLE_3270;
+#endif
+ } else {
+#if defined(CONFIG_HWC_CONSOLE)
+ SET_CONSOLE_HWC;
+#endif
+ }
+}
+
/*
* Reboot, halt and power_off routines for non SMP.
*/
unsigned long start_pfn, end_pfn;
static unsigned int smptrap=0;
unsigned long delay = 0;
- int len = 0;
if (smptrap)
return;
smptrap=1;
- printk("Command line is: %s\n", COMMAND_LINE);
-
/*
* Setup lowcore information for boot cpu
*/
* "mem=XXX[kKmM]" sets memsize
*/
if (c == ' ' && strncmp(from, "mem=", 4) == 0) {
- if (to != command_line) to--;
memory_end = simple_strtoul(from+4, &from, 0);
if ( *from == 'K' || *from == 'k' ) {
memory_end = memory_end << 10;
* "ipldelay=XXX[sm]" sets ipl delay in seconds or minutes
*/
if (c == ' ' && strncmp(from, "ipldelay=", 9) == 0) {
- if (to != command_line) to--;
delay = simple_strtoul(from+9, &from, 0);
if (*from == 's' || *from == 'S') {
delay = delay*1000000;
delay = delay*60*1000000;
from++;
}
- /* now wait for the requestion amount of time */
+ /* now wait for the requested amount of time */
udelay(delay);
}
cn = *(from++);
break;
if (cn == '\n')
cn = ' '; /* replace newlines with space */
+ if (cn == 0x0d)
+ cn = ' '; /* replace 0x0d with space */
if (cn == ' ' && c == ' ')
continue; /* remove additional spaces */
c = cn;
- if (COMMAND_LINE_SIZE <= ++len)
+ if (to - command_line >= COMMAND_LINE_SIZE)
break;
*(to++) = c;
}
request_resource(&iomem_resource, res);
request_resource(res, &code_resource);
request_resource(res, &data_resource);
+
+ /* Setup default console */
+ conmode_default();
}
void print_cpu_info(struct cpuinfo_S390 *cpuinfo)
/* Set up registers for signal handler */
regs->gprs[15] = (addr_t)frame;
regs->psw.addr = FIX_PSW(ka->sa.sa_handler);
+ regs->psw.mask = _USER_PSW_MASK;
}
/* Set up to return from userspace. If provided, use a stub
already in userspace. */
#endif
/* Martin wants this for pthreads */
regs->gprs[3] = (addr_t)&frame->sc;
+
+ /* We forgot to include these in the sigcontext.
+ To avoid breaking binary compatibility, they are passed as args. */
+ regs->gprs[4] = current->thread.trap_no;
+ regs->gprs[5] = current->thread.prot_addr;
return;
give_sigsegv:
siginfo_t *info, sigset_t *oldset, struct pt_regs * regs)
{
/* Are we from a system call? */
- if (regs->orig_gpr2 >= 0) {
+ if (regs->trap == __LC_SVC_OLD_PSW) {
/* If so, check system call restarting.. */
switch (regs->gprs[2]) {
case -ERESTARTNOHAND:
/* FALLTHRU */
default:
- lock_kernel();
sigaddset(¤t->pending.signal, signr);
recalc_sigpending(current);
current->flags |= PF_SIGNALED;
* Activate a secondary processor.
*/
extern void init_100hz_timer(void);
+extern int pfault_init(void);
int __init start_secondary(void *cpuvoid)
{
/* nothing */ ;
/* init per CPU 100 hz timer */
init_100hz_timer();
+#ifdef CONFIG_PFAULT
+ /* Enable pfault pseudo page faults on this cpu. */
+ pfault_init();
+#endif
/* cpu_idle will call schedule for us */
return cpu_idle(NULL);
}
{
unsigned long flags;
unsigned long usec, sec;
- unsigned long lost_ticks = jiffies - wall_jiffies;
+ unsigned long lost_ticks;
read_lock_irqsave(&xtime_lock, flags);
+ lost_ticks = jiffies - wall_jiffies;
usec = do_gettimeoffset();
if (lost_ticks)
usec +=(USECS_PER_JIFFY*lost_ticks);
#if CONFIG_REMOTE_DEBUG
#include <asm/gdb-stub.h>
#endif
+#include <asm/cpcmd.h>
+#include <asm/s390_ext.h>
/* Called from entry.S only */
extern void handle_per_exception(struct pt_regs *regs);
#endif
extern pgm_check_handler_t do_page_fault;
+#ifdef CONFIG_PFAULT
+extern int pfault_init(void);
+extern void pfault_fini(void);
+extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
+#endif
spinlock_t die_lock;
__u16 *location;
int do_sig = 0;
- lock_kernel();
location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
/* WARNING don't change this check back to */
/* int problem_state=(regs->psw.mask & PSW_PROBLEM_STATE); */
do_sig = 1;
if (do_sig)
do_trap(interruption_code, SIGILL, "illegal operation", regs, NULL);
- unlock_kernel();
}
asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
__u16 *location;
int do_sig = 0;
- lock_kernel();
location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
__asm__ volatile ("stfpc %0\n\t"
: "=m" (current->thread.fp_regs.fpc));
do_sig = 1;
if (do_sig)
do_trap(interruption_code, SIGILL, "data exception", regs, NULL);
- unlock_kernel();
}
pgm_check_table[0x1C] = &privileged_op;
pgm_check_table[0x38] = &addressing_exception;
pgm_check_table[0x3B] = &do_page_fault;
+#ifdef CONFIG_PFAULT
+ if (MACHINE_IS_VM) {
+ /* request the 0x2603 external interrupt */
+ if (register_external_interrupt(0x2603, pfault_interrupt) != 0)
+ panic("Couldn't request external interrupt 0x2603");
+ /*
+ * Try to get pfault pseudo page faults going.
+ */
+ if (pfault_init() != 0) {
+ /* Tough luck, no pfault. */
+ unregister_external_interrupt(0x2603,
+ pfault_interrupt);
+ }
+ }
+#endif
}
#include <linux/mm.h>
#include <linux/smp.h>
#include <linux/smp_lock.h>
+#include <linux/init.h>
#include <asm/system.h>
#include <asm/uaccess.h>
unsigned long address;
unsigned long fixup;
int write;
- unsigned long psw_mask;
- unsigned long psw_addr;
int si_code = SEGV_MAPERR;
int kernel_address = 0;
- /*
- * get psw mask of Program old psw to find out,
- * if user or kernel mode
- */
-
- psw_mask = S390_lowcore.program_old_psw.mask;
- psw_addr = S390_lowcore.program_old_psw.addr;
-
/*
* get the failing address
* more specific the segment and page table portion of
up_read(&mm->mmap_sem);
/* User mode accesses just cause a SIGSEGV */
- if (psw_mask & PSW_PROBLEM_STATE) {
+ if (regs->psw.mask & PSW_PROBLEM_STATE) {
struct siginfo si;
tsk->thread.prot_addr = address;
tsk->thread.trap_no = error_code;
out_of_memory:
up_read(&mm->mmap_sem);
printk("VM: killing process %s\n", tsk->comm);
- if (psw_mask & PSW_PROBLEM_STATE)
+ if (regs->psw.mask & PSW_PROBLEM_STATE)
do_exit(SIGKILL);
goto no_context;
force_sig(SIGBUS, tsk);
/* Kernel mode? Handle exceptions or die */
- if (!(psw_mask & PSW_PROBLEM_STATE))
+ if (!(regs->psw.mask & PSW_PROBLEM_STATE))
goto no_context;
}
+
+#ifdef CONFIG_PFAULT
+/*
+ * 'pfault' pseudo page faults routines.
+ */
+static int pfault_disable = 0;
+
+static int __init nopfault(char *str)
+{
+ pfault_disable = 1;
+ return 1;
+}
+
+__setup("nopfault", nopfault);
+
+typedef struct {
+ __u16 refdiagc;
+ __u16 reffcode;
+ __u16 refdwlen;
+ __u16 refversn;
+ __u64 refgaddr;
+ __u64 refselmk;
+ __u64 refcmpmk;
+ __u64 reserved;
+} __attribute__ ((packed)) pfault_refbk_t;
+
+typedef struct _pseudo_wait_t {
+ struct _pseudo_wait_t *next;
+ wait_queue_head_t queue;
+ unsigned long address;
+ int resolved;
+} pseudo_wait_t;
+
+static pseudo_wait_t *pseudo_lock_queue = NULL;
+static spinlock_t pseudo_wait_spinlock; /* spinlock to protect lock queue */
+
+int pfault_init(void)
+{
+ pfault_refbk_t refbk =
+ { 0x258, 0, 5, 2, __LC_KERNEL_STACK, 1ULL << 48, 1ULL << 48, 0ULL };
+ int rc;
+
+ if (pfault_disable)
+ return -1;
+ __asm__ __volatile__(
+ " diag %1,%0,0x258\n"
+ "0: j 2f\n"
+ "1: la %0,8\n"
+ "2:\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .quad 0b,1b\n"
+ ".previous"
+ : "=d" (rc) : "a" (&refbk) : "cc" );
+ __ctl_set_bit(0, 9);
+ return rc;
+}
+
+void pfault_fini(void)
+{
+ pfault_refbk_t refbk =
+ { 0x258, 1, 5, 2, 0ULL, 0ULL, 0ULL, 0ULL };
+
+ if (pfault_disable)
+ return;
+ __ctl_clear_bit(0, 9);
+ __asm__ __volatile__(
+ " diag %0,0,0x258\n"
+ "0:\n"
+ ".section __ex_table,\"a\"\n"
+ " .align 4\n"
+ " .quad 0b,0b\n"
+ ".previous"
+ : : "a" (&refbk) : "cc" );
+}
+
+asmlinkage void
+pfault_interrupt(struct pt_regs *regs, __u16 error_code)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ struct task_struct *tsk;
+ wait_queue_head_t queue;
+ wait_queue_head_t *qp;
+ __u16 subcode;
+
+ /*
+ * Get the external interruption subcode & pfault
+ * initial/completion signal bit. VM stores this
+ * in the 'cpu address' field associated with the
+ * external interrupt.
+ */
+ subcode = S390_lowcore.cpu_addr;
+ if ((subcode & 0xff00) != 0x06)
+ return;
+
+ /*
+ * Get the token (= address of kernel stack of affected task).
+ */
+ tsk = (struct task_struct *)
+ (*((unsigned long *) __LC_PFAULT_INTPARM) - THREAD_SIZE);
+
+ if (subcode & 0x0080) {
+ /* signal bit is set -> a page has been swapped in by VM */
+ qp = (wait_queue_head_t *)
+ xchg(&tsk->thread.pfault_wait, -1);
+ if (qp != NULL) {
+ /* Initial interrupt was faster than the completion
+ * interrupt. pfault_wait is valid. Set pfault_wait
+ * back to zero and wake up the process. This can
+ * safely be done because the task is still sleeping
+ * and can't procude new pfaults. */
+ tsk->thread.pfault_wait = 0ULL;
+ wake_up(qp);
+ }
+ } else {
+ /* signal bit not set -> a real page is missing. */
+ init_waitqueue_head (&queue);
+ qp = (wait_queue_head_t *)
+ xchg(&tsk->thread.pfault_wait, (addr_t) &queue);
+ if (qp != NULL) {
+ /* Completion interrupt was faster than the initial
+ * interrupt (swapped in a -1 for pfault_wait). Set
+ * pfault_wait back to zero and exit. This can be
+ * done safely because tsk is running in kernel
+ * mode and can't produce new pfaults. */
+ tsk->thread.pfault_wait = 0ULL;
+ }
+
+ /* go to sleep */
+ wait_event(queue, tsk->thread.pfault_wait == 0ULL);
+ }
+}
+#endif
+
+++ /dev/null
-all: dasdfmt
-
-dasdfmt: dasdfmt.c
- $(CC) -o $@ $^
- $(STRIP) $@
-
-clean:
- rm -f dasdfmt
-
+++ /dev/null
-.TH DASDFMT 8 "Tue Jan 25 2000"
-.UC 4
-.SH NAME
-dasdfmt \- formatting of DSAD (ECKD) disk drives.
-.SH SYNOPSIS
-\fBdasdfmt\fR [-tvyLV] [-b \fIblockSize\fR] [-l \fIdiskLabel\fR] \fIdiskSpec\fR
-.SH DESCRIPTION
-\fBdasdfmt\fR formats a DASD (ECKD) disk drive to prepare it
-for usage with Linux for S/390. \fBWARNING\fR: Incautious usage of
-\fBdasdfmt\fR can result in \fBLOSS OF DATA\fR.
-
-.SH OPTIONS
-.TP
-\fB-t\fR
-Disables any modification of the disk drive. \fBdasdfmt\fR just prints
-out, what it \fBwould\fR do.
-
-.TP
-\fB-v\fR
-Increases verbosity.
-
-.TP
-\fB-y\fR
-Start formatting without further user-confirmation.
-
-.TP
-\fB-L\fR
-Omit the writing of a disk label after formatting.
-
-.TP
-\fB-V\fR
-Print version number and exit.
-
-.TP
-\fB-b\fR \fIblockSize\fR
-Specify blocksize to be used. \fIblocksize\fR must be a positive integer
-and always be a power of two. Due due some limitations in the driver,
-it is \fBstrongly\fR recommended to use a \fIblockSize\fR of \fI4096\fR.
-
-.TP
-\fB-l\fR \fIdiskLabel\fR
-Specify the label to be written to disk after formatting. If no label is
-specified, a sensible default is used. \fIdiskLabel\fR is interpreted as
-ASCII string and is automatically converted to EBCDIC.
-
-.TP
-\fIdiskSpec\fR
-This parameter specified the device to be formatted. It also can be
-given in two variants:
-.sp
- \fB-f\fR \fB/dev/dasd\fR\fIX\fR
-.br
-or
-.br
- \fB-n\fR \fIdevnum\fR
-.sp
-The first form uses the commonly used
-.SM UNIX
-device notation where \fIX\fR is a single lowercase letter.
-The second form uses simply the device number.
-
-.SH BUGS
-None so far ;-)
-
-.SH AUTHOR
-.nf
-This man-page was written by Fritz Elfert <felfert@to.com>
-.fi
+++ /dev/null
-/*
- *
- * dasdfmt.c
- *
- * S390 version
- * Copyright (C) 1999,2000 IBM Corporation
- * Author(s): Utz Bacher, <utz.bacher@de.ibm.com>
- *
- * Device-in-use-checks by Fritz Elfert, <felfert@to.com>
- * Compatible Disk Layout enhancements by Carsten Otte, <cotte@de.ibm.com>
- *
- * Still to do:
- * detect non-switch parameters ("dasdfmt -n 170 XY") and complain about them
- */
-
-/* #define _LINUX_BLKDEV_H */
-
-#include <unistd.h>
-#include <stdio.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <sys/ioctl.h>
-#include <errno.h>
-#include <getopt.h>
-#include <limits.h>
-#include <stdlib.h>
-#include <string.h>
-#include <dirent.h>
-#include <mntent.h>
-#define __KERNEL__ /* we want to use kdev_t and not have to define it */
-#include <linux/kdev_t.h>
-#undef __KERNEL__
-
-#include <linux/fs.h>
-#include <asm/dasd.h>
-#include <linux/hdreg.h>
-
-#define EXIT_MISUSE 1
-#define EXIT_BUSY 2
-#define TEMPFILENAME "/tmp/ddfXXXXXX"
-#define TEMPFILENAMECHARS 8 /* 8 characters are fixed in all temp filenames */
-#define SLASHDEV "/dev/"
-#define PROC_DASD_DEVICES "/proc/dasd/devices"
-/* _PATH_MOUNTED is /etc/mtab - /proc/mounts does not show root-fs correctly */
-#define PROC_MOUNTS _PATH_MOUNTED
-#define PROC_SWAPS "/proc/swaps"
-#define DASD_DRIVER_NAME "dasd"
-#define LABEL_LENGTH 10
-#define PROC_LINE_LENGTH 80
-#define ERR_LENGTH 80
-
-#define MAX_FILELEN NAME_MAX+PATH_MAX
-
-#define GIVEN_DEVNO 1
-#define GIVEN_MAJOR 2
-#define GIVEN_MINOR 4
-
-#define CHECK_START 1
-#define CHECK_END 2
-#define CHECK_BLKSIZE 4
-#define CHECK_ALL ~0
-
-#define ERRMSG(x...) {fflush(stdout);fprintf(stderr,x);}
-#define ERRMSG_EXIT(ec,x...) {fflush(stdout);fprintf(stderr,x);exit(ec);}
-
-#define CHECK_SPEC_MAX_ONCE(i,str) \
- {if (i>1) \
- ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
- "can only be specified once\n",prog_name);}
-
-#define PARSE_PARAM_INTO(x,param,base,str) \
- {x=(int)strtol(param,&endptr,base); \
- if (*endptr) \
- ERRMSG_EXIT(EXIT_MISUSE,"%s: " str " " \
- "is in invalid format\n",prog_name);}
-
-char *prog_name;/*="dasdfmt";*/
-char tempfilename[]=TEMPFILENAME;
-
-__u8 _ascebc[256] =
-{
- /*00 NUL SOH STX ETX EOT ENQ ACK BEL */
- 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F,
- /*08 BS HT LF VT FF CR SO SI */
- /* ->NL */
- 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
- /*10 DLE DC1 DC2 DC3 DC4 NAK SYN ETB */
- 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26,
- /*18 CAN EM SUB ESC FS GS RS US */
- /* ->IGS ->IRS ->IUS */
- 0x18, 0x19, 0x3F, 0x27, 0x22, 0x1D, 0x1E, 0x1F,
- /*20 SP ! " # $ % & ' */
- 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D,
- /*28 ( ) * + , - . / */
- 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61,
- /*30 0 1 2 3 4 5 6 7 */
- 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7,
- /*38 8 9 : ; < = > ? */
- 0xF8, 0xF9, 0x7A, 0x5E, 0x4C, 0x7E, 0x6E, 0x6F,
- /*40 @ A B C D E F G */
- 0x7C, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7,
- /*48 H I J K L M N O */
- 0xC8, 0xC9, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6,
- /*50 P Q R S T U V W */
- 0xD7, 0xD8, 0xD9, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6,
- /*58 X Y Z [ \ ] ^ _ */
- 0xE7, 0xE8, 0xE9, 0xBA, 0xE0, 0xBB, 0xB0, 0x6D,
- /*60 ` a b c d e f g */
- 0x79, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
- /*68 h i j k l m n o */
- 0x88, 0x89, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96,
- /*70 p q r s t u v w */
- 0x97, 0x98, 0x99, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6,
- /*78 x y z { | } ~ DL */
- 0xA7, 0xA8, 0xA9, 0xC0, 0x4F, 0xD0, 0xA1, 0x07,
- /*80*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*88*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*90*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*98*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*A0*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*A8*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*B0*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*B8*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*C0*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*C8*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*D0*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*D8*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*E0 sz */
- 0x3F, 0x59, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*E8*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*F0*/
- 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
- /*F8*/
- 0x90, 0x3F, 0x3F, 0x3F, 0x3F, 0xEA, 0x3F, 0xFF
-};
-
-void convert_label(char *str)
-{
- int i;
- for (i=0;i<LABEL_LENGTH;i++) str[i]=_ascebc[str[i]];
-}
-
-void
-exit_usage(int exitcode)
-{
-#ifdef RANGE_FORMATTING
- printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] [<range>] " \
- "<diskspec>\n\n",prog_name);
-#else /* RANGE_FORMATTING */
- printf("Usage: %s [-htvyCLV] [-l <label>] [-b <blocksize>] " \
- "<diskspec>\n\n",prog_name);
-#endif /* RANGE_FORMATTING */
- printf(" -t means testmode\n");
- printf(" -v means verbose mode\n");
- printf(" -C means format compatible disk layout\n");
- printf(" -V means print version\n");
- printf(" -L means don't write disk label\n");
- printf(" <label> is a label which is converted to EBCDIC and " \
- "written to disk\n");
- printf(" <blocksize> has to be power of 2 and at least 512\n");
-#ifdef RANGE_FORMATTING
- printf(" <range> is either\n");
- printf(" -s <start_track> -e <end_track>\n");
- printf(" or\n");
- printf(" -r <start_track>-<end_track>\n");
-#endif /* RANGE_FORMATTING */
- printf(" and <diskspec> is either\n");
- printf(" -f /dev/dasdX\n");
- printf(" or\n");
- printf(" -n <s390-devnr>\n");
- exit(exitcode);
-}
-
-void
-get_xno_from_xno(int *devno,kdev_t *major_no,kdev_t *minor_no,int mode)
-{
- FILE *file;
- int d,rc;
- kdev_t mi,ma;
- int mi_i,ma_i; /* for scanf :-( */
- char line[PROC_LINE_LENGTH];
-
- file=fopen(PROC_DASD_DEVICES,"r");
- if (file==NULL)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to open " \
- PROC_DASD_DEVICES ": %s (do you have the /proc " \
- "filesystem enabled?)\n",prog_name,strerror(errno));
-
- /* fgets(line,sizeof(line),file); omit first line */
- while (fgets(line,sizeof(line),file)!=NULL) {
- rc=sscanf(line,"%X %*[(A-Z) ] at (%d:%d)",&d,&ma_i,&mi_i);
- ma=ma_i;
- mi=mi_i;
- if ( (rc==3) &&
- !((d!=*devno)&&(mode&GIVEN_DEVNO)) &&
- !((ma!=*major_no)&&(mode&GIVEN_MAJOR)) &&
- !((mi!=*minor_no)&&(mode&GIVEN_MINOR)) ) {
- *devno=d;
- *major_no=ma;
- *minor_no=mi;
- /* yes, this is a quick exit, but the easiest way */
- fclose(file);
- return;
- }
- }
- fclose(file);
-
- ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to find device in the /proc " \
- "filesystem (are you sure to have the right parameter " \
- "dasd=xxx?)\n",
- prog_name);
-}
-
-char *
-get_devname_from_devno(int devno,int verbosity)
-{
- kdev_t major_no,minor_no;
- kdev_t file_major,file_minor;
- struct stat stat_buf;
- int rc;
- int found;
- char *devname;
- char tmpname[MAX_FILELEN];
-
- DIR *dp;
- struct dirent *direntp;
-
- /**** get minor number ****/
- get_xno_from_xno(&devno,&major_no,&minor_no,GIVEN_DEVNO);
-
- /**** get device file ****/
- if ((dp=opendir(SLASHDEV)) == NULL)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: unable to read " SLASHDEV \
- "\n",prog_name);
- found=0;
- while ((direntp=readdir(dp)) != NULL) {
- strcpy(tmpname,SLASHDEV);
- strcat(tmpname,direntp->d_name);
- rc=stat(tmpname,&stat_buf);
- if (!rc) {
- file_major=MAJOR(stat_buf.st_rdev);
- file_minor=MINOR(stat_buf.st_rdev);
- if ((file_major==major_no) && (file_minor==minor_no)) {
- found=1;
- break;
- }
- }
- }
- if (found) {
- devname=malloc(strlen(direntp->d_name));
- strcpy(devname,tmpname);
- }
- rc=closedir(dp);
- if (rc<0) ERRMSG("%s: unable to close directory " SLASHDEV \
- "; continuing\n",prog_name);
- if (found)
- return devname;
-
- if (verbosity>=1)
- printf("I didn't find device node in " SLASHDEV \
- "; trying to create a temporary node\n");
-
- /**** get temp file and create device node *****/
- rc=mkstemp(tempfilename);
- if (rc==-1)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to get temporary " \
- "filename: %s\n",prog_name,strerror(errno));
- close(rc);
- rc=unlink(tempfilename);
-
- rc=mknod(tempfilename,S_IFBLK|0600,MKDEV(major_no,minor_no));
- if (rc)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: failed to create temporary " \
- "device node %s: %s\n",prog_name,tempfilename,
- strerror(errno));
- return tempfilename;
-}
-
-char *
-check_param(int mode,format_data_t data)
-{
- char *s;
-
- if (NULL==(s=malloc(ERR_LENGTH)))
- ERRMSG_EXIT(EXIT_FAILURE,"%s: not enough memory.\n",prog_name);
-
- if ((mode&CHECK_START)&&(data.start_unit<0)) {
- strcpy(s,"start track must be greater than zero");
- goto exit;
- }
- if ((mode&CHECK_END)&&(data.stop_unit<-1)) {
- strcpy(s,"end track must be -1 or greater than zero");
- goto exit;
- }
- if ((mode&CHECK_END)&&(data.start_unit>data.stop_unit)&&
- (data.stop_unit!=-1)) {
- strcpy(s,"end track must be higher than start track");
- goto exit;
- }
-
- if ((mode&CHECK_BLKSIZE)&&(data.blksize<1)) {
- strcpy(s,"blocksize must be a positive integer");
- goto exit;
- }
- if (mode&CHECK_BLKSIZE) while (data.blksize>0) {
- if ((data.blksize%2)&&(data.blksize!=1)) {
- strcpy(s,"blocksize must be a power of 2");
- goto exit;
- }
- data.blksize/=2;
- }
-
- free(s);
- return NULL;
-exit:
- return s;
-}
-
-#define ASK_PRINTOUT printf("Please enter %s",output)
-#define ASK_GETBUFFER fgets(buffer,sizeof(buffer),stdin)
-#define ASK_SCANFORNUMBER(var) rc=sscanf(buffer,"%d%c",&var,&c)
-#define ASK_COMPLAIN_FORMAT if ((rc==2)&&(c=='\n')) rc=1; \
- if (rc==-1) rc=1; /* this happens, if enter is pressed */ \
- if (rc!=1) printf(" -- wrong input, try again.\n")
-#define ASK_CHECK_PARAM(mode) str=check_param(mode,params); \
- if (str!=NULL) { printf(" -- %s\n",str); rc=0; free(str); }
-
-format_data_t
-ask_user_for_data(format_data_t params)
-{
- char buffer[20]; /* should be enough for inputing track numbers */
- char c;
- int i,rc;
- char *str;
- char output[60],o2[12];
-
-#ifdef RANGE_FORMATTING
- i=params.start_unit;
- do {
- params.start_unit=i;
- sprintf(output,"the start track of the range to format " \
- "[%d]: ",i);
- ASK_PRINTOUT;
- ASK_GETBUFFER;
- ASK_SCANFORNUMBER(params.start_unit);
- ASK_COMPLAIN_FORMAT;
- ASK_CHECK_PARAM(CHECK_START);
- } while (rc!=1);
-
- i=params.stop_unit;
- do {
- params.stop_unit=i;
- sprintf(output,"the end track of the range to format [");
- if (i==-1) sprintf(o2,"END]: "); else
- sprintf(o2,"%d]: ",i);
- strcat(output,o2);
- ASK_PRINTOUT;
- ASK_GETBUFFER;
- if ( (!strcasecmp(buffer,"end")) ||
- (!strcasecmp(buffer,"end\n")) ) {
- rc=1;
- params.stop_unit=-1;
- } else {
- ASK_SCANFORNUMBER(params.stop_unit);
- ASK_COMPLAIN_FORMAT;
- ASK_CHECK_PARAM(CHECK_END);
- }
- } while (rc!=1);
-#endif /* RANGE_FORMATTING */
-
- i=params.blksize;
- do {
- params.blksize=i;
- sprintf(output,"the blocksize of the formatting [%d]: ",i);
- ASK_PRINTOUT;
- ASK_GETBUFFER;
- ASK_SCANFORNUMBER(params.blksize);
- ASK_COMPLAIN_FORMAT;
- ASK_CHECK_PARAM(CHECK_BLKSIZE);
- } while (rc!=1);
-
- return params;
-}
-
-/* Check if the device we are going to format is mounted.
- * If true, complain and exit.
- */
-void
-check_mounted(int major, int minor)
-{
- FILE *f;
- int ishift = 0;
- struct mntent *ment;
- struct stat stbuf;
- char line[128];
-
- /* If whole disk to be formatted ... */
- if ((minor % (1U << DASD_PARTN_BITS)) == 0) {
- /* ... ignore partition-selector */
- minor >>= DASD_PARTN_BITS;
- ishift = DASD_PARTN_BITS;
- }
- /*
- * first, check filesystems
- */
- if (!(f = fopen(PROC_MOUNTS, "r")))
- ERRMSG_EXIT(EXIT_FAILURE, "%s: %s\n", PROC_MOUNTS,
- strerror(errno));
- while ((ment = getmntent(f))) {
- if (stat(ment->mnt_fsname, &stbuf) == 0)
- if ((major == MAJOR(stbuf.st_rdev)) &&
- (minor == (MINOR(stbuf.st_rdev)>>ishift))) {
- ERRMSG("%s: device is mounted on %s!!\n",
- prog_name,ment->mnt_dir);
- ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
- "format it, please unmount it.\n");
- }
- }
- fclose(f);
- /*
- * second, check active swap spaces
- */
- if (!(f = fopen(PROC_SWAPS, "r")))
- ERRMSG_EXIT(EXIT_FAILURE, PROC_SWAPS " %s", strerror(errno));
- /*
- * skip header line
- */
- fgets(line, sizeof(line), f);
- while (fgets(line, sizeof(line), f)) {
- char *p;
- for (p = line; *p && (!isspace(*p)); p++) ;
- *p = '\0';
- if (stat(line, &stbuf) == 0)
- if ((major == MAJOR(stbuf.st_rdev)) &&
- (minor == (MINOR(stbuf.st_rdev)>>ishift))) {
- ERRMSG("%s: the device is in use for "
- "swapping!!\n",prog_name);
- ERRMSG_EXIT(EXIT_BUSY, "If you really want to "
- "format it, please use swapoff %s.\n",
- line);
- }
- }
- fclose(f);
-}
-
-void
-do_format_dasd(char *dev_name,format_data_t format_params,int testmode,
- int verbosity,int writenolabel,int labelspec,
- char *label,int withoutprompt,int devno)
-{
- int fd,rc;
- struct stat stat_buf;
- kdev_t minor_no,major_no;
- int new_blksize;
- unsigned int label_position;
- struct hd_geometry new_geometry;
- char inp_buffer[5]; /* to contain yes */
-
- fd=open(dev_name,O_RDWR);
- if (fd==-1)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: error opening device %s: " \
- "%s\n",prog_name,dev_name,strerror(errno));
-
- if (verbosity>=1) {
- }
-
- rc=stat(dev_name,&stat_buf);
- if (rc) {
- ERRMSG_EXIT(EXIT_FAILURE,"%s: error occurred during stat: " \
- "%s\n",prog_name,strerror(errno));
- } else {
- if (!S_ISBLK(stat_buf.st_mode))
- ERRMSG_EXIT(EXIT_FAILURE,"%s: file is not a " \
- "blockdevice.\n",prog_name);
- major_no=MAJOR(stat_buf.st_rdev);
- minor_no=MINOR(stat_buf.st_rdev);
- }
- check_mounted(major_no, minor_no);
-
- get_xno_from_xno(&devno,&major_no,&minor_no,
- GIVEN_MAJOR|GIVEN_MINOR);
- if ((!writenolabel) && (!labelspec)) {
- sprintf(label,"LNX1 x%04x",devno);
- }
-
- if ( ((withoutprompt)&&(verbosity>=1)) ||
- (!withoutprompt) ) {
- printf("\nI am going to format the device %s in the " \
- "following way:\n",dev_name);
- printf(" Device number of device : 0x%x\n",devno);
- printf(" Major number of device : %u\n",major_no);
- printf(" Minor number of device : %u\n",minor_no);
- printf(" Labelling device : %s\n",(writenolabel)?
- "no":"yes");
- if (!writenolabel)
- printf(" Disk label : %s\n",label);
- if (format_params.intensity != DASD_FORMAT_DEFAULT_INTENSITY)
- printf(" Compatible Disk Layout : %s\n",(format_params.intensity&0x08)?
- "yes":"no");
-#ifdef RANGE_FORMATTING
- printf(" Start track : %d\n" \
- ,format_params.start_unit);
- printf(" End track : ");
- if (format_params.stop_unit==-1)
- printf("last track of disk\n");
- else
- printf("%d\n",format_params.stop_unit);
-#endif /* RANGE_FORMATTING */
- printf(" Blocksize : %d\n" \
- ,format_params.blksize);
- if (testmode) printf("Test mode active, omitting ioctl.\n");
- }
-
- while (!testmode) {
- if (!withoutprompt) {
- printf("\n--->> ATTENTION! <<---\n");
- printf("All data in the specified range of that " \
- "device will be lost.\nType \"yes\" to " \
- "continue, no will leave the disk untouched: ");
- fgets(inp_buffer,sizeof(inp_buffer),stdin);
- if (strcasecmp(inp_buffer,"yes") &&
- strcasecmp(inp_buffer,"yes\n")) {
- printf("Omitting ioctl call (disk will " \
- "NOT be formatted).\n");
- break;
- }
- }
-
- if ( !( (withoutprompt)&&(verbosity<1) ))
- printf("Formatting the device. This may take a " \
- "while (get yourself a coffee).\n");
- rc=ioctl(fd,BIODASDFORMAT,format_params);
- if (rc)
- ERRMSG_EXIT(EXIT_FAILURE,"%s: the dasd driver " \
- "returned with the following error " \
- "message:\n%s\n",prog_name,strerror(errno));
- printf("Finished formatting the device.\n");
-
- if (!writenolabel) {
- if (verbosity>0)
- printf("Retrieving disk geometry... ");
-
- rc=ioctl(fd,HDIO_GETGEO,&new_geometry);
- if (rc) {
- ERRMSG("%s: the ioctl call to get geometry " \
- "returned with the following error " \
- "message:\n%s\n",prog_name,
- strerror(errno));
- goto reread;
- }
-
-
- rc=ioctl(fd,BLKSSZGET,&new_blksize);
- if (rc) {
- ERRMSG("%s: the ioctl call to get blocksize " \
- "returned with the following error " \
- "message:\n%s\n",prog_name,
- strerror(errno));
- goto reread;
- }
-
- if (verbosity>0) printf("done\n");
-
- label_position=new_geometry.start*new_blksize;
-
- if (verbosity>0) printf("Writing label... ");
- convert_label(label);
- rc=lseek(fd,label_position,SEEK_SET);
- if (rc!=label_position) {
- ERRMSG("%s: lseek on the device to %i " \
- "failed with the following error " \
- "message:\n%s\n",prog_name,
- label_position,strerror(errno));
- goto reread;
- }
- rc=write(fd,label,LABEL_LENGTH);
- if (rc!=LABEL_LENGTH) {
- ERRMSG("%s: writing the label only wrote %d " \
- "bytes.\n",prog_name,rc);
- goto reread;
- }
-
- sync();
- sync();
-
- if (verbosity>0) printf("done\n");
- }
- reread:
- printf("Rereading the partition table... ");
- rc=ioctl(fd,BLKRRPART,NULL);
- if (rc) {
- ERRMSG("%s: error during rereading the partition " \
- "table: %s.\n",prog_name,strerror(errno));
- } else printf("done.\n");
-
- break;
- }
-
- rc=close(fd);
- if (rc)
- ERRMSG("%s: error during close: " \
- "%s; continuing.\n",prog_name,strerror(errno));
-}
-
-
-
-int main(int argc,char *argv[]) {
- int verbosity;
- int testmode;
- int withoutprompt;
- int writenolabel,labelspec;
-
- char *dev_name;
- int devno;
- char *dev_filename,*devno_param_str,*range_param_str;
- char *start_param_str,*end_param_str,*blksize_param_str;
- char label[LABEL_LENGTH+1];
-
- format_data_t format_params;
-
- int rc;
- int oc;
- char *endptr;
-
- char c1,c2,cbuffer[6]; /* should be able to contain -end plus 1 char */
- int i,i1,i2;
- char *str;
-
- int start_specified,end_specified,blksize_specified;
- int devfile_specified,devno_specified,range_specified;
-
- /******************* initialization ********************/
- prog_name=argv[0];
-
- endptr=NULL;
-
- /* set default values */
- format_params.start_unit=DASD_FORMAT_DEFAULT_START_UNIT;
- format_params.stop_unit=DASD_FORMAT_DEFAULT_STOP_UNIT;
- format_params.blksize=DASD_FORMAT_DEFAULT_BLOCKSIZE;
- format_params.intensity=DASD_FORMAT_DEFAULT_INTENSITY;
- testmode=0;
- verbosity=0;
- withoutprompt=0;
- writenolabel=0;
- labelspec=0;
- for (i=0;i<LABEL_LENGTH;i++) label[i]=' ';
- label[LABEL_LENGTH]=0;
-
- start_specified=end_specified=blksize_specified=0;
- devfile_specified=devno_specified=range_specified=0;
-
- /*************** parse parameters **********************/
-
- /* avoid error message generated by getopt */
- opterr=0;
-
-#ifdef RANGE_FORMATTING
- while ( (oc=getopt(argc,argv,"r:s:e:b:n:l:f:ChLty?vV")) !=EOF) {
-#endif /* RANGE_FORMATTING */
- while ( (oc=getopt(argc,argv,"b:n:l:f:ChLty?vV")) !=EOF) {
- switch (oc) {
- case 'y':
- withoutprompt=1;
- break;
-
- case 't':
- testmode=1;
- break;
-
- case 'v':
- verbosity++;
- break;
-
- case '?': /* fall-through */
- case ':':
- exit_usage(EXIT_MISUSE);
-
- case 'h':
- exit_usage(0);
- case 'C':
- format_params.intensity&=0x08;
- break;
-
- case 'V':
- printf("%s version 0.99\n",prog_name);
- exit(0);
-
- case 'l':
- strncpy(label,optarg,LABEL_LENGTH);
- if (strlen(optarg)<LABEL_LENGTH)
- label[strlen(optarg)]=' ';
- labelspec++;
- break;
-
- case 'L':
- writenolabel++;
- break;
-
-#ifdef RANGE_FORMATTING
- case 's' :
- start_param_str=optarg;
- start_specified++;
- break;
-
- case 'e' :
- end_param_str=optarg;
- end_specified++;
- break;
-
- case 'r' :
- range_param_str=optarg;
- range_specified++;
- break;
-#endif /* RANGE_FORMATTING */
-
- case 'b' :
- blksize_param_str=optarg;
- blksize_specified++;
- break;
-
- case 'n' :
- devno_param_str=optarg;
- devno_specified++;
- break;
-
- case 'f' :
- dev_filename=optarg;
- devfile_specified++;
- break;
- }
- }
-
- /******************** checking of parameters **************/
-
- /* convert range into -s and -e */
- CHECK_SPEC_MAX_ONCE(range_specified,"formatting range");
-
- while (range_specified) {
- start_specified++;
- end_specified++;
-
- /* scan for 1 or 2 integers, separated by a dash */
- rc=sscanf(range_param_str,"%d%c%d%c",&i1,&c1,&i2,&c2);
- if ((rc==3)&&(c1=='-')) {
- format_params.start_unit=i1;
- format_params.stop_unit=i2;
- break;
- }
- if (rc==1) {
- format_params.start_unit=i1;
- break;
- }
-
- /* scan for integer and -END */
- rc=sscanf(range_param_str,"%d%s",&i1,cbuffer);
- if ((rc==2)&&(!strcasecmp(cbuffer,"-END"))) {
- format_params.start_unit=i1;
- format_params.stop_unit=-1;
- break;
- }
- ERRMSG_EXIT(EXIT_MISUSE,"%s: specified range " \
- "is in invalid format\n",prog_name);
- }
-
- if ((!devfile_specified)&&(!devno_specified))
- ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
- "not specified\n",prog_name);
-
- if ((devfile_specified+devno_specified)>1)
- ERRMSG_EXIT(EXIT_MISUSE,"%s: device to format " \
- "can only be specified once\n",prog_name);
-
- if ((!start_specified)&&(!end_specified)&&(!range_specified)&&
- (!blksize_specified)) {
- format_params=ask_user_for_data(format_params);
- }
-
- CHECK_SPEC_MAX_ONCE(start_specified,"start track");
- CHECK_SPEC_MAX_ONCE(end_specified,"end track");
- CHECK_SPEC_MAX_ONCE(blksize_specified,"blocksize");
- CHECK_SPEC_MAX_ONCE(labelspec,"label");
- CHECK_SPEC_MAX_ONCE(writenolabel,"omit-label-writing flag");
-
- if (devno_specified)
- PARSE_PARAM_INTO(devno,devno_param_str,16,"device number");
- if (start_specified&&!range_specified)
- PARSE_PARAM_INTO(format_params.start_unit,start_param_str,10,
- "start track");
- if (end_specified&&!range_specified)
- PARSE_PARAM_INTO(format_params.stop_unit,end_param_str,10,
- "end track");
- if (blksize_specified)
- PARSE_PARAM_INTO(format_params.blksize,blksize_param_str,10,
- "blocksize");
-
- /***********get dev_name *********************/
- dev_name=(devno_specified)?
- get_devname_from_devno(devno,verbosity):
- dev_filename;
-
- /*** range checking *********/
- str=check_param(CHECK_ALL,format_params);
- if (str!=NULL) ERRMSG_EXIT(EXIT_MISUSE,"%s: %s\n",prog_name,str);
-
- /******* issue the real command and reread part table *******/
- do_format_dasd(dev_name,format_params,testmode,verbosity,
- writenolabel,labelspec,label,withoutprompt,devno);
-
- /*************** cleanup ********************************/
- if (strncmp(dev_name,TEMPFILENAME,TEMPFILENAMECHARS)==0) {
- rc=unlink(dev_name);
- if ((rc)&&(verbosity>=1))
- ERRMSG("%s: temporary device node %s could not be " \
- "removed: %s\n",prog_name,dev_name,
- strerror(errno));
- } else {
- if (devno_specified) {
- /* so we have allocated space for the filename */
- free(dev_name);
- }
- }
-
- return 0;
-}
+++ /dev/null
-all: silo
-
-silo.o: silo.c
- $(CC) -c -o silo.o -O2 silo.c
-
-cfg.o: cfg.c
- $(CC) -c -o cfg.o -O2 cfg.c
-
-silo: silo.o cfg.o
- $(CC) -o $@ $^
- $(STRIP) $@
-
-clean:
- rm -f *.o silo
-
+++ /dev/null
-/* cfg.c - Configuration file parser */
-
-/* Copyright 1992-1997 Werner Almesberger. See file COPYING for details. */
-
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <ctype.h>
-#include <string.h>
-
-#include "cfg.h"
-
-#define MAX_TOKEN 200
-#define MAX_VAR_NAME MAX_TOKEN
-
-static FILE *file;
-static char flag_set;
-static char *last_token = NULL,*last_item = NULL,*last_value = NULL;
-static int line_num;
-static char *file_name = NULL;
-static int back = 0; /* can go back by one char */
-
-
-void pdie(char *msg)
-{
- fflush(stdout);
- perror(msg);
- exit(1);
-}
-
-
-void die(char *fmt,...)
-{
- va_list ap;
-
- fflush(stdout);
- va_start(ap,fmt);
- vfprintf(stderr,fmt,ap);
- va_end(ap);
- fputc('\n',stderr);
- exit(1);
-}
-
-char *pstrdup(const char *str)
-{
- char *this;
-
- if ((this = strdup(str)) == NULL) pdie("Out of memory");
- return this;
-}
-
-int cfg_open(char *name)
-{
- if (!strcmp(name,"-")) file = stdin;
- else if (!(file = fopen(file_name = name,"r"))) pdie(name);
- line_num = 1;
- return fileno(file);
-}
-
-void cfg_error(char *msg,...)
-{
- va_list ap;
-
- fflush(stdout);
- va_start(ap,msg);
- vfprintf(stderr,msg,ap);
- va_end(ap);
- if (!file_name) fputc('\n',stderr);
- else fprintf(stderr," near line %d in file %s\n",line_num,file_name);
- exit(1);
-}
-
-
-static int next_raw(void)
-{
- int ch;
-
- if (!back) return getc(file);
- ch = back;
- back = 0;
- return ch;
-}
-
-
-static int next(void)
-{
- static char *var;
- char buffer[MAX_VAR_NAME+1];
- int ch,braced;
- char *put;
-
- if (back) {
- ch = back;
- back = 0;
- return ch;
- }
- if (var && *var) return *var++;
- ch = getc(file);
- if (ch == '\\') {
- ch = getc(file);
- if (ch == '$') return ch;
- ungetc(ch,file);
- return '\\';
- }
- if (ch != '$') return ch;
- ch = getc(file);
- braced = ch == '{';
- put = buffer;
- if (!braced) *put++ = ch;
- while (1) {
- ch = getc(file);
-#if 0
- if (!braced && ch < ' ') {
- ungetc(ch,file);
- break;
- }
-#endif
- if (ch == EOF) cfg_error("EOF in variable name");
- if (ch < ' ') cfg_error("control character in variable name");
- if (braced && ch == '}') break;
- if (!braced && !isalpha(ch) && !isdigit(ch) && ch != '_') {
- ungetc(ch,file);
- break;
- }
- if (put-buffer == MAX_VAR_NAME) cfg_error("variable name too long");
- *put++ = ch;
- }
- *put = 0;
- if (!(var = getenv(buffer))) cfg_error("unknown variable \"%s\"",buffer);
- return next();
-}
-
-
-static void again(int ch)
-{
- if (back) die("internal error: again invoked twice");
- back = ch;
-}
-
-
-static char *cfg_get_token(void)
-{
- char buf[MAX_TOKEN+1];
- char *here;
- int ch,escaped;
-
- if (last_token) {
- here = last_token;
- last_token = NULL;
- return here;
- }
- while (1) {
- while ((ch = next()), ch == ' ' || ch == '\t' || ch == '\n')
- if (ch == '\n') line_num++;
- if (ch == EOF) return NULL;
- if (ch != '#') break;
- while ((ch = next_raw()), ch != '\n')
- if (ch == EOF) return NULL;
- line_num++;
- }
- if (ch == '=') return pstrdup("=");
- if (ch == '"') {
- here = buf;
- while (here-buf < MAX_TOKEN) {
- if ((ch = next()) == EOF) cfg_error("EOF in quoted string");
- if (ch == '"') {
- *here = 0;
- return pstrdup(buf);
- }
- if (ch == '\\') {
- ch = next();
- if (ch != '"' && ch != '\\' && ch != '\n')
- cfg_error("Bad use of \\ in quoted string");
- if (ch == '\n') {
- while ((ch = next()), ch == ' ' || ch == '\t');
- if (!ch) continue;
- again(ch);
- ch = ' ';
- }
- }
- if (ch == '\n' || ch == '\t')
- cfg_error("\\n and \\t are not allowed in quoted strings");
- *here++ = ch;
- }
- cfg_error("Quoted string is too long");
- return 0; /* not reached */
- }
- here = buf;
- escaped = 0;
- while (here-buf < MAX_TOKEN) {
- if (escaped) {
- if (ch == EOF) cfg_error("\\ precedes EOF");
- if (ch == '\n') line_num++;
- else *here++ = ch == '\t' ? ' ' : ch;
- escaped = 0;
- }
- else {
- if (ch == ' ' || ch == '\t' || ch == '\n' || ch == '#' ||
- ch == '=' || ch == EOF) {
- again(ch);
- *here = 0;
- return pstrdup(buf);
- }
- if (!(escaped = (ch == '\\'))) *here++ = ch;
- }
- ch = next();
- }
- cfg_error("Token is too long");
- return 0; /* not reached */
-}
-
-
-static void cfg_return_token(char *token)
-{
- last_token = token;
-}
-
-
-static int cfg_next(char **item,char **value)
-{
- char *this;
-
- if (last_item) {
- *item = last_item;
- *value = last_value;
- last_item = NULL;
- return 1;
- }
- *value = NULL;
- if (!(*item = cfg_get_token())) return 0;
- if (!strcmp(*item,"=")) cfg_error("Syntax error");
- if (!(this = cfg_get_token())) return 1;
- if (strcmp(this,"=")) {
- cfg_return_token(this);
- return 1;
- }
- if (!(*value = cfg_get_token())) cfg_error("Value expected at EOF");
- if (!strcmp(*value,"=")) cfg_error("Syntax error after %s",*item);
- return 1;
-}
-
-
-static void cfg_return(char *item,char *value)
-{
- last_item = item;
- last_value = value;
-}
-
-
-void cfg_init(CONFIG *table)
-{
- while (table->type != cft_end) {
- switch (table->type) {
- case cft_strg:
- if (table->data) free(table->data);
- case cft_flag:
- table->data = NULL;
- break;
- case cft_link:
- table = ((CONFIG *) table->action)-1;
- break;
- default:
- die("Unknown syntax code %d",table->type);
- }
- table++;
- }
-}
-
-
-static int cfg_do_set(CONFIG *table,char *item,char *value,int copy,
- void *context)
-{
- CONFIG *walk;
-
- for (walk = table; walk->type != cft_end; walk++) {
- if (walk->name && !strcasecmp(walk->name,item)) {
- if (value && walk->type != cft_strg)
- cfg_error("'%s' doesn't have a value",walk->name);
- if (!value && walk->type == cft_strg)
- cfg_error("Value expected for '%s'",walk->name);
- if (walk->data) {
- if (walk->context == context)
- cfg_error("Duplicate entry '%s'",walk->name);
- else {
- fprintf(stderr,"Ignoring entry '%s'\n",walk->name);
- if (!copy) free(value);
- return 1;
- }
- }
- if (walk->type == cft_flag) walk->data = &flag_set;
- else if (walk->type == cft_strg) {
- if (copy) walk->data = pstrdup(value);
- else walk->data = value;
- }
- walk->context = context;
- if (walk->action) ((void (*)(void)) walk->action)();
- break;
- }
- if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
- }
- if (walk->type != cft_end) return 1;
- cfg_return(item,value);
- return 0;
-}
-
-
-void cfg_set(CONFIG *table,char *item,char *value,void *context)
-{
- if (!cfg_do_set(table,item,value,1,context))
- cfg_error("cfg_set: Can't set %s",item);
-}
-
-
-void cfg_unset(CONFIG *table,char *item)
-{
- CONFIG *walk;
-
- for (walk = table; walk->type != cft_end; walk++)
- if (walk->name && !strcasecmp(walk->name,item)) {
- if (!walk->data) die("internal error (cfg_unset %s, unset)",item);
- if (walk->type == cft_strg) free(walk->data);
- walk->data = NULL;
- return;
- }
- die("internal error (cfg_unset %s, unknown",item);
-}
-
-
-int cfg_parse(CONFIG *table)
-{
- char *item,*value;
-
- while (1) {
- if (!cfg_next(&item,&value)) return 0;
- if (!cfg_do_set(table,item,value,0,table)) return 1;
- free(item);
- }
-}
-
-
-int cfg_get_flag(CONFIG *table,char *item)
-{
- CONFIG *walk;
-
- for (walk = table; walk->type != cft_end; walk++) {
- if (walk->name && !strcasecmp(walk->name,item)) {
- if (walk->type != cft_flag)
- die("cfg_get_flag: operating on non-flag %s",item);
- return !!walk->data;
- }
- if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
- }
- die("cfg_get_flag: unknown item %s",item);
- return 0; /* not reached */
-}
-
-
-char *cfg_get_strg(CONFIG *table,char *item)
-{
- CONFIG *walk;
-
- for (walk = table; walk->type != cft_end; walk++) {
- if (walk->name && !strcasecmp(walk->name,item)) {
- if (walk->type != cft_strg)
- die("cfg_get_strg: operating on non-string %s",item);
- return walk->data;
- }
- if (walk->type == cft_link) walk = ((CONFIG *) walk->action)-1;
- }
- die("cfg_get_strg: unknown item %s",item);
- return 0; /* not reached */
-}
+++ /dev/null
-/* cfg.h - Configuration file parser */
-
-/* Copyright 1992-1996 Werner Almesberger. See file COPYING for details. */
-
-
-#ifndef CFG_H
-#define CFG_H
-
-typedef enum { cft_strg, cft_flag, cft_link, cft_end } CFG_TYPE;
-
-typedef struct {
- CFG_TYPE type;
- char *name;
- void *action;
- void *data;
- void *context;
-} CONFIG;
-
-extern int cfg_open(char *name);
-
-/* Opens the configuration file. Returns the file descriptor of the open
- file. */
-
-extern void cfg_error(char *msg,...);
-
-/* Signals an error while parsing the configuration file and terminates the
- program. */
-
-extern void cfg_init(CONFIG *table);
-
-/* Initializes the specified table. */
-
-extern void cfg_set(CONFIG *table,char *item,char *value,void *context);
-
-/* Sets the specified variable in table. If the variable has already been set
- since the last call to cfg_init, a warning message is issued if the context
- keys don't match or a fatal error is reported if they do. */
-
-extern void cfg_unset(CONFIG *table,char *item);
-
-/* Unsets the specified variable in table. It is a fatal error if the variable
- was not set. */
-
-extern int cfg_parse(CONFIG *table);
-
-/* Parses the configuration file for variables contained in table. A non-zero
- value is returned if a variable not found in table has been met. Zero is
- returned if EOF has been reached. */
-
-extern int cfg_get_flag(CONFIG *table,char *item);
-
-/* Returns one if the specified variable is set, zero if it isn't. */
-
-extern char *cfg_get_strg(CONFIG *table,char *item);
-
-/* Returns the value of the specified variable if it is set, NULL otherwise. */
-
-#endif
+++ /dev/null
-/*
- * arch/s390/boot/silo.c
- *
- * S390 version
- * Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
- *
- * Report bugs to: <linux390@de.ibm.com>
- *
- * Author(s): Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * Fritz Elfert <felfert@to.com> contributed support for
- * /etc/silo.conf based on Intel's lilo
- * Changes :
- * 01/15/01 Holger Smolinski <Holger.Smolinski@de.ibm.com>
- * adapted to deal with devices and bootsects of various sizes
- */
-
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <errno.h>
-#include <limits.h>
-#include <dirent.h>
-#include <linux/fs.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <asm/ioctl.h>
-
-#include "cfg.h"
-
-CONFIG cf_options[] = {
- { cft_strg, "append", NULL, NULL,NULL },
- { cft_strg, "image", NULL, NULL,NULL },
- { cft_strg, "ipldevice", NULL, NULL,NULL },
- { cft_strg, "bootsect", NULL, NULL,NULL },
- { cft_strg, "map", NULL, NULL,NULL },
- { cft_strg, "parmfile", NULL, NULL,NULL },
- { cft_strg, "ramdisk", NULL, NULL,NULL },
- { cft_strg, "root", NULL, NULL,NULL },
- { cft_flag, "readonly", NULL, NULL,NULL },
- { cft_strg, "verbose", NULL, NULL,NULL },
- { cft_strg, "testlevel", NULL, NULL,NULL },
- { cft_end, NULL, NULL, NULL,NULL }
-};
-
-/* from dasd.h */
-#define DASD_PARTN_BITS 2
-#define BIODASDRWTB _IOWR('D',0,int)
-/* end */
-
-#define SILO_CFG "/etc/silo.conf"
-#define SILO_IMAGE "./image"
-#define SILO_BOOTMAP "./boot.map"
-#define SILO_PARMFILE "./parmfile"
-#define SILO_BOOTSECT "/boot/ipleckd.boot"
-
-#define PRINT_LEVEL(x,y...) if ( silo_options.verbosity >= x ) printf(y)
-#define ERROR_LEVEL(x,y...) if ( silo_options.verbosity >= x ) fprintf(stderr,y)
-#define TOGGLE(x) ((x)=((x)?(0):(1)))
-#define GETARG(x) {int len=strlen(optarg);x=malloc(len);strncpy(x,optarg,len);PRINT_LEVEL(1,"%s set to %s\n",#x,optarg);}
-
-#define ITRY(x) if ( (x) == -1 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
-#define NTRY(x) if ( (x) == 0 ) { ERROR_LEVEL(0,"%s (line:%d) '%s' returned %d='%s'\n", __FILE__,__LINE__,#x,errno,strerror(errno)); usage(); exit(1); }
-
-#define MAX_CLUSTERS 256
-#define PARTN_MASK ((1 << DASD_PARTN_BITS) - 1)
-
-#define SILO_VERSION "1.1"
-
-struct silo_options
- {
- short int verbosity;
- short int testlevel;
- char *image;
- char *ipldevice;
- char *parmfile;
- char *ramdisk;
- char *bootsect;
- char *conffile;
- char *bootmap;
- }
-silo_options =
-{
- 1, /* verbosity */
- 2, /* testlevel */
- SILO_IMAGE, /* image */
- NULL, /* ipldevice */
- SILO_PARMFILE, /* parmfile */
- NULL, /* initrd */
- SILO_BOOTSECT, /* bootsector */
- SILO_CFG, /* silo.conf file */
- SILO_BOOTMAP, /* boot.map */
-};
-
-struct blockdesc
- {
- unsigned long off;
- unsigned short ct;
- unsigned long addr;
- };
-
-struct blocklist
- {
- struct blockdesc blk[MAX_CLUSTERS];
- unsigned short ix;
- };
-
-void
-usage (void)
-{
- printf ("Usage:\n");
- printf ("silo -d ipldevice [additional options]\n");
- printf ("-d /dev/node : set ipldevice to /dev/node\n");
- printf ("-f image : set image to image\n");
- printf ("-F conffile : specify configuration file (/etc/silo.conf)\n");
- printf ("-p parmfile : set parameter file to parmfile\n");
- printf ("-b bootsect : set bootsector to bootsect\n");
- printf ("Additional options\n");
- printf ("-B bootmap:\n");
- printf ("-v: increase verbosity level\n");
- printf ("-v#: set verbosity level to #\n");
- printf ("-t: decrease testing level\n");
- printf ("-h: print this message\n");
- printf ("-?: print this message\n");
- printf ("-V: print version\n");
-}
-
-int
-read_cfg(struct silo_options *o)
-{
- char *tmp;
- if (access(o->conffile, R_OK) && (errno == ENOENT))
- return 0;
- /* If errno != ENOENT, let cfg_open report an error */
- cfg_open(o->conffile);
- cfg_parse(cf_options);
- tmp = cfg_get_strg(cf_options, "ipldevice");
- if ( ! o->ipldevice && tmp )
- o->ipldevice = tmp;
- tmp = cfg_get_strg(cf_options, "image");
- if ( ! strncmp(o-> image,SILO_IMAGE,strlen(SILO_IMAGE)) && tmp )
- o->image = tmp;
- tmp = cfg_get_strg(cf_options, "parmfile");
- if ( !strncmp(o->parmfile,SILO_PARMFILE,strlen(SILO_PARMFILE)) && tmp)
- o->parmfile = tmp;
- if ( ! o -> ramdisk )
- o->ramdisk = cfg_get_strg(cf_options, "ramdisk");
- tmp = cfg_get_strg(cf_options, "bootsect");
- if ( !strncmp(o -> bootsect,SILO_BOOTSECT,strlen(SILO_BOOTSECT))&&tmp)
- o->bootsect = tmp;
- tmp = cfg_get_strg(cf_options, "map") ;
- if ( !strncmp(o -> bootmap,SILO_BOOTMAP,strlen(SILO_BOOTMAP)) && tmp)
- o->bootmap = tmp;
- tmp = cfg_get_strg(cf_options, "verbose");
- if ( tmp ) {
- unsigned short v;
- sscanf (tmp, "%hu", &v);
- o->verbosity = v;
- }
- tmp = cfg_get_strg(cf_options, "testlevel");
- if ( tmp ) {
- unsigned short t;
- sscanf (tmp, "%hu", &t);
- o->testlevel += t;
- }
- return 1;
-}
-
-char *
-gen_tmpparm( char *pfile )
-{
- char *append = cfg_get_strg(cf_options, "append");
- char *root = cfg_get_strg(cf_options, "root");
- int ro = cfg_get_flag(cf_options, "readonly");
- FILE *f,*of;
- char *fn;
- char c;
- char *tmpdir=NULL,*save=NULL;
-
- if (!append && !root && !ro)
- return pfile;
- of = fopen(pfile, "r");
- if ( of ) {
- NTRY( fn = tempnam(NULL,"parm."));
- } else {
- fn = pfile;
- }
- NTRY( f = fopen(fn, "a+"));
- if ( of ) {
- while ( ! feof (of) ) {
- c=fgetc(of);
- fputc(c,f);
- }
- }
- if (root)
- fprintf(f, " root=%s", root);
- if (ro)
- fprintf(f, " ro");
- if (append)
- fprintf(f, " %s", append);
- fprintf(f, "\n");
- fclose(f);
- fclose(of);
- printf ("tempfile is %s\n",fn);
- return strdup(fn);
-}
-
-int
-parse_options (struct silo_options *o, int argc, char *argv[])
-{
- int rc = 0;
- int oc;
-
- while ((oc = getopt (argc, argv, "Vf:F:d:p:r:b:B:h?v::t::")) != -1)
- {
- switch (oc)
- {
- case 'V':
- printf("silo version: %s\n",SILO_VERSION);
- exit(0);
- case 'v':
- {
- unsigned short v;
- if (optarg && sscanf (optarg, "%hu", &v))
- o->verbosity = v;
- else
- o->verbosity++;
- PRINT_LEVEL (1, "Verbosity value is now %hu\n", o->verbosity);
- break;
- }
- case 't':
- {
- unsigned short t;
- if (optarg && sscanf (optarg, "%hu", &t))
- o->testlevel -= t;
- else
- o->testlevel--;
- PRINT_LEVEL (1, "Testonly flag is now %d\n", o->testlevel);
- break;
- }
- case 'h':
- case '?':
- usage ();
- exit(0);
- case 'd':
- GETARG (o->ipldevice);
- break;
- case 'f':
- GETARG (o->image);
- break;
- case 'F':
- GETARG (o->conffile);
- break;
- case 'p':
- GETARG (o->parmfile);
- break;
- case 'r':
- GETARG (o->ramdisk);
- break;
- case 'b':
- GETARG (o->bootsect);
- break;
- case 'B':
- GETARG (o->bootmap);
- default:
- rc = EINVAL;
- break;
- }
- }
- read_cfg(o);
- return rc;
-}
-
-int
-verify_device (char *name)
-{
- int rc = 0;
- struct stat dst;
- struct stat st;
- ITRY (stat (name, &dst));
- if (S_ISBLK (dst.st_mode))
- {
- if (!(MINOR (dst.st_rdev) & PARTN_MASK))
- {
- rc = dst.st_rdev;
- }
- else
- /* invalid MINOR & PARTN_MASK */
- {
- ERROR_LEVEL (1, "Cannot boot from partition %d %d %d",
- (int) PARTN_MASK, (int) MINOR (dst.st_rdev), (int) (PARTN_MASK & MINOR (dst.st_rdev)));
- rc = -1;
- errno = EINVAL;
- }
- }
- else
- /* error S_ISBLK */
- {
- ERROR_LEVEL (1, "%s is no block device\n", name);
- rc = -1;
- errno = EINVAL;
- }
- return rc;
-}
-
-int
-verify_file (char *name, int dev)
-{
- int rc = 0;
- struct stat dst;
- struct stat st;
- int bs = 1024;
- int l;
-
- ITRY(stat ( name, &dst ));
- if (S_ISREG (dst.st_mode))
- {
- if ((unsigned) MAJOR (dev) == (unsigned) MAJOR (dst.st_dev) && (unsigned) MINOR (dev) == (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK))
- {
- /* whatever to do if all is ok... */
- }
- else
- /* devicenumber doesn't match */
- {
- ERROR_LEVEL (1, "%s is not on device (%d/%d) but on (%d/%d)\n", name, (unsigned) MAJOR (dev), (unsigned) MINOR (dev), (unsigned) MAJOR (dst.st_dev), (unsigned) (MINOR (dst.st_dev) & ~PARTN_MASK));
- rc = -1;
- errno = EINVAL;
- }
- }
- else
- /* error S_ISREG */
- {
- ERROR_LEVEL (1, "%s is neither regular file nor linkto one\n", name);
- rc = -1;
- errno = EINVAL;
- }
- return rc;
-}
-
-int
-verify_options (struct silo_options *o)
-{
- int rc = 0;
- int dev = 0;
- int crc = 0;
- if (!o->ipldevice || !o->image || !o->bootsect)
- {
- if (!o->ipldevice)
- fprintf(stderr,"ipldevice\n");
- if (!o->image)
- fprintf(stderr,"image\n");
- if (!o->bootsect)
- fprintf(stderr,"bootsect\n");
-
- usage ();
- exit (1);
- }
- PRINT_LEVEL (1, "Testlevel is set to %d\n",o->testlevel);
-
- PRINT_LEVEL (1, "IPL device is: '%s'", o->ipldevice);
- ITRY (dev = verify_device (o->ipldevice));
- PRINT_LEVEL (2, "...ok...(%d/%d)", (unsigned short) MAJOR (dev), (unsigned short) MINOR (dev));
- PRINT_LEVEL (1, "\n");
-
- PRINT_LEVEL (0, "bootsector is: '%s'", o->bootsect);
- ITRY (verify_file (o->bootsect, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
-
- if ( o -> testlevel > 0 &&
- ! strncmp( o->bootmap, SILO_BOOTMAP,strlen(SILO_BOOTMAP) )) {
- NTRY( o -> bootmap = tempnam(NULL,"boot."));
- }
- PRINT_LEVEL (0, "bootmap is set to: '%s'", o->bootmap);
- if ( access ( o->bootmap, O_RDWR ) == -1 ) {
- if ( errno == ENOENT ) {
- ITRY (creat ( o-> bootmap, O_RDWR ));
- } else {
- PRINT_LEVEL(1,"Cannot access bootmap file '%s': %s\n",o->bootmap,
- strerror(errno));
- }
- }
- ITRY (verify_file (o->bootmap, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
-
- PRINT_LEVEL (0, "Kernel image is: '%s'", o->image);
- ITRY (verify_file (o->image, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
-
- PRINT_LEVEL (0, "original parameterfile is: '%s'", o->parmfile);
- ITRY (verify_file (o->parmfile, dev));
- PRINT_LEVEL (1, "...ok...");
- o->parmfile = gen_tmpparm(o->parmfile);
- PRINT_LEVEL (0, "final parameterfile is: '%s'", o->parmfile);
- ITRY (verify_file (o->parmfile, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
-
- if (o->ramdisk)
- {
- PRINT_LEVEL (0, "initialramdisk is: '%s'", o->ramdisk);
- ITRY (verify_file (o->ramdisk, dev));
- PRINT_LEVEL (1, "...ok...");
- PRINT_LEVEL (0, "\n");
- }
-
- return crc;
-}
-
-
-int
-add_file_to_blocklist (char *name, struct blocklist *lst, long addr)
-{
- int fd;
- int devfd;
- struct stat fst;
- int i;
- int blk;
- int bs;
- int blocks;
-
- int rc = 0;
-
- ITRY (fd = open (name, O_RDONLY));
- ITRY (fstat (fd, &fst));
- ITRY (mknod ("/tmp/silodev", S_IFBLK | S_IRUSR | S_IWUSR, fst.st_dev));
- ITRY (devfd = open ("/tmp/silodev", O_RDONLY));
- ITRY (ioctl (fd, FIGETBSZ, &bs));
- blocks = (fst.st_size + bs - 1) / bs;
- for (i = 0; i < blocks; i++)
- {
- blk = i;
- ITRY (ioctl (fd, FIBMAP, &blk));
- if (blk)
- {
- int oldblk = blk;
- ITRY (ioctl (devfd, BIODASDRWTB, &blk));
- if (blk <= 0)
- {
- ERROR_LEVEL (0, "BIODASDRWTB on blk %d returned %d\n", oldblk, blk);
- break;
- }
- }
- else
- {
- PRINT_LEVEL (1, "Filled hole on blk %d\n", i);
- }
- if (lst->ix == 0 || i == 0 ||
- lst->blk[lst->ix - 1].ct >= 128 ||
- (lst->blk[lst->ix - 1].off + lst->blk[lst->ix - 1].ct != blk &&
- !(lst->blk[lst->ix - 1].off == 0 && blk == 0)))
- {
- if (lst->ix >= MAX_CLUSTERS)
- {
- rc = 1;
- errno = ENOMEM;
- break;
- }
- lst->blk[lst->ix].off = blk;
- lst->blk[lst->ix].ct = 1;
- lst->blk[lst->ix].addr = addr + i * bs;
- lst->ix++;
- }
- else
- {
- lst->blk[lst->ix - 1].ct++;
- }
- }
- ITRY(unlink("/tmp/silodev"));
- return rc;
-}
-
-int
-write_bootsect (struct silo_options *o, struct blocklist *blklst)
-{
- int i;
- int s_fd, d_fd, b_fd, bd_fd;
- struct stat s_st, d_st, b_st;
- int rc=0;
- int bs, boots;
- char *tmpdev;
- char buffer[4096]={0,};
- int blocksize, sectsize;
- ITRY (d_fd = open (o->ipldevice, O_RDWR | O_SYNC));
- ITRY (fstat (d_fd, &d_st));
- ITRY (s_fd = open (o->bootmap, O_RDWR | O_TRUNC | O_CREAT | O_SYNC));
- ITRY (verify_file (o->bootsect, d_st.st_rdev));
- for (i = 0; i < blklst->ix; i++)
- {
- int offset = blklst->blk[i].off;
- int addrct = blklst->blk[i].addr | (blklst->blk[i].ct & 0xff);
- PRINT_LEVEL (1, "ix %i: offset: %06x count: %02x address: 0x%08x\n", i, offset, blklst->blk[i].ct & 0xff, blklst->blk[i].addr);
- if ( o->testlevel <= 1 ) {
- NTRY (write (s_fd, &offset, sizeof (int)));
- NTRY (write (s_fd, &addrct, sizeof (int)));
- }
- }
- ITRY (ioctl (s_fd,FIGETBSZ, &bs));
- ITRY (stat (o->bootmap, &s_st));
- if (s_st.st_size > bs )
- {
- ERROR_LEVEL (0,"%s is larger than one block\n", o->bootmap);
- rc = -1;
- errno = EINVAL;
- }
- boots=0;
- NTRY ( tmpdev = tmpnam(NULL) );
- ITRY (mknod (tmpdev, S_IFBLK | S_IRUSR | S_IWUSR, s_st.st_dev));
- ITRY (bd_fd = open (tmpdev, O_RDONLY));
- ITRY (ioctl(bd_fd,BLKSSZGET,&blocksize));
- ITRY (ioctl(s_fd,FIBMAP,&boots));
- ITRY (ioctl (bd_fd, BIODASDRWTB, &boots));
- PRINT_LEVEL (1, "Bootmap is in block no: 0x%08x\n", boots);
- close (bd_fd);
- close(s_fd);
- ITRY (unlink(tmpdev));
- /* Now patch the bootsector */
- ITRY (stat (o->bootsect, &b_st));
- if ((sectsize = b_st.st_size) > blocksize )
- {
- ERROR_LEVEL (0,"Bootsector is larger than sectorsize of volume %d vs %d\n", sectsize, blocksize);
- rc = -1;
- errno = EINVAL;
- }
- ITRY (b_fd = open (o->bootsect, O_RDONLY));
- ITRY (read (b_fd, buffer, sectsize));
- memset (buffer + 0xe0, 0, 8);
- *(int *) (buffer + 0xe0) = boots;
- if ( o -> testlevel <= 0 ) {
- ITRY (write (d_fd, buffer, sectsize));
- ITRY (lseek (d_fd, blocksize, SEEK_SET));
- ITRY (write (d_fd, buffer, sectsize));
- }
- close (b_fd);
- close (d_fd);
- return rc;
-}
-
-int
-do_silo (struct silo_options *o)
-{
- int rc = 0;
-
- int device_fd;
- int image_fd;
- struct blocklist blklist;
- memset (&blklist, 0, sizeof (struct blocklist));
- ITRY (add_file_to_blocklist (o->image, &blklist, 0x00000000));
- if (o->parmfile)
- {
- ITRY (add_file_to_blocklist (o->parmfile, &blklist, 0x00008000));
- }
- if (o->ramdisk)
- {
- ITRY (add_file_to_blocklist (o->ramdisk, &blklist, 0x00800000));
- }
- ITRY (write_bootsect (o, &blklist));
- return rc;
-}
-
-int
-main (int argct, char *argv[])
-{
- int rc = 0;
- char *save=NULL;
- char *tmpdir=getenv("TMPDIR");
- if (tmpdir) {
- NTRY( save=(char*)malloc(strlen(tmpdir)));
- NTRY( strncpy(save,tmpdir,strlen(tmpdir)));
- }
- ITRY( setenv("TMPDIR",".",1));
- ITRY (parse_options (&silo_options, argct, argv));
- ITRY (verify_options (&silo_options));
- if ( silo_options.testlevel > 0 ) {
- printf ("WARNING: silo does not modify your volume. Use -t2 to change IPL records\n");
- }
- ITRY (do_silo (&silo_options));
- if ( save )
- ITRY( setenv("TMPDIR",save,1));
- return rc;
-}
+++ /dev/null
-ipldevice = /dev/dasda
-image = /boot/image
-bootsect = /boot/ipleckd.boot
-map = /boot/boot.map
-root = /dev/dasd01
-readonly
-append = "dasd=200-20f noinitrd"
*
* Questions/Comments/Bugfixes to arrays@compaq.com
*
- * If you want to make changes, improve or add functionality to this
- * driver, you'll probably need the Compaq Array Controller Interface
- * Specificiation (Document number ECG086/1198)
*/
#include <linux/config.h> /* CONFIG_PROC_FS */
#include <linux/module.h>
#define SMART2_DRIVER_VERSION(maj,min,submin) ((maj<<16)|(min<<8)|(submin))
-#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.4)"
-#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,4)
+#define DRIVER_NAME "Compaq SMART2 Driver (v 2.4.5)"
+#define DRIVER_VERSION SMART2_DRIVER_VERSION(2,4,5)
/* Embedded module documentation macros - see modules.h */
/* Original author Chris Frantz - Compaq Computer Corporation */
static void __init ida_procinit(int i)
{
if (proc_array == NULL) {
- proc_array = proc_mkdir("array", proc_root_driver);
+ proc_array = proc_mkdir("cpqarray", proc_root_driver);
if (!proc_array) return;
}
{
int i;
struct gendisk *g;
-
- remove_proc_entry("array", proc_root_driver);
+ char buff[4];
for(i=0; i<nr_ctlr; i++) {
- hba[i]->access.set_intr_mask(hba[i], 0);
+
+ /* sendcmd will turn off interrupt, and send the flush...
+ * To write all data in the battery backed cache to disks
+ * no data returned, but don't want to send NULL to sendcmd */
+ if( sendcmd(FLUSH_CACHE, i, buff, 4, 0, 0, 0))
+ {
+ printk(KERN_WARNING "Unable to flush cache on "
+ "controller %d\n", i);
+ }
free_irq(hba[i]->intr, hba[i]);
iounmap(hba[i]->vaddr);
unregister_blkdev(MAJOR_NR+i, hba[i]->devname);
}
}
}
-
+ remove_proc_entry("cpqarray", proc_root_driver);
kfree(ida);
kfree(ida_sizes);
kfree(ida_hardsizes);
if (cmd->req.hdr.rcode & RCODE_NONFATAL &&
(hba[cmd->ctlr]->misc_tflags & MISC_NONFATAL_WARN) == 0) {
- printk(KERN_WARNING "Non Fatal error on ida/c%dd%d\n",
+ printk(KERN_NOTICE "Non Fatal error on ida/c%dd%d\n",
cmd->ctlr, cmd->hdr.unit);
hba[cmd->ctlr]->misc_tflags |= MISC_NONFATAL_WARN;
}
*/
if (c->busaddr == a) {
removeQ(&h->cmpQ, c);
+ /* Check for invalid command.
+ * Controller returns command error,
+ * But rcode = 0.
+ */
+
+ if((a1 & 0x03) && (c->req.hdr.rcode == 0))
+ {
+ c->req.hdr.rcode = RCODE_INVREQ;
+ }
if (c->type == CMD_RWREQ) {
complete_command(c, 0);
cmd_free(h, c, 1);
c->req.hdr.sg_cnt = 1;
break;
case IDA_READ:
+ case READ_FLASH_ROM:
+ case SENSE_CONTROLLER_PERFORMANCE:
p = kmalloc(io->sg[0].size, GFP_KERNEL);
if (!p)
{
case IDA_WRITE:
case IDA_WRITE_MEDIA:
case DIAG_PASS_THRU:
+ case COLLECT_BUFFER:
+ case WRITE_FLASH_ROM:
p = kmalloc(io->sg[0].size, GFP_KERNEL);
if (!p)
{
PCI_DMA_BIDIRECTIONAL);
case IDA_READ:
case DIAG_PASS_THRU:
+ case SENSE_CONTROLLER_PERFORMANCE:
+ case READ_FLASH_ROM:
copy_to_user((void*)io->sg[0].addr, p, io->sg[0].size);
/* fall through and free p */
case IDA_WRITE:
case IDA_WRITE_MEDIA:
+ case COLLECT_BUFFER:
+ case WRITE_FLASH_ROM:
kfree(p);
break;
default:;
*
* Questions/Comments/Bugfixes to arrays@compaq.com
*
- * If you want to make changes, improve or add functionality to this
- * driver, you'll probably need the Compaq Array Controller Interface
- * Specificiation (Document number ECG086/1198)
*/
#ifndef ARRAYCMD_H
#define ARRAYCMD_H
} scsi_param_t;
#define RESUME_BACKGROUND_ACTIVITY 0x99
+#define SENSE_CONTROLLER_PERFORMANCE 0xa8
+#define FLUSH_CACHE 0xc2
+#define COLLECT_BUFFER 0xd2
+#define READ_FLASH_ROM 0xf6
+#define WRITE_FLASH_ROM 0xf7
#pragma pack()
#endif /* ARRAYCMD_H */
*
* Questions/Comments/Bugfixes to arrays@compaq.com
*
- * If you want to make changes, improve or add functionality to this
- * driver, you'll probably need the Compaq Array Controller Interface
- * Specificiation (Document number ECG086/1198)
*/
#ifndef IDA_IOCTL_H
#define IDA_IOCTL_H
up(&moxaBuffSem);
return (-ENOMEM);
}
+ /* This test is guarded by the BuffSem so no longer needed
+ delete me in 2.5 */
if (moxaXmitBuff)
free_page(page);
else
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * Revision 1.0
+ * Revision 1.1
+ *
+ * ChangeLog:
+ * Arnaldo Carvalho de Melo <acme@conectiva.com.br> - 27-Jun-2001
+ * - get rid of check_region and several cleanups
*/
#include <linux/module.h>
};
static struct riscom_board rc_board[RC_NBOARD] = {
- { 0, RC_IOBASE1, 0, },
- { 0, RC_IOBASE2, 0, },
- { 0, RC_IOBASE3, 0, },
- { 0, RC_IOBASE4, 0, },
+ {
+ base: RC_IOBASE1,
+ },
+ {
+ base: RC_IOBASE2,
+ },
+ {
+ base: RC_IOBASE3,
+ },
+ {
+ base: RC_IOBASE4,
+ },
};
static struct riscom_port rc_port[RC_NBOARD * RC_NPORT];
kdev_t device, const char *routine)
{
#ifdef RISCOM_PARANOIA_CHECK
- static const char *badmagic =
+ static const char badmagic[] = KERN_INFO
"rc: Warning: bad riscom port magic number for device %s in %s\n";
- static const char *badinfo =
+ static const char badinfo[] = KERN_INFO
"rc: Warning: null riscom port for device %s in %s\n";
if (!port) {
if (!rc_in(bp, CD180_CCR))
return;
- printk("rc%d: Timeout waiting for CCR.\n", board_No(bp));
+ printk(KERN_INFO "rc%d: Timeout waiting for CCR.\n", board_No(bp));
}
/*
* RISCom/8 probe functions.
*/
-static inline int rc_check_io_range(struct riscom_board * const bp)
+static inline int rc_request_io_range(struct riscom_board * const bp)
{
int i;
for (i = 0; i < RC_NIOPORT; i++)
- if (check_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1)) {
- printk("rc%d: Skipping probe at 0x%03x. I/O address in use.\n",
- board_No(bp), bp->base);
- return 1;
+ if (!request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1,
+ "RISCom/8")) {
+ goto out_release;
}
return 0;
-}
-
-static inline void rc_request_io_range(struct riscom_board * const bp)
-{
- int i;
-
- for (i = 0; i < RC_NIOPORT; i++)
- request_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1, "RISCom/8" );
+out_release:
+ printk(KERN_INFO "rc%d: Skipping probe at 0x%03x. IO address in use.\n",
+ board_No(bp), bp->base);
+ while(--i >= 0)
+ release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
+ return 1;
}
static inline void rc_release_io_range(struct riscom_board * const bp)
for (i = 0; i < RC_NIOPORT; i++)
release_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1);
}
-
/* Must be called with enabled interrupts */
static inline void rc_long_delay(unsigned long delay)
bp->irq = 0;
- if (rc_check_io_range(bp))
+ if (rc_request_io_range(bp))
return 1;
/* Are the I/O ports here ? */
val2 = rc_in(bp, CD180_PPRL);
if ((val1 != 0x5a) || (val2 != 0xa5)) {
- printk("rc%d: RISCom/8 Board at 0x%03x not found.\n",
+ printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not found.\n",
board_No(bp), bp->base);
- return 1;
+ goto out_release;
}
/* It's time to find IRQ for this board */
rc_init_CD180(bp); /* Reset CD180 again */
if ((val1 & RC_BSR_TINT) || (val2 != (RC_ID | GIVR_IT_TX))) {
- printk("rc%d: RISCom/8 Board at 0x%03x not found.\n",
- board_No(bp), bp->base);
- return 1;
+ printk(KERN_ERR "rc%d: RISCom/8 Board at 0x%03x not "
+ "found.\n", board_No(bp), bp->base);
+ goto out_release;
}
}
if (irqs <= 0) {
- printk("rc%d: Can't find IRQ for RISCom/8 board at 0x%03x.\n",
- board_No(bp), bp->base);
- return 1;
+ printk(KERN_ERR "rc%d: Can't find IRQ for RISCom/8 board "
+ "at 0x%03x.\n", board_No(bp), bp->base);
+ goto out_release;
}
- rc_request_io_range(bp);
bp->irq = irqs;
bp->flags |= RC_BOARD_PRESENT;
- printk("rc%d: RISCom/8 Rev. %c board detected at 0x%03x, IRQ %d.\n",
+ printk(KERN_INFO "rc%d: RISCom/8 Rev. %c board detected at "
+ "0x%03x, IRQ %d.\n",
board_No(bp),
(rc_in(bp, CD180_GFRCR) & 0x0f) + 'A', /* Board revision */
bp->base, bp->irq);
return 0;
+out_release:
+ rc_release_io_range(bp);
+ return 1;
}
/*
return port;
}
}
- printk("rc%d: %s interrupt from invalid port %d\n",
+ printk(KERN_ERR "rc%d: %s interrupt from invalid port %d\n",
board_No(bp), what, channel);
return NULL;
}
tty = port->tty;
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- printk("rc%d: port %d: Working around flip buffer overflow.\n",
+ printk(KERN_WARNING "rc%d: port %d: Working around flip "
+ "buffer overflow.\n",
board_No(bp), port_No(port));
return;
}
if (status & RCSR_OE) {
port->overrun++;
#if 0
- printk("rc%d: port %d: Overrun. Total %ld overruns.\n",
+ printk(KERN_ERR "rc%d: port %d: Overrun. Total %ld overruns\n",
board_No(bp), port_No(port), port->overrun);
#endif
}
return;
}
if (status & RCSR_TOUT) {
- printk("rc%d: port %d: Receiver timeout. Hardware problems ?\n",
+ printk(KERN_WARNING "rc%d: port %d: Receiver timeout. "
+ "Hardware problems ?\n",
board_No(bp), port_No(port));
return;
} else if (status & RCSR_BREAK) {
- printk("rc%d: port %d: Handling break...\n",
+ printk(KERN_INFO "rc%d: port %d: Handling break...\n",
board_No(bp), port_No(port));
*tty->flip.flag_buf_ptr++ = TTY_BREAK;
if (port->flags & ASYNC_SAK)
while (count--) {
if (tty->flip.count >= TTY_FLIPBUF_SIZE) {
- printk("rc%d: port %d: Working around flip buffer overflow.\n",
+ printk(KERN_WARNING "rc%d: port %d: Working around "
+ "flip buffer overflow.\n",
board_No(bp), port_No(port));
break;
}
RC_BSR_MINT | RC_BSR_RINT))) {
if (status & RC_BSR_TOUT)
- printk("rc%d: Got timeout. Hardware error ?\n", board_No(bp));
+ printk(KERN_WARNING "rc%d: Got timeout. Hardware "
+ "error?\n", board_No(bp));
else if (status & RC_BSR_RINT) {
ack = rc_in(bp, RC_ACK_RINT);
else if (ack == (RC_ID | GIVR_IT_REXC))
rc_receive_exc(bp);
else
- printk("rc%d: Bad receive ack 0x%02x.\n",
+ printk(KERN_WARNING "rc%d: Bad receive ack "
+ "0x%02x.\n",
board_No(bp), ack);
} else if (status & RC_BSR_TINT) {
if (ack == (RC_ID | GIVR_IT_TX))
rc_transmit(bp);
else
- printk("rc%d: Bad transmit ack 0x%02x.\n",
+ printk(KERN_WARNING "rc%d: Bad transmit ack "
+ "0x%02x.\n",
board_No(bp), ack);
} else /* if (status & RC_BSR_MINT) */ {
if (ack == (RC_ID | GIVR_IT_MODEM))
rc_check_modem(bp);
else
- printk("rc%d: Bad modem ack 0x%02x.\n",
+ printk(KERN_WARNING "rc%d: Bad modem ack "
+ "0x%02x.\n",
board_No(bp), ack);
}
if (bp->flags & RC_BOARD_ACTIVE)
return 0;
- error = request_irq(bp->irq, rc_interrupt, SA_INTERRUPT, "RISCom/8", NULL);
+ error = request_irq(bp->irq, rc_interrupt, SA_INTERRUPT,
+ "RISCom/8", NULL);
if (error)
return error;
return;
#ifdef RC_REPORT_OVERRUN
- printk("rc%d: port %d: Total %ld overruns were detected.\n",
+ printk(KERN_INFO "rc%d: port %d: Total %ld overruns were detected.\n",
board_No(bp), port_No(port), port->overrun);
#endif
#ifdef RC_REPORT_FIFO
{
int i;
- printk("rc%d: port %d: FIFO hits [ ",
+ printk(KERN_INFO "rc%d: port %d: FIFO hits [ ",
board_No(bp), port_No(port));
for (i = 0; i < 10; i++) {
printk("%ld ", port->hits[i]);
port->flags &= ~ASYNC_INITIALIZED;
if (--bp->count < 0) {
- printk("rc%d: rc_shutdown_port: bad board count: %d\n",
+ printk(KERN_INFO "rc%d: rc_shutdown_port: "
+ "bad board count: %d\n",
board_No(bp), bp->count);
bp->count = 0;
}
return;
save_flags(flags); cli();
- if (tty_hung_up_p(filp)) {
- restore_flags(flags);
- return;
- }
+ if (tty_hung_up_p(filp))
+ goto out;
bp = port_Board(port);
if ((tty->count == 1) && (port->count != 1)) {
- printk("rc%d: rc_close: bad port count;"
+ printk(KERN_INFO "rc%d: rc_close: bad port count;"
" tty->count is 1, port count is %d\n",
board_No(bp), port->count);
port->count = 1;
}
if (--port->count < 0) {
- printk("rc%d: rc_close: bad port count for tty%d: %d\n",
+ printk(KERN_INFO "rc%d: rc_close: bad port count "
+ "for tty%d: %d\n",
board_No(bp), port_No(port), port->count);
port->count = 0;
}
- if (port->count) {
- restore_flags(flags);
- return;
- }
+ if (port->count)
+ goto out;
port->flags |= ASYNC_CLOSING;
/*
* Save the termios structure, since this port may have
port->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE|
ASYNC_CLOSING);
wake_up_interruptible(&port->close_wait);
- restore_flags(flags);
+out: restore_flags(flags);
}
static int rc_write(struct tty_struct * tty, int from_user,
save_flags(flags); cli();
- if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1) {
- restore_flags(flags);
- return;
- }
+ if (port->xmit_cnt >= SERIAL_XMIT_SIZE - 1)
+ goto out;
port->xmit_buf[port->xmit_head++] = ch;
port->xmit_head &= SERIAL_XMIT_SIZE - 1;
port->xmit_cnt++;
- restore_flags(flags);
+out: restore_flags(flags);
}
static void rc_flush_chars(struct tty_struct * tty)
| ((status & MSVR_CD) ? TIOCM_CAR : 0)
| ((status & MSVR_DSR) ? TIOCM_DSR : 0)
| ((status & MSVR_CTS) ? TIOCM_CTS : 0);
- put_user(result, value);
- return 0;
+ return put_user(result, value);
}
static int rc_set_modem_info(struct riscom_port * port, unsigned int cmd,
unsigned int *value)
{
- int error;
unsigned int arg;
unsigned long flags;
struct riscom_board *bp = port_Board(port);
- error = get_user(arg, value);
- if (error)
- return error;
+ if (get_user(arg, value))
+ return -EFAULT;
switch (cmd) {
case TIOCMBIS:
if (arg & TIOCM_RTS)
struct riscom_board *bp = port_Board(port);
int change_speed;
unsigned long flags;
- int error;
- error = verify_area(VERIFY_READ, (void *) newinfo, sizeof(tmp));
- if (error)
- return error;
- copy_from_user(&tmp, newinfo, sizeof(tmp));
+ if (copy_from_user(&tmp, newinfo, sizeof(tmp)))
+ return -EFAULT;
#if 0
if ((tmp.irq != bp->irq) ||
{
struct serial_struct tmp;
struct riscom_board *bp = port_Board(port);
- int error;
-
- error = verify_area(VERIFY_WRITE, (void *) retinfo, sizeof(tmp));
- if (error)
- return error;
memset(&tmp, 0, sizeof(tmp));
tmp.type = PORT_CIRRUS;
tmp.close_delay = port->close_delay * HZ/100;
tmp.closing_wait = port->closing_wait * HZ/100;
tmp.xmit_fifo_size = CD180_NFIFO;
- copy_to_user(retinfo, &tmp, sizeof(tmp));
- return 0;
+ return copy_to_user(retinfo, &tmp, sizeof(tmp)) ? -EFAULT : 0;
}
static int rc_ioctl(struct tty_struct * tty, struct file * filp,
{
struct riscom_port *port = (struct riscom_port *)tty->driver_data;
- int error;
int retval;
if (rc_paranoia_check(port, tty->device, "rc_ioctl"))
tty_wait_until_sent(tty, 0);
if (!arg)
rc_send_break(port, HZ/4); /* 1/4 second */
- return 0;
+ break;
case TCSBRKP: /* support for POSIX tcsendbreak() */
retval = tty_check_change(tty);
if (retval)
return retval;
tty_wait_until_sent(tty, 0);
rc_send_break(port, arg ? arg*(HZ/10) : HZ/4);
- return 0;
+ break;
case TIOCGSOFTCAR:
return put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned int *) arg);
case TIOCSSOFTCAR:
- retval = get_user(arg,(unsigned int *) arg);
- if (retval)
- return retval;
+ if (get_user(arg,(unsigned int *) arg))
+ return -EFAULT;
tty->termios->c_cflag =
((tty->termios->c_cflag & ~CLOCAL) |
(arg ? CLOCAL : 0));
- return 0;
+ break;
case TIOCMGET:
- error = verify_area(VERIFY_WRITE, (void *) arg,
- sizeof(unsigned int));
- if (error)
- return error;
return rc_get_modem_info(port, (unsigned int *) arg);
case TIOCMBIS:
case TIOCMBIC:
if (!(tmp_buf = (unsigned char *) get_free_page(GFP_KERNEL))) {
- printk("rc: Couldn't get free page.\n");
+ printk(KERN_ERR "rc: Couldn't get free page.\n");
return 1;
}
init_bh(RISCOM8_BH, do_riscom_bh);
if ((error = tty_register_driver(&riscom_driver))) {
free_page((unsigned long)tmp_buf);
- printk("rc: Couldn't register RISCom/8 driver, error = %d\n",
+ printk(KERN_ERR "rc: Couldn't register RISCom/8 driver, "
+ "error = %d\n",
error);
return 1;
}
if ((error = tty_register_driver(&riscom_callout_driver))) {
free_page((unsigned long)tmp_buf);
tty_unregister_driver(&riscom_driver);
- printk("rc: Couldn't register RISCom/8 callout driver, error = %d\n",
+ printk(KERN_ERR "rc: Couldn't register RISCom/8 callout "
+ "driver, error = %d\n",
error);
return 1;
}
__setup("riscom8=", riscom8_setup);
#endif
+static const char banner[] __initdata =
+ KERN_INFO "rc: SDL RISCom/8 card driver v1.1, (c) D.Gorodchanin "
+ "1994-1996.\n";
+static const char no_boards_msg[] __initdata =
+ KERN_INFO "rc: No RISCom/8 boards detected.\n";
+
/*
* This routine must be called by kernel at boot time
*/
int i;
int found = 0;
- printk("rc: SDL RISCom/8 card driver v1.0, (c) D.Gorodchanin 1994-1996.\n");
+ printk(banner);
if (rc_init_drivers())
return -EIO;
if (!found) {
rc_release_drivers();
- printk("rc: No RISCom/8 boards detected.\n");
+ printk(no_boards_msg);
return -EIO;
}
return 0;
info->tty->low_latency = (info->flags & ASYNC_LOW_LATENCY) ? 1 : 0;
#endif
+ /*
+ * This relies on lock_kernel() stuff so wants tidying for 2.5
+ */
if (!tmp_buf) {
page = get_zeroed_page(GFP_KERNEL);
if (!page) {
/*
* linux/drivers/char/synclink.c
*
- * $Id: synclink.c,v 3.8 2001/03/30 17:30:38 ez Exp $
+ * $Id: synclink.c,v 3.12 2001/07/18 19:14:21 paulkf Exp $
*
* Device driver for Microgate SyncLink ISA and PCI
* high speed multiprotocol serial adapters.
/*
* Global linked list of SyncLink devices
*/
-struct mgsl_struct *mgsl_device_list = NULL;
-int mgsl_device_count = 0;
+struct mgsl_struct *mgsl_device_list;
+int mgsl_device_count;
/*
* Set this param to non-zero to load eax with the
* .text section address and breakpoint on module load.
* This is useful for use with gdb and add-symbol-file command.
*/
-int break_on_load=0;
+int break_on_load;
/*
* Driver major number, defaults to zero to get auto
* assigned major number. May be forced as module parameter.
*/
-int ttymajor=0;
+int ttymajor;
-int cuamajor=0;
+int cuamajor;
/*
* Array of user specified options for ISA adapters.
*/
-static int io[MAX_ISA_DEVICES] = {0,};
-static int irq[MAX_ISA_DEVICES] = {0,};
-static int dma[MAX_ISA_DEVICES] = {0,};
-static int debug_level = 0;
-static int maxframe[MAX_TOTAL_DEVICES] = {0,};
-static int dosyncppp[MAX_TOTAL_DEVICES] = {0,};
-static int txdmabufs[MAX_TOTAL_DEVICES] = {0,};
-static int txholdbufs[MAX_TOTAL_DEVICES] = {0,};
+static int io[MAX_ISA_DEVICES];
+static int irq[MAX_ISA_DEVICES];
+static int dma[MAX_ISA_DEVICES];
+static int debug_level;
+static int maxframe[MAX_TOTAL_DEVICES];
+static int dosyncppp[MAX_TOTAL_DEVICES];
+static int txdmabufs[MAX_TOTAL_DEVICES];
+static int txholdbufs[MAX_TOTAL_DEVICES];
MODULE_PARM(break_on_load,"i");
MODULE_PARM(ttymajor,"i");
MODULE_PARM(txholdbufs,"1-" __MODULE_STRING(MAX_TOTAL_DEVICES) "i");
static char *driver_name = "SyncLink serial driver";
-static char *driver_version = "3.8";
+static char *driver_version = "$Revision: 3.12 $";
static int __init synclink_init_one (struct pci_dev *dev,
const struct pci_device_id *ent);
goto errout;
}
info->shared_mem_requested = 1;
- if (request_mem_region(info->phys_lcr_base,128,"synclink") == NULL) {
+ if (request_mem_region(info->phys_lcr_base + info->lcr_offset,128,"synclink") == NULL) {
printk( "%s(%d):lcr mem addr conflict device %s Addr=%08X\n",
- __FILE__,__LINE__,info->device_name, info->phys_lcr_base);
+ __FILE__,__LINE__,info->device_name, info->phys_lcr_base + info->lcr_offset);
goto errout;
}
info->lcr_mem_requested = 1;
info->shared_mem_requested = 0;
}
if ( info->lcr_mem_requested ) {
- release_mem_region(info->phys_lcr_base,128);
+ release_mem_region(info->phys_lcr_base + info->lcr_offset,128);
info->lcr_mem_requested = 0;
}
if (info->memory_base){
}
#ifdef CONFIG_SYNCLINK_SYNCPPP
+#ifdef MODULE
if (info->dosyncppp)
+#endif
mgsl_sppp_init(info);
#endif
} /* end of mgsl_add_device() */
printk("%s(%d):Couldn't register callout driver\n",
__FILE__,__LINE__);
- printk("%s version %s, tty major#%d callout major#%d\n",
+ printk("%s %s, tty major#%d callout major#%d\n",
driver_name, driver_version,
serial_driver.major, callout_driver.major);
EXPORT_NO_SYMBOLS;
- printk("%s version %s\n", driver_name, driver_version);
+ printk("%s %s\n", driver_name, driver_version);
mgsl_enum_isa_devices();
pci_register_driver(&synclink_pci_driver);
struct mgsl_struct *info;
struct mgsl_struct *tmp;
- printk("Unloading %s: version %s\n", driver_name, driver_version);
+ printk("Unloading %s: %s\n", driver_name, driver_version);
save_flags(flags);
cli();
if ((rc = tty_unregister_driver(&serial_driver)))
d->tx_timeout = mgsl_sppp_tx_timeout;
d->watchdog_timeo = 10*HZ;
+#if LINUX_VERSION_CODE < VERSION(2,4,4)
+ dev_init_buffers(d);
+#endif
+
if (register_netdev(d) == -1) {
printk(KERN_WARNING "%s: register_netdev failed.\n", d->name);
sppp_detach(info->netdev);
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/major.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/signal.h>
/*
* Write the overlay mask if clips are wanted.
*/
+
+ if (vw.clipcount > 2048)
+ return -EINVAL;
if (vw.clipcount) {
vcp =
vmalloc(sizeof(struct video_clip) *
{
DEV_NET *pNet;
SK_AC *pAC;
-unsigned int Flags; /* for spin lock */
+unsigned long Flags; /* for spin lock */
int i;
SK_EVPARA EvPara; /* an event parameter union */
DEV_NET *pNet;
SK_AC *pAC;
-unsigned int Flags; /* for spin lock */
+unsigned long Flags; /* for spin lock */
int i;
int PortIdx;
SK_EVPARA EvPara;
struct sk_buff *pMessage) /* pointer to send-message */
{
TXD *pTxd; /* the rxd to fill */
-unsigned int Flags;
+unsigned long Flags;
SK_U64 PhysAddr;
int BytesSend;
RX_PORT *pRxPort) /* ptr to port struct for which the ring
should be filled */
{
-unsigned int Flags;
+unsigned long Flags;
spin_lock_irqsave(&pRxPort->RxDesRingLock, Flags);
while (pRxPort->RxdRingFree > pRxPort->RxFillLimit) {
RX_PORT *pRxPort) /* pointer to rx port struct */
{
RXD *pRxd; /* pointer to the current descriptor */
-unsigned int Flags;
+unsigned long Flags;
SK_U64 PhysAddr;
if (pRxPort->RxdRingFree == pAC->RxDescrPerRing) {
{
TXD *pTxd; /* pointer to the current descriptor */
int i;
-unsigned int Flags;
+unsigned long Flags;
spin_lock_irqsave(&pTxPort->TxDesRingLock, Flags);
pTxd = pTxPort->pTxdRingHead;
SK_AC *pAC = pNet->pAC;
struct sockaddr *addr = p;
-unsigned int Flags;
-
+unsigned long Flags;
+
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
("SkGeSetMacAddr starts now...\n"));
if(netif_running(dev)) {
struct dev_mc_list *pMcList;
int i;
int PortIdx;
-unsigned int Flags;
+unsigned long Flags;
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
("SkGeSetRxMode starts now... "));
DEV_NET *pNet;
DEV_NET *pOtherNet;
SK_AC *pAC;
-unsigned int Flags;
+unsigned long Flags;
int i;
SK_EVPARA EvPara;
SK_PNMI_STRUCT_DATA *pPnmiStruct; /* structure for all Pnmi-Data */
SK_PNMI_STAT *pPnmiStat; /* pointer to virtual XMAC stat. data */SK_PNMI_CONF *pPnmiConf; /* pointer to virtual link config. */
unsigned int Size; /* size of pnmi struct */
-unsigned int Flags; /* for spin lock */
+unsigned long Flags; /* for spin lock */
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
("SkGeStats starts now...\n"));
unsigned int Size, /* length of ioctl data */
int mode) /* flag for set/preset */
{
-unsigned int Flags; /* for spin lock */
+unsigned long Flags; /* for spin lock */
SK_AC *pAC;
SK_DBG_MSG(NULL, SK_DBGMOD_DRV, SK_DBGCAT_DRV_ENTRY,
int StrLen = 80; /* length of the string, defined in SK_AC */
char Keyword[] = VPD_NAME; /* vpd productname identifier */
int ReturnCode; /* return code from vpd_read */
-unsigned int Flags;
+unsigned long Flags;
spin_lock_irqsave(&pAC->SlowPathLock, Flags);
ReturnCode = VpdRead(pAC, pAC->IoBase, Keyword, pAC->DeviceStr,
int ToPort; /* the port we switch to */
SK_EVPARA NewPara; /* parameter for further events */
int Stat;
-unsigned int Flags;
+unsigned long Flags;
switch (Event) {
case SK_DRV_ADAP_FAIL:
DEV_NET *pNet;
SK_AC *pAC;
char test_buf[100];
- unsigned int Flags;
+ unsigned long Flags;
unsigned int Size;
struct net_device *next;
struct net_device *SkgeProcDev = root_dev;
-/*
- * Driver for Granch SBNI-12 leased line network adapters.
- *
- * Copyright 1997 - 1999, Granch ltd.
- * Written 1999 by Yaroslav Polyakov (xenon@granch.ru).
+/* sbni.c: Granch SBNI12 leased line adapters driver for linux
+ *
+ * Written 2001 by Denis I.Timofeev (timofeev@granch.ru)
+ *
+ * Previous versions were written by Yaroslav Polyakov,
+ * Alexey Zverev and Max Khon.
+ *
+ * Driver supports SBNI12-02,-04,-05,-10,-11 cards, single and
+ * double-channel, PCI and ISA modifications.
+ * More info and useful utilities to work with SBNI12 cards you can find
+ * at http://www.granch.com (English) or http://www.granch.ru (Russian)
+ *
+ * This software may be used and distributed according to the terms
+ * of the GNU Public License.
*
- * This software may be used and distributed according to the terms
- * of the GNU General Public License, incorporated herein by reference.
- *
- * // Whole developers team:
- * // Yaroslav Polyakov (xenon@granch.ru)
- * // - main developer of this version
- * // Alexey Zverev (zverev@granch.ru)
- * // - previous SBNI driver for linux
- * // Alexey Chirkov (chirkov@granch.ru)
- * // - all the hardware work and consulting
- * // Max Khon (max@iclub.nsu.ru)
- * // - first SBNI driver for linux
- * // --------------------------------------------
- * // also I thank:
- * // Max Krasnyansky (max@uznet.net)
- * // - for bug hunting and many ideas
- * // Alan Cox (Alan.Cox@linux.org)
- * // - for consulting in some hardcore questions
- * // Donald Becker (becker@scyld.com)
- * // - for pretty nice skeleton
- *
- * More info and useful utilities to work w/ SBNI you can find at
- * http://www.granch.ru.
*
- * 3.0.0 = Initial Revision, Yaroslav Polyakov (24 Feb 1999)
+ * 5.0.1 Jun 22 2001
+ * - Fixed bug in probe
+ * 5.0.0 Jun 06 2001
+ * - Driver was completely redesigned by Denis I.Timofeev,
+ * - now PCI/Dual, ISA/Dual (with single interrupt line) models are
+ * - supported
+ * 3.3.0 Thu Feb 24 21:30:28 NOVT 2000
+ * - PCI cards support
+ * 3.2.0 Mon Dec 13 22:26:53 NOVT 1999
+ * - Completely rebuilt all the packet storage system
+ * - to work in Ethernet-like style.
+ * 3.1.1 just fixed some bugs (5 aug 1999)
+ * 3.1.0 added balancing feature (26 apr 1999)
+ * 3.0.1 just fixed some bugs (14 apr 1999).
+ * 3.0.0 Initial Revision, Yaroslav Polyakov (24 Feb 1999)
* - added pre-calculation for CRC, fixed bug with "len-2" frames,
* - removed outbound fragmentation (MTU=1000), written CRC-calculation
* - on asm, added work with hard_headers and now we have our own cache
* - for them, optionally supported word-interchange on some chipsets,
- * - something else I cant remember ;)
*
- * 3.0.1 = just fixed some bugs (14 apr 1999).
- * - fixed statistical tx bug
- * - fixed wrong creation dates (1998 -> 1999) in driver source code ;)
- * - fixed source address bug.
- * - fixed permanent nirvana bug
- *
- * 3.1.0 = (Katyusha) (26 apr 1999)
- * - Added balancing feature
- *
- * 3.1.1 = (Medea) (5 aug 1999)
- * - Fixed mac.raw bug
- * - Thanks to tolix@olviko.ru and
- * - to Barnaul Brewery, producers of my favorite beer "Medea".
- *
- *
+ * Known problem: this driver wasn't tested on multiprocessor machine.
*/
-
-#undef GOODBUS16
-#define CRCASM
-#define KATYUSHA
-
-#include <linux/version.h>
-
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/fcntl.h>
#include <linux/ioport.h>
#include <linux/interrupt.h>
-#include <linux/slab.h>
+#include <linux/malloc.h>
#include <linux/string.h>
#include <linux/errno.h>
-#include <linux/spinlock.h>
#include <asm/io.h>
#include <asm/types.h>
#include <asm/byteorder.h>
+#include <asm/irq.h>
+#include <asm/uaccess.h>
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/skbuff.h>
#include <linux/timer.h>
-#include <linux/config.h> /* for CONFIG_INET. do we need this?*/
+#include <linux/init.h>
#include <net/arp.h>
+#include <linux/pci.h>
-#include <asm/uaccess.h>
-#include <linux/init.h>
+#ifndef MODULE
+#include <linux/string.h>
+#endif
+
+#include <linux/config.h>
#include "sbni.h"
-static const char *version =
-"sbni.c: ver. 3.1.1 Medea 5 Aug 1999 Yaroslav Polyakov (xenon@granch.ru)\n";
+/* device private data */
-int sbni_probe(struct net_device *dev);
-static int sbni_probe1(struct net_device *dev, int ioaddr);
-static int sbni_open(struct net_device *dev);
-static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev);
-static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs);
-static int sbni_close(struct net_device *dev);
-static void sbni_drop_tx_queue(struct net_device *dev);
-static struct net_device_stats *sbni_get_stats(struct net_device *dev);
-static void card_start(struct net_device *dev);
-static inline unsigned short sbni_recv(struct net_device *dev);
-void change_level(struct net_device *dev);
-static inline void sbni_xmit(struct net_device *dev);
-static inline void sbni_get_packet(struct net_device* dev);
-static void sbni_watchdog(unsigned long arg);
-static void set_multicast_list(struct net_device *dev);
-static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd);
-static int sbni_set_mac_address(struct net_device *dev, void *addr);
-unsigned long calc_crc(char *mem, int len, unsigned initial);
-void sbni_nirvana(struct net_device *dev);
-static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len);
+struct net_local {
+ struct net_device_stats stats;
+ struct timer_list watchdog;
-static int sbni_rebuild_header(struct sk_buff *skb);
-static int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh);
+ spinlock_t lock;
+ struct sk_buff *rx_buf_p; /* receive buffer ptr */
+ struct sk_buff *tx_buf_p; /* transmit buffer ptr */
+
+ unsigned int framelen; /* current frame length */
+ unsigned int maxframe; /* maximum valid frame length */
+ unsigned int state;
+ unsigned int inppos, outpos; /* positions in rx/tx buffers */
-static inline void sbni_outs(int port, void *data, int len);
-static inline void sbni_ins(int port, void *data, int len);
+ /* transmitting frame number - from frames qty to 1 */
+ unsigned int tx_frameno;
+ /* expected number of next receiving frame */
+ unsigned int wait_frameno;
+ /* count of failed attempts to frame send - 32 attempts do before
+ error - while receiver tunes on opposite side of wire */
+ unsigned int trans_errors;
-#define SIZE_OF_TIMEOUT_RXL_TAB 4
-static u_char timeout_rxl_tab[] = {
- 0x03, 0x05, 0x08, 0x0b
-};
+ /* idle time; send pong when limit exceeded */
+ unsigned int timer_ticks;
-static u_char rxl_tab[] = {
- 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
- 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
-};
+ /* fields used for receive level autoselection */
+ int delta_rxl;
+ unsigned int cur_rxl_index, timeout_rxl;
+ unsigned long cur_rxl_rcvd, prev_rxl_rcvd;
-/* A zero-terminated list of I/O addresses to be probed */
-static unsigned int netcard_portlist[] = {
- 0x210, 0x2c0, 0x2d0, 0x2f0, 0x220, 0x230, 0x240, 0x250,
- 0x260, 0x290, 0x2a0, 0x2b0, 0x224, 0x234, 0x244, 0x254,
- 0x264, 0x294, 0x2a4, 0x2b4, 0};
+ struct sbni_csr1 csr1; /* current value of CSR1 */
+ struct sbni_in_stats in_stats; /* internal statistics */
-static unsigned char magic_reply[] = {
- 0x5a,0x06,0x30,0x00,0x00,0x50,0x65,0x44,0x20
+ struct net_device *second; /* for ISA/dual cards */
+
+#ifdef CONFIG_SBNI_MULTILINE
+ struct net_device *master;
+ struct net_device *link;
+#endif
};
-static int def_baud = DEF_RATE;
-static int def_rxl = DEF_RXL_DELTA;
-static long def_mac = 0;
+
+static int sbni_card_probe( unsigned long );
+static int sbni_pci_probe( struct net_device * );
+static struct net_device *sbni_probe1(struct net_device *, unsigned long, int);
+static int sbni_open( struct net_device * );
+static int sbni_close( struct net_device * );
+static int sbni_start_xmit( struct sk_buff *, struct net_device * );
+static int sbni_ioctl( struct net_device *, struct ifreq *, int );
+static struct net_device_stats *sbni_get_stats( struct net_device * );
+static void set_multicast_list( struct net_device * );
+
+static void sbni_interrupt( int, void *, struct pt_regs * );
+static void handle_channel( struct net_device * );
+static int recv_frame( struct net_device * );
+static void send_frame( struct net_device * );
+static int upload_data( struct net_device *,
+ unsigned, unsigned, unsigned, u32 );
+static void download_data( struct net_device *, u32 * );
+static void sbni_watchdog( unsigned long );
+static void interpret_ack( struct net_device *, unsigned );
+static int append_frame_to_pkt( struct net_device *, unsigned, u32 );
+static void indicate_pkt( struct net_device * );
+static void card_start( struct net_device * );
+static void prepare_to_send( struct sk_buff *, struct net_device * );
+static void drop_xmit_queue( struct net_device * );
+static void send_frame_header( struct net_device *, u32 * );
+static int skip_tail( unsigned int, unsigned int, u32 );
+static int check_fhdr( u32, u32 *, u32 *, u32 *, u32 *, u32 * );
+static void change_level( struct net_device * );
+static void timeout_change_level( struct net_device * );
+static u32 calc_crc32( u32, u8 *, u32 );
+static struct sk_buff * get_rx_buf( struct net_device * );
+
+#ifdef CONFIG_SBNI_MULTILINE
+static int enslave( struct net_device *, struct net_device * );
+static int emancipate( struct net_device * );
+#endif
+
+#define ASM_CRC 1
+
+static const char version[] =
+ "Granch SBNI12 driver ver 5.0.1 Jun 22 2001 Denis I.Timofeev.\n";
+
+static int skip_pci_probe __initdata = 0;
+static int scandone __initdata = 0;
+static int num __initdata = 0;
+
+static unsigned char rxl_tab[];
+static u32 crc32tab[];
+
+/* A list of all installed devices, for removing the driver module. */
+static struct net_device *sbni_cards[ SBNI_MAX_NUM_CARDS ];
+
+/* Lists of device's parameters */
+static u32 io[ SBNI_MAX_NUM_CARDS ] __initdata =
+ { [0 ... SBNI_MAX_NUM_CARDS-1] = -1 };
+static u32 irq[ SBNI_MAX_NUM_CARDS ] __initdata;
+static u32 baud[ SBNI_MAX_NUM_CARDS ] __initdata;
+static u32 rxl[ SBNI_MAX_NUM_CARDS ] __initdata =
+ { [0 ... SBNI_MAX_NUM_CARDS-1] = -1 };
+static u32 mac[ SBNI_MAX_NUM_CARDS ] __initdata;
+
+#ifndef MODULE
+typedef u32 iarr[];
+static iarr *dest[5] = { &io, &irq, &baud, &rxl, &mac };
+#endif
+
+/* A zero-terminated list of I/O addresses to be probed on ISA bus */
+static unsigned int netcard_portlist[ ] __initdata = {
+ 0x210, 0x214, 0x220, 0x224, 0x230, 0x234, 0x240, 0x244, 0x250, 0x254,
+ 0x260, 0x264, 0x270, 0x274, 0x280, 0x284, 0x290, 0x294, 0x2a0, 0x2a4,
+ 0x2b0, 0x2b4, 0x2c0, 0x2c4, 0x2d0, 0x2d4, 0x2e0, 0x2e4, 0x2f0, 0x2f4,
+ 0 };
/*
- * CRC-32 stuff
+ * Look for SBNI card which addr stored in dev->base_addr, if nonzero.
+ * Otherwise, look through PCI bus. If none PCI-card was found, scan ISA.
*/
-#define CRC32(c,crc) (crc32tab[((size_t)(crc) ^ (c)) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF))
-/* CRC generator 0xEDB88320 */
-/* CRC remainder 0x2144DF1C */
-/* CRC initial value 0x00000000 */
-#define CRC32_REMAINDER 0x2144DF1C
-#define CRC32_INITIAL 0x00000000
+static inline int __init
+sbni_isa_probe( struct net_device *dev )
+{
+ if( dev->base_addr > 0x1ff
+ && !check_region( dev->base_addr, SBNI_IO_EXTENT )
+ && sbni_probe1( dev, dev->base_addr, dev->irq ) )
+
+ return 0;
+ else {
+ printk( KERN_ERR "sbni: base address 0x%lx is busy, or adapter "
+ "is malfunctional!\n", dev->base_addr );
+ return -ENODEV;
+ }
+}
-static unsigned long crc32tab[] = {
- 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37,
- 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E,
- 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605,
- 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C,
- 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53,
- 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A,
- 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661,
- 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278,
- 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF,
- 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6,
- 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD,
- 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4,
- 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B,
- 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82,
- 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9,
- 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0,
- 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7,
- 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE,
- 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795,
- 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C,
- 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3,
- 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA,
- 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1,
- 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8,
- 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F,
- 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76,
- 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D,
- 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344,
- 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B,
- 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12,
- 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739,
- 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320,
- 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17,
- 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E,
- 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525,
- 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C,
- 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73,
- 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A,
- 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541,
- 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158,
- 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF,
- 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6,
- 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED,
- 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4,
- 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB,
- 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2,
- 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589,
- 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190,
- 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87,
- 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E,
- 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5,
- 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC,
- 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3,
- 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA,
- 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1,
- 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8,
- 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F,
- 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856,
- 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D,
- 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064,
- 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B,
- 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832,
- 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419,
- 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000
-};
-static inline void sbni_outs(int port, void *data, int len)
+int __init
+sbni_probe( struct net_device *dev )
{
-#ifdef GOODBUS16
- outsw(port,data,len/2);
- if(len & 1)
- outb(((char*)data)[len - 1],port);
-#else
- outsb(port,data,len);
-#endif
+ int i;
+
+ static unsigned version_printed __initdata = 0;
+ if( version_printed++ == 0 )
+ printk( KERN_INFO "%s", version );
+
+ if( !dev ) { /* simple sanity check */
+ printk( KERN_ERR "sbni: NULL device!\n" );
+ return -ENODEV;
+ }
+
+ SET_MODULE_OWNER( dev );
+
+ if( dev->base_addr )
+ return sbni_isa_probe( dev );
+ /* otherwise we have to perform search our adapter */
+
+ if( io[ num ] != -1 )
+ dev->base_addr = io[ num ],
+ dev->irq = irq[ num ];
+ else if( scandone || io[ 0 ] != -1 )
+ return -ENODEV;
+
+ /* if io[ num ] contains non-zero address, then that is on ISA bus */
+ if( dev->base_addr )
+ return sbni_isa_probe( dev );
+
+ /* ...otherwise - scan PCI first */
+ if( !skip_pci_probe && !sbni_pci_probe( dev ) )
+ return 0;
+
+ if( io[ num ] == -1 ) {
+ /* Auto-scan will be stopped when first ISA card were found */
+ scandone = 1;
+ if( num > 0 )
+ return -ENODEV;
+ }
+
+ for( i = 0; netcard_portlist[ i ]; ++i ) {
+ int ioaddr = netcard_portlist[ i ];
+ if( !check_region( ioaddr, SBNI_IO_EXTENT )
+ && sbni_probe1( dev, ioaddr, 0 ))
+ return 0;
+ }
+
+ return -ENODEV;
}
-static inline void sbni_ins(int port, void *data, int len)
+
+int __init
+sbni_pci_probe( struct net_device *dev )
{
-#ifdef GOODBUS16
- insw(port,data,len/2);
- if(len & 1)
- ((char*)data)[len - 1] = inb(port);
-#else
- insb(port,data,len);
-#endif
+ struct pci_dev *pdev = NULL;
+
+ if( !pci_present( ) )
+ return -ENODEV;
+
+ while( (pdev = pci_find_class( PCI_CLASS_NETWORK_OTHER << 8, pdev ))
+ != NULL ) {
+ int pci_irq_line;
+ unsigned long pci_ioaddr;
+ u16 subsys;
+
+ if( pdev->vendor != SBNI_PCI_VENDOR
+ && pdev->device != SBNI_PCI_DEVICE )
+ continue;
+
+ pci_ioaddr = pci_resource_start( pdev, 0 );
+ pci_irq_line = pdev->irq;
+
+ /* Avoid already found cards from previous calls */
+ if( check_region( pci_ioaddr, SBNI_IO_EXTENT ) ) {
+ pci_read_config_word( pdev, PCI_SUBSYSTEM_ID, &subsys );
+ if( subsys != 2 || /* Dual adapter is present */
+ check_region( pci_ioaddr += 4, SBNI_IO_EXTENT ) )
+ continue;
+ }
+
+ if( pci_irq_line <= 0 || pci_irq_line >= NR_IRQS )
+ printk( KERN_WARNING " WARNING: The PCI BIOS assigned "
+ "this PCI card to IRQ %d, which is unlikely "
+ "to work!.\n"
+ KERN_WARNING " You should use the PCI BIOS "
+ "setup to assign a valid IRQ line.\n",
+ pci_irq_line );
+
+ /* avoiding re-enable dual adapters */
+ if( (pci_ioaddr & 7) == 0 && pci_enable_device( pdev ) )
+ return -EIO;
+ if( sbni_probe1( dev, pci_ioaddr, pci_irq_line ) )
+ return 0;
+ }
+ return -ENODEV;
}
-static int sbni_header(struct sk_buff *skb, struct net_device *dev, unsigned short type,
- void *daddr, void *saddr, unsigned len)
+static struct net_device * __init
+sbni_probe1( struct net_device *dev, unsigned long ioaddr, int irq )
{
- struct sbni_hard_header *hh = (struct sbni_hard_header *)
- skb_push(skb, sizeof(struct sbni_hard_header));
-
-
- if(type!=ETH_P_802_3)
- hh->h_proto = htons(type);
+ struct net_local *nl;
+
+ if( !request_region( ioaddr, SBNI_IO_EXTENT, dev->name ) )
+ return 0;
+
+ if( sbni_card_probe( ioaddr ) ) {
+ release_region( ioaddr, SBNI_IO_EXTENT );
+ return 0;
+ }
+
+ outb( 0, ioaddr + CSR0 );
+
+ if( irq < 2 ) {
+ autoirq_setup( 5 );
+ outb( EN_INT | TR_REQ, ioaddr + CSR0 );
+ outb( PR_RES, ioaddr + CSR1 );
+ irq = autoirq_report( 5 );
+ outb( 0, ioaddr + CSR0 );
+
+ if( !irq ) {
+ printk( KERN_ERR "%s: can't detect device irq!\n",
+ dev->name );
+ release_region( ioaddr, SBNI_IO_EXTENT );
+ return 0;
+ }
+ } else if( irq == 2 )
+ irq = 9;
+
+ dev->irq = irq;
+ dev->base_addr = ioaddr;
+
+ /* Allocate dev->priv and fill in sbni-specific dev fields. */
+ nl = (struct net_local *) kmalloc(sizeof(struct net_local), GFP_KERNEL);
+ if( !nl ) {
+ printk( KERN_ERR "%s: unable to get memory!\n", dev->name );
+ release_region( ioaddr, SBNI_IO_EXTENT );
+ return 0;
+ }
+
+ dev->priv = nl;
+ memset( nl, 0, sizeof(struct net_local) );
+ spin_lock_init( &nl->lock );
+
+ /* store MAC address (generate if that isn't known) */
+ *(u16 *)dev->dev_addr = htons( 0x00ff );
+ *(u32 *)(dev->dev_addr + 2) = htonl( 0x01000000 |
+ ( (mac[num] ? mac[num] : (u32)dev->priv) & 0x00ffffff) );
+
+ /* store link settings (speed, receive level ) */
+ nl->maxframe = DEFAULT_FRAME_LEN;
+ nl->csr1.rate = baud[ num ];
+
+ if( (nl->cur_rxl_index = rxl[ num ]) == -1 )
+ /* autotune rxl */
+ nl->cur_rxl_index = DEF_RXL,
+ nl->delta_rxl = DEF_RXL_DELTA;
else
- hh->h_proto = htons(len);
-
- if(saddr)
- memcpy(hh->h_source,saddr,dev->addr_len);
+ nl->delta_rxl = 0;
+ nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index ];
+ if( inb( ioaddr + CSR0 ) & 0x01 )
+ nl->state |= FL_SLOW_MODE;
+
+ printk( KERN_NOTICE "%s: ioaddr %#lx, irq %d, "
+ "MAC: 00:ff:01:%02x:%02x:%02x\n",
+ dev->name, dev->base_addr, dev->irq,
+ ((u8 *) dev->dev_addr) [3],
+ ((u8 *) dev->dev_addr) [4],
+ ((u8 *) dev->dev_addr) [5] );
+
+ printk( KERN_NOTICE "%s: speed %d, receive level ", dev->name,
+ ( (nl->state & FL_SLOW_MODE) ? 500000 : 2000000)
+ / (1 << nl->csr1.rate) );
+
+ if( nl->delta_rxl == 0 )
+ printk( "0x%x (fixed)\n", nl->cur_rxl_index );
else
- memcpy(hh->h_source,dev->dev_addr,dev->addr_len);
-
- if(daddr)
- {
- memcpy(hh->h_dest,daddr,dev->addr_len);
- return dev->hard_header_len;
- }
- return -dev->hard_header_len;
+ printk( "(auto)\n");
+
+#ifdef CONFIG_SBNI_MULTILINE
+ nl->master = dev;
+ nl->link = NULL;
+#endif
+
+ dev->open = &sbni_open;
+ dev->stop = &sbni_close;
+ dev->hard_start_xmit = &sbni_start_xmit;
+ dev->get_stats = &sbni_get_stats;
+ dev->set_multicast_list = &set_multicast_list;
+ dev->do_ioctl = &sbni_ioctl;
+ ether_setup( dev );
+
+ sbni_cards[ num++ ] = dev;
+ return dev;
}
+/* -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_SBNI_MULTILINE
-int sbni_header_cache(struct neighbour *neigh, struct hh_cache *hh)
+static int
+sbni_start_xmit( struct sk_buff *skb, struct net_device *dev )
{
- unsigned short type = hh->hh_type;
- struct sbni_hard_header *sbni = (struct sbni_hard_header*)
- (((u8*)hh->hh_data) - 8);
- struct net_device *dev = neigh->dev;
-
-
- if (type == htons(ETH_P_802_3))
- return -1;
-
- sbni->h_proto = type;
- memcpy(sbni->h_source, dev->dev_addr, dev->addr_len);
- memcpy(sbni->h_dest, neigh->ha, dev->addr_len);
- return 0;
+ struct net_device *p;
+
+ netif_stop_queue( dev );
+
+ /* Looking for idle device in the list */
+ for( p = dev; p; ) {
+ struct net_local *nl = (struct net_local *) p->priv;
+ spin_lock( &nl->lock );
+ if( nl->tx_buf_p || (nl->state & FL_LINE_DOWN) ) {
+ p = nl->link;
+ spin_unlock( &nl->lock );
+ } else {
+ /* Idle dev is found */
+ prepare_to_send( skb, p );
+ spin_unlock( &nl->lock );
+ netif_start_queue( dev );
+ return 0;
+ }
+ }
+
+ return 1;
}
-static int sbni_rebuild_header(struct sk_buff *skb)
+#else /* CONFIG_SBNI_MULTILINE */
+
+static int
+sbni_start_xmit( struct sk_buff *skb, struct net_device *dev )
{
- struct sbni_hard_header *hh = (struct sbni_hard_header *)skb;
- /*
- * Only ARP/IP is currently supported
- */
+ struct net_local *nl = (struct net_local *) dev->priv;
- /*
- * Try to get ARP to resolve the header.
- */
-
-#ifdef CONFIG_INET
- return arp_find((unsigned char*)hh->h_dest, skb)? 1 : 0;
-#else
- return 0;
-#endif
+ netif_stop_queue( dev );
+ spin_lock( &nl->lock );
+
+ prepare_to_send( skb, dev );
+
+ spin_unlock( &nl->lock );
+ return 0;
}
-static void sbni_header_cache_update(struct hh_cache *hh, struct net_device *dev, unsigned char * haddr)
+#endif /* CONFIG_SBNI_MULTILINE */
+
+/* -------------------------------------------------------------------------- */
+
+/* interrupt handler */
+
+/*
+ * SBNI12D-10, -11/ISA boards within "common interrupt" mode could not
+ * be looked as two independent single-channel devices. Every channel seems
+ * as Ethernet interface but interrupt handler must be common. Really, first
+ * channel ("master") driver only registers the handler. In its struct net_local
+ * it has got pointer to "slave" channel's struct net_local and handles that's
+ * interrupts too.
+ * dev of successfully attached ISA SBNI boards is linked to list.
+ * While next board driver is initialized, it scans this list. If one
+ * has found dev with same irq and ioaddr different by 4 then it assumes
+ * this board to be "master".
+ */
+
+static void
+sbni_interrupt( int irq, void *dev_id, struct pt_regs *regs )
{
- memcpy(((u8*)hh->hh_data) + 2, haddr, dev->addr_len);
+ struct net_device *dev = (struct net_device *) dev_id;
+ struct net_local *nl = (struct net_local *) dev->priv;
+ int repeat;
+
+ spin_lock( &nl->lock );
+ if( nl->second )
+ spin_lock( &((struct net_local *) nl->second->priv)->lock );
+
+ do {
+ repeat = 0;
+ if( inb( dev->base_addr + CSR0 ) & (RC_RDY | TR_RDY) )
+ handle_channel( dev ),
+ repeat = 1;
+ if( nl->second && /* second channel present */
+ (inb( nl->second->base_addr+CSR0 ) & (RC_RDY | TR_RDY)) )
+ handle_channel( nl->second ),
+ repeat = 1;
+ } while( repeat );
+
+ if( nl->second )
+ spin_unlock( &((struct net_local *)nl->second->priv)->lock );
+ spin_unlock( &nl->lock );
}
+static void
+handle_channel( struct net_device *dev )
+{
+ struct net_local *nl = (struct net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
-#ifdef HAVE_DEVLIST
-struct netdev_entry sbni_drv = {
- "sbni", sbni_probe1, SBNI_IO_EXTENT, netcard_portlist
-};
+ int req_ans;
+ unsigned char csr0;
-#else
+#ifdef CONFIG_SBNI_MULTILINE
+ /* Lock the master device because we going to change its local data */
+ if( nl->state & FL_SLAVE )
+ spin_lock( &((struct net_local *) nl->master->priv)->lock );
+#endif
-int __init sbni_probe(struct net_device *dev)
-{
- int i;
- int base_addr = dev ? dev->base_addr : 0;
-
- DP( printk("%s: sbni_probe\n", dev->name); )
-
- if(base_addr > 0x1ff) /* Check a single specified location. */
- return sbni_probe1(dev, base_addr);
- else if(base_addr != 0) /* Don't probe at all. */
- return -ENXIO;
- for(i = 0; (base_addr = netcard_portlist[i]); i++)
- {
- if(!check_region(base_addr, SBNI_IO_EXTENT) && base_addr != 1)
- {
- /* Lock this address, or later we'll try it again */
- netcard_portlist[i] = 1;
- if(sbni_probe1(dev, base_addr) == 0)
- return 0;
- }
+ outb( (inb( ioaddr + CSR0 ) & ~EN_INT) | TR_REQ, ioaddr + CSR0 );
+
+ nl->timer_ticks = CHANGE_LEVEL_START_TICKS;
+ for(;;) {
+ csr0 = inb( ioaddr + CSR0 );
+ if( ( csr0 & (RC_RDY | TR_RDY) ) == 0 )
+ break;
+
+ req_ans = !(nl->state & FL_PREV_OK);
+
+ if( csr0 & RC_RDY )
+ req_ans = recv_frame( dev );
+
+ /*
+ * TR_RDY always equals 1 here because we have owned the marker,
+ * and we set TR_REQ when disabled interrupts
+ */
+ csr0 = inb( ioaddr + CSR0 );
+ if( !(csr0 & TR_RDY) || (csr0 & RC_RDY) )
+ printk( KERN_ERR "%s: internal error!\n", dev->name );
+
+ /* if state & FL_NEED_RESEND != 0 then tx_frameno != 0 */
+ if( req_ans || nl->tx_frameno != 0 )
+ send_frame( dev );
+ else
+ /* send marker without any data */
+ outb( inb( ioaddr + CSR0 ) & ~TR_REQ, ioaddr + CSR0 );
}
- return -ENODEV;
+
+ outb( inb( ioaddr + CSR0 ) | EN_INT, ioaddr + CSR0 );
+
+#ifdef CONFIG_SBNI_MULTILINE
+ if( nl->state & FL_SLAVE )
+ spin_unlock( &((struct net_local *) nl->master->priv)->lock );
+#endif
}
-#endif /* have devlist*/
/*
- * The actual probe.
+ * Routine returns 1 if it need to acknoweledge received frame.
+ * Empty frame received without errors won't be acknoweledged.
*/
-/*
- Valid combinations in CSR0 (for probing):
+static int
+recv_frame( struct net_device *dev )
+{
+ struct net_local *nl = (struct net_local *) dev->priv;
+ unsigned long ioaddr = dev->base_addr;
+
+ u32 crc = CRC32_INITIAL;
+
+ unsigned framelen, frameno, ack;
+ unsigned is_first, frame_ok;
+
+ if( check_fhdr( ioaddr, &framelen, &frameno, &ack, &is_first, &crc ) ) {
+ frame_ok = framelen > 4
+ ? upload_data( dev, framelen, frameno, is_first, crc )
+ : skip_tail( ioaddr, framelen, crc );
+ if( frame_ok )
+ interpret_ack( dev, ack );
+ } else
+ frame_ok = 0;
+
+ outb( inb( ioaddr + CSR0 ) ^ CT_ZER, ioaddr + CSR0 );
+ if( frame_ok ) {
+ nl->state |= FL_PREV_OK;
+ if( framelen > 4 )
+ nl->in_stats.all_rx_number++;
+ } else
+ nl->state &= ~FL_PREV_OK,
+ change_level( dev ),
+ nl->in_stats.all_rx_number++,
+ nl->in_stats.bad_rx_number++;
+
+ return !frame_ok || framelen > 4;
+}
- VALID_DECODER 0000,0011,1011,1010
- ; 0 ; -
- TR_REQ ; 1 ; +
- TR_RDY ; 2 ; -
- TR_RDY TR_REQ ; 3 ; +
- BU_EMP ; 4 ; +
- BU_EMP TR_REQ ; 5 ; +
- BU_EMP TR_RDY ; 6 ; -
- BU_EMP TR_RDY TR_REQ ; 7 ; +
- RC_RDY ; 8 ; +
- RC_RDY TR_REQ ; 9 ; +
- RC_RDY TR_RDY ; 10 ; -
- RC_RDY TR_RDY TR_REQ ; 11 ; -
- RC_RDY BU_EMP ; 12 ; -
- RC_RDY BU_EMP TR_REQ ; 13 ; -
- RC_RDY BU_EMP TR_RDY ; 14 ; -
- RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; -
-*/
-#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
+static void
+send_frame( struct net_device *dev )
+{
+ struct net_local *nl = (struct net_local *) dev->priv;
-static int __init sbni_probe1(struct net_device *dev, int ioaddr)
+ u32 crc = CRC32_INITIAL;
-{
- int autoirq = 0;
- int bad_card = 0;
- unsigned char csr0;
- struct net_local* lp;
- static int version_printed = 0;
-
- DP( printk("%s: sbni_probe1 ioaddr=%d\n", dev->name, ioaddr); )
-
- if(check_region(ioaddr, SBNI_IO_EXTENT) < 0)
- return -ENODEV;
- if(version_printed++ == 0)
- printk(version);
-
- /* check for valid combination in CSR0 */
- csr0 = inb(ioaddr + CSR0);
- if(csr0 == 0xff || csr0 == 0)
- bad_card = 1;
- else
- {
- csr0 &= ~EN_INT;
- if(csr0 & BU_EMP)
- csr0 |= EN_INT;
- if((VALID_DECODER & (1 << (csr0 >> 4))) == 0)
- bad_card = 1;
- }
+ if( nl->state & FL_NEED_RESEND ) {
- if(bad_card)
- return -ENODEV;
- else
- outb(0, ioaddr + CSR0);
- if(dev->irq < 2)
- {
- DP( printk("%s: autoprobing\n", dev->name); );
- autoirq_setup(5);
- outb(EN_INT | TR_REQ, ioaddr + CSR0);
- outb(PR_RES, ioaddr + CSR1);
- autoirq = autoirq_report(5);
-
- if(autoirq == 0)
- {
- printk("sbni probe at %#x failed to detect IRQ line\n", ioaddr);
- return -EAGAIN;
- }
- }
- /* clear FIFO buffer */
- outb(0, ioaddr + CSR0);
-
- if(autoirq)
- dev->irq = autoirq;
-
- {
- int irqval=request_irq(dev->irq, sbni_interrupt, 0, dev->name, dev);
- if (irqval)
- {
- printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval);
- return -EAGAIN;
+ /* if frame was sended but not ACK'ed - resend it */
+ if( nl->trans_errors ) {
+ --nl->trans_errors;
+ if( nl->framelen != 0 )
+ nl->in_stats.resend_tx_number++;
+ } else {
+ /* cannot xmit with many attempts */
+#ifdef CONFIG_SBNI_MULTILINE
+ if( (nl->state & FL_SLAVE) || nl->link )
+#endif
+ nl->state |= FL_LINE_DOWN;
+ drop_xmit_queue( dev );
+ goto do_send;
}
- }
-
- /*
- * Initialize the device structure.
- */
-
- dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
- if(dev->priv == NULL)
- {
- DP( printk("%s: cannot allocate memory\n", dev->name); )
- free_irq(dev->irq, dev);
- return -ENOMEM;
- }
-
- memset(dev->priv, 0, sizeof(struct net_local));
- dev->base_addr = ioaddr;
- request_region(ioaddr, SBNI_IO_EXTENT, "sbni");
+ } else
+ nl->trans_errors = TR_ERROR_COUNT;
- /*
- * generate Ethernet address (0x00ff01xxxxxx)
+ send_frame_header( dev, &crc );
+ nl->state |= FL_NEED_RESEND;
+ /*
+ * FL_NEED_RESEND will be cleared after ACK, but if empty
+ * frame sended then in prepare_to_send next frame
*/
- *(u16*)dev->dev_addr = htons(0x00ff);
- *(u32*)(dev->dev_addr+2) = htonl(((def_mac ? def_mac : (u32) dev->priv) & 0x00ffffff) | 0x01000000);
-
- lp = dev->priv;
- if(def_rxl < 0)
- {
- /* autodetect receive level */
- lp->rxl_curr = 0xf;
- lp->rxl_delta = -1;
- } else {
- /* fixed receive level */
- lp->rxl_curr = def_rxl & 0xf;
- lp->rxl_delta = 0;
+
+ if( nl->framelen ) {
+ download_data( dev, &crc );
+ nl->in_stats.all_tx_number++;
+ nl->state |= FL_WAIT_ACK;
}
- lp->csr1.rxl = rxl_tab[lp->rxl_curr];
- lp->csr1.rate = def_baud & 3;
- lp->frame_len = DEF_FRAME_LEN;
- printk("%s: sbni adapter at %#lx, using %sIRQ %d, MAC: 00:ff:01:%x:%x:%x\n",
- dev->name, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq,
- *(unsigned char*)(dev->dev_addr+3),
- *(unsigned char*)(dev->dev_addr+4),
- *(unsigned char*)(dev->dev_addr+5)
- );
- printk("%s: receive level: ", dev->name);
- if(lp->rxl_delta == 0)
- printk ("%#1x (fixed)", lp->rxl_curr);
- else
- printk ("autodetect");
- printk(", baud rate: %u\n", (unsigned)lp->csr1.rate);
-
- /*
- * The SBNI-specific entries in the device structure.
- */
- dev->open = &sbni_open;
- dev->hard_start_xmit = &sbni_start_xmit;
- dev->stop = &sbni_close;
- dev->get_stats = &sbni_get_stats;
- dev->set_multicast_list = &set_multicast_list;
- dev->set_mac_address = &sbni_set_mac_address;
- dev->do_ioctl = &sbni_ioctl;
-
- /*
- * Setup the generic properties
- */
+ outsb( dev->base_addr + DAT, (u8 *)&crc, sizeof crc );
- ether_setup(dev);
-
- dev->hard_header = sbni_header;
- dev->hard_header_len = sizeof(struct sbni_hard_header);
- dev->rebuild_header=sbni_rebuild_header;
- dev->mtu = DEF_FRAME_LEN;
+do_send:
+ outb( inb( dev->base_addr + CSR0 ) & ~TR_REQ, dev->base_addr + CSR0 );
- dev->hard_header_cache = sbni_header_cache;
- dev->header_cache_update = sbni_header_cache_update;
-
- spin_lock_init(&lp->lock);
- lp->m=dev;
- lp->me=dev;
- lp->next_lp=NULL;
-
- return 0;
+ if( nl->tx_frameno )
+ /* next frame exists - we request card to send it */
+ outb( inb( dev->base_addr + CSR0 ) | TR_REQ,
+ dev->base_addr + CSR0 );
}
+
/*
- * Open/initialize the board.
+ * Write the frame data into adapter's buffer memory, and calculate CRC.
+ * Do padding if necessary.
*/
-static int sbni_open(struct net_device *dev)
-{
- struct net_local* lp = (struct net_local*)dev->priv;
- struct timer_list* watchdog = &lp->watchdog;
- unsigned long flags;
-
- DP( printk("%s: sbni_open\n", dev->name); )
-
- save_flags(flags);
- cli();
- lp->currframe = NULL;
-
- card_start(dev);
- /* set timer watchdog */
- init_timer(watchdog);
- watchdog->expires = jiffies + SBNI_TIMEOUT;
- watchdog->data = (unsigned long)dev;
- watchdog->function = sbni_watchdog;
- add_timer(watchdog);
- DP( printk("%s: sbni timer watchdog initialized\n", dev->name); );
-
- restore_flags(flags);
-
- netif_start_queue(dev);
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-static int sbni_close(struct net_device *dev)
+static void
+download_data( struct net_device *dev, u32 *crc_p )
{
- int ioaddr = dev->base_addr;
- struct net_local* lp = (struct net_local*) dev->priv;
- struct timer_list* watchdog = &lp->watchdog;
- unsigned long flags;
-
- DP( printk("%s: sbni_close\n", dev->name); )
+ struct net_local *nl = (struct net_local *) dev->priv;
+ struct sk_buff *skb = nl->tx_buf_p;
- netif_stop_queue(dev);
+ unsigned len = min( skb->len - nl->outpos, nl->framelen );
- save_flags(flags);
- cli();
- sbni_drop_tx_queue(dev);
- del_timer(watchdog);
- outb(0, ioaddr + CSR0);
- restore_flags(flags);
+ outsb( dev->base_addr + DAT, skb->data + nl->outpos, len );
+ *crc_p = calc_crc32( *crc_p, skb->data + nl->outpos, len );
- MOD_DEC_USE_COUNT;
- return 0;
+ /* if packet too short we should write some more bytes to pad */
+ for( len = nl->framelen - len; len--; )
+ outb( 0, dev->base_addr + DAT ),
+ *crc_p = CRC32( 0, *crc_p );
}
-static int sbni_start_xmit(struct sk_buff *skb, struct net_device *dev)
+
+static int
+upload_data( struct net_device *dev, unsigned framelen, unsigned frameno,
+ unsigned is_first, u32 crc )
{
- struct net_local *lp = (struct net_local*)dev->priv;
- struct sbni_hard_header *hh=(struct sbni_hard_header *)skb->data;
- unsigned long flags;
-
-#ifdef KATYUSHA
- struct net_local *nl;
- int stop;
+ struct net_local *nl = (struct net_local *) dev->priv;
+
+ int frame_ok;
+
+ if( is_first )
+ nl->wait_frameno = frameno,
+ nl->inppos = 0;
+
+ if( nl->wait_frameno == frameno ) {
+
+ if( nl->inppos + framelen <= ETHER_MAX_LEN )
+ frame_ok = append_frame_to_pkt( dev, framelen, crc );
+
+ /*
+ * if CRC is right but framelen incorrect then transmitter
+ * error was occured... drop entire packet
+ */
+ else if( (frame_ok = skip_tail( dev->base_addr, framelen, crc ))
+ != 0 )
+ nl->wait_frameno = 0,
+ nl->inppos = 0,
+#ifdef CONFIG_SBNI_MULTILINE
+ ((struct net_local *) nl->master->priv)
+ ->stats.rx_errors++,
+ ((struct net_local *) nl->master->priv)
+ ->stats.rx_missed_errors++;
+#else
+ nl->stats.rx_errors++,
+ nl->stats.rx_missed_errors++;
+#endif
+ /* now skip all frames until is_first != 0 */
+ } else
+ frame_ok = skip_tail( dev->base_addr, framelen, crc );
+
+ if( is_first && !frame_ok )
+ /*
+ * Frame has been broken, but we had already stored
+ * is_first... Drop entire packet.
+ */
+ nl->wait_frameno = 0,
+#ifdef CONFIG_SBNI_MULTILINE
+ ((struct net_local *) nl->master->priv)->stats.rx_errors++,
+ ((struct net_local *) nl->master->priv)->stats.rx_crc_errors++;
+#else
+ nl->stats.rx_errors++,
+ nl->stats.rx_crc_errors++;
+#endif
+
+ return frame_ok;
+}
+
+
+static __inline void
+send_complete( struct net_local *nl )
+{
+#ifdef CONFIG_SBNI_MULTILINE
+ ((struct net_local *) nl->master->priv)->stats.tx_packets++;
+ ((struct net_local *) nl->master->priv)->stats.tx_bytes
+ += nl->tx_buf_p->len;
+#else
+ nl->stats.tx_packets++;
+ nl->stats.tx_bytes += nl->tx_buf_p->len;
+#endif
+ dev_kfree_skb_irq( nl->tx_buf_p );
+
+ nl->tx_buf_p = NULL;
+
+ nl->outpos = 0;
+ nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+ nl->framelen = 0;
+}
+
+
+static void
+interpret_ack( struct net_device *dev, unsigned ack )
+{
+ struct net_local *nl = (struct net_local *) dev->priv;
+
+ if( ack == FRAME_SENT_OK ) {
+ nl->state &= ~FL_NEED_RESEND;
+
+ if( nl->state & FL_WAIT_ACK ) {
+ nl->outpos += nl->framelen;
+
+ if( --nl->tx_frameno )
+ nl->framelen = min( nl->maxframe,
+ nl->tx_buf_p->len - nl->outpos );
+ else
+ send_complete( nl ),
+#ifdef CONFIG_SBNI_MULTILINE
+ netif_wake_queue( nl->master );
+#else
+ netif_wake_queue( dev );
#endif
-
- DP( printk("%s: sbni_start_xmit In \n", dev->name); );
-
-
- if(lp->me != dev)
- panic("sbni: lp->me != dev !!!\nMail to developer (xenon@granch.ru) if you noticed this error\n");
-
- hh->number = 1;
- hh->reserv = 0;
-
- hh->packetlen = (skb->len - sizeof (unsigned short) -
- (sizeof(struct sbni_hard_header) - SBNI_HH_SZ))
- | PACKET_SEND_OK | PACKET_FIRST_FRAME;
-
- /* we should use hairy method to calculate crc because of extra bytes are
- livin between hard header and data*/
- hh->crc = calc_crc((void*)&hh->packetlen, SBNI_HH_SZ - sizeof(unsigned), CRC32_INITIAL);
- hh->crc = calc_crc(skb->data + sizeof(struct sbni_hard_header),
- skb->len - sizeof(struct sbni_hard_header),
- hh->crc);
-
- spin_lock_irqsave(&lp->lock, flags);
-#ifdef KATYUSHA
- /* looking for first idle device */
- for (stop=0,nl=lp; nl && !stop; nl=nl->next_lp)
- {
- if((!nl->currframe) && (nl->carrier)) /* if idle */
- {
- skb->dev = lp->me;
- nl->currframe = skb;
- /* set request for transmit */
- outb(inb(nl->me->base_addr + CSR0) | TR_REQ,
- nl->me->base_addr + CSR0);
- stop=1;
}
}
-
- if(!stop) /* we havent found any idle.*/
- {
- skb_queue_tail(&lp->queue,skb);
- outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
-
- }
-#else
- if (lp->currframe || 1)
- {
- skb_queue_tail(&lp->queue,skb);
-
- }
- else
- {
- lp->currframe = skb;
- }
- /* set request for transmit */
- outb(inb(dev->base_addr + CSR0) | TR_REQ, dev->base_addr + CSR0);
-#endif
- spin_unlock_irqrestore(&lp->lock, flags);
- return 0;
+
+ nl->state &= ~FL_WAIT_ACK;
}
-static void card_start(struct net_device *dev)
+
+/*
+ * Glue received frame with previous fragments of packet.
+ * Indicate packet when last frame would be accepted.
+ */
+
+static int
+append_frame_to_pkt( struct net_device *dev, unsigned framelen, u32 crc )
{
- struct net_local *lp = (struct net_local*)dev->priv;
-
- DP( printk("%s: card_start\n",dev->name); )
- lp->wait_frame_number = 0;
- lp->inppos = lp->outpos = 0;
- lp->eth_trans_buffer_len = 0;
- lp->tr_err = TR_ERROR_COUNT;
- lp->last_receive_OK = FALSE;
- lp->tr_resend = FALSE;
- lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
- lp->timeout_rxl = 0;
-
- lp->waitack=0;
- skb_queue_head_init(&lp->queue);
- sbni_drop_tx_queue(dev);
- /* Reset the card and set start parameters */
- outb(PR_RES | *(char*)&lp->csr1, dev->base_addr + CSR1);
- outb(EN_INT, dev->base_addr + CSR0);
+ struct net_local *nl = (struct net_local *) dev->priv;
+
+ u8 *p;
+
+ if( nl->inppos + framelen > ETHER_MAX_LEN )
+ return 0;
+
+ if( !nl->rx_buf_p && !(nl->rx_buf_p = get_rx_buf( dev )) )
+ return 0;
+
+ p = nl->rx_buf_p->data + nl->inppos;
+ insb( dev->base_addr + DAT, p, framelen );
+ if( calc_crc32( crc, p, framelen ) != CRC32_REMAINDER )
+ return 0;
+
+ nl->inppos += framelen - 4;
+ if( --nl->wait_frameno == 0 ) /* last frame received */
+ indicate_pkt( dev );
+
+ return 1;
}
-void sbni_nirvana(struct net_device *dev)
+
+/*
+ * Prepare to start output on adapter.
+ * Transmitter will be actually activated when marker is accepted.
+ */
+
+static void
+prepare_to_send( struct sk_buff *skb, struct net_device *dev )
{
- sbni_outs(dev->base_addr+DAT,magic_reply,9);
+ struct net_local *nl = (struct net_local *) dev->priv;
+
+ unsigned int len;
+
+ /* nl->tx_buf_p == NULL here! */
+ if( nl->tx_buf_p )
+ printk( KERN_ERR "%s: memory leak!\n", dev->name );
+
+ nl->outpos = 0;
+ nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+
+ len = skb->len;
+ if( len < SBNI_MIN_LEN )
+ len = SBNI_MIN_LEN;
+
+ nl->tx_buf_p = skb;
+ nl->tx_frameno = (len + nl->maxframe - 1) / nl->maxframe;
+ nl->framelen = len < nl->maxframe ? len : nl->maxframe;
+
+ outb( inb( dev->base_addr + CSR0 ) | TR_REQ, dev->base_addr + CSR0 );
+#ifdef CONFIG_SBNI_MULTILINE
+ nl->master->trans_start = jiffies;
+#else
+ dev->trans_start = jiffies;
+#endif
}
-static inline unsigned short sbni_recv(struct net_device *dev)
+
+static void
+drop_xmit_queue( struct net_device *dev )
{
- struct net_local *lp = (struct net_local*)dev->priv;
- unsigned long crc;
- unsigned short packetlen = 0;
- unsigned short packetinf, packetfirst, receiveframeresend;
- unsigned char current_frame;
- unsigned int i, j;
- unsigned char delme,rcv_res=RCV_WR;
-
- lp->in_stats.all_rx_number++;
-
- if((delme=inb(dev->base_addr + DAT)) == SBNI_SIG)
- {
- crc = CRC32_INITIAL;
- *(((unsigned char *)&packetlen) + 0) = inb(dev->base_addr + DAT);
- crc = CRC32(*(((unsigned char *)&packetlen) + 0), crc);
- *(((unsigned char *)&packetlen) + 1) = inb(dev->base_addr + DAT);
- crc = CRC32(*(((unsigned char *)&packetlen) + 1), crc);
- packetinf = packetlen & PACKET_INF_MASK;
- packetfirst = packetlen & PACKET_FIRST_FRAME;
- receiveframeresend = packetlen & RECEIVE_FRAME_RESEND;
- packetlen = packetlen & PACKET_LEN_MASK;
-
-
- if((packetlen <= SB_MAX_BUFFER_ARRAY - 3) && (packetlen >= 6))
- {
- /* read frame number */
- current_frame = inb(dev->base_addr + DAT);
- crc = CRC32(current_frame, crc);
- /* read HandShake counter */
- lp->HSCounter = inb(dev->base_addr + DAT);
- crc = CRC32(lp->HSCounter, crc);
- packetlen -= 2;
-
- sbni_ins(dev->base_addr + DAT, lp->eth_rcv_buffer + lp->inppos, packetlen);
-
- for(i = lp->inppos; i < (packetlen + lp->inppos); i++)
- {
- crc = CRC32(lp->eth_rcv_buffer[i], crc);
- }
-
- if(crc == CRC32_REMAINDER)
- {
- if(packetlen > 4)
- rcv_res=RCV_OK;
- else if(packetlen == 4)
- rcv_res=RCV_NO;
-
- if(lp->waitack && packetinf == PACKET_RESEND)
- lp->in_stats.resend_tx_number++;
-
-
- switch(packetinf)
- {
- case PACKET_SEND_OK:
- {
- lp->tr_err = TR_ERROR_COUNT;
- lp->tr_resend = FALSE;
- /* if(lp->trans_frame_number){ */
- lp->outpos += lp->realframelen;
-
- /* SendComplete
- * not supported
- */
- DP( printk("%s: sbni_recv SendComplete\n",dev->name); );
- /*
- * We successfully sent current packet
- */
-
- if(lp->waitack)
- {
- dev_kfree_skb(lp->currframe);
- lp->stats.tx_packets++;
-#ifdef KATYUSHA
- lp->currframe=skb_dequeue(&(((struct net_local*) (lp->m->priv))->queue));
+ struct net_local *nl = (struct net_local *) dev->priv;
+
+ if( nl->tx_buf_p )
+ dev_kfree_skb_any( nl->tx_buf_p ),
+ nl->tx_buf_p = NULL,
+#ifdef CONFIG_SBNI_MULTILINE
+ ((struct net_local *) nl->master->priv)
+ ->stats.tx_errors++,
+ ((struct net_local *) nl->master->priv)
+ ->stats.tx_carrier_errors++;
#else
- lp->currframe=skb_dequeue(&lp->queue);
-#endif
- lp->in_stats.all_tx_number++;
- lp->waitack=0;
- }
-
- /*
- * reset output active flags
- */
- netif_wake_queue(dev);
- /*} if */
- }
- case PACKET_RESEND:
- {
- if(lp->tr_err) /**/
- lp->tr_err--;
- if(lp->ok_curr < 0xffffffff)
- lp->ok_curr++;
- if(packetlen > 4 && !(lp->last_receive_OK && receiveframeresend))
- {
- if(packetfirst)
- {
- if(lp->wait_frame_number)
- {
- for(i = lp->inppos, j = 0;
- i < (lp->inppos + packetlen - 4);
- i++, j++)
- lp->eth_rcv_buffer[j] = lp->eth_rcv_buffer[i];
- }
- lp->wait_frame_number = current_frame;
- lp->inppos = 0;
- }
- if(current_frame == lp->wait_frame_number)
- {
- lp->inppos += (packetlen - 4);
- if(lp->wait_frame_number == 1)
- {
- sbni_get_packet(dev);
- lp->inppos = 0;
- }
- lp->wait_frame_number--;
- }
- }
- lp->last_receive_OK = TRUE;
- break;
- }
- default:
- break;
- }
- }
- else
- {
- DP(printk("%s: bad CRC32\n",dev->name));
- change_level(dev);
- }
- }
- else
- {
- DP(printk("%s: bad len\n ",dev->name));
- change_level(dev);
- lp->stats.rx_over_errors++;
- }
- }
- else
- {
- DP(printk("%s: bad sig\n",dev->name));
- change_level(dev);
- }
- outb(inb(dev->base_addr + CSR0) ^ CT_ZER, dev->base_addr + CSR0);
- return (rcv_res);
+ nl->stats.tx_errors++,
+ nl->stats.tx_carrier_errors++;
+#endif
+
+ nl->tx_frameno = 0;
+ nl->framelen = 0;
+ nl->outpos = 0;
+ nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+#ifdef CONFIG_SBNI_MULTILINE
+ netif_start_queue( nl->master );
+ nl->master->trans_start = jiffies;
+#else
+ netif_start_queue( dev );
+ dev->trans_start = jiffies;
+#endif
}
-void change_level(struct net_device *dev)
+
+static void
+send_frame_header( struct net_device *dev, u32 *crc_p )
{
- struct net_local *lp = (struct net_local*)dev->priv;
+ struct net_local *nl = (struct net_local *) dev->priv;
- lp->in_stats.bad_rx_number++;
- lp->stats.tx_errors++;
- if(lp->rxl_delta == 0)
- return;
- /*
- * set new rxl_delta value
- */
- if(lp->rxl_curr == 0)
- lp->rxl_delta = 1;
- else if(lp->rxl_curr == 0xf)
- lp->rxl_delta = -1;
- else if(lp->ok_curr < lp->ok_prev)
- lp->rxl_delta = -lp->rxl_delta;
- /*
- * set new rxl_curr value
- */
- lp->csr1.rxl = rxl_tab[lp->rxl_curr += lp->rxl_delta];
- outb(*(char*)&lp->csr1, dev->base_addr + CSR1);
-
-
- /*
- * update ok_prev/ok_curr counters
- */
- lp->ok_prev = lp->ok_curr;
- lp->ok_curr = 0;
+ u32 crc = *crc_p;
+ u32 len_field = nl->framelen + 6; /* CRC + frameno + reserved */
+ u8 value;
+
+ if( nl->state & FL_NEED_RESEND )
+ len_field |= FRAME_RETRY; /* non-first attempt... */
+
+ if( nl->outpos == 0 )
+ len_field |= FRAME_FIRST;
- DP( printk("%s: receive error, rxl_curr = %d, rxl_delta = %d\n",\
- dev->name,lp->rxl_curr, lp->rxl_delta); )
-
+ len_field |= (nl->state & FL_PREV_OK) ? FRAME_SENT_OK : FRAME_SENT_BAD;
+ outb( SBNI_SIG, dev->base_addr + DAT );
+
+ value = (u8) len_field;
+ outb( value, dev->base_addr + DAT );
+ crc = CRC32( value, crc );
+ value = (u8) (len_field >> 8);
+ outb( value, dev->base_addr + DAT );
+ crc = CRC32( value, crc );
+
+ outb( nl->tx_frameno, dev->base_addr + DAT );
+ crc = CRC32( nl->tx_frameno, crc );
+ outb( 0, dev->base_addr + DAT );
+ crc = CRC32( 0, crc );
+ *crc_p = crc;
}
-static inline void sbni_xmit(struct net_device *dev)
+
+/*
+ * if frame tail not needed (incorrect number or received twice),
+ * it won't store, but CRC will be calculated
+ */
+
+static int
+skip_tail( unsigned int ioaddr, unsigned int tail_len, u32 crc )
{
- struct net_local* lp = (struct net_local *)dev->priv;
- struct sk_buff *skb;
-
- skb=lp->currframe;
-
- DP( printk("%s: sbni_xmit CSR0=%02x\n",dev->name, (unsigned char)inb(dev->base_addr + CSR0)); );
-
- /* push signature*/
- outb(SBNI_SIG, dev->base_addr + DAT);
-
- /* push frame w/o crc [HAiRY]*/
- sbni_outs(dev->base_addr + DAT,
- &((struct sbni_hard_header *)(skb->data))->packetlen,
- SBNI_HH_SZ - sizeof(unsigned));
-
- sbni_outs(dev->base_addr + DAT,
- skb->data + sizeof(struct sbni_hard_header),
- skb->len - sizeof(struct sbni_hard_header)); /* ÕÓÐÅÅÍ ÅÝÅ */
+ while( tail_len-- )
+ crc = CRC32( inb( ioaddr + DAT ), crc );
- /* push crc */
- sbni_outs(dev->base_addr + DAT, skb->data, sizeof(unsigned));
-
- lp->waitack=1;
+ return crc == CRC32_REMAINDER;
}
+
/*
- * The typical workload of the driver:
- * Handle the ether interface interrupts.
+ * Preliminary checks if frame header is correct, calculates its CRC
+ * and split it to simple fields
*/
-static void sbni_interrupt(int irq, void *dev_id, struct pt_regs *regs)
+
+static int
+check_fhdr( u32 ioaddr, u32 *framelen, u32 *frameno, u32 *ack,
+ u32 *is_first, u32 *crc_p )
{
- struct net_device *dev = dev_id;
- struct net_local* lp;
- u_char csr0;
- unsigned short rcv_res = RCV_NO;
-
-
- if(dev == NULL || dev->irq != irq)
- {
- printk("sbni: irq %d for unknown device\n", irq);
- return;
- }
-
- csr0 = inb(dev->base_addr + CSR0);
- DP( printk("%s: entering interrupt handler, CSR0 = %02x\n", dev->name, csr0); )
-
- lp=dev->priv;
+ u32 crc = *crc_p;
+ u8 value;
- spin_lock(&lp->lock);
-
- if(!lp->carrier)
- lp->carrier=1;
-
- /*
- * Disable adapter interrupts
- */
- outb((csr0 & ~EN_INT) | TR_REQ, dev->base_addr + CSR0);
- lp->timer_ticks = CHANGE_LEVEL_START_TICKS;
- csr0 = inb(dev->base_addr + CSR0);
-
- if(csr0 & (TR_RDY | RC_RDY))
- {
- if(csr0 & RC_RDY)
- rcv_res = sbni_recv(dev);
-
- if((lp->currframe) && (rcv_res != RCV_WR))
- sbni_xmit(dev);
- else if (rcv_res == RCV_OK)
- sbni_nirvana(dev);
-
- csr0 = inb(dev->base_addr + CSR0);
- DP( printk("%s: CSR0 = %02x\n",dev->name, (u_int)csr0); );
- }
-
-
- DP( printk("%s: leaving interrupt handler, CSR0 = %02x\n",dev->name, csr0 | EN_INT); );
-
- /* here we should send pong */
- outb(inb(dev->base_addr+CSR0) & ~TR_REQ, dev->base_addr + CSR0);
- if(lp->currframe)
- outb(inb(dev->base_addr+CSR0) | TR_REQ, dev->base_addr + CSR0);
- else
- csr0 = inb(dev->base_addr + CSR0);
-
- /*
- * Enable adapter interrupts
- */
-
- outb(csr0 | EN_INT, dev->base_addr + CSR0);
- spin_unlock(&lp->lock);
+ if( inb( ioaddr + DAT ) != SBNI_SIG )
+ return 0;
+
+ value = inb( ioaddr + DAT );
+ *framelen = (u32)value;
+ crc = CRC32( value, crc );
+ value = inb( ioaddr + DAT );
+ *framelen |= ((u32)value) << 8;
+ crc = CRC32( value, crc );
+
+ *ack = *framelen & FRAME_ACK_MASK;
+ *is_first = (*framelen & FRAME_FIRST) != 0;
+
+ if( (*framelen &= FRAME_LEN_MASK) < 6
+ || *framelen > SBNI_MAX_FRAME - 3 )
+ return 0;
+
+ value = inb( ioaddr + DAT );
+ *frameno = (u32)value;
+ crc = CRC32( value, crc );
+
+ crc = CRC32( inb( ioaddr + DAT ), crc ); /* reserved byte */
+ *framelen -= 2;
+
+ *crc_p = crc;
+ return 1;
}
-static struct net_device_stats *sbni_get_stats(struct net_device *dev)
+
+static struct sk_buff *
+get_rx_buf( struct net_device *dev )
{
- struct net_local *lp = (struct net_local *)dev->priv;
- return &lp->stats;
+ /* +2 is to compensate for the alignment fixup below */
+ struct sk_buff *skb = dev_alloc_skb( ETHER_MAX_LEN + 2 );
+ if( !skb )
+ return NULL;
+
+#ifdef CONFIG_SBNI_MULTILINE
+ skb->dev = ((struct net_local *) dev->priv)->master;
+#else
+ skb->dev = dev;
+#endif
+ skb_reserve( skb, 2 ); /* Align IP on longword boundaries */
+ return skb;
}
-static inline void sbni_get_packet(struct net_device* dev)
+
+static void
+indicate_pkt( struct net_device *dev )
{
- struct net_local* lp = (struct net_local*)dev->priv;
- struct sk_buff* skb;
- unsigned char *rawp;
-
-
-
- skb = dev_alloc_skb(lp->inppos - ETH_HLEN + sizeof(struct sbni_hard_header));
-
- if(skb == NULL)
- {
- DP( printk("%s: Memory squeeze, dropping packet.\n", dev->name); )
- lp->stats.rx_dropped++;
- return;
- } else {
-#ifdef KATYUSHA
- skb->dev = lp->m;
+ struct net_local *nl = (struct net_local *) dev->priv;
+ struct sk_buff *skb = nl->rx_buf_p;
+
+ skb_put( skb, nl->inppos );
+
+#ifdef CONFIG_SBNI_MULTILINE
+ skb->protocol = eth_type_trans( skb, nl->master );
+ netif_rx( skb );
+ dev->last_rx = jiffies;
+ ++((struct net_local *) nl->master->priv)->stats.rx_packets;
+ ((struct net_local *) nl->master->priv)->stats.rx_bytes += nl->inppos;
#else
- skb->dev = dev;
-#endif
- memcpy((unsigned char*)skb_put(skb, lp->inppos + 8)+8,
- lp->eth_rcv_buffer,
- lp->inppos);
-
-
- skb->mac.raw = skb->data + 8;
-
- if((*(char*)lp->eth_rcv_buffer) & 1)
- {
- if(memcmp(lp->eth_rcv_buffer,dev->broadcast, ETH_ALEN)==0)
- skb->pkt_type=PACKET_BROADCAST;
- else
- skb->pkt_type=PACKET_MULTICAST;
- }
- else if(dev->flags&(IFF_PROMISC|IFF_ALLMULTI))
- {
- if(memcmp(lp->eth_rcv_buffer,dev->dev_addr, ETH_ALEN))
- skb->pkt_type=PACKET_OTHERHOST;
- }
-
- if( htons(*((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]))) >= 1536)
- skb->protocol = *((unsigned short*)(&lp->eth_rcv_buffer[2*ETH_ALEN]));
- else
- {
- rawp = (unsigned char*)(&lp->eth_rcv_buffer[2*ETH_ALEN]);
- if (*(unsigned short *)rawp == 0xFFFF)
- skb->protocol=htons(ETH_P_802_3);
- else
- skb->protocol=htons(ETH_P_802_2);
+ skb->protocol = eth_type_trans( skb, dev );
+ netif_rx( skb );
+ dev->last_rx = jiffies;
+ ++nl->stats.rx_packets;
+ nl->stats.rx_bytes += nl->inppos;
+#endif
+ nl->rx_buf_p = NULL; /* protocol driver will clear this sk_buff */
+}
+
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Routine checks periodically wire activity and regenerates marker if
+ * connect was inactive for a long time.
+ */
+
+static void
+sbni_watchdog( unsigned long arg )
+{
+ struct net_device *dev = (struct net_device *) arg;
+ struct net_local *nl = (struct net_local *) dev->priv;
+ struct timer_list *w = &nl->watchdog;
+ unsigned long flags;
+ unsigned char csr0;
+
+ spin_lock_irqsave( &nl->lock, flags );
+
+ csr0 = inb( dev->base_addr + CSR0 );
+ if( csr0 & RC_CHK ) {
+
+ if( nl->timer_ticks ) {
+ if( csr0 & (RC_RDY | BU_EMP) )
+ /* receiving not active */
+ nl->timer_ticks--;
+ } else {
+ nl->in_stats.timeout_number++;
+ if( nl->delta_rxl )
+ timeout_change_level( dev );
+
+ outb( *(u_char *)&nl->csr1 | PR_RES,
+ dev->base_addr + CSR1 );
+ csr0 = inb( dev->base_addr + CSR0 );
}
-
+ } else
+ nl->state &= ~FL_LINE_DOWN;
- skb_pull(skb,SBNI_HH_SZ);
-
- skb->dev->last_rx = jiffies;
- lp->stats.rx_bytes += skb->len;
- netif_rx(skb);
- lp->stats.rx_packets++;
- }
- return;
+ outb( csr0 | RC_CHK, dev->base_addr + CSR0 );
+
+ init_timer( w );
+ w->expires = jiffies + SBNI_TIMEOUT;
+ w->data = arg;
+ w->function = sbni_watchdog;
+ add_timer( w );
+
+ spin_unlock_irqrestore( &nl->lock, flags );
}
-static void sbni_watchdog(unsigned long arg)
+
+static unsigned char rxl_tab[] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x08,
+ 0x0a, 0x0c, 0x0f, 0x16, 0x18, 0x1a, 0x1c, 0x1f
+};
+
+#define SIZE_OF_TIMEOUT_RXL_TAB 4
+static unsigned char timeout_rxl_tab[] = {
+ 0x03, 0x05, 0x08, 0x0b
+};
+
+/* -------------------------------------------------------------------------- */
+
+static void
+card_start( struct net_device *dev )
{
- struct net_device* dev = (struct net_device*)arg;
- struct net_local* lp = (struct net_local *)dev->priv;
- u_char csr0;
+ struct net_local *nl = (struct net_local *) dev->priv;
+ nl->timer_ticks = CHANGE_LEVEL_START_TICKS;
+ nl->state &= ~(FL_WAIT_ACK | FL_NEED_RESEND);
+ nl->state |= FL_PREV_OK;
+
+ nl->inppos = nl->outpos = 0;
+ nl->wait_frameno = 0;
+ nl->tx_frameno = 0;
+ nl->framelen = 0;
+
+ outb( *(u_char *)&nl->csr1 | PR_RES, dev->base_addr + CSR1 );
+ outb( EN_INT, dev->base_addr + CSR0 );
+}
+
+/* -------------------------------------------------------------------------- */
+
+/* Receive level auto-selection */
+
+static void
+change_level( struct net_device *dev )
+{
+ struct net_local *nl = (struct net_local *) dev->priv;
+
+ if( nl->delta_rxl == 0 ) /* do not auto-negotiate RxL */
+ return;
+
+ if( nl->cur_rxl_index == 0 )
+ nl->delta_rxl = 1;
+ else if( nl->cur_rxl_index == 15 )
+ nl->delta_rxl = -1;
+ else if( nl->cur_rxl_rcvd < nl->prev_rxl_rcvd )
+ nl->delta_rxl = -nl->delta_rxl;
+
+ nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index += nl->delta_rxl ];
+ inb( dev->base_addr + CSR0 ); /* needs for PCI cards */
+ outb( *(u8 *)&nl->csr1, dev->base_addr + CSR1 );
+
+ nl->prev_rxl_rcvd = nl->cur_rxl_rcvd;
+ nl->cur_rxl_rcvd = 0;
+}
+
+
+static void
+timeout_change_level( struct net_device *dev )
+{
+ struct net_local *nl = (struct net_local *) dev->priv;
+
+ nl->cur_rxl_index = timeout_rxl_tab[ nl->timeout_rxl ];
+ if( ++nl->timeout_rxl >= 4 )
+ nl->timeout_rxl = 0;
+
+ nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index ];
+ inb( dev->base_addr + CSR0 );
+ outb( *(unsigned char *)&nl->csr1, dev->base_addr + CSR1 );
+
+ nl->prev_rxl_rcvd = nl->cur_rxl_rcvd;
+ nl->cur_rxl_rcvd = 0;
+}
+
+/* -------------------------------------------------------------------------- */
+
+/*
+ * Open/initialize the board.
+ */
+
+static int
+sbni_open( struct net_device *dev )
+{
+ struct net_local *nl = (struct net_local *) dev->priv;
+ struct timer_list *w = &nl->watchdog;
-
- DP( printk("%s: watchdog start\n",dev->name); )
/*
- * if no pong received and transmission is not in progress
- * then assume error
+ * For double ISA adapters within "common irq" mode, we have to
+ * determine whether primary or secondary channel is initialized,
+ * and set the irq handler only in first case.
*/
- cli();
- csr0 = inb(dev->base_addr + CSR0);
- if(csr0 & (RC_CHK | TR_REQ))
- {
- if(lp->timer_ticks)
- {
- if(csr0 & (RC_RDY | BU_EMP))
- {
- lp->timer_ticks--;
- }
- }
- else
- {
- if(lp->rxl_delta)
- {
- lp->ok_prev = lp->ok_curr;
- lp->ok_curr = 0;
- lp->rxl_curr = timeout_rxl_tab[lp->timeout_rxl];
- lp->timeout_rxl++;
- if(lp->timeout_rxl > SIZE_OF_TIMEOUT_RXL_TAB - 1)
- lp->timeout_rxl = 0;
- lp->csr1.rxl = rxl_tab[lp->rxl_curr];
- /*
- * update ok_prev/ok_curr counters
- */
- lp->ok_prev = lp->ok_curr;
- lp->ok_curr = 0;
- }
- if(lp->tr_err)
- lp->tr_err--;
- else
- {
- /* Drop the queue of tx packets */
- sbni_drop_tx_queue(dev);
- lp->carrier=0;
+ if( dev->base_addr < 0x400 ) { /* ISA only */
+ struct net_device **p = sbni_cards;
+ for( ; *p && p < sbni_cards + SBNI_MAX_NUM_CARDS; ++p )
+ if( (*p)->irq == dev->irq
+ && ((*p)->base_addr == dev->base_addr + 4
+ || (*p)->base_addr == dev->base_addr - 4)
+ && (*p)->flags & IFF_UP ) {
+
+ ((struct net_local *) ((*p)->priv))
+ ->second = dev;
+ printk( KERN_NOTICE "%s: using shared irq "
+ "with %s\n", dev->name, (*p)->name );
+ nl->state |= FL_SECONDARY;
+ goto handler_attached;
}
-
- /*
- * send pong
- */
-
- csr0 = inb(dev->base_addr + CSR0);
- outb(csr0 & ~TR_REQ, dev->base_addr + CSR0);
- outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
- lp->in_stats.timeout_number++;
- }
}
- sti();
- outb(csr0 | RC_CHK, dev->base_addr + CSR0);
- if(netif_running(dev))
- {
- struct timer_list* watchdog = &lp->watchdog;
- init_timer(watchdog);
- watchdog->expires = jiffies + SBNI_TIMEOUT;
- watchdog->data = arg;
- watchdog->function = sbni_watchdog;
- add_timer(watchdog);
+
+ if( request_irq(dev->irq, sbni_interrupt, SA_SHIRQ, dev->name, dev) ) {
+ printk( KERN_ERR "%s: unable to get IRQ %d.\n",
+ dev->name, dev->irq );
+ return -EAGAIN;
}
-}
-static void sbni_drop_tx_queue(struct net_device *dev)
-{
- struct net_local* lp = (struct net_local *)dev->priv,*nl;
- struct sk_buff *tmp;
+handler_attached:
+
+ spin_lock( &nl->lock );
+ memset( &nl->stats, 0, sizeof(struct net_device_stats) );
+ memset( &nl->in_stats, 0, sizeof(struct sbni_in_stats) );
+
+ card_start( dev );
+
+ netif_start_queue( dev );
+
+ /* set timer watchdog */
+ init_timer( w );
+ w->expires = jiffies + SBNI_TIMEOUT;
+ w->data = (unsigned long) dev;
+ w->function = sbni_watchdog;
+ add_timer( w );
- /* first of all, we should try to gift our packets to another interface */
-
- nl=(struct net_local *)lp->m->priv;
- if(nl==lp)
- nl=lp->next_lp;
-
- if(nl)
- {
- /* we found device*/
- if(lp->currframe)
- {
- if(!nl->currframe)
- {
- nl->currframe=lp->currframe;
- }
- else
- {
- skb_queue_head(&((struct net_local*)(lp->m->priv))->queue,lp->currframe);
- }
- }
- lp->currframe=NULL;
+ spin_unlock( &nl->lock );
+ return 0;
+}
- if(!nl->currframe)
- nl->currframe=skb_dequeue(&(((struct net_local*)(lp->m->priv))->queue));
- /* set request for transmit */
- outb(inb(nl->me->base_addr + CSR0) | TR_REQ, nl->me->base_addr + CSR0);
-
+static int
+sbni_close( struct net_device *dev )
+{
+ struct net_local *nl = (struct net_local *) dev->priv;
+
+ if( nl->second && nl->second->flags & IFF_UP ) {
+ printk( KERN_NOTICE "Secondary channel (%s) is active!\n",
+ nl->second->name );
+ return -EBUSY;
}
+
+#ifdef CONFIG_SBNI_MULTILINE
+ if( nl->state & FL_SLAVE )
+ emancipate( dev );
else
- {
- /* *sigh*, we should forget this packets */
- nl=lp->m->priv;
-
- while((tmp = skb_dequeue(&nl->queue)) != NULL)
- {
- dev_kfree_skb(tmp);
- lp->stats.tx_packets++;
- }
-
- if (lp->currframe)
- {
- dev_kfree_skb(lp->currframe);
- lp->currframe = NULL;
- lp->stats.tx_packets++;
- }
- }
- lp->waitack=0;
- netif_wake_queue(dev);
-
- DP( printk("%s: queue dropping stopped\n",dev->name); );
+ while( nl->link ) /* it's master device! */
+ emancipate( nl->link );
+#endif
+
+ spin_lock( &nl->lock );
+
+ nl->second = NULL;
+ drop_xmit_queue( dev );
+ netif_stop_queue( dev );
+
+ del_timer( &nl->watchdog );
+
+ outb( 0, dev->base_addr + CSR0 );
+
+ if( !(nl->state & FL_SECONDARY) )
+ free_irq( dev->irq, dev );
+ nl->state &= FL_SECONDARY;
+
+ spin_unlock( &nl->lock );
+ return 0;
}
+
/*
- * Set or clear the multicast filter for this adaptor.
- * num_addrs == -1 Promiscuous mode, receive all packets
- * num_addrs == 0 Normal mode, clear multicast list
- * num_addrs > 0 Multicast mode, receive normal and MC packets,
- * and do best-effort filtering.
- */
-
-static void set_multicast_list(struct net_device *dev)
+ Valid combinations in CSR0 (for probing):
+
+ VALID_DECODER 0000,0011,1011,1010
+
+ ; 0 ; -
+ TR_REQ ; 1 ; +
+ TR_RDY ; 2 ; -
+ TR_RDY TR_REQ ; 3 ; +
+ BU_EMP ; 4 ; +
+ BU_EMP TR_REQ ; 5 ; +
+ BU_EMP TR_RDY ; 6 ; -
+ BU_EMP TR_RDY TR_REQ ; 7 ; +
+ RC_RDY ; 8 ; +
+ RC_RDY TR_REQ ; 9 ; +
+ RC_RDY TR_RDY ; 10 ; -
+ RC_RDY TR_RDY TR_REQ ; 11 ; -
+ RC_RDY BU_EMP ; 12 ; -
+ RC_RDY BU_EMP TR_REQ ; 13 ; -
+ RC_RDY BU_EMP TR_RDY ; 14 ; -
+ RC_RDY BU_EMP TR_RDY TR_REQ ; 15 ; -
+*/
+
+#define VALID_DECODER (2 + 8 + 0x10 + 0x20 + 0x80 + 0x100 + 0x200)
+
+
+static int
+sbni_card_probe( unsigned long ioaddr )
{
- /*
- * always enabled promiscuous mode.
- */
- return;
-}
+ unsigned char csr0;
-static int sbni_set_mac_address(struct net_device *dev, void *addr)
-{
- /* struct net_local *lp = (struct net_local *)dev->priv; */
- struct sockaddr *saddr = addr;
-
- if(netif_running(dev))
- {
- /* Only possible while card isn't started */
- return -EBUSY;
+ csr0 = inb( ioaddr + CSR0 );
+ if( csr0 != 0xff && csr0 != 0x00 ) {
+ csr0 &= ~EN_INT;
+ if( csr0 & BU_EMP )
+ csr0 |= EN_INT;
+
+ if( VALID_DECODER & (1 << (csr0 >> 4)) )
+ return 0;
}
- memcpy(dev->dev_addr, saddr->sa_data, dev->addr_len);
- return (0);
+
+ return -ENODEV;
}
-static int sbni_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
+/* -------------------------------------------------------------------------- */
+
+static int
+sbni_ioctl( struct net_device *dev, struct ifreq *ifr, int cmd )
{
- struct net_local* lp = (struct net_local *)dev->priv,*tlp;
- struct net_device *slave;
- int error = 0;
- char tmpstr[6];
-
+ struct net_local *nl = (struct net_local *) dev->priv;
+ struct sbni_flags flags;
+ int error = 0;
+
+#ifdef CONFIG_SBNI_MULTILINE
+ struct net_device *slave_dev;
+ char slave_name[ 8 ];
+#endif
- switch(cmd)
- {
- case SIOCDEVGETINSTATS:
- {
- struct sbni_in_stats *in_stats = (struct sbni_in_stats *)ifr->ifr_data;
- DP( printk("%s: SIOCDEVGETINSTATS %08x\n",dev->name,(unsigned)in_stats);)
- if(copy_to_user((void *)in_stats, (void *)(&(lp->in_stats)), sizeof(struct sbni_in_stats)))
- return -EFAULT;
- break;
- }
- case SIOCDEVRESINSTATS:
- {
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
- DP( printk("%s: SIOCDEVRESINSTATS\n",dev->name); )
- lp->in_stats.all_rx_number = 0;
- lp->in_stats.bad_rx_number = 0;
- lp->in_stats.timeout_number = 0;
- lp->in_stats.all_tx_number = 0;
- lp->in_stats.resend_tx_number = 0;
- break;
- }
- case SIOCDEVGHWSTATE:
- {
- struct sbni_flags flags;
- flags.rxl = lp->rxl_curr;
- flags.rate = lp->csr1.rate;
- flags.fixed_rxl = (lp->rxl_delta == 0);
- flags.fixed_rate = 1;
- ifr->ifr_data = *(caddr_t*)&flags;
- DP( printk("%s: get flags (0x%02x)\n",dev->name, (unsigned char)ifr->ifr_data); )
- break;
- }
- case SIOCDEVSHWSTATE:
- {
- struct sbni_flags flags;
- DP( printk("%s: SIOCDEVSHWSTATE flags=0x%02x\n",dev->name, (unsigned char)ifr->ifr_data); )
- /* root only */
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
- flags = *(struct sbni_flags*)&ifr->ifr_data;
- if(flags.fixed_rxl)
- {
- lp->rxl_delta = 0;
- lp->rxl_curr = flags.rxl;
- }
- else
- {
- lp->rxl_delta = DEF_RXL_DELTA;
- lp->rxl_curr = DEF_RXL;
- }
- lp->csr1.rxl = rxl_tab[lp->rxl_curr];
- if(flags.fixed_rate)
- lp->csr1.rate = flags.rate;
- else
- lp->csr1.rate = DEF_RATE;
- /*
- * Don't be afraid...
- */
- outb(*(char*)(&lp->csr1) | PR_RES, dev->base_addr + CSR1);
-
- DP( printk("%s: set flags (0x%02x)\n receive level: %u, baud rate: %u\n",\
- dev->name, (unsigned char)ifr->ifr_data, (unsigned)lp->rxl_curr, (unsigned)lp->csr1.rate); )
- break;
+ switch( cmd ) {
+ case SIOCDEVGETINSTATS :
+ error = verify_area( VERIFY_WRITE, ifr->ifr_data,
+ sizeof(struct sbni_in_stats) );
+ if( !error )
+ copy_to_user( ifr->ifr_data, &nl->in_stats,
+ sizeof(struct sbni_in_stats) );
+ break;
+
+ case SIOCDEVRESINSTATS :
+ if( current->euid != 0 ) /* root only */
+ return -EPERM;
+ memset( &nl->in_stats, 0, sizeof(struct sbni_in_stats) );
+ break;
+
+ case SIOCDEVGHWSTATE :
+ flags.mac_addr = *(u32 *)(dev->dev_addr + 3);
+ flags.rate = nl->csr1.rate;
+ flags.slow_mode = (nl->state & FL_SLOW_MODE) != 0;
+ flags.rxl = nl->cur_rxl_index;
+ flags.fixed_rxl = nl->delta_rxl == 0;
+
+ error = verify_area( VERIFY_WRITE, ifr->ifr_data,
+ sizeof flags );
+ if( !error )
+ copy_to_user( ifr->ifr_data, &flags, sizeof flags );
+ break;
+
+ case SIOCDEVSHWSTATE :
+ if( current->euid != 0 ) /* root only */
+ return -EPERM;
+
+ spin_lock( &nl->lock );
+ flags = *(struct sbni_flags*) &ifr->ifr_data;
+ if( flags.fixed_rxl )
+ nl->delta_rxl = 0,
+ nl->cur_rxl_index = flags.rxl;
+ else
+ nl->delta_rxl = DEF_RXL_DELTA,
+ nl->cur_rxl_index = DEF_RXL;
+
+ nl->csr1.rxl = rxl_tab[ nl->cur_rxl_index ];
+ nl->csr1.rate = flags.rate;
+ outb( *(u8 *)&nl->csr1 | PR_RES, dev->base_addr + CSR1 );
+ spin_unlock( &nl->lock );
+ break;
+
+#ifdef CONFIG_SBNI_MULTILINE
+
+ case SIOCDEVENSLAVE :
+ if( current->euid != 0 ) /* root only */
+ return -EPERM;
+
+ if( (error = verify_area( VERIFY_READ, ifr->ifr_data,
+ sizeof slave_name )) != 0 )
+ return error;
+
+ copy_from_user( slave_name, ifr->ifr_data, sizeof slave_name );
+ slave_dev = dev_get_by_name( slave_name );
+ if( !slave_dev || !(slave_dev->flags & IFF_UP) ) {
+ printk( KERN_ERR "%s: trying to enslave non-active "
+ "device %s\n", dev->name, slave_name );
+ return -EPERM;
}
- case SIOCDEVENSLAVE:
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
- if(copy_from_user( tmpstr, ifr->ifr_data, 6))
- return -EFAULT;
- slave = dev_get_by_name(tmpstr);
- if(!(slave && slave->flags & IFF_UP && dev->flags & IFF_UP))
- {
- printk("%s: Both devices should be UP to enslave!\n",dev->name);
- if (slave)
- dev_put(slave);
- return -EINVAL;
- }
-
- if(slave)
- {
- if(!((dev->flags & IFF_SLAVE) || (slave->flags & IFF_SLAVE)))
- {
- /* drop queue*/
- sbni_drop_tx_queue(slave);
- slave->flags |= IFF_SLAVE;
- ((struct net_local *)(slave->priv))->m=dev;
- while(lp->next_lp) //tail it after last slave
- lp=lp->next_lp;
- lp->next_lp=slave->priv;
- lp=(struct net_local *)dev->priv;
- dev->flags |= IFF_MASTER;
- }
- else
- {
- printk("%s: one of devices is already slave!\n",dev->name);
- error = -EBUSY;
- }
- dev_put(slave);
- }
- else
- {
- printk("%s: can't find device %s to enslave\n",dev->name,ifr->ifr_data);
- return -ENOENT;
- }
- break;
-
- case SIOCDEVEMANSIPATE:
- if(!capable(CAP_NET_ADMIN))
- return -EPERM;
-
- if(dev->flags & IFF_SLAVE)
- {
- dev->flags &= ~IFF_SLAVE;
- /* exclude us from masters slavelist*/
- for(tlp=lp->m->priv;tlp->next_lp!=lp && tlp->next_lp;tlp=tlp->next_lp);
- if(tlp->next_lp)
- {
- tlp->next_lp = lp->next_lp;
- if(!((struct net_local *)lp->m->priv)->next_lp)
- {
- lp->m->flags &= ~IFF_MASTER;
- }
- lp->next_lp=NULL;
- lp->m=dev;
- }
- else
- {
- printk("%s: Ooops. drivers structure is mangled!\n",dev->name);
- return -EIO;
- }
- }
- else
- {
- printk("%s: isn't slave device!\n",dev->name);
- return -EINVAL;
- }
- break;
+ return enslave( dev, slave_dev );
+
+ case SIOCDEVEMANSIPATE :
+ if( current->euid != 0 ) /* root only */
+ return -EPERM;
+
+ return emancipate( dev );
+
+#endif /* CONFIG_SBNI_MULTILINE */
- default:
- DP( printk("%s: invalid ioctl: 0x%x\n",dev->name, cmd); )
- error = -EINVAL;
+ default :
+ return -EOPNOTSUPP;
}
- return (error);
-}
+ return error;
+}
-#ifdef CRCASM
+#ifdef CONFIG_SBNI_MULTILINE
-unsigned long calc_crc(char *mem, int len, unsigned initial)
+static int
+enslave( struct net_device *dev, struct net_device *slave_dev )
{
- unsigned crc, dummy_len;
- __asm__ (
- "xorl %%eax,%%eax\n\t"
- "1:\n\t"
- "lodsb\n\t"
- "xorb %%dl,%%al\n\t"
- "shrl $8,%%edx\n\t"
- "xorl (%%edi,%%eax,4),%%edx\n\t"
- "loop 1b"
- : "=d" (crc), "=c" (dummy_len)
- : "S" (mem), "D" (&crc32tab[0]), "1" (len), "0" (initial)
- : "eax"
- );
- return crc;
+ struct net_local *nl = (struct net_local *) dev->priv;
+ struct net_local *snl = (struct net_local *) slave_dev->priv;
+
+ if( nl->state & FL_SLAVE ) /* This isn't master or free device */
+ return -EBUSY;
+
+ if( snl->state & FL_SLAVE ) /* That was already enslaved */
+ return -EBUSY;
+
+ spin_lock( &nl->lock );
+ spin_lock( &snl->lock );
+
+ /* append to list */
+ snl->link = nl->link;
+ nl->link = slave_dev;
+ snl->master = dev;
+ snl->state |= FL_SLAVE;
+
+ /* Summary statistics of MultiLine operation will be stored
+ in master's counters */
+ memset( &snl->stats, 0, sizeof(struct net_device_stats) );
+ netif_stop_queue( slave_dev );
+ netif_wake_queue( dev ); /* Now we are able to transmit */
+
+ spin_unlock( &snl->lock );
+ spin_unlock( &nl->lock );
+ printk( KERN_NOTICE "%s: slave device (%s) attached.\n",
+ dev->name, slave_dev->name );
+ return 0;
}
-#else
-unsigned long calc_crc(char *mem, int len, unsigned initial)
+static int
+emancipate( struct net_device *dev )
{
- unsigned crc;
- crc = initial;
-
- for(;len;mem++,len--)
- {
- crc = CRC32(*mem, crc);
+ struct net_local *snl = (struct net_local *) dev->priv;
+ struct net_device *p = snl->master;
+ struct net_local *nl = (struct net_local *) p->priv;
+
+ if( !(snl->state & FL_SLAVE) )
+ return -EINVAL;
+
+ spin_lock( &nl->lock );
+ spin_lock( &snl->lock );
+ drop_xmit_queue( dev );
+
+ /* exclude from list */
+ for(;;) { /* must be in list */
+ struct net_local *t = (struct net_local *) p->priv;
+ if( t->link == dev ) {
+ t->link = snl->link;
+ break;
+ }
+ p = t->link;
}
- return(crc);
+
+ snl->link = NULL;
+ snl->master = dev;
+ snl->state &= ~FL_SLAVE;
+
+ netif_start_queue( dev );
+
+ spin_unlock( &snl->lock );
+ spin_unlock( &nl->lock );
+
+ dev_put( dev );
+ return 0;
}
-#endif /* CRCASM */
+
+#endif
+
+
+static struct net_device_stats *
+sbni_get_stats( struct net_device *dev )
+{
+ return &((struct net_local *) dev->priv)->stats;
+}
+
+
+static void
+set_multicast_list( struct net_device *dev )
+{
+ return; /* sbni always operate in promiscuos mode */
+}
+
+
#ifdef MODULE
-static int io[SBNI_MAX_NUM_CARDS] = { 0 };
-static int irq[SBNI_MAX_NUM_CARDS] = { 0 };
-static int rxl[SBNI_MAX_NUM_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
-static int baud[SBNI_MAX_NUM_CARDS] = { 0 };
-static long mac[SBNI_MAX_NUM_CARDS] = { 0 };
-
-MODULE_PARM(io, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(irq, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(rxl, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(baud, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-MODULE_PARM(mac, "1-" __MODULE_STRING(SBNI_MAX_NUM_CARDS) "i");
-
-
-static int sbniautodetect = -1;
-
-static struct net_device dev_sbni[SBNI_MAX_NUM_CARDS] = {
- {
- "sbni0",
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, sbni_probe
- },
- {
- "sbni1",
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, sbni_probe
- },
- {
- "sbni2",
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, sbni_probe
- },
- {
- "sbni3",
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, sbni_probe
- },
- {
- "sbni4",
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, sbni_probe
- },
- {
- "sbni5",
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, sbni_probe
- },
- {
- "sbni6",
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, sbni_probe
- },
- {
- "sbni7",
- 0, 0, 0, 0, /* memory */
- 0, 0, /* base, irq */
- 0, 0, 0, NULL, sbni_probe
- }
-};
+MODULE_PARM( io, "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM( irq, "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM( baud, "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM( rxl, "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
+MODULE_PARM( mac, "1-" __MODULE_STRING( SBNI_MAX_NUM_CARDS ) "i" );
-int init_module(void)
+MODULE_PARM( skip_pci_probe, "i" );
+
+
+int
+init_module( void )
{
- int devices = 0;
- int installed = 0;
- int i;
+ struct net_device *dev;
- /* My simple plug for this huge init_module. "XenON */
-
- if(sbniautodetect != -1)
- {
- /* Autodetect mode */
- printk("sbni: Autodetect mode (not recommended!) ...\n");
- if(!sbniautodetect)
- sbniautodetect=SBNI_MAX_NUM_CARDS;
- printk("Trying to find %d SBNI cards...\n", sbniautodetect);
- if(sbniautodetect > SBNI_MAX_NUM_CARDS)
- {
- sbniautodetect = SBNI_MAX_NUM_CARDS;
- printk("sbni: You want to detect too many cards. Truncated to %d\n", SBNI_MAX_NUM_CARDS);
+ while( num < SBNI_MAX_NUM_CARDS ) {
+ if( !(dev = kmalloc(sizeof(struct net_device), GFP_KERNEL)) ){
+ printk( KERN_ERR "sbni: unable to allocate device!\n" );
+ return -ENOMEM;
}
- for(i = 0; i < sbniautodetect; i++)
- {
- if(!register_netdev(&dev_sbni[i]))
- installed++;
+
+ memset( dev, 0, sizeof(struct net_device) );
+ sprintf( dev->name, "sbni%d", num );
+
+ dev->init = sbni_probe;
+ if( register_netdev( dev ) ) {
+ kfree( dev );
+ break;
}
- if(installed)
- return 0;
- else
- return -EIO;
- }
-
- /* Manual mode */
- for(i = 0; i < SBNI_MAX_NUM_CARDS; i++)
- {
- if((io[i] != 0) || (irq[i] != 0))
- devices++;
}
- for(i = 0; i < devices; i++)
- {
- dev_sbni[i].irq = irq[i];
- dev_sbni[i].base_addr = io[i];
- def_rxl = rxl[i];
- def_baud = baud[i];
- def_mac = mac[i];
- if(register_netdev(&dev_sbni[i]))
- printk("sbni: card not found!\n");
- else
- installed++;
- }
- if(installed)
- return 0;
- else
- return -EIO;
+
+ return *sbni_cards ? 0 : -ENODEV;
}
-void cleanup_module(void)
+void
+cleanup_module( void )
{
- int i;
- for(i = 0; i < 4; i++)
- {
- if(dev_sbni[i].priv)
- {
- free_irq(dev_sbni[i].irq, &dev_sbni[i]);
- release_region(dev_sbni[i].base_addr, SBNI_IO_EXTENT);
- unregister_netdev(&dev_sbni[i]);
- kfree(dev_sbni[i].priv);
- dev_sbni[i].priv = NULL;
+ struct net_device *dev;
+ int num;
+
+ /* No need to check MOD_IN_USE, as sys_delete_module( ) checks. */
+ for( num = 0; num < SBNI_MAX_NUM_CARDS; ++num )
+ if( (dev = sbni_cards[ num ]) != NULL ) {
+ unregister_netdev( dev );
+ release_region( dev->base_addr, SBNI_IO_EXTENT );
+ kfree( dev->priv );
+ kfree( dev );
}
+}
+
+#else /* MODULE */
+
+void __init
+sbni_setup( char *p )
+{
+ int n, parm;
+
+ if( *p++ != '(' )
+ goto bad_param;
+
+ for( n = 0, parm = 0; *p && n < 8; ) {
+ (*dest[ parm ])[ n ] = simple_strtol( p, &p, 0 );
+ if( !*p || *p == ')' )
+ return;
+ if( *p == ';' )
+ ++p, ++n, parm = 0;
+ else if( *p++ != ',' )
+ break;
+ else
+ if( ++parm >= 5 )
+ break;
}
+bad_param:
+ printk( KERN_ERR "Error in sbni kernel parameter!\n" );
+}
+
+__setup( "sbni=", sbni_setup );
+
+#endif /* MODULE */
+
+/* -------------------------------------------------------------------------- */
+
+#ifdef ASM_CRC
+
+static u32
+calc_crc32( u32 crc, u8 *p, u32 len )
+{
+ register u32 _crc __asm ( "ax" );
+ _crc = crc;
+
+ __asm __volatile (
+ "xorl %%ebx, %%ebx\n"
+ "movl %1, %%esi\n"
+ "movl %2, %%ecx\n"
+ "movl $crc32tab, %%edi\n"
+ "shrl $2, %%ecx\n"
+ "jz 1f\n"
+
+ ".align 4\n"
+ "0:\n"
+ "movb %%al, %%bl\n"
+ "movl (%%esi), %%edx\n"
+ "shrl $8, %%eax\n"
+ "xorb %%dl, %%bl\n"
+ "shrl $8, %%edx\n"
+ "xorl (%%edi,%%ebx,4), %%eax\n"
+
+ "movb %%al, %%bl\n"
+ "shrl $8, %%eax\n"
+ "xorb %%dl, %%bl\n"
+ "shrl $8, %%edx\n"
+ "xorl (%%edi,%%ebx,4), %%eax\n"
+
+ "movb %%al, %%bl\n"
+ "shrl $8, %%eax\n"
+ "xorb %%dl, %%bl\n"
+ "movb %%dh, %%dl\n"
+ "xorl (%%edi,%%ebx,4), %%eax\n"
+
+ "movb %%al, %%bl\n"
+ "shrl $8, %%eax\n"
+ "xorb %%dl, %%bl\n"
+ "addl $4, %%esi\n"
+ "xorl (%%edi,%%ebx,4), %%eax\n"
+
+ "decl %%ecx\n"
+ "jnz 0b\n"
+
+ "1:\n"
+ "movl %2, %%ecx\n"
+ "andl $3, %%ecx\n"
+ "jz 2f\n"
+
+ "movb %%al, %%bl\n"
+ "shrl $8, %%eax\n"
+ "xorb (%%esi), %%bl\n"
+ "xorl (%%edi,%%ebx,4), %%eax\n"
+
+ "decl %%ecx\n"
+ "jz 2f\n"
+
+ "movb %%al, %%bl\n"
+ "shrl $8, %%eax\n"
+ "xorb 1(%%esi), %%bl\n"
+ "xorl (%%edi,%%ebx,4), %%eax\n"
+
+ "decl %%ecx\n"
+ "jz 2f\n"
+
+ "movb %%al, %%bl\n"
+ "shrl $8, %%eax\n"
+ "xorb 2(%%esi), %%bl\n"
+ "xorl (%%edi,%%ebx,4), %%eax\n"
+ "2:\n"
+ :
+ : "a" (_crc), "g" (p), "g" (len)
+ : "ax", "bx", "cx", "dx", "si", "di"
+ );
+
+ return _crc;
}
-#endif /* MODULE */
+
+#else /* ASM_CRC */
+
+static u32
+calc_crc32( u32 crc, u8 *p, u32 len )
+{
+ while( len-- )
+ crc = CRC32( *p++, crc );
+
+ return crc;
+}
+
+#endif /* ASM_CRC */
+
+
+static u32 crc32tab[] __attribute__ ((aligned(8))) = {
+ 0xD202EF8D, 0xA505DF1B, 0x3C0C8EA1, 0x4B0BBE37,
+ 0xD56F2B94, 0xA2681B02, 0x3B614AB8, 0x4C667A2E,
+ 0xDCD967BF, 0xABDE5729, 0x32D70693, 0x45D03605,
+ 0xDBB4A3A6, 0xACB39330, 0x35BAC28A, 0x42BDF21C,
+ 0xCFB5FFE9, 0xB8B2CF7F, 0x21BB9EC5, 0x56BCAE53,
+ 0xC8D83BF0, 0xBFDF0B66, 0x26D65ADC, 0x51D16A4A,
+ 0xC16E77DB, 0xB669474D, 0x2F6016F7, 0x58672661,
+ 0xC603B3C2, 0xB1048354, 0x280DD2EE, 0x5F0AE278,
+ 0xE96CCF45, 0x9E6BFFD3, 0x0762AE69, 0x70659EFF,
+ 0xEE010B5C, 0x99063BCA, 0x000F6A70, 0x77085AE6,
+ 0xE7B74777, 0x90B077E1, 0x09B9265B, 0x7EBE16CD,
+ 0xE0DA836E, 0x97DDB3F8, 0x0ED4E242, 0x79D3D2D4,
+ 0xF4DBDF21, 0x83DCEFB7, 0x1AD5BE0D, 0x6DD28E9B,
+ 0xF3B61B38, 0x84B12BAE, 0x1DB87A14, 0x6ABF4A82,
+ 0xFA005713, 0x8D076785, 0x140E363F, 0x630906A9,
+ 0xFD6D930A, 0x8A6AA39C, 0x1363F226, 0x6464C2B0,
+ 0xA4DEAE1D, 0xD3D99E8B, 0x4AD0CF31, 0x3DD7FFA7,
+ 0xA3B36A04, 0xD4B45A92, 0x4DBD0B28, 0x3ABA3BBE,
+ 0xAA05262F, 0xDD0216B9, 0x440B4703, 0x330C7795,
+ 0xAD68E236, 0xDA6FD2A0, 0x4366831A, 0x3461B38C,
+ 0xB969BE79, 0xCE6E8EEF, 0x5767DF55, 0x2060EFC3,
+ 0xBE047A60, 0xC9034AF6, 0x500A1B4C, 0x270D2BDA,
+ 0xB7B2364B, 0xC0B506DD, 0x59BC5767, 0x2EBB67F1,
+ 0xB0DFF252, 0xC7D8C2C4, 0x5ED1937E, 0x29D6A3E8,
+ 0x9FB08ED5, 0xE8B7BE43, 0x71BEEFF9, 0x06B9DF6F,
+ 0x98DD4ACC, 0xEFDA7A5A, 0x76D32BE0, 0x01D41B76,
+ 0x916B06E7, 0xE66C3671, 0x7F6567CB, 0x0862575D,
+ 0x9606C2FE, 0xE101F268, 0x7808A3D2, 0x0F0F9344,
+ 0x82079EB1, 0xF500AE27, 0x6C09FF9D, 0x1B0ECF0B,
+ 0x856A5AA8, 0xF26D6A3E, 0x6B643B84, 0x1C630B12,
+ 0x8CDC1683, 0xFBDB2615, 0x62D277AF, 0x15D54739,
+ 0x8BB1D29A, 0xFCB6E20C, 0x65BFB3B6, 0x12B88320,
+ 0x3FBA6CAD, 0x48BD5C3B, 0xD1B40D81, 0xA6B33D17,
+ 0x38D7A8B4, 0x4FD09822, 0xD6D9C998, 0xA1DEF90E,
+ 0x3161E49F, 0x4666D409, 0xDF6F85B3, 0xA868B525,
+ 0x360C2086, 0x410B1010, 0xD80241AA, 0xAF05713C,
+ 0x220D7CC9, 0x550A4C5F, 0xCC031DE5, 0xBB042D73,
+ 0x2560B8D0, 0x52678846, 0xCB6ED9FC, 0xBC69E96A,
+ 0x2CD6F4FB, 0x5BD1C46D, 0xC2D895D7, 0xB5DFA541,
+ 0x2BBB30E2, 0x5CBC0074, 0xC5B551CE, 0xB2B26158,
+ 0x04D44C65, 0x73D37CF3, 0xEADA2D49, 0x9DDD1DDF,
+ 0x03B9887C, 0x74BEB8EA, 0xEDB7E950, 0x9AB0D9C6,
+ 0x0A0FC457, 0x7D08F4C1, 0xE401A57B, 0x930695ED,
+ 0x0D62004E, 0x7A6530D8, 0xE36C6162, 0x946B51F4,
+ 0x19635C01, 0x6E646C97, 0xF76D3D2D, 0x806A0DBB,
+ 0x1E0E9818, 0x6909A88E, 0xF000F934, 0x8707C9A2,
+ 0x17B8D433, 0x60BFE4A5, 0xF9B6B51F, 0x8EB18589,
+ 0x10D5102A, 0x67D220BC, 0xFEDB7106, 0x89DC4190,
+ 0x49662D3D, 0x3E611DAB, 0xA7684C11, 0xD06F7C87,
+ 0x4E0BE924, 0x390CD9B2, 0xA0058808, 0xD702B89E,
+ 0x47BDA50F, 0x30BA9599, 0xA9B3C423, 0xDEB4F4B5,
+ 0x40D06116, 0x37D75180, 0xAEDE003A, 0xD9D930AC,
+ 0x54D13D59, 0x23D60DCF, 0xBADF5C75, 0xCDD86CE3,
+ 0x53BCF940, 0x24BBC9D6, 0xBDB2986C, 0xCAB5A8FA,
+ 0x5A0AB56B, 0x2D0D85FD, 0xB404D447, 0xC303E4D1,
+ 0x5D677172, 0x2A6041E4, 0xB369105E, 0xC46E20C8,
+ 0x72080DF5, 0x050F3D63, 0x9C066CD9, 0xEB015C4F,
+ 0x7565C9EC, 0x0262F97A, 0x9B6BA8C0, 0xEC6C9856,
+ 0x7CD385C7, 0x0BD4B551, 0x92DDE4EB, 0xE5DAD47D,
+ 0x7BBE41DE, 0x0CB97148, 0x95B020F2, 0xE2B71064,
+ 0x6FBF1D91, 0x18B82D07, 0x81B17CBD, 0xF6B64C2B,
+ 0x68D2D988, 0x1FD5E91E, 0x86DCB8A4, 0xF1DB8832,
+ 0x616495A3, 0x1663A535, 0x8F6AF48F, 0xF86DC419,
+ 0x660951BA, 0x110E612C, 0x88073096, 0xFF000000
+};
+
-/*
- * sbni.h - header file for sbni linux device driver
- *
- * Copyright (C) 1999 Granch ltd., Yaroslav Polyakov (xenon@granch.ru).
- *
- */
-
-/*
- * SBNI12 definitions
- *
- * Revision 2.0.0 1997/08/27
- * Initial revision
- *
- * Revision 2.1.0 1999/04/26
- * dev_priv structure changed to support balancing and some other features.
- *
+/* sbni.h: definitions for a Granch SBNI12 driver, version 5.0.0
+ * Written 2001 Denis I.Timofeev (timofeev@granch.ru)
+ * This file is distributed under the GNU GPL
*/
-#ifndef __SBNI_H
-#define __SBNI_H
-
-#define SBNI_DEBUG 0
+#ifndef SBNI_H
+#define SBNI_H
#if SBNI_DEBUG
#define DP( A ) A
#define DP( A )
#endif
-typedef unsigned char BOOLEAN;
-#define TRUE 1
-#define FALSE 0
+/* We don't have official vendor id yet... */
+#define SBNI_PCI_VENDOR 0x55
+#define SBNI_PCI_DEVICE 0x9f
-#define SBNI_IO_EXTENT 0x4
-#define SB_MAX_BUFFER_ARRAY 1023
+#define ISA_MODE 0x00
+#define PCI_MODE 0x01
-#define CSR0 0
-#define CSR1 1
+#define SBNI_IO_EXTENT 4
-#define DAT 2
+enum sbni_reg {
+ CSR0 = 0,
+ CSR1 = 1,
+ DAT = 2
+};
/* CSR0 mapping */
-#define BU_EMP (1 << 1) /* r z */
-#define RC_CHK (1 << 2) /* rw */
-#define CT_ZER (1 << 3) /* w */
-#define TR_REQ (1 << 4) /* rwz* */
+enum {
+ BU_EMP = 0x02,
+ RC_CHK = 0x04,
+ CT_ZER = 0x08,
+ TR_REQ = 0x10,
+ TR_RDY = 0x20,
+ EN_INT = 0x40,
+ RC_RDY = 0x80
+};
-#define TR_RDY (1 << 5) /* r z */
-#define EN_INT (1 << 6) /* rwz* */
-#define RC_RDY (1 << 7) /* r z */
/* CSR1 mapping */
-#define PR_RES (1 << 7) /* w */
+#define PR_RES 0x80
struct sbni_csr1 {
- unsigned rxl:5;
- unsigned rate:2;
- unsigned:1;
+ unsigned rxl : 5;
+ unsigned rate : 2;
+ unsigned : 1;
};
-#define DEF_RXL_DELTA -1
-#define DEF_RXL 0xf
-#define DEF_RATE 0
-#define DEF_FRAME_LEN (1023 - 14 - 9)
-
-#ifdef MODULE
-
-#define SBNI_MAX_NUM_CARDS 8
-#define SBNI_MAX_SLAVES 8
-
-
-#endif /* MODULE */
-
-#define SBNI_SIG 0x5a
-
-#define SB_ETHER_MIN_LEN 60
-
-#define SB_FILLING_CHAR (unsigned char)0x00
-#define TR_ERROR_COUNT 32
-#define CHANGE_LEVEL_START_TICKS 4
-#define SBNI_INTERNAL_QUEUE_SIZE 10 /* 100 ? */
-
-#define PACKET_FIRST_FRAME (unsigned short)0x8000
-#define RECEIVE_FRAME_RESEND (unsigned short)0x0800
-#define PACKET_RESEND 0x4000
-#define PACKET_SEND_OK 0x3000
-#define PACKET_LEN_MASK (unsigned short)0x03ff
-#define PACKET_INF_MASK (unsigned short)0x7000
-
-#define ETHER_ADDR_LEN 6
-
-#define SBNI_TIMEOUT HZ/10 /* ticks to wait for pong or packet */
- /* sbni watchdog called SBNI_HZ times per sec. */
-
-struct sbni_in_stats {
- unsigned int all_rx_number;
- unsigned int bad_rx_number;
- unsigned int timeout_number;
- unsigned int all_tx_number;
- unsigned int resend_tx_number;
+/* fields in frame header */
+#define FRAME_ACK_MASK (unsigned short)0x7000
+#define FRAME_LEN_MASK (unsigned short)0x03FF
+#define FRAME_FIRST (unsigned short)0x8000
+#define FRAME_RETRY (unsigned short)0x0800
+
+#define FRAME_SENT_BAD (unsigned short)0x4000
+#define FRAME_SENT_OK (unsigned short)0x3000
+
+
+/* state flags */
+enum {
+ FL_WAIT_ACK = 0x01,
+ FL_NEED_RESEND = 0x02,
+ FL_PREV_OK = 0x04,
+ FL_SLOW_MODE = 0x08,
+ FL_SECONDARY = 0x10,
+#ifdef CONFIG_SBNI_MULTILINE
+ FL_SLAVE = 0x20,
+#endif
+ FL_LINE_DOWN = 0x40
};
-/*
- * Board-specific info in dev->priv.
- */
-struct net_local {
- struct net_device_stats stats;
-
- struct timer_list watchdog;
- unsigned int realframelen; /* the current size of the SB-frame */
- unsigned int eth_trans_buffer_len; /* tx buffer length */
- unsigned int outpos;
- unsigned int inppos;
- unsigned int frame_len; /* The set SB-frame size */
- unsigned int tr_err;
- unsigned int timer_ticks;
- BOOLEAN last_receive_OK;
- BOOLEAN tr_resend;
-
- unsigned char wait_frame_number;
- unsigned char eth_trans_buffer[1520]; /* tx buffer */
- unsigned char HSCounter; /* Reserved field */
- unsigned char eth_rcv_buffer[2600]; /* rx buffer */
- struct sbni_csr1 csr1;
- /* Internal Statistics */
- struct sbni_in_stats in_stats;
-
- int rxl_curr; /* current receive level value [0..0xf] */
- int rxl_delta; /* receive level delta (+1, -1)
- rxl_delta == 0 - receive level
- autodetection
- disabled */
- unsigned int ok_curr; /* current ok frames received */
- unsigned int ok_prev; /* previous ok frames received */
- unsigned int timeout_rxl;
-
- struct sk_buff_head queue;
- struct sk_buff *currframe;
- BOOLEAN waitack;
-
- struct net_device *m; /* master */
- struct net_device *me; /* me */
- struct net_local *next_lp; /* next lp */
-
- int carrier;
-
- spinlock_t lock;
+enum {
+ DEFAULT_IOBASEADDR = 0x210,
+ DEFAULT_INTERRUPTNUMBER = 5,
+ DEFAULT_RATE = 0,
+ DEFAULT_FRAME_LEN = 1012
};
+#define DEF_RXL_DELTA -1
+#define DEF_RXL 0xf
-struct sbni_hard_header {
-
- /* internal sbni stuff */
- unsigned int crc; /* 4 */
- unsigned short packetlen; /* 2 */
- unsigned char number; /* 1 */
- unsigned char reserv; /* 1 */
+#define SBNI_SIG 0x5a
- /* 8 */
+#define SBNI_MIN_LEN 60 /* Shortest Ethernet frame without FCS */
+#define SBNI_MAX_FRAME 1023
+#define ETHER_MAX_LEN 1518
- /* ethernet stuff */
- unsigned char h_dest[ETH_ALEN]; /* destination eth addr */
- unsigned char h_source[ETH_ALEN]; /* source ether addr */
- unsigned short h_proto; /* packet type ID field */
- /* +14 */
- /* 22 */
+#define SBNI_TIMEOUT (HZ/10)
-};
+#define TR_ERROR_COUNT 32
+#define CHANGE_LEVEL_START_TICKS 4
-#define SBNI_HH_SZ 22
+#define SBNI_MAX_NUM_CARDS 16
-struct sbni_flags {
- unsigned rxl:4;
- unsigned rate:2;
- unsigned fixed_rxl:1;
- unsigned fixed_rate:1;
+/* internal SBNI-specific statistics */
+struct sbni_in_stats {
+ u32 all_rx_number;
+ u32 bad_rx_number;
+ u32 timeout_number;
+ u32 all_tx_number;
+ u32 resend_tx_number;
};
-#define RCV_NO 0
-#define RCV_OK 1
-#define RCV_WR 2
-
-
+/* SBNI ioctl params */
#define SIOCDEVGETINSTATS SIOCDEVPRIVATE
#define SIOCDEVRESINSTATS SIOCDEVPRIVATE+1
#define SIOCDEVGHWSTATE SIOCDEVPRIVATE+2
#define SIOCDEVEMANSIPATE SIOCDEVPRIVATE+5
-#endif /* __SBNI_H */
+/* data packet for SIOCDEVGHWSTATE/SIOCDEVSHWSTATE ioctl requests */
+struct sbni_flags {
+ u32 rxl : 4;
+ u32 rate : 2;
+ u32 fixed_rxl : 1;
+ u32 slow_mode : 1;
+ u32 mac_addr : 24;
+};
+
+/*
+ * CRC-32 stuff
+ */
+#define CRC32(c,crc) (crc32tab[((size_t)(crc) ^ (c)) & 0xff] ^ (((crc) >> 8) & 0x00FFFFFF))
+ /* CRC generator 0xEDB88320 */
+ /* CRC remainder 0x2144DF1C */
+ /* CRC initial value 0x00000000 */
+#define CRC32_REMAINDER 0x2144DF1C
+#define CRC32_INITIAL 0x00000000
+
+#ifndef __initdata
+#define __initdata
+#endif
+
+#define min( x, y ) ( (x) < (y) ? (x) : (y) )
+
+#endif
+
#include <pcmcia/ss.h>
#include <pcmcia/cs.h>
+#include <linux/isapnp.h>
+
/* ISA-bus controllers */
#include "i82365.h"
#include "cirrus.h"
#ifdef CONFIG_ISA
+#if defined(CONFIG_ISAPNP) || (defined(CONFIG_ISAPNP_MODULE) && defined(MODULE))
+#define I82365_ISAPNP
+#endif
+
+#ifdef I82365_ISAPNP
+static struct isapnp_device_id id_table[] __initdata = {
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+ ISAPNP_FUNCTION(0x0e00), (unsigned long) "Intel 82365-Compatible" },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+ ISAPNP_FUNCTION(0x0e01), (unsigned long) "Cirrus Logic CL-PD6720" },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P', 'N', 'P'),
+ ISAPNP_FUNCTION(0x0e02), (unsigned long) "VLSI VL82C146" },
+ { 0 }
+};
+MODULE_DEVICE_TABLE(isapnp, id_table);
+
+static struct pci_dev *i82365_pnpdev;
+#endif
+
static void __init isa_probe(void)
{
int i, j, sock, k, ns, id;
ioaddr_t port;
+#ifdef I82365_ISAPNP
+ struct isapnp_device_id *devid;
+ struct pci_dev *dev;
+
+ for (devid = id_table; devid->vendor; devid++) {
+ if ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, NULL))) {
+ printk("ISAPNP ");
+
+ if (dev->prepare && dev->prepare(dev) < 0) {
+ printk("prepare failed\n");
+ break;
+ }
+
+ if (dev->activate && dev->activate(dev) < 0) {
+ printk("activate failed\n");
+ break;
+ }
+
+ if ((i365_base = pci_resource_start(dev, 0))) {
+ printk("no resources ?\n");
+ break;
+ }
+ i82365_pnpdev = dev;
+ break;
+ }
+ }
+#endif
if (check_region(i365_base, 2) != 0) {
if (sockets == 0)
i365_set(i, I365_CSCINT, 0);
release_region(socket[i].ioaddr, 2);
}
+#if defined(CONFIG_ISA) && defined(I82365_ISAPNP)
+ if (i82365_pnpdev && i82365_pnpdev->deactivate)
+ i82365_pnpdev->deactivate(i82365_pnpdev);
+#endif
} /* exit_i82365 */
module_init(init_i82365);
dep_tristate ' ISA Plug and Play support' CONFIG_ISAPNP $CONFIG_PNP
+if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+ dep_bool ' PNPBIOS support (EXPERIMENTAL)' CONFIG_PNPBIOS $CONFIG_PNP
+fi
+
endmenu
comment 'S/390 character device drivers'
-tristate 'Support for locally attached 3270 tubes' CONFIG_3270
-if [ "$CONFIG_3270" = "y" ]; then
- bool 'Support for console on 3270 line mode terminal' CONFIG_3270_CONSOLE
+tristate 'Support for locally attached 3270 tubes' CONFIG_TN3270
+if [ "$CONFIG_TN3270" = "y" ]; then
+ bool 'Support for console on 3270 line mode terminal' CONFIG_TN3270_CONSOLE
fi
-if [ "$CONFIG_3270_CONSOLE" != "y" ]; then
- bool 'Support for 3215 line mode terminal' CONFIG_3215
- if [ "$CONFIG_3215" = "y" ]; then
- bool 'Support for console on 3215 line mode terminal' CONFIG_3215_CONSOLE
- fi
+bool 'Support for 3215 line mode terminal' CONFIG_TN3215
+if [ "$CONFIG_TN3215" = "y" ]; then
+ bool 'Support for console on 3215 line mode terminal' CONFIG_TN3215_CONSOLE
fi
bool 'Support for HWC line mode terminal' CONFIG_HWC
if [ "$CONFIG_HWC" = "y" ]; then
- bool 'console on HWC line mode terminal' CONFIG_HWC_CONSOLE
+ bool ' console on HWC line mode terminal' CONFIG_HWC_CONSOLE
+ tristate ' Control-Program Identification' CONFIG_HWC_CPI
fi
tristate 'S/390 tape device support' CONFIG_S390_TAPE
if [ "$CONFIG_S390_TAPE" != "n" ]; then
if [ "$CONFIG_NETDEVICES" = "y" ]; then
tristate 'Dummy net driver support' CONFIG_DUMMY
+ tristate 'Bonding driver support' CONFIG_BONDING
+ tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
+ tristate 'Universal TUN/TAP device driver support' CONFIG_TUN
bool 'Ethernet (10 or 100Mbit)' CONFIG_NET_ETHERNET
bool 'Token Ring driver support' CONFIG_TR
bool 'FDDI driver support' CONFIG_FDDI
comment 'S/390 network device drivers'
- bool 'Channel Device Configuration (Temporary Option)' CONFIG_CHANDEV
+ bool 'Channel Device Configuration' CONFIG_CHANDEV
+ if [ "$CONFIG_CHANDEV" = "y" ]; then
+ define_bool CONFIG_HOTPLUG y
+ fi
+
tristate 'CTC device support' CONFIG_CTC
tristate 'IUCV device support (VM only)' CONFIG_IUCV
fi
subdir-y := block char misc net
subdir-m := $(subdir-y)
-obj-y := $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o)
-obj-y += s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
+obj-y := s390io.o s390mach.o s390dyn.o idals.o ccwcache.o
export-objs += ccwcache.o idals.o s390dyn.o s390io.o
+obj-y += $(foreach dir,$(subdir-y),$(dir)/s390-$(dir).o)
+
include $(TOPDIR)/Rules.make
#include <linux/kernel.h>
#include <linux/tqueue.h>
#include <linux/timer.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/genhd.h>
#include <linux/hdreg.h>
#include <linux/interrupt.h>
#include "dasd_diag.h"
#endif /* CONFIG_DASD_DIAG */
+/* SECTION: exported variables of dasd.c */
+
+debug_info_t *dasd_debug_area;
+
MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");
MODULE_DESCRIPTION ("Linux on S/390 DASD device driver,"
" Copyright 2000 IBM Corporation");
#include <linux/kernel.h>
#include <asm/debug.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/blk.h>
#include <asm/ccwcache.h>
#include <linux/kernel.h>
#include <asm/debug.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/blk.h>
#include <asm/ccwcache.h>
#include <linux/kernel.h>
#include <asm/debug.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/hdreg.h> /* HDIO_GETGEO */
#include <linux/blk.h>
#include <asm/ccwcache.h>
#endif /* V24 */
#include <linux/sched.h>
#include <linux/kernel.h> /* printk() */
-#include <linux/malloc.h> /* kmalloc() */
+#include <linux/slab.h> /* kmalloc() */
#if (XPRAM_VERSION == 24)
# include <linux/devfs_fs_kernel.h>
#endif /* V24 */
#if (XPRAM_VERSION == 24)
#define MAJOR_NR xpram_major /* force definitions on in blk.h */
int xpram_major; /* must be declared before including blk.h */
+devfs_handle_t xpram_devfs_handle;
#define DEVICE_NR(device) MINOR(device) /* xpram has no partition bits */
#define DEVICE_NAME "xpram" /* name for messaging */
#elif (XPRAM_VERSION == 24)
result = devfs_register_blkdev(xpram_major, "xpram", &xpram_devops);
#endif /* V22/V24 */
-
if (result < 0) {
PRINT_ERR("Can't get major %d\n",xpram_major);
PRINT_ERR("Giving up xpram\n");
return result;
}
+#if (XPRAM_VERSION == 24)
+ xpram_devfs_handle = devfs_mk_dir (NULL, "slram", NULL);
+ devfs_register_series (xpram_devfs_handle, "%u", XPRAM_MAX_DEVS,
+ DEVFS_FL_DEFAULT, XPRAM_MAJOR, 0,
+ S_IFBLK | S_IRUSR | S_IWUSR,
+ &xpram_devops, NULL);
+#endif /* V22/V24 */
if (xpram_major == 0) xpram_major = result; /* dynamic */
major = xpram_major; /* Use `major' later on to save typing */
kfree(xpram_offsets);
/* finally, the usual cleanup */
+#if (XPRAM_VERSION == 22)
unregister_blkdev(major, "xpram");
+#elif (XPRAM_VERSION == 24)
+ devfs_unregister(xpram_devfs_handle);
+ if (devfs_unregister_blkdev(MAJOR_NR, "xpram"))
+ printk(KERN_WARNING "xpram: cannot unregister blkdev\n");
+#endif /* V22/V24 */
kfree(xpram_devices);
}
*/
#include <linux/module.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/version.h>
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
-# Makefile for the S/390 supported character devices
#
-# 4 January 2001 Richard Hitt
-# Modeled after similar files of Michael Elizabeth Chastain
-# Rewritten to use lists instead of if-statements.
+# S/390 character devices
+#
-O_TARGET := s390-char.o
+O_TARGET := s390-char.o
-export-objs :=
list-multi := tub3270.o tape390.o
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
+tub3270-objs := tuball.o tubfs.o tubtty.o \
+ tubttyaid.o tubttybld.o tubttyscl.o \
+ tubttyrcl.o tubttysiz.o
-tub3270-objs := tuball.o tubfs.o tubtty.o \
- tubttyaid.o tubttybld.o tubttyrcl.o \
- tubttyscl.o tubttysiz.o
+tape390-$(CONFIG_S390_TAPE_CHAR) += tapechar.o
+tape390-$(CONFIG_S390_TAPE_BLOCK) += tapeblock.o
+tape390-$(CONFIG_S390_TAPE_3480) += tape3480.o tape34xx.o
+tape390-$(CONFIG_S390_TAPE_3490) += tape3490.o tape34xx.o
+tape390-objs := tape.o $(sort $(tape390-y))
obj-y += ctrlchar.o
-obj-$(CONFIG_3215_CONSOLE) += con3215.o
-obj-$(CONFIG_HWC) += hwc_con.o hwc_rw.o hwc_tty.o
-obj-$(CONFIG_3270) += tub3270.o
-
-tape-y := tape.o
-tape-$(CONFIG_S390_TAPE_CHAR) += tapechar.o
-tape-$(CONFIG_S390_TAPE_BLOCK) += tapeblock.o
-tape-$(CONFIG_S390_TAPE_3480) += tape3480.o tape34xx.o
-tape-$(CONFIG_S390_TAPE_3490) += tape3490.o tape34xx.o
-tape390-objs := $(sort $(tape-y))
-obj-$(CONFIG_S390_TAPE) += tape390.o
-
-# Hand off to Rules.make.
+obj-$(CONFIG_TN3215) += con3215.o
+obj-$(CONFIG_HWC) += hwc_con.o hwc_rw.o hwc_tty.o
+obj-$(CONFIG_HWC_CPI) += hwc_cpi.o
+obj-$(CONFIG_TN3270) += tub3270.o
+obj-$(CONFIG_S390_TAPE) += tape390.o
include $(TOPDIR)/Rules.make
-tub3270.o: $(tub3270-objs)
+tub3270.o: $(tub3270-objs)
$(LD) -r -o $@ $(tub3270-objs)
-tape390.o: $(tape390-objs)
+tape390.o: $(tape390-objs)
$(LD) -r -o $@ $(tape390-objs)
+
#include <asm/delay.h>
#include <asm/cpcmd.h>
#include <asm/irq.h>
+#include <asm/setup.h>
#include "ctrlchar.h"
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#endif
-static int __init con3215_setup(char *str)
-{
- int vdev;
-
- vdev = simple_strtoul(str,&str,0);
- if (vdev >= 0 && vdev < 65536)
- raw3215_condevice = vdev;
- return 1;
-}
-
-__setup("condev=", con3215_setup);
-
/*
* Get a request structure from the free list
*/
while (count <= number && irq != -ENODEV) {
if (get_dev_info(irq, &dinfo) == -ENODEV)
break;
- if (dinfo.devno == raw3215_condevice ||
+ if (dinfo.devno == console_device ||
dinfo.sid_data.cu_type == 0x3215) {
count++;
if (count > number)
return -1; /* console not found */
}
-#ifdef CONFIG_3215_CONSOLE
+#ifdef CONFIG_TN3215_CONSOLE
/*
* Write a string to the 3215 console
{
raw3215_info *raw;
raw3215_req *req;
+ int irq;
int i;
- if (!MACHINE_IS_VM && !MACHINE_IS_P390)
- return;
- if (MACHINE_IS_VM) {
- cpcmd("TERM CONMODE 3215", NULL, 0);
- cpcmd("TERM AUTOCR OFF", NULL, 0);
- }
+ /* Check if 3215 is to be the console */
+ if (!CONSOLE_IS_3215)
+ return;
+ irq = raw3215_find_dev(0);
+
+ /* Set the console mode for VM */
+ if (MACHINE_IS_VM) {
+ cpcmd("TERM CONMODE 3215", NULL, 0);
+ cpcmd("TERM AUTOCR OFF", NULL, 0);
+ }
/* allocate 3215 request structures */
raw3215_freelist = NULL;
ctrlchar_init();
-#ifdef CONFIG_3215_CONSOLE
+#ifdef CONFIG_TN3215_CONSOLE
raw3215[0] = raw = (raw3215_info *)
alloc_bootmem_low(sizeof(raw3215_info));
memset(raw, 0, sizeof(raw3215_info));
*/
void __init tty3215_init(void)
{
- if (!MACHINE_IS_VM && !MACHINE_IS_P390)
- return;
/*
* Initialize the tty_driver structure
* Entries in tty3215_driver that are NOT initialized:
/*
- * drivers/s390/char/controlchar.c
+ * drivers/s390/char/ctrlchar.c
* Unified handling of special chars.
*
* Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
/*
- * drivers/s390/char/controlchar.c
+ * drivers/s390/char/ctrlchar.c
* Unified handling of special chars.
*
* Copyright (C) 2001 IBM Deutschland Entwicklung GmbH, IBM Corporation
*
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/tty.h>
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
*
*
*
#ifndef __HWC_H__
#define __HWC_H__
+#define HWC_EXT_INT_PARAM_ADDR 0xFFFFFFF8
+#define HWC_EXT_INT_PARAM_PEND 0x00000001
+
#define ET_OpCmd 0x01
#define ET_Msg 0x02
#define ET_StateChange 0x08
#define ET_PMsgCmd 0x09
#define ET_CntlProgOpCmd 0x20
+#define ET_CntlProgIdent 0x0B
#define ET_OpCmd_Mask 0x80000000
#define ET_Msg_Mask 0x40000000
#define ET_StateChange_Mask 0x01000000
#define ET_PMsgCmd_Mask 0x00800000
#define ET_CtlProgOpCmd_Mask 0x00000001
+#define ET_CtlProgIdent_Mask 0x00200000
#define GMF_DOM 0x8000
#define GMF_SndAlrm 0x4000
0x0000,
sizeof (_hwcb_mask_t),
ET_OpCmd_Mask | ET_PMsgCmd_Mask | ET_StateChange_Mask,
- ET_Msg_Mask | ET_PMsgCmd_Mask
+ ET_Msg_Mask | ET_PMsgCmd_Mask | ET_CtlProgIdent_Mask
};
typedef struct {
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
*/
#include <linux/config.h>
#include <linux/fs.h>
#include <linux/init.h>
-#include "ctrlchar.h"
#include "hwc_rw.h"
#ifdef CONFIG_HWC_CONSOLE
void __init
hwc_console_init (void)
{
-
-#if defined(CONFIG_3215_CONSOLE) || defined(CONFIG_3270_CONSOLE)
- if (MACHINE_IS_VM)
- return;
-#endif
- if (MACHINE_IS_P390)
+ if (!MACHINE_HAS_HWC)
return;
- ctrlchar_init ();
-
if (hwc_init () == 0) {
#ifdef CONFIG_HWC_CONSOLE
- register_console (&hwc_console);
+ if (CONSOLE_IS_HWC)
+ register_console (&hwc_console);
#endif
} else
panic (HWC_CON_PRINT_HEADER "hwc initialisation failed !");
--- /dev/null
+
+/*
+ * Author: Martin Peschke <mpeschke@de.ibm.com>
+ * Copyright (C) 2001 IBM Entwicklung GmbH, IBM Corporation
+ */
+
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/errno.h>
+#include <linux/malloc.h>
+#include <linux/version.h>
+#include <asm/semaphore.h>
+#include <asm/ebcdic.h>
+#include "hwc_rw.h"
+#include "hwc.h"
+
+#define CPI_LENGTH_SYSTEM_TYPE 8
+#define CPI_LENGTH_SYSTEM_NAME 8
+#define CPI_LENGTH_SYSPLEX_NAME 8
+
+typedef struct {
+ _EBUF_HEADER
+ u8 id_format;
+ u8 reserved0;
+ u8 system_type[CPI_LENGTH_SYSTEM_TYPE];
+ u64 reserved1;
+ u8 system_name[CPI_LENGTH_SYSTEM_NAME];
+ u64 reserved2;
+ u64 system_level;
+ u64 reserved3;
+ u8 sysplex_name[CPI_LENGTH_SYSPLEX_NAME];
+ u8 reserved4[16];
+} __attribute__ ((packed))
+
+cpi_evbuf_t;
+
+typedef struct _cpi_hwcb_t {
+ _HWCB_HEADER
+ cpi_evbuf_t cpi_evbuf;
+} __attribute__ ((packed))
+
+cpi_hwcb_t;
+
+cpi_hwcb_t *cpi_hwcb;
+
+static int __init cpi_module_init (void);
+static void __exit cpi_module_exit (void);
+
+module_init (cpi_module_init);
+module_exit (cpi_module_exit);
+
+MODULE_AUTHOR (
+ "Martin Peschke, IBM Deutschland Entwicklung GmbH "
+ "<mpeschke@de.ibm.com>");
+
+MODULE_DESCRIPTION (
+ "identify this operating system instance to the S/390 or zSeries hardware");
+
+static char *system_name = NULL;
+MODULE_PARM (system_name, "s");
+MODULE_PARM_DESC (system_name, "e.g. hostname - max. 8 characters");
+
+static char *sysplex_name = NULL;
+#ifdef ALLOW_SYSPLEX_NAME
+MODULE_PARM (sysplex_name, "s");
+MODULE_PARM_DESC (sysplex_name, "if applicable - max. 8 characters");
+#endif
+
+static char *system_type = "LINUX";
+
+hwc_request_t cpi_request =
+{};
+
+hwc_callback_t cpi_callback;
+
+static DECLARE_MUTEX_LOCKED (sem);
+
+static int __init
+cpi_module_init (void)
+{
+ int retval;
+ int system_type_length;
+ int system_name_length;
+ int sysplex_name_length = 0;
+
+ if (!MACHINE_HAS_HWC) {
+ printk ("cpi: bug: hardware console not present\n");
+ retval = -EINVAL;
+ goto out;
+ }
+ if (!system_type) {
+ printk ("cpi: bug: no system type specified\n");
+ retval = -EINVAL;
+ goto out;
+ }
+ system_type_length = strlen (system_type);
+ if (system_type_length > CPI_LENGTH_SYSTEM_NAME) {
+ printk ("cpi: bug: system type has length of %i characters - "
+ "only %i characters supported\n",
+ system_type_length,
+ CPI_LENGTH_SYSTEM_TYPE);
+ retval = -EINVAL;
+ goto out;
+ }
+ if (!system_name) {
+ printk ("cpi: no system name specified\n");
+ retval = -EINVAL;
+ goto out;
+ }
+ system_name_length = strlen (system_name);
+ if (system_name_length > CPI_LENGTH_SYSTEM_NAME) {
+ printk ("cpi: system name has length of %i characters - "
+ "only %i characters supported\n",
+ system_name_length,
+ CPI_LENGTH_SYSTEM_NAME);
+ retval = -EINVAL;
+ goto out;
+ }
+ if (sysplex_name) {
+ sysplex_name_length = strlen (sysplex_name);
+ if (sysplex_name_length > CPI_LENGTH_SYSPLEX_NAME) {
+ printk ("cpi: sysplex name has length of %i characters - "
+ "only %i characters supported\n",
+ sysplex_name_length,
+ CPI_LENGTH_SYSPLEX_NAME);
+ retval = -EINVAL;
+ goto out;
+ }
+ }
+ cpi_hwcb = kmalloc (sizeof (cpi_hwcb_t), GFP_KERNEL);
+ if (!cpi_hwcb) {
+ printk ("cpi: no storage to fulfill request\n");
+ retval = -ENOMEM;
+ goto out;
+ }
+ memset (cpi_hwcb, 0, sizeof (cpi_hwcb_t));
+
+ cpi_hwcb->length = sizeof (cpi_hwcb_t);
+ cpi_hwcb->cpi_evbuf.length = sizeof (cpi_evbuf_t);
+ cpi_hwcb->cpi_evbuf.type = 0x0B;
+
+ memset (cpi_hwcb->cpi_evbuf.system_type, ' ', CPI_LENGTH_SYSTEM_TYPE);
+ memcpy (cpi_hwcb->cpi_evbuf.system_type, system_type, system_type_length);
+ HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.system_type, CPI_LENGTH_SYSTEM_TYPE);
+ EBC_TOUPPER (cpi_hwcb->cpi_evbuf.system_type, CPI_LENGTH_SYSTEM_TYPE);
+
+ memset (cpi_hwcb->cpi_evbuf.system_name, ' ', CPI_LENGTH_SYSTEM_NAME);
+ memcpy (cpi_hwcb->cpi_evbuf.system_name, system_name, system_name_length);
+ HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.system_name, CPI_LENGTH_SYSTEM_NAME);
+ EBC_TOUPPER (cpi_hwcb->cpi_evbuf.system_name, CPI_LENGTH_SYSTEM_NAME);
+
+ cpi_hwcb->cpi_evbuf.system_level = LINUX_VERSION_CODE;
+
+ if (sysplex_name) {
+ memset (cpi_hwcb->cpi_evbuf.sysplex_name, ' ', CPI_LENGTH_SYSPLEX_NAME);
+ memcpy (cpi_hwcb->cpi_evbuf.sysplex_name, sysplex_name, sysplex_name_length);
+ HWC_ASCEBC_STR (cpi_hwcb->cpi_evbuf.sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
+ EBC_TOUPPER (cpi_hwcb->cpi_evbuf.sysplex_name, CPI_LENGTH_SYSPLEX_NAME);
+ }
+ cpi_request.block = cpi_hwcb;
+ cpi_request.word = HWC_CMDW_WRITEDATA;
+ cpi_request.callback = cpi_callback;
+
+ retval = hwc_send (&cpi_request);
+ if (retval) {
+ printk ("cpi: failed (%i)\n", retval);
+ goto free;
+ }
+ down (&sem);
+
+ switch (cpi_hwcb->response_code) {
+ case 0x0020:
+ printk ("cpi: succeeded\n");
+ break;
+ default:
+ printk ("cpi: failed with response code 0x%x\n",
+ cpi_hwcb->response_code);
+ }
+
+ free:
+ kfree (cpi_hwcb);
+
+ out:
+ return retval;
+}
+
+static void __exit
+cpi_module_exit (void)
+{
+ printk ("cpi: exit\n");
+}
+
+void
+cpi_callback (hwc_request_t * req)
+{
+ up (&sem);
+}
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
*
*
*
#include <linux/mm.h>
#include <linux/timer.h>
#include <linux/bootmem.h>
+#include <linux/module.h>
#include <asm/ebcdic.h>
#include <asm/uaccess.h>
#include <asm/setup.h>
#include <asm/page.h>
#include <asm/s390_ext.h>
+#include <asm/irq.h>
#ifndef MIN
#define MIN(a,b) (((a<b) ? a : b))
#endif
-#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
-
-#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
-
#define HWC_RW_PRINT_HEADER "hwc low level driver: "
#define USE_VM_DETECTION
#define DEFAULT_CASE_DELIMITER '%'
-#define DUMP_HWC_INIT_ERROR
+#undef DUMP_HWC_INIT_ERROR
-#define DUMP_HWC_WRITE_ERROR
+#undef DUMP_HWC_WRITE_ERROR
-#define DUMP_HWC_WRITE_LIST_ERROR
+#undef DUMP_HWC_WRITE_LIST_ERROR
-#define DUMP_HWC_READ_ERROR
+#undef DUMP_HWC_READ_ERROR
#undef DUMP_HWCB_INPUT
hwc_high_level_calls_t *calls;
+ hwc_request_t *request;
+
spinlock_t lock;
struct timer_list write_timer;
0,
0,
0,
+ NULL,
NULL
};
return condition_code;
}
-static inline unsigned char *
-ext_int_param (void)
+static inline unsigned long
+hwc_ext_int_param (void)
{
u32 param;
__asm__ __volatile__ ("L %0,128\n\t"
:"=r" (param));
- return ((unsigned char *) param);
+ return (unsigned long) param;
}
static int
internal_print (
DELAYED_WRITE,
HWC_RW_PRINT_HEADER
- "found invalid HWCB at address 0x%x. List corrupted. "
+ "found invalid HWCB at address 0x%lx. List corrupted. "
"Lost %i HWCBs with %i characters within up to %i "
"messages. Saved %i HWCB with last %i characters i"
"within up to %i messages.\n",
- (unsigned int) bad_addr,
+ (unsigned long) bad_addr,
lost_hwcb, lost_char, lost_msg,
hwc_data.hwcb_count,
ALL_HWCB_CHAR, ALL_HWCB_MTO);
}
static int
-write_event_data_2 (void)
+write_event_data_2 (u32 ext_int_param)
{
write_hwcb_t *hwcb;
int retval = 0;
#ifdef DUMP_HWC_WRITE_ERROR
- unsigned char *param;
-
- param = ext_int_param ();
- if (param != hwc_data.current_hwcb) {
+ if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
+ != (unsigned long) hwc_data.current_hwcb) {
internal_print (
DELAYED_WRITE,
HWC_RW_PRINT_HEADER
- "write_event_mask_2 : "
+ "write_event_data_2 : "
"HWCB address does not fit "
- "(expected: 0x%x, got: 0x%x).\n",
- hwc_data.current_hwcb,
- param);
+ "(expected: 0x%lx, got: 0x%lx).\n",
+ (unsigned long) hwc_data.current_hwcb,
+ ext_int_param);
return -EINVAL;
}
#endif
}
static int
-unconditional_read_2 (void)
+unconditional_read_2 (u32 ext_int_param)
{
read_hwcb_t *hwcb = (read_hwcb_t *) hwc_data.page;
}
static int
-write_event_mask_2 (void)
+write_event_mask_2 (u32 ext_int_param)
{
init_hwcb_t *hwcb = (init_hwcb_t *) hwc_data.page;
int retval = 0;
return retval;
}
-void do_hwc_interrupt (struct pt_regs *regs, __u16 code);
+void hwc_interrupt_handler (struct pt_regs *regs, __u16 code);
int
hwc_init (void)
#endif
- if (register_external_interrupt (0x2401, do_hwc_interrupt) != 0)
+ if (register_external_interrupt (0x2401, hwc_interrupt_handler) != 0)
panic ("Couldn't request external interrupts 0x2401");
spin_lock_init (&hwc_data.lock);
return 0;
}
+int
+hwc_send (hwc_request_t * req)
+{
+ unsigned long flags;
+ int retval;
+ int cc;
+
+ spin_lock_irqsave (&hwc_data.lock, flags);
+ if (!req || !req->callback || !req->block) {
+ retval = -EINVAL;
+ goto unlock;
+ }
+ if (hwc_data.request) {
+ retval = -ENOTSUPP;
+ goto unlock;
+ }
+ hwc_data.request = req;
+ cc = service_call (req->word, req->block);
+ switch (cc) {
+ case 0:
+ hwc_data.current_servc = req->word;
+ hwc_data.current_hwcb = req->block;
+ retval = 0;
+ break;
+ case 2:
+ retval = -EBUSY;
+ break;
+ default:
+ retval = -ENOSYS;
+
+ }
+ unlock:
+ spin_unlock_irqrestore (&hwc_data.lock, flags);
+ return retval;
+}
+
+EXPORT_SYMBOL (hwc_send);
+
void
-do_hwc_interrupt (struct pt_regs *regs, __u16 code)
+do_hwc_callback (u32 ext_int_param)
{
+ if (!hwc_data.request || !hwc_data.request->callback)
+ return;
+ if ((ext_int_param & HWC_EXT_INT_PARAM_ADDR)
+ != (unsigned long) hwc_data.request->block)
+ return;
+ hwc_data.request->callback (hwc_data.request);
+ hwc_data.request = NULL;
+ hwc_data.current_hwcb = NULL;
+ hwc_data.current_servc = 0;
+}
- if (hwc_data.flags & HWC_INIT) {
+void
+hwc_do_interrupt (u32 ext_int_param)
+{
+ u32 finished_hwcb = ext_int_param & HWC_EXT_INT_PARAM_ADDR;
+ u32 evbuf_pending = ext_int_param & HWC_EXT_INT_PARAM_PEND;
- hwc_data.flags |= HWC_INTERRUPT;
- } else if (hwc_data.flags & HWC_BROKEN) {
+ if (hwc_data.flags & HWC_PTIMER_RUNS) {
+ del_timer (&hwc_data.poll_timer);
+ hwc_data.flags &= ~HWC_PTIMER_RUNS;
+ }
+ if (finished_hwcb) {
- if (!do_hwc_init ()) {
- hwc_data.flags &= ~HWC_BROKEN;
- internal_print (DELAYED_WRITE,
- HWC_RW_PRINT_HEADER
- "delayed HWC setup after"
- " temporary breakdown\n");
+ if ((unsigned long) hwc_data.current_hwcb != finished_hwcb) {
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "interrupt: mismatch: "
+ "ext. int param. (0x%x) vs. "
+ "current HWCB (0x%x)\n",
+ ext_int_param,
+ hwc_data.current_hwcb);
+ } else {
+ if (hwc_data.request) {
+
+ do_hwc_callback (ext_int_param);
+ } else {
+
+ switch (hwc_data.current_servc) {
+
+ case HWC_CMDW_WRITEMASK:
+
+ write_event_mask_2 (ext_int_param);
+ break;
+
+ case HWC_CMDW_WRITEDATA:
+
+ write_event_data_2 (ext_int_param);
+ break;
+
+ case HWC_CMDW_READDATA:
+
+ unconditional_read_2 (ext_int_param);
+ break;
+ default:
+ }
+ }
}
} else {
- spin_lock (&hwc_data.lock);
- if (hwc_data.flags & HWC_PTIMER_RUNS) {
- del_timer (&hwc_data.poll_timer);
- hwc_data.flags &= ~HWC_PTIMER_RUNS;
+ if (hwc_data.current_hwcb) {
+ internal_print (
+ DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "interrupt: mismatch: "
+ "ext. int. param. (0x%x) vs. "
+ "current HWCB (0x%x)\n",
+ ext_int_param,
+ hwc_data.current_hwcb);
}
- if (!hwc_data.current_servc) {
+ }
- unconditional_read_1 ();
+ if (evbuf_pending) {
- } else {
+ unconditional_read_1 ();
+ } else {
- switch (hwc_data.current_servc) {
+ write_event_data_1 ();
+ }
- case HWC_CMDW_WRITEMASK:
+ if (!hwc_data.calls || !hwc_data.calls->wake_up)
+ return;
+ (hwc_data.calls->wake_up) ();
+}
- write_event_mask_2 ();
- break;
+void
+hwc_interrupt_handler (struct pt_regs *regs, __u16 code)
+{
+ int cpu = smp_processor_id ();
- case HWC_CMDW_WRITEDATA:
+ u32 ext_int_param = hwc_ext_int_param ();
- write_event_data_2 ();
- break;
+ irq_enter (cpu, 0x2401);
- case HWC_CMDW_READDATA:
+ if (hwc_data.flags & HWC_INIT) {
- unconditional_read_2 ();
- break;
- }
+ hwc_data.flags |= HWC_INTERRUPT;
+ } else if (hwc_data.flags & HWC_BROKEN) {
- write_event_data_1 ();
+ if (!do_hwc_init ()) {
+ hwc_data.flags &= ~HWC_BROKEN;
+ internal_print (DELAYED_WRITE,
+ HWC_RW_PRINT_HEADER
+ "delayed HWC setup after"
+ " temporary breakdown"
+ " (ext. int. parameter=0x%x)\n",
+ ext_int_param);
}
- if (hwc_data.calls != NULL)
- if (hwc_data.calls->wake_up != NULL)
- (hwc_data.calls->wake_up) ();
+ } else {
+ spin_lock (&hwc_data.lock);
+ hwc_do_interrupt (ext_int_param);
spin_unlock (&hwc_data.lock);
}
+ irq_exit (cpu, 0x2401);
}
void
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
*/
#ifndef __HWC_RW_H__
void (*wake_up) (void);
} hwc_high_level_calls_t;
+struct _hwc_request;
+
+typedef void hwc_callback_t (struct _hwc_request *);
+
+typedef struct _hwc_request {
+ void *block;
+ u32 word;
+ hwc_callback_t *callback;
+ void *data;
+} __attribute__ ((packed))
+
+hwc_request_t;
+
+#define HWC_ASCEBC(x) ((MACHINE_IS_VM ? _ascebc[x] : _ascebc_500[x]))
+
+#define HWC_EBCASC_STR(s,c) ((MACHINE_IS_VM ? EBCASC(s,c) : EBCASC_500(s,c)))
+
+#define HWC_ASCEBC_STR(s,c) ((MACHINE_IS_VM ? ASCEBC(s,c) : ASCEBC_500(s,c)))
+
#define IN_HWCB 1
#define IN_WRITE_BUF 2
#define IN_BUFS_TOTAL (IN_HWCB | IN_WRITE_BUF)
extern signed int hwc_unregister_calls (hwc_high_level_calls_t *);
+extern int hwc_send (hwc_request_t *);
+
#endif
#endif
*
* S390 version
* Copyright (C) 1999 IBM Deutschland Entwicklung GmbH, IBM Corporation
- * Author(s): Martin Peschke <peschke@fh-brandenburg.de>
+ * Author(s): Martin Peschke <mpeschke@de.ibm.com>
*
* Thanks to Martin Schwidefsky.
*/
#include <asm/uaccess.h>
#include "hwc_rw.h"
+#include "ctrlchar.h"
#define HWC_TTY_PRINT_HEADER "hwc tty driver: "
void
hwc_tty_init (void)
{
-#if defined(CONFIG_3215_CONSOLE) || defined(CONFIG_3270_CONSOLE)
- if (MACHINE_IS_VM)
- return;
-#endif
- if (MACHINE_IS_P390)
+ if (!CONSOLE_IS_HWC)
return;
+ ctrlchar_init ();
+
memset (&hwc_tty_driver, 0, sizeof (struct tty_driver));
memset (&hwc_tty_data, 0, sizeof (hwc_tty_data_struct));
hwc_tty_driver.magic = TTY_DRIVER_MAGIC;
#include <linux/kernel.h>
#include <linux/version.h>
#include <linux/proc_fs.h>
+#include <linux/init.h>
#include <asm/types.h>
#include <asm/ccwcache.h>
#include <asm/idals.h>
#ifdef MODULE
#include <linux/module.h>
#endif
-#ifdef TAPE_DEBUG
#include <asm/debug.h>
-#endif
#ifdef CONFIG_S390_TAPE_DYNAMIC
#include <asm/s390dyn.h>
#endif
#endif
#define PRINTK_HEADER "T390:"
+
/* state handling routines */
-inline void tapestate_set (tape_info_t * tape, int newstate);
-inline int tapestate_get (tape_info_t * tape);
-void tapestate_event (tape_info_t * tape, int event);
+inline void tapestate_set (tape_info_t * ti, int newstate);
+inline int tapestate_get (tape_info_t * ti);
+void tapestate_event (tape_info_t * ti, int event);
/* our globals */
tape_info_t *first_tape_info = NULL;
tape_discipline_t *first_discipline = NULL;
tape_frontend_t *first_frontend = NULL;
+devreg_t* tape_devreg[128];
+int devregct=0;
+
#ifdef TAPE_DEBUG
debug_info_t *tape_debug_area = NULL;
#endif
devfs_handle_t tape_devfs_root_entry;
inline void
-tape_mkdevfsroots (tape_info_t* tape)
+tape_mkdevfsroots (tape_info_t* ti)
{
char devno [5];
- sprintf (devno,"%04X",tape->devinfo.devno);
- tape->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, tape);
+ sprintf (devno,"%04x",ti->devinfo.devno);
+ ti->devfs_dir=devfs_mk_dir (tape_devfs_root_entry, devno, ti);
}
inline void
-tape_rmdevfsroots (tape_info_t* tape)
+tape_rmdevfsroots (tape_info_t* ti)
{
- devfs_unregister (tape->devfs_dir);
+ devfs_unregister (ti->devfs_dir);
}
#endif
tape_devices_open (struct inode *inode, struct file *file)
{
int size=80;
- tape_info_t* tape;
+ tape_info_t* ti;
tempinfo_t* tempinfo;
char* data;
int pos=0;
tempinfo = kmalloc (sizeof(tempinfo_t),GFP_KERNEL);
if (!tempinfo)
return -ENOMEM;
- for (tape=first_tape_info;tape!=NULL;tape=tape->next)
+ for (ti=first_tape_info;ti!=NULL;ti=ti->next)
size+=80; // FIXME: Guess better!
data=vmalloc(size);
if (!data) {
return -ENOMEM;
}
pos+=sprintf(data+pos,"TapeNo\tDevNo\tCuType\tCuModel\tDevType\tDevModel\tState\n");
- for (tape=first_tape_info;tape!=NULL;tape=tape->next) {
- pos+=sprintf(data+pos,"%d\t%04X\t%04X\t%02X\t%04X\t%02X\t\t%s\n",tape->rew_minor/2,
- tape->devinfo.devno,tape->devinfo.sid_data.cu_type,
- tape->devinfo.sid_data.cu_model,tape->devinfo.sid_data.dev_type,
- tape->devinfo.sid_data.dev_model,((tapestate_get(tape) >= 0) &&
- (tapestate_get(tape) < TS_SIZE)) ?
- state_verbose[tapestate_get (tape)] : "TS UNKNOWN");
+ for (ti=first_tape_info;ti!=NULL;ti=ti->next) {
+ pos+=sprintf(data+pos,"%d\t%04X\t%04X\t%02X\t%04X\t%02X\t\t%s\n",ti->rew_minor/2,
+ ti->devinfo.devno,ti->devinfo.sid_data.cu_type,
+ ti->devinfo.sid_data.cu_model,ti->devinfo.sid_data.dev_type,
+ ti->devinfo.sid_data.dev_model,((tapestate_get(ti) >= 0) &&
+ (tapestate_get(ti) < TS_SIZE)) ?
+ state_verbose[tapestate_get (ti)] : "TS UNKNOWN");
}
tempinfo->len=pos;
tempinfo->data=data;
};
#endif /* CONFIG_PROC_FS */
+/* SECTION: Parameters for tape */
+char *tape[256] = { NULL, };
+
+#ifndef MODULE
+static char tape_parm_string[1024] __initdata = { 0, };
+static void
+tape_split_parm_string (char *str)
+{
+ char *tmp = str;
+ int count = 0;
+ while (tmp != NULL && *tmp != '\0') {
+ char *end;
+ int len;
+ end = strchr (tmp, ',');
+ if (end == NULL) {
+ len = strlen (tmp) + 1;
+ } else {
+ len = (long) end - (long) tmp + 1;
+ *end = '\0';
+ end++;
+ }
+ tape[count] = kmalloc (len * sizeof (char), GFP_ATOMIC);
+ if (tape[count] == NULL) {
+ printk (KERN_WARNING PRINTK_HEADER
+ "can't store tape= parameter no %d\n",
+ count + 1);
+ break;
+ }
+ memset (tape[count], 0, len * sizeof (char));
+ memcpy (tape[count], tmp, len * sizeof (char));
+ count++;
+ tmp = end;
+ };
+}
+
+void __init
+tape_parm_setup (char *str, int *ints)
+{
+ int len = strlen (tape_parm_string);
+ if (len != 0) {
+ strcat (tape_parm_string, ",");
+ }
+ strcat (tape_parm_string, str);
+}
+
+int __init
+tape_parm_call_setup (char *str)
+{
+ int dummy;
+ tape_parm_setup (str, &dummy);
+ return 1;
+}
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,16))
+__setup("tape=", tape_parm_call_setup);
+#endif /* kernel <2.2.19 */
+#endif /* not defined MODULE */
+
+static inline int
+tape_parm_strtoul (char *str, char **stra)
+{
+ char *temp = str;
+ int val;
+ if (*temp == '0') {
+ temp++; /* strip leading zero */
+ if (*temp == 'x')
+ temp++; /* strip leading x */
+ }
+ val = simple_strtoul (temp, &temp, 16); /* interpret anything as hex */
+ *stra = temp;
+ return val;
+}
+
+static inline devreg_t *
+tape_create_devreg (int devno)
+{
+ devreg_t *devreg = kmalloc (sizeof (devreg_t), GFP_KERNEL);
+ if (devreg != NULL) {
+ memset (devreg, 0, sizeof (devreg_t));
+ devreg->ci.devno = devno;
+ devreg->flag = DEVREG_TYPE_DEVNO;
+ devreg->oper_func = tape_oper_handler;
+ }
+ return devreg;
+}
+
+static inline void
+tape_parm_parse (char **str)
+{
+ char *temp;
+ int from, to,i,irq=0,rc,retries=0,tape_num=0;
+ s390_dev_info_t dinfo;
+ tape_info_t* ti,*tempti;
+ tape_discipline_t* disc;
+ long lockflags;
+ if (*str==NULL) {
+ /* no params present -> leave */
+ return;
+ }
+ while (*str) {
+ temp = *str;
+ from = 0;
+ to = 0;
+
+ /* turn off autodetect mode, if any range is present */
+ from = tape_parm_strtoul (temp, &temp);
+ to = from;
+ if (*temp == '-') {
+ temp++;
+ to = tape_parm_strtoul (temp, &temp);
+ }
+ for (i=from;i<=to;i++) {
+ retries=0;
+ // register for attch/detach of a devno
+ tape_devreg[devregct]=tape_create_devreg(i);
+ if (tape_devreg[devregct]==NULL) {
+ PRINT_WARN ("Could not create devreg for devno %04x, dyn. attach for this devno deactivated.\n",i);
+ } else {
+ s390_device_register (tape_devreg[devregct++]);
+ }
+ // we are activating a device if it is present
+ for (irq = get_irq_first(); irq!=-ENODEV; irq=get_irq_next(irq)) {
+ rc = get_dev_info_by_irq (irq, &dinfo);
+
+ disc = first_discipline;
+ while ((dinfo.devno == i) && (disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
+ disc = (tape_discipline_t *) (disc->next);
+ if ((disc == NULL) || (rc == -ENODEV) || (i!=dinfo.devno)) {
+ continue;
+ }
+#ifdef TAPE_DEBUG
+ debug_text_event (tape_debug_area,3,"det irq: ");
+ debug_int_event (tape_debug_area,3,irq);
+ debug_text_event (tape_debug_area,3,"cu: ");
+ debug_int_event (tape_debug_area,3,disc->cu_type);
+#endif /* TAPE_DEBUG */
+ PRINT_INFO ("using devno %04x with discipline %04x on irq %d as tape device %d\n",dinfo.devno,dinfo.sid_data.cu_type,irq,tape_num/2);
+ /* Allocate tape structure */
+ ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
+ if (ti == NULL) {
+#ifdef TAPE_DEBUG
+ debug_text_exception (tape_debug_area,3,"ti:no mem ");
+#endif /* TAPE_DEBUG */
+ PRINT_INFO ("tape: can't allocate memory for "
+ "tape info structure\n");
+ continue;
+ }
+ memset(ti,0,sizeof(tape_info_t));
+ ti->discipline = disc;
+ disc->tape = ti;
+ rc = tape_setup (ti, irq, tape_num);
+ if (rc) {
+#ifdef TAPE_DEBUG
+ debug_text_event (tape_debug_area,3,"tsetup err");
+ debug_int_exception (tape_debug_area,3,rc);
+#endif /* TAPE_DEBUG */
+ kfree (ti);
+ } else {
+ s390irq_spin_lock_irqsave (irq, lockflags);
+ if (first_tape_info == NULL) {
+ first_tape_info = ti;
+ } else {
+ tempti = first_tape_info;
+ while (tempti->next != NULL)
+ tempti = tempti->next;
+ tempti->next = ti;
+ }
+ s390irq_spin_unlock_irqrestore (irq, lockflags);
+ }
+ }
+ tape_num+=2;
+ }
+ str++;
+ }
+}
+
+
/* SECTION: Managing wrappers for ccwcache */
#define TAPE_EMERGENCY_REQUESTS 16
*((ccw_req_t **) (request->cache)) = request;
} else {
clear_normalized_cda ((ccw1_t *) (request->cpaddr)); // avoid memory leak caused by modeset_byte
-
ccw_free_request (request);
}
}
*/
inline
ccw_req_t *
-tape_alloc_ccw_req (tape_info_t * tape, int cplength, int datasize)
+tape_alloc_ccw_req (tape_info_t * ti, int cplength, int datasize)
{
char tape_magic_id[] = "tape";
ccw_req_t *cqr = NULL;
- if (!tape)
+ if (!ti)
return NULL;
cqr = tape_alloc_request (tape_magic_id, cplength, datasize);
#endif
}
cqr->magic = TAPE_MAGIC; /* sets an identifier for tape driver */
- cqr->device = tape; /* save pointer to tape info */
+ cqr->device = ti; /* save pointer to tape info */
return cqr;
}
static inline tape_info_t *
tapedev_find_info (int irq)
{
- tape_info_t *tape;
+ tape_info_t *ti;
- tape = first_tape_info;
- if (tape != NULL)
+ ti = first_tape_info;
+ if (ti != NULL)
do {
- if (tape->devinfo.irq == irq)
+ if (ti->devinfo.irq == irq)
break;
- } while ((tape = (tape_info_t *) tape->next) != NULL);
- return tape;
+ } while ((ti = (tape_info_t *) ti->next) != NULL);
+ return ti;
}
#define QUEUE_THRESHOLD 5
void
tape_irq (int irq, void *int_parm, struct pt_regs *regs)
{
- tape_info_t *tape = tapedev_find_info (irq);
+ tape_info_t *ti = tapedev_find_info (irq);
/* analyse devstat and fire event */
- if (tape->devstat.dstat & DEV_STAT_UNIT_CHECK) {
- tapestate_event (tape, TE_ERROR);
- } else if (tape->devstat.dstat & (DEV_STAT_DEV_END)) {
- tapestate_event (tape, TE_DONE);
+ if (ti->devstat.dstat & DEV_STAT_UNIT_CHECK) {
+ tapestate_event (ti, TE_ERROR);
+ } else if (ti->devstat.dstat & (DEV_STAT_DEV_END)) {
+ tapestate_event (ti, TE_DONE);
} else
- tapestate_event (tape, TE_OTHER);
+ tapestate_event (ti, TE_OTHER);
}
int
tape_oper_handler ( int irq, struct _devreg *dreg) {
- tape_info_t* tape=first_tape_info;
+ tape_info_t* ti=first_tape_info;
tape_info_t* newtape;
- int rc,tape_num,retries=0;
+ int rc,tape_num,retries=0,i;
s390_dev_info_t dinfo;
tape_discipline_t* disc;
#ifdef CONFIG_DEVFS_FS
tape_frontend_t* frontend;
#endif
long lockflags;
- PRINT_WARN ("oper handler was called\n");
- while ((tape!=NULL) && (tape->devinfo.irq!=irq))
- tape=tape->next;
- if (tape!=NULL) {
+ while ((ti!=NULL) && (ti->devinfo.irq!=irq))
+ ti=ti->next;
+ if (ti!=NULL) {
// irq is (still) used by tape. tell ingo to try again later
PRINT_WARN ("Oper handler for irq %d called while irq still (internaly?) used.\n",irq);
return -EAGAIN;
while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
disc = (tape_discipline_t *) (disc->next);
if (disc == NULL)
- PRINT_WARN ("No matching discipline for cu_type %x found\n",dinfo.sid_data.cu_type);
+ PRINT_WARN ("No matching discipline for cu_type %x found, ignoring device %04x.\n",dinfo.sid_data.cu_type,dinfo.devno);
if (rc == -ENODEV)
PRINT_WARN ("No device information for new dev. could be retrieved.\n");
if ((disc == NULL) || (rc == -ENODEV))
return -ENODEV;
/* Allocate tape structure */
- tape = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
- if (tape == NULL) {
- PRINT_INFO (KERN_ERR "tape: can't allocate memory for "
+ ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
+ if (ti == NULL) {
+ PRINT_INFO ( "tape: can't allocate memory for "
"tape info structure\n");
return -ENOBUFS;
}
- memset(tape,0,sizeof(tape_info_t));
- tape->discipline = disc;
- disc->tape = tape;
+ memset(ti,0,sizeof(tape_info_t));
+ ti->discipline = disc;
+ disc->tape = ti;
tape_num=0;
- newtape=first_tape_info;
- while (newtape!=NULL) {
- if (newtape->rew_minor==tape_num) {
- // tape num in use. try next one
- tape_num+=2;
- newtape=first_tape_info;
- } else {
- // tape num not used by newtape. look at next tape info
- newtape=newtape->next;
+ if (*tape) {
+ // we have static device ranges, so fingure out the tape_num of the attached tape
+ for (i=0;i<devregct;i++)
+ if (tape_devreg[i]->ci.devno==dinfo.devno) {
+ tape_num=2*i;
+ break;
+ }
+ } else {
+ // we are running in autoprobe mode, find a free tape_num
+ newtape=first_tape_info;
+ while (newtape!=NULL) {
+ if (newtape->rew_minor==tape_num) {
+ // tape num in use. try next one
+ tape_num+=2;
+ newtape=first_tape_info;
+ } else {
+ // tape num not used by newtape. look at next tape info
+ newtape=newtape->next;
+ }
}
}
- rc = tape_setup (tape, irq, tape_num);
+ rc = tape_setup (ti, irq, tape_num);
if (rc) {
- kfree (tape);
+ kfree (ti);
return -ENOBUFS;
}
#ifdef CONFIG_DEVFS_FS
for (frontend=first_frontend;frontend!=NULL;frontend=frontend->next)
- frontend->mkdevfstree(tape);
+ frontend->mkdevfstree(ti);
#endif
s390irq_spin_lock_irqsave (irq,lockflags);
if (first_tape_info == NULL) {
- first_tape_info = tape;
+ first_tape_info = ti;
} else {
newtape = first_tape_info;
while (newtape->next != NULL)
newtape = newtape->next;
- newtape->next = tape;
+ newtape->next = ti;
}
s390irq_spin_unlock_irqrestore (irq, lockflags);
return 0;
void
tape_dump_sense (devstat_t * stat)
{
- int sl;
+#ifdef TAPE_DEBUG
+ int sl;
+#endif
#if 0
+
PRINT_WARN ("------------I/O resulted in unit check:-----------\n");
for (sl = 0; sl < 4; sl++) {
PRINT_WARN ("Sense:");
long lockflags;
int rc = 0;
+ if (minor>254) {
+ PRINT_WARN ("Device id %d on irq %d will not be accessible since this driver is restricted to 128 devices.\n",minor/2,irq);
+ return -EINVAL;
+ }
rc = get_dev_info_by_irq (irq, &(ti->devinfo));
if (rc == -ENODEV) { /* end of device list */
return rc;
#endif
s390irq_spin_lock_irqsave (irq, lockflags);
ti->next = NULL;
- if (rc) {
- PRINT_WARN ("Cannot register irq %d, rc=%d\n", irq, rc);
- } else
- PRINT_WARN ("Register irq %d for using with discipline %x dev #%d\n", irq, ti->discipline->cu_type,ti->blk_minor/2);
+ if (rc)
+ PRINT_WARN ("Cannot register irq %d, rc=%d\n", irq, rc);
init_waitqueue_head (&ti->wq);
ti->kernbuf = ti->userbuf = ti->discdata = NULL;
tapestate_set (ti, TS_UNUSED);
#endif /* TAPE_DEBUG */
/* print banner */
- PRINT_WARN ("IBM S/390 Tape Device Driver (BETA).\n");
+ PRINT_WARN ("IBM S/390 Tape Device Driver (v1.01).\n");
PRINT_WARN ("(C) IBM Deutschland Entwicklung GmbH, 2000\n");
opt_char=opt_block=opt_3480=opt_3490="not present";
#ifdef CONFIG_S390_TAPE_CHAR
PRINT_WARN ("support for 3480 compatible : %s\n",opt_3480);
PRINT_WARN ("support for 3490 compatible : %s\n",opt_3490);
-
+#ifndef MODULE
+ tape_split_parm_string(tape_parm_string);
+#endif
+ if (*tape)
+ PRINT_INFO ("Using ranges supplied in parameters, disabling autoprobe mode.\n");
+ else
+ PRINT_INFO ("No parameters supplied, enabling autoprobe mode for all supported devices.\n");
#ifdef CONFIG_S390_TAPE_3490
- first_discipline = tape3490_init ();
+ if (*tape)
+ first_discipline = tape3490_init (0); // no autoprobe for devices
+ else
+ first_discipline = tape3490_init (1); // do autoprobe since no parm specified
first_discipline->next = NULL;
#endif
#ifdef CONFIG_S390_TAPE_3480
if (first_discipline == NULL) {
- first_discipline = tape3480_init ();
+ if (*tape)
+ first_discipline = tape3480_init (0); // no autoprobe for devices
+ else
+ first_discipline = tape3480_init (1); // do autoprobe since no parm specified
first_discipline->next = NULL;
} else {
- first_discipline->next = tape3480_init ();
+ if (*tape)
+ first_discipline->next = tape3480_init (0); // no autoprobe for devices
+ else
+ first_discipline->next = tape3480_init (1); // do autoprobe since no parm specified
((tape_discipline_t*) (first_discipline->next))->next=NULL;
}
#endif
debug_text_event (tape_debug_area,3,"dev detect");
#endif /* TAPE_DEBUG */
/* Allocate the tape structures */
- for (irq = 0; irq < NR_IRQS; irq++) {
+ if (*tape!=NULL) {
+ // we have parameters, continue with parsing the parameters and set the devices online
+ tape_parm_parse (tape);
+ } else {
+ // we are running in autodetect mode, search all devices for compatibles
+ for (irq = get_irq_first(); irq!=-ENODEV; irq=get_irq_next(irq)) {
rc = get_dev_info_by_irq (irq, &dinfo);
-
- if (rc == -ENODEV) {
- retries++;
- if (retries > 5)
- irq = NR_IRQS;
- }
disc = first_discipline;
while ((disc != NULL) && (disc->cu_type != dinfo.sid_data.cu_type))
- disc = (tape_discipline_t *) (disc->next);
-
+ disc = (tape_discipline_t *) (disc->next);
if ((disc == NULL) || (rc == -ENODEV))
- continue;
+ continue;
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"det irq: ");
debug_int_event (tape_debug_area,3,irq);
debug_text_event (tape_debug_area,3,"cu: ");
debug_int_event (tape_debug_area,3,disc->cu_type);
#endif /* TAPE_DEBUG */
+ PRINT_INFO ("using devno %04x with discipline %04x on irq %d as tape device %d\n",dinfo.devno,dinfo.sid_data.cu_type,irq,tape_num/2);
/* Allocate tape structure */
ti = kmalloc (sizeof (tape_info_t), GFP_ATOMIC);
if (ti == NULL) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,3,"ti:no mem ");
#endif /* TAPE_DEBUG */
- PRINT_INFO (KERN_ERR "tape: can't allocate memory for "
+ PRINT_INFO ("tape: can't allocate memory for "
"tape info structure\n");
continue;
}
rc = tape_setup (ti, irq, tape_num);
if (rc) {
#ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,3,"tsetup err");
- debug_int_exception (tape_debug_area,3,rc);
+ debug_text_event (tape_debug_area,3,"tsetup err");
+ debug_int_exception (tape_debug_area,3,rc);
#endif /* TAPE_DEBUG */
- kfree (ti);
+ kfree (ti);
} else {
- s390irq_spin_lock_irqsave (irq, lockflags);
- if (first_tape_info == NULL) {
- first_tape_info = ti;
- } else {
- tempti = first_tape_info;
- while (tempti->next != NULL)
- tempti = tempti->next;
- tempti->next = ti;
- }
- tape_num += 2;
- s390irq_spin_unlock_irqrestore (irq, lockflags);
+ s390irq_spin_lock_irqsave (irq, lockflags);
+ if (first_tape_info == NULL) {
+ first_tape_info = ti;
+ } else {
+ tempti = first_tape_info;
+ while (tempti->next != NULL)
+ tempti = tempti->next;
+ tempti->next = ti;
+ }
+ tape_num += 2;
+ s390irq_spin_unlock_irqrestore (irq, lockflags);
}
- }
-
+ }
+ }
+
/* Allocate local buffer for the ccwcache */
tape_init_emergency_req ();
#ifdef CONFIG_PROC_FS
#ifdef MODULE
MODULE_AUTHOR("(C) 2001 IBM Deutschland Entwicklung GmbH by Carsten Otte (cotte@de.ibm.com)");
MODULE_DESCRIPTION("Linux for S/390 channel attached tape device driver");
+MODULE_PARM (tape, "1-" __MODULE_STRING (256) "s");
int
init_module (void)
void
cleanup_module (void)
{
- tape_info_t *tape ,*temp;
+ tape_info_t *ti ,*temp;
tape_frontend_t* frontend, *tempfe;
tape_discipline_t* disc ,*tempdi;
+ int i;
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"cleaup mod");
#endif /* TAPE_DEBUG */
- tape = first_tape_info;
- while (tape != NULL) {
- temp = tape;
- tape = tape->next;
+ if (*tape) {
+ // we are running with parameters. we'll now deregister from our devno's
+ for (i=0;i<devregct;i++) {
+ s390_device_unregister(tape_devreg[devregct]);
+ }
+ }
+ ti = first_tape_info;
+ while (ti != NULL) {
+ temp = ti;
+ ti = ti->next;
//cleanup a device
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"free irq:");
#endif CONFIG_DEVFS_FS
#ifdef CONFIG_PROC_FS
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- remove_proc_entry ("devices", &proc_root);
+ remove_proc_entry ("tapedevices", &proc_root);
#else
proc_unregister (&proc_root, tape_devices_entry->low_ino);
kfree (tape_devices_entry);
}
disc=first_discipline;
while (disc != NULL) {
+ if (*tape)
+ disc->shutdown(0);
+ else
+ disc->shutdown(1);
tempdi = disc;
disc = disc->next;
kfree (tempdi);
#endif /* MODULE */
inline void
-tapestate_set (tape_info_t * tape, int newstate)
+tapestate_set (tape_info_t * ti, int newstate)
{
- if (tape->tape_state == TS_NOT_OPER) {
+ if (ti->tape_state == TS_NOT_OPER) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"ts_set err");
debug_text_exception (tape_debug_area,3,"dev n.oper");
} else {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,4,"ts. dev: ");
- debug_int_event (tape_debug_area,4,tape->blk_minor);
+ debug_int_event (tape_debug_area,4,ti->blk_minor);
debug_text_event (tape_debug_area,4,"old ts: ");
- debug_text_event (tape_debug_area,4,(((tapestate_get (tape) < TS_SIZE) &&
- (tapestate_get (tape) >=0 )) ?
- state_verbose[tapestate_get (tape)] :
+ debug_text_event (tape_debug_area,4,(((tapestate_get (ti) < TS_SIZE) &&
+ (tapestate_get (ti) >=0 )) ?
+ state_verbose[tapestate_get (ti)] :
"UNKNOWN TS"));
debug_text_event (tape_debug_area,4,"new ts: ");
debug_text_event (tape_debug_area,4,(((newstate < TS_SIZE) &&
state_verbose[newstate] :
"UNKNOWN TS"));
#endif /* TAPE_DEBUG */
- tape->tape_state = newstate;
+ ti->tape_state = newstate;
}
}
inline int
-tapestate_get (tape_info_t * tape)
+tapestate_get (tape_info_t * ti)
{
- return (tape->tape_state);
+ return (ti->tape_state);
}
void
-tapestate_event (tape_info_t * tape, int event)
+tapestate_event (tape_info_t * ti, int event)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"te! dev: ");
- debug_int_event (tape_debug_area,6,tape->blk_minor);
+ debug_int_event (tape_debug_area,6,ti->blk_minor);
debug_text_event (tape_debug_area,6,"event:");
debug_text_event (tape_debug_area,6,((event >=0) &&
(event < TE_SIZE)) ?
event_verbose[event] : "TE UNKNOWN");
debug_text_event (tape_debug_area,6,"state:");
- debug_text_event (tape_debug_area,6,((tapestate_get(tape) >= 0) &&
- (tapestate_get(tape) < TS_SIZE)) ?
- state_verbose[tapestate_get (tape)] :
+ debug_text_event (tape_debug_area,6,((tapestate_get(ti) >= 0) &&
+ (tapestate_get(ti) < TS_SIZE)) ?
+ state_verbose[tapestate_get (ti)] :
"TS UNKNOWN");
#endif /* TAPE_DEBUG */
if (event == TE_ERROR) {
- tape->discipline->error_recovery(tape);
+ ti->discipline->error_recovery(ti);
} else {
if ((event >= 0) &&
(event < TE_SIZE) &&
- (tapestate_get (tape) >= 0) &&
- (tapestate_get (tape) < TS_SIZE) &&
- ((*(tape->discipline->event_table))[tapestate_get (tape)][event] != NULL))
- ((*(tape->discipline->event_table))[tapestate_get (tape)][event]) (tape);
+ (tapestate_get (ti) >= 0) &&
+ (tapestate_get (ti) < TS_SIZE) &&
+ ((*(ti->discipline->event_table))[tapestate_get (ti)][event] != NULL))
+ ((*(ti->discipline->event_table))[tapestate_get (ti)][event]) (ti);
else {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,3,"TE UNEXPEC");
#endif /* TAPE_DEBUG */
- tape->discipline->default_handler (tape);
+ ti->discipline->default_handler (ti);
}
}
}
TE_START=0, TE_DONE, TE_FAILED, TE_ERROR, TE_OTHER,
TE_SIZE } tape_events;
+typedef void (*tape_disc_shutdown_t) (int);
typedef void (*tape_event_handler_t) (struct _tape_info_t*);
-typedef ccw_req_t* (*tape_ccwgen_t)(struct _tape_info_t* tape,int count);
-typedef ccw_req_t* (*tape_reqgen_t)(struct request* req,struct _tape_info_t* tape,int tapeblock_major);
-typedef ccw_req_t* (*tape_rwblock_t)(const char* data,size_t count,struct _tape_info_t* tape);
-typedef void (*tape_freeblock_t)(ccw_req_t* cqr,struct _tape_info_t* tape);
+typedef ccw_req_t* (*tape_ccwgen_t)(struct _tape_info_t* ti,int count);
+typedef ccw_req_t* (*tape_reqgen_t)(struct request* req,struct _tape_info_t* ti,int tapeblock_major);
+typedef ccw_req_t* (*tape_rwblock_t)(const char* data,size_t count,struct _tape_info_t* ti);
+typedef void (*tape_freeblock_t)(ccw_req_t* cqr,struct _tape_info_t* ti);
typedef void (*tape_setup_assist_t) (struct _tape_info_t*);
#ifdef CONFIG_DEVFS_FS
typedef void (*tape_devfs_handler_t) (struct _tape_info_t*);
tape_ccwgen_t mtmkpart;
tape_ccwgen_t mtiocget;
tape_ccwgen_t mtiocpos;
+ tape_disc_shutdown_t shutdown;
int (*discipline_ioctl_overload)(struct inode *,struct file*, unsigned int,unsigned long);
tape_event_table_t* event_table;
tape_event_handler_t default_handler;
struct request* current_request;
int blk_retries;
long position;
+ int medium_is_unloaded; // Becomes true when a unload-type operation was issued, false again when medium-insert was detected
ccw_req_t* cqr;
atomic_t bh_scheduled;
struct tq_struct bh_tq;
int tape_setup (tape_info_t * ti, int irq, int minor);
/* functoins for alloc'ing ccw stuff */
-inline ccw_req_t * tape_alloc_ccw_req (tape_info_t* tape, int cplength, int datasize);
+inline ccw_req_t * tape_alloc_ccw_req (tape_info_t* ti, int cplength, int datasize);
void tape_free_request (ccw_req_t * request);
/* a function for dumping device sense info */
#endif
/* functions for handling the status of a device */
-inline void tapestate_set (tape_info_t * tape, int newstate);
-inline int tapestate_get (tape_info_t * tape);
-void tapestate_event (tape_info_t * tape, int event);
+inline void tapestate_set (tape_info_t * ti, int newstate);
+inline int tapestate_get (tape_info_t * ti);
+void tapestate_event (tape_info_t * ti, int event);
extern char* state_verbose[TS_SIZE];
extern char* event_verbose[TE_SIZE];
void
-tape3480_setup_assist (tape_info_t * tape)
+tape3480_setup_assist (tape_info_t * ti)
{
tape3480_disc_data_t *data = NULL;
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"3480 dsetu");
debug_text_event (tape_debug_area,6,"dev:");
- debug_int_event (tape_debug_area,6,tape->blk_minor);
+ debug_int_event (tape_debug_area,6,ti->blk_minor);
#endif /* TAPE_DEBUG */
while (data == NULL)
data = kmalloc (sizeof (tape3480_disc_data_t), GFP_KERNEL);
data->modeset_byte = 0x00;
- tape->discdata = (void *) data;
+ ti->discdata = (void *) data;
+}
+
+
+void
+tape3480_shutdown (int autoprobe) {
+ if (autoprobe)
+ s390_device_unregister(&tape3480_devreg);
}
tape_discipline_t *
-tape3480_init (void)
+tape3480_init (int autoprobe)
{
tape_discipline_t *disc;
#ifdef TAPE_DEBUG
disc->mtmkpart = tape34xx_mtmkpart;
disc->mtiocget = tape34xx_mtiocget;
disc->mtiocpos = tape34xx_mtiocpos;
+ disc->shutdown = tape3480_shutdown;
disc->discipline_ioctl_overload = tape34xx_ioctl_overload;
disc->event_table = &tape3480_event_handler_table;
disc->default_handler = tape34xx_default_handler;
disc->free_bread = tape34xx_free_bread;
disc->tape = NULL; /* pointer for backreference */
disc->next = NULL;
- s390_device_register(&tape3480_devreg);
+ if (autoprobe)
+ s390_device_register(&tape3480_devreg);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"3480 regis");
#endif /* TAPE_DEBUG */
typedef struct _tape3480_disc_data_t {
__u8 modeset_byte;
} tape3480_disc_data_t __attribute__ ((packed, aligned(8)));
-tape_discipline_t * tape3480_init (void);
+tape_discipline_t * tape3480_init (int);
#endif // _TAPE3480_H
};
void
-tape3490_setup_assist (tape_info_t * tape)
+tape3490_setup_assist (tape_info_t * ti)
{
tape3490_disc_data_t *data = NULL;
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"3490 dsetu");
debug_text_event (tape_debug_area,6,"dev:");
- debug_int_event (tape_debug_area,6,tape->blk_minor);
+ debug_int_event (tape_debug_area,6,ti->blk_minor);
#endif /* TAPE_DEBUG */
while (data == NULL)
data = kmalloc (sizeof (tape3490_disc_data_t), GFP_KERNEL);
data->modeset_byte = 0x00;
- tape->discdata = (void *) data;
+ ti->discdata = (void *) data;
}
+
+void
+tape3490_shutdown (int autoprobe) {
+ if (autoprobe)
+ s390_device_unregister(&tape3490_devreg);
+}
+
+
tape_discipline_t *
-tape3490_init (void)
+tape3490_init (int autoprobe)
{
tape_discipline_t *disc;
#ifdef TAPE_DEBUG
disc->mtmkpart = tape34xx_mtmkpart;
disc->mtiocget = tape34xx_mtiocget;
disc->mtiocpos = tape34xx_mtiocpos;
+ disc->shutdown = tape3490_shutdown;
disc->discipline_ioctl_overload = tape34xx_ioctl_overload;
disc->event_table = &tape3490_event_handler_table;
disc->default_handler = tape34xx_default_handler;
disc->free_bread = tape34xx_free_bread;
disc->tape = NULL; /* pointer for backreference */
disc->next = NULL;
- s390_device_register(&tape3490_devreg);
+ if (autoprobe)
+ s390_device_register(&tape3490_devreg);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"3490 regis");
#endif /* TAPE_DEBUG */
typedef struct _tape3490_disc_data_t {
__u8 modeset_byte;
} tape3490_disc_data_t __attribute__ ((packed, aligned(8)));
-tape_discipline_t * tape3490_init (void);
+tape_discipline_t * tape3490_init (int);
#endif // _TAPE3490_H
}
ccw_req_t *
-tape34xx_write_block (const char *data, size_t count, tape_info_t * tape)
+tape34xx_write_block (const char *data, size_t count, tape_info_t * ti)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
void *mem;
- cqr = tape_alloc_ccw_req (tape, 2, 0);
+ cqr = tape_alloc_ccw_req (ti, 2, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xwbl nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = WRITE_CMD;
tape_free_request (cqr);
return NULL;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = mem;
- tape->userbuf = (void *) data;
- tapestate_set (tape, TS_WRI_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = mem;
+ ti->userbuf = (void *) data;
+ tapestate_set (ti, TS_WRI_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xwbl ccwg");
#endif /* TAPE_DEBUG */
}
void
-tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * tape)
+tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * ti)
{
unsigned long lockflags;
ccw1_t *ccw;
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
ccw = cqr->cpaddr;
ccw++;
clear_normalized_cda (ccw);
- kfree (tape->kernbuf);
+ kfree (ti->kernbuf);
tape_free_request (cqr);
- tape->kernbuf = tape->userbuf = NULL;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ ti->kernbuf = ti->userbuf = NULL;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xfwb free");
#endif /* TAPE_DEBUG */
}
ccw_req_t *
-tape34xx_read_block (const char *data, size_t count, tape_info_t * tape)
+tape34xx_read_block (const char *data, size_t count, tape_info_t * ti)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
void *mem;
- cqr = tape_alloc_ccw_req (tape, 2, 0);
+ cqr = tape_alloc_ccw_req (ti, 2, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xrbl nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = READ_FORWARD;
tape_free_request (cqr);
return NULL;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = mem;
- tape->userbuf = (void *) data;
- tapestate_set (tape, TS_RFO_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = mem;
+ ti->userbuf = (void *) data;
+ tapestate_set (ti, TS_RFO_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xrbl ccwg");
#endif /* TAPE_DEBUG */
return cqr;
}
+
ccw_req_t *
-tape34xx_read_opposite (tape_info_t * tape,int novalue)
+tape34xx_read_opposite (tape_info_t * ti,int novalue)
{
ccw_req_t *cqr;
ccw1_t *ccw;
size_t count;
// first, retrieve the count from the old cqr.
- cqr = tape->cqr;
+ cqr = ti->cqr;
ccw = cqr->cpaddr;
ccw++;
count=ccw->count;
clear_normalized_cda (ccw);
tape_free_request (cqr);
// build new cqr
- cqr = tape_alloc_ccw_req (tape, 3, 0);
+ cqr = tape_alloc_ccw_req (ti, 3, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xrop nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = READ_BACKWARD;
ccw->flags = CCW_FLAG_CC;
ccw->count = count;
- set_normalized_cda (ccw, (unsigned long) tape->kernbuf);
+ set_normalized_cda (ccw, (unsigned long) ti->kernbuf);
if ((ccw->cda) == 0) {
tape_free_request (cqr);
return NULL;
ccw->flags = 0;
ccw->count = 1;
ccw->cda = (unsigned long)ccw;
- tapestate_set (tape, TS_RBA_INIT);
+ tapestate_set (ti, TS_RBA_INIT);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xrop ccwg");
#endif /* TAPE_DEBUG */
}
void
-tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * tape)
+tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * ti)
{
unsigned long lockflags;
size_t cpysize;
ccw1_t *ccw;
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
ccw = cqr->cpaddr;
ccw++;
- cpysize = ccw->count - tape->devstat.rescnt;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- if (copy_to_user (tape->userbuf, tape->kernbuf, cpysize)) {
+ cpysize = ccw->count - ti->devstat.rescnt;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ if (copy_to_user (ti->userbuf, ti->kernbuf, cpysize)) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xfrb segf.");
#endif /* TAPE_DEBUG */
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
clear_normalized_cda (ccw);
- kfree (tape->kernbuf);
+ kfree (ti->kernbuf);
tape_free_request (cqr);
- tape->kernbuf = tape->userbuf = NULL;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ ti->kernbuf = ti->userbuf = NULL;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xfrb free");
#endif /* TAPE_DEBUG */
* at the EOT (End of Tape) side of the file mark.
*/
ccw_req_t *
-tape34xx_mtfsf (tape_info_t * tape, int count)
+tape34xx_mtfsf (tape_info_t * ti, int count)
{
long lockflags;
int i;
#endif /* TAPE_DEBUG */
return NULL;
}
- cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+ cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xfsf nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
for (i = 0; i < count; i++) {
ccw->cmd_code = FORSPACEFILE;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_FSF_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_FSF_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xfsf ccwg");
#endif /* TAPE_DEBUG */
* the EOT (End of Tape) side of the last skipped file mark.
*/
ccw_req_t *
-tape34xx_mtbsf (tape_info_t * tape, int count)
+tape34xx_mtbsf (tape_info_t * ti, int count)
{
long lockflags;
int i;
#endif /* TAPE_DEBUG */
return NULL;
}
- cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+ cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xbsf nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
for (i = 0; i < count; i++) {
ccw->cmd_code = BACKSPACEFILE;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_BSF_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_BSF_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xbsf ccwg");
#endif /* TAPE_DEBUG */
* via MTSETBLK.
*/
ccw_req_t *
-tape34xx_mtfsr (tape_info_t * tape, int count)
+tape34xx_mtfsr (tape_info_t * ti, int count)
{
long lockflags;
int i;
#endif /* TAPE_DEBUG */
return NULL;
}
- cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+ cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xfsr nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
for (i = 0; i < count; i++) {
ccw->cmd_code = FORSPACEBLOCK;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_FSB_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_FSB_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xfsr ccwgen");
#endif /* TAPE_DEBUG */
* (blocksize is set via MTSETBLK.
*/
ccw_req_t *
-tape34xx_mtbsr (tape_info_t * tape, int count)
+tape34xx_mtbsr (tape_info_t * ti, int count)
{
long lockflags;
int i;
#endif /* TAPE_DEBUG */
return NULL;
}
- cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+ cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xbsr nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
for (i = 0; i < count; i++) {
ccw->cmd_code = BACKSPACEBLOCK;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_BSB_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_BSB_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xbsr ccwg");
#endif /* TAPE_DEBUG */
* MTWEOF: Write 'count' file marks at the current position.
*/
ccw_req_t *
-tape34xx_mtweof (tape_info_t * tape, int count)
+tape34xx_mtweof (tape_info_t * ti, int count)
{
long lockflags;
int i;
#endif /* TAPE_DEBUG */
return NULL;
}
- cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+ cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xweo nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
for (i = 0; i < count; i++) {
ccw->cmd_code = WRITETAPEMARK;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
ccw++;
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_WTM_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_WTM_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xweo ccwg");
#endif /* TAPE_DEBUG */
* MTREW: Rewind the tape.
*/
ccw_req_t *
-tape34xx_mtrew (tape_info_t * tape, int count)
+tape34xx_mtrew (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 3, 0);
+ cqr = tape_alloc_ccw_req (ti, 3, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xrew nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = REWIND;
ccw->flags = CCW_FLAG_CC;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_REW_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_REW_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xrew ccwg");
#endif /* TAPE_DEBUG */
* Implement 'rewind unload'
*/
ccw_req_t *
-tape34xx_mtoffl (tape_info_t * tape, int count)
+tape34xx_mtoffl (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 3, 32);
+ cqr = tape_alloc_ccw_req (ti, 3, 32);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xoff nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = REWIND_UNLOAD;
ccw->flags = CCW_FLAG_CC;
ccw->flags = 0;
ccw->count = 32;
ccw->cda = (unsigned long) cqr->cpaddr;
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_RUN_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_RUN_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xoff ccwg");
#endif /* TAPE_DEBUG */
* MTNOP: 'No operation'.
*/
ccw_req_t *
-tape34xx_mtnop (tape_info_t * tape, int count)
+tape34xx_mtnop (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 1, 0);
+ cqr = tape_alloc_ccw_req (ti, 1, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xnop nomem");
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) ccw->cmd_code;
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_NOP_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_NOP_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xnop ccwg");
#endif /* TAPE_DEBUG */
* last skipped file mark.
*/
ccw_req_t *
-tape34xx_mtbsfm (tape_info_t * tape, int count)
+tape34xx_mtbsfm (tape_info_t * ti, int count)
{
long lockflags;
int i;
#endif /* TAPE_DEBUG */
return NULL;
}
- cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+ cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xbsm nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
for (i = 0; i < count; i++) {
ccw->cmd_code = BACKSPACEFILE;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_BSF_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_BSF_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xbsm ccwg");
#endif /* TAPE_DEBUG */
* of the last skipped file mark.
*/
ccw_req_t *
-tape34xx_mtfsfm (tape_info_t * tape, int count)
+tape34xx_mtfsfm (tape_info_t * ti, int count)
{
long lockflags;
int i;
#endif /* TAPE_DEBUG */
return NULL;
}
- cqr = tape_alloc_ccw_req (tape, 2 + count, 0);
+ cqr = tape_alloc_ccw_req (ti, 2 + count, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xfsm nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
for (i = 0; i < count; i++) {
ccw->cmd_code = FORSPACEFILE;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_FSF_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_FSF_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xfsm ccwg");
#endif /* TAPE_DEBUG */
* MTRETEN: Retension the tape, i.e. forward space to end of tape and rewind.
*/
ccw_req_t *
-tape34xx_mteom (tape_info_t * tape, int count)
+tape34xx_mteom (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 4, 0);
+ cqr = tape_alloc_ccw_req (ti, 4, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xeom nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = FORSPACEFILE;
ccw->flags = CCW_FLAG_CC;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (cqr->cpaddr);
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_FSF_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_FSF_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xeom ccwg");
#endif /* TAPE_DEBUG */
* MTERASE: erases the tape.
*/
ccw_req_t *
-tape34xx_mterase (tape_info_t * tape, int count)
+tape34xx_mterase (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 5, 0);
+ cqr = tape_alloc_ccw_req (ti, 5, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xera nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = REWIND;
ccw->flags = CCW_FLAG_CC;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_DSE_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_DSE_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xera ccwg");
#endif /* TAPE_DEBUG */
* MTSETDENSITY: set tape density.
*/
ccw_req_t *
-tape34xx_mtsetdensity (tape_info_t * tape, int count)
+tape34xx_mtsetdensity (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 2, 0);
+ cqr = tape_alloc_ccw_req (ti, 2, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xden nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = NOP;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_NOP_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_NOP_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xden ccwg");
#endif /* TAPE_DEBUG */
* MTSEEK: seek to the specified block.
*/
ccw_req_t *
-tape34xx_mtseek (tape_info_t * tape, int count)
+tape34xx_mtseek (tape_info_t * ti, int count)
{
long lockflags;
__u8 *data;
kfree(data);
return NULL;
}
- if (((tape34xx_disc_data_t *) tape->discdata)->modeset_byte & 0x08) // IDRC on
+ if (((tape34xx_disc_data_t *) ti->discdata)->modeset_byte & 0x08) // IDRC on
data[1] = data[1] | 0x80;
data[3] += count % 256;
debug_text_event (tape_debug_area,6,"xsee id:");
debug_int_event (tape_debug_area,6,count);
#endif /* TAPE_DEBUG */
- cqr = tape_alloc_ccw_req (tape, 3, 0);
+ cqr = tape_alloc_ccw_req (ti, 3, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xsee nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = LOCATE;
ccw->flags = CCW_FLAG_CC;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = data;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_LBL_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = data;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_LBL_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xsee ccwg");
#endif /* TAPE_DEBUG */
* MTTELL: Tell block. Return the number of block relative to current file.
*/
ccw_req_t *
-tape34xx_mttell (tape_info_t * tape, int count)
+tape34xx_mttell (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
void *mem;
- cqr = tape_alloc_ccw_req (tape, 2, 0);
+ cqr = tape_alloc_ccw_req (ti, 2, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xtel nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = READ_BLOCK_ID;
ccw->flags = 0;
ccw->count = 8;
set_normalized_cda (ccw, (unsigned long) mem);
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = mem;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_RBI_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = mem;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_RBI_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xtel ccwg");
#endif /* TAPE_DEBUG */
* Implement NOP.
*/
ccw_req_t *
-tape34xx_mtsetdrvbuffer (tape_info_t * tape, int count)
+tape34xx_mtsetdrvbuffer (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 2, 0);
+ cqr = tape_alloc_ccw_req (ti, 2, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xbuf nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = NOP;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_NOP_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_NOP_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xbuf ccwg");
#endif /* TAPE_DEBUG */
* Implement NOP CCW command.
*/
ccw_req_t *
-tape34xx_mtlock (tape_info_t * tape, int count)
+tape34xx_mtlock (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 2, 0);
+ cqr = tape_alloc_ccw_req (ti, 2, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xloc nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = NOP;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_NOP_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_NOP_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xloc ccwg");
#endif /* TAPE_DEBUG */
* Implement the NOP CCW command.
*/
ccw_req_t *
-tape34xx_mtunlock (tape_info_t * tape, int count)
+tape34xx_mtunlock (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 2, 0);
+ cqr = tape_alloc_ccw_req (ti, 2, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xulk nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = NOP;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_NOP_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_NOP_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xulk ccwg");
#endif /* TAPE_DEBUG */
/*
* MTLOAD: Loads the tape.
- * Implement the NOP CCW command.
+ * This function is not implemented and returns NULL, which causes the Frontend to wait for a medium being loaded.
+ * The 3480/3490 type Tapes do not support a load command
*/
ccw_req_t *
-tape34xx_mtload (tape_info_t * tape, int count)
+tape34xx_mtload (tape_info_t * ti, int count)
{
- long lockflags;
- ccw_req_t *cqr;
- ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 2, 0);
- if (!cqr) {
-#ifdef TAPE_DEBUG
- debug_text_exception (tape_debug_area,6,"xloa nomem");
-#endif /* TAPE_DEBUG */
- return NULL;
- }
- ccw = cqr->cpaddr;
- ccw->cmd_code = MODE_SET_DB;
- ccw->flags = CCW_FLAG_CC;
- ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
- ccw++;
- ccw->cmd_code = NOP;
- ccw->flags = 0;
- ccw->count = 0;
- ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_NOP_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
-#ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"xloa ccwg");
-#endif /* TAPE_DEBUG */
- return cqr;
+ return NULL;
}
/*
* MTUNLOAD: Rewind the tape and unload it.
*/
ccw_req_t *
-tape34xx_mtunload (tape_info_t * tape, int count)
+tape34xx_mtunload (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 3, 32);
+ cqr = tape_alloc_ccw_req (ti, 3, 32);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xunl nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = REWIND_UNLOAD;
ccw->flags = CCW_FLAG_CC;
ccw->flags = 0;
ccw->count = 32;
ccw->cda = (unsigned long) cqr->cpaddr;
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_RUN_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_RUN_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xunl ccwg");
#endif /* TAPE_DEBUG */
* Sets the IDRC on/off.
*/
ccw_req_t *
-tape34xx_mtcompression (tape_info_t * tape, int count)
+tape34xx_mtcompression (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
return NULL;
}
if (count == 0)
- ((tape34xx_disc_data_t *) tape->discdata)->modeset_byte = 0x00; // IDRC off
+ ((tape34xx_disc_data_t *) ti->discdata)->modeset_byte = 0x00; // IDRC off
else
- ((tape34xx_disc_data_t *) tape->discdata)->modeset_byte = 0x08; // IDRC on
+ ((tape34xx_disc_data_t *) ti->discdata)->modeset_byte = 0x08; // IDRC on
- cqr = tape_alloc_ccw_req (tape, 2, 0);
+ cqr = tape_alloc_ccw_req (ti, 2, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xcom nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = NOP;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_NOP_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_NOP_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xcom ccwg");
#endif /* TAPE_DEBUG */
* Implement the NOP CCW command.
*/
ccw_req_t *
-tape34xx_mtsetpart (tape_info_t * tape, int count)
+tape34xx_mtsetpart (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 2, 0);
+ cqr = tape_alloc_ccw_req (ti, 2, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xspa nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = NOP;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_NOP_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_NOP_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xspa ccwg");
#endif /* TAPE_DEBUG */
* Implement the NOP CCW command.
*/
ccw_req_t *
-tape34xx_mtmkpart (tape_info_t * tape, int count)
+tape34xx_mtmkpart (tape_info_t * ti, int count)
{
long lockflags;
ccw_req_t *cqr;
ccw1_t *ccw;
- cqr = tape_alloc_ccw_req (tape, 2, 0);
+ cqr = tape_alloc_ccw_req (ti, 2, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xnpa nomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
ccw++;
ccw->cmd_code = NOP;
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = NULL;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_NOP_INIT);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = NULL;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_NOP_INIT);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xnpa ccwg");
#endif /* TAPE_DEBUG */
* MTIOCGET: query the tape drive status.
*/
ccw_req_t *
-tape34xx_mtiocget (tape_info_t * tape, int count)
+tape34xx_mtiocget (tape_info_t * ti, int count)
{
return NULL;
}
* MTIOCPOS: query the tape position.
*/
ccw_req_t *
-tape34xx_mtiocpos (tape_info_t * tape, int count)
+tape34xx_mtiocpos (tape_info_t * ti, int count)
{
return NULL;
}
-ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* tape,int tapeblock_major) {
+ccw_req_t * tape34xx_bread (struct request *req,tape_info_t* ti,int tapeblock_major) {
ccw_req_t *cqr;
ccw1_t *ccw;
__u8 *data;
- int s2b = blksize_size[tapeblock_major][tape->blk_minor]/hardsect_size[tapeblock_major][tape->blk_minor];
+ int s2b = blksize_size[tapeblock_major][ti->blk_minor]/hardsect_size[tapeblock_major][ti->blk_minor];
int realcount;
int size,bhct = 0;
struct buffer_head* bh;
for (bh = req->bh; bh; bh = bh->b_reqnext) {
- if (bh->b_size > blksize_size[tapeblock_major][tape->blk_minor])
- for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][tape->blk_minor])
+ if (bh->b_size > blksize_size[tapeblock_major][ti->blk_minor])
+ for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][ti->blk_minor])
bhct++;
else
bhct++;
data[0] = 0x01;
data[1] = data[2] = data[3] = 0x00;
realcount=req->sector/s2b;
- if (((tape34xx_disc_data_t *) tape->discdata)->modeset_byte & 0x08) // IDRC on
+ if (((tape34xx_disc_data_t *) ti->discdata)->modeset_byte & 0x08) // IDRC on
data[1] = data[1] | 0x80;
data[3] += realcount % 256;
debug_text_event (tape_debug_area,6,"xBREDid:");
debug_int_event (tape_debug_area,6,realcount);
#endif /* TAPE_DEBUG */
- cqr = tape_alloc_ccw_req (tape, 2+bhct+1, 0);
+ cqr = tape_alloc_ccw_req (ti, 2+bhct+1, 0);
if (!cqr) {
#ifdef TAPE_DEBUG
debug_text_exception (tape_debug_area,6,"xBREDnomem");
ccw->cmd_code = MODE_SET_DB;
ccw->flags = CCW_FLAG_CC;
ccw->count = 1;
- set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)));
- if (realcount!=tape->position) {
+ set_normalized_cda (ccw, (unsigned long) (&(((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)));
+ if (realcount!=ti->position) {
ccw++;
ccw->cmd_code = LOCATE;
ccw->flags = CCW_FLAG_CC;
ccw->count = 4;
set_normalized_cda (ccw, (unsigned long) data);
}
- tape->position=realcount+req->nr_sectors/s2b;
+ ti->position=realcount+req->nr_sectors/s2b;
for (bh=req->bh;bh!=NULL;) {
ccw->flags = CCW_FLAG_CC;
- if (bh->b_size >= blksize_size[tapeblock_major][tape->blk_minor]) {
- for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][tape->blk_minor]) {
+ if (bh->b_size >= blksize_size[tapeblock_major][ti->blk_minor]) {
+ for (size = 0; size < bh->b_size; size += blksize_size[tapeblock_major][ti->blk_minor]) {
ccw++;
ccw->flags = CCW_FLAG_CC;
ccw->cmd_code = READ_FORWARD;
- ccw->count = blksize_size[tapeblock_major][tape->blk_minor];
+ ccw->count = blksize_size[tapeblock_major][ti->blk_minor];
set_normalized_cda (ccw, __pa (bh->b_data + size));
}
bh = bh->b_reqnext;
} else { /* group N bhs to fit into byt_per_blk */
- for (size = 0; bh != NULL && size < blksize_size[tapeblock_major][tape->blk_minor];) {
+ for (size = 0; bh != NULL && size < blksize_size[tapeblock_major][ti->blk_minor];) {
ccw++;
ccw->flags = CCW_FLAG_DC;
ccw->cmd_code = READ_FORWARD;
size += bh->b_size;
bh = bh->b_reqnext;
}
- if (size != blksize_size[tapeblock_major][tape->blk_minor]) {
+ if (size != blksize_size[tapeblock_major][ti->blk_minor]) {
PRINT_WARN ("Cannot fulfill small request %d vs. %d (%ld sects)\n",
size,
- blksize_size[tapeblock_major][tape->blk_minor],
+ blksize_size[tapeblock_major][ti->blk_minor],
req->nr_sectors);
kfree(data);
tape_free_request (cqr);
ccw->flags = 0;
ccw->count = 0;
ccw->cda = (unsigned long) (&(ccw->cmd_code));
- tape->kernbuf = data;
- tape->userbuf = NULL;
- tapestate_set (tape, TS_BLOCK_INIT);
+ ti->kernbuf = data;
+ ti->userbuf = NULL;
+ tapestate_set (ti, TS_BLOCK_INIT);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xBREDccwg");
#endif /* TAPE_DEBUG */
return cqr;
}
-void tape34xx_free_bread (ccw_req_t* cqr,struct _tape_info_t* tape) {
+void tape34xx_free_bread (ccw_req_t* cqr,struct _tape_info_t* ti) {
ccw1_t* ccw;
for (ccw=(ccw1_t*)cqr->cpaddr;(ccw->flags & CCW_FLAG_CC)||(ccw->flags & CCW_FLAG_DC);ccw++)
if ((ccw->cmd_code == MODE_SET_DB) ||
(ccw->cmd_code == READ_FORWARD))
clear_normalized_cda(ccw);
tape_free_request(cqr);
- kfree(tape->kernbuf);
- tape->kernbuf=NULL;
+ kfree(ti->kernbuf);
+ ti->kernbuf=NULL;
}
/* event handlers */
void
-tape34xx_default_handler (tape_info_t * tape)
+tape34xx_default_handler (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"xdefhandle");
#endif /* TAPE_DEBUG */
- tapestate_set (tape, TS_FAILED);
PRINT_ERR ("TAPE34XX: An unexpected Unit Check occurred.\n");
PRINT_ERR ("TAPE34XX: Please read Documentation/s390/TAPE and report it!\n");
PRINT_ERR ("TAPE34XX: Current state is: %s",
- (((tapestate_get (tape) < TS_SIZE) && (tapestate_get (tape) >= 0)) ?
- state_verbose[tapestate_get (tape)] : "->UNKNOWN STATE<-"));
- tape_dump_sense (&tape->devstat);
- tape->rc = -EIO;
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ (((tapestate_get (ti) < TS_SIZE) && (tapestate_get (ti) >= 0)) ?
+ state_verbose[tapestate_get (ti)] : "->UNKNOWN STATE<-"));
+ tape_dump_sense (&ti->devstat);
+ ti->rc = -EIO;
+ ti->wanna_wakeup=1;
+ switch (tapestate_get(ti)) {
+ case TS_REW_RELEASE_INIT:
+ tapestate_set(ti,TS_FAILED);
+ wake_up (&ti->wq);
+ break;
+ case TS_BLOCK_INIT:
+ tapestate_set(ti,TS_FAILED);
+ schedule_tapeblock_exec_IO(ti);
+ break;
+ default:
+ tapestate_set(ti,TS_FAILED);
+ wake_up_interruptible (&ti->wq);
+ }
}
void
-tape34xx_unexpect_uchk_handler (tape_info_t * tape)
+tape34xx_unexpect_uchk_handler (tape_info_t * ti)
{
- if ((tape->devstat.ii.sense.data[0] == 0x40) &&
- (tape->devstat.ii.sense.data[1] == 0x40) &&
- (tape->devstat.ii.sense.data[3] == 0x43)) {
+ if ((ti->devstat.ii.sense.data[0] == 0x40) &&
+ (ti->devstat.ii.sense.data[1] == 0x40) &&
+ (ti->devstat.ii.sense.data[3] == 0x43)) {
// no tape in the drive
- PRINT_INFO ("Drive %d not ready. No volume loaded.\n", tape->rew_minor / 2);
+ PRINT_INFO ("Drive %d not ready. No volume loaded.\n", ti->rew_minor / 2);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"xuuh nomed");
#endif /* TAPE_DEBUG */
- tapestate_set (tape, TS_FAILED);
- tape->rc = -ENOMEDIUM;
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
- } else if ((tape->devstat.ii.sense.data[0] == 0x42) &&
- (tape->devstat.ii.sense.data[1] == 0x44) &&
- (tape->devstat.ii.sense.data[3] == 0x3b)) {
+ tapestate_set (ti, TS_FAILED);
+ ti->rc = -ENOMEDIUM;
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
+ } else if ((ti->devstat.ii.sense.data[0] == 0x42) &&
+ (ti->devstat.ii.sense.data[1] == 0x44) &&
+ (ti->devstat.ii.sense.data[3] == 0x3b)) {
PRINT_INFO ("Media in drive %d was changed!\n",
- tape->rew_minor / 2);
+ ti->rew_minor / 2);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"xuuh medchg");
#endif
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"xuuh unexp");
debug_text_event (tape_debug_area,3,"state:");
- debug_text_event (tape_debug_area,3,((tapestate_get (tape) < TS_SIZE) &&
- (tapestate_get (tape) >= 0)) ?
- state_verbose[tapestate_get (tape)] :
+ debug_text_event (tape_debug_area,3,((tapestate_get (ti) < TS_SIZE) &&
+ (tapestate_get (ti) >= 0)) ?
+ state_verbose[tapestate_get (ti)] :
"TS UNKNOWN");
#endif /* TAPE_DEBUG */
- tape34xx_default_handler (tape);
+ tape34xx_default_handler (ti);
}
}
void
-tape34xx_unused_done (tape_info_t * tape)
+tape34xx_unused_done (tape_info_t * ti)
{
- if ((tape->devstat.ii.sense.data[0] == 0x40) &&
- (tape->devstat.ii.sense.data[1] == 0x40) &&
- (tape->devstat.ii.sense.data[3] == 0x43)) {
- // A medium was inserted in the drive!
+ if (ti->medium_is_unloaded) {
+ // A medium was inserted in the drive!
#ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,6,"xuud med");
+ debug_text_event (tape_debug_area,6,"xuui med");
#endif /* TAPE_DEBUG */
- } else {
+ PRINT_WARN ("A medium was inserted into the tape.\n");
+ ti->medium_is_unloaded=0;
+ } else {
#ifdef TAPE_DEBUG
- debug_text_event (tape_debug_area,3,"unsol.irq!");
- debug_text_event (tape_debug_area,3,"dev end");
- debug_int_exception (tape_debug_area,3,tape->devinfo.irq);
+ debug_text_event (tape_debug_area,3,"unsol.irq!");
+ debug_text_event (tape_debug_area,3,"dev end");
+ debug_int_exception (tape_debug_area,3,ti->devinfo.irq);
#endif /* TAPE_DEBUG */
- PRINT_WARN ("Unsolicited IRQ (Device End) caught in unused state.\n");
- tape_dump_sense (&tape->devstat);
- }
+ PRINT_WARN ("Unsolicited IRQ (Device End) caught in unused state.\n");
+ tape_dump_sense (&ti->devstat);
+ }
}
void
-tape34xx_idle_done (tape_info_t * tape)
+tape34xx_idle_done (tape_info_t * ti)
{
+ if (ti->medium_is_unloaded) {
+ // A medium was inserted in the drive!
+#ifdef TAPE_DEBUG
+ debug_text_event (tape_debug_area,6,"xuud med");
+#endif /* TAPE_DEBUG */
+ PRINT_WARN ("A medium was inserted into the tape.\n");
+ ti->medium_is_unloaded=0;
+ wake_up_interruptible (&ti->wq);
+ } else {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"unsol.irq!");
debug_text_event (tape_debug_area,3,"dev end");
- debug_int_exception (tape_debug_area,3,tape->devinfo.irq);
+ debug_int_exception (tape_debug_area,3,ti->devinfo.irq);
#endif /* TAPE_DEBUG */
PRINT_WARN ("Unsolicited IRQ (Device End) caught in idle state.\n");
- tape_dump_sense (&tape->devstat);
+ tape_dump_sense (&ti->devstat);
+ }
}
void
-tape34xx_block_done (tape_info_t * tape)
+tape34xx_block_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"x:bREQdone");
#endif /* TAPE_DEBUG */
- tapestate_set(tape,TS_DONE);
- schedule_tapeblock_exec_IO(tape);
+ tapestate_set(ti,TS_DONE);
+ schedule_tapeblock_exec_IO(ti);
}
void
-tape34xx_bsf_init_done (tape_info_t * tape)
+tape34xx_bsf_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"bsf done");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
void
-tape34xx_dse_init_done (tape_info_t * tape)
+tape34xx_dse_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"dse done");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
void
-tape34xx_fsf_init_done (tape_info_t * tape)
+tape34xx_fsf_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"fsf done");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
void
-tape34xx_fsb_init_done (tape_info_t * tape)
+tape34xx_fsb_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"fsb done");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
void
-tape34xx_bsb_init_done (tape_info_t * tape)
+tape34xx_bsb_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"bsb done");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
void
-tape34xx_lbl_init_done (tape_info_t * tape)
+tape34xx_lbl_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"lbl done");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
//s390irq_spin_unlock(tape->devinfo.irq);
- tape->wanna_wakeup=1;
- wake_up (&tape->wq);
+ ti->wanna_wakeup=1;
+ wake_up (&ti->wq);
}
void
-tape34xx_nop_init_done (tape_info_t * tape)
+tape34xx_nop_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"nop done..");
debug_text_exception (tape_debug_area,6,"or rew/rel");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
//s390irq_spin_unlock(tape->devinfo.irq);
- tape->wanna_wakeup=1;
- wake_up (&tape->wq);
+ ti->wanna_wakeup=1;
+ wake_up (&ti->wq);
}
void
-tape34xx_rfo_init_done (tape_info_t * tape)
+tape34xx_rfo_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"rfo done");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
void
-tape34xx_rbi_init_done (tape_info_t * tape)
+tape34xx_rbi_init_done (tape_info_t * ti)
{
__u8 *data;
+#ifdef TAPE_DEBUG
int i;
- tapestate_set (tape, TS_FAILED);
- data = tape->kernbuf;
- tape->rc = data[3];
- tape->rc += 256 * data[2];
- tape->rc += 65536 * (data[1] & 0x3F);
+#endif
+ tapestate_set (ti, TS_FAILED);
+ data = ti->kernbuf;
+ ti->rc = data[3];
+ ti->rc += 256 * data[2];
+ ti->rc += 65536 * (data[1] & 0x3F);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"rbi done");
debug_text_event (tape_debug_area,6,"data:");
for (i=0;i<8;i++)
debug_int_event (tape_debug_area,6,data[i]);
#endif
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
void
-tape34xx_rew_init_done (tape_info_t * tape)
+tape34xx_rew_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"rew done");
#endif
//BH: use irqsave
//s390irq_spin_lock(tape->devinfo.irq);
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
//s390irq_spin_unlock(tape->devinfo.irq);
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
void
-tape34xx_rew_release_init_done (tape_info_t * tape)
+tape34xx_rew_release_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"rewR done");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
//s390irq_spin_unlock(tape->devinfo.irq);
- tape->wanna_wakeup=1;
- wake_up (&tape->wq);
+ ti->wanna_wakeup=1;
+ wake_up (&ti->wq);
}
void
-tape34xx_run_init_done (tape_info_t * tape)
+tape34xx_run_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"rew done");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
void
-tape34xx_wri_init_done (tape_info_t * tape)
+tape34xx_wri_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"wri done");
#endif
//BH: use irqsave
- //s390irq_spin_lock(tape->devinfo.irq);
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
- //s390irq_spin_unlock(tape->devinfo.irq);
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ //s390irq_spin_lock(ti->devinfo.irq);
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
+ //s390irq_spin_unlock(ti->devinfo.irq);
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
void
-tape34xx_wtm_init_done (tape_info_t * tape)
+tape34xx_wtm_init_done (tape_info_t * ti)
{
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"wtm done");
#endif
- tapestate_set (tape, TS_DONE);
- tape->rc = 0;
- tape->wanna_wakeup=1;
- wake_up_interruptible (&tape->wq);
+ tapestate_set (ti, TS_DONE);
+ ti->rc = 0;
+ ti->wanna_wakeup=1;
+ wake_up_interruptible (&ti->wq);
}
/* This function analyses the tape's sense-data in case of a unit-check. If possible,
it tries to recover from the error. Else the user is informed about the problem. */
void
-tape34xx_error_recovery (tape_info_t* tape)
+tape34xx_error_recovery (tape_info_t* ti)
{
- __u8* sense=tape->devstat.ii.sense.data;
+ __u8* sense=ti->devstat.ii.sense.data;
int inhibit_cu_recovery=0;
- int cu_type=tape->discipline->cu_type;
- if ((((tape34xx_disc_data_t *) tape->discdata)->modeset_byte)&0x80) inhibit_cu_recovery=1;
- if (tapestate_get(tape)==TS_BLOCK_INIT) {
+ int cu_type=ti->discipline->cu_type;
+ if ((((tape34xx_disc_data_t *) ti->discdata)->modeset_byte)&0x80) inhibit_cu_recovery=1;
+ if (tapestate_get(ti)==TS_BLOCK_INIT) {
// no recovery for block device, bottom half will retry...
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
}
if (sense[0]&SENSE_COMMAND_REJECT)
- switch (tapestate_get(tape)) {
+ switch (tapestate_get(ti)) {
case TS_BLOCK_INIT:
case TS_DSE_INIT:
case TS_EGA_INIT:
case TS_WTM_INIT:
if (sense[1]&SENSE_WRITE_PROTECT) {
// trying to write, but medium is write protected
- tape34xx_error_recovery_has_failed(tape,EACCES);
+ tape34xx_error_recovery_has_failed(ti,EACCES);
return;
}
default:
- tape34xx_error_recovery_HWBUG(tape,1);
+ tape34xx_error_recovery_HWBUG(ti,1);
return;
}
// special cases for various tape-states when reaching end of recorded area
if (((sense[0]==0x08) || (sense[0]==0x10) || (sense[0]==0x12)) &&
((sense[1]==0x40) || (sense[1]==0x0c)))
- switch (tapestate_get(tape)) {
+ switch (tapestate_get(ti)) {
case TS_FSF_INIT:
// Trying to seek beyond end of recorded area
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case TS_LBL_INIT:
// Block could not be located.
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case TS_RFO_INIT:
// Try to read beyond end of recorded area -> 0 bytes read
- tape34xx_error_recovery_has_failed(tape,0);
+ tape34xx_error_recovery_has_failed(ti,0);
return;
}
// Sensing special bits
if (sense[0]&SENSE_BUS_OUT_CHECK) {
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
}
if (sense[0]&SENSE_DATA_CHECK) {
(inhibit_cu_recovery)) {
// data check is not permanent, may be recovered.
// We always use async-mode with cu-recovery, so this should *never* happen.
- tape34xx_error_recovery_HWBUG(tape,2);
+ tape34xx_error_recovery_HWBUG(ti,2);
return;
} else {
// data check is permanent, CU recovery has failed
PRINT_WARN("Permanent read error, recovery failed!\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
}
case 0x25:
(inhibit_cu_recovery)) {
// data check is not permanent, may be recovered.
// We always use async-mode with cu-recovery, so this should *never* happen.
- tape34xx_error_recovery_HWBUG(tape,3);
+ tape34xx_error_recovery_HWBUG(ti,3);
return;
} else {
// data check is permanent, cu-recovery has failed
PRINT_WARN("Permanent write error, recovery failed!\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
}
case 0x26:
// Data Check (read opposite) occurred. We'll recover this.
- tape34xx_error_recovery_read_opposite(tape);
+ tape34xx_error_recovery_read_opposite(ti);
return;
case 0x28:
// The ID-Mark at the beginning of the tape could not be written. This is fatal, we'll report and exit.
PRINT_WARN("ID-Mark could not be written. Check your hardware!\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x31:
// Tape void. Tried to read beyond end of device. We'll report and exit.
PRINT_WARN("Try to read beyond end of recorded area!\n");
- tape34xx_error_recovery_has_failed(tape,ENOSPC);
+ tape34xx_error_recovery_has_failed(ti,ENOSPC);
return;
case 0x41:
// Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit.
PRINT_WARN("Illegal block-id sequence found!\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
default:
// well, all data checks for 3480 should result in one of the above erpa-codes. if not -> bug
// On 3490, other data-check conditions do exist.
if (cu_type==0x3480) {
- tape34xx_error_recovery_HWBUG(tape,4);
+ tape34xx_error_recovery_HWBUG(ti,4);
return;
}
}
switch (sense[3]) {
case 0x40: // overrun error
PRINT_WARN ("Data overrun error between control-unit and drive. Use a faster channel connection, if possible! \n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
default:
// Overrun bit is set, but erpa does not show overrun error. This is a bug.
- tape34xx_error_recovery_HWBUG(tape,5);
+ tape34xx_error_recovery_HWBUG(ti,5);
return;
}
}
case 0x41:
// Record sequence error. cu detected incorrect block-id sequence on tape. We'll report and exit.
PRINT_WARN("Illegal block-id sequence found!\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
default:
// Record sequence error bit is set, but erpa does not show record sequence error. This is a bug.
- tape34xx_error_recovery_HWBUG(tape,6);
+ tape34xx_error_recovery_HWBUG(ti,6);
return;
}
}
case 0x21:
// Data streaming not operational. Cu switches to interlock mode, we reissue the command.
PRINT_WARN ("Data streaming not operational. Switching to interlock-mode! \n");
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x22:
// Path equipment check. Might be drive adapter error, buffer error on the lower interface, internal path not useable, or error during cartridge load.
// All of the above are not recoverable
PRINT_WARN ("A path equipment check occurred. One of the following conditions occurred:\n");
PRINT_WARN ("drive adapter error,buffer error on the lower interface, internal path not useable, error during cartridge load.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x23:
// Read data check. Should have been be covered earlier -> Bug!
- tape34xx_error_recovery_HWBUG(tape,7);
+ tape34xx_error_recovery_HWBUG(ti,7);
return;
case 0x24:
// Load display check. Load display was command was issued, but the drive is displaying a drive check message. Can be threated as "device end".
- tape34xx_error_recovery_succeded(tape);
+ tape34xx_error_recovery_succeded(ti);
return;
case 0x25:
// Write data check. Should have been covered earlier -> Bug!
- tape34xx_error_recovery_HWBUG(tape,8);
+ tape34xx_error_recovery_HWBUG(ti,8);
return;
case 0x26:
// Data check (read opposite). Should have been covered earlier -> Bug!
- tape34xx_error_recovery_HWBUG(tape,9);
+ tape34xx_error_recovery_HWBUG(ti,9);
return;
case 0x27:
// Command reject. May indicate illegal channel program or buffer over/underrun.
// Since all channel programms are issued by this driver and ought be correct,
// we assume a over/underrun situaltion and retry the channel program.
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x28:
// Write id mark check. Should have beed covered earlier -> bug!
- tape34xx_error_recovery_HWBUG(tape,10);
+ tape34xx_error_recovery_HWBUG(ti,10);
return;
case 0x29:
// Function incompatible. Either idrc is on but hardware not capable doing idrc
// or a perform subsystem func is issued and the cu is not online. Anyway, this
// cannot be recovered and is an I/O error.
PRINT_WARN ("Function incompatible. Try to switch off idrc! \n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x2a:
// Unsolicited environmental data. An internal counter overflows, we can ignore
// this and reissue the cmd.
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x2b:
// Environmental data present. Indicates either unload completed ok or read buffered
// log command completed ok.
- if (tapestate_get(tape)==TS_RUN_INIT) {
+ if (tapestate_get(ti)==TS_RUN_INIT) {
// Rewind unload completed ok.
- tape34xx_error_recovery_succeded(tape);
+ tape34xx_error_recovery_succeded(ti);
return;
}
// Since we do not issue read buffered log commands, this should never occur -> bug.
- tape34xx_error_recovery_HWBUG(tape,11);
+ tape34xx_error_recovery_HWBUG(ti,11);
return;
case 0x2c:
// Permanent equipment check. cu has tried recovery, but did not succeed. This is an
// I/O error.
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x2d:
// Data security erase failure.
- if (tapestate_get(tape)==TS_DSE_INIT) {
+ if (tapestate_get(ti)==TS_DSE_INIT) {
// report an I/O error
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
}
// Data security erase failure, but no such command issued. This is a bug.
- tape34xx_error_recovery_HWBUG(tape,12);
+ tape34xx_error_recovery_HWBUG(ti,12);
return;
case 0x2e:
// Not capable. This indicates either that the drive fails reading the format id mark
// or that that format specified is not supported by the drive. We write a message and
// return an I/O error.
PRINT_WARN("Drive not capable processing the tape format!");
- tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+ tape34xx_error_recovery_has_failed(ti,EMEDIUMTYPE);
return;
case 0x2f:
// This erpa is reserved. This is a bug.
- tape34xx_error_recovery_HWBUG(tape,13);
+ tape34xx_error_recovery_HWBUG(ti,13);
return;
case 0x30:
// The medium is write protected, while trying to write on it. We'll report this.
PRINT_WARN("Medium is write protected!\n");
- tape34xx_error_recovery_has_failed(tape,EACCES);
+ tape34xx_error_recovery_has_failed(ti,EACCES);
return;
case 0x31:
// Tape void. Should have beed covered ealier -> bug
- tape34xx_error_recovery_HWBUG(tape,14);
+ tape34xx_error_recovery_HWBUG(ti,14);
return;
case 0x32:
// Tension loss. We cannot recover this, it's an I/O error.
PRINT_WARN("The drive lost tape tension.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x33:
// Load Failure. The catridge was not inserted correctly or the tape is not threaded
// correctly. We cannot recover this, the user has to reload the catridge.
PRINT_WARN("Cartridge load failure. Reload the cartridge and try again.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x34:
// Unload failure. The drive cannot maintain tape tension and control tape movement
// during an unload operation.
PRINT_WARN("Failure during cartridge unload. Please try manually.\n");
- if (tapestate_get(tape)!=TS_RUN_INIT) {
- tape34xx_error_recovery_HWBUG(tape,15);
+ if (tapestate_get(ti)!=TS_RUN_INIT) {
+ tape34xx_error_recovery_HWBUG(ti,15);
return;
}
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x35:
// Drive equipment check. One of the following:
// - the cartridge loader does not respond correctly
// - a failure occurs during an index, load, or unload cycle
PRINT_WARN("Equipment check! Please check the drive and the cartridge loader.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x36:
switch (cu_type) {
case 0x3480:
// This erpa is reserved for 3480 -> BUG
- tape34xx_error_recovery_HWBUG(tape,16);
+ tape34xx_error_recovery_HWBUG(ti,16);
return;
case 0x3490:
// End of data. This is a permanent I/O error, which cannot be recovered.
// A read-type command has reached the end-of-data mark.
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
}
case 0x37:
// Tape length error. The tape is shorter than reported in the beginning-of-tape data.
PRINT_WARN("Tape length error.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x38:
// Physical end of tape. A read/write operation reached the physical end of tape.
- if (tapestate_get(tape)==TS_WRI_INIT) {
- tape34xx_error_recovery_has_failed(tape,ENOSPC);
+ if (tapestate_get(ti)==TS_WRI_INIT) {
+ tape34xx_error_recovery_has_failed(ti,ENOSPC);
}
return;
case 0x39:
// Backward at BOT. The drive is at BOT and is requestet to move backward.
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x3a:
// Drive switched not ready, but the command needs the drive to be ready.
PRINT_WARN("Drive not ready. Turn the ready/not ready switch to ready position and try again.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x3b:
// Manual rewind or unload. This causes an I/O error.
- PRINT_WARN("Medium is rewinded or unloaded manually.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ PRINT_WARN("Medium was rewound or unloaded manually. Expect errors! Please do only use the mtoffl and mtrew ioctl to unload tapes or rewind tapes.\n");
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x3c:
case 0x3d:
case 0x3e:
case 0x3f:
// These erpas are reserved -> BUG
- tape34xx_error_recovery_HWBUG(tape,17);
+ tape34xx_error_recovery_HWBUG(ti,17);
return;
case 0x40:
// Overrun error. This should have been covered earlier -> bug.
- tape34xx_error_recovery_HWBUG(tape,18);
+ tape34xx_error_recovery_HWBUG(ti,18);
return;
case 0x41:
// Record sequence error. This should have been covered earlier -> bug.
- tape34xx_error_recovery_HWBUG(tape,19);
+ tape34xx_error_recovery_HWBUG(ti,19);
return;
case 0x42:
// Degraded mode. A condition that can cause degraded performace is detected.
PRINT_WARN("Subsystem is running in degraded mode. This may compromise your performace.\n");
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x43:
// Drive not ready. Probably swith the ready/not ready switch to ready?
PRINT_WARN("The drive is not ready. Maybe no medium in?\n");
- tape34xx_error_recovery_has_failed(tape,ENOMEDIUM);
+ tape34xx_error_recovery_has_failed(ti,ENOMEDIUM);
return;
case 0x44:
// Locate Block unsuccessfull. We'll report this.
- if ((tapestate_get(tape)!=TS_BLOCK_INIT) &&
- (tapestate_get(tape)!=TS_LBL_INIT)) {
- tape34xx_error_recovery_HWBUG(tape,20); // No locate block was issued...
+ if ((tapestate_get(ti)!=TS_BLOCK_INIT) &&
+ (tapestate_get(ti)!=TS_LBL_INIT)) {
+ tape34xx_error_recovery_HWBUG(ti,20); // No locate block was issued...
return;
}
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x45:
// The drive is assigned elsewhere [to a different channel path/computer].
PRINT_WARN("The drive is assigned elsewhere.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x46:
// Drive not online. Drive may be switched offline, the power supply may be switched off
// or the drive address may not be set correctly.
PRINT_WARN("The drive is not online.");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x47:
// Volume fenced. cu reports volume integrity is lost!
PRINT_WARN("Volume fenced. The volume integrity is lost! \n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x48:
// Log sense data and retry request. We'll do so...
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x49:
// Bus out check. A parity check error on the bus was found. PRINT_WARN("Bus out check. A data transfer over the bus was corrupted.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x4a:
// Control unit erp failed. We'll report this.
PRINT_WARN("The control unit failed recovering an I/O error.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x4b:
// Cu and drive incompatible. The drive requests micro-program patches, which are not available on the cu.
PRINT_WARN("The drive needs microprogram patches from the control unit, which are not available.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x4c:
// Recovered Check-One failure. Cu develops a hardware error, but is able to recover. We'll reissue the command.
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x4d:
switch (cu_type) {
case 0x3480:
// This erpa is reserved for 3480 -> bug
- tape34xx_error_recovery_HWBUG(tape,21);
+ tape34xx_error_recovery_HWBUG(ti,21);
return;
case 0x3490:
// Resetting event recieved. Since the driver does not support resetting event recovery
// (which has to be handled by the I/O Layer), we'll report and retry our command.
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
}
case 0x4e:
switch (cu_type) {
case 0x3480:
// This erpa is reserved for 3480 -> bug.
- tape34xx_error_recovery_HWBUG(tape,22);
+ tape34xx_error_recovery_HWBUG(ti,22);
return;
case 0x3490:
// Maximum block size exeeded. This indicates, that the block to be written is larger
// than allowed for buffered mode. We'll report this...
PRINT_WARN("Maximum block size for buffered mode exceeded.\n");
- tape34xx_error_recovery_has_failed(tape,ENOBUFS);
+ tape34xx_error_recovery_has_failed(ti,ENOBUFS);
return;
}
case 0x4f:
// These erpas are reserved -> bug
- tape34xx_error_recovery_HWBUG(tape,23);
+ tape34xx_error_recovery_HWBUG(ti,23);
return;
case 0x50:
// Read buffered log (Overflow). Cu is running in extended beffered log mode, and a counter overflows.
// This should never happen, since we're never running in extended buffered log mode -> bug.
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x51:
// Read buffered log (EOV). EOF processing occurs while the cu is in extended buffered log mode.
// This should never happen, since we're never running in extended buffered log mode -> bug.
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x52:
// End of Volume complete. Rewind unload completed ok. We'll report to the user...
- if (tapestate_get(tape)!=TS_RUN_INIT) {
- tape34xx_error_recovery_HWBUG(tape,24);
+ if (tapestate_get(ti)!=TS_RUN_INIT) {
+ tape34xx_error_recovery_HWBUG(ti,24);
return;
}
- tape34xx_error_recovery_succeded(tape);
+ tape34xx_error_recovery_succeded(ti);
return;
case 0x53:
// Global command intercept. We'll have to reissue our command.
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x54:
// Channel interface recovery (temporary). This can be recovered by reissuing the command.
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x55:
// Channel interface recovery (permanent). This cannot be recovered, we'll inform the user.
PRINT_WARN("A permanent channel interface error occurred.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x56:
// Channel protocol error. This cannot be recovered.
PRINT_WARN("A channel protocol error occurred.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x57:
switch (cu_type) {
case 0x3480:
// Attention intercept. We have to reissue the command.
PRINT_WARN("An attention intercept occurred, which will be recovered.\n");
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
case 0x3490:
// Global status intercept. We have to reissue the command.
PRINT_WARN("An global status intercept was recieved, which will be recovered.\n");
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
}
case 0x58:
case 0x59:
// These erpas are reserved -> bug.
- tape34xx_error_recovery_HWBUG(tape,25);
+ tape34xx_error_recovery_HWBUG(ti,25);
return;
case 0x5a:
// Tape length incompatible. The tape inserted is too long,
// which could cause damage to the tape or the drive.
PRINT_WARN("Tape length incompatible [should be IBM Cartridge System Tape]. May cause damage to drive or tape.n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x5b:
// Format 3480 XF incompatible
if (sense[1]&SENSE_BEGINNING_OF_TAPE) {
// Everything is fine. The tape will be overwritten in a different format.
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
return;
}
PRINT_WARN("Tape format is incompatible to the drive, which writes 3480-2 XF.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x5c:
// Format 3480-2 XF incompatible
PRINT_WARN("Tape format is incompatible to the drive. The drive cannot access 3480-2 XF volumes.\n");
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
return;
case 0x5d:
// Tape length violation.
PRINT_WARN("Tape length violation [should be IBM Enhanced Capacity Cartridge System Tape]. May cause damage to drive or tape.\n");
- tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+ tape34xx_error_recovery_has_failed(ti,EMEDIUMTYPE);
return;
case 0x5e:
// Compaction algorithm incompatible.
PRINT_WARN("The volume is recorded using an incompatible compaction algorith, which is not supported by the control unit.\n");
- tape34xx_error_recovery_has_failed(tape,EMEDIUMTYPE);
+ tape34xx_error_recovery_has_failed(ti,EMEDIUMTYPE);
return;
default:
// Reserved erpas -> bug
- tape34xx_error_recovery_HWBUG(tape,26);
+ tape34xx_error_recovery_HWBUG(ti,26);
return;
}
}
-void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id) {
+void tape34xx_error_recovery_has_failed (tape_info_t* ti,int error_id) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"xerp fail");
- debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) &&
- (tapestate_get (tape) >= 0)) ?
- state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+ debug_text_event (tape_debug_area,3,(((tapestate_get (ti) < TS_SIZE) &&
+ (tapestate_get (ti) >= 0)) ?
+ state_verbose[tapestate_get (ti)] : "UNKNOWN"));
#endif
- if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) {
- tape_dump_sense(&tape->devstat);
- tape->rc = -error_id;
- tape->wanna_wakeup=1;
- switch (tapestate_get(tape)) {
+ if ((tapestate_get(ti)!=TS_UNUSED) && (tapestate_get(ti)!=TS_IDLE)) {
+ tape_dump_sense(&ti->devstat);
+ ti->rc = -error_id;
+ ti->wanna_wakeup=1;
+ switch (tapestate_get(ti)) {
case TS_REW_RELEASE_INIT:
- tapestate_set(tape,TS_FAILED);
- wake_up (&tape->wq);
+ tapestate_set(ti,TS_FAILED);
+ wake_up (&ti->wq);
break;
case TS_BLOCK_INIT:
- tapestate_set(tape,TS_FAILED);
- schedule_tapeblock_exec_IO(tape);
+ tapestate_set(ti,TS_FAILED);
+ schedule_tapeblock_exec_IO(ti);
break;
default:
- tapestate_set(tape,TS_FAILED);
- wake_up_interruptible (&tape->wq);
+ tapestate_set(ti,TS_FAILED);
+ wake_up_interruptible (&ti->wq);
}
} else {
PRINT_WARN("Recieved an unsolicited IRQ.\n");
- tape_dump_sense(&tape->devstat);
+ tape_dump_sense(&ti->devstat);
}
}
-void tape34xx_error_recovery_succeded(tape_info_t* tape) {
+void tape34xx_error_recovery_succeded(tape_info_t* ti) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"xerp done");
- debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) &&
- (tapestate_get (tape) >= 0)) ?
- state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+ debug_text_event (tape_debug_area,3,(((tapestate_get (ti) < TS_SIZE) &&
+ (tapestate_get (ti) >= 0)) ?
+ state_verbose[tapestate_get (ti)] : "UNKNOWN"));
#endif
- if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_DONE)) {
- tapestate_event (tape, TE_DONE);
+ if ((tapestate_get(ti)!=TS_UNUSED) && (tapestate_get(ti)!=TS_DONE)) {
+ tapestate_event (ti, TE_DONE);
} else {
PRINT_WARN("Recieved an unsolicited IRQ.\n");
- tape_dump_sense(&tape->devstat);
+ tape_dump_sense(&ti->devstat);
}
}
-void tape34xx_error_recovery_do_retry(tape_info_t* tape) {
+void tape34xx_error_recovery_do_retry(tape_info_t* ti) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"xerp retr");
- debug_text_event (tape_debug_area,3,(((tapestate_get (tape) < TS_SIZE) &&
- (tapestate_get (tape) >= 0)) ?
- state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+ debug_text_event (tape_debug_area,3,(((tapestate_get (ti) < TS_SIZE) &&
+ (tapestate_get (ti) >= 0)) ?
+ state_verbose[tapestate_get (ti)] : "UNKNOWN"));
#endif
- if ((tapestate_get(tape)!=TS_UNUSED) && (tapestate_get(tape)!=TS_IDLE)) {
- tape_dump_sense(&tape->devstat);
- while (do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) tape->cqr, 0x00, tape->cqr->options));
+ if ((tapestate_get(ti)!=TS_UNUSED) && (tapestate_get(ti)!=TS_IDLE)) {
+ tape_dump_sense(&ti->devstat);
+ while (do_IO (ti->devinfo.irq, ti->cqr->cpaddr, (unsigned long) ti->cqr, 0x00, ti->cqr->options));
} else {
PRINT_WARN("Recieved an unsolicited IRQ.\n");
- tape_dump_sense(&tape->devstat);
+ tape_dump_sense(&ti->devstat);
}
}
void
-tape34xx_error_recovery_read_opposite (tape_info_t* tape) {
- switch (tapestate_get(tape)) {
+tape34xx_error_recovery_read_opposite (tape_info_t* ti) {
+ switch (tapestate_get(ti)) {
case TS_RFO_INIT:
// We did read forward, but the data could not be read *correctly*.
// We will read backward and then skip forward again.
- tape->cqr=tape34xx_read_opposite(tape,0);
- if (tape->cqr==NULL)
- tape34xx_error_recovery_has_failed(tape,EIO);
+ ti->cqr=tape34xx_read_opposite(ti,0);
+ if (ti->cqr==NULL)
+ tape34xx_error_recovery_has_failed(ti,EIO);
else
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
break;
case TS_RBA_INIT:
// We tried to read forward and backward, but hat no success -> failed.
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
break;
case TS_BLOCK_INIT:
- tape34xx_error_recovery_do_retry(tape);
+ tape34xx_error_recovery_do_retry(ti);
break;
default:
PRINT_WARN("read_opposite_recovery_called_with_state:%s\n",
- (((tapestate_get (tape) < TS_SIZE) &&
- (tapestate_get (tape) >= 0)) ?
- state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+ (((tapestate_get (ti) < TS_SIZE) &&
+ (tapestate_get (ti) >= 0)) ?
+ state_verbose[tapestate_get (ti)] : "UNKNOWN"));
}
}
void
-tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno) {
- devstat_t* stat=&tape->devstat;
+tape34xx_error_recovery_HWBUG (tape_info_t* ti,int condno) {
+ devstat_t* stat=&ti->devstat;
PRINT_WARN("An unexpected condition #%d was caught in tape error recovery.\n",condno);
PRINT_WARN("Please report this incident.\n");
PRINT_WARN("State of the tape:%s\n",
- (((tapestate_get (tape) < TS_SIZE) &&
- (tapestate_get (tape) >= 0)) ?
- state_verbose[tapestate_get (tape)] : "UNKNOWN"));
+ (((tapestate_get (ti) < TS_SIZE) &&
+ (tapestate_get (ti) >= 0)) ?
+ state_verbose[tapestate_get (ti)] : "UNKNOWN"));
PRINT_INFO ("Sense data: %02X%02X%02X%02X %02X%02X%02X%02X "
" %02X%02X%02X%02X %02X%02X%02X%02X \n",
stat->ii.sense.data[0], stat->ii.sense.data[1],
stat->ii.sense.data[26], stat->ii.sense.data[27],
stat->ii.sense.data[28], stat->ii.sense.data[29],
stat->ii.sense.data[30], stat->ii.sense.data[31]);
- tape34xx_error_recovery_has_failed(tape,EIO);
+ tape34xx_error_recovery_has_failed(ti,EIO);
}
/* discipline functions */
int tape34xx_ioctl_overload (struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg);
-ccw_req_t * tape34xx_write_block (const char *data, size_t count, tape_info_t * tape);
-void tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * tape);
-ccw_req_t * tape34xx_read_block (const char *data, size_t count, tape_info_t * tape);
-void tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * tape);
-void tape34xx_clear_read_block (ccw_req_t * cqr, tape_info_t * tape);
-ccw_req_t * tape34xx_mtfsf (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtbsf (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtfsr (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtbsr (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtweof (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtrew (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtoffl (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtnop (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtbsfm (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtfsfm (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mteom (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mterase (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtsetdensity (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtseek (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mttell (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtsetdrvbuffer (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtlock (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtunlock (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtload (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtunload (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtcompression (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtsetpart (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtmkpart (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtiocget (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_mtiocpos (tape_info_t * tape, int count);
-ccw_req_t * tape34xx_bread (struct request *req, tape_info_t* tape,int tapeblock_major);
-ccw_req_t * tape34xx_bwrite (struct request *req, tape_info_t* tape,int tapeblock_major);
+ccw_req_t * tape34xx_write_block (const char *data, size_t count, tape_info_t * ti);
+void tape34xx_free_write_block (ccw_req_t * cqr, tape_info_t * ti);
+ccw_req_t * tape34xx_read_block (const char *data, size_t count, tape_info_t * ti);
+void tape34xx_free_read_block (ccw_req_t * cqr, tape_info_t * ti);
+void tape34xx_clear_read_block (ccw_req_t * cqr, tape_info_t * ti);
+ccw_req_t * tape34xx_mtfsf (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtbsf (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtfsr (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtbsr (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtweof (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtrew (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtoffl (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtnop (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtbsfm (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtfsfm (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mteom (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mterase (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtsetdensity (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtseek (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mttell (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtsetdrvbuffer (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtlock (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtunlock (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtload (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtunload (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtcompression (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtsetpart (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtmkpart (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtiocget (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_mtiocpos (tape_info_t * ti, int count);
+ccw_req_t * tape34xx_bread (struct request *req, tape_info_t* ti,int tapeblock_major);
+ccw_req_t * tape34xx_bwrite (struct request *req, tape_info_t* ti,int tapeblock_major);
void tape34xx_free_bread (ccw_req_t*,struct _tape_info_t*);
void tape34xx_free_bwrite (ccw_req_t*,struct _tape_info_t*);
/* Event handlers */
-void tape34xx_default_handler (tape_info_t * tape);
-void tape34xx_unexpect_uchk_handler (tape_info_t * tape);
-void tape34xx_unused_done(tape_info_t* tape);
-void tape34xx_idle_done(tape_info_t* tape);
-void tape34xx_block_done(tape_info_t* tape);
-void tape34xx_bsf_init_done(tape_info_t* tape);
-void tape34xx_dse_init_done(tape_info_t* tape);
-void tape34xx_fsf_init_done(tape_info_t* tape);
-void tape34xx_bsb_init_done(tape_info_t* tape);
-void tape34xx_fsb_init_done(tape_info_t* tape);
-void tape34xx_lbl_init_done(tape_info_t* tape);
-void tape34xx_nop_init_done(tape_info_t* tape);
-void tape34xx_rfo_init_done(tape_info_t* tape);
-void tape34xx_rbi_init_done(tape_info_t* tape);
-void tape34xx_rew_init_done(tape_info_t* tape);
-void tape34xx_rew_release_init_done(tape_info_t* tape);
-void tape34xx_run_init_done(tape_info_t* tape);
-void tape34xx_wri_init_done(tape_info_t* tape);
-void tape34xx_wtm_init_done(tape_info_t* tape);
-
-extern void schedule_tapeblock_exec_IO (tape_info_t *tape);
+void tape34xx_default_handler (tape_info_t * ti);
+void tape34xx_unexpect_uchk_handler (tape_info_t * ti);
+void tape34xx_unused_done(tape_info_t* ti);
+void tape34xx_idle_done(tape_info_t* ti);
+void tape34xx_block_done(tape_info_t* ti);
+void tape34xx_bsf_init_done(tape_info_t* ti);
+void tape34xx_dse_init_done(tape_info_t* ti);
+void tape34xx_fsf_init_done(tape_info_t* ti);
+void tape34xx_bsb_init_done(tape_info_t* ti);
+void tape34xx_fsb_init_done(tape_info_t* ti);
+void tape34xx_lbl_init_done(tape_info_t* ti);
+void tape34xx_nop_init_done(tape_info_t* ti);
+void tape34xx_rfo_init_done(tape_info_t* ti);
+void tape34xx_rbi_init_done(tape_info_t* ti);
+void tape34xx_rew_init_done(tape_info_t* ti);
+void tape34xx_rew_release_init_done(tape_info_t* ti);
+void tape34xx_run_init_done(tape_info_t* ti);
+void tape34xx_wri_init_done(tape_info_t* ti);
+void tape34xx_wtm_init_done(tape_info_t* ti);
+
+extern void schedule_tapeblock_exec_IO (tape_info_t *ti);
// the error recovery stuff:
-void tape34xx_error_recovery (tape_info_t* tape);
-void tape34xx_error_recovery_has_failed (tape_info_t* tape,int error_id);
-void tape34xx_error_recovery_succeded(tape_info_t* tape);
-void tape34xx_error_recovery_do_retry(tape_info_t* tape);
-void tape34xx_error_recovery_read_opposite (tape_info_t* tape);
-void tape34xx_error_recovery_HWBUG (tape_info_t* tape,int condno);
+void tape34xx_error_recovery (tape_info_t* ti);
+void tape34xx_error_recovery_has_failed (tape_info_t* ti,int error_id);
+void tape34xx_error_recovery_succeded(tape_info_t* ti);
+void tape34xx_error_recovery_do_retry(tape_info_t* ti);
+void tape34xx_error_recovery_read_opposite (tape_info_t* ti);
+void tape34xx_error_recovery_HWBUG (tape_info_t* ti,int condno);
#endif // _TAPE34XX_H
#ifdef CONFIG_DEVFS_FS
void
-tapeblock_mkdevfstree (tape_info_t* tape) {
- tape->devfs_block_dir=devfs_mk_dir (tape->devfs_dir, "block", tape);
- tape->devfs_disc=devfs_register(tape->devfs_block_dir, "disc",DEVFS_FL_DEFAULT,
- tapeblock_major, tape->blk_minor,
- TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, tape);
+tapeblock_mkdevfstree (tape_info_t* ti) {
+ ti->devfs_block_dir=devfs_mk_dir (ti->devfs_dir, "block", ti);
+ ti->devfs_disc=devfs_register(ti->devfs_block_dir, "disc",DEVFS_FL_DEFAULT,
+ tapeblock_major, ti->blk_minor,
+ TAPEBLOCK_DEFAULTMODE, &tapeblock_fops, ti);
}
void
-tapeblock_rmdevfstree (tape_info_t* tape) {
- devfs_unregister(tape->devfs_disc);
- devfs_unregister(tape->devfs_block_dir);
+tapeblock_rmdevfstree (tape_info_t* ti) {
+ devfs_unregister(ti->devfs_disc);
+ devfs_unregister(ti->devfs_block_dir);
}
#endif
void
-tapeblock_setup(tape_info_t* tape) {
- blk_size[tapeblock_major][tape->blk_minor]=0; // this will be detected
- blksize_size[tapeblock_major][tape->blk_minor]=2048; // blocks are 2k by default.
- hardsect_size[tapeblock_major][tape->blk_minor]=512;
- blk_init_queue (&tape->request_queue, tape_request_fn);
- blk_queue_headactive (&tape->request_queue, 0);
+tapeblock_setup(tape_info_t* ti) {
+ blk_size[tapeblock_major][ti->blk_minor]=0; // this will be detected
+ blksize_size[tapeblock_major][ti->blk_minor]=2048; // blocks are 2k by default.
+ hardsect_size[tapeblock_major][ti->blk_minor]=512;
+ blk_init_queue (&ti->request_queue, tape_request_fn);
+ blk_queue_headactive (&ti->request_queue, 0);
#ifdef CONFIG_DEVFS_FS
- tapeblock_mkdevfstree(tape);
+ tapeblock_mkdevfstree(ti);
#endif
}
tapeblock_init(void) {
int result;
tape_frontend_t* blkfront,*temp;
- tape_info_t* tape;
+ tape_info_t* ti;
tape_init();
/* Register the tape major number to the kernel */
temp=temp->next;
temp->next=blkfront;
}
- tape=first_tape_info;
- while (tape!=NULL) {
- tapeblock_setup(tape);
- tape=tape->next;
+ ti=first_tape_info;
+ while (ti!=NULL) {
+ tapeblock_setup(ti);
+ ti=ti->next;
}
return 0;
}
s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
rc=tapeblock_mediumdetect(ti);
- if (rc) return rc; // in case of errors, we don't have a size of the medium
+ if (rc) {
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ tapestate_set (ti, TS_UNUSED);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ return rc; // in case of errors, we don't have a size of the medium
+ }
dev = MKDEV (tapeblock_major, MINOR (inode->i_rdev)); /* Get the device */
s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
ti->blk_filp = filp;
}
static void
-tapeblock_end_request(tape_info_t* tape) {
+tapeblock_end_request(tape_info_t* ti) {
struct buffer_head *bh;
int uptodate;
- if ((tapestate_get(tape)!=TS_FAILED) &&
- (tapestate_get(tape)!=TS_DONE))
+ if ((tapestate_get(ti)!=TS_FAILED) &&
+ (tapestate_get(ti)!=TS_DONE))
BUG(); // A request has to be completed to end it
- uptodate=(tapestate_get(tape)==TS_DONE); // is the buffer up to date?
+ uptodate=(tapestate_get(ti)==TS_DONE); // is the buffer up to date?
#ifdef TAPE_DEBUG
if (uptodate) {
debug_text_event (tape_debug_area,6,"b:done:");
- debug_int_event (tape_debug_area,6,(long)tape->cqr);
+ debug_int_event (tape_debug_area,6,(long)ti->cqr);
} else {
debug_text_event (tape_debug_area,3,"b:failed:");
- debug_int_event (tape_debug_area,3,(long)tape->cqr);
+ debug_int_event (tape_debug_area,3,(long)ti->cqr);
}
#endif
// now inform ll_rw_block about a request status
- while ((bh = tape->current_request->bh) != NULL) {
- tape->current_request->bh = bh->b_reqnext;
+ while ((bh = ti->current_request->bh) != NULL) {
+ ti->current_request->bh = bh->b_reqnext;
bh->b_reqnext = NULL;
bh->b_end_io (bh, uptodate);
}
- if (!end_that_request_first (tape->current_request, uptodate, "tBLK")) {
+ if (!end_that_request_first (ti->current_request, uptodate, "tBLK")) {
#ifndef DEVICE_NO_RANDOM
- add_blkdev_randomness (MAJOR (tape->current_request->rq_dev));
+ add_blkdev_randomness (MAJOR (ti->current_request->rq_dev));
#endif
- end_that_request_last (tape->current_request);
+ end_that_request_last (ti->current_request);
}
- tape->discipline->free_bread(tape->cqr,tape);
- tape->cqr=NULL;
- tape->current_request=NULL;
- if (tapestate_get(tape)!=TS_NOT_OPER) tapestate_set(tape,TS_IDLE);
+ ti->discipline->free_bread(ti->cqr,ti);
+ ti->cqr=NULL;
+ ti->current_request=NULL;
+ if (tapestate_get(ti)!=TS_NOT_OPER) tapestate_set(ti,TS_IDLE);
return;
}
static void
-tapeblock_exec_IO (tape_info_t* tape) {
+tapeblock_exec_IO (tape_info_t* ti) {
int rc;
struct request* req;
- if (tape->cqr) { // process done/failed request
- while ((tapestate_get(tape)==TS_FAILED) &&
- tape->blk_retries>0) {
- tape->blk_retries--;
- tape->position=-1;
- tapestate_set(tape,TS_BLOCK_INIT);
+ if (ti->cqr) { // process done/failed request
+ while ((tapestate_get(ti)==TS_FAILED) &&
+ ti->blk_retries>0) {
+ ti->blk_retries--;
+ ti->position=-1;
+ tapestate_set(ti,TS_BLOCK_INIT);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"b:retryreq:");
- debug_int_event (tape_debug_area,3,(long)tape->cqr);
+ debug_int_event (tape_debug_area,3,(long)ti->cqr);
#endif
- rc = do_IO (tape->devinfo.irq, tape->cqr->cpaddr, (unsigned long) tape->cqr,
- 0x00, tape->cqr->options);
+ rc = do_IO (ti->devinfo.irq, ti->cqr->cpaddr, (unsigned long) ti->cqr,
+ 0x00, ti->cqr->options);
if (rc) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"b:doIOfail:");
- debug_int_event (tape_debug_area,3,(long)tape->cqr);
+ debug_int_event (tape_debug_area,3,(long)ti->cqr);
#endif
continue; // one retry lost 'cause doIO failed
}
return;
}
- tapeblock_end_request (tape); // check state, inform user, free mem, dev=idl
+ tapeblock_end_request (ti); // check state, inform user, free mem, dev=idl
}
- if (tape->cqr!=NULL) BUG(); // tape should be idle now, request should be freed!
- if (tapestate_get (tape) == TS_NOT_OPER) {
- tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
- tape->devinfo.irq=-1;
+ if (ti->cqr!=NULL) BUG(); // tape should be idle now, request should be freed!
+ if (tapestate_get (ti) == TS_NOT_OPER) {
+ ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+ ti->devinfo.irq=-1;
return;
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- if (list_empty (&tape->request_queue.queue_head)) {
+ if (list_empty (&ti->request_queue.queue_head)) {
#else
- if (tape->request_queue==NULL) {
+ if (ti->request_queue==NULL) {
#endif
// nothing more to do or device has dissapeared;)
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"b:Qempty");
#endif
- tapestate_set(tape,TS_IDLE);
+ tapestate_set(ti,TS_IDLE);
return;
}
// queue is not empty, fetch a request and start IO!
- req=tape->current_request=tape_next_request(&tape->request_queue);
+ req=ti->current_request=tape_next_request(&ti->request_queue);
if (req==NULL) {
BUG(); // Yo. The queue was not reported empy, but no request found. This is _bad_.
}
if (req->cmd!=READ) { // we only support reading
- tapestate_set(tape,TS_FAILED);
- tapeblock_end_request (tape); // check state, inform user, free mem, dev=idl
- tapestate_set(tape,TS_BLOCK_INIT);
- schedule_tapeblock_exec_IO(tape);
+ tapestate_set(ti,TS_FAILED);
+ tapeblock_end_request (ti); // check state, inform user, free mem, dev=idl
+ tapestate_set(ti,TS_BLOCK_INIT);
+ schedule_tapeblock_exec_IO(ti);
return;
}
- tape->cqr=tape->discipline->bread(req,tape,tapeblock_major); //build channel program from request
- if (!tape->cqr) {
+ ti->cqr=ti->discipline->bread(req,ti,tapeblock_major); //build channel program from request
+ if (!ti->cqr) {
// ccw generation failed. we try again later.
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"b:cqrNULL");
#endif
- schedule_tapeblock_exec_IO(tape);
- tape->current_request=NULL;
+ schedule_tapeblock_exec_IO(ti);
+ ti->current_request=NULL;
return;
}
- tape->blk_retries = TAPEBLOCK_RETRIES;
- rc= do_IO (tape->devinfo.irq, tape->cqr->cpaddr,
- (unsigned long) tape->cqr, 0x00, tape->cqr->options);
+ ti->blk_retries = TAPEBLOCK_RETRIES;
+ rc= do_IO (ti->devinfo.irq, ti->cqr->cpaddr,
+ (unsigned long) ti->cqr, 0x00, ti->cqr->options);
if (rc) {
// okay. ssch failed. we try later.
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,3,"b:doIOfail");
#endif
- tape->discipline->free_bread(tape->cqr,tape);
- tape->cqr=NULL;
- tape->current_request=NULL;
- schedule_tapeblock_exec_IO(tape);
+ ti->discipline->free_bread(ti->cqr,ti);
+ ti->cqr=NULL;
+ ti->current_request=NULL;
+ schedule_tapeblock_exec_IO(ti);
return;
}
// our request is in IO. we remove it from the queue and exit
- tape_dequeue_request (&tape->request_queue,req);
+ tape_dequeue_request (&ti->request_queue,req);
}
static void
do_tape_request (request_queue_t * queue) {
- tape_info_t* tape;
+ tape_info_t* ti;
long lockflags;
- for (tape=first_tape_info;
- ((tape!=NULL) && ((&tape->request_queue)!=queue));
- tape=tape->next);
- if (tape==NULL) BUG();
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- if (tapestate_get(tape)!=TS_IDLE) {
- s390irq_spin_unlock_irqrestore(tape->devinfo.irq,lockflags);
+ for (ti=first_tape_info;
+ ((ti!=NULL) && ((&ti->request_queue)!=queue));
+ ti=ti->next);
+ if (ti==NULL) BUG();
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ if (tapestate_get(ti)!=TS_IDLE) {
+ s390irq_spin_unlock_irqrestore(ti->devinfo.irq,lockflags);
return;
}
- if (tapestate_get(tape)!=TS_IDLE) BUG();
- tapestate_set(tape,TS_BLOCK_INIT);
- tapeblock_exec_IO(tape);
- s390irq_spin_unlock_irqrestore(tape->devinfo.irq,lockflags);
+ if (tapestate_get(ti)!=TS_IDLE) BUG();
+ tapestate_set(ti,TS_BLOCK_INIT);
+ tapeblock_exec_IO(ti);
+ s390irq_spin_unlock_irqrestore(ti->devinfo.irq,lockflags);
}
static void
-run_tapeblock_exec_IO (tape_info_t* tape) {
+run_tapeblock_exec_IO (tape_info_t* ti) {
long flags_390irq,flags_ior;
spin_lock_irqsave (&io_request_lock, flags_ior);
- s390irq_spin_lock_irqsave(tape->devinfo.irq,flags_390irq);
- atomic_set(&tape->bh_scheduled,0);
- tapeblock_exec_IO(tape);
- s390irq_spin_unlock_irqrestore(tape->devinfo.irq,flags_390irq);
+ s390irq_spin_lock_irqsave(ti->devinfo.irq,flags_390irq);
+ atomic_set(&ti->bh_scheduled,0);
+ tapeblock_exec_IO(ti);
+ s390irq_spin_unlock_irqrestore(ti->devinfo.irq,flags_390irq);
spin_unlock_irqrestore (&io_request_lock, flags_ior);
}
void
-schedule_tapeblock_exec_IO (tape_info_t *tape)
+schedule_tapeblock_exec_IO (tape_info_t *ti)
{
/* Protect against rescheduling, when already running */
- if (atomic_compare_and_swap(0,1,&tape->bh_scheduled)) {
+ if (atomic_compare_and_swap(0,1,&ti->bh_scheduled)) {
return;
}
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
- INIT_LIST_HEAD(&tape->bh_tq.list);
+ INIT_LIST_HEAD(&ti->bh_tq.list);
#endif
- tape->bh_tq.sync = 0;
- tape->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO;
- tape->bh_tq.data = tape;
+ ti->bh_tq.sync = 0;
+ ti->bh_tq.routine = (void *) (void *) run_tapeblock_exec_IO;
+ ti->bh_tq.data = ti;
- queue_task (&tape->bh_tq, &tq_immediate);
+ queue_task (&ti->bh_tq, &tq_immediate);
mark_bh (IMMEDIATE_BH);
return;
}
/* wrappers around do_tape_request for different kernel versions */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,98))
static void tape_request_fn (void) {
- tape_info_t* tape=first_tape_info;
- while (tape!=NULL) {
- do_tape_request(&tape->request_queue);
- tape=tape->next;
+ tape_info_t* ti=first_tape_info;
+ while (ti!=NULL) {
+ do_tape_request(&ti->request_queue);
+ ti=ti->next;
}
}
#else
#endif
static request_queue_t* tapeblock_getqueue (kdev_t kdev) {
- tape_info_t* tape=first_tape_info;
- while ((tape!=NULL) && (MINOR(kdev)!=tape->blk_minor))
- tape=tape->next;
- if (tape!=NULL) return &tape->request_queue;
+ tape_info_t* ti=first_tape_info;
+ while ((ti!=NULL) && (MINOR(kdev)!=ti->blk_minor))
+ ti=ti->next;
+ if (ti!=NULL) return &ti->request_queue;
return NULL;
}
-int tapeblock_mediumdetect(tape_info_t* tape) {
+int tapeblock_mediumdetect(tape_info_t* ti) {
ccw_req_t* cqr;
int losize=1,hisize=1,rc;
long lockflags;
PRINT_WARN("Detecting media size. This will take _long_, so get yourself a coffee...\n");
while (1) { //is interruped by break
hisize=hisize << 1; // try twice the size tested before
- cqr=tape->discipline->mtseek (tape, hisize);
+ cqr=ti->discipline->mtseek (ti, hisize);
if (cqr == NULL) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"b:ccwg fail");
#endif
return -ENOSPC;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->cqr = cqr;
- tape->wanna_wakeup=0;
- rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->cqr = cqr;
+ ti->wanna_wakeup=0;
+ rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
if (rc) return -EIO;
- wait_event_interruptible (tape->wq,tape->wanna_wakeup);
- tape->cqr = NULL;
+ wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+ ti->cqr = NULL;
tape_free_request (cqr);
- if (tape->kernbuf) {
- kfree (tape->kernbuf);
- tape->kernbuf=NULL;
+ if (ti->kernbuf) {
+ kfree (ti->kernbuf);
+ ti->kernbuf=NULL;
}
if (signal_pending (current)) {
- tapestate_set (tape, TS_IDLE);
+ tapestate_set (ti, TS_IDLE);
return -ERESTARTSYS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- if (tapestate_get (tape) == TS_FAILED) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ if (tapestate_get (ti) == TS_FAILED) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
break;
}
- if (tapestate_get (tape) == TS_NOT_OPER) {
- tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
- tape->devinfo.irq=-1;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+ if (tapestate_get (ti) == TS_NOT_OPER) {
+ ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+ ti->devinfo.irq=-1;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
return -ENODEV;
}
- if (tapestate_get (tape) != TS_DONE) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ if (tapestate_get (ti) != TS_DONE) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
return -EIO;
}
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
losize=hisize;
}
- cqr = tape->discipline->mtrew (tape, 1);
+ cqr = ti->discipline->mtrew (ti, 1);
if (cqr == NULL) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"b:ccwg fail");
#endif
return -ENOSPC;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->cqr = cqr;
- tape->wanna_wakeup=0;
- rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- wait_event_interruptible (tape->wq,tape->wanna_wakeup);
- tape->cqr = NULL;
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->cqr = cqr;
+ ti->wanna_wakeup=0;
+ rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+ ti->cqr = NULL;
tape_free_request (cqr);
if (signal_pending (current)) {
- tapestate_set (tape, TS_IDLE);
+ tapestate_set (ti, TS_IDLE);
return -ERESTARTSYS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- if (tapestate_get (tape) == TS_FAILED) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ if (tapestate_get (ti) == TS_FAILED) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
return -EIO;
}
- if (tapestate_get (tape) == TS_NOT_OPER) {
- tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
- tape->devinfo.irq=-1;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+ if (tapestate_get (ti) == TS_NOT_OPER) {
+ ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+ ti->devinfo.irq=-1;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
return -ENODEV;
}
- if (tapestate_get (tape) != TS_DONE) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ if (tapestate_get (ti) != TS_DONE) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
return -EIO;
}
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
while (losize!=hisize) {
- cqr=tape->discipline->mtseek (tape, (hisize+losize)/2+1);
+ cqr=ti->discipline->mtseek (ti, (hisize+losize)/2+1);
if (cqr == NULL) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"b:ccwg fail");
#endif
return -ENOSPC;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->cqr = cqr;
- tape->wanna_wakeup=0;
- rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->cqr = cqr;
+ ti->wanna_wakeup=0;
+ rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
if (rc) return -EIO;
- wait_event_interruptible (tape->wq,tape->wanna_wakeup);
- tape->cqr = NULL;
+ wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+ ti->cqr = NULL;
tape_free_request (cqr);
- if (tape->kernbuf) {
- kfree (tape->kernbuf);
- tape->kernbuf=NULL;
+ if (ti->kernbuf) {
+ kfree (ti->kernbuf);
+ ti->kernbuf=NULL;
}
if (signal_pending (current)) {
- tapestate_set (tape, TS_IDLE);
+ tapestate_set (ti, TS_IDLE);
return -ERESTARTSYS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- if (tapestate_get (tape) == TS_NOT_OPER) {
- tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
- tape->devinfo.irq=-1;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ if (tapestate_get (ti) == TS_NOT_OPER) {
+ ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+ ti->devinfo.irq=-1;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
return -ENODEV;
}
- if (tapestate_get (tape) == TS_FAILED) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ if (tapestate_get (ti) == TS_FAILED) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
hisize=(hisize+losize)/2;
- cqr = tape->discipline->mtrew (tape, 1);
+ cqr = ti->discipline->mtrew (ti, 1);
if (cqr == NULL) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"b:ccwg fail");
#endif
return -ENOSPC;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->cqr = cqr;
- tape->wanna_wakeup=0;
- rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- wait_event_interruptible (tape->wq,tape->wanna_wakeup);
- tape->cqr = NULL;
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->cqr = cqr;
+ ti->wanna_wakeup=0;
+ rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+ ti->cqr = NULL;
tape_free_request (cqr);
if (signal_pending (current)) {
- tapestate_set (tape, TS_IDLE);
+ tapestate_set (ti, TS_IDLE);
return -ERESTARTSYS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- if (tapestate_get (tape) == TS_FAILED) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ if (tapestate_get (ti) == TS_FAILED) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
return -EIO;
}
- if (tapestate_get (tape) != TS_DONE) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ if (tapestate_get (ti) != TS_DONE) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
return -EIO;
}
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
continue;
}
- if (tapestate_get (tape) != TS_DONE) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ if (tapestate_get (ti) != TS_DONE) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
return -EIO;
}
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
losize=(hisize+losize)/2+1;
}
- blk_size[tapeblock_major][tape->blk_minor]=(losize)*(blksize_size[tapeblock_major][tape->blk_minor]/1024);
+ blk_size[tapeblock_major][ti->blk_minor]=(losize)*(blksize_size[tapeblock_major][ti->blk_minor]/1024);
return 0;
}
int tapeblock_open(struct inode *, struct file *);
int tapeblock_release(struct inode *, struct file *);
-void tapeblock_setup(tape_info_t* tape);
-void schedule_tapeblock_exec_IO (tape_info_t *tape);
-int tapeblock_mediumdetect(tape_info_t* tape);
+void tapeblock_setup(tape_info_t* ti);
+void schedule_tapeblock_exec_IO (tape_info_t *ti);
+int tapeblock_mediumdetect(tape_info_t* ti);
#ifdef CONFIG_DEVFS_FS
-void tapeblock_mkdevfstree (tape_info_t* tape);
+void tapeblock_mkdevfstree (tape_info_t* ti);
#endif
int tapeblock_init (void);
void tapeblock_uninit (void);
#ifdef CONFIG_DEVFS_FS
void
-tapechar_mkdevfstree (tape_info_t* tape) {
- tape->devfs_char_dir=devfs_mk_dir (tape->devfs_dir, "char", tape);
- tape->devfs_nonrewinding=devfs_register(tape->devfs_char_dir, "nonrewinding",
+tapechar_mkdevfstree (tape_info_t* ti) {
+ ti->devfs_char_dir=devfs_mk_dir (ti->devfs_dir, "char", ti);
+ ti->devfs_nonrewinding=devfs_register(ti->devfs_char_dir, "nonrewinding",
DEVFS_FL_DEFAULT,tape_major,
- tape->nor_minor, TAPECHAR_DEFAULTMODE,
- &tape_fops, tape);
- tape->devfs_rewinding=devfs_register(tape->devfs_char_dir, "rewinding",
- DEVFS_FL_DEFAULT, tape_major, tape->rew_minor,
- TAPECHAR_DEFAULTMODE, &tape_fops, tape);
+ ti->nor_minor, TAPECHAR_DEFAULTMODE,
+ &tape_fops, ti);
+ ti->devfs_rewinding=devfs_register(ti->devfs_char_dir, "rewinding",
+ DEVFS_FL_DEFAULT, tape_major, ti->rew_minor,
+ TAPECHAR_DEFAULTMODE, &tape_fops, ti);
}
void
-tapechar_rmdevfstree (tape_info_t* tape) {
- devfs_unregister(tape->devfs_nonrewinding);
- devfs_unregister(tape->devfs_rewinding);
- devfs_unregister(tape->devfs_char_dir);
+tapechar_rmdevfstree (tape_info_t* ti) {
+ devfs_unregister(ti->devfs_nonrewinding);
+ devfs_unregister(ti->devfs_rewinding);
+ devfs_unregister(ti->devfs_char_dir);
}
#endif
void
-tapechar_setup (tape_info_t * tape)
+tapechar_setup (tape_info_t * ti)
{
#ifdef CONFIG_DEVFS_FS
- tapechar_mkdevfstree(tape);
+ tapechar_mkdevfstree(ti);
#endif
}
{
int result;
tape_frontend_t *charfront,*temp;
- tape_info_t* tape;
+ tape_info_t* ti;
tape_init();
temp=temp->next;
temp->next=charfront;
}
- tape=first_tape_info;
- while (tape!=NULL) {
- tapechar_setup(tape);
- tape=tape->next;
+ ti=first_tape_info;
+ while (ti!=NULL) {
+ tapechar_setup(ti);
+ ti=ti->next;
}
}
tape_read (struct file *filp, char *data, size_t count, loff_t * ppos)
{
long lockflags;
- tape_info_t *tape;
+ tape_info_t *ti;
size_t block_size;
ccw_req_t *cqr;
int rc;
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:read");
#endif /* TAPE_DEBUG */
- tape = first_tape_info;
- while ((tape != NULL) && (tape->rew_filp != filp) && (tape->nor_filp != filp))
- tape = (tape_info_t *) tape->next;
- if (tape == NULL) {
+ ti = first_tape_info;
+ while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp))
+ ti = (tape_info_t *) ti->next;
+ if (ti == NULL) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:nodev");
#endif /* TAPE_DEBUG */
#endif /* TAPE_DEBUG */
return -EOVERFLOW; /* errno=75 Value too large for def. data type */
}
- if (tape->block_size == 0) {
+ if (ti->block_size == 0) {
block_size = count;
} else {
- block_size = tape->block_size;
+ block_size = ti->block_size;
}
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:nbytes:");
debug_int_event (tape_debug_area,6,block_size);
#endif
- cqr = tape->discipline->read_block (data, block_size, tape);
+ cqr = ti->discipline->read_block (data, block_size, ti);
if (!cqr) {
return -ENOBUFS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->cqr = cqr;
- tape->wanna_wakeup=0;
- rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->cqr = cqr;
+ ti->wanna_wakeup=0;
+ rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
if (rc) {
- tapestate_set(tape,TS_IDLE);
+ tapestate_set(ti,TS_IDLE);
kfree (cqr);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
return rc;
}
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- wait_event_interruptible (tape->wq,tape->wanna_wakeup);
- tape->cqr = NULL;
- tape->discipline->free_read_block (cqr, tape);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+ ti->cqr = NULL;
+ ti->discipline->free_read_block (cqr, ti);
if (signal_pending (current)) {
- tapestate_set (tape, TS_IDLE);
+ tapestate_set (ti, TS_IDLE);
return -ERESTARTSYS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- if (tapestate_get (tape) == TS_FAILED) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- return tape->rc;
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ if (tapestate_get (ti) == TS_FAILED) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ return ti->rc;
}
- if (tapestate_get (tape) == TS_NOT_OPER) {
- tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
- tape->devinfo.irq=-1;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+ if (tapestate_get (ti) == TS_NOT_OPER) {
+ ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+ ti->devinfo.irq=-1;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
return -ENODEV;
}
- if (tapestate_get (tape) != TS_DONE) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ if (tapestate_get (ti) != TS_DONE) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
return -EIO;
}
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:rbytes:");
- debug_int_event (tape_debug_area,6,block_size - tape->devstat.rescnt);
+ debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);
#endif /* TAPE_DEBUG */
- filp->f_pos += block_size - tape->devstat.rescnt;
- return block_size - tape->devstat.rescnt;
+ filp->f_pos += block_size - ti->devstat.rescnt;
+ return block_size - ti->devstat.rescnt;
}
/*
tape_write (struct file *filp, const char *data, size_t count, loff_t * ppos)
{
long lockflags;
- tape_info_t *tape;
+ tape_info_t *ti;
size_t block_size;
ccw_req_t *cqr;
int nblocks, i, rc;
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:write");
#endif
- tape = first_tape_info;
- while ((tape != NULL) && (tape->nor_filp != filp) && (tape->rew_filp != filp))
- tape = (tape_info_t *) tape->next;
- if (tape == NULL)
+ ti = first_tape_info;
+ while ((ti != NULL) && (ti->nor_filp != filp) && (ti->rew_filp != filp))
+ ti = (tape_info_t *) ti->next;
+ if (ti == NULL)
return -ENODEV;
if (ppos != &filp->f_pos) {
/* "A request was outside the capabilities of the device." */
#endif
return -EOVERFLOW; /* errno=75 Value too large for def. data type */
}
- if ((tape->block_size != 0) && (count % tape->block_size != 0))
+ if ((ti->block_size != 0) && (count % ti->block_size != 0))
return -EIO;
- if (tape->block_size == 0) {
+ if (ti->block_size == 0) {
block_size = count;
nblocks = 1;
} else {
- block_size = tape->block_size;
- nblocks = count / (tape->block_size);
+ block_size = ti->block_size;
+ nblocks = count / (ti->block_size);
}
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:nbytes:");
debug_int_event (tape_debug_area,6,nblocks);
#endif
for (i = 0; i < nblocks; i++) {
- cqr = tape->discipline->write_block (data + i * block_size, block_size, tape);
+ cqr = ti->discipline->write_block (data + i * block_size, block_size, ti);
if (!cqr) {
return -ENOBUFS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->cqr = cqr;
- tape->wanna_wakeup=0;
- rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- wait_event_interruptible (tape->wq,tape->wanna_wakeup);
- tape->cqr = NULL;
- tape->discipline->free_write_block (cqr, tape);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->cqr = cqr;
+ ti->wanna_wakeup=0;
+ rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+ ti->cqr = NULL;
+ ti->discipline->free_write_block (cqr, ti);
if (signal_pending (current)) {
- tapestate_set (tape, TS_IDLE);
+ tapestate_set (ti, TS_IDLE);
return -ERESTARTSYS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- if (tapestate_get (tape) == TS_FAILED) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- if ((tape->rc==-ENOSPC) && (i!=0))
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ if (tapestate_get (ti) == TS_FAILED) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ if ((ti->rc==-ENOSPC) && (i!=0))
return i*block_size;
- return tape->rc;
+ return ti->rc;
}
- if (tapestate_get (tape) == TS_NOT_OPER) {
- tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
- tape->devinfo.irq=-1;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+ if (tapestate_get (ti) == TS_NOT_OPER) {
+ ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+ ti->devinfo.irq=-1;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
return -ENODEV;
}
- if (tapestate_get (tape) != TS_DONE) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ if (tapestate_get (ti) != TS_DONE) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
return -EIO;
}
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:wbytes:");
- debug_int_event (tape_debug_area,6,block_size - tape->devstat.rescnt);
+ debug_int_event (tape_debug_area,6,block_size - ti->devstat.rescnt);
#endif
- filp->f_pos += block_size - tape->devstat.rescnt;
- written += block_size - tape->devstat.rescnt;
- if (tape->devstat.rescnt > 0)
+ filp->f_pos += block_size - ti->devstat.rescnt;
+ written += block_size - ti->devstat.rescnt;
+ if (ti->devstat.rescnt > 0)
return written;
}
#ifdef TAPE_DEBUG
static int
tape_mtioctop (struct file *filp, short mt_op, int mt_count)
{
- tape_info_t *tape;
+ tape_info_t *ti;
ccw_req_t *cqr = NULL;
int rc;
long lockflags;
debug_text_event (tape_debug_area,6,"c:arg:");
debug_int_event (tape_debug_area,6,mt_count);
#endif
- tape = first_tape_info;
- while ((tape != NULL) && (tape->rew_filp != filp) && (tape->nor_filp != filp))
- tape = (tape_info_t *) tape->next;
- if (tape == NULL)
+ ti = first_tape_info;
+ while ((ti != NULL) && (ti->rew_filp != filp) && (ti->nor_filp != filp))
+ ti = (tape_info_t *) ti->next;
+ if (ti == NULL)
return -ENODEV;
switch (mt_op) {
case MTREW: // rewind
- cqr = tape->discipline->mtrew (tape, mt_count);
+ cqr = ti->discipline->mtrew (ti, mt_count);
break;
case MTOFFL: // put drive offline
- cqr = tape->discipline->mtoffl (tape, mt_count);
+ cqr = ti->discipline->mtoffl (ti, mt_count);
break;
case MTUNLOAD: // unload the tape
- cqr = tape->discipline->mtunload (tape, mt_count);
+ cqr = ti->discipline->mtunload (ti, mt_count);
break;
case MTWEOF: // write tapemark
- cqr = tape->discipline->mtweof (tape, mt_count);
+ cqr = ti->discipline->mtweof (ti, mt_count);
break;
case MTFSF: // forward space file
- cqr = tape->discipline->mtfsf (tape, mt_count);
+ cqr = ti->discipline->mtfsf (ti, mt_count);
break;
case MTBSF: // backward space file
- cqr = tape->discipline->mtbsf (tape, mt_count);
+ cqr = ti->discipline->mtbsf (ti, mt_count);
break;
case MTFSFM: // forward space file, stop at BOT side
- cqr = tape->discipline->mtfsfm (tape, mt_count);
+ cqr = ti->discipline->mtfsfm (ti, mt_count);
break;
case MTBSFM: // backward space file, stop at BOT side
- cqr = tape->discipline->mtbsfm (tape, mt_count);
+ cqr = ti->discipline->mtbsfm (ti, mt_count);
break;
case MTFSR: // forward space file
- cqr = tape->discipline->mtfsr (tape, mt_count);
+ cqr = ti->discipline->mtfsr (ti, mt_count);
break;
case MTBSR: // backward space file
- cqr = tape->discipline->mtbsr (tape, mt_count);
+ cqr = ti->discipline->mtbsr (ti, mt_count);
break;
case MTNOP:
- cqr = tape->discipline->mtnop (tape, mt_count);
+ cqr = ti->discipline->mtnop (ti, mt_count);
break;
case MTEOM: // postion at the end of portion
case MTRETEN: // retension the tape
- cqr = tape->discipline->mteom (tape, mt_count);
+ cqr = ti->discipline->mteom (ti, mt_count);
break;
case MTERASE:
- cqr = tape->discipline->mterase (tape, mt_count);
+ cqr = ti->discipline->mterase (ti, mt_count);
break;
case MTSETDENSITY:
- cqr = tape->discipline->mtsetdensity (tape, mt_count);
+ cqr = ti->discipline->mtsetdensity (ti, mt_count);
break;
case MTSEEK:
- cqr = tape->discipline->mtseek (tape, mt_count);
+ cqr = ti->discipline->mtseek (ti, mt_count);
break;
case MTSETDRVBUFFER:
- cqr = tape->discipline->mtsetdrvbuffer (tape, mt_count);
+ cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
break;
case MTLOCK:
- cqr = tape->discipline->mtsetdrvbuffer (tape, mt_count);
+ cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
break;
case MTUNLOCK:
- cqr = tape->discipline->mtsetdrvbuffer (tape, mt_count);
+ cqr = ti->discipline->mtsetdrvbuffer (ti, mt_count);
break;
case MTLOAD:
- cqr = tape->discipline->mtload (tape, mt_count);
- break;
+ cqr = ti->discipline->mtload (ti, mt_count);
+ if (cqr!=NULL) break; // if backend driver has an load function ->use it
+ // if no medium is in, wait until it gets inserted
+ if (ti->medium_is_unloaded) {
+ wait_event_interruptible (ti->wq,ti->medium_is_unloaded==0);
+ }
+ return 0;
case MTCOMPRESSION:
- cqr = tape->discipline->mtcompression (tape, mt_count);
+ cqr = ti->discipline->mtcompression (ti, mt_count);
break;
case MTSETPART:
- cqr = tape->discipline->mtsetpart (tape, mt_count);
+ cqr = ti->discipline->mtsetpart (ti, mt_count);
break;
case MTMKPART:
- cqr = tape->discipline->mtmkpart (tape, mt_count);
+ cqr = ti->discipline->mtmkpart (ti, mt_count);
break;
case MTTELL: // return number of block relative to current file
- cqr = tape->discipline->mttell (tape, mt_count);
+ cqr = ti->discipline->mttell (ti, mt_count);
break;
case MTSETBLK:
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->block_size = mt_count;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->block_size = mt_count;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:setblk:");
debug_int_event (tape_debug_area,6,mt_count);
#endif
return 0;
case MTRESET:
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->kernbuf = tape->userbuf = NULL;
- tapestate_set (tape, TS_IDLE);
- tape->block_size = 0;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->kernbuf = ti->userbuf = NULL;
+ tapestate_set (ti, TS_IDLE);
+ ti->block_size = 0;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:devreset:");
- debug_int_event (tape_debug_area,6,tape->blk_minor);
+ debug_int_event (tape_debug_area,6,ti->blk_minor);
#endif
return 0;
default:
#endif
return -ENOSPC;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->cqr = cqr;
- tape->wanna_wakeup=0;
- rc = do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- wait_event_interruptible (tape->wq,tape->wanna_wakeup);
- tape->cqr = NULL;
- if (tape->kernbuf != NULL) {
- kfree (tape->kernbuf);
- tape->kernbuf = NULL;
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->cqr = cqr;
+ ti->wanna_wakeup=0;
+ rc = do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+ ti->cqr = NULL;
+ if (ti->kernbuf != NULL) {
+ kfree (ti->kernbuf);
+ ti->kernbuf = NULL;
}
tape_free_request (cqr);
+ // if medium was unloaded, update the corresponding variable.
+ switch (mt_op) {
+ case MTOFFL:
+ case MTUNLOAD:
+ ti->medium_is_unloaded=1;
+ }
if (signal_pending (current)) {
- tapestate_set (tape, TS_IDLE);
+ tapestate_set (ti, TS_IDLE);
return -ERESTARTSYS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- if (((mt_op == MTEOM) || (mt_op == MTRETEN)) && (tapestate_get (tape) == TS_FAILED))
- tapestate_set (tape, TS_DONE);
- if (tapestate_get (tape) == TS_FAILED) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- return tape->rc;
- }
- if (tapestate_get (tape) == TS_NOT_OPER) {
- tape->blk_minor=tape->rew_minor=tape->nor_minor=-1;
- tape->devinfo.irq=-1;
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq,lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ if (((mt_op == MTEOM) || (mt_op == MTRETEN)) && (tapestate_get (ti) == TS_FAILED))
+ tapestate_set (ti, TS_DONE);
+ if (tapestate_get (ti) == TS_FAILED) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ return ti->rc;
+ }
+ if (tapestate_get (ti) == TS_NOT_OPER) {
+ ti->blk_minor=ti->rew_minor=ti->nor_minor=-1;
+ ti->devinfo.irq=-1;
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq,lockflags);
return -ENODEV;
}
- if (tapestate_get (tape) != TS_DONE) {
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ if (tapestate_get (ti) != TS_DONE) {
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
return -EIO;
}
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
switch (mt_op) {
case MTRETEN: //need to rewind the tape after moving to eom
unsigned int cmd, unsigned long arg)
{
long lockflags;
- tape_info_t *tape;
+ tape_info_t *ti;
ccw_req_t *cqr;
struct mtop op; /* structure for MTIOCTOP */
struct mtpos pos; /* structure for MTIOCPOS */
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:ioct");
#endif
- tape = first_tape_info;
- while ((tape != NULL) &&
- (tape->rew_minor != MINOR (inode->i_rdev)) &&
- (tape->nor_minor != MINOR (inode->i_rdev)))
- tape = (tape_info_t *) tape->next;
- if (tape == NULL) {
+ ti = first_tape_info;
+ while ((ti != NULL) &&
+ (ti->rew_minor != MINOR (inode->i_rdev)) &&
+ (ti->nor_minor != MINOR (inode->i_rdev)))
+ ti = (tape_info_t *) ti->next;
+ if (ti == NULL) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:nodev");
#endif
return -ENODEV;
}
// check for discipline ioctl overloading
- if ((rc = tape->discipline->discipline_ioctl_overload (inode, filp, cmd, arg))
+ if ((rc = ti->discipline->discipline_ioctl_overload (inode, filp, cmd, arg))
!= -EINVAL) {
#ifdef TAPE_DEBUG
debug_text_event (tape_debug_area,6,"c:ioverloa");
switch (cmd) {
case MTIOCTOP: /* tape op command */
- if (copy_from_user (&op, (char *) arg, sizeof (struct mtop)))
+ if (copy_from_user (&op, (char *) arg, sizeof (struct mtop))) {
return -EFAULT;
+ }
return (tape_mtioctop (filp, op.mt_op, op.mt_count));
case MTIOCPOS: /* query tape position */
- cqr = tape->discipline->mttell (tape, 0);
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->cqr = cqr;
- tape->wanna_wakeup=0;
- do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- wait_event_interruptible (tape->wq,tape->wanna_wakeup);
- pos.mt_blkno = tape->rc;
- tape->cqr = NULL;
- if (tape->kernbuf != NULL) {
- kfree (tape->kernbuf);
- tape->kernbuf = NULL;
+ cqr = ti->discipline->mttell (ti, 0);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->cqr = cqr;
+ ti->wanna_wakeup=0;
+ do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+ pos.mt_blkno = ti->rc;
+ ti->cqr = NULL;
+ if (ti->kernbuf != NULL) {
+ kfree (ti->kernbuf);
+ ti->kernbuf = NULL;
}
tape_free_request (cqr);
if (signal_pending (current)) {
- tapestate_set (tape, TS_IDLE);
+ tapestate_set (ti, TS_IDLE);
return -ERESTARTSYS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
if (copy_to_user ((char *) arg, &pos, sizeof (struct mtpos)))
return -EFAULT;
return 0;
case MTIOCGET:
- get.mt_erreg = tape->rc;
- cqr = tape->discipline->mttell (tape, 0);
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tape->cqr = cqr;
- tape->wanna_wakeup=0;
- do_IO (tape->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
- wait_event_interruptible (tape->wq,tape->wanna_wakeup);
- get.mt_blkno = tape->rc;
+ get.mt_erreg = ti->rc;
+ cqr = ti->discipline->mttell (ti, 0);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ ti->cqr = cqr;
+ ti->wanna_wakeup=0;
+ do_IO (ti->devinfo.irq, cqr->cpaddr, (unsigned long) cqr, 0x00, cqr->options);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
+ wait_event_interruptible (ti->wq,ti->wanna_wakeup);
+ get.mt_blkno = ti->rc;
get.mt_fileno = 0;
get.mt_type = MT_ISUNKNOWN;
- get.mt_resid = tape->devstat.rescnt;
- get.mt_dsreg = tape->devstat.ii.sense.data[3];
+ get.mt_resid = ti->devstat.rescnt;
+ get.mt_dsreg = ti->devstat.ii.sense.data[3];
get.mt_gstat = 0;
- if (tape->devstat.ii.sense.data[1] & 0x08)
+ if (ti->devstat.ii.sense.data[1] & 0x08)
get.mt_gstat &= GMT_BOT (1); // BOT
- if (tape->devstat.ii.sense.data[1] & 0x02)
+ if (ti->devstat.ii.sense.data[1] & 0x02)
get.mt_gstat &= GMT_WR_PROT (1); // write protected
- if (tape->devstat.ii.sense.data[1] & 0x40)
+ if (ti->devstat.ii.sense.data[1] & 0x40)
get.mt_gstat &= GMT_ONLINE (1); //drive online
- tape->cqr = NULL;
- if (tape->kernbuf != NULL) {
- kfree (tape->kernbuf);
- tape->kernbuf = NULL;
+ ti->cqr = NULL;
+ if (ti->kernbuf != NULL) {
+ kfree (ti->kernbuf);
+ ti->kernbuf = NULL;
}
tape_free_request (cqr);
if (signal_pending (current)) {
- tapestate_set (tape, TS_IDLE);
+ tapestate_set (ti, TS_IDLE);
return -ERESTARTSYS;
}
- s390irq_spin_lock_irqsave (tape->devinfo.irq, lockflags);
- tapestate_set (tape, TS_IDLE);
- s390irq_spin_unlock_irqrestore (tape->devinfo.irq, lockflags);
+ s390irq_spin_lock_irqsave (ti->devinfo.irq, lockflags);
+ tapestate_set (ti, TS_IDLE);
+ s390irq_spin_unlock_irqrestore (ti->devinfo.irq, lockflags);
if (copy_to_user ((char *) arg, &get, sizeof (struct mtget)))
return -EFAULT;
return 0;
int tape_open (struct inode *,struct file *);
int tape_release (struct inode *,struct file *);
#ifdef CONFIG_DEVFS_FS
-void tapechar_mkdevfstree (tape_info_t* tape);
+void tapechar_mkdevfstree (tape_info_t* ti);
#endif
void tapechar_init (void);
void tapechar_uninit (void);
***********************************************************************
*/
+/* Kernel Version Compatibility section */
+#include <linux/version.h>
+#include <linux/blkdev.h>
+#include <linux/blk.h>
+#include <asm/irq.h>
+
+#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,2,17))
#define TAPE_DEBUG // use s390 debug feature
+#else
+#undef TAPE_DEBUG // debug feature not supported by our 2.2.16 code
+static inline void set_normalized_cda ( ccw1_t * cp, unsigned long address ) {
+ cp -> cda = address;
+}
+static inline void clear_normalized_cda ( ccw1_t * ccw ) {
+ ccw -> cda = 0;
+}
+#define BUG() PRINT_FATAL("tape390: CRITICAL INTERNAL ERROR OCCURED. REPORT THIS BACK TO LINUX390@DE.IBM.COM\n")
+#endif
#define CONFIG_S390_TAPE_DYNAMIC // allow devices to be attached or detached on the fly
#define TAPEBLOCK_RETRIES 20 // number of retries, when a block-dev request fails.
-/* Kernel Version Compatibility section */
-#include <linux/version.h>
-#include <linux/blkdev.h>
-#include <linux/blk.h>
#if (LINUX_VERSION_CODE > KERNEL_VERSION(2,3,98))
#define INIT_BLK_DEV(d_major,d_request_fn,d_queue_fn,d_current) \
do { \
/* Module parameters */
int tubdebug;
-int tubscrolltime;
-int tubscrollparm;
+int tubscrolltime = -1;
int tubxcorrect = 1; /* Do correct ebc<->asc tables */
#ifdef MODULE
MODULE_PARM(tubdebug, "i");
0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
0xf8, 0xf9, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f };
-static int tub3270_init(void);
+int tub3270_init(void);
#ifndef MODULE
/*
* Can't have this driver a module & support console at the same time
*/
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
static kdev_t tub3270_con_device(struct console *);
static void tub3270_con_unblank(void);
static void tub3270_con_write(struct console *, const char *,
NULL /* next */
};
-int tub3270_con_devno = -1; /* set by tub3270_con_setup() */
bcb_t tub3270_con_bcb; /* Buffer that receives con writes */
spinlock_t tub3270_con_bcblock; /* Lock for the buffer */
int tub3270_con_irq = -1; /* set nonneg by _activate() */
struct tty_driver tty3270_con_driver; /* for /dev/console at 4, 64 */
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+int tub3270_con_devno = -1; /* set by tub3270_con_setup() */
__initfunc(void tub3270_con_setup(char *str, int *ints))
-#else
-static int __init tub3270_con_setup(char *str)
-#endif
{
int vdev;
vdev = simple_strtoul(str, 0, 16);
if (vdev >= 0 && vdev < 65536)
tub3270_con_devno = vdev;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
return;
-#else
- return 1;
-#endif
}
-#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
-__setup("condev=", tub3270_con_setup);
-#endif
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
__initfunc (long tub3270_con_init(long kmem_start, long kmem_end))
-#else
-void __init tub3270_con_init(void)
-#endif
{
tub3270_con_bcb.bc_len = 65536;
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
if (!MACHINE_IS_VM && !MACHINE_IS_P390)
return kmem_start;
tub3270_con_bcb.bc_buf = (void *)kmem_start;
kmem_start += tub3270_con_bcb.bc_len;
register_console(&tub3270_con);
return kmem_start;
+}
#else
- if (!MACHINE_IS_VM && !MACHINE_IS_P390)
+#define tub3270_con_devno console_device
+
+void __init tub3270_con_init(void)
+{
+ tub3270_con_bcb.bc_len = 65536;
+ if (!CONSOLE_IS_3270)
return;
tub3270_con_bcb.bc_buf = (void *)alloc_bootmem_low(
tub3270_con_bcb.bc_len);
register_console(&tub3270_con);
-#endif
}
+#endif
static kdev_t
tub3270_con_device(struct console *conp)
{
- return MKDEV(IBM_TTY3270_MAJOR, conp->index);
+ return MKDEV(IBM_TTY3270_MAJOR, conp->index + 1);
}
static void
tub3270_con_write(struct console *conp,
const char *buf, unsigned int count)
{
- int flags;
+ long flags;
tub_t *tubp = tub3270_con_tubp;
void tty3270_sched_bh(tub_t *);
int rc;
obcb.bc_rd = 0;
spin_lock_irqsave(&tub3270_con_bcblock, flags);
- rc = tub3270_movedata(&obcb, &tub3270_con_bcb);
+ rc = tub3270_movedata(&obcb, &tub3270_con_bcb, 0);
spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
if (tubp && rc && TUBTRYLOCK(tubp->irq, flags)) {
int tub3270_con_copy(tub_t *tubp)
{
- int flags;
+ long flags;
int rc;
spin_lock_irqsave(&tub3270_con_bcblock, flags);
- rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb);
+ rc = tub3270_movedata(&tub3270_con_bcb, &tubp->tty_bcb, 0);
spin_unlock_irqrestore(&tub3270_con_bcblock, flags);
return rc;
}
-#endif /* CONFIG_3270_CONSOLE */
-
-
-
-
-#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
-__initfunc(void tub3270_initfunc(void))
-#else
-void __init tub3270_initfunc(void)
-#endif
-{
- tub3270_init();
-}
+#endif /* CONFIG_TN3270_CONSOLE */
#else /* If generated as a MODULE */
/*
* module init: find tubes; get a major nbr
/*
* tub3270_init() called by kernel or module initialization
*/
-static int
+int
tub3270_init(void)
{
s390_dev_info_t d;
int i, rc;
- /*
- * Initialize default scrolltime to either -1 or the
- * module parameter tubscrolltime.
- */
- if (tubscrolltime)
- tubscrollparm = tubscrolltime;
- else
- tubscrollparm = -1;
-
/*
* Copy and correct ebcdic - ascii translate tables
*/
if (rc != 0)
return rc;
+ if (fs3270_init() || tty3270_init()) {
+ printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n");
+ fs3270_fini();
+ tty3270_fini();
+ tubfiniminors();
+ return -1;
+ }
+
for (i = get_irq_first(); i >= 0; i = get_irq_next(i)) {
if ((rc = get_dev_info_by_irq(i, &d)))
continue;
if (d.status)
continue;
-#ifdef CONFIG_3270_CONSOLE
+
+#ifdef CONFIG_TN3270_CONSOLE
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
if (d.sid_data.cu_type == 0x3215 && MACHINE_IS_VM) {
cpcmd("TERM CONMODE 3270", NULL, 0);
d.sid_data.cu_type = 0x3270;
}
-#endif /* CONFIG_3270_CONSOLE */
+#else
+ if (d.sid_data.cu_type == 0x3215 && CONSOLE_IS_3270) {
+ cpcmd("TERM CONMODE 3270", NULL, 0);
+ d.sid_data.cu_type = 0x3270;
+ }
+#endif /* LINUX_VERSION_CODE */
+#endif /* CONFIG_TN3270_CONSOLE */
if ((d.sid_data.cu_type & 0xfff0) != 0x3270)
continue;
rc = tubmakemin(i, &d);
if (rc < 0) {
- if (tubnummins == 1) { /* if first time */
- tubfiniminors();
- printk(KERN_ERR "No kernel memory available"
- " for 3270 tube devices.\n");
- return rc;
- }
- printk(KERN_WARNING "3270 tube registration ran out of memory"
- " after %d devices\n", tubnummins - 1);
+ printk(KERN_WARNING
+ "3270 tube registration ran out of memory"
+ " after %d devices\n", tubnummins - 1);
break;
} else {
printk(KERN_INFO "3270: %.4x on sch %d, minor %d\n",
}
}
- if (fs3270_init() || tty3270_init()) {
- printk(KERN_ERR "fs3270_init() or tty3270_init() failed\n");
- fs3270_fini();
- tty3270_fini();
- tubfiniminors();
- return -1;
- }
-
return 0;
}
* tub3270_movedata(bcb_t *, bcb_t *) -- Move data stream
*/
int
-tub3270_movedata(bcb_t *ib, bcb_t *ob)
+tub3270_movedata(bcb_t *ib, bcb_t *ob, int fromuser)
{
int count; /* Total move length */
int rc;
len2 = ob->bc_len - ob->bc_wr;
if (len2 > len1)
len2 = len1;
-
- memcpy(ob->bc_buf + ob->bc_wr,
- ib->bc_buf + ib->bc_rd,
- len2);
-
+
+ if (fromuser) {
+ len2 -= copy_from_user(ob->bc_buf + ob->bc_wr,
+ ib->bc_buf + ib->bc_rd,
+ len2);
+ if (len2 == 0) {
+ if (!rc)
+ rc = -EFAULT;
+ break;
+ }
+ } else
+ memcpy(ob->bc_buf + ob->bc_wr,
+ ib->bc_buf + ib->bc_rd,
+ len2);
+
ib->bc_rd += len2;
if (ib->bc_rd == ib->bc_len)
ib->bc_rd = 0;
{
tub_t *tubp;
int minor;
- int flags;
+ long flags;
if ((minor = ++tubnummins) == TUBMAXMINS)
return -ENODEV;
tubp->tty_bcb.bc_len = TTY_OUTPUT_SIZE;
tubp->tty_bcb.bc_buf = (void *)kmalloc(tubp->tty_bcb.bc_len,
- GFP_KERNEL);
+ GFP_KERNEL|GFP_DMA);
if (tubp->tty_bcb.bc_buf == NULL) {
TUBUNLOCK(tubp->irq, flags);
tubdelbyirq(tubp, irq);
tubp->tty_bcb.bc_wr = 0;
tubp->tty_bcb.bc_rd = 0;
(*tubminors)[minor] = tubp;
-#ifdef CONFIG_3270_CONSOLE
- if (tub3270_con_tubp == NULL && tub3270_con_bcb.bc_buf != NULL &&
- (tub3270_con_devno == -1 ||
- tub3270_con_devno == dp->devno)) {
- extern void tty3270_int(tub_t *, devstat_t *);
-
- tubp->cmd = TBC_CONOPEN;
- tubp->flags |= TUB_OPEN_STET;
- tty3270_size(tubp, &flags);
- tty3270_aid_init(tubp);
- tty3270_scl_init(tubp);
- tub3270_con_irq = tubp->irq;
- tub3270_con_tubp = tubp;
- tubp->intv = tty3270_int;
- tubp->cmd = TBC_UPDSTAT;
- tty3270_build(tubp);
+
+#ifdef CONFIG_TN3270_CONSOLE
+ if (CONSOLE_IS_3270) {
+ if (tub3270_con_tubp == NULL &&
+ tub3270_con_bcb.bc_buf != NULL &&
+ (tub3270_con_devno == -1 ||
+ tub3270_con_devno == dp->devno)) {
+ extern void tty3270_int(tub_t *, devstat_t *);
+
+ tub3270_con_devno = dp->devno;
+ tubp->cmd = TBC_CONOPEN;
+ tubp->flags |= TUB_OPEN_STET;
+ tty3270_size(tubp, &flags);
+ tty3270_aid_init(tubp);
+ tty3270_scl_init(tubp);
+ tub3270_con_irq = tubp->irq;
+ tub3270_con_tubp = tubp;
+ tubp->intv = tty3270_int;
+ tubp->cmd = TBC_UPDSTAT;
+ tty3270_build(tubp);
+ }
}
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
+
+#ifdef CONFIG_DEVFS_FS
+ fs3270_devfs_register(tubp);
+#endif
+
TUBUNLOCK(tubp->irq, flags);
return minor;
}
for (i = 0; i < TUBMAXMINS; i++) {
tubpp = &(*tubminors)[i];
if ((tubp = *tubpp)) {
+#ifdef CONFIG_DEVFS_FS
+ fs3270_devfs_unregister(tubp);
+#endif
tubdelbyirq(tubp, tubp->irq);
tty3270_rcl_fini(tubp);
kfree(tubp->tty_bcb.bc_buf);
static int fs3270_open(struct inode *, struct file *);
static int fs3270_close(struct inode *, struct file *);
static int fs3270_ioctl(struct inode *, struct file *, unsigned int, unsigned long);
-static int fs3270_read(struct file *, char *, size_t, loff_t *);
-static int fs3270_write(struct file *, const char *, size_t, loff_t *);
-static int fs3270_wait(tub_t *, int *);
+static ssize_t fs3270_read(struct file *, char *, size_t, loff_t *);
+static ssize_t fs3270_write(struct file *, const char *, size_t, loff_t *);
+static int fs3270_wait(tub_t *, long *);
static void fs3270_int(tub_t *tubp, devstat_t *dsp);
extern void tty3270_refresh(tub_t *);
release:fs3270_close, /* release */
};
+#ifdef CONFIG_DEVFS_FS
+devfs_handle_t fs3270_devfs_dir;
+devfs_handle_t fs3270_devfs_tub;
+extern struct file_operations tty_fops;
+
+void fs3270_devfs_register(tub_t *tubp)
+{
+ char name[16];
+
+ sprintf(name, "tub%x", tubp->devno);
+ devfs_register(fs3270_devfs_dir, name, DEVFS_FL_DEFAULT,
+ IBM_FS3270_MAJOR, tubp->minor,
+ S_IFCHR | S_IRUSR | S_IWUSR, &fs3270_fops, NULL);
+ sprintf(name, "tty%x", tubp->devno);
+ tty_register_devfs_name(&tty3270_driver, 0, tubp->minor,
+ fs3270_devfs_dir, name);
+}
+
+void fs3270_devfs_unregister(tub_t *tubp)
+{
+ char name[16];
+ devfs_handle_t handle;
+
+ sprintf(name, "tub%x", tubp->devno);
+ handle = devfs_find_handle (fs3270_devfs_dir, name,
+ IBM_FS3270_MAJOR, tubp->minor,
+ DEVFS_SPECIAL_CHR, 0);
+ devfs_unregister (handle);
+ sprintf(name, "tty%x", tubp->devno);
+ handle = devfs_find_handle (fs3270_devfs_dir, name,
+ IBM_TTY3270_MAJOR, tubp->minor,
+ DEVFS_SPECIAL_CHR, 0);
+ devfs_unregister(handle);
+}
+#endif
+
/*
* fs3270_init() -- Initialize fullscreen tubes
*/
{
int rc;
+#ifdef CONFIG_DEVFS_FS
+ rc = devfs_register_chrdev (IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
+ if (rc) {
+ printk(KERN_ERR "tubmod can't get major nbr %d: error %d\n",
+ IBM_FS3270_MAJOR, rc);
+ return -1;
+ }
+ fs3270_devfs_dir = devfs_mk_dir(NULL, "3270", NULL);
+ fs3270_devfs_tub =
+ devfs_register(fs3270_devfs_dir, "tub", DEVFS_FL_DEFAULT,
+ IBM_FS3270_MAJOR, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
+ &fs3270_fops, NULL);
+#else
rc = register_chrdev(IBM_FS3270_MAJOR, "fs3270", &fs3270_fops);
if (rc) {
printk(KERN_ERR "tubmod can't get major nbr %d: error %d\n",
IBM_FS3270_MAJOR, rc);
return -1;
- } else {
- fs3270_major = IBM_FS3270_MAJOR;
- return 0;
}
+#endif
+ fs3270_major = IBM_FS3270_MAJOR;
+ return 0;
}
/*
fs3270_fini(void)
{
if (fs3270_major != -1) {
+#ifdef CONFIG_DEVFS_FS
+ devfs_unregister(fs3270_devfs_tub);
+ devfs_unregister(fs3270_devfs_dir);
+#endif
unregister_chrdev(fs3270_major, "fs3270");
fs3270_major = -1;
}
fs3270_open(struct inode *ip, struct file *fp)
{
tub_t *tubp;
- int flags;
+ long flags;
/* See INODE2TUB(ip) for handling of "/dev/3270/tub" */
if ((tubp = INODE2TUB(ip)) == NULL)
fs3270_close(struct inode *ip, struct file *fp)
{
tub_t *tubp;
- int flags;
+ long flags;
if ((tubp = INODE2TUB(ip)) == NULL)
return -ENODEV;
void
fs3270_release(tub_t *tubp)
{
- int flags;
+ long flags;
if (tubp->mode != TBM_FS)
return;
* * Value is 0 or -ERESTARTSYS
*/
static int
-fs3270_wait(tub_t *tubp, int *flags)
+fs3270_wait(tub_t *tubp, long *flags)
{
DECLARE_WAITQUEUE(wait, current);
static void
fs3270_bh(void *data)
{
- int flags;
+ long flags;
tub_t *tubp;
tubp = data;
unsigned int cmd, unsigned long arg)
{
tub_t *tubp;
- int rc = 0, flags;
+ int rc = 0;
+ long flags;
if ((tubp = INODE2TUB(ip)) == NULL)
return -ENODEV;
/*
* process read commands for the tube driver
*/
-static int
+static ssize_t
fs3270_read(struct file *fp, char *dp, size_t len, loff_t *off)
{
tub_t *tubp;
char *kp;
ccw1_t *cp;
- int rc, flags;
+ int rc;
+ long flags;
if ((tubp = INODE2TUB((struct inode *)fp->private_data)) == NULL)
return -ENODEV;
return rc;
}
- kp = kmalloc(len, GFP_KERNEL);
+ kp = kmalloc(len, GFP_KERNEL|GFP_DMA);
if (kp == NULL) {
TUBUNLOCK(tubp->irq, flags);
return -ENOMEM;
if (tubdebug & 1)
printk(KERN_DEBUG "minor %d: %.8x %.8x %.8x %.8x\n",
tubp->minor,
- *(int*)((int)kp + 0),
- *(int*)((int)kp + 4),
- *(int*)((int)kp + 8),
- *(int*)((int)kp + 12));
+ *(int*)((long)kp + 0),
+ *(int*)((long)kp + 4),
+ *(int*)((long)kp + 8),
+ *(int*)((long)kp + 12));
copy_to_user(dp, kp, len);
kfree(kp);
return len;
/*
* process write commands for the tube driver
*/
-static int
+static ssize_t
fs3270_write(struct file *fp, const char *dp, size_t len, loff_t *off)
{
tub_t *tubp;
ccw1_t *cp;
- int rc, flags;
+ int rc;
+ long flags;
void *kb;
/* Locate the tube */
return -ENODEV;
/* Copy data to write from user address space */
- if ((kb = kmalloc(len, GFP_KERNEL)) == NULL)
+ if ((kb = kmalloc(len, GFP_KERNEL|GFP_DMA)) == NULL)
return -ENOMEM;
if (copy_from_user(kb, dp, len) != 0) {
kfree(kb);
#endif /* IBM_FS3270_MAJOR */
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/irq.h>
#include <asm/io.h>
#include <linux/console.h>
#include <asm/ebcdic.h>
#include <asm/uaccess.h>
#include <linux/proc_fs.h>
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
+#include <linux/devfs_fs_kernel.h>
+#endif
#define TUB(x) (('3'<<8)|(x))
#define TUBICMD TUB(3)
#define TUB_OPEN_STET 0x0400 /* No screen clear on open */
#define TUB_UE_BUSY 0x0800
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
/*
* Extra stuff for 3270 console support
*/
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
#define S390_CONSOLE_DEV MKDEV(TTY_MAJOR, 64)
+#else
+#define S390_CONSOLE_DEV MKDEV(TTYAUX_MAJOR, 1)
+#endif
extern int tub3270_con_devno;
extern char (*tub3270_con_output)[];
extern int tub3270_con_outputl;
extern int tub3270_con_irq;
extern tub_t *tub3270_con_tubp;
extern struct tty_driver tty3270_con_driver;
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
extern int tubnummins;
extern tub_t *(*tubminors)[TUBMAXMINS];
extern int tty3270_major;
extern int tty3270_proc_misc;
extern enum tubwhat tty3270_proc_what;
+extern struct tty_driver tty3270_driver;
+#ifdef CONFIG_DEVFS_FS
+extern devfs_handle_t fs3270_devfs_dir;
+extern void fs3270_devfs_register(tub_t *);
+extern void fs3270_devfs_unregister(tub_t *);
+#endif
#ifndef spin_trylock_irqsave
#define spin_trylock_irqsave(lock, flags) \
* Find tub_t * given fullscreen device's inode pointer
* This algorithm takes into account /dev/3270/tub.
*/
-#ifdef CONFIG_3270_CONSOLE
-#define INODE2TUB(ip) \
-({ \
- unsigned int minor; \
- tub_t *tubp = NULL; \
- minor = MINOR((ip)->i_rdev); \
- if (minor == 0 && current->tty != NULL) { \
- if (tub3270_con_tubp != NULL && \
- current->tty->device == S390_CONSOLE_DEV) \
- minor = tub3270_con_tubp->minor; \
- else if (MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \
- minor = MINOR(current->tty->device); \
- } \
- if (minor <= tubnummins && minor > 0) \
- tubp = (*tubminors)[minor]; \
- tubp; \
-})
-#else /* not CONFIG_3270_CONSOLE */
-#define INODE2TUB(ip) \
-({ \
- unsigned int minor; \
- tub_t *tubp = NULL; \
- minor = MINOR((ip)->i_rdev); \
- if (minor == 0 && current->tty != NULL && \
- MAJOR(current->tty->device) == IBM_TTY3270_MAJOR) \
- minor = MINOR(current->tty->device); \
- if (minor <= tubnummins && minor > 0) \
- tubp = (*tubminors)[minor]; \
- tubp; \
-})
-#endif /* CONFIG_3270_CONSOLE or not */
+extern inline tub_t *INODE2TUB(struct inode *ip)
+{
+ unsigned int minor = MINOR(ip->i_rdev);
+ tub_t *tubp = NULL;
+ if (minor == 0 && current->tty != NULL) {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+#ifdef CONFIG_TN3270_CONSOLE
+ if (tub3270_con_tubp != NULL &&
+ current->tty->device == S390_CONSOLE_DEV)
+ minor = tub3270_con_tubp->minor;
+ else
+#endif
+#endif
+ if (MAJOR(current->tty->device) == IBM_TTY3270_MAJOR)
+ minor = MINOR(current->tty->device);
+ }
+ if (minor >= tubnummins && minor > 0)
+ tubp = (*tubminors)[minor];
+ return tubp;
+}
+
/*
* Find tub_t * given non-fullscreen (tty) device's tty_struct pointer
*/
-#ifdef CONFIG_3270_CONSOLE
-#define TTY2TUB(tty) \
-({ \
- unsigned int minor; \
- tub_t *tubp = NULL; \
- minor = MINOR(tty->device); \
- if (tty->device == S390_CONSOLE_DEV) \
- tubp = tub3270_con_tubp; \
- else if (minor <= tubnummins && minor > 0) \
- tubp = (*tubminors)[minor]; \
- tubp; \
-})
-#else /* if not CONFIG_3270_CONSOLE */
-#define TTY2TUB(tty) \
-({ \
- unsigned int minor; \
- tub_t *tubp = NULL; \
- minor = MINOR(tty->device); \
- if (minor <= tubnummins && minor > 0) \
- tubp = (*tubminors)[minor]; \
- tubp; \
-})
-#endif /* CONFIG_3270_CONSOLE or not */
+extern inline tub_t *TTY2TUB(struct tty_struct *tty)
+{
+ unsigned int minor = MINOR(tty->device);
+ tub_t *tubp = NULL;
+
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+#ifdef CONFIG_TN3270_CONSOLE
+ if (tty->device == S390_CONSOLE_DEV)
+ tubp = tub3270_con_tubp;
+ else
+#endif
+#endif
+ if (minor <= tubnummins && minor > 0)
+ tubp = (*tubminors)[minor];
+ return tubp;
+}
extern void tub_inc_use_count(void);
extern void tub_dec_use_count(void);
-extern int tub3270_movedata(bcb_t *, bcb_t *);
+extern int tub3270_movedata(bcb_t *, bcb_t *, int);
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
extern int tubmakemin(int, dev_info_t *);
#else
extern void tty3270_rcl_sync(tub_t *);
extern void tty3270_rcl_purge(tub_t *);
extern int tty3270_rcl_resize(tub_t *, int);
-extern int tty3270_size(tub_t *, int *);
+extern int tty3270_size(tub_t *, long *);
extern int tty3270_aid_init(tub_t *);
extern void tty3270_aid_fini(tub_t *);
extern void tty3270_aid_reinit(tub_t *);
/* tty3270 utility functions */
static void tty3270_bh(void *);
void tty3270_sched_bh(tub_t *);
-static int tty3270_wait(tub_t *, int *);
+static int tty3270_wait(tub_t *, long *);
void tty3270_int(tub_t *, devstat_t *);
int tty3270_try_logging(tub_t *);
static void tty3270_start_input(tub_t *);
static int tty3270_show_tube(int, char *, int);
int tty3270_major = -1;
-char tty3270_major_string[16];
struct tty_driver tty3270_driver;
int tty3270_refcount;
struct tty_struct *tty3270_table[TUBMAXMINS];
struct termios *tty3270_termios[TUBMAXMINS];
struct termios *tty3270_termios_locked[TUBMAXMINS];
-#ifdef CONFIG_3270_CONSOLE
+#ifdef CONFIG_TN3270_CONSOLE
int con3270_major = -1;
struct tty_driver con3270_driver;
int con3270_refcount;
struct tty_struct *con3270_table[1];
struct termios *con3270_termios[1];
struct termios *con3270_termios_locked[1];
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
int tty3270_proc_index;
int tty3270_proc_data;
td->subtype = SYSTEM_TYPE_TTY;
td->init_termios = tty_std_termios;
td->flags = TTY_DRIVER_RESET_TERMIOS;
+#ifdef CONFIG_DEVFS_FS
+ td->flags |= TTY_DRIVER_NO_DEVFS;
+#endif
td->refcount = &tty3270_refcount;
td->table = tty3270_table;
td->termios = tty3270_termios;
printk(KERN_ERR "tty3270 registration failed with %d\n", rc);
} else {
tty3270_major = IBM_TTY3270_MAJOR;
- sprintf(tty3270_major_string, "%d", tty3270_major);
if (td->proc_entry != NULL)
td->proc_entry->mode = S_IRUGO | S_IWUGO;
}
-#ifdef CONFIG_3270_CONSOLE
- tty3270_con_driver = *td;
- td = &tty3270_con_driver;
- td->driver_name = "con3270";
- td->name = "con3270";
- td->major = MAJOR(S390_CONSOLE_DEV);
- td->minor_start = MINOR(S390_CONSOLE_DEV);
- td->num = 1;
- td->refcount = &con3270_refcount;
- td->table = con3270_table;
- td->termios = con3270_termios;
- td->termios_locked = con3270_termios_locked;
-
- rc = tty_register_driver(td);
- if (rc) {
- printk(KERN_ERR "con3270 registration failed with %d\n", rc);
- } else {
- con3270_major = MAJOR(S390_CONSOLE_DEV);
- if (td->proc_entry != NULL)
- td->proc_entry->mode = S_IRUGO | S_IWUGO;
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+#ifdef CONFIG_TN3270_CONSOLE
+ if (CONSOLE_IS_3270) {
+ tty3270_con_driver = *td;
+ td = &tty3270_con_driver;
+ td->driver_name = "con3270";
+ td->name = "con3270";
+ td->major = MAJOR(S390_CONSOLE_DEV);
+ td->minor_start = MINOR(S390_CONSOLE_DEV);
+ td->num = 1;
+ td->refcount = &con3270_refcount;
+ td->table = con3270_table;
+ td->termios = con3270_termios;
+ td->termios_locked = con3270_termios_locked;
+
+ rc = tty_register_driver(td);
+ if (rc) {
+ printk(KERN_ERR
+ "con3270 registration failed with %d\n", rc);
+ } else {
+ con3270_major = MAJOR(S390_CONSOLE_DEV);
+ if (td->proc_entry != NULL)
+ td->proc_entry->mode = S_IRUGO | S_IWUGO;
+ }
}
-#endif /* if CONFIG_3270_CONSOLE */
+#endif /* ifdef CONFIG_TN3270_CONSOLE */
+#endif /* if LINUX_VERSION_CODE */
return rc;
}
tty_unregister_driver(&tty3270_driver);
tty3270_major = -1;
}
-#ifdef CONFIG_3270_CONSOLE
- if (con3270_major != -1) {
+#ifdef CONFIG_TN3270_CONSOLE
+ if (CONSOLE_IS_3270 && con3270_major != -1) {
tty_unregister_driver(&con3270_driver);
con3270_major = -1;
}
tty3270_open(struct tty_struct *tty, struct file *filp)
{
tub_t *tubp;
- int flags;
+ long flags;
int rc;
int cmd;
tty3270_close(struct tty_struct *tty, struct file *filp)
{
tub_t *tubp;
- int flags;
+ long flags;
if ((tubp = tty->driver_data) == NULL)
return;
const unsigned char *buf, int count)
{
tub_t *tubp;
- int flags;
+ long flags;
bcb_t obcb;
int rc = 0;
if ((tubp = tty->driver_data) == NULL)
return -1;
-#ifdef CONFIG_3270_CONSOLE
- if (tub3270_con_tubp == tubp)
+#ifdef CONFIG_TN3270_CONSOLE
+ if (CONSOLE_IS_3270 && tub3270_con_tubp == tubp)
tub3270_con_copy(tubp);
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
obcb.bc_buf = (char *)buf;
obcb.bc_len = obcb.bc_cnt = obcb.bc_wr = count;
obcb.bc_rd = 0;
TUBLOCK(tubp->irq, flags);
- rc = tub3270_movedata(&obcb, &tubp->tty_bcb);
+ rc = tub3270_movedata(&obcb, &tubp->tty_bcb, fromuser);
tty3270_try_logging(tubp);
TUBUNLOCK(tubp->irq, flags);
return rc;
static void
tty3270_put_char(struct tty_struct *tty, unsigned char ch)
{
- int flags;
+ long flags;
tub_t *tubp;
bcb_t *ob;
tty3270_flush_chars(struct tty_struct *tty)
{
tub_t *tubp;
- int flags;
+ long flags;
if ((tubp = tty->driver_data) == NULL)
return;
unsigned int cmd, unsigned long arg)
{
tub_t *tubp;
- int flags;
+ long flags;
int ret = 0;
struct termios termios;
tty3270_set_termios(struct tty_struct *tty, struct termios *old)
{
tub_t *tubp;
- int flags;
+ long flags;
int new;
if ((tubp = tty->driver_data) == NULL)
{
tub_t *tubp;
bcb_t *ob;
- int flags;
+ long flags;
if ((tubp = tty->driver_data) == NULL)
return;
int i;
int rc;
int len = 0;
- char *majstr;
if (tty3270_proc_what == TW_CONFIG) {
/*
len += sprintf(buf + len, "0 %d 0\n", fs3270_major);
for (i = 1; i <= tubnummins; i++) {
tubp = (*tubminors)[i];
- majstr = tty3270_major_string;
-#ifdef CONFIG_3270_CONSOLE
- if (tubp == tub3270_con_tubp)
- majstr = "CONSOLE";
-#endif /* CONFIG_3270_CONSOLE */
- len += sprintf(buf + len, "%.3x %s %d\n",
- tubp->devno, majstr, i);
+#ifdef CONFIG_TN3270_CONSOLE
+ if (CONSOLE_IS_3270 && tubp == tub3270_con_tubp)
+ len += sprintf(buf + len, "%.3x CONSOLE %d\n",
+ tubp->devno, i);
+ else
+#endif
+ len += sprintf(buf + len, "%.3x %d %d\n",
+ tubp->devno, tty3270_major, i);
if (begin + len > off + count)
break;
if (begin + len < off) {
if (device) {
if (MAJOR(device) == IBM_TTY3270_MAJOR)
tubp = (*tubminors)[MINOR(device)];
-#ifdef CONFIG_3270_CONSOLE
- if (device == S390_CONSOLE_DEV)
+#ifdef CONFIG_TN3270_CONSOLE
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ if (CONSOLE_IS_3270 && device == S390_CONSOLE_DEV)
tubp = tub3270_con_tubp;
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* LINUX_VERSION_CODE */
+#endif /* CONFIG_TN3270_CONSOLE */
}
if (tubp) {
if ((rc = tty3270_aid_set(tubp, mybuf, mycount + 1)))
static void
tty3270_bh(void *data)
{
- int flags;
+ long flags;
tub_t *tubp;
struct tty_struct *tty;
* On entry the lock must not be held; on exit it is held.
*/
static int
-tty3270_wait(tub_t *tubp, int *flags)
+tty3270_wait(tub_t *tubp, long *flags)
{
DECLARE_WAITQUEUE(wait, current);
return 0;
if (tubp->stat == TBS_MORE)
return 0;
-#ifdef CONFIG_3270_CONSOLE
- if (tub3270_con_tubp == tubp)
+#ifdef CONFIG_TN3270_CONSOLE
+ if (CONSOLE_IS_3270 && tub3270_con_tubp == tubp)
tub3270_con_copy(tubp);
-#endif /* CONFIG_3270_CONSOLE */
+#endif /* CONFIG_TN3270_CONSOLE */
if (tubp->tty_bcb.bc_cnt == 0)
return 0;
if (tubp->intv != tty3270_int)
if (minor < 0 || minor > tubnummins ||
(tubp = (*tubminors)[minor]) == NULL)
return sprintf(buf, "No tube at index=%d\n", minor);
-
+
tty = tubp->tty;
len = 0;
- len += sprintf(buf+len,
-"Info for tub_t[%d] at %.8x:\n",
- minor, (int)tubp);
+ len += sprintf(buf+len, "Info for tub_t[%d] at %p:\n", minor, tubp);
- len += sprintf(buf+len, "inattr is at %.8x\n",
- (int)&tubp->tty_inattr);
+ len += sprintf(buf+len, "inattr is at %p\n", &tubp->tty_inattr);
- len += sprintf(buf+len,
-" geom: rows=%.2d cols=%.2d model=%.1d\n",
- tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model);
+ len += sprintf(buf+len, " geom: rows=%.2d cols=%.2d model=%.1d\n",
+ tubp->geom_rows, tubp->geom_cols, tubp->tubiocb.model);
len += sprintf(buf+len,
-" lnopen=%-2d fsopen=%-2d waitq=%.8x\n",
- tubp->lnopen, tubp->fsopen, (int)&tubp->waitq);
+ " lnopen=%-2d fsopen=%-2d waitq=%p\n",
+ tubp->lnopen, tubp->fsopen, &tubp->waitq);
- len += sprintf(buf+len,
-" dstat=%.2x mode=%-2d stat=%-2d flags=%-4x\n",
- tubp->dstat, tubp->mode, tubp->stat, tubp->flags);
+ len += sprintf(buf+len, " dstat=%.2x mode=%-2d "
+ "stat=%-2d flags=%-4x\n", tubp->dstat,
+ tubp->mode, tubp->stat, tubp->flags);
#ifdef RBH_FIXTHIS
len += sprintf(buf+len,
-" oucount=%-4d ourd=%-5d ouwr=%-5d nextlogx=%-5d\n",
- tubp->tty_oucount, tubp->tty_ourd, tubp->tty_ouwr,
- tubp->tty_nextlogx);
+ " oucount=%-4d ourd=%-5d ouwr=%-5d"
+ " nextlogx=%-5d\n", tubp->tty_oucount,
+ tubp->tty_ourd, tubp->tty_ouwr, tubp->tty_nextlogx);
#endif
- len += sprintf(buf+len,
-" tty=%.8x\n",
- (int)tubp->tty);
+ len += sprintf(buf+len, " tty=%p\n",tubp->tty);
- if (tty) len += sprintf(buf+len,
-" write_wait=%.8x read_wait=%.8x\n",
- (int)&tty->write_wait, (int)&tty->read_wait);
+ if (tty)
+ len += sprintf(buf+len,
+ " write_wait=%.8x read_wait=%.8x\n",
+ tty->write_wait, tty->read_wait);
- if (tty && ((mp = tty->termios))) len += sprintf(buf+len,
-" iflag=%.8x oflag=%.8x cflag=%.8x lflag=%.8x\n",
- mp->c_iflag, mp->c_oflag, mp->c_cflag, mp->c_lflag);
+ if (tty && ((mp = tty->termios)))
+ len += sprintf(buf+len," iflag=%.8x oflag=%.8x "
+ "cflag=%.8x lflag=%.8x\n", mp->c_iflag,
+ mp->c_oflag, mp->c_cflag, mp->c_lflag);
return len;
tty3270_scl_timeout(unsigned long data)
{
tub_t *tubp = (void *)data;
- int flags;
+ long flags;
TUBLOCK(tubp->irq, flags);
tubp->stat = TBS_RUNNING;
int
tty3270_scl_init(tub_t *tubp)
{
- extern int tubscrollparm;
+ extern int tubscrolltime;
- tubp->tty_scrolltime = tubscrollparm;
+ tubp->tty_scrolltime = tubscrolltime;
if (tubp->tty_scrolltime < 0)
tubp->tty_scrolltime = DEFAULT_SCROLLTIME;
return 0;
#include "tubio.h"
static int tty3270_size_io(tub_t *tubp);
static void tty3270_size_int(tub_t *tubp, devstat_t *dsp);
-static int tty3270_size_wait(tub_t *tubp, int *flags, int stat);
+static int tty3270_size_wait(tub_t *tubp, long *flags, int stat);
/*
* Structure representing Usable Area Query Reply Base
* Try to determine screen size using Read Partition (Query)
*/
int
-tty3270_size(tub_t *tubp, int *flags)
+tty3270_size(tub_t *tubp, long *flags)
{
char wbuf[7] = { 0x00, 0x07, 0x01, 0xff, 0x03, 0x00, 0x81 };
int rc = 0;
* Return 0 unless signal pending, in which case -ERESTARTSYS.
*/
static int
-tty3270_size_wait(tub_t *tubp, int *flags, int stat)
+tty3270_size_wait(tub_t *tubp, long *flags, int stat)
{
DECLARE_WAITQUEUE(wait, current);
#include <linux/module.h>
#include <linux/config.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <asm/irq.h>
#include <asm/idals.h>
#ifdef CONFIG_ARCH_S390X
-#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
-#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
-void
-set_normalized_cda ( ccw1_t * cp, unsigned long address )
+
+unsigned long __create_idal (unsigned long address, int count)
{
int nridaws;
- idaw_t *idal;
- int count = cp->count;
+ unsigned long *idal, *tmp;
- if (cp->flags & CCW_FLAG_IDA)
- BUG();
- if (((address + count) >> 31) == 0) {
- cp -> cda = address;
- return;
- }
nridaws = ((address & (IDA_BLOCK_SIZE-1)) + count +
(IDA_BLOCK_SIZE-1)) >> IDA_SIZE_LOG;
idal = idal_alloc(nridaws);
- if ( idal == NULL ) {
- /* probably we should have a fallback here */
- panic ("Cannot allocate memory for IDAL\n");
+ if (idal != NULL) {
+ tmp = idal;
+ *tmp++ = address;
+ address &= -IDA_BLOCK_SIZE;
+ while (--nridaws > 0) {
+ address += IDA_BLOCK_SIZE;
+ *tmp++ = address;
+ }
}
- cp->flags |= CCW_FLAG_IDA;
- cp->cda = (__u32)(unsigned long)(idaw_t *)idal;
- do {
- *idal++ = address;
- address = (address & -(IDA_BLOCK_SIZE)) + (IDA_BLOCK_SIZE);
- nridaws --;
- } while ( nridaws > 0 );
- return;
+ return (unsigned long) idal;
}
-EXPORT_SYMBOL (set_normalized_cda);
+EXPORT_SYMBOL (__create_idal);
#endif
#include <asm/s390dyn.h>
#include <asm/queue.h>
#include <linux/kmod.h>
+#ifndef MIN
+#define MIN(a,b) ((a<b)?a:b)
+#endif
+#ifndef MAX
+#define MAX(a,b) ((a>b)?a:b)
+#endif
+
+
typedef struct chandev_model_info chandev_model_info;
struct chandev_model_info
s32 dev_type; /* device type -1 = don't care */
s16 dev_model; /* device model -1 = don't care */
u8 max_port_no;
- int auto_msck_recovery;
+ int auto_msck_recovery;
+ u8 default_checksum_received_ip_pkts;
+ u8 default_use_hw_stats; /* where available e.g. lcs */
devreg_t drinfo;
};
{
struct chandev *next;
chandev_model_info *model_info;
- u16 cu_type; /* control unit type */
- u8 cu_model; /* control unit model */
- u16 dev_type; /* device type */
- u8 dev_model; /* device model */
- u16 devno;
- unsigned int irq;
+ chandev_subchannel_info sch;
int owned;
};
{
struct chandev_force *next;
chandev_type chan_type;
- s32 devif_num; /* -1 don't care e.g. tr0 implies 0 */
- u16 read_devno;
- u16 write_devno;
+ s32 devif_num; /* -1 don't care, -2 we are forcing a range e.g. tr0 implies 0 */
+ u16 read_lo_devno;
+ u16 write_hi_devno;
+ u16 data_devno; /* only used by gigabit ethernet */
+ s32 memory_usage_in_k;
s16 port_protocol_no; /* where available e.g. lcs,-1 don't care */
u8 checksum_received_ip_pkts;
u8 use_hw_stats; /* where available e.g. lcs */
+ /* claw specific stuff */
+ chandev_claw_info claw;
};
typedef struct chandev_probelist chandev_probelist;
struct chandev_probelist
{
- struct chandev_probelist *next;
- chandev_probefunc probefunc;
- chandev_shutdownfunc shutdownfunc;
- chandev_reoperfunc reoperfunc;
- chandev_type chan_type;
- int devices_found;
+ struct chandev_probelist *next;
+ chandev_probefunc probefunc;
+ chandev_shutdownfunc shutdownfunc;
+ chandev_msck_notification_func msck_notfunc;
+ chandev_type chan_type;
+ int devices_found;
};
-#define default_msck_bits ((1<<(not_oper-1))|(1<<(no_path-1))|(1<<(revalidate-1))|(1<<(gone-1)))
+#define default_msck_bits ((1<<(chandev_status_not_oper-1))|(1<<(chandev_status_no_path-1))|(1<<(chandev_status_revalidate-1))|(1<<(chandev_status_gone-1)))
static char *msck_status_strs[]=
typedef struct chandev_irqinfo chandev_irqinfo;
struct chandev_irqinfo
{
- chandev_irqinfo *next;
- chandev_msck_status msck_status;
- u16 devno;
- unsigned int irq;
- void (*handler)(int, void *, struct pt_regs *);
- unsigned long irqflags;
- void *dev_id;
- char devname[0];
+ chandev_irqinfo *next;
+ chandev_subchannel_info sch;
+ chandev_msck_status msck_status;
+ void (*handler)(int, void *, struct pt_regs *);
+ unsigned long irqflags;
+ void *dev_id;
+ char devname[0];
};
{
chandev_parms *next;
chandev_type chan_type;
+ u16 lo_devno;
+ u16 hi_devno;
char parmstr[0];
};
+static chandev_type chandev_persistent=0;
+
chandev_parms *chandev_parms_head=NULL;
typedef struct chandev_activelist chandev_activelist;
struct chandev_activelist
{
- struct chandev_activelist *next;
- chandev_irqinfo *read_irqinfo;
- chandev_irqinfo *write_irqinfo;
- u16 cu_type; /* control unit type */
- u8 cu_model; /* control unit model */
- u16 dev_type; /* device type */
- u8 dev_model; /* device model */
- chandev_probefunc probefunc;
- chandev_shutdownfunc shutdownfunc;
- chandev_reoperfunc reoperfunc;
- chandev_unregfunc unreg_dev;
- chandev_type chan_type;
- u8 port_no;
- chandev_category category;
- int saved_busy_flag;
-
-
- void *dev_ptr;
- char devname[0];
+ struct chandev_activelist *next;
+ chandev_irqinfo *read_irqinfo;
+ chandev_irqinfo *write_irqinfo;
+ chandev_irqinfo *data_irqinfo;
+ chandev_probefunc probefunc;
+ chandev_shutdownfunc shutdownfunc;
+ chandev_msck_notification_func msck_notfunc;
+ chandev_unregfunc unreg_dev;
+ chandev_type chan_type;
+ u8 port_no;
+ chandev_category category;
+ s32 memory_usage_in_k;
+ void *dev_ptr;
+ char devname[0];
};
static chandev_probelist *chandev_probelist_head=NULL;
static chandev_activelist *chandev_activelist_head=NULL;
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-static int use_devno_names=FALSE;
+int chandev_use_devno_names=FALSE;
#endif
-static int chandev_conf_read=FALSE;
-static int chandev_initialised=FALSE;
+static int chandev_cautious_auto_detect=TRUE;
+static atomic_t chandev_conf_read=ATOMIC_INIT(FALSE);
+static atomic_t chandev_initialised=ATOMIC_INIT(FALSE);
static unsigned long chandev_last_machine_check;
static atomic_t chandev_new_msck;
static unsigned long chandev_last_startmsck_list_update;
-typedef struct chandev_startmsck_list chandev_startmsck_list;
-struct chandev_startmsck_list
+
+typedef enum
+{
+ chandev_start,
+ chandev_first_tag=chandev_start,
+ chandev_msck,
+ chandev_num_notify_tags
+} chandev_userland_notify_tag;
+
+static char *userland_notify_strs[]=
+{
+ "start",
+ "machine_check"
+};
+
+typedef struct chandev_userland_notify_list chandev_userland_notify_list;
+struct chandev_userland_notify_list
{
- chandev_startmsck_list *next;
- chandev_msck_status pre_recovery_action_status;
- chandev_msck_status post_recovery_action_status;
+ chandev_userland_notify_list *next;
+ chandev_userland_notify_tag tag;
+ chandev_msck_status prev_status;
+ chandev_msck_status curr_status;
char devname[0];
};
-static chandev_startmsck_list *startlist_head=NULL;
-static chandev_startmsck_list *mscklist_head=NULL;
+static chandev_userland_notify_list *chandev_userland_notify_head=NULL;
+static void chandev_read_conf_if_necessary(void);
static void chandev_read_conf(void);
#if LINUX_VERSION_CODE >=KERNEL_VERSION(2,3,0)
static long chandev_lock_owner;
static int chandev_lock_cnt;
static spinlock_t chandev_spinlock;
-void *chandev_firstlock_addr,*chandev_lastlock_addr;
+#define CHANDEV_LOCK_DEBUG 0
+#if CHANDEV_LOCK_DEBUG && !defined(CONFIG_ARCH_S390X)
+#define CHANDEV_BACKTRACE_LOOPCNT 10
+void *chandev_first_lock_addr[CHANDEV_BACKTRACE_LOOPCNT],
+ *chandev_last_lock_addr[CHANDEV_BACKTRACE_LOOPCNT],
+ *chandev_last_unlock_addr[CHANDEV_BACKTRACE_LOOPCNT];
+#define CHANDEV_BACKTRACE(variable) \
+memset((variable),0,sizeof(void *)*CHANDEV_BACKTRACE_LOOPCNT); \
+(variable)[0]=__builtin_return_address(0); \
+if(((long)variable[0])&0x80000000) \
+{ \
+(variable)[1]=__builtin_return_address(1); \
+if(((long)variable[1])&0x80000000) \
+{ \
+(variable)[2]=__builtin_return_address(2); \
+if(((long)variable[2])&0x80000000) \
+{ \
+(variable)[3]=__builtin_return_address(3); \
+if(((long)variable[3])&0x80000000) \
+{ \
+(variable)[4]=__builtin_return_address(4); \
+if(((long)variable[4])&0x80000000) \
+{ \
+(variable)[5]=__builtin_return_address(5); \
+if(((long)variable[5])&0x80000000) \
+{ \
+(variable)[6]=__builtin_return_address(6); \
+if(((long)variable[6])&0x80000000) \
+{ \
+(variable)[7]=__builtin_return_address(7); \
+if(((long)variable[7])&0x80000000) \
+{ \
+(variable)[8]=__builtin_return_address(8); \
+if(((long)variable[8])&0x80000000) \
+{ \
+(variable)[9]=__builtin_return_address(9); \
+} \
+} \
+} \
+} \
+} \
+} \
+} \
+} \
+}
+#else
+#define CHANDEV_BACKTRACE(variable)
+#endif
+
+
typedef struct chandev_not_oper_struct chandev_not_oper_struct;
*/
static qheader chandev_not_oper_head={NULL,NULL};
static spinlock_t chandev_not_oper_spinlock;
-static char exec_script[]="/bin/chandev";
#define chandev_interrupt_check() \
if(in_interrupt()) \
#define for_each(variable,head) \
for((variable)=(head);(variable)!=NULL;(variable)=(variable)->next)
+#define for_each_allow_delete(variable,nextmember,head) \
+for((variable)=(head),(nextmember)=((head) ? (head)->next:NULL); \
+(variable)!=NULL; (variable)=(nextmember),(nextmember)=((nextmember) ? (nextmember->next) : NULL))
+
+#define for_each_allow_delete2(variable,nextmember,head) \
+for((variable)=(head);(variable)!=NULL;(variable)=(nextmember))
+
static void chandev_lock(void)
{
- chandev_interrupt_check();
eieio();
+ chandev_interrupt_check();
if(chandev_lock_owner!=(long)current)
{
- spin_lock(&chandev_spinlock);
+ while(!spin_trylock(&chandev_spinlock))
+ schedule();
chandev_lock_cnt=1;
chandev_lock_owner=(long)current;
- chandev_firstlock_addr=__builtin_return_address(0);
+ CHANDEV_BACKTRACE(chandev_first_lock_addr)
}
else
{
chandev_lock_cnt++;
- chandev_lastlock_addr=__builtin_return_address(0);
+ CHANDEV_BACKTRACE(chandev_last_lock_addr)
}
if(chandev_lock_cnt<0||chandev_lock_cnt>100)
{
(long)current,
chandev_lock_owner,
chandev_lock_cnt);
+ CHANDEV_BACKTRACE(chandev_last_unlock_addr)
if(--chandev_lock_cnt==0)
{
chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
}
-void chandev_relock(int saved_lock_cnt)
-{
-
- chandev_lock();
- chandev_lock_cnt=saved_lock_cnt;
-}
-
void *chandev_alloc(size_t size)
{
void chandev_free_listmember(list **listhead,list *member)
{
+ chandev_lock();
if(member)
{
if(chandev_remove_from_list(listhead,member))
printk(KERN_CRIT"chandev_free_listmember detected nonexistant"
"listmember listhead=%p member %p\n",listhead,member);
}
+ chandev_unlock();
}
void chandev_free_queuemember(qheader *qhead,queue *member)
{
+ chandev_lock();
if(member)
{
if(chandev_remove_from_queue(qhead,member))
kfree(member);
else
- printk(KERN_CRIT"chandev_free_listmember detected nonexistant"
- "listmember qhead=%p member %p\n",qhead,member);
+ printk(KERN_CRIT"chandev_free_queuemember detected nonexistant"
+ "queuemember qhead=%p member %p\n",qhead,member);
}
+ chandev_unlock();
}
{
list *head;
+ chandev_lock();
while((head=remove_listhead(listhead)))
kfree(head);
+ chandev_unlock();
}
void chandev_free_all_queue(qheader *qhead)
{
+ chandev_lock();
while(qhead->head)
chandev_free_queuemember(qhead,qhead->head);
+ chandev_unlock();
}
+static void chandev_wait_for_root_fs(void)
+{
+ wait_queue_head_t wait;
+ init_waitqueue_head(&wait);
+ /* We need to wait till there is a root filesystem */
+ while(init_task.fs->root==NULL)
+ {
+ sleep_on_timeout(&wait,HZ);
+ }
+}
+/* We are now hotplug compliant i.e. */
+/* we typically get called in /sbin/hotplug chandev our parameters */
static int chandev_exec_start_script(void *unused)
{
char **argv,*tempname;
int retval=-ENOMEM;
- int loopcnt,argc;
+ int argc,loopcnt;
size_t allocsize;
- chandev_startmsck_list *member;
+ chandev_userland_notify_list *member;
wait_queue_head_t wait;
+ int have_tag[chandev_num_notify_tags]={FALSE,};
+ chandev_userland_notify_tag tagidx;
static char * envp[] = { "HOME=/", "TERM=linux", "PATH=/sbin:/usr/sbin:/bin:/usr/bin", NULL };
init_waitqueue_head(&wait);
{
sleep_on_timeout(&wait,HZ);
}
+ if(!chandev_userland_notify_head)
+ return(0);
chandev_lock();
- argc=1;
- if(startlist_head)
- argc++;
- for_each(member,startlist_head)
- argc++;
- if(mscklist_head)
- argc+=3;
- for_each(member,mscklist_head)
- argc++;
+ argc=2;
+ for(tagidx=chandev_first_tag;tagidx<chandev_num_notify_tags;tagidx++)
+ {
+ for_each(member,chandev_userland_notify_head)
+ {
+ if(member->tag==tagidx)
+ {
+ switch(tagidx)
+ {
+ case chandev_start:
+ argc++;
+ break;
+ case chandev_msck:
+ argc+=3;
+ break;
+ default:
+ }
+ if(have_tag[tagidx]==FALSE)
+ argc++;
+ have_tag[tagidx]=TRUE;
+ }
+ }
+ }
allocsize=(argc+1)*sizeof(char *);
/* Warning possible stack overflow */
/* We can't kmalloc the parameters here as execve will */
if(argv)
{
memset(argv,0,allocsize);
- argc=0;
- argv[argc++]=exec_script;
- if(startlist_head)
- argv[argc++]="start";
- for_each(member,startlist_head)
- {
- tempname=alloca(strlen(member->devname)+1);
- if(tempname)
- {
- strcpy(tempname,member->devname);
- argv[argc++]=tempname;
- }
- else
- goto Fail;
- }
- if(mscklist_head)
- argv[argc++]="machine_check";
- for_each(member,mscklist_head)
+ argv[0]=hotplug_path;
+ argv[1]="chandev";
+ argc=2;
+ for(tagidx=chandev_first_tag;tagidx<chandev_num_notify_tags;tagidx++)
{
- tempname=alloca(strlen(member->devname)+1);
- if(tempname)
+ if(have_tag[tagidx])
{
- strcpy(tempname,member->devname);
- argv[argc++]=tempname;
+ argv[argc++]=userland_notify_strs[tagidx];
+ for_each(member,chandev_userland_notify_head)
+ {
+ if(member->tag==tagidx)
+ {
+ tempname=alloca(strlen(member->devname)+1);
+ if(tempname)
+ {
+ strcpy(tempname,member->devname);
+ argv[argc++]=tempname;
+ }
+ else
+ goto Fail;
+ if(member->tag==chandev_msck)
+ {
+ argv[argc++]=msck_status_strs[member->prev_status];
+ argv[argc++]=msck_status_strs[member->curr_status];
+ }
+ }
+ }
}
- else
- goto Fail;
- argv[loopcnt++]=msck_status_strs[member->pre_recovery_action_status];
- argv[loopcnt++]=msck_status_strs[member->post_recovery_action_status];
}
- chandev_free_all_list((list **)&startlist_head);
- chandev_free_all_list((list **)&mscklist_head);
+ chandev_free_all_list((list **)&chandev_userland_notify_head);
chandev_unlock();
-
- /* We need to wait till there is a root filesystem */
- while(init_task.fs->root==NULL)
- {
- sleep_on_timeout(&wait,HZ);
- }
+ chandev_wait_for_root_fs();
/* We are basically execve'ing here there normally is no */
/* return */
- retval=exec_usermodehelper(exec_script, argv, envp);
+ retval=exec_usermodehelper(hotplug_path, argv, envp);
goto Fail2;
}
Fail:
chandev_unlock();
Fail2:
- /* We don't really need to report /bin/chandev not existing */
+ /* We don't really need to report /sbin/hotplug not existing */
if(retval!=-ENOENT)
printk("chandev_exec_start_script failed retval=%d\n",retval);
- return(0);
+ return(retval);
}
}
-static int chandev_add_to_startmsck_list(chandev_startmsck_list **listhead,char *devname,
-chandev_msck_status pre_recovery_action_status,chandev_msck_status post_recovery_action_status)
+static int chandev_add_to_userland_notify_list(chandev_userland_notify_tag tag,
+char *devname, chandev_msck_status prev_status,chandev_msck_status curr_status)
{
- chandev_startmsck_list *member;
+ chandev_userland_notify_list *member,*nextmember;
int pid;
chandev_lock();
/* remove operations still outstanding for this device */
- for_each(member,startlist_head)
- if(strcmp(member->devname,devname)==0)
- chandev_remove_from_list((list **)&startlist_head,(list *)member);
- for_each(member,mscklist_head)
+ for_each_allow_delete(member,nextmember,chandev_userland_notify_head)
if(strcmp(member->devname,devname)==0)
- chandev_remove_from_list((list **)&mscklist_head,(list *)member);
+ chandev_free_listmember((list **)&chandev_userland_notify_head,(list *)member);
- if((member=chandev_allocstr(devname,offsetof(chandev_startmsck_list,devname))))
+ if((member=chandev_allocstr(devname,offsetof(chandev_userland_notify_list,devname))))
{
- member->pre_recovery_action_status=pre_recovery_action_status;
- member->post_recovery_action_status=post_recovery_action_status;
- add_to_list((list **)listhead,(list *)member);
+ member->tag=tag;
+ member->prev_status=prev_status;
+ member->curr_status=curr_status;
+ add_to_list((list **)&chandev_userland_notify_head,(list *)member);
chandev_last_startmsck_list_update=jiffies;
chandev_unlock();
pid = kernel_thread(chandev_exec_start_script,NULL,SIGCHLD);
{
chandev_irqinfo *curr_irqinfo;
for_each(curr_irqinfo,chandev_irqinfo_head)
- if(irq==curr_irqinfo->irq)
+ if(irq==curr_irqinfo->sch.irq)
return(curr_irqinfo);
return(NULL);
}
chandev *curr_chandev;
for_each(curr_chandev,(chandev *)chandev_head.head)
- if(curr_chandev->irq==irq)
+ if(curr_chandev->sch.irq==irq)
{
return(curr_chandev);
}
for_each(curr_device,chandev_activelist_head)
{
- if(curr_device->read_irqinfo->irq==irq||
- curr_device->write_irqinfo->irq==irq)
+ if(curr_device->read_irqinfo->sch.irq==irq||
+ curr_device->write_irqinfo->sch.irq==irq||
+ (curr_device->data_irqinfo&&curr_device->data_irqinfo->sch.irq==irq))
return(curr_device);
}
return(NULL);
void chandev_remove_irqinfo_by_irq(unsigned int irq)
{
chandev_irqinfo *remove_irqinfo;
+ chandev_activelist *curr_device;
chandev_lock();
/* remove any orphan irqinfo left lying around. */
if((remove_irqinfo=chandev_get_irqinfo_by_irq(irq)))
- chandev_remove_from_list((list **)&chandev_irqinfo_head,
+ {
+ for_each(curr_device,chandev_activelist_head)
+ {
+ if(curr_device->read_irqinfo==remove_irqinfo)
+ {
+ curr_device->read_irqinfo=NULL;
+ break;
+ }
+ if(curr_device->write_irqinfo==remove_irqinfo)
+ {
+ curr_device->write_irqinfo=NULL;
+ break;
+ }
+ if(curr_device->data_irqinfo&&curr_device->data_irqinfo==remove_irqinfo)
+ {
+ curr_device->data_irqinfo=NULL;
+ break;
+ }
+ }
+ chandev_free_listmember((list **)&chandev_irqinfo_head,
(list *)remove_irqinfo);
+ }
chandev_unlock();
}
+int chandev_add_schib_info(int irq,chandev_subchannel_info *sch)
+{
+ schib_t *new_schib;
+
+ if((new_schib=s390_get_schib(irq)))
+ {
+ sch->pim=new_schib->pmcw.pim;
+ memcpy(&sch->chpid,&new_schib->pmcw.chpid,sizeof(sch->chpid));
+ return(0);
+ }
+ return(-ENODEV);
+}
+
int chandev_request_irq(unsigned int irq,
void (*handler)(int, void *, struct pt_regs *),
unsigned long irqflags,
kfree(new_irqinfo);
else
{
- new_irqinfo->irq=irq;
+ new_irqinfo->msck_status=chandev_status_good;
+ new_irqinfo->sch.devno=devinfo.devno;
+ new_irqinfo->sch.irq=irq;
+ new_irqinfo->sch.cu_type=devinfo.sid_data.cu_type; /* control unit type */
+ new_irqinfo->sch.cu_model=devinfo.sid_data.cu_model; /* control unit model */
+ new_irqinfo->sch.dev_type=devinfo.sid_data.dev_type; /* device type */
+ new_irqinfo->sch.dev_model=devinfo.sid_data.dev_model; /* device model */
+ chandev_add_schib_info(irq,&new_irqinfo->sch);
new_irqinfo->handler=handler;
new_irqinfo->dev_id=dev_id;
- new_irqinfo->devno=devinfo.devno;
chandev_add_to_list((list **)&chandev_irqinfo_head,new_irqinfo);
}
}
return(retval);
}
+/* This should be safe to call even multiple times. */
void chandev_free_irq(unsigned int irq, void *dev_id)
{
+ s390_dev_info_t devinfo;
+ int err;
+
/* remove any orphan irqinfo left lying around. */
chandev_remove_irqinfo_by_irq(irq);
- free_irq(irq,dev_id);
+ if((err=get_dev_info_by_irq(irq,&devinfo)))
+ {
+ printk("chandev_free_irq get_dev_info_by_irq reported err=%X on irq %d\n"
+ "should not happen\n",err,irq);
+ return;
+ }
+ if(devinfo.status&DEVSTAT_DEVICE_OWNED)
+ free_irq(irq,dev_id);
}
+/* This should be safe even if chandev_free_irq is already called by the device */
+void chandev_free_irq_by_irqinfo(chandev_irqinfo *irqinfo)
+{
+ if(irqinfo)
+ chandev_free_irq(irqinfo->sch.irq,irqinfo->dev_id);
+}
+
+
void chandev_sprint_type_model(char *buff,s32 type,s16 model)
{
chandev_sprint_type_model(&buff[strlen(buff)],dev_type,dev_model);
}
-void chandev_remove_parms(chandev_type chan_type,int exact_match)
+void chandev_remove_parms(chandev_type chan_type,int exact_match,int lo_devno)
{
- chandev_parms *curr_parms;
+ chandev_parms *curr_parms,*next_parms;
chandev_lock();
- for_each(curr_parms,chandev_parms_head)
+ for_each_allow_delete(curr_parms,next_parms,chandev_parms_head)
{
- if((chan_type&(curr_parms->chan_type)&&!exact_match)||
- (chan_type==(curr_parms->chan_type)&&exact_match))
- chandev_free_listmember((list **)&chandev_parms_head,(list *)curr_parms);
+ if(((chan_type&(curr_parms->chan_type)&&!exact_match)||
+ (chan_type==(curr_parms->chan_type)&&exact_match))&&
+ (lo_devno==-1||lo_devno==curr_parms->lo_devno))
+ chandev_free_listmember((list **)&chandev_parms_head,(list *)curr_parms);
}
chandev_unlock();
}
-void chandev_add_parms(chandev_type chan_type,char *parmstr)
+
+void chandev_add_parms(chandev_type chan_type,u16 lo_devno,u16 hi_devno,char *parmstr)
{
- chandev_parms *new_parms;
-
- if((new_parms=chandev_allocstr(parmstr,offsetof(chandev_parms,parmstr))))
+ chandev_parms *parms;
+
+ if(lo_devno>hi_devno)
{
- chandev_remove_parms(chan_type,TRUE);
- new_parms->chan_type=chan_type;
- chandev_add_to_list((list **)&chandev_parms_head,(void *)new_parms);
+ printk("chandev_add_parms detected bad device range lo_devno=0x%04x hi_devno=0x%04x\n,",
+ (int)lo_devno,(int)hi_devno);
+ return;
+ }
+ chandev_lock();
+ for_each(parms,chandev_parms_head)
+ {
+ if(chan_type&(parms->chan_type))
+ {
+ u16 lomax=MAX(parms->lo_devno,lo_devno),
+ himin=MIN(parms->hi_devno,lo_devno);
+ if(lomax<=himin)
+ {
+ chandev_unlock();
+ printk("chandev_add_parms detected overlapping "
+ "parameter definitions for chan_type=0x%02x"
+ " lo_devno=0x%04x hi_devno=0x%04x\n,"
+ " do a del_parms.",chan_type,(int)lo_devno,(int)hi_devno);
+ return;
+ }
+ }
+ }
+ chandev_unlock();
+ if((parms=chandev_allocstr(parmstr,offsetof(chandev_parms,parmstr))))
+ {
+ parms->chan_type=chan_type;
+ parms->lo_devno=lo_devno;
+ parms->hi_devno=hi_devno;
+ chandev_add_to_list((list **)&chandev_parms_head,(void *)parms);
}
else
- printk("chandev_add_parmstr memory request failed\n");
+ printk("chandev_add_parms memory request failed\n");
}
void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
- s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery)
+ s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,
+ u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats)
{
chandev_model_info *newmodel;
int err;
newmodel->dev_model=dev_model;
newmodel->max_port_no=max_port_no;
newmodel->auto_msck_recovery=auto_msck_recovery;
-
+ newmodel->default_checksum_received_ip_pkts=default_checksum_received_ip_pkts;
+ newmodel->default_use_hw_stats=default_use_hw_stats; /* where available e.g. lcs */
if(cu_type==-1&&dev_type==-1)
{
chandev_sprint_devinfo(buff,newmodel->cu_type,newmodel->cu_model,
kfree(newmodel);
return;
}
- /* We ignore errors as they are likely to
- occur owing to incompatibilities with
- Ingos layer
- */
drinfo->flag=DEVREG_TYPE_DEVCHARS;
- if(dev_model==-1)
- drinfo->flag|=(dev_type==-1 ? DEVREG_NO_DEV_INFO:DEVREG_MATCH_DEV_TYPE);
- if(cu_model==-1)
- drinfo->flag|=(cu_type==-1 ? DEVREG_NO_CU_INFO:DEVREG_MATCH_CU_TYPE);
- else if(dev_model!=-1&&cu_type!=-1)
- drinfo->flag|=DEVREG_EXACT_MATCH;
+ if(cu_type!=-1)
+ drinfo->flag|=DEVREG_MATCH_CU_TYPE;
+ if(cu_model!=-1)
+ drinfo->flag|=DEVREG_MATCH_CU_MODEL;
+ if(dev_type!=-1)
+ drinfo->flag|=DEVREG_MATCH_DEV_TYPE;
+ if(dev_model!=-1)
+ drinfo->flag|=DEVREG_MATCH_DEV_MODEL;
drinfo->ci.hc.ctype=cu_type;
drinfo->ci.hc.cmode=cu_model;
drinfo->ci.hc.dtype=dev_type;
void chandev_remove_model(chandev_model_info *model)
{
- chandev *curr_chandev;
+ chandev *curr_chandev,*next_chandev;
chandev_lock();
- for_each(curr_chandev,(chandev *)chandev_head.head)
+ for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
if(curr_chandev->model_info==model)
chandev_remove(curr_chandev);
if(model->drinfo.oper_func)
void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model)
{
- chandev_model_info *curr_model;
+ chandev_model_info *curr_model,*next_model;
chandev_lock();
- for_each(curr_model,chandev_models_head)
+ for_each_allow_delete(curr_model,next_model,chandev_models_head)
if((curr_model->cu_type==cu_type||cu_type==-1)&&
(curr_model->cu_model==cu_model||cu_model==-1)&&
(curr_model->dev_type==dev_type||dev_type==-1)&&
static void chandev_init_default_models(void)
{
- /* P390/Planter 3172 emulation assume maximum 16 to be safe. */
- chandev_add_model(lcs,0x3088,0x1,-1,-1,15,default_msck_bits);
+ /* Usually P390/Planter 3172 emulation assume maximum 16 to be safe. */
+ chandev_add_model(chandev_type_lcs,0x3088,0x1,-1,-1,15,default_msck_bits,FALSE,FALSE);
/* 3172/2216 Paralell the 2216 allows 16 ports per card the */
/* the original 3172 only allows 4 we will assume the max of 16 */
- chandev_add_model(lcs|ctc,0x3088,0x8,-1,-1,15,default_msck_bits);
+ chandev_add_model(chandev_type_lcs|chandev_type_ctc,0x3088,0x8,-1,-1,15,default_msck_bits,FALSE,FALSE);
/* 3172/2216 Escon serial the 2216 allows 16 ports per card the */
/* the original 3172 only allows 4 we will assume the max of 16 */
- chandev_add_model(lcs|escon,0x3088,0x1F,-1,-1,15,default_msck_bits);
+ chandev_add_model(chandev_type_lcs|chandev_type_escon,0x3088,0x1F,-1,-1,15,default_msck_bits,FALSE,FALSE);
/* Only 2 ports allowed on OSA2 cards model 0x60 */
- chandev_add_model(lcs,0x3088,0x60,-1,-1,1,default_msck_bits);
- /* qeth has relative adapter concept so we give it 16 */
- chandev_add_model(qeth,0x1731,0x1,0x1732,0x1,15,default_msck_bits);
+ chandev_add_model(chandev_type_lcs,0x3088,0x60,-1,-1,1,default_msck_bits,FALSE,FALSE);
+ /* qeth gigabit ethernet */
+ chandev_add_model(chandev_type_qeth,0x1731,0x1,0x1732,0x1,0,default_msck_bits,FALSE,FALSE);
+ chandev_add_model(chandev_type_qeth,0x1731,0x5,0x1732,0x5,0,default_msck_bits,FALSE,FALSE);
/* Osa-D we currently aren't too emotionally involved with this */
- chandev_add_model(osad,0x3088,0x62,-1,-1,0,default_msck_bits);
+ chandev_add_model(chandev_type_osad,0x3088,0x62,-1,-1,0,default_msck_bits,FALSE,FALSE);
+ /* claw */
+ chandev_add_model(chandev_type_claw,0x3088,0x61,-1,-1,0,default_msck_bits,FALSE,FALSE);
}
void chandev_del_noauto(u16 devno)
{
- chandev_noauto_range *curr_noauto;
+ chandev_noauto_range *curr_noauto,*next_noauto;
chandev_lock();
- for_each(curr_noauto,chandev_noauto_head)
+ for_each_allow_delete(curr_noauto,next_noauto,chandev_noauto_head)
if(curr_noauto->lo_devno<=devno&&curr_noauto->hi_devno>=devno)
chandev_free_listmember((list **)&chandev_noauto_head,(list *)curr_noauto);
chandev_unlock();
void chandev_del_msck(u16 devno)
{
- chandev_msck_range *curr_msck_range;
+ chandev_msck_range *curr_msck_range,*next_msck_range;
chandev_lock();
- for_each(curr_msck_range,chandev_msck_range_head)
+ for_each_allow_delete(curr_msck_range,next_msck_range,chandev_msck_range_head)
if(curr_msck_range->lo_devno<=devno&&curr_msck_range->hi_devno>=devno)
chandev_free_listmember((list **)&chandev_msck_range_head,(list *)curr_msck_range);
chandev_unlock();
if((new_chandev=chandev_alloc(sizeof(chandev))))
{
new_chandev->model_info=newmodelinfo;
- new_chandev->cu_type=newdevinfo->sid_data.cu_type; /* control unit type */
- new_chandev->cu_model=newdevinfo->sid_data.cu_model; /* control unit model */
- new_chandev->dev_type=newdevinfo->sid_data.dev_type; /* device type */
- new_chandev->dev_model=newdevinfo->sid_data.dev_model; /* device model */
- new_chandev->devno=newdevinfo->devno;
- new_chandev->irq=newdevinfo->irq;
+ new_chandev->sch.devno=newdevinfo->devno;
+ new_chandev->sch.irq=newdevinfo->irq;
+ new_chandev->sch.cu_type=newdevinfo->sid_data.cu_type; /* control unit type */
+ new_chandev->sch.cu_model=newdevinfo->sid_data.cu_model; /* control unit model */
+ new_chandev->sch.dev_type=newdevinfo->sid_data.dev_type; /* device type */
+ new_chandev->sch.dev_model=newdevinfo->sid_data.dev_model; /* device model */
+ chandev_add_schib_info(newdevinfo->irq,&new_chandev->sch);
new_chandev->owned=(newdevinfo->status&DEVSTAT_DEVICE_OWNED ? TRUE:FALSE);
chandev_queuemember(&chandev_head,new_chandev);
}
void chandev_unregister_probe(chandev_probefunc probefunc)
{
- chandev_probelist *curr_probe;
+ chandev_probelist *curr_probe,*next_probe;
chandev_lock();
- for_each(curr_probe,chandev_probelist_head)
+ for_each_allow_delete(curr_probe,next_probe,chandev_probelist_head)
if(curr_probe->probefunc==probefunc)
chandev_free_listmember((list **)&chandev_probelist_head,
(list *)curr_probe);
chandev_unlock();
}
+void chandev_unregister_probe_by_chan_type(chandev_type chan_type)
+{
+ chandev_probelist *curr_probe,*next_probe;
+
+ chandev_lock();
+ for_each_allow_delete(curr_probe,next_probe,chandev_probelist_head)
+ if(curr_probe->chan_type==chan_type)
+ chandev_free_listmember((list **)&chandev_probelist_head,
+ (list *)curr_probe);
+ chandev_unlock();
+}
+
+
void chandev_reset(void)
{
chandev_free_all_list((list **)&chandev_noauto_head);
chandev_free_all_list((list **)&chandev_msck_range_head);
chandev_free_all_list((list **)&chandev_force_head);
- chandev_remove_parms(-1,FALSE);
+ chandev_remove_parms(-1,FALSE,-1);
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
- use_devno_names=FALSE;
+ chandev_use_devno_names=FALSE;
#endif
- chandev_conf_read=FALSE;
chandev_unlock();
}
-chandev_model_info *chandev_is_chandev(int irq,s390_dev_info_t *devinfo)
+int chandev_is_chandev(int irq,s390_dev_info_t *devinfo,chandev_force **forceinfo,chandev_model_info **ret_model)
{
+ chandev_force *curr_force;
chandev_model_info *curr_model=NULL;
int err;
+ int retval=FALSE;
+
+ if(forceinfo)
+ *forceinfo=NULL;
+ if(ret_model)
+ *ret_model=NULL;
if((err=get_dev_info_by_irq(irq,devinfo)))
{
printk("chandev_is_chandev get_dev_info_by_irq reported err=%X on irq %d\n"
"should not happen\n",err,irq);
- return(NULL);
+ return FALSE;
}
chandev_lock();
+
for_each(curr_model,chandev_models_head)
{
if(((curr_model->cu_type==devinfo->sid_data.cu_type)||(curr_model->cu_type==-1))&&
((curr_model->cu_model==devinfo->sid_data.cu_model)||(curr_model->cu_model==-1))&&
((curr_model->dev_type==devinfo->sid_data.dev_type)||(curr_model->dev_type==-1))&&
((curr_model->dev_model==devinfo->sid_data.dev_model)||(curr_model->dev_model==-1)))
+ {
+ retval=TRUE;
+ if(ret_model)
+ *ret_model=curr_model;
+ break;
+ }
+ }
+ for_each(curr_force,chandev_force_head)
+ {
+ if(((curr_force->read_lo_devno==devinfo->devno)&&
+ (curr_force->write_hi_devno==devinfo->devno)&&
+ (curr_force->devif_num!=-2))||
+ ((curr_force->read_lo_devno>=devinfo->devno)&&
+ (curr_force->write_hi_devno<=devinfo->devno)&&
+ (curr_force->devif_num==-2)))
+ {
+ if(forceinfo)
+ *forceinfo=curr_force;
break;
+ }
}
chandev_unlock();
- return(curr_model);
+ return(retval);
}
void chandev_collect_devices(void)
break;
}
chandev_lock();
- if((curr_model=chandev_is_chandev(curr_irq,&curr_devinfo)))
+ if(chandev_is_chandev(curr_irq,&curr_devinfo,NULL,&curr_model))
chandev_add(&curr_devinfo,curr_model);
chandev_unlock();
}
}
-void chandev_add_force(chandev_type chan_type,s32 devif_num,u16 read_devno,
-u16 write_devno,s16 port_protocol_no,u8 checksum_received_ip_pkts,u8 use_hw_stats)
-
+int chandev_add_force(chandev_type chan_type,s32 devif_num,u16 read_lo_devno,
+u16 write_hi_devno,u16 data_devno,s32 memory_usage_in_k,s16 port_protocol_no,u8 checksum_received_ip_pkts,
+u8 use_hw_stats,char *host_name,char *adapter_name,char *api_type)
{
chandev_force *new_chandev_force;
-
+
+ if(devif_num==-2&&read_lo_devno>write_hi_devno)
+ {
+ printk("chandev_add_force detected bad device range lo_devno=0x%04x hi_devno=0x%04x\n,",
+ (int)read_lo_devno,(int)write_hi_devno);
+ return(-1);
+ }
+ if(memory_usage_in_k<0)
+ {
+ printk("chandev_add_force memory_usage_in_k is bad\n");
+ return(-1);
+ }
+ if(chan_type==chandev_type_claw)
+ {
+ int host_name_len=strlen(host_name),
+ adapter_name_len=strlen(adapter_name),
+ api_type_len=strlen(api_type);
+ if(host_name_len>=CLAW_NAMELEN||host_name_len==0||
+ adapter_name_len>=CLAW_NAMELEN||adapter_name_len==0||
+ api_type_len>=CLAW_NAMELEN||api_type_len==0)
+ return(-1);
+ }
if((new_chandev_force=chandev_alloc(sizeof(chandev_force))))
{
new_chandev_force->chan_type=chan_type;
new_chandev_force->devif_num=devif_num;
- new_chandev_force->read_devno=read_devno;
- new_chandev_force->write_devno=write_devno;
+ new_chandev_force->read_lo_devno=read_lo_devno;
+ new_chandev_force->write_hi_devno=write_hi_devno;
+ new_chandev_force->data_devno=data_devno;
+ new_chandev_force->memory_usage_in_k=memory_usage_in_k;
new_chandev_force->port_protocol_no=port_protocol_no;
new_chandev_force->checksum_received_ip_pkts=checksum_received_ip_pkts;
new_chandev_force->use_hw_stats=use_hw_stats;
+
+ if(chan_type==chandev_type_claw)
+ {
+ strcpy(new_chandev_force->claw.host_name,host_name);
+ strcpy(new_chandev_force->claw.adapter_name,adapter_name);
+ strcpy(new_chandev_force->claw.api_type,api_type);
+ }
chandev_add_to_list((list **)&chandev_force_head,new_chandev_force);
}
+ return(0);
}
-void chandev_del_force(u16 read_devno)
+void chandev_del_force(int read_lo_devno)
{
- chandev_force *curr_force;
+ chandev_force *curr_force,*next_force;
chandev_lock();
- for_each(curr_force,chandev_force_head)
+ for_each_allow_delete(curr_force,next_force,chandev_force_head)
{
- if(curr_force->read_devno==read_devno)
+ if(curr_force->read_lo_devno==read_lo_devno||read_lo_devno==-1)
chandev_free_listmember((list **)&chandev_force_head,
(list *)curr_force);
}
void chandev_shutdown(chandev_activelist *curr_device)
{
- int saved_lock_cnt;
+ int err=0;
chandev_lock();
- if(curr_device->category==network_device)
+
+ /* unregister_netdev calls the dev->close so we shouldn't do this */
+ /* this otherwise we crash */
+ if(curr_device->unreg_dev)
{
- /* unregister_netdev calls the dev->close so we shouldn't do this */
- /* this otherwise we crash */
- if(curr_device->unreg_dev)
- {
- saved_lock_cnt=chandev_full_unlock();
- curr_device->unreg_dev(curr_device->dev_ptr);
- chandev_relock(saved_lock_cnt);
- }
+ curr_device->unreg_dev(curr_device->dev_ptr);
+ curr_device->unreg_dev=NULL;
}
- saved_lock_cnt=chandev_full_unlock();
- curr_device->shutdownfunc(curr_device->dev_ptr);
- chandev_relock(saved_lock_cnt);
- kfree(curr_device->dev_ptr);
- chandev_free_listmember((list **)&chandev_activelist_head,
+ if(curr_device->shutdownfunc)
+ {
+ err=curr_device->shutdownfunc(curr_device->dev_ptr);
+ }
+ if(err)
+ printk("chandev_shutdown unable to fully shutdown & unload %s err=%d\n"
+ "probably some upper layer still requires the device to exist\n",
+ curr_device->devname,err);
+ else
+ {
+
+ chandev_free_irq_by_irqinfo(curr_device->read_irqinfo);
+ chandev_free_irq_by_irqinfo(curr_device->write_irqinfo);
+ if(curr_device->data_irqinfo)
+ chandev_free_irq_by_irqinfo(curr_device->data_irqinfo);
+ chandev_free_listmember((list **)&chandev_activelist_head,
(list *)curr_device);
+ }
chandev_unlock();
}
chandev_activelist *curr_device;
for_each(curr_device,chandev_activelist_head)
- if(curr_device->read_irqinfo->devno==devno||
- curr_device->write_irqinfo->devno==devno)
+ if(curr_device->read_irqinfo->sch.devno==devno||
+ curr_device->write_irqinfo->sch.devno==devno||
+ (curr_device->data_irqinfo&&curr_device->data_irqinfo->sch.devno==devno))
{
return(curr_device);
}
str++;
continue;
}
- if(isspace(*str)||((*str)=='-'))
+ if(isspace(*str))
{
*str=',';
goto pack_dn;
int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname,chandev_category category,chandev_unregfunc unreg_dev)
{
- chandev_activelist *newdevice;
+ chandev_activelist *newdevice,*curr_device;
chandev_interrupt_check();
if(probeinfo->newdevice!=NULL)
printk("probeinfo->newdevice!=NULL in chandev_initdevice for %s",devname);
return(-EPERM);
}
-
+
+ chandev_lock();
+ for_each(curr_device,chandev_activelist_head)
+ {
+ if(strcmp(curr_device->devname,devname)==0)
+ {
+ printk("chandev_initdevice detected duplicate devicename %s\n",devname);
+ chandev_unlock();
+ return(-EPERM);
+ }
+ }
if((newdevice=chandev_allocstr(devname,offsetof(chandev_activelist,devname))))
{
- probeinfo->newdevice=newdevice;
- chandev_lock();
- newdevice->read_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->read_irq);
- newdevice->write_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->write_irq);
+ newdevice->read_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->read.irq);
+ newdevice->write_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->write.irq);
+ if(probeinfo->data_exists)
+ newdevice->data_irqinfo=chandev_get_irqinfo_by_irq(probeinfo->data.irq);
chandev_unlock();
- if(newdevice->read_irqinfo==NULL||newdevice->write_irqinfo==NULL)
+ if(newdevice->read_irqinfo==NULL||newdevice->write_irqinfo==NULL||
+ (probeinfo->data_exists&&newdevice->data_irqinfo==NULL))
{
printk("chandev_initdevice, it appears that chandev_request_irq was not "
- "called for devname=%s read_irq=%d write_irq=%d\n",devname,probeinfo->read_irq,probeinfo->write_irq);
+ "called for devname=%s read_irq=%d write_irq=%d data_irq=%d\n",
+ devname,probeinfo->read.irq,probeinfo->write.irq,probeinfo->data.irq);
kfree(newdevice);
return(-EPERM);
}
- newdevice->cu_type=probeinfo->cu_type;
- newdevice->cu_model=probeinfo->cu_model;
- newdevice->dev_type=probeinfo->dev_type;
- newdevice->dev_model=probeinfo->dev_model;
newdevice->chan_type=probeinfo->chan_type;
newdevice->dev_ptr=dev_ptr;
newdevice->port_no=port_no;
+ newdevice->memory_usage_in_k=probeinfo->memory_usage_in_k;
newdevice->category=category;
newdevice->unreg_dev=unreg_dev;
+ probeinfo->newdevice=newdevice;
return(0);
}
+ chandev_unlock();
return(-ENOMEM);
}
+
+char *chandev_build_device_name(chandev_probeinfo *probeinfo,char *destnamebuff,char *basename,int buildfullname)
+{
+ if (chandev_use_devno_names&&(!probeinfo->device_forced||probeinfo->devif_num==-1))
+ sprintf(destnamebuff,"%s%04x",basename,(int)probeinfo->read.devno);
+ else
+ {
+ if(probeinfo->devif_num==-1)
+ {
+ if(buildfullname)
+ {
+ int idx,len=strlen(basename);
+
+ chandev_activelist *curr_device;
+ for(idx=0;idx<0xffff;idx++)
+ {
+ for_each(curr_device,chandev_activelist_head)
+ {
+ if(strncmp(curr_device->devname,basename,len)==0)
+ {
+ char numbuff[10];
+ sprintf(numbuff,"%d",idx);
+ if(strcmp(&curr_device->devname[len],numbuff)==0)
+ goto next_idx;
+ }
+ }
+ sprintf(destnamebuff,"%s%d",basename,idx);
+ return(destnamebuff);
+ next_idx:
+ }
+ printk("chandev_build_device_name was usable to build a unique name for %s\n",basename);
+ return(NULL);
+ }
+ else
+ sprintf(destnamebuff,"%s%%d",basename);
+ }
+ else
+ {
+ sprintf(destnamebuff,"%s%d",basename,(int)probeinfo->devif_num);
+ }
+ }
+ return(destnamebuff);
+}
+
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
-struct net_device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
-struct net_device *dev, int sizeof_priv, char *basename,
-struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv),
-void (*unreg_netdevfunc)(struct net_device *dev))
+struct net_device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct net_device *dev, int sizeof_priv,
+struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv))
#else
-struct device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
-struct device *dev, int sizeof_priv, char *basename,
-struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv),
-void (*unreg_netdevfunc)(struct device *dev))
+struct device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct device *dev, int sizeof_priv,
+struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv))
#endif
{
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
struct net_device *retdevice=NULL;
- int new_device = 0;
+ int new_device = FALSE;
#else
struct device *retdevice=NULL;
#endif
+
+ chandev_interrupt_check();
if (!init_netdevfunc)
{
- printk("init_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
+ printk("init_netdevfunc=NULL in chandev_init_netdev, it should not be valid.\n");
return NULL;
}
- if (!unreg_netdevfunc)
- {
- printk("unreg_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
- return NULL;
- }
-
- chandev_interrupt_check();
-
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
- /* Allocate a device if one is not provided. */
+ /* Allocate a device if one is not provided. */
if (dev == NULL)
{
/* ensure 32-byte alignment of the private area */
if (sizeof_priv)
dev->priv = (void *) (((long)(dev + 1) + 31) & ~31);
-
- if (probeinfo->devif_num != -1)
- sprintf(dev->name,"%s%d",basename,(int)probeinfo->devif_num);
- else if (use_devno_names)
- sprintf(dev->name,"%s0x%04x",basename,(int)probeinfo->read_devno);
-
- new_device = 1;
+ new_device=TRUE;
}
+ chandev_build_device_name(probeinfo,dev->name,basename,FALSE);
#endif
-
retdevice=init_netdevfunc(dev,sizeof_priv);
-
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
/* Register device if necessary */
+ /* we need to do this as init_netdev doesn't call register_netdevice */
+ /* for already allocated devices */
if (retdevice && new_device)
register_netdev(retdevice);
#endif
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+ /* We allocated it, so we should free it on error */
+ if (!retdevice && new_device)
+ kfree(dev);
+#endif
+ return retdevice;
+}
+
+
+
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+struct net_device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
+struct net_device *dev, int sizeof_priv, char *basename,
+struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv),
+void (*unreg_netdevfunc)(struct net_device *dev))
+#else
+struct device *chandev_initnetdevice(chandev_probeinfo *probeinfo,u8 port_no,
+struct device *dev, int sizeof_priv, char *basename,
+struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv),
+void (*unreg_netdevfunc)(struct device *dev))
+#endif
+{
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+ struct net_device *retdevice=NULL;
+ int new_device=(dev==NULL);
+#else
+ struct device *retdevice=NULL;
+#endif
+
+ if (!unreg_netdevfunc)
+ {
+ printk("unreg_netdevfunc=NULL in chandev_initnetdevice, it should not be valid.\n");
+ return NULL;
+ }
+ chandev_interrupt_check();
+ retdevice=chandev_init_netdev(probeinfo,basename,dev,sizeof_priv,init_netdevfunc);
if (retdevice)
{
if (chandev_initdevice(probeinfo,retdevice,port_no,retdevice->name,
- network_device,(chandev_unregfunc)unreg_netdevfunc))
+ chandev_category_network_device,(chandev_unregfunc)unreg_netdevfunc))
{
unreg_netdevfunc(retdevice);
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+ /* We allocated it, so we should free it on error */
+ if(new_device)
+ kfree(dev);
+#endif
+
retdevice = NULL;
}
}
+ return retdevice;
+}
-#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
- /* We allocated it, so we should free it on error */
- if (!retdevice && new_device)
- kfree(dev);
-#endif
- return retdevice;
+int chandev_compare_chpid_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+{
+ return (chan1->pim!=chan2->pim || *chan1->chpid!=*chan2->chpid);
}
+int chandev_compare_cu_dev_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+{
+ return ((chan1->cu_type != chan2->cu_type)||
+ (chan1->cu_model != chan2->cu_model)||
+ (chan1->dev_type != chan2->dev_type)||
+ (chan1->dev_model != chan2->dev_model));
+}
+int chandev_compare_subchannel_info(chandev_subchannel_info *chan1,chandev_subchannel_info *chan2)
+{
+ return((chan1->devno == chan2->devno) &&
+ (chan1->cu_type == chan2->cu_type) &&
+ (chan1->cu_model == chan2->cu_model) &&
+ (chan1->dev_type == chan2->dev_type) &&
+ (chan1->dev_model == chan2->dev_model) &&
+ (chan1->pim == chan2->pim) &&
+ (*chan1->chpid == *chan2->chpid));
+}
-int chandev_doprobe(chandev_force *force,chandev *read_chandev,
-chandev *write_chandev)
+int chandev_doprobe(chandev_force *force,chandev *read,
+chandev *write,chandev *data)
{
chandev_probelist *probe;
chandev_model_info *model_info;
int rc=-1,hint=-1;
chandev_activelist *newdevice;
chandev_probefunc probefunc;
- int saved_lock_cnt;
chandev_parms *curr_parms;
+ chandev_model_info dummy_model_info;
memset(&probeinfo,0,sizeof(probeinfo));
- model_info=read_chandev->model_info;
- if(read_chandev->model_info!=write_chandev->model_info||
- (force&&((force->chan_type&model_info->chan_type)==0))||
- (!force&&((read_chandev->cu_type!=write_chandev->cu_type)||
- (read_chandev->cu_model!=write_chandev->cu_model)||
- (read_chandev->dev_type!=write_chandev->dev_type)||
- (read_chandev->dev_model!=write_chandev->dev_model))))
- return(-1); /* inconsistent */
+ memset(&dummy_model_info,0,sizeof(dummy_model_info));
+ probeinfo.device_forced=(force!=NULL);
+ probeinfo.chpid_info_inconsistent=chandev_compare_chpid_info(&read->sch,&write->sch)||
+ (data&&chandev_compare_chpid_info(&read->sch,&data->sch));
+ probeinfo.cu_dev_info_inconsistent=chandev_compare_cu_dev_info(&read->sch,&write->sch)||
+ (data&&chandev_compare_cu_dev_info(&read->sch,&data->sch));
+ if(read->model_info)
+ model_info=read->model_info;
+ else
+ {
+ dummy_model_info.chan_type=chandev_type_none;
+ dummy_model_info.max_port_no=16;
+ model_info=&dummy_model_info;
+ }
for_each(probe,chandev_probelist_head)
{
- probeinfo.chan_type=(probe->chan_type&model_info->chan_type);
- if(probeinfo.chan_type)
+ if(force)
+ probeinfo.chan_type = ( probe->chan_type & force->chan_type );
+ else
+ {
+ if(chandev_cautious_auto_detect)
+ probeinfo.chan_type = ( probe->chan_type == model_info->chan_type ?
+ probe->chan_type : chandev_type_none );
+ else
+ probeinfo.chan_type = ( probe->chan_type & model_info->chan_type );
+ }
+ if(probeinfo.chan_type && (force || ( !probeinfo.cu_dev_info_inconsistent &&
+ ((probe->chan_type&(chandev_type_ctc|chandev_type_escon)) ||
+ !probeinfo.chpid_info_inconsistent))))
{
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
- if(use_devno_names)
- probeinfo.devif_num=read_chandev->devno;
+ if(chandev_use_devno_names)
+ probeinfo.devif_num=read->sch.devno;
else
#endif
probeinfo.devif_num=-1;
- probeinfo.read_irq=read_chandev->irq;
- probeinfo.write_irq=write_chandev->irq;
- probeinfo.read_devno=read_chandev->devno;
- probeinfo.write_devno=write_chandev->devno;
- probeinfo.max_port_no=model_info->max_port_no;
- probeinfo.cu_type=read_chandev->cu_type;
- probeinfo.cu_model=read_chandev->cu_model;
- probeinfo.dev_type=read_chandev->dev_type;
- probeinfo.dev_model=read_chandev->dev_model;
+ probeinfo.read=read->sch;
+ probeinfo.write=write->sch;
+ if(data)
+ {
+ probeinfo.data=data->sch;
+ probeinfo.data_exists=TRUE;
+ }
+ probeinfo.max_port_no=(force&&(force->port_protocol_no!=-1) ?
+ force->port_protocol_no : model_info->max_port_no);
for_each(curr_parms,chandev_parms_head)
{
- if(probe->chan_type==curr_parms->chan_type)
+ if(probe->chan_type==curr_parms->chan_type&&
+ read->sch.devno>=curr_parms->lo_devno&&
+ read->sch.devno<=curr_parms->hi_devno)
{
probeinfo.parmstr=curr_parms->parmstr;
break;
}
if(force)
{
+ if(force->chan_type==chandev_type_claw)
+ memcpy(&probeinfo.claw,&force->claw,sizeof(chandev_claw_info));
probeinfo.port_protocol_no=force->port_protocol_no;
- if(force->devif_num!=-1)
+ if(force->devif_num==-1&&force->devif_num==-2)
+ probeinfo.devif_num=-1;
+ else
probeinfo.devif_num=force->devif_num;
+ probeinfo.memory_usage_in_k=force->memory_usage_in_k;
probeinfo.checksum_received_ip_pkts=force->checksum_received_ip_pkts;
probeinfo.use_hw_stats=force->use_hw_stats;
-
}
else
{
- probeinfo.port_protocol_no=-1;
- probeinfo.checksum_received_ip_pkts=FALSE;
- probeinfo.use_hw_stats=FALSE;
- if(probe->chan_type&lcs)
+ probeinfo.port_protocol_no=0;
+ probeinfo.checksum_received_ip_pkts=model_info->default_checksum_received_ip_pkts;
+ probeinfo.use_hw_stats=model_info->default_use_hw_stats;
+ probeinfo.memory_usage_in_k=0;
+ if(probe->chan_type&chandev_type_lcs)
{
- if((probeinfo.read_devno&1)||
- ((probeinfo.read_devno|1)!=
- (probeinfo.write_devno)))
- return(-1);
- hint=(read_chandev->devno&0xFF)>>1;
+ hint=(read->sch.devno&0xFF)>>1;
if(hint>model_info->max_port_no)
{
/* The card is possibly emulated e.g P/390 */
}
probeinfo.hint_port_no=hint;
probefunc=probe->probefunc;
- saved_lock_cnt=chandev_full_unlock();
- /* We have to leave the lock go here */
- /* as probefunctions can call schedule & */
- /* reenter to do a kernel thread & we may deadlock */
rc=probefunc(&probeinfo);
- chandev_relock(saved_lock_cnt);
if(rc==0)
{
newdevice=probeinfo.newdevice;
{
newdevice->probefunc=probe->probefunc;
newdevice->shutdownfunc=probe->shutdownfunc;
- newdevice->reoperfunc=probe->reoperfunc;
+ newdevice->msck_notfunc=probe->msck_notfunc;
probe->devices_found++;
chandev_add_to_list((list **)&chandev_activelist_head,
newdevice);
- chandev_add_to_startmsck_list(&startlist_head,
- newdevice->devname,good,good);
-
+ chandev_add_to_userland_notify_list(chandev_start,
+ newdevice->devname,chandev_status_good,chandev_status_good);
}
else
{
- printk("chandev_initdevice either failed or wasn't called for device read_irq=0x%04x\n",probeinfo.read_irq);
+ printk("chandev_initdevice either failed or wasn't called for device read_irq=0x%04x\n",probeinfo.read.irq);
}
break;
+
}
}
}
+ chandev_remove(read);
+ chandev_remove(write);
+ if(data)
+ chandev_remove(data);
return(rc);
}
int chandev_request_irq_from_irqinfo(chandev_irqinfo *irqinfo,chandev *this_chandev)
{
- int retval=s390_request_irq_special(irqinfo->irq,
+ int retval=s390_request_irq_special(irqinfo->sch.irq,
irqinfo->handler,
chandev_not_oper_handler,
irqinfo->irqflags,
irqinfo->devname,
irqinfo->dev_id);
if(retval==0)
+ {
+ irqinfo->msck_status=chandev_status_good;
this_chandev->owned=TRUE;
+ }
return(retval);
}
void chandev_irqallocerr(chandev_irqinfo *irqinfo,int err)
{
- printk("chandev_probe failed to realloc irq=%d for %s err=%d\n",irqinfo->irq,irqinfo->devname,err);
+ printk("chandev_probe failed to realloc irq=%d for %s err=%d\n",irqinfo->sch.irq,irqinfo->devname,err);
+}
+
+
+void chandev_call_notification_func(chandev_activelist *curr_device,chandev_irqinfo *curr_irqinfo,
+chandev_msck_status prevstatus)
+{
+ if(curr_irqinfo->msck_status!=prevstatus)
+ {
+ chandev_msck_status new_msck_status=curr_irqinfo->msck_status;
+ if(curr_irqinfo->msck_status==chandev_status_good)
+ {
+ if(curr_device->read_irqinfo->msck_status==chandev_status_good&&
+ curr_device->write_irqinfo->msck_status==chandev_status_good)
+ {
+ if(curr_device->data_irqinfo)
+ {
+ if(curr_device->data_irqinfo->msck_status==chandev_status_good)
+ new_msck_status=chandev_status_all_chans_good;
+ }
+ else
+ new_msck_status=chandev_status_all_chans_good;
+ }
+ }
+ if(curr_device->msck_notfunc)
+ {
+ curr_device->msck_notfunc(curr_device->dev_ptr,
+ curr_irqinfo->sch.irq,
+ prevstatus,new_msck_status);
+ }
+ if(new_msck_status!=chandev_status_good)
+ {
+ /* No point in sending a machine check if only one channel is good */
+ chandev_add_to_userland_notify_list(chandev_msck,curr_device->devname,
+ prevstatus,curr_irqinfo->msck_status);
+ }
+ }
+}
+
+int chandev_find_eligible_channels(chandev *first_chandev_to_check,
+ chandev **read,chandev **write,chandev **data,chandev **next,
+ chandev_type chan_type)
+{
+ chandev *curr_chandev;
+ int eligible_found=FALSE,changed;
+
+ *next=first_chandev_to_check->next;
+ *read=*write=*data=NULL;
+ for_each(curr_chandev,first_chandev_to_check)
+ if((curr_chandev->sch.devno&1)==0&&curr_chandev->model_info->chan_type!=chandev_type_claw)
+ {
+ *read=curr_chandev;
+ if(chan_type==chandev_type_none)
+ chan_type=(*read)->model_info->chan_type;
+ break;
+ }
+ if(*read)
+ {
+ for_each(curr_chandev,(chandev *)chandev_head.head)
+ if((((*read)->sch.devno|1)==curr_chandev->sch.devno)&&
+ (chandev_compare_cu_dev_info(&(*read)->sch,&curr_chandev->sch)==0)&&
+ ((chan_type&(chandev_type_ctc|chandev_type_escon))||
+ chandev_compare_chpid_info(&(*read)->sch,&curr_chandev->sch)==0))
+ {
+ *write=curr_chandev;
+ break;
+ }
+ }
+ if((chan_type&chandev_type_qeth))
+ {
+ if(*write)
+ {
+ for_each(curr_chandev,(chandev *)chandev_head.head)
+ if((curr_chandev!=*read&&curr_chandev!=*write)&&
+ (chandev_compare_cu_dev_info(&(*read)->sch,&curr_chandev->sch)==0)&&
+ (chandev_compare_chpid_info(&(*read)->sch,&curr_chandev->sch)==0))
+ {
+ *data=curr_chandev;
+ break;
+ }
+ if(*data)
+ eligible_found=TRUE;
+ }
+
+ }
+ else
+ if(*write)
+ eligible_found=TRUE;
+ if(eligible_found)
+ {
+ do
+ {
+ changed=FALSE;
+ if(*next&&
+ ((*read&&(*read==*next))||
+ (*write&&(*write==*next))||
+ (*data&&(*data==*next))))
+ {
+ *next=(*next)->next;
+ changed=TRUE;
+ }
+ }while(changed==TRUE);
+ }
+ return(eligible_found);
+}
+
+chandev *chandev_get_free_chandev_by_devno(int devno)
+{
+ chandev *curr_chandev;
+ if(devno==-1)
+ return(NULL);
+ for_each(curr_chandev,(chandev *)chandev_head.head)
+ if(curr_chandev->sch.devno==devno)
+ {
+ if(chandev_active(devno))
+ return(NULL);
+ else
+ return(curr_chandev);
+ }
+ return(NULL);
+
}
void chandev_probe(void)
{
- chandev *read_chandev,*write_chandev,*curr_chandev;
+ chandev *read_chandev,*write_chandev,*data_chandev,*curr_chandev,*next_chandev;
chandev_force *curr_force;
chandev_noauto_range *curr_noauto;
chandev_activelist *curr_device;
chandev_interrupt_check();
+ chandev_read_conf_if_necessary();
chandev_collect_devices();
chandev_lock();
for_each(curr_irqinfo,chandev_irqinfo_head)
{
- if((curr_device=chandev_get_activelist_by_irq(curr_irqinfo->irq)))
+ if((curr_device=chandev_get_activelist_by_irq(curr_irqinfo->sch.irq)))
{
prevstatus=curr_irqinfo->msck_status;
- if(curr_irqinfo->msck_status!=good)
+ if(curr_irqinfo->msck_status!=chandev_status_good)
{
- curr_chandev=chandev_get_by_irq(curr_irqinfo->irq);
+ curr_chandev=chandev_get_by_irq(curr_irqinfo->sch.irq);
if(curr_chandev)
{
auto_msck_recovery=curr_chandev->model_info->
for_each(curr_msck_range,chandev_msck_range_head)
{
if(curr_msck_range->lo_devno<=
- curr_irqinfo->devno&&
+ curr_irqinfo->sch.devno&&
curr_msck_range->hi_devno>=
- curr_irqinfo->devno)
+ curr_irqinfo->sch.devno)
{
auto_msck_recovery=
curr_msck_range->
}
if((1<<(curr_irqinfo->msck_status-1))&auto_msck_recovery)
{
- if(curr_irqinfo->msck_status==revalidate)
+ if(curr_irqinfo->msck_status==chandev_status_revalidate)
{
- if((get_dev_info_by_irq(curr_irqinfo->irq,&curr_devinfo)==0))
+ if((get_dev_info_by_irq(curr_irqinfo->sch.irq,&curr_devinfo)==0))
{
- curr_irqinfo->devno=curr_devinfo.devno;
- curr_irqinfo->msck_status=good;
- goto remove;
+ curr_irqinfo->sch.devno=curr_devinfo.devno;
+ curr_irqinfo->msck_status=chandev_status_good;
}
}
else
{
- if((curr_chandev=chandev_get_by_irq(curr_irqinfo->irq)))
+ if(curr_chandev)
{
/* Has the device reappeared */
- if(curr_chandev->cu_type==curr_device->cu_type&&
- curr_chandev->cu_model==curr_device->cu_model&&
- curr_chandev->dev_type==curr_device->dev_type&&
- curr_chandev->dev_model==curr_device->dev_model&&
- curr_chandev->devno==curr_irqinfo->devno)
+ if(chandev_compare_subchannel_info(
+ &curr_chandev->sch,
+ &curr_device->read_irqinfo->sch)||
+ chandev_compare_subchannel_info(
+ &curr_chandev->sch,
+ &curr_device->write_irqinfo->sch)||
+ (curr_device->data_irqinfo&&
+ chandev_compare_subchannel_info(
+ &curr_chandev->sch,
+ &curr_device->data_irqinfo->sch)))
{
if((err=chandev_request_irq_from_irqinfo(curr_irqinfo,curr_chandev))==0)
- curr_irqinfo->msck_status=good;
+ curr_irqinfo->msck_status=chandev_status_good;
else
chandev_irqallocerr(curr_irqinfo,err);
}
}
}
}
- if(curr_irqinfo->msck_status==good&&prevstatus!=good)
- {
- if(curr_device->reoperfunc)
- {
- int saved_lock_cnt=chandev_full_unlock();
- curr_device->reoperfunc(curr_device->dev_ptr,
- (curr_device->read_irqinfo==curr_irqinfo),
- prevstatus);
- chandev_relock(saved_lock_cnt);
- }
- if(curr_device->category==network_device&&
- curr_device->write_irqinfo==curr_irqinfo)
- {
- net_device *dev=(net_device *)curr_device->dev_ptr;
- if(dev->flags&IFF_UP)
- netif_start_queue(dev);
- }
- chandev_add_to_startmsck_list(&mscklist_head,curr_device->devname,
- prevstatus,curr_irqinfo->msck_status);
- }
+ chandev_call_notification_func(curr_device,curr_irqinfo,prevstatus);
}
/* This is required because the device can go & come back */
/* even before we realize it is gone owing to the waits in our kernel threads */
/* & the device will be marked as not owned but its status will be good */
/* & an attempt to accidently reprobe it may be done. */
remove:
- chandev_remove(chandev_get_by_irq(curr_irqinfo->irq));
+ chandev_remove(chandev_get_by_irq(curr_irqinfo->sch.irq));
}
/* extra sanity */
- for_each(curr_chandev,(chandev *)chandev_head.head)
+ for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
if(curr_chandev->owned)
chandev_remove(curr_chandev);
for_each(curr_force,chandev_force_head)
{
- for_each(read_chandev,(chandev *)chandev_head.head)
- if(read_chandev->devno==curr_force->read_devno&&
- !chandev_active(curr_force->read_devno))
+ if(curr_force->devif_num==-2)
+ {
+ for_each_allow_delete2(curr_chandev,next_chandev,(chandev *)chandev_head.head)
{
- for_each(write_chandev,(chandev *)chandev_head.head)
- if(write_chandev->devno==
- curr_force->write_devno&&
- !chandev_active(curr_force->write_devno))
+ if(chandev_find_eligible_channels(curr_chandev,&read_chandev,
+ &write_chandev,&data_chandev,
+ &next_chandev,
+ curr_force->chan_type));
+ {
+ if((curr_force->read_lo_devno>=read_chandev->sch.devno)&&
+ (curr_force->write_hi_devno<=read_chandev->sch.devno)&&
+ (curr_force->read_lo_devno>=write_chandev->sch.devno)&&
+ (curr_force->write_hi_devno<=write_chandev->sch.devno)&&
+ (!data_chandev||(data_chandev&&
+ (curr_force->read_lo_devno>=data_chandev->sch.devno)&&
+ (curr_force->write_hi_devno<=data_chandev->sch.devno))))
+ chandev_doprobe(curr_force,read_chandev,write_chandev,
+ data_chandev);
+ }
+ }
+ }
+ else
+ {
+ read_chandev=chandev_get_free_chandev_by_devno(curr_force->read_lo_devno);
+ if(read_chandev)
+ {
+ write_chandev=chandev_get_free_chandev_by_devno(curr_force->write_hi_devno);
+ if(write_chandev)
+ {
+ if(curr_force->chan_type==chandev_type_qeth)
{
- if(chandev_doprobe(curr_force,
- read_chandev,
- write_chandev)==0)
- {
- chandev_remove(read_chandev);
- chandev_remove(write_chandev);
- goto chandev_probe_skip;
- }
+
+ data_chandev=chandev_get_free_chandev_by_devno(curr_force->data_devno);
+ if(data_chandev==NULL)
+ printk("chandev_probe unable to force gigabit_ethernet driver invalid device no 0x%04x given\n",curr_force->data_devno);
}
+ else
+ data_chandev=NULL;
+ chandev_doprobe(curr_force,read_chandev,write_chandev,
+ data_chandev);
+ }
}
- chandev_probe_skip:
+ }
}
- for_each(curr_chandev,(chandev *)chandev_head.head)
+ for_each_allow_delete(curr_chandev,next_chandev,(chandev *)chandev_head.head)
{
for_each(curr_noauto,chandev_noauto_head)
{
- if(curr_chandev->devno>=curr_noauto->lo_devno&&
- curr_chandev->devno<=curr_noauto->hi_devno)
+ if(curr_chandev->sch.devno>=curr_noauto->lo_devno&&
+ curr_chandev->sch.devno<=curr_noauto->hi_devno)
{
chandev_remove(curr_chandev);
break;
}
}
}
- for_each(curr_chandev,(chandev *)chandev_head.head)
+ for_each_allow_delete2(curr_chandev,next_chandev,(chandev *)chandev_head.head)
{
- if(curr_chandev->next&&curr_chandev->model_info==
- curr_chandev->next->model_info)
- {
-
- chandev_doprobe(NULL,curr_chandev,curr_chandev->next);
- curr_chandev=curr_chandev->next;
- }
+ if(chandev_find_eligible_channels(curr_chandev,&read_chandev,
+ &write_chandev,&data_chandev,
+ &next_chandev,
+ chandev_type_none))
+ chandev_doprobe(NULL,read_chandev,write_chandev,
+ data_chandev);
}
- chandev_unlock();
chandev_remove_all();
+ chandev_unlock();
}
static void chandev_not_oper_func(int irq,int status)
chandev_lock();
for_each(curr_irqinfo,chandev_irqinfo_head)
- if(curr_irqinfo->irq==irq)
+ if(curr_irqinfo->sch.irq==irq)
{
+ chandev_msck_status prevstatus=curr_irqinfo->msck_status;
switch(status)
{
/* Currently defined but not used in kernel */
/* Despite being in specs */
case DEVSTAT_NOT_OPER:
- curr_irqinfo->msck_status=not_oper;
+ curr_irqinfo->msck_status=chandev_status_not_oper;
break;
#ifdef DEVSTAT_NO_PATH
/* Kernel hasn't this defined currently. */
/* Despite being in specs */
case DEVSTAT_NO_PATH:
- curr_irqinfo->msck_status=no_path;
+ curr_irqinfo->msck_status=chandev_status_no_path;
break;
#endif
case DEVSTAT_REVALIDATE:
- curr_irqinfo->msck_status=revalidate;
+ curr_irqinfo->msck_status=chandev_status_revalidate;
break;
case DEVSTAT_DEVICE_GONE:
- curr_irqinfo->msck_status=gone;
- break;
- }
- for_each(curr_device,chandev_activelist_head)
- {
- if(curr_device->write_irqinfo==curr_irqinfo)
- {
- if(curr_device->category==network_device)
- {
- net_device *dev=(net_device *)curr_device->dev_ptr;
- if(dev->flags&IFF_UP)
- netif_stop_queue(dev);
- }
- }
+ curr_irqinfo->msck_status=chandev_status_gone;
break;
- }
- break;
+ }
+ if((curr_device=chandev_get_activelist_by_irq(irq)))
+ chandev_call_notification_func(curr_device,curr_irqinfo,prevstatus);
+ else
+ printk("chandev_not_oper_func received channel check for unowned irq %d",irq);
}
chandev_unlock();
}
-static void chandev_msck_task(void *unused)
+static int chandev_msck_thread(void *unused)
{
int loopcnt,not_oper_probe_required=FALSE;
wait_queue_head_t wait;
}
if(not_oper_probe_required)
chandev_probe();
+ return(0);
}
-
+static void chandev_msck_task(void *unused)
+{
+ if(kernel_thread(chandev_msck_thread,NULL,SIGCHLD)<0)
+ {
+ atomic_set(&chandev_msck_thread_lock,1);
+ printk("error making chandev_msck_thread kernel thread\n");
+ }
+}
"use_devno_names",
"dont_use_devno_names",
#endif
+ "cautious_auto_detect",
+ "non_cautious_auto_detect",
"add_model",
"del_model",
"auto_msck",
"shutdown",
"reprobe",
"unregister_probe",
+ "unregister_probe_by_chan_type",
"read_conf",
"dont_read_conf",
+ "persistent"
};
typedef enum
use_devno_names_stridx,
dont_use_devno_names_stridx,
#endif
+ cautious_auto_detect_stridx,
+ non_cautious_auto_detect_stridx,
add_model_stridx,
del_model_stridx,
auto_msck_stridx,
shutdown_stridx,
reprobe_stridx,
unregister_probe_stridx,
+ unregister_probe_by_chan_type_stridx,
read_conf_stridx,
dont_read_conf_stridx,
+ persistent_stridx,
last_stridx,
} chandev_str_enum;
return 1;
}
+
static char *chandev_get_options(char *str, int nints, chandev_int *ints)
{
int res,i=1;
- while (i<nints) {
- res = chandev_get_option(&str, ints+i);
- if (res==0) break;
- i++;
- if (res==1) break;
- }
+ while (i<nints)
+ {
+ res = chandev_get_option(&str, ints+i);
+ if (res==0) break;
+ i++;
+ if (res==1) break;
+ }
ints[0] = i-1;
return(str);
}
#define chandev_get_option get_option
#define chandev_get_options get_options
#endif
+/*
+ * Read an string from an option string; if available accept a subsequent
+ * comma as well & set this comma to a null character when returning the string.
+ *
+ * Return values:
+ * 0 : no string found
+ * 1 : string found, no subsequent comma
+ * 2 : string found including a subsequent comma
+ */
+static int chandev_get_string(char **instr,char **outstr)
+{
+ char *cur = *instr;
+
+ if (!cur ||*cur==0)
+ {
+ *outstr=NULL;
+ return 0;
+ }
+ *outstr=*instr;
+ for(;;)
+ {
+ if(*(++cur)==',')
+ {
+ *cur=0;
+ *instr=cur+1;
+ return 2;
+ }
+ else if(*cur==0)
+ {
+ *instr=cur+1;
+ return 1;
+ }
+ }
+}
+
+
+
static int chandev_setup(char *instr,char *errstr,int lineno)
{
char *str,*currstr,*interpretstr=NULL;
int cnt,strcnt;
int retval=0;
-#define CHANDEV_MAX_EXTRA_INTS 8
+#define CHANDEV_MAX_EXTRA_INTS 12
chandev_int ints[CHANDEV_MAX_EXTRA_INTS+1];
- memset(ints,0,sizeof(ints));
currstr=alloca(strlen(instr)+1);
strcpy(currstr,instr);
strcnt=chandev_pack_args(currstr);
for(cnt=1;cnt<=strcnt;cnt++)
{
interpretstr=currstr;
+ memset(ints,0,sizeof(ints));
for(stridx=first_stridx;stridx<last_stridx;stridx++)
{
str=currstr;
currstr=str;
if(val)
{
- if(val&iscomma)
+ val=(((chandev_strval)stridx)*stridx_mult)+(val&~isstr);
+ switch(val)
{
- if(stridx==add_parms_stridx&&(val==(isstr|iscomma)))
+ case (add_parms_stridx*stridx_mult)|iscomma:
+ currstr=chandev_get_options(currstr,4,ints);
+ if(*currstr&&ints[0]>=1)
{
- str=currstr;
- if(chandev_get_option(&str,&ints[0])==2)
+ if(ints[0]==1)
{
- chandev_add_parms(ints[0],str);
- currstr=str+strlen(str)+1;
- continue;
+ ints[2]=0;
+ ints[3]=0xffff;
}
- else
- goto BadArgs;
+ else if(ints[0]==2)
+ ints[3]=ints[2];
+ chandev_add_parms(ints[1],ints[2],ints[3],currstr);
+// currstr=currstr+strlen(currstr)+1;
+ continue;
}
else
- currstr=chandev_get_options(str,CHANDEV_MAX_EXTRA_INTS,ints)+1;
- }
- else
- {
- ints[0]=0;
- currstr++;
+ goto BadArgs;
+ break;
+ case (claw_stridx*stridx_mult)|isnum|iscomma:
+ case (claw_stridx*stridx_mult)|iscomma:
+ currstr=chandev_get_options(str,6,ints);
+ break;
+ default:
+ if(val&iscomma)
+ currstr=chandev_get_options(str,CHANDEV_MAX_EXTRA_INTS,ints);
+ break;
}
- val=(((chandev_strval)stridx)*stridx_mult)+(val&~isstr);
switch(val)
{
case noauto_stridx*stridx_mult:
else
goto BadArgs;
break;
+ case (qeth_stridx*stridx_mult)|isnum|iscomma:
+ if(ints[0]<3||ints[0]>7)
+ goto BadArgs;
+ chandev_add_force(chandev_type_qeth,endlong,ints[1],ints[2],
+ ints[3],ints[4],ints[5],ints[6],ints[7],
+ NULL,NULL,NULL);
+ break;
case (ctc_stridx*stridx_mult)|isnum|iscomma:
case (escon_stridx*stridx_mult)|isnum|iscomma:
case (lcs_stridx*stridx_mult)|isnum|iscomma:
case (osad_stridx*stridx_mult)|isnum|iscomma:
- case (qeth_stridx*stridx_mult)|isnum|iscomma:
- case (claw_stridx*stridx_mult)|isnum|iscomma:
- switch(val)
+ case (ctc_stridx*stridx_mult)|iscomma:
+ case (escon_stridx*stridx_mult)|iscomma:
+ case (lcs_stridx*stridx_mult)|iscomma:
+ case (osad_stridx*stridx_mult)|iscomma:
+ switch(val&~(isnum|iscomma))
{
- case (ctc_stridx*stridx_mult)|isnum|iscomma:
- chan_type=ctc;
- break;
- case (escon_stridx*stridx_mult)|isnum|iscomma:
- chan_type=escon;
+ case (ctc_stridx*stridx_mult):
+ chan_type=chandev_type_ctc;
break;
- case (lcs_stridx*stridx_mult)|isnum|iscomma:
- chan_type=lcs;
+ case (escon_stridx*stridx_mult):
+ chan_type=chandev_type_escon;
break;
- case (osad_stridx*stridx_mult)|isnum|iscomma:
- chan_type=osad;
+ case (lcs_stridx*stridx_mult):
+ chan_type=chandev_type_lcs;
break;
- case (qeth_stridx*stridx_mult)|isnum|iscomma:
- chan_type=qeth;
+ case (osad_stridx*stridx_mult):
+ chan_type=chandev_type_osad;
break;
- case (claw_stridx*stridx_mult)|isnum|iscomma:
- chan_type=claw;
+ case (qeth_stridx*stridx_mult):
+ chan_type=chandev_type_qeth;
break;
default:
goto BadArgs;
}
+ if((val&isnum)==0)
+ endlong=-2;
+ if(ints[0]<2||ints[0]>6)
+ goto BadArgs;
chandev_add_force(chan_type,endlong,ints[1],ints[2],
- ints[3],ints[4],ints[5]);
+ 0,ints[3],ints[4],ints[5],ints[6],
+ NULL,NULL,NULL);
+ break;
+ case (claw_stridx*stridx_mult)|isnum|iscomma:
+ case (claw_stridx*stridx_mult)|iscomma:
+ if(ints[0]>=2&&ints[0]<=5)
+ {
+ char *host_name,*adapter_name,*api_type;
+ char *clawstr=alloca(strlen(currstr)+1);
+
+ strcpy(clawstr,currstr);
+ if(!(chandev_get_string(&clawstr,&host_name)==2&&
+ chandev_get_string(&clawstr,&adapter_name)==2&&
+ chandev_get_string(&clawstr,&api_type)==1&&
+ chandev_add_force(chandev_type_claw,
+ endlong,ints[1],ints[2],0,
+ ints[3],0,ints[4],ints[5],
+ host_name,adapter_name,api_type)==0))
+ goto BadArgs;
+
+ }
+ else
+ goto BadArgs;
break;
case (del_parms_stridx*stridx_mult):
ints[1]=-1;
case (del_parms_stridx*stridx_mult)|iscomma:
- if(ints[0]==1)
+ if(ints[0]==0)
+ ints[1]=-1;
+ if(ints[0]<=1)
ints[2]=FALSE;
- if(ints[0]>2)
+ if(ints[0]<=2)
+ ints[3]=-1;
+ if(ints[0]>3)
goto BadArgs;
- chandev_remove_parms(ints[1],ints[2]);
+ chandev_remove_parms(ints[1],ints[2],ints[3]);
break;
case (del_force_stridx*stridx_mult)|iscomma:
if(ints[0]!=1)
goto BadArgs;
chandev_del_force(ints[1]);
break;
+ case (del_force_stridx*stridx_mult):
+ chandev_del_force(-1);
+ break;
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
case (use_devno_names_stridx*stridx_mult):
- use_devno_names=1;
+ chandev_use_devno_names=TRUE;
break;
case (dont_use_devno_names_stridx*stridx_mult):
- use_devno_names=0;
+ chandev_use_devno_names=FALSE;
+ break;
#endif
+ case (cautious_auto_detect_stridx*stridx_mult):
+ chandev_cautious_auto_detect=TRUE;
+ break;
+ case (non_cautious_auto_detect_stridx*stridx_mult):
+ chandev_cautious_auto_detect=FALSE;
+ break;
case (add_model_stridx*stridx_mult)|iscomma:
if(ints[0]<3)
goto BadArgs;
ints[6]=-1;
if(ints[0]<=6)
ints[7]=default_msck_bits;
+ if(ints[0]<=7)
+ ints[8]=FALSE;
+ if(ints[0]<=8)
+ ints[9]=FALSE;
ints[0]=7;
chandev_add_model(ints[1],ints[2],ints[3],
- ints[4],ints[5],ints[6],ints[7]);
+ ints[4],ints[5],ints[6],ints[7],ints[8],ints[9]);
break;
case (del_model_stridx*stridx_mult)|iscomma:
if(ints[0]<2||ints[0]>4)
goto BadArgs;
chandev_unregister_probe((chandev_probefunc)ints[1]);
break;
+ case (unregister_probe_by_chan_type_stridx*stridx_mult)|iscomma:
+ if(ints[0]!=1)
+ goto BadArgs;
+ chandev_unregister_probe_by_chan_type((chandev_type)ints[1]);
+ break;
case read_conf_stridx*stridx_mult:
chandev_read_conf();
break;
case dont_read_conf_stridx*stridx_mult:
- chandev_conf_read=TRUE;
+ atomic_set(&chandev_conf_read,TRUE);
+ break;
+ case (persistent_stridx*stridx_mult)|iscomma:
+ if(ints[0]==1)
+ chandev_persistent=ints[1];
+ else
+ goto BadArgs;
break;
default:
goto BadArgs;
- }
+ }
}
else
goto BadArgs;
+ if(cnt<strcnt)
+ {
+ /* eat up stuff till next string */
+ while(*(currstr++));
+ }
}
retval=1;
BadArgs:
if(!retval)
{
- printk("chandev_setup bad argument %s",instr);
+ printk("chandev_setup %s %s",(val==0 ? "unknown verb":"bad argument"),instr);
if(errstr)
{
printk("%s %d interpreted as %s",errstr,lineno,interpretstr);
if(strcnt>1)
- printk(" before semicolon no %d",cnt);
+ {
+ if(cnt==strcnt)
+ printk(" after the last semicolon\n");
+ else
+ printk(" before semicolon no %d",cnt);
+ }
}
printk(".\n Type man chandev for more info.\n\n");
}
- eieio();
- if(chandev_lock_owner==(long)current)
- {
- printk("chandev_setup bug chandev_lock_cnt=%d lock_owner=%lx\n"
- "firstlock_retaddr=%p last_lock_returnaddr=%p\n",
- chandev_lock_cnt,chandev_lock_owner,chandev_firstlock_addr,
- chandev_lastlock_addr);
- chandev_full_unlock();
- }
return(retval);
}
#define CHANDEV_KEYWORD "chandev="
char *buff;
int curr,left,len,fd;
+ /* if called from chandev_register_and_probe &
+ the driver is compiled into the kernel the
+ parameters will need to be passed in from
+ the kernel boot parameter line as the root
+ fs is not mounted yet, we can't wait here.
+ */
if(in_interrupt()||current->fs->root==NULL)
return;
- chandev_conf_read=TRUE;
+ atomic_set(&chandev_conf_read,TRUE);
set_fs(KERNEL_DS);
if(stat(CHANDEV_FILE,&statbuf)==0)
{
static void chandev_read_conf_if_necessary(void)
{
- if(!chandev_conf_read)
+ if(in_interrupt()||current->fs->root==NULL)
+ return;
+ if(!atomic_compare_and_swap(FALSE,TRUE,&chandev_conf_read))
chandev_read_conf();
}
chandev_msck_status idx;
int first_time=TRUE;
buff[0]=0;
- for(idx=first_msck;idx<last_msck;idx++)
+ for(idx=chandev_status_first_msck;idx<chandev_status_last_msck;idx++)
{
if((1<<(idx-1))&auto_msck_recovery)
{
chandev_msck_range *curr_msck_range;
s390_dev_info_t curr_devinfo;
int pass,chandevs_detected,curr_irq,loopcnt;
- chandev_irqinfo *read_irqinfo,*write_irqinfo;
- char buff[40],buff2[80];
+ chandev_irqinfo *read_irqinfo,*write_irqinfo,*data_irqinfo;
+ char buff[3][80];
chandev_lock();
- chandev_read_conf_if_necessary();
chandev_printf(chan_exit,"\n%s\n"
"*'s for cu/dev type/models indicate don't cares\n",chandev_keydescript);
+ chandev_printf(chan_exit,"\ncautious_auto_detect: %s\n",chandev_cautious_auto_detect ? "on":"off");
+ chandev_printf(chan_exit,"\nchandev_persistent = 0x%02x\n",chandev_persistent);
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
- chandev_printf(chan_exit,"\nuse_devno_names: %s\n\n",use_devno_names ? "on":"off");
+ chandev_printf(chan_exit,"\nuse_devno_names: %s\n\n",chandev_use_devno_names ? "on":"off");
#endif
+
if(chandev_models_head)
{
chandev_printf(chan_exit,"Channels enabled for detection\n");
- chandev_printf(chan_exit," chan cu cu dev dev max auto recovery\n");
- chandev_printf(chan_exit," type type model type model port_no. type \n");
- chandev_printf(chan_exit,"============================================================\n");
+ chandev_printf(chan_exit," chan cu cu dev dev max checksum use hw auto recovery\n");
+ chandev_printf(chan_exit," type type model type model port_no. received stats type\n");
+ chandev_printf(chan_exit,"==============================================================================\n");
for_each(curr_model,chandev_models_head)
{
- chandev_sprint_devinfo(buff,curr_model->cu_type,
+ chandev_sprint_devinfo(buff[0],curr_model->cu_type,
curr_model->cu_model,
curr_model->dev_type,
curr_model->dev_model);
- sprintf_msck(buff2,curr_model->auto_msck_recovery);
- chandev_printf(chan_exit," 0x%02x %s%3d %s\n",
- curr_model->chan_type,buff,
- (int)curr_model->max_port_no,buff2);
+ sprintf_msck(buff[1],curr_model->auto_msck_recovery);
+ chandev_printf(chan_exit," 0x%02x %s%3d %s %s %s\n",
+ curr_model->chan_type,buff[0],
+ (int)curr_model->max_port_no,
+ curr_model->default_checksum_received_ip_pkts ? "yes":"no ",
+ curr_model->default_use_hw_stats ? "yes":"no ",
+ buff[1]);
}
}
chandev_printf(chan_exit,"===========================================\n");
for_each(curr_msck_range,chandev_msck_range_head)
{
- sprintf_msck(buff2,curr_msck_range->auto_msck_recovery);
+ sprintf_msck(buff[0],curr_msck_range->auto_msck_recovery);
chandev_printf(chan_exit," 0x%04x 0x%04x %s\n",
curr_msck_range->lo_devno,
- curr_msck_range->hi_devno,buff2)
+ curr_msck_range->hi_devno,buff[0])
}
}
if(chandev_force_head)
{
chandev_printf(chan_exit,"\nForced devices\n");
- chandev_printf(chan_exit," chan defif read write port ip hw\n");
- chandev_printf(chan_exit," type num devno devno protocol no. chksum stats\n");
- chandev_printf(chan_exit,"======================================================\n");
+ chandev_printf(chan_exit," chan defif read write data memory port ip hw host adapter api\n");
+ chandev_printf(chan_exit," type num devno devno devno usage(k) protocol no. chksum stats name name name\n");
+ chandev_printf(chan_exit,"===============================================================================================\n");
for_each(curr_force,chandev_force_head)
{
- chandev_printf(chan_exit," 0x%02x %3d 0x%04x 0x%04x %3d %1d %1d\n",
- curr_force->chan_type,curr_force->devif_num,
- curr_force->read_devno,curr_force->write_devno,
- curr_force->port_protocol_no,curr_force->checksum_received_ip_pkts,
- curr_force->use_hw_stats);
+ if(curr_force->memory_usage_in_k==0)
+ strcpy(buff[0],"default");
+ else
+ sprintf(buff[0],"%6d",curr_force->memory_usage_in_k);
+ chandev_printf(chan_exit," 0x%02x %3d 0x%04x 0x%04x 0x%04x %7s %3d %1d %1d%s",
+ (int)curr_force->chan_type,(int)curr_force->devif_num,
+ (int)curr_force->read_lo_devno,(int)curr_force->write_hi_devno,
+ (int)curr_force->data_devno,buff[0],
+ (int)curr_force->port_protocol_no,(int)curr_force->checksum_received_ip_pkts,
+ (int)curr_force->use_hw_stats,curr_force->chan_type==chandev_type_claw ? "":"\n");
+ if(curr_force->chan_type==chandev_type_claw)
+ {
+ chandev_printf(chan_exit," %9s %9s %9s\n",
+ curr_force->claw.host_name,
+ curr_force->claw.adapter_name,
+ curr_force->claw.api_type);
+ }
+
}
}
if(chandev_probelist_head)
{
#if CONFIG_ARCH_S390X
chandev_printf(chan_exit,"\nRegistered probe functions\n"
- "probefunc shutdownfunc reoperfunc chan devices\n"
- " type found\n"
- "==========================================================================\n");
+ "probefunc shutdownfunc msck_notfunc chan devices devices\n"
+ " type found active\n"
+ "==================================================================================\n");
#else
chandev_printf(chan_exit,"\nRegistered probe functions\n"
- "probefunc shutdownfunc reoperfunc chan devices\n"
- " type found\n"
- "==================================================\n");
+ "probefunc shutdownfunc msck_notfunc chan devices devices\n"
+ " type found active\n"
+ "===============================================================\n");
#endif
for_each(curr_probe,chandev_probelist_head)
{
- chandev_printf(chan_exit,"0x%p 0x%p 0x%p 0x%02x %d\n",
+ int devices_active=0;
+ for_each(curr_device,chandev_activelist_head)
+ {
+ if(curr_device->probefunc==curr_probe->probefunc)
+ devices_active++;
+ }
+ chandev_printf(chan_exit,"0x%p 0x%p 0x%p 0x%02x %d %d\n",
curr_probe->probefunc,
curr_probe->shutdownfunc,
- curr_probe->reoperfunc,
+ curr_probe->msck_notfunc,
curr_probe->chan_type,
- curr_probe->devices_found);
+ curr_probe->devices_found,
+ devices_active);
}
}
if(chandev_activelist_head)
{
-#if CONFIG_ARCH_S390X
+ unsigned long long total_memory_usage_in_k=0;
chandev_printf(chan_exit,
"\nInitialised Devices\n"
- " read write read write chan port dev dev read msck write msck\n"
- " irq irq devno devno type no. ptr name status status \n"
- "========================================================================================\n");
-#else
- chandev_printf(chan_exit,
- "\nInitialised Devices\n"
- " read write read write chan port dev dev read msck write msck\n"
- " irq irq devno devno type no. ptr name status status \n"
- "================================================================================\n");
-#endif
+ " read write data read write data chan port dev dev memory read msck write msck data msck\n"
+ " irq irq irq devno devno devno type no. ptr name usage(k) status status status\n"
+ "=====================================================================================================================\n");
/* We print this list backwards for cosmetic reasons */
for(curr_device=chandev_activelist_head;
curr_device->next!=NULL;curr_device=curr_device->next);
{
read_irqinfo=curr_device->read_irqinfo;
write_irqinfo=curr_device->write_irqinfo;
+ data_irqinfo=curr_device->data_irqinfo;
+ if(data_irqinfo)
+ {
+ sprintf(buff[0],"0x%04x",data_irqinfo->sch.irq);
+ sprintf(buff[1],"0x%04x",(int)data_irqinfo->sch.devno);
+ }
+ else
+ {
+ strcpy(buff[0]," n/a ");
+ strcpy(buff[1]," n/a ");
+ }
+ if(curr_device->memory_usage_in_k<0)
+ {
+ sprintf(buff[2],"%d",(int)-curr_device->memory_usage_in_k);
+ total_memory_usage_in_k-=curr_device->memory_usage_in_k;
+ }
+ else
+ strcpy(buff[2]," n/a ");
chandev_printf(chan_exit,
- "0x%04x 0x%04x 0x%04x 0x%04x 0x%02x %2d 0x%p %-10s %-12s %-12s\n",
- curr_device->read_irqinfo->irq,curr_device->write_irqinfo->irq,
- (int)read_irqinfo->devno,
- (int)write_irqinfo->devno,
+ "0x%04x 0x%04x %s 0x%04x 0x%04x %s 0x%02x %2d 0x%p %-10s %6s %-12s %-12s %-12s\n",
+ read_irqinfo->sch.irq,
+ write_irqinfo->sch.irq,
+ buff[0],
+ (int)read_irqinfo->sch.devno,
+ (int)write_irqinfo->sch.devno,
+ buff[1],
curr_device->chan_type,(int)curr_device->port_no,
curr_device->dev_ptr,curr_device->devname,
+ buff[2],
msck_status_strs[read_irqinfo->msck_status],
- msck_status_strs[write_irqinfo->msck_status]);
+ msck_status_strs[write_irqinfo->msck_status],
+ data_irqinfo ? msck_status_strs[data_irqinfo->msck_status] :
+ "not applicable");
get_prev((list *)chandev_activelist_head,
(list *)curr_device,
(list **)&curr_device);
}
+ chandev_printf(chan_exit,"\nTotal device memory usage %Luk.\n",total_memory_usage_in_k);
}
chandevs_detected=FALSE;
for(pass=FALSE;pass<=TRUE;pass++)
if(pass&&chandevs_detected)
{
chandev_printf(chan_exit,"\nchannels detected\n");
- chandev_printf(chan_exit," chan cu cu dev dev in chandev\n");
- chandev_printf(chan_exit," irq devno type type model type model use reg.\n");
- chandev_printf(chan_exit,"==========================================================\n");
+ chandev_printf(chan_exit," chan cu cu dev dev in chandev\n");
+ chandev_printf(chan_exit," irq devno type type model type model pim chpids use reg.\n");
+ chandev_printf(chan_exit,"===============================================================================\n");
}
for(curr_irq=get_irq_first(),loopcnt=0;curr_irq>=0; curr_irq=get_irq_next(curr_irq),loopcnt++)
{
printk(KERN_ERR"chandev_read_proc detected infinite loop bug in get_irq_next\n");
goto chan_error;
}
- if((curr_model=chandev_is_chandev(curr_irq,&curr_devinfo)))
+ if(chandev_is_chandev(curr_irq,&curr_devinfo,&curr_force,&curr_model))
{
+ schib_t *curr_schib;
+ curr_schib=s390_get_schib(curr_irq);
chandevs_detected=TRUE;
if(pass)
{
- chandev_printf(chan_exit,"0x%04x 0x%04x 0x%02x 0x%04x 0x%02x 0x%04x 0x%02x %-5s %-5s\n",
+ chandev_printf(chan_exit,"0x%04x 0x%04x 0x%02x 0x%04x 0x%02x 0x%04x 0x%02x 0x%02x 0x%016Lx %-5s %-5s\n",
curr_irq,curr_devinfo.devno,
- curr_model->chan_type,
+ ( curr_force ? curr_force->chan_type :
+ ( curr_model ? curr_model->chan_type :
+ chandev_type_none )),
(int)curr_devinfo.sid_data.cu_type,
(int)curr_devinfo.sid_data.cu_model,
(int)curr_devinfo.sid_data.dev_type,
(int)curr_devinfo.sid_data.dev_model,
- (curr_devinfo.status&DEVSTAT_DEVICE_OWNED) ? "yes":"no",
- (chandev_get_irqinfo_by_irq(curr_irq) ? "yes":"no"));
+ (int)(curr_schib ? curr_schib->pmcw.pim : 0),
+ *(long long *)(curr_schib ? &curr_schib->pmcw.chpid[0] : 0),
+ (curr_devinfo.status&DEVSTAT_DEVICE_OWNED) ? "yes":"no ",
+ (chandev_get_irqinfo_by_irq(curr_irq) ? "yes":"no "));
}
chandev_parms *curr_parms;
chandev_printf(chan_exit,"\n driver specific parameters\n");
- chandev_printf(chan_exit,"chan driver\n");
- chandev_printf(chan_exit,"type parameters\n");
+ chandev_printf(chan_exit,"chan lo hi driver\n");
+ chandev_printf(chan_exit,"type devno devno parameters\n");
chandev_printf(chan_exit,"=============================================================================\n");
for_each(curr_parms,chandev_parms_head)
{
- chandev_printf(chan_exit,"0x%02x %s\n",
- curr_parms->chan_type,
- curr_parms->parmstr);
+ chandev_printf(chan_exit,"0x%02x 0x%04x 0x%04x %s\n",
+ curr_parms->chan_type,(int)curr_parms->lo_devno,
+ (int)curr_parms->hi_devno,curr_parms->parmstr);
}
}
chan_error:
int rc;
char *buff;
- chandev_read_conf_if_necessary();
buff=vmalloc(count+1);
if(buff)
{
#endif
int __init chandev_init(void)
{
- if(!chandev_initialised)
- {
- chandev_parse_args();
- chandev_init_default_models();
+ atomic_set(&chandev_initialised,TRUE);
+ chandev_parse_args();
+ chandev_init_default_models();
#if CONFIG_PROC_FS
- chandev_create_proc();
+ chandev_create_proc();
#endif
- chandev_msck_task_tq.routine=
+ chandev_msck_task_tq.routine=
chandev_msck_task;
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
- INIT_LIST_HEAD(&chandev_msck_task_tq.list);
- chandev_msck_task_tq.sync=0;
+ INIT_LIST_HEAD(&chandev_msck_task_tq.list);
+ chandev_msck_task_tq.sync=0;
#endif
- chandev_msck_task_tq.data=NULL;
- chandev_last_startmsck_list_update=chandev_last_machine_check=jiffies-HZ;
- atomic_set(&chandev_msck_thread_lock,1);
- chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
- chandev_lock_cnt=0;
- spin_lock_init(&chandev_spinlock);
- spin_lock_init(&chandev_not_oper_spinlock);
- chandev_initialised=TRUE;
- atomic_set(&chandev_new_msck,FALSE);
- }
+ chandev_msck_task_tq.data=NULL;
+ chandev_last_startmsck_list_update=chandev_last_machine_check=jiffies-HZ;
+ atomic_set(&chandev_msck_thread_lock,1);
+ chandev_lock_owner=CHANDEV_INVALID_LOCK_OWNER;
+ chandev_lock_cnt=0;
+ spin_lock_init(&chandev_spinlock);
+ spin_lock_init(&chandev_not_oper_spinlock);
+ atomic_set(&chandev_new_msck,FALSE);
return(0);
}
#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
int chandev_register_and_probe(chandev_probefunc probefunc,
chandev_shutdownfunc shutdownfunc,
- chandev_reoperfunc reoperfunc,
+ chandev_msck_notification_func msck_notfunc,
chandev_type chan_type)
{
chandev_probelist *new_probe;
/* are initialised. */
chandev_interrupt_check();
- if(!chandev_initialised)
+ if(!atomic_compare_and_swap(FALSE,TRUE,&chandev_initialised))
chandev_init();
- chandev_read_conf_if_necessary();
if((new_probe=chandev_alloc(sizeof(chandev_probelist))))
{
new_probe->probefunc=probefunc;
new_probe->shutdownfunc=shutdownfunc;
- new_probe->reoperfunc=reoperfunc;
+ new_probe->msck_notfunc=msck_notfunc;
new_probe->chan_type=chan_type;
new_probe->devices_found=0;
chandev_add_to_list((list **)&chandev_probelist_head,new_probe);
void chandev_unregister(chandev_probefunc probefunc,int call_shutdown)
{
chandev_probelist *curr_probe=NULL;
- chandev_activelist *curr_device;
+ chandev_activelist *curr_device,*next_device;
chandev_interrupt_check();
chandev_lock();
{
if(curr_probe->probefunc==probefunc)
{
- for_each(curr_device,chandev_activelist_head)
- if(curr_device->probefunc==probefunc)
- {
- if(call_shutdown)
- {
- chandev_shutdown(curr_device);
- }
- }
+ for_each_allow_delete(curr_device,next_device,chandev_activelist_head)
+ if(curr_device->probefunc==probefunc&&call_shutdown)
+ chandev_shutdown(curr_device);
chandev_free_listmember((list **)&chandev_probelist_head,
(list *)curr_probe);
+ break;
}
}
chandev_unlock();
}
+
+int chandev_persist(chandev_type chan_type)
+{
+ return((chandev_persistent&chan_type) ? TRUE:FALSE);
+}
+
EXPORT_SYMBOL(chandev_register_and_probe);
EXPORT_SYMBOL(chandev_request_irq);
-EXPORT_SYMBOL(chandev_free_irq);
EXPORT_SYMBOL(chandev_unregister);
EXPORT_SYMBOL(chandev_initdevice);
+EXPORT_SYMBOL(chandev_build_device_name);
EXPORT_SYMBOL(chandev_initnetdevice);
-
-
+EXPORT_SYMBOL(chandev_init_netdev);
+EXPORT_SYMBOL(chandev_use_devno_names);
+EXPORT_SYMBOL(chandev_free_irq);
+EXPORT_SYMBOL(chandev_add_model);
+EXPORT_SYMBOL(chandev_del_model);
+EXPORT_SYMBOL(chandev_persist);
O_TARGET := s390-net.o
list-multi := ctc.o
-export-objs := iucv.o
+export-objs := iucv.o fsm.o
-ctc-objs := ctcmain.o ctctty.o fsm.o
+ctc-objs := ctcmain.o ctctty.o
-obj-y += iucv.o
+obj-y += iucv.o fsm.o
obj-$(CONFIG_CTC) += ctc.o
obj-$(CONFIG_IUCV) += netiucv.o
/*
- * $Id: ctcmain.c,v 1.17 2001/01/23 14:23:51 felfert Exp $
+ * $Id: ctcmain.c,v 1.46 2001/07/05 17:36:41 felfert Exp $
*
* CTC / ESCON network driver
*
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
- * $Log: ctcmain.c,v $
- * Revision 1.17 2001/01/23 14:23:51 felfert
- * Added ctc based tty.
+ * RELEASE-TAG: CTC/ESCON network driver $Revision: 1.46 $
*
- * Revision 1.16 2001/01/18 16:10:53 felfert
- * Added fixes by acme@conectiva.com.br.
- *
- * Revision 1.15 2001/01/12 15:40:11 felfert
- * Fixed ITPM# PL030052IME (Unitchecks when using real escon).
- *
- * Revision 1.14 2001/01/11 17:43:52 felfert
- * Fixed ITPM# PL030051IME (Initialization of escon).
- *
- * Revision 1.13 2001/01/11 16:40:26 smolinsk
- * resolved name space conflict with LVM and renamed
- * dev_info_t to s390_dev_info_t
- * worked around a bug in OSA microcode by stepping back to 2k IDALS in idals.c
- *
- * Revision 1.12 2000/12/27 09:40:45 tonn
- * upgrade to test12
- *
- * Revision 1.11 2000/12/15 19:34:54 bird
- * struct ctc_priv_t: set type of tbusy to "unsigned long"
- *
- * Revision 1.10 2000/12/14 16:49:50 bird
- * ch_action_txretry(): added missing clear_normalized_cda()
- *
- * Revision 1.9 2000/12/14 13:56:53 felfert
- * Eliminated a compiler warning when building in old kernel.
- *
- * Revision 1.8 2000/12/14 13:11:59 felfert
- * static ccws now separately allocated.
- * remove locally allocated ccw for setup.
- *
- * Revision 1.7 2000/12/14 03:32:15 bird
- * Fixes for >2GB memory. Switch on checksumming.
- *
- * Revision 1.6 2000/12/07 20:08:30 felfert
- * Modified RX channel initialization to be compatible with VM TCP
- *
- * Revision 1.5 2000/12/07 18:15:05 felfert
- * Added workaround against VM TCP bug.
- * Fixed an error message.
- *
- * Revision 1.4 2000/12/06 16:55:57 felfert
- * Removed check for double call of ctc_setup().
- * ctc_setup can now handle mutiple calls.
- *
- * Revision 1.3 2000/12/06 16:48:44 felfert
- * New initialization.
- * Removed old cvs log from 2.2 kernel.
- *
- * Revision 1.2 2000/12/06 14:13:46 felfert
- * New unified configuration.
- *
- * Revision 1.1 2000/11/30 11:21:08 bird
- * Support for new ctc driver
*/
\f
#include <linux/version.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/kernel.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/errno.h>
#include <linux/types.h>
#include <linux/interrupt.h>
#include <asm/io.h>
#include <asm/bitops.h>
#include <asm/uaccess.h>
+#ifdef CONFIG_CHANDEV
+#define CTC_CHANDEV
+#endif
-#define CTC_USE_IDALS 1
-#if CTC_USE_IDALS
+#ifdef CTC_CHANDEV
+#include <asm/chandev.h>
+#define REQUEST_IRQ chandev_request_irq
+#define FREE_IRQ chandev_free_irq
+#else
+#define REQUEST_IRQ request_irq
+#define FREE_IRQ free_irq
+#endif
+
+#if LINUX_VERSION_CODE >= 0x020213
# include <asm/idals.h>
#else
# define set_normalized_cda(ccw, addr) ((ccw)->cda = (addr))
# define clear_normalized_cda(ccw)
#endif
+#if LINUX_VERSION_CODE < 0x020400
+# define s390_dev_info_t dev_info_t
+# define dev_kfree_skb_irq(a) dev_kfree_skb(a)
+#endif
#include <asm/irq.h>
#ifdef MODULE
MODULE_AUTHOR("(C) 2000 IBM Corp. by Fritz Elfert (felfert@millenux.com)");
MODULE_DESCRIPTION("Linux for S/390 CTC/Escon Driver");
+#ifndef CTC_CHANDEV
MODULE_PARM(ctc, "s");
MODULE_PARM_DESC(ctc,
"One or more definitions in the same format like the kernel param for ctc.\n"
"E.g.: ctc0:0x700:0x701:0:ctc1:0x702:0x703:0\n");
char *ctc = NULL;
+#endif
#else
/**
* Number of devices in monolithic (not module) driver version.
#define CTC_PROTO_S390 0
#define CTC_PROTO_LINUX 1
#define CTC_PROTO_LINUX_TTY 2
-#define CTC_PROTO_MAX 2
+#define CTC_PROTO_OS390 3
+#define CTC_PROTO_MAX 3
#define CTC_BUFSIZE_LIMIT 65535
#define CTC_BUFSIZE_DEFAULT 32768
typedef enum channel_types channel_type_t;
+#ifndef CTC_CHANDEV
static int ctc_no_auto = 0;
+#endif
/**
* If running on 64 bit, this must be changed. XXX Why? (bird)
*/
typedef unsigned long intparm_t;
+#ifndef CTC_CHANDEV
/**
* Definition of a per device parameter block
*/
} param;
static param *params = NULL;
+#endif
\f
typedef struct {
unsigned long maxmulti;
* Pointer to next channel in list.
*/
struct channel_t *next;
-
__u16 devno;
int irq;
struct tq_struct tq;
/**
- * RX/TX buffer for init sequence.
- */
- __u16 dummy_buf;
-
- /**
- * RX buffer size
+ * RX/TX buffer size
*/
int max_bufsize;
/**
- * Receive buffer.
+ * Transmit/Receive buffer.
*/
- struct sk_buff *rx_skb;
+ struct sk_buff *trans_skb;
/**
* Universal I/O queue.
*/
spinlock_t collect_lock;
- /**
- * Pointer to dynamic allocated CCWs for TX
- */
- ccw1_t *dccw;
-
- /**
- * Number of dynamic allocated CCWs needed for clearing IDALs.
- */
- int dccw_count;
-
/**
* Timer for detecting unresposive
* I/O operations.
ctc_profile prof;
} channel;
-#define CHANNEL_FLAGS_READ 0
-#define CHANNEL_FLAGS_WRITE 1
-#define CHANNEL_FLAGS_INUSE 2
+#define CHANNEL_FLAGS_READ 0
+#define CHANNEL_FLAGS_WRITE 1
+#define CHANNEL_FLAGS_INUSE 2
+#define CHANNEL_FLAGS_BUFSIZE_CHANGED 4
#define CHANNEL_FLAGS_RWMASK 1
#define CHANNEL_DIRECTION(f) (f & CHANNEL_FLAGS_RWMASK)
*/
static channel *channels = NULL;
+#ifdef CTC_CHANDEV
+static int activated;
+#endif
+
typedef struct ctc_priv_t {
struct net_device_stats stats;
#if LINUX_VERSION_CODE >= 0x02032D
struct proc_dir_entry *proc_dentry;
struct proc_dir_entry *proc_stat_entry;
struct proc_dir_entry *proc_ctrl_entry;
+ int proc_registered;
} ctc_priv;
/**
*/
static void print_banner(void) {
static int printed = 0;
- char vbuf[] = "$Revision: 1.17 $";
+ char vbuf[] = "$Revision: 1.46 $";
char *version = vbuf;
if (printed)
printed = 1;
}
\f
+
+#ifndef CTC_CHANDEV
/**
* Return type of a detected device.
*/
}
return type;
}
+#endif
+
\f
/**
* States of the interface statemachine.
*/
CH_EVENT_SC_UNKNOWN,
+ /**
+ * Events, representing machine checks
+ */
+ CH_EVENT_MC_FAIL,
+ CH_EVENT_MC_GOOD,
+
/**
* Event, representing normal IRQ
*/
"SubChannel check Unknown",
+ "Machine check failure",
+ "Machine check operational",
+
"IRQ normal",
"IRQ final",
CH_STATE_TXERR,
CH_STATE_TERM,
CH_STATE_DTERM,
+ CH_STATE_NOTOP,
/**
* MUST be always the last element!!
"TX error",
"Terminating",
"Restarting",
+ "Not operational",
};
\f
+#ifdef DEBUG
/**
* Dump header and first 16 bytes of an sk_buff for debugging purposes.
*
bl = 16;
printk(KERN_DEBUG "data: ");
for (i = 0; i < bl; i++)
- printk("%02x ", *p++);
+ printk("%02x%s", *p++, (i % 16) ? " " : "\n<7>");
printk("\n");
}
+#endif
/**
- * Bottom half routine.
+ * Unpack a just received skb and hand it over to
+ * upper layers.
*
- * @param ch The channel to work on.
+ * @param ch The channel where this skb has been received.
+ * @param pskb The received skb.
*/
-static void ctc_bh(channel *ch)
+static __inline__ void ctc_unpack_skb(channel *ch, struct sk_buff *pskb)
{
net_device *dev = ch->netdev;
ctc_priv *privptr = (ctc_priv *)dev->priv;
- struct sk_buff *skb;
- while ((skb = skb_dequeue(&ch->io_queue))) {
- __u16 len = *((__u16*)skb->data);
-
- skb_put(skb, 2 + LL_HEADER_LENGTH);
- skb_pull(skb, 2);
- skb->dev = dev;
- skb->ip_summed = CHECKSUM_NONE;
- while (len > 0) {
- ll_header *header = (ll_header *)skb->data;
- skb_pull(skb, LL_HEADER_LENGTH);
- if ((ch->protocol == CTC_PROTO_S390) &&
- (header->type != ETH_P_IP)) {
- /**
- * Check packet type only if we stick strictly
- * to S/390's protocol of OS390. This only
- * supports IP. Otherwise allow any packet
- * type.
- */
- printk(KERN_WARNING
- "%s Illegal packet type 0x%04x "
- "received, dropping\n",
- dev->name, header->type);
- ctc_dump_skb(skb, -6);
- privptr->stats.rx_dropped++;
- privptr->stats.rx_frame_errors++;
- dev_kfree_skb(skb);
- goto again;
- }
- skb->protocol = ntohs(header->type);
- header->length -= LL_HEADER_LENGTH;
- if ((header->length > dev->mtu) ||
- (header->length == 0)) {
- printk(KERN_WARNING
- "%s Illegal packet size %d "
- "received (MTU=%d), "
- "dropping\n", dev->name, header->length,
- dev->mtu);
- ctc_dump_skb(skb, -6);
- privptr->stats.rx_dropped++;
- privptr->stats.rx_length_errors++;
- dev_kfree_skb(skb);
- goto again;
- }
- skb_put(skb, header->length);
- skb->mac.raw = skb->data;
+ __u16 len = *((__u16*)pskb->data);
+ skb_put(pskb, 2 + LL_HEADER_LENGTH);
+ skb_pull(pskb, 2);
+ pskb->dev = dev;
+ pskb->ip_summed = CHECKSUM_UNNECESSARY;
+ while (len > 0) {
+ struct sk_buff *skb;
+ ll_header *header = (ll_header *)pskb->data;
+
+ skb_pull(pskb, LL_HEADER_LENGTH);
+ if ((ch->protocol == CTC_PROTO_S390) &&
+ (header->type != ETH_P_IP)) {
/**
- * Set truesize here to make the kernel's
- * socket layer happy. If this is not done,
- * the RX-routines of the socket code are dropping
- * most of the received packets, because they "think"
- * there isn't enough buffer space for the incoming
- * data.
+ * Check packet type only if we stick strictly
+ * to S/390's protocol of OS390. This only
+ * supports IP. Otherwise allow any packet
+ * type.
*/
- skb->truesize = skb->len;
- len -= (LL_HEADER_LENGTH + header->length);
- if (len > 0) {
- /**
- * Clone the skb only if there are still
- * sub-packets.
- */
- struct sk_buff *skb2 =
- skb_clone(skb, GFP_ATOMIC);
- if (!skb2) {
- printk(KERN_WARNING "%s Out of memory"
- " in ctc_bh\n",
- dev->name);
- privptr->stats.rx_dropped++;
- dev_kfree_skb(skb);
- goto again;
- }
- if (ch->protocol == CTC_PROTO_LINUX_TTY)
- ctc_tty_netif_rx(skb2);
- else
- netif_rx(skb2);
- privptr->stats.rx_packets++;
- privptr->stats.rx_bytes += skb2->len;
- /**
- * Advance pointers to next sub-packet.
- */
- skb_pull(skb, header->length);
- skb_put(skb, LL_HEADER_LENGTH);
- } else {
- if (ch->protocol == CTC_PROTO_LINUX_TTY)
- ctc_tty_netif_rx(skb);
- else
- netif_rx(skb);
- privptr->stats.rx_packets++;
- privptr->stats.rx_bytes += skb->len;
- }
+ printk(KERN_WARNING
+ "%s Illegal packet type 0x%04x "
+ "received, dropping\n",
+ dev->name, header->type);
+#ifdef DEBUG
+ ctc_dump_skb(pskb, -6);
+#endif
+ privptr->stats.rx_dropped++;
+ privptr->stats.rx_frame_errors++;
+ return;
+ }
+ pskb->protocol = ntohs(header->type);
+ header->length -= LL_HEADER_LENGTH;
+ if ((header->length == 0) ||
+ (header->length > skb_tailroom(pskb))) {
+ printk(KERN_WARNING
+ "%s Illegal packet size %d "
+ "received (MTU=%d), "
+ "dropping\n", dev->name, header->length,
+ dev->mtu);
+#ifdef DEBUG
+ ctc_dump_skb(pskb, -6);
+#endif
+ privptr->stats.rx_dropped++;
+ privptr->stats.rx_length_errors++;
+ return;
+ }
+ if (header->length > skb_tailroom(pskb)) {
+ printk(KERN_WARNING
+ "%s Illegal packet size %d "
+ "(beyond the end of received data), "
+ "dropping\n", dev->name, header->length);
+#ifdef DEBUG
+ ctc_dump_skb(pskb, -6);
+#endif
+ privptr->stats.rx_dropped++;
+ privptr->stats.rx_length_errors++;
+ return;
+ }
+ skb_put(pskb, header->length);
+ pskb->mac.raw = pskb->data;
+ len -= (LL_HEADER_LENGTH + header->length);
+ skb = dev_alloc_skb(pskb->len);
+ if (!skb) {
+ printk(KERN_WARNING
+ "%s Out of memory in ctc_unpack_skb\n",
+ dev->name);
+ privptr->stats.rx_dropped++;
+ return;
+ }
+ memcpy(skb_put(skb, pskb->len), pskb->data, pskb->len);
+ skb->mac.raw = skb->data;
+ skb->dev = pskb->dev;
+ skb->protocol = pskb->protocol;
+ pskb->ip_summed = CHECKSUM_UNNECESSARY;
+ if (ch->protocol == CTC_PROTO_LINUX_TTY)
+ ctc_tty_netif_rx(skb);
+ else
+ netif_rx(skb);
+ privptr->stats.rx_packets++;
+ privptr->stats.rx_bytes += skb->len;
+ if (len > 0) {
+ skb_pull(pskb, header->length);
+ skb_put(pskb, LL_HEADER_LENGTH);
}
- again:
}
- return;
+}
+
+/**
+ * Bottom half routine.
+ *
+ * @param ch The channel to work on.
+ */
+static void ctc_bh(channel *ch)
+{
+ struct sk_buff *skb;
+
+ while ((skb = skb_dequeue(&ch->io_queue)))
+ ctc_unpack_skb(ch, skb);
}
/**
static void inline ccw_unit_check (channel *ch, unsigned char sense) {
if (sense & SNS0_INTERVENTION_REQ) {
if (sense & 0x01) {
- printk(KERN_DEBUG
- "ch-%04x: Interface disc. or Sel. reset "
- "(remote)\n", ch->devno);
+ if (ch->protocol != CTC_PROTO_LINUX_TTY)
+ printk(KERN_DEBUG
+ "ch-%04x: Interface disc. or Sel. reset "
+ "(remote)\n", ch->devno);
fsm_event(ch->fsm, CH_EVENT_UC_RCRESET, ch);
} else {
printk(KERN_DEBUG "ch-%04x: System reset (remote)\n",
fsm_event(ch->fsm, CH_EVENT_UC_TXPARITY, ch);
}
} else if (sense & SNS0_CMD_REJECT) {
- printk(KERN_WARNING "ch-%04x: Command reject\n", ch->devno);
+ printk(KERN_WARNING "ch-%04x: Command reject\n",
+ ch->devno);
} else if (sense == 0) {
printk(KERN_DEBUG "ch-%04x: Unit check ZERO\n", ch->devno);
fsm_event(ch->fsm, CH_EVENT_UC_ZERO, ch);
while ((skb = skb_dequeue(q))) {
atomic_dec(&skb->users);
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
+ }
+}
+
+static __inline__ int ctc_checkalloc_buffer(channel *ch, int warn) {
+ if ((ch->trans_skb == NULL) ||
+ (ch->flags & CHANNEL_FLAGS_BUFSIZE_CHANGED)) {
+ if (ch->trans_skb != NULL)
+ dev_kfree_skb(ch->trans_skb);
+ ch->trans_skb = dev_alloc_skb(ch->max_bufsize);
+ if (ch->trans_skb == NULL) {
+ if (warn)
+ printk(KERN_WARNING
+ "ch-%04x: Couldn't alloc %s trans_skb\n",
+ ch->devno,
+ (CHANNEL_DIRECTION(ch->flags) == READ) ?
+ "RX" : "TX");
+ return -ENOMEM;
+ }
+ set_normalized_cda(&ch->ccw[1],
+ virt_to_phys(ch->trans_skb->data));
+ if (ch->ccw[1].cda == 0) {
+ dev_kfree_skb(ch->trans_skb);
+ ch->trans_skb = NULL;
+ if (warn)
+ printk(KERN_WARNING
+ "ch-%04x: set_normalized_cda for %s "
+ "trans_skb failed, dropping packets\n",
+ ch->devno,
+ (CHANNEL_DIRECTION(ch->flags) == READ) ?
+ "RX" : "TX");
+ return -ENOMEM;
+ }
+ ch->flags &= ~CHANNEL_FLAGS_BUFSIZE_CHANGED;
}
+ return 0;
}
/**
first = 0;
}
atomic_dec(&skb->users);
- dev_kfree_skb(skb);
+ dev_kfree_skb_irq(skb);
}
spin_lock(&ch->collect_lock);
- if (ch->dccw) {
- for (i = 0; i < ch->dccw_count; i++)
- clear_normalized_cda(&ch->dccw[i]);
- kfree(ch->dccw);
- ch->dccw = NULL;
- }
+ clear_normalized_cda(&ch->ccw[4]);
if (ch->collect_len > 0) {
int rc;
- ch->dccw_count = skb_queue_len(&ch->collect_queue) + 1;
- if (ch->prof.maxmulti < (ch->collect_len + 2))
- ch->prof.maxmulti = ch->collect_len + 2;
- if (ch->prof.maxcqueue < ch->dccw_count)
- ch->prof.maxcqueue = ch->dccw_count;
-
- ch->dccw = kmalloc(ch->dccw_count *
- sizeof(ccw1_t), GFP_ATOMIC|GFP_DMA);
- if (!ch->dccw) {
+ if (ctc_checkalloc_buffer(ch, 1)) {
spin_unlock(&ch->collect_lock);
- printk(KERN_WARNING
- "%s: Unable to alloc dynamic ccws\n",
- dev->name);
return;
}
-
- ch->dccw[0].cmd_code = CCW_CMD_PREPARE;
- ch->dccw[0].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
- ch->dccw[0].count = 0;
- ch->dccw[0].cda = 0;
- i = 1;
+ ch->trans_skb->tail = ch->trans_skb->data;
+ ch->trans_skb->len = 0;
+ if (ch->prof.maxmulti < (ch->collect_len + 2))
+ ch->prof.maxmulti = ch->collect_len + 2;
+ if (ch->prof.maxcqueue < skb_queue_len(&ch->collect_queue))
+ ch->prof.maxcqueue = skb_queue_len(&ch->collect_queue);
+ ch->ccw[1].count = ch->collect_len + 2;
+ *((__u16 *)skb_put(ch->trans_skb, 2)) = ch->collect_len + 2;
+ i = 0;
while ((skb = skb_dequeue(&ch->collect_queue))) {
- ch->prof.txlen += (skb->len - LL_HEADER_LENGTH);
- if (i == 1)
- *((__u16 *)skb_push(skb, 2)) =
- ch->collect_len + 2;
- ch->dccw[i].cmd_code = CCW_CMD_WRITE;
- ch->dccw[i].flags = CCW_FLAG_SLI |
- ((skb_queue_len(&ch->collect_queue))
- ? CCW_FLAG_DC : 0);
- ch->dccw[i].count = skb->len;
- set_normalized_cda(&ch->dccw[i],
- virt_to_phys(skb->data));
- skb_queue_tail(&ch->io_queue, skb);
+ memcpy(skb_put(ch->trans_skb, skb->len), skb->data,
+ skb->len);
+ privptr->stats.tx_packets++;
+ privptr->stats.tx_bytes += skb->len - LL_HEADER_LENGTH;
+ atomic_dec(&skb->users);
+ dev_kfree_skb_irq(skb);
i++;
}
ch->collect_len = 0;
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
ch->prof.send_stamp = xtime;
- rc = do_IO(ch->irq, ch->dccw, (intparm_t)ch, 0xff, 0);
+#ifdef DEBUG
+ printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
+ rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
ch->prof.doios_multi++;
if (rc != 0) {
+ privptr->stats.tx_dropped += i;
+ privptr->stats.tx_errors += i;
fsm_deltimer(&ch->timer);
- i = 0;
- while ((skb = skb_dequeue(&ch->io_queue))) {
- privptr->stats.tx_dropped++;
- privptr->stats.tx_errors++;
- atomic_dec(&skb->users);
- dev_kfree_skb(skb);
- i++;
- }
- kfree(ch->dccw);
- ch->dccw = NULL;
- if (i != ch->dccw_count)
- printk(KERN_WARNING "ctc: i != nccws !!!\n");
ccw_check_return_code(ch, rc);
}
} else
net_device *dev = ch->netdev;
ctc_priv *privptr = dev->priv;
int len = ch->max_bufsize - ch->devstat->rescnt;
- struct sk_buff *skb = ch->rx_skb;
+ struct sk_buff *skb = ch->trans_skb;
__u16 block_len = *((__u16*)skb->data);
char *saved_data = skb->data;
- int queued = 0;
+ int check_len;
int rc;
fsm_deltimer(&ch->timer);
privptr->stats.rx_length_errors++;
goto again;
}
+
/**
* VM TCP seems to have a bug sending 2 trailing bytes of garbage.
*/
- if ((len < block_len) ||
- ((len > block_len) && (ch->protocol != CTC_PROTO_S390)) ||
- ((len > (block_len + 2)) && (ch->protocol == CTC_PROTO_S390))) {
- printk(KERN_WARNING
- "%s: got block length %d != rx length %d\n", dev->name,
- block_len, len);
- *((__u16*)skb->data) = len;
+ switch (ch->protocol) {
+ case CTC_PROTO_S390:
+ case CTC_PROTO_OS390:
+ check_len = block_len + 2;
+ break;
+ default:
+ check_len = block_len;
+ break;
+ }
+ if ((len < block_len) || (len > check_len)) {
+ printk(KERN_WARNING "%s: got block length %d != rx length %d\n",
+ dev->name, block_len, len);
+#ifdef DEBUG
ctc_dump_skb(skb, 0);
+#endif
+ *((__u16*)skb->data) = len;
privptr->stats.rx_dropped++;
privptr->stats.rx_length_errors++;
goto again;
block_len -= 2;
if (block_len > 0) {
*((__u16*)skb->data) = block_len;
- skb_queue_tail(&ch->io_queue, skb);
- queued++;
+ ctc_unpack_skb(ch, skb);
}
again:
- if (queued) {
- queue_task(&ch->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- ch->rx_skb = dev_alloc_skb(ch->max_bufsize);
- if (ch->rx_skb == NULL) {
- printk(KERN_WARNING "%s: Couldn't alloc rx_skb in "
- "ch_action_rx\n", dev->name);
- /* TODO: retry after bottom half */
- return;
- }
- } else {
- skb->data = skb->tail = saved_data;
- skb->len = 0;
- }
+ skb->data = skb->tail = saved_data;
+ skb->len = 0;
+ if (ctc_checkalloc_buffer(ch, 1))
+ return;
ch->ccw[1].count = ch->max_bufsize;
- set_normalized_cda(&ch->ccw[1], virt_to_phys(ch->rx_skb->data));
+#ifdef DEBUG
+ printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
if (rc != 0)
ccw_check_return_code(ch, rc);
}
+static void ch_action_rxidle(fsm_instance *fi, int event, void *arg);
+
/**
* Initialize connection by sending a __u16 of value 0.
*
printk(KERN_DEBUG "ch-%04x: remote side issued READ?, "
"init ...\n", ch->devno);
fsm_deltimer(&ch->timer);
+ if (ctc_checkalloc_buffer(ch, 1))
+ return;
+ if ((fsm_getstate(fi) == CH_STATE_SETUPWAIT) &&
+ (ch->protocol == CTC_PROTO_OS390)) {
+ /* OS/390 resp. z/OS */
+ if (CHANNEL_DIRECTION(ch->flags) == READ) {
+ *((__u16 *)ch->trans_skb->data) = CTC_INITIAL_BLOCKLEN;
+ fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC,
+ CH_EVENT_TIMER, ch);
+ ch_action_rxidle(fi, event, arg);
+ } else {
+ net_device *dev = ch->netdev;
+ fsm_newstate(fi, CH_STATE_TXIDLE);
+ fsm_event(((ctc_priv *)dev->priv)->fsm,
+ DEV_EVENT_TXUP, dev);
+ }
+ return;
+ }
+
/**
* Don´t setup a timer for receiving the initial RX frame
* if in compatibility mode, since VM TCP delays the initial
(ch->protocol != CTC_PROTO_S390))
fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
- ch->dummy_buf = CTC_INITIAL_BLOCKLEN;
+ *((__u16 *)ch->trans_skb->data) = CTC_INITIAL_BLOCKLEN;
ch->ccw[1].count = 2; /* Transfer only length */
- set_normalized_cda(&ch->ccw[1], virt_to_phys(&ch->dummy_buf));
+
+#ifdef DEBUG
+ printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
fsm_newstate(fi, (CHANNEL_DIRECTION(ch->flags) == READ)
? CH_STATE_RXINIT : CH_STATE_TXINIT);
rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
{
channel *ch = (channel *)arg;
net_device *dev = ch->netdev;
+ __u16 buflen;
int rc;
fsm_deltimer(&ch->timer);
- if (ch->dummy_buf >= CTC_INITIAL_BLOCKLEN) {
- ch->rx_skb = dev_alloc_skb(ch->max_bufsize);
- if (ch->rx_skb == NULL) {
- printk(KERN_WARNING "%s: Couldn't alloc rx_skb in "
- "ch_action_rxidle\n", dev->name);
+ buflen = *((__u16 *)ch->trans_skb->data);
+#ifdef DEBUG
+ printk(KERN_DEBUG "%s: Initial RX count %d\n", dev->name, buflen);
+#endif
+ if (buflen >= CTC_INITIAL_BLOCKLEN) {
+ if (ctc_checkalloc_buffer(ch, 1))
return;
- }
ch->ccw[1].count = ch->max_bufsize;
- set_normalized_cda(&ch->ccw[1],
- virt_to_phys(ch->rx_skb->data));
fsm_newstate(fi, CH_STATE_RXIDLE);
+#ifdef DEBUG
+ printk(KERN_DEBUG "ccw[1].cda = %08x\n", ch->ccw[1].cda);
+#endif
rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
if (rc != 0) {
fsm_newstate(fi, CH_STATE_RXINIT);
DEV_EVENT_RXUP, dev);
} else {
printk(KERN_DEBUG "%s: Initial RX count %d not %d\n",
- dev->name, ch->dummy_buf, CTC_INITIAL_BLOCKLEN);
+ dev->name, buflen, CTC_INITIAL_BLOCKLEN);
ch_action_firstio(fi, event, arg);
}
}
fsm_newstate(fi, CH_STATE_SETUPWAIT);
if (event == CH_EVENT_TIMER)
s390irq_spin_lock_irqsave(ch->irq, saveflags);
- rc = do_IO(ch->irq, &ch->ccw[3], (intparm_t)ch, 0xff, 0);
+ rc = do_IO(ch->irq, &ch->ccw[6], (intparm_t)ch, 0xff, 0);
if (event == CH_EVENT_TIMER)
s390irq_spin_unlock_irqrestore(ch->irq, saveflags);
if (rc != 0) {
ch->irq);
return;
}
-
- dev = ch->netdev;
+ dev = ch->netdev;
#ifdef DEBUG
printk(KERN_DEBUG "%s: %s channel start\n", dev->name,
(CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");
#endif
+ if (ch->trans_skb != NULL) {
+ clear_normalized_cda(&ch->ccw[1]);
+ dev_kfree_skb(ch->trans_skb);
+ ch->trans_skb = NULL;
+ }
+ if (ctc_checkalloc_buffer(ch, 0))
+ printk(KERN_NOTICE
+ "%s: Could not allocate %s trans_skb, delaying "
+ "allocation until first transfer\n",
+ dev->name,
+ (CHANNEL_DIRECTION(ch->flags) == READ) ? "RX" : "TX");
+
+#if LINUX_VERSION_CODE >= 0x020400
INIT_LIST_HEAD(&ch->tq.list);
+#else
+ ch->tq.next = NULL;
+#endif
ch->tq.sync = 0;
ch->tq.routine = (void *)(void *)ctc_bh;
ch->tq.data = ch;
ch->ccw[1].cmd_code = CCW_CMD_READ;
ch->ccw[1].flags = CCW_FLAG_SLI;
ch->ccw[1].count = 0;
- ch->ccw[1].cda = 0;
} else {
ch->ccw[1].cmd_code = CCW_CMD_WRITE;
ch->ccw[1].flags = CCW_FLAG_SLI | CCW_FLAG_CC;
ch->ccw[1].count = 0;
- ch->ccw[1].cda = 0;
}
ch->ccw[2].cmd_code = CCW_CMD_NOOP; /* jointed CE + DE */
ch->ccw[2].flags = CCW_FLAG_SLI;
ch->ccw[2].count = 0;
ch->ccw[2].cda = 0;
+ memcpy(&ch->ccw[3], &ch->ccw[0], sizeof(ccw1_t) * 3);
+ ch->ccw[4].cda = 0;
+
fsm_newstate(fi, CH_STATE_STARTWAIT);
fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch);
s390irq_spin_lock_irqsave(ch->irq, saveflags);
channel *ch = (channel *)arg;
net_device *dev = ch->netdev;
- if (ch->dccw) {
- printk(KERN_WARNING "ch_action_stopped: dccw !NULL\n");
- return;
- }
fsm_deltimer(&ch->timer);
fsm_newstate(fi, CH_STATE_STOPPED);
+ if (ch->trans_skb != NULL) {
+ clear_normalized_cda(&ch->ccw[1]);
+ dev_kfree_skb(ch->trans_skb);
+ ch->trans_skb = NULL;
+ }
+ if (CHANNEL_DIRECTION(ch->flags) == READ) {
+ skb_queue_purge(&ch->io_queue);
+ fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);
+ } else {
+ ctc_purge_skb_queue(&ch->io_queue);
+ spin_lock(&ch->collect_lock);
+ ctc_purge_skb_queue(&ch->collect_queue);
+ ch->collect_len = 0;
+ spin_unlock(&ch->collect_lock);
+ fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);
+ }
+}
+
+/**
+ * A stop command from device statemachine arrived and we are in
+ * not operational mode. Set state to stopped.
+ *
+ * @param fi An instance of a channel statemachine.
+ * @param event The event, just happened.
+ * @param arg Generic pointer, casted from channel * upon call.
+ */
+static void ch_action_stop(fsm_instance *fi, int event, void *arg)
+{
+ fsm_newstate(fi, CH_STATE_STOPPED);
+}
+
+/**
+ * A machine check for no path, not operational status or gone device has
+ * happened.
+ * Cleanup queue and notify interface statemachine.
+ *
+ * @param fi An instance of a channel statemachine.
+ * @param event The event, just happened.
+ * @param arg Generic pointer, casted from channel * upon call.
+ */
+static void ch_action_fail(fsm_instance *fi, int event, void *arg)
+{
+ channel *ch = (channel *)arg;
+ net_device *dev = ch->netdev;
+
+ fsm_deltimer(&ch->timer);
+ fsm_newstate(fi, CH_STATE_NOTOP);
if (CHANNEL_DIRECTION(ch->flags) == READ) {
skb_queue_purge(&ch->io_queue);
- if (ch->rx_skb != NULL) {
- dev_kfree_skb(ch->rx_skb);
- ch->rx_skb = NULL;
- }
fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_RXDOWN, dev);
} else {
ctc_purge_skb_queue(&ch->io_queue);
spin_lock(&ch->collect_lock);
ctc_purge_skb_queue(&ch->collect_queue);
- if (ch->dccw)
- kfree(ch->dccw);
- ch->dccw = NULL;
ch->collect_len = 0;
spin_unlock(&ch->collect_lock);
fsm_event(((ctc_priv *)dev->priv)->fsm, DEV_EVENT_TXDOWN, dev);
if ((skb = skb_peek(&ch->io_queue))) {
int rc = 0;
+ set_normalized_cda(&ch->ccw[4],
+ virt_to_phys(skb->data));
+ if (ch->ccw[4].cda == 0) {
+ printk(KERN_DEBUG "%s: IDAL alloc failed, "
+ "restarting channel\n", dev->name);
+ fsm_event(((ctc_priv *)dev->priv)->fsm,
+ DEV_EVENT_TXDOWN, dev);
+ ch_action_restart(fi, event, arg);
+ return;
+ }
fsm_addtimer(&ch->timer, 1000, CH_EVENT_TIMER, ch);
if (event == CH_EVENT_TIMER)
s390irq_spin_lock_irqsave(ch->irq, saveflags);
- if (ch->dccw)
- rc = do_IO(ch->irq, ch->dccw, (intparm_t)ch,
- 0xff, 0);
- else {
- clear_normalized_cda(&ch->ccw[1]);
- ch->ccw[1].count = skb->len;
- set_normalized_cda(&ch->ccw[1],
- virt_to_phys(skb->data));
- rc = do_IO(ch->irq, &ch->ccw[0],
- (intparm_t)ch, 0xff, 0);
- }
+ ch->ccw[4].count = skb->len;
+#ifdef DEBUG
+ printk(KERN_DEBUG "ccw[4].cda = %08x\n", ch->ccw[4].cda);
+#endif
+ rc = do_IO(ch->irq, &ch->ccw[3],
+ (intparm_t)ch, 0xff, 0);
if (event == CH_EVENT_TIMER)
s390irq_spin_unlock_irqrestore(ch->irq,
saveflags);
{ CH_STATE_STOPPED, CH_EVENT_STOP, fsm_action_nop },
{ CH_STATE_STOPPED, CH_EVENT_START, ch_action_start },
{ CH_STATE_STOPPED, CH_EVENT_FINSTAT, fsm_action_nop },
+ { CH_STATE_STOPPED, CH_EVENT_MC_FAIL, fsm_action_nop },
+
+ { CH_STATE_NOTOP, CH_EVENT_STOP, ch_action_stop },
+ { CH_STATE_NOTOP, CH_EVENT_START, fsm_action_nop },
+ { CH_STATE_NOTOP, CH_EVENT_FINSTAT, fsm_action_nop },
+ { CH_STATE_NOTOP, CH_EVENT_MC_FAIL, fsm_action_nop },
+ { CH_STATE_NOTOP, CH_EVENT_MC_GOOD, ch_action_start },
{ CH_STATE_STARTWAIT, CH_EVENT_STOP, ch_action_haltio },
{ CH_STATE_STARTWAIT, CH_EVENT_START, fsm_action_nop },
{ CH_STATE_STARTWAIT, CH_EVENT_TIMER, ch_action_setuperr },
{ CH_STATE_STARTWAIT, CH_EVENT_IO_ENODEV, ch_action_iofatal },
{ CH_STATE_STARTWAIT, CH_EVENT_IO_EIO, ch_action_iofatal },
+ { CH_STATE_STARTWAIT, CH_EVENT_MC_FAIL, ch_action_fail },
{ CH_STATE_STARTRETRY, CH_EVENT_STOP, ch_action_haltio },
{ CH_STATE_STARTRETRY, CH_EVENT_TIMER, ch_action_setmode },
{ CH_STATE_STARTRETRY, CH_EVENT_FINSTAT, fsm_action_nop },
+ { CH_STATE_STARTRETRY, CH_EVENT_MC_FAIL, ch_action_fail },
{ CH_STATE_SETUPWAIT, CH_EVENT_STOP, ch_action_haltio },
{ CH_STATE_SETUPWAIT, CH_EVENT_START, fsm_action_nop },
{ CH_STATE_SETUPWAIT, CH_EVENT_TIMER, ch_action_setmode },
{ CH_STATE_SETUPWAIT, CH_EVENT_IO_ENODEV, ch_action_iofatal },
{ CH_STATE_SETUPWAIT, CH_EVENT_IO_EIO, ch_action_iofatal },
+ { CH_STATE_SETUPWAIT, CH_EVENT_MC_FAIL, ch_action_fail },
{ CH_STATE_RXINIT, CH_EVENT_STOP, ch_action_haltio },
{ CH_STATE_RXINIT, CH_EVENT_START, fsm_action_nop },
{ CH_STATE_RXINIT, CH_EVENT_IO_ENODEV, ch_action_iofatal },
{ CH_STATE_RXINIT, CH_EVENT_IO_EIO, ch_action_iofatal },
{ CH_STATE_RXINIT, CH_EVENT_UC_ZERO, ch_action_firstio },
+ { CH_STATE_RXINIT, CH_EVENT_MC_FAIL, ch_action_fail },
{ CH_STATE_RXIDLE, CH_EVENT_STOP, ch_action_haltio },
{ CH_STATE_RXIDLE, CH_EVENT_START, fsm_action_nop },
// { CH_STATE_RXIDLE, CH_EVENT_UC_RSRESET, ch_action_rxretry },
{ CH_STATE_RXIDLE, CH_EVENT_IO_ENODEV, ch_action_iofatal },
{ CH_STATE_RXIDLE, CH_EVENT_IO_EIO, ch_action_iofatal },
+ { CH_STATE_RXIDLE, CH_EVENT_MC_FAIL, ch_action_fail },
+ { CH_STATE_RXIDLE, CH_EVENT_UC_ZERO, ch_action_rx },
{ CH_STATE_TXINIT, CH_EVENT_STOP, ch_action_haltio },
{ CH_STATE_TXINIT, CH_EVENT_START, fsm_action_nop },
{ CH_STATE_TXINIT, CH_EVENT_TIMER, ch_action_txiniterr },
{ CH_STATE_TXINIT, CH_EVENT_IO_ENODEV, ch_action_iofatal },
{ CH_STATE_TXINIT, CH_EVENT_IO_EIO, ch_action_iofatal },
+ { CH_STATE_TXINIT, CH_EVENT_MC_FAIL, ch_action_fail },
{ CH_STATE_TXIDLE, CH_EVENT_STOP, ch_action_haltio },
{ CH_STATE_TXIDLE, CH_EVENT_START, fsm_action_nop },
{ CH_STATE_TXIDLE, CH_EVENT_UC_RSRESET, fsm_action_nop },
{ CH_STATE_TXIDLE, CH_EVENT_IO_ENODEV, ch_action_iofatal },
{ CH_STATE_TXIDLE, CH_EVENT_IO_EIO, ch_action_iofatal },
+ { CH_STATE_TXIDLE, CH_EVENT_MC_FAIL, ch_action_fail },
{ CH_STATE_TERM, CH_EVENT_STOP, fsm_action_nop },
{ CH_STATE_TERM, CH_EVENT_START, ch_action_restart },
{ CH_STATE_TERM, CH_EVENT_FINSTAT, ch_action_stopped },
{ CH_STATE_TERM, CH_EVENT_UC_RCRESET, fsm_action_nop },
{ CH_STATE_TERM, CH_EVENT_UC_RSRESET, fsm_action_nop },
+ { CH_STATE_TERM, CH_EVENT_MC_FAIL, ch_action_fail },
{ CH_STATE_DTERM, CH_EVENT_STOP, ch_action_haltio },
{ CH_STATE_DTERM, CH_EVENT_START, ch_action_restart },
{ CH_STATE_DTERM, CH_EVENT_FINSTAT, ch_action_setmode },
{ CH_STATE_DTERM, CH_EVENT_UC_RCRESET, fsm_action_nop },
{ CH_STATE_DTERM, CH_EVENT_UC_RSRESET, fsm_action_nop },
+ { CH_STATE_DTERM, CH_EVENT_MC_FAIL, ch_action_fail },
{ CH_STATE_TX, CH_EVENT_STOP, ch_action_haltio },
{ CH_STATE_TX, CH_EVENT_START, fsm_action_nop },
{ CH_STATE_TX, CH_EVENT_TIMER, ch_action_txretry },
{ CH_STATE_TX, CH_EVENT_IO_ENODEV, ch_action_iofatal },
{ CH_STATE_TX, CH_EVENT_IO_EIO, ch_action_iofatal },
+ { CH_STATE_TX, CH_EVENT_MC_FAIL, ch_action_fail },
{ CH_STATE_RXERR, CH_EVENT_STOP, ch_action_haltio },
{ CH_STATE_TXERR, CH_EVENT_STOP, ch_action_haltio },
+ { CH_STATE_TXERR, CH_EVENT_MC_FAIL, ch_action_fail },
+ { CH_STATE_RXERR, CH_EVENT_MC_FAIL, ch_action_fail },
};
static const int CH_FSM_LEN = sizeof(ch_fsm) / sizeof(fsm_node);
return -1;
}
memset(ch, 0, sizeof(channel));
- if ((ch->ccw = (ccw1_t *)kmalloc(sizeof(ccw1_t) * 5,
+ if ((ch->ccw = (ccw1_t *)kmalloc(sizeof(ccw1_t) * 8,
GFP_KERNEL|GFP_DMA)) == NULL) {
kfree(ch);
printk(KERN_WARNING "ctc: Out of memory in add_channel\n");
*
* ccw[0..2] (Channel program for generic I/O):
* 0: prepare
- * 1: read or write (depending on direction)
+ * 1: read or write (depending on direction) with fixed
+ * buffer (idal allocated once when buffer is allocated)
* 2: nop
- * ccw[3..4] (Channel program for initial channel setup):
+ * ccw[3..5] (Channel program for direct write of packets)
+ * 3: prepare
+ * 4: write (idal allocated on every write).
+ * 5: nop
+ * ccw[6..7] (Channel program for initial channel setup):
* 3: set extended mode
* 4: nop
*
- * ch->ccw[0..2] are initialized in ch_action_start because
+ * ch->ccw[0..5] are initialized in ch_action_start because
* the channel's direction is yet unknown here.
*/
- ch->ccw[3].cmd_code = CCW_CMD_SET_EXTENDED;
- ch->ccw[3].flags = CCW_FLAG_SLI;
- ch->ccw[3].count = 0;
- ch->ccw[3].cda = 0;
+ ch->ccw[6].cmd_code = CCW_CMD_SET_EXTENDED;
+ ch->ccw[6].flags = CCW_FLAG_SLI;
+ ch->ccw[6].count = 0;
+ ch->ccw[6].cda = 0;
- ch->ccw[4].cmd_code = CCW_CMD_NOOP;
- ch->ccw[4].flags = CCW_FLAG_SLI;
- ch->ccw[4].count = 0;
- ch->ccw[4].cda = 0;
+ ch->ccw[7].cmd_code = CCW_CMD_NOOP;
+ ch->ccw[7].flags = CCW_FLAG_SLI;
+ ch->ccw[7].count = 0;
+ ch->ccw[7].cda = 0;
ch->irq = irq;
ch->devno = devno;
ch_event_names, NR_CH_STATES, NR_CH_EVENTS,
ch_fsm, CH_FSM_LEN, GFP_KERNEL);
if (ch->fsm == NULL) {
- printk(KERN_WARNING "ctc: Could not create FSM in add_channel\n");
+ printk(KERN_WARNING
+ "ctc: Could not create FSM in add_channel\n");
kfree(ch);
return -1;
}
c = &(*c)->next;
if ((*c)->devno == devno) {
printk(KERN_DEBUG
- "ctc: add_channel: device %04x already in list\n",
- (*c)->devno);
+ "ctc: add_channel: device %04x already in list, "
+ "using old entry\n", (*c)->devno);
kfree(ch->devstat);
kfree_fsm(ch->fsm);
kfree(ch);
return 0;
}
+#ifndef CTC_CHANDEV
/**
* scan for all channels and create an entry in the channels list
* for every supported channel.
- *
- * @param print_result Flag: If !0, print a final result.
*/
-static void channel_scan(int print_result)
+static void channel_scan(void)
{
+ static int print_result = 1;
int irq;
int nr_escon = 0;
int nr_ctca = 0;
else
printk(KERN_INFO "ctc: No channel devices found.\n");
}
+ print_result = 0;
}
+#endif
/**
* Release a specific channel in the channel list.
fsm_newstate(ch->fsm, CH_STATE_IDLE);
}
+/**
+ * Remove a specific channel in the channel list.
+ *
+ * @param ch Pointer to channel struct to be released.
+ */
+static void channel_remove(channel *ch)
+{
+ channel **c = &channels;
+
+ if (ch == NULL)
+ return;
+
+#ifndef CTC_CHANDEV
+ if (ch->flags & CHANNEL_FLAGS_INUSE)
+ FREE_IRQ(ch->irq, ch->devstat);
+#endif
+ channel_free(ch);
+ while (*c) {
+ if (*c == ch) {
+ *c = ch->next;
+ fsm_deltimer(&ch->timer);
+ kfree_fsm(ch->fsm);
+ clear_normalized_cda(&ch->ccw[4]);
+ if (ch->trans_skb != NULL) {
+ clear_normalized_cda(&ch->ccw[1]);
+ dev_kfree_skb(ch->trans_skb);
+ }
+ kfree(ch->ccw);
+ return;
+ }
+ c = &((*c)->next);
+ }
+}
+
/**
* Get a specific channel from the channel list.
return ch;
}
-
+#ifndef CTC_CHANDEV
/**
* Get the next free channel from the channel list
*
}
return ch;
}
+#endif
/**
* Return the channel type by name.
}
}
- clear_normalized_cda(&ch->ccw[1]);
dev = (net_device *)(ch->netdev);
if (dev == NULL) {
printk(KERN_CRIT
static void dev_action_chup(fsm_instance *fi, int event, void *arg)
{
net_device *dev = (net_device *)arg;
+ ctc_priv *privptr = dev->priv;
switch (fsm_getstate(fi)) {
case DEV_STATE_STARTWAIT_RXTX:
printk(KERN_INFO
"%s: connected with remote side\n",
dev->name);
+ if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+ ctc_tty_setcarrier(dev, 1);
ctc_clear_busy(dev);
}
break;
printk(KERN_INFO
"%s: connected with remote side\n",
dev->name);
+ if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+ ctc_tty_setcarrier(dev, 1);
ctc_clear_busy(dev);
}
break;
*/
static void dev_action_chdown(fsm_instance *fi, int event, void *arg)
{
+ net_device *dev = (net_device *)arg;
+ ctc_priv *privptr = dev->priv;
+
switch (fsm_getstate(fi)) {
case DEV_STATE_RUNNING:
+ if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+ ctc_tty_setcarrier(dev, 0);
if (event == DEV_EVENT_TXDOWN)
fsm_newstate(fi, DEV_STATE_STARTWAIT_TX);
else
if (fsm_getstate(ch->fsm) != CH_STATE_TXIDLE) {
int l = skb->len + LL_HEADER_LENGTH;
- if (ch->type == channel_type_escon)
- return -EBUSY;
spin_lock_irqsave(&ch->collect_lock, saveflags);
if (ch->collect_len + l > ch->max_bufsize - 2)
rc = -EBUSY;
spin_unlock_irqrestore(&ch->collect_lock, saveflags);
} else {
__u16 block_len;
+ int ccw_idx;
/**
* Protect skb against beeing free'd by upper
LL_HEADER_LENGTH);
block_len = skb->len + 2;
*((__u16 *)skb_push(skb, 2)) = block_len;
- skb_queue_tail(&ch->io_queue, skb);
+ set_normalized_cda(&ch->ccw[4], virt_to_phys(skb->data));
+ if (ch->ccw[4].cda == 0) {
+ /**
+ * idal allocation failed, try via copying to
+ * trans_skb. trans_skb usually has a pre-allocated
+ * idal.
+ */
+ if (ctc_checkalloc_buffer(ch, 1)) {
+ /**
+ * Remove our header. It gets added
+ * again on retransmit.
+ */
+ skb_pull(skb, LL_HEADER_LENGTH + 2);
+ return -EBUSY;
+ }
+
+ ch->trans_skb->tail = ch->trans_skb->data;
+ ch->trans_skb->len = 0;
+ ch->ccw[1].count = skb->len;
+ memcpy(skb_put(ch->trans_skb, skb->len), skb->data,
+ skb->len);
+ atomic_dec(&skb->users);
+ dev_kfree_skb_irq(skb);
+ ccw_idx = 0;
+ } else {
+ ch->ccw[4].count = block_len;
+ skb_queue_tail(&ch->io_queue, skb);
+ ccw_idx = 3;
+ }
ch->retry = 0;
+#ifdef DEBUG
+ ctc_dump_skb(skb, 0);
+#endif
fsm_newstate(ch->fsm, CH_STATE_TX);
- fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC, CH_EVENT_TIMER, ch);
- ch->ccw[1].count = block_len;
- set_normalized_cda(&ch->ccw[1], virt_to_phys(skb->data));
+ fsm_addtimer(&ch->timer, CTC_TIMEOUT_5SEC,
+ CH_EVENT_TIMER, ch);
s390irq_spin_lock_irqsave(ch->irq, saveflags);
ch->prof.send_stamp = xtime;
- rc = do_IO(ch->irq, &ch->ccw[0], (intparm_t)ch, 0xff, 0);
+#ifdef DEBUG
+ printk(KERN_DEBUG "ccw[%d].cda = %08x\n", ccw_idx+1,
+ ch->ccw[ccw_idx+1].cda);
+#endif
+ rc = do_IO(ch->irq, &ch->ccw[ccw_idx], (intparm_t)ch, 0xff, 0);
s390irq_spin_unlock_irqrestore(ch->irq, saveflags);
- ch->prof.doios_single++;
+ if (ccw_idx == 3)
+ ch->prof.doios_single++;
if (rc != 0) {
fsm_deltimer(&ch->timer);
ccw_check_return_code(ch, rc);
* again on retransmit.
*/
skb_pull(skb, LL_HEADER_LENGTH + 2);
+ } else {
+ if (ccw_idx == 0) {
+ net_device *dev = ch->netdev;
+ ctc_priv *privptr = dev->priv;
+ privptr->stats.tx_packets++;
+ privptr->stats.tx_bytes +=
+ skb->len - LL_HEADER_LENGTH;
+ }
}
}
return 0;
}
if (skb_headroom(skb) < (LL_HEADER_LENGTH + 2)) {
- printk(KERN_WARNING "%s: Got sk_buff with head room < %ld bytes\n",
- dev->name, LL_HEADER_LENGTH + 2);
+ printk(KERN_WARNING
+ "%s: Got sk_buff with head room < %ld bytes\n",
+ dev->name, LL_HEADER_LENGTH + 2);
dev_kfree_skb(skb);
privptr->stats.tx_dropped++;
return 0;
*/
if (fsm_getstate(privptr->fsm) != DEV_STATE_RUNNING) {
fsm_event(privptr->fsm, DEV_EVENT_START, dev);
+ if (privptr->protocol == CTC_PROTO_LINUX_TTY)
+ return -EBUSY;
dst_link_failure(skb);
dev_kfree_skb(skb);
privptr->stats.tx_dropped++;
return -EFAULT;
tmp[count+1] = '\0';
bs1 = simple_strtoul(tmp, &e, 0);
+
if ((bs1 > CTC_BUFSIZE_LIMIT) ||
- (bs1 < (dev->mtu - LL_HEADER_LENGTH - 2)) ||
(e && (!isspace(*e))))
return -EINVAL;
+ if ((dev->flags & IFF_RUNNING) &&
+ (bs1 < (dev->mtu + LL_HEADER_LENGTH + 2)))
+ return -EINVAL;
+ if (bs1 < (576 + LL_HEADER_LENGTH + 2))
+ return -EINVAL;
+
+
privptr->channel[READ]->max_bufsize =
privptr->channel[WRITE]->max_bufsize = bs1;
+ if (!(dev->flags & IFF_RUNNING))
+ dev->mtu = bs1 - LL_HEADER_LENGTH - 2;
+ privptr->channel[READ]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
+ privptr->channel[WRITE]->flags |= CHANNEL_FLAGS_BUFSIZE_CHANGED;
return count;
}
fsm_getstate_str(privptr->channel[WRITE]->fsm));
p += sprintf(p, "Max. TX buffer used: %ld\n",
privptr->channel[WRITE]->prof.maxmulti);
- p += sprintf(p, "Max. chained CCWs: %ld\n",
+ p += sprintf(p, "Max. chained SKBs: %ld\n",
privptr->channel[WRITE]->prof.maxcqueue);
p += sprintf(p, "TX single write ops: %ld\n",
privptr->channel[WRITE]->prof.doios_single);
proc_register(privptr->proc_dentry, privptr->proc_stat_entry);
proc_register(privptr->proc_dentry, privptr->proc_ctrl_entry);
#endif
+ privptr->proc_registered = 1;
}
-#ifdef MODULE
+
/**
* Destroy a device specific subdirectory.
*
* @param privptr Pointer to device private data.
*/
static void ctc_proc_destroy_sub(ctc_priv *privptr) {
+ if (!privptr->proc_registered)
+ return;
#if LINUX_VERSION_CODE > 0x020362
remove_proc_entry("statistics", privptr->proc_dentry);
remove_proc_entry("buffersize", privptr->proc_dentry);
proc_unregister(&ctc_dir,
privptr->proc_dentry->low_ino);
#endif
+ privptr->proc_registered = 0;
}
-#endif MODULE
+
\f
+
+#ifndef CTC_CHANDEV
/**
* Setup related routines
*****************************************************************************/
#else
static param parms_array[MAX_STATIC_DEVICES];
static param *next_param = parms_array;
-#define alloc_param() ((next_param<parms_array+MAX_STATIC_DEVICES)?next_param++:NULL)
+#define alloc_param() \
+ ((next_param<parms_array+MAX_STATIC_DEVICES)?next_param++:NULL)
#endif MODULE
/**
#if LINUX_VERSION_CODE >= 0x020300
__setup("ctc=", ctc_setup);
#endif
+#endif /* !CTC_CHANDEV */
\f
+
+static void
+ctc_netdev_unregister(net_device *dev)
+{
+ ctc_priv *privptr;
+
+ if (!dev)
+ return;
+ privptr = (ctc_priv *)dev->priv;
+ if (privptr->protocol != CTC_PROTO_LINUX_TTY)
+ unregister_netdev(dev);
+ else
+ ctc_tty_unregister_netdev(dev);
+}
+
+static int
+ctc_netdev_register(net_device *dev)
+{
+ ctc_priv *privptr = (ctc_priv *)dev->priv;
+ if (privptr->protocol != CTC_PROTO_LINUX_TTY)
+ return register_netdev(dev);
+ else
+ return ctc_tty_register_netdev(dev);
+}
+
+static void
+ctc_free_netdevice(net_device *dev, int free_dev)
+{
+ ctc_priv *privptr;
+ if (!dev)
+ return;
+ privptr = dev->priv;
+ if (privptr) {
+ if (privptr->fsm)
+ kfree_fsm(privptr->fsm);
+ ctc_proc_destroy_sub(privptr);
+ kfree(privptr);
+ }
+#ifdef MODULE
+ if (free_dev)
+ kfree(dev);
+#endif
+}
+
+#ifdef CTC_CHANDEV
+static int
+ctc_shutdown(net_device *dev)
+{
+ ctc_priv *privptr;
+
+ if (!dev)
+ return 0;
+ privptr = (ctc_priv *)dev->priv;
+ channel_remove(privptr->channel[READ]);
+ channel_remove(privptr->channel[WRITE]);
+ ctc_free_netdevice(dev, 0);
+ return 0;
+}
+#endif
+
+/**
+ * Initialize everything of the net device except the name and the
+ * channel structs.
+ */
+static net_device *
+ctc_init_netdevice(net_device *dev, int alloc_device)
+{
+ ctc_priv *privptr;
+ int priv_size;
+ if (alloc_device) {
+ dev = kmalloc(sizeof(net_device)
+#if LINUX_VERSION_CODE < 0x020300
+ + 11 /* name + zero */
+#endif
+ , GFP_KERNEL);
+ if (!dev)
+ return NULL;
+ memset(dev, 0, sizeof(net_device));
+ }
+ priv_size = sizeof(ctc_priv) + sizeof(ctc_template) +
+ sizeof(stat_entry) + sizeof(ctrl_entry);
+ dev->priv = kmalloc(priv_size, GFP_KERNEL);
+ if (dev->priv == NULL) {
+ if (alloc_device)
+ kfree(dev);
+ return NULL;
+ }
+ memset(dev->priv, 0, priv_size);
+ privptr = (ctc_priv *)dev->priv;
+ privptr->proc_dentry = (struct proc_dir_entry *)
+ (((char *)privptr) + sizeof(ctc_priv));
+ privptr->proc_stat_entry = (struct proc_dir_entry *)
+ (((char *)privptr) + sizeof(ctc_priv) +
+ sizeof(ctc_template));
+ privptr->proc_ctrl_entry = (struct proc_dir_entry *)
+ (((char *)privptr) + sizeof(ctc_priv) +
+ sizeof(ctc_template) + sizeof(stat_entry));
+ memcpy(privptr->proc_dentry, &ctc_template, sizeof(ctc_template));
+ memcpy(privptr->proc_stat_entry, &stat_entry, sizeof(stat_entry));
+ memcpy(privptr->proc_ctrl_entry, &ctrl_entry, sizeof(ctrl_entry));
+ privptr->fsm = init_fsm("ctcdev", dev_state_names,
+ dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
+ dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
+ if (privptr->fsm == NULL) {
+ kfree(privptr);
+ if (alloc_device)
+ kfree(dev);
+ return NULL;
+ }
+ fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
+ dev->mtu = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
+ dev->hard_start_xmit = ctc_tx;
+ dev->open = ctc_open;
+ dev->stop = ctc_close;
+ dev->get_stats = ctc_stats;
+ dev->change_mtu = ctc_change_mtu;
+ dev->hard_header_len = LL_HEADER_LENGTH + 2;
+ dev->addr_len = 0;
+ dev->type = ARPHRD_SLIP;
+ dev->tx_queue_len = 100;
+ SET_DEVICE_START(dev, 1);
+ dev_init_buffers(dev);
+ dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+ return dev;
+}
+
+#ifdef CTC_CHANDEV
+static void
+ctc_chandev_msck_notify(void *dev, int msck_irq,
+ chandev_msck_status prevstatus,
+ chandev_msck_status newstatus)
+{
+ net_device *device = (net_device *)dev;
+ ctc_priv *privptr;
+ int direction;
+
+ if (!dev)
+ return;
+
+ privptr = device->priv;
+ if (prevstatus == chandev_status_revalidate)
+ for (direction = READ; direction <= WRITE; direction++) {
+ channel *ch = privptr->channel[direction];
+ if(ch->irq == msck_irq) {
+ s390_dev_info_t devinfo;
+
+ if (get_dev_info_by_irq(ch->irq, &devinfo))
+ ch->devno = devinfo.devno;
+ else
+ printk(KERN_WARNING
+ "ctc_chandev_msck_notify: "
+ "get_dev_info_by_irq failed for "
+ "irq %d\n", ch->irq);
+ }
+ }
+ switch (newstatus) {
+ case chandev_status_not_oper:
+ case chandev_status_no_path:
+ case chandev_status_gone:
+ for (direction = READ; direction <= WRITE; direction++) {
+ channel *ch = privptr->channel[direction];
+ fsm_event(ch->fsm, CH_EVENT_MC_FAIL, ch);
+ }
+ printk(KERN_WARNING
+ "ctc: %s channel deactivated\n", device->name);
+ break;
+ case chandev_status_all_chans_good:
+ for (direction = READ; direction <= WRITE; direction++) {
+ channel *ch = privptr->channel[direction];
+ fsm_event(ch->fsm, CH_EVENT_MC_GOOD, ch);
+ }
+ printk(KERN_WARNING
+ "ctc: %s channel activated\n", device->name);
+ break;
+ default:
+ break;
+ }
+}
+
+/**
+ *
+ * Setup an interface.
+ *
+ * Like ctc_setup(), ctc_probe() can be called from two different locations:
+ * - If built as module, it is called from within init_module().
+ * - If built in monolithic kernel, it is called from within generic network
+ * layer during initialization for every corresponding device, declared in
+ * drivers/net/Space.c
+ *
+ * @param dev Pointer to net_device to be initialized.
+ *
+ * @returns 0 on success, !0 on failure.
+ */
+static int ctc_chandev_probe(chandev_probeinfo *info)
+{
+ int devno[2];
+ __u16 proto;
+ int rc;
+ int direction;
+ channel_type_t type;
+ ctc_priv *privptr;
+ net_device *dev;
+
+ ctc_proc_create_main();
+
+
+ switch (info->chan_type) {
+ case chandev_type_ctc:
+ type = channel_type_ctca;
+ break;
+ case chandev_type_escon:
+ type = channel_type_escon;
+ break;
+ default:
+ printk(KERN_WARNING "ctc_chandev_probe called with "
+ "unsupported channel type %d\n", info->chan_type);
+ return -ENODEV;
+ }
+ devno[READ] = info->read.devno;
+ devno[WRITE] = info->write.devno;
+ proto = info->port_protocol_no;
+
+ if (add_channel(info->read.irq, info->read.devno, type))
+ return -ENOMEM;
+ if (add_channel(info->write.irq, info->write.devno, type))
+ return -ENOMEM;
+
+ dev = ctc_init_netdevice(NULL, 1);
+
+
+ if (!dev) {
+ printk(KERN_WARNING "ctc_init_netdevice failed\n");
+ return -ENODEV;
+ }
+
+ if (proto == CTC_PROTO_LINUX_TTY)
+ chandev_build_device_name(info, dev->name, "ctctty", 1);
+ else
+ chandev_build_device_name(info, dev->name, "ctc", 1);
+
+ privptr = (ctc_priv *)dev->priv;
+ privptr->protocol = proto;
+ for (direction = READ; direction <= WRITE; direction++) {
+ privptr->channel[direction] =
+ channel_get(type, devno[direction], direction);
+ if (privptr->channel[direction] == NULL) {
+ if (direction == WRITE) {
+ FREE_IRQ(privptr->channel[READ]->irq,
+ privptr->channel[READ]->devstat);
+ channel_free(privptr->channel[READ]);
+ }
+ ctc_free_netdevice(dev, 1);
+ return -ENODEV;
+ }
+ privptr->channel[direction]->netdev = dev;
+ privptr->channel[direction]->protocol = proto;
+ privptr->channel[direction]->max_bufsize = CTC_BUFSIZE_DEFAULT;
+ rc = REQUEST_IRQ(privptr->channel[direction]->irq,
+ (void *)ctc_irq_handler, SA_INTERRUPT,
+ dev->name,
+ privptr->channel[direction]->devstat);
+ if (rc) {
+ printk(KERN_WARNING
+ "%s: requested irq %d is busy rc=%02x\n",
+ dev->name, privptr->channel[direction]->irq,
+ rc);
+ if (direction == WRITE) {
+ FREE_IRQ(privptr->channel[READ]->irq,
+ privptr->channel[READ]->devstat);
+ channel_free(privptr->channel[READ]);
+ }
+ channel_free(privptr->channel[direction]);
+ ctc_free_netdevice(dev, 1);
+ return -EBUSY;
+ }
+ }
+ if (ctc_netdev_register(dev) != 0) {
+ ctc_free_netdevice(dev, 1);
+ return -ENODEV;
+ }
+
+ /**
+ * register subdir in /proc/net/ctc
+ */
+ ctc_proc_create_sub(dev);
+ strncpy(privptr->fsm->name, dev->name, sizeof(privptr->fsm->name));
+ activated++;
+
+ print_banner();
+
+ printk(KERN_INFO
+ "%s: read: ch %04x (irq %04x), "
+ "write: ch %04x (irq %04x) proto: %d\n",
+ dev->name, privptr->channel[READ]->devno,
+ privptr->channel[READ]->irq, privptr->channel[WRITE]->devno,
+ privptr->channel[WRITE]->irq, proto);
+
+ chandev_initdevice(info, dev, 0, dev->name,
+ (proto == CTC_PROTO_LINUX_TTY)
+ ? chandev_category_serial_device :
+ chandev_category_network_device,
+ (chandev_unregfunc)ctc_netdev_unregister);
+ return 0;
+}
+#else /* ! CHANDEV */
/**
*
* Setup an interface.
* ctc_probe gets control.
*/
if (channels == NULL)
- channel_scan(1);
+ channel_scan();
type = extract_channel_media(dev->name);
if (type == channel_type_unknown)
}
}
- dev->priv = kmalloc(sizeof(ctc_priv)
- + sizeof(ctc_template)
- + sizeof(stat_entry)
- + sizeof(ctrl_entry)
- , GFP_KERNEL);
- if (dev->priv == NULL)
- return -ENOMEM;
- memset(dev->priv, 0, sizeof(ctc_priv));
+#ifndef MODULE
+ if (ctc_init_netdevice(dev, 0) == NULL)
+ return -ENODEV;
+#endif
privptr = (ctc_priv *)dev->priv;
privptr->protocol = proto;
- privptr->proc_dentry = (struct proc_dir_entry *)
- (((char *)privptr) + sizeof(ctc_priv));
- privptr->proc_stat_entry = (struct proc_dir_entry *)
- (((char *)privptr) + sizeof(ctc_priv) +
- sizeof(ctc_template));
- privptr->proc_ctrl_entry = (struct proc_dir_entry *)
- (((char *)privptr) + sizeof(ctc_priv) +
- sizeof(ctc_template) + sizeof(stat_entry));
- memcpy(privptr->proc_dentry, &ctc_template, sizeof(ctc_template));
- memcpy(privptr->proc_stat_entry, &stat_entry, sizeof(stat_entry));
- memcpy(privptr->proc_ctrl_entry, &ctrl_entry, sizeof(ctrl_entry));
- privptr->fsm = init_fsm(dev->name, dev_state_names,
- dev_event_names, NR_DEV_STATES, NR_DEV_EVENTS,
- dev_fsm, DEV_FSM_LEN, GFP_KERNEL);
- fsm_newstate(privptr->fsm, DEV_STATE_STOPPED);
- if (privptr->fsm == NULL) {
- kfree(privptr);
- return -ENOMEM;
- }
- dev->mtu = CTC_BUFSIZE_DEFAULT - LL_HEADER_LENGTH - 2;
- dev->hard_start_xmit = ctc_tx;
- dev->open = ctc_open;
- dev->stop = ctc_close;
- dev->get_stats = ctc_stats;
- dev->change_mtu = ctc_change_mtu;
- dev->hard_header_len = LL_HEADER_LENGTH + 2;
- dev->addr_len = 0;
- dev->type = ARPHRD_SLIP;
- dev->tx_queue_len = 100;
- SET_DEVICE_START(dev, 1);
- dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+
for (direction = READ; direction <= WRITE; direction++) {
if ((ctc_no_auto == 0) || (devno[direction] == -1))
privptr->channel[direction] =
channel_get(type, devno[direction], direction);
if (privptr->channel[direction] == NULL) {
if (direction == WRITE) {
- free_irq(privptr->channel[READ]->irq,
+ FREE_IRQ(privptr->channel[READ]->irq,
privptr->channel[READ]->devstat);
channel_free(privptr->channel[READ]);
}
- kfree_fsm(privptr->fsm);
- kfree(dev->priv);
- dev->priv = NULL;
+ ctc_free_netdevice(dev, 1);
return -ENODEV;
}
privptr->channel[direction]->netdev = dev;
privptr->channel[direction]->protocol = proto;
privptr->channel[direction]->max_bufsize = CTC_BUFSIZE_DEFAULT;
- rc = request_irq(privptr->channel[direction]->irq,
+ rc = REQUEST_IRQ(privptr->channel[direction]->irq,
(void *)ctc_irq_handler, SA_INTERRUPT,
dev->name,
privptr->channel[direction]->devstat);
dev->name, privptr->channel[direction]->irq,
rc);
if (direction == WRITE) {
- free_irq(privptr->channel[READ]->irq,
+ FREE_IRQ(privptr->channel[READ]->irq,
privptr->channel[READ]->devstat);
channel_free(privptr->channel[READ]);
}
channel_free(privptr->channel[direction]);
- kfree_fsm(privptr->fsm);
- kfree(dev->priv);
- dev->priv = NULL;
+ ctc_free_netdevice(dev, 1);
return -EBUSY;
}
}
print_banner();
printk(KERN_INFO
- "%s: read: ch %04x (irq %04x), write: ch %04x (irq %04x) proto: %d\n",
+ "%s: read: ch %04x (irq %04x), "
+ "write: ch %04x (irq %04x) proto: %d\n",
dev->name, privptr->channel[READ]->devno,
privptr->channel[READ]->irq, privptr->channel[WRITE]->devno,
privptr->channel[WRITE]->irq, proto);
return 0;
}
+#endif
\f
/**
* Module related routines
* for that.
*/
void cleanup_module(void) {
- channel *c = channels;
- ctc_tty_cleanup();
+ ctc_tty_cleanup(0);
/* we are called if all interfaces are down only, so no need
* to bother around with locking stuff
*/
- channels = NULL;
- while (c) {
- channel *oldc = c;
- if (c->netdev && c->netdev->priv) {
- net_device *nd = c->netdev;
- ctc_priv *privptr = (ctc_priv *)nd->priv;
-
- fsm_deltimer(&privptr->channel[READ]->timer);
- fsm_deltimer(&privptr->channel[WRITE]->timer);
- free_irq(privptr->channel[READ]->irq,
- privptr->channel[READ]->devstat);
- free_irq(privptr->channel[WRITE]->irq,
- privptr->channel[WRITE]->devstat);
- kfree_fsm(privptr->channel[READ]->fsm);
- kfree_fsm(privptr->channel[WRITE]->fsm);
- if (privptr->protocol != CTC_PROTO_LINUX_TTY)
- unregister_netdev(nd);
- else
- ctc_tty_unregister_netdev(nd);
- kfree_fsm(privptr->fsm);
- privptr->channel[READ]->netdev = NULL;
- privptr->channel[WRITE]->netdev = NULL;
- ctc_proc_destroy_sub(privptr);
- kfree(privptr);
- kfree(nd);
- if (c->netdev != NULL)
- printk(KERN_EMERG
- "ctc: PANIC: channel list corrupted\n");
+#ifndef CTC_CHANDEV
+ while (channels) {
+ if ((channels->flags & CHANNEL_FLAGS_INUSE) &&
+ (channels->netdev != NULL)) {
+ net_device *dev = channels->netdev;
+ ctc_priv *privptr = dev->priv;
+
+ if (privptr) {
+ privptr->channel[READ]->netdev = NULL;
+ privptr->channel[WRITE]->netdev = NULL;
+ }
+ channels->netdev = NULL;
+ ctc_netdev_unregister(dev);
+ ctc_free_netdevice(dev, 1);
}
- c = c->next;
- kfree(oldc->ccw);
- kfree(oldc);
+ channel_remove(channels);
}
+ channels = NULL;
+#endif
+ ctc_tty_cleanup(1);
ctc_proc_destroy_main();
+#ifdef CTC_CHANDEV
+ chandev_unregister(ctc_chandev_probe, 1);
+#endif
printk(KERN_INFO "CTC driver unloaded\n");
}
* @return 0 on success, !0 on error.
*/
int ctc_init(void) {
+#ifndef CTC_CHANDEV
int cnt[2];
int itype;
int activated;
- int ret = 0;
param *par;
+#endif
+ int ret = 0;
+ int probed = 0;
print_banner();
-#ifdef DEBUG
+#if defined(DEBUG) && !defined(CTC_CHANDEV)
printk(KERN_DEBUG
- "ctc: init_module(): got string '%s'\n", setup);
+ "ctc: init_module(): got string '%s'\n", ctc);
#endif
+#ifndef CTC_CHANDEV
#ifdef MODULE
ctc_setup(ctc);
#endif
- activated = 0;
par = params;
+#endif
+
+ activated = 0;
ctc_tty_init();
+#ifdef CTC_CHANDEV
+ chandev_register_and_probe(ctc_chandev_probe,
+ (chandev_shutdownfunc)ctc_shutdown,
+ ctc_chandev_msck_notify,
+ chandev_type_ctc|chandev_type_escon);
+#else /* CTC_CHANDEV */
for (itype = 0; itype < 2; itype++) {
net_device *dev = NULL;
char *bname = (itype) ? "escon" : "ctc";
cnt[itype] = 0;
do {
- dev = kmalloc(sizeof(net_device)
-#if LINUX_VERSION_CODE < 0x020300
- + 11 /* name + zero */
-#endif
- , GFP_KERNEL);
+ dev = ctc_init_netdevice(NULL, 1);
if (!dev) {
ret = -ENOMEM;
break;
}
- memset(dev, 0, sizeof(net_device));
#if LINUX_VERSION_CODE < 0x020300
dev->name = (unsigned char *)dev + sizeof(net_device);
#endif
if (isdigit(*p))
break;
if (p && *p) {
- int it = (strncmp(dev->name, "escon", 5)) ? 1 : 0;
+ int it =
+ (strncmp(dev->name, "escon", 5))
+ ? 1 : 0;
n = simple_strtoul(p, NULL, 0);
if (n >= cnt[it])
cnt[it] = n + 1;
} else {
if (ctc_no_auto) {
itype = 3;
- kfree(dev);
+ ctc_free_netdevice(dev, 1);
dev = NULL;
break;
}
printk(KERN_DEBUG "ctc: %s(): probing for device %s\n",
__FUNCTION__, dev->name);
#endif
+ probed = 1;
if (ctc_probe(dev) == 0) {
ctc_priv *privptr = (ctc_priv *)dev->priv;
#ifdef DEBUG
"ctc: %s(): registering device %s\n",
__FUNCTION__, dev->name);
#endif
- if (privptr->protocol != CTC_PROTO_LINUX_TTY) {
- if (register_netdev(dev) != 0) {
- printk(KERN_WARNING
- "ctc: Couldn't register netdev %s\n",
- dev->name);
- free_irq(privptr->channel[READ]->irq,
- privptr->channel[READ]->devstat);
- free_irq(privptr->channel[WRITE]->irq,
- privptr->channel[WRITE]->devstat);
- channel_free(privptr->channel[READ]);
- channel_free(privptr->channel[WRITE]);
- kfree(dev->priv);
- kfree(dev);
- } else {
-#ifdef DEBUG
- printk(KERN_DEBUG
- "ctc: %s(): register succeed\n",
- __FUNCTION__);
-#endif
- activated++;
- }
+ if (ctc_netdev_register(dev) != 0) {
+ printk(KERN_WARNING
+ "ctc: Couldn't register %s\n",
+ dev->name);
+ FREE_IRQ(
+ privptr->channel[READ]->irq,
+ privptr->channel[READ]->devstat);
+ FREE_IRQ(
+ privptr->channel[WRITE]->irq,
+ privptr->channel[WRITE]->devstat);
+ channel_free(privptr->channel[READ]);
+ channel_free(privptr->channel[WRITE]);
+ ctc_free_netdevice(dev, 1);
+ dev = NULL;
} else {
- if (ctc_tty_register_netdev(dev) != 0) {
- printk(KERN_WARNING
- "ctc: Couldn't register ttydev %s\n",
- dev->name);
- free_irq(privptr->channel[READ]->irq,
- privptr->channel[READ]->devstat);
- free_irq(privptr->channel[WRITE]->irq,
- privptr->channel[WRITE]->devstat);
- channel_free(privptr->channel[READ]);
- channel_free(privptr->channel[WRITE]);
- kfree(dev->priv);
- kfree(dev);
- } else {
#ifdef DEBUG
- printk(KERN_DEBUG
- "ctc: %s(): register succeed\n",
- __FUNCTION__);
+ printk(KERN_DEBUG
+ "ctc: %s(): register succeed\n",
+ __FUNCTION__);
#endif
- activated++;
- }
+ activated++;
}
-
} else {
#ifdef DEBUG
printk(KERN_DEBUG
"ctc: %s(): probing failed\n",
__FUNCTION__);
#endif
- kfree(dev);
dev = NULL;
}
} while (dev && (ret == 0));
}
+#endif /* CHANDEV */
+#if !defined(CTC_CHANDEV) && defined(MODULE)
if (!activated) {
printk(KERN_WARNING "ctc: No devices registered\n");
ret = -ENODEV;
}
- if (ret)
- ctc_tty_cleanup();
+#endif
+ if (ret) {
+ ctc_tty_cleanup(0);
+ ctc_tty_cleanup(1);
+#if defined(CTC_CHANDEV) && defined(MODULE)
+ chandev_unregister(ctc_chandev_probe, 0);
+#endif
+#ifdef MODULE
+ if (probed)
+ ctc_proc_destroy_main();
+#endif
+ }
return ret;
}
/*
- * $Id: ctctty.c,v 1.1 2001/01/23 14:23:51 felfert Exp $
+ * $Id: ctctty.c,v 1.8 2001/05/16 16:28:31 felfert Exp $
*
* CTC / ESCON network driver, tty interface.
*
# include <linux/devfs_fs_kernel.h>
#endif
#include "ctctty.h"
-#include <net/dst.h>
+
+#if LINUX_VERSION_CODE < 0x020212
+typedef struct wait_queue wait_queue_t;
+typedef struct wait_queue *wait_queue_head_t;
+#define DECLARE_WAITQUEUE(wait, current) \
+ struct wait_queue wait = { current, NULL }
+#define init_waitqueue_head(x) *(x)=NULL
+#define __set_current_state(state_value) \
+ do { current->state = state_value; } while (0)
+#ifdef __SMP__
+#define set_current_state(state_value) \
+ do { __set_current_state(state_value); mb(); } while (0)
+#else
+#define set_current_state(state_value) __set_current_state(state_value)
+#endif
+#define init_MUTEX(x) *(x)=MUTEX
+#endif
#define CTC_TTY_MAJOR 43
#define CTC_TTY_MAX_DEVICES 64
#define CTC_ASYNC_CTS_FLOW 0x04000000 /* Do CTS flow control */
#define CTC_ASYNC_CHECK_CD 0x02000000 /* i.e., CLOCAL */
#define CTC_ASYNC_HUP_NOTIFY 0x0001 /* Notify tty on hangups/closes */
+#define CTC_ASYNC_NETDEV_OPEN 0x0002 /* Underlying netdev is open */
+#define CTC_ASYNC_TX_LINESTAT 0x0004 /* Must send line status */
#define CTC_ASYNC_SPLIT_TERMIOS 0x0008 /* Sep. termios for dialin/out */
#define CTC_TTY_XMIT_SIZE 1024 /* Default bufsize for write */
#define CTC_SERIAL_XMIT_MAX 4000 /* Maximum bufsize for write */
typedef struct {
int magic;
int flags; /* defined in tty.h */
- int x_char; /* xon/xoff character */
int mcr; /* Modem control register */
int msr; /* Modem status register */
int lsr; /* Line status register */
int line;
int count; /* # of fd on device */
int blocked_open; /* # of blocked opens */
- net_device *netdev;
+ net_device *netdev;
struct sk_buff_head tx_queue; /* transmit queue */
struct sk_buff_head rx_queue; /* receive queue */
struct tty_struct *tty; /* Pointer to corresponding tty */
wait_queue_head_t open_wait;
wait_queue_head_t close_wait;
struct semaphore write_sem;
- struct tq_struct tq;
+ struct tq_struct tq;
+ struct timer_list stoptimer;
} ctc_tty_info;
/* Description of one CTC-tty */
#define MODEM_PARANOIA_CHECK
#define MODEM_DO_RESTART
-#define CTC_TTY_NAME "ttyZ"
+#define CTC_TTY_NAME "ctctty"
#ifdef CONFIG_DEVFS_FS
static char *ctc_ttyname = "ctc/" CTC_TTY_NAME "%d";
static char *ctc_ttyname = CTC_TTY_NAME;
#endif
-char *ctc_tty_revision = "$Revision: 1.1 $";
+char *ctc_tty_revision = "$Revision: 1.8 $";
+
+static __u32 ctc_tty_magic = CTC_ASYNC_MAGIC;
+static int ctc_tty_shuttingdown = 0;
+
+static spinlock_t ctc_tty_lock;
/* ctc_tty_try_read() is called from within ctc_tty_rcv_skb()
* to stuff incoming data directly into a tty's flip-buffer. If the
len = skb->len;
if (c >= len) {
memcpy(tty->flip.char_buf_ptr, skb->data, len);
+ memset(tty->flip.flag_buf_ptr, 0, len);
tty->flip.count += len;
tty->flip.char_buf_ptr += len;
- memset(tty->flip.flag_buf_ptr, 0, len);
tty->flip.flag_buf_ptr += len;
- queue_task(&tty->flip.tqueue, &tq_timer);
+ tty_flip_buffer_push(tty);
kfree_skb(skb);
return 1;
}
static int
ctc_tty_readmodem(ctc_tty_info *info)
{
- int ret = 0;
+ int ret = 1;
struct tty_struct *tty;
if ((tty = info->tty)) {
int len = skb->len;
if (len > c)
len = c;
- memcpy(tty->flip.char_buf_ptr, skb_pull(skb, len), len);
- tty->flip.count += len;
+ memcpy(tty->flip.char_buf_ptr, skb->data, len);
+ skb_pull(skb, len);
memset(tty->flip.flag_buf_ptr, 0, len);
+ tty->flip.count += len;
+ tty->flip.char_buf_ptr += len;
tty->flip.flag_buf_ptr += len;
- queue_task(&tty->flip.tqueue, &tq_timer);
- if (skb->len) {
+ tty_flip_buffer_push(tty);
+ if (skb->len > 0)
skb_queue_head(&info->rx_queue, skb);
- ret = 1;
- } else
+ else {
kfree_skb(skb);
+ ret = skb_queue_len(&info->rx_queue);
+ }
}
}
}
return ret;
}
+void
+ctc_tty_setcarrier(net_device *netdev, int on)
+{
+ int i;
+
+ if ((!driver) || ctc_tty_shuttingdown)
+ return;
+ for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
+ if (driver->info[i].netdev == netdev) {
+ ctc_tty_info *info = &driver->info[i];
+ if (on)
+ info->msr |= UART_MSR_DCD;
+ else
+ info->msr &= ~UART_MSR_DCD;
+ if ((info->flags & CTC_ASYNC_CHECK_CD) && (!on))
+ tty_hangup(info->tty);
+ }
+}
+
void
ctc_tty_netif_rx(struct sk_buff *skb)
{
if (!skb)
return;
- if (!skb->dev) {
+ if ((!skb->dev) || (!driver) || ctc_tty_shuttingdown) {
dev_kfree_skb(skb);
return;
}
dev_kfree_skb(skb);
return;
}
- skb_pull(skb, sizeof(int));
+ if (skb->len < 6) {
+ dev_kfree_skb(skb);
+ return;
+ }
+ if (memcmp(skb->data, &ctc_tty_magic, sizeof(__u32))) {
+ dev_kfree_skb(skb);
+ return;
+ }
+ skb_pull(skb, sizeof(__u32));
+
+ i = *((int *)skb->data);
+ skb_pull(skb, sizeof(info->mcr));
+ if (i & UART_MCR_RTS) {
+ info->msr |= UART_MSR_CTS;
+ if (info->flags & CTC_ASYNC_CTS_FLOW)
+ info->tty->hw_stopped = 0;
+ } else {
+ info->msr &= ~UART_MSR_CTS;
+ if (info->flags & CTC_ASYNC_CTS_FLOW)
+ info->tty->hw_stopped = 1;
+ }
+ if (i & UART_MCR_DTR)
+ info->msr |= UART_MSR_DSR;
+ else
+ info->msr &= ~UART_MSR_DSR;
+ if (skb->len <= 0) {
+ kfree_skb(skb);
+ return;
+ }
/* Try to deliver directly via tty-flip-buf if queue is empty */
if (skb_queue_empty(&info->rx_queue))
if (ctc_tty_try_read(info, skb))
mark_bh(IMMEDIATE_BH);
}
-static void
-ctc_tty_dstfail(struct sk_buff *skb) {
- if (!skb)
- return;
- dev_kfree_skb(skb);
- return;
-}
-
-static struct dst_entry dst_e;
-static struct dst_ops dst_o;
-
static int
ctc_tty_tint(ctc_tty_info * info)
{
struct sk_buff *skb = skb_dequeue(&info->tx_queue);
+ int stopped = (info->tty->hw_stopped || info->tty->stopped);
+ int wake = 1;
int rc;
- int l;
- char c;
- if (!skb)
- return 0;
if (!info->netdev) {
- kfree(skb);
+ if (skb)
+ kfree(skb);
return 0;
}
- skb->dst = &dst_e;
- l = skb->len;
- c = *(skb->data);
- rc = info->netdev->hard_start_xmit(skb, info->netdev);
-printk(KERN_DEBUG "xmit: l=%d rc=%d '%02x'\n", l, rc, c);
- if (rc) {
+ if (info->flags & CTC_ASYNC_TX_LINESTAT) {
+ int skb_res = info->netdev->hard_header_len +
+ sizeof(info->mcr) + sizeof(__u32);
+ /* If we must update line status,
+ * create an empty dummy skb and insert it.
+ */
+ if (skb)
+ skb_queue_head(&info->tx_queue, skb);
+
+ skb = dev_alloc_skb(skb_res);
+ if (!skb) {
+ printk(KERN_WARNING
+ "ctc_tty: Out of memory in %s%d tint\n",
+ CTC_TTY_NAME, info->line);
+ return 1;
+ }
+ skb_reserve(skb, skb_res);
+ stopped = 0;
+ wake = 0;
+ }
+ if (!skb)
+ return 0;
+ if (stopped) {
skb_queue_head(&info->tx_queue, skb);
return 1;
+ }
+#if 0
+ if (skb->len > 0)
+ printk(KERN_DEBUG "tint: %d %02x\n", skb->len, *(skb->data));
+ else
+ printk(KERN_DEBUG "tint: %d STAT\n", skb->len);
+#endif
+ memcpy(skb_push(skb, sizeof(info->mcr)), &info->mcr, sizeof(info->mcr));
+ memcpy(skb_push(skb, sizeof(__u32)), &ctc_tty_magic, sizeof(__u32));
+ rc = info->netdev->hard_start_xmit(skb, info->netdev);
+ if (rc) {
+ skb_pull(skb, sizeof(info->mcr) + sizeof(__u32));
+ if (skb->len > 0)
+ skb_queue_head(&info->tx_queue, skb);
+ else
+ kfree_skb(skb);
} else {
struct tty_struct *tty = info->tty;
- info->lsr |= UART_LSR_TEMT;
- if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
- tty->ldisc.write_wakeup)
- (tty->ldisc.write_wakeup)(tty);
- wake_up_interruptible(&tty->write_wait);
+
+ info->flags &= ~CTC_ASYNC_TX_LINESTAT;
+ if (tty) {
+ if (wake && (tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
+ tty->ldisc.write_wakeup)
+ (tty->ldisc.write_wakeup)(tty);
+ wake_up_interruptible(&tty->write_wait);
+ }
}
return (skb_queue_empty(&info->tx_queue) ? 0 : 1);
}
return 0;
}
+static void
+ctc_tty_inject(ctc_tty_info *info, char c)
+{
+ int skb_res;
+ struct sk_buff *skb;
+
+ if (ctc_tty_shuttingdown)
+ return;
+ skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
+ sizeof(__u32) + 1;
+ skb = dev_alloc_skb(skb_res);
+ if (!skb) {
+ printk(KERN_WARNING
+ "ctc_tty: Out of memory in %s%d tx_inject\n",
+ CTC_TTY_NAME, info->line);
+ return;
+ }
+ skb_reserve(skb, skb_res);
+ *(skb_put(skb, 1)) = c;
+ skb_queue_head(&info->tx_queue, skb);
+ queue_task(&info->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
+static void
+ctc_tty_transmit_status(ctc_tty_info *info)
+{
+ if (ctc_tty_shuttingdown)
+ return;
+ info->flags |= CTC_ASYNC_TX_LINESTAT;
+ queue_task(&info->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+}
+
static void
ctc_tty_change_speed(ctc_tty_info * info)
{
}
if (quot) {
info->mcr |= UART_MCR_DTR;
+ info->mcr |= UART_MCR_RTS;
+ ctc_tty_transmit_status(info);
} else {
info->mcr &= ~UART_MCR_DTR;
+ info->mcr &= ~UART_MCR_RTS;
+ ctc_tty_transmit_status(info);
return;
}
ctc_tty_change_speed(info);
info->flags |= CTC_ASYNC_INITIALIZED;
- info->msr |= (UART_MSR_DSR | UART_MSR_CTS);
- info->netdev->open(info->netdev);
+ if (!(info->flags & CTC_ASYNC_NETDEV_OPEN))
+ info->netdev->open(info->netdev);
+ info->flags |= CTC_ASYNC_NETDEV_OPEN;
return 0;
}
+static void
+ctc_tty_stopdev(unsigned long data)
+{
+ ctc_tty_info *info = (ctc_tty_info *)data;
+
+ if ((!info) || (!info->netdev) ||
+ (info->flags & CTC_ASYNC_INITIALIZED))
+ return;
+ info->netdev->stop(info->netdev);
+ info->flags &= ~CTC_ASYNC_NETDEV_OPEN;
+}
+
/*
* This routine will shutdown a serial port; interrupts are disabled, and
* DTR is dropped if the hangup on close termio flag is on.
printk(KERN_DEBUG "Shutting down %s%d ....\n", CTC_TTY_NAME, info->line);
#endif
info->msr &= ~UART_MSR_RI;
- if (!info->tty || (info->tty->termios->c_cflag & HUPCL)) {
+ if (!info->tty || (info->tty->termios->c_cflag & HUPCL))
info->mcr &= ~(UART_MCR_DTR | UART_MCR_RTS);
- }
if (info->tty)
set_bit(TTY_IO_ERROR, &info->tty->flags);
- info->netdev->stop(info->netdev);
+ mod_timer(&info->stoptimer, jiffies + (10 * HZ));
skb_queue_purge(&info->tx_queue);
skb_queue_purge(&info->rx_queue);
info->flags &= ~CTC_ASYNC_INITIALIZED;
int total = 0;
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+ if (ctc_tty_shuttingdown)
+ return 0;
if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_write"))
return 0;
if (!tty)
if (c <= 0)
break;
- skb_res = info->netdev->hard_header_len + sizeof(int);
+ skb_res = info->netdev->hard_header_len + sizeof(info->mcr) +
+ + sizeof(__u32);
skb = dev_alloc_skb(skb_res + c);
if (!skb) {
printk(KERN_WARNING
count -= c;
}
if (skb_queue_len(&info->tx_queue)) {
+ info->lsr &= ~UART_LSR_TEMT;
queue_task(&info->tq, &tq_immediate);
mark_bh(IMMEDIATE_BH);
}
return;
}
skb_queue_purge(&info->tx_queue);
+ info->lsr |= UART_LSR_TEMT;
restore_flags(flags);
wake_up_interruptible(&tty->write_wait);
if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
{
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+ if (ctc_tty_shuttingdown)
+ return;
if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_flush_chars"))
return;
- if (skb_queue_len(&info->tx_queue)) {
- queue_task(&info->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
- }
+ if (tty->stopped || tty->hw_stopped || (!skb_queue_len(&info->tx_queue)))
+ return;
+ queue_task(&info->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
}
/*
if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_throttle"))
return;
- if (I_IXOFF(tty))
- info->x_char = STOP_CHAR(tty);
info->mcr &= ~UART_MCR_RTS;
+ if (I_IXOFF(tty))
+ ctc_tty_inject(info, STOP_CHAR(tty));
+ ctc_tty_transmit_status(info);
}
static void
if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_unthrottle"))
return;
- if (I_IXOFF(tty)) {
- if (info->x_char)
- info->x_char = 0;
- else
- info->x_char = START_CHAR(tty);
- }
info->mcr |= UART_MCR_RTS;
+ if (I_IXOFF(tty))
+ ctc_tty_inject(info, START_CHAR(tty));
+ ctc_tty_transmit_status(info);
}
/*
ctc_tty_set_ctc_tty_info(ctc_tty_info * info, uint cmd, uint * value)
{
uint arg;
+ int old_mcr = info->mcr & (UART_MCR_RTS | UART_MCR_DTR);
get_user(arg, (uint *) value);
switch (cmd) {
printk(KERN_DEBUG "%s%d ioctl TIOCMBIS\n", CTC_TTY_NAME,
info->line);
#endif
- if (arg & TIOCM_RTS) {
+ if (arg & TIOCM_RTS)
info->mcr |= UART_MCR_RTS;
- }
- if (arg & TIOCM_DTR) {
+ if (arg & TIOCM_DTR)
info->mcr |= UART_MCR_DTR;
- }
break;
case TIOCMBIC:
#ifdef CTC_DEBUG_MODEM_IOCTL
printk(KERN_DEBUG "%s%d ioctl TIOCMBIC\n", CTC_TTY_NAME,
info->line);
#endif
- if (arg & TIOCM_RTS) {
+ if (arg & TIOCM_RTS)
info->mcr &= ~UART_MCR_RTS;
- }
- if (arg & TIOCM_DTR) {
+ if (arg & TIOCM_DTR)
info->mcr &= ~UART_MCR_DTR;
- }
break;
case TIOCMSET:
#ifdef CTC_DEBUG_MODEM_IOCTL
default:
return -EINVAL;
}
+ if ((info->mcr & (UART_MCR_RTS | UART_MCR_DTR)) != old_mcr)
+ ctc_tty_transmit_status(info);
return 0;
}
ctc_tty_set_termios(struct tty_struct *tty, struct termios *old_termios)
{
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+ unsigned int cflag = tty->termios->c_cflag;
- if (!old_termios)
- ctc_tty_change_speed(info);
- else {
- if (tty->termios->c_cflag == old_termios->c_cflag)
- return;
- ctc_tty_change_speed(info);
- if ((old_termios->c_cflag & CRTSCTS) &&
- !(tty->termios->c_cflag & CRTSCTS)) {
- tty->hw_stopped = 0;
- }
+ ctc_tty_change_speed(info);
+
+ /* Handle transition to B0 */
+ if ((old_termios->c_cflag & CBAUD) && !(cflag & CBAUD)) {
+ info->mcr &= ~(UART_MCR_DTR|UART_MCR_RTS);
+ ctc_tty_transmit_status(info);
+ }
+
+ /* Handle transition from B0 to other */
+ if (!(old_termios->c_cflag & CBAUD) && (cflag & CBAUD)) {
+ info->mcr |= UART_MCR_DTR;
+ if (!(tty->termios->c_cflag & CRTSCTS) ||
+ !test_bit(TTY_THROTTLED, &tty->flags)) {
+ info->mcr |= UART_MCR_RTS;
+ }
+ ctc_tty_transmit_status(info);
}
+
+ /* Handle turning off CRTSCTS */
+ if ((old_termios->c_cflag & CRTSCTS) &&
+ !(tty->termios->c_cflag & CRTSCTS))
+ tty->hw_stopped = 0;
}
/*
ctc_tty_open(struct tty_struct *tty, struct file *filp)
{
ctc_tty_info *info;
+ unsigned long saveflags;
int retval,
line;
printk(KERN_DEBUG "ctc_tty_open %s%d, count = %d\n", tty->driver.name,
info->line, info->count);
#endif
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
info->count++;
tty->driver_data = info;
info->tty = tty;
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
/*
* Start up serial port
*/
ctc_tty_close(struct tty_struct *tty, struct file *filp)
{
ctc_tty_info *info = (ctc_tty_info *) tty->driver_data;
+ unsigned long saveflags;
ulong flags;
ulong timeout;
tty->driver.flush_buffer(tty);
if (tty->ldisc.flush_buffer)
tty->ldisc.flush_buffer(tty);
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
info->tty = 0;
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
tty->closing = 0;
if (info->blocked_open) {
set_current_state(TASK_INTERRUPTIBLE);
ctc_tty_hangup(struct tty_struct *tty)
{
ctc_tty_info *info = (ctc_tty_info *)tty->driver_data;
+ unsigned long saveflags;
if (ctc_tty_paranoia_check(info, tty->device, "ctc_tty_hangup"))
return;
ctc_tty_shutdown(info);
info->count = 0;
info->flags &= ~CTC_ASYNC_NORMAL_ACTIVE;
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
info->tty = 0;
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
wake_up_interruptible(&info->open_wait);
}
static void
ctc_tty_task(ctc_tty_info *info)
{
+ unsigned long saveflags;
int again;
- again = ctc_tty_tint(info);
- again |= ctc_tty_readmodem(info);
- if (again) {
- queue_task(&info->tq, &tq_immediate);
- mark_bh(IMMEDIATE_BH);
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
+ if ((!ctc_tty_shuttingdown) && info) {
+ again = ctc_tty_tint(info);
+ if (!again)
+ info->lsr |= UART_LSR_TEMT;
+ again |= ctc_tty_readmodem(info);
+ if (again) {
+ queue_task(&info->tq, &tq_immediate);
+ mark_bh(IMMEDIATE_BH);
+ }
}
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
}
int
ctc_tty_info *info;
struct tty_driver *device;
- dst_e.ops = &dst_o;
- dst_o.link_failure = ctc_tty_dstfail;
driver = kmalloc(sizeof(ctc_tty_driver), GFP_KERNEL);
if (driver == NULL) {
printk(KERN_WARNING "Out of memory in ctc_tty_modem_init\n");
for (i = 0; i < CTC_TTY_MAX_DEVICES; i++) {
info = &driver->info[i];
init_MUTEX(&info->write_sem);
+#if LINUX_VERSION_CODE >= 0x020400
INIT_LIST_HEAD(&info->tq.list);
+#else
+ info->tq.next = NULL;
+#endif
info->tq.sync = 0;
info->tq.routine = (void *)(void *)ctc_tty_task;
info->tq.data = info;
info->magic = CTC_ASYNC_MAGIC;
info->line = i;
info->tty = 0;
- info->x_char = 0;
info->count = 0;
info->blocked_open = 0;
info->normal_termios = device->init_termios;
init_waitqueue_head(&info->close_wait);
skb_queue_head_init(&info->tx_queue);
skb_queue_head_init(&info->rx_queue);
+ init_timer(&info->stoptimer);
+ info->stoptimer.function = ctc_tty_stopdev;
+ info->stoptimer.data = (unsigned long)info;
+ info->mcr = UART_MCR_RTS;
}
return 0;
}
void
ctc_tty_unregister_netdev(net_device *dev) {
int i;
+ unsigned long saveflags;
ctc_tty_info *info = NULL;
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
if (driver->info[i].netdev == dev) {
info = &driver->info[i];
skb_queue_purge(&info->tx_queue);
skb_queue_purge(&info->rx_queue);
}
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
}
void
-ctc_tty_cleanup(void) {
- tty_unregister_driver(&driver->ctc_tty_device);
- kfree(driver);
+ctc_tty_cleanup(int final) {
+ unsigned long saveflags;
+
+ spin_lock_irqsave(&ctc_tty_lock, saveflags);
+ ctc_tty_shuttingdown = 1;
+ if (final) {
+ kfree(driver);
+ driver = NULL;
+ } else {
+ int i;
+
+ for (i = 0; i < CTC_TTY_MAX_DEVICES; i++)
+ driver->info[i].tq.routine = NULL;
+ tty_unregister_driver(&driver->ctc_tty_device);
+ }
+ spin_unlock_irqrestore(&ctc_tty_lock, saveflags);
}
/*
- * $Id: ctctty.h,v 1.2 2001/01/30 22:09:28 uweigand Exp $
+ * $Id: ctctty.h,v 1.4 2001/03/22 12:46:01 felfert Exp $
*
* CTC / ESCON network driver, tty interface.
*
typedef struct net_device net_device;
#endif
-extern int ctc_tty_register_netdev(net_device *dev);
-extern void ctc_tty_unregister_netdev(net_device *dev);
-extern void ctc_tty_netif_rx(struct sk_buff *skb);
+extern int ctc_tty_register_netdev(net_device *);
+extern void ctc_tty_unregister_netdev(net_device *);
+extern void ctc_tty_netif_rx(struct sk_buff *);
extern int ctc_tty_init(void);
-extern void ctc_tty_cleanup(void);
+extern void ctc_tty_cleanup(int);
+extern void ctc_tty_setcarrier(net_device *, int);
#endif
/**
- * $Id: fsm.c,v 1.1 2000/11/30 11:21:08 bird Exp $
+ * $Id: fsm.c,v 1.3 2001/06/18 16:49:19 felfert Exp $
*
* A generic FSM based on fsm used in isdn4linux
*
- * $Log: fsm.c,v $
- * Revision 1.1 2000/11/30 11:21:08 bird
- * Support for new ctc driver
- *
- * Revision 1.2 2000/11/10 17:25:11 felfert
- * Changes for kernel 2.4
- *
- * Revision 1.1 2000/11/03 16:58:45 felfert
- * Initial import
- *
- *
*/
#include "fsm.h"
#include <linux/version.h>
+#include <linux/config.h>
+#include <linux/module.h>
fsm_instance *
init_fsm(char *name, const char **state_names, const char **event_names, int nr_states,
this->tl.expires = jiffies + (millisec * HZ) / 1000;
add_timer(&this->tl);
}
+
+EXPORT_SYMBOL(init_fsm);
+EXPORT_SYMBOL(kfree_fsm);
+EXPORT_SYMBOL(fsm_settimer);
+EXPORT_SYMBOL(fsm_deltimer);
+EXPORT_SYMBOL(fsm_addtimer);
+EXPORT_SYMBOL(fsm_modtimer);
+EXPORT_SYMBOL(fsm_getstate_str);
+
+#if FSM_DEBUG_HISTORY
+EXPORT_SYMBOL(fsm_print_history);
+EXPORT_SYMBOL(fsm_record_history);
+#endif
-/* $Id: fsm.h,v 1.1 2000/11/30 11:21:08 bird Exp $
- *
- * $Log: fsm.h,v $
- * Revision 1.1 2000/11/30 11:21:08 bird
- * Support for new ctc driver
- *
- * Revision 1.1 2000/11/03 16:58:45 felfert
- * Initial import
- *
- *
+/* $Id: fsm.h,v 1.3 2001/06/18 16:49:19 felfert Exp $
*/
#ifndef _FSM_H_
#define _FSM_H_
#include <linux/types.h>
#include <linux/timer.h>
#include <linux/time.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <asm/atomic.h>
* @param tmpl_len Length of the describing array.
* @param order Parameter for allocation of the FSM data structs.
*/
-fsm_instance * init_fsm(char *name, const char **state_names,
- const char **event_names,
- int nr_states, int nr_events, const fsm_node *tmpl,
- int tmpl_len, int order);
+extern fsm_instance *
+init_fsm(char *name, const char **state_names,
+ const char **event_names,
+ int nr_states, int nr_events, const fsm_node *tmpl,
+ int tmpl_len, int order);
/**
* Releases an FSM
-/*
- * drivers/s390/net/iucv.c
+/*
+ * drivers/s390/net/iucv.c
* Support for VM IUCV functions for use by other part of the
* kernel or loadable modules.
*
* S390 version
* Copyright (C) 2000 IBM Corporation
- * Author(s): Xenia Tkatschow (xenia@us.ibm.com)
- * Alan Altmark (Alan_Altmark@us.ibm.com)
- */
-
+ * Author(s): Alan Altmark (Alan_Altmark@us.ibm.com)
+ * Xenia Tkatschow (xenia@us.ibm.com)
+ * Functionality:
+ * To explore any of the IUCV functions, one must first register
+ * their program using iucv_register(). Once your program has
+ * successfully completed a register, it can use the other functions.
+ * For furthur reference on all IUCV functionality, refer to the
+ * CP Programming Services book, also available on the web
+ * thru www.ibm.com/s390/vm/pubs , manual # SC24-5760.
+ *
+ * Definition of Return Codes
+ * -All positive return codes including zero are reflected back
+ * from CP and the definition can be found in CP Programming
+ * Services book.
+ * - (-ENOMEM) Out of memory
+ * - (-EINVAL) Invalid value
+*/
+/* #define DEBUG 1 */
#include <linux/module.h>
+#include <linux/config.h>
#include <linux/version.h>
#include <linux/spinlock.h>
#include <linux/kernel.h>
#include <asm/atomic.h>
#include "iucv.h"
#include <asm/io.h>
+#include <asm/irq.h>
#include <asm/s390_ext.h>
#include <asm/ebcdic.h>
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+#ifndef max
+#define max(a,b) (((a)>(b))?(a):(b))
+#endif
+
+#ifdef DEBUG
+#undef KERN_INFO
#undef KERN_DEBUG
+#define KERN_INFO KERN_EMERG
#define KERN_DEBUG KERN_EMERG
-//#define DEBUG3
-//#define DEBUG /* Turns Printk's on */
-//#define DEBUG2 /* This prints the parameter list before and */
- /* after the b2f0 call to cp */
+#endif
+
#undef NULL
#define NULL 0
-#define ADDED_STOR 64 /* ADDITIONAL STORAGE FOR PATHID @'S */
-ulong declare_flag = 0;
+
+#define PRRTY_PRMTD 0x01 /* priority permitted */
+#define RPY_RQRD 0x01 /* reply required */
+#define ADDED_STOR 64 /* ADDITIONAL STORAGE FOR PATHID @'S */
+#define BUFFER_SIZE 40 /* Size of 31-bit iparml */
+
+/* FLAGS:
+ * All flags are defined in the field IPFLAGS1 of each function
+ * and can be found in CP Programming Services.
+ * IPSRCCLS - Indicates you have specified a source class
+ * IPFGMCL - Indicates you have specified a target class
+ * IPFGPID - Indicates you have specified a pathid
+ * IPFGMID - Indicates you have specified a message ID
+ * IPANSLST - Indicates that you are using an address list for
+ * reply data
+ * IPBUFLST - Indicates that you are using an address list for
+ * message data
+ */
+
+#define IPSRCCLS 0x01
+#define IPFGMCL 0x01
+#define IPFGPID 0x02
+#define IPFGMID 0x04
+#define IPANSLST 0x08
+#define IPBUFLST 0x40
+
static uchar iucv_external_int_buffer[40];
+
+/* Spin Lock declaration */
struct tq_struct short_task; /* automatically initialized to zero */
-static iucv_interrupt_ops_t my_ops;
-spinlock_t lock = SPIN_LOCK_UNLOCKED;
+static spinlock_t iucv_lock = SPIN_LOCK_UNLOCKED;
-static void do_int (iucv_ConnectionPending *);
+/* General IUCV interrupt structure */
+typedef struct {
+ u16 ippathid;
+ uchar res1;
+ uchar iptype;
+ u32 res2;
+ uchar ipvmid[8];
+ uchar res3[24];
+} iucv_GeneralInterrupt;
/***************INTERRUPT HANDLING DEFINITIONS***************/
typedef struct _iucv_packet {
uchar data[40];
} iucv_packet;
struct tq_struct short_task;
+
static spinlock_t iucv_packets_lock = SPIN_LOCK_UNLOCKED;
+
iucv_packet *iucv_packets_head, *iucv_packets_tail;
static atomic_t bh_scheduled = ATOMIC_INIT (0);
+
+/*
+ *Internal function prototypes
+ */
+
+static ulong iucv_vmsize (void);
+
+int iucv_declare_buffer (void);
+
+int iucv_retrieve_buffer (void);
+
+static int iucv_add_pathid (u16 pathid, iucv_handle_t handle, void *pgm_data);
+
+static void iucv_remove_pathid (u16 pathid);
+
void bottom_half_interrupt (void);
+static void do_int (iucv_GeneralInterrupt *);
+
+inline void top_half_interrupt (struct pt_regs *regs, __u16 code);
/************FUNCTION ID'S****************************/
-#define accept 10
-#define connect 11
-#define declare_buffer 12
-#define purge 9
-#define query 0
-#define quiesc 13
-#define receive 5
-#define reject 8
-#define reply 6
-#define resume 14
-#define retrieve_buffer 2
-#define send 4
-#define setmask 16
-#define sever 15
-
-/*****************************************************************/
-/* Structure: handler */
-/* members: next - is a pointer to next handler on chain */
-/* prev - is a pointer to prev handler on chain */
-/* vmid - 8 char array of machine identification */
-/* user_data - 16 char array for user identification */
-/* mask - 24 char array used to compare the 2 previous */
-/* interrupt_table - functions for interrupts */
-/* start - pointer to start of block of pointers to */
-/* handler_table_entries */
-/* end - pointer to end of block of pointers to */
-/* handler_table_entries */
-/* size - ulong, size of block */
-/* pgm_data - ulong, program data */
-/* NOTE: Keep vmid and user_data together in this order */
-/*****************************************************************/
+
+#define ACCEPT 10
+#define CONNECT 11
+#define DECLARE_BUFFER 12
+#define PURGE 9
+#define QUERY 0
+#define QUIESCE 13
+#define RECEIVE 5
+#define REJECT 8
+#define REPLY 6
+#define RESUME 14
+#define RETRIEVE_BUFFER 2
+#define SEND 4
+#define SETMASK 16
+#define SEVER 15
+
+/*
+ * Structure: handler
+ * members: next - is a pointer to next handler on chain
+ * prev - is a pointer to prev handler on chain
+ * structure: id
+ * vmid - 8 char array of machine identification
+ * user_data - 16 char array for user identification
+ * mask - 24 char array used to compare the 2 previous
+ * interrupt_table - vector of interrupt functions.
+ * pathid_head - pointer to start of user_pathid_table
+ * pathid_tail - pointer to end of user_pathid_table
+ * entries - ulong, size of user_pathid_table
+ * pgm_data - ulong, application data that is passed
+ * to the interrupt handlers
+*/
typedef struct {
ulong *next;
ulong *prev;
- uchar vmid[8];
- uchar user_data[16];
- uchar mask[24];
+ struct {
+ uchar userid[8];
+ uchar user_data[16];
+ uchar mask[24];
+ } id;
iucv_interrupt_ops_t *interrupt_table;
- ulong *start;
- ulong *end;
- ulong size;
- ulong pgm_data;
+ ulong *pathid_head;
+ ulong *pathid_tail;
+ ulong entries;
+ void *pgm_data;
} handler;
-/*******************************************************************/
-/* Structure: handler_table_entry */
-/* members: addrs - pointer to a handler */
-/* pathid - ushort containing path identification */
-/* pgm_data - ulong, program data */
-/*******************************************************************/
+/*
+ * Structure: handler_table_entry
+ * members: addrs - pointer to a handler
+ * pathid - ushort containing path identification
+ * pgm_data - ulong, application data that is
+ * passed to the interrupt handlers
+ * ops - pointer to iucv interrupt vector
+ */
+
typedef struct {
handler *addrs;
- ushort pathid;
- ulong pgm_data;
+ u16 pathid;
+ void *pgm_data;
+ iucv_interrupt_ops_t *ops;
} handler_table_entry;
-/* main_table: array of pointers to handler_tables */
-static handler_table_entry *main_table[128];
-/* handler_anchor: points to first handler on chain */
-static handler *handler_anchor;
-
-/****************FIVE STRUCTURES************************************/
-/* Data struct 1: iparml_control */
-/* Used for iucv_accept */
-/* iucv_connect */
-/* iucv_quiesce */
-/* iucv_resume */
-/* iucv_sever */
-/* iucv_retrieve_buffer */
-/* Data struct 2: iparml_dpl (data in parameter list) */
-/* Used for iucv_send_prmmsg */
-/* iucv_send2way_prmmsg */
-/* iucv_send2way_prmmsg_array */
-/* iucv_reply_prmmsg */
-/* Data struct 3: iparml_db (data in a buffer) */
-/* Used for iucv_receive */
-/* iucv_receive_array */
-/* iucv_receive_simple */
-/* iucv_reject */
-/* iucv_reply */
-/* iucv_reply_array */
-/* iucv_send */
-/* iucv_send_simple */
-/* iucv_send_array */
-/* iucv_send2way */
-/* iucv_send2way_array */
-/* iucv_declare_buffer */
-/* Data struct 4: iparml_purge */
-/* Used for iucv_purge */
-/* iucv_query */
-/* Data struct 5: iparml_set_mask */
-/* Used for iucv_set_mask */
-/********************************************************************/
+/*
+ * Internal function prototypes
+ */
+
+static int iucv_add_handler (handler * new_handler);
+
+static void iucv_remove_handler (handler * users_handler);
+
+/* handler_anchor: points to first handler on chain */
+/* handler_tail: points to last handler on chain */
+/* handler_table_anchor: points to beginning of handler_table_entries*/
+
+static handler *handler_anchor = NULL;
+
+static handler *handler_tail = NULL;
+
+static handler_table_entry *handler_table_anchor = NULL;
+
+/* declare_flag: is 0 when iucv_declare_buffer has not been called */
+
+static ulong declare_flag = 0;
+
+/****************FIVE 40-BYTE PARAMETER STRUCTURES******************/
+/* Data struct 1: iparml_control
+ * Used for iucv_accept
+ * iucv_connect
+ * iucv_quiesce
+ * iucv_resume
+ * iucv_sever
+ * iucv_retrieve_buffer
+ * Data struct 2: iparml_dpl (data in parameter list)
+ * Used for iucv_send_prmmsg
+ * iucv_send2way_prmmsg
+ * iucv_send2way_prmmsg_array
+ * iucv_reply_prmmsg
+ * Data struct 3: iparml_db (data in a buffer)
+ * Used for iucv_receive
+ * iucv_receive_array
+ * iucv_reject
+ * iucv_reply
+ * iucv_reply_array
+ * iucv_send
+ * iucv_send_array
+ * iucv_send2way
+ * iucv_send2way_array
+ * iucv_declare_buffer
+ * Data struct 4: iparml_purge
+ * Used for iucv_purge
+ * iucv_query
+ * Data struct 5: iparml_set_mask
+ * Used for iucv_set_mask
+*/
+
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar ipflags1;
uchar iprcode;
- ushort ipmsglim;
- ushort res1;
+ u16 ipmsglim;
+ u16 res1;
uchar ipvmid[8];
uchar ipuser[16];
uchar iptarget[8];
} iparml_control;
-/******************/
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar ipflags1;
uchar iprcode;
- ulong ipmsgid;
- ulong iptrgcls;
+ u32 ipmsgid;
+ u32 iptrgcls;
uchar iprmmsg[8];
- ulong ipsrccls;
- ulong ipmsgtag;
- ulong ipbfadr2;
- ulong ipbfln2f;
- ulong res;
+ u32 ipsrccls;
+ u32 ipmsgtag;
+ u32 ipbfadr2;
+ u32 ipbfln2f;
+ u32 res;
} iparml_dpl;
-/*******************/
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar ipflags1;
uchar iprcode;
- ulong ipmsgid;
- ulong iptrgcls;
- ulong ipbfadr1;
- ulong ipbfln1f;
- ulong ipsrccls;
- ulong ipmsgtag;
- ulong ipbfadr2;
- ulong ipbfln2f;
- ulong res;
+ u32 ipmsgid;
+ u32 iptrgcls;
+ u32 ipbfadr1;
+ u32 ipbfln1f;
+ u32 ipsrccls;
+ u32 ipmsgtag;
+ u32 ipbfadr2;
+ u32 ipbfln2f;
+ u32 res;
} iparml_db;
-/********************/
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar ipflags1;
uchar iprcode;
- ulong ipmsgid;
- uchar ipaudit[4];
- uchar res1[4];
- ulong res2;
- ulong ipsrccls;
- ulong ipmsgtag;
- ulong res3[3];
+ u32 ipmsgid;
+ uchar ipaudit[3];
+ uchar res1[5];
+ u32 res2;
+ u32 ipsrccls;
+ u32 ipmsgtag;
+ u32 res3[3];
} iparml_purge;
-/*******************/
typedef struct {
uchar ipmask;
uchar res1[2];
uchar iprcode;
- ulong res2[9];
+ u32 res2[9];
} iparml_set_mask;
/*********************INTERNAL FUNCTIONS*****************************/
-/********************************************************************/
-/* Name: b2f0 */
-/* Purpose: this function calls cp to execute iucv commands. */
-/* Input: code - int, identifier of iucv call to cp. */
-/* parm - void *, pointer to 40 byte iparml area passed to cp */
-/* Output: iprcode- return code from iucv call to cp */
-/********************************************************************/
-/* Assembler code performing iucv call */
-/*******************************************************************/
-inline ulong
-b2f0 (int code, void *parm)
+
+static ulong
+iucv_vmsize (void)
+{
+ extern unsigned long memory_size;
+ return memory_size;
+}
+
+/*
+ * Name: dumpit
+ * Purpose: print to the console buffers of a given length
+ * Input: buf - (* uchar) - pointer to buffer to be printed
+ * len - int - length of buffer being printed
+ * Output: void
+ */
+
+#ifdef DEBUG
+
+static void
+iucv_dumpit (uchar * buf, int len)
{
- uchar *iprcode; /* used to extract iprcode */
-#ifdef DEBUG2
int i;
- uchar *prt_parm;
- prt_parm = (uchar *) (parm);
- printk (KERN_DEBUG "parameter list before b2f0 call\n");
- for (i = 0; i < 40; i++)
- printk (KERN_DEBUG "%02x ", prt_parm[i]);
- printk (KERN_DEBUG "\n");
-#endif
- asm volatile ("LRA 1,0(%1)\n\t"
- "LR 0,%0\n\t"
- ".long 0xb2f01000"
- : : "d" (code), "a" (parm) : "0", "1");
-#ifdef DEBUG2
- printk (KERN_DEBUG "parameter list after b2f0 call\n");
- for (i = 0; i < 40; i++)
- printk (KERN_DEBUG "%02x ", prt_parm[i]);
- printk (KERN_DEBUG "\n");
-#endif
- iprcode = (uchar *) (parm + 3);
- return (ulong) (*iprcode);
+ for (i = 0; i < len; i++) {
+ if (!(i % 16) && i != 0)
+ printk ("\n");
+ else if (!(i % 4) && i != 0)
+ printk (" ");
+ printk ("%02X", buf[i]);
+ }
+ if (len % 16)
+ printk ("\n");
+ return;
}
-/**************************************************************/
-/* Name: iucv_retrieve_buffer */
-/* Purpose: terminates all use of iucv */
-/* Input: void */
-/* Output: Return code from CP */
-/**************************************************************/
-int
-iucv_retrieve_buffer (void)
+#else
+static void
+iucv_dumpit (uchar * buf, int len)
{
- iparml_control parm;
- ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_retrieve_buffer\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- b2f0_result = b2f0 (retrieve_buffer, &parm);
- if (b2f0_result == NULL)
- declare_flag = 0;
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_retrieve_buffer\n");
-#endif
- return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_declare_buffer */
-/* Purpose: specifies the guests real address of an external */
-/* interrupt. */
-/* Input: bfr - pointer to buffer */
-/* Output: iprcode - return code from b2f0 call */
-/* Note : See output options for b2f0 call */
-/**************************************************************/
+#endif
+
+/*
+ * Name iucv_add_handler
+ * Purpose: Place new handle on handler_anchor chain, if identical handler is not
+ * found. Handlers are ordered with largest mask integer value first.
+ * Input: new_handler - handle that is being entered into chain
+ * Return: int
+ * 0 - handler added
+ * 1 - identical handler found, handler not added to chain
+*/
int
-iucv_declare_buffer (uchar * bfr)
+iucv_add_handler (handler * new_handler)
{
- iparml_db parm;
- ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "Entering iucv_declare_buffer\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- parm.ipbfadr1 = virt_to_phys (bfr);
- b2f0_result = b2f0 (declare_buffer, &parm);
-#ifdef DEBUG
- printk (KERN_DEBUG "Address of EIB = %p\n", bfr);
- printk (KERN_DEBUG "Exiting iucv_declare_buffer\n");
-#endif
- return b2f0_result;
+ handler *R = new_handler;
+ int rc = 1, comp = 0; /* return code (rc = 1 not added) or (rc = 0 added) */
+ ulong flags;
+ pr_debug ("iucv_add_handler: entering\n");
+ iucv_dumpit ((uchar *) new_handler, sizeof (handler));
+ spin_lock_irqsave (&iucv_lock, flags);
+ if (handler_anchor == NULL) {
+ /* add to beginning of chain */
+ handler_anchor = handler_tail = new_handler;
+ rc = 0;
+ } else
+ for (R = handler_anchor; R != NULL; R = (handler *) R->next) {
+ comp = memcmp ((void *) &(new_handler->id),
+ (void *) &(R->id), sizeof (R->id));
+ pr_debug ("comp = %d\n", comp);
+ if (comp == 0) /* identicle handler found */
+ break; /* break out of for loop */
+ else if (comp > 0) { /* new_handler > R */
+ pr_debug
+ ("iucv_add_handler: Found a place to add,"
+ "R is\n");
+ iucv_dumpit ((uchar *) R, sizeof (handler));
+ if ((R->prev != NULL)) {
+ /* add to middle of chain */
+ pr_debug
+ ("iucv_add_handler: added to middle\n");
+ new_handler->prev = R->prev;
+ new_handler->next = (ulong *) R;
+ ((handler *) (R->prev))->next =
+ (ulong *) new_handler;
+ R->prev = (ulong *) new_handler;
+ rc = 0;
+ break; /* break out of FOR loop */
+ } else { /* R->prev == NULL */
+ /* add to start of chain; */
+ pr_debug ("iucv_add_handler:"
+ "added to beginning\n");
+ R->prev = (ulong *) new_handler;
+ new_handler->next = (ulong *) R;
+ handler_anchor = new_handler;
+ rc = 0;
+ break; /* break out of FOR loop */
+ }
+ } /* end of else if */
+ } /* end of for loop */
+ if (R == NULL) {
+ /* add to end of chain */
+ pr_debug ("iucv_add_handler: added to end\n");
+ handler_tail->next = (ulong *) new_handler;
+ new_handler->prev = (ulong *) handler_tail;
+ handler_tail = new_handler;
+ rc = 0;
+ }
+ spin_unlock_irqrestore (&iucv_lock, flags);
+
+ pr_debug ("Current Chain of handlers is\n");
+ for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+ iucv_dumpit ((uchar *) R, (int) sizeof (handler));
+
+ pr_debug ("iucv_add_handler: exiting\n");
+ return rc;
+}
+
+/*
+ * Name: iucv_remove_handler
+ * Purpose: Remove handler when application unregisters.
+ * Input: users_handler - handler to be removed
+ * Output: void
+*/
+void
+iucv_remove_handler (handler * users_handler)
+{
+ handler *R; /* used for Debugging */
+ pr_debug ("iucv_remove_handler: entering\n");
+ if ((users_handler->next != NULL) & (users_handler->prev != NULL)) {
+ /* remove from middle of chain */
+ ((handler *) (users_handler->next))->prev =
+ (ulong *) users_handler->prev;
+ ((handler *) (users_handler->prev))->next =
+ (ulong *) users_handler->next;
+ } else if ((users_handler->next != NULL) &
+ (users_handler->prev == NULL)) {
+ /* remove from start of chain */
+ ((handler *) (users_handler->next))->prev = NULL;
+ handler_anchor = (handler *) users_handler->next;
+ } else if ((users_handler->next == NULL) &
+ (users_handler->prev != NULL)) {
+ /* remove from end of chain */
+ ((handler *) (users_handler->prev))->next = NULL;
+ handler_tail = (handler *) users_handler->prev;
+ } else {
+ handler_anchor = NULL;
+ handler_tail = NULL;
+ }
+
+ pr_debug ("Current Chain of handlers is\n");
+ for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+ iucv_dumpit ((uchar *) R, (int) sizeof (handler));
+
+ pr_debug ("iucv_remove_handler: exiting\n");
+ return;
+}
+
+/*
+ * Name: b2f0
+ * Purpose: This function calls CP to execute IUCV commands.
+ * Input: code - identifier of IUCV call to CP.
+ * parm - pointer to 40 byte iparml area
+ * passed to CP
+ * Output: iprcode- return code from CP's IUCV call
+ * NOTE: Assembler code performing IUCV call
+*/
+inline ulong
+b2f0 (u32 code, void *parm)
+{
+ uchar *iprcode;
+ pr_debug ("iparml before b2f0 call\n");
+ iucv_dumpit ((uchar *) parm, (int) BUFFER_SIZE);
+ asm volatile ("LRA 1,0(%1)\n\t"
+ "LR 0,%0\n\t"
+ ".long 0xb2f01000"::"d" (code), "a" (parm):"0", "1");
+ pr_debug ("iparml after b2f0 call\n");
+ iucv_dumpit ((uchar *) parm, (int) BUFFER_SIZE);
+ iprcode = (uchar *) (parm + 3);
+ return (ulong) (*iprcode);
}
-/**************************************************************/
-/* Name: add_pathid */
-/* Purpose: adds a path id to the system */
-/* Input: pathid - ushort, pathid to enter system */
-/* handle - iucv_handle_t, address of handler to add to */
-/* pgm_data - ulong, pathid identifier. */
-/* Output: 0: successful addition of pathid */
-/**************************************************************/
+/*
+ * Name: iucv_add_pathid
+ * Purpose: Adds a path id to the system.
+ * Input: pathid - pathid that is going to be entered into system
+ * handle - address of handler that the pathid will be associated
+ * with.
+ * pgm_data - token passed in by application.
+ * Output: 0: successful addition of pathid
+ * - EINVAL - pathid entry is being used by another application
+ * - ENOMEM - storage allocation for a new pathid table failed
+*/
int
-add_pathid (ushort pathid, iucv_handle_t handle, ulong pgm_data)
+iucv_add_pathid (u16 pathid, iucv_handle_t handle, void *pgm_data)
{
- ulong index1, index2; /* index1 into main_table */
ulong add_flag = 0;
ulong old_size = 0, new_size = 0;
+ ulong flags;
uchar *to, *from; /* pointer for copying the table */
- handler_table_entry *P = 0; /*P is a pointer to H_T_E */
- handler *Q = 0; /*Q is a pointer to handler */
- ulong *X = 0; /*Points to array of pointers */
-#ifdef DEBUG
- printk (KERN_DEBUG "entering add_pathid\n");
-#endif
- Q = (handler *) handle; /* Q points to a handler */
- /*
- * main_table has 128 entries.
- * 128*512 = 65536 maximum number of pathid's allowed
- */
- index1 = ((ulong) pathid) / 512;
- index2 = ((ulong) pathid) % 512;
-#ifdef DEBUG
- printk (KERN_DEBUG "index1 = %d\n ", (int) index1);
- printk (KERN_DEBUG "index2 = %d\n ", (int) index2);
- printk (KERN_DEBUG "Q is pointing to %p ", Q);
-#endif
- spin_lock (&lock);
- /*
- * If NULL then handler table does not exist and need to get storage
- * and have main_table[index1] point to it
- * If allocating storage failed, return
- */
- if (main_table[index1] == NULL) {
- main_table[index1] = (handler_table_entry *) kmalloc
- (512 * sizeof (handler_table_entry), GFP_KERNEL);
- if (main_table[index1] == NULL) {
- spin_unlock (&lock);
- return -ENOBUFS;
- }
- memset (main_table[index1], 0,
- 512 * sizeof (handler_table_entry));
-#ifdef DEBUG
- printk (KERN_DEBUG "address of table H_T is %p \n",
- main_table[index1]);
-#endif
- }
+ handler_table_entry *P = 0; /*P is a pointer to the users H_T_E */
+ handler *users_handler = 0;
+ ulong *X = 0; /* Points to array of pointers to H-T_E */
+
+ pr_debug ("iucv_add_pathid: entering\n");
+
+ users_handler = (handler *) handle;
+
+ pr_debug ("iucv_add_pathid: users_handler is pointing to %p ",
+ users_handler);
+
+ spin_lock_irqsave (&iucv_lock, flags);
+
/*
- * P points to a handler table entry (H_T_E) in which all entries in
+ * P points to the users handler table entry (H_T_E) in which all entries in
* that structure should be NULL. If they're not NULL, then there
- * is a bad pointer and it will return(-2) immediately, otherwise
+ * is a bad pointer and it will return(-EINVAL) immediately, otherwise users
* data will be entered into H_T_E.
*/
- P = main_table[index1];
- if ((P + index2)->addrs) {
-#ifdef DEBUG
- printk (KERN_DEBUG "main_table[index1] = %p \n",
- main_table[index1]);
- printk (KERN_DEBUG "P+index2 = %p \n", P + index2);
- printk (KERN_DEBUG "(P+index2)->addrs is %p \n",
- (P + index2)->addrs);
-#endif
- spin_unlock (&lock);
- printk (KERN_DEBUG "bad pointer1\n");
- return (-2);
+
+ P = handler_table_anchor + pathid; /* index into users handler table */
+
+ pr_debug ("handler_table_anchor is %p\n", handler_table_anchor);
+ pr_debug ("P=handler_table_anchor+pathid = %p\n", P);
+
+ if (P->addrs) {
+ pr_debug ("iucv_add_pathid: P = %p \n", P);
+ pr_debug ("iucv_add_pathid: P->addrs is %p \n", P->addrs);
+ spin_unlock_irqrestore (&iucv_lock, flags);
+ /* This message should be sent to syslog */
+ printk (KERN_WARNING "iucv_add_pathid: Pathid being used,"
+ "error.\n");
+ return (-EINVAL);
}
- (P + index2)->addrs = handle;
+
+ P->addrs = handle;
+ P->pathid = pathid;
+
/*
- * checking if address of handle is valid, if it's not valid,
- * unlock the lock and return(-2) immediately.
+ * pgm_data provided in iucv_register may be overwritten on a connect, accept.
*/
- if ((P + index2)->addrs == NULL) {
- spin_unlock (&lock);
- printk (KERN_DEBUG "bad pointer2\n");
- return (-2);
- }
- (P + index2)->pathid = pathid;
+
if (pgm_data)
- (P + index2)->pgm_data = pgm_data;
+ P->pgm_data = pgm_data;
else
- (P + index2)->pgm_data = Q->pgm_data;
+ P->pgm_data = users_handler->pgm_data;
+
+ /*
+ * Address of pathid's iucv_interrupt_ops is taken from the associated handler
+ * and added here for quicker access to the interrupt tables during interrupt
+ * handling.
+ */
+
+ P->ops = (P->addrs)->interrupt_table;
+
+ pr_debug ("Complete users H_T_E is\n");
+ iucv_dumpit ((uchar *) P, sizeof (handler_table_entry));
+
/*
* Step thru the table of addresses of pathid's to find the first
* available entry (NULL). If an entry is found, add the pathid,
* unlock and exit. If an available entry is not found, allocate a
- * new, larger table, copy over the old table and deallocate the
- * old table and add the pathid.
+ * new, larger table, copy over the old table to the new table. De-allocate the
+ * old table and enter the new pathid.
*/
-#ifdef DEBUG
- printk (KERN_DEBUG "address of handle is %p\n", handle);
- printk (KERN_DEBUG "&(Q->start) is %p\n", &(Q->start));
- printk (KERN_DEBUG "&(Q->end) is %p\n", &(Q->end));
- printk (KERN_DEBUG "start of pathid table is %p\n", (Q->start));
- printk (KERN_DEBUG "end of pathid table is %p\n", (Q->end));
- for (X = (Q->start); X < (Q->end); X++)
- printk (KERN_DEBUG "X = %p ", X);
- printk (KERN_DEBUG "\n");
-#endif
- for (X = (Q->start); X < (Q->end); X++) {
+
+ pr_debug ("iucv_add_pathid: address of handle is %p\n", handle);
+ pr_debug ("iucv_add_pathid: &(users_handler->pathid_head) is %p\n",
+ &(users_handler->pathid_head));
+ pr_debug ("iucv_add_pathid: &(users_handler->pathid_tail) is %p\n",
+ &(users_handler->pathid_tail));
+ pr_debug ("iucv_add_pathid: start of pathid table is %p\n",
+ (users_handler->pathid_head));
+ pr_debug ("iucv_add_pathid: end of pathid table is %p\n",
+ (users_handler->pathid_tail));
+ iucv_dumpit ((uchar *) users_handler->pathid_head,
+ (int) (users_handler->pathid_tail -
+ users_handler->pathid_head));
+
+ for (X = (users_handler->pathid_head);
+ X <
+ (users_handler->pathid_head +
+ users_handler->entries * sizeof (ulong)); X++)
if (*X == NULL) {
-#ifdef DEBUG
- printk (KERN_DEBUG "adding pathid, %p = P+index2\n",
- (P + index2));
-#endif
- *X = (ulong) (P + index2);
+ pr_debug ("adding pathid, %p = P\n", P);
+ *X = (ulong) P;
add_flag = 1;
+ break; /* breaks out of for loop */
}
- if (add_flag == 1)
- break;
- }
- if (add_flag == 0) { /* element not added to list */
- X = Q->start;
- old_size = Q->size;
- new_size = old_size + ADDED_STOR; /* size of new table */
- from = (uchar *) (Q->start); /* address of old table */
- (*Q).start = kmalloc (new_size * sizeof (ulong), GFP_KERNEL);
- if ((Q->start) == NULL) {
- spin_unlock (&lock);
- return -ENOBUFS;
+
+ pr_debug ("Addresses of HTE's are\n");
+ iucv_dumpit ((uchar *) users_handler->pathid_head,
+ users_handler->entries * sizeof (ulong));
+
+ if (add_flag == 0) { /* element not added to list: must get a new table */
+ X = users_handler->pathid_head;
+ old_size = users_handler->entries;
+ new_size = old_size + ADDED_STOR; /*number of entries of new table */
+ from = (uchar *) (users_handler->pathid_head); /*address of old table */
+ users_handler->pathid_head =
+ kmalloc (new_size * sizeof (ulong), GFP_ATOMIC);
+
+ if (users_handler->pathid_head == NULL) {
+ users_handler->pathid_head = X; /*setting old condition */
+ spin_unlock_irqrestore (&iucv_lock, flags);
+ printk (KERN_WARNING
+ "iucv_add_pathid: storage allocation"
+ "failed for new pathid table \n ");
+ memset (P, 0, sizeof (handler_table_entry));
+ return -ENOMEM;
}
- memset ((*Q).start, 0, new_size * sizeof (ulong));
- to = (uchar *) (Q->start); /* address of new table */
+
+ memset (users_handler->pathid_head, 0,
+ new_size * sizeof (ulong));
+ to = (uchar *) (users_handler->pathid_head); /* address of new table */
/* copy old table to new */
memcpy (to, from, old_size * (sizeof (ulong)));
-#ifdef DEBUG
- printk (KERN_DEBUG "Getting a new pathid table\n");
- printk (KERN_DEBUG "to is %p \n", to);
- printk (KERN_DEBUG "from is %p \n", from);
-#endif
- Q->size = new_size; /* storing new size of table */
- Q->end = (Q->start) + (Q->size);
- X = Q->start + old_size; /* next blank in table */
- *X = (ulong) (P + index2); /* adding element to new table */
-#ifdef DEBUG
- printk (KERN_DEBUG "Q->size is %u \n", (int) (Q->size));
- printk (KERN_DEBUG "Q->end is %p \n", Q->end);
- printk (KERN_DEBUG "Q->start is %p \n", Q->start);
- printk (KERN_DEBUG "X is %p \n", X);
- printk (KERN_DEBUG "*X is %u \n", (int) (*X));
-#endif
+
+ pr_debug ("iucv: add_pathid: Getting a new pathid table\n");
+ pr_debug ("iucv: add_pathid: to is %p \n", to);
+ pr_debug ("iucv: add_pathid: from is %p \n", from);
+
+ users_handler->entries = new_size; /* storing new size of table */
+ users_handler->pathid_tail =
+ (users_handler->pathid_head) + (users_handler->entries);
+ X = users_handler->pathid_head + old_size;
+ *X = (ulong) P; /* adding element to new table */
+
+ pr_debug ("iucv: add_pathid: users_handler->entries is %u \n",
+ (int) (users_handler->entries));
+ pr_debug
+ ("iucv: add_pathid: users_handler->pathid_tail is %p\n",
+ users_handler->pathid_tail);
+ pr_debug ("users_handler->pathid_head is %p \n",
+ users_handler->pathid_head);
+ pr_debug ("iucv: add_pathid: X is %p \n", X);
+ pr_debug ("iucv: add_pathid: *X is %u \n", (int) (*X));
+ pr_debug ("Addresses of HTE's after getting new table is\n");
+ iucv_dumpit ((uchar *) users_handler->pathid_head,
+ users_handler->entries * sizeof (ulong));
+ pr_debug ("New handler is\n");
+ iucv_dumpit ((uchar *) users_handler, sizeof (handler));
+
kfree (from); /* free old table */
}
- spin_unlock (&lock);
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting add_pathid\n");
-#endif
+ spin_unlock_irqrestore (&iucv_lock, flags);
+ pr_debug ("iucv_dd_pathid: exiting\n");
return (0);
} /* end of add_pathid function */
-/***********************EXTERNAL FUNCTIONS***************************/
-/**************************************************************/
-/* Name: iucv_query */
-/* Purpose: determines how large an external interrupt buffer */
-/* IUCV requires to store information */
-/* Input : bufsize - ulong: size of interrupt buffer */
-/* - filled in by function and returned to caller */
-/* conmax - ulong: maximum number of connections that */
-/* can be outstanding for this VM */
-/* - filled in by function and returned to caller */
-/* Output: void */
-/**************************************************************/
-void
-iucv_query (ulong * bufsize, ulong * conmax)
-{
- iparml_purge parm; /* DOESN'T MATTER WHICH IPARML IS USED */
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_purge\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- /*
- * Assembler instruction calling b2f0 and storing R0 and R1
- */
- asm volatile ("LRA 1,0(%3)\n\t"
- "LR 0,%2\n\t"
- ".long 0xb2f01000\n\t"
- "ST 0,%0\n\t"
- "ST 1,%1\n\t":"=m" (*bufsize),
- "=m" (*conmax):"d" (query), "a" (&parm):"0", "1");
- return;
-}
-
-/**************************************************************/
-/* Name: iucv_purge */
-/* Purpose: cancels a message you have sent */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong, mid of message */
-/* srccls - ulong, sourse message class */
-/* audit - uchar[4], info about ansync. error condit. */
-/* filled in by function and passed back */
-/* Output: void */
-/* NOTE: pathid is required, flag is always turned on */
-/**************************************************************/
+/*
+ * Name: iucv_declare_buffer
+ * Purpose: Specifies the guests real address of an external
+ * interrupt.
+ * Input: void
+ * Output: iprcode - return code from b2f0 call
+*/
int
-iucv_purge (ulong msgid, ushort pathid, ulong srccls, uchar audit[4])
+iucv_declare_buffer (void)
{
- iparml_purge parm;
+ iparml_db parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_purge\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- parm.ipmsgid = msgid;
- parm.ippathid = pathid;
- parm.ipsrccls = srccls;
- parm.ipflags1 |= specify_pathid; /* pathid id flag */
- if (parm.ipmsgid)
- parm.ipflags1 |= specify_msgid;
- if (parm.ipsrccls)
- parm.ipflags1 |= source_class;
- b2f0_result = b2f0 (purge, &parm);
- if (b2f0_result != NULL)
- return b2f0_result;
- memcpy (audit, parm.ipaudit, 4);
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_purge\n");
-#endif
+ pr_debug ("iucv_declare_buffer: entering\n");
+ memset (&parm, 0, sizeof (parm));
+ parm.ipbfadr1 = virt_to_phys ((uchar *) iucv_external_int_buffer);
+ b2f0_result = b2f0 (DECLARE_BUFFER, &parm);
+ pr_debug ("iucv_declare_buffer: Address of EIB = %p\n",
+ iucv_external_int_buffer);
+ pr_debug ("iucv_declare_buffer: exiting\n");
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_quiesce */
-/* Purpose: temporarily suspends incoming messages */
-/* Input: pathid - ushort, pathid */
-/* user_data - uchar[16], user id */
-/* Output: iprcode - return code from b2f0 call */
-/* NOTE: see b2f0 output list */
-/**************************************************************/
+/*
+ * Name: iucv_retrieve_buffer
+ * Purpose: Terminates all use of IUCV.
+ * Input: void
+ * Output:
+ * b2f0_result: return code from CP
+*/
int
-iucv_quiesce (ushort pathid, uchar user_data[16])
+iucv_retrieve_buffer (void)
{
iparml_control parm;
- ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_quiesce\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- memcpy (parm.ipuser, user_data, 16);
- parm.ippathid = pathid;
- b2f0_result = b2f0 (quiesc, &parm);
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_quiesce\n");
-#endif
+ ulong b2f0_result = 0;
+ pr_debug ("iucv_retrieve_buffer: entering\n");
+ memset (&parm, 0, sizeof (parm));
+ b2f0_result = b2f0 (RETRIEVE_BUFFER, &parm);
+ if (b2f0_result == NULL) {
+ kfree (handler_table_anchor);
+ handler_table_anchor = NULL;
+ declare_flag = 0;
+ }
+ pr_debug ("iucv_retrieve_buffer: exiting\n");
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_resume */
-/* Purpose: restores communication over a quiesced path */
-/* Input: pathid - ushort, pathid */
-/* user_data - uchar[16], user id */
-/* Output: iprcode - return code from b2f0 call */
-/* NOTE: see b2f0 output list */
-/**************************************************************/
-int
-iucv_resume (ushort pathid, uchar user_data[16])
-{
- iparml_control parm;
- ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_resume\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- memcpy (parm.ipuser, user_data, 16);
- parm.ippathid = pathid;
- b2f0_result = b2f0 (resume, &parm);
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_resume\n");
-#endif
- return b2f0_result;
-}
+/*
+ * Name: iucv_register_program
+ * Purpose: Registers an application with IUCV.
+ * Input: prmname - user identification
+ * userid - machine identification
+ * pgmmask - indicates which bits in the prmname and userid combined will be used
+ * to determine who is given control
+ * ops - address of vector of interrupt handlers
+ * pgm_data- application data passed to interrupt handlers
+ * Output: NA
+ * Return: type: iucv_handle_t
+ * address of handler
+ * (0) - registration failed
+ * - Machine size > 2GB
+ * - new_handler kmalloc failed
+ * - pgmname was not provided
+ * - pathid_table kmalloc failed
+ * - application with identical pgmname, userid, and pgmmask is registered
+ * - iucv_declare_buffer failed
+ * NOTE: pgmmask
+ * When pgmname, userid, pgmmask is provided, mask is entered into the handler
+ * as is.
+ * When pgmname, userid is provided, pgmmask is all 0xff's
+ * When pgmname, pgmmask is provided, the first 8 bytes = 0x00 and the last 16
+ * bytes are as provided by pgmmask.
+ * When pgmname is provided is provided, the first 8 bytes = 0x00 and the last
+ * 16 bytes are 0xff.
+*/
-/**************************************************************/
-/* Name: iucv_reject */
-/* Purpose: rejects a message */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong, mid of message */
-/* trgcls - ulong, target message class */
-/* Output: iprcode - return code from b2f0 call */
-/* NOTE: pathid is required field, flag always turned on */
-/* RESTRICTION: target class cannot be zero */
-/* NOTE: see b2f0 output list */
-/**************************************************************/
-int
-iucv_reject (ushort pathid, ulong msgid, ulong trgcls)
+iucv_handle_t
+iucv_register_program (uchar pgmname[16],
+ uchar userid[8],
+ uchar pgmmask[24],
+ iucv_interrupt_ops_t * ops, void *pgm_data)
{
- iparml_db parm;
- ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_reject\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- parm.ipmsgid = msgid;
- parm.ippathid = pathid;
- parm.iptrgcls = trgcls;
- parm.ipflags1 |= specify_pathid; /* flag for pathid */
- if (parm.ipmsgid)
- parm.ipflags1 |= specify_msgid;
- if (parm.iptrgcls)
- parm.ipflags1 |= target_class;
- b2f0_result = b2f0 (reject, &parm);
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_reject\n");
-#endif
- return b2f0_result;
-}
+ ulong rc = 0; /* return code from function calls */
+ ulong machine_size = 0; /* size of virtual machine */
+ static u32 maxconn1;
+ handler *new_handler = NULL;
-/**************************************************************/
-/* Name: iucv_setmask */
-/* Purpose: enables or disables certain iucv external interr. */
-/* Input: non_priority_interrupts - uchar */
-/* priority_interrupts - uchar */
-/* non_priority_completion_interrupts - uchar */
-/* priority_completion_interrupts) - uchar */
-/* Output: iprcode - return code from b2f0 call */
-/* NOTE: see b2f0 output list */
-/**************************************************************/
-int
-iucv_setmask (uchar non_priority_interrupts,
- uchar priority_interrupts,
- uchar non_priority_completion_interrupts,
- uchar priority_completion_interrupts)
-{
- iparml_set_mask parm;
- ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_setmask\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- if (non_priority_interrupts)
- parm.ipmask |= 0x80;
- if (priority_interrupts)
- parm.ipmask |= 0x40;
- if (non_priority_completion_interrupts)
- parm.ipmask |= 0x20;
- if (priority_completion_interrupts)
- parm.ipmask |= 0x10;
- b2f0_result = b2f0 (setmask, &parm);
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_setmask\n");
-#endif
- return b2f0_result;
-}
+ pr_debug ("iucv_register_program:entering\n");
-/**************************************************************/
-/* Name: iucv_sever */
-/* Purpose: terminates an iucv path to another machine */
-/* Input: pathid - ushort, pathid */
-/* user_data - uchar[16], user id */
-/* Output: iprcode - return code from b2f0 call */
-/* NOTE: see b2f0 output list */
-/**************************************************************/
-int
-iucv_sever (ushort pathid, uchar user_data[16])
-{
- ulong index1, index2;
- ulong b2f0_result;
- handler_table_entry *P = 0;
- handler *Q = 0;
- ulong *X;
- iparml_control parm;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_sever\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- memcpy (parm.ipuser, user_data, 16);
- parm.ippathid = pathid;
- b2f0_result = b2f0 (sever, &parm);
- if (b2f0_result)
- return b2f0_result;
- index1 = ((ulong) pathid) / 512;
- index2 = ((ulong) pathid) % 512;
- spin_lock (&lock);
- P = main_table[index1];
- if (((P + index2)->addrs) == NULL) { /* called from interrupt code */
- spin_unlock (&lock);
- return (-2); /* bad pointer */
+ if (ops == NULL) {
+ /* interrupt table is not defined */
+ printk (KERN_WARNING "iucv_register_program:"
+ "Interrupt table is not defined, exiting\n");
+ return NULL;
}
- Q = (*(P + index2)).addrs;
-#ifdef DEBUG
- printk (KERN_DEBUG "pathid is %d\n", pathid);
- printk (KERN_DEBUG "index1 is %d\n", (int) index1);
- printk (KERN_DEBUG "index2 is %d\n", (int) index2);
- printk (KERN_DEBUG "H_T_E is %p\n", P);
- printk (KERN_DEBUG "address of handler is %p\n", Q);
- for (X = ((*Q).start); X < ((*Q).end); X++)
- printk (KERN_DEBUG " %x ", (int) (*X));
- printk (KERN_DEBUG "\n above is pathid table\n");
-#endif
-/********************************************************************/
-/* Searching the pathid address table for matching address, once */
-/* found, NULL the field. Then Null the H_T_E fields. */
-/********************************************************************/
- for (X = ((*Q).start); X < ((*Q).end); X++)
- if (*X == (ulong) (P + index2)) {
-#ifdef DEBUG
- printk (KERN_DEBUG "found a path to sever\n");
- printk (KERN_DEBUG "severing %d \n", (int) (*X));
-#endif
- *X = NULL;
- (*(P + index2)).addrs = NULL; /*clearing the fields */
- (*(P + index2)).pathid = 0;
- (*(P + index2)).pgm_data = 0;
+
+ if (declare_flag == 0) {
+ /* check size of virtual machine */
+ if ((machine_size = iucv_vmsize ()) > 0x100000000) { /* 2GB */
+ printk (KERN_WARNING "iucv_register_progam: Virtual"
+ "storage = %lx hex," "exiting\n", machine_size);
+ return NULL;
}
- spin_unlock (&lock);
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_sever\n");
-#endif
- return b2f0_result;
+
+ pr_debug ("machine_size is %lx\n", machine_size);
+
+ maxconn1 = iucv_query_maxconn ();
+ handler_table_anchor = kmalloc (maxconn1 * sizeof
+ (handler_table_entry),
+ GFP_KERNEL);
+
+ if (handler_table_anchor == NULL) {
+ printk (KERN_WARNING "iucv_register_program:"
+ "handler_table_anchor"
+ "storage allocation failed\n");
+ return NULL;
+ }
+
+ memset (handler_table_anchor, 0,
+ maxconn1 * sizeof (handler_table_entry));
+
+ }
+ /* Allocate handler table */
+ new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL);
+ if (new_handler == NULL) {
+ printk (KERN_WARNING "iucv_register_program: storage allocation"
+ "for new handler failed. \n ");
+ return NULL;
+ }
+ memset (new_handler, 0, sizeof (handler));
+ if (pgmname) {
+ memcpy (new_handler->id.user_data, pgmname,
+ sizeof (new_handler->id.user_data));
+ if (userid) {
+ memcpy (new_handler->id.userid, userid,
+ sizeof (new_handler->id.userid));
+ ASCEBC (new_handler->id.userid,
+ sizeof (new_handler->id.userid));
+ EBC_TOUPPER (new_handler->id.userid,
+ sizeof (new_handler->id.userid));
+
+ if (pgmmask) {
+ memcpy (new_handler->id.mask, pgmmask,
+ sizeof (new_handler->id.mask));
+ } else {
+ memset (new_handler->id.mask, 0xFF,
+ sizeof (new_handler->id.mask));
+ }
+ } else {
+ if (pgmmask) {
+ memcpy (new_handler->id.mask, pgmmask,
+ sizeof (new_handler->id.mask));
+ } else {
+ memset (new_handler->id.mask, 0xFF,
+ sizeof (new_handler->id.mask));
+ }
+ memset (new_handler->id.mask, 0x00,
+ sizeof (new_handler->id.userid));
+ }
+ } else {
+ kfree (new_handler);
+ printk (KERN_WARNING "iucv_register_program: pgmname not"
+ "provided\n");
+ return NULL;
+ }
+ /* fill in the rest of handler */
+ new_handler->pgm_data = pgm_data;
+ new_handler->interrupt_table = ops;
+ new_handler->entries = ADDED_STOR;
+ /* Allocate storage for pathid table */
+ new_handler->pathid_head =
+ kmalloc (new_handler->entries * sizeof (ulong), GFP_KERNEL);
+ if (new_handler->pathid_head == NULL) {
+ printk (KERN_WARNING "iucv_register_program: storage allocation"
+ "failed\n");
+ kfree (new_handler);
+ return NULL;
+ }
+
+ memset (new_handler->pathid_head, 0,
+ new_handler->entries * sizeof (ulong));
+ new_handler->pathid_tail =
+ new_handler->pathid_head + new_handler->entries;
+ /*
+ * Check if someone else is registered with same pgmname, userid, and mask.
+ * If someone is already registered with same pgmname, userid, and mask
+ * registration will fail and NULL will be returned to the application.
+ * If identical handler not found, then handler is added to list.
+ */
+ rc = iucv_add_handler (new_handler);
+ if (rc) {
+ printk (KERN_WARNING "iucv_register_program: Someone already"
+ "registered with same pgmname, userid, pgmmask\n");
+ kfree (new_handler->pathid_head);
+ kfree (new_handler);
+ return NULL;
+ }
+
+ if (declare_flag == 0) {
+ rc = iucv_declare_buffer ();
+ if (rc) {
+ kfree (handler_table_anchor);
+ kfree (new_handler->pathid_head);
+ kfree (new_handler);
+ handler_table_anchor = NULL;
+ printk (KERN_WARNING "iucv_register_program: rc from"
+ "iucv_declare_buffer is:% ld \n ", rc);
+ return NULL;
+ }
+ /* request the 0x4000 external interrupt */
+ rc = register_external_interrupt (0x4000, top_half_interrupt);
+ if (rc) {
+ iucv_retrieve_buffer ();
+ kfree (new_handler->pathid_head);
+ kfree (new_handler);
+ printk (KERN_WARNING "iucv_register_program: rc from"
+ "register_external_interrupt is:% ld \n ", rc);
+ return NULL;
+
+ }
+ declare_flag = 1;
+ }
+ pr_debug ("iucv_register_program: exiting\n");
+ return new_handler;
+} /* end of register function */
+
+/*
+ * Name: iucv_unregister_program
+ * Purpose: Unregister application with IUCV.
+ * Input: handle address of handler
+ * Output: NA
+ * Return: (0) - Normal return
+ * (-EINVAL)- Matching handler was not found
+*/
+
+int
+iucv_unregister_program (iucv_handle_t handle)
+{
+ handler *users_handler = 0, *R;
+ handler_table_entry *H_T_E = 0;
+ ulong *S = 0; /*points to the beginning of block of h_t_e's */
+ ulong flags;
+ u16 pathid_sever = 0;
+ pr_debug ("iucv_unregister_program: entering\n");
+ pr_debug ("iucv_unregister_program: address of handle is %p\n", handle);
+ spin_lock_irqsave (&iucv_lock, flags);
+ users_handler = (handler *) handle;
+ /*
+ * Checking if handle is still registered: if yes, continue
+ * if not registered, return.
+ */
+ for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+ if (users_handler == R) {
+ pr_debug ("iucv_unregister_program: found a matching"
+ "handler\n");
+ break;
+ }
+ if (!R) {
+ pr_debug ("You are not registered\n");
+ spin_unlock_irqrestore (&iucv_lock, flags);
+ return (0);
+ }
+ S = users_handler->pathid_head;
+ while (S < (users_handler->pathid_tail)) { /* index thru table */
+ if (*S) {
+ H_T_E = (handler_table_entry *) (*S);
+
+ pr_debug ("iucv_unregister_program: pointer to H_T_E is"
+ "%p\n", H_T_E);
+ pr_debug
+ ("iucv_unregister_program: address of handle in"
+ "H_T_E is %p", (H_T_E->addrs));
+ pathid_sever = H_T_E->pathid;
+ spin_unlock_irqrestore (&iucv_lock, flags);
+ iucv_sever (pathid_sever, users_handler->id.user_data);
+ spin_lock_irqsave (&iucv_lock, flags);
+ }
+
+ S++; /* index by address */
+ }
+
+ kfree (users_handler->pathid_head);
+ iucv_remove_handler (users_handler);
+ spin_unlock_irqrestore (&iucv_lock, flags);
+ kfree (handle);
+ pr_debug ("iucv_unregister_program: exiting\n");
+ return 0;
}
-/**************************************************************/
-/* Name: iucv_receive */
-/* Purpose: receives incoming message */
-/* Input: pathid - ushort, pathid */
-/* msgid - *ulong, mid of message */
-/* trgcls - *ulong, target message class */
-/* buffer - pointer of buffer */
-/* buflen - length of buffer */
-/* adds_curr_buffer - pointer to updated buffer address*/
-/* to write to */
-/* adds_curr_length - pointer to updated length in */
-/* buffer available to write to */
-/* reply_required - uchar *, flag */
-/* priority_msg - uchar *, flag */
-/* Output: iprcode - return code from b2f0 call */
-/* NOTE: pathid must be specified, flag being turned on */
-/* RESTRICTIONS: target class CANNOT be zero because the code */
-/* checks for a non-NULL value to turn flag on, therefore if */
-/* target class = zero, flag will not be turned on. */
-/**************************************************************/
+/*
+ * Name: iucv_accept
+ * Purpose: This function is issued after the user receives a Connection Pending external
+ * interrupt and now wishes to complete the IUCV communication path.
+ * Input: pathid - u16 , path identification number
+ * msglim_reqstd - u16, The number of outstanding messages requested.
+ * user_data - uchar[16], Data specified by the iucv_connect function.
+ * flags1 - int, Contains options for this path.
+ * -IPPRTY - 0x20- Specifies if you want to send priority message.
+ * -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ * in the parameter list.
+ * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
+ * established.
+ * handle - iucv_handle_t, Address of handler.
+ * pgm_data - ulong, Application data passed to interrupt handlers.
+ * flags1_out - int *, Options for path.
+ * IPPRTY - 0x20 - Indicates you may send a priority message.
+ * priority_permitted -uchar *, Indicates you may send priority messages.
+ * msglim - *u16, Number of outstanding messages.
+ * Output: b2f0_result - return code from CP
+*/
int
-iucv_receive (ushort pathid, ulong * msgid, ulong * trgcls,
- void *buffer, ulong buflen,
- uchar * reply_required,
- uchar * priority_msg,
- ulong * adds_curr_buffer, ulong * adds_curr_length)
+iucv_accept (u16 pathid, u16 msglim_reqstd,
+ uchar user_data[16], int flags1,
+ iucv_handle_t handle, void *pgm_data,
+ int *flags1_out, u16 * msglim)
{
- iparml_db parm;
- ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_receive\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- parm.ipmsgid = *msgid;
+ iparml_control parm;
+ ulong b2f0_result = 0;
+ ulong flags;
+ handler *R = NULL;
+ pr_debug ("iucv_accept: entering \n");
+ pr_debug ("iucv_accept: pathid = %d\n", pathid);
+
+ /* Checking if handle is valid */
+ spin_lock_irqsave (&iucv_lock, flags);
+
+ for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+ if (R == handle)
+ break;
+
+ spin_unlock_irqrestore (&iucv_lock, flags);
+ if (R == NULL) {
+ printk (KERN_WARNING "iucv_connect: NULL handle passed by"
+ "application\n");
+ return -EINVAL;
+ }
+
+ memset (&parm, 0, sizeof (parm));
parm.ippathid = pathid;
- parm.iptrgcls = *trgcls;
- parm.ipflags1 |= specify_pathid; /* turning pathid flag */
- if (parm.ipmsgid)
- parm.ipflags1 |= 0x05;
- if (parm.iptrgcls)
- parm.ipflags1 |= target_class;
- parm.ipbfadr1 = (ulong) buffer;
- parm.ipbfln1f = buflen;
- b2f0_result = b2f0 (receive, &parm);
+ parm.ipmsglim = msglim_reqstd;
+ if (user_data)
+ memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
+ parm.ipflags1 = (uchar) flags1;
+ b2f0_result = b2f0 (ACCEPT, &parm);
+
+ if (b2f0_result == 0) {
+ if (pgm_data)
+ (handler_table_anchor + pathid)->pgm_data = pgm_data;
+ if (parm.ipflags1 & IPPRTY)
+ if (flags1_out) {
+ pr_debug ("*flags1_out = %d\n", *flags1_out);
+ *flags1_out = 0;
+ *flags1_out |= IPPRTY;
+ pr_debug (" *flags1_out = %d\n", *flags1_out);
+ }
+ }
+
+ pr_debug ("iucv_accept: exiting\n");
+ return b2f0_result;
+}
+
+/*
+ * Name: iucv_connect
+ * Purpose: This function establishes an IUCV path. Although the connect may complete
+ * successfully, you are not able to use the path until you receive an IUCV
+ * Connection Complete external interrupt.
+ * Input: pathid - u16 *, path identification number
+ * msglim_reqstd - u16, number of outstanding messages requested
+ * user_data - uchar[16], 16-byte user data
+ * userid - uchar[8], 8-byte of user identification
+ * system_name - uchar[8], 8-byte identifying the system name
+ * flags1 - int, Contains options for this path.
+ * -IPPRTY - 0x20- Specifies if you want to send priority message.
+ * -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ * in the parameter list.
+ * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
+ * established.
+ * -IPLOCAL - 0X01, allows an application to force the partner to be on the
+ * local system. If local is specified then target class cannot be
+ * specified.
+ * flags1_out - int *, Options for path.
+ * IPPRTY - 0x20 - Indicates you may send a priority message.
+ * msglim - * u16, number of outstanding messages
+ * handle - iucv_handle_t, address of handler
+ * pgm_data - *void, application data passed to interrupt handlers
+ * Output: b2f0_result - return code from CP
+ * -ENOMEM
+ * rc - return code from iucv_declare_buffer
+ * -EINVAL - invalid handle passed by application
+ * -EINVAL - pathid address is NULL
+ * -ENOMEM - pathid table storage allocation failed
+ * add_pathid_result - return code from internal function add_pathid
+*/
+int
+iucv_connect (u16 * pathid, u16 msglim_reqstd,
+ uchar user_data[16], uchar userid[8],
+ uchar system_name[8], int flags1,
+ int *flags1_out, u16 * msglim,
+ iucv_handle_t handle, void *pgm_data)
+{
+ iparml_control parm;
+ ulong b2f0_result = 0;
+ ulong flags;
+ int add_pathid_result = 0;
+ handler *R = NULL;
+ uchar no_memory[16] = "NO MEMORY";
+
+ pr_debug ("iucv_connect: entering \n");
+
+ /* Checking if handle is valid */
+ spin_lock_irqsave (&iucv_lock, flags);
+
+ for (R = handler_anchor; R != NULL; R = (handler *) R->next)
+ if (R == handle)
+ break;
+
+ spin_unlock_irqrestore (&iucv_lock, flags);
+
+ if (R == NULL) {
+ printk (KERN_WARNING "iucv_connect: NULL handle passed by"
+ "application\n");
+ return -EINVAL;
+ }
+
+ if (pathid == NULL) {
+ printk (KERN_WARNING "iucv_connect: NULL pathid pointer\n");
+ return -EINVAL;
+ }
+ memset (&parm, 0, sizeof (iparml_control));
+ parm.ipmsglim = msglim_reqstd;
+
+ if (user_data)
+ memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
+
+ if (userid) {
+ memcpy (parm.ipvmid, userid, sizeof (parm.ipvmid));
+ ASCEBC (parm.ipvmid, sizeof (parm.ipvmid));
+ EBC_TOUPPER (parm.ipvmid, sizeof (parm.ipvmid));
+ }
+
+ if (system_name) {
+ memcpy (parm.iptarget, system_name, sizeof (parm.iptarget));
+ ASCEBC (parm.iptarget, sizeof (parm.iptarget));
+ EBC_TOUPPER (parm.iptarget, sizeof (parm.iptarget));
+ }
+
+ parm.ipflags1 = (uchar) flags1;
+ b2f0_result = b2f0 (CONNECT, &parm);
if (b2f0_result)
return b2f0_result;
- if (msgid)
- *msgid = parm.ipmsgid;
- if (trgcls)
- *trgcls = parm.iptrgcls;
- if (parm.ipflags1 & prior_msg)
- if (priority_msg)
- *priority_msg = 0x01; /*yes, priority msg */
- if (!(parm.ipflags1 & 0x10)) /*& with X'10' */
- if (reply_required)
- *reply_required = 0x01; /*yes, reply required */
- if (!(parm.ipflags1 & parm_data)) { /*msg not in parmlist */
- if (adds_curr_length)
- *adds_curr_length = parm.ipbfln1f;
- if (adds_curr_buffer)
- *adds_curr_buffer = parm.ipbfadr1;
- } else {
- if ((buflen) >= 8) {
- if (buffer)
- memcpy ((char *) buffer,
- (char *) parm.ipbfadr1, 8);
- if (adds_curr_length)
- *adds_curr_length = ((buflen) - 8);
- if (adds_curr_buffer)
- *adds_curr_buffer = (ulong) buffer + 8;
- } else {
- parm.iprcode |= 0x05;
- b2f0_result = (ulong) parm.iprcode;
- }
+
+ add_pathid_result = iucv_add_pathid (parm.ippathid, handle, pgm_data);
+ if (add_pathid_result) {
+
+ iucv_sever (parm.ippathid, no_memory);
+ printk (KERN_WARNING "iucv_connect: add_pathid failed with rc ="
+ "%d\n", add_pathid_result);
+ return (add_pathid_result);
}
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_receive\n");
-#endif
+
+ *pathid = parm.ippathid;
+
+ if (msglim)
+ *msglim = parm.ipmsglim;
+
+ if (parm.ipflags1 & IPPRTY)
+ if (flags1_out) {
+ *flags1_out = 0;
+ *flags1_out |= IPPRTY;
+ }
+
+ pr_debug ("iucv_connect: exiting\n");
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_receive_simple */
-/* Purpose: receives fully-qualified message */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong, id of message */
-/* trgcls - ulong, target message class */
-/* buffer - pointer of buffer */
-/* buflen - length of buffer */
-/* Output: iprcode - return code from b2f0 call */
-/**************************************************************/
+/*
+ * Name: iucv_purge
+ * Purpose: Cancels a message you have sent.
+ * Input: pathid - address of pathid
+ * msgid - address of message identification
+ * srccls - address of source message class
+ * audit - contains information about
+ * asynchronous error that may have affected
+ * the normal completion of this message.
+ * Output:b2f0_result - return code from CP
+*/
int
-iucv_receive_simple (ushort pathid, ulong msgid, ulong trgcls,
- void *buffer, ulong buflen)
+iucv_purge (u16 pathid, u32 msgid, u32 srccls, uchar audit[3])
+{
+ iparml_purge parm;
+ ulong b2f0_result = 0;
+ pr_debug ("iucv_purge: entering\n");
+ pr_debug ("iucv_purge: pathid = %d \n", pathid);
+ memset (&parm, 0, sizeof (parm));
+ parm.ipmsgid = msgid;
+ parm.ippathid = pathid;
+ parm.ipsrccls = srccls;
+ parm.ipflags1 |= (IPSRCCLS | IPFGMID | IPFGPID);
+ b2f0_result = b2f0 (PURGE, &parm);
+
+ if ((b2f0_result == 0) && (audit))
+ memcpy (audit, parm.ipaudit, sizeof (parm.ipaudit));
+
+ pr_debug ("iucv_purge: b2f0_result = %ld \n", b2f0_result);
+ pr_debug ("iucv_purge: exiting\n");
+ return b2f0_result;
+}
+
+/*
+ * Name: iucv_query_maxconn
+ * Purpose: Determines the maximum number of connections thay may be established.
+ * Output: maxconn - ulong: Maximum number of connections that can be.
+*/
+ulong
+iucv_query_maxconn (void)
+{
+ iparml_purge parm; /* DOESN'T MATTER WHICH IPARML IS USED */
+ static u32 maxconn1, bufsize1;
+
+ pr_debug ("iucv_query_maxconn: entering\n");
+
+ memset (&parm, 0, sizeof (parm));
+
+ /* Assembler instruction calling b2f0 and storing R0 and R1 */
+ asm volatile ("LRA 1,0(%3)\n\t"
+ "LR 0,%2\n\t"
+ ".long 0xb2f01000\n\t"
+ "ST 0,%0\n\t"
+ "ST 1,%1\n\t":"=m" (bufsize1),
+ "=m" (maxconn1):"d" (QUERY), "a" (&parm):"0", "1");
+
+ pr_debug (" bufsize1 = %d and maxconn1 = %d \n", bufsize1, maxconn1);
+ pr_debug ("iucv_query_maxconn: exiting\n");
+
+ return maxconn1;
+}
+
+/*
+ * Name: iucv_query_bufsize
+ * Purpose: Determines the size of the external interrupt buffer.
+ * Output: bufsize - ulong: Size of external interrupt buffer.
+ */
+ulong
+iucv_query_bufsize (void)
+{
+ iparml_purge parm; /* DOESN'T MATTER WHICH IPARML IS USED */
+ static u32 maxconn1, bufsize1;
+
+ pr_debug ("iucv_query_bufsize: entering\n");
+ pr_debug ("iucv_query_maxconn: entering\n");
+
+ memset (&parm, 0, sizeof (parm));
+
+ /* Assembler instruction calling b2f0 and storing R0 and R1 */
+ asm volatile ("LRA 1,0(%3)\n\t"
+ "LR 0,%2\n\t"
+ ".long 0xb2f01000\n\t"
+ "ST 0,%0\n\t"
+ "ST 1,%1\n\t":"=m" (bufsize1),
+ "=m" (maxconn1):"d" (QUERY), "a" (&parm):"0", "1");
+
+ pr_debug (" bufsize1 = %d and maxconn1 = %d \n", bufsize1, maxconn1);
+ pr_debug ("iucv_query_bufsize: exiting\n");
+
+ return bufsize1;
+}
+
+/*
+ * Name: iucv_quiesce
+ * Purpose: temporarily suspends incoming messages on an IUCV path.
+ * You can later reactivate the path by invoking the iucv_resume function
+ * Input: pathid - u16, path identification number
+ * user_data - uchar[16], 16-byte user data
+ * Output: b2f0_result - return code from CP
+ */
+int
+iucv_quiesce (u16 pathid, uchar user_data[16])
+{
+ iparml_control parm;
+ ulong b2f0_result = 0;
+
+ pr_debug ("iucv_quiesce: entering \n");
+ pr_debug ("iucv_quiesce: pathid = %d\n", pathid);
+
+ memset (&parm, 0, sizeof (parm));
+ memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
+ parm.ippathid = pathid;
+
+ b2f0_result = b2f0 (QUIESCE, &parm);
+
+ pr_debug ("iucv_quiesce: b2f0_result = %ld\n", b2f0_result);
+ pr_debug ("iucv_quiesce: exiting\n");
+
+ return b2f0_result;
+}
+
+/*
+ * Name: iucv_receive
+ * Purpose: This function receives messages that are being sent to you
+ * over established paths.
+ * Input:
+ * pathid - path identification number
+ * buffer - address of buffer to receive
+ * buflen - length of buffer to receive
+ * msgid - specifies the message ID.
+ * trgcls - specifies target class
+ * Output:
+ * flags1_out: Options for path.
+ * IPNORPY - 0x10 specifies whether a reply is required
+ * IPPRTY - 0x20 specifies if you want to send priority message
+ * IPRMDATA - 0x80 specifies the data is contained in the parameter list
+ * residual_buffer - address of buffer updated by the number
+ * of bytes you have received.
+ * residual_length -
+ * Contains one of the following values, if the receive buffer is:
+ * The same length as the message, this field is zero.
+ * Longer than the message, this field contains the number of
+ * bytes remaining in the buffer.
+ * Shorter than the message, this field contains the residual
+ * count (that is, the number of bytes remaining in the
+ * message that does not fit into the buffer. In this
+ * case b2f0_result = 5.
+ * Return: b2f0_result - return code from CP IUCV call.
+ * (-EINVAL) - buffer address is pointing to NULL
+ */
+int
+iucv_receive (u16 pathid, u32 msgid, u32 trgcls,
+ void *buffer, ulong buflen,
+ int *flags1_out, ulong * residual_buffer, ulong * residual_length)
{
iparml_db parm;
ulong b2f0_result;
- pr_debug ("entering iucv_receive_simple\n");
+ int moved = 0; /* number of bytes moved from parmlist to buffer */
+ pr_debug ("iucv_receive: entering\n");
+
+ if (!buffer)
+ return -EINVAL;
- memset (&(parm), 0, sizeof (parm));
+ memset (&parm, 0, sizeof (parm));
+ parm.ipbfadr1 = (u32) buffer;
+ parm.ipbfln1f = (u32) ((ulong) buflen);
parm.ipmsgid = msgid;
parm.ippathid = pathid;
parm.iptrgcls = trgcls;
- parm.ipflags1 = IPFGMID + IPFGPID + IPFGMCL;
- parm.ipbfadr1 = (ulong) buffer;
- parm.ipbfln1f = buflen;
+ parm.ipflags1 = (IPFGPID | IPFGMID | IPFGMCL);
- b2f0_result = b2f0 (receive, &parm);
- if (b2f0_result)
- return b2f0_result;
+ b2f0_result = b2f0 (RECEIVE, &parm);
+
+ if (b2f0_result == 0 || b2f0_result == 5) {
+ if (flags1_out) {
+ pr_debug ("*flags1_out = %d\n", *flags1_out);
+ *flags1_out = (parm.ipflags1 & (~0x07));
+ pr_debug ("*flags1_out = %d\n", *flags1_out);
+ }
+
+ if (!(parm.ipflags1 & IPRMDATA)) { /*msg not in parmlist */
+ if (residual_length)
+ *residual_length = parm.ipbfln1f;
+
+ if (residual_buffer)
+ *residual_buffer = parm.ipbfadr1;
+ } else {
+ moved = min (buflen, 8);
- if (parm.ipflags1 & IPRMDATA) { /*msg in parmlist */
- if ((buflen) >= 8)
- memcpy ((char *) buffer, (char *) parm.ipbfadr1, 8);
- else
- b2f0_result = 5;
+ memcpy ((char *) buffer,
+ (char *) &parm.ipbfadr1, moved);
+
+ if (buflen < 8)
+ b2f0_result = 5;
+
+ if (residual_length)
+ *residual_length = abs (buflen - 8);
+
+ if (residual_buffer)
+ *residual_buffer = (ulong) (buffer + moved);
+ }
}
- pr_debug ("exiting iucv_receive_simple\n");
+ pr_debug ("iucv_receive: exiting \n");
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_receive_array */
-/* Purpose: receives incoming message */
-/* Input: pathid - ushort, pathid */
-/* msgid -* ulong, mid of message */
-/* trgcls -* ulong, target message class */
-/* buffer - pointer of iucv_array_t */
-/* buflen - ulong , length of buffer */
-/* reply_required - uchar *, flag returned to caller */
-/* priority_msg - uchar *, flag returned to caller */
-/* adds_curr_buffer - pointer to updated buffer array */
-/* to write to */
-/* adds_curr_length - pointer to updated length in */
-/* buffer available to write to */
-/* Output: iprcode - return code from b2f0 call */
-/* NOTE: pathid must be specified, flag being turned on */
-/* RESTRICTIONS: target class CANNOT be zero because the code */
-/* checks for a non-NULL value to turn flag on, therefore if */
-/* target class = if target class = zero flag will not be */
-/* turned on, therefore if target class is specified it cannot */
-/* be zero. */
-/**************************************************************/
+/*
+ * Name: iucv_receive_array
+ * Purpose: This function receives messages that are being sent to you
+ * over established paths.
+ * Input: pathid - path identification number
+ * buffer - address of array of buffers
+ * buflen - total length of buffers
+ * msgid - specifies the message ID.
+ * trgcls - specifies target class
+ * Output:
+ * flags1_out: Options for path.
+ * IPNORPY - 0x10 specifies whether a reply is required
+ * IPPRTY - 0x20 specifies if you want to send priority message
+ * IPRMDATA - 0x80 specifies the data is contained in the parameter list
+ * residual_buffer - address points to the current list entry IUCV
+ * is working on.
+ * residual_length -
+ * Contains one of the following values, if the receive buffer is:
+ * The same length as the message, this field is zero.
+ * Longer than the message, this field contains the number of
+ * bytes remaining in the buffer.
+ * Shorter than the message, this field contains the residual
+ * count (that is, the number of bytes remaining in the
+ * message that does not fit into the buffer. In this case
+ * b2f0_result = 5.
+ * Return: b2f0_result - return code from CP
+ * (-EINVAL) - buffer address is NULL
+ */
int
-iucv_receive_array (ushort pathid, ulong * msgid, ulong * trgcls,
- iucv_array_t * buffer, ulong * buflen,
- uchar * reply_required,
- uchar * priority_msg,
- ulong * adds_curr_buffer, ulong * adds_curr_length)
+iucv_receive_array (u16 pathid,
+ u32 msgid, u32 trgcls,
+ iucv_array_t * buffer, ulong buflen,
+ int *flags1_out,
+ ulong * residual_buffer, ulong * residual_length)
{
iparml_db parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_receive_array\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- parm.ipmsgid = *msgid;
+ int i = 0, moved = 0, need_to_move = 8, dyn_len;
+ pr_debug ("iucv_receive_array: entering\n");
+
+ if (!buffer)
+ return -EINVAL;
+
+ memset (&parm, 0, sizeof (parm));
+ parm.ipbfadr1 = (u32) ((ulong) buffer);
+ parm.ipbfln1f = (u32) buflen;
+ parm.ipmsgid = msgid;
parm.ippathid = pathid;
- parm.iptrgcls = *trgcls;
- parm.ipflags1 |= array; /* using an address list */
- parm.ipflags1 |= specify_pathid; /*turning on pathid flag */
- if (parm.ipmsgid)
- parm.ipflags1 |= 0x05;
- if (parm.iptrgcls)
- parm.ipflags1 |= target_class;
- parm.ipbfadr1 = (ulong) buffer;
- parm.ipbfln1f = *buflen;
- b2f0_result = b2f0 (receive, &parm);
- if (b2f0_result)
- return b2f0_result;
- if (msgid)
- *msgid = parm.ipmsgid;
- if (trgcls)
- *trgcls = parm.iptrgcls;
- if (parm.ipflags1 & prior_msg)
- if (priority_msg)
- *priority_msg = 0x01; /*yes, priority msg */
- if (!(parm.ipflags1 & 0x10)) /*& with X'10' */
- if (reply_required)
- *reply_required = 0x01; /*yes, reply required */
- if (!(parm.ipflags1 & parm_data)) { /*msg not in parmlist */
- if (adds_curr_length)
- *adds_curr_length = parm.ipbfln1f;
- if (adds_curr_buffer)
- *adds_curr_buffer = parm.ipbfadr1;
- } else {
- if ((buffer->length) >= 8) {
- memcpy ((char *) buffer->address,
- (char *) parm.ipbfadr1, 8);
- if (adds_curr_buffer)
- *adds_curr_buffer =
- (ulong) ((buffer->address) + 8);
- if (adds_curr_length)
- *adds_curr_length = ((buffer->length) - 8);
+ parm.iptrgcls = trgcls;
+ parm.ipflags1 = (IPBUFLST | IPFGPID | IPFGMID | IPFGMCL);
+
+ b2f0_result = b2f0 (RECEIVE, &parm);
+
+ if (b2f0_result == 0 || b2f0_result == 5) {
+
+ if (flags1_out) {
+ pr_debug ("*flags1_out = %d\n", *flags1_out);
+ *flags1_out = (parm.ipflags1 & (~0x07));
+ pr_debug ("*flags1_out = %d\n", *flags1_out);
+ }
+
+ if (!(parm.ipflags1 & IPRMDATA)) { /*msg not in parmlist */
+
+ if (residual_length)
+ *residual_length = parm.ipbfln1f;
+
+ if (residual_buffer)
+ *residual_buffer = parm.ipbfadr1;
} else {
- parm.iprcode |= 0x05;
- b2f0_result = (ulong) parm.iprcode;
+ /* copy msg from parmlist to users array. */
+
+ while ((moved < 8) && (moved < buflen)) {
+ dyn_len =
+ min ((buffer + i)->length, need_to_move);
+
+ memcpy ((char *)((ulong)((buffer + i)->address)),
+ ((char *) &parm.ipbfadr1) + moved,
+ dyn_len);
+
+ moved += dyn_len;
+ need_to_move -= dyn_len;
+
+ (buffer + i)->address =
+ (u32)
+ ((ulong)(uchar *) ((ulong)(buffer + i)->address)
+ + dyn_len);
+
+ (buffer + i)->length -= dyn_len;
+ i++;
+ }
+
+ if (need_to_move) /* buflen < 8 bytes */
+ b2f0_result = 5;
+
+ if (residual_length)
+ *residual_length = abs (buflen - 8);
+
+ if (residual_buffer) {
+ if (moved == 0)
+ *residual_buffer = (ulong) buffer;
+ else
+ *residual_buffer =
+ (ulong) (buffer + (i - 1));
+ }
+
}
}
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_receive\n");
-#endif
+
+ pr_debug ("iucv_receive_array: exiting\n");
+ return b2f0_result;
+}
+
+/*
+ * Name: iucv_reject
+ * Purpose: Refuses a specified message. Between the time you are notified of a
+ * message and the time that you complete the message, the message may
+ * be rejected.
+ * Input: pathid - u16, path identification number.
+ * msgid - u32, specifies the message ID.
+ * trgcls - u32, specifies target class.
+ * Output: b2f0_result - return code from CP
+ * NOTE: see b2f0 output list
+*/
+int
+iucv_reject (u16 pathid, u32 msgid, u32 trgcls)
+{
+ iparml_db parm;
+ ulong b2f0_result = 0;
+
+ pr_debug ("iucv_reject: entering \n");
+ pr_debug ("iucv_reject: pathid = %d\n", pathid);
+
+ memset (&parm, 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.ipmsgid = msgid;
+ parm.iptrgcls = trgcls;
+ parm.ipflags1 = (IPFGMCL | IPFGMID | IPFGPID);
+
+ b2f0_result = b2f0 (REJECT, &parm);
+
+ pr_debug ("iucv_reject: b2f0_result = %ld\n", b2f0_result);
+ pr_debug ("iucv_reject: exiting\n");
+
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_send */
-/* Purpose: sends messages */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong *, id of message returned to caller */
-/* trgcls - ulong, target message class */
-/* srccls - ulong, source message class */
-/* msgtag - ulong, message tag */
-/* priority_msg - uchar, flag */
-/* buffer - pointer to buffer */
-/* buflen - ulong, length of buffer */
-/* Output: iprcode - return code from b2f0 call */
-/* msgid - returns message id */
-/**************************************************************/
+/*
+ * Name: iucv_reply
+ * Purpose: This function responds to the two-way messages that you
+ * receive. You must identify completely the message to
+ * which you wish to reply. ie, pathid, msgid, and trgcls.
+ * Input: pathid - path identification number
+ * msgid - specifies the message ID.
+ * trgcls - specifies target class
+ * flags1 - option for path
+ * IPPRTY- 0x20 - specifies if you want to send priority message
+ * buffer - address of reply buffer
+ * buflen - length of reply buffer
+ * Output: ipbfadr2 - Address of buffer updated by the number
+ * of bytes you have moved.
+ * ipbfln2f - Contains on the the following values
+ * If the answer buffer is the same length as the reply, this field
+ * contains zero.
+ * If the answer buffer is longer than the reply, this field contains
+ * the number of bytes remaining in the buffer.
+ * If the answer buffer is shorter than the reply, this field contains
+ * a residual count (that is, the number of bytes remianing in the
+ * reply that does not fit into the buffer. In this
+ * case b2f0_result = 5.
+ * Return: b2f0_result - return code from CP
+ * (-EINVAL) - buffer address is NULL
+ */
int
-iucv_send (ushort pathid, ulong * msgid,
- ulong trgcls, ulong srccls,
- ulong msgtag, uchar priority_msg, void *buffer, ulong buflen)
+iucv_reply (u16 pathid,
+ u32 msgid, u32 trgcls,
+ int flags1,
+ void *buffer, ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
{
iparml_db parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_send\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
+
+ pr_debug ("iucv_reply: entering\n");
+
+ if (!buffer)
+ return -EINVAL;
+
+ memset (&parm, 0, sizeof (parm));
+ parm.ipbfadr2 = (u32) ((ulong) buffer);
+ parm.ipbfln2f = (u32) buflen; /* length of message */
parm.ippathid = pathid;
+ parm.ipmsgid = msgid;
parm.iptrgcls = trgcls;
- parm.ipbfadr1 = (ulong) buffer;
- parm.ipbfln1f = buflen; /* length of message */
- parm.ipsrccls = srccls;
- parm.ipmsgtag = msgtag;
- parm.ipflags1 |= one_way_msg; /* one way message */
- if (priority_msg)
- parm.ipflags1 |= prior_msg; /* priority message */
- b2f0_result = b2f0 (send, &parm);
- if (b2f0_result)
- return b2f0_result;
- if (msgid)
- *msgid = parm.ipmsgid;
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_send\n");
-#endif
+ parm.ipflags1 = (uchar) flags1; /* priority message */
+
+ b2f0_result = b2f0 (REPLY, &parm);
+
+ if ((b2f0_result == 0) || (b2f0_result == 5)) {
+ if (ipbfadr2)
+ *ipbfadr2 = parm.ipbfadr2;
+ if (ipbfln2f)
+ *ipbfln2f = parm.ipbfln2f;
+ }
+
+ pr_debug ("iucv_reply: exiting\n");
+
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_send_array */
-/* Purpose: sends messages in buffer array */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong *, id of message returned to caller */
-/* trgcls - ulong, target message class */
-/* srccls - ulong, source message class */
-/* msgtag - ulong, message tag */
-/* priority_msg - uchar, flag */
-/* buffer - pointer to iucv_array_t */
-/* buflen - ulong, length of buffer */
-/* Output: iprcode - return code from b2f0 call */
-/* msgid - returns message id */
-/**************************************************************/
+/*
+ * Name: iucv_reply_array
+ * Purpose: This function responds to the two-way messages that you
+ * receive. You must identify completely the message to
+ * which you wish to reply. ie, pathid, msgid, and trgcls.
+ * The array identifies a list of addresses and lengths of
+ * discontiguous buffers that contains the reply data.
+ * Input: pathid - path identification number
+ * msgid - specifies the message ID.
+ * trgcls - specifies target class
+ * flags1 - option for path
+ * IPPRTY- specifies if you want to send priority message
+ * buffer - address of array of reply buffers
+ * buflen - total length of reply buffers
+ * Output: ipbfadr2 - Address of buffer which IUCV is currently working on.
+ * ipbfln2f - Contains on the the following values
+ * If the answer buffer is the same length as the reply, this field
+ * contains zero.
+ * If the answer buffer is longer than the reply, this field contains
+ * the number of bytes remaining in the buffer.
+ * If the answer buffer is shorter than the reply, this field contains
+ * a residual count (that is, the number of bytes remianing in the
+ * reply that does not fit into the buffer. In this
+ * case b2f0_result = 5.
+ * Return: b2f0_result - return code from CP
+ * (-EINVAL) - buffer address is NULL
+*/
int
-iucv_send_array (ushort pathid, ulong * msgid,
- ulong trgcls, ulong srccls,
- ulong msgtag, uchar priority_msg,
- iucv_array_t * buffer, ulong buflen)
+iucv_reply_array (u16 pathid,
+ u32 msgid, u32 trgcls,
+ int flags1,
+ iucv_array_t * buffer,
+ ulong buflen, ulong * ipbfadr2, ulong * ipbfln2f)
{
iparml_db parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_send_array\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
+
+ pr_debug ("iucv_reply_array: entering\n");
+
+ if (!buffer)
+ return -EINVAL;
+
+ memset (&parm, 0, sizeof (parm));
+ parm.ipbfadr2 = (u32) ((ulong) buffer);
+ parm.ipbfln2f = buflen; /* length of message */
parm.ippathid = pathid;
+ parm.ipmsgid = msgid;
parm.iptrgcls = trgcls;
- parm.ipbfadr1 = (ulong) buffer;
- parm.ipbfln1f = buflen; /* length of message */
- parm.ipsrccls = srccls;
- parm.ipmsgtag = msgtag;
- parm.ipflags1 |= one_way_msg; /* one way message */
- parm.ipflags1 |= array; /* one way w/ array */
- if (priority_msg)
- parm.ipflags1 |= prior_msg; /* priority message */
- b2f0_result = b2f0 (send, &parm);
- if (msgid)
- *msgid = parm.ipmsgid;
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_send_array\n");
-#endif
+ parm.ipflags1 = (IPANSLST | flags1);
+
+ b2f0_result = b2f0 (REPLY, &parm);
+
+ if ((b2f0_result == 0) || (b2f0_result == 5)) {
+
+ if (ipbfadr2)
+ *ipbfadr2 = parm.ipbfadr2;
+ if (ipbfln2f)
+ *ipbfln2f = parm.ipbfln2f;
+ }
+
+ pr_debug ("iucv_reply_array: exiting\n");
+
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_send_prmmsg */
-/* Purpose: sends messages in parameter list */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong *, id of message */
-/* trgcls - ulong, target message class */
-/* srccls - ulong, source message class */
-/* msgtag - ulong, message tag */
-/* priority_msg - uchar, flag */
-/* prmmsg - uchar[8], message being sent */
-/* Output: iprcode - return code from b2f0 call */
-/* msgid - returns message id */
-/**************************************************************/
+/*
+ * Name: iucv_reply_prmmsg
+ * Purpose: This function responds to the two-way messages that you
+ * receive. You must identify completely the message to
+ * which you wish to reply. ie, pathid, msgid, and trgcls.
+ * Prmmsg signifies the data is moved into the
+ * parameter list.
+ * Input: pathid - path identification number
+ * msgid - specifies the message ID.
+ * trgcls - specifies target class
+ * flags1 - option for path
+ * IPPRTY- specifies if you want to send priority message
+ * prmmsg - 8-bytes of data to be placed into the parameter
+ * list.
+ * Output: NA
+ * Return: b2f0_result - return code from CP
+*/
int
-iucv_send_prmmsg (ushort pathid, ulong * msgid,
- ulong trgcls, ulong srccls,
- ulong msgtag, uchar priority_msg, uchar prmmsg[8])
+iucv_reply_prmmsg (u16 pathid,
+ u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8])
{
iparml_dpl parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_send_prmmsg\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
+
+ pr_debug ("iucv_reply_prmmsg: entering\n");
+
+ memset (&parm, 0, sizeof (parm));
parm.ippathid = pathid;
+ parm.ipmsgid = msgid;
parm.iptrgcls = trgcls;
- parm.ipsrccls = srccls;
- parm.ipmsgtag = msgtag;
- parm.ipflags1 |= parm_data; /* message in prmlist */
- parm.ipflags1 |= one_way_msg; /* one way message */
- if (priority_msg)
- parm.ipflags1 |= prior_msg; /* priority message */
- memcpy (parm.iprmmsg, prmmsg, 8);
- b2f0_result = b2f0 (send, &parm);
- if (msgid)
- *msgid = parm.ipmsgid;
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_send_prmmsg\n");
-#endif
+ memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+ parm.ipflags1 = (IPRMDATA | flags1);
+
+ b2f0_result = b2f0 (REPLY, &parm);
+
+ pr_debug ("iucv_reply_prmmsg: exiting\n");
+
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_send2way */
-/* Purpose: sends messages in both directions */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong *, id of message */
-/* trgcls - ulong, target message class */
-/* srccls - ulong, source message class */
-/* msgtag - ulong, message tag */
-/* priority_msg - uchar, flag */
-/* buffer - pointer to buffer */
-/* buflen - ulong, length of buffer */
-/* ansbuf - pointer to buffer on reply */
-/* anslen - length of ansbuf buffer */
-/* Output: iprcode - return code from b2f0 call */
-/* msgid - returns message id */
-/**************************************************************/
+/*
+ * Name: iucv_resume
+ * Purpose: This function restores communication over a quiesced path.
+ * Input: pathid - u16, path identification number
+ * user_data - uchar[16], 16-byte of user data
+ * Output: b2f0_result - return code from CP
+ */
int
-iucv_send2way (ushort pathid, ulong * msgid,
- ulong trgcls, ulong srccls,
- ulong msgtag, uchar priority_msg,
- void *buffer, ulong buflen, void *ansbuf, ulong anslen)
+iucv_resume (u16 pathid, uchar user_data[16])
+{
+ iparml_control parm;
+ ulong b2f0_result = 0;
+
+ pr_debug ("iucv_resume: entering\n");
+ pr_debug ("iucv_resume: pathid = %d\n", pathid);
+
+ memset (&parm, 0, sizeof (parm));
+ memcpy (parm.ipuser, user_data, sizeof (*user_data));
+ parm.ippathid = pathid;
+
+ b2f0_result = b2f0 (RESUME, &parm);
+
+ pr_debug ("iucv_resume: exiting \n");
+
+ return b2f0_result;
+}
+
+/*
+ * Name: iucv_send
+ * Purpose: sends messages
+ * Input: pathid - ushort, pathid
+ * msgid - ulong *, id of message returned to caller
+ * trgcls - ulong, target message class
+ * srccls - ulong, source message class
+ * msgtag - ulong, message tag
+ * flags1 - Contains options for this path.
+ * IPPRTY - Ox20 - specifies if you want to send a priority message.
+ * buffer - pointer to buffer
+ * buflen - ulong, length of buffer
+ * Output: b2f0_result - return code from b2f0 call
+ * msgid - returns message id
+ */
+int
+iucv_send (u16 pathid, u32 * msgid,
+ u32 trgcls, u32 srccls,
+ u32 msgtag, int flags1, void *buffer, ulong buflen)
{
iparml_db parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_send2way\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
+
+ pr_debug ("iucv_send: entering\n");
+
+ if (!buffer)
+ return -EINVAL;
+
+ memset (&parm, 0, sizeof (parm));
+ parm.ipbfadr1 = (u32) ((ulong) buffer);
parm.ippathid = pathid;
parm.iptrgcls = trgcls;
- parm.ipbfadr1 = (ulong) buffer;
- parm.ipbfln1f = buflen; /* length of message */
- parm.ipbfadr2 = (ulong) ansbuf;
- parm.ipbfln2f = anslen;
+ parm.ipbfln1f = (u32) buflen; /* length of message */
parm.ipsrccls = srccls;
parm.ipmsgtag = msgtag;
- if (priority_msg)
- parm.ipflags1 |= prior_msg; /* priority message */
- b2f0_result = b2f0 (send, &parm);
- if (msgid)
+ parm.ipflags1 = (IPNORPY | flags1); /* one way priority message */
+
+ b2f0_result = b2f0 (SEND, &parm);
+
+ if ((b2f0_result == 0) && (msgid))
*msgid = parm.ipmsgid;
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_send2way\n");
-#endif
+
+ pr_debug ("iucv_send: exiting\n");
+
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_send2way_array */
-/* Purpose: sends messages in both directions in arrays */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong *, id of message */
-/* trgcls - ulong, target message class */
-/* srccls - ulong, source message class */
-/* msgtag - ulong, message tag */
-/* priority_msg - uchar, flag */
-/* buffer - pointer to iucv_array_t */
-/* buflen - ulong, length of buffer */
-/* ansbuf - pointer to iucv_array_t on reply */
-/* anslen - length of ansbuf buffer */
-/* Output: iprcode - return code from b2f0 call */
-/* msgid - returns message id */
-/**************************************************************/
+/*
+ * Name: iucv_send_array
+ * Purpose: This function transmits data to another application.
+ * The contents of buffer is the address of the array of
+ * addresses and lengths of discontiguous buffers that hold
+ * the message text. This is a one-way message and the
+ * receiver will not reply to the message.
+ * Input: pathid - path identification number
+ * trgcls - specifies target class
+ * srccls - specifies the source message class
+ * msgtag - specifies a tag to be associated witht the message
+ * flags1 - option for path
+ * IPPRTY- specifies if you want to send priority message
+ * buffer - address of array of send buffers
+ * buflen - total length of send buffers
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ * (-EINVAL) - buffer address is NULL
+ */
int
-iucv_send2way_array (ushort pathid, ulong * msgid,
- ulong trgcls, ulong srccls,
- ulong msgtag, uchar priority_msg,
- iucv_array_t * buffer, ulong buflen,
- iucv_array_t * ansbuf, ulong anslen)
+iucv_send_array (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls,
+ u32 msgtag, int flags1, iucv_array_t * buffer, ulong buflen)
{
iparml_db parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_send2way_array\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
+
+ pr_debug ("iucv_send_array: entering\n");
+
+ if (!buffer)
+ return -EINVAL;
+
+ memset (&parm, 0, sizeof (parm));
parm.ippathid = pathid;
parm.iptrgcls = trgcls;
- parm.ipbfadr1 = (ulong) buffer;
- parm.ipbfln1f = buflen; /* length of message */
- parm.ipbfadr2 = (ulong) ansbuf;
- parm.ipbfln2f = anslen;
+ parm.ipbfadr1 = (u32) ((ulong) buffer);
+ parm.ipbfln1f = (u32) buflen; /* length of message */
parm.ipsrccls = srccls;
parm.ipmsgtag = msgtag;
- parm.ipflags1 |= array; /* send w/ array */
- parm.ipflags1 |= reply_array; /* reply w/ array */
- if (priority_msg)
- parm.ipflags1 |= prior_msg; /* priority message */
- b2f0_result = b2f0 (send, &parm);
- if (msgid)
+ parm.ipflags1 = (IPNORPY | IPBUFLST | flags1);
+ b2f0_result = b2f0 (SEND, &parm);
+
+ if ((b2f0_result == 0) && (msgid))
*msgid = parm.ipmsgid;
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_send2way_array\n");
-#endif
+ pr_debug ("iucv_send_array: exiting\n");
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_send2way_prmmsg */
-/* Purpose: sends messages in both directions w/parameter lst */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong *, id of message */
-/* trgcls - ulong, target message class */
-/* srccls - ulong, source message class */
-/* msgtag - ulong, message tag */
-/* priority_msg - uchar, flag */
-/* prmmsg - uchar[8], message being sent in parameter */
-/* ansbuf - pointer to buffer */
-/* anslen - length of ansbuf buffer */
-/* Output: iprcode - return code from b2f0 call */
-/* msgid - returns message id */
-/**************************************************************/
+/*
+ * Name: iucv_send_prmmsg
+ * Purpose: This function transmits data to another application.
+ * Prmmsg specifies that the 8-bytes of data are to be moved
+ * into the parameter list. This is a one-way message and the
+ * receiver will not reply to the message.
+ * Input: pathid - path identification number
+ * trgcls - specifies target class
+ * srccls - specifies the source message class
+ * msgtag - specifies a tag to be associated with the message
+ * flags1 - option for path
+ * IPPRTY- specifies if you want to send priority message
+ * prmmsg - 8-bytes of data to be placed into parameter list
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+*/
int
-iucv_send2way_prmmsg (ushort pathid, ulong * msgid,
- ulong trgcls, ulong srccls,
- ulong msgtag, uchar priority_msg,
- uchar prmmsg[8], void *ansbuf, ulong anslen)
+iucv_send_prmmsg (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8])
{
iparml_dpl parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
+
+ pr_debug ("iucv_send_prmmsg: entering\n");
+
+ memset (&parm, 0, sizeof (parm));
parm.ippathid = pathid;
parm.iptrgcls = trgcls;
parm.ipsrccls = srccls;
parm.ipmsgtag = msgtag;
- parm.ipbfadr2 = (ulong) ansbuf;
- parm.ipbfln2f = anslen;
- parm.ipflags1 |= parm_data; /* message in prmlist */
- if (priority_msg)
- parm.ipflags1 |= prior_msg; /* priority message */
- memcpy (parm.iprmmsg, prmmsg, 8);
- b2f0_result = b2f0 (send, &parm);
- if (msgid)
+ parm.ipflags1 = (IPRMDATA | IPNORPY | flags1);
+ memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+
+ b2f0_result = b2f0 (SEND, &parm);
+
+ if ((b2f0_result == 0) && (msgid))
*msgid = parm.ipmsgid;
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n");
-#endif
+
+ pr_debug ("iucv_send_prmmsg: exiting\n");
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_reply */
-/* Purpose: responds to the two-way messages that you receive */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong, id of message */
-/* trgcls - ulong, target message class */
-/* priority_msg - uchar, flag */
-/* buf - pointer, address of buffer */
-/* buflen - length of buffer */
-/* Output: iprcode - return code from b2f0 call */
-/**************************************************************/
+/*
+ * Name: iucv_send2way
+ * Purpose: This function transmits data to another application.
+ * Data to be transmitted is in a buffer. The receiver
+ * of the send is expected to reply to the message and
+ * a buffer is provided into which IUCV moves the reply
+ * to this message.
+ * Input: pathid - path identification number
+ * trgcls - specifies target class
+ * srccls - specifies the source message class
+ * msgtag - specifies a tag associated with the message
+ * flags1 - option for path
+ * IPPRTY- specifies if you want to send priority message
+ * buffer - address of send buffer
+ * buflen - length of send buffer
+ * ansbuf - address of buffer to reply with
+ * anslen - length of buffer to reply with
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ * (-EINVAL) - buffer or ansbuf address is NULL
+ */
int
-iucv_reply (ushort pathid, ulong msgid, ulong trgcls,
- uchar priority_msg, void *buf, ulong buflen)
+iucv_send2way (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls,
+ u32 msgtag,
+ int flags1,
+ void *buffer, ulong buflen, void *ansbuf, ulong anslen)
{
iparml_db parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_reply\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
+ pr_debug ("iucv_send2way: entering\n");
+
+ if (!buffer || !ansbuf)
+ return -EINVAL;
+
+ memset (&parm, 0, sizeof (parm));
parm.ippathid = pathid;
- parm.ipmsgid = msgid;
parm.iptrgcls = trgcls;
- parm.ipbfadr2 = (ulong) buf;
- parm.ipbfln2f = buflen; /* length of message */
- if (priority_msg)
- parm.ipflags1 |= prior_msg; /* priority message */
- b2f0_result = b2f0 (reply, &parm);
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_reply\n");
-#endif
+ parm.ipbfadr1 = (u32) ((ulong) buffer);
+ parm.ipbfln1f = (u32) buflen; /* length of message */
+ parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+ parm.ipbfln2f = (u32) anslen;
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ parm.ipflags1 = flags1; /* priority message */
+
+ b2f0_result = b2f0 (SEND, &parm);
+
+ if ((b2f0_result == 0) && (msgid))
+ *msgid = parm.ipmsgid;
+
+ pr_debug ("iucv_send2way: exiting\n");
+
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_reply_array */
-/* Purpose: responds to the two-way messages that you receive */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong, id of message */
-/* trgcls - ulong, target message class */
-/* priority_msg - uchar, flag */
-/* buf - pointer, address of array */
-/* buflen - length of buffer */
-/* Output: iprcode - return code from b2f0 call */
-/**************************************************************/
+/*
+ * Name: iucv_send2way_array
+ * Purpose: This function transmits data to another application.
+ * The contents of buffer is the address of the array of
+ * addresses and lengths of discontiguous buffers that hold
+ * the message text. The receiver of the send is expected to
+ * reply to the message and a buffer is provided into which
+ * IUCV moves the reply to this message.
+ * Input: pathid - path identification number
+ * trgcls - specifies target class
+ * srccls - specifies the source message class
+ * msgtag - spcifies a tag to be associated with the message
+ * flags1 - option for path
+ * IPPRTY- specifies if you want to send priority message
+ * buffer - address of array of send buffers
+ * buflen - total length of send buffers
+ * ansbuf - address of buffer to reply with
+ * anslen - length of buffer to reply with
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ * (-EINVAL) - buffer address is NULL
+ */
int
-iucv_reply_array (ushort pathid, ulong msgid, ulong trgcls,
- uchar priority_msg, iucv_array_t * buffer, ulong buflen)
+iucv_send2way_array (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls,
+ u32 msgtag,
+ int flags1,
+ iucv_array_t * buffer,
+ ulong buflen, iucv_array_t * ansbuf, ulong anslen)
{
iparml_db parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_reply_array\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
+
+ pr_debug ("iucv_send2way_array: entering\n");
+
+ if (!buffer || !ansbuf)
+ return -EINVAL;
+
+ memset (&parm, 0, sizeof (parm));
parm.ippathid = pathid;
- parm.ipmsgid = msgid;
parm.iptrgcls = trgcls;
- parm.ipbfadr2 = (ulong) buffer;
- parm.ipbfln2f = buflen; /* length of message */
- parm.ipflags1 |= reply_array; /* reply w/ array */
- if (priority_msg)
- parm.ipflags1 |= prior_msg; /* priority message */
- b2f0_result = b2f0 (reply, &parm);
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_reply_array\n");
-#endif
+ parm.ipbfadr1 = (u32) ((ulong) buffer);
+ parm.ipbfln1f = (u32) buflen; /* length of message */
+ parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+ parm.ipbfln2f = (u32) anslen;
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ parm.ipflags1 = (IPBUFLST | IPANSLST | flags1);
+ b2f0_result = b2f0 (SEND, &parm);
+ if ((b2f0_result == 0) && (msgid))
+ *msgid = parm.ipmsgid;
+ pr_debug ("iucv_send2way_array: exiting\n");
+ return b2f0_result;
+}
+
+/*
+ * Name: iucv_send2way_prmmsg
+ * Purpose: This function transmits data to another application.
+ * Prmmsg specifies that the 8-bytes of data are to be moved
+ * into the parameter list. This is a two-way message and the
+ * receiver of the message is expected to reply. A buffer
+ * is provided into which IUCV moves the reply to this
+ * message.
+ * Input: pathid - path identification number
+ * trgcls - specifies target class
+ * srccls - specifies the source message class
+ * msgtag - specifies a tag to be associated with the message
+ * flags1 - option for path
+ * IPPRTY- specifies if you want to send priority message
+ * prmmsg - 8-bytes of data to be placed in parameter list
+ * ansbuf - address of buffer to reply with
+ * anslen - length of buffer to reply with
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ * (-EINVAL) - buffer address is NULL
+*/
+int
+iucv_send2way_prmmsg (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls,
+ u32 msgtag,
+ ulong flags1, uchar prmmsg[8], void *ansbuf, ulong anslen)
+{
+ iparml_dpl parm;
+ ulong b2f0_result;
+ pr_debug ("iucv_send2way_prmmsg: entering\n");
+
+ if (!ansbuf)
+ return -EINVAL;
+
+ memset (&parm, 0, sizeof (parm));
+ parm.ippathid = pathid;
+ parm.iptrgcls = trgcls;
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+ parm.ipbfln2f = (u32) anslen;
+ parm.ipflags1 = (IPRMDATA | flags1); /* message in prmlist */
+ memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+
+ b2f0_result = b2f0 (SEND, &parm);
+
+ if ((b2f0_result == 0) && (msgid))
+ *msgid = parm.ipmsgid;
+
+ pr_debug ("iucv_send2way_prmmsg: exiting\n");
+
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_reply_prmmsg */
-/* Purpose: responds to the two-way messages in parameter list */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong, id of message */
-/* trgcls - ulong, target message class */
-/* priority_msg - uchar, flag */
-/* prmmsg - uchar[8], message in parameter list */
-/* Output: iprcode - return code from b2f0 call */
-/**************************************************************/
+/*
+ * Name: iucv_send2way_prmmsg_array
+ * Purpose: This function transmits data to another application.
+ * Prmmsg specifies that the 8-bytes of data are to be moved
+ * into the parameter list. This is a two-way message and the
+ * receiver of the message is expected to reply. A buffer
+ * is provided into which IUCV moves the reply to this
+ * message. The contents of ansbuf is the address of the
+ * array of addresses and lengths of discontiguous buffers
+ * that contain the reply.
+ * Input: pathid - path identification number
+ * trgcls - specifies target class
+ * srccls - specifies the source message class
+ * msgtag - specifies a tag to be associated with the message
+ * flags1 - option for path
+ * IPPRTY- specifies if you want to send priority message
+ * prmmsg - 8-bytes of data to be placed into the parameter list
+ * ansbuf - address of buffer to reply with
+ * anslen - length of buffer to reply with
+ * Output: msgid - specifies the message ID.
+ * Return: b2f0_result - return code from CP
+ * (-EINVAL) - ansbuf address is NULL
+ */
int
-iucv_reply_prmmsg (ushort pathid, ulong msgid, ulong trgcls,
- uchar priority_msg, uchar prmmsg[8])
+iucv_send2way_prmmsg_array (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls,
+ u32 msgtag,
+ int flags1,
+ uchar prmmsg[8],
+ iucv_array_t * ansbuf, ulong anslen)
{
iparml_dpl parm;
ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_reply_prmmsg\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
+
+ pr_debug ("iucv_send2way_prmmsg_array: entering\n");
+
+ if (!ansbuf)
+ return -EINVAL;
+
+ memset (&parm, 0, sizeof (parm));
parm.ippathid = pathid;
- parm.ipmsgid = msgid;
parm.iptrgcls = trgcls;
- memcpy (parm.iprmmsg, prmmsg, 8);
- parm.ipflags1 |= parm_data;
- if (priority_msg)
- parm.ipflags1 |= prior_msg; /* priority message */
- b2f0_result = b2f0 (reply, &parm);
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_reply_prmmsg\n");
-#endif
+ parm.ipsrccls = srccls;
+ parm.ipmsgtag = msgtag;
+ parm.ipbfadr2 = (u32) ((ulong) ansbuf);
+ parm.ipbfln2f = (u32) anslen;
+ parm.ipflags1 = (IPRMDATA | IPANSLST | flags1);
+ memcpy (parm.iprmmsg, prmmsg, sizeof (parm.iprmmsg));
+ b2f0_result = b2f0 (SEND, &parm);
+ if ((b2f0_result == 0) && (msgid))
+ *msgid = parm.ipmsgid;
+ pr_debug ("iucv_send2way_prmmsg_array: exiting\n");
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_connect */
-/* Purpose: establishes an IUCV path to another vm */
-/* Input: pathid - ushort *, pathid returned to user */
-/* msglim - ushort, limit of outstanding messages */
-/* user_data - uchar[16], user data */
-/* userid - uchar[8], user's id */
-/* system_name - uchar[8], system identification */
-/* priority_requested - uchar- flag */
-/* prmdata - uchar, flag prgrm can handler messages */
-/* in parameter list */
-/* quiesce - uchar, flag to quiesce a path being establ */
-/* control - uchar, flag, option not used */
-/* local - uchar, flag, establish connection only on */
-/* local system */
-/* priority_permitted - uchar *, flag returned to user */
-/* handle - address of handler */
-/* pgm_data - ulong */
-/* Output: iprcode - return code from b2f0 call */
-/**************************************************************/
+/*
+ * Name: iucv_setmask
+ * Purpose: This function enables or disables the following IUCV
+ * external interruptions: Nonpriority and priority message
+ * interrupts, nonpriority and priority reply interrupts.
+ * Input: SetMaskFlag - options for interrupts
+ * 0x80 - Nonpriority_MessagePendingInterruptsFlag
+ * 0x40 - Priority_MessagePendingInterruptsFlag
+ * 0x20 - Nonpriority_MessageCompletionInterruptsFlag
+ * 0x10 - Priority_MessageCompletionInterruptsFlag
+ * Output: NA
+ * Return: b2f0_result - return code from CP
+*/
int
-iucv_connect (ushort * pathid, ushort msglim, uchar user_data[16],
- uchar userid[8], uchar system_name[8],
- uchar priority_requested, uchar prmdata,
- uchar quiesce, uchar control,
- uchar local, uchar * priority_permitted,
- iucv_handle_t handle, ulong pgm_data)
+iucv_setmask (int SetMaskFlag)
{
- iparml_control parm;
- ulong b2f0_result;
- int add_pathid_result, rc;
- handler *R;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_connect\n");
-#endif
+ iparml_set_mask parm;
+ ulong b2f0_result = 0;
+ pr_debug ("iucv_setmask: entering \n");
+
memset (&parm, 0, sizeof (parm));
- if (declare_flag == NULL) {
- rc = iucv_declare_buffer (iucv_external_int_buffer);
- if (rc) {
- printk (KERN_DEBUG "IUCV: registration failed\n");
-#ifdef DEBUG
- printk (KERN_DEBUG "rc from declare buffer is: %i\n",
- rc);
-#endif
- return rc;
- } else
- declare_flag = 1;
- }
- /* Checking if handle is valid */
- spin_lock (&lock);
- for (R = handler_anchor; R != NULL; R = (handler *) R->next)
- if (R == handle)
- break;
- if (R == NULL) {
- spin_unlock (&lock);
-#ifdef DEBUG
- printk (KERN_DEBUG "iucv_connect: Invalid Handle\n");
-#endif
- return (-2);
- }
- if (pathid == NULL) {
- spin_unlock (&lock);
-#ifdef DEBUG
- printk (KERN_DEBUG "iucv_connect: invalid pathid pointer\n");
-#endif
- return (-3);
- }
- spin_unlock (&lock);
- parm.ipmsglim = msglim;
- memcpy (parm.ipuser, user_data, 16);
- memcpy (parm.ipvmid, userid, 8);
- memcpy (parm.iptarget, system_name, 8);
- if (parm.iptarget)
- ASCEBC (parm.iptarget, 8);
- if (parm.ipvmid) {
- ASCEBC (parm.ipvmid, 8);
- EBC_TOUPPER(parm.ipvmid, 8);
- }
- if (priority_requested)
- parm.ipflags1 |= prior_msg;
- if (prmdata)
- parm.ipflags1 |= parm_data; /*data in parameter list */
- if (quiesce)
- parm.ipflags1 |= quiesce_msg;
- if (control) {
- /* do nothing at the time being */
- /*control not provided yet */
- }
- if (local)
- parm.ipflags1 |= local_conn; /*connect on local system */
- b2f0_result = b2f0 (connect, &parm);
- if (b2f0_result)
- return b2f0_result;
- add_pathid_result = add_pathid (parm.ippathid, handle, pgm_data);
- if (add_pathid_result) {
-#ifdef DEBUG
- printk (KERN_DEBUG "iucv_connect: add_pathid failed \n");
-#endif
- return (add_pathid_result);
- }
- *pathid = parm.ippathid;
- if (parm.ipflags1 & prior_msg)
- if (priority_permitted)
- *priority_permitted = 0x01;
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_connect\n");
-#endif
+ parm.ipmask = (uchar) SetMaskFlag;
+
+ b2f0_result = b2f0 (SETMASK, &parm);
+
+ pr_debug ("iucv_setmask: b2f0_result = %ld\n", b2f0_result);
+ pr_debug ("iucv_setmask: exiting\n");
+
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_accept */
-/* Purpose: completes the iucv communication path */
-/* Input: pathid - ushort , pathid */
-/* msglim - ushort, limit of outstanding messages */
-/* user_data - uchar[16], user data */
-/* priority_requested - uchar- flag */
-/* prmdata - uchar, flag prgrm can handler messages */
-/* in parameter list */
-/* quiesce - uchar, flag to quiesce a path being establ*/
-/* control - uchar, flag, option not used */
-/* priority_permitted -uchar *, flag returned to caller*/
-/* handle - address of handler */
-/* pgm_data - ulong */
-/* Output: iprcode - return code from b2f0 call */
-/**************************************************************/
+/*
+ * Name: iucv_sever
+ * Purpose: This function terminates an iucv path
+ * Input: pathid - u16, path identification number
+ * user_data - uchar[16], 16-byte of user data
+ * Output: b2f0_result - return code from CP
+ * -EINVAL - NULL address found for handler
+ */
int
-iucv_accept (ushort pathid, ushort msglim, uchar user_data[16],
- uchar priority_requested,
- uchar prmdata, uchar quiesce, uchar control,
- uchar * priority_permitted, iucv_handle_t handle, ulong pgm_data)
+iucv_sever (u16 pathid, uchar user_data[16])
{
- ulong index1, index2;
- handler_table_entry *P = 0;
iparml_control parm;
- ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_accept\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
+ ulong b2f0_result = 0;
+ pr_debug ("iucv_sever: entering\n");
+ memset (&parm, 0, sizeof (parm));
+ memcpy (parm.ipuser, user_data, sizeof (parm.ipuser));
parm.ippathid = pathid;
- parm.ipmsglim = msglim;
- memcpy (parm.ipuser, user_data, 16);
- if (priority_requested)
- parm.ipflags1 |= prior_msg;
- if (prmdata)
- parm.ipflags1 |= parm_data; /*data in parameter list */
- if (quiesce)
- parm.ipflags1 |= quiesce_msg;
- if (control) {
- /* do nothing at the time being */
- /*control not provided yet */
- }
- b2f0_result = b2f0 (accept, &parm);
- if (b2f0_result)
- return b2f0_result;
- index1 = ((ulong) pathid) / 512;
- index2 = ((ulong) pathid) % 512;
- spin_lock (&lock);
- if (pgm_data) {
- P = main_table[index1];
- (P + index2)->pgm_data = pgm_data;
- }
- spin_unlock (&lock);
- if (parm.ipflags1 & prior_msg)
- if (priority_permitted)
- *priority_permitted = 0x01;
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_accept\n");
-#endif
+
+ b2f0_result = b2f0 (SEVER, &parm);
+
+ if (!b2f0_result)
+ iucv_remove_pathid (pathid);
+
+ pr_debug ("iucv_sever: exiting \n");
return b2f0_result;
}
-/**************************************************************/
-/* Name: iucv_send2way_prmmsg_array */
-/* Purpose: sends messages in both directions w/parameter lst */
-/* Input: pathid - ushort, pathid */
-/* msgid - ulong *, id of message returned to caller */
-/* trgcls - ulong, target message class */
-/* srccls - ulong, source message class */
-/* msgtag - ulong, message tag */
-/* priority_msg - uchar, flag */
-/* prmmsg - uchar[8], message being sent in parameter */
-/* ansbuf - pointer to array of buffers */
-/* anslen - length of ansbuf buffer */
-/* Output: iprcode - return code from b2f0 call */
-/* msgid - returns message id */
-/**************************************************************/
-int
-iucv_send2way_prmmsg_array (ushort pathid, ulong * msgid,
- ulong trgcls, ulong srccls,
- ulong msgtag, uchar priority_msg,
- uchar prmmsg[8],
- iucv_array_t * ansbuf, ulong anslen)
+static void
+iucv_remove_pathid (u16 pathid)
{
- iparml_dpl parm;
- ulong b2f0_result;
-#ifdef DEBUG
- printk (KERN_DEBUG "entering iucv_send2way_prmmsg\n");
-#endif
- memset (&(parm), 0, sizeof (parm));
- parm.ippathid = pathid;
- parm.iptrgcls = trgcls;
- parm.ipsrccls = srccls;
- parm.ipmsgtag = msgtag;
- parm.ipbfadr2 = (ulong) ansbuf;
- parm.ipbfln2f = anslen;
- parm.ipflags1 |= 0x88; /* message in prmlist */
- if (priority_msg)
- parm.ipflags1 |= prior_msg; /* priority message */
- memcpy (parm.iprmmsg, prmmsg, 8);
- b2f0_result = b2f0 (send, &parm);
- if (msgid)
- *msgid = parm.ipmsgid;
-#ifdef DEBUG
- printk (KERN_DEBUG "exiting iucv_send2way_prmmsg\n");
-#endif
- return b2f0_result;
+ handler_table_entry *users_hte = NULL; /*users handler_table_entry */
+ handler *users_handler = NULL;
+ ulong *users_pathid = NULL;
+ ulong flags;
+ spin_lock_irqsave (&iucv_lock, flags);
+ users_hte = handler_table_anchor + (int) pathid;
+
+ if ((users_hte->addrs) == NULL) {
+ spin_unlock_irqrestore (&iucv_lock, flags);
+ return; /* wild pointer has been found */
+ }
+
+ users_handler = users_hte->addrs;
+
+ pr_debug ("iucv_sever: pathid is %d\n", pathid);
+ pr_debug ("iucv_sever: H_T_E is %p\n", users_hte);
+ pr_debug ("iucv_sever: address of handler is %p\n", users_handler);
+ pr_debug ("iucv_sever: below is pathid table\n");
+ iucv_dumpit ((uchar *) users_handler->pathid_head,
+ (int) users_handler->entries * sizeof (ulong));
+
+/*
+ * Searching the pathid address table for matching address, once
+ * found, NULL the handler_table_entry field and then zero the H_T_E fields.
+ */
+
+ for (users_pathid = (users_handler->pathid_head);
+ users_pathid < (users_handler->pathid_tail); users_pathid++)
+
+ if (*users_pathid == (ulong) users_hte) {
+ pr_debug ("iucv_sever: found a path to remove from"
+ "table\n");
+ pr_debug ("iucv_sever: removing %d \n",
+ (int) (*users_pathid)); *users_pathid = NULL;
+
+ memset (users_hte, 0, sizeof (handler_table_entry));
+ }
+ spin_unlock_irqrestore (&iucv_lock, flags);
+ return;
}
-/******************************************************************/
-/* Name: top_half_handler */
-/* Purpose: handle minimum amount of interrupt in fastest time */
-/* possible and then pass interrupt to bottom half handler. */
-/* Input: external interrupt buffer */
-/* Output: void */
-/******************************************************************/
+/*
+ * Interrupt Handling Functions
+ * top_half_interrupt
+ * bottom_half_interrupt
+ * do_int
+ */
+
+/*
+ * Name: top_half_interrupt
+ * Purpose: Handles interrupts coming in from CP. Places the interrupt on a queue and
+ * calls bottom_half_interrupt
+ * Input: external interrupt buffer
+ * Output: void
+ */
inline void
top_half_interrupt (struct pt_regs *regs, __u16 code)
{
iucv_packet *pkt;
- pkt = (iucv_packet *) kmalloc
- (sizeof (iucv_packet), GFP_ATOMIC);
+ int cpu = smp_processor_id();
+
+ irq_enter(cpu, 0x4000);
+
+ pkt = (iucv_packet *) kmalloc (sizeof (iucv_packet), GFP_ATOMIC);
if (pkt == NULL) {
- printk (KERN_DEBUG "out of memory\n");
+ printk (KERN_WARNING
+ "iucv:top_half_interrupt: out of memory\n");
+ irq_exit(cpu, 0x4000);
return;
}
- memcpy (pkt->data, iucv_external_int_buffer, 40);
-#ifdef DEBUG3
-printk (KERN_EMERG "TH: Got INT: %08x\n", *(int *)(pkt->data+4));
-#endif
+
+ memcpy (pkt->data, iucv_external_int_buffer, BUFFER_SIZE);
+
+ pr_debug ("TH: Got INT: %08x\n", *(int *) (pkt->data + 4));
+
/* put new packet on the list */
spin_lock (&iucv_packets_lock);
pkt->next = NULL;
+
if (iucv_packets_tail != NULL)
iucv_packets_tail->next = pkt;
else
iucv_packets_head = pkt;
+
iucv_packets_tail = pkt;
spin_unlock (&iucv_packets_lock);
if (atomic_compare_and_swap (0, 1, &bh_scheduled) == 0) {
-#ifdef DEBUG3
-printk (KERN_EMERG "TH: Queuing BH\n");
-#endif
- INIT_LIST_HEAD(&short_task.list);
- short_task.sync = 0;
short_task.routine = (void *) bottom_half_interrupt;
queue_task (&short_task, &tq_immediate);
mark_bh (IMMEDIATE_BH);
}
+ irq_exit(cpu, 0x4000);
return;
}
-/*******************************************************************/
-/* Name: bottom_half_interrupt */
-/* Purpose: Handle interrupt at a more safer time */
-/* Input: void */
-/* Output: void */
-/*******************************************************************/
+/*
+ * Name: bottom_half_interrupt
+ * Purpose: Handle interrupt at a more safer time
+ * Input: void
+ * Output: void
+ */
void
bottom_half_interrupt (void)
{
iucv_packet *iucv_packet_list;
iucv_packet *tmp;
ulong flags;
-
atomic_set (&bh_scheduled, 0);
+
spin_lock_irqsave (&iucv_packets_lock, flags);
iucv_packet_list = iucv_packets_head;
iucv_packets_head = iucv_packets_tail = NULL;
spin_unlock_irqrestore (&iucv_packets_lock, flags);
/* now process all the request in the iucv_packet_list */
-#ifdef DEBUG3
- printk (KERN_EMERG "BH: Process all packets\n");
-#endif
+ pr_debug ("BH: Process all packets\n");
while (iucv_packet_list != NULL) {
-#ifdef DEBUG3
- printk( KERN_EMERG "BH:> %08x\n",
- *(int *)(iucv_packet_list->data+4));
-#endif
- do_int ((iucv_ConnectionPending *) iucv_packet_list->data);
-#ifdef DEBUG3
- printk( KERN_EMERG "BH:< %08x\n",
- *(int *)(iucv_packet_list->data+4));
-#endif
+ pr_debug ("BH:> %08x\n",
+ *(int *) (iucv_packet_list->data + 4));
+
+ do_int ((iucv_GeneralInterrupt *) iucv_packet_list->data);
+
+ pr_debug ("BH:< %08x\n",
+ *(int *) (iucv_packet_list->data + 4));
tmp = iucv_packet_list;
iucv_packet_list = iucv_packet_list->next;
kfree (tmp);
}
-#ifdef DEBUG3
- printk (KERN_EMERG "BH: Done\n");
-#endif
+ pr_debug ("BH: Done\n");
return;
}
-/*******************************************************************/
-/* Name: do_int */
-/* Purpose: Handle interrupt in a more safe environment */
-/* Inuput: int_buf - pointer to copy of external interrupt buffer */
-/* Output: void */
-/*******************************************************************/
+
+/*
+ * Name: do_int
+ * Purpose: Handles the interrupts in a more safe environment
+ * Input: int_buf - pointer to copy of external interrupt buffer
+ * Output: void
+ */
void
-do_int (iucv_ConnectionPending * int_buf)
+do_int (iucv_GeneralInterrupt * int_buf)
{
- ulong index1 = 0, index2 = 0;
- handler_table_entry *P = 0; /* P is a pointer */
- handler *Q = 0, *R; /* Q and R are pointers */
+ handler_table_entry *P = 0;
+ ulong flags;
+ handler *Q = 0, *R;
iucv_interrupt_ops_t *interrupt = 0; /* interrupt addresses */
uchar temp_buff1[24], temp_buff2[24]; /* masked handler id. */
int add_pathid_result = 0, j = 0;
uchar no_listener[16] = "NO LISTENER";
-#ifdef DEBUG
- int i;
- uchar *prt_parm;
-#endif
-#ifdef DEBUG3
- printk (KERN_DEBUG "BH:- Entered do_int "
- "pathid %d, type %02X\n",
- int_buf->ippathid, int_buf->iptype);
-#endif
-#ifdef DEBUG
- prt_parm = (uchar *) (int_buf);
- printk (KERN_DEBUG "External Interrupt Buffer\n");
- for (i = 0; i < 40; i++)
- printk (KERN_DEBUG "%02x ", prt_parm[i]);
- printk (KERN_DEBUG "\n");
-#endif
+
+ pr_debug ("IUCV: BHI: - Entered do_int "
+ "pathid %d, type %02X\n", int_buf->ippathid, int_buf->iptype);
+ pr_debug ("BHI:External Interrupt Buffer\n");
+ iucv_dumpit ((uchar *) int_buf, sizeof (iucv_GeneralInterrupt));
+
ASCEBC (no_listener, 16);
if (int_buf->iptype != 01) {
- index1 = ((ulong) (int_buf->ippathid)) / 512;
- index2 = ((ulong) (int_buf->ippathid)) % 512;
- spin_lock (&lock);
-
- P = main_table[index1];
- Q = (P + index2)->addrs;
- interrupt = Q->interrupt_table; /* interrupt functions */
- spin_unlock (&lock);
-#ifdef DEBUG
- printk (KERN_DEBUG "Handler is: \n");
- prt_parm = (uchar *) Q;
- for (i = 0; i < sizeof (handler); i++)
- printk (KERN_DEBUG " %02x ", prt_parm[i]);
- printk (KERN_DEBUG "\n");
-#endif
- } /* end of if statement */
+ spin_lock_irqsave (&iucv_lock, flags);
+ P = handler_table_anchor + int_buf->ippathid;
+ Q = P->addrs;
+ interrupt = P->ops; /* interrupt functions */
+
+ pr_debug ("iucv: do_int: Handler\n");
+ iucv_dumpit ((uchar *) Q, sizeof (handler));
+ spin_unlock_irqrestore (&iucv_lock, flags);
+ }
+ /* end of if statement */
switch (int_buf->iptype) {
case 0x01: /* connection pending */
- spin_lock (&lock);
+ spin_lock_irqsave (&iucv_lock, flags);
for (R = handler_anchor; R != NULL; R = (handler *) R->next) {
memcpy (temp_buff1, &(int_buf->ipvmid), 24);
- memcpy (temp_buff2, &(R->vmid), 24);
+ memcpy (temp_buff2, &(R->id.userid), 24);
for (j = 0; j < 24; j++) {
- temp_buff1[j] = (temp_buff1[j]) & (R->mask)[j];
- temp_buff2[j] = (temp_buff2[j]) & (R->mask)[j];
+ temp_buff1[j] =
+ (temp_buff1[j]) & (R->id.mask)[j];
+ temp_buff2[j] =
+ (temp_buff2[j]) & (R->id.mask)[j];
}
-#ifdef DEBUG
- for (i = 0; i < sizeof (temp_buff1); i++)
- printk (KERN_DEBUG " %c ", temp_buff1[i]);
- printk (KERN_DEBUG "\n");
- for (i = 0; i < sizeof (temp_buff2); i++)
- printk (KERN_DEBUG " %c ", temp_buff2[i]);
- printk (KERN_DEBUG "\n");
-#endif
- if (memcmp((void *) temp_buff1,
- (void *) temp_buff2, 24) == 0) {
-#ifdef DEBUG
- printk (KERN_DEBUG
- "found a matching handler\n");
-#endif
+
+ pr_debug ("iucv:do_int: temp_buff1\n");
+ iucv_dumpit (temp_buff1, sizeof (temp_buff1));
+ pr_debug ("iucv:do_int: temp_buff2\n");
+ iucv_dumpit (temp_buff2, sizeof (temp_buff2));
+
+ if (memcmp ((void *) temp_buff1,
+ (void *) temp_buff2, 24) == 0) {
+
+ pr_debug
+ ("iucv:do_int: found a matching handler\n");
break;
}
}
- spin_unlock (&lock);
+ spin_unlock_irqrestore (&iucv_lock, flags);
+
if (R) {
/* ADD PATH TO PATHID TABLE */
- add_pathid_result =
- add_pathid (int_buf->ippathid, R, R->pgm_data);
+ add_pathid_result = iucv_add_pathid (int_buf->ippathid,
+ R, R->pgm_data);
if (add_pathid_result == NULL) {
interrupt = R->interrupt_table;
- if ((*interrupt).ConnectionPending) {
+ if (interrupt->ConnectionPending) {
+
EBCASC (int_buf->ipvmid, 8);
-
- ((*interrupt).
- ConnectionPending) (int_buf,
- R->pgm_data);
+
+ (interrupt->ConnectionPending)
+ ((iucv_ConnectionPending *) int_buf,
+ (R->pgm_data));
} else {
iucv_sever (int_buf->ippathid,
no_listener);
}
- } /* end if if(add_p...... */
+ } /* end of if(add_p...... */
else {
iucv_sever (int_buf->ippathid, no_listener);
-#ifdef DEBUG
- printk (KERN_DEBUG
- "add_pathid failed with rc = %d\n",
- (int) add_pathid_result);
-#endif
+ pr_debug ("iucv:do_int:add_pathid failed"
+ "with rc = %d\n",
+ (int) add_pathid_result);
}
} else
iucv_sever (int_buf->ippathid, no_listener);
break;
+
case 0x02: /*connection complete */
if (Q) {
- if ((*interrupt).ConnectionComplete)
- ((*interrupt).ConnectionComplete)
-
- ((iucv_ConnectionComplete *) int_buf,
- (P + index2)->pgm_data);
- else {
-#ifdef DEBUG
- printk (KERN_DEBUG
- "ConnectionComplete not called\n");
- printk (KERN_DEBUG "routine@ is %p\n",
- (*interrupt).ConnectionComplete);
-#endif
- }
+ if (interrupt->ConnectionComplete)
+ (interrupt->ConnectionComplete)
+ ((iucv_ConnectionComplete *) int_buf, (P->pgm_data));
+ else
+ pr_debug ("iucv:do_int:"
+ "ConnectionComplete not called\n");
}
+
break;
+
case 0x03: /* connection severed */
if (Q) {
- if ((*interrupt).ConnectionSevered)
- ((*interrupt).ConnectionSevered)
-
+ if (interrupt->ConnectionSevered)
+ (interrupt->ConnectionSevered)
((iucv_ConnectionSevered *) int_buf,
- (P + index2)->pgm_data);
+ (P->pgm_data));
+
else
iucv_sever (int_buf->ippathid, no_listener);
} else
iucv_sever (int_buf->ippathid, no_listener);
break;
+
case 0x04: /* connection quiesced */
if (Q) {
- if ((*interrupt).ConnectionQuiesced)
- ((*interrupt).ConnectionQuiesced)
-
+ if (interrupt->ConnectionQuiesced)
+ (interrupt->ConnectionQuiesced)
((iucv_ConnectionQuiesced *) int_buf,
- (P + index2)->pgm_data);
- else {
-#ifdef DEBUG
- printk (KERN_DEBUG
- "ConnectionQuiesced not called\n");
- printk (KERN_DEBUG "routine@ is %p\n",
- (*interrupt).ConnectionQuiesced);
-#endif
- }
+ (P->pgm_data));
+ else
+ pr_debug ("iucv:do_int:"
+ "ConnectionQuiesced not called\n");
}
break;
+
case 0x05: /* connection resumed */
if (Q) {
- if ((*interrupt).ConnectionResumed)
- ((*interrupt).ConnectionResumed)
-
- ((iucv_ConnectionResumed *) int_buf,
- (P + index2)->pgm_data);
- else {
-#ifdef DEBUG
- printk (KERN_DEBUG
- "ConnectionResumed not called\n");
- printk (KERN_DEBUG "routine@ is %p\n",
- (*interrupt).ConnectionResumed);
-#endif
- }
+ if (interrupt->ConnectionResumed)
+ (interrupt->ConnectionResumed)
+ ((iucv_ConnectionResumed *) int_buf, (P->pgm_data));
+ else
+ pr_debug ("iucv:do_int:"
+ "ConnectionResumed not called\n");
}
break;
+
case 0x06: /* priority message complete */
case 0x07: /* nonpriority message complete */
if (Q) {
- if ((*interrupt).MessageComplete)
- ((*interrupt).MessageComplete)
-
- ((iucv_MessageComplete *) int_buf,
- (P + index2)->pgm_data);
- else {
-#ifdef DEBUG
- printk (KERN_DEBUG
- "MessageComplete not called\n");
- printk (KERN_DEBUG "routine@ is %p\n",
- (*interrupt).MessageComplete);
-#endif
- }
+ if (interrupt->MessageComplete)
+ (interrupt->MessageComplete)
+ ((iucv_MessageComplete *) int_buf, (P->pgm_data));
+ else
+ pr_debug ("iucv:do_int:"
+ "MessageComplete not called\n");
}
break;
+
case 0x08: /* priority message pending */
case 0x09: /* nonpriority message pending */
if (Q) {
- if ((*interrupt).MessagePending)
- ((*interrupt).MessagePending)
-
- ((iucv_MessagePending *) int_buf,
- (P + index2)->pgm_data);
- else {
-#ifdef DEBUG
- printk (KERN_DEBUG
- "MessagePending not called\n");
- printk (KERN_DEBUG "routine@ is %p\n",
- (*interrupt).MessagePending);
-#endif
- }
+ if (interrupt->MessagePending)
+ (interrupt->MessagePending)
+ ((iucv_MessagePending *) int_buf, (P->pgm_data));
+ else
+ pr_debug ("iucv:do_int:"
+ "MessagePending not called\n");
}
break;
default: /* unknown iucv type */
- printk (KERN_DEBUG "unknown iucv interrupt \n");
+ printk (KERN_WARNING "iucv:do_int: unknown iucv interrupt \n");
break;
} /* end switch */
-#ifdef DEBUG3
- printk (KERN_DEBUG "BH:- Exiting do_int "
- "pathid %d, type %02X\n",
- int_buf->ippathid, int_buf->iptype);
-#endif
- return;
-} /* end of function call */
-
-/**************************************************************/
-/* Name: iucv_register_program */
-/* Purpose: registers a new handler */
-/* Input: pgmname- uchar[16], user id */
-/* userid - uchar[8], machine id */
-/* prmmask- mask */
-/* ops - pointer to iucv_interrupt_ops buffer */
-/* Output: new_handler - address of new handler */
-/**************************************************************/
-iucv_handle_t
-iucv_register_program (uchar pgmname[16],
- uchar userid[8],
- uchar pgmmask[24],
- iucv_interrupt_ops_t * ops, ulong pgm_data)
-{
- int rc;
- handler *new_handler = 0;
-#ifdef DEBUG
- int i;
- uchar *prt_parm;
- printk (KERN_DEBUG "enter iucv_register_program\n");
-#endif
- my_ops = *ops;
- /* Allocate handler table */
- new_handler = (handler *) kmalloc (sizeof (handler), GFP_KERNEL);
- if (new_handler == NULL) {
-#ifdef DEBUG
- printk (KERN_DEBUG
- "IUCV: returned NULL address for new handle \n");
-#endif
- return NULL;
- }
- /* fill in handler table */
- memcpy (new_handler->user_data, pgmname, 16);
- memcpy (new_handler->vmid, userid, 8);
- memcpy (new_handler->mask, pgmmask, 24);
- new_handler->pgm_data = pgm_data;
- /* Convert from ASCII to EBCDIC */
- if (new_handler->vmid) {
- ASCEBC (new_handler->vmid, 8);
- EBC_TOUPPER(new_handler->vmid, 8);
- }
- /* fill in handler table */
- new_handler->interrupt_table = ops;
- new_handler->size = ADDED_STOR;
- /* Allocate storage for pathid table */
- new_handler->start = kmalloc (ADDED_STOR * sizeof (ulong), GFP_KERNEL);
- if (new_handler->start == NULL) {
-#ifdef DEBUG
- printk (KERN_DEBUG
- "IUCV: returned NULL address for pathid table,"
- " exiting\n");
-#endif
- kfree(new_handler);
- return NULL;
- }
- memset (new_handler->start, 0, ADDED_STOR * sizeof (ulong));
- new_handler->end = (*new_handler).start + ADDED_STOR;
- new_handler->next = 0;
- new_handler->prev = 0;
- /* Place handler at beginning of chain */
- spin_lock (&lock);
- if (handler_anchor == NULL)
- handler_anchor = new_handler;
- else {
- handler_anchor->prev = (ulong *) new_handler;
- new_handler->next = (ulong *) handler_anchor;
- handler_anchor = new_handler;
-#ifdef DEBUG
- printk (KERN_DEBUG "adding a another handler to list\n");
- printk (KERN_DEBUG "handler_anchor->prev is %p \n",
- handler_anchor->prev);
- printk (KERN_DEBUG "new_handler->next is %p \n",
- new_handler->next);
- printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor);
-#endif
- }
- spin_unlock (&lock);
- if (declare_flag == NULL) {
- rc = iucv_declare_buffer (iucv_external_int_buffer);
- if (rc == 0) {
- declare_flag = 1;
- /* request the 0x4000 external interrupt */
- rc =
- register_external_interrupt (0x4000,
- top_half_interrupt);
- } else {
- panic ("Registration failed");
-#ifdef DEBUG
- printk (KERN_DEBUG "rc from declare buffer is: %i\n",
- rc);
-#endif
- }
- }
-#ifdef DEBUG
- printk (KERN_DEBUG "address of handle is %p ", new_handler);
- printk (KERN_DEBUG "size of handle is %d ", (int) (sizeof (handler)));
- printk (KERN_DEBUG "exit iucv_register_program\n");
- printk (KERN_DEBUG "main_table is %p \n", main_table);
- printk (KERN_DEBUG "handler_anchor is %p \n", handler_anchor);
- printk (KERN_DEBUG "Handler is: \n");
- prt_parm = (uchar *) new_handler;
- for (i = 0; i < sizeof (handler); i++)
- printk (KERN_DEBUG " %02x ", prt_parm[i]);
- printk (KERN_DEBUG "\n");
-#endif
- return new_handler; /* send buffer address back */
-} /* end of register function */
-/**************************************************************/
-/* Name: iucv_unregister */
-/* Purpose: remove handler from chain and sever all paths */
-/* Input: handle - address of handler to be severed */
-/* Output: returns 0 */
-/**************************************************************/
-int
-iucv_unregister (iucv_handle_t handle)
-{
- handler *temp_next = 0, *temp_prev = 0;
- handler *Q = 0, *R;
- handler_table_entry *H_T_E = 0;
- ulong *S = 0; /*points to the beginning of block of h_t_e's*/
-#ifdef DEBUG
- printk (KERN_DEBUG "enter iucv_unregister\n");
- printk (KERN_DEBUG "address of handle is %p ", handle);
- printk (KERN_DEBUG "size of handle is %u ", (int) (sizeof (handle)));
-#endif
- spin_lock (&lock);
- Q = (handler *) handle;
- /*
- * Checking if handle is still registered: if yes, continue
- * if not registered, return.
- */
- for (R = handler_anchor; R != NULL; R = (handler *) R->next)
- if (Q == R) {
-#ifdef DEBUG
- printk (KERN_DEBUG "found a matching handler\n");
-#endif
- break;
- }
- if (!R) {
- spin_unlock (&lock);
- return (0);
- }
- S = Q->start;
-#ifdef DEBUG
- printk (KERN_DEBUG "Q is handle? %p ", Q);
- printk (KERN_DEBUG "Q->start is %p ", Q->start);
- printk (KERN_DEBUG "&(Q->start) is %p ", &(Q->start));
- printk (KERN_DEBUG "Q->end is %p ", Q->end);
- printk (KERN_DEBUG "&(Q->end) is %p ", &(Q->end));
-#endif
- while (S < (Q->end)) { /* index thru table */
- if (*S) {
- H_T_E = (handler_table_entry *) (*S);
-#ifdef DEBUG
- printk (KERN_DEBUG "Pointer to H_T_E is %p ", H_T_E);
- printk (KERN_DEBUG "Address of handle in H_T_E is %p",
- (H_T_E->addrs));
-#endif
- if ((H_T_E->addrs) != handle) {
- spin_unlock (&lock);
- return (-2); /*handler addresses don't match */
- } else {
- spin_unlock (&lock);
- iucv_sever (H_T_E->pathid, Q->user_data);
- spin_lock (&lock);
- }
- }
- S++; /* index by size of ulong */
- }
- kfree (Q->start);
- temp_next = (handler *) Q->next; /* address of next handler on list */
- temp_prev = (handler *) Q->prev; /* address of prev handler on list */
- if ((temp_next != NULL) & (temp_prev != NULL)) {
- (*temp_next).prev = (ulong *) temp_prev;
- (*temp_prev).next = (ulong *) temp_next;
- } else if ((temp_next != NULL) & (temp_prev == NULL)) {
- (*temp_next).prev = NULL;
- handler_anchor = temp_next;
- } else if ((temp_next == NULL) & (temp_prev != NULL))
- (*temp_prev).next = NULL;
- else
- handler_anchor = NULL;
- if (handler_anchor == NULL)
- iucv_retrieve_buffer ();
- kfree (handle);
- spin_unlock (&lock);
-#ifdef DEBUG
- printk (KERN_DEBUG "exit iucv_unregister\n");
-#endif
- return 0;
+ pr_debug ("BH:- Exiting do_int "
+ "pathid %d, type %02X\n", int_buf->ippathid, int_buf->iptype);
+
+ return;
}
+/* end of function call */
EXPORT_SYMBOL (iucv_accept);
EXPORT_SYMBOL (iucv_connect);
EXPORT_SYMBOL (iucv_purge);
-EXPORT_SYMBOL (iucv_query);
+EXPORT_SYMBOL (iucv_query_maxconn);
+EXPORT_SYMBOL (iucv_query_bufsize);
EXPORT_SYMBOL (iucv_quiesce);
EXPORT_SYMBOL (iucv_receive);
-EXPORT_SYMBOL (iucv_receive_simple);
EXPORT_SYMBOL (iucv_receive_array);
EXPORT_SYMBOL (iucv_reject);
EXPORT_SYMBOL (iucv_reply);
EXPORT_SYMBOL (iucv_setmask);
EXPORT_SYMBOL (iucv_sever);
EXPORT_SYMBOL (iucv_register_program);
-EXPORT_SYMBOL (iucv_unregister);
-
+EXPORT_SYMBOL (iucv_unregister_program);
/*
- * drivers/s390/net/netiucv.h
+ * drivers/s390/net/iucv.h
* IUCV base support.
*
* S390 version
* Copyright (C) 2000 IBM Corporation
- * Author(s): Xenia Tkatschow (xenia@us.ibm.com)
+ * Author(s):Alan Altmark (Alan_Altmark@us.ibm.com)
+ * Xenia Tkatschow (xenia@us.ibm.com)
*
*
+ * Linux Kernel IUCV will not support a machine with storage > 2 GB.
+ *
* Functionality:
* To explore any of the IUCV functions, one must first register
- * their program using iucv_register(). Once your program has
- * successfully completed a register, it can use the other functions.
+ * their program using iucv_register_program(). Once your program has
+ * successfully completed a register, it can exploit the other functions.
* For furthur reference on all IUCV functionality, refer to the
* CP Programming Services book, also available on the web
- * thru www.ibm.com/s390/vm.
+ * thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
+ *
+ * Definition of Return Codes
+ * -All positive return codes including zero are reflected back
+ * from CP except for iucv_register_program. The definition of each
+ * return code can be found in CP Programming Services book.
+ * Also available on the web thru www.ibm.com/s390/vm/pubs, manual # SC24-5760
+ * - Return Code of:
+ * (-EINVAL) Invalid value
+ * (-ENOMEM) storage allocation failed
+ * pgmask defined in iucv_register_program will be set depending on input
+ * paramters.
+ *
*/
-#ifndef _IUCV_H
-#define _IUCV_H
+
+#include <linux/types.h>
#define uchar unsigned char
#define ushort unsigned short
#define ulong unsigned long
#define iucv_handle_t void *
-/***********************FLAGS*************************************/
-#define source_class 0x01
-#define target_class 0x01
-#define local_conn 0x01
-#define specify_pathid 0x02
-#define specify_msgid 0x04
-#define reply_array 0x08
-#define one_way_msg 0x10
-#define prior_msg 0x20
-#define array 0x40
-#define quiesce_msg 0x40
-#define parm_data 0x80
-#define IPRMDATA 0x80
-#define IPBUFLST 0x40
-#define IPPRTY 0x20
-#define IPNORPY 0x10
-#define IPANSLST 0x08
-#define IPFGMID 0x04
-#define IPFGPID 0x02
-#define IPFGMCL 0x01
-
-/*---------------------------------------------------------*/
-/* Mapping of external interrupt buffers */
-/* Names: iucv_ConnectionPending -> connection pending */
-/* iucv_ConnectionComplete -> connection complete */
-/* iucv_ConnectionSevered -> connection severed */
-/* iucv_ConnectionQuiesced -> connection quiesced */
-/* iucv_ConnectionResumed -> connection resumed */
-/* iucv_MessagePending -> message pending */
-/* iucv_MessageComplete -> message complete */
-/*---------------------------------------------------------*/
+
+/* flags1:
+ * All flags are defined in the field IPFLAGS1 of each function
+ * and can be found in CP Programming Services.
+ * IPLOCAL - Indicates the connect can only be satisfied on the
+ * local system
+ * IPPRTY - Indicates a priority message
+ * IPQUSCE - Indicates you do not want to receive messages on a
+ * path until an iucv_resume is issued
+ * IPRMDATA - Indicates that the message is in the parameter list
+ */
+#define IPLOCAL 0x01
+#define IPPRTY 0x20
+#define IPQUSCE 0x40
+#define IPRMDATA 0x80
+
+/* flags1_out:
+ * All flags are defined in the output field of IPFLAGS1 for each function
+ * and can be found in CP Programming Services.
+ * IPNORPY - Specifies this is a one-way message and no reply is expected.
+ * IPPRTY - Indicates a priority message is permitted. Defined in flags1.
+ */
+#define IPNORPY 0x10
+
+#define Nonpriority_MessagePendingInterruptsFlag 0x80
+#define Priority_MessagePendingInterruptsFlag 0x40
+#define Nonpriority_MessageCompletionInterruptsFlag 0x20
+#define Priority_MessageCompletionInterruptsFlag 0x10
+/*
+ * Mapping of external interrupt buffers should be used with the corresponding
+ * interrupt types.
+ * Names: iucv_ConnectionPending -> connection pending
+ * iucv_ConnectionComplete -> connection complete
+ * iucv_ConnectionSevered -> connection severed
+ * iucv_ConnectionQuiesced -> connection quiesced
+ * iucv_ConnectionResumed -> connection resumed
+ * iucv_MessagePending -> message pending
+ * iucv_MessageComplete -> message complete
+ */
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar ipflags1;
uchar iptype;
- ushort ipmsglim;
- ushort res1;
+ u16 ipmsglim;
+ u16 res1;
uchar ipvmid[8];
uchar ipuser[16];
- ulong res3;
+ u32 res3;
uchar ippollfg;
uchar res4[3];
} iucv_ConnectionPending;
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar ipflags1;
uchar iptype;
- ushort ipmsglim;
- ushort res1;
+ u16 ipmsglim;
+ u16 res1;
uchar res2[8];
uchar ipuser[16];
- ulong res3;
+ u32 res3;
uchar ippollfg;
uchar res4[3];
} iucv_ConnectionComplete;
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar res1;
uchar iptype;
- ulong res2;
+ u32 res2;
uchar res3[8];
uchar ipuser[16];
- ulong res4;
+ u32 res4;
uchar ippollfg;
uchar res5[3];
} iucv_ConnectionSevered;
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar res1;
uchar iptype;
- ulong res2;
+ u32 res2;
uchar res3[8];
uchar ipuser[16];
- ulong res4;
+ u32 res4;
uchar ippollfg;
uchar res5[3];
} iucv_ConnectionQuiesced;
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar res1;
uchar iptype;
- ulong res2;
+ u32 res2;
uchar res3[8];
uchar ipuser[16];
- ulong res4;
+ u32 res4;
uchar ippollfg;
uchar res5[3];
} iucv_ConnectionResumed;
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar ipflags1;
uchar iptype;
- ulong ipmsgid;
- ulong iptrgcls;
- ulong iprmmsg1;
+ u32 ipmsgid;
+ u32 iptrgcls;
+ uchar iprmmsg1[4];
union u1 {
- ulong ipbfln1f;
- ulong iprmmsg2;
+ u32 ipbfln1f;
+ uchar iprmmsg2[4];
} ln1msg2;
- ulong res1[3];
- ulong ipbfln2f;
+ u32 res1[3];
+ u32 ipbfln2f;
uchar ippollfg;
uchar res2[3];
} iucv_MessagePending;
typedef struct {
- ushort ippathid;
+ u16 ippathid;
uchar ipflags1;
uchar iptype;
- ulong ipmsgid;
- ulong ipaudit;
- ulong iprmmsg1;
- ulong iprmmsg2;
- ulong ipsrccls;
- ulong ipmsgtag;
- ulong res;
- ulong ipbfln2f;
+ u32 ipmsgid;
+ u32 ipaudit;
+ uchar iprmmsg[8];
+ u32 ipsrccls;
+ u32 ipmsgtag;
+ u32 res;
+ u32 ipbfln2f;
uchar ippollfg;
uchar res2[3];
} iucv_MessageComplete;
-/************************structures*************************/
-/*---------------------------------------------------------*/
-/*iucv_interrupt_ops_t: List of functions for interrupt */
-/* handling. */
-/*---------------------------------------------------------*/
-
+/*
+ * iucv_interrupt_ops_t: Is a vector of functions that handle
+ * IUCV interrupts.
+ * Parameter list:
+ * eib - is a pointer to a 40-byte area described
+ * with one of the structures above.
+ * pgm_data - this data is strictly for the
+ * interrupt handler that is passed by
+ * the application. This may be an address
+ * or token.
+*/
typedef struct {
void (*ConnectionPending) (iucv_ConnectionPending * eib,
- ulong pgm_data);
+ void *pgm_data);
void (*ConnectionComplete) (iucv_ConnectionComplete * eib,
- ulong pgm_data);
+ void *pgm_data);
void (*ConnectionSevered) (iucv_ConnectionSevered * eib,
- ulong pgm_data);
+ void *pgm_data);
void (*ConnectionQuiesced) (iucv_ConnectionQuiesced * eib,
- ulong pgm_data);
+ void *pgm_data);
void (*ConnectionResumed) (iucv_ConnectionResumed * eib,
- ulong pgm_data);
- void (*MessagePending) (iucv_MessagePending * eib,
- ulong pgm_data);
- void (*MessageComplete) (iucv_MessageComplete * eib,
- ulong pgm_data);
+ void *pgm_data);
+ void (*MessagePending) (iucv_MessagePending * eib, void *pgm_data);
+ void (*MessageComplete) (iucv_MessageComplete * eib, void *pgm_data);
} iucv_interrupt_ops_t;
-/*---------------------------------------------------------*/
-/*iucv_array_t : Defines buffer array */
-/*---------------------------------------------------------*/
-
+/*
+ *iucv_array_t : Defines buffer array.
+ * Inside the array may be 31- bit addresses and 31-bit lengths.
+*/
typedef struct {
- void *address;
- int length;
+ u32 address;
+ u32 length;
} iucv_array_t __attribute__ ((aligned (8)));
-/*************************-prototypes-******************************/
-
+/* -prototypes- */
+/*
+ * Name: iucv_register_program
+ * Purpose: Registers an application with IUCV
+ * Input: prmname - user identification
+ * userid - machine identification
+ * pgmmask - indicates which bits in the prmname and userid combined will be
+ * used to determine who is given control
+ * ops - address of vector of interrupt handlers
+ * pgm_data- application data passed to interrupt handlers
+ * Output: NA
+ * Return: address of handler
+ * (0) - Error occured, registration not completed.
+ * NOTE: Exact cause of failure will be recorded in syslog.
+*/
iucv_handle_t iucv_register_program (uchar pgmname[16],
uchar userid[8],
uchar pgmmask[24],
iucv_interrupt_ops_t * ops,
- ulong pgm_data);
-
-int iucv_unregister (iucv_handle_t handle);
-
-int iucv_purge (ulong msgid,
- ushort pathid,
- ulong srccls,
- uchar audit[4]);
-
-void iucv_query (ulong * bufsize,
- ulong * conmax);
-
-int iucv_quiesce (ushort pathid,
- uchar user_data[16]);
+ void *pgm_data);
+
+/*
+ * Name: iucv_unregister_program
+ * Purpose: Unregister application with IUCV
+ * Input: address of handler
+ * Output: NA
+ * Return: (0) - Normal return
+ * (-EINVAL) - Internal error, wild pointer
+*/
+int iucv_unregister_program (iucv_handle_t handle);
-int iucv_resume (ushort pathid,
- uchar user_data[16]);
-
-int iucv_reject (ushort pathid,
- ulong msgid,
- ulong trgcls);
-
-int iucv_setmask (uchar non_priority_interrupts,
- uchar priority_interrupts,
- uchar non_priority_completion_interrupts,
- uchar priority_completion_interrupts);
+/*
+ * Name: iucv_accept
+ * Purpose: This function is issued after the user receives a Connection Pending external
+ * interrupt and now wishes to complete the IUCV communication path.
+ * Input: pathid - u16 , Path identification number
+ * msglim_reqstd - u16, The number of outstanding messages requested.
+ * user_data - uchar[16], Data specified by the iucv_connect function.
+ * flags1 - int, Contains options for this path.
+ * -IPPRTY - 0x20- Specifies if you want to send priority message.
+ * -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ * in the parameter list.
+ * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
+ * established.
+ * handle - iucv_handle_t, Address of handler.
+ * pgm_data - void *, Application data passed to interrupt handlers.
+ * flags1_out - int * Contains information about the path
+ * - IPPRTY - 0x20, Indicates you may send priority messages.
+ * msglim - *u16, Number of outstanding messages.
+ * Output: return code from CP IUCV call.
+*/
+
+int iucv_accept (u16 pathid,
+ u16 msglim_reqstd,
+ uchar user_data[16],
+ int flags1,
+ iucv_handle_t handle,
+ void *pgm_data, int *flags1_out, u16 * msglim);
-int iucv_connect (ushort * pathid,
- ushort msglim,
+/*
+ * Name: iucv_connect
+ * Purpose: This function establishes an IUCV path. Although the connect may complete
+ * successfully, you are not able to use the path until you receive an IUCV
+ * Connection Complete external interrupt.
+ * Input: pathid - u16 *, Path identification number
+ * msglim_reqstd - u16, Number of outstanding messages requested
+ * user_data - uchar[16], 16-byte user data
+ * userid - uchar[8], User identification
+ * system_name - uchar[8], 8-byte identifying the system name
+ * flags1 - int, Contains options for this path.
+ * -IPPRTY - 0x20, Specifies if you want to send priority message.
+ * -IPRMDATA - 0x80, Specifies whether your program can handle a message
+ * in the parameter list.
+ * -IPQUSCE - 0x40, Specifies whether you want to quiesce the path being
+ * established.
+ * -IPLOCAL - 0X01, Allows an application to force the partner to be on
+ * the local system. If local is specified then target class cannot be
+ * specified.
+ * flags1_out - int * Contains information about the path
+ * - IPPRTY - 0x20, Indicates you may send priority messages.
+ * msglim - * u16, Number of outstanding messages
+ * handle - iucv_handle_t, Address of handler
+ * pgm_data - void *, Application data passed to interrupt handlers
+ * Output: return code from CP IUCV call
+ * rc - return code from iucv_declare_buffer
+ * -EINVAL - Invalid handle passed by application
+ * -EINVAL - Pathid address is NULL
+ * add_pathid_result - Return code from internal function add_pathid
+*/
+int
+ iucv_connect (u16 * pathid,
+ u16 msglim_reqstd,
uchar user_data[16],
uchar userid[8],
uchar system_name[8],
- uchar priority_requested,
- uchar prmdata,
- uchar quiesce,
- uchar control,
- uchar local,
- uchar * priority_permitted,
- iucv_handle_t handle,
- ulong pgm_data);
-
-int iucv_accept (ushort pathid,
- ushort msglim,
- uchar user_data[16],
- uchar priority_requested,
- uchar prmdata,
- uchar quiesce,
- uchar control,
- uchar * priority_permitted,
- iucv_handle_t handle,
- ulong pgm_data);
-
-int iucv_sever (ushort pathid,
- uchar user_data[16]);
-
-int iucv_receive (ushort pathid,
- ulong * msgid,
- ulong * trgcls,
- void *buffer, ulong buflen,
- uchar * reply_required,
- uchar * priority_msg,
- ulong * adds_curr_buffer,
- ulong * adds_curr_length);
-
-int iucv_receive_simple (ushort pathid,
- ulong msgid,
- ulong trgcls,
- void *buffer, ulong buflen);
-
-int iucv_receive_array (ushort pathid,
- ulong * msgid,
- ulong * trgcls,
+ int flags1,
+ int *flags1_out,
+ u16 * msglim, iucv_handle_t handle, void *pgm_data);
+
+/*
+ * Name: iucv_purge
+ * Purpose: This function cancels a message that you have sent.
+ * Input: pathid - Path identification number.
+ * msgid - Specifies the message ID of the message to be purged.
+ * srccls - Specifies the source message class.
+ * Output: audit - Contains information about asynchronous error
+ * that may have affected the normal completion
+ * of this message.
+ * Return: Return code from CP IUCV call.
+*/
+int iucv_purge (u16 pathid, u32 msgid, u32 srccls, uchar audit[3]);
+/*
+ * Name: iucv_query_maxconn
+ * Purpose: This function determines the maximum number of communication paths you
+ * may establish.
+ * Return: maxconn - ulong, Maximum number of connection the virtual machine may
+ * establish.
+*/
+ulong iucv_query_maxconn (void);
+
+/*
+ * Name: iucv_query_bufsize
+ * Purpose: This function determines how large an external interrupt
+ * buffer IUCV requires to store information.
+ * Return: bufsize - ulong, Size of external interrupt buffer.
+ */
+ulong iucv_query_bufsize (void);
+
+/*
+ * Name: iucv_quiesce
+ * Purpose: This function temporarily suspends incoming messages on an
+ * IUCV path. You can later reactivate the path by invoking
+ * the iucv_resume function.
+ * Input: pathid - Path identification number
+ * user_data - 16-bytes of user data
+ * Output: NA
+ * Return: Return code from CP IUCV call.
+*/
+int iucv_quiesce (u16 pathid, uchar user_data[16]);
+
+/*
+ * Name: iucv_receive
+ * Purpose: This function receives messages that are being sent to you
+ * over established paths. Data will be returned in buffer for length of
+ * buflen.
+ * Input:
+ * pathid - Path identification number.
+ * buffer - Address of buffer to receive.
+ * buflen - Length of buffer to receive.
+ * msgid - Specifies the message ID.
+ * trgcls - Specifies target class.
+ * Output:
+ * flags1_out: int *, Contains information about this path.
+ * IPNORPY - 0x10 Specifies this is a one-way message and no reply is
+ * expected.
+ * IPPRTY - 0x20 Specifies if you want to send priority message.
+ * IPRMDATA - 0x80 specifies the data is contained in the parameter list
+ * residual_buffer - address of buffer updated by the number
+ * of bytes you have received.
+ * residual_length -
+ * Contains one of the following values, if the receive buffer is:
+ * The same length as the message, this field is zero.
+ * Longer than the message, this field contains the number of
+ * bytes remaining in the buffer.
+ * Shorter than the message, this field contains the residual
+ * count (that is, the number of bytes remaining in the
+ * message that does not fit into the buffer. In this
+ * case b2f0_result = 5.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - buffer address is pointing to NULL
+*/
+int iucv_receive (u16 pathid,
+ u32 msgid,
+ u32 trgcls,
+ void *buffer,
+ ulong buflen,
+ int *flags1_out,
+ ulong * residual_buffer, ulong * residual_length);
+
+ /*
+ * Name: iucv_receive_array
+ * Purpose: This function receives messages that are being sent to you
+ * over established paths. Data will be returned in first buffer for
+ * length of first buffer.
+ * Input: pathid - Path identification number.
+ * msgid - specifies the message ID.
+ * trgcls - Specifies target class.
+ * buffer - Address of array of buffers.
+ * buflen - Total length of buffers.
+ * Output:
+ * flags1_out: int *, Contains information about this path.
+ * IPNORPY - 0x10 Specifies this is a one-way message and no reply is
+ * expected.
+ * IPPRTY - 0x20 Specifies if you want to send priority message.
+ * IPRMDATA - 0x80 specifies the data is contained in the parameter list
+ * residual_buffer - address points to the current list entry IUCV
+ * is working on.
+ * residual_length -
+ * Contains one of the following values, if the receive buffer is:
+ * The same length as the message, this field is zero.
+ * Longer than the message, this field contains the number of
+ * bytes remaining in the buffer.
+ * Shorter than the message, this field contains the residual
+ * count (that is, the number of bytes remaining in the
+ * message that does not fit into the buffer. In this
+ * case b2f0_result = 5.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
+ */
+int iucv_receive_array (u16 pathid,
+ u32 msgid,
+ u32 trgcls,
iucv_array_t * buffer,
- ulong * buflen,
- uchar * reply_required,
- uchar * priority_msg,
- ulong * adds_curr_buffer,
- ulong * adds_curr_length);
-
-int iucv_send (ushort pathid,
- ulong * msgid,
- ulong trgcls,
- ulong srccls,
- ulong msgtag,
- uchar priority_msg,
- void *buffer,
- ulong buflen);
-
-int iucv_send_array (ushort pathid,
- ulong * msgid,
- ulong trgcls,
- ulong srccls,
- ulong msgtag,
- uchar priority_msg,
- iucv_array_t * buffer,
- ulong buflen);
-
-int iucv_send_prmmsg (ushort pathid,
- ulong * msgid,
- ulong trgcls,
- ulong srccls,
- ulong msgtag,
- uchar priority_msg,
- uchar prmmsg[8]);
-
-int iucv_send2way (ushort pathid,
- ulong * msgid,
- ulong trgcls,
- ulong srccls,
- ulong msgtag,
- uchar priority_msg,
- void *buffer,
- ulong buflen,
- void *ansbuf,
- ulong anslen);
-
-int iucv_send2way_array (ushort pathid,
- ulong * msgid,
- ulong trgcls,
- ulong srccls,
- ulong msgtag,
- uchar priority_msg,
+ ulong buflen,
+ int *flags1_out,
+ ulong * residual_buffer, ulong * residual_length);
+
+/*
+ * Name: iucv_reject
+ * Purpose: The reject function refuses a specified message. Between the
+ * time you are notified of a message and the time that you
+ * complete the message, the message may be rejected.
+ * Input: pathid - Path identification number.
+ * msgid - Specifies the message ID.
+ * trgcls - Specifies target class.
+ * Output: NA
+ * Return: Return code from CP IUCV call.
+*/
+int iucv_reject (u16 pathid, u32 msgid, u32 trgcls);
+
+/*
+ * Name: iucv_reply
+ * Purpose: This function responds to the two-way messages that you
+ * receive. You must identify completely the message to
+ * which you wish to reply. ie, pathid, msgid, and trgcls.
+ * Input: pathid - Path identification number.
+ * msgid - Specifies the message ID.
+ * trgcls - Specifies target class.
+ * flags1 - Option for path.
+ * IPPRTY- 0x20, Specifies if you want to send priority message.
+ * buffer - Address of reply buffer.
+ * buflen - Length of reply buffer.
+ * Output: residual_buffer - Address of buffer updated by the number
+ * of bytes you have moved.
+ * residual_length - Contains on the the following values
+ * If the answer buffer is the same length as the reply, this field
+ * contains zero.
+ * If the answer buffer is longer than the reply, this field contains
+ * the number of bytes remaining in the buffer.
+ * If the answer buffer is shorter than the reply, this field contains
+ * a residual count (that is, the number of bytes remianing in the
+ * reply that does not fit into the buffer. In this
+ * case b2f0_result = 5.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
+*/
+int iucv_reply (u16 pathid,
+ u32 msgid,
+ u32 trgcls,
+ int flags1,
+ void *buffer, ulong buflen, ulong * residual_buffer,
+ ulong * residual_length);
+
+/*
+ * Name: iucv_reply_array
+ * Purpose: This function responds to the two-way messages that you
+ * receive. You must identify completely the message to
+ * which you wish to reply. ie, pathid, msgid, and trgcls.
+ * The array identifies a list of addresses and lengths of
+ * discontiguous buffers that contains the reply data.
+ * Input: pathid - Path identification number
+ * msgid - Specifies the message ID.
+ * trgcls - Specifies target class.
+ * flags1 - Option for path.
+ * IPPRTY- 0x20, Specifies if you want to send priority message.
+ * buffer - Address of array of reply buffers.
+ * buflen - Total length of reply buffers.
+ * Output: residual_buffer - Address of buffer which IUCV is currently working on.
+ * residual_length - Contains on the the following values
+ * If the answer buffer is the same length as the reply, this field
+ * contains zero.
+ * If the answer buffer is longer than the reply, this field contains
+ * the number of bytes remaining in the buffer.
+ * If the answer buffer is shorter than the reply, this field contains
+ * a residual count (that is, the number of bytes remianing in the
+ * reply that does not fit into the buffer. In this
+ * case b2f0_result = 5.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
+*/
+int iucv_reply_array (u16 pathid,
+ u32 msgid,
+ u32 trgcls,
+ int flags1,
+ iucv_array_t * buffer,
+ ulong buflen, ulong * residual_address,
+ ulong * residual_length);
+
+/*
+ * Name: iucv_reply_prmmsg
+ * Purpose: This function responds to the two-way messages that you
+ * receive. You must identify completely the message to
+ * which you wish to reply. ie, pathid, msgid, and trgcls.
+ * Prmmsg signifies the data is moved into the
+ * parameter list.
+ * Input: pathid - Path identification number.
+ * msgid - Specifies the message ID.
+ * trgcls - Specifies target class.
+ * flags1 - Option for path.
+ * IPPRTY- 0x20 Specifies if you want to send priority message.
+ * prmmsg - 8-bytes of data to be placed into the parameter.
+ * list.
+ * Output: NA
+ * Return: Return code from CP IUCV call.
+*/
+int iucv_reply_prmmsg (u16 pathid,
+ u32 msgid, u32 trgcls, int flags1, uchar prmmsg[8]);
+
+/*
+ * Name: iucv_resume
+ * Purpose: This function restores communications over a quiesced path
+ * Input: pathid - Path identification number.
+ * user_data - 16-bytes of user data.
+ * Output: NA
+ * Return: Return code from CP IUCV call.
+*/
+int iucv_resume (u16 pathid, uchar user_data[16]);
+
+/*
+ * Name: iucv_send
+ * Purpose: This function transmits data to another application.
+ * Data to be transmitted is in a buffer and this is a
+ * one-way message and the receiver will not reply to the
+ * message.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated with the message.
+ * flags1 - Option for path.
+ * IPPRTY- 0x20 Specifies if you want to send priority message.
+ * buffer - Address of send buffer.
+ * buflen - Length of send buffer.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
+*/
+int iucv_send (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls, u32 msgtag, int flags1, void *buffer, ulong buflen);
+
+/*
+ * Name: iucv_send_array
+ * Purpose: This function transmits data to another application.
+ * The contents of buffer is the address of the array of
+ * addresses and lengths of discontiguous buffers that hold
+ * the message text. This is a one-way message and the
+ * receiver will not reply to the message.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated witht the message.
+ * flags1 - Option for path.
+ * IPPRTY- specifies if you want to send priority message.
+ * buffer - Address of array of send buffers.
+ * buflen - Total length of send buffers.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
+*/
+int iucv_send_array (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls,
+ u32 msgtag,
+ int flags1, iucv_array_t * buffer, ulong buflen);
+
+/*
+ * Name: iucv_send_prmmsg
+ * Purpose: This function transmits data to another application.
+ * Prmmsg specifies that the 8-bytes of data are to be moved
+ * into the parameter list. This is a one-way message and the
+ * receiver will not reply to the message.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated with the message.
+ * flags1 - Option for path.
+ * IPPRTY- 0x20 specifies if you want to send priority message.
+ * prmmsg - 8-bytes of data to be placed into parameter list.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+*/
+int iucv_send_prmmsg (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls, u32 msgtag, int flags1, uchar prmmsg[8]);
+
+/*
+ * Name: iucv_send2way
+ * Purpose: This function transmits data to another application.
+ * Data to be transmitted is in a buffer. The receiver
+ * of the send is expected to reply to the message and
+ * a buffer is provided into which IUCV moves the reply
+ * to this message.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag associated with the message.
+ * flags1 - Option for path.
+ * IPPRTY- 0x20 Specifies if you want to send priority message.
+ * buffer - Address of send buffer.
+ * buflen - Length of send buffer.
+ * ansbuf - Address of buffer into which IUCV moves the reply of
+ * this message.
+ * anslen - Address of length of buffer.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer or ansbuf address is NULL.
+*/
+int iucv_send2way (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls,
+ u32 msgtag,
+ int flags1,
+ void *buffer, ulong buflen, void *ansbuf, ulong anslen);
+
+/*
+ * Name: iucv_send2way_array
+ * Purpose: This function transmits data to another application.
+ * The contents of buffer is the address of the array of
+ * addresses and lengths of discontiguous buffers that hold
+ * the message text. The receiver of the send is expected to
+ * reply to the message and a buffer is provided into which
+ * IUCV moves the reply to this message.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated with the message.
+ * flags1 - Option for path.
+ * IPPRTY- 0x20 Specifies if you want to send priority message.
+ * buffer - Sddress of array of send buffers.
+ * buflen - Total length of send buffers.
+ * ansbuf - Address of array of buffer into which IUCV moves the reply
+ * of this message.
+ * anslen - Address of length reply buffers.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
+*/
+int iucv_send2way_array (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls,
+ u32 msgtag,
+ int flags1,
iucv_array_t * buffer,
- ulong buflen,
- iucv_array_t * ansbuf,
- ulong anslen);
-
-int iucv_send2way_prmmsg (ushort pathid,
- ulong * msgid,
- ulong trgcls,
- ulong srccls,
- ulong msgtag,
- uchar priority_msg,
- uchar prmmsg[8],
- void *ansbuf,
- ulong anslen);
-
-int iucv_send2way_prmmsg_array (ushort pathid,
- ulong * msgid,
- ulong trgcls, ulong srccls,
- ulong msgtag,
- uchar priority_msg,
+ ulong buflen, iucv_array_t * ansbuf, ulong anslen);
+
+/*
+ * Name: iucv_send2way_prmmsg
+ * Purpose: This function transmits data to another application.
+ * Prmmsg specifies that the 8-bytes of data are to be moved
+ * into the parameter list. This is a two-way message and the
+ * receiver of the message is expected to reply. A buffer
+ * is provided into which IUCV moves the reply to this
+ * message.
+ * Input: pathid - Rath identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated with the message.
+ * flags1 - Option for path.
+ * IPPRTY- 0x20 Specifies if you want to send priority message.
+ * prmmsg - 8-bytes of data to be placed in parameter list.
+ * ansbuf - Address of buffer into which IUCV moves the reply of
+ * this message.
+ * anslen - Address of length of buffer.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Buffer address is NULL.
+*/
+int iucv_send2way_prmmsg (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls,
+ u32 msgtag,
+ ulong flags1,
+ uchar prmmsg[8], void *ansbuf, ulong anslen);
+
+/*
+ * Name: iucv_send2way_prmmsg_array
+ * Purpose: This function transmits data to another application.
+ * Prmmsg specifies that the 8-bytes of data are to be moved
+ * into the parameter list. This is a two-way message and the
+ * receiver of the message is expected to reply. A buffer
+ * is provided into which IUCV moves the reply to this
+ * message. The contents of ansbuf is the address of the
+ * array of addresses and lengths of discontiguous buffers
+ * that contain the reply.
+ * Input: pathid - Path identification number.
+ * trgcls - Specifies target class.
+ * srccls - Specifies the source message class.
+ * msgtag - Specifies a tag to be associated with the message.
+ * flags1 - Option for path.
+ * IPPRTY- 0x20 specifies if you want to send priority message.
+ * prmmsg - 8-bytes of data to be placed into the parameter list.
+ * ansbuf - Address of array of buffer into which IUCV moves the reply
+ * of this message.
+ * anslen - Address of length of reply buffers.
+ * Output: msgid - Specifies the message ID.
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Ansbuf address is NULL.
+*/
+int iucv_send2way_prmmsg_array (u16 pathid,
+ u32 * msgid,
+ u32 trgcls,
+ u32 srccls,
+ u32 msgtag,
+ int flags1,
uchar prmmsg[8],
- iucv_array_t * ansbuf,
- ulong anslen);
-int iucv_reply (ushort pathid,
- ulong msgid,
- ulong trgcls,
- uchar priority_msg,
- void *buf,
- ulong buflen);
-
-int iucv_reply_array (ushort pathid,
- ulong msgid,
- ulong trgcls,
- uchar priority_msg,
- iucv_array_t * buffer,
- ulong buflen);
-
-int iucv_reply_prmmsg (ushort pathid,
- ulong msgid,
- ulong trgcls,
- uchar priority_msg,
- uchar prmmsg[8]);
-
-#endif
+ iucv_array_t * ansbuf, ulong anslen);
+
+/*
+ * Name: iucv_setmask
+ * Purpose: This function enables or disables the following IUCV
+ * external interruptions: Nonpriority and priority message
+ * interrupts, nonpriority and priority reply interrupts.
+ * Input: SetMaskFlag - options for interrupts
+ * 0x80 - Nonpriority_MessagePendingInterruptsFlag
+ * 0x40 - Priority_MessagePendingInterruptsFlag
+ * 0x20 - Nonpriority_MessageCompletionInterruptsFlag
+ * 0x10 - Priority_MessageCompletionInterruptsFlag
+ * Output: NA
+ * Return: Return code from CP IUCV call.
+*/
+int iucv_setmask (int SetMaskFlag);
+
+/*
+ * Name: iucv_sever
+ * Purpose: This function terminates an IUCV path.
+ * Input: pathid - Path identification number.
+ * user_data - 16-bytes of user data.
+ * Output: NA
+ * Return: Return code from CP IUCV call.
+ * (-EINVAL) - Interal error, wild pointer.
+*/
+int iucv_sever (u16 pathid, uchar user_data[16]);
* Re-write: Alan Altmark (Alan_Altmark@us.ibm.com) Sept. 2000
* Uses iucv.c kernel module for IUCV services.
*
+ * 2.4 Updates Alan Altmark (Alan_Altmark@us.ibm.com) June 2001
+ * Update to use changed IUCV (iucv.c) interface.
+ *
* --------------------------------------------------------------------------
* An IUCV frame consists of one or more packets preceded by a 16-bit
* header. The header contains the offset to the next packet header,
* measured from the beginning of the _frame_. If zero, there are no more
* packets in the frame. Consider a frame which contains a 10-byte packet
* followed by a 20-byte packet:
- * +-----+----------------+-----+----------------------------+-----+
- * |h'12'| 10-byte packet |h'34'| 20-byte packet |h'00'|
- * +-----+----------------+-----+----------------------------+-----+
- * Offset: 0 2 12 14 34
+ * +-----+----------------+--------------------------------+-----+
+ * |h'12'| 10-byte packet |h'34'| 20-byte packet |h'00'|
+ * +-----+----------------+-----+--------------------------+-----+
+ * Offset: 0 2 12 14 34
*
* This means that each header will always have a larger value than the
* previous one (except for the final zero header, of course).
* --------------------------------------------------------------------------
*/
//#define DEBUG 1
+//#define DEBUG2 1
+//#define IPDEBUG 1
+#define LEVEL "1.1"
/* If MAX_DEVICES increased, add initialization data to iucv_netdev[] array */
/* (See bottom of program.) */
-#define MAX_DEVICES 10 /* Allows "iucv0" to "iucv9" */
+#define MAX_DEVICES 20 /* Allows "iucv0" to "iucv19" */
#define MAX_VM_MTU 32764 /* 32K IUCV buffer, minus 4 */
#define MAX_TX_Q 50 /* Maximum pending TX */
#include <linux/module.h>
MODULE_AUTHOR
("(C) 2000 IBM Corporation by Alan Altmark (Alan_Altmark@us.ibm.com)");
-MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver");
+MODULE_DESCRIPTION ("Linux for S/390 IUCV network driver " LEVEL);
MODULE_PARM (iucv, "1-" __MODULE_STRING (MAX_DEVICES) "s");
MODULE_PARM_DESC (iucv,
"Specify the userids associated with iucv0-iucv9:\n"
"iucv=userid1,userid2,...,userid10\n");
+#ifdef MODVERSIONS
+#include <linux/modversions.h>
+#endif
#else
#define MOD_INC_USE_COUNT
#define MOD_DEC_USE_COUNT
#include <linux/interrupt.h> /* mark_bh */
#include <linux/netdevice.h> /* struct net_device, etc. */
#include <linux/if_arp.h> /* ARPHRD_SLIP */
+#include <linux/ip.h> /* IP header */
#include <linux/skbuff.h> /* skb */
#include <linux/init.h> /* __setup() */
-#include <asm/io.h> /* virt_to_phys() */
#include <asm/string.h> /* memset, memcpy, etc. */
#include "iucv.h"
#define min(a,b) (a < b) ? a : b
-#ifdef DEBUG
+#if defined( DEBUG )
#undef KERN_INFO
#undef KERN_DEBUG
+#undef KERN_NOTICE
+#undef KERN_ERR
#define KERN_INFO KERN_EMERG
#define KERN_DEBUG KERN_EMERG
+#define KERN_NOTICE KERN_EMERG
+#define KERN_ERR KERN_EMERG
#endif
#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,3,0))
static int iucv_stop (net_device *);
static int iucv_change_mtu (net_device *, int);
static int iucv_init (net_device *);
-static void iucv_rx (net_device *, uchar *, int);
+static void iucv_rx (net_device *, u32, uchar *, int);
static int iucv_tx (struct sk_buff *, net_device *);
-static void connection_severed (iucv_ConnectionSevered *, ulong);
-static void connection_pending (iucv_ConnectionPending *, ulong);
-static void connection_complete (iucv_ConnectionComplete *, ulong);
-static void message_pending (iucv_MessagePending *, ulong);
-static void send_complete (iucv_MessageComplete *, ulong);
+static void connection_severed (iucv_ConnectionSevered *, void *);
+static void connection_pending (iucv_ConnectionPending *, void *);
+static void connection_complete (iucv_ConnectionComplete *, void *);
+static void message_pending (iucv_MessagePending *, void *);
+static void send_complete (iucv_MessageComplete *, void *);
void register_iucv_dev (int, char *);
static char iucv_userid[MAX_DEVICES][8];
net_device iucv_netdev[MAX_DEVICES];
-static char eodata[2] = { '\0', '\0' };
/* This structure is private to each device. It contains the */
/* information necessary to do IUCV operations. */
u16 pathid;
};
-struct iucvtag {
- iucv_array_t iucvvec[3];
- u16 framelen;
- struct sk_buff *skb;
-};
-
uchar iucv_host[8] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uchar iucvMagic[16] = { 0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40,
0xF0, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40, 0x40
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};
-#ifdef DEBUG
+#if defined( DEBUG2 ) || defined( IPDEBUG )
/*--------------------------*/
/* Dump buffer formatted */
/*--------------------------*/
iucv_start (net_device * dev)
{
int rc, i;
- uchar pri;
- uchar unused = '\0';
struct iucv_priv *p = (struct iucv_priv *) dev->priv;
pr_debug ("iucv_start(%s)\n", dev->name);
if (p == NULL) {
/* Allocate priv data */
p = (struct iucv_priv *) kmalloc (sizeof (struct iucv_priv),
- GFP_KERNEL);
+ GFP_ATOMIC);
if (p == NULL) {
printk (KERN_CRIT "%s: no memory for dev->priv.\n",
dev->name);
atomic_set (&p->state, FREE);
p->handle =
iucv_register_program (iucvMagic, p->userid2, (char *) mask,
- &netiucv_ops, (ulong) dev);
+ &netiucv_ops, (void *) dev);
if (p->handle <= 0) {
printk (KERN_ERR
- "%s: iucv_register_program error, rc=%i\n",
- dev->name, (int) p->handle);
+ "%s: iucv_register_program error, rc=%p\n",
+ dev->name, p->handle);
dev->priv = NULL;
kfree (p);
return -ENODEV;
rc =
iucv_connect (&(p->pathid), MAX_TX_Q, iucvMagic, p->userid2,
- iucv_host, unused, unused, unused, unused, unused,
- &pri, p->handle, (ulong) p);
+ iucv_host, 0, NULL, NULL, p->handle, p);
/* Some errors are not fatal. In these cases we will report "OK". */
switch (rc) {
pr_debug ("...waiting for connection to complete...");
return 0;
case 11: /* Wait for parter to connect */
- printk (KERN_NOTICE "Device %s: "
+ printk (KERN_NOTICE "%s: "
"User %s is not available now.\n",
dev->name, p->userid);
atomic_set (&p->state, FREE);
return 0;
case 12: /* Wait for partner to connect */
- printk (KERN_NOTICE "Device %s: "
+ printk (KERN_NOTICE "%s: "
"User %s is not ready to talk now.\n",
dev->name, p->userid);
atomic_set (&p->state, FREE);
return 0;
case 13: /* Fatal */
- printk (KERN_ERR "Device %s: "
+ printk (KERN_ERR "%s: "
"You have too many IUCV connections."
"Check MAXCONN in CP directory.\n", dev->name);
break;
case 14: /* Fatal */
- printk (KERN_ERR "Device %s: "
+ printk (KERN_ERR "%s: "
"User %s has too many IUCV connections."
"Check MAXCONN in CP directory.\n",
dev->name, p->userid);
break;
case 15: /* Fatal */
- printk (KERN_ERR "Device %s: "
+ printk (KERN_ERR "%s: "
"No IUCV authorization found in CP directory.\n",
dev->name);
break;
"return code %i from iucv_connect()\n", dev->name, rc);
}
- rc = iucv_unregister (p->handle);
+ rc = iucv_unregister_program (p->handle);
dev->priv = NULL;
kfree (p);
MOD_DEC_USE_COUNT;
/* Our connection TO another stack has been accepted. */
/*********************************************************************/
static void
-connection_complete (iucv_ConnectionComplete * cci, ulong pgm_data)
+connection_complete (iucv_ConnectionComplete * cci, void *pgm_data)
{
struct iucv_priv *p = (struct iucv_priv *) pgm_data;
pr_debug ("...%s connection complete... txq=%u\n",
p->dev->tx_queue_len = cci->ipmsglim;
netif_start (p->dev);
netif_start_queue (p->dev);
- printk (KERN_INFO "%s: Connection to user %s is up\n",
+ printk (KERN_NOTICE "%s: Connection to user %s is up\n",
p->dev->name, p->userid);
} /* end connection_complete() */
/* the remote user is the correct user. */
/*********************************************************************/
static void
-connection_pending (iucv_ConnectionPending * cpi, ulong pgm_data)
+connection_pending (iucv_ConnectionPending * cpi, void *pgm_data)
{
/* Only get this far if handler is set up, so we know userid is ok. */
/* and the device is started. */
net_device *dev = (net_device *) pgm_data;
struct iucv_priv *p = (struct iucv_priv *) dev->priv;
int rc;
+ u16 msglimit;
uchar udata[16];
- uchar no = '\0';
- uchar na;
/* If we're not waiting on a connect, reject the connection */
if (atomic_compare_and_swap (FREE, CONNECTING, &p->state) != 0) {
return;
}
- rc = iucv_accept (cpi->ippathid, /* Path id */
- MAX_TX_Q, /* msglimit */
+ rc = iucv_accept (cpi->ippathid, /* Path id */
+ MAX_TX_Q, /* desired IUCV msg limit */
udata, /* user_Data */
- no, /* will we send priority msgs? */
- no, /* do we accept prmdata? */
- no, /* quiece immediately? */
- no, /* control path? */
- &na, /* other side accept prmdata? */
- p->handle, /* registration handle */
- (ulong) p); /* private data */
+ 0, /* No flags */
+ p->handle, /* registration handle */
+ p, /* private data */
+ NULL, /* don't care about output flags */
+ &msglimit); /* Actual IUCV msg limit */
if (rc != 0) {
atomic_set (&p->state, FREE);
printk (KERN_ERR "%s: iucv accept failed rc=%i\n",
p->dev->name, rc);
} else {
+ atomic_set (&p->state, CONNECTED);
p->pathid = cpi->ippathid;
- p->dev->tx_queue_len = cpi->ipmsglim;
+ p->dev->tx_queue_len = (u32) msglimit;
netif_start (p->dev);
netif_start_queue (p->dev);
- atomic_set (&p->state, CONNECTED);
- printk (KERN_INFO "Device %s: Connection to user %s is up\n",
+ printk (KERN_NOTICE "%s: Connection to user %s is up\n",
p->dev->name, p->userid);
}
} /* end connection_pending() */
/* Our connection to another stack has been severed. */
/*********************************************************************/
static void
-connection_severed (iucv_ConnectionSevered * eib, ulong pgm_data)
+connection_severed (iucv_ConnectionSevered * eib, void *pgm_data)
{
struct iucv_priv *p = (struct iucv_priv *) pgm_data;
printk (KERN_INFO "%s: Connection to user %s is down\n",
p->dev->name, p->userid);
+ /* FIXME: We can also get a severed interrupt while in
+ state CONNECTING! Fix the state machine ... */
+#if 0
if (atomic_compare_and_swap (CONNECTED, FREE, &p->state) != 0)
return; /* In case reconnect in progress already */
+#else
+ atomic_set (&p->state, FREE);
+#endif
netif_stop_queue (p->dev);
netif_stop (p->dev);
if (p == NULL)
return 0;
- rc = iucv_unregister (p->handle); /* Will sever connections */
+ /* Unregister will sever associated connections */
+ rc = iucv_unregister_program (p->handle);
dev->priv = NULL;
kfree (p);
MOD_DEC_USE_COUNT;
/* separate packets, and send them to the "generic" packet processor. */
/*---------------------------------------------------------------------*/
static void
-message_pending (iucv_MessagePending * mpi, ulong pgm_data)
+message_pending (iucv_MessagePending * mpi, void *pgm_data)
{
struct iucv_priv *p = (struct iucv_priv *) pgm_data;
int rc;
void *buffer;
buffer_length = mpi->ln1msg2.ipbfln1f;
- pr_debug ("message_pending: ID=%p Length=%u\n", (void *) mpi->ipmsgid,
- buffer_length);
+ pr_debug ("%s: MP id=%i Length=%u\n",
+ p->dev->name, mpi->ipmsgid, buffer_length);
buffer = kmalloc (buffer_length, GFP_ATOMIC | GFP_DMA);
if (buffer == NULL) {
p->stats.rx_dropped++;
return;
}
-
- rc = iucv_receive_simple (p->pathid, mpi->ipmsgid, mpi->iptrgcls,
- buffer, buffer_length);
+ rc = iucv_receive (p->pathid, mpi->ipmsgid, mpi->iptrgcls,
+ buffer, buffer_length, NULL, NULL, NULL);
if (rc != 0 || buffer_length < 5) {
printk (KERN_INFO
- "%s: iucv_receive error. rc=%X, length=%u\n",
- p->dev->name, rc, buffer_length);
+ "%s: IUCV rcv error. rc=%X ID=%i length=%u\n",
+ p->dev->name, rc, mpi->ipmsgid, buffer_length);
p->stats.rx_errors++;
kfree (buffer);
return;
break;
} else {
/* Kick the packet upstairs */
- iucv_rx (p->dev,
+ iucv_rx (p->dev, mpi->ipmsgid,
buffer + prev_offset + 2,
packet_offset - prev_offset - 2);
prev_offset = packet_offset;
/* Add meta-data to packet and send upstairs. */
/*-------------------------------------------------------------*/
static void
-iucv_rx (net_device * dev, uchar * buf, int len)
+iucv_rx (net_device * dev, u32 msgid, uchar * buf, int len)
{
struct iucv_priv *p = (struct iucv_priv *) dev->priv;
struct sk_buff *skb;
- pr_debug ("%s: iucv_rx len=%u\n", p->dev->name, len);
-#ifdef DEBUG
+#ifdef IPDEBUG
+ printk (KERN_DEBUG "RX id=%i\n", msgid);
dumpit (buf, 20);
+ dumpit (buf + 20, 20);
#endif
+ pr_debug ("%s: RX len=%u\n", p->dev->name, len);
+
if (len > p->dev->mtu) {
printk (KERN_INFO
- "%s: inbound packet length %u exceeds MTU %i\n",
- p->dev->name, len, p->dev->mtu);
+ "%s: inbound packet id# %i length %u exceeds MTU %i\n",
+ p->dev->name, msgid, len, p->dev->mtu);
p->stats.rx_errors++;
return;
}
iucv_tx (struct sk_buff *skb, net_device * dev)
{
int rc, pktlen;
- struct iucvtag *tag;
+ u32 framelen, msgid;
+ void *frame;
struct iucv_priv *p = (struct iucv_priv *) dev->priv;
- if (skb == NULL) /* Nothing to do */
- return 0;
-
- if (netif_is_busy (dev)) {
- p->stats.tx_dropped++;
- dev_kfree_skb (skb);
- printk (KERN_ERR "%s: tx conflict! leave iucv_tx.\n",
+ if (skb == NULL) { /* Nothing to do */
+ printk (KERN_WARNING "%s: TX Kernel passed null sk_buffer\n",
dev->name);
- return -EBUSY;
+ p->stats.tx_dropped++;
+ return -EIO;
}
- netif_stop_queue (dev); /* transmission is busy */
+ if (netif_is_busy (dev))
+ return -EBUSY;
dev->trans_start = jiffies; /* save the timestamp */
- /* Tag contains data that must survive exit from this */
- /* routine. MessageComplete exit will free the tag */
- /* and any structures it points to. */
- tag =
- (struct iucvtag *) kmalloc (sizeof (struct iucvtag),
- GFP_DMA | GFP_KERNEL);
- if (!tag) {
+ /* IUCV frame will be released when MessageComplete */
+ /* interrupt is received. */
+ pktlen = skb->len;
+ framelen = pktlen + 4;
+
+ frame = kmalloc (framelen, GFP_ATOMIC | GFP_DMA);
+ if (!frame) {
p->stats.tx_dropped++;
dev_kfree_skb (skb);
- return -ENOMEM;
+ return 0;
}
- pktlen = skb->len;
- tag->framelen = (u16) pktlen + 2;
- tag->skb = skb;
- tag->iucvvec[0].address = &tag->framelen;
- tag->iucvvec[0].length = 2;
- tag->iucvvec[1].address = (void *) virt_to_phys (skb->data);
- tag->iucvvec[1].length = pktlen;
- tag->iucvvec[2].address = (void *) virt_to_phys (eodata);
- tag->iucvvec[2].length = 2;
- pr_debug ("iucv_tx: length=%i, skb=%p tag=%p\n", pktlen, tag->skb, tag);
-
- /* Ok, now the packet is ready for transmission: send it. */
- rc =
- iucv_send_array (p->pathid, NULL, 0, 0, (ulong) tag, 0,
- tag->iucvvec, pktlen + 4);
- if (rc == 0)
+ netif_stop_queue (dev); /* transmission is busy */
+
+ *(u16 *) frame = pktlen + 2; /* Set header */
+ memcpy (frame + 2, skb->data, pktlen); /* Copy data */
+ memset (frame + pktlen + 2, 0, 2); /* Set trailer */
+
+ /* Ok, now the frame is ready for transmission: send it. */
+ rc = iucv_send (p->pathid, &msgid, 0, 0,
+ (u32) frame, /* Msg tag */
+ 0, /* No flags */
+ frame, framelen);
+ if (rc == 0) {
+#ifdef IPDEBUG
+ printk (KERN_DEBUG "TX id=%i\n", msgid);
+ dumpit (skb->data, 20);
+ dumpit (skb->data + 20, 20);
+#endif
+ pr_debug ("%s: tx START %i.%i @=%p len=%i\n",
+ p->dev->name, p->pathid, msgid, frame, framelen);
p->stats.tx_packets++;
- else {
+ } else {
if (rc == 3) /* Exceeded MSGLIMIT */
p->stats.tx_dropped++;
else {
p->stats.tx_errors++;
- printk (KERN_INFO "%s: iucv send failed, rc=%i\n",
- p->dev->name, rc);
+ printk (KERN_INFO "%s: tx ERROR id=%i.%i rc=%i\n",
+ p->dev->name, p->pathid, msgid, rc);
}
- dev_kfree_skb (skb);
- kfree (tag);
+ /* We won't get interrupt. Free frame now. */
+ kfree (frame);
}
+ dev_kfree_skb (skb); /* Finished with skb */
netif_wake_queue (p->dev);
- return rc; /* zero == done; nonzero == fail */
+ return 0;
} /* end iucv_tx() */
/*-----------------------------------------------------------*/
/* SEND COMPLETE Called by IUCV handler. */
-/* Free SKB associated with this transmission and free */
-/* the IUCV buffer list and SKB pointer. */
+/* Free the IUCV frame that was used for this transmission. */
/*-----------------------------------------------------------*/
static void
-send_complete (iucv_MessageComplete * mci, ulong pgm_data)
+send_complete (iucv_MessageComplete * mci, void *pgm_data)
{
- struct iucvtag *tag = (struct iucvtag *) mci->ipmsgtag;
- pr_debug ("TX COMPLETE: Tag=%p skb=%p\n", tag, tag->skb);
- dev_kfree_skb (tag->skb);
- kfree (tag);
+ void *frame;
+#ifdef DEBUG
+ struct iucv_priv *p = (struct iucv_priv *) pgm_data;
+#endif
+ frame = (void *) (ulong) mci->ipmsgtag;
+ kfree (frame);
+ pr_debug ("%s: TX DONE %i.%i @=%p\n",
+ p->dev->name, mci->ippathid, mci->ipmsgid, frame);
} /* end send_complete() */
/*-----------------------------------------------------------*/
dev->type = ARPHRD_SLIP;
dev->tx_queue_len = MAX_TX_Q; /* Default - updated based on IUCV */
/* keep the default flags, just add NOARP and POINTOPOINT */
- dev->flags = IFF_NOARP | IFF_POINTOPOINT;
+ dev->flags |= IFF_NOARP | IFF_POINTOPOINT;
dev->mtu = 9216;
+ dev_init_buffers (dev);
pr_debug ("%s: iucv_init dev@=%p\n", dev->name, dev);
return 0;
}
i = devnumber = 0;
memset (temp_userid, ' ', 8);
temp_userid[8] = '\0';
+ printk (KERN_NOTICE "netiucv: IUCV network driver " LEVEL "\n");
if (!iucv)
init_return (0);
init_module (void)
{
int i;
+ printk (KERN_NOTICE "netiucv: IUCV network driver " LEVEL "\n");
for (i = 0; i < MAX_DEVICES; i++) {
if (iucv[i] == NULL)
break;
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
name: &iucv_names[0][0], /* Name filled in at load time */
#endif
- init: iucv_init /* probe function */
+ init: iucv_init /* probe function */
},
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
name: &iucv_names[1][0], /* Name filled in at load time */
#endif
- init: iucv_init /* probe function */
+ init: iucv_init /* probe function */
},
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
name: &iucv_names[2][0], /* Name filled in at load time */
#endif
- init: iucv_init /* probe function */
+ init: iucv_init /* probe function */
},
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
name: &iucv_names[3][0], /* Name filled in at load time */
#endif
- init: iucv_init /* probe function */
+ init: iucv_init /* probe function */
},
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
name: &iucv_names[4][0], /* Name filled in at load time */
#endif
- init: iucv_init /* probe function */
+ init: iucv_init /* probe function */
},
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
name: &iucv_names[5][0], /* Name filled in at load time */
#endif
- init: iucv_init /* probe function */
+ init: iucv_init /* probe function */
},
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
name: &iucv_names[6][0], /* Name filled in at load time */
#endif
- init: iucv_init /* probe function */
+ init: iucv_init /* probe function */
},
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
name: &iucv_names[7][0], /* Name filled in at load time */
#endif
- init: iucv_init /* probe function */
+ init: iucv_init /* probe function */
},
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
name: &iucv_names[8][0], /* Name filled in at load time */
#endif
- init: iucv_init /* probe function */
+ init: iucv_init /* probe function */
},
{
#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
name: &iucv_names[9][0], /* Name filled in at load time */
#endif
- init: iucv_init /* probe function */
+ init: iucv_init /* probe function */
+ },
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ name: &iucv_names[10][0], /* Name filled in at load time */
+#endif
+ init: iucv_init /* probe function */
+ },
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ name: &iucv_names[11][0], /* Name filled in at load time */
+#endif
+ init: iucv_init /* probe function */
+ },
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ name: &iucv_names[12][0], /* Name filled in at load time */
+#endif
+ init: iucv_init /* probe function */
+ },
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ name: &iucv_names[13][0], /* Name filled in at load time */
+#endif
+ init: iucv_init /* probe function */
+ },
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ name: &iucv_names[14][0], /* Name filled in at load time */
+#endif
+ init: iucv_init /* probe function */
+ },
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ name: &iucv_names[15][0], /* Name filled in at load time */
+#endif
+ init: iucv_init /* probe function */
+ },
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ name: &iucv_names[16][0], /* Name filled in at load time */
+#endif
+ init: iucv_init /* probe function */
+ },
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ name: &iucv_names[17][0], /* Name filled in at load time */
+#endif
+ init: iucv_init /* probe function */
+ },
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ name: &iucv_names[18][0], /* Name filled in at load time */
+#endif
+ init: iucv_init /* probe function */
+ },
+ {
+#if (LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0))
+ name: &iucv_names[19][0], /* Name filled in at load time */
+#endif
+ init: iucv_init /* probe function */
},
};
if (ioinfo->ui.flags.dval != 1 ||
ioinfo->devno != pdevreg->ci.devno)
continue;
- } else if ((flag & DEVREG_TYPE_DEVCHARS) &&
- (flag & DEVREG_EXACT_MATCH)) {
- if (pdevreg->ci.hc.ctype != sid->cu_type ||
- pdevreg->ci.hc.cmode != sid->cu_model ||
- pdevreg->ci.hc.dtype != sid->dev_type ||
- pdevreg->ci.hc.dmode != sid->dev_model)
- continue;
} else if (flag & DEVREG_TYPE_DEVCHARS) {
- if (!(flag & DEVREG_NO_CU_INFO) &&
- pdevreg->ci.hc.ctype != sid->cu_type)
+ if ( (flag & DEVREG_MATCH_CU_TYPE) &&
+ pdevreg->ci.hc.ctype != sid->cu_type )
continue;
-
- if (!(flag & DEVREG_NO_CU_INFO) &&
- !(flag & DEVREG_MATCH_CU_TYPE) &&
- pdevreg->ci.hc.cmode != sid->cu_model)
- continue;
-
- if (!(flag & DEVREG_NO_DEV_INFO) &&
- pdevreg->ci.hc.dtype != sid->dev_type)
- continue;
-
- if (!(flag & DEVREG_NO_DEV_INFO) &&
- !(flag & DEVREG_MATCH_DEV_TYPE) &&
- pdevreg->ci.hc.dmode != sid->dev_model)
- continue;
+ if ( (flag & DEVREG_MATCH_CU_MODEL) &&
+ pdevreg->ci.hc.cmode != sid->cu_model )
+ continue;
+ if ( (flag & DEVREG_MATCH_DEV_TYPE) &&
+ pdevreg->ci.hc.dtype != sid->dev_type )
+ continue;
+ if ( (flag & DEVREG_MATCH_DEV_MODEL) &&
+ pdevreg->ci.hc.dmode != sid->dev_model )
+ continue;
+ } else {
+ continue;
}
+
return pdevreg;
}
return NULL;
* decrease retry2 on busy while
* disabling sync_isc; reset isc_cnt
* on io error during sync_isc enablement
+ * 05/09/2001 Cornelia Huck added exploitation of debug feature
+ * 05/16/2001 Cornelia Huck added /proc/deviceinfo/<devno>/
+ * 05/22/2001 Cornelia Huck added /proc/cio_ignore
+ * un-ignore blacklisted devices by piping
+ * to /proc/cio_ignore
*/
#include <linux/module.h>
#include <linux/signal.h>
#include <linux/sched.h>
#include <linux/interrupt.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#include <linux/string.h>
#include <linux/smp.h>
#include <linux/threads.h>
#include <asm/s390io.h>
#include <asm/s390dyn.h>
#include <asm/s390mach.h>
+#include <asm/debug.h>
#ifndef TRUE
#define TRUE 1
static __u64 irq_IPL_TOD;
static adapter_int_handler_t adapter_handler = NULL;
+/* for use of debug feature */
+debug_info_t *cio_debug_msg_id = NULL;
+debug_info_t *cio_debug_trace_id = NULL;
+debug_info_t *cio_debug_crw_id = NULL;
+int cio_debug_initialized = 0;
+
static void init_IRQ_handler( int irq, void *dev_id, struct pt_regs *regs);
static void s390_process_subchannels( void);
static void s390_device_recognition_all( void);
static void s390_device_recognition_irq( int irq);
+static void s390_redo_validation(void);
static int s390_validate_subchannel( int irq, int enable);
static int s390_SenseID( int irq, senseid_t *sid, __u8 lpm);
static int s390_SetPGID( int irq, __u8 lpm, pgid_t *pgid);
static int enable_subchannel( unsigned int irq);
static int disable_subchannel( unsigned int irq);
-void chan_proc_init( void );
+static int chan_proc_init( void );
static inline void do_adapter_IO( __u32 intparm );
asmlinkage void do_IRQ( struct pt_regs regs );
+#define MAX_CIO_PROCFS_ENTRIES 0x300
+/* magic number; we want to have some room to spare */
+
+int cio_procfs_device_create(int devno);
+int cio_procfs_device_remove(int devno);
+int cio_procfs_device_purge(void);
+
+int cio_notoper_msg = 1;
+int cio_proc_devinfo = 0; /* switch off the /proc/deviceinfo/ stuff by default
+ until problems are dealt with */
/*
* "Blacklisting" of certain devices:
static dev_blacklist_range_t *dev_blacklist_range_head = NULL; /* Anchor for list of ranges */
static spinlock_t blacklist_lock = SPIN_LOCK_UNLOCKED;
+static int nr_blacklisted_ranges = 0;
/* Handling of the blacklist ranges */
static inline dev_blacklist_range_t *blacklist_range_create( int from, int to)
{
dev_blacklist_range_t *range = NULL;
- range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) );
+
+ if (to && (from>to)) {
+ printk("Invalid blacklist range %x to %x, skipping\n", from, to);
+ return NULL;
+ }
+ if (init_IRQ_complete) {
+ range = ( dev_blacklist_range_t *) kmalloc( sizeof( dev_blacklist_range_t ), GFP_KERNEL);
+ } else {
+ range = ( dev_blacklist_range_t *) alloc_bootmem( sizeof( dev_blacklist_range_t ) );
+ }
if (range == NULL)
return NULL;
memset( range, 0, sizeof( dev_blacklist_range_t ));
} else {
range->to = to;
}
+ nr_blacklisted_ranges++;
return range;
}
static inline void blacklist_range_destroy( dev_blacklist_range_t *range )
{
- kfree( range );
+ nr_blacklisted_ranges--;
+ /*
+ * FIXME: the memory was allocated as bootmem,
+ * how to get it free again ?!
+ */
+ /* kfree( range ); */
}
/*
/*
* Function: blacklist_range_add
* Creates a range from the specified arguments and appends it to the list of
- * blacklisted devices
+ * blacklisted devices
*/
static inline dev_blacklist_range_t *blacklist_range_add( int from, int to )
#ifdef CONFIG_DEBUG_IO
printk( "Reading blacklist...\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 6,
+ "Reading blacklist\n");
blacklist_split_parm_string( blacklist_parm_string );
blacklist_parse( blacklist );
}
#ifdef CONFIG_DEBUG_IO
printk( "Reading blacklist parameters...\n" );
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 6,
+ "Reading blacklist parameters\n");
blacklist_setup(str,&dummy);
blacklist_init(); /* Blacklist ranges must be ready when device recognition starts */
return 0;
}
+/*
+ * Function: blacklist_free_all_ranges
+ * set all blacklisted devices free...
+ */
+
+void blacklist_free_all_ranges(void)
+{
+ dev_blacklist_range_t *tmp = dev_blacklist_range_head;
+
+ while (tmp) {
+ blacklist_range_dechain(tmp);
+ blacklist_range_destroy(tmp);
+ tmp = dev_blacklist_range_head;
+ }
+}
+
+/*
+ * Function: blacklist_parse_proc_parameters
+ * parse the stuff which is piped to /proc/cio_ignore
+ */
+void blacklist_parse_proc_parameters(char *buf)
+{
+ char *tmp;
+ int i;
+ char *end;
+ int len = -1;
+ char *param;
+ int from = 0;
+ int to = 0;
+ int changed = 0;
+ dev_blacklist_range_t *range, *temp;
+
+ tmp = buf;
+ if (strstr(tmp, "free ")) {
+ for (i=0; i<5; i++) {
+ tmp++;
+ }
+ if (strstr(tmp, "all")) {
+ blacklist_free_all_ranges();
+ s390_redo_validation();
+ } else {
+ while (tmp != NULL) {
+ end = strchr(tmp, ',');
+ if (end == NULL) {
+ len = strlen(tmp) + 1;
+ } else {
+ len = (long)end - (long) tmp + 1;
+ *end = '\0';
+ end++;
+ }
+ param = (char*) kmalloc(len * sizeof(char) + 1, GFP_KERNEL);
+ strncpy(param, (const char *) tmp, len);
+ tmp = end;
+ from = blacklist_strtoul(param, ¶m);
+ if (*param == '-') {
+ param++;
+ to = blacklist_strtoul(param, ¶m);
+ } else {
+ to = from;
+ }
+ range = dev_blacklist_range_head;
+ while (range != NULL) {
+ temp = range->next;
+ if ((from <= range->from) && (to >= range->to)) {
+ blacklist_range_dechain(range);
+ blacklist_range_destroy(range);
+ changed = 1;
+ } else if ((from <= range->from) && (to>=range->from) && (to < range->to)) {
+ blacklist_range_add(to+1, range->to);
+ blacklist_range_dechain(range);
+ blacklist_range_destroy(range);
+ changed = 1;
+ } else if ((from > range->from) && (from<=range->to) && (to >= range->to)) {
+ blacklist_range_add(range->from, from-1);
+ blacklist_range_dechain(range);
+ blacklist_range_destroy(range);
+ changed = 1;
+ } else if ((from > range->from) && (to < range->to)) {
+ blacklist_range_add(range->from, from-1);
+ blacklist_range_add(to+1, range->to);
+ blacklist_range_dechain(range);
+ blacklist_range_destroy(range);
+ changed = 1;
+ }
+ range = temp;
+ }
+ kfree(param);
+ }
+ if (changed)
+ s390_redo_validation();
+ }
+ } else {
+ printk("cio_ignore: Parse error; try using 'free all|<devno-range>,<devno-range>,...'\n");
+ }
+}
+
/* End of blacklist handling */
void s390_displayhex(char *str,void *ptr,s32 cnt);
+void s390_displayhex2(char *str, void *ptr, s32 cnt, int level);
void s390_displayhex(char *str,void *ptr,s32 cnt)
{
}
}
+void s390_displayhex2(char *str, void *ptr, s32 cnt, int level)
+{
+ s32 cnt1, cnt2, maxcnt2;
+ u32 *currptr = (__u32 *)ptr;
+
+ debug_sprintf_event(cio_debug_msg_id, level, "%s\n", str);
+
+ for (cnt1 = 0; cnt1<cnt; cnt1+=16) {
+ debug_sprintf_event(cio_debug_msg_id, level, "%08lX ", (unsigned long)currptr);
+ maxcnt2 = cnt - cnt1;
+ if (maxcnt2 > 16)
+ maxcnt2 = 16;
+ for (cnt2 = 0; cnt2 < maxcnt2; cnt2 += 4)
+ debug_sprintf_event(cio_debug_msg_id, level, "%08X ", *currptr++);
+ }
+}
+
static int __init cio_setup( char *parm )
{
if ( !strcmp( parm, "yes") )
__setup("cio_msg=", cio_setup);
+static int __init cio_notoper_setup(char *parm)
+{
+ if (!strcmp(parm, "yes")) {
+ cio_notoper_msg = 1;
+ } else if (!strcmp(parm, "no")) {
+ cio_notoper_msg = 0;
+ } else {
+ printk("cio_notoper_setup: invalid cio_notoper_msg parameter '%s'", parm);
+ }
+
+ return 1;
+}
+
+__setup("cio_notoper_msg=", cio_notoper_setup);
+
+static int __init cio_proc_devinfo_setup(char *parm)
+{
+ if (!strcmp(parm, "yes")) {
+ cio_proc_devinfo = 1;
+ } else if (!strcmp(parm, "no")) {
+ cio_proc_devinfo = 0;
+ } else {
+ printk("cio_proc_devinfo_setup: invalid parameter '%s'\n",parm);
+ }
+
+ return 1;
+}
+
+__setup("cio_proc_devinfo=", cio_proc_devinfo_setup);
/*
* register for adapter interrupts
int s390_register_adapter_interrupt( adapter_int_handler_t handler )
{
int ret = 0;
+
+ if (cio_debug_initialized)
+ debug_text_event(cio_debug_trace_id, 4, "rgaint");
spin_lock( &adapter_lock );
int s390_unregister_adapter_interrupt( adapter_int_handler_t handler )
{
int ret = 0;
+
+ if (cio_debug_initialized)
+ debug_text_event(cio_debug_trace_id, 4, "urgaint");
spin_lock( &adapter_lock );
static inline void do_adapter_IO( __u32 intparm )
{
+ if (cio_debug_initialized)
+ debug_text_event(cio_debug_trace_id, 4, "doaio");
+
spin_lock( &adapter_lock );
if ( adapter_handler )
return;
}
-
int s390_request_irq_special( int irq,
io_handler_func_t io_handler,
not_oper_handler_func_t not_oper_handler,
{
int retval = 0;
unsigned long flags;
+ char dbf_txt[15];
if (irq >= __MAX_SUBCHANNELS)
return -EINVAL;
return -ENODEV;
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "reqsp");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* The following block of code has to be executed atomically
*/
int ret;
unsigned int count = 0;
+ char dbf_txt[15];
if ( irq >= __MAX_SUBCHANNELS || ioinfo[irq] == INVALID_STORAGE_AREA )
{
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 2, "free");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+ }
+
s390irq_spin_lock_irqsave( irq, flags);
#ifdef CONFIG_KERNEL_DEBUG
} /* endif */
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2, "Trying to free IRQ %d\n", irq);
/*
* disable the device and reset all IRQ info if
"count exceeded\n",
irq,
ioinfo[irq]->devstat.devno);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "free_irq(%04X) - device %04X busy, retry count exceeded\n",
+ irq, ioinfo[irq]->devstat.devno);
} /* endif */
s390irq_spin_unlock_irqrestore( irq, flags);
printk( "free_irq(%04X) : error, "
- "dev_id does not match !", irq);
+ "dev_id does not match !\n", irq);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "free_irq(%04X) : error, dev_id does not match !\n", irq);
} /* endif */
printk( "free_irq(%04X) : error, "
"no action block ... !\n", irq);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "free_irq(%04X) : error, no action block ... !\n", irq);
} /* endif */
{
unsigned long flags;
int ret;
+ char dbf_txt[15];
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
return( -ENODEV);
if ( !ioinfo[irq]->ui.flags.ready )
return -ENODEV;
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "disirq");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
s390irq_spin_lock_irqsave(irq, flags);
ret = disable_subchannel(irq);
s390irq_spin_unlock_irqrestore(irq, flags);
{
unsigned long flags;
int ret;
+ char dbf_txt[15];
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
return( -ENODEV);
if ( !ioinfo[irq]->ui.flags.ready )
return -ENODEV;
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "enirq");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
s390irq_spin_lock_irqsave(irq, flags);
ret = enable_subchannel(irq);
s390irq_spin_unlock_irqrestore(irq, flags);
int ret;
int ccode;
int retry = 5;
+ char dbf_txt[15];
if ( irq > highest_subchannel || irq < 0 )
{
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
return( -ENODEV);
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 2, "ensch");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+ }
+
/*
* If a previous disable request is pending we reset it. However, this
* status implies that the device may (still) be not-operational.
"%04X received !\n",
irq,
ioinfo[irq]->devstat.devno);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "enable_subchannel(%04X) : ccode 2 on msch() for device %04X received !\n",
+ irq, ioinfo[irq]->devstat.devno);
ret = -ENODEV; // never reached
}
int cc; /* condition code */
int ret; /* function return value */
int retry = 5;
+ char dbf_txt[15];
if ( irq > highest_subchannel )
{
}
else
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 2, "dissch");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+ }
+
/*
* If device isn't operational we have to perform delayed
* disabling when the next interrupt occurs - unless the
"device %04X received !\n",
irq,
ioinfo[irq]->devstat.devno);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "disable_subchannel(%04X) - unexpected busy condition for device %04X received !\n",
+ irq, ioinfo[irq]->devstat.devno);
ret = -EBUSY;
break;
unsigned long flags; /* PSW flags */
long cr6 __attribute__ ((aligned (8)));
- // Hopefully bh_count's will get set when we copy the prefix lowcore
- // structure to other CPI's ( DJB )
- softirq_active(smp_processor_id()) = 0;
- softirq_mask(smp_processor_id()) = 0;
- local_bh_count(smp_processor_id()) = 0;
- local_irq_count(smp_processor_id()) = 0;
- syscall_count(smp_processor_id()) = 0;
-
asm volatile ("STCK %0" : "=m" (irq_IPL_TOD));
p_init_schib = alloc_bootmem_low( sizeof(schib_t));
{
int ccode;
int ret = 0;
+ char buffer[80];
+ char dbf_txt[15];
/*
* The flag usage is mutal exclusive ...
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "stIO");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* setup ORB
*/
{
ret = -ENODEV;
ioinfo[irq]->ui.flags.oper = 0;
- }
+ }
else
{
ret = -EIO;
- } /* endif */
+ } /* endif */
ioinfo[irq]->devstat.flag |= DEVSTAT_NOT_OPER;
#ifdef CONFIG_DEBUG_IO
{
- char buffer[80];
stsch(irq, &(ioinfo[irq]->schib) );
} /* endif */
}
#endif
+ if (cio_debug_initialized) {
+ stsch(irq, &(ioinfo[irq]->schib) );
+
+ sprintf( buffer, "s390_start_IO(%04X) - irb for "
+ "device %04X, after status pending\n",
+ irq,
+ ioinfo[irq]->devstat.devno );
+
+ s390_displayhex2( buffer,
+ &(ioinfo[irq]->devstat.ii.irb) ,
+ sizeof(irb_t), 2);
+
+ sprintf( buffer, "s390_start_IO(%04X) - schib for "
+ "device %04X, after status pending\n",
+ irq,
+ ioinfo[irq]->devstat.devno );
+
+ s390_displayhex2( buffer,
+ &(ioinfo[irq]->schib) ,
+ sizeof(schib_t), 2);
+
+
+ if (ioinfo[irq]->devstat.flag & DEVSTAT_FLAG_SENSE_AVAIL) {
+ sprintf( buffer, "s390_start_IO(%04X) - sense "
+ "data for "
+ "device %04X, after status pending\n",
+ irq,
+ ioinfo[irq]->devstat.devno );
+
+ s390_displayhex2( buffer,
+ ioinfo[irq]->irq_desc.dev_id->ii.sense.data,
+ ioinfo[irq]->irq_desc.dev_id->rescnt, 2);
+
+ } /* endif */
+ }
}
else
{
&(ioinfo[irq]->devstat),
sizeof( devstat_t) );
+
#ifdef CONFIG_DEBUG_IO
- {
- char buffer[80];
stsch(irq, &(ioinfo[irq]->schib) );
s390_displayhex( buffer,
&(ioinfo[irq]->schib),
sizeof(schib_t));
- }
#endif
+ if (cio_debug_initialized) {
+ stsch(irq, &(ioinfo[irq]->schib) );
+
+ sprintf( buffer, "s390_start_IO(%04X) - schib for "
+ "device %04X, after 'not oper' status\n",
+ irq,
+ ioinfo[irq]->devstat.devno );
+
+ s390_displayhex2( buffer,
+ &(ioinfo[irq]->schib),
+ sizeof(schib_t), 2);
+ }
+
break;
} /* endswitch */
unsigned long flag) /* flags : see above */
{
int ret = 0;
+ char dbf_txt[15];
if ( irq > highest_subchannel || irq < 0 )
{
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "doIO");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* Note: We ignore the device operational status - if not operational,
* the SSCH will lead to an -ENODEV condition ...
int resume_IO( int irq)
{
int ret = 0;
+ char dbf_txt[15];
if ( irq > highest_subchannel || irq < 0 )
{
return( -ENODEV);
}
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "resIO");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* We allow for 'resume' requests only for active I/O operations
*/
{
int ret;
int ccode;
+ char dbf_txt[15];
if ( irq > highest_subchannel || irq < 0 )
{
- ret = -ENODEV;
+ return -ENODEV;
}
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
return( -ENODEV);
- }
+ }
/*
* we only allow for halt_IO if the device has an I/O handler associated
}
else
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 2, "haltIO");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+ }
/*
* If sync processing was requested we lock the sync ISC,
* modify the device to present interrupts for this ISC only
{
int ret;
int ccode;
+ char dbf_txt[15];
if ( irq > highest_subchannel || irq < 0 )
{
- ret = -ENODEV;
+ return -ENODEV;
}
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
}
else
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 2, "clearIO");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 2, dbf_txt);
+ }
/*
* If sync processing was requested we lock the sync ISC,
* modify the device to present interrupts for this ISC only
break;
case 1 : /* status pending */
-
+
ioinfo[irq]->devstat.flag |= DEVSTAT_STATUS_PENDING;
/*
ioinfo[irq]->devstat.flag &= ~DEVSTAT_NOT_OPER;
ioinfo[irq]->ui.flags.oper = 1;
- } /* endif */
+ } /* endif */
break;
return;
} /* endif */
-
#ifdef CONFIG_FAST_IRQ
do {
#endif /* CONFIG_FAST_IRQ */
int chnchk = 0;
devstat_t *dp;
devstat_t *udp;
+
+ char dbf_txt[15];
#if 0
int cpu = smp_processor_id();
kstat.irqs[cpu][irq]++;
#endif
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 3, "procIRQ");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 3, dbf_txt);
+ }
+
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
/* we can't properly process the interrupt ... */
udp = ioinfo[irq]->irq_desc.dev_id;
-#ifdef CONFIG_DEBUG_IO
/*
* It might be possible that a device was not-oper. at the time
* of free_irq() processing. This means the handler is no longer
{
if ( !ioinfo[irq]->ui.flags.d_disable )
{
+#ifdef CONFIG_DEBUG_IO
printk( KERN_CRIT"s390_process_IRQ(%04X) "
"- no interrupt handler registered "
"for device %04X !\n",
irq,
ioinfo[irq]->devstat.devno);
-
+#endif /* CONFIG_DEBUG_IO */
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "s390_process_IRQ(%04X) - no interrupt handler registered for device %04X !\n",
+ irq, ioinfo[irq]->devstat.devno);
} /* endif */
} /* endif */
-#endif
/*
* retrieve the i/o interrupt information (irb),
"residual count from irb after tsch() %d\n",
irq, dp->rescnt );
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 6,
+ "s390_process_IRQ( %04X ) : residual count from irq after tsch() %d\n",
+ irq, dp->rescnt);
} /* endif */
if ( (dp->ii.irb.scsw.cstat
& ( SCHN_STAT_CHN_DATA_CHK
| SCHN_STAT_CHN_CTRL_CHK
- | SCHN_STAT_INTF_CTRL_CHK ) )
- && (irq != cons_dev ) )
- {
- printk( "Channel-Check or Interface-Control-Check "
- "received\n"
- " ... device %04X on subchannel %04X, dev_stat "
- ": %02X sch_stat : %02X\n",
- ioinfo[irq]->devstat.devno,
- irq,
- dp->dstat,
- dp->cstat);
+ | SCHN_STAT_INTF_CTRL_CHK )))
+ {
+ if (irq != cons_dev)
+ printk( "Channel-Check or Interface-Control-Check "
+ "received\n"
+ " ... device %04X on subchannel %04X, dev_stat "
+ ": %02X sch_stat : %02X\n",
+ ioinfo[irq]->devstat.devno,
+ irq,
+ dp->dstat,
+ dp->cstat);
+ if (cio_debug_initialized) {
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "Channel-Check or Interface-Control-Check received\n");
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "... device %04X on subchannel %04X, dev_stat: %02X sch_stat: %02X\n",
+ ioinfo[irq]->devstat.devno, irq, dp->dstat, dp->cstat);
+ }
chnchk = 1;
"concurrent sense bytes avail %d\n",
irq, dp->scnt );
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 4,
+ "s390_process_IRQ( %04X ): concurrent sense bytes avail %d\n",
+ irq, dp->scnt);
}
else
{
s390_displayhex( buffer,
&(dp->ii.irb) ,
sizeof(irb_t));
+ if (cio_debug_initialized) {
+
+ sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
+ "device %04X after channel check\n",
+ irq,
+ dp->devno );
+
+ s390_displayhex2( buffer,
+ &(dp->ii.irb) ,
+ sizeof(irb_t), 0);
+ }
} /* endif */
ioinfo[irq]->stctl |= stctl;
* unsolicited interrupt applies to the console device
* itself !
*/
-#ifdef CONFIG_DEBUG_IO
- if ( ( irq != cons_dev )
- && !( stctl & SCSW_STCTL_ALERT_STATUS )
- && ( ioinfo[irq]->ui.flags.busy == 0 ) )
+ if ( !( stctl & SCSW_STCTL_ALERT_STATUS )
+ && ( ioinfo[irq]->ui.flags.busy == 0 ) )
{
char buffer[80];
-
- printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
- " ... device status : %02X subchannel status : %02X\n",
- dp->devno,
- irq,
- dp->dstat,
- dp->cstat);
-
+#ifdef CONFIG_DEBUG_IO
+ if (irq != cons_dev)
+ printk( "Unsolicited interrupt received for device %04X on subchannel %04X\n"
+ " ... device status : %02X subchannel status : %02X\n",
+ dp->devno,
+ irq,
+ dp->dstat,
+ dp->cstat);
+
sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
"device %04X, ending_status %d\n",
irq,
s390_displayhex( buffer,
&(dp->ii.irb) ,
sizeof(irb_t));
-
+#endif
+ if (cio_debug_initialized) {
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "Unsolicited interrupt received for device %04X on subchannel %04X\n"
+ " ... device status : %02X subchannel status : %02X\n",
+ dp->devno,
+ irq,
+ dp->dstat,
+ dp->cstat);
+ sprintf( buffer, "s390_process_IRQ(%04X) - irb for "
+ "device %04X, ending_status %d\n",
+ irq,
+ dp->devno,
+ ending_status);
+
+ s390_displayhex2( buffer,
+ &(dp->ii.irb) ,
+ sizeof(irb_t), 2);
+ }
} /* endif */
-#endif
/*
* take fast exit if no handler is available
*/
int sense_count = SENSE_MAX_COUNT-ioinfo[irq]->devstat.rescnt;
#ifdef CONFIG_DEBUG_IO
- if ( irq != cons_dev )
- printk( "s390_process_IRQ( %04X ) : "
- "BASIC SENSE bytes avail %d\n",
- irq, sense_count );
+ if ( irq != cons_dev )
+ printk( "s390_process_IRQ( %04X ) : "
+ "BASIC SENSE bytes avail %d\n",
+ irq, sense_count );
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 4,
+ "s390_process_IRQ( %04X ): BASIC SENSE bytes avail %d\n",
+ irq, sense_count);
ioinfo[irq]->ui.flags.w4sense = 0;
udp->flag |= DEVSTAT_FLAG_SENSE_AVAIL;
udp->scnt = sense_count;
printk( KERN_CRIT"s390_process_IRQ(%04x) encountered "
"negative sense count\n",
irq);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "s390_process_IRQ(%04x) encountered "
+ "negative sense count\n",
+ irq);
#endif
} /* endif */
}
int ccode;
unsigned long cr6 __attribute__ ((aligned (8)));
int rc = 0;
+ char dbf_txt[15];
if ( cons_dev != -1 )
{
}
else
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "scons");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* modify the indicated console device to operate
* on special console interrupt sublass 7
int rc = 0;
int ccode;
long cr6 __attribute__ ((aligned (8)));
+ char dbf_txt[15];
if ( cons_dev != -1 )
{
}
else
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "rcons");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* reset the indicated console device to operate
* on default console interrupt sublass 3
{
int rc = 0;
long save_cr6;
+ char dbf_txt[15];
if ( irq == cons_dev )
{
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "wcons");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* before entering the spinlock we may already have
* processed the interrupt on a different CPU ...
int count = 0;
int rc = 0;
+ char dbf_txt[15];
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "enisc");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
/* This one spins until it can get the sync_isc lock for irq# irq */
} /* endif */
+
if ( rc ) /* can only happen if stsch/msch fails */
{
sync_isc_cnt = 0;
int ccode;
long cr6 __attribute__ ((aligned (8)));
+ char dbf_txt[15];
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "disisc");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
if ( irq <= highest_subchannel && ioinfo[irq] != INVALID_STORAGE_AREA )
{
/*
int error = 0;
+ if (cio_debug_initialized)
+ debug_text_event(cio_debug_trace_id, 4, "VMvdinf");
+
if ( init_IRQ_complete )
{
p_diag_data = kmalloc( sizeof( diag210_t), GFP_DMA );
p_diag_data->vrdcrccl,
p_diag_data->vrdccrty,
p_diag_data->vrdccrmd );
+ if (cio_debug_initialized)
+ debug_sprintf_event( cio_debug_msg_id, 0,
+ "DIAG X'210' for "
+ "device %04X returned "
+ "(cc = %d): vdev class : %02X, "
+ "vdev type : %04X \n ... rdev class : %02X, rdev type : %04X, rdev model: %02X\n",
+ devno,
+ ccode,
+ p_diag_data->vrdcvcla,
+ p_diag_data->vrdcvtyp,
+ p_diag_data->vrdcrccl,
+ p_diag_data->vrdccrty,
+ p_diag_data->vrdccrmd );
} /* endif */
int emulated = 0;
int retry = 5;
+ char dbf_txt[15];
+
if ( !buffer || !length )
{
return( -EINVAL );
else if ( ioinfo[irq] == INVALID_STORAGE_AREA )
{
return( -ENODEV);
- }
+ }
if ( ioinfo[irq]->ui.flags.oper == 0 )
{
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "rddevch");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* Before playing around with irq locks we should assure
* running disabled on (just) our CPU. Sync. I/O requests
int found = 0; // RCD CIW found
int ret = 0; // return code
+ char dbf_txt[15];
+
if ( (irq > highest_subchannel) || (irq < 0 ) )
{
return( -ENODEV );
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "rdconf");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
/*
* scan for RCD command in extended SenseID data
*/
void s390_device_recognition_irq( int irq )
{
int ret;
+ char dbf_txt[15];
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "devrec");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
/*
* We issue the SenseID command on I/O subchannels we think are
int irq_ret;
devstat_t devstat;
- irq_ret = request_irq( irq,
+ irq_ret = request_irq( irq,
init_IRQ_handler,
0,
"INIT",
{
ret = enable_cpu_sync_isc( irq );
- if ( !ret )
+ if ( !ret )
{
ioinfo[irq]->ui.flags.unknown = 0;
if ( !ret ) // on success only ...
{
-#ifdef CONFIG_DEBUG_IO
char buffer[80];
-
+#ifdef CONFIG_DEBUG_IO
sprintf( buffer,
"RCD for device(%04X)/"
"subchannel(%04X) returns :\n",
s390_displayhex( buffer, prcd, lrcd );
#endif
+ if (cio_debug_initialized) {
+ sprintf( buffer,
+ "RCD for device(%04X)/"
+ "subchannel(%04X) returns :\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq );
+
+ s390_displayhex2( buffer, prcd, lrcd, 2);
+ }
if ( init_IRQ_complete )
{
kfree( prcd );
} /* endif */
- } /* endif */
-
- } /* endif */
+ } /* endif */
+
+ } /* endif */
#endif
s390_DevicePathVerification( irq, 0 );
}
+/*
+ * Function: s390_redo_validation
+ * Look for no longer blacklisted devices
+ * FIXME: there must be a better way to do this...
+ */
+
+void s390_redo_validation(void)
+{
+ int irq = 0;
+ int ret;
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 0, "redoval");
+ }
+ do {
+ if (ioinfo[irq] == INVALID_STORAGE_AREA) {
+ ret = s390_validate_subchannel(irq, 0);
+ if (!ret) {
+ s390_device_recognition_irq(irq);
+ if (ioinfo[irq]->ui.flags.oper) {
+ devreg_t *pdevreg;
+
+ pdevreg = s390_search_devreg( ioinfo[irq] );
+ if ( pdevreg != NULL ) {
+ if ( pdevreg->oper_func != NULL )
+ pdevreg->oper_func( irq, pdevreg );
+
+ }
+ }
+ if (cio_proc_devinfo)
+ if (irq < MAX_CIO_PROCFS_ENTRIES) {
+ cio_procfs_device_create(ioinfo[irq]->devno);
+ }
+ }
+ }
+ irq++;
+ } while (irq<=highest_subchannel);
+}
/*
* s390_search_devices
printk( "Highest subchannel number detected (hex) : %04X\n",
highest_subchannel);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "Highest subchannel number detected (hex) : %04X\n",
+ highest_subchannel);
}
/*
int ccode2; /* condition code for other I/O routines */
schib_t *p_schib;
int ret;
+
+ char dbf_txt[15];
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "valsch");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
/*
* The first subchannel that is not-operational (ccode==3)
"non-I/O subchannel type %04X\n",
irq,
p_schib->pmcw.st);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "Subchannel %04X reports non-I/O subchannel type %04X\n",
+ irq, p_schib->pmcw.st);
if ( ioinfo[irq] != INVALID_STORAGE_AREA )
ioinfo[irq]->ui.flags.oper = 0;
#ifdef CONFIG_DEBUG_IO
printk( "Blacklisted device detected at devno %04X\n", p_schib->pmcw.dev );
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "Blacklisted device detected at devno %04X\n",
+ p_schib->pmcw.dev);
ret = -ENODEV;
} else {
if ( ioinfo[irq] == INVALID_STORAGE_AREA )
ioinfo[irq]->schib.pmcw.pom);
} /* endif */
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "Detected device %04X "
+ "on subchannel %04X"
+ " - PIM = %02X, PAM = %02X, POM = %02X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq,
+ ioinfo[irq]->schib.pmcw.pim,
+ ioinfo[irq]->schib.pmcw.pam,
+ ioinfo[irq]->schib.pmcw.pom);
/*
* initialize ioinfo structure
{
printk( " ... msch() (2) failed with CC = %X\n",
ccode2 );
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "msch() (2) failed with CC=%X\n",
+ ccode2);
ioinfo[irq]->ui.flags.oper = 0;
ret = -EIO;
}
{
printk( " ... msch() (1) failed with CC = %X\n",
ccode2);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ "msch() (1) failed with CC = %X\n",
+ ccode2);
ioinfo[irq]->ui.flags.oper = 0;
ret = -EIO;
"subchannel %04X exceeded, CC = %d\n",
irq,
ccode2);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 0,
+ " ... msch() retry count for "
+ "subchannel %04X exceeded, CC = %d\n",
+ irq, ccode2);
} /* endif */
}
senseid_t *psid = sid;/* start with the external buffer */
int sbuffer = 0; /* switch SID data buffer */
+ char dbf_txt[15];
+
if ( (irq > highest_subchannel) || (irq < 0 ) )
{
return( -ENODEV );
} /* endif */
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "snsID");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
if ( !ioinfo[irq]->ui.flags.ready )
{
} /* endif */
if ( irq_ret == 0 )
- {
- int i;
+ {
+ int i;
s390irq_spin_lock( irq);
irq,
retry);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : device %04X on "
+ "Subchannel %04X "
+ "reports pending status, "
+ "retry : %d\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq,
+ retry);
} /* endif */
if ( pdevstat->flag & DEVSTAT_FLAG_SENSE_AVAIL )
ioinfo[irq]->schib.pmcw.dev,
irq);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : device %04X on "
+ "Subchannel %04X "
+ "reports cmd reject or "
+ "intervention required\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
io_retry = 1;
}
-#ifdef CONFIG_DEBUG_IO
+
else
{
+#ifdef CONFIG_DEBUG_IO
printk( "SenseID : UC on "
"dev %04X, "
"retry %d, "
pdevstat->ii.sense.data[5],
pdevstat->ii.sense.data[6],
pdevstat->ii.sense.data[7]);
-
- } /* endif */
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : UC on "
+ "dev %04X, "
+ "retry %d, "
+ "lpum %02X, "
+ "cnt %02d, "
+ "sns :"
+ " %02X%02X%02X%02X "
+ "%02X%02X%02X%02X ...\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ retry,
+ pdevstat->lpum,
+ pdevstat->scnt,
+ pdevstat->ii.sense.data[0],
+ pdevstat->ii.sense.data[1],
+ pdevstat->ii.sense.data[2],
+ pdevstat->ii.sense.data[3],
+ pdevstat->ii.sense.data[4],
+ pdevstat->ii.sense.data[5],
+ pdevstat->ii.sense.data[6],
+ pdevstat->ii.sense.data[7]);
+ } /* endif */
+
}
else if ( ( pdevstat->flag & DEVSTAT_NOT_OPER )
|| ( irq_ret == -ENODEV ) )
ioinfo[irq]->schib.pmcw.dev,
irq);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : path %02X for "
+ "device %04X on "
+ "subchannel %04X "
+ "is 'not operational'\n",
+ domask,
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
io_retry = 0;
ioinfo[irq]->opm &= ~domask;
}
-#ifdef CONFIG_DEBUG_IO
+
else if ( (pdevstat->flag !=
( DEVSTAT_START_FUNCTION
| DEVSTAT_FINAL_STATUS ) )
&& !(pdevstat->flag &
DEVSTAT_STATUS_PENDING ) )
{
+#ifdef CONFIG_DEBUG_IO
printk( "SenseID : start_IO() for "
"device %04X on "
"subchannel %04X "
irq_ret,
retry,
pdevstat->flag);
+#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : start_IO() for "
+ "device %04X on "
+ "subchannel %04X "
+ "returns %d, retry %d, "
+ "status %04X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq,
+ irq_ret,
+ retry,
+ pdevstat->flag);
} /* endif */
-#endif
+
}
else // we got it ...
{
ioinfo[irq]->schib.pmcw.dev,
irq);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : unknown device %04X on subchannel %04X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
ioinfo[irq]->ui.flags.unknown = 1;
} /* endif */
- if ( cio_show_msg )
- {
+
/*
* Issue device info message if unit was operational .
*/
- if ( !ioinfo[irq]->ui.flags.unknown )
- {
- if ( sid->dev_type != 0 )
- {
+ if ( !ioinfo[irq]->ui.flags.unknown ) {
+ if ( sid->dev_type != 0 ) {
+ if ( cio_show_msg )
printk( KERN_INFO"SenseID : device %04X reports: "
- "CU Type/Mod = %04X/%02X,"
- " Dev Type/Mod = %04X/%02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model,
- sid->dev_type,
- sid->dev_model);
- }
- else
- {
+ "CU Type/Mod = %04X/%02X,"
+ " Dev Type/Mod = %04X/%02X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ sid->cu_type,
+ sid->cu_model,
+ sid->dev_type,
+ sid->dev_model);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : device %04X reports: "
+ "CU Type/Mod = %04X/%02X,"
+ " Dev Type/Mod = %04X/%02X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ sid->cu_type,
+ sid->cu_model,
+ sid->dev_type,
+ sid->dev_model);
+ } else {
+ if ( cio_show_msg )
printk( KERN_INFO"SenseID : device %04X reports:"
- " Dev Type/Mod = %04X/%02X\n",
- ioinfo[irq]->schib.pmcw.dev,
- sid->cu_type,
- sid->cu_model);
-
- } /* endif */
-
+ " Dev Type/Mod = %04X/%02X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ sid->cu_type,
+ sid->cu_model);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SenseID : device %04X reports:"
+ " Dev Type/Mod = %04X/%02X\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ sid->cu_type,
+ sid->cu_model);
} /* endif */
} /* endif */
int ret = 0;
+ char dbf_txt[15];
+
+ if (cio_debug_initialized) {
+ debug_text_event(cio_debug_trace_id, 4, "dpver");
+ sprintf(dbf_txt, "%x", irq);
+ debug_text_event(cio_debug_trace_id, 4, dbf_txt);
+ }
+
if ( ioinfo[irq]->ui.flags.pgid_supp == 0 )
{
return( 0); // just exit ...
irq,
ioinfo[irq]->schib.pmcw.dev);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "PathVerification(%04X) "
+ "- Device %04X doesn't "
+ " support path grouping\n",
+ irq,
+ ioinfo[irq]->schib.pmcw.dev);
} /* endif */
}
- else if ( ret == -EIO )
+ else if ( ret == -EIO )
{
#ifdef CONFIG_DEBUG_IO
printk("PathVerification(%04X) - I/O error "
"on device %04X\n", irq,
ioinfo[irq]->schib.pmcw.dev);
#endif
+
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "PathVerification(%04X) - I/O error "
+ "on device %04X\n", irq,
+ ioinfo[irq]->schib.pmcw.dev);
+
ioinfo[irq]->ui.flags.pgid_supp = 0;
} else {
irq,
ioinfo[irq]->schib.pmcw.dev);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "PathVerification(%04X) - "
+ "Unexpected error on device %04X\n",
+ irq,
+ ioinfo[irq]->schib.pmcw.dev);
+
ioinfo[irq]->ui.flags.pgid_supp = 0;
} /* endif */
if ( irq_ret == 0 )
inlreq = 1;
- }
+ }
else
{
pdevstat = ioinfo[irq]->irq_desc.dev_id;
irq,
retry);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SPID - Device %04X "
+ "on Subchannel %04X "
+ "reports pending status, "
+ "retry : %d\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq,
+ retry);
} /* endif */
if ( pdevstat->flag == ( DEVSTAT_START_FUNCTION
pdevstat->ii.sense.data[5],
pdevstat->ii.sense.data[6],
pdevstat->ii.sense.data[7]);
-
#endif
- retry--;
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SPID - device %04X,"
+ " unit check,"
+ " retry %d, cnt %02d,"
+ " sns :"
+ " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ retry,
+ pdevstat->scnt,
+ pdevstat->ii.sense.data[0],
+ pdevstat->ii.sense.data[1],
+ pdevstat->ii.sense.data[2],
+ pdevstat->ii.sense.data[3],
+ pdevstat->ii.sense.data[4],
+ pdevstat->ii.sense.data[5],
+ pdevstat->ii.sense.data[6],
+ pdevstat->ii.sense.data[7]);
+
+ retry--;
+
} /* endif */
+
}
else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
{
- printk( "SPID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
+ /* don't issue warnings during startup unless requested*/
+ if (init_IRQ_complete || cio_notoper_msg) {
+
+ printk( "SPID - Device %04X "
+ "on Subchannel %04X "
+ "became 'not operational'\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SPID - Device %04X "
+ "on Subchannel %04X "
+ "became 'not operational'\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
+ }
retry = 0;
irq_ret = -EIO;
{
irq_ret = -EIO;
- } /* endif */
+ } /* endif */
if ( init_IRQ_complete )
{
pdevstat->ii.sense.data[7]);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SNID - device %04X,"
+ " unit check,"
+ " flag %04X, "
+ " retry %d, cnt %02d,"
+ " sns :"
+ " %02X%02X%02X%02X %02X%02X%02X%02X ...\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ pdevstat->flag,
+ retry,
+ pdevstat->scnt,
+ pdevstat->ii.sense.data[0],
+ pdevstat->ii.sense.data[1],
+ pdevstat->ii.sense.data[2],
+ pdevstat->ii.sense.data[3],
+ pdevstat->ii.sense.data[4],
+ pdevstat->ii.sense.data[5],
+ pdevstat->ii.sense.data[6],
+ pdevstat->ii.sense.data[7]);
retry--;
} /* endif */
}
else if ( pdevstat->flag & DEVSTAT_NOT_OPER )
{
- printk( "SNID - Device %04X "
- "on Subchannel %04X "
- "became 'not operational'\n",
- ioinfo[irq]->schib.pmcw.dev,
- irq);
+ /* don't issue warnings during startup unless requested*/
+ if (init_IRQ_complete || cio_notoper_msg) {
+ printk( "SNID - Device %04X "
+ "on Subchannel %04X "
+ "became 'not operational'\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SNID - Device %04X "
+ "on Subchannel %04X "
+ "became 'not operational'\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq);
+ }
retry = 0;
}
else if ( irq_ret != -ENODEV ) // -EIO, or -EBUSY
{
-#ifdef CONFIG_DEBUG_IO
+
if ( pdevstat->flag & DEVSTAT_STATUS_PENDING )
{
+#ifdef CONFIG_DEBUG_IO
printk( "SNID - Device %04X "
"on Subchannel %04X "
"reports pending status, "
ioinfo[irq]->schib.pmcw.dev,
irq,
retry);
- } /* endif */
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SNID - Device %04X "
+ "on Subchannel %04X "
+ "reports pending status, "
+ "retry : %d\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq,
+ retry);
+ } /* endif */
+
printk( "SNID - device %04X,"
" start_io() reports rc : %d, retrying ...\n",
ioinfo[irq]->schib.pmcw.dev,
irq_ret);
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2,
+ "SNID - device %04X,"
+ " start_io() reports rc : %d, retrying ...\n",
+ ioinfo[irq]->schib.pmcw.dev,
+ irq_ret);
retry--;
}
else // -ENODEV ...
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : starting ...\n");
#endif
-
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "do_crw_pending: starting\n");
while ( pcrwe != NULL )
{
int is_owned = 0;
printk( KERN_INFO"do_crw_pending : source is "
"subchannel %04X\n", irq);
#endif
-
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "source is subchannel %04X\n", irq);
/*
* If the device isn't known yet
* we can't lock it ...
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : subchannel validation - start ...\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 4,
+ "subchannel validation - start\n");
s390_validate_subchannel( irq, is_owned );
if ( irq > highest_subchannel )
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : subchannel validation - done\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 4,
+ "subchannel validation - done\n");
/*
* After the validate processing
* the ioinfo control block
} /* endif */
-#ifdef CONFIG_DEBUG_CRW
+
if ( ioinfo[irq] != INVALID_STORAGE_AREA )
{
+#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : ioinfo at %08X\n",
(unsigned)ioinfo[irq]);
-
- } /* endif */
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 4,
+ "ioinfo at %08X\n");
+ } /* endif */
+
if ( ioinfo[irq] != INVALID_STORAGE_AREA )
{
if ( ioinfo[irq]->ui.flags.oper == 0 )
{
not_oper_handler_func_t nopfunc=ioinfo[irq]->nopfunc;
+
+ /* remove procfs entry */
+ if (cio_proc_devinfo)
+ cio_procfs_device_remove(dev_no);
/*
* If the device has gone
* call not oper handler
*/
- if ( ( dev_oper == 1 )
- && ( nopfunc != NULL ) )
+ if (( dev_oper == 1 )
+ && ( nopfunc != NULL))
{
free_irq( irq,ioinfo[irq]->irq_desc.dev_id );
printk( "do_crw_pending : device "
"recognition - start ...\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 4,
+ "device recognition - start\n");
s390_device_recognition_irq( irq );
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : device "
"recognition - done\n");
#endif
-
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 4,
+ "device recognition - done\n");
/*
* the device became operational
*/
pdevreg->oper_func( irq, pdevreg );
} /* endif */
+
+ /* add new procfs entry */
+ if (cio_proc_devinfo)
+ if (highest_subchannel < MAX_CIO_PROCFS_ENTRIES) {
+ cio_procfs_device_create(ioinfo[irq]->devno);
+ }
}
/*
* ... it is and was operational, but
*/
else if ((ioinfo[irq]->devno != dev_no) && ( ioinfo[irq]->nopfunc != NULL ))
{
+ int devno_old = ioinfo[irq]->devno;
ioinfo[irq]->nopfunc( irq,
DEVSTAT_REVALIDATE );
+ /* remove old entry, add new */
+ if (cio_proc_devinfo) {
+ cio_procfs_device_remove(devno_old);
+ cio_procfs_device_create(ioinfo[irq]->devno);
+ }
} /* endif */
} /* endif */
+ /* get rid of dead procfs entries */
+ if (cio_proc_devinfo)
+ cio_procfs_device_purge();
+
} /* endif */
break;
printk( "do_crw_pending : source is "
"monitoring facility\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "source is monitoring facility\n");
break;
case CRW_RSC_CPATH :
printk( "do_crw_pending : source is "
"channel path %02X\n", chpid);
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "source is channel path %02X\n");
break;
case CRW_RSC_CONFIG :
printk( "do_crw_pending : source is "
"configuration-alert facility\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "source is configuration-alert facility\n");
break;
case CRW_RSC_CSS :
printk( "do_crw_pending : source is "
"channel subsystem\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "source is channel subsystem\n");
break;
default :
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : unknown source\n");
#endif
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "unknown source\n");
break;
} /* endswitch */
#ifdef CONFIG_DEBUG_CRW
printk( "do_crw_pending : done\n");
#endif
-
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_crw_id, 2,
+ "do_crw_pending: done\n");
return;
}
do_reipl( 0x10000 | sch );
}
-/* Display info on subchannels in /proc/subchannels. *
- * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01. */
+
+/*
+ * Function: cio_debug_init
+ * Initializes three debug logs (under /proc/s390dbf) for common I/O:
+ * - cio_msg logs the messages which are printk'ed when CONFIG_DEBUG_IO is on
+ * - cio_trace logs the calling of different functions
+ * - cio_crw logs the messages which are printk'ed when CONFIG_DEBUG_CRW is on
+ * debug levels depend on CONFIG_DEBUG_IO resp. CONFIG_DEBUG_CRW
+ */
+int cio_debug_init( void )
+{
+ int ret = 0;
+
+ cio_debug_msg_id = debug_register("cio_msg",2,4,16*sizeof(long));
+ if (cio_debug_msg_id != NULL) {
+ debug_register_view(cio_debug_msg_id, &debug_sprintf_view);
+#ifdef CONFIG_DEBUG_IO
+ debug_set_level(cio_debug_msg_id, 6);
+#else /* CONFIG_DEBUG_IO */
+ debug_set_level(cio_debug_msg_id, 2);
+#endif /* CONFIG_DEBUG_IO */
+ } else {
+ ret = -1;
+ }
+ cio_debug_trace_id = debug_register("cio_trace",4,4,8);
+ if (cio_debug_trace_id != NULL) {
+ debug_register_view(cio_debug_trace_id, &debug_hex_ascii_view);
+#ifdef CONFIG_DEBUG_IO
+ debug_set_level(cio_debug_trace_id, 6);
+#else /* CONFIG_DEBUG_IO */
+ debug_set_level(cio_debug_trace_id, 2);
+#endif /* CONFIG_DEBUG_IO */
+ } else {
+ ret = -1;
+ }
+ cio_debug_crw_id = debug_register("cio_crw",2,4,16*sizeof(long));
+ if (cio_debug_crw_id != NULL) {
+ debug_register_view(cio_debug_crw_id, &debug_sprintf_view);
+#ifdef CONFIG_DEBUG_CRW
+ debug_set_level(cio_debug_crw_id, 6);
+#else /* CONFIG_DEBUG_CRW */
+ debug_set_level(cio_debug_crw_id, 2);
+#endif /* CONFIG_DEBUG_CRW */
+ } else {
+ ret = -1;
+ }
+ if (ret)
+ return ret;
+ cio_debug_initialized = 1;
+ return 0;
+}
+
+__initcall(cio_debug_init);
+
+/*
+ * Display info on subchannels in /proc/subchannels.
+ * Adapted from procfs stuff in dasd.c by Cornelia Huck, 02/28/01.
+ */
typedef struct {
char *data;
release:chan_subch_close,
};
-void chan_proc_init( void )
+static int chan_proc_init( void )
{
chan_subch_entry = create_proc_entry( "subchannels", S_IFREG|S_IRUGO, &proc_root);
chan_subch_entry->proc_fops = &chan_subch_file_ops;
+
+ return 1;
}
__initcall(chan_proc_init);
remove_proc_entry( "subchannels", &proc_root);
}
+/*
+ * Display device specific information under /proc/deviceinfo/<devno>
+ */
+
+static struct proc_dir_entry *cio_procfs_deviceinfo_root = NULL;
+
+/*
+ * cio_procfs_device_list holds all devno-specific procfs directories
+ */
+
+typedef struct {
+ int devno;
+ struct proc_dir_entry *cio_device_entry;
+ struct proc_dir_entry *cio_sensedata_entry;
+ struct proc_dir_entry *cio_in_use_entry;
+ struct proc_dir_entry *cio_chpid_entry;
+} cio_procfs_entry_t;
+
+typedef struct _cio_procfs_device{
+ struct _cio_procfs_device *next;
+ cio_procfs_entry_t *entry;
+} cio_procfs_device_t;
+
+cio_procfs_device_t *cio_procfs_device_list = NULL;
+
+/*
+ * File operations
+ */
+
+static int cio_device_entry_close( struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+ if (p_info) {
+ if (p_info->data)
+ vfree( p_info->data );
+ vfree( p_info );
+ }
+
+ return rc;
+}
+
+static ssize_t cio_device_entry_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+{
+ loff_t len;
+ tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+ if ( *offset>=p_info->len) {
+ return 0;
+ } else {
+ len = MIN(user_len, (p_info->len - *offset));
+ if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+ return -EFAULT;
+ (* offset) += len;
+ return len;
+ }
+}
+
+int cio_search_devno_by_inode(struct inode *inode)
+{
+ int devno = -1;
+ struct proc_dir_entry *pde;
+ cio_procfs_device_t *tmp;
+
+ pde = (struct proc_dir_entry *)inode->u.generic_ip;
+ tmp = cio_procfs_device_list;
+
+ while (tmp) {
+ if ((tmp->entry->cio_device_entry == pde) ||
+ (tmp->entry->cio_sensedata_entry == pde) ||
+ (tmp->entry->cio_in_use_entry == pde) ||
+ (tmp->entry->cio_chpid_entry == pde))
+ break;
+ tmp = tmp->next;
+ }
+
+ if (tmp)
+ devno = tmp->entry->devno;
+
+ return devno;
+}
+
+
+static int cio_sensedata_entry_open( struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int size = 1;
+ int len = 0;
+ tempinfo_t *info;
+ int irq;
+ int devno;
+
+ info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+ if (info == NULL) {
+ printk( KERN_WARNING "No memory available for data\n");
+ rc = -ENOMEM;
+ } else {
+ file->private_data = (void *) info;
+ size += 2 * 32;
+ info->data = (char *) vmalloc(size);
+ if (size && info->data == NULL) {
+ printk(KERN_WARNING "No memory available for data\n");
+ vfree(info);
+ rc = -ENOMEM;
+ } else {
+ devno = cio_search_devno_by_inode(inode);
+ if (devno != 0xFFFF) {
+ irq = get_irq_by_devno(devno);
+ if (irq != -1) {
+ len += sprintf(info->data+len, "Dev Type/Mod: ");
+ if (ioinfo[irq]->senseid.dev_type == 0) {
+ len += sprintf(info->data+len, "%04X/%02X\n",
+ ioinfo[irq]->senseid.cu_type,
+ ioinfo[irq]->senseid.cu_model);
+ } else {
+ len += sprintf(info->data+len, "%04X/%02X\n",
+ ioinfo[irq]->senseid.dev_type,
+ ioinfo[irq]->senseid.dev_model);
+ len+= sprintf(info->data+len, "CU Type/Mod: %04X/%02X\n",
+ ioinfo[irq]->senseid.cu_type,
+ ioinfo[irq]->senseid.cu_model);
+ }
+ }
+ }
+ info->len = len;
+ }
+ }
+
+ return rc;
+}
+
+static int cio_in_use_entry_open( struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int size = 1;
+ int len = 0;
+ tempinfo_t *info;
+ int irq;
+ int devno;
+
+ info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+ if (info == NULL) {
+ printk( KERN_WARNING "No memory available for data\n");
+ rc = -ENOMEM;
+ } else {
+ file->private_data = (void *) info;
+ size += 8;
+ info->data = (char *) vmalloc(size);
+ if (size && info->data == NULL) {
+ printk(KERN_WARNING "No memory available for data\n");
+ vfree(info);
+ rc = -ENOMEM;
+ } else {
+ devno = cio_search_devno_by_inode(inode);
+ if (devno != -1) {
+ irq = get_irq_by_devno(devno);
+ if (irq != -1) {
+ len += sprintf(info->data+len, "%s\n", ioinfo[irq]->ui.flags.ready?"yes":"no");
+ }
+ }
+ info->len = len;
+ }
+ }
+
+ return rc;
+}
+
+static int cio_chpid_entry_open( struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int size = 1;
+ int len = 0;
+ tempinfo_t *info;
+ int irq;
+ int devno;
+ int i;
+
+ info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+ if (info == NULL) {
+ printk( KERN_WARNING "No memory available for data\n");
+ rc = -ENOMEM;
+ } else {
+ file->private_data = (void *) info;
+ size += 8*16;
+ info->data = (char *) vmalloc(size);
+ if (size && info->data == NULL) {
+ printk(KERN_WARNING "No memory available for data\n");
+ vfree(info);
+ rc = -ENOMEM;
+ } else {
+ devno = cio_search_devno_by_inode(inode);
+ if (devno != -1) {
+ irq = get_irq_by_devno(devno);
+ if (irq != -1) {
+ for (i=0; i<8; i++) {
+ len += sprintf(info->data+len, "CHPID[%d]: ", i);
+ len += sprintf(info->data+len, "%02X\n", ioinfo[irq]->schib.pmcw.chpid[i]);
+ }
+ }
+ }
+ info->len = len;
+ }
+ }
+
+ return rc;
+}
+
+static struct file_operations cio_sensedata_entry_file_ops =
+{
+ read:cio_device_entry_read,
+ open:cio_sensedata_entry_open,
+ release:cio_device_entry_close,
+};
+
+static struct file_operations cio_in_use_entry_file_ops =
+{
+ read:cio_device_entry_read,
+ open:cio_in_use_entry_open,
+ release:cio_device_entry_close,
+};
+
+static struct file_operations cio_chpid_entry_file_ops =
+{
+ read:cio_device_entry_read,
+ open:cio_chpid_entry_open,
+ release:cio_device_entry_close,
+};
+
+/*
+ * Function: cio_procfs_device_create
+ * create procfs entry for given device number
+ * and insert it into list
+ */
+int cio_procfs_device_create(int devno)
+{
+ cio_procfs_entry_t *entry;
+ cio_procfs_device_t *tmp;
+ cio_procfs_device_t *where;
+ char buf[8];
+ int i;
+ int rc = 0;
+
+
+ /* create the directory entry */
+ entry = (cio_procfs_entry_t *)kmalloc(sizeof(cio_procfs_entry_t), GFP_KERNEL);
+ if (entry) {
+ entry->devno = devno;
+ sprintf(buf, "%x", devno);
+ entry->cio_device_entry = proc_mkdir(buf, cio_procfs_deviceinfo_root);
+
+ if (entry->cio_device_entry) {
+ tmp = (cio_procfs_device_t *)kmalloc(sizeof(cio_procfs_device_t), GFP_KERNEL);
+ if (tmp) {
+ tmp->entry = entry;
+
+ if (cio_procfs_device_list == NULL) {
+ cio_procfs_device_list = tmp;
+ tmp->next = NULL;
+ } else {
+ where = cio_procfs_device_list;
+ i = where->entry->devno;
+ while ((devno>i) && (where->next != NULL)) {
+ where = where->next;
+ i = where->entry->devno;
+ }
+ if (where->next == NULL) {
+ where->next = tmp;
+ tmp->next = NULL;
+ } else {
+ tmp->next = where->next;
+ where->next = tmp;
+ }
+ }
+ /* create the different entries */
+ entry->cio_sensedata_entry = create_proc_entry( "sensedata", S_IFREG|S_IRUGO, entry->cio_device_entry);
+ entry->cio_sensedata_entry->proc_fops = &cio_sensedata_entry_file_ops;
+ entry->cio_in_use_entry = create_proc_entry( "in_use", S_IFREG|S_IRUGO, entry->cio_device_entry);
+ entry->cio_in_use_entry->proc_fops = &cio_in_use_entry_file_ops;
+ entry->cio_chpid_entry = create_proc_entry( "chpids", S_IFREG|S_IRUGO, entry->cio_device_entry);
+ entry->cio_chpid_entry->proc_fops = &cio_chpid_entry_file_ops;
+ } else {
+ printk("Error, could not allocate procfs structure!\n");
+ remove_proc_entry(buf, cio_procfs_deviceinfo_root);
+ kfree(entry);
+ rc = -ENOMEM;
+ }
+ } else {
+ printk("Error, could not allocate procfs structure!\n");
+ kfree(entry);
+ rc = -ENOMEM;
+ }
+
+ } else {
+ printk("Error, could not allocate procfs structure!\n");
+ rc = -ENOMEM;
+ }
+ return rc;
+}
+
+/*
+ * Function: cio_procfs_device_remove
+ * remove procfs entry for given device number
+ */
+int cio_procfs_device_remove(int devno)
+{
+ int rc = 0;
+ cio_procfs_device_t *tmp;
+ cio_procfs_device_t *prev = NULL;
+
+ tmp=cio_procfs_device_list;
+ while (tmp) {
+ if (tmp->entry->devno == devno)
+ break;
+ prev = tmp;
+ tmp = tmp->next;
+ }
+
+ if (tmp) {
+ char buf[8];
+
+ remove_proc_entry("sensedata", tmp->entry->cio_device_entry);
+ remove_proc_entry("in_use", tmp->entry->cio_device_entry);
+ remove_proc_entry("chpid", tmp->entry->cio_device_entry);
+ sprintf(buf, "%x", devno);
+ remove_proc_entry(buf, cio_procfs_deviceinfo_root);
+
+ if (tmp == cio_procfs_device_list) {
+ cio_procfs_device_list = tmp->next;
+ } else {
+ prev->next = tmp->next;
+ }
+ kfree(tmp->entry);
+ kfree(tmp);
+ } else {
+ rc = -ENODEV;
+ }
+
+ return rc;
+}
+
+/*
+ * Function: cio_procfs_purge
+ * purge /proc/deviceinfo of entries for gone devices
+ */
+
+int cio_procfs_device_purge(void)
+{
+ int i;
+
+ for (i=0; i<=highest_subchannel; i++) {
+ if (ioinfo[i] != INVALID_STORAGE_AREA) {
+ if (!ioinfo[i]->ui.flags.oper)
+ cio_procfs_device_remove(ioinfo[i]->devno);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Function: cio_procfs_create
+ * create /proc/deviceinfo/ and subdirs for the devices
+ */
+static int cio_procfs_create( void )
+{
+ int irq;
+
+ if (cio_proc_devinfo) {
+
+ cio_procfs_deviceinfo_root = proc_mkdir( "deviceinfo", &proc_root);
+
+ if (highest_subchannel >= MAX_CIO_PROCFS_ENTRIES) {
+ printk(KERN_ALERT "Warning: Not enough inodes for creating all entries under /proc/deviceinfo/. "
+ "Not every device will get an entry.\n");
+ }
+
+ for (irq=0; irq<=highest_subchannel; irq++) {
+ if (irq >= MAX_CIO_PROCFS_ENTRIES)
+ break;
+ if (ioinfo[irq] != INVALID_STORAGE_AREA) {
+ if (ioinfo[irq]->ui.flags.oper)
+ if (cio_procfs_device_create(ioinfo[irq]->devno) == -ENOMEM) {
+ printk(KERN_CRIT "Out of memory while creating entries in /proc/deviceinfo/, "
+ "not all devices might show up\n");
+ break;
+ }
+ }
+ }
+
+ }
+
+ return 1;
+}
+
+__initcall(cio_procfs_create);
+
+/*
+ * Entry /proc/cio_ignore to display blacklisted ranges of devices.
+ * un-ignore devices by piping to /proc/cio_ignore:
+ * free all frees all blacklisted devices, free <range>,<range>,...
+ * frees specified ranges of devnos
+ */
+
+static struct proc_dir_entry *cio_ignore_proc_entry;
+
+static int cio_ignore_proc_open(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ int size = 1;
+ int len = 0;
+ tempinfo_t *info;
+ dev_blacklist_range_t *tmp;
+
+ info = (tempinfo_t *) vmalloc(sizeof(tempinfo_t));
+ if (info == NULL) {
+ printk( KERN_WARNING "No memory available for data\n");
+ rc = -ENOMEM;
+ } else {
+ file->private_data = (void *) info;
+ size += nr_blacklisted_ranges * 32;
+ info->data = (char *) vmalloc(size);
+ if (size && info->data == NULL) {
+ printk( KERN_WARNING "No memory available for data\n");
+ vfree (info);
+ rc = -ENOMEM;
+ } else {
+ tmp = dev_blacklist_range_head;
+ while (tmp) {
+ len += sprintf(info->data+len, "%04x ", tmp->from);
+ if (tmp->to != tmp->from)
+ len += sprintf(info->data+len, "- %04x", tmp->to);
+ len += sprintf(info->data+len, "\n");
+ tmp = tmp->next;
+ }
+ info->len = len;
+ }
+ }
+ return rc;
+}
+
+static int cio_ignore_proc_close(struct inode *inode, struct file *file)
+{
+ int rc = 0;
+ tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+ if (p_info) {
+ if (p_info->data)
+ vfree( p_info->data );
+ vfree( p_info );
+ }
+
+ return rc;
+}
+
+static ssize_t cio_ignore_proc_read( struct file *file, char *user_buf, size_t user_len, loff_t * offset)
+{
+ loff_t len;
+ tempinfo_t *p_info = (tempinfo_t *) file->private_data;
+
+ if ( *offset>=p_info->len) {
+ return 0;
+ } else {
+ len = MIN(user_len, (p_info->len - *offset));
+ if (copy_to_user( user_buf, &(p_info->data[*offset]), len))
+ return -EFAULT;
+ (* offset) += len;
+ return len;
+ }
+}
+
+static ssize_t cio_ignore_proc_write (struct file *file, const char *user_buf,
+ size_t user_len, loff_t * offset)
+{
+ char *buffer = vmalloc (user_len);
+
+ if (buffer == NULL)
+ return -ENOMEM;
+ if (copy_from_user (buffer, user_buf, user_len)) {
+ vfree (buffer);
+ return -EFAULT;
+ }
+ buffer[user_len]='\0';
+#ifdef CIO_DEBUG_IO
+ printk ("/proc/cio_ignore: '%s'\n", buffer);
+#endif /* CIO_DEBUG_IO */
+ if (cio_debug_initialized)
+ debug_sprintf_event(cio_debug_msg_id, 2, "/proc/cio_ignore: '%s'\n",buffer);
+
+ blacklist_parse_proc_parameters(buffer);
+
+ return user_len;
+}
+
+static struct file_operations cio_ignore_proc_file_ops =
+{
+ read:cio_ignore_proc_read,
+ open:cio_ignore_proc_open,
+ write:cio_ignore_proc_write,
+ release:cio_ignore_proc_close,
+};
+
+static int cio_ignore_proc_init(void)
+{
+ cio_ignore_proc_entry = create_proc_entry("cio_ignore", S_IFREG|S_IRUGO|S_IWUSR, &proc_root);
+ cio_ignore_proc_entry->proc_fops = &cio_ignore_proc_file_ops;
+
+ return 1;
+}
+
+__initcall(cio_ignore_proc_init);
+
+/* end of procfs stuff */
+
+schib_t *s390_get_schib( int irq )
+{
+ if ( (irq > highest_subchannel) || (irq < 0) )
+ return NULL;
+ if ( ioinfo[irq] == INVALID_STORAGE_AREA )
+ return NULL;
+ return &ioinfo[irq]->schib;
+
+}
+
+
EXPORT_SYMBOL(halt_IO);
EXPORT_SYMBOL(clear_IO);
EXPORT_SYMBOL(do_IO);
EXPORT_SYMBOL(read_conf_data);
EXPORT_SYMBOL(read_dev_chars);
EXPORT_SYMBOL(s390_request_irq_special);
+EXPORT_SYMBOL(s390_get_schib);
+EXPORT_SYMBOL(s390_register_adapter_interrupt);
+EXPORT_SYMBOL(s390_unregister_adapter_interrupt);
#include <linux/config.h>
#include <linux/spinlock.h>
#include <linux/init.h>
-#include <linux/malloc.h>
+#include <linux/slab.h>
#ifdef CONFIG_SMP
#include <linux/smp.h>
#endif
{
printk(" %2x ",workrequ->cmnd[k]);
}
- printk(" last_lenu= %x ",dev->id[j].last_lenu);
+ printk(" last_lenu= %lx ",dev->id[j].last_lenu);
}
}
return (SCSI_ABORT_SNOOZE);
release_mem_region(overrides[current_override].NCR5380_map_name,
NCR5380_region_size);
#endif
+ continue;
}
instance->NCR5380_instance_name = overrides[current_override].NCR5380_map_name;
#if LINUX_VERSION_CODE >= 0x020322
sdev = scsi_get_host_dev(gdth_ctr_vtab[vh]);
scp = scsi_allocate_device(sdev, 1, FALSE);
+ if (!scp)
+ return -ENOMEM;
scp->cmd_len = 12;
scp->use_sg = 0;
#else
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*
- * Version : v1.15d(May 30, 2001)
+ * Version : v1.17a (July 13, 2001)
*
* Description: Linux device driver for AMI MegaRAID controller
*
* Original source contributed by Dell; integrated it into the kernel and
* cleaned up some things. Added support for 438/466 controllers.
* Version 0.91:
- * Aligned mailbox area on 16-byte boundry.
+ * Aligned mailbox area on 16-byte boundary.
* Added schedule() at the end to properly clean up.
* Made improvements for conformity to linux driver standards.
*
* Added new ioctl command 0x81 to support NEW_READ/WRITE_CONFIG with
* data area greater than 4 KB, which is the upper bound for data
* tranfer through scsi_ioctl interface.
- * The addtional 32 bit field for 64bit address in the newly defined
+ * The additional 32 bit field for 64bit address in the newly defined
* mailbox64 structure is set to 0 at this point.
*
* Version 1.05
* Changed the queing implementation for handling SCBs and completed
* commands.
- * Added spinlocks in the interrupt service routine to enable the dirver
+ * Added spinlocks in the interrupt service routine to enable the driver
* function in the SMP environment.
* Fixed the problem of unnecessary aborts in the abort entry point, which
* also enables the driver to handle large amount of I/O requests for
* MEGA_HP_FIX)
*
* Version 1a12
- * I. reboot notifer and new ioctl changes ported from 1c09
+ * I. reboot notifier and new ioctl changes ported from 1c09
*
- * Veriosn 1b12
+ * Version 1b12
* I. Changes in new ioctl interface routines ( Nov 06, 2000 )
*
- * Veriosn 1c12
+ * Version 1c12
* I. Changes in new ioctl interface routines ( Nov 07, 2000 )
*
- * Veriosn 1d12
+ * Version 1d12
* I. Compilation error under kernel 2.4.0 for 32-bit machine in mega_ioctl
*
- * Veriosn 1e12, 1f12
+ * Version 1e12, 1f12
* 1. Fixes for pci_map_single, pci_alloc_consistent along with mailbox
* alignment
*
*
* Version 1.13j
* Moved some code to megaraid.h file, replaced some hard coded values
- * with respective macros. Chaged some funtions to static
+ * with respective macros. Changed some functions to static
*
* Version 1.13k
* Only some idendation correction to 1.13j
* Assorted changes to remove compilation error in 1.14k when compiled
* with kernel < 2.4.0
*
+ * Version 1.14m
+ * Tue Mar 27 12:09:22 EST 2001 - AM
+ *
+ * Added support for extended CDBs ( > 10 bytes ) and OBDR ( One Button
+ * Disaster Recovery ) feature.
+ *
+ *
+ * Version 1.14n
+ * Tue Apr 10 14:28:13 EDT 2001 - AM
+ *
+ * "modeversions.h" is no longer included in the code.
+ * 2.4.xx style mutex initialization used for older kernels also
+ *
+ * Version 1.14o
+ * Wed Apr 18 17:47:26 EDT 2001 - PJ
+ *
+ * Before returning status for 'inquiry', we first check if request buffer
+ * is SG list, and then return appropriate status
+ *
+ * Version 1.14p
+ * Wed Apr 25 13:44:48 EDT 2001 - PJ
+ *
+ * SCSI result made appropriate in case of check conditions for extended
+ * passthru commands
+ *
+ * Do not support lun >7 for physically accessed devices
+ *
+ *
* Version 1.15
* Thu Apr 19 09:38:38 EDT 2001 - AM
*
- * 1.14l rollover to 1.15
+ * 1.14l rollover to 1.15 - merged with main trunk after 1.15d
*
* Version 1.15b
* Wed May 16 20:10:01 EDT 2001 - AM
* "modeversions.h" is no longer included in the code.
* 2.4.xx style mutex initialization used for older kernels also
* Brought in-sync with Alan's changes in 2.4.4
- * Note: 1.15a is on OBDR brabch(main trunk), and is not merged with yet.
+ * Note: 1.15a is on OBDR branch(main trunk), and is not merged with yet.
*
* Version 1.15c
* Mon May 21 23:10:42 EDT 2001 - AM
* NULL is not a valid first argument for pci_alloc_consistent() on
* IA64(2.4.3-2.10.1). Code shuffling done in ioctl interface to get
* "pci_dev" before making calls to pci interface routines.
-
+ *
+ * Version 1.16pre
+ * Fri Jun 1 19:40:48 EDT 2001 - AM
+ *
+ * 1.14p and 1.15d merged
+ * ROMB support added
+ *
+ * Version 1.16-pre1
+ * Mon Jun 4 15:01:01 EDT 2001 - AM
+ *
+ * Non-ROMB firmware do no DMA support 0xA9 command. Value 0xFF
+ * (all channels are raid ) is chosen for those firmware.
+ *
+ * Version 1.16-pre2
+ * Mon Jun 11 18:15:31 EDT 2001 - AM
+ *
+ * Changes for boot from any logical drive
+ *
+ * Version 1.16
+ * Tue Jun 26 18:07:02 EDT 2001 - AM
+ *
+ * branched at 1.14p
+ *
+ * Check added for HP 1M/2M controllers if having firmware H.01.07 or
+ * H.01.08. If found, disable 64 bit support since these firmware have
+ * limitations for 64 bit addressing
+ *
+ *
+ * Version 1.17
+ * Thu Jul 12 11:14:09 EDT 2001 - AM
+ *
+ * 1.16pre2 and 1.16 merged.
+ *
+ * init_MUTEX and init_MUTEX_LOCKED are defined in 2.2.19. Pre-processor
+ * statements are added for them
+ *
+ * Linus's 2.4.7pre3 kernel introduces a new field 'max_sectors' in Scsi_Host
+ * structure, to improve IO performance.
+ *
+ *
+ * Version 1.17a
+ * Fri Jul 13 18:44:01 EDT 2001 - AM
+ *
+ * Starting from kernel 2.4.x, LUN is not < 8 - following SCSI-III. So to have
+ * our current formula working to calculate logical drive number, return
+ * failure for LUN > 7
+ *
* BUGS:
* Some older 2.1 kernels (eg. 2.1.90) have a bug in pci.c that
* fails to detect the controller as a pci device on the system.
#define pci_free_consistent(a,b,c,d)
#define pci_unmap_single(a,b,c,d)
-
-#define init_MUTEX_LOCKED(x) (*(x)=MUTEX_LOCKED)
-#define init_MUTEX(x) (*(x)=MUTEX)
-
#define pci_enable_device(x) (0)
-
#define queue_task_irq(a,b) queue_task(a,b)
#define queue_task_irq_off(a,b) queue_task(a,b)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19) /* 0x020219 */
+#define init_MUTEX_LOCKED(x) (*(x)=MUTEX_LOCKED)
+#define init_MUTEX(x) (*(x)=MUTEX)
#define DECLARE_WAIT_QUEUE_HEAD(x) struct wait_queue *x = NULL
+#endif
+
+
#else
/*
#define dma_alloc_consistent pci_alloc_consistent
#define dma_free_consistent pci_free_consistent
#else
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,19) /* 0x020219 */
typedef unsigned long dma_addr_t;
+#endif
void *dma_alloc_consistent(void *, size_t, dma_addr_t *);
void dma_free_consistent(void *, size_t, void *, dma_addr_t);
int mega_get_order(int);
static struct mcontroller mcontroller[MAX_CONTROLLERS];
/* The current driver version */
-static u32 driver_ver = 114;
+static u32 driver_ver = 117;
/* major number used by the device for character interface */
static int major;
extern struct proc_dir_entry proc_root;
#endif
+static char mega_ch_class; /* channels are raid or scsi */
+#define IS_RAID_CH(ch) ( (mega_ch_class >> (ch)) & 0x01 )
#if SERDEBUG
static char strbuf[MAX_SERBUF + 1];
pScb->pthru->dataxferlen,
pScb->dma_direction);
break;
+ case M_RD_EPTHRU_WITH_BULK_DATA:
+ pci_unmap_single (megaCfg->dev, pScb->dma_h_bulkdata,
+ pScb->epthru->dataxferlen,
+ pScb->dma_direction);
+ break;
case M_RD_PTHRU_WITH_SGLIST:
{
int count;
int islogical;
Scsi_Cmnd *SCpnt;
mega_passthru *pthru;
+ mega_ext_passthru *epthru;
mega_mailbox *mbox;
+ struct scatterlist *sgList;
+ u8 c;
if (pScb == NULL) {
TRACE (("NULL pScb in mega_cmd_done!"));
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
pthru = pScb->pthru;
+ epthru = pScb->epthru;
#else
pthru = &pScb->pthru;
+ epthru = &pScb->epthru;
#endif
mbox = (mega_mailbox *) & pScb->mboxData;
mega_freeSCB (megaCfg, pScb);
+ /*
+ * Do not return the presence of hard disk on the channel so, inquiry
+ * sent, and returned data==hard disk or removable hard disk and not
+ * logical, request should return failure! - PJ
+ */
+#if 0
if (SCpnt->cmnd[0] == INQUIRY && ((((u_char *) SCpnt->request_buffer)[0] & 0x1F) == TYPE_DISK) && !islogical) {
status = 0xF0;
}
+#endif
+ if (SCpnt->cmnd[0] == INQUIRY && !islogical) {
+ if ( SCpnt->use_sg ) {
+ sgList = (struct scatterlist *)SCpnt->request_buffer;
+ memcpy(&c, sgList[0].address, 0x1);
+ } else {
+ memcpy(&c, SCpnt->request_buffer, 0x1);
+ }
+#if 0
+ if( (c & 0x1F ) == TYPE_DISK ) {
+ status = 0xF0;
+ }
+#endif
+ if( IS_RAID_CH(SCpnt->channel) && ((c & 0x1F ) == TYPE_DISK) ) {
+ status = 0xF0;
+ }
+ }
+
/* clear result; otherwise, success returns corrupt value */
SCpnt->result = 0;
/*set sense_buffer and result fields */
if (mbox->cmd == MEGA_MBOXCMD_PASSTHRU) {
memcpy (SCpnt->sense_buffer, pthru->reqsensearea, 14);
- SCpnt->result = (DRIVER_SENSE << 24) | (DID_ERROR << 16) | status;
+ } else if (mbox->cmd == MEGA_MBOXCMD_EXTPASSTHRU) {
+ SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1);
+ memcpy(
+ SCpnt->sense_buffer,
+ epthru->reqsensearea, 14
+ );
+ SCpnt->result = (DRIVER_SENSE << 24) | (DID_OK << 16) | (CHECK_CONDITION < 1);
+ /*SCpnt->result =
+ (DRIVER_SENSE << 24) |
+ (DID_ERROR << 16) | status;*/
} else {
SCpnt->sense_buffer[0] = 0x70;
SCpnt->sense_buffer[2] = ABORTED_COMMAND;
mega_scb *pScb;
mega_mailbox *mbox;
mega_passthru *pthru;
+ mega_ext_passthru *epthru;
long seg;
char islogical;
char lun = SCpnt->lun;
}
#endif
- islogical = (SCpnt->channel == megaCfg->host->max_channel);
+ islogical = (IS_RAID_CH(SCpnt->channel) && /* virtual ch is raid - AM */
+ (SCpnt->channel == megaCfg->host->max_channel));
- if (!islogical && lun != 0) {
+ if ( ! megaCfg->support_ext_cdb ) {
+ if (!islogical && lun != 0) {
+ SCpnt->result = (DID_BAD_TARGET << 16);
+ callDone (SCpnt);
+ return NULL;
+ }
+ }
+
+ if (!islogical && SCpnt->target == skip_id) {
SCpnt->result = (DID_BAD_TARGET << 16);
callDone (SCpnt);
return NULL;
}
- if (!islogical && SCpnt->target == skip_id) {
+ /*
+ * Return error for LUN > 7. The way we calculate logical drive number
+ * requires it to be so.
+ */
+ if( lun > 7 ) {
SCpnt->result = (DID_BAD_TARGET << 16);
callDone (SCpnt);
return NULL;
}
if (islogical) {
+
lun = (SCpnt->target * 8) + lun;
- if (lun > FC_MAX_LOGICAL_DRIVES) {
+
+ if(lun >= megaCfg->numldrv ) {
SCpnt->result = (DID_BAD_TARGET << 16);
callDone (SCpnt);
return NULL;
}
+
+ /*
+ * If we have a logical drive with boot enabled, project it first
+ */
+ if( megaCfg->boot_ldrv_enabled ) {
+ if( lun == 0 ) {
+ lun = megaCfg->boot_ldrv;
+ }
+ else {
+ if( lun <= megaCfg->boot_ldrv ) {
+ lun--;
+ }
+ }
+ }
}
/*-----------------------------------------------------
*
mbox->numsectors;
}
}
+
+ /* 12-byte */
+ if (*SCpnt->cmnd == READ_12 || *SCpnt->cmnd == WRITE_12) {
+ mbox->lba =
+ ((u32) SCpnt->cmnd[2] << 24) |
+ ((u32) SCpnt->cmnd[3] << 16) |
+ ((u32) SCpnt->cmnd[4] << 8) |
+ (u32) SCpnt->cmnd[5];
+
+ mbox->numsectors =
+ ((u32) SCpnt->cmnd[6] << 24) |
+ ((u32) SCpnt->cmnd[7] << 16) |
+ ((u32) SCpnt->cmnd[8] << 8) |
+ (u32) SCpnt->cmnd[9];
+
+ if (*SCpnt->cmnd == READ_12) {
+ megaCfg->nReads[(int) lun]++;
+ megaCfg->nReadBlocks[(int) lun] +=
+ mbox->numsectors;
+ } else {
+ megaCfg->nWrites[(int) lun]++;
+ megaCfg->nWriteBlocks[(int) lun] +=
+ mbox->numsectors;
+ }
+ }
+
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10) {
+ if (*SCpnt->cmnd == READ_6 || *SCpnt->cmnd == READ_10
+ || *SCpnt->cmnd == READ_12) {
pScb->dma_direction = PCI_DMA_FROMDEVICE;
} else { /*WRITE_6 or WRITE_10 */
pScb->dma_direction = PCI_DMA_TODEVICE;
/* Calculate Scatter-Gather info */
mbox->numsgelements = mega_build_sglist (megaCfg, pScb,
- (u32 *) &
- mbox->xferaddr,
- (u32 *) & seg);
+ (u32 *)&mbox->xferaddr, (u32 *)&seg);
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
pScb->iDataSize = seg;
callDone (SCpnt);
return NULL;
}
+
+ mbox = (mega_mailbox *) pScb->mboxData;
+ memset (mbox, 0, sizeof (pScb->mboxData));
+
+ if ( megaCfg->support_ext_cdb && SCpnt->cmd_len > 10 ) {
+ epthru = mega_prepare_extpassthru(megaCfg, pScb, SCpnt);
+ mbox->cmd = MEGA_MBOXCMD_EXTPASSTHRU;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- pthru = pScb->pthru;
+ mbox->xferaddr = pScb->dma_ext_passthruhandle64;
+
+ if(epthru->numsgelements) {
+ pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
+ } else {
+ pScb->dma_type = M_RD_EPTHRU_WITH_BULK_DATA;
+ }
#else
- pthru = &pScb->pthru;
+ mbox->xferaddr = virt_to_bus(epthru);
#endif
- mbox = (mega_mailbox *) pScb->mboxData;
+ }
+ else {
+ pthru = mega_prepare_passthru(megaCfg, pScb, SCpnt);
- memset (mbox, 0, sizeof (pScb->mboxData));
- memset (pthru, 0, sizeof (mega_passthru));
+ /* Initialize mailbox */
+ mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ mbox->xferaddr = pScb->dma_passthruhandle64;
- /* set adapter timeout value to 10 min. for tape drive */
- /* 0=6sec/1=60sec/2=10min/3=3hrs */
- pthru->timeout = 2;
- pthru->ars = 1;
- pthru->reqsenselen = 14;
- pthru->islogical = 0;
- pthru->channel =
- (megaCfg->flag & BOARD_40LD) ? 0 : SCpnt->channel;
- pthru->target = (megaCfg->flag & BOARD_40LD) ? /*BOARD_40LD */
- (SCpnt->channel << 4) | SCpnt->target : SCpnt->target;
- pthru->cdblen = SCpnt->cmd_len;
+ if (pthru->numsgelements) {
+ pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
+ } else {
+ pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA;
+ }
+#else
+ mbox->xferaddr = virt_to_bus(pthru);
+#endif
+ }
+ return pScb;
+ }
+ return NULL;
+}
- memcpy (pthru->cdb, SCpnt->cmnd, SCpnt->cmd_len);
+static mega_passthru *
+mega_prepare_passthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+{
+ mega_passthru *pthru;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- /* Not sure about the direction */
- pScb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+ pthru = scb->pthru;
+#else
+ pthru = &scb->pthru;
+#endif
+ memset (pthru, 0, sizeof (mega_passthru));
+
+ /* set adapter timeout value to 10 min. for tape drive */
+ /* 0=6sec/1=60sec/2=10min/3=3hrs */
+ pthru->timeout = 2;
+ pthru->ars = 1;
+ pthru->reqsenselen = 14;
+ pthru->islogical = 0;
+ pthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+ pthru->target = (megacfg->flag & BOARD_40LD) ?
+ (sc->channel << 4) | sc->target : sc->target;
+ pthru->cdblen = sc->cmd_len;
+ pthru->logdrv = sc->lun;
+
+ memcpy (pthru->cdb, sc->cmnd, sc->cmd_len);
- /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
- switch (SCpnt->cmnd[0]) {
- case INQUIRY:
- case READ_CAPACITY:
- pthru->numsgelements = 0;
- pthru->dataxferaddr = pScb->dma_bounce_buffer;
- pthru->dataxferlen = SCpnt->request_bufflen;
- break;
- default:
- pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
- (u32 *) &
- pthru->
- dataxferaddr,
- (u32 *) &
- pthru->
- dataxferlen);
- break;
- }
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ /* Not sure about the direction */
+ scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+ /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+ switch (sc->cmnd[0]) {
+ case INQUIRY:
+ case READ_CAPACITY:
+ pthru->numsgelements = 0;
+ pthru->dataxferaddr = scb->dma_bounce_buffer;
+ pthru->dataxferlen = sc->request_bufflen;
+ break;
+ default:
+ pthru->numsgelements =
+ mega_build_sglist(
+ megacfg, scb, (u32 *)&pthru->dataxferaddr,
+ (u32 *)&pthru->dataxferlen
+ );
+ break;
+ }
#else
- pthru->numsgelements = mega_build_sglist (megaCfg, pScb,
- (u32 *) & pthru->
- dataxferaddr,
- (u32 *) & pthru->
- dataxferlen);
+ pthru->numsgelements =
+ mega_build_sglist(
+ megacfg, scb, (u32 *)&pthru->dataxferaddr,
+ (u32 *)&pthru->dataxferlen
+ );
#endif
+ return pthru;
+}
- /* Initialize mailbox */
- mbox->cmd = MEGA_MBOXCMD_PASSTHRU;
+static mega_ext_passthru *
+mega_prepare_extpassthru(mega_host_config *megacfg, mega_scb *scb, Scsi_Cmnd *sc)
+{
+ mega_ext_passthru *epthru;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
- mbox->xferaddr = pScb->dma_passthruhandle64;
-
- if (pthru->numsgelements) {
- pScb->dma_type = M_RD_PTHRU_WITH_SGLIST;
- TRACE1 (("M_RD_PTHRU_WITH_SGLIST Enabled \n"));
- } else {
- pScb->dma_type = M_RD_PTHRU_WITH_BULK_DATA
- TRACE1 (("M_RD_PTHRU_WITH_BULK_DATA Enabled \n"));
- }
+ epthru = scb->epthru;
#else
- mbox->xferaddr = virt_to_bus (pthru);
+ epthru = &scb->epthru;
#endif
+ memset(epthru, 0, sizeof(mega_ext_passthru));
+
+ /* set adapter timeout value to 10 min. for tape drive */
+ /* 0=6sec/1=60sec/2=10min/3=3hrs */
+ epthru->timeout = 2;
+ epthru->ars = 1;
+ epthru->reqsenselen = 14;
+ epthru->islogical = 0;
+ epthru->channel = (megacfg->flag & BOARD_40LD) ? 0 : sc->channel;
+ epthru->target = (megacfg->flag & BOARD_40LD) ?
+ (sc->channel << 4) | sc->target : sc->target;
+ epthru->cdblen = sc->cmd_len;
+ epthru->logdrv = sc->lun;
+
+ memcpy(epthru->cdb, sc->cmnd, sc->cmd_len);
- return pScb;
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ /* Not sure about the direction */
+ scb->dma_direction = PCI_DMA_BIDIRECTIONAL;
+
+ /* Special Code for Handling READ_CAPA/ INQ using bounce buffers */
+ switch (sc->cmnd[0]) {
+ case INQUIRY:
+ case READ_CAPACITY:
+ epthru->numsgelements = 0;
+ epthru->dataxferaddr = scb->dma_bounce_buffer;
+ epthru->dataxferlen = sc->request_bufflen;
+ break;
+ default:
+ epthru->numsgelements =
+ mega_build_sglist(
+ megacfg, scb, (u32 *)&epthru->dataxferaddr,
+ (u32 *)&epthru->dataxferlen
+ );
+ break;
}
- return NULL;
+#else
+ epthru->numsgelements =
+ mega_build_sglist(
+ megacfg, scb, (u32 *)&epthru->dataxferaddr,
+ (u32 *)&epthru->dataxferlen
+ );
+#endif
+ return epthru;
}
/* Handle Driver Level IOCTLs
* int intr - if 1, interrupt, 0 is blocking
* Return Value: (added on 7/26 for 40ld/64bit)
* -1: the command was not actually issued out
- * othercases:
+ * other cases:
* intr==0, return ScsiStatus, i.e. mbox->status
* intr==1, return 0
*=====================================================
scb->SCpnt->request_bufflen,
scb->dma_direction);
/* We need to handle special commands like READ64, WRITE64
- as they need a minimum of 1 SG irrespective of actaully SG
+ as they need a minimum of 1 SG irrespective of actually SG
*/
if ((megaCfg->flag & BOARD_64BIT) &&
((mbox->cmd == MEGA_MBOXCMD_LREAD64) ||
}
/*--------------------------------------------------------------------
- * Initializes the adress of the controller's mailbox register
+ * Initializes the address of the controller's mailbox register
* The mailbox register is used to issue commands to the card.
* Format of the mailbox area:
* 00 01 command
static int
mega_register_mailbox (mega_host_config * megaCfg, u32 paddr)
{
- /* align on 16-byte boundry */
+ /* align on 16-byte boundary */
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
megaCfg->mbox = &megaCfg->mailbox64ptr->mailbox;
#else
/*
* Try to issue Enquiry3 command
- * if not suceeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
+ * if not succeeded, then issue MEGA_MBOXCMD_ADAPTERINQ command and
* update enquiry3 structure
*/
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
memcpy (megaCfg->biosVer, (char *) megaCfg->productInfo.BiosVer, 4);
megaCfg->biosVer[4] = 0;
#endif
+ megaCfg->support_ext_cdb = mega_support_ext_cdb(megaCfg);
printk (KERN_NOTICE "megaraid: [%s:%s] detected %d logical drives" M_RD_CRLFSTR,
megaCfg->fwVer, megaCfg->biosVer, megaCfg->numldrv);
+
+ if ( megaCfg->support_ext_cdb ) {
+ printk(KERN_NOTICE "megaraid: supports extended CDBs.\n");
+ }
+
/*
* I hope that I can unmap here, reason DMA transaction is not required any more
* after this
continue; /* not an AMI board */
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
-#if 0
-/*
- * This leads to corruption on some HP boards so disable it
- */
pcibios_read_config_dword (pciBus, pciDevFun,
PCI_CONF_AMISIG64, &magic64);
if (magic64 == AMI_64BIT_SIGNATURE)
flag |= BOARD_64BIT;
-#endif
#endif
}
pci_read_config_word (pdev,
PCI_SUBSYSTEM_ID, &subsysid);
#endif
- if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
- printk (KERN_WARNING
- "megaraid: Your card is a Dell PERC 2/SC RAID controller with firmware\n"
- "megaraid: 3.00 or 3.01. This driver is known to have corruption issues\n"
- "megaraid: with those firmware versions on this specific card. In order\n"
- "megaraid: to protect your data, please upgrade your firmware to version\n"
- "megaraid: 3.10 or later, available from the Dell Technical Support web\n"
- "megaraid: site at\n"
- "http://support.dell.com/us/en/filelib/download/index.asp?fileid=2940\n");
- continue;
- }
+
+#if 0
+ /*
+ * This routine is called with well know values and we
+ * should not be getting what we have not asked.
+ * Also, the check is not right. It should have been for
+ * pci_vendor_id not subsysvid - AM
+ */
/* If we dont detect this valid subsystem vendor id's
we refuse to load the driver
&& (subsysvid != DELL_SUBSYS_ID)
&& (subsysvid != HP_SUBSYS_ID))
continue;
+#endif
}
printk (KERN_NOTICE
if (!host)
goto err_unmap;
+ /*
+ * Comment the following initialization if you know 'max_sectors' is
+ * not defined for this kernel.
+ * This field was introduced in Linus's kernel 2.4.7pre3 and it
+ * greatly increases the IO performance - AM
+ */
+ host->max_sectors = 1024;
+
scsi_set_pci_device(host, pdev);
megaCfg = (mega_host_config *) host->hostdata;
memset (megaCfg, 0, sizeof (mega_host_config));
virt_to_bus ((void *) megaCfg->
mailbox64ptr));
#else
- /*Taken care */
mega_register_mailbox (megaCfg,
virt_to_bus ((void *) &megaCfg->
mailbox64));
mega_i_query_adapter (megaCfg);
+ if ((subsysid == 0x1111) && (subsysvid == 0x1111)) {
+
+ /*
+ * Which firmware
+ */
+ if( strcmp(megaCfg->fwVer, "3.00") == 0 ||
+ strcmp(megaCfg->fwVer, "3.01") == 0 ) {
+
+ printk( KERN_WARNING
+ "megaraid: Your card is a Dell PERC 2/SC RAID controller "
+ "with firmware\nmegaraid: 3.00 or 3.01. This driver is "
+ "known to have corruption issues\nmegaraid: with those "
+ "firmware versions on this specific card. In order\n"
+ "megaraid: to protect your data, please upgrade your "
+ "firmware to version\nmegaraid: 3.10 or later, available "
+ "from the Dell Technical Support web\nmegaraid: site at\n"
+ "http://support.dell.com/us/en/filelib/download/"
+ "index.asp?fileid=2940\n"
+ );
+ }
+ }
+
+#ifdef MEGA_HP_FIX
+ /*
+ * If we have a HP 1M(0x60E7)/2M(0x60E8) controller with
+ * firmware H.01.07 or H.01.08, disable 64 bit support,
+ * since this firmware cannot handle 64 bit addressing
+ */
+
+ if( (subsysvid == HP_SUBSYS_ID) &&
+ ((subsysid == 0x60E7)||(subsysid == 0x60E8)) ) {
+
+ /*
+ * which firmware
+ */
+ if( strcmp(megaCfg->fwVer, "H01.07") == 0 ||
+ strcmp(megaCfg->fwVer, "H01.08") == 0 ) {
+ printk(KERN_WARNING
+ "megaraid: Firmware H.01.07 or H.01.08 on 1M/2M "
+ "controllers\nmegaraid: do not support 64 bit "
+ "addressing.\n"
+ "megaraid: DISABLING 64 bit support.\n");
+ megaCfg->flag &= ~BOARD_64BIT;
+ }
+ }
+#endif
+
if (mega_is_bios_enabled (megaCfg)) {
mega_hbas[numCtlrs].is_bios_enabled = 1;
}
+
+ /*
+ * Find out which channel is raid and which is scsi
+ */
+ mega_enum_raid_scsi(megaCfg);
+ for( i = 0; i < megaCfg->host->max_channel; i++ ) {
+ if(IS_RAID_CH(i))
+ printk(KERN_NOTICE"megaraid: channel[%d] is raid.\n", i+1);
+ else
+ printk(KERN_NOTICE"megaraid: channel[%d] is scsi.\n", i+1);
+ }
+
+ /*
+ * Find out if a logical drive is set as the boot drive. If there is
+ * one, will make that as the first logical drive.
+ */
+ mega_get_boot_ldrv(megaCfg);
+
mega_hbas[numCtlrs].hostdata_addr = megaCfg;
/* Initialize SCBs */
#endif
/*
- * Register the driver as a character device, for appliactions to access
+ * Register the driver as a character device, for applications to access
* it for ioctls.
* Ideally, this should go in the init_module() routine, but since it is
* hidden in the file "scsi_module.c" ( included in the end ), we define
if (register_reboot_notifier (&mega_notifier)) {
printk ("MegaRAID Shutdown routine not registered!!\n");
}
+
init_MUTEX (&mimd_entry_mtx);
return count;
0, sizeof (megacfg->mega_buffer));
/*
- * issue command to find out if the BIOS is enbled for this controller
+ * issue command to find out if the BIOS is enabled for this controller
*/
mbox[0] = IS_BIOS_ENABLED;
mbox[2] = GET_BIOS;
return (*(char *) megacfg->mega_buffer);
}
+/*
+ * Find out what channels are RAID/SCSI
+ */
+void
+mega_enum_raid_scsi(mega_host_config *megacfg)
+{
+ mega_mailbox *mboxp;
+ unsigned char mbox[16];
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ dma_addr_t dma_handle;
+#endif
+
+ mboxp = (mega_mailbox *)mbox;
+
+ memset(mbox, 0, sizeof(mbox));
+ /*
+ * issue command to find out what channels are raid/scsi
+ */
+ mbox[0] = CHNL_CLASS;
+ mbox[2] = GET_CHNL_CLASS;
+
+ memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer,
+ (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+ mboxp->xferaddr = dma_handle;
+#else
+ mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer);
+#endif
+
+ /*
+ * Non-ROMB firware fail this command, so all channels
+ * must be shown RAID
+ */
+ if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
+ mega_ch_class = *((char *)megacfg->mega_buffer);
+
+ /* logical drives channel is RAID */
+ mega_ch_class |= (0x01 << megacfg->host->max_channel);
+ }
+ else {
+ mega_ch_class = 0xFF;
+ }
+
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ pci_unmap_single(megacfg->dev, dma_handle,
+ (2 * 1024L), PCI_DMA_FROMDEVICE);
+#endif
+
+}
+
+
+/*
+ * get the boot logical drive number if enabled
+ */
+void
+mega_get_boot_ldrv(mega_host_config *megacfg)
+{
+ mega_mailbox *mboxp;
+ unsigned char mbox[16];
+ struct private_bios_data *prv_bios_data;
+ u16 cksum = 0;
+ char *cksum_p;
+ int i;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ dma_addr_t dma_handle;
+#endif
+
+ mboxp = (mega_mailbox *)mbox;
+
+ memset(mbox, 0, sizeof(mbox));
+
+ mbox[0] = BIOS_PVT_DATA;
+ mbox[2] = GET_BIOS_PVT_DATA;
+
+ memset((void *)megacfg->mega_buffer, 0, sizeof(megacfg->mega_buffer));
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ dma_handle = pci_map_single(megacfg->dev, (void *)megacfg->mega_buffer,
+ (2 * 1024L), PCI_DMA_FROMDEVICE);
+
+ mboxp->xferaddr = dma_handle;
+#else
+ mboxp->xferaddr = virt_to_bus((void *)megacfg->mega_buffer);
+#endif
+
+ megacfg->boot_ldrv_enabled = 0;
+ megacfg->boot_ldrv = 0;
+ if( megaIssueCmd(megacfg, mbox, NULL, 0) == 0 ) {
+
+ prv_bios_data = (struct private_bios_data *)megacfg->mega_buffer;
+
+ cksum = 0;
+ cksum_p = (char *)prv_bios_data;
+ for( i = 0; i < 14; i++ ) {
+ cksum += (u16)(*cksum_p++);
+ }
+
+ if( prv_bios_data->cksum == (u16)(0-cksum) ) {
+ megacfg->boot_ldrv_enabled = 1;
+ megacfg->boot_ldrv = prv_bios_data->boot_ldrv;
+ }
+ }
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
+ pci_unmap_single(megacfg->dev, dma_handle,
+ (2 * 1024L), PCI_DMA_FROMDEVICE);
+#endif
+
+}
+
+
static void mega_reorder_hosts (void)
{
struct Scsi_Host *shpnt;
*start = page;
proc_printf (megaCfg, "Statistical Information for this controller\n");
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */
- proc_printf (megaCfg, "Interrupts Collected = %Lu\n",
+ proc_printf (megaCfg, "Interrupts Collected = %lu\n",
megaCfg->nInterrupts);
-#else
- proc_printf (megaCfg, "Interrupts Collected = %u\n",
- (u32) megaCfg->nInterrupts);
-#endif
for (i = 0; i < megaCfg->numldrv; i++) {
proc_printf (megaCfg, "Logical Drive %d:\n", i);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
proc_printf (megaCfg,
- "\tReads Issued = %Lu, Writes Issued = %Lu\n",
+ "\tReads Issued = %lu, Writes Issued = %lu\n",
megaCfg->nReads[i], megaCfg->nWrites[i]);
proc_printf (megaCfg,
- "\tSectors Read = %Lu, Sectors Written = %Lu\n\n",
+ "\tSectors Read = %lu, Sectors Written = %lu\n\n",
megaCfg->nReadBlocks[i], megaCfg->nWriteBlocks[i]);
-#else
- proc_printf (megaCfg,
- "\tReads Issued = %10u, Writes Issued = %10u\n",
- (u32) megaCfg->nReads[i],
- (u32) megaCfg->nWrites[i]);
-
- proc_printf (megaCfg,
- "\tSectors Read = %10u, Sectors Written = %10u\n\n",
- (u32) megaCfg->nReadBlocks[i],
- (u32) megaCfg->nWriteBlocks[i]);
-#endif
}
/* Get pointer to host config structure */
megaCfg = (mega_host_config *) disk->device->host->hostdata;
- /* Default heads (64) & sectors (32) */
- heads = 64;
- sectors = 32;
- cylinders = disk->capacity / (heads * sectors);
+ if( IS_RAID_CH(disk->device->channel)) {
+ /* Default heads (64) & sectors (32) */
+ heads = 64;
+ sectors = 32;
+ cylinders = disk->capacity / (heads * sectors);
+
+ /* Handle extended translation size for logical drives > 1Gb */
+ if (disk->capacity >= 0x200000) {
+ heads = 255;
+ sectors = 63;
+ cylinders = disk->capacity / (heads * sectors);
+ }
- /* Handle extended translation size for logical drives > 1Gb */
- if (disk->capacity >= 0x200000) {
- heads = 255;
- sectors = 63;
- cylinders = disk->capacity / (heads * sectors);
+ /* return result */
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
}
+ else {
+ if( mega_partsize(disk, dev, geom) == 0 ) return 0;
+
+ printk(KERN_WARNING
+ "megaraid: invalid partition on this disk on channel %d\n",
+ disk->device->channel);
- /* return result */
- geom[0] = heads;
- geom[1] = sectors;
- geom[2] = cylinders;
+ /* Default heads (64) & sectors (32) */
+ heads = 64;
+ sectors = 32;
+ cylinders = disk->capacity / (heads * sectors);
+
+ /* Handle extended translation size for logical drives > 1Gb */
+ if (disk->capacity >= 0x200000) {
+ heads = 255;
+ sectors = 63;
+ cylinders = disk->capacity / (heads * sectors);
+ }
+
+ /* return result */
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cylinders;
+ }
return 0;
}
+/*
+ * Function : static int mega_partsize(Disk * disk, kdev_t dev, int *geom)
+ *
+ * Purpose : to determine the BIOS mapping used to create the partition
+ * table, storing the results (cyls, hds, and secs) in geom
+ *
+ * Note: Code is picked from scsicam.h
+ *
+ * Returns : -1 on failure, 0 on success.
+ */
+static int
+mega_partsize(Disk * disk, kdev_t dev, int *geom)
+{
+ struct buffer_head *bh;
+ struct partition *p, *largest = NULL;
+ int i, largest_cyl;
+ int heads, cyls, sectors;
+ int capacity = disk->capacity;
+
+ int ma = MAJOR(dev);
+ int mi = (MINOR(dev) & ~0xf);
+
+ int block = 1024;
+
+ if(blksize_size[ma])
+ block = blksize_size[ma][mi];
+
+ if(!(bh = bread(MKDEV(ma,mi), 0, block)))
+ return -1;
+
+ if( *(unsigned short *)(bh->b_data + 510) == 0xAA55 ) {
+ for( largest_cyl = -1, p = (struct partition *)(0x1BE + bh->b_data),
+ i = 0; i < 4; ++i, ++p) {
+
+ if (!p->sys_ind) continue;
+
+ cyls = p->end_cyl + ((p->end_sector & 0xc0) << 2);
+
+ if(cyls >= largest_cyl) {
+ largest_cyl = cyls;
+ largest = p;
+ }
+ }
+ }
+ if (largest) {
+ heads = largest->end_head + 1;
+ sectors = largest->end_sector & 0x3f;
+
+ if (heads == 0 || sectors == 0) {
+ brelse(bh);
+ return -1;
+ }
+
+ cyls = capacity/(heads * sectors);
+
+ geom[0] = heads;
+ geom[1] = sectors;
+ geom[2] = cyls;
+
+ brelse(bh);
+ return 0;
+ }
+
+ brelse(bh);
+ return -1;
+}
+
+
/*
* This routine will be called when the use has done a forced shutdown on the
* system. Flush the Adapter cache, that's the most we can do.
printk (KERN_WARNING
"Can't allocate passthru for id %d\n", idx);
}
+
+ megacfg->scbList[idx].epthru =
+ pci_alloc_consistent(
+ megacfg->dev, sizeof(mega_ext_passthru),
+ &(megacfg->scbList[idx].dma_ext_passthruhandle64)
+ );
+
+ if (megacfg->scbList[idx].epthru == NULL) {
+ printk (KERN_WARNING
+ "Can't allocate extended passthru for id %d\n", idx);
+ }
/*
* Allocate a 256 Byte Bounce Buffer for handling INQ/RD_CAPA
*/
struct uioctl_t *uioc;
dma_addr_t dma_addr;
u32 length;
- mega_host_config *megacfg;
+ mega_host_config *megacfg = NULL;
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0) /* 0x020400 */
struct pci_dev pdev;
struct pci_dev *pdevp = &pdev;
}
+static int
+mega_support_ext_cdb(mega_host_config *this_hba)
+{
+ mega_mailbox *mboxpnt;
+ unsigned char mbox[16];
+ int ret;
+
+ mboxpnt = (mega_mailbox *) mbox;
+
+ memset(mbox, 0, sizeof (mbox));
+ /*
+ * issue command to find out if controller supports extended CDBs.
+ */
+ mbox[0] = 0xA4;
+ mbox[2] = 0x16;
+
+ ret = megaIssueCmd(this_hba, mbox, NULL, 0);
+
+ return !ret;
+}
+
+
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,4,0)
void *
dma_alloc_consistent(void *dev, size_t size, dma_addr_t *dma_addr)
#include "scsi_module.c"
#endif /* LINUX VERSION 2.4.XX || MODULE */
+
+/* vi: set ts=4: */
#define IN_RESET 0x20000000L
#define IN_QUEUE 0x10000000L
-#define BOARD_QUARTZ 0x08000000L
+#define BOARD_QUARTZ 0x08000000L
#define BOARD_40LD 0x04000000L
#define BOARD_64BIT 0x02000000L
#define M_RD_IOCTL_CMD_NEW 0x81
#define M_RD_DRIVER_IOCTL_INTERFACE 0x82
-#define MEGARAID_VERSION "v1.15d (Release Date: Wed May 30 17:30:41 EDT 2001)"
+#define MEGARAID_VERSION "v1.17a (Release Date: Fri Jul 13 18:44:01 EDT 2001)"
#define MEGARAID_IOCTL_VERSION 114
#define FROMTO_DEVICE 0x2
/* Mailbox commands */
-#define MEGA_MBOXCMD_LREAD 0x01
-#define MEGA_MBOXCMD_LWRITE 0x02
-#define MEGA_MBOXCMD_LREAD64 0xA7
-#define MEGA_MBOXCMD_LWRITE64 0xA8
-#define MEGA_MBOXCMD_PASSTHRU 0x03
-#define MEGA_MBOXCMD_ADAPTERINQ 0x05
+#define MEGA_MBOXCMD_LREAD 0x01
+#define MEGA_MBOXCMD_LWRITE 0x02
+#define MEGA_MBOXCMD_LREAD64 0xA7
+#define MEGA_MBOXCMD_LWRITE64 0xA8
+#define MEGA_MBOXCMD_PASSTHRU 0x03
+#define MEGA_MBOXCMD_EXTPASSTHRU 0xE3
+#define MEGA_MBOXCMD_ADAPTERINQ 0x05
+
/* Offsets into Mailbox */
#define COMMAND_PORT 0x00
#define M_RD_PTHRU_WITH_SGLIST 0x0002
#define M_RD_BULK_DATA_ONLY 0x0004
#define M_RD_SGLIST_ONLY 0x0008
+#define M_RD_EPTHRU_WITH_BULK_DATA 0x0010
#endif
/********************************************
* ENQUIRY3
u32 dataxferlen;
} mega_passthru;
+/*
+ * Extended passthru: support CDB > 10 bytes
+ */
+typedef struct {
+ u8 timeout:3; /* 0=6sec/1=60sec/2=10min/3=3hrs */
+ u8 ars:1;
+ u8 rsvd1:1;
+ u8 cd_rom:1;
+ u8 rsvd2:1;
+ u8 islogical:1;
+
+ u8 logdrv; /* if islogical == 1 */
+ u8 channel; /* if islogical == 0 */
+ u8 target; /* if islogical == 0 */
+
+ u8 queuetag; /* unused */
+ u8 queueaction; /* unused */
+
+ u8 cdblen;
+ u8 rsvd3;
+ u8 cdb[16];
+
+ u8 numsgelements;
+ u8 status;
+ u8 reqsenselen;
+ u8 reqsensearea[MAX_REQ_SENSE_LEN];
+ u8 rsvd4;
+
+ u32 dataxferaddr;
+ u32 dataxferlen;
+}mega_ext_passthru;
+
struct _mega_mailbox {
/* 0x0 */ u8 cmd;
/* 0x1 */ u8 cmdid;
u8 sglist_count;
dma_addr_t dma_sghandle64;
dma_addr_t dma_passthruhandle64;
+ dma_addr_t dma_ext_passthruhandle64;
dma_addr_t dma_bounce_buffer;
u8 *bounce_buffer;
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,0)
mega_passthru *pthru;
+ mega_ext_passthru *epthru;
#else
mega_passthru pthru;
+ mega_ext_passthru epthru;
#endif
Scsi_Cmnd *SCpnt;
int procidx;
struct proc_dir_entry *controller_proc_dir_entry;
struct proc_dir_entry *proc_read, *proc_stat, *proc_status, *proc_mbox;
+ int support_ext_cdb;
+ int boot_ldrv_enabled;
+ int boot_ldrv;
} mega_host_config;
typedef struct _driver_info {
#define IS_BIOS_ENABLED 0x62
#define GET_BIOS 0x01
+#define CHNL_CLASS 0xA9
+#define GET_CHNL_CLASS 0x00
+#define SET_CHNL_CLASS 0x01
+#define CH_RAID 0x01
+#define CH_SCSI 0x00
+
+
+#define BIOS_PVT_DATA 0x40
+#define GET_BIOS_PVT_DATA 0x00
+
+#pragma pack(1)
+struct private_bios_data {
+ u8 geometry:4; /*
+ * bits 0-3 - BIOS geometry
+ * 0x0001 - 1GB
+ * 0x0010 - 2GB
+ * 0x1000 - 8GB
+ * Others values are invalid
+ */
+ u8 unused:4; /* bits 4-7 are unused */
+ u8 boot_ldrv; /*
+ * logical drive set as boot drive
+ * 0..7 - for 8LD cards
+ * 0..39 - for 40LD cards
+ */
+ u8 rsvd[12];
+ u16 cksum; /* 0-(sum of first 13 bytes of this structure) */
+};
+#pragma pack()
+
/*================================================================
*
static void mega_swap_hosts (struct Scsi_Host *, struct Scsi_Host *);
static void mega_create_proc_entry (int index, struct proc_dir_entry *);
+static int mega_support_ext_cdb(mega_host_config *);
+static mega_passthru* mega_prepare_passthru(mega_host_config *, mega_scb *,
+ Scsi_Cmnd *);
+static mega_ext_passthru* mega_prepare_extpassthru(mega_host_config *,
+ mega_scb *, Scsi_Cmnd *);
+static void mega_enum_raid_scsi(mega_host_config *);
+static int mega_partsize(Disk *, kdev_t, int *);
+static void mega_get_boot_ldrv(mega_host_config *);
#endif
+
+/* vi: set ts=4: */
tpnt->sg_tablesize = ULTRASTOR_24F_MAX_SG;
shpnt = scsi_register(tpnt, 0);
+ if (!shpnt) {
+ printk(KERN_WARNING "(ultrastor:) Could not register scsi device. Aborting registration.\n");
+ free_irq(config.interrupt, do_ultrastor_interrupt);
+ return FALSE;
+ }
+
shpnt->irq = config.interrupt;
shpnt->dma_channel = config.dma_channel;
shpnt->io_port = config.port_address;
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
0,0,0,0,
0,1,1,-1},
+ {"Sound Blaster 16",
+ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c),
+ ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031),
+ 0,0,0,0,
+ 0,1,1,-1},
{"Sound Blaster 16",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
0,0,0,0,
0,1,1,-1},
+ {"Sound Blaster 16",
+ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086),
+ ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041),
+ 0,0,0,0,
+ 0,1,1,-1},
{"Sound Blaster Vibra16S",
ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001),
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002b),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
+ { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x002c),
+ ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0031), 0 },
+
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x00ed),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
+ { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0086),
+ ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0041), 0 },
+
{ ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x0051),
ISAPNP_VENDOR('C','T','L'), ISAPNP_FUNCTION(0x0001), 0 },
void sb_mixer_unload(sb_devc *devc)
{
+ kfree(mixer_devs[devc->my_mixerdev]);
sound_unload_mixerdev(devc->my_mixerdev);
sbmixnum--;
}
if (!(status32 & VIA_INTR_MASK))
{
#ifdef CONFIG_MIDI_VIA82CXXX
- uart401intr(irq, card->midi_devc, regs);
+ if (card->midi_devc)
+ uart401intr(irq, card->midi_devc, regs);
#endif
return;
}
{
struct video_window vw;
+ memset(&vw, 0, sizeof(vw));
vw.x = 0;
vw.y = 0;
vw.width = imgwidth;
vw.height = imgheight;
- vw.chromakey = 0;
vw.flags = usb_ibmcam_calculate_fps();
if (copy_to_user(arg, &vw, sizeof(vw)))
if (copy_from_user((void *)&frame, arg, sizeof(int)))
return -EFAULT;
+ if ((unsigned)frame >= IBMCAM_NUMFRAMES) {
+ err("VIDIOCSYNC: invalid frame %d.", frame);
+ return -EINVAL;
+ }
+
if (debug >= 1)
printk(KERN_DEBUG "ibmcam: syncing to frame %d\n", frame);
MODULE_AUTHOR( DRIVER_AUTHOR );
MODULE_DESCRIPTION( DRIVER_DESC );
-
-
PDEBUG (4, "VIDIOCGCAP");
+ memset(&b, 0, sizeof(b));
strcpy(b.name, "OV511 USB Camera");
b.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
b.channels = 1;
PDEBUG (4, "VIDIOCGPICT");
+ memset(&p, 0, sizeof(p));
+
if (ov7610_get_picture(ov511, &p))
return -EIO;
-
+
if (copy_to_user(arg, &p, sizeof(p)))
return -EFAULT;
{
struct video_window vw;
+ memset(&vw, 0, sizeof(vw));
vw.x = 0; /* FIXME */
vw.y = 0;
vw.width = ov511->frame[0].width;
vw.height = ov511->frame[0].height;
- vw.chromakey = 0;
vw.flags = 30;
PDEBUG (4, "VIDIOCGWIN: %dx%d", vw.width, vw.height);
case VIDIOCGMBUF:
{
struct video_mbuf vm;
-
+ int i;
+
memset(&vm, 0, sizeof(vm));
vm.size = OV511_NUMFRAMES * MAX_DATA_SIZE;
vm.frames = OV511_NUMFRAMES;
vm.offsets[0] = 0;
- vm.offsets[1] = MAX_FRAME_SIZE + sizeof (struct timeval);
+ for (i = 1; i < OV511_NUMFRAMES; i++) {
+ vm.offsets[i] = vm.offsets[i-1] + MAX_FRAME_SIZE
+ + sizeof (struct timeval);
+ }
if (copy_to_user((void *)arg, (void *)&vm, sizeof(vm)))
return -EFAULT;
return -EINVAL;
}
- if ((vm.frame != 0) && (vm.frame != 1)) {
+ if ((unsigned)vm.frame >= OV511_NUMFRAMES) {
err("VIDIOCMCAPTURE: invalid frame (%d)", vm.frame);
return -EINVAL;
}
if (copy_from_user((void *)&frame, arg, sizeof(int)))
return -EFAULT;
+ if ((unsigned)frame >= OV511_NUMFRAMES) {
+ err("VIDIOCSYNC: invalid frame (%d)", frame);
+ return -EINVAL;
+ }
+
PDEBUG(4, "syncing to frame %d, grabstate = %d", frame,
ov511->frame[frame].grabstate);
#include <linux/spinlock.h>
#include <linux/usb.h>
#include <linux/smp_lock.h>
+#include <linux/devfs_fs_kernel.h>
#include "rio500_usb.h"
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.0.0"
+#define DRIVER_VERSION "v1.1"
#define DRIVER_AUTHOR "Cesar Miquel <miquel@df.uba.ar>"
#define DRIVER_DESC "USB Rio 500 driver"
struct rio_usb_data {
struct usb_device *rio_dev; /* init: probe_rio */
+ devfs_handle_t devfs; /* devfs device */
unsigned int ifnum; /* Interface number of the USB device */
int isopen; /* nz if open */
int present; /* Device is present on the bus */
struct semaphore lock; /* general race avoidance */
};
+extern devfs_handle_t usb_devfs_handle; /* /dev/usb dir. */
+
static struct rio_usb_data rio_instance;
static int open_rio(struct inode *inode, struct file *file)
int this_read;
int result;
int maxretry = 10;
- char *ibuf = rio->ibuf;
+ char *ibuf;
/* Sanity check to make sure rio is connected, powered, etc */
if ( rio == NULL ||
rio->rio_dev == NULL )
return -1;
+ ibuf = rio->ibuf;
+
read_count = 0;
down(&(rio->lock));
return read_count;
}
+static struct
+file_operations usb_rio_fops = {
+ read: read_rio,
+ write: write_rio,
+ ioctl: ioctl_rio,
+ open: open_rio,
+ release: close_rio,
+};
+
static void *probe_rio(struct usb_device *dev, unsigned int ifnum,
const struct usb_device_id *id)
{
}
dbg("probe_rio: ibuf address:%p", rio->ibuf);
+ rio->devfs = devfs_register(usb_devfs_handle, "rio500",
+ DEVFS_FL_DEFAULT, USB_MAJOR,
+ RIO_MINOR,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP |
+ S_IWGRP, &usb_rio_fops, NULL);
+ if (rio->devfs == NULL)
+ dbg("probe_rio: device node registration failed");
+
init_MUTEX(&(rio->lock));
return rio;
{
struct rio_usb_data *rio = (struct rio_usb_data *) ptr;
+ devfs_unregister(rio->devfs);
+
if (rio->isopen) {
rio->isopen = 0;
/* better let it finish - the release will do whats needed */
rio->present = 0;
}
-static struct
-file_operations usb_rio_fops = {
- read: read_rio,
- write: write_rio,
- ioctl: ioctl_rio,
- open: open_rio,
- release: close_rio,
-};
-
static struct usb_device_id rio_table [] = {
{ USB_DEVICE(0x0841, 1) }, /* Rio 500 */
{ } /* Terminating entry */
switch (cmd)
{
+ case IOCTL_SCANNER_VENDOR :
+ return (put_user(dev->descriptor.idVendor, (unsigned int *) arg));
+ case IOCTL_SCANNER_PRODUCT :
+ return (put_user(dev->descriptor.idProduct, (unsigned int *) arg));
case PV8630_IOCTL_INREQUEST :
{
struct {
/* Enable to activate the ioctl interface. This is mainly meant for */
/* development purposes until an ioctl number is officially registered */
-// #define SCN_IOCTL
+#define SCN_IOCTL
/* WARNING: These DATA_DUMP's can produce a lot of data. Caveat Emptor. */
// #define RD_DATA_DUMP /* Enable to dump data - limited to 24 bytes */
{ USB_DEVICE(0x04b8, 0x010a) }, /* Perfection 1640SU and 1640SU Photo */
{ USB_DEVICE(0x04b8, 0x010b) }, /* Perfection 1240U */
{ USB_DEVICE(0x04b8, 0x010c) }, /* Perfection 640U */
+ { USB_DEVICE(0x04b8, 0x010e) }, /* Expression 1680 */
/* Umax */
{ USB_DEVICE(0x1606, 0x0010) }, /* Astra 1220U */
{ USB_DEVICE(0x1606, 0x0030) }, /* Astra 2000U */
#define PV8630_IOCTL_INREQUEST 69
#define PV8630_IOCTL_OUTREQUEST 70
+/* read vendor and product IDs */
+#define IOCTL_SCANNER_VENDOR _IOR('u', 0xa0, int)
+#define IOCTL_SCANNER_PRODUCT _IOR('u', 0xa1, int)
+
#define SCN_MAX_MNR 16 /* We're allocated 16 minors */
#define SCN_BASE_MNR 48 /* USB Scanners start at minor 48 */
/* irq handler for snapshot button */
static void se401_button_irq(struct urb *urb)
{
- struct usb_se401 *se401=urb->context;
+ struct usb_se401 *se401 = urb->context;
- if (!urb) {
- info("ohoh: null urb");
- return;
- }
if (!se401->dev) {
info("ohoh: device vapourished");
return;
static void se401_video_irq(struct urb *urb)
{
- struct usb_se401 *se401=urb->context;
- int length=urb->actual_length;
+ struct usb_se401 *se401 = urb->context;
+ int length = urb->actual_length;
/* ohoh... */
- if (!se401->streaming) {
- return;
- }
- if (!urb) {
- info ("ohoh: null urb");
+ if (!se401->streaming)
return;
- }
+
if (!se401->dev) {
info ("ohoh: device vapourished");
return;
*
* See Documentation/usb/usb-serial.txt for more information on using this driver
*
+ * (07/16/2001) gb
+ * remove unused code in empeg_close() (thanks to Oliver Neukum for pointing this
+ * out) and rewrote empeg_set_termios().
+ *
* (05/30/2001) gkh
* switched from using spinlock to a semaphore, which fixes lots of problems.
*
/*
* Version Information
*/
-#define DRIVER_VERSION "v1.1"
+#define DRIVER_VERSION "v1.2"
#define DRIVER_AUTHOR "Greg Kroah-Hartman <greg@kroah.com>, Gary Brubaker <xavyer@ix.netcom.com>"
#define DRIVER_DESC "USB Empeg Mark I/II Driver"
if (!port->active) {
- /* gb - 2000/11/05
- * personally, I think these termios should be set in
- * empeg_startup(), but it appears doing so leads to one
- * of those chicken/egg problems. :)
- */
- port->tty->termios->c_iflag
- &= ~(IGNBRK
- | BRKINT
- | PARMRK
- | ISTRIP
- | INLCR
- | IGNCR
- | ICRNL
- | IXON);
-
- port->tty->termios->c_oflag
- &= ~OPOST;
-
- port->tty->termios->c_lflag
- &= ~(ECHO
- | ECHONL
- | ICANON
- | ISIG
- | IEXTEN);
-
- port->tty->termios->c_cflag
- &= ~(CSIZE
- | PARENB);
-
- port->tty->termios->c_cflag
- |= CS8;
-
- /* gb - 2000/12/03
- * Contributed by Borislav Deianov
- * Notify the tty driver that the termios have changed!!
- */
- port->tty->ldisc.set_termios(port->tty, NULL);
-
- /* gb - 2000/11/05
- * force low_latency on
- *
- * The tty_flip_buffer_push()'s in empeg_read_bulk_callback() will actually
- * force the data through if low_latency is set. Otherwise the pushes are
- * scheduled; this is bad as it opens up the possibility of dropping bytes
- * on the floor. We are trying to sustain high data transfer rates; and
- * don't want to drop bytes on the floor.
- * Moral: use low_latency - drop no bytes - life is good. :)
- */
- port->tty->low_latency = 1;
+ /* Force default termio settings */
+ empeg_set_termios (port, NULL) ;
port->active = 1;
bytes_in = 0;
}
-/* This function is all nice and good, but we don't change anything based on it :) */
static void empeg_set_termios (struct usb_serial_port *port, struct termios *old_termios)
{
- unsigned int cflag = port->tty->termios->c_cflag;
dbg(__FUNCTION__ " - port %d", port->number);
- /* check that they really want us to change something */
- if (old_termios) {
- if ((cflag == old_termios->c_cflag) &&
- (RELEVANT_IFLAG(port->tty->termios->c_iflag) == RELEVANT_IFLAG(old_termios->c_iflag))) {
- dbg(__FUNCTION__ " - nothing to change...");
- return;
- }
- }
-
if ((!port->tty) || (!port->tty->termios)) {
dbg(__FUNCTION__" - no tty structures");
return;
}
- /* get the byte size */
- switch (cflag & CSIZE) {
- case CS5: dbg(__FUNCTION__ " - data bits = 5"); break;
- case CS6: dbg(__FUNCTION__ " - data bits = 6"); break;
- case CS7: dbg(__FUNCTION__ " - data bits = 7"); break;
- default:
- case CS8: dbg(__FUNCTION__ " - data bits = 8"); break;
- }
-
- /* determine the parity */
- if (cflag & PARENB)
- if (cflag & PARODD)
- dbg(__FUNCTION__ " - parity = odd");
- else
- dbg(__FUNCTION__ " - parity = even");
- else
- dbg(__FUNCTION__ " - parity = none");
-
- /* figure out the stop bits requested */
- if (cflag & CSTOPB)
- dbg(__FUNCTION__ " - stop bits = 2");
- else
- dbg(__FUNCTION__ " - stop bits = 1");
-
- /* figure out the flow control settings */
- if (cflag & CRTSCTS)
- dbg(__FUNCTION__ " - RTS/CTS is enabled");
- else
- dbg(__FUNCTION__ " - RTS/CTS is disabled");
-
- /* determine software flow control */
- if (I_IXOFF(port->tty))
- dbg(__FUNCTION__ " - XON/XOFF is enabled, XON = %2x, XOFF = %2x", START_CHAR(port->tty), STOP_CHAR(port->tty));
- else
- dbg(__FUNCTION__ " - XON/XOFF is disabled");
-
- /* get the baud rate wanted */
- dbg(__FUNCTION__ " - baud rate = %d", tty_get_baud_rate(port->tty));
+ /*
+ * The empeg-car player wants these particular tty settings.
+ * You could, for example, change the baud rate, however the
+ * player only supports 115200 (currently), so there is really
+ * no point in support for changes to the tty settings.
+ * (at least for now)
+ *
+ * The default requirements for this device are:
+ */
+ port->tty->termios->c_iflag
+ &= ~(IGNBRK /* disable ignore break */
+ | BRKINT /* disable break causes interrupt */
+ | PARMRK /* disable mark parity errors */
+ | ISTRIP /* disable clear high bit of input characters */
+ | INLCR /* disable translate NL to CR */
+ | IGNCR /* disable ignore CR */
+ | ICRNL /* disable translate CR to NL */
+ | IXON); /* disable enable XON/XOFF flow control */
+
+ port->tty->termios->c_oflag
+ &= ~OPOST; /* disable postprocess output characters */
+
+ port->tty->termios->c_lflag
+ &= ~(ECHO /* disable echo input characters */
+ | ECHONL /* disable echo new line */
+ | ICANON /* disable erase, kill, werase, and rprnt special characters */
+ | ISIG /* disable interrupt, quit, and suspend special characters */
+ | IEXTEN); /* disable non-POSIX special characters */
+
+ port->tty->termios->c_cflag
+ &= ~(CSIZE /* no size */
+ | PARENB /* disable parity bit */
+ | CBAUD); /* clear current baud rate */
+
+ port->tty->termios->c_cflag
+ |= (CS8 /* character size 8 bits */
+ | B115200); /* baud rate 115200 */
+
+ /*
+ * Force low_latency on; otherwise the pushes are scheduled;
+ * this is bad as it opens up the possibility of dropping bytes
+ * on the floor. We don't want to drop bytes on the floor. :)
+ */
+ port->tty->low_latency = 1;
+
+ /* Notify the tty driver that the termios have changed. */
+ port->tty->ldisc.set_termios(port->tty, NULL);
return;
* URB OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000 David Brownell <david-b@pacbell.net>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
*
* [ Initialisation is based on Linus' ]
* [ uhci code and gregs ohci fragments ]
*
* History:
*
- * 2001/04/08 Identify version on module load gb
+ * 2001/07/17 power management and pmac cleanup (Benjamin Herrenschmidt)
* 2001/03/24 td/ed hashing to remove bus_to_virt (Steve Longerbeam);
pci_map_single (db)
* 2001/03/21 td and dev/ed allocation uses new pci_pool API (db)
#ifdef CONFIG_PMAC_PBOOK
-/* All this PMAC_PBOOK stuff should disappear when those
- * platforms fully support the 2.4 kernel PCI APIs.
- */
-#include <linux/adb.h>
-#include <linux/pmu.h>
+#include <asm/feature.h>
+#include <asm/pci-bridge.h>
#ifndef CONFIG_PM
#define CONFIG_PM
#endif
/*
* Version Information
*/
-#define DRIVER_VERSION "v5.2"
+#define DRIVER_VERSION "v5.3"
#define DRIVER_AUTHOR "Roman Weissgaerber <weissg@vienna.at>, David Brownell"
#define DRIVER_DESC "USB OHCI Host Controller Driver"
{
int i;
int last = urb_priv->length - 1;
+ int len;
+ int dir;
struct td *td;
- for (i = 0; i <= last; i++) {
- td = urb_priv->td [i];
- if (td) {
- int len;
- int dir;
-
- if ((td->hwINFO & cpu_to_le32 (TD_DP)) == TD_DP_SETUP) {
- len = 8;
- dir = PCI_DMA_TODEVICE;
- } else if (i == last) {
- len = td->urb->transfer_buffer_length,
- dir = usb_pipeout (td->urb->pipe)
+ if (last >= 0) {
+
+ /* ISOC, BULK, INTR data buffer starts at td 0
+ * CTRL setup starts at td 0 */
+ td = urb_priv->td [0];
+
+ len = td->urb->transfer_buffer_length,
+ dir = usb_pipeout (td->urb->pipe)
? PCI_DMA_TODEVICE
: PCI_DMA_FROMDEVICE;
- } else
- len = dir = 0;
- if (len && td->data_dma)
- pci_unmap_single (hc->ohci_dev,
- td->data_dma, len, dir);
- td_free (hc, urb_priv->td [i]);
+
+ /* unmap CTRL URB setup */
+ if (usb_pipecontrol (td->urb->pipe)) {
+ pci_unmap_single (hc->ohci_dev,
+ td->data_dma, 8, PCI_DMA_TODEVICE);
+
+ /* CTRL data buffer starts at td 1 if len > 0 */
+ if (len && last > 0)
+ td = urb_priv->td [1];
+ }
+
+ /* unmap data buffer */
+ if (len && td->data_dma)
+ pci_unmap_single (hc->ohci_dev, td->data_dma, len, dir);
+
+ for (i = 0; i <= last; i++) {
+ td = urb_priv->td [i];
+ if (td)
+ td_free (hc, td);
}
}
}
ed->ed_prev = ohci->ed_controltail;
if (!ohci->ed_controltail && !ohci->ed_rm_list[0] &&
- !ohci->ed_rm_list[1]) {
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
ohci->hc_control |= OHCI_CTRL_CLE;
writel (ohci->hc_control, &ohci->regs->control);
}
}
ed->ed_prev = ohci->ed_bulktail;
if (!ohci->ed_bulktail && !ohci->ed_rm_list[0] &&
- !ohci->ed_rm_list[1]) {
+ !ohci->ed_rm_list[1] && !ohci->sleeping) {
ohci->hc_control |= OHCI_CTRL_BLE;
writel (ohci->hc_control, &ohci->regs->control);
}
ed->ed_rm_list = ohci->ed_rm_list[frame];
ohci->ed_rm_list[frame] = ed;
- if (!ohci->disabled) {
+ if (!ohci->disabled && !ohci->sleeping) {
/* enable SOF interrupt */
writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
writel (OHCI_INTR_SF, &ohci->regs->intrenable);
TD_CC | TD_DP_OUT : TD_CC | TD_R | TD_DP_IN ;
td_fill (ohci, info | (cnt? TD_T_TOGGLE:toggle), data, data_len, urb, cnt);
cnt++;
- writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+ if (!ohci->sleeping)
+ writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
break;
case PIPE_INTERRUPT:
info = usb_pipeout (urb->pipe)?
TD_CC | TD_DP_IN | TD_T_DATA1: TD_CC | TD_DP_OUT | TD_T_DATA1;
td_fill (ohci, info, data, 0, urb, cnt++);
- writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
+ if (!ohci->sleeping)
+ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
break;
case PIPE_ISOCHRONOUS:
writel (0, &ohci->regs->ed_controlcurrent);
if (bulk) /* reset bulk list */
writel (0, &ohci->regs->ed_bulkcurrent);
- if (!ohci->ed_rm_list[!frame]) {
+ if (!ohci->ed_rm_list[!frame] && !ohci->sleeping) {
if (ohci->ed_controltail)
ohci->hc_control |= OHCI_CTRL_CLE;
if (ohci->ed_bulktail)
memset (ohci->hcca, 0, sizeof (struct ohci_hcca));
ohci->disabled = 1;
+ ohci->sleeping = 0;
ohci->irq = -1;
ohci->regs = mem_base;
pci_write_config_byte (ohci->ohci_dev, PCI_LATENCY_TIMER, ohci->pci_latency);
ohci->disabled = 1;
+ ohci->sleeping = 0;
if (ohci->bus->root_hub)
usb_disconnect (&ohci->bus->root_hub);
static int
ohci_pci_suspend (struct pci_dev *dev, u32 state)
{
- ohci_t *ohci = (ohci_t *) dev->driver_data;
+ ohci_t *ohci = (ohci_t *) dev->driver_data;
+ unsigned long flags;
+ u16 cmd;
if ((ohci->hc_control & OHCI_CTRL_HCFS) != OHCI_USB_OPER) {
dbg ("can't suspend usb-%s (state is %s)", dev->slot_name,
/* act as if usb suspend can always be used */
info ("USB suspend: usb-%s", dev->slot_name);
+ ohci->sleeping = 1;
+
+ /* First stop processing */
+ spin_lock_irqsave (&usb_ed_lock, flags);
+ ohci->hc_control &= ~(OHCI_CTRL_PLE|OHCI_CTRL_CLE|OHCI_CTRL_BLE|OHCI_CTRL_IE);
+ writel (ohci->hc_control, &ohci->regs->control);
+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+ (void) readl (&ohci->regs->intrstatus);
+ spin_unlock_irqrestore (&usb_ed_lock, flags);
+
+ /* Wait a frame or two */
+ mdelay(1);
+ if (!readl (&ohci->regs->intrstatus) & OHCI_INTR_SF)
+ mdelay (1);
+
#ifdef CONFIG_PMAC_PBOOK
- disable_irq (ohci->irq);
+ if (_machine == _MACH_Pmac)
+ disable_irq (ohci->irq);
/* else, 2.4 assumes shared irqs -- don't disable */
#endif
+ /* Enable remote wakeup */
+ writel (readl(&ohci->regs->intrenable) | OHCI_INTR_RD, &ohci->regs->intrenable);
+
+ /* Suspend chip and let things settle down a bit */
ohci->hc_control = OHCI_USB_SUSPEND;
writel (ohci->hc_control, &ohci->regs->control);
- wait_ms (10);
+ (void) readl (&ohci->regs->control);
+ mdelay (500); /* No schedule here ! */
+ switch (readl (&ohci->regs->control) & OHCI_CTRL_HCFS) {
+ case OHCI_USB_RESET:
+ dbg("Bus in reset phase ???");
+ break;
+ case OHCI_USB_RESUME:
+ dbg("Bus in resume phase ???");
+ break;
+ case OHCI_USB_OPER:
+ dbg("Bus in operational phase ???");
+ break;
+ case OHCI_USB_SUSPEND:
+ dbg("Bus suspended");
+ break;
+ }
+ /* In some rare situations, Apple's OHCI have happily trashed
+ * memory during sleep. We disable it's bus master bit during
+ * suspend
+ */
+ pci_read_config_word (dev, PCI_COMMAND, &cmd);
+ cmd &= ~PCI_COMMAND_MASTER;
+ pci_write_config_word (dev, PCI_COMMAND, cmd);
+#ifdef CONFIG_PMAC_PBOOK
+ {
+ struct device_node *of_node;
+ /* Disable USB PAD & cell clock */
+ of_node = pci_device_to_OF_node (ohci->ohci_dev);
+ if (of_node && _machine == _MACH_Pmac)
+ feature_set_usb_power (of_node, 0);
+ }
+#endif
return 0;
}
{
ohci_t *ohci = (ohci_t *) dev->driver_data;
int temp;
+ unsigned long flags;
/* guard against multiple resumes */
atomic_inc (&ohci->resume_count);
if (atomic_read (&ohci->resume_count) != 1) {
err ("concurrent PCI resumes for usb-%s", dev->slot_name);
atomic_dec (&ohci->resume_count);
- return -EBUSY;
+ return 0;
+ }
+
+#ifdef CONFIG_PMAC_PBOOK
+ {
+ struct device_node *of_node;
+
+ /* Re-enable USB PAD & cell clock */
+ of_node = pci_device_to_OF_node (ohci->ohci_dev);
+ if (of_node && _machine == _MACH_Pmac)
+ feature_set_usb_power (of_node, 1);
}
+#endif
/* did we suspend, or were we powered off? */
ohci->hc_control = readl (&ohci->regs->control);
ohci_dump_status (ohci);
#endif
+ /* Re-enable bus mastering */
+ pci_set_master(ohci->ohci_dev);
+
switch (temp) {
case OHCI_USB_RESET: // lost power
? "host" : "remote");
ohci->hc_control = OHCI_USB_RESUME;
writel (ohci->hc_control, &ohci->regs->control);
- wait_ms (20);
-
+ (void) readl (&ohci->regs->control);
+ mdelay (20); /* no schedule here ! */
+ /* Some controllers (lucent) need a longer delay here */
+ mdelay (15);
temp = readl (&ohci->regs->control);
temp = ohci->hc_control & OHCI_CTRL_HCFS;
if (temp != OHCI_USB_RESUME) {
return -EIO;
}
+ /* Some chips likes being resumed first */
+ writel (OHCI_USB_OPER, &ohci->regs->control);
+ (void) readl (&ohci->regs->control);
+ mdelay (3);
+
+ /* Then re-enable operations */
+ spin_lock_irqsave (&usb_ed_lock, flags);
ohci->disabled = 0;
+ ohci->sleeping = 0;
ohci->hc_control = OHCI_CONTROL_INIT | OHCI_USB_OPER;
- if (!ohci->ed_rm_list[0] & !ohci->ed_rm_list[1]) {
+ if (!ohci->ed_rm_list[0] && !ohci->ed_rm_list[1]) {
if (ohci->ed_controltail)
ohci->hc_control |= OHCI_CTRL_CLE;
if (ohci->ed_bulktail)
ohci->hc_control |= OHCI_CTRL_BLE;
}
writel (ohci->hc_control, &ohci->regs->control);
+ writel (OHCI_INTR_SF, &ohci->regs->intrstatus);
+ writel (OHCI_INTR_SF, &ohci->regs->intrenable);
+ /* Check for a pending done list */
+ writel (OHCI_INTR_WDH, &ohci->regs->intrdisable);
+ (void) readl (&ohci->regs->intrdisable);
+ spin_unlock_irqrestore (&usb_ed_lock, flags);
#ifdef CONFIG_PMAC_PBOOK
- enable_irq (ohci->irq);
+ if (_machine == _MACH_Pmac)
+ enable_irq (ohci->irq);
#endif
+ if (ohci->hcca->done_head)
+ dl_done_list (ohci, dl_reverse_done_list (ohci));
+ writel (OHCI_INTR_WDH, &ohci->regs->intrenable);
+ writel (OHCI_BLF, &ohci->regs->cmdstatus); /* start bulk list */
+ writel (OHCI_CLF, &ohci->regs->cmdstatus); /* start Control list */
break;
default:
probe: ohci_pci_probe,
remove: ohci_pci_remove,
-#ifdef CONFIG_PMAC_PBOOK
- /* pbook PCI thinks different ... for now :-) */
-#else
#ifdef CONFIG_PM
suspend: ohci_pci_suspend,
resume: ohci_pci_resume,
#endif /* PM */
-#endif /* PBOOK */
};
-#ifdef CONFIG_PMAC_PBOOK
-
-/*-------------------------------------------------------------------------*/
-
-static int ohci_sleep_notify (struct pmu_sleep_notifier * self, int when)
-{
- struct list_head * ohci_l;
- ohci_t * ohci;
-
- for (ohci_l = ohci_hcd_list.next; ohci_l != &ohci_hcd_list; ohci_l = ohci_l->next) {
- ohci = list_entry (ohci_l, ohci_t, ohci_hcd_list);
-
- switch (when) {
- case PBOOK_SLEEP_NOW:
- ohci_pci_suspend (ohci->ohci_dev, 3);
- break;
- case PBOOK_WAKE:
- ohci_pci_resume (ohci->ohci_dev);
- break;
- }
- }
- return PBOOK_SLEEP_OK;
-}
-
-static struct pmu_sleep_notifier ohci_sleep_notifier = {
- ohci_sleep_notify, SLEEP_LEVEL_MISC,
-};
-#endif /* CONFIG_PMAC_PBOOK */
-
-
/*-------------------------------------------------------------------------*/
static int __init ohci_hcd_init (void)
{
- int ret;
-
- if ((ret = pci_module_init (&ohci_pci_driver)) < 0) {
- return ret;
- }
-
-#ifdef CONFIG_PMAC_PBOOK
- pmu_register_sleep_notifier (&ohci_sleep_notifier);
-#endif
- info(DRIVER_VERSION ":" DRIVER_DESC);
- return ret;
+ return pci_module_init (&ohci_pci_driver);
}
/*-------------------------------------------------------------------------*/
static void __exit ohci_hcd_cleanup (void)
{
-#ifdef CONFIG_PMAC_PBOOK
- pmu_unregister_sleep_notifier (&ohci_sleep_notifier);
-#endif
pci_unregister_driver (&ohci_pci_driver);
}
* URB OHCI HCD (Host Controller Driver) for USB.
*
* (C) Copyright 1999 Roman Weissgaerber <weissg@vienna.at>
- * (C) Copyright 2000 David Brownell <david-b@pacbell.net>
+ * (C) Copyright 2000-2001 David Brownell <dbrownell@users.sourceforge.net>
*
* usb-ohci.h
*/
int irq;
int disabled; /* e.g. got a UE, we're hung */
+ int sleeping;
atomic_t resume_count; /* defending against multiple resumes */
unsigned long flags; /* for HC bugs */
#define OHCI_QUIRK_AMD756 0x01 /* erratum #4 */
dev->devnum, err);
clear_bit(dev->devnum, &dev->bus->devmap.devicemap);
dev->devnum = -1;
- usb_free_dev(dev);
return 1;
}
unsigned long symlink_bitmap[AUTOFS_SYMLINK_BITMAP_LEN];
};
-extern inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
+static inline struct autofs_sb_info *autofs_sbi(struct super_block *sb)
{
return (struct autofs_sb_info *)(sb->u.generic_sbp);
}
{
ll_rw_block(opr,nbreq,bh);
}
-
-struct buffer_head *bigblock_fat_bread(struct super_block *sb, int block)
-{
- unsigned int hardsect = get_hardsect_size(sb->s_dev);
- int rblock, roffset;
- struct buffer_head *real, *dummy;
-
- if (hardsect <= sb->s_blocksize)
- BUG();
-
- dummy = NULL;
- rblock = block / (hardsect / sb->s_blocksize);
- roffset = (block % (hardsect / sb->s_blocksize)) * sb->s_blocksize;
- real = bread(sb->s_dev, rblock, hardsect);
- if (real != NULL) {
- dummy = kmalloc(sizeof(struct buffer_head), GFP_KERNEL);
- if (dummy != NULL) {
- memset(dummy, 0, sizeof(*dummy));
- dummy->b_data = real->b_data + roffset;
- dummy->b_next = real;
- } else
- brelse(real);
- }
-
- return dummy;
-}
-
-void bigblock_fat_brelse(struct super_block *sb, struct buffer_head *bh)
-{
- brelse(bh->b_next);
- kfree(bh);
-}
-
-void bigblock_fat_mark_buffer_dirty(struct super_block *sb, struct buffer_head *bh)
-{
- mark_buffer_dirty(bh->b_next);
-}
-
-void bigblock_fat_set_uptodate(struct super_block *sb, struct buffer_head *bh,
- int val)
-{
- mark_buffer_uptodate(bh->b_next, val);
-}
-
-int bigblock_fat_is_uptodate(struct super_block *sb, struct buffer_head *bh)
-{
- return buffer_uptodate(bh->b_next);
-}
-
-void bigblock_fat_ll_rw_block (struct super_block *sb, int opr, int nbreq,
- struct buffer_head *bh[32])
-{
- struct buffer_head *tmp[32];
- int i;
-
- for (i = 0; i < nbreq; i++)
- tmp[i] = bh[i]->b_next;
- ll_rw_block(opr, nbreq, tmp);
-}
struct buffer_head *default_fat_bread(struct super_block *,int);
struct buffer_head *default_fat_getblk(struct super_block *, int);
-struct buffer_head *bigblock_fat_bread(struct super_block *, int);
void default_fat_brelse(struct super_block *, struct buffer_head *);
-void bigblock_fat_brelse(struct super_block *, struct buffer_head *);
-void default_fat_mark_buffer_dirty (struct super_block *,
- struct buffer_head *);
-void bigblock_fat_mark_buffer_dirty (struct super_block *,
- struct buffer_head *);
+void default_fat_mark_buffer_dirty (struct super_block *, struct buffer_head *);
void default_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
-void bigblock_fat_set_uptodate (struct super_block *, struct buffer_head *,int);
int default_fat_is_uptodate(struct super_block *, struct buffer_head *);
-int bigblock_fat_is_uptodate(struct super_block *, struct buffer_head *);
int default_fat_access(struct super_block *sb,int nr,int new_value);
-void default_fat_ll_rw_block (
- struct super_block *sb,
- int opr,
- int nbreq,
- struct buffer_head *bh[32]);
-void bigblock_fat_ll_rw_block (
- struct super_block *sb,
- int opr,
- int nbreq,
- struct buffer_head *bh[32]);
+void default_fat_ll_rw_block (struct super_block *sb, int opr, int nbreq,
+ struct buffer_head *bh[32]);
int default_fat_bmap(struct inode *inode,int block);
-ssize_t default_fat_file_write(
- struct file *filp,
- const char *buf,
- size_t count,
- loff_t *ppos);
+ssize_t default_fat_file_write(struct file *filp, const char *buf,
+ size_t count, loff_t *ppos);
struct cvf_format default_cvf = {
- 0, /* version - who cares? */
- "plain",
- 0, /* flags - who cares? */
- NULL,
- NULL,
- NULL,
- default_fat_bread,
- default_fat_getblk,
- default_fat_brelse,
- default_fat_mark_buffer_dirty,
- default_fat_set_uptodate,
- default_fat_is_uptodate,
- default_fat_ll_rw_block,
- default_fat_access,
- NULL,
- default_fat_bmap,
- generic_file_read,
- default_fat_file_write,
- NULL,
- NULL
-};
-
-struct cvf_format bigblock_cvf = {
- 0, /* version - who cares? */
- "big_blocks",
- 0, /* flags - who cares? */
- NULL,
- NULL,
- NULL,
- bigblock_fat_bread,
- bigblock_fat_bread,
- bigblock_fat_brelse,
- bigblock_fat_mark_buffer_dirty,
- bigblock_fat_set_uptodate,
- bigblock_fat_is_uptodate,
- bigblock_fat_ll_rw_block,
- default_fat_access,
- NULL,
- default_fat_bmap,
- NULL,
- default_fat_file_write,
- NULL,
- NULL
+ cvf_version: 0, /* version - who cares? */
+ cvf_version_text: "plain",
+ flags: 0, /* flags - who cares? */
+ cvf_bread: default_fat_bread,
+ cvf_getblk: default_fat_getblk,
+ cvf_brelse: default_fat_brelse,
+ cvf_mark_buffer_dirty: default_fat_mark_buffer_dirty,
+ cvf_set_uptodate: default_fat_set_uptodate,
+ cvf_is_uptodate: default_fat_is_uptodate,
+ cvf_ll_rw_block: default_fat_ll_rw_block,
+ fat_access: default_fat_access,
+ cvf_bmap: default_fat_bmap,
+ cvf_file_read: generic_file_read,
+ cvf_file_write: default_fat_file_write,
};
struct cvf_format *cvf_formats[MAX_CVF_FORMATS];
#include <asm/uaccess.h>
#include <asm/unaligned.h>
-extern struct cvf_format default_cvf, bigblock_cvf;
+extern struct cvf_format default_cvf;
/* #define FAT_PARANOIA 1 */
#define DEBUG_LEVEL 0
hard_blksize = get_hardsect_size(sb->s_dev);
if (!hard_blksize)
hard_blksize = 512;
- if (hard_blksize != 512)
- printk("MSDOS: Hardware sector size is %d\n", hard_blksize);
opts.isvfat = sbi->options.isvfat;
if (!parse_options((char *) data, &fat, &debug, &opts,
set_blocksize(sb->s_dev, hard_blksize);
bh = bread(sb->s_dev, 0, sb->s_blocksize);
if (bh == NULL) {
- brelse (bh);
- goto out_no_bread;
+ printk("FAT: unable to read boot sector\n");
+ goto out_fail;
}
/*
CF_LE_W(get_unaligned((unsigned short *) &b->sector_size));
if (!logical_sector_size
|| (logical_sector_size & (logical_sector_size - 1))) {
- printk("fatfs: bogus logical sector size %d\n",
+ printk("FAT: bogus logical sector size %d\n",
logical_sector_size);
brelse(bh);
goto out_invalid;
}
sbi->cluster_size = b->cluster_size;
- if (!sbi->cluster_size || (sbi->cluster_size & (sbi->cluster_size - 1))) {
- printk("fatfs: bogus cluster size %d\n", sbi->cluster_size);
+ if (!sbi->cluster_size
+ || (sbi->cluster_size & (sbi->cluster_size - 1))) {
+ printk("FAT: bogus cluster size %d\n", sbi->cluster_size);
+ brelse(bh);
+ goto out_invalid;
+ }
+
+ if (logical_sector_size < hard_blksize) {
+ printk("FAT: logical sector size too small for device"
+ " (logical sector size = %d)\n", logical_sector_size);
brelse(bh);
goto out_invalid;
}
if (bh->b_blocknr != fsinfo_block) {
fsinfo_bh = bread(sb->s_dev, fsinfo_block, hard_blksize);
if (fsinfo_bh == NULL) {
- printk("FAT: bread failed, fsinfo block %d\n",
- fsinfo_block);
+ printk("FAT: bread failed, FSINFO block"
+ " (blocknr = %d)\n", fsinfo_block);
brelse(bh);
goto out_invalid;
}
sb->s_blocksize = logical_sector_size;
sb->s_blocksize_bits = ffs(logical_sector_size) - 1;
- if (sb->s_blocksize >= hard_blksize) {
- set_blocksize(sb->s_dev, sb->s_blocksize);
- sbi->cvf_format = &default_cvf;
- } else {
- set_blocksize(sb->s_dev, hard_blksize);
- sbi->cvf_format = &bigblock_cvf;
- }
-
- if (!strcmp(cvf_format,"none"))
+ set_blocksize(sb->s_dev, sb->s_blocksize);
+ sbi->cvf_format = &default_cvf;
+ if (!strcmp(cvf_format, "none"))
i = -1;
else
i = detect_cvf(sb,cvf_format);
if (i >= 0)
- error = cvf_formats[i]->mount_cvf(sb,cvf_options);
+ error = cvf_formats[i]->mount_cvf(sb, cvf_options);
if (error || debug) {
/* The MSDOS_CAN_BMAP is obsolete, but left just to remember */
printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c,"
opts.conversion,opts.fs_uid,opts.fs_gid,opts.fs_umask,
MSDOS_CAN_BMAP(sbi) ? ",bmap" : "");
printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%ld,ds=%ld,de=%d,data=%ld,"
- "se=%d,ts=%ld,ls=%d,rc=%ld,fc=%u]\n",
- b->media,sbi->cluster_size,
- sbi->fats,sbi->fat_start,
- sbi->fat_length,
- sbi->dir_start,sbi->dir_entries,
- sbi->data_start,
- CF_LE_W(*(unsigned short *) &b->sectors),
- (unsigned long)b->total_sect,logical_sector_size,
- sbi->root_cluster,sbi->free_clusters);
- printk ("Transaction block size = %d\n", hard_blksize);
+ "se=%u,ts=%u,ls=%d,rc=%ld,fc=%u]\n",
+ b->media, sbi->cluster_size, sbi->fats,
+ sbi->fat_start, sbi->fat_length, sbi->dir_start,
+ sbi->dir_entries, sbi->data_start,
+ CF_LE_W(get_unaligned((unsigned short *)&b->sectors)),
+ CF_LE_L(b->total_sect), logical_sector_size,
+ sbi->root_cluster, sbi->free_clusters);
+ printk ("hard sector size = %d\n", hard_blksize);
}
if (i < 0)
if (sbi->clusters + 2 > fat_clusters)
if (! sbi->nls_io)
sbi->nls_io = load_nls_default();
- root_inode=new_inode(sb);
+ root_inode = new_inode(sb);
if (!root_inode)
goto out_unload_nls;
root_inode->i_ino = MSDOS_ROOT_INO;
sb->s_root = d_alloc_root(root_inode);
if (!sb->s_root)
goto out_no_root;
- if(i>=0) {
+ if(i >= 0) {
sbi->cvf_format = cvf_formats[i];
++cvf_format_use_count[i];
}
return sb;
out_no_root:
- printk("get root inode failed\n");
+ printk("FAT: get root inode failed\n");
iput(root_inode);
unload_nls(sbi->nls_io);
out_unload_nls:
unload_nls(sbi->nls_disk);
goto out_fail;
out_invalid:
- if (!silent)
- printk("VFS: Can't find a valid MSDOS filesystem on dev %s.\n",
+ if (!silent) {
+ printk("VFS: Can't find a valid FAT filesystem on dev %s.\n",
kdevname(sb->s_dev));
- goto out_fail;
-out_no_bread:
- printk("FAT bread failed\n");
+ }
out_fail:
if (opts.iocharset) {
- printk("VFS: freeing iocharset=%s\n", opts.iocharset);
+ printk("FAT: freeing iocharset=%s\n", opts.iocharset);
kfree(opts.iocharset);
}
if(sbi->private_data)
return -EIO;
}
attr = ntfs_find_attr(ino, vol->at_index_allocation, I30);
+ if (!attr) {
+ ntfs_free(buf);
+ ntfs_debug(DEBUG_DIR3, "unsorted 9.5\n");
+ return -EIO;
+ }
while (1) {
if ((__s64)*p_high << vol->cluster_size_bits > attr->size) {
/* No more index records. */
ntfs_io io;
mdata = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
+ if (!mdata)
+ return -EINVAL;
/* First check whether there is uninitialized space. */
if (mdata->allocated < mdata->size + vol->mft_record_size) {
size = (__s64)ntfs_get_free_cluster_count(vol->bitmap) <<
/* Now extend the bitmap if necessary. */
rcount = mdata->size >> vol->mft_record_size_bits;
bmp = ntfs_find_attr(vol->mft_ino, vol->at_bitmap, 0);
+ if (!bmp)
+ return -EINVAL;
if (bmp->size * 8 < rcount) { /* Less bits than MFT records. */
ntfs_u8 buf[1];
/* Extend bitmap by one byte. */
*result = 0;
/* Determine the number of mft records in the mft. */
data = ntfs_find_attr(vol->mft_ino, vol->at_data, 0);
+ if (!data)
+ return -EINVAL;
length = data->size >> vol->mft_record_size_bits;
/* Allocate sufficient space for the mft bitmap attribute value,
inferring it from the number of mft records. */
bool ' Solaris (x86) partition table support' CONFIG_SOLARIS_X86_PARTITION
bool ' Unixware slices support' CONFIG_UNIXWARE_DISKLABEL
fi
+ dep_bool ' Windows Logical Disk Manager (Dynamic Disk) support' CONFIG_LDM_PARTITION $CONFIG_EXPERIMENTAL
+ if [ "$CONFIG_LDM_PARTITION" = "y" ]; then
+ bool ' Windows LDM extra logging' CONFIG_LDM_DEBUG
+ fi
bool ' SGI partition support' CONFIG_SGI_PARTITION
bool ' Ultrix partition table support' CONFIG_ULTRIX_PARTITION
bool ' Sun partition tables support' CONFIG_SUN_PARTITION
obj-$(CONFIG_AMIGA_PARTITION) += amiga.o
obj-$(CONFIG_ATARI_PARTITION) += atari.o
obj-$(CONFIG_MAC_PARTITION) += mac.o
+obj-$(CONFIG_LDM_PARTITION) += ldm.o
obj-$(CONFIG_MSDOS_PARTITION) += msdos.o
obj-$(CONFIG_OSF_PARTITION) += osf.o
obj-$(CONFIG_SGI_PARTITION) += sgi.o
#include "acorn.h"
#include "amiga.h"
#include "atari.h"
+#include "ldm.h"
#include "mac.h"
#include "msdos.h"
#include "osf.h"
#ifdef CONFIG_ACORN_PARTITION
acorn_partition,
#endif
+#ifdef CONFIG_LDM_PARTITION
+ ldm_partition, /* this must come before msdos */
+#endif
#ifdef CONFIG_MSDOS_PARTITION
msdos_partition,
#endif
--- /dev/null
+/*
+ * $Id: ldm.c,v 1.25 2001/07/25 23:32:02 flatcap Exp $
+ *
+ * ldm - Part of the Linux-NTFS project.
+ *
+ * Copyright (C) 2001 Richard Russon <ntfs@flatcap.org>
+ * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
+ *
+ * Documentation is available at http://linux-ntfs.sf.net/ldm
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (in the main directory of the Linux-NTFS source
+ * in the file COPYING); if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <asm/types.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/genhd.h>
+#include <linux/blkdev.h>
+#include <linux/slab.h>
+#include "check.h"
+#include "ldm.h"
+#include "msdos.h"
+
+#if 0 /* Fool kernel-doc since it doesn't do macros yet. */
+/**
+ * ldm_debug - output an error message if debugging was enabled at compile time
+ * @f: a printf format string containing the message
+ * @...: the variables to substitute into @f
+ *
+ * ldm_debug() writes a DEBUG level message to the syslog but only if the
+ * driver was compiled with debug enabled. Otherwise, the call turns into a NOP.
+ */
+static void ldm_debug(const char *f, ...);
+#endif
+#ifdef CONFIG_LDM_DEBUG
+#define ldm_debug(f, a...) \
+ { \
+ printk(LDM_DEBUG " DEBUG (%s, %d): %s: ", \
+ __FILE__, __LINE__, __FUNCTION__); \
+ printk(f, ##a); \
+ }
+#else /* !CONFIG_LDM_DEBUG */
+#define ldm_debug(f, a...) do {} while (0)
+#endif /* !CONFIG_LDM_DEBUG */
+
+/* Necessary forward declarations. */
+static int create_partition(struct gendisk *, int, int, int);
+static int parse_privhead(const u8 *, struct privhead *);
+static u64 get_vnum(const u8 *, int *);
+static int get_vstr(const u8 *, u8 *, const int);
+
+/**
+ * parse_vblk_part - parse a LDM database vblk partition record
+ * @buffer: vblk partition record loaded from the LDM database
+ * @buf_size: size of @buffer in bytes
+ * @vb: in memory vblk structure to return parsed information in
+ *
+ * This parses the LDM database vblk record of type VBLK_PART, i.e. a partition
+ * record, supplied in @buffer and sets up the in memory vblk structure @vb
+ * with the obtained information.
+ *
+ * Return 1 on success and -1 on error, in which case @vb is undefined.
+ */
+static int parse_vblk_part(const u8 *buffer, const int buf_size,
+ struct vblk *vb)
+{
+ int err, rel_objid, rel_name, rel_size, rel_parent;
+
+ if (0x34 >= buf_size)
+ return -1;
+ /* Calculate relative offsets. */
+ rel_objid = 1 + buffer[0x18];
+ if (0x18 + rel_objid >= buf_size)
+ return -1;
+ rel_name = 1 + buffer[0x18 + rel_objid] + rel_objid;
+ if (0x34 + rel_name >= buf_size)
+ return -1;
+ rel_size = 1 + buffer[0x34 + rel_name] + rel_name;
+ if (0x34 + rel_size >= buf_size)
+ return -1;
+ rel_parent = 1 + buffer[0x34 + rel_size] + rel_size;
+ if (0x34 + rel_parent >= buf_size)
+ return -1;
+ /* Setup @vb. */
+ vb->vblk_type = VBLK_PART;
+ vb->obj_id = get_vnum(buffer + 0x18, &err);
+ if (err || 0x34 + rel_parent + buffer[0x34 + rel_parent] >= buf_size)
+ return -1;
+ vb->disk_id = get_vnum(buffer + 0x34 + rel_parent, &err);
+ if (err || 0x24 + rel_name + 8 > buf_size)
+ return -1;
+ vb->start_sector = BE64(buffer + 0x24 + rel_name);
+ if (0x34 + rel_name + buffer[0x34 + rel_name] >= buf_size)
+ return -1;
+ vb->num_sectors = get_vnum(buffer + 0x34 + rel_name, &err);
+ if (err || 0x18 + rel_objid + buffer[0x18 + rel_objid] >= buf_size)
+ return -1;
+ err = get_vstr(buffer + 0x18 + rel_objid, vb->name, sizeof(vb->name));
+ if (err == -1)
+ return err;
+ ldm_debug("Parsed Partition VBLK successfully.\n");
+ return 1;
+}
+
+/**
+ * parse_vblk - parse a LDM database vblk record
+ * @buffer: vblk record loaded from the LDM database
+ * @buf_size: size of @buffer in bytes
+ * @vb: in memory vblk structure to return parsed information in
+ *
+ * This parses the LDM database vblk record supplied in @buffer and sets up
+ * the in memory vblk structure @vb with the obtained information.
+ *
+ * Return 1 on success, 0 if successful but record not in use, and -1 on error.
+ * If the return value is 0 or -1, @vb is undefined.
+ *
+ * NOTE: Currently the only record type we handle is VBLK_PART, i.e. records
+ * describing a partition. For all others, we just set @vb->vblk_type to 0 and
+ * return success. This of course means that if @vb->vblk_type is zero, all
+ * other fields in @vb are undefined.
+ */
+static int parse_vblk(const u8 *buffer, const int buf_size, struct vblk *vb)
+{
+ int err = 1;
+
+ if (buf_size < 0x14)
+ return -1;
+ if (MAGIC_VBLK != BE32(buffer)) {
+ printk(LDM_CRIT "Cannot find VBLK, database may be corrupt.\n");
+ return -1;
+ }
+ if (BE16(buffer + 0x0E) == 0) /* Record is not in use. */
+ return 0;
+ /* FIXME: What about extended VBLKs? */
+ switch (buffer[0x13]) {
+ case VBLK_PART:
+ err = parse_vblk_part(buffer, buf_size, vb);
+ break;
+ default:
+ vb->vblk_type = 0;
+ }
+ if (err != -1)
+ ldm_debug("Parsed VBLK successfully.\n");
+ return err;
+}
+
+/**
+ * create_data_partitions - create the data partition devices
+ * @hd: gendisk structure in which to create the data partitions
+ * @first_sector: first sector within the disk device
+ * @first_part_minor: first minor number of data partition devices
+ * @dev: partition device holding the LDM database
+ * @vm: in memory vmdb structure of @dev
+ * @ph: in memory privhead structure of the disk device
+ * @dk: in memory ldmdisk structure of the disk device
+ *
+ * The database contains ALL the partitions for ALL the disks, so we need to
+ * filter out this specific disk. Using the disk's object id, we can find all
+ * the partitions in the database that belong to this disk.
+ *
+ * For each found partition, we create a corresponding partition device starting
+ * with minor number @first_part_minor.
+ *
+ * Return 1 on success and -1 on error.
+ */
+static int create_data_partitions(struct gendisk *hd,
+ const unsigned long first_sector, int first_part_minor,
+ const kdev_t dev, const struct vmdb *vm,
+ const struct privhead *ph, const struct ldmdisk *dk)
+{
+ struct buffer_head *bh;
+ struct vblk *vb;
+ int vblk;
+ int vsize; /* VBLK size. */
+ int perbuf; /* VBLKs per buffer. */
+ int buffer, lastbuf, lastofs, err;
+
+ vb = (struct vblk*)kmalloc(sizeof(struct vblk), GFP_KERNEL);
+ if (!vb)
+ goto no_mem;
+ vsize = vm->vblk_size;
+ if (vsize < 1 || vsize > LDM_BLOCKSIZE)
+ goto err_out;
+ perbuf = LDM_BLOCKSIZE / vsize;
+ if (perbuf < 1 || LDM_BLOCKSIZE % vsize)
+ goto err_out;
+ /* 512 == VMDB size */
+ lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf;
+ lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf;
+ if (lastofs)
+ lastbuf++;
+ if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
+ ph->config_size * 512)
+ goto err_out;
+ printk(" <");
+ for (buffer = 0; buffer < lastbuf; buffer++) {
+ if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE)))
+ goto read_err;
+ for (vblk = 0; vblk < perbuf; vblk++) {
+ u8 *block;
+
+ if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
+ break;
+ block = bh->b_data + vsize * vblk;
+ if (block + vsize > (u8*)bh->b_data + LDM_BLOCKSIZE)
+ goto brelse_out;
+ if (parse_vblk(block, LDM_BLOCKSIZE, vb) != 1)
+ continue;
+ if (vb->vblk_type != VBLK_PART)
+ continue;
+ if (dk->obj_id != vb->disk_id)
+ continue;
+ if (create_partition(hd, first_part_minor,
+ first_sector + vb->start_sector +
+ ph->logical_disk_start,
+ vb->num_sectors) == 1)
+ first_part_minor++;
+ }
+ brelse(bh);
+ }
+ printk(" >\n");
+ err = 1;
+out:
+ kfree(vb);
+ return err;
+brelse_out:
+ brelse(bh);
+ goto err_out;
+no_mem:
+ printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+ goto err_out;
+read_err:
+ printk(LDM_CRIT "Disk read failed in create_partitions.\n");
+err_out:
+ err = -1;
+ goto out;
+}
+
+/**
+ * get_vnum - convert a variable-width, big endian number, to cpu u64 one
+ * @block: pointer to the variable-width number to convert
+ * @err: address of an integer into which to return the error code.
+ *
+ * This converts a variable-width, big endian number into a 64-bit, CPU format
+ * number and returns the result with err set to 0. If an error occurs return 0
+ * with err set to -1.
+ *
+ * The first byte of a variable-width number is the size of the number in bytes.
+ */
+static u64 get_vnum(const u8 *block, int *err)
+{
+ u64 tmp = 0ULL;
+ u8 length = *block++;
+
+ if (length && length <= 8) {
+ while (length--)
+ tmp = (tmp << 8) | *block++;
+ *err = 0;
+ } else {
+ printk(LDM_ERR "Illegal length in get_vnum(): %d.\n", length);
+ *err = 1;
+ }
+ return tmp;
+}
+
+/**
+ * get_vstr - convert a counted, non-null-terminated ASCII string to C-style one
+ * @block: string to convert
+ * @buffer: output buffer
+ * @buflen: size of output buffer
+ *
+ * This converts @block, a counted, non-null-terminated ASCII string, into a
+ * C-style, null-terminated, ASCII string and returns this in @buffer. The
+ * maximum number of characters converted is given by @buflen.
+ *
+ * The first bytes of a counted string stores the length of the string in bytes.
+ *
+ * Return the number of characters written to @buffer, not including the
+ * terminating null character, on success, and -1 on error, in which case
+ * @buffer is not defined.
+ */
+static int get_vstr(const u8 *block, u8 *buffer, const int buflen)
+{
+ int length = block[0];
+
+ if (length < 1)
+ return -1;
+ if (length >= buflen) {
+ printk(LDM_ERR "String too long for buffer in get_vstr(): "
+ "(%d/%d). Truncating.\n", length, buflen);
+ length = buflen - 1;
+ }
+ memcpy(buffer, block + 1, length);
+ buffer[length] = (u8)'\0';
+ return length;
+}
+
+/**
+ * get_disk_objid - obtain the object id for the device we are working on
+ * @dev: partition device holding the LDM database
+ * @vm: in memory vmdb structure of the LDM database
+ * @ph: in memory privhead structure of the device we are working on
+ * @dk: in memory ldmdisk structure to return information into
+ *
+ * This obtains the object id for the device we are working on as defined by
+ * the private header @ph. The obtained object id, together with the disk's
+ * GUID from @ph are returned in the ldmdisk structure pointed to by @dk.
+ *
+ * A Disk has two Ids. The main one is a GUID in string format. The second,
+ * used internally for cross-referencing, is a small, sequentially allocated,
+ * number. The PRIVHEAD, just after the partition table, tells us the disk's
+ * GUID. To find the disk's object id, we have to look through the database.
+ *
+ * Return 1 on success and -1 on error, in which case @dk is undefined.
+ */
+static int get_disk_objid(const kdev_t dev, const struct vmdb *vm,
+ const struct privhead *ph, struct ldmdisk *dk)
+{
+ struct buffer_head *bh;
+ u8 *disk_id;
+ int vblk;
+ int vsize; /* VBLK size. */
+ int perbuf; /* VBLKs per buffer. */
+ int buffer, lastbuf, lastofs, err;
+
+ disk_id = (u8*)kmalloc(DISK_ID_SIZE, GFP_KERNEL);
+ if (!disk_id)
+ goto no_mem;
+ vsize = vm->vblk_size;
+ if (vsize < 1 || vsize > LDM_BLOCKSIZE)
+ goto err_out;
+ perbuf = LDM_BLOCKSIZE / vsize;
+ if (perbuf < 1 || LDM_BLOCKSIZE % vsize)
+ goto err_out;
+ /* 512 == VMDB size */
+ lastbuf = (vm->last_vblk_seq - (512 / vsize)) / perbuf;
+ lastofs = (vm->last_vblk_seq - (512 / vsize)) % perbuf;
+ if (lastofs)
+ lastbuf++;
+ if (OFF_VBLK * LDM_BLOCKSIZE + vm->last_vblk_seq * vsize >
+ ph->config_size * 512)
+ goto err_out;
+ for (buffer = 0; buffer < lastbuf; buffer++) {
+ if (!(bh = bread(dev, buffer + OFF_VBLK, LDM_BLOCKSIZE)))
+ goto read_err;
+ for (vblk = 0; vblk < perbuf; vblk++) {
+ int rel_objid, rel_name, delta;
+ u8 *block;
+
+ if (lastofs && buffer == lastbuf - 1 && vblk >= lastofs)
+ break;
+ block = bh->b_data + vblk * vsize;
+ delta = vblk * vsize + 0x18;
+ if (delta >= LDM_BLOCKSIZE)
+ goto brelse_out;
+ if (block[0x13] != VBLK_DISK)
+ continue;
+ /* Calculate relative offsets. */
+ rel_objid = 1 + block[0x18];
+ if (delta + rel_objid >= LDM_BLOCKSIZE)
+ goto brelse_out;
+ rel_name = 1 + block[0x18 + rel_objid] + rel_objid;
+ if (delta + rel_name >= LDM_BLOCKSIZE ||
+ delta + rel_name + block[0x18 + rel_name] >=
+ LDM_BLOCKSIZE)
+ goto brelse_out;
+ err = get_vstr(block + 0x18 + rel_name, disk_id,
+ DISK_ID_SIZE);
+ if (err == -1)
+ goto brelse_out;
+ if (!strncmp(disk_id, ph->disk_id, DISK_ID_SIZE)) {
+ dk->obj_id = get_vnum(block + 0x18, &err);
+ brelse(bh);
+ if (err)
+ goto out;
+ strncpy(dk->disk_id, ph->disk_id,
+ sizeof(dk->disk_id));
+ dk->disk_id[sizeof(dk->disk_id) - 1] = (u8)'\0';
+ err = 1;
+ goto out;
+ }
+ }
+ brelse(bh);
+ }
+ err = -1;
+out:
+ kfree(disk_id);
+ return err;
+brelse_out:
+ brelse(bh);
+ goto err_out;
+no_mem:
+ printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+ goto err_out;
+read_err:
+ printk(LDM_CRIT "Disk read failed in get_disk_objid.\n");
+err_out:
+ err = -1;
+ goto out;
+}
+
+/**
+ * parse_vmdb - parse the LDM database vmdb structure
+ * @buffer: LDM database vmdb structure loaded from the device
+ * @vm: in memory vmdb structure to return parsed information in
+ *
+ * This parses the LDM database vmdb structure supplied in @buffer and sets up
+ * the in memory vmdb structure @vm with the obtained information.
+ *
+ * Return 1 on success and -1 on error, in which case @vm is undefined.
+ *
+ * NOTE: The *_start, *_size and *_seq values returned in @vm have not been
+ * checked for validity, so make sure to check them when using them.
+ */
+static int parse_vmdb(const u8 *buffer, struct vmdb *vm)
+{
+ if (MAGIC_VMDB != BE32(buffer)) {
+ printk(LDM_CRIT "Cannot find VMDB, database may be corrupt.\n");
+ return -1;
+ }
+ vm->ver_major = BE16(buffer + 0x12);
+ vm->ver_minor = BE16(buffer + 0x14);
+ if ((vm->ver_major != 4) || (vm->ver_minor != 10)) {
+ printk(LDM_ERR "Expected VMDB version %d.%d, got %d.%d. "
+ "Aborting.\n", 4, 10, vm->ver_major,
+ vm->ver_minor);
+ return -1;
+ }
+ vm->vblk_size = BE32(buffer + 0x08);
+ vm->vblk_offset = BE32(buffer + 0x0C);
+ vm->last_vblk_seq = BE32(buffer + 0x04);
+
+ ldm_debug("Parsed VMDB successfully.\n");
+ return 1;
+}
+
+/**
+ * validate_vmdb - validate the vmdb
+ * @dev: partition device holding the LDM database
+ * @vm: in memory vmdb in which to return information
+ *
+ * Find the vmdb of the LDM database stored on @dev and return the parsed
+ * information into @vm.
+ *
+ * Return 1 on success and -1 on error, in which case @vm is undefined.
+ */
+static int validate_vmdb(const kdev_t dev, struct vmdb *vm)
+{
+ struct buffer_head *bh;
+ int ret;
+
+ if (!(bh = bread(dev, OFF_VMDB, LDM_BLOCKSIZE))) {
+ printk(LDM_CRIT "Disk read failed in validate_vmdb.\n");
+ return -1;
+ }
+ ret = parse_vmdb(bh->b_data + 0x200, vm);
+ brelse(bh);
+ return ret;
+}
+
+/**
+ * compare_tocblocks - compare two tables of contents
+ * @toc1: first toc
+ * @toc2: second toc
+ *
+ * This compares the two tables of contents @toc1 and @toc2.
+ *
+ * Return 1 if @toc1 and @toc2 are equal and -1 otherwise.
+ */
+static int compare_tocblocks(const struct tocblock *toc1,
+ const struct tocblock *toc2)
+{
+ if ((toc1->bitmap1_start == toc2->bitmap1_start) &&
+ (toc1->bitmap1_size == toc2->bitmap1_size) &&
+ (toc1->bitmap2_start == toc2->bitmap2_start) &&
+ (toc1->bitmap2_size == toc2->bitmap2_size) &&
+ !strncmp(toc1->bitmap1_name, toc2->bitmap1_name,
+ sizeof(toc1->bitmap1_name)) &&
+ !strncmp(toc1->bitmap2_name, toc2->bitmap2_name,
+ sizeof(toc1->bitmap2_name)))
+ return 1;
+ return -1;
+}
+
+/**
+ * parse_tocblock - parse the LDM database table of contents structure
+ * @buffer: LDM database toc structure loaded from the device
+ * @toc: in memory toc structure to return parsed information in
+ *
+ * This parses the LDM database table of contents structure supplied in @buffer
+ * and sets up the in memory table of contents structure @toc with the obtained
+ * information.
+ *
+ * Return 1 on success and -1 on error, in which case @toc is undefined.
+ *
+ * FIXME: The *_start and *_size values returned in @toc are not been checked
+ * for validity but as we don't use the actual values for anything other than
+ * comparing between the toc and its backups, the values are not important.
+ */
+static int parse_tocblock(const u8 *buffer, struct tocblock *toc)
+{
+ if (MAGIC_TOCBLOCK != BE64(buffer)) {
+ printk(LDM_CRIT "Cannot find TOCBLOCK, database may be "
+ "corrupt.\n");
+ return -1;
+ }
+ strncpy(toc->bitmap1_name, buffer + 0x24, sizeof(toc->bitmap1_name));
+ toc->bitmap1_name[sizeof(toc->bitmap1_name) - 1] = (u8)'\0';
+ toc->bitmap1_start = BE64(buffer + 0x2E);
+ toc->bitmap1_size = BE64(buffer + 0x36);
+ /*toc->bitmap1_flags = BE64(buffer + 0x3E);*/
+ if (strncmp(toc->bitmap1_name, TOC_BITMAP1,
+ sizeof(toc->bitmap1_name)) != 0) {
+ printk(LDM_CRIT "TOCBLOCK's first bitmap should be %s, but is "
+ "%s.\n", TOC_BITMAP1, toc->bitmap1_name);
+ return -1;
+ }
+ strncpy(toc->bitmap2_name, buffer + 0x46, sizeof(toc->bitmap2_name));
+ toc->bitmap2_name[sizeof(toc->bitmap2_name) - 1] = (u8)'\0';
+ toc->bitmap2_start = BE64(buffer + 0x50);
+ toc->bitmap2_size = BE64(buffer + 0x58);
+ /*toc->bitmap2_flags = BE64(buffer + 0x60);*/
+ if (strncmp(toc->bitmap2_name, TOC_BITMAP2,
+ sizeof(toc->bitmap2_name)) != 0) {
+ printk(LDM_CRIT "TOCBLOCK's second bitmap should be %s, but is "
+ "%s.\n", TOC_BITMAP2, toc->bitmap2_name);
+ return -1;
+ }
+ ldm_debug("Parsed TOCBLOCK successfully.\n");
+ return 1;
+}
+
+/**
+ * validate_tocblocks - validate the table of contents and its backups
+ * @dev: partition device holding the LDM database
+ * @toc1: in memory table of contents in which to return information
+ *
+ * Find and compare the four tables of contents of the LDM database stored on
+ * @dev and return the parsed information into @toc1.
+ *
+ * Return 1 on success and -1 on error, in which case @toc1 is undefined.
+ */
+static int validate_tocblocks(const kdev_t devdb, struct tocblock *toc1)
+{
+ struct buffer_head *bh;
+ struct tocblock *toc2 = NULL, *toc3 = NULL, *toc4 = NULL;
+ int err;
+
+ toc2 = (struct tocblock*)kmalloc(sizeof(*toc2), GFP_KERNEL);
+ if (!toc2)
+ goto no_mem;
+ toc3 = (struct tocblock*)kmalloc(sizeof(*toc3), GFP_KERNEL);
+ if (!toc3)
+ goto no_mem;
+ toc4 = (struct tocblock*)kmalloc(sizeof(*toc4), GFP_KERNEL);
+ if (!toc4)
+ goto no_mem;
+ /* Read and parse first toc. */
+ if (!(bh = bread(devdb, OFF_TOCBLOCK1, LDM_BLOCKSIZE))) {
+ printk(LDM_CRIT "Disk read 1 failed in validate_tocblocks.\n");
+ goto err_out;
+ }
+ err = parse_tocblock(bh->b_data + 0x0200, toc1);
+ brelse(bh);
+ if (err != 1)
+ goto out;
+ /* Read and parse second toc. */
+ if (!(bh = bread(devdb, OFF_TOCBLOCK2, LDM_BLOCKSIZE))) {
+ printk(LDM_CRIT "Disk read 2 failed in validate_tocblocks.\n");
+ goto err_out;
+ }
+ err = parse_tocblock(bh->b_data, toc2);
+ brelse(bh);
+ if (err != 1)
+ goto out;
+ /* Read and parse third toc. */
+ if (!(bh = bread(devdb, OFF_TOCBLOCK3, LDM_BLOCKSIZE))) {
+ printk(LDM_CRIT "Disk read 3 failed in validate_tocblocks.\n");
+ goto err_out;
+ }
+ err = parse_tocblock(bh->b_data + 0x0200, toc3);
+ brelse(bh);
+ if (err != 1)
+ goto out;
+ /* Read and parse fourth toc. */
+ if (!(bh = bread(devdb, OFF_TOCBLOCK4, LDM_BLOCKSIZE))) {
+ printk(LDM_CRIT "Disk read 4 failed in validate_tocblocks.\n");
+ goto err_out;
+ }
+ err = parse_tocblock(bh->b_data, toc4);
+ brelse(bh);
+ if (err != 1)
+ goto out;
+ /* Compare all tocs. */
+ err = compare_tocblocks(toc1, toc2);
+ if (err != 1) {
+ printk(LDM_CRIT "First and second TOCBLOCKs don't match.\n");
+ goto out;
+ }
+ err = compare_tocblocks(toc3, toc4);
+ if (err != 1) {
+ printk(LDM_CRIT "Third and fourth TOCBLOCKs don't match.\n");
+ goto out;
+ }
+ err = compare_tocblocks(toc1, toc3);
+ if (err != 1)
+ printk(LDM_CRIT "First and third TOCBLOCKs don't match.\n");
+ else
+ ldm_debug("Validated TOCBLOCKs successfully.\n");
+out:
+ kfree(toc2);
+ kfree(toc3);
+ kfree(toc4);
+ return err;
+no_mem:
+ printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+err_out:
+ err = -1;
+ goto out;
+}
+
+/**
+ * compare_privheads - compare two privheads
+ * @ph1: first privhead
+ * @ph2: second privhead
+ *
+ * This compares the two privheads @ph1 and @ph2.
+ *
+ * Return 1 if @ph1 and @ph2 are equal and -1 otherwise.
+ */
+static int compare_privheads(const struct privhead *ph1,
+ const struct privhead *ph2)
+{
+ if ((ph1->ver_major == ph2->ver_major) &&
+ (ph1->ver_minor == ph2->ver_minor) &&
+ (ph1->logical_disk_start == ph2->logical_disk_start) &&
+ (ph1->logical_disk_size == ph2->logical_disk_size) &&
+ (ph1->config_start == ph2->config_start) &&
+ (ph1->config_size == ph2->config_size) &&
+ !strncmp(ph1->disk_id, ph2->disk_id, sizeof(ph1->disk_id)))
+ return 1;
+ return -1;
+}
+
+/**
+ * validate_privheads - compare the privhead backups to the first one
+ * @dev: partition device holding the LDM database
+ * @ph1: first privhead which we have already validated before
+ *
+ * We already have one privhead from the beginning of the disk.
+ * Now we compare the two other copies for safety.
+ *
+ * Return 1 on succes and -1 on error.
+ */
+static int validate_privheads(const kdev_t dev, const struct privhead *ph1)
+{
+ struct buffer_head *bh;
+ struct privhead *ph2 = NULL, *ph3 = NULL;
+ int err;
+
+ ph2 = (struct privhead*)kmalloc(sizeof(*ph2), GFP_KERNEL);
+ if (!ph2)
+ goto no_mem;
+ ph3 = (struct privhead*)kmalloc(sizeof(*ph3), GFP_KERNEL);
+ if (!ph3)
+ goto no_mem;
+ if (!(bh = bread(dev, OFF_PRIVHEAD2, LDM_BLOCKSIZE))) {
+ printk(LDM_CRIT "Disk read 1 failed in validate_privheads.\n");
+ goto err_out;
+ }
+ err = parse_privhead(bh->b_data, ph2);
+ brelse(bh);
+ if (err != 1)
+ goto out;
+ if (!(bh = bread(dev, OFF_PRIVHEAD3, LDM_BLOCKSIZE))) {
+ printk(LDM_CRIT "Disk read 2 failed in validate_privheads.\n");
+ goto err_out;
+ }
+ err = parse_privhead(bh->b_data + 0x0200, ph3);
+ brelse(bh);
+ if (err != 1)
+ goto out;
+ err = compare_privheads(ph1, ph2);
+ if (err != 1) {
+ printk(LDM_CRIT "First and second PRIVHEADs don't match.\n");
+ goto out;
+ }
+ err = compare_privheads(ph1, ph3);
+ if (err != 1)
+ printk(LDM_CRIT "First and third PRIVHEADs don't match.\n");
+ else
+ /* We _could_ have checked more. */
+ ldm_debug("Validated PRIVHEADs successfully.\n");
+out:
+ kfree(ph2);
+ kfree(ph3);
+ return err;
+no_mem:
+ printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+err_out:
+ err = -1;
+ goto out;
+}
+
+/**
+ * create_partition - validate input and create a kernel partition device
+ * @hd: gendisk structure in which to create partition
+ * @minor: minor number for device to create
+ * @start: starting offset of the partition into the parent device
+ * @size: size of the partition
+ *
+ * This validates the range, then puts an entry into the kernel's partition
+ * table.
+ *
+ * @start and @size are numbers of sectors.
+ *
+ * Return 1 on succes and -1 on error.
+ */
+static int create_partition(struct gendisk *hd, const int minor,
+ const int start, const int size)
+{
+ int disk_minor;
+
+ if (!hd->part)
+ return -1;
+ /*
+ * Get the minor number of the parent device so we can check we don't
+ * go beyond the end of the device.
+ */
+ disk_minor = (minor >> hd->minor_shift) << hd->minor_shift;
+ if ((start < 1) || ((start + size) > hd->part[disk_minor].nr_sects)) {
+ printk(LDM_CRIT "LDM Partition exceeds physical disk. "
+ "Aborting.\n");
+ return -1;
+ }
+ add_gd_partition(hd, minor, start, size);
+ ldm_debug("Created partition successfully.\n");
+ return 1;
+}
+
+/**
+ * parse_privhead - parse the LDM database PRIVHEAD structure
+ * @buffer: LDM database privhead structure loaded from the device
+ * @ph: in memory privhead structure to return parsed information in
+ *
+ * This parses the LDM database PRIVHEAD structure supplied in @buffer and
+ * sets up the in memory privhead structure @ph with the obtained information.
+ *
+ * Return 1 on succes and -1 on error, in which case @ph is undefined.
+ */
+static int parse_privhead(const u8 *buffer, struct privhead *ph)
+{
+ if (MAGIC_PRIVHEAD != BE64(buffer)) {
+ printk(LDM_ERR "Cannot find PRIVHEAD structure. LDM database "
+ "is corrupt. Aborting.\n");
+ return -1;
+ }
+ ph->ver_major = BE16(buffer + 0x000C);
+ ph->ver_minor = BE16(buffer + 0x000E);
+ if ((ph->ver_major != 2) || (ph->ver_minor != 11)) {
+ printk(LDM_ERR "Expected PRIVHEAD version %d.%d, got %d.%d. "
+ "Aborting.\n", 2, 11, ph->ver_major,
+ ph->ver_minor);
+ return -1;
+ }
+ ph->config_start = BE64(buffer + 0x012B);
+ ph->config_size = BE64(buffer + 0x0133);
+ if (ph->config_size != LDM_DB_SIZE) { /* 1 MiB in sectors. */
+ printk(LDM_ERR "Database should be %u bytes, claims to be %Lu "
+ "bytes. Aborting.\n", LDM_DB_SIZE,
+ ph->config_size);
+ return -1;
+ }
+ ph->logical_disk_start = BE64(buffer + 0x011B);
+ ph->logical_disk_size = BE64(buffer + 0x0123);
+ if (!ph->logical_disk_size ||
+ ph->logical_disk_start + ph->logical_disk_size > ph->config_start)
+ return -1;
+
+ memcpy(ph->disk_id, buffer + 0x0030, sizeof(ph->disk_id));
+
+ ldm_debug("Parsed PRIVHEAD successfully.\n");
+ return 1;
+}
+
+/**
+ * create_db_partition - create a dedicated partition for our database
+ * @hd: gendisk structure in which to create partition
+ * @dev: device of which to create partition
+ * @ph: @dev's LDM database private header
+ *
+ * Find the primary private header, locate the LDM database, then create a
+ * partition to wrap it.
+ *
+ * Return 1 on succes, 0 if device is not a dynamic disk and -1 on error.
+ */
+static int create_db_partition(struct gendisk *hd, const kdev_t dev,
+ const unsigned long first_sector, const int first_part_minor,
+ struct privhead *ph)
+{
+ struct buffer_head *bh;
+ int err;
+
+ if (!(bh = bread(dev, OFF_PRIVHEAD1, LDM_BLOCKSIZE))) {
+ printk(LDM_CRIT __FUNCTION__ "(): Device read failed.\n");
+ return -1;
+ }
+ if (BE64(bh->b_data) != MAGIC_PRIVHEAD) {
+ ldm_debug("Cannot find PRIVHEAD structure. Not a dynamic disk "
+ "or corrupt LDM database.\n");
+ return 0;
+ }
+ err = parse_privhead(bh->b_data, ph);
+ if (err == 1)
+ err = create_partition(hd, first_part_minor, first_sector +
+ ph->config_start, ph->config_size);
+ brelse(bh);
+ return err;
+}
+
+/**
+ * validate_patition_table - check whether @dev is a dynamic disk
+ * @dev: device to test
+ *
+ * Check whether @dev is a dynamic disk by looking for an MS-DOS-style partition
+ * table with one or more entries of type 0x42 (the former Secure File System
+ * (Landis) partition type, now recycled by Microsoft for dynamic disks) in it.
+ * If this succeeds we assume we have a dynamic disk, and not otherwise.
+ *
+ * Return 1 if @dev is a dynamic disk, 0 if not and -1 on error.
+ */
+static int validate_partition_table(const kdev_t dev)
+{
+ struct buffer_head *bh;
+ struct partition *p;
+ int i, nr_sfs;
+
+ if (!(bh = bread(dev, 0, LDM_BLOCKSIZE))) {
+ if (warn_no_part)
+ printk(LDM_ERR "Unable to read partition table.\n");
+ return -1;
+ }
+ if (*(u16*)(bh->b_data + 0x01FE) != cpu_to_le16(MSDOS_LABEL_MAGIC)) {
+ ldm_debug("No MS-DOS partition found.\n");
+ goto no_msdos_partition;
+ }
+ nr_sfs = 0;
+ p = (struct partition*)(bh->b_data + 0x01BE);
+ for (i = 0; i < 4; i++) {
+ if (!SYS_IND(p+i) || SYS_IND(p+i) == WIN2K_EXTENDED_PARTITION)
+ continue;
+ if (SYS_IND(p+i) == WIN2K_DYNAMIC_PARTITION) {
+ nr_sfs++;
+ continue;
+ }
+ goto not_dynamic_disk;
+ }
+ if (!nr_sfs)
+ goto not_dynamic_disk;
+ ldm_debug("Parsed partition table successfully.\n");
+ brelse(bh);
+ return 1;
+not_dynamic_disk:
+ ldm_debug("Found basic MS-DOS partition, not a dynamic disk.\n");
+no_msdos_partition:
+ brelse(bh);
+ return 0;
+}
+
+/**
+ * ldm_partition - find out whether a device is a dynamic disk and handle it
+ * @hd: gendisk structure in which to return the handled disk
+ * @dev: device we need to look at
+ * @first_sector: first sector within the device
+ * @first_part_minor: first minor number of partitions for the device
+ *
+ * Description:
+ *
+ * This determines whether the device @dev is a dynamic disk and if so creates
+ * the partitions necessary in the gendisk structure pointed to by @hd.
+ *
+ * We create a dummy device 1, which contains the LDM database, we skip
+ * devices 2-4 and then create each partition described by the LDM database
+ * in sequence as devices 5 and following. For example, if the device is hda,
+ * we would have: hda1: LDM database, hda2-4: nothing, hda5-following: the
+ * actual data containing partitions.
+ *
+ * Return values:
+ *
+ * 1 if @dev is a dynamic disk and we handled it,
+ * 0 if @dev is not a dynamic disk,
+ * -1 if an error occured.
+ */
+int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+ int first_part_minor)
+{
+ kdev_t devdb;
+ struct privhead *ph = NULL;
+ struct tocblock *toc = NULL;
+ struct vmdb *vm = NULL;
+ struct ldmdisk *dk = NULL;
+ int err;
+
+ if (!hd)
+ return 0;
+ err = (int)get_ptable_blocksize(dev);
+ if (err != LDM_BLOCKSIZE) { /* 1024 bytes */
+ ldm_debug("Expected a blocksize of %d bytes, got %d instead.\n",
+ LDM_BLOCKSIZE, get_ptable_blocksize(dev));
+ return 0;
+ }
+ err = get_hardsect_size(dev);
+ if (err != 512) {
+ ldm_debug("Expected a sector size of %d bytes, got %d "
+ "instead.\n", 512, get_hardsect_size(dev));
+ return 0;
+ }
+ /* Check the partition table. */
+ err = validate_partition_table(dev);
+ if (err != 1)
+ return err;
+ if (!(ph = (struct privhead*)kmalloc(sizeof(*ph), GFP_KERNEL)))
+ goto no_mem;
+ /* Create the LDM database device. */
+ err = create_db_partition(hd, dev, first_sector, first_part_minor, ph);
+ if (err != 1)
+ goto out;
+ /* For convenience, work with the LDM database device from now on. */
+ devdb = MKDEV(MAJOR(dev), first_part_minor);
+ /* Check the backup privheads. */
+ err = validate_privheads(devdb, ph);
+ if (err != 1)
+ goto out;
+ /* Check the table of contents and its backups. */
+ if (!(toc = (struct tocblock*)kmalloc(sizeof(*toc), GFP_KERNEL)))
+ goto no_mem;
+ err = validate_tocblocks(devdb, toc);
+ if (err != 1)
+ goto out;
+ /* Check the vmdb. */
+ if (!(vm = (struct vmdb*)kmalloc(sizeof(*vm), GFP_KERNEL)))
+ goto no_mem;
+ err = validate_vmdb(devdb, vm);
+ if (err != 1)
+ goto out;
+ /* Find the object id for @dev in the LDM database. */
+ if (!(dk = (struct ldmdisk*)kmalloc(sizeof(*dk), GFP_KERNEL)))
+ goto no_mem;
+ err = get_disk_objid(devdb, vm, ph, dk);
+ if (err != 1)
+ goto out;
+ /* Finally, create the data partition devices. */
+ err = create_data_partitions(hd, first_sector, first_part_minor +
+ LDM_FIRST_PART_OFFSET, devdb, vm, ph, dk);
+ if (err == 1)
+ ldm_debug("Parsed LDM database successfully.\n");
+out:
+ kfree(ph);
+ kfree(toc);
+ kfree(vm);
+ kfree(dk);
+ return err;
+no_mem:
+ printk(LDM_CRIT "Not enough memory to allocate required buffers.\n");
+ err = -1;
+ goto out;
+}
+
--- /dev/null
+#ifndef _FS_PT_LDM_H_
+#define _FS_PT_LDM_H_
+/*
+ * $Id: ldm.h,v 1.13 2001/07/23 19:49:49 antona Exp $
+ *
+ * ldm - Part of the Linux-NTFS project.
+ *
+ * Copyright (C) 2001 Richard Russon <ntfs@flatcap.org>
+ * Copyright (C) 2001 Anton Altaparmakov <antona@users.sf.net>
+ *
+ * Documentation is available at http://linux-ntfs.sf.net/ldm
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program (in the main directory of the Linux-NTFS source
+ * in the file COPYING); if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+#include <asm/types.h>
+#include <asm/unaligned.h>
+#include <asm/byteorder.h>
+#include <linux/genhd.h>
+
+/* Borrowed from kernel.h. */
+#define LDM_PREFIX "LDM: " /* Prefix our error messages with this. */
+#define LDM_CRIT KERN_CRIT LDM_PREFIX /* critical conditions */
+#define LDM_ERR KERN_ERR LDM_PREFIX /* error conditions */
+#define LDM_DEBUG KERN_DEBUG LDM_PREFIX /* debug-level messages */
+
+/* Magic numbers in CPU format. */
+#define MAGIC_VMDB 0x564D4442 /* VMDB */
+#define MAGIC_VBLK 0x56424C4B /* VBLK */
+#define MAGIC_PRIVHEAD 0x5052495648454144 /* PRIVHEAD */
+#define MAGIC_TOCBLOCK 0x544F43424C4F434B /* TOCBLOCK */
+
+/* The defined vblk types. */
+#define VBLK_COMP 0x32 /* Component */
+#define VBLK_PART 0x33 /* Partition */
+#define VBLK_DISK 0x34 /* Disk */
+#define VBLK_DGRP 0x45 /* Disk Group */
+#define VBLK_VOLU 0x51 /* Volume */
+
+/* Other constants. */
+#define LDM_BLOCKSIZE 1024 /* Size of block in bytes. */
+#define LDM_DB_SIZE 2048 /* Size in sectors (= 1MiB). */
+#define LDM_FIRST_PART_OFFSET 4 /* Add this to first_part_minor
+ to get to the first data
+ partition device minor. */
+
+#define OFF_PRIVHEAD1 3 /* Offset of the first privhead
+ relative to the start of the
+ device in units of
+ LDM_BLOCKSIZE. */
+
+/* Offsets to structures within the LDM Database in units of LDM_BLOCKSIZE. */
+#define OFF_PRIVHEAD2 928 /* Backup private headers. */
+#define OFF_PRIVHEAD3 1023
+
+#define OFF_TOCBLOCK1 0 /* Tables of contents. */
+#define OFF_TOCBLOCK2 1
+#define OFF_TOCBLOCK3 1022
+#define OFF_TOCBLOCK4 1023
+
+#define OFF_VMDB 8 /* List of partitions. */
+#define OFF_VBLK 9
+
+#define WIN2K_DYNAMIC_PARTITION 0x42 /* Formerly SFS (Landis). */
+#define WIN2K_EXTENDED_PARTITION 0x05 /* A standard extended
+ partition. */
+
+#define TOC_BITMAP1 "config" /* Names of the two defined */
+#define TOC_BITMAP2 "log" /* bitmaps in the TOCBLOCK. */
+
+/* Borrowed from msdos.c */
+#define SYS_IND(p) (get_unaligned(&p->sys_ind))
+#define NR_SECTS(p) ({ __typeof__(p->nr_sects) __a = \
+ get_unaligned(&p->nr_sects); \
+ le32_to_cpu(__a); \
+ })
+#define START_SECT(p) ({ __typeof__(p->start_sect) __a = \
+ get_unaligned(&p->start_sect); \
+ le32_to_cpu(__a); \
+ })
+
+/* Most numbers we deal with are big-endian and won't be aligned. */
+#define BE16(x) ((u16)be16_to_cpu(get_unaligned((u16*)(x))))
+#define BE32(x) ((u32)be32_to_cpu(get_unaligned((u32*)(x))))
+#define BE64(x) ((u64)be64_to_cpu(get_unaligned((u64*)(x))))
+
+/* Borrowed from msdos.c. */
+#define SYS_IND(p) (get_unaligned(&(p)->sys_ind))
+#define NR_SECTS(p) ({ __typeof__((p)->nr_sects) __a = \
+ get_unaligned(&(p)->nr_sects); \
+ le32_to_cpu(__a); \
+ })
+
+#define START_SECT(p) ({ __typeof__((p)->start_sect) __a = \
+ get_unaligned(&(p)->start_sect);\
+ le32_to_cpu(__a); \
+ })
+
+/* In memory LDM database structures. */
+
+#define DISK_ID_SIZE 64 /* Size in bytes. */
+
+struct ldmdisk {
+ u64 obj_id;
+ u8 disk_id[DISK_ID_SIZE];
+};
+
+struct privhead { /* Offsets and sizes are in sectors. */
+ u16 ver_major;
+ u16 ver_minor;
+ u64 logical_disk_start;
+ u64 logical_disk_size;
+ u64 config_start;
+ u64 config_size;
+ u8 disk_id[DISK_ID_SIZE];
+};
+
+struct tocblock { /* We have exactly two bitmaps. */
+ u8 bitmap1_name[16];
+ u64 bitmap1_start;
+ u64 bitmap1_size;
+ /*u64 bitmap1_flags;*/
+ u8 bitmap2_name[16];
+ u64 bitmap2_start;
+ u64 bitmap2_size;
+ /*u64 bitmap2_flags;*/
+};
+
+struct vmdb {
+ u16 ver_major;
+ u16 ver_minor;
+ u32 vblk_size;
+ u32 vblk_offset;
+ u32 last_vblk_seq;
+};
+
+struct vblk {
+ u8 name[64];
+ u8 vblk_type;
+ u64 obj_id;
+ u64 disk_id;
+ u64 start_sector;
+ u64 num_sectors;
+};
+
+int ldm_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector,
+ int first_part_minor);
+
+#endif /* _FS_PT_LDM_H_ */
+
return buffer;
}
-extern inline char *task_cap(struct task_struct *p, char *buffer)
+static inline char *task_cap(struct task_struct *p, char *buffer)
{
return buffer + sprintf(buffer, "CapInh:\t%016x\n"
"CapPrm:\t%016x\n"
-/* $Id: atomic.h,v 1.2 2000/07/13 16:51:57 bjornw Exp $ */
+/* $Id: atomic.h,v 1.3 2001/07/25 16:15:19 bjornw Exp $ */
#ifndef __ASM_CRIS_ATOMIC__
#define __ASM_CRIS_ATOMIC__
return retval;
}
+/* Atomic operations are already serializing */
+#define smp_mb__before_atomic_dec() barrier()
+#define smp_mb__after_atomic_dec() barrier()
+#define smp_mb__before_atomic_inc() barrier()
+#define smp_mb__after_atomic_inc() barrier()
+
#endif
* tools/mkptable is used to generate the ptable.
*/
-/* The partition table starts with code to "jump over" it: */
+/* The partition table starts with code to "jump over" it. The ba
+ instruction and delay-slot is modified elsewhere (for example the
+ mkptable script); don't change this to fill the delay-slot. */
#define PARTITIONTABLE_CODE_START { \
0x0f, 0x05, /* nop 0 */\
0x25, 0xf0, /* di 2 */\
#define PARTITIONTABLE_END_MARKER_SIZE 4
/*#define PARTITION_TYPE_RESCUE 0x0000?*/ /* Not used, maybe it should? */
-#define PARTITION_TYPE_PARAM 0x0001 /* Hmm.. */
+#define PARTITION_TYPE_PARAM 0x0001
#define PARTITION_TYPE_KERNEL 0x0002
#define PARTITION_TYPE_JFFS 0x0003
-/* $Id: checksum.h,v 1.3 2000/11/15 17:35:16 bjornw Exp $ */
+/* $Id: checksum.h,v 1.4 2001/06/28 03:58:36 hp Exp $ */
/* TODO: csum_tcpudp_magic could be speeded up, and csum_fold as well */
#ifndef _CRIS_CHECKSUM_H
return res;
}
-
-/* TODO we need to write this properly to handle userland VM exceptions!! */
-
-#define csum_partial_copy_from_user(a,b,c,d,errptr) csum_partial_copy_nocheck(a,b,c,d)
-
-#if 0
-unsigned int csum_partial_copy_from_user(const char *src, char *dst,
- int len, unsigned int sum);
-#endif
-
-
+extern unsigned int csum_partial_copy_from_user(const char *src, char *dst,
+ int len, unsigned int sum,
+ int *errptr);
/*
* This is a version of ip_compute_csum() optimized for IP headers,
-/* $Id: delay.h,v 1.4 2001/05/31 06:40:53 markusl Exp $ */
+/* $Id: delay.h,v 1.5 2001/06/28 04:59:25 hp Exp $ */
#ifndef _CRIS_DELAY_H
#define _CRIS_DELAY_H
/*
- * Copyright (C) 1998, 1999, 2000 Axis Communications AB
+ * Copyright (C) 1998, 1999, 2000, 2001 Axis Communications AB
*
* Delay routines, using a pre-computed "loops_per_second" value.
*/
extern __inline__ void __delay(int loops)
{
__asm__ __volatile__ (
- "move.d %0,r0\n\t"
- "1:\n\t"
- "cmpq 0,r0\n\t"
+ "move.d %0,r9\n\t"
"beq 2f\n\t"
- "nop\n\t"
- "subq 1,r0\n\t"
- "ba 1b\n\t"
- "nop\n\t"
- "2:\n\t"
- : : "r" (loops) : "r0");
+ "subq 1,r9\n\t"
+ "1:\n\t"
+ "bne 1b\n\t"
+ "subq 1,r9\n"
+ "2:"
+ : : "g" (loops) : "r9");
}
-/*
- * Use only for very small delays ( < 1 msec). Should probably use a
- * lookup table, really, as the multiplications take much too long with
- * short delays. This is a "reasonable" implementation, though (and the
- * first constant multiplications gets optimized away if the delay is
- * a constant)
- */
+/* Use only for very small delays ( < 1 msec). */
extern unsigned long loops_per_usec; /* arch/cris/mm/init.c */
/* entry.S is sensitive to the offsets of these fields */
typedef struct {
- unsigned int __softirq_active;
- unsigned int __softirq_mask;
+ unsigned int __softirq_pending;
unsigned int __local_irq_count;
unsigned int __local_bh_count;
unsigned int __syscall_count;
+ struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
} ____cacheline_aligned irq_cpustat_t;
#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
use will be evident. */
#ifdef CONFIG_SVINTO_SIM
/* Let's use the ucsim interface since it lets us do write(2, ...) */
-#define SIMCOUT(s,len) asm ("moveq 4,r1\n\tmoveq 2,r10\n\tmove.d %0,r11\n\tmove.d %1,r12\
-\n\tpush irp\n\t.word 0xae3f\n\t.dword 0f\n\tjump -6809\n0:\n\tpop irp" \
+#define SIMCOUT(s,len) \
+ asm ("moveq 4,r1 \n\t" \
+ "moveq 2,r10 \n\t" \
+ "move.d %0,r11 \n\t" \
+ "move.d %1,r12 \n\t" \
+ "push irp \n\t" \
+ "move 0f,irp \n\t" \
+ "jump -6809 \n" \
+ "0: \n\t" \
+ "pop irp" \
: : "rm" (s), "rm" (len) : "r1","r10","r11","r12","memory")
#define TRACE_ON() __extension__ \
({ int _Foofoo; __asm__ volatile ("bmod [%0],%0" : "=r" (_Foofoo) : "0" \
#define LED_ACTIVE_SET_R(x) \
REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED2R, !(x))
#define LED_DISK_WRITE(x) \
- REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x))
+ do{\
+ REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x));\
+ REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3R, !(x));\
+ }while(0)
#define LED_DISK_READ(x) \
REG_SHADOW_SET(R_PORT_PA_DATA, port_pa_data_shadow, CONFIG_ETRAX_LED3G, !(x))
#endif
#define LED_ACTIVE_SET_R(x) \
REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED2R, !(x))
#define LED_DISK_WRITE(x) \
- REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x))
+ do{\
+ REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x));\
+ REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3R, !(x));\
+ }while(0)
#define LED_DISK_READ(x) \
REG_SHADOW_SET(R_PORT_PB_DATA, port_pb_data_shadow, CONFIG_ETRAX_LED3G, !(x))
#endif
#define LED_ACTIVE_SET_R(x) \
REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED2R, !(x))
#define LED_DISK_WRITE(x) \
- REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x))
+ do{\
+ REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x));\
+ REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3R, !(x));\
+ }while(0)
#define LED_DISK_READ(x) \
REG_SHADOW_SET(port_csp0_addr, port_csp0_shadow, CONFIG_ETRAX_LED3G, !(x))
#define LED_BIT_SET(x)\
/*
* Interrupt handling assembler and defines for Linux/CRIS
*
- * Copyright (c) 2000 Axis Communications AB
+ * Copyright (c) 2000, 2001 Axis Communications AB
*
* Authors: Bjorn Wesen (bjornw@axis.com)
*
- * $Id: irq.h,v 1.11 2001/06/01 14:57:17 starvik Exp $
+ * $Id: irq.h,v 1.13 2001/07/06 18:52:08 hp Exp $
*/
#ifndef _ASM_IRQ_H
/* par1, scsi1 on 5 */
#define NETWORK_STATUS_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 6 */
-#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, network) /* 8 */
+#define SERIAL_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, serial) /* 8 */
#define PA_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, pa) /* 11 */
/* extdma0 and extdma1 is at irq 12 and 13 and/or same as dma5 and dma6 ? */
#define EXTDMA0_IRQ_NBR IO_BITNR(R_VECT_MASK_RD, ext_dma0)
#define start_thread(regs, ip, usp) do { \
set_fs(USER_DS); \
regs->irp = ip; \
- regs->dccr |= 1 << 8; \
+ regs->dccr |= 1 << U_DCCR_BITNR; \
wrusp(usp); \
} while(0)
#define PT_USP 23 /* special case - USP is not in the pt_regs */
#define PT_MAX 23
+/* Condition code bit numbers. The same numbers apply to CCR of course,
+ but we use DCCR everywhere else, so let's try and be consistent. */
+#define C_DCCR_BITNR 0
+#define V_DCCR_BITNR 1
+#define Z_DCCR_BITNR 2
+#define N_DCCR_BITNR 3
+#define X_DCCR_BITNR 4
+#define I_DCCR_BITNR 5
+#define B_DCCR_BITNR 6
+#define M_DCCR_BITNR 7
+#define U_DCCR_BITNR 8
+#define P_DCCR_BITNR 9
+#define F_DCCR_BITNR 10
+
/* Frame types */
#define CRIS_FRAME_NORMAL 0 /* normal frame without SBFS stacking */
#define PTRACE_SETREGS 13
/* bit 8 is user-mode flag */
-#define user_mode(regs) ((regs)->dccr & 0x100)
+#define user_mode(regs) (((regs)->dccr & 0x100) != 0)
#define instruction_pointer(regs) ((regs)->irp)
extern void show_regs(struct pt_regs *);
#endif
/* level. For writing rarp and */
/* other similar things on the */
/* user level. */
-#define SOCK_MAX (SOCK_PACKET+1)
+#define SOCK_MAX (SOCK_PACKET+1)
#endif
#endif /* _ASM_SOCKET_H */
#include <asm/atomic.h>
#include <asm/hardirq.h>
-#define local_bh_disable() (local_bh_count(smp_processor_id())++)
-#define local_bh_enable() (local_bh_count(smp_processor_id())--)
+#define local_bh_disable() \
+do { \
+ local_bh_count(smp_processor_id())++; \
+ barrier(); \
+} while (0)
+
+#define __local_bh_enable() \
+do { \
+ barrier(); \
+ local_bh_count(smp_processor_id())--; \
+} while (0)
+
+#define local_bh_enable() \
+do { \
+ if (!--local_bh_count(smp_processor_id()) \
+ && softirq_pending(smp_processor_id())) { \
+ do_softirq(); \
+ __sti(); \
+ } \
+} while (0)
#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
+#define __cpu_raise_softirq(cpu,nr) set_bit((nr), &softirq_pending(cpu))
+
#endif /* __ASM_SOFTIRQ_H */
* Basic functions accessing APICs.
*/
-extern __inline void apic_write(unsigned long reg, unsigned long v)
+static __inline void apic_write(unsigned long reg, unsigned long v)
{
*((volatile unsigned long *)(APIC_BASE+reg)) = v;
}
-extern __inline void apic_write_atomic(unsigned long reg, unsigned long v)
+static __inline void apic_write_atomic(unsigned long reg, unsigned long v)
{
xchg((volatile unsigned long *)(APIC_BASE+reg), v);
}
-extern __inline unsigned long apic_read(unsigned long reg)
+static __inline unsigned long apic_read(unsigned long reg)
{
return *((volatile unsigned long *)(APIC_BASE+reg));
}
# define apic_write_around(x,y) apic_write_atomic((x),(y))
#endif
-extern inline void ack_APIC_irq(void)
+static inline void ack_APIC_irq(void)
{
/*
* ack_APIC_irq() actually gets compiled as a single instruction:
* If you use these functions directly please don't forget the
* verify_area().
*/
-extern __inline__
+static __inline__
unsigned int csum_partial_copy_nocheck ( const char *src, char *dst,
int len, int sum)
{
return csum_partial_copy_generic ( src, dst, len, sum, NULL, NULL);
}
-extern __inline__
+static __inline__
unsigned int csum_partial_copy_from_user ( const char *src, char *dst,
int len, int sum, int *err_ptr)
{
#define CO_IRQ_8259 12
#ifdef CONFIG_X86_VISWS_APIC
-extern __inline void co_cpu_write(unsigned long reg, unsigned long v)
+static __inline void co_cpu_write(unsigned long reg, unsigned long v)
{
*((volatile unsigned long *)(CO_CPU_VADDR+reg))=v;
}
-extern __inline unsigned long co_cpu_read(unsigned long reg)
+static __inline unsigned long co_cpu_read(unsigned long reg)
{
return *((volatile unsigned long *)(CO_CPU_VADDR+reg));
}
-extern __inline void co_apic_write(unsigned long reg, unsigned long v)
+static __inline void co_apic_write(unsigned long reg, unsigned long v)
{
*((volatile unsigned long *)(CO_APIC_VADDR+reg))=v;
}
-extern __inline unsigned long co_apic_read(unsigned long reg)
+static __inline unsigned long co_apic_read(unsigned long reg)
{
return *((volatile unsigned long *)(CO_APIC_VADDR+reg));
}
extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
extern void set_tss_desc(unsigned int n, void *addr);
-extern inline void clear_LDT(void)
+static inline void clear_LDT(void)
{
int cpu = smp_processor_id();
set_ldt_desc(cpu, &default_ldt[0], 5);
/*
* load one particular LDT into the current CPU
*/
-extern inline void load_LDT (struct mm_struct *mm)
+static inline void load_LDT (struct mm_struct *mm)
{
int cpu = smp_processor_id();
void *segments = mm->context.segments;
* directly without tranlation, we catch the bug with a NULL-deference
* kernel oops. Illegal ranges of incoming indices are caught too.
*/
-extern inline unsigned long fix_to_virt(const unsigned int idx)
+static inline unsigned long fix_to_virt(const unsigned int idx)
{
/*
* this branch gets completely eliminated after inlining,
* Talk about misusing macros..
*/
#define __OUT1(s,x) \
-extern inline void out##s(unsigned x value, unsigned short port) {
+static inline void out##s(unsigned x value, unsigned short port) {
#define __OUT2(s,s1,s2) \
__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1"
__OUT1(s##_p,x) __OUT2(s,s1,"w") __FULL_SLOW_DOWN_IO : : "a" (value), "Nd" (port));} \
#define __IN1(s) \
-extern inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
+static inline RETURN_TYPE in##s(unsigned short port) { RETURN_TYPE _v;
#define __IN2(s,s1,s2) \
__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0"
__IN1(s##_p) __IN2(s,s1,"w") __FULL_SLOW_DOWN_IO : "=a" (_v) : "Nd" (port) ,##i ); return _v; } \
#define __INS(s) \
-extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \
+static inline void ins##s(unsigned short port, void * addr, unsigned long count) \
{ __asm__ __volatile__ ("rep ; ins" #s \
: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
#define __OUTS(s) \
-extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
+static inline void outs##s(unsigned short port, const void * addr, unsigned long count) \
{ __asm__ __volatile__ ("rep ; outs" #s \
: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); }
* Change virtual addresses to physical addresses and vv.
* These are pretty trivial
*/
-extern inline unsigned long virt_to_phys(volatile void * address)
+static inline unsigned long virt_to_phys(volatile void * address)
{
return __pa(address);
}
-extern inline void * phys_to_virt(unsigned long address)
+static inline void * phys_to_virt(unsigned long address)
{
return __va(address);
}
extern void * __ioremap(unsigned long offset, unsigned long size, unsigned long flags);
-extern inline void * ioremap (unsigned long offset, unsigned long size)
+static inline void * ioremap (unsigned long offset, unsigned long size)
{
return __ioremap(offset, size, 0);
}
* it's useful if some control registers are in such an area and write combining
* or read caching is not desirable:
*/
-extern inline void * ioremap_nocache (unsigned long offset, unsigned long size)
+static inline void * ioremap_nocache (unsigned long offset, unsigned long size)
{
return __ioremap(offset, size, _PAGE_PCD);
}
#ifdef CONFIG_X86_VISWS_APIC
/* More special purpose macros... */
-extern __inline void li_pcia_write16(unsigned long reg, unsigned short v)
+static __inline void li_pcia_write16(unsigned long reg, unsigned short v)
{
*((volatile unsigned short *)(LI_PCIA_VADDR+reg))=v;
}
-extern __inline unsigned short li_pcia_read16(unsigned long reg)
+static __inline unsigned short li_pcia_read16(unsigned long reg)
{
return *((volatile unsigned short *)(LI_PCIA_VADDR+reg));
}
-extern __inline void li_pcib_write16(unsigned long reg, unsigned short v)
+static __inline void li_pcib_write16(unsigned long reg, unsigned short v)
{
*((volatile unsigned short *)(LI_PCIB_VADDR+reg))=v;
}
-extern __inline unsigned short li_pcib_read16(unsigned long reg)
+static __inline unsigned short li_pcib_read16(unsigned long reg)
{
return *((volatile unsigned short *)(LI_PCIB_VADDR+reg));
}
* to borrow for other processors if it was just assembler.
*/
-extern __inline__ void prim_spin_lock(struct spinlock *sp)
+static __inline__ void prim_spin_lock(struct spinlock *sp)
{
int processor=smp_processor_id();
* Release a spin lock
*/
-extern __inline__ int prim_spin_unlock(struct spinlock *sp)
+static __inline__ int prim_spin_unlock(struct spinlock *sp)
{
/* This is safe. The decrement is still guarded by the lock. A multilock would
not be safe this way */
* Non blocking lock grab
*/
-extern __inline__ int prim_spin_lock_nb(struct spinlock *sp)
+static __inline__ int prim_spin_lock_nb(struct spinlock *sp)
{
if(lock_set_bit(0,&sp->lock))
return 0; /* Locked already */
* These wrap the locking primitives up for usage
*/
-extern __inline__ void spinlock(struct spinlock *sp)
+static __inline__ void spinlock(struct spinlock *sp)
{
if(sp->priority<current->lock_order)
panic("lock order violation: %s (%d)\n", sp->name, current->lock_order);
}
}
-extern __inline__ void spinunlock(struct spinlock *sp)
+static __inline__ void spinunlock(struct spinlock *sp)
{
int pri;
if(current->lock_order!=sp->priority)
}
}
-extern __inline__ void spintestlock(struct spinlock *sp)
+static __inline__ void spintestlock(struct spinlock *sp)
{
/*
* We do no sanity checks, it's legal to optimistically
prim_spin_lock_nb(sp);
}
-extern __inline__ void spintestunlock(struct spinlock *sp)
+static __inline__ void spintestunlock(struct spinlock *sp)
{
/*
* A testlock doesn't update the lock chain so we
*/
typedef struct {
void *segments;
+ unsigned long cpuvalid;
} mm_context_t;
#endif
cpu_tlbstate[cpu].active_mm = next;
#endif
set_bit(cpu, &next->cpu_vm_mask);
+ set_bit(cpu, &next->context.cpuvalid);
/* Re-load page tables */
asm volatile("movl %0,%%cr3": :"r" (__pa(next->pgd)));
}
*/
local_flush_tlb();
}
+ if (!test_and_set_bit(cpu, &next->context.cpuvalid))
+ load_LDT(next);
}
#endif
}
} while (0)
/* Pure 2^n version of get_order */
-extern __inline__ int get_order(unsigned long size)
+static __inline__ int get_order(unsigned long size)
{
int order;
* Once the device is given the dma address, the device owns this memory
* until either pci_unmap_single or pci_dma_sync_single is performed.
*/
-extern inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
+static inline dma_addr_t pci_map_single(struct pci_dev *hwdev, void *ptr,
size_t size, int direction)
{
if (direction == PCI_DMA_NONE)
* After this call, reads by the cpu to the buffer are guarenteed to see
* whatever the device wrote there.
*/
-extern inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
+static inline void pci_unmap_single(struct pci_dev *hwdev, dma_addr_t dma_addr,
size_t size, int direction)
{
if (direction == PCI_DMA_NONE)
* Device ownership issues as mentioned above for pci_map_single are
* the same here.
*/
-extern inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+static inline int pci_map_sg(struct pci_dev *hwdev, struct scatterlist *sg,
int nents, int direction)
{
if (direction == PCI_DMA_NONE)
* Again, cpu read rules concerning calls here are the same as for
* pci_unmap_single() above.
*/
-extern inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
+static inline void pci_unmap_sg(struct pci_dev *hwdev, struct scatterlist *sg,
int nents, int direction)
{
if (direction == PCI_DMA_NONE)
* next point you give the PCI dma address back to the card, the
* device again owns the buffer.
*/
-extern inline void pci_dma_sync_single(struct pci_dev *hwdev,
+static inline void pci_dma_sync_single(struct pci_dev *hwdev,
dma_addr_t dma_handle,
size_t size, int direction)
{
* The same as pci_dma_sync_single but for a scatter-gather list,
* same rules and usage.
*/
-extern inline void pci_dma_sync_sg(struct pci_dev *hwdev,
+static inline void pci_dma_sync_sg(struct pci_dev *hwdev,
struct scatterlist *sg,
int nelems, int direction)
{
* only drive the low 24-bits during PCI bus mastering, then
* you would pass 0x00ffffff as the mask to this function.
*/
-extern inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
+static inline int pci_dma_supported(struct pci_dev *hwdev, dma_addr_t mask)
{
/*
* we fall back to GFP_DMA when the mask isn't all 1s,
extern void *kmalloc(size_t, int);
extern void kfree(const void *);
-extern __inline__ pgd_t *get_pgd_slow(void)
+static __inline__ pgd_t *get_pgd_slow(void)
{
int i;
pgd_t *pgd = kmalloc(PTRS_PER_PGD * sizeof(pgd_t), GFP_KERNEL);
#else
-extern __inline__ pgd_t *get_pgd_slow(void)
+static __inline__ pgd_t *get_pgd_slow(void)
{
pgd_t *pgd = (pgd_t *)__get_free_page(GFP_KERNEL);
#endif
-extern __inline__ pgd_t *get_pgd_fast(void)
+static __inline__ pgd_t *get_pgd_fast(void)
{
unsigned long *ret;
return (pgd_t *)ret;
}
-extern __inline__ void free_pgd_fast(pgd_t *pgd)
+static __inline__ void free_pgd_fast(pgd_t *pgd)
{
*(unsigned long *)pgd = (unsigned long) pgd_quicklist;
pgd_quicklist = (unsigned long *) pgd;
pgtable_cache_size++;
}
-extern __inline__ void free_pgd_slow(pgd_t *pgd)
+static __inline__ void free_pgd_slow(pgd_t *pgd)
{
#if CONFIG_X86_PAE
int i;
return (pte_t *)ret;
}
-extern __inline__ void pte_free_fast(pte_t *pte)
+static __inline__ void pte_free_fast(pte_t *pte)
{
*(unsigned long *)pte = (unsigned long) pte_quicklist;
pte_quicklist = (unsigned long *) pte;
pgtable_cache_size++;
}
-extern __inline__ void pte_free_slow(pte_t *pte)
+static __inline__ void pte_free_slow(pte_t *pte)
{
free_page((unsigned long)pte);
}
#endif
-extern inline void flush_tlb_pgtables(struct mm_struct *mm,
+static inline void flush_tlb_pgtables(struct mm_struct *mm,
unsigned long start, unsigned long end)
{
/* i386 does not keep any page table caches in TLB */
* setup: the pgd is never bad, and a pmd always exists (as it's folded
* into the pgd entry)
*/
-extern inline int pgd_none(pgd_t pgd) { return 0; }
-extern inline int pgd_bad(pgd_t pgd) { return 0; }
-extern inline int pgd_present(pgd_t pgd) { return 1; }
+static inline int pgd_none(pgd_t pgd) { return 0; }
+static inline int pgd_bad(pgd_t pgd) { return 0; }
+static inline int pgd_present(pgd_t pgd) { return 1; }
#define pgd_clear(xp) do { } while (0)
/*
#define pgd_page(pgd) \
((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
-extern inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
+static inline pmd_t * pmd_offset(pgd_t * dir, unsigned long address)
{
return (pmd_t *) dir;
}
#define pgd_ERROR(e) \
printk("%s:%d: bad pgd %p(%016Lx).\n", __FILE__, __LINE__, &(e), pgd_val(e))
-extern inline int pgd_none(pgd_t pgd) { return 0; }
-extern inline int pgd_bad(pgd_t pgd) { return 0; }
-extern inline int pgd_present(pgd_t pgd) { return 1; }
+static inline int pgd_none(pgd_t pgd) { return 0; }
+static inline int pgd_bad(pgd_t pgd) { return 0; }
+static inline int pgd_present(pgd_t pgd) { return 1; }
/* Rules for using set_pte: the pte being assigned *must* be
* either not present or in a state where the hardware will
* We do not let the generic code free and clear pgd entries due to
* this erratum.
*/
-extern inline void pgd_clear (pgd_t * pgd) { }
+static inline void pgd_clear (pgd_t * pgd) { }
#define pgd_page(pgd) \
((unsigned long) __va(pgd_val(pgd) & PAGE_MASK))
/*
* Generic CPUID function
*/
-extern inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
+static inline void cpuid(int op, int *eax, int *ebx, int *ecx, int *edx)
{
__asm__("cpuid"
: "=a" (*eax),
/*
* CPUID functions returning a single datum
*/
-extern inline unsigned int cpuid_eax(unsigned int op)
+static inline unsigned int cpuid_eax(unsigned int op)
{
unsigned int eax;
: "bx", "cx", "dx");
return eax;
}
-extern inline unsigned int cpuid_ebx(unsigned int op)
+static inline unsigned int cpuid_ebx(unsigned int op)
{
unsigned int eax, ebx;
: "cx", "dx" );
return ebx;
}
-extern inline unsigned int cpuid_ecx(unsigned int op)
+static inline unsigned int cpuid_ecx(unsigned int op)
{
unsigned int eax, ecx;
: "bx", "dx" );
return ecx;
}
-extern inline unsigned int cpuid_edx(unsigned int op)
+static inline unsigned int cpuid_edx(unsigned int op)
{
unsigned int eax, edx;
/*
* Return saved PC of a blocked thread.
*/
-extern inline unsigned long thread_saved_pc(struct thread_struct *t)
+static inline unsigned long thread_saved_pc(struct thread_struct *t)
{
return ((unsigned long *)t->esp)[3];
}
#define MICROCODE_IOCFREE _IO('6',0)
/* REP NOP (PAUSE) is a good thing to insert into busy-wait loops. */
-extern inline void rep_nop(void)
+static inline void rep_nop(void)
{
__asm__ __volatile__("rep;nop");
}
#ifdef __KERNEL__
#include <linux/string.h>
-extern inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
+static inline void copy_siginfo(siginfo_t *to, siginfo_t *from)
{
if (from->si_code < 0)
memcpy(to, from, sizeof(siginfo_t));
#define __HAVE_ARCH_SIG_BITOPS
-extern __inline__ void sigaddset(sigset_t *set, int _sig)
+static __inline__ void sigaddset(sigset_t *set, int _sig)
{
__asm__("btsl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
}
-extern __inline__ void sigdelset(sigset_t *set, int _sig)
+static __inline__ void sigdelset(sigset_t *set, int _sig)
{
__asm__("btrl %1,%0" : "=m"(*set) : "Ir"(_sig - 1) : "cc");
}
-extern __inline__ int __const_sigismember(sigset_t *set, int _sig)
+static __inline__ int __const_sigismember(sigset_t *set, int _sig)
{
unsigned long sig = _sig - 1;
return 1 & (set->sig[sig / _NSIG_BPW] >> (sig % _NSIG_BPW));
}
-extern __inline__ int __gen_sigismember(sigset_t *set, int _sig)
+static __inline__ int __gen_sigismember(sigset_t *set, int _sig)
{
int ret;
__asm__("btl %2,%1\n\tsbbl %0,%0"
#define sigmask(sig) (1UL << ((sig) - 1))
-extern __inline__ int sigfindinword(unsigned long word)
+static __inline__ int sigfindinword(unsigned long word)
{
__asm__("bsfl %1,%0" : "=r"(word) : "rm"(word) : "cc");
return word;
* This simplifies scheduling and IPI sending and
* compresses data structures.
*/
-extern inline int cpu_logical_map(int cpu)
+static inline int cpu_logical_map(int cpu)
{
return cpu;
}
-extern inline int cpu_number_map(int cpu)
+static inline int cpu_number_map(int cpu)
{
return cpu;
}
#define smp_processor_id() (current->processor)
-extern __inline int hard_smp_processor_id(void)
+static __inline int hard_smp_processor_id(void)
{
/* we don't want to mark this access volatile - bad code generation */
return GET_APIC_ID(*(unsigned long *)(APIC_BASE+APIC_ID));
* so we only need to worry about other
* CPU's.
*/
-extern __inline__ void lock_kernel(void)
+static __inline__ void lock_kernel(void)
{
#if 1
if (!++current->lock_depth)
#endif
}
-extern __inline__ void unlock_kernel(void)
+static __inline__ void unlock_kernel(void)
{
if (current->lock_depth < 0)
BUG();
return _mmx_memcpy(to, from, len);
}
-extern __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
+static __inline__ void *__memcpy3d(void *to, const void *from, size_t len)
{
if (len < 512)
return __memcpy(to, from, len);
* might have an implicit FPU-save as a cost, so it's not
* clear which path to go.)
*/
-extern inline void __set_64bit (unsigned long long * ptr,
+static inline void __set_64bit (unsigned long long * ptr,
unsigned int low, unsigned int high)
{
__asm__ __volatile__ (
: "ax","dx","memory");
}
-extern void inline __set_64bit_constant (unsigned long long *ptr,
+static inline void __set_64bit_constant (unsigned long long *ptr,
unsigned long long value)
{
__set_64bit(ptr,(unsigned int)(value), (unsigned int)((value)>>32ULL));
#define ll_low(x) *(((unsigned int*)&(x))+0)
#define ll_high(x) *(((unsigned int*)&(x))+1)
-extern void inline __set_64bit_var (unsigned long long *ptr,
+static inline void __set_64bit_var (unsigned long long *ptr,
unsigned long long value)
{
__set_64bit(ptr,ll_low(value), ll_high(value));
#endif
-extern inline int verify_area(int type, const void * addr, unsigned long size)
+static inline int verify_area(int type, const void * addr, unsigned long size)
{
return access_ok(type,addr,size) ? 0 : -EFAULT;
}
#define atomic_eieio() __asm__ __volatile__ ("BCR 15,0")
-#define __CS_LOOP(old, new, ptr, op_val, op_string) \
+#define __CS_LOOP(old_val, new_val, ptr, op_val, op_string) \
__asm__ __volatile__(" l %0,0(%2)\n" \
"0: lr %1,%0\n" \
op_string " %1,%3\n" \
" cs %0,%1,0(%2)\n" \
" jl 0b" \
- : "=&d" (old), "=&d" (new) \
+ : "=&d" (old_val), "=&d" (new_val) \
: "a" (ptr), "d" (op_val) : "cc" );
static __inline__ int atomic_read(atomic_t *v)
static __inline__ void atomic_add(int i, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, i, "ar");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "ar");
}
static __inline__ int atomic_add_return (int i, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, i, "ar");
- return new;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "ar");
+ return new_val;
}
static __inline__ int atomic_add_negative(int i, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, i, "ar");
- return new < 0;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "ar");
+ return new_val < 0;
}
static __inline__ void atomic_sub(int i, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, i, "sr");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "sr");
}
static __inline__ void atomic_inc(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "ar");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "ar");
}
static __inline__ int atomic_inc_return(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "ar");
- return new;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "ar");
+ return new_val;
}
static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "ar");
- return new != 0;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "ar");
+ return new_val != 0;
}
static __inline__ void atomic_dec(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "sr");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "sr");
}
static __inline__ int atomic_dec_return(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "sr");
- return new;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "sr");
+ return new_val;
}
static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "sr");
- return new == 0;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "sr");
+ return new_val == 0;
}
static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, ~mask, "nr");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, ~mask, "nr");
}
static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, mask, "or");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, mask, "or");
}
/*
" icm %0,2,1(%1)\n"
" icm %0,4,2(%1)\n"
" icm %0,8,3(%1)"
- : "=&a" (word) : "a" (p) );
+ : "=&a" (word) : "a" (p) : "cc" );
word >>= bit;
res = bit;
/* Look for zero in first longword */
" icm %0,4,2(%1)\n"
" icm %0,2,1(%1)\n"
" ic %0,0(%1)"
- : "+&d" (x) : "a" (&temp) : "memory" );
+ : "+&d" (x) : "a" (&temp) : "cc" );
return x;
}
" icm %0,4,2(%1)\n"
" icm %0,2,1(%1)\n"
" ic %0,0(%1)"
- : "=&d" (result) : "a" (x) );
+ : "=&d" (result) : "a" (x) : "cc" );
return result;
}
" icm 0,2,1(%0)\n"
" ic 0,0(%0)\n"
" st 0,0(%0)"
- : : "a" (x) : "0", "memory");
+ : : "a" (x) : "0", "memory", "cc");
}
static __inline__ __const__ __u16 ___arch__swab16(__u16 x)
" sth %0,0(%1)\n"
" icm %0,2,1(%1)\n"
" ic %0,0(%1)\n"
- : "+&d" (x) : "a" (&temp) : "memory");
+ : "+&d" (x) : "a" (&temp) : "memory", "cc" );
return x;
}
" sr %0,%0\n"
" icm %0,2,1(%1)\n"
" ic %0,0(%1)\n"
- : "=&d" (result) : "a" (x) );
+ : "=&d" (result) : "a" (x) : "cc" );
return result;
}
" icm 0,2,1(%0)\n"
" ic 0,0(%0)\n"
" sth 0,0(%0)"
- : : "a" (x) : "0", "memory");
+ : : "a" (x) : "0", "memory", "cc" );
}
#define __arch__swab32(x) ___arch__swab32(x)
#ifndef __ARCH_S390_CACHE_H
#define __ARCH_S390_CACHE_H
-#define L1_CACHE_BYTES 16
+#define L1_CACHE_BYTES 256
+#define L1_CACHE_SHIFT 16
#endif
*
* Generic channel device initialisation support.
*/
+#ifndef __S390_CHANDEV_H
+#define __S390_CHANDEV_H
#include <linux/version.h>
#include <asm/types.h>
#include <linux/netdevice.h>
+
+/* Setting this flag to true causes a device name to be built based on the read_devno of the device */
+/* this is exported so external code can look at this flags setting */
+extern int chandev_use_devno_names;
+
+
/* chandev_type is a bitmask for registering & describing device types. */
typedef enum
{
- none=0x0,
- ctc=0x1,
- escon=0x2,
- lcs=0x4,
- osad=0x8,
- qeth=0x10,
- claw=0x20,
+ chandev_type_none=0x0,
+ chandev_type_ctc=0x1,
+ chandev_type_escon=0x2,
+ chandev_type_lcs=0x4,
+ chandev_type_osad=0x8,
+ chandev_type_qeth=0x10,
+ chandev_type_claw=0x20,
} chandev_type;
typedef enum
{
- no_category,
- network_device,
- serial_device,
+ chandev_category_none,
+ chandev_category_network_device,
+ chandev_category_serial_device,
} chandev_category;
+
+
+typedef struct
+{
+ int irq;
+ u16 devno;
+ u16 cu_type; /* control unit type */
+ u8 cu_model; /* control unit model */
+ u16 dev_type; /* device type */
+ u8 dev_model; /* device model */
+ u8 pim; /* path installed mask */
+ u8 chpid[8]; /* CHPID 0-7 (if available) */
+} chandev_subchannel_info;
+
+#define CLAW_NAMELEN 9
+/* CLAW specific parameters other drivers should ignore these fields */
+typedef struct
+{
+
+ char host_name[CLAW_NAMELEN]; /* local host name */
+ char adapter_name[CLAW_NAMELEN]; /* workstation adapter name */
+ char api_type[CLAW_NAMELEN]; /* API type either TCPIP or API */
+} chandev_claw_info;
+
/*
* The chandev_probeinfo structure is passed to the device driver with configuration
* info for which irq's & ports to use when attempting to probe the device.
*/
typedef struct
{
- int read_irq;
- int write_irq;
- u16 read_devno;
- u16 write_devno;
- s16 port_protocol_no; /* -1 don't care */
+ chandev_subchannel_info read;
+ chandev_subchannel_info write;
+ chandev_subchannel_info data;
+ /* memory_usage_in_k is the suggested memory the driver should attempt to use for io */
+ /* buffers -1 means use the driver default the driver should set this field to the */
+ /* amount of memory it actually uses when returning this probeinfo to the channel */
+ /* device layer with chandev_initdevice */
+ s32 memory_usage_in_k;
+ chandev_claw_info claw;
+ u8 data_exists; /* whether this device has a data channel */
+ u8 cu_dev_info_inconsistent; /* either ctc or we possibly had a bad sense_id */
+ u8 chpid_info_inconsistent; /* either ctc or schib info bad */
+ s16 port_protocol_no; /* 0 by default, set specifically when forcing */
u8 hint_port_no; /* lcs specific */
- u8 max_port_no; /* lcs specific */
+ u8 max_port_no; /* lcs/qeth specific */
chandev_type chan_type;
u8 checksum_received_ip_pkts;
u8 use_hw_stats; /* where available e.g. lcs */
- u16 cu_type; /* control unit type */
- u8 cu_model; /* control unit model */
- u16 dev_type; /* device type */
- u8 dev_model; /* device model */
+ u8 device_forced; /* indicates the device hasn't been autodetected */
char *parmstr; /* driver specific parameters added by add_parms keyword */
/* newdevice used internally by chandev.c */
struct chandev_activelist *newdevice;
typedef enum
{
- good=0,
- not_oper,
- first_msck=not_oper,
- no_path,
- revalidate,
- gone,
- last_msck,
+ chandev_status_good,
+ chandev_status_not_oper,
+ chandev_status_first_msck=chandev_status_not_oper,
+ chandev_status_no_path,
+ chandev_status_revalidate,
+ chandev_status_gone,
+ chandev_status_last_msck,
+ chandev_status_all_chans_good /* pseudo machine check to indicate all channels are healthy */
} chandev_msck_status;
typedef int (*chandev_probefunc)(chandev_probeinfo *probeinfo);
-typedef void (*chandev_shutdownfunc)(void *device);
+typedef int (*chandev_shutdownfunc)(void *device);
typedef void (*chandev_unregfunc)(void *device);
-typedef void (*chandev_reoperfunc)(void *device,int msck_for_read_chan,chandev_msck_status prevstatus);
+typedef void (*chandev_msck_notification_func)(void *device,int msck_irq,
+chandev_msck_status prevstatus,chandev_msck_status newstatus);
*/
int chandev_register_and_probe(chandev_probefunc probefunc,
chandev_shutdownfunc shutdownfunc,
- chandev_reoperfunc reoperfunc,
+ chandev_msck_notification_func msck_notfunc,
chandev_type chan_type);
/* The chandev_unregister function is typically called when a module is being removed
int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname,
chandev_category category,chandev_unregfunc unreg_dev);
+/* This function builds a device name & copies it into destnamebuff suitable for calling
+ init_trdev or whatever & it honours the use_devno_names flag, it is used by chandev_initnetdevice
+ setting the buildfullname flag to TRUE will cause it to always build a full unique name based
+ on basename either honouring the chandev_use_devno_names flag if set or starting at index
+ 0 & checking the namespace of the channel device layer itself for a free index, this
+ may be useful when one doesn't have control of the name an upper layer may choose.
+ It returns NULL on error.
+*/
+char *chandev_build_device_name(chandev_probeinfo *probeinfo,char *destnamebuff,char *basename,int buildfullname);
+
+
+
+
+/* chandev_init_netdev registers with the normal network device layer */
+/* it doesn't update any of the chandev internal structures. */
+/* i.e. it is optional */
+/* it was part of chandev_initnetdevice but I separated it as */
+/* chandev_initnetdevice may make too many assumptions for some users */
+/* chandev_initnetdevice = chandev_initdevice followed by chandev_init_netdev */
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+struct net_device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct net_device *dev, int sizeof_priv,struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv));
+#else
+struct device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct device *dev, int sizeof_priv,struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv));
+#endif
+
/* chandev_initnetdevice registers a network device with the channel layer.
* It returns the device structure if successful,if dev=NULL it kmallocs it,
* On device initialisation failure it will kfree it under ALL curcumstances
void (*unreg_netdevfunc)(struct device *dev));
#endif
-
-
+/* chandev_add & delete model shouldn't normally be needed by drivers except if */
+/* someone is developing a driver which the channel device layer doesn't know about */
+void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
+ s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,
+ u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats);
+void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model);
+
+/* modules should use chandev_persist to see if they should stay loaded */
+/* this is useful for debugging purposes where you may wish to examine */
+/* /proc/s390dbf/ entries */
+int chandev_persist(chandev_type chan_type);
+#endif /* __S390_CHANDEV_H */
*
* here even more important to align src and dst on a 32-bit (or even
* better 64-bit) boundary
+ *
+ * Copy from userspace and compute checksum. If we catch an exception
+ * then zero the rest of the buffer.
*/
-
extern inline unsigned int
-csum_partial_copy_from_user(const char *src, char *dst,
- int len, unsigned int sum, int *errp)
+csum_partial_copy_from_user (const char *src, char *dst,
+ int len, unsigned int sum,
+ int *err_ptr)
{
- if (copy_from_user(dst, src, len)) {
- *errp = -EFAULT;
- memset(dst, 0, len);
- return sum;
- }
- return csum_partial(dst, len, sum);
+ int missing;
+
+ missing = copy_from_user(dst, src, len);
+ if (missing) {
+ memset(dst + len - missing, 0, missing);
+ *err_ptr = -EFAULT;
+ }
+
+ return csum_partial(dst, len, sum);
}
+
extern inline unsigned int
csum_partial_copy_nocheck (const char *src, char *dst, int len, unsigned int sum)
{
struct task_struct *current;
__asm__("lhi %0,-8192\n\t"
"nr %0,15"
- : "=&r" (current) );
+ : "=&r" (current) : : "cc" );
return current;
}
int dasd_oper_handler (int irq, devreg_t * devreg);
void dasd_schedule_bh (dasd_device_t *);
-debug_info_t *dasd_debug_area;
-
#endif /* __KERNEL__ */
#endif /* DASD_H */
#define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
/* the entry information */
-#define STCK(x) asm volatile ("STCK %0":"=m" (x))
+#define STCK(x) asm volatile ("STCK %0" : "=m" (x) : : "cc" )
typedef struct __debug_entry debug_entry_t;
"1: st 1,4+%1\n" \
" lr %0,0" \
: "=d" (__r), "+m" (__n) \
- : "d" (base) : "0", "1", "2" ); \
+ : "d" (base) : "0", "1", "2", "cc" ); \
(n) = (__n); \
__r; \
})
#include <asm/lowcore.h>
#include <linux/sched.h>
-/* No irq_cpustat_t for s390, the data is held directly in S390_lowcore */
+/* entry.S is sensitive to the offsets of these fields */
+typedef struct {
+ unsigned int __softirq_pending;
+ unsigned int __local_irq_count;
+ unsigned int __local_bh_count;
+ unsigned int __syscall_count;
+ struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+} ____cacheline_aligned irq_cpustat_t;
-/*
- * Simple wrappers reducing source bloat. S390 specific because each
- * cpu stores its data in S390_lowcore (PSA) instead of using a cache
- * aligned array element like most architectures.
- */
-
-#ifdef CONFIG_SMP
-
-#define softirq_active(cpu) (safe_get_cpu_lowcore(cpu).__softirq_active)
-#define softirq_mask(cpu) (safe_get_cpu_lowcore(cpu).__softirq_mask)
-#define local_irq_count(cpu) (safe_get_cpu_lowcore(cpu).__local_irq_count)
-#define local_bh_count(cpu) (safe_get_cpu_lowcore(cpu).__local_bh_count)
-#define syscall_count(cpu) (safe_get_cpu_lowcore(cpu).__syscall_count)
-
-#else /* CONFIG_SMP */
-
-/* Optimize away the cpu calculation, it is always current PSA */
-#define softirq_active(cpu) ((void)(cpu), S390_lowcore.__softirq_active)
-#define softirq_mask(cpu) ((void)(cpu), S390_lowcore.__softirq_mask)
-#define local_irq_count(cpu) ((void)(cpu), S390_lowcore.__local_irq_count)
-#define local_bh_count(cpu) ((void)(cpu), S390_lowcore.__local_bh_count)
-#define syscall_count(cpu) ((void)(cpu), S390_lowcore.__syscall_count)
-
-#endif /* CONFIG_SMP */
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
/*
* Are we in an interrupt context? Either doing bottom half
* or hardware interrupt processing?
- * Special definitions for s390, always access current PSA.
*/
-#define in_interrupt() ((S390_lowcore.__local_irq_count + S390_lowcore.__local_bh_count) != 0)
-
-#define in_irq() (S390_lowcore.__local_irq_count != 0)
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+ (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
#ifndef CONFIG_SMP
-
+
#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0)
#define hardirq_endlock(cpu) do { } while (0)
#define synchronize_irq() do { } while (0)
-#else
+#else /* CONFIG_SMP */
#include <asm/atomic.h>
#include <asm/smp.h>
/* if we didn't own the irq lock, just ignore.. */
if (atomic_read(&global_irq_holder) == cpu) {
atomic_set(&global_irq_holder,NO_PROC_ID);
- clear_bit(0,&global_irq_lock);
+ atomic_set(&global_irq_lock,0);
}
}
static inline int hardirq_trylock(int cpu)
{
- return !atomic_read(&global_irq_count) && !test_bit(0,&global_irq_lock);
+ return !atomic_read(&global_irq_count) &&
+ !atomic_read(&global_irq_lock);
}
#define hardirq_endlock(cpu) do { } while (0)
extern void synchronize_irq(void);
-#endif /* CONFIG_SMP */
+#endif /* CONFIG_SMP */
#endif /* __ASM_HARDIRQ_H */
#include <linux/config.h>
#include <asm/irq.h>
-typedef unsigned long idaw_t;
+#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
+#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
-static inline idaw_t *
+static inline addr_t *
idal_alloc ( int nridaws )
{
if ( nridaws > 33 )
BUG();
- return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA );
+ return kmalloc(nridaws * sizeof(addr_t), GFP_ATOMIC | GFP_DMA );
}
static inline void
-idal_free ( idaw_t *idal )
+idal_free ( addr_t *idal )
{
kfree (idal);
}
+#if defined(CONFIG_ARCH_S390X)
+extern unsigned long __create_idal(unsigned long address, int count);
+#endif
+
/*
* Function: set_normalized_cda
* sets the address of the data in CCW
* if necessary it allocates an IDAL and sets sthe appropriate flags
*/
-#if defined (CONFIG_ARCH_S390X)
-extern void set_normalized_cda(ccw1_t * ccw, unsigned long address);
-#else
-static inline void
+static inline int
set_normalized_cda(ccw1_t * ccw, unsigned long address)
{
- ccw->cda = address;
-}
+ int ret = 0;
+
+#if defined (CONFIG_ARCH_S390X)
+ if (((address + ccw->count) >> 31) != 0) {
+ if (ccw->flags & CCW_FLAG_IDA)
+ BUG();
+ address = __create_idal(address, ccw->count);
+ if (address)
+ ccw->flags |= CCW_FLAG_IDA;
+ else
+ ret = -ENOMEM;
+ }
#endif
+ ccw->cda = (__u32) address;
+ return ret;
+}
/*
* Function: clear_normalized_cda
static inline void
clear_normalized_cda ( ccw1_t * ccw )
{
+#if defined(CONFIG_ARCH_S390X)
if ( ccw -> flags & CCW_FLAG_IDA ) {
- idal_free ( (idaw_t *) (ccw -> cda ));
+ idal_free ( (addr_t *)(unsigned long) (ccw -> cda ));
ccw -> flags &= ~CCW_FLAG_IDA;
}
+#endif
ccw -> cda = 0;
}
#define __INITDATA .section ".data.init",#alloc,#write
*/
-#define __cacheline_aligned __attribute__ ((__aligned__(16)))
+#define __cacheline_aligned __attribute__ ((__aligned__(256)))
#endif
" jz 0f\n"
" sr %0,%0\n"
"0:"
- : "=a" (real_address) : "a" (address) );
+ : "=a" (real_address) : "a" (address) : "cc" );
return real_address;
}
extern int set_cons_dev(int irq);
extern int reset_cons_dev(int irq);
extern int wait_cons_dev(int irq);
+extern schib_t *s390_get_schib( int irq );
+
+extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
+extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
/*
* Some S390 specific IO instructions as inline
#define __LC_SAVE_AREA 0xC00
#define __LC_KERNEL_STACK 0xC40
#define __LC_KERNEL_LEVEL 0xC44
-#define __LC_IRQ_STAT 0xC48
#define __LC_CPUID 0xC60
#define __LC_CPUADDR 0xC68
#define __LC_IPLDEV 0xC7C
#define __LC_PANIC_MAGIC 0xE00
+#define __LC_PFAULT_INTPARM 0x080
+
/* interrupt handler start with all io, external and mcck interrupt disabled */
#define _RESTART_PSW_MASK 0x00080000
__u32 kernel_stack; /* 0xc40 */
__u32 kernel_level; /* 0xc44 */
/* entry.S sensitive area start */
- /* Next 6 words are the s390 equivalent of irq_stat */
- __u32 __softirq_active; /* 0xc48 */
- __u32 __softirq_mask; /* 0xc4c */
- __u32 __local_irq_count; /* 0xc50 */
- __u32 __local_bh_count; /* 0xc54 */
- __u32 __syscall_count; /* 0xc58 */
- __u8 pad10[0xc60-0xc5c]; /* 0xc5c */
+ __u8 pad10[0xc60-0xc48]; /* 0xc5c */
struct cpuinfo_S390 cpu_data; /* 0xc60 */
__u32 ipl_device; /* 0xc7c */
/* entry.S sensitive area end */
rp.subreg.odd = (unsigned long) 4096;
asm volatile (" slr 1,1\n"
" mvcl %0,0"
- : "+&a" (rp) : : "memory", "1" );
+ : "+&a" (rp) : : "memory", "cc", "1" );
}
static inline void copy_page(void *to, void *from)
asm volatile (" sr 0,0\n"
" mvpg %0,%1"
: : "a" ((void *)(to)), "a" ((void *)(from))
- : "memory", "0" );
+ : "memory", "cc", "0" );
else
asm volatile (" mvc 0(256,%0),0(%1)\n"
" mvc 256(256,%0),256(%1)\n"
extern inline pte_t pte_mkold(pte_t pte)
{
- asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)));
+ asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)) : "cc" );
return pte;
}
asm volatile ("rrbe 0,%1\n\t"
"ipm %0\n\t"
- "srl %0,28\n\t" : "=d" (ccode) : "a" (pte_val(*ptep)));
+ "srl %0,28\n\t"
+ : "=d" (ccode) : "a" (pte_val(*ptep)) : "cc" );
return ccode & 2;
}
/* perform syscall argument validation (get/set_fs) */
mm_segment_t fs;
per_struct per_info;/* Must be aligned on an 4 byte boundary*/
- addr_t ieee_instruction_pointer;
/* Used to give failing instruction back to user for ieee exceptions */
+ addr_t ieee_instruction_pointer;
+ /* pfault_wait is used to block the process on a pfault event */
+ addr_t pfault_wait;
};
typedef struct thread_struct thread_struct;
(__pa((__u32) &swapper_pg_dir[0]) + _SEGMENT_TABLE),\
0,0,0, \
(mm_segment_t) { 0,1}, \
- (per_struct) {{{{0,}}},0,0,0,0,{{0,}}} \
+ (per_struct) {{{{0,}}},0,0,0,0,{{0,}}}, \
+ 0, 0 \
}
/* need to define ... */
" stctl 0,15,0x1c0\n" /* store control registers */
" oi 0(%1),0x10\n" /* fake protection bit */
" lpsw 0(%0)"
- : : "a" (dw_psw), "a" (&ctl_buf));
+ : : "a" (dw_psw), "a" (&ctl_buf) : "cc" );
}
#endif /* __ASM_S390_PROCESSOR_H */
*
* A little set of queue utilies.
*/
-
+#ifndef __ASM_QUEUE_H
+#define __ASM_QUEUE_H
#include <linux/stddef.h>
typedef struct queue
}
static __inline__ void enqueue_tail(qheader *qhead,queue *member)
-{
- queue *tail=qhead->tail;
- member->next=NULL;
-
+{
if(member)
{
+ queue *tail=qhead->tail;
+
if(tail)
tail->next=member;
else
return(0);
}
-
+#endif /* __ASM_QUEUE_H */
oper_handler_func_t oper_func;
} devreg_t;
-#define DEVREG_EXACT_MATCH 0x00000001
-#define DEVREG_MATCH_DEV_TYPE 0x00000002
-#define DEVREG_MATCH_CU_TYPE 0x00000004
-#define DEVREG_NO_CU_INFO 0x00000008
-#define DEVREG_NO_DEV_INFO 0x00000010
+#define DEVREG_MATCH_CU_TYPE 0x00000001
+#define DEVREG_MATCH_CU_MODEL 0x00000002
+#define DEVREG_MATCH_DEV_TYPE 0x00000004
+#define DEVREG_MATCH_DEV_MODEL 0x00000008
+
+#define DEVREG_EXACT_MATCH (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL|DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_CU_INFO (DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_DEV_INFO (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL)
#define DEVREG_TYPE_DEVNO 0x80000000
#define DEVREG_TYPE_DEVCHARS 0x40000000
#define MACHINE_HAS_CSP (machine_flags & 8)
#define MACHINE_HAS_MVPG (machine_flags & 16)
+#define MACHINE_HAS_HWC (!MACHINE_IS_P390)
+
+/*
+ * Console mode. Override with conmode=
+ */
+extern unsigned int console_mode;
+extern unsigned int console_device;
+
+#define CONSOLE_IS_UNDEFINED (console_mode == 0)
+#define CONSOLE_IS_HWC (console_mode == 1)
+#define CONSOLE_IS_3215 (console_mode == 2)
+#define CONSOLE_IS_3270 (console_mode == 3)
+#define SET_CONSOLE_HWC do { console_mode = 1; } while (0)
+#define SET_CONSOLE_3215 do { console_mode = 2; } while (0)
+#define SET_CONSOLE_3270 do { console_mode = 3; } while (0)
+
#else
#define IPL_DEVICE 0x10404
#include <asm/hardirq.h>
#include <asm/lowcore.h>
-#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0)
-
-#define local_bh_disable() cpu_bh_disable(smp_processor_id())
-#define local_bh_enable() cpu_bh_enable(smp_processor_id())
+#define local_bh_disable() \
+do { \
+ local_bh_count(smp_processor_id())++; \
+ barrier(); \
+} while (0)
+
+#define __local_bh_enable() \
+do { \
+ barrier(); \
+ local_bh_count(smp_processor_id())--; \
+} while (0)
+
+#define local_bh_enable() \
+do { \
+ if (!--local_bh_count(smp_processor_id()) \
+ && softirq_pending(smp_processor_id())) { \
+ do_softirq(); \
+ __sti(); \
+ } \
+} while (0)
+
+#define __cpu_raise_softirq(cpu, nr) (softirq_pending(cpu) |= (1<<nr))
#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
" jl 1b\n"
" ex 0,4(2)" /* store *ptr to x */
: "+a&" (ptr) : "a" (&x)
- : "memory", "0", "1", "2");
+ : "memory", "cc", "0", "1", "2");
break;
case 2:
if(((__u32)ptr)&1)
" jl 1b\n"
" ex 0,4(2)" /* store *ptr to x */
: "+a&" (ptr) : "a" (&x)
- : "memory", "0", "1", "2");
+ : "memory", "cc", "0", "1", "2");
break;
case 4:
if(((__u32)ptr)&3)
" jl 0b\n"
" lr %0,0\n"
: "+d&" (x) : "a" (ptr)
- : "memory", "0" );
+ : "memory", "cc", "0" );
break;
default:
abort();
__asm__ __volatile__("ssm %0" : : "m" (x) : "memory")
#define __load_psw(psw) \
- __asm__ __volatile__("lpsw %0" : : "m" (psw));
+ __asm__ __volatile__("lpsw %0" : : "m" (psw) : "cc" );
#define __ctl_load(array, low, high) ({ \
__asm__ __volatile__ ( \
" st 0,0(1)\n" \
"1: ex %1,4(2)" /* execute lctl */ \
: "=m" (dummy) : "a" (cr*17), "a" (1<<(bit)) \
- : "0", "1", "2"); \
+ : "cc", "0", "1", "2"); \
})
#define __ctl_clear_bit(cr, bit) ({ \
" st 0,0(1)\n" \
"1: ex %1,4(2)" /* execute lctl */ \
: "=m" (dummy) : "a" (cr*17), "a" (~(1<<(bit))) \
- : "0", "1", "2"); \
+ : "cc", "0", "1", "2"); \
})
/* For spinlocks etc */
".previous"
: "=m" (*((__u32*) ptr)) , "=&d" (err)
: "d" (x), "K" (-EFAULT)
- : "4" );
+ : "cc", "4" );
return err;
}
".previous"
: "=m" (*((__u16*) ptr)) , "=&d" (err)
: "d" (x), "K" (-EFAULT)
- : "4" );
+ : "cc", "4" );
return err;
}
".previous"
: "=m" (*((__u8*) ptr)) , "=&d" (err)
: "d" (x), "K" (-EFAULT)
- : "4" );
+ : "cc", "4" );
return err;
}
".previous" \
: "=d" (x) , "=&d" (err) \
: "m" (*(const __u32*)(ptr)),"K" (-EFAULT) \
- : "4" ); \
+ : "cc", "4" ); \
})
#define __get_user_asm_2(x, ptr, err) \
".previous" \
: "=d" (x) , "=&d" (err) \
: "m" (*(const __u16*)(ptr)),"K" (-EFAULT) \
- : "4" ); \
+ : "cc", "4" ); \
})
#define __get_user_asm_1(x, ptr, err) \
".previous" \
: "=d" (x) , "=&d" (err) \
: "m" (*(const __u8*)(ptr)),"K" (-EFAULT) \
- : "4" ); \
+ : "cc", "4" ); \
})
#define __get_user(x, ptr) \
" .long 0b,__copy_to_user_fixup\n"
".previous"
: "+&d" (n) : "d" (to), "d" (from)
- : "2", "3", "4", "5" );
+ : "cc", "2", "3", "4", "5" );
return n;
}
" .long 0b,__copy_from_user_fixup\n"
".previous"
: "+&d" (n) : "d" (to), "d" (from)
- : "2", "3", "4", "5" );
+ : "cc", "2", "3", "4", "5" );
return n;
}
: "=&a" (len)
: "a" (dst), "d" (src), "d" (count),
"K" (-EFAULT)
- : "2", "3", "4", "memory" );
+ : "2", "3", "4", "memory", "cc" );
return len;
}
#define atomic_eieio() __asm__ __volatile__ ("BCR 15,0")
-#define __CS_LOOP(old, new, ptr, op_val, op_string) \
+#define __CS_LOOP(old_val, new_val, ptr, op_val, op_string) \
__asm__ __volatile__(" l %0,0(%2)\n" \
"0: lr %1,%0\n" \
op_string " %1,%3\n" \
" cs %0,%1,0(%2)\n" \
" jl 0b" \
- : "=&d" (old), "=&d" (new) \
+ : "=&d" (old_val), "=&d" (new_val) \
: "a" (ptr), "d" (op_val) : "cc" );
static __inline__ int atomic_read(atomic_t *v)
static __inline__ void atomic_add(int i, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, i, "ar");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "ar");
}
static __inline__ int atomic_add_return (int i, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, i, "ar");
- return new;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "ar");
+ return new_val;
}
static __inline__ int atomic_add_negative(int i, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, i, "ar");
- return new < 0;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "ar");
+ return new_val < 0;
}
static __inline__ void atomic_sub(int i, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, i, "sr");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, i, "sr");
}
static __inline__ void atomic_inc(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "ar");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "ar");
}
static __inline__ int atomic_inc_return(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "ar");
- return new;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "ar");
+ return new_val;
}
static __inline__ int atomic_inc_and_test(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "ar");
- return new != 0;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "ar");
+ return new_val != 0;
}
static __inline__ void atomic_dec(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "sr");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "sr");
}
static __inline__ int atomic_dec_return(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "sr");
- return new;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "sr");
+ return new_val;
}
static __inline__ int atomic_dec_and_test(volatile atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, 1, "sr");
- return new == 0;
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, 1, "sr");
+ return new_val == 0;
}
static __inline__ void atomic_clear_mask(unsigned long mask, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, ~mask, "nr");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, ~mask, "nr");
}
static __inline__ void atomic_set_mask(unsigned long mask, atomic_t *v)
{
- int old, new;
- __CS_LOOP(old, new, v, mask, "or");
+ int old_val, new_val;
+ __CS_LOOP(old_val, new_val, v, mask, "or");
}
/*
#ifndef __ARCH_S390_CACHE_H
#define __ARCH_S390_CACHE_H
-#define L1_CACHE_BYTES 16
+#define L1_CACHE_BYTES 256
+#define L1_CACHE_SHIFT 16
#endif
*
* Generic channel device initialisation support.
*/
+#ifndef __S390_CHANDEV_H
+#define __S390_CHANDEV_H
#include <linux/version.h>
#include <asm/types.h>
#include <linux/netdevice.h>
+
+/* Setting this flag to true causes a device name to be built based on the read_devno of the device */
+/* this is exported so external code can look at this flags setting */
+extern int chandev_use_devno_names;
+
+
/* chandev_type is a bitmask for registering & describing device types. */
typedef enum
{
- none=0x0,
- ctc=0x1,
- escon=0x2,
- lcs=0x4,
- osad=0x8,
- qeth=0x10,
- claw=0x20,
+ chandev_type_none=0x0,
+ chandev_type_ctc=0x1,
+ chandev_type_escon=0x2,
+ chandev_type_lcs=0x4,
+ chandev_type_osad=0x8,
+ chandev_type_qeth=0x10,
+ chandev_type_claw=0x20,
} chandev_type;
typedef enum
{
- no_category,
- network_device,
- serial_device,
+ chandev_category_none,
+ chandev_category_network_device,
+ chandev_category_serial_device,
} chandev_category;
+
+
+typedef struct
+{
+ int irq;
+ u16 devno;
+ u16 cu_type; /* control unit type */
+ u8 cu_model; /* control unit model */
+ u16 dev_type; /* device type */
+ u8 dev_model; /* device model */
+ u8 pim; /* path installed mask */
+ u8 chpid[8]; /* CHPID 0-7 (if available) */
+} chandev_subchannel_info;
+
+#define CLAW_NAMELEN 9
+/* CLAW specific parameters other drivers should ignore these fields */
+typedef struct
+{
+
+ char host_name[CLAW_NAMELEN]; /* local host name */
+ char adapter_name[CLAW_NAMELEN]; /* workstation adapter name */
+ char api_type[CLAW_NAMELEN]; /* API type either TCPIP or API */
+} chandev_claw_info;
+
/*
* The chandev_probeinfo structure is passed to the device driver with configuration
* info for which irq's & ports to use when attempting to probe the device.
*/
typedef struct
{
- int read_irq;
- int write_irq;
- u16 read_devno;
- u16 write_devno;
- s16 port_protocol_no; /* -1 don't care */
+ chandev_subchannel_info read;
+ chandev_subchannel_info write;
+ chandev_subchannel_info data;
+ /* memory_usage_in_k is the suggested memory the driver should attempt to use for io */
+ /* buffers -1 means use the driver default the driver should set this field to the */
+ /* amount of memory it actually uses when returning this probeinfo to the channel */
+ /* device layer with chandev_initdevice */
+ s32 memory_usage_in_k;
+ chandev_claw_info claw;
+ u8 data_exists; /* whether this device has a data channel */
+ u8 cu_dev_info_inconsistent; /* either ctc or we possibly had a bad sense_id */
+ u8 chpid_info_inconsistent; /* either ctc or schib info bad */
+ s16 port_protocol_no; /* 0 by default, set specifically when forcing */
u8 hint_port_no; /* lcs specific */
- u8 max_port_no; /* lcs specific */
+ u8 max_port_no; /* lcs/qeth specific */
chandev_type chan_type;
u8 checksum_received_ip_pkts;
u8 use_hw_stats; /* where available e.g. lcs */
- u16 cu_type; /* control unit type */
- u8 cu_model; /* control unit model */
- u16 dev_type; /* device type */
- u8 dev_model; /* device model */
+ u8 device_forced; /* indicates the device hasn't been autodetected */
char *parmstr; /* driver specific parameters added by add_parms keyword */
/* newdevice used internally by chandev.c */
struct chandev_activelist *newdevice;
typedef enum
{
- good=0,
- not_oper,
- first_msck=not_oper,
- no_path,
- revalidate,
- gone,
- last_msck,
+ chandev_status_good,
+ chandev_status_not_oper,
+ chandev_status_first_msck=chandev_status_not_oper,
+ chandev_status_no_path,
+ chandev_status_revalidate,
+ chandev_status_gone,
+ chandev_status_last_msck,
+ chandev_status_all_chans_good /* pseudo machine check to indicate all channels are healthy */
} chandev_msck_status;
typedef int (*chandev_probefunc)(chandev_probeinfo *probeinfo);
-typedef void (*chandev_shutdownfunc)(void *device);
+typedef int (*chandev_shutdownfunc)(void *device);
typedef void (*chandev_unregfunc)(void *device);
-typedef void (*chandev_reoperfunc)(void *device,int msck_for_read_chan,chandev_msck_status prevstatus);
+typedef void (*chandev_msck_notification_func)(void *device,int msck_irq,
+chandev_msck_status prevstatus,chandev_msck_status newstatus);
*/
int chandev_register_and_probe(chandev_probefunc probefunc,
chandev_shutdownfunc shutdownfunc,
- chandev_reoperfunc reoperfunc,
+ chandev_msck_notification_func msck_notfunc,
chandev_type chan_type);
/* The chandev_unregister function is typically called when a module is being removed
int chandev_initdevice(chandev_probeinfo *probeinfo,void *dev_ptr,u8 port_no,char *devname,
chandev_category category,chandev_unregfunc unreg_dev);
+/* This function builds a device name & copies it into destnamebuff suitable for calling
+ init_trdev or whatever & it honours the use_devno_names flag, it is used by chandev_initnetdevice
+ setting the buildfullname flag to TRUE will cause it to always build a full unique name based
+ on basename either honouring the chandev_use_devno_names flag if set or starting at index
+ 0 & checking the namespace of the channel device layer itself for a free index, this
+ may be useful when one doesn't have control of the name an upper layer may choose.
+ It returns NULL on error.
+*/
+char *chandev_build_device_name(chandev_probeinfo *probeinfo,char *destnamebuff,char *basename,int buildfullname);
+
+
+
+
+/* chandev_init_netdev registers with the normal network device layer */
+/* it doesn't update any of the chandev internal structures. */
+/* i.e. it is optional */
+/* it was part of chandev_initnetdevice but I separated it as */
+/* chandev_initnetdevice may make too many assumptions for some users */
+/* chandev_initnetdevice = chandev_initdevice followed by chandev_init_netdev */
+#if LINUX_VERSION_CODE>=KERNEL_VERSION(2,3,0)
+struct net_device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct net_device *dev, int sizeof_priv,struct net_device *(*init_netdevfunc)(struct net_device *dev, int sizeof_priv));
+#else
+struct device *chandev_init_netdev(chandev_probeinfo *probeinfo,char *basename,
+struct device *dev, int sizeof_priv,struct device *(*init_netdevfunc)(struct device *dev, int sizeof_priv));
+#endif
+
/* chandev_initnetdevice registers a network device with the channel layer.
* It returns the device structure if successful,if dev=NULL it kmallocs it,
* On device initialisation failure it will kfree it under ALL curcumstances
void (*unreg_netdevfunc)(struct device *dev));
#endif
-
-
+/* chandev_add & delete model shouldn't normally be needed by drivers except if */
+/* someone is developing a driver which the channel device layer doesn't know about */
+void chandev_add_model(chandev_type chan_type,s32 cu_type,s16 cu_model,
+ s32 dev_type,s16 dev_model,u8 max_port_no,int auto_msck_recovery,
+ u8 default_checksum_received_ip_pkts,u8 default_use_hw_stats);
+void chandev_del_model(s32 cu_type,s16 cu_model,s32 dev_type,s16 dev_model);
+
+/* modules should use chandev_persist to see if they should stay loaded */
+/* this is useful for debugging purposes where you may wish to examine */
+/* /proc/s390dbf/ entries */
+int chandev_persist(chandev_type chan_type);
+#endif /* __S390_CHANDEV_H */
*
* here even more important to align src and dst on a 32-bit (or even
* better 64-bit) boundary
+ *
+ * Copy from userspace and compute checksum. If we catch an exception
+ * then zero the rest of the buffer.
*/
-
extern inline unsigned int
-csum_partial_copy_from_user(const char *src, char *dst,
- int len, unsigned int sum, int *errp)
+csum_partial_copy_from_user (const char *src, char *dst,
+ int len, unsigned int sum,
+ int *err_ptr)
{
- if (copy_from_user(dst, src, len)) {
- *errp = -EFAULT;
- memset(dst, 0, len);
- return sum;
- }
- return csum_partial_inline(dst, len, sum);
+ int missing;
+
+ missing = copy_from_user(dst, src, len);
+ if (missing) {
+ memset(dst + len - missing, 0, missing);
+ *err_ptr = -EFAULT;
+ }
+
+ return csum_partial(dst, len, sum);
}
extern inline unsigned int
struct task_struct *current;
__asm__("lghi %0,-16384\n\t"
"ngr %0,15"
- : "=&r" (current) );
+ : "=&r" (current) : : "cc" );
return current;
}
int dasd_oper_handler (int irq, devreg_t * devreg);
void dasd_schedule_bh (dasd_device_t *);
-debug_info_t *dasd_debug_area;
-
#endif /* __KERNEL__ */
#endif /* DASD_H */
#define DEBUG_DATA(entry) (char*)(entry + 1) /* data is stored behind */
/* the entry information */
-#define STCK(x) asm volatile ("STCK %0":"=m" (x))
+#define STCK(x) asm volatile ("STCK %0" : "=m" (x) : : "cc" )
typedef struct __debug_entry debug_entry_t;
#include <asm/lowcore.h>
#include <linux/sched.h>
-/* No irq_cpustat_t for s390, the data is held directly in S390_lowcore */
+/* entry.S is sensitive to the offsets of these fields */
+typedef struct {
+ unsigned int __softirq_pending;
+ unsigned int __local_irq_count;
+ unsigned int __local_bh_count;
+ unsigned int __syscall_count;
+ struct task_struct * __ksoftirqd_task; /* waitqueue is too large */
+} ____cacheline_aligned irq_cpustat_t;
-/*
- * Simple wrappers reducing source bloat. S390 specific because each
- * cpu stores its data in S390_lowcore (PSA) instead of using a cache
- * aligned array element like most architectures.
- */
-
-#ifdef CONFIG_SMP
-
-#define softirq_active(cpu) (safe_get_cpu_lowcore(cpu).__softirq_active)
-#define softirq_mask(cpu) (safe_get_cpu_lowcore(cpu).__softirq_mask)
-#define local_irq_count(cpu) (safe_get_cpu_lowcore(cpu).__local_irq_count)
-#define local_bh_count(cpu) (safe_get_cpu_lowcore(cpu).__local_bh_count)
-#define syscall_count(cpu) (safe_get_cpu_lowcore(cpu).__syscall_count)
-
-#else /* CONFIG_SMP */
-
-/* Optimize away the cpu calculation, it is always current PSA */
-#define softirq_active(cpu) ((void)(cpu), S390_lowcore.__softirq_active)
-#define softirq_mask(cpu) ((void)(cpu), S390_lowcore.__softirq_mask)
-#define local_irq_count(cpu) ((void)(cpu), S390_lowcore.__local_irq_count)
-#define local_bh_count(cpu) ((void)(cpu), S390_lowcore.__local_bh_count)
-#define syscall_count(cpu) ((void)(cpu), S390_lowcore.__syscall_count)
-
-#endif /* CONFIG_SMP */
+#include <linux/irq_cpustat.h> /* Standard mappings for irq_cpustat_t above */
/*
* Are we in an interrupt context? Either doing bottom half
* or hardware interrupt processing?
- * Special definitions for s390, always access current PSA.
*/
-#define in_interrupt() ((S390_lowcore.__local_irq_count + S390_lowcore.__local_bh_count) != 0)
-
-#define in_irq() (S390_lowcore.__local_irq_count != 0)
-
+#define in_interrupt() ({ int __cpu = smp_processor_id(); \
+ (local_irq_count(__cpu) + local_bh_count(__cpu) != 0); })
+
+#define in_irq() (local_irq_count(smp_processor_id()) != 0)
+
#ifndef CONFIG_SMP
#define hardirq_trylock(cpu) (local_irq_count(cpu) == 0)
#include <linux/config.h>
#include <asm/irq.h>
-typedef unsigned long idaw_t;
+#define IDA_SIZE_LOG 12 /* 11 for 2k , 12 for 4k */
+#define IDA_BLOCK_SIZE (1L<<IDA_SIZE_LOG)
-static inline idaw_t *
+static inline addr_t *
idal_alloc ( int nridaws )
{
if ( nridaws > 33 )
BUG();
- return kmalloc(nridaws * sizeof(idaw_t), GFP_ATOMIC | GFP_DMA );
+ return kmalloc(nridaws * sizeof(addr_t), GFP_ATOMIC | GFP_DMA );
}
static inline void
-idal_free ( idaw_t *idal )
+idal_free ( addr_t *idal )
{
kfree (idal);
}
+#if defined(CONFIG_ARCH_S390X)
+extern unsigned long __create_idal(unsigned long address, int count);
+#endif
+
/*
* Function: set_normalized_cda
* sets the address of the data in CCW
* if necessary it allocates an IDAL and sets sthe appropriate flags
*/
-#if defined (CONFIG_ARCH_S390X)
-extern void set_normalized_cda(ccw1_t * ccw, unsigned long address);
-#else
-static inline void
+static inline int
set_normalized_cda(ccw1_t * ccw, unsigned long address)
{
- ccw->cda = address;
-}
+ int ret = 0;
+
+#if defined (CONFIG_ARCH_S390X)
+ if (((address + ccw->count) >> 31) != 0) {
+ if (ccw->flags & CCW_FLAG_IDA)
+ BUG();
+ address = __create_idal(address, ccw->count);
+ if (address)
+ ccw->flags |= CCW_FLAG_IDA;
+ else
+ ret = -ENOMEM;
+ }
#endif
+ ccw->cda = (__u32) address;
+ return ret;
+}
/*
* Function: clear_normalized_cda
static inline void
clear_normalized_cda ( ccw1_t * ccw )
{
+#if defined(CONFIG_ARCH_S390X)
if ( ccw -> flags & CCW_FLAG_IDA ) {
- idal_free ( (idaw_t *)(unsigned long) (ccw -> cda ));
+ idal_free ( (addr_t *)(unsigned long) (ccw -> cda ));
ccw -> flags &= ~CCW_FLAG_IDA;
}
+#endif
ccw -> cda = 0;
}
#define __INITDATA .section ".data.init",#alloc,#write
*/
-#define __cacheline_aligned __attribute__ ((__aligned__(16)))
+#define __cacheline_aligned __attribute__ ((__aligned__(256)))
#endif
" jz 0f\n"
" slgr %0,%0\n"
"0:"
- : "=a" (real_address) : "a" (address) );
+ : "=a" (real_address) : "a" (address) : "cc" );
return real_address;
}
extern int set_cons_dev(int irq);
extern int reset_cons_dev(int irq);
extern int wait_cons_dev(int irq);
+extern schib_t *s390_get_schib( int irq );
+
+extern int s390_register_adapter_interrupt(adapter_int_handler_t handler);
+extern int s390_unregister_adapter_interrupt(adapter_int_handler_t handler);
/*
* Some S390 specific IO instructions as inline
#define __LC_MCCK_CODE 0x0E8
#define __LC_SAVE_AREA 0xC00
-#define __LC_CREGS_SAVE_AREA 0xC80
-#define __LC_AREGS_SAVE_AREA 0xD00
#define __LC_KERNEL_STACK 0xD40
#define __LC_KERNEL_LEVEL 0xD48
-#define __LC_IRQ_STAT 0xD50
#define __LC_CPUID 0xD90
#define __LC_CPUADDR 0xD98
#define __LC_IPLDEV 0xDB8
#define __LC_PANIC_MAGIC 0xE00
+#define __LC_AREGS_SAVE_AREA 0x1340
+#define __LC_CREGS_SAVE_AREA 0x1380
+
+#define __LC_PFAULT_INTPARM 0x11B8
/* interrupt handler start with all io, external and mcck interrupt disabled */
__u8 pad8[0xc00-0x214]; /* 0x214 */
/* System info area */
__u64 save_area[16]; /* 0xc00 */
- __u64 cregs_save_area[16]; /* 0xc80 */
- __u32 access_regs_save_area[16];/* 0xd00 */
+ __u8 pad9[0xd40-0xc80]; /* 0xc80 */
__u64 kernel_stack; /* 0xd40 */
__u64 kernel_level; /* 0xd48 */
/* entry.S sensitive area start */
- /* Next 6 words are the s390 equivalent of irq_stat */
- __u32 __softirq_active; /* 0xd50 */
- __u32 __softirq_mask; /* 0xd54 */
- __u32 __local_irq_count; /* 0xd58 */
- __u32 __local_bh_count; /* 0xd5c */
- __u32 __syscall_count; /* 0xd60 */
- __u8 pad10[0xd80-0xd64]; /* 0xd64 */
+ __u8 pad10[0xd80-0xd50]; /* 0xd64 */
struct cpuinfo_S390 cpu_data; /* 0xd80 */
__u32 ipl_device; /* 0xdb8 */
- __u32 pad13; /* 0xdbc was lsw word of ipl_device until a bug was found DJB */
+ __u32 pad11; /* 0xdbc was lsw word of ipl_device until a bug was found DJB */
/* entry.S sensitive area end */
/* SMP info area: defined by DJB */
__u64 ext_call_queue; /* 0xdd0 */
__u64 ext_call_count; /* 0xdd8 */
- __u8 pad11[0xe00-0xde0]; /* 0xde0 */
+ __u8 pad12[0xe00-0xde0]; /* 0xde0 */
/* 0xe00 is used as indicator for dump tools */
/* whether the kernel died with panic() or not */
__u32 panic_magic; /* 0xe00 */
- /* Align to the top 1k of prefix area */
- __u8 pad12[0x1000-0xe04]; /* 0xe04 */
+ __u8 pad13[0x1200-0xe04]; /* 0xe04 */
+
+ /* System info area */
+
+ __u64 floating_pt_save_area[16]; /* 0x1200 */
+ __u64 gpregs_save_area[16]; /* 0x1280 */
+ __u32 st_status_fixed_logout[4]; /* 0x1300 */
+ __u8 pad14[0x1318-0x1310]; /* 0x1310 */
+ __u32 prefixreg_save_area; /* 0x1318 */
+ __u32 fpt_creg_save_area; /* 0x131c */
+ __u8 pad15[0x1324-0x1320]; /* 0x1320 */
+ __u32 tod_progreg_save_area; /* 0x1324 */
+ __u32 cpu_timer_save_area[2]; /* 0x1328 */
+ __u32 clock_comp_save_area[2]; /* 0x1330 */
+ __u8 pad16[0x1340-0x1338]; /* 0x1338 */
+ __u32 access_regs_save_area[16]; /* 0x1340 */
+ __u64 cregs_save_area[16]; /* 0x1380 */
+
+ /* align to the top of the prefix area */
+
+ __u8 pad17[0x2000-0x1400]; /* 0x1400 */
} __attribute__((packed)); /* End structure*/
extern __inline__ void set_prefix(__u32 address)
" slgr 1,1\n"
" mvcl 2,0"
: : "a" ((void *) (page))
- : "memory", "1", "2", "3" );
+ : "memory", "cc", "1", "2", "3" );
}
static inline void copy_page(void *to, void *from)
asm volatile (" sgr 0,0\n"
" mvpg %0,%1"
: : "a" ((void *)(to)), "a" ((void *)(from))
- : "memory", "0" );
+ : "memory", "cc", "0" );
else
asm volatile (" mvc 0(256,%0),0(%1)\n"
" mvc 256(256,%0),256(%1)\n"
--- /dev/null
+#ifndef __ASM_S390_PCI_H
+#define __ASM_S390_PCI_H
+
+/* S/390 systems don't have a PCI bus. This file is just here because some stupid .c code
+ * includes it even if CONFIG_PCI is not set.
+ */
+
+#endif /* __ASM_S390_PCI_H */
+
" slr 2,2\n"
" slr 3,3\n"
" csp 2,4"
- : : "a" (&dummy) : "2", "3", "4" );
+ : : "a" (&dummy) : "cc", "2", "3", "4" );
}
/*
*/
#define _REGION_THIRD 0x4
#define _REGION_THIRD_LEN 0x3
-#define _REGION_TABLE (_REGION_THIRD|_REGION_THIRD_LEN)
+#define _REGION_TABLE (_REGION_THIRD|_REGION_THIRD_LEN|0x40)
/* Bits in the storage key */
#define _PAGE_CHANGED 0x02 /* HW changed bit */
extern inline pte_t pte_mkold(pte_t pte)
{
- asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)));
+ asm volatile ("rrbe 0,%0" : : "a" (pte_val(pte)) : "cc" );
return pte;
}
asm volatile ("rrbe 0,%1\n\t"
"ipm %0\n\t"
- "srl %0,28\n\t" : "=d" (ccode) : "a" (pte_val(*ptep)));
+ "srl %0,28\n\t"
+ : "=d" (ccode) : "a" (pte_val(*ptep)) : "cc" );
return ccode & 2;
}
__u32 error_code; /* error-code of last prog-excep. */
__u32 trap_no;
per_struct per_info;/* Must be aligned on an 4 byte boundary*/
- addr_t ieee_instruction_pointer;
/* Used to give failing instruction back to user for ieee exceptions */
+ addr_t ieee_instruction_pointer;
unsigned long flags; /* various flags */
+ /* pfault_wait is used to block the process on a pfault event */
+ addr_t pfault_wait;
};
typedef struct thread_struct thread_struct;
(__pa((addr_t) &swapper_pg_dir[0]) + _REGION_TABLE),\
0,0,0, \
(per_struct) {{{{0,}}},0,0,0,0,{{0,}}}, \
- 0 \
+ 0, 0, 0 \
}
/* need to define ... */
" stctg 0,15,0x380(1)\n" /* store control registers */
" oi 0x384(1),0x10\n" /* fake protection bit */
" lpswe 0(%0)"
- : : "a" (dw_psw), "a" (&ctl_buf) : "0", "1");
+ : : "a" (dw_psw), "a" (&ctl_buf) : "cc", "0", "1");
}
#endif /* __ASM_S390_PROCESSOR_H */
*
* A little set of queue utilies.
*/
-
+#ifndef __ASM_QUEUE_H
+#define __ASM_QUEUE_H
#include <linux/stddef.h>
typedef struct queue
}
static __inline__ void enqueue_tail(qheader *qhead,queue *member)
-{
- queue *tail=qhead->tail;
- member->next=NULL;
-
+{
if(member)
{
+ queue *tail=qhead->tail;
+
if(tail)
tail->next=member;
else
return(0);
}
-
+#endif /* __ASM_QUEUE_H */
oper_handler_func_t oper_func;
} devreg_t;
-#define DEVREG_EXACT_MATCH 0x00000001
-#define DEVREG_MATCH_DEV_TYPE 0x00000002
-#define DEVREG_MATCH_CU_TYPE 0x00000004
-#define DEVREG_NO_CU_INFO 0x00000008
-#define DEVREG_NO_DEV_INFO 0x00000010
+#define DEVREG_MATCH_CU_TYPE 0x00000001
+#define DEVREG_MATCH_CU_MODEL 0x00000002
+#define DEVREG_MATCH_DEV_TYPE 0x00000004
+#define DEVREG_MATCH_DEV_MODEL 0x00000008
+
+#define DEVREG_EXACT_MATCH (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL|DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_CU_INFO (DEVREG_MATCH_DEV_TYPE|DEVREG_MATCH_DEV_MODEL)
+#define DEVREG_NO_DEV_INFO (DEVREG_MATCH_CU_TYPE|DEVREG_MATCH_CU_MODEL)
#define DEVREG_TYPE_DEVNO 0x80000000
#define DEVREG_TYPE_DEVCHARS 0x40000000
#define MACHINE_IS_P390 (machine_flags & 4)
#define MACHINE_HAS_MVPG (machine_flags & 16)
+#define MACHINE_HAS_HWC (!MACHINE_IS_P390)
+
+/*
+ * Console mode. Override with conmode=
+ */
+extern unsigned int console_mode;
+extern unsigned int console_device;
+
+#define CONSOLE_IS_UNDEFINED (console_mode == 0)
+#define CONSOLE_IS_HWC (console_mode == 1)
+#define CONSOLE_IS_3215 (console_mode == 2)
+#define CONSOLE_IS_3270 (console_mode == 3)
+#define SET_CONSOLE_HWC do { console_mode = 1; } while (0)
+#define SET_CONSOLE_3215 do { console_mode = 2; } while (0)
+#define SET_CONSOLE_3270 do { console_mode = 3; } while (0)
+
#else
#define IPL_DEVICE 0x10400
__sighandler_t _sa_handler;
void (*_sa_sigaction)(int, struct siginfo *, void *);
} _u;
- sigset_t sa_mask;
unsigned long sa_flags;
void (*sa_restorer)(void);
+ sigset_t sa_mask;
};
#define sa_handler _u._sa_handler
#include <asm/hardirq.h>
#include <asm/lowcore.h>
-#define cpu_bh_disable(cpu) do { local_bh_count(cpu)++; barrier(); } while (0)
-#define cpu_bh_enable(cpu) do { barrier(); local_bh_count(cpu)--; } while (0)
-
-#define local_bh_disable() cpu_bh_disable(smp_processor_id())
-#define local_bh_enable() cpu_bh_enable(smp_processor_id())
+#define local_bh_disable() \
+do { \
+ local_bh_count(smp_processor_id())++; \
+ barrier(); \
+} while (0)
+
+#define __local_bh_enable() \
+do { \
+ barrier(); \
+ local_bh_count(smp_processor_id())--; \
+} while (0)
+
+#define local_bh_enable() \
+do { \
+ if (!--local_bh_count(smp_processor_id()) \
+ && softirq_pending(smp_processor_id())) { \
+ do_softirq(); \
+ __sti(); \
+ } \
+} while (0)
+
+#define __cpu_raise_softirq(cpu, nr) (softirq_pending(cpu) |= (1<<nr))
#define in_softirq() (local_bh_count(smp_processor_id()) != 0)
" jl 1b\n"
" ex 0,4(2)" /* store *ptr to x */
: "+&a" (ptr) : "a" (&x)
- : "memory", "0", "1", "2");
+ : "memory", "cc", "0", "1", "2");
break;
case 2:
if(((addr_t)ptr)&1)
" jl 1b\n"
" ex 0,4(2)" /* store *ptr to x */
: "+&a" (ptr) : "a" (&x)
- : "memory", "0", "1", "2");
+ : "memory", "cc", "0", "1", "2");
break;
case 4:
if(((addr_t)ptr)&3)
" jl 0b\n"
" lgfr %0,0\n"
: "+d" (x) : "a" (ptr)
- : "memory", "0" );
+ : "memory", "cc", "0" );
break;
case 8:
if(((addr_t)ptr)&7)
" jl 0b\n"
" lgr %0,0\n"
: "+d" (x) : "a" (ptr)
- : "memory", "0" );
+ : "memory", "cc", "0" );
break;
default:
abort();
__asm__ __volatile__("ssm %0" : : "m" (x) : "memory")
#define __load_psw(psw) \
- __asm__ __volatile__("lpswe %0" : : "m" (psw));
+ __asm__ __volatile__("lpswe %0" : : "m" (psw) : "cc" );
#define __ctl_load(array, low, high) ({ \
__asm__ __volatile__ ( \
" stg 0,0(1)\n" \
"1: ex %1,6(2)" /* execute lctl */ \
: "=m" (dummy) : "a" (cr*17), "a" (1L<<(bit)) \
- : "0", "1", "2"); \
+ : "cc", "0", "1", "2"); \
})
#define __ctl_clear_bit(cr, bit) ({ \
" stg 0,0(1)\n" \
"1: ex %1,6(2)" /* execute lctl */ \
: "=m" (dummy) : "a" (cr*17), "a" (~(1L<<(bit))) \
- : "0", "1", "2"); \
+ : "cc", "0", "1", "2"); \
})
/* For spinlocks etc */
#define N_IRDA 11 /* Linux IR - http://irda.sourceforge.net/ */
#define N_SMSBLOCK 12 /* SMS block mode - for talking to GSM data cards about SMS messages */
#define N_HDLC 13 /* synchronous HDLC */
-#define N_BT 15 /* bluetooth */
+#define N_HCI 15 /* Bluetooth HCI UART */
#ifdef __KERNEL__
".previous"
: "=m" (*((__u64*) ptr)) , "=&d" (err)
: "d" (x), "K" (-EFAULT)
- : "4" );
+ : "cc", "4" );
return err;
}
extern inline int __put_user_asm_4(__u32 x, void *ptr)
".previous"
: "=m" (*((__u32*) ptr)) , "=&d" (err)
: "d" (x), "K" (-EFAULT)
- : "4" );
+ : "cc", "4" );
return err;
}
".previous"
: "=m" (*((__u16*) ptr)) , "=&d" (err)
: "d" (x), "K" (-EFAULT)
- : "4" );
+ : "cc", "4" );
return err;
}
".previous"
: "=m" (*((__u8*) ptr)) , "=&d" (err)
: "d" (x), "K" (-EFAULT)
- : "1", "4" );
+ : "cc", "1", "4" );
return err;
}
".previous" \
: "=d" (x) , "=&d" (err) \
: "m" (*(const __u64*)(ptr)),"K" (-EFAULT) \
- : "4" ); \
+ : "cc", "4" ); \
})
#define __get_user_asm_4(x, ptr, err) \
({ \
".previous" \
: "=d" (x) , "=&d" (err) \
: "m" (*(const __u32*)(ptr)),"K" (-EFAULT) \
- : "4" ); \
+ : "cc", "4" ); \
})
#define __get_user_asm_2(x, ptr, err) \
".previous" \
: "=d" (x) , "=&d" (err) \
: "m" (*(const __u16*)(ptr)),"K" (-EFAULT) \
- : "4" ); \
+ : "cc", "4" ); \
})
#define __get_user_asm_1(x, ptr, err) \
".previous" \
: "=d" (x) , "=&d" (err) \
: "m" (*(const __u8*)(ptr)),"K" (-EFAULT) \
- : "4" ); \
+ : "cc", "4" ); \
})
#define __get_user(x, ptr) \
" .quad 0b,__copy_to_user_fixup\n"
".previous"
: "+&d" (n) : "d" (to), "d" (from)
- : "1", "2", "3", "4", "5" );
+ : "cc", "1", "2", "3", "4", "5" );
return n;
}
" .quad 0b,__copy_from_user_fixup\n"
".previous"
: "+&d" (n) : "d" (to), "d" (from)
- : "1", "2", "3", "4", "5" );
+ : "cc", "1", "2", "3", "4", "5" );
return n;
}
: "=&a" (len)
: "a" (dst), "d" (src), "d" (count),
"K" (-EFAULT)
- : "2" ,"3", "4" );
+ : "cc", "2" ,"3", "4" );
return len;
}
#define __NR_mincore 218
#define __NR_madvise 219
#define __NR_getdents64 220
-#define __NR_fcntl64 221
/* user-visible error numbers are in the range -1 - -122: see <asm-s390/errno.h> */
#endif /* OPTIMIZE */
-extern __inline__ __const__ __u16 __fswab16(__u16 x)
+static __inline__ __const__ __u16 __fswab16(__u16 x)
{
return __arch__swab16(x);
}
-extern __inline__ __u16 __swab16p(__u16 *x)
+static __inline__ __u16 __swab16p(__u16 *x)
{
return __arch__swab16p(x);
}
-extern __inline__ void __swab16s(__u16 *addr)
+static __inline__ void __swab16s(__u16 *addr)
{
__arch__swab16s(addr);
}
-extern __inline__ __const__ __u32 __fswab32(__u32 x)
+static __inline__ __const__ __u32 __fswab32(__u32 x)
{
return __arch__swab32(x);
}
-extern __inline__ __u32 __swab32p(__u32 *x)
+static __inline__ __u32 __swab32p(__u32 *x)
{
return __arch__swab32p(x);
}
-extern __inline__ void __swab32s(__u32 *addr)
+static __inline__ void __swab32s(__u32 *addr)
{
__arch__swab32s(addr);
}
#ifdef __BYTEORDER_HAS_U64__
-extern __inline__ __const__ __u64 __fswab64(__u64 x)
+static __inline__ __const__ __u64 __fswab64(__u64 x)
{
# ifdef __SWAB_64_THRU_32__
__u32 h = x >> 32;
return __arch__swab64(x);
# endif
}
-extern __inline__ __u64 __swab64p(__u64 *x)
+static __inline__ __u64 __swab64p(__u64 *x)
{
return __arch__swab64p(x);
}
-extern __inline__ void __swab64s(__u64 *addr)
+static __inline__ void __swab64s(__u64 *addr)
{
__arch__swab64s(addr);
}
#endif /* OPTIMIZE */
-extern __inline__ __const__ __u32 __fswahw32(__u32 x)
+static __inline__ __const__ __u32 __fswahw32(__u32 x)
{
return __arch__swahw32(x);
}
-extern __inline__ __u32 __swahw32p(__u32 *x)
+static __inline__ __u32 __swahw32p(__u32 *x)
{
return __arch__swahw32p(x);
}
-extern __inline__ void __swahw32s(__u32 *addr)
+static __inline__ void __swahw32s(__u32 *addr)
{
__arch__swahw32s(addr);
}
-extern __inline__ __const__ __u32 __fswahb32(__u32 x)
+static __inline__ __const__ __u32 __fswahb32(__u32 x)
{
return __arch__swahb32(x);
}
-extern __inline__ __u32 __swahb32p(__u32 *x)
+static __inline__ __u32 __swahb32p(__u32 *x)
{
return __arch__swahb32p(x);
}
-extern __inline__ void __swahb32s(__u32 *addr)
+static __inline__ void __swahb32s(__u32 *addr)
{
__arch__swahb32s(addr);
}
return 0;
}
-extern inline int get_lease(struct inode *inode, unsigned int mode)
+static inline int get_lease(struct inode *inode, unsigned int mode)
{
if (inode->i_flock && (inode->i_flock->fl_flags & FL_LEASE))
return __get_lease(inode, mode);
void hdlc_netif_rx(hdlc_device *hdlc, struct sk_buff *skb);
-extern __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
+static __inline__ struct net_device* hdlc_to_dev(hdlc_device *hdlc)
{
return &hdlc->netdev;
}
-extern __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
+static __inline__ hdlc_device* dev_to_hdlc(struct net_device *dev)
{
return (hdlc_device*)dev;
}
-extern __inline__ struct net_device* pvc_to_dev(pvc_device *pvc)
+static __inline__ struct net_device* pvc_to_dev(pvc_device *pvc)
{
return &pvc->netdev;
}
-extern __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
+static __inline__ pvc_device* dev_to_pvc(struct net_device *dev)
{
return (pvc_device*)dev;
}
-extern __inline__ const char *hdlc_to_name(hdlc_device *hdlc)
+static __inline__ const char *hdlc_to_name(hdlc_device *hdlc)
{
return hdlc_to_dev(hdlc)->name;
}
-extern __inline__ const char *pvc_to_name(pvc_device *pvc)
+static __inline__ const char *pvc_to_name(pvc_device *pvc)
{
return pvc_to_dev(pvc)->name;
}
-extern __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
+static __inline__ u16 status_to_dlci(hdlc_device *hdlc, u8 *status, u8 *state)
{
*state &= ~(PVC_STATE_ACTIVE | PVC_STATE_NEW);
if (status[2] & 0x08)
}
-extern __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
+static __inline__ void dlci_to_status(hdlc_device *hdlc, u16 dlci, u8 *status,
u8 state)
{
status[0] = (dlci>>4) & 0x3F;
-extern __inline__ u16 netdev_dlci(struct net_device *dev)
+static __inline__ u16 netdev_dlci(struct net_device *dev)
{
return ntohs(*(u16*)dev->dev_addr);
}
-extern __inline__ u16 q922_to_dlci(u8 *hdr)
+static __inline__ u16 q922_to_dlci(u8 *hdr)
{
return ((hdr[0] & 0xFC)<<2) | ((hdr[1] & 0xF0)>>4);
}
-extern __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
+static __inline__ void dlci_to_q922(u8 *hdr, u16 dlci)
{
hdr[0] = (dlci>>2) & 0xFC;
hdr[1] = ((dlci<<4) & 0xF0) | 0x01;
-extern __inline__ int mode_is(hdlc_device *hdlc, int mask)
+static __inline__ int mode_is(hdlc_device *hdlc, int mask)
{
return (hdlc->mode & mask) == mask;
}
-extern __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
+static __inline__ pvc_device* find_pvc(hdlc_device *hdlc, u16 dlci)
{
pvc_device *pvc=hdlc->first_pvc;
-extern __inline__ void debug_frame(const struct sk_buff *skb)
+static __inline__ void debug_frame(const struct sk_buff *skb)
{
int i;
#include <sys/ioctl.h>
-extern inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
+static inline __s32 i2c_smbus_access(int file, char read_write, __u8 command,
int size, union i2c_smbus_data *data)
{
struct i2c_smbus_ioctl_data args;
}
-extern inline __s32 i2c_smbus_write_quick(int file, __u8 value)
+static inline __s32 i2c_smbus_write_quick(int file, __u8 value)
{
return i2c_smbus_access(file,value,0,I2C_SMBUS_QUICK,NULL);
}
-extern inline __s32 i2c_smbus_read_byte(int file)
+static inline __s32 i2c_smbus_read_byte(int file)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,0,I2C_SMBUS_BYTE,&data))
return 0x0FF & data.byte;
}
-extern inline __s32 i2c_smbus_write_byte(int file, __u8 value)
+static inline __s32 i2c_smbus_write_byte(int file, __u8 value)
{
return i2c_smbus_access(file,I2C_SMBUS_WRITE,value,
I2C_SMBUS_BYTE,NULL);
}
-extern inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
+static inline __s32 i2c_smbus_read_byte_data(int file, __u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
return 0x0FF & data.byte;
}
-extern inline __s32 i2c_smbus_write_byte_data(int file, __u8 command,
+static inline __s32 i2c_smbus_write_byte_data(int file, __u8 command,
__u8 value)
{
union i2c_smbus_data data;
I2C_SMBUS_BYTE_DATA, &data);
}
-extern inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
+static inline __s32 i2c_smbus_read_word_data(int file, __u8 command)
{
union i2c_smbus_data data;
if (i2c_smbus_access(file,I2C_SMBUS_READ,command,
return 0x0FFFF & data.word;
}
-extern inline __s32 i2c_smbus_write_word_data(int file, __u8 command,
+static inline __s32 i2c_smbus_write_word_data(int file, __u8 command,
__u16 value)
{
union i2c_smbus_data data;
I2C_SMBUS_WORD_DATA, &data);
}
-extern inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
+static inline __s32 i2c_smbus_process_call(int file, __u8 command, __u16 value)
{
union i2c_smbus_data data;
data.word = value;
/* Returns the number of read bytes */
-extern inline __s32 i2c_smbus_read_block_data(int file, __u8 command,
+static inline __s32 i2c_smbus_read_block_data(int file, __u8 command,
__u8 *values)
{
union i2c_smbus_data data;
}
}
-extern inline __s32 i2c_smbus_write_block_data(int file, __u8 command,
+static inline __s32 i2c_smbus_write_block_data(int file, __u8 command,
__u8 length, __u8 *values)
{
union i2c_smbus_data data;
I2C_SMBUS_BLOCK_DATA, &data);
}
-extern inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
+static inline __s32 i2c_smbus_write_i2c_block_data(int file, __u8 command,
__u8 length, __u8 *values)
{
union i2c_smbus_data data;
/*
* Messenger inlines
*/
-extern inline u32 I2O_POST_READ32(struct i2o_controller *c)
+static inline u32 I2O_POST_READ32(struct i2o_controller *c)
{
return *c->post_port;
}
-extern inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 Val)
+static inline void I2O_POST_WRITE32(struct i2o_controller *c, u32 Val)
{
*c->post_port = Val;
}
-extern inline u32 I2O_REPLY_READ32(struct i2o_controller *c)
+static inline u32 I2O_REPLY_READ32(struct i2o_controller *c)
{
return *c->reply_port;
}
-extern inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 Val)
+static inline void I2O_REPLY_WRITE32(struct i2o_controller *c, u32 Val)
{
*c->reply_port= Val;
}
-extern inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
+static inline u32 I2O_IRQ_READ32(struct i2o_controller *c)
{
return *c->irq_mask;
}
-extern inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 Val)
+static inline void I2O_IRQ_WRITE32(struct i2o_controller *c, u32 Val)
{
*c->irq_mask = Val;
}
-extern inline void i2o_post_message(struct i2o_controller *c, u32 m)
+static inline void i2o_post_message(struct i2o_controller *c, u32 m)
{
/* The second line isnt spurious - thats forcing PCI posting */
I2O_POST_WRITE32(c,m);
(void) I2O_IRQ_READ32(c);
}
-extern inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
+static inline void i2o_flush_reply(struct i2o_controller *c, u32 m)
{
I2O_REPLY_WRITE32(c,m);
}
extern struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, u32 prefix, u32 mask);
extern void inet_forward_change(void);
-extern __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
+static __inline__ int inet_ifa_match(u32 addr, struct in_ifaddr *ifa)
{
return !((addr^ifa->ifa_address)&ifa->ifa_mask);
}
* Check if a mask is acceptable.
*/
-extern __inline__ int bad_mask(u32 mask, u32 addr)
+static __inline__ int bad_mask(u32 mask, u32 addr)
{
if (addr & (mask = ~mask))
return 1;
extern rwlock_t inetdev_lock;
-extern __inline__ struct in_device *
+static __inline__ struct in_device *
in_dev_get(const struct net_device *dev)
{
struct in_device *in_dev;
return in_dev;
}
-extern __inline__ struct in_device *
+static __inline__ struct in_device *
__in_dev_get(const struct net_device *dev)
{
return (struct in_device*)dev->ip_ptr;
extern void in_dev_finish_destroy(struct in_device *idev);
-extern __inline__ void
+static __inline__ void
in_dev_put(struct in_device *idev)
{
if (atomic_dec_and_test(&idev->refcnt))
#endif /* __KERNEL__ */
-extern __inline__ __u32 inet_make_mask(int logmask)
+static __inline__ __u32 inet_make_mask(int logmask)
{
if (logmask)
return htonl(~((1<<(32-logmask))-1));
return 0;
}
-extern __inline__ int inet_mask_len(__u32 mask)
+static __inline__ int inet_mask_len(__u32 mask)
{
if (!(mask = ntohl(mask)))
return 0;
typedef void (*__cleanup_module_func_t)(void);
#define module_init(x) \
int init_module(void) __attribute__((alias(#x))); \
- extern inline __init_module_func_t __init_module_inline(void) \
+ static inline __init_module_func_t __init_module_inline(void) \
{ return x; }
#define module_exit(x) \
void cleanup_module(void) __attribute__((alias(#x))); \
- extern inline __cleanup_module_func_t __cleanup_module_inline(void) \
+ static inline __cleanup_module_func_t __cleanup_module_inline(void) \
{ return x; }
#define __setup(str,func) /* nothing */
*/
#ifdef CONFIG_NET_SECURITY
-extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
+static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
{
return ((sk->authentication < IPSEC_LEVEL_REQUIRE) ||
(skb->security & RCV_AUTH)) &&
#else
-extern __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
+static __inline__ int ipsec_sk_policy(struct sock *sk, struct sk_buff *skb)
{
return 1;
}
#else /* !CONFIG_ISAPNP */
/* lowlevel configuration */
-extern inline int isapnp_present(void) { return 0; }
-extern inline int isapnp_cfg_begin(int csn, int device) { return -ENODEV; }
-extern inline int isapnp_cfg_end(void) { return -ENODEV; }
-extern inline unsigned char isapnp_read_byte(unsigned char idx) { return 0xff; }
-extern inline unsigned short isapnp_read_word(unsigned char idx) { return 0xffff; }
-extern inline unsigned int isapnp_read_dword(unsigned char idx) { return 0xffffffff; }
-extern inline void isapnp_write_byte(unsigned char idx, unsigned char val) { ; }
-extern inline void isapnp_write_word(unsigned char idx, unsigned short val) { ; }
-extern inline void isapnp_write_dword(unsigned char idx, unsigned int val) { ; }
-extern inline void isapnp_wake(unsigned char csn) { ; }
-extern inline void isapnp_device(unsigned char device) { ; }
-extern inline void isapnp_activate(unsigned char device) { ; }
-extern inline void isapnp_deactivate(unsigned char device) { ; }
+static inline int isapnp_present(void) { return 0; }
+static inline int isapnp_cfg_begin(int csn, int device) { return -ENODEV; }
+static inline int isapnp_cfg_end(void) { return -ENODEV; }
+static inline unsigned char isapnp_read_byte(unsigned char idx) { return 0xff; }
+static inline unsigned short isapnp_read_word(unsigned char idx) { return 0xffff; }
+static inline unsigned int isapnp_read_dword(unsigned char idx) { return 0xffffffff; }
+static inline void isapnp_write_byte(unsigned char idx, unsigned char val) { ; }
+static inline void isapnp_write_word(unsigned char idx, unsigned short val) { ; }
+static inline void isapnp_write_dword(unsigned char idx, unsigned int val) { ; }
+static inline void isapnp_wake(unsigned char csn) { ; }
+static inline void isapnp_device(unsigned char device) { ; }
+static inline void isapnp_activate(unsigned char device) { ; }
+static inline void isapnp_deactivate(unsigned char device) { ; }
/* manager */
-extern inline struct pci_bus *isapnp_find_card(unsigned short vendor,
+static inline struct pci_bus *isapnp_find_card(unsigned short vendor,
unsigned short device,
struct pci_bus *from) { return NULL; }
-extern inline struct pci_dev *isapnp_find_dev(struct pci_bus *card,
+static inline struct pci_dev *isapnp_find_dev(struct pci_bus *card,
unsigned short vendor,
unsigned short function,
struct pci_dev *from) { return NULL; }
-extern inline int isapnp_probe_cards(const struct isapnp_card_id *ids,
+static inline int isapnp_probe_cards(const struct isapnp_card_id *ids,
int (*probe)(struct pci_bus *card,
const struct isapnp_card_id *id)) { return -ENODEV; }
-extern inline int isapnp_probe_devs(const struct isapnp_device_id *ids,
+static inline int isapnp_probe_devs(const struct isapnp_device_id *ids,
int (*probe)(struct pci_dev *dev,
const struct isapnp_device_id *id)) { return -ENODEV; }
-extern inline void isapnp_resource_change(struct resource *resource,
+static inline void isapnp_resource_change(struct resource *resource,
unsigned long start,
unsigned long size) { ; }
-extern inline int isapnp_activate_dev(struct pci_dev *dev, const char *name) { return -ENODEV; }
+static inline int isapnp_activate_dev(struct pci_dev *dev, const char *name) { return -ENODEV; }
#endif /* CONFIG_ISAPNP */
* ISI Card specific ops ...
*/
-extern inline void raise_dtr(struct isi_port * port)
+static inline void raise_dtr(struct isi_port * port)
{
struct isi_board * card = port->card;
unsigned short base = card->base;
port->status |= ISI_DTR;
}
-extern inline void drop_dtr(struct isi_port * port)
+static inline void drop_dtr(struct isi_port * port)
{
struct isi_board * card = port->card;
unsigned short base = card->base;
InterruptTheCard(base);
port->status &= ~ISI_DTR;
}
-extern inline void raise_rts(struct isi_port * port)
+static inline void raise_rts(struct isi_port * port)
{
struct isi_board * card = port->card;
unsigned short base = card->base;
InterruptTheCard(base);
port->status |= ISI_RTS;
}
-extern inline void drop_rts(struct isi_port * port)
+static inline void drop_rts(struct isi_port * port)
{
struct isi_board * card = port->card;
unsigned short base = card->base;
InterruptTheCard(base);
port->status &= ~ISI_RTS;
}
-extern inline void raise_dtr_rts(struct isi_port * port)
+static inline void raise_dtr_rts(struct isi_port * port)
{
struct isi_board * card = port->card;
unsigned short base = card->base;
InterruptTheCard(base);
port->status |= (ISI_DTR | ISI_RTS);
}
-extern inline void drop_dtr_rts(struct isi_port * port)
+static inline void drop_dtr_rts(struct isi_port * port)
{
struct isi_board * card = port->card;
unsigned short base = card->base;
port->status &= ~(ISI_RTS | ISI_DTR);
}
-extern inline void kill_queue(struct isi_port * port, short queue)
+static inline void kill_queue(struct isi_port * port, short queue)
{
struct isi_board * card = port->card;
unsigned short base = card->base;
extern void (*kbd_ledfunc)(unsigned int led);
-extern inline void show_console(void)
+static inline void show_console(void)
{
do_poke_blanked_console = 1;
tasklet_schedule(&console_tasklet);
}
-extern inline void set_console(int nr)
+static inline void set_console(int nr)
{
want_console = nr;
tasklet_schedule(&console_tasklet);
}
-extern inline void set_leds(void)
+static inline void set_leds(void)
{
tasklet_schedule(&keyboard_tasklet);
}
-extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline int vc_kbd_mode(struct kbd_struct * kbd, int flag)
{
return ((kbd->modeflags >> flag) & 1);
}
-extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline int vc_kbd_led(struct kbd_struct * kbd, int flag)
{
return ((kbd->ledflagstate >> flag) & 1);
}
-extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag)
{
kbd->modeflags |= 1 << flag;
}
-extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag)
{
kbd->ledflagstate |= 1 << flag;
}
-extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag)
{
kbd->modeflags &= ~(1 << flag);
}
-extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag)
{
kbd->ledflagstate &= ~(1 << flag);
}
-extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag)
{
kbd->lockstate ^= 1 << flag;
}
-extern inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_slock(struct kbd_struct * kbd, int flag)
{
kbd->slockstate ^= 1 << flag;
}
-extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag)
{
kbd->modeflags ^= 1 << flag;
}
-extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
+static inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag)
{
kbd->ledflagstate ^= 1 << flag;
}
extern task_queue con_task_queue;
-extern inline void con_schedule_flip(struct tty_struct *t)
+static inline void con_schedule_flip(struct tty_struct *t)
{
queue_task(&t->flip.tqueue, &con_task_queue);
tasklet_schedule(&console_tasklet);
/*
* Number of interrupts per specific IRQ source, since bootup
*/
-extern inline int kstat_irqs (int irq)
+static inline int kstat_irqs (int irq)
{
int i, sum=0;
void nlmsvc_mark_resources(void);
void nlmsvc_free_host_resources(struct nlm_host *);
-extern __inline__ struct inode *
+static __inline__ struct inode *
nlmsvc_file_inode(struct nlm_file *file)
{
return file->f_file.f_dentry->d_inode;
/*
* Compare two host addresses (needs modifying for ipv6)
*/
-extern __inline__ int
+static __inline__ int
nlm_cmp_addr(struct sockaddr_in *sin1, struct sockaddr_in *sin2)
{
return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
* Compare two NLM locks.
* When the second lock is of type F_UNLCK, this acts like a wildcard.
*/
-extern __inline__ int
+static __inline__ int
nlm_compare_locks(struct file_lock *fl1, struct file_lock *fl2)
{
return fl1->fl_pid == fl2->fl_pid
*/
extern void __wait_on_buffer(struct buffer_head *);
-extern inline void wait_on_buffer(struct buffer_head * bh)
+static inline void wait_on_buffer(struct buffer_head * bh)
{
if (test_bit(BH_Lock, &bh->b_state))
__wait_on_buffer(bh);
}
-extern inline void lock_buffer(struct buffer_head * bh)
+static inline void lock_buffer(struct buffer_head * bh)
{
while (test_and_set_bit(BH_Lock, &bh->b_state))
__wait_on_buffer(bh);
* nfs may need it).
*/
-extern inline void lock_super(struct super_block * sb)
+static inline void lock_super(struct super_block * sb)
{
down(&sb->s_lock);
}
-extern inline void unlock_super(struct super_block * sb)
+static inline void unlock_super(struct super_block * sb)
{
up(&sb->s_lock);
}
char *raw_buf, char *loop_buf, int size,
int real_block);
-extern inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
+static inline int lo_do_transfer(struct loop_device *lo, int cmd, char *rbuf,
char *lbuf, int size, int rblock)
{
if (!lo->transfer)
IP_CT_DIR_MAX
};
-extern inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
+static inline int ip_ct_tuple_src_equal(const struct ip_conntrack_tuple *t1,
const struct ip_conntrack_tuple *t2)
{
return t1->src.ip == t2->src.ip
&& t1->src.u.all == t2->src.u.all;
}
-extern inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
+static inline int ip_ct_tuple_dst_equal(const struct ip_conntrack_tuple *t1,
const struct ip_conntrack_tuple *t2)
{
return t1->dst.ip == t2->dst.ip
&& t1->dst.protonum == t2->dst.protonum;
}
-extern inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
+static inline int ip_ct_tuple_equal(const struct ip_conntrack_tuple *t1,
const struct ip_conntrack_tuple *t2)
{
return ip_ct_tuple_src_equal(t1, t2) && ip_ct_tuple_dst_equal(t1, t2);
}
-extern inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
+static inline int ip_ct_tuple_mask_cmp(const struct ip_conntrack_tuple *t,
const struct ip_conntrack_tuple *tuple,
const struct ip_conntrack_tuple *mask)
{
#define IPT_ERROR_TARGET "ERROR"
/* Helper functions */
-extern __inline__ struct ipt_entry_target *
+static __inline__ struct ipt_entry_target *
ipt_get_target(struct ipt_entry *e)
{
return (void *)e + e->target_offset;
(type)__i; \
})
-extern inline int
+static inline int
__list_cmp_same(const void *p1, const void *p2) { return p1 == p2; }
/* Is this entry in the list? */
-extern inline int
+static inline int
list_inlist(struct list_head *head, const void *entry)
{
return LIST_FIND(head, __list_cmp_same, void *, entry) != NULL;
#endif
/* Append. */
-extern inline void
+static inline void
list_append(struct list_head *head, void *new)
{
ASSERT_WRITE_LOCK(head);
}
/* Prepend. */
-extern inline void
+static inline void
list_prepend(struct list_head *head, void *new)
{
ASSERT_WRITE_LOCK(head);
/* If the field after the list_head is a nul-terminated string, you
can use these functions. */
-extern inline int __list_cmp_name(const void *i, const char *name)
+static inline int __list_cmp_name(const void *i, const char *name)
{
return strcmp(name, i+sizeof(struct list_head)) == 0;
}
/* Returns false if same name already in list, otherwise does insert. */
-extern inline int
+static inline int
list_named_insert(struct list_head *head, void *new)
{
if (LIST_FIND(head, __list_cmp_name, void *,
#define IP6T_ERROR_TARGET "ERROR"
/* Helper functions */
-extern __inline__ struct ip6t_entry_target *
+static __inline__ struct ip6t_entry_target *
ip6t_get_target(struct ip6t_entry *e)
{
return (void *)e + e->target_offset;
long args[4];
};
-extern __inline__ struct nlmsghdr *
+static __inline__ struct nlmsghdr *
__nlmsg_put(struct sk_buff *skb, u32 pid, u32 seq, int type, int len)
{
struct nlmsghdr *nlh;
/*
* Conversion macros for the filehandle fields.
*/
-extern inline __u32 kdev_t_to_u32(kdev_t dev)
+static inline __u32 kdev_t_to_u32(kdev_t dev)
{
return (__u32) dev;
}
-extern inline kdev_t u32_to_kdev_t(__u32 udev)
+static inline kdev_t u32_to_kdev_t(__u32 udev)
{
return (kdev_t) udev;
}
-extern inline __u32 ino_t_to_u32(ino_t ino)
+static inline __u32 ino_t_to_u32(ino_t ino)
{
return (__u32) ino;
}
-extern inline ino_t u32_to_ino_t(__u32 uino)
+static inline ino_t u32_to_ino_t(__u32 uino)
{
return (ino_t) uino;
}
int maxlen);
/* We'd like to get rid of this eventually. Only daynaport.c uses it now. */
-extern inline void *nubus_slot_addr(int slot)
+static inline void *nubus_slot_addr(int slot)
{
return (void *)(0xF0000000|(slot<<24));
}
* For the time being it will work for struct address_space too (most of
* them sitting inside the inodes). We might want to change it later.
*/
-extern inline unsigned long _page_hashfn(struct address_space * mapping, unsigned long index)
+static inline unsigned long _page_hashfn(struct address_space * mapping, unsigned long index)
{
#define i (((unsigned long) mapping)/(sizeof(struct inode) & ~ (sizeof(struct inode) - 1)))
#define s(x) ((x)+((x)>>PAGE_HASH_BITS))
extern void ___wait_on_page(struct page *);
-extern inline void wait_on_page(struct page * page)
+static inline void wait_on_page(struct page * page)
{
if (PageLocked(page))
___wait_on_page(page);
* timeslice is half a second, but it can be adjusted via the /proc
* interface.
**/
-extern __inline__ int parport_yield(struct pardevice *dev)
+static __inline__ int parport_yield(struct pardevice *dev)
{
unsigned long int timeslip = (jiffies - dev->time);
if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
* parport_claim_or_block(), and the return value is the same as for
* parport_claim_or_block().
**/
-extern __inline__ int parport_yield_blocking(struct pardevice *dev)
+static __inline__ int parport_yield_blocking(struct pardevice *dev)
{
unsigned long int timeslip = (jiffies - dev->time);
if ((dev->port->waithead == NULL) || (timeslip < dev->timeslice))
extern int parport_find_class (parport_device_class cls, int from);
/* Lowlevel drivers _can_ call this support function to handle irqs. */
-extern __inline__ void parport_generic_irq(int irq, struct parport *port,
+static __inline__ void parport_generic_irq(int irq, struct parport *port,
struct pt_regs *regs)
{
parport_ieee1284_interrupt (irq, port, regs);
struct pci_dev *dev;
};
-extern __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
+static __inline__ void parport_pc_write_data(struct parport *p, unsigned char d)
{
#ifdef DEBUG_PARPORT
printk (KERN_DEBUG "parport_pc_write_data(%p,0x%02x)\n", p, d);
outb(d, DATA(p));
}
-extern __inline__ unsigned char parport_pc_read_data(struct parport *p)
+static __inline__ unsigned char parport_pc_read_data(struct parport *p)
{
unsigned char val = inb (DATA (p));
#ifdef DEBUG_PARPORT
}
#ifdef DEBUG_PARPORT
-extern __inline__ void dump_parport_state (char *str, struct parport *p)
+static __inline__ void dump_parport_state (char *str, struct parport *p)
{
/* here's hoping that reading these ports won't side-effect anything underneath */
unsigned char ecr = inb (ECONTROL (p));
return ctr;
}
-extern __inline__ void parport_pc_data_reverse (struct parport *p)
+static __inline__ void parport_pc_data_reverse (struct parport *p)
{
__parport_pc_frob_control (p, 0x20, 0x20);
}
-extern __inline__ void parport_pc_data_forward (struct parport *p)
+static __inline__ void parport_pc_data_forward (struct parport *p)
{
__parport_pc_frob_control (p, 0x20, 0x00);
}
-extern __inline__ void parport_pc_write_control (struct parport *p,
+static __inline__ void parport_pc_write_control (struct parport *p,
unsigned char d)
{
const unsigned char wm = (PARPORT_CONTROL_STROBE |
__parport_pc_frob_control (p, wm, d & wm);
}
-extern __inline__ unsigned char parport_pc_read_control(struct parport *p)
+static __inline__ unsigned char parport_pc_read_control(struct parport *p)
{
const unsigned char rm = (PARPORT_CONTROL_STROBE |
PARPORT_CONTROL_AUTOFD |
return priv->ctr & rm; /* Use soft copy */
}
-extern __inline__ unsigned char parport_pc_frob_control (struct parport *p,
+static __inline__ unsigned char parport_pc_frob_control (struct parport *p,
unsigned char mask,
unsigned char val)
{
return __parport_pc_frob_control (p, mask, val);
}
-extern __inline__ unsigned char parport_pc_read_status(struct parport *p)
+static __inline__ unsigned char parport_pc_read_status(struct parport *p)
{
return inb(STATUS(p));
}
-extern __inline__ void parport_pc_disable_irq(struct parport *p)
+static __inline__ void parport_pc_disable_irq(struct parport *p)
{
__parport_pc_frob_control (p, 0x10, 0x00);
}
-extern __inline__ void parport_pc_enable_irq(struct parport *p)
+static __inline__ void parport_pc_enable_irq(struct parport *p)
{
__parport_pc_frob_control (p, 0x10, 0x10);
}
*/
struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from);
-extern inline void pm_access(struct pm_dev *dev) {}
-extern inline void pm_dev_idle(struct pm_dev *dev) {}
+static inline void pm_access(struct pm_dev *dev) {}
+static inline void pm_dev_idle(struct pm_dev *dev) {}
#else /* CONFIG_PM */
#define PM_IS_ACTIVE() 0
-extern inline struct pm_dev *pm_register(pm_dev_t type,
+static inline struct pm_dev *pm_register(pm_dev_t type,
unsigned long id,
pm_callback callback)
{
return 0;
}
-extern inline void pm_unregister(struct pm_dev *dev) {}
+static inline void pm_unregister(struct pm_dev *dev) {}
-extern inline void pm_unregister_all(pm_callback callback) {}
+static inline void pm_unregister_all(pm_callback callback) {}
-extern inline int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
+static inline int pm_send(struct pm_dev *dev, pm_request_t rqst, void *data)
{
return 0;
}
-extern inline int pm_send_all(pm_request_t rqst, void *data)
+static inline int pm_send_all(pm_request_t rqst, void *data)
{
return 0;
}
-extern inline struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from)
+static inline struct pm_dev *pm_find(pm_dev_t type, struct pm_dev *from)
{
return 0;
}
-extern inline void pm_access(struct pm_dev *dev) {}
-extern inline void pm_dev_idle(struct pm_dev *dev) {}
+static inline void pm_access(struct pm_dev *dev) {}
+static inline void pm_dev_idle(struct pm_dev *dev) {}
#endif /* CONFIG_PM */
extern void __pollwait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p);
-extern inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
+static inline void poll_wait(struct file * filp, wait_queue_head_t * wait_address, poll_table *p)
{
if (p && wait_address)
__pollwait(filp, wait_address, p);
/*
* Operations supported for diskquotas.
*/
-extern __inline__ void DQUOT_INIT(struct inode *inode)
+static __inline__ void DQUOT_INIT(struct inode *inode)
{
if (inode->i_sb && inode->i_sb->dq_op)
inode->i_sb->dq_op->initialize(inode, -1);
}
-extern __inline__ void DQUOT_DROP(struct inode *inode)
+static __inline__ void DQUOT_DROP(struct inode *inode)
{
if (IS_QUOTAINIT(inode)) {
if (inode->i_sb && inode->i_sb->dq_op)
}
}
-extern __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ int DQUOT_PREALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
{
if (sb->dq_op) {
if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), 1) == NO_QUOTA)
return 0;
}
-extern __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ int DQUOT_ALLOC_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
{
if (sb->dq_op) {
if (sb->dq_op->alloc_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize), 0) == NO_QUOTA)
return 0;
}
-extern __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode)
+static __inline__ int DQUOT_ALLOC_INODE(struct super_block *sb, struct inode *inode)
{
if (sb->dq_op) {
sb->dq_op->initialize (inode, -1);
return 0;
}
-extern __inline__ void DQUOT_FREE_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
+static __inline__ void DQUOT_FREE_BLOCK(struct super_block *sb, const struct inode *inode, int nr)
{
if (sb->dq_op)
sb->dq_op->free_block(inode, fs_to_dq_blocks(nr, sb->s_blocksize));
}
-extern __inline__ void DQUOT_FREE_INODE(struct super_block *sb, struct inode *inode)
+static __inline__ void DQUOT_FREE_INODE(struct super_block *sb, struct inode *inode)
{
if (sb->dq_op)
sb->dq_op->free_inode(inode, 1);
}
-extern __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr)
+static __inline__ int DQUOT_TRANSFER(struct dentry *dentry, struct iattr *iattr)
{
int error = -EDQUOT;
#ifdef __i386__
/* 001 */
-extern __inline__ int md_cpu_has_mmx(void)
+static __inline__ int md_cpu_has_mmx(void)
{
return test_bit(X86_FEATURE_MMX, &boot_cpu_data.x86_capability);
}
#define md_put_user put_user
/* 007 */
-extern inline int md_capable_admin(void)
+static inline int md_capable_admin(void)
{
return capable(CAP_SYS_ADMIN);
}
#define MD_FILE_TO_INODE(file) ((file)->f_dentry->d_inode)
/* 009 */
-extern inline void md_flush_signals (void)
+static inline void md_flush_signals (void)
{
spin_lock(¤t->sigmask_lock);
flush_signals(current);
}
/* 010 */
-extern inline void md_init_signals (void)
+static inline void md_init_signals (void)
{
current->exit_signal = SIGCHLD;
siginitsetinv(¤t->blocked, sigmask(SIGKILL));
return MD_RESERVED;
}
-extern inline int level_to_pers (int level)
+static inline int level_to_pers (int level)
{
switch (level) {
case -3: return HSM;
#define REISERFS_SUPER_MAGIC_STRING "ReIsErFs"
#define REISER2FS_SUPER_MAGIC_STRING "ReIsEr2Fs"
-extern inline int is_reiserfs_magic_string (struct reiserfs_super_block * rs)
+static inline int is_reiserfs_magic_string (struct reiserfs_super_block * rs)
{
return (!strncmp (rs->s_magic, REISERFS_SUPER_MAGIC_STRING,
strlen ( REISERFS_SUPER_MAGIC_STRING)) ||
//
// here are conversion routines
//
-extern inline int uniqueness2type (__u32 uniqueness)
+static inline int uniqueness2type (__u32 uniqueness)
{
switch (uniqueness) {
case V1_SD_UNIQUENESS: return TYPE_STAT_DATA;
return TYPE_ANY;
}
-extern inline __u32 type2uniqueness (int type)
+static inline __u32 type2uniqueness (int type)
{
switch (type) {
case TYPE_STAT_DATA: return V1_SD_UNIQUENESS;
// there is no way to get version of object from key, so, provide
// version to these defines
//
-extern inline loff_t le_key_k_offset (int version, struct key * key)
+static inline loff_t le_key_k_offset (int version, struct key * key)
{
return (version == ITEM_VERSION_1) ? key->u.k_offset_v1.k_offset :
le64_to_cpu (key->u.k_offset_v2.k_offset);
}
-extern inline loff_t le_ih_k_offset (struct item_head * ih)
+static inline loff_t le_ih_k_offset (struct item_head * ih)
{
return le_key_k_offset (ih_version (ih), &(ih->ih_key));
}
-extern inline loff_t le_key_k_type (int version, struct key * key)
+static inline loff_t le_key_k_type (int version, struct key * key)
{
return (version == ITEM_VERSION_1) ? uniqueness2type (key->u.k_offset_v1.k_uniqueness) :
le16_to_cpu (key->u.k_offset_v2.k_type);
}
-extern inline loff_t le_ih_k_type (struct item_head * ih)
+static inline loff_t le_ih_k_type (struct item_head * ih)
{
return le_key_k_type (ih_version (ih), &(ih->ih_key));
}
-extern inline void set_le_key_k_offset (int version, struct key * key, loff_t offset)
+static inline void set_le_key_k_offset (int version, struct key * key, loff_t offset)
{
(version == ITEM_VERSION_1) ? (key->u.k_offset_v1.k_offset = offset) :
(key->u.k_offset_v2.k_offset = cpu_to_le64 (offset));
}
-extern inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset)
+static inline void set_le_ih_k_offset (struct item_head * ih, loff_t offset)
{
set_le_key_k_offset (ih_version (ih), &(ih->ih_key), offset);
}
-extern inline void set_le_key_k_type (int version, struct key * key, int type)
+static inline void set_le_key_k_type (int version, struct key * key, int type)
{
(version == ITEM_VERSION_1) ? (key->u.k_offset_v1.k_uniqueness = type2uniqueness (type)) :
(key->u.k_offset_v2.k_type = cpu_to_le16 (type));
}
-extern inline void set_le_ih_k_type (struct item_head * ih, int type)
+static inline void set_le_ih_k_type (struct item_head * ih, int type)
{
set_le_key_k_type (ih_version (ih), &(ih->ih_key), type);
}
//
// key is pointer to cpu key, result is cpu
//
-extern inline loff_t cpu_key_k_offset (struct cpu_key * key)
+static inline loff_t cpu_key_k_offset (struct cpu_key * key)
{
return (key->version == ITEM_VERSION_1) ? key->on_disk_key.u.k_offset_v1.k_offset :
key->on_disk_key.u.k_offset_v2.k_offset;
}
-extern inline loff_t cpu_key_k_type (struct cpu_key * key)
+static inline loff_t cpu_key_k_type (struct cpu_key * key)
{
return (key->version == ITEM_VERSION_1) ? uniqueness2type (key->on_disk_key.u.k_offset_v1.k_uniqueness) :
key->on_disk_key.u.k_offset_v2.k_type;
}
-extern inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
+static inline void set_cpu_key_k_offset (struct cpu_key * key, loff_t offset)
{
(key->version == ITEM_VERSION_1) ? (key->on_disk_key.u.k_offset_v1.k_offset = offset) :
(key->on_disk_key.u.k_offset_v2.k_offset = offset);
}
-extern inline void set_cpu_key_k_type (struct cpu_key * key, int type)
+static inline void set_cpu_key_k_type (struct cpu_key * key, int type)
{
(key->version == ITEM_VERSION_1) ? (key->on_disk_key.u.k_offset_v1.k_uniqueness = type2uniqueness (type)) :
(key->on_disk_key.u.k_offset_v2.k_type = type);
}
-extern inline void cpu_key_k_offset_dec (struct cpu_key * key)
+static inline void cpu_key_k_offset_dec (struct cpu_key * key)
{
if (key->version == ITEM_VERSION_1)
key->on_disk_key.u.k_offset_v1.k_offset --;
/* compose directory item containing "." and ".." entries (entries are
not aligned to 4 byte boundary) */
-extern inline void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
+static inline void make_empty_dir_item_v1 (char * body, __u32 dirid, __u32 objid,
__u32 par_dirid, __u32 par_objid)
{
struct reiserfs_de_head * deh;
}
/* compose directory item containing "." and ".." entries */
-extern inline void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
+static inline void make_empty_dir_item (char * body, __u32 dirid, __u32 objid,
__u32 par_dirid, __u32 par_objid)
{
struct reiserfs_de_head * deh;
#define I_DEH_N_ENTRY_LENGTH(ih,deh,i) \
((i) ? (((deh)-1)->deh_location - (deh)->deh_location) : ((ih)->ih_item_len) - (deh)->deh_location)
*/
-extern inline int entry_length (struct buffer_head * bh, struct item_head * ih,
+static inline int entry_length (struct buffer_head * bh, struct item_head * ih,
int pos_in_item)
{
struct reiserfs_de_head * deh;
// reiserfs version 2 has max offset 60 bits. Version 1 - 32 bit offset
#define U32_MAX (~(__u32)0)
-extern inline loff_t max_reiserfs_offset (struct inode * inode)
+static inline loff_t max_reiserfs_offset (struct inode * inode)
{
if (inode_items_version (inode) == ITEM_VERSION_1)
return (loff_t)U32_MAX;
//
// get key version from on disk key - kludge
//
-extern inline int le_key_version (struct key * key)
+static inline int le_key_version (struct key * key)
{
int type;
}
-extern inline void copy_key (void * to, void * from)
+static inline void copy_key (void * to, void * from)
{
memcpy (to, from, KEY_SIZE);
}
#ifdef __i386__
-extern __inline__ int
+static __inline__ int
find_first_nonzero_bit(void * addr, unsigned size) {
int res;
int __d0;
#else /* __i386__ */
-extern __inline__ int find_next_nonzero_bit(void * addr, unsigned size, unsigned offset)
+static __inline__ int find_next_nonzero_bit(void * addr, unsigned size, unsigned offset)
{
unsigned int * p = ((unsigned int *) addr) + (offset >> 5);
unsigned int result = offset & ~31UL;
absolutely safe */
#define SPARE_SPACE 500
-extern inline unsigned long reiserfs_get_journal_block(struct super_block *s) {
+static inline unsigned long reiserfs_get_journal_block(struct super_block *s) {
return le32_to_cpu(SB_DISK_SUPER_BLOCK(s)->s_journal_block) ;
}
-extern inline unsigned long reiserfs_get_journal_orig_size(struct super_block *s) {
+static inline unsigned long reiserfs_get_journal_orig_size(struct super_block *s) {
return le32_to_cpu(SB_DISK_SUPER_BLOCK(s)->s_orig_journal_size) ;
}
#include <linux/config.h>
-extern __inline__ int rtattr_strcmp(struct rtattr *rta, char *str)
+static __inline__ int rtattr_strcmp(struct rtattr *rta, char *str)
{
int len = strlen(str) + 1;
return len > rta->rta_len || memcmp(RTA_DATA(rta), str, len);
}
-extern __inline__ void
+static __inline__ void
rpc_set_timeout(struct rpc_clnt *clnt, unsigned int retr, unsigned long incr)
{
xprt_set_timeout(&clnt->cl_timeout, retr, incr);
void rpc_show_tasks(void);
#endif
-extern __inline__ void *
+static __inline__ void *
rpc_malloc(struct rpc_task *task, unsigned int size)
{
return rpc_allocate(task->tk_flags, size);
}
-extern __inline__ void
+static __inline__ void
rpc_exit(struct rpc_task *task, int status)
{
task->tk_status = status;
}
#ifdef RPC_DEBUG
-extern __inline__ char *
+static __inline__ char *
rpc_qname(struct rpc_wait_queue *q)
{
return q->name? q->name : "unknown";
#else
-extern inline void svc_proc_unregister(const char *p) {}
-extern inline struct proc_dir_entry*svc_proc_register(struct svc_stat *s)
+static inline void svc_proc_unregister(const char *p) {}
+static inline struct proc_dir_entry*svc_proc_register(struct svc_stat *s)
{
return NULL;
}
-extern inline int svc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f)
+static inline int svc_proc_read(char *a, char **b, off_t c, int d, int *e, void *f)
{
return 0;
}
struct rpc_listitem * next;
};
-extern __inline__ void
+static __inline__ void
__rpc_append_list(struct rpc_listitem **q, struct rpc_listitem *item)
{
struct rpc_listitem *next, *prev;
}
}
-extern __inline__ void
+static __inline__ void
__rpc_insert_list(struct rpc_listitem **q, struct rpc_listitem *item)
{
__rpc_append_list(q, item);
*q = item;
}
-extern __inline__ void
+static __inline__ void
__rpc_remove_list(struct rpc_listitem **q, struct rpc_listitem *item)
{
struct rpc_listitem *prev = item->prev,
extern wait_queue_head_t kreclaimd_wait;
extern int page_launder(int, int);
extern int free_shortage(void);
+extern int total_free_shortage(void);
extern int inactive_shortage(void);
+extern int total_inactive_shortage(void);
extern void wakeup_kswapd(void);
extern int try_to_free_pages(unsigned int gfp_mask);
+extern unsigned int zone_free_shortage(zone_t *zone);
+extern unsigned int zone_inactive_shortage(zone_t *zone);
+extern unsigned int zone_inactive_plenty(zone_t *zone);
+
/* linux/mm/page_io.c */
extern void rw_swap_page(int, struct page *);
extern void rw_swap_page_nolock(int, swp_entry_t, char *);
*/
#define COH_KLUDGE_SYMLINK_MODE (S_IFREG | S_ISVTX)
#define COH_KLUDGE_NOT_SYMLINK (S_IFREG | S_ISVTX | S_IRUSR) /* force read access */
-extern inline mode_t from_coh_imode(unsigned short mode)
+static inline mode_t from_coh_imode(unsigned short mode)
{
if (mode == COH_KLUDGE_SYMLINK_MODE)
return (S_IFLNK | 0777);
else
return mode;
}
-extern inline unsigned short to_coh_imode(mode_t mode)
+static inline unsigned short to_coh_imode(mode_t mode)
{
if (S_ISLNK(mode))
return COH_KLUDGE_SYMLINK_MODE;
#ifdef INCLUDE_INLINE_FUNCS
#define _INLINE_ extern
#else
-#define _INLINE_ extern __inline__
+#define _INLINE_ static __inline__
#endif
_INLINE_ void tty_insert_flip_char(struct tty_struct *tty,
#define VID_HARDWARE_SE401 30 /* SE401 USB webcams */
#define VID_HARDWARE_PWC 31 /* Philips webcams */
#define VID_HARDWARE_MEYE 32 /* Sony Vaio MotionEye cameras */
+#define VID_HARDWARE_CPIA2 33
/*
* Initialiser list
- Bottom halves: globally serialized, grr...
*/
-/* No separate irq_stat for s390, it is part of PSA */
-#if !defined(CONFIG_ARCH_S390)
irq_cpustat_t irq_stat[NR_CPUS];
-#endif /* CONFIG_ARCH_S390 */
static struct softirq_action softirq_vec[32] __cacheline_aligned;
* files..
* Thanks to Olaf Kirch and Peter Benie for spotting this.
*/
-extern inline void cap_emulate_setxuid(int old_ruid, int old_euid,
+static inline void cap_emulate_setxuid(int old_ruid, int old_euid,
int old_suid)
{
if ((old_ruid == 0 || old_euid == 0 || old_suid == 0) &&
spin_unlock(&pagecache_lock);
}
-/*
- * This function is pretty much like __find_page_nolock(), but it only
- * requires 2 arguments and doesn't mark the page as touched, making it
- * ideal for ->writepage() clustering and other places where you don't
- * want to mark the page referenced.
- *
- * The caller needs to hold the pagecache_lock.
- */
-static struct page * FASTCALL(__find_page_simple(struct address_space *, unsigned long));
-static struct page * __find_page_simple(struct address_space *mapping, unsigned long index)
-{
- struct page **next = page_hash(mapping, index);;
-
- for (;;) {
- struct page *page = *next;
- if (!page)
- break;
- next = &page->next_hash;
- if (page->mapping != mapping)
- continue;
- if (page->index != index)
- continue;
- return page;
- }
-
- return NULL;
-}
-
static inline struct page * __find_page_nolock(struct address_space *mapping, unsigned long offset, struct page *page)
{
goto inside;
#define DEBUG_READAHEAD
#endif
-/*
- * We combine this with read-ahead to deactivate pages when we
- * think there's sequential IO going on. Note that this is
- * harmless since we don't actually evict the pages from memory
- * but just move them to the inactive list.
- *
- * TODO:
- * - make the readahead code smarter
- * - move readahead to the VMA level so we can do the same
- * trick with mmap()
- *
- * Rik van Riel, 2000
- */
-static void drop_behind(struct file * file, unsigned long index)
-{
- struct inode *inode = file->f_dentry->d_inode;
- struct address_space *mapping = inode->i_mapping;
- struct page *page;
- unsigned long start;
-
- /* Nothing to drop-behind if we're on the first page. */
- if (!index)
- return;
-
- if (index > file->f_rawin)
- start = index - file->f_rawin;
- else
- start = 0;
-
- /*
- * Go backwards from index-1 and drop all pages in the
- * readahead window. Since the readahead window may have
- * been increased since the last time we were called, we
- * stop when the page isn't there.
- */
- spin_lock(&pagecache_lock);
- while (--index >= start) {
- page = __find_page_simple(mapping, index);
- if (!page)
- break;
- deactivate_page(page);
- }
- spin_unlock(&pagecache_lock);
-}
-
/*
* Read-ahead profiling information
* --------------------------------
if (filp->f_ramax > max_readahead)
filp->f_ramax = max_readahead;
- /*
- * Move the pages that have already been passed
- * to the inactive list.
- */
- drop_behind(filp, index);
-
#ifdef PROFILE_READAHEAD
profile_readahead((reada_ok == 2), filp);
#endif
}
+static inline void check_used_once (struct page *page)
+{
+ if (!page->age) {
+ page->age = PAGE_AGE_START;
+ ClearPageReferenced(page);
+ }
+}
+
/*
* This is a generic file read routine, and uses the
* inode->i_op->readpage() function for the actual low-level
offset += ret;
index += offset >> PAGE_CACHE_SHIFT;
offset &= ~PAGE_CACHE_MASK;
-
+
+ check_used_once (page);
page_cache_release(page);
if (ret == nr && desc->count)
continue;
while (count) {
unsigned long index, offset;
char *kaddr;
- int deactivate = 1;
/*
* Try to find the page in the cache. If it isn't there,
offset = (pos & (PAGE_CACHE_SIZE -1)); /* Within page */
index = pos >> PAGE_CACHE_SHIFT;
bytes = PAGE_CACHE_SIZE - offset;
- if (bytes > count) {
+ if (bytes > count)
bytes = count;
- deactivate = 0;
- }
/*
* Bring in the user page that we will copy from _first_.
unlock:
/* Mark it unlocked again and drop the page.. */
UnlockPage(page);
- if (deactivate)
- deactivate_page(page);
+ check_used_once(page);
page_cache_release(page);
if (status < 0)
static inline void break_cow(struct vm_area_struct * vma, struct page * old_page, struct page * new_page, unsigned long address,
pte_t *page_table)
{
- copy_cow_page(old_page,new_page,address);
flush_page_to_ram(new_page);
flush_cache_page(vma, address);
establish_pte(vma, address, page_table, pte_mkwrite(pte_mkdirty(mk_pte(new_page, vma->vm_page_prot))));
* Ok, we need to copy. Oh, well..
*/
spin_unlock(&mm->page_table_lock);
+
new_page = alloc_page(GFP_HIGHUSER);
- spin_lock(&mm->page_table_lock);
if (!new_page)
- return -1;
+ goto no_mem;
+ copy_cow_page(old_page,new_page,address);
/*
* Re-check the pte - we dropped the lock
*/
+ spin_lock(&mm->page_table_lock);
if (pte_same(*page_table, pte)) {
if (PageReserved(old_page))
++mm->rss;
bad_wp_page:
printk("do_wp_page: bogus page at address %08lx (page 0x%lx)\n",address,(unsigned long)old_page);
return -1;
+no_mem:
+ spin_lock(&mm->page_table_lock);
+ return -1;
}
static void vmtruncate_list(struct vm_area_struct *mpnt, unsigned long pgoff)
/* Allocate our own private page. */
spin_unlock(&mm->page_table_lock);
+
page = alloc_page(GFP_HIGHUSER);
- spin_lock(&mm->page_table_lock);
if (!page)
- return -1;
+ goto no_mem;
+ clear_user_highpage(page, addr);
+
+ spin_lock(&mm->page_table_lock);
if (!pte_none(*page_table)) {
page_cache_release(page);
return 1;
}
mm->rss++;
- clear_user_highpage(page, addr);
flush_page_to_ram(page);
entry = pte_mkwrite(pte_mkdirty(mk_pte(page, vma->vm_page_prot)));
}
/* No need to invalidate - it was non-present before */
update_mmu_cache(vma, addr, entry);
return 1; /* Minor fault */
+
+no_mem:
+ spin_lock(&mm->page_table_lock);
+ return -1;
}
/*
* to give up than to deadlock the kernel looping here.
*/
if (gfp_mask & __GFP_WAIT) {
- if (!order || free_shortage()) {
+ if (!order || total_free_shortage()) {
int progress = try_to_free_pages(gfp_mask);
if (progress || (gfp_mask & __GFP_FS))
goto try_again;
}
#endif
+unsigned int zone_free_shortage(zone_t *zone)
+{
+ int sum = 0;
+
+ if (!zone->size)
+ goto ret;
+
+ if (zone->inactive_clean_pages + zone->free_pages
+ < zone->pages_min) {
+ sum += zone->pages_min;
+ sum -= zone->free_pages;
+ sum -= zone->inactive_clean_pages;
+ }
+ret:
+ return sum;
+}
+
+unsigned int zone_inactive_plenty(zone_t *zone)
+{
+ int inactive;
+
+ if (!zone->size)
+ return 0;
+
+ inactive = zone->inactive_dirty_pages;
+ inactive += zone->inactive_clean_pages;
+ inactive += zone->free_pages;
+
+ return (inactive > (zone->size / 3));
+
+}
+unsigned int zone_inactive_shortage(zone_t *zone)
+{
+ int sum = 0;
+
+ if (!zone->size)
+ goto ret;
+
+ sum = zone->pages_high;
+ sum -= zone->inactive_dirty_pages;
+ sum -= zone->inactive_clean_pages;
+ sum -= zone->free_pages;
+
+ret:
+ return (sum > 0 ? sum : 0);
+}
+
/*
* Show free area list (used inside shift_scroll-lock stuff)
* We also calculate the percentage fragmentation. We do this by counting the
spin_lock(&pagemap_lru_lock);
if (!PageLocked(page))
BUG();
- DEBUG_ADD_PAGE
- add_page_to_active_list(page);
- /* This should be relatively rare */
- if (!page->age)
- deactivate_page_nolock(page);
+ add_page_to_inactive_dirty_list(page);
+ page->age = 0;
spin_unlock(&pagemap_lru_lock);
}
pte_t pte;
swp_entry_t entry;
+ /*
+ * If we are doing a zone-specific scan, do not
+ * touch pages from zones which don't have a
+ * shortage.
+ */
+ if (zone_inactive_plenty(page->zone))
+ return;
+
/* Don't look at this pte if it's been accessed recently. */
if (ptep_test_and_clear_young(page_table)) {
page->age += PAGE_AGE_ADV;
}
/* Page is or was in use? Move it to the active list. */
- if (PageReferenced(page) || page->age > 0 ||
- (!page->buffers && page_count(page) > 1)) {
+ if (PageReferenced(page) || (!page->buffers && page_count(page) > 1)) {
del_page_from_inactive_clean_list(page);
add_page_to_active_list(page);
+ page->age = PAGE_AGE_START;
continue;
}
#define MAX_LAUNDER (4 * (1 << page_cluster))
#define CAN_DO_FS (gfp_mask & __GFP_FS)
#define CAN_DO_IO (gfp_mask & __GFP_IO)
-int page_launder(int gfp_mask, int sync)
+int do_page_launder(zone_t *zone, int gfp_mask, int sync)
{
int launder_loop, maxscan, cleaned_pages, maxlaunder;
struct list_head * page_lru;
}
/* Page is or was in use? Move it to the active list. */
- if (PageReferenced(page) || page->age > 0 ||
- (!page->buffers && page_count(page) > 1) ||
+ if (PageReferenced(page) || (!page->buffers && page_count(page) > 1) ||
page_ramdisk(page)) {
del_page_from_inactive_dirty_list(page);
add_page_to_active_list(page);
+ page->age = PAGE_AGE_START;
+ continue;
+ }
+
+ /*
+ * If we are doing zone-specific laundering,
+ * avoid touching pages from zones which do
+ * not have a free shortage.
+ */
+ if (zone && !zone_free_shortage(page->zone)) {
+ list_del(page_lru);
+ list_add(page_lru, &inactive_dirty_list);
continue;
}
* If we're freeing buffer cache pages, stop when
* we've got enough free memory.
*/
- if (freed_page && !free_shortage())
- break;
+ if (freed_page) {
+ if (zone) {
+ if (!zone_free_shortage(zone))
+ break;
+ } else if (!free_shortage())
+ break;
+ }
continue;
} else if (page->mapping && !PageDirty(page)) {
/*
* loads, flush out the dirty pages before we have to wait on
* IO.
*/
- if (CAN_DO_IO && !launder_loop && free_shortage()) {
+ if (CAN_DO_IO && !launder_loop && total_free_shortage()) {
launder_loop = 1;
/* If we cleaned pages, never do synchronous IO. */
if (cleaned_pages)
return cleaned_pages;
}
+int page_launder(int gfp_mask, int sync)
+{
+ int type = 0, ret = 0;
+ pg_data_t *pgdat = pgdat_list;
+ /*
+ * First do a global scan if there is a
+ * global shortage.
+ */
+ if (free_shortage())
+ ret += do_page_launder(NULL, gfp_mask, sync);
+
+ /*
+ * Then check if there is any specific zone
+ * needs laundering.
+ */
+ for (type = 0; type < MAX_NR_ZONES; type++) {
+ zone_t *zone = pgdat->node_zones + type;
+
+ if (zone_free_shortage(zone))
+ ret += do_page_launder(zone, gfp_mask, sync);
+ }
+
+ return ret;
+}
+
+
+
/**
* refill_inactive_scan - scan the active list and find pages to deactivate
* @priority: the priority at which to scan
* This function will scan a portion of the active list to find
* unused pages, those pages will then be moved to the inactive list.
*/
-int refill_inactive_scan(unsigned int priority, int target)
+int refill_inactive_scan(zone_t *zone, unsigned int priority, int target)
{
struct list_head * page_lru;
struct page * page;
continue;
}
+ /*
+ * Do not deactivate pages from zones which
+ * have plenty inactive pages.
+ */
+
+ if (zone_inactive_plenty(page->zone)) {
+ page_active = 1;
+ goto skip_page;
+ }
+
/* Do aging on the pages. */
if (PageTestandClearReferenced(page)) {
age_page_up_nolock(page);
* we have done enough work.
*/
if (page_active || PageActive(page)) {
+skip_page:
list_del(page_lru);
list_add(page_lru, &active_list);
} else {
- nr_deactivated++;
+ if (!zone || (zone && (zone == page->zone)))
+ nr_deactivated++;
if (target && nr_deactivated >= target)
break;
}
}
/*
- * Check if there are zones with a severe shortage of free pages,
- * or if all zones have a minor shortage.
+ * Check if we have are low on free pages globally.
*/
int free_shortage(void)
{
- pg_data_t *pgdat = pgdat_list;
- int sum = 0;
int freeable = nr_free_pages() + nr_inactive_clean_pages();
int freetarget = freepages.high;
/* Are we low on free pages globally? */
if (freeable < freetarget)
return freetarget - freeable;
+ return 0;
+}
+
+/*
+ *
+ * Check if there are zones with a severe shortage of free pages,
+ * or if all zones have a minor shortage.
+ */
+int total_free_shortage(void)
+{
+ int sum = 0;
+ pg_data_t *pgdat = pgdat_list;
+
+ /* Do we have a global free shortage? */
+ if((sum = free_shortage()))
+ return sum;
/* If not, are we very low on any particular zone? */
do {
} while (pgdat);
return sum;
+
}
/*
- * How many inactive pages are we short?
+ * How many inactive pages are we short globally?
*/
int inactive_shortage(void)
{
int shortage = 0;
- pg_data_t *pgdat = pgdat_list;
/* Is the inactive dirty list too small? */
if (shortage > 0)
return shortage;
+ return 0;
+}
+/*
+ * Are we low on inactive pages globally or in any zone?
+ */
+int total_inactive_shortage(void)
+{
+ int shortage = 0;
+ pg_data_t *pgdat = pgdat_list;
- /* If not, do we have enough per-zone pages on the inactive list? */
+ if((shortage = inactive_shortage()))
+ return shortage;
- shortage = 0;
+ shortage = 0;
do {
int i;
* when called from a user process.
*/
#define DEF_PRIORITY (6)
-static int refill_inactive(unsigned int gfp_mask, int user)
+static int refill_inactive_global(unsigned int gfp_mask, int user)
{
int count, start_count, maxtry;
/* Walk the VM space for a bit.. */
swap_out(DEF_PRIORITY, gfp_mask);
- count -= refill_inactive_scan(DEF_PRIORITY, count);
+ count -= refill_inactive_scan(NULL, DEF_PRIORITY, count);
if (count <= 0)
goto done;
return (count < start_count);
}
+static int refill_inactive_zone(zone_t *zone, unsigned int gfp_mask, int user)
+{
+ int count, start_count, maxtry;
+
+ count = start_count = zone_inactive_shortage(zone);
+
+ maxtry = (1 << DEF_PRIORITY);
+
+ do {
+ swap_out(DEF_PRIORITY, gfp_mask);
+
+ count -= refill_inactive_scan(zone, DEF_PRIORITY, count);
+
+ if (count <= 0)
+ goto done;
+
+ if (--maxtry <= 0)
+ return 0;
+
+ } while(zone_inactive_shortage(zone));
+done:
+ return (count < start_count);
+}
+
+
+static int refill_inactive(unsigned int gfp_mask, int user)
+{
+ int type = 0, ret = 0;
+ pg_data_t *pgdat = pgdat_list;
+ /*
+ * First do a global scan if there is a
+ * global shortage.
+ */
+ if (inactive_shortage())
+ ret += refill_inactive_global(gfp_mask, user);
+
+ /*
+ * Then check if there is any specific zone
+ * with a shortage and try to refill it if
+ * so.
+ */
+ for (type = 0; type < MAX_NR_ZONES; type++) {
+ zone_t *zone = pgdat->node_zones + type;
+
+ if (zone_inactive_shortage(zone))
+ ret += refill_inactive_zone(zone, gfp_mask, user);
+ }
+
+ return ret;
+}
+
+#define DEF_PRIORITY (6)
+
static int do_try_to_free_pages(unsigned int gfp_mask, int user)
{
int ret = 0;
* before we get around to moving them to the other
* list, so this is a relatively cheap operation.
*/
- if (free_shortage()) {
- ret += page_launder(gfp_mask, user);
+
+ ret += page_launder(gfp_mask, user);
+
+ if (total_free_shortage()) {
shrink_dcache_memory(DEF_PRIORITY, gfp_mask);
shrink_icache_memory(DEF_PRIORITY, gfp_mask);
}
* If needed, we move pages from the active list
* to the inactive list.
*/
- if (inactive_shortage())
- ret += refill_inactive(gfp_mask, user);
+ ret += refill_inactive(gfp_mask, user);
/*
* Reclaim unused slab cache if memory is low.
static long recalc = 0;
/* If needed, try to free some memory. */
- if (inactive_shortage() || free_shortage())
+ if (total_inactive_shortage() || total_free_shortage())
do_try_to_free_pages(GFP_KSWAPD, 0);
/* Once a second ... */
recalculate_vm_stats();
/* Do background page aging. */
- refill_inactive_scan(DEF_PRIORITY, 0);
+ refill_inactive_scan(NULL, DEF_PRIORITY, 0);
}
run_task_queue(&tq_disk);
* We go to sleep for one second, but if it's needed
* we'll be woken up earlier...
*/
- if (!free_shortage() || !inactive_shortage()) {
+ if (!total_free_shortage() || !total_inactive_shortage()) {
interruptible_sleep_on_timeout(&kswapd_wait, HZ);
/*
* If we couldn't free enough memory, we see if it was
/* Check if this is a "normal" ircomm device, or an irlpt device */
if (line < 0x10) {
self->service_type = IRCOMM_3_WIRE | IRCOMM_9_WIRE;
- self->settings.service_type = IRCOMM_9_WIRE; /* Default */
+ self->settings.service_type = IRCOMM_9_WIRE; /* 9 wire as default */
+ self->settings.dce = IRCOMM_CTS | IRCOMM_CD; /* Default line settings */
IRDA_DEBUG(2, __FUNCTION__ "(), IrCOMM device\n");
} else {
IRDA_DEBUG(2, __FUNCTION__ "(), IrLPT device\n");
* will have to wait for the peer device (DCE) to raise the CTS
* line.
*/
- if (self->flags & ASYNC_CTS_FLOW) {
+ if ((self->flags & ASYNC_CTS_FLOW) && ((self->settings.dce & IRCOMM_CTS) == 0)) {
IRDA_DEBUG(0, __FUNCTION__ "(), waiting for CTS ...\n");
return;
} else {