Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
L
linux
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
linux
Commits
2b3163d4
Commit
2b3163d4
authored
Mar 16, 2003
by
Paul Mackerras
Browse files
Options
Browse Files
Download
Plain Diff
Merge samba.org:/home/paulus/kernel/linux-2.5
into samba.org:/home/paulus/kernel/for-linus-ppc
parents
ac912b2b
baf1aaad
Changes
46
Hide whitespace changes
Inline
Side-by-side
Showing
46 changed files
with
3814 additions
and
1017 deletions
+3814
-1017
Documentation/hw_random.txt
Documentation/hw_random.txt
+0
-0
Documentation/md.txt
Documentation/md.txt
+64
-4
arch/i386/kernel/cpu/centaur.c
arch/i386/kernel/cpu/centaur.c
+32
-15
arch/i386/kernel/cpu/common.c
arch/i386/kernel/cpu/common.c
+3
-2
arch/i386/kernel/cpu/proc.c
arch/i386/kernel/cpu/proc.c
+14
-1
arch/i386/kernel/dmi_scan.c
arch/i386/kernel/dmi_scan.c
+3
-0
drivers/base/platform.c
drivers/base/platform.c
+3
-1
drivers/char/Kconfig
drivers/char/Kconfig
+6
-25
drivers/char/Makefile
drivers/char/Makefile
+1
-2
drivers/char/amd768_rng.c
drivers/char/amd768_rng.c
+0
-295
drivers/char/hw_random.c
drivers/char/hw_random.c
+630
-0
drivers/i2c/busses/Kconfig
drivers/i2c/busses/Kconfig
+60
-0
drivers/i2c/busses/Makefile
drivers/i2c/busses/Makefile
+3
-0
drivers/i2c/busses/i2c-ali15x3.c
drivers/i2c/busses/i2c-ali15x3.c
+575
-0
drivers/i2c/busses/i2c-amd756.c
drivers/i2c/busses/i2c-amd756.c
+3
-0
drivers/i2c/busses/i2c-amd8111.c
drivers/i2c/busses/i2c-amd8111.c
+4
-1
drivers/i2c/busses/i2c-i801.c
drivers/i2c/busses/i2c-i801.c
+715
-0
drivers/i2c/busses/i2c-piix4.c
drivers/i2c/busses/i2c-piix4.c
+521
-0
drivers/i2c/i2c-core.c
drivers/i2c/i2c-core.c
+140
-87
drivers/i2c/i2c-proc.c
drivers/i2c/i2c-proc.c
+80
-100
drivers/md/linear.c
drivers/md/linear.c
+8
-10
drivers/md/md.c
drivers/md/md.c
+666
-289
drivers/md/multipath.c
drivers/md/multipath.c
+12
-14
drivers/md/raid0.c
drivers/md/raid0.c
+13
-14
drivers/md/raid1.c
drivers/md/raid1.c
+23
-27
drivers/md/raid5.c
drivers/md/raid5.c
+26
-30
fs/lockd/svclock.c
fs/lockd/svclock.c
+6
-2
fs/nfsd/export.c
fs/nfsd/export.c
+12
-3
fs/nfsd/vfs.c
fs/nfsd/vfs.c
+19
-3
fs/reiserfs/journal.c
fs/reiserfs/journal.c
+36
-40
include/asm-generic/xor.h
include/asm-generic/xor.h
+20
-20
include/asm-i386/cpufeature.h
include/asm-i386/cpufeature.h
+8
-2
include/asm-i386/msr.h
include/asm-i386/msr.h
+1
-0
include/asm-i386/xor.h
include/asm-i386/xor.h
+1
-0
include/linux/device.h
include/linux/device.h
+1
-0
include/linux/i2c.h
include/linux/i2c.h
+5
-0
include/linux/nfsd/export.h
include/linux/nfsd/export.h
+4
-3
include/linux/raid/md.h
include/linux/raid/md.h
+5
-3
include/linux/raid/md_k.h
include/linux/raid/md_k.h
+24
-12
include/linux/raid/md_p.h
include/linux/raid/md_p.h
+53
-0
include/linux/raid/multipath.h
include/linux/raid/multipath.h
+0
-1
include/linux/raid/raid1.h
include/linux/raid/raid1.h
+0
-2
include/linux/raid/raid5.h
include/linux/raid/raid5.h
+0
-2
include/linux/sunrpc/cache.h
include/linux/sunrpc/cache.h
+1
-0
net/sunrpc/svcauth_unix.c
net/sunrpc/svcauth_unix.c
+6
-4
net/sunrpc/svcsock.c
net/sunrpc/svcsock.c
+7
-3
No files found.
Documentation/
i810_rng
.txt
→
Documentation/
hw_random
.txt
View file @
2b3163d4
File moved
Documentation/md.txt
View file @
2b3163d4
Tools that manage md devices can be found at
http://www.<country>.kernel.org/pub/linux/
daemon
s/raid/....
http://www.<country>.kernel.org/pub/linux/
util
s/raid/....
You can boot
(if you selected boot support in the configuration) with your md
device with the following kernel command
lines:
You can boot
with your md device with the following kernel command
lines:
for old raid arrays without persistent superblocks:
md=<md device no.>,<raid level>,<chunk size factor>,<fault level>,dev0,dev1,...,devn
...
...
@@ -33,4 +33,64 @@ dev0-devn: e.g. /dev/hda1,/dev/hdc1,/dev/sda1,/dev/sdb1
A possible loadlin line (Harald Hoyer <HarryH@Royal.Net>) looks like this:
e:\loadlin\loadlin e:\zimage root=/dev/md0 md=0,0,4,0,/dev/hdb2,/dev/hdc3 ro
-------------------------------
The md driver can support a variety of different superblock formats.
(It doesn't yet, but it can)
The kernel does *NOT* autodetect which format superblock is being
used. It must be told.
Superblock format '0' is treated differently to others for legacy
reasons.
General Rules - apply for all superblock formats
------------------------------------------------
An array is 'created' by writing appropriate superblocks to all
devices.
It is 'assembled' by associating each of these devices with an
particular md virtual device. Once it is completely assembled, it can
be accessed.
An array should be created by a user-space tool. This will write
superblocks to all devices. It will usually mark the array as
'unclean', or with some devices missing so that the kernel md driver
can create approrpriate redundancy (copying in raid1, parity
calculation in raid4/5).
When an array is assembled, it is first initialised with the
SET_ARRAY_INFO ioctl. This contains, in particular, a major and minor
version number. The major version number selects which superblock
format is to be used. The minor number might be used to tune handling
of the format, such as suggesting where on each device to look for the
superblock.
Then each device is added using the ADD_NEW_DISK ioctl. This
provides, in particular, a major and minor number identifying the
device to add.
The array is started with the RUN_ARRAY ioctl.
Once started, new devices can be added. They should have an
appropriate superblock written to them, and then passed be in with
ADD_NEW_DISK.
Devices that have failed or are not yet active can be detached from an
array using HOT_REMOVE_DISK.
Specific Rules that apply to format-0 super block arrays, and
arrays with no superblock (non-presistant).
-------------------------------------------------------------
An array can be 'created' by describing the array (level, chunksize
etc) in a SET_ARRAY_INFO ioctl. This must has major_version==0 and
raid_disks != 0.
Then uninitialised devices can be added with ADD_NEW_DISK. The
structure passed to ADD_NEW_DISK must specify the state of the device
and it's role in the array.
One started with RUN_ARRAY, uninitialised spares can be added with
HOT_ADD_DISK.
arch/i386/kernel/cpu/centaur.c
View file @
2b3163d4
...
...
@@ -248,6 +248,37 @@ static void __init winchip2_protect_mcr(void)
}
#endif
static
void
__init
init_c3
(
struct
cpuinfo_x86
*
c
)
{
u32
lo
,
hi
;
/* Test for Centaur Extended Feature Flags presence */
if
(
cpuid_eax
(
0xC0000000
)
>=
0xC0000001
)
{
/* store Centaur Extended Feature Flags as
* word 5 of the CPU capability bit array
*/
c
->
x86_capability
[
5
]
=
cpuid_edx
(
0xC0000001
);
}
switch
(
c
->
x86_model
)
{
case
6
...
8
:
/* Cyrix III family */
rdmsr
(
MSR_VIA_FCR
,
lo
,
hi
);
lo
|=
(
1
<<
1
|
1
<<
7
);
/* Report CX8 & enable PGE */
wrmsr
(
MSR_VIA_FCR
,
lo
,
hi
);
set_bit
(
X86_FEATURE_CX8
,
c
->
x86_capability
);
set_bit
(
X86_FEATURE_3DNOW
,
c
->
x86_capability
);
/* fall through */
case
9
:
/* Nehemiah */
default:
get_model_name
(
c
);
display_cacheinfo
(
c
);
break
;
}
}
static
void
__init
init_centaur
(
struct
cpuinfo_x86
*
c
)
{
enum
{
...
...
@@ -386,21 +417,7 @@ static void __init init_centaur(struct cpuinfo_x86 *c)
break
;
case
6
:
switch
(
c
->
x86_model
)
{
case
6
...
8
:
/* Cyrix III family */
rdmsr
(
MSR_VIA_FCR
,
lo
,
hi
);
lo
|=
(
1
<<
1
|
1
<<
7
);
/* Report CX8 & enable PGE */
wrmsr
(
MSR_VIA_FCR
,
lo
,
hi
);
set_bit
(
X86_FEATURE_CX8
,
c
->
x86_capability
);
set_bit
(
X86_FEATURE_3DNOW
,
c
->
x86_capability
);
case
9
:
/* Nehemiah */
default:
get_model_name
(
c
);
display_cacheinfo
(
c
);
break
;
}
init_c3
(
c
);
break
;
}
}
...
...
arch/i386/kernel/cpu/common.c
View file @
2b3163d4
...
...
@@ -211,9 +211,10 @@ void __init generic_identify(struct cpuinfo_x86 * c)
/* Intel-defined flags: level 0x00000001 */
if
(
c
->
cpuid_level
>=
0x00000001
)
{
u32
capability
;
cpuid
(
0x00000001
,
&
tfms
,
&
junk
,
&
junk
,
&
capability
);
u32
capability
,
excap
;
cpuid
(
0x00000001
,
&
tfms
,
&
junk
,
&
excap
,
&
capability
);
c
->
x86_capability
[
0
]
=
capability
;
c
->
x86_capability
[
4
]
=
excap
;
c
->
x86
=
(
tfms
>>
8
)
&
15
;
c
->
x86_model
=
(
tfms
>>
4
)
&
15
;
c
->
x86_mask
=
tfms
&
15
;
...
...
arch/i386/kernel/cpu/proc.c
View file @
2b3163d4
...
...
@@ -37,7 +37,20 @@ static int show_cpuinfo(struct seq_file *m, void *v)
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
/* Other (Linux-defined) */
"cxmmx"
,
"k6_mtrr"
,
"cyrix_arr"
,
"centaur_mcr"
,
NULL
,
NULL
,
NULL
,
NULL
,
"cxmmx"
,
"k6_mtrr"
,
"cyrix_arr"
,
"centaur_mcr"
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
/* Intel-defined (#2) */
"pni"
,
NULL
,
NULL
,
"monitor"
,
"ds_cpl"
,
NULL
,
NULL
,
NULL
,
"tm2"
,
NULL
,
"cnxt_id"
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
/* VIA/Cyrix/Centaur-defined */
NULL
,
NULL
,
"xstore"
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
NULL
,
...
...
arch/i386/kernel/dmi_scan.c
View file @
2b3163d4
...
...
@@ -3,6 +3,7 @@
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/apm_bios.h>
#include <linux/slab.h>
#include <asm/io.h>
...
...
@@ -893,3 +894,5 @@ void __init dmi_scan_machine(void)
if
(
err
==
0
)
dmi_check_blacklist
();
}
EXPORT_SYMBOL
(
is_unsafe_smbus
);
drivers/base/platform.c
View file @
2b3163d4
...
...
@@ -9,7 +9,7 @@
#include <linux/module.h>
#include <linux/init.h>
st
atic
st
ruct
device
legacy_bus
=
{
struct
device
legacy_bus
=
{
.
name
=
"legacy bus"
,
.
bus_id
=
"legacy"
,
};
...
...
@@ -75,5 +75,7 @@ int __init platform_bus_init(void)
return
bus_register
(
&
platform_bus_type
);
}
EXPORT_SYMBOL
(
legacy_bus
);
EXPORT_SYMBOL
(
platform_bus_type
);
EXPORT_SYMBOL
(
platform_device_register
);
EXPORT_SYMBOL
(
platform_device_unregister
);
drivers/char/Kconfig
View file @
2b3163d4
...
...
@@ -709,39 +709,20 @@ config NWFLASH
If you're not sure, say N.
config
INTEL_RNG
tristate "Intel
i8x0
Random Number Generator support"
config
HW_RANDOM
tristate "Intel
/AMD/VIA HW
Random Number Generator support"
depends on (X86 || IA64) && PCI
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on Intel i8xx-based motherboards.
Generator hardware found on Intel i8xx-based motherboards,
AMD 76x-based motherboards, and Via Nehemiah CPUs.
Both a character driver, used to read() entropy data, and a timer
function which automatically adds entropy directly into the
kernel pool, are exported by this driver.
Provides a character driver, used to read() entropy data.
To compile this driver as a module ( = code which can be inserted in
and removed from the running kernel whenever you want), say M here
and read <file:Documentation/modules.txt>. The module will be called
i810_rng.
If unsure, say N.
config AMD_RNG
tristate "AMD 768 Random Number Generator support"
depends on X86 && PCI
---help---
This driver provides kernel-side support for the Random Number
Generator hardware found on AMD 76x based motherboards.
Both a character driver, used to read() entropy data, and a timer
function which automatically adds entropy directly into the
kernel pool, are exported by this driver.
To compile this driver as a module ( = code which can be inserted in
and removed from the running kernel whenever you want), say M here
and read <file:Documentation/modules.txt>. The module will be called
amd768_rng.
hw_random.
If unsure, say N.
...
...
drivers/char/Makefile
View file @
2b3163d4
...
...
@@ -59,8 +59,7 @@ endif
obj-$(CONFIG_TOSHIBA)
+=
toshiba.o
obj-$(CONFIG_I8K)
+=
i8k.o
obj-$(CONFIG_DS1620)
+=
ds1620.o
obj-$(CONFIG_INTEL_RNG)
+=
i810_rng.o
obj-$(CONFIG_AMD_RNG)
+=
amd768_rng.o
obj-$(CONFIG_HW_RANDOM)
+=
hw_random.o
obj-$(CONFIG_QIC02_TAPE)
+=
tpqic02.o
obj-$(CONFIG_FTAPE)
+=
ftape/
obj-$(CONFIG_H8)
+=
h8.o
...
...
drivers/char/amd768_rng.c
deleted
100644 → 0
View file @
ac912b2b
/*
Hardware driver for the AMD 768 Random Number Generator (RNG)
(c) Copyright 2001 Red Hat Inc <alan@redhat.com>
derived from
Hardware driver for Intel i810 Random Number Generator (RNG)
Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
Please read Documentation/i810_rng.txt for details on use.
----------------------------------------------------------
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
*/
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/fs.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/interrupt.h>
#include <linux/spinlock.h>
#include <linux/random.h>
#include <linux/miscdevice.h>
#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <asm/uaccess.h>
/*
* core module and version information
*/
#define RNG_VERSION "0.1.0"
#define RNG_MODULE_NAME "amd768_rng"
#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION
#define PFX RNG_MODULE_NAME ": "
/*
* debugging macros
*/
#undef RNG_DEBUG
/* define to enable copious debugging info */
#ifdef RNG_DEBUG
/* note: prints function name for you */
#define DPRINTK(fmt, args...) printk(KERN_DEBUG "%s: " fmt, __FUNCTION__ , ## args)
#else
#define DPRINTK(fmt, args...)
#endif
#undef RNG_NDEBUG
/* define to disable lightweight runtime checks */
#ifdef RNG_NDEBUG
#define assert(expr)
#else
#define assert(expr) \
if(!(expr)) { \
printk( "Assertion failed! %s,%s,%s,line=%d\n", \
#expr,__FILE__,__FUNCTION__,__LINE__); \
}
#endif
#define RNG_MISCDEV_MINOR 183
/* official */
/*
* various RNG status variables. they are globals
* as we only support a single RNG device
*/
static
u32
pmbase
;
/* PMxx I/O base */
static
struct
semaphore
rng_open_sem
;
/* Semaphore for serializing rng_open/release */
/*
* inlined helper functions for accessing RNG registers
*/
static
inline
int
rng_data_present
(
void
)
{
return
inl
(
pmbase
+
0xF4
)
&
1
;
}
static
inline
int
rng_data_read
(
void
)
{
return
inl
(
pmbase
+
0xF0
);
}
static
int
rng_dev_open
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
if
((
filp
->
f_mode
&
FMODE_READ
)
==
0
)
return
-
EINVAL
;
if
(
filp
->
f_mode
&
FMODE_WRITE
)
return
-
EINVAL
;
/* wait for device to become free */
if
(
filp
->
f_flags
&
O_NONBLOCK
)
{
if
(
down_trylock
(
&
rng_open_sem
))
return
-
EAGAIN
;
}
else
{
if
(
down_interruptible
(
&
rng_open_sem
))
return
-
ERESTARTSYS
;
}
return
0
;
}
static
int
rng_dev_release
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
up
(
&
rng_open_sem
);
return
0
;
}
static
ssize_t
rng_dev_read
(
struct
file
*
filp
,
char
*
buf
,
size_t
size
,
loff_t
*
offp
)
{
static
spinlock_t
rng_lock
=
SPIN_LOCK_UNLOCKED
;
int
have_data
;
u32
data
=
0
;
ssize_t
ret
=
0
;
while
(
size
)
{
spin_lock
(
&
rng_lock
);
have_data
=
0
;
if
(
rng_data_present
())
{
data
=
rng_data_read
();
have_data
=
4
;
}
spin_unlock
(
&
rng_lock
);
while
(
have_data
>
0
)
{
if
(
put_user
((
u8
)
data
,
buf
++
))
{
ret
=
ret
?
:
-
EFAULT
;
break
;
}
size
--
;
ret
++
;
have_data
--
;
data
>>=
8
;
}
if
(
filp
->
f_flags
&
O_NONBLOCK
)
return
ret
?
:
-
EAGAIN
;
if
(
need_resched
())
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
1
);
}
else
udelay
(
200
);
/* FIXME: We could poll for 250uS ?? */
if
(
signal_pending
(
current
))
return
ret
?
:
-
ERESTARTSYS
;
}
return
ret
;
}
static
struct
file_operations
rng_chrdev_ops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
rng_dev_open
,
.
release
=
rng_dev_release
,
.
read
=
rng_dev_read
,
};
static
struct
miscdevice
rng_miscdev
=
{
RNG_MISCDEV_MINOR
,
RNG_MODULE_NAME
,
&
rng_chrdev_ops
,
};
/*
* rng_init_one - look for and attempt to init a single RNG
*/
static
int
__init
rng_init_one
(
struct
pci_dev
*
dev
)
{
int
rc
;
u8
rnen
;
DPRINTK
(
"ENTER
\n
"
);
rc
=
misc_register
(
&
rng_miscdev
);
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"cannot register misc device
\n
"
);
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
goto
err_out
;
}
pci_read_config_dword
(
dev
,
0x58
,
&
pmbase
);
pmbase
&=
0x0000FF00
;
if
(
pmbase
==
0
)
{
printk
(
KERN_ERR
PFX
"power management base not set
\n
"
);
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
goto
err_out_free_miscdev
;
}
pci_read_config_byte
(
dev
,
0x40
,
&
rnen
);
rnen
|=
(
1
<<
7
);
/* RNG on */
pci_write_config_byte
(
dev
,
0x40
,
rnen
);
pci_read_config_byte
(
dev
,
0x41
,
&
rnen
);
rnen
|=
(
1
<<
7
);
/* PMIO enable */
pci_write_config_byte
(
dev
,
0x41
,
rnen
);
printk
(
KERN_INFO
PFX
"AMD768 system management I/O registers at 0x%X.
\n
"
,
pmbase
);
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
err_out_free_miscdev:
misc_deregister
(
&
rng_miscdev
);
err_out:
return
rc
;
}
/*
* Data for PCI driver interface
*
* This data only exists for exporting the supported
* PCI ids via MODULE_DEVICE_TABLE. We do not actually
* register a pci_driver, because someone else might one day
* want to register another driver on the same PCI id.
*/
static
struct
pci_device_id
rng_pci_tbl
[]
__initdata
=
{
{
0x1022
,
0x7443
,
PCI_ANY_ID
,
PCI_ANY_ID
,
},
{
0
,
},
};
MODULE_DEVICE_TABLE
(
pci
,
rng_pci_tbl
);
MODULE_AUTHOR
(
"Alan Cox, Jeff Garzik, Philipp Rumpf, Matt Sottek"
);
MODULE_DESCRIPTION
(
"AMD 768 Random Number Generator (RNG) driver"
);
MODULE_LICENSE
(
"GPL"
);
/*
* rng_init - initialize RNG module
*/
static
int
__init
rng_init
(
void
)
{
int
rc
;
struct
pci_dev
*
pdev
;
DPRINTK
(
"ENTER
\n
"
);
init_MUTEX
(
&
rng_open_sem
);
pci_for_each_dev
(
pdev
)
{
if
(
pci_match_device
(
rng_pci_tbl
,
pdev
)
!=
NULL
)
goto
match
;
}
DPRINTK
(
"EXIT, returning -ENODEV
\n
"
);
return
-
ENODEV
;
match:
rc
=
rng_init_one
(
pdev
);
if
(
rc
)
return
rc
;
printk
(
KERN_INFO
RNG_DRIVER_NAME
" loaded
\n
"
);
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
}
/*
* rng_init - shutdown RNG module
*/
static
void
__exit
rng_cleanup
(
void
)
{
DPRINTK
(
"ENTER
\n
"
);
misc_deregister
(
&
rng_miscdev
);
DPRINTK
(
"EXIT
\n
"
);
}
module_init
(
rng_init
);
module_exit
(
rng_cleanup
);
drivers/char/
i810_rng
.c
→
drivers/char/
hw_random
.c
View file @
2b3163d4
/*
Hardware driver for the Intel/AMD/VIA Random Number Generators (RNG)
(c) Copyright 2003 Red Hat Inc <jgarzik@redhat.com>
derived from
Hardware driver for the AMD 768 Random Number Generator (RNG)
(c) Copyright 2001 Red Hat Inc <alan@redhat.com>
derived from
Hardware driver for Intel i810 Random Number Generator (RNG)
Copyright 2000,2001 Jeff Garzik <jgarzik@pobox.com>
Copyright 2000,2001 Philipp Rumpf <prumpf@mandrakesoft.com>
Driver Web site: http://sourceforge.net/projects/gkernel/
Please read Documentation/i810_rng.txt for details on use.
Please read Documentation/hw_random.txt for details on use.
----------------------------------------------------------
This software may be used and distributed according to the terms
of the GNU General Public License, incorporated herein by reference.
...
...
@@ -29,6 +35,11 @@
#include <linux/mm.h>
#include <linux/delay.h>
#ifdef __i386__
#include <asm/msr.h>
#include <asm/cpufeature.h>
#endif
#include <asm/io.h>
#include <asm/uaccess.h>
...
...
@@ -36,8 +47,8 @@
/*
* core module and version information
*/
#define RNG_VERSION "0.9.
8
"
#define RNG_MODULE_NAME "
i810_rng
"
#define RNG_VERSION "0.9.
0
"
#define RNG_MODULE_NAME "
hw_random
"
#define RNG_DRIVER_NAME RNG_MODULE_NAME " hardware driver " RNG_VERSION
#define PFX RNG_MODULE_NAME ": "
...
...
@@ -54,7 +65,7 @@
#define DPRINTK(fmt, args...)
#endif
#
undef
RNG_NDEBUG
/* define to disable lightweight runtime checks */
#
define
RNG_NDEBUG
/* define to disable lightweight runtime checks */
#ifdef RNG_NDEBUG
#define assert(expr)
#else
...
...
@@ -65,150 +76,405 @@
}
#endif
#define RNG_MISCDEV_MINOR 183
/* official */
/*
* RNG registers (offsets from rng_mem)
*/
#define RNG_HW_STATUS 0
#define RNG_PRESENT 0x40
#define RNG_ENABLED 0x01
#define RNG_STATUS 1
#define RNG_DATA_PRESENT 0x01
#define RNG_DATA 2
static
int
rng_dev_open
(
struct
inode
*
inode
,
struct
file
*
filp
);
static
ssize_t
rng_dev_read
(
struct
file
*
filp
,
char
*
buf
,
size_t
size
,
loff_t
*
offp
);
static
int
__init
intel_init
(
struct
pci_dev
*
dev
);
static
void
intel_cleanup
(
void
);
static
unsigned
int
intel_data_present
(
void
);
static
u32
intel_data_read
(
void
);
static
int
__init
amd_init
(
struct
pci_dev
*
dev
);
static
void
amd_cleanup
(
void
);
static
unsigned
int
amd_data_present
(
void
);
static
u32
amd_data_read
(
void
);
static
int
__init
via_init
(
struct
pci_dev
*
dev
);
static
void
via_cleanup
(
void
);
static
unsigned
int
via_data_present
(
void
);
static
u32
via_data_read
(
void
);
struct
rng_operations
{
int
(
*
init
)
(
struct
pci_dev
*
dev
);
void
(
*
cleanup
)
(
void
);
unsigned
int
(
*
data_present
)
(
void
);
u32
(
*
data_read
)
(
void
);
unsigned
int
n_bytes
;
/* number of bytes per ->data_read */
};
static
struct
rng_operations
*
rng_ops
;
static
struct
file_operations
rng_chrdev_ops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
rng_dev_open
,
.
read
=
rng_dev_read
,
};
static
struct
miscdevice
rng_miscdev
=
{
RNG_MISCDEV_MINOR
,
RNG_MODULE_NAME
,
&
rng_chrdev_ops
,
};
enum
{
rng_hw_none
,
rng_hw_intel
,
rng_hw_amd
,
rng_hw_via
,
};
static
struct
rng_operations
rng_vendor_ops
[]
__initdata
=
{
/* rng_hw_none */
{
},
/* rng_hw_intel */
{
intel_init
,
intel_cleanup
,
intel_data_present
,
intel_data_read
,
1
},
/* rng_hw_amd */
{
amd_init
,
amd_cleanup
,
amd_data_present
,
amd_data_read
,
4
},
/* rng_hw_via */
{
via_init
,
via_cleanup
,
via_data_present
,
via_data_read
,
1
},
};
/*
* Magic address at which Intel PCI bridges locate the RNG
* Data for PCI driver interface
*
* This data only exists for exporting the supported
* PCI ids via MODULE_DEVICE_TABLE. We do not actually
* register a pci_driver, because someone else might one day
* want to register another driver on the same PCI id.
*/
#define RNG_ADDR 0xFFBC015F
#define RNG_ADDR_LEN 3
static
struct
pci_device_id
rng_pci_tbl
[]
__initdata
=
{
{
0x1022
,
0x7443
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
rng_hw_amd
},
#define RNG_MISCDEV_MINOR 183
/* official */
{
0x8086
,
0x2418
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
rng_hw_intel
},
{
0x8086
,
0x2428
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
rng_hw_intel
},
{
0x8086
,
0x2448
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
rng_hw_intel
},
{
0x8086
,
0x244e
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
rng_hw_intel
},
{
0x8086
,
0x245e
,
PCI_ANY_ID
,
PCI_ANY_ID
,
0
,
0
,
rng_hw_intel
},
/*
* various RNG status variables. they are globals
* as we only support a single RNG device
{
0
,
},
/* terminate list */
};
MODULE_DEVICE_TABLE
(
pci
,
rng_pci_tbl
);
/***********************************************************************
*
* Intel RNG operations
*
*/
static
void
*
rng_mem
;
/* token to our ioremap'd RNG register area */
static
struct
semaphore
rng_open_sem
;
/* Semaphore for serializing rng_open/release */
/*
* RNG registers (offsets from rng_mem)
*/
#define INTEL_RNG_HW_STATUS 0
#define INTEL_RNG_PRESENT 0x40
#define INTEL_RNG_ENABLED 0x01
#define INTEL_RNG_STATUS 1
#define INTEL_RNG_DATA_PRESENT 0x01
#define INTEL_RNG_DATA 2
/*
*
inlined helper functions for accessing RNG registers
*
Magic address at which Intel PCI bridges locate the RNG
*/
static
inline
u8
rng_hwstatus
(
void
)
#define INTEL_RNG_ADDR 0xFFBC015F
#define INTEL_RNG_ADDR_LEN 3
/* token to our ioremap'd RNG register area */
static
void
*
rng_mem
;
static
inline
u8
intel_hwstatus
(
void
)
{
assert
(
rng_mem
!=
NULL
);
return
readb
(
rng_mem
+
RNG_HW_STATUS
);
return
readb
(
rng_mem
+
INTEL_
RNG_HW_STATUS
);
}
static
inline
u8
rng
_hwstatus_set
(
u8
hw_status
)
static
inline
u8
intel
_hwstatus_set
(
u8
hw_status
)
{
assert
(
rng_mem
!=
NULL
);
writeb
(
hw_status
,
rng_mem
+
RNG_HW_STATUS
);
return
rng
_hwstatus
();
writeb
(
hw_status
,
rng_mem
+
INTEL_
RNG_HW_STATUS
);
return
intel
_hwstatus
();
}
static
inline
int
rng_data_present
(
void
)
static
unsigned
int
intel_data_present
(
void
)
{
assert
(
rng_mem
!=
NULL
);
return
(
readb
(
rng_mem
+
RNG_STATUS
)
&
RNG_DATA_PRESENT
)
?
1
:
0
;
return
(
readb
(
rng_mem
+
INTEL_RNG_STATUS
)
&
INTEL_RNG_DATA_PRESENT
)
?
1
:
0
;
}
static
inline
int
rng_data_read
(
void
)
static
u32
intel_data_read
(
void
)
{
assert
(
rng_mem
!=
NULL
);
return
readb
(
rng_mem
+
RNG_DATA
);
return
readb
(
rng_mem
+
INTEL_
RNG_DATA
);
}
/*
* rng_enable - enable the RNG hardware
*/
static
int
rng_enable
(
void
)
static
int
__init
intel_init
(
struct
pci_dev
*
dev
)
{
int
rc
=
0
;
u8
hw_status
,
new_status
;
int
rc
;
u8
hw_status
;
DPRINTK
(
"ENTER
\n
"
);
hw_status
=
rng_hwstatus
();
rng_mem
=
ioremap
(
INTEL_RNG_ADDR
,
INTEL_RNG_ADDR_LEN
);
if
(
rng_mem
==
NULL
)
{
printk
(
KERN_ERR
PFX
"cannot ioremap RNG Memory
\n
"
);
rc
=
-
EBUSY
;
goto
err_out
;
}
if
((
hw_status
&
RNG_ENABLED
)
==
0
)
{
new_status
=
rng_hwstatus_set
(
hw_status
|
RNG_ENABLED
);
/* Check for Intel 82802 */
hw_status
=
intel_hwstatus
();
if
((
hw_status
&
INTEL_RNG_PRESENT
)
==
0
)
{
printk
(
KERN_ERR
PFX
"RNG not detected
\n
"
);
rc
=
-
ENODEV
;
goto
err_out_free_map
;
}
if
(
new_status
&
RNG_ENABLED
)
printk
(
KERN_INFO
PFX
"RNG h/w enabled
\n
"
);
else
{
printk
(
KERN_ERR
PFX
"Unable to enable the RNG
\n
"
);
rc
=
-
EIO
;
}
/* turn RNG h/w on, if it's off */
if
((
hw_status
&
INTEL_RNG_ENABLED
)
==
0
)
hw_status
=
intel_hwstatus_set
(
hw_status
|
INTEL_RNG_ENABLED
);
if
((
hw_status
&
INTEL_RNG_ENABLED
)
==
0
)
{
printk
(
KERN_ERR
PFX
"cannot enable RNG, aborting
\n
"
);
rc
=
-
EIO
;
goto
err_out_free_map
;
}
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
err_out_free_map:
iounmap
(
rng_mem
);
rng_mem
=
NULL
;
err_out:
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
return
rc
;
}
/*
* rng_disable - disable the RNG hardware
static
void
intel_cleanup
(
void
)
{
u8
hw_status
;
hw_status
=
intel_hwstatus
();
if
(
hw_status
&
INTEL_RNG_ENABLED
)
intel_hwstatus_set
(
hw_status
&
~
INTEL_RNG_ENABLED
);
else
printk
(
KERN_WARNING
PFX
"unusual: RNG already disabled
\n
"
);
iounmap
(
rng_mem
);
rng_mem
=
NULL
;
}
/***********************************************************************
*
* AMD RNG operations
*
*/
static
void
rng_disable
(
void
)
static
u32
pmbase
;
/* PMxx I/O base */
static
struct
pci_dev
*
amd_dev
;
static
unsigned
int
amd_data_present
(
void
)
{
return
inl
(
pmbase
+
0xF4
)
&
1
;
}
static
u32
amd_data_read
(
void
)
{
return
inl
(
pmbase
+
0xF0
);
}
static
int
__init
amd_init
(
struct
pci_dev
*
dev
)
{
u8
hw_status
,
new_status
;
int
rc
;
u8
rnen
;
DPRINTK
(
"ENTER
\n
"
);
hw_status
=
rng_hwstatus
(
);
pci_read_config_dword
(
dev
,
0x58
,
&
pmbase
);
if
(
hw_status
&
RNG_ENABLED
)
{
new_status
=
rng_hwstatus_set
(
hw_status
&
~
RNG_ENABLED
);
if
((
new_status
&
RNG_ENABLED
)
==
0
)
printk
(
KERN_INFO
PFX
"RNG h/w disabled
\n
"
);
else
{
printk
(
KERN_ERR
PFX
"Unable to disable the RNG
\n
"
);
}
pmbase
&=
0x0000FF00
;
if
(
pmbase
==
0
)
{
printk
(
KERN_ERR
PFX
"power management base not set
\n
"
);
rc
=
-
EIO
;
goto
err_out
;
}
DPRINTK
(
"EXIT
\n
"
);
pci_read_config_byte
(
dev
,
0x40
,
&
rnen
);
rnen
|=
(
1
<<
7
);
/* RNG on */
pci_write_config_byte
(
dev
,
0x40
,
rnen
);
pci_read_config_byte
(
dev
,
0x41
,
&
rnen
);
rnen
|=
(
1
<<
7
);
/* PMIO enable */
pci_write_config_byte
(
dev
,
0x41
,
rnen
);
printk
(
KERN_INFO
PFX
"AMD768 system management I/O registers at 0x%X.
\n
"
,
pmbase
);
amd_dev
=
dev
;
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
err_out:
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
return
rc
;
}
static
int
rng_dev_open
(
struct
inode
*
inode
,
struct
file
*
filp
)
static
void
amd_cleanup
(
void
)
{
int
rc
;
u8
rnen
;
if
((
filp
->
f_mode
&
FMODE_READ
)
==
0
)
return
-
EINVAL
;
if
(
filp
->
f_mode
&
FMODE_WRITE
)
return
-
EINVAL
;
pci_read_config_byte
(
amd_dev
,
0x40
,
&
rnen
);
rnen
&=
~
(
1
<<
7
);
/* RNG off */
pci_write_config_byte
(
amd_dev
,
0x40
,
rnen
);
/* wait for device to become free */
if
(
filp
->
f_flags
&
O_NONBLOCK
)
{
if
(
down_trylock
(
&
rng_open_sem
))
return
-
EAGAIN
;
}
else
{
if
(
down_interruptible
(
&
rng_open_sem
))
return
-
ERESTARTSYS
;
}
/* FIXME: twiddle pmio, also? */
}
rc
=
rng_enable
();
if
(
rc
)
{
up
(
&
rng_open_sem
);
return
rc
;
/***********************************************************************
*
* VIA RNG operations
*
*/
enum
{
VIA_STRFILT_CNT_SHIFT
=
16
,
VIA_STRFILT_FAIL
=
(
1
<<
15
),
VIA_STRFILT_ENABLE
=
(
1
<<
14
),
VIA_RAWBITS_ENABLE
=
(
1
<<
13
),
VIA_RNG_ENABLE
=
(
1
<<
6
),
VIA_XSTORE_CNT_MASK
=
0x0F
,
VIA_RNG_CHUNK_8
=
0x00
,
/* 64 rand bits, 64 stored bits */
VIA_RNG_CHUNK_4
=
0x01
,
/* 32 rand bits, 32 stored bits */
VIA_RNG_CHUNK_4_MASK
=
0xFFFFFFFF
,
VIA_RNG_CHUNK_2
=
0x02
,
/* 16 rand bits, 32 stored bits */
VIA_RNG_CHUNK_2_MASK
=
0xFFFF
,
VIA_RNG_CHUNK_1
=
0x03
,
/* 8 rand bits, 32 stored bits */
VIA_RNG_CHUNK_1_MASK
=
0xFF
,
};
u32
via_rng_datum
;
/*
* Investigate using the 'rep' prefix to obtain 32 bits of random data
* in one insn. The upside is potentially better performance. The
* downside is that the instruction becomes no longer atomic. Due to
* this, just like familiar issues with /dev/random itself, the worst
* case of a 'rep xstore' could potentially pause a cpu for an
* unreasonably long time. In practice, this condition would likely
* only occur when the hardware is failing. (or so we hope :))
*
* Another possible performance boost may come from simply buffering
* until we have 4 bytes, thus returning a u32 at a time,
* instead of the current u8-at-a-time.
*/
static
inline
u32
xstore
(
u32
*
addr
,
u32
edx_in
)
{
u32
eax_out
;
asm
(
".byte 0x0F,0xA7,0xC0 /* xstore %%edi (addr=%0) */"
:
"=m"
(
*
addr
),
"=a"
(
eax_out
)
:
"D"
(
addr
),
"d"
(
edx_in
));
return
eax_out
;
}
static
unsigned
int
via_data_present
(
void
)
{
u32
bytes_out
;
/* We choose the recommended 1-byte-per-instruction RNG rate,
* for greater randomness at the expense of speed. Larger
* values 2, 4, or 8 bytes-per-instruction yield greater
* speed at lesser randomness.
*
* If you change this to another VIA_CHUNK_n, you must also
* change the ->n_bytes values in rng_vendor_ops[] tables.
* VIA_CHUNK_8 requires further code changes.
*
* A copy of MSR_VIA_RNG is placed in eax_out when xstore
* completes.
*/
via_rng_datum
=
0
;
/* paranoia, not really necessary */
bytes_out
=
xstore
(
&
via_rng_datum
,
VIA_RNG_CHUNK_1
)
&
VIA_XSTORE_CNT_MASK
;
if
(
bytes_out
==
0
)
return
0
;
return
1
;
}
static
u32
via_data_read
(
void
)
{
return
via_rng_datum
;
}
static
int
__init
via_init
(
struct
pci_dev
*
dev
)
{
u32
lo
,
hi
,
old_lo
;
/* Control the RNG via MSR. Tread lightly and pay very close
* close attention to values written, as the reserved fields
* are documented to be "undefined and unpredictable"; but it
* does not say to write them as zero, so I make a guess that
* we restore the values we find in the register.
*/
rdmsr
(
MSR_VIA_RNG
,
lo
,
hi
);
old_lo
=
lo
;
lo
&=
~
(
0x7f
<<
VIA_STRFILT_CNT_SHIFT
);
lo
&=
~
VIA_XSTORE_CNT_MASK
;
lo
&=
~
(
VIA_STRFILT_ENABLE
|
VIA_STRFILT_FAIL
|
VIA_RAWBITS_ENABLE
);
lo
|=
VIA_RNG_ENABLE
;
if
(
lo
!=
old_lo
)
wrmsr
(
MSR_VIA_RNG
,
lo
,
hi
);
/* perhaps-unnecessary sanity check; remove after testing if
unneeded */
rdmsr
(
MSR_VIA_RNG
,
lo
,
hi
);
if
((
lo
&
VIA_RNG_ENABLE
)
==
0
)
{
printk
(
KERN_ERR
PFX
"cannot enable VIA C3 RNG, aborting
\n
"
);
return
-
ENODEV
;
}
return
0
;
}
static
void
via_cleanup
(
void
)
{
u32
lo
,
hi
;
rdmsr
(
MSR_VIA_RNG
,
lo
,
hi
);
lo
&=
~
VIA_RNG_ENABLE
;
wrmsr
(
MSR_VIA_RNG
,
lo
,
hi
);
}
static
int
rng_dev_release
(
struct
inode
*
inode
,
struct
file
*
filp
)
/***********************************************************************
*
* /dev/hwrandom character device handling (major 10, minor 183)
*
*/
static
int
rng_dev_open
(
struct
inode
*
inode
,
struct
file
*
filp
)
{
rng_disable
();
up
(
&
rng_open_sem
);
/* enforce read-only access to this chrdev */
if
((
filp
->
f_mode
&
FMODE_READ
)
==
0
)
return
-
EINVAL
;
if
(
filp
->
f_mode
&
FMODE_WRITE
)
return
-
EINVAL
;
return
0
;
}
...
...
@@ -217,63 +483,50 @@ static ssize_t rng_dev_read (struct file *filp, char *buf, size_t size,
loff_t
*
offp
)
{
static
spinlock_t
rng_lock
=
SPIN_LOCK_UNLOCKED
;
int
have_data
;
u
8
data
=
0
;
unsigned
int
have_data
;
u
32
data
=
0
;
ssize_t
ret
=
0
;
while
(
size
)
{
spin_lock
(
&
rng_lock
);
spin_lock
(
&
rng_lock
);
have_data
=
0
;
if
(
rng_
data_present
())
{
data
=
rng_
data_read
();
have_data
=
1
;
if
(
rng_
ops
->
data_present
())
{
data
=
rng_
ops
->
data_read
();
have_data
=
rng_ops
->
n_bytes
;
}
spin_unlock
(
&
rng_lock
);
if
(
have_data
)
{
if
(
put_user
(
data
,
buf
++
))
{
while
(
have_data
>
0
)
{
if
(
put_user
((
u8
)
data
,
buf
++
))
{
ret
=
ret
?
:
-
EFAULT
;
break
;
}
size
--
;
ret
++
;
have_data
--
;
data
>>=
8
;
}
if
(
filp
->
f_flags
&
O_NONBLOCK
)
return
ret
?
:
-
EAGAIN
;
if
(
need_resched
())
if
(
need_resched
())
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
1
);
}
else
udelay
(
200
);
udelay
(
200
);
/* FIXME: We could poll for 250uS ?? */
if
(
signal_pending
(
current
))
return
ret
?
:
-
ERESTARTSYS
;
}
return
ret
;
}
static
struct
file_operations
rng_chrdev_ops
=
{
.
owner
=
THIS_MODULE
,
.
open
=
rng_dev_open
,
.
release
=
rng_dev_release
,
.
read
=
rng_dev_read
,
};
static
struct
miscdevice
rng_miscdev
=
{
RNG_MISCDEV_MINOR
,
RNG_MODULE_NAME
,
&
rng_chrdev_ops
,
};
/*
* rng_init_one - look for and attempt to init a single RNG
...
...
@@ -281,75 +534,35 @@ static struct miscdevice rng_miscdev = {
static
int
__init
rng_init_one
(
struct
pci_dev
*
dev
)
{
int
rc
;
u8
hw_status
;
DPRINTK
(
"ENTER
\n
"
);
rc
=
misc_register
(
&
rng_miscdev
);
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"cannot register misc device
\n
"
);
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
goto
err_out
;
}
rng_mem
=
ioremap
(
RNG_ADDR
,
RNG_ADDR_LEN
);
if
(
rng_mem
==
NULL
)
{
printk
(
KERN_ERR
PFX
"cannot ioremap RNG Memory
\n
"
);
DPRINTK
(
"EXIT, returning -EBUSY
\n
"
);
rc
=
-
EBUSY
;
goto
err_out_free_miscdev
;
}
assert
(
rng_ops
!=
NULL
);
/* Check for Intel 82802 */
hw_status
=
rng_hwstatus
();
if
((
hw_status
&
RNG_PRESENT
)
==
0
)
{
printk
(
KERN_ERR
PFX
"RNG not detected
\n
"
);
DPRINTK
(
"EXIT, returning -ENODEV
\n
"
);
rc
=
-
ENODEV
;
goto
err_out_free_map
;
}
rc
=
rng_ops
->
init
(
dev
);
if
(
rc
)
goto
err_out
;
/* turn RNG h/w off, if it's on */
if
(
hw_status
&
RNG_ENABLED
)
hw_status
=
rng_hwstatus_set
(
hw_status
&
~
RNG_ENABLED
);
if
(
hw_status
&
RNG_ENABLED
)
{
printk
(
KERN_ERR
PFX
"cannot disable RNG, aborting
\n
"
);
goto
err_out_free_map
;
rc
=
misc_register
(
&
rng_miscdev
);
if
(
rc
)
{
printk
(
KERN_ERR
PFX
"misc device register failed
\n
"
);
goto
err_out_cleanup_hw
;
}
DPRINTK
(
"EXIT, returning 0
\n
"
);
return
0
;
err_out_free_map:
iounmap
(
rng_mem
);
err_out_free_miscdev:
misc_deregister
(
&
rng_miscdev
);
err_out_cleanup_hw:
rng_ops
->
cleanup
();
err_out:
DPRINTK
(
"EXIT, returning %d
\n
"
,
rc
);
return
rc
;
}
/*
* Data for PCI driver interface
*
* This data only exists for exporting the supported
* PCI ids via MODULE_DEVICE_TABLE. We do not actually
* register a pci_driver, because someone else might one day
* want to register another driver on the same PCI id.
*/
static
struct
pci_device_id
rng_pci_tbl
[]
__initdata
=
{
{
0x8086
,
0x2418
,
PCI_ANY_ID
,
PCI_ANY_ID
,
},
{
0x8086
,
0x2428
,
PCI_ANY_ID
,
PCI_ANY_ID
,
},
{
0x8086
,
0x2448
,
PCI_ANY_ID
,
PCI_ANY_ID
,
},
{
0x8086
,
0x244e
,
PCI_ANY_ID
,
PCI_ANY_ID
,
},
{
0x8086
,
0x245e
,
PCI_ANY_ID
,
PCI_ANY_ID
,
},
{
0
,
},
};
MODULE_DEVICE_TABLE
(
pci
,
rng_pci_tbl
);
MODULE_AUTHOR
(
"
Jeff Garzik, Philipp Rumpf, Matt Sottek
"
);
MODULE_DESCRIPTION
(
"
Intel i8xx chipset
Random Number Generator (RNG) driver"
);
MODULE_AUTHOR
(
"
The Linux Kernel team
"
);
MODULE_DESCRIPTION
(
"
H/W
Random Number Generator (RNG) driver"
);
MODULE_LICENSE
(
"GPL"
);
...
...
@@ -360,15 +573,27 @@ static int __init rng_init (void)
{
int
rc
;
struct
pci_dev
*
pdev
;
const
struct
pci_device_id
*
ent
;
DPRINTK
(
"ENTER
\n
"
);
init_MUTEX
(
&
rng_open_sem
);
/* Probe for Intel, AMD RNGs */
pci_for_each_dev
(
pdev
)
{
if
(
pci_match_device
(
rng_pci_tbl
,
pdev
)
!=
NULL
)
ent
=
pci_match_device
(
rng_pci_tbl
,
pdev
);
if
(
ent
)
{
rng_ops
=
&
rng_vendor_ops
[
ent
->
driver_data
];
goto
match
;
}
}
#ifdef __i386__
/* Probe for VIA RNG */
if
(
cpu_has_xstore
)
{
rng_ops
=
&
rng_vendor_ops
[
rng_hw_via
];
pdev
=
NULL
;
goto
match
;
}
#endif
DPRINTK
(
"EXIT, returning -ENODEV
\n
"
);
return
-
ENODEV
;
...
...
@@ -394,7 +619,8 @@ static void __exit rng_cleanup (void)
misc_deregister
(
&
rng_miscdev
);
iounmap
(
rng_mem
);
if
(
rng_ops
->
cleanup
)
rng_ops
->
cleanup
();
DPRINTK
(
"EXIT
\n
"
);
}
...
...
drivers/i2c/busses/Kconfig
View file @
2b3163d4
...
...
@@ -5,6 +5,20 @@
menu "I2C Hardware Sensors Mainboard support"
config I2C_ALI15X3
tristate " ALI 15x3"
depends on I2C && I2C_PROC && PCI && EXPERIMENTAL
help
If you say yes to this option, support will be included for the
Acer Labs Inc. (ALI) M1514 and M1543 motherboard I2C interfaces.
This can also be built as a module. If so, the module will be
called i2c-ali15x3.
You will also need the latest user-space utilties: you can find them
in the lm_sensors package, which you can download at
http://www.lm-sensors.nu
config I2C_AMD756
tristate " AMD 756/766"
depends on I2C && I2C_PROC
...
...
@@ -39,5 +53,51 @@ config I2C_AMD8111
in the lm_sensors package, which you can download at
http://www.lm-sensors.nu
config I2C_I801
tristate " Intel 801"
depends on I2C && I2C_PROC && PCI && EXPERIMENTAL
help
If you say yes to this option, support will be included for the Intel
801 family of mainboard I2C interfaces. Specifically, the following
versions of the chipset is supported:
82801AA
82801AB
82801BA
82801CA/CAM
82801DB
This can also be built as a module which can be inserted and removed
while the kernel is running. If you want to compile it as a module,
say M here and read <file:Documentation/modules.txt>.
The module will be called i2c-i801.
You will also need the latest user-space utilties: you can find them
in the lm_sensors package, which you can download at
http://www.lm-sensors.nu
config I2C_PIIX4
tristate " Intel PIIX4"
depends on I2C && I2C_PROC && PCI && EXPERIMENTAL
help
If you say yes to this option, support will be included for the Intel
PIIX4 family of mainboard I2C interfaces. Specifically, the following
versions of the chipset is supported:
Intel PIIX4
Intel 440MX
Serverworks OSB4
Serverworks CSB5
SMSC Victory66
This can also be built as a module which can be inserted and removed
while the kernel is running. If you want to compile it as a module,
say M here and read <file:Documentation/modules.txt>.
The module will be called i2c-piix4.
You will also need the latest user-space utilties: you can find them
in the lm_sensors package, which you can download at
http://www.lm-sensors.nu
endmenu
drivers/i2c/busses/Makefile
View file @
2b3163d4
...
...
@@ -2,5 +2,8 @@
# Makefile for the kernel hardware sensors bus drivers.
#
obj-$(CONFIG_I2C_ALI15X3)
+=
i2c-ali15x3.o
obj-$(CONFIG_I2C_AMD756)
+=
i2c-amd756.o
obj-$(CONFIG_I2C_AMD8111)
+=
i2c-amd8111.o
obj-$(CONFIG_I2C_I801)
+=
i2c-i801.o
obj-$(CONFIG_I2C_PIIX4)
+=
i2c-piix4.o
drivers/i2c/busses/i2c-ali15x3.c
0 → 100644
View file @
2b3163d4
/*
ali15x3.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1999 Frodo Looijaard <frodol@dds.nl> and
Philip Edelbrock <phil@netroedge.com> and
Mark D. Studebaker <mdsxyz123@yahoo.com>
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; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
This is the driver for the SMB Host controller on
Acer Labs Inc. (ALI) M1541 and M1543C South Bridges.
The M1543C is a South bridge for desktop systems.
The M1533 is a South bridge for portable systems.
They are part of the following ALI chipsets:
"Aladdin Pro 2": Includes the M1621 Slot 1 North bridge
with AGP and 100MHz CPU Front Side bus
"Aladdin V": Includes the M1541 Socket 7 North bridge
with AGP and 100MHz CPU Front Side bus
"Aladdin IV": Includes the M1541 Socket 7 North bridge
with host bus up to 83.3 MHz.
For an overview of these chips see http://www.acerlabs.com
The M1533/M1543C devices appear as FOUR separate devices
on the PCI bus. An output of lspci will show something similar
to the following:
00:02.0 USB Controller: Acer Laboratories Inc. M5237
00:03.0 Bridge: Acer Laboratories Inc. M7101
00:07.0 ISA bridge: Acer Laboratories Inc. M1533
00:0f.0 IDE interface: Acer Laboratories Inc. M5229
The SMB controller is part of the 7101 device, which is an
ACPI-compliant Power Management Unit (PMU).
The whole 7101 device has to be enabled for the SMB to work.
You can't just enable the SMB alone.
The SMB and the ACPI have separate I/O spaces.
We make sure that the SMB is enabled. We leave the ACPI alone.
This driver controls the SMB Host only.
The SMB Slave controller on the M15X3 is not enabled.
This driver does not use interrupts.
*/
/* Note: we assume there can only be one ALI15X3, with one SMBus interface */
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <asm/io.h>
/* ALI15X3 SMBus address offsets */
#define SMBHSTSTS (0 + ali15x3_smba)
#define SMBHSTCNT (1 + ali15x3_smba)
#define SMBHSTSTART (2 + ali15x3_smba)
#define SMBHSTCMD (7 + ali15x3_smba)
#define SMBHSTADD (3 + ali15x3_smba)
#define SMBHSTDAT0 (4 + ali15x3_smba)
#define SMBHSTDAT1 (5 + ali15x3_smba)
#define SMBBLKDAT (6 + ali15x3_smba)
/* PCI Address Constants */
#define SMBCOM 0x004
#define SMBBA 0x014
#define SMBATPC 0x05B
/* used to unlock xxxBA registers */
#define SMBHSTCFG 0x0E0
#define SMBSLVC 0x0E1
#define SMBCLK 0x0E2
#define SMBREV 0x008
/* Other settings */
#define MAX_TIMEOUT 200
/* times 1/100 sec */
#define ALI15X3_SMB_IOSIZE 32
/* this is what the Award 1004 BIOS sets them to on a ASUS P5A MB.
We don't use these here. If the bases aren't set to some value we
tell user to upgrade BIOS and we fail.
*/
#define ALI15X3_SMB_DEFAULTBASE 0xE800
/* ALI15X3 address lock bits */
#define ALI15X3_LOCK 0x06
/* ALI15X3 command constants */
#define ALI15X3_ABORT 0x02
#define ALI15X3_T_OUT 0x04
#define ALI15X3_QUICK 0x00
#define ALI15X3_BYTE 0x10
#define ALI15X3_BYTE_DATA 0x20
#define ALI15X3_WORD_DATA 0x30
#define ALI15X3_BLOCK_DATA 0x40
#define ALI15X3_BLOCK_CLR 0x80
/* ALI15X3 status register bits */
#define ALI15X3_STS_IDLE 0x04
#define ALI15X3_STS_BUSY 0x08
#define ALI15X3_STS_DONE 0x10
#define ALI15X3_STS_DEV 0x20
/* device error */
#define ALI15X3_STS_COLL 0x40
/* collision or no response */
#define ALI15X3_STS_TERM 0x80
/* terminated by abort */
#define ALI15X3_STS_ERR 0xE0
/* all the bad error bits */
/* If force_addr is set to anything different from 0, we forcibly enable
the device at the given address. */
static
int
force_addr
=
0
;
MODULE_PARM
(
force_addr
,
"i"
);
MODULE_PARM_DESC
(
force_addr
,
"Initialize the base address of the i2c controller"
);
static
void
ali15x3_do_pause
(
unsigned
int
amount
);
static
int
ali15x3_transaction
(
void
);
static
unsigned
short
ali15x3_smba
=
0
;
int
ali15x3_setup
(
struct
pci_dev
*
ALI15X3_dev
)
{
u16
a
;
unsigned
char
temp
;
/* Check the following things:
- SMB I/O address is initialized
- Device is enabled
- We can use the addresses
*/
/* Unlock the register.
The data sheet says that the address registers are read-only
if the lock bits are 1, but in fact the address registers
are zero unless you clear the lock bits.
*/
pci_read_config_byte
(
ALI15X3_dev
,
SMBATPC
,
&
temp
);
if
(
temp
&
ALI15X3_LOCK
)
{
temp
&=
~
ALI15X3_LOCK
;
pci_write_config_byte
(
ALI15X3_dev
,
SMBATPC
,
temp
);
}
/* Determine the address of the SMBus area */
pci_read_config_word
(
ALI15X3_dev
,
SMBBA
,
&
ali15x3_smba
);
ali15x3_smba
&=
(
0xffff
&
~
(
ALI15X3_SMB_IOSIZE
-
1
));
if
(
ali15x3_smba
==
0
&&
force_addr
==
0
)
{
printk
(
"i2c-ali15x3.o: ALI15X3_smb region uninitialized - upgrade BIOS or use force_addr=0xaddr
\n
"
);
return
-
ENODEV
;
}
if
(
force_addr
)
ali15x3_smba
=
force_addr
&
~
(
ALI15X3_SMB_IOSIZE
-
1
);
if
(
check_region
(
ali15x3_smba
,
ALI15X3_SMB_IOSIZE
))
{
printk
(
"i2c-ali15x3.o: ALI15X3_smb region 0x%x already in use!
\n
"
,
ali15x3_smba
);
return
-
ENODEV
;
}
if
(
force_addr
)
{
printk
(
"i2c-ali15x3.o: forcing ISA address 0x%04X
\n
"
,
ali15x3_smba
);
if
(
PCIBIOS_SUCCESSFUL
!=
pci_write_config_word
(
ALI15X3_dev
,
SMBBA
,
ali15x3_smba
))
return
-
ENODEV
;
if
(
PCIBIOS_SUCCESSFUL
!=
pci_read_config_word
(
ALI15X3_dev
,
SMBBA
,
&
a
))
return
-
ENODEV
;
if
((
a
&
~
(
ALI15X3_SMB_IOSIZE
-
1
))
!=
ali15x3_smba
)
{
/* make sure it works */
printk
(
"i2c-ali15x3.o: force address failed - not supported?
\n
"
);
return
-
ENODEV
;
}
}
/* check if whole device is enabled */
pci_read_config_byte
(
ALI15X3_dev
,
SMBCOM
,
&
temp
);
if
((
temp
&
1
)
==
0
)
{
printk
(
"i2c-ali15x3: enabling SMBus device
\n
"
);
pci_write_config_byte
(
ALI15X3_dev
,
SMBCOM
,
temp
|
0x01
);
}
/* Is SMB Host controller enabled? */
pci_read_config_byte
(
ALI15X3_dev
,
SMBHSTCFG
,
&
temp
);
if
((
temp
&
1
)
==
0
)
{
printk
(
"i2c-ali15x3: enabling SMBus controller
\n
"
);
pci_write_config_byte
(
ALI15X3_dev
,
SMBHSTCFG
,
temp
|
0x01
);
}
/* set SMB clock to 74KHz as recommended in data sheet */
pci_write_config_byte
(
ALI15X3_dev
,
SMBCLK
,
0x20
);
/* Everything is happy, let's grab the memory and set things up. */
request_region
(
ali15x3_smba
,
ALI15X3_SMB_IOSIZE
,
"ali15x3-smb"
);
#ifdef DEBUG
/*
The interrupt routing for SMB is set up in register 0x77 in the
1533 ISA Bridge device, NOT in the 7101 device.
Don't bother with finding the 1533 device and reading the register.
if ((....... & 0x0F) == 1)
printk("i2c-ali15x3.o: ALI15X3 using Interrupt 9 for SMBus.\n");
*/
pci_read_config_byte
(
ALI15X3_dev
,
SMBREV
,
&
temp
);
printk
(
"i2c-ali15x3.o: SMBREV = 0x%X
\n
"
,
temp
);
printk
(
"i2c-ali15x3.o: ALI15X3_smba = 0x%X
\n
"
,
ali15x3_smba
);
#endif
/* DEBUG */
return
0
;
}
/* Internally used pause function */
void
ali15x3_do_pause
(
unsigned
int
amount
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
amount
);
}
/* Another internally used function */
int
ali15x3_transaction
(
void
)
{
int
temp
;
int
result
=
0
;
int
timeout
=
0
;
#ifdef DEBUG
printk
(
"i2c-ali15x3.o: Transaction (pre): STS=%02x, CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
"DAT1=%02x
\n
"
,
inb_p
(
SMBHSTSTS
),
inb_p
(
SMBHSTCNT
),
inb_p
(
SMBHSTCMD
),
inb_p
(
SMBHSTADD
),
inb_p
(
SMBHSTDAT0
),
inb_p
(
SMBHSTDAT1
));
#endif
/* get status */
temp
=
inb_p
(
SMBHSTSTS
);
/* Make sure the SMBus host is ready to start transmitting */
/* Check the busy bit first */
if
(
temp
&
ALI15X3_STS_BUSY
)
{
/*
If the host controller is still busy, it may have timed out in the previous transaction,
resulting in a "SMBus Timeout" printk.
I've tried the following to reset a stuck busy bit.
1. Reset the controller with an ABORT command.
(this doesn't seem to clear the controller if an external device is hung)
2. Reset the controller and the other SMBus devices with a T_OUT command.
(this clears the host busy bit if an external device is hung,
but it comes back upon a new access to a device)
3. Disable and reenable the controller in SMBHSTCFG
Worst case, nothing seems to work except power reset.
*/
/* Abort - reset the host controller */
/*
#ifdef DEBUG
printk("i2c-ali15x3.o: Resetting host controller to clear busy condition\n",temp);
#endif
outb_p(ALI15X3_ABORT, SMBHSTCNT);
temp = inb_p(SMBHSTSTS);
if (temp & ALI15X3_STS_BUSY) {
*/
/*
Try resetting entire SMB bus, including other devices -
This may not work either - it clears the BUSY bit but
then the BUSY bit may come back on when you try and use the chip again.
If that's the case you are stuck.
*/
printk
(
"i2c-ali15x3.o: Resetting entire SMB Bus to clear busy condition (%02x)
\n
"
,
temp
);
outb_p
(
ALI15X3_T_OUT
,
SMBHSTCNT
);
temp
=
inb_p
(
SMBHSTSTS
);
}
/*
}
*/
/* now check the error bits and the busy bit */
if
(
temp
&
(
ALI15X3_STS_ERR
|
ALI15X3_STS_BUSY
))
{
/* do a clear-on-write */
outb_p
(
0xFF
,
SMBHSTSTS
);
if
((
temp
=
inb_p
(
SMBHSTSTS
))
&
(
ALI15X3_STS_ERR
|
ALI15X3_STS_BUSY
))
{
/* this is probably going to be correctable only by a power reset
as one of the bits now appears to be stuck */
/* This may be a bus or device with electrical problems. */
printk
(
"i2c-ali15x3.o: SMBus reset failed! (0x%02x) - controller or device on bus is probably hung
\n
"
,
temp
);
return
-
1
;
}
}
else
{
/* check and clear done bit */
if
(
temp
&
ALI15X3_STS_DONE
)
{
outb_p
(
temp
,
SMBHSTSTS
);
}
}
/* start the transaction by writing anything to the start register */
outb_p
(
0xFF
,
SMBHSTSTART
);
/* We will always wait for a fraction of a second! */
timeout
=
0
;
do
{
ali15x3_do_pause
(
1
);
temp
=
inb_p
(
SMBHSTSTS
);
}
while
((
!
(
temp
&
(
ALI15X3_STS_ERR
|
ALI15X3_STS_DONE
)))
&&
(
timeout
++
<
MAX_TIMEOUT
));
/* If the SMBus is still busy, we give up */
if
(
timeout
>=
MAX_TIMEOUT
)
{
result
=
-
1
;
printk
(
"i2c-ali15x3.o: SMBus Timeout!
\n
"
);
}
if
(
temp
&
ALI15X3_STS_TERM
)
{
result
=
-
1
;
#ifdef DEBUG
printk
(
"i2c-ali15x3.o: Error: Failed bus transaction
\n
"
);
#endif
}
/*
Unfortunately the ALI SMB controller maps "no response" and "bus collision"
into a single bit. No reponse is the usual case so don't
do a printk.
This means that bus collisions go unreported.
*/
if
(
temp
&
ALI15X3_STS_COLL
)
{
result
=
-
1
;
#ifdef DEBUG
printk
(
"i2c-ali15x3.o: Error: no response or bus collision ADD=%02x
\n
"
,
inb_p
(
SMBHSTADD
));
#endif
}
/* haven't ever seen this */
if
(
temp
&
ALI15X3_STS_DEV
)
{
result
=
-
1
;
printk
(
"i2c-ali15x3.o: Error: device error
\n
"
);
}
#ifdef DEBUG
printk
(
"i2c-ali15x3.o: Transaction (post): STS=%02x, CNT=%02x, CMD=%02x, ADD=%02x, "
"DAT0=%02x, DAT1=%02x
\n
"
,
inb_p
(
SMBHSTSTS
),
inb_p
(
SMBHSTCNT
),
inb_p
(
SMBHSTCMD
),
inb_p
(
SMBHSTADD
),
inb_p
(
SMBHSTDAT0
),
inb_p
(
SMBHSTDAT1
));
#endif
return
result
;
}
/* Return -1 on error. */
s32
ali15x3_access
(
struct
i2c_adapter
*
adap
,
u16
addr
,
unsigned
short
flags
,
char
read_write
,
u8
command
,
int
size
,
union
i2c_smbus_data
*
data
)
{
int
i
,
len
;
int
temp
;
int
timeout
;
/* clear all the bits (clear-on-write) */
outb_p
(
0xFF
,
SMBHSTSTS
);
/* make sure SMBus is idle */
temp
=
inb_p
(
SMBHSTSTS
);
for
(
timeout
=
0
;
(
timeout
<
MAX_TIMEOUT
)
&&
!
(
temp
&
ALI15X3_STS_IDLE
);
timeout
++
)
{
ali15x3_do_pause
(
1
);
temp
=
inb_p
(
SMBHSTSTS
);
}
if
(
timeout
>=
MAX_TIMEOUT
)
{
printk
(
"i2c-ali15x3.o: Idle wait Timeout! STS=0x%02x
\n
"
,
temp
);
}
switch
(
size
)
{
case
I2C_SMBUS_PROC_CALL
:
printk
(
"i2c-ali15x3.o: I2C_SMBUS_PROC_CALL not supported!
\n
"
);
return
-
1
;
case
I2C_SMBUS_QUICK
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
size
=
ALI15X3_QUICK
;
break
;
case
I2C_SMBUS_BYTE
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
outb_p
(
command
,
SMBHSTCMD
);
size
=
ALI15X3_BYTE
;
break
;
case
I2C_SMBUS_BYTE_DATA
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
outb_p
(
command
,
SMBHSTCMD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
outb_p
(
data
->
byte
,
SMBHSTDAT0
);
size
=
ALI15X3_BYTE_DATA
;
break
;
case
I2C_SMBUS_WORD_DATA
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
outb_p
(
command
,
SMBHSTCMD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
{
outb_p
(
data
->
word
&
0xff
,
SMBHSTDAT0
);
outb_p
((
data
->
word
&
0xff00
)
>>
8
,
SMBHSTDAT1
);
}
size
=
ALI15X3_WORD_DATA
;
break
;
case
I2C_SMBUS_BLOCK_DATA
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
outb_p
(
command
,
SMBHSTCMD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
{
len
=
data
->
block
[
0
];
if
(
len
<
0
)
{
len
=
0
;
data
->
block
[
0
]
=
len
;
}
if
(
len
>
32
)
{
len
=
32
;
data
->
block
[
0
]
=
len
;
}
outb_p
(
len
,
SMBHSTDAT0
);
outb_p
(
inb_p
(
SMBHSTCNT
)
|
ALI15X3_BLOCK_CLR
,
SMBHSTCNT
);
/* Reset SMBBLKDAT */
for
(
i
=
1
;
i
<=
len
;
i
++
)
outb_p
(
data
->
block
[
i
],
SMBBLKDAT
);
}
size
=
ALI15X3_BLOCK_DATA
;
break
;
}
outb_p
(
size
,
SMBHSTCNT
);
/* output command */
if
(
ali15x3_transaction
())
/* Error in transaction */
return
-
1
;
if
((
read_write
==
I2C_SMBUS_WRITE
)
||
(
size
==
ALI15X3_QUICK
))
return
0
;
switch
(
size
)
{
case
ALI15X3_BYTE
:
/* Result put in SMBHSTDAT0 */
data
->
byte
=
inb_p
(
SMBHSTDAT0
);
break
;
case
ALI15X3_BYTE_DATA
:
data
->
byte
=
inb_p
(
SMBHSTDAT0
);
break
;
case
ALI15X3_WORD_DATA
:
data
->
word
=
inb_p
(
SMBHSTDAT0
)
+
(
inb_p
(
SMBHSTDAT1
)
<<
8
);
break
;
case
ALI15X3_BLOCK_DATA
:
len
=
inb_p
(
SMBHSTDAT0
);
if
(
len
>
32
)
len
=
32
;
data
->
block
[
0
]
=
len
;
outb_p
(
inb_p
(
SMBHSTCNT
)
|
ALI15X3_BLOCK_CLR
,
SMBHSTCNT
);
/* Reset SMBBLKDAT */
for
(
i
=
1
;
i
<=
data
->
block
[
0
];
i
++
)
{
data
->
block
[
i
]
=
inb_p
(
SMBBLKDAT
);
#ifdef DEBUG
printk
(
"i2c-ali15x3.o: Blk: len=%d, i=%d, data=%02x
\n
"
,
len
,
i
,
data
->
block
[
i
]);
#endif
/* DEBUG */
}
break
;
}
return
0
;
}
u32
ali15x3_func
(
struct
i2c_adapter
*
adapter
)
{
return
I2C_FUNC_SMBUS_QUICK
|
I2C_FUNC_SMBUS_BYTE
|
I2C_FUNC_SMBUS_BYTE_DATA
|
I2C_FUNC_SMBUS_WORD_DATA
|
I2C_FUNC_SMBUS_BLOCK_DATA
;
}
static
struct
i2c_algorithm
smbus_algorithm
=
{
.
name
=
"Non-I2C SMBus adapter"
,
.
id
=
I2C_ALGO_SMBUS
,
.
smbus_xfer
=
ali15x3_access
,
.
functionality
=
ali15x3_func
,
};
static
struct
i2c_adapter
ali15x3_adapter
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"unset"
,
.
id
=
I2C_ALGO_SMBUS
|
I2C_HW_SMBUS_ALI15X3
,
.
algo
=
&
smbus_algorithm
,
};
static
struct
pci_device_id
ali15x3_ids
[]
__devinitdata
=
{
{
.
vendor
=
PCI_VENDOR_ID_AL
,
.
device
=
PCI_DEVICE_ID_AL_M7101
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
},
{
0
,
}
};
static
int
__devinit
ali15x3_probe
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
id
)
{
if
(
ali15x3_setup
(
dev
))
{
printk
(
"i2c-ali15x3.o: ALI15X3 not detected, module not inserted.
\n
"
);
return
-
ENODEV
;
}
/* set up the driverfs linkage to our parent device */
ali15x3_adapter
.
dev
.
parent
=
&
dev
->
dev
;
sprintf
(
ali15x3_adapter
.
name
,
"SMBus ALI15X3 adapter at %04x"
,
ali15x3_smba
);
return
i2c_add_adapter
(
&
ali15x3_adapter
);
}
static
void
__devexit
ali15x3_remove
(
struct
pci_dev
*
dev
)
{
i2c_del_adapter
(
&
ali15x3_adapter
);
}
static
struct
pci_driver
ali15x3_driver
=
{
.
name
=
"ali15x3 smbus"
,
.
id_table
=
ali15x3_ids
,
.
probe
=
ali15x3_probe
,
.
remove
=
__devexit_p
(
ali15x3_remove
),
};
static
int
__init
i2c_ali15x3_init
(
void
)
{
printk
(
"i2c-ali15x3.o version %s (%s)
\n
"
,
I2C_VERSION
,
I2C_DATE
);
return
pci_module_init
(
&
ali15x3_driver
);
}
static
void
__exit
i2c_ali15x3_exit
(
void
)
{
pci_unregister_driver
(
&
ali15x3_driver
);
release_region
(
ali15x3_smba
,
ALI15X3_SMB_IOSIZE
);
}
MODULE_AUTHOR
(
"Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com>"
);
MODULE_DESCRIPTION
(
"ALI15X3 SMBus driver"
);
MODULE_LICENSE
(
"GPL"
);
module_init
(
i2c_ali15x3_init
);
module_exit
(
i2c_ali15x3_exit
);
drivers/i2c/busses/i2c-amd756.c
View file @
2b3163d4
...
...
@@ -375,6 +375,9 @@ static int __devinit amd756_probe(struct pci_dev *pdev,
printk
(
KERN_DEBUG
DRV_NAME
": AMD756_smba = 0x%X
\n
"
,
amd756_ioport
);
#endif
/* set up the driverfs linkage to our parent device */
amd756_adapter
.
dev
.
parent
=
&
pdev
->
dev
;
sprintf
(
amd756_adapter
.
name
,
"SMBus AMD75x adapter at %04x"
,
amd756_ioport
);
...
...
drivers/i2c/busses/i2c-amd8111.c
View file @
2b3163d4
...
...
@@ -363,6 +363,9 @@ static int __devinit amd8111_probe(struct pci_dev *dev, const struct pci_device_
smbus
->
adapter
.
algo
=
&
smbus_algorithm
;
smbus
->
adapter
.
algo_data
=
smbus
;
/* set up the driverfs linkage to our parent device */
smbus
->
adapter
.
dev
.
parent
=
&
dev
->
dev
;
error
=
i2c_add_adapter
(
&
smbus
->
adapter
);
if
(
error
)
goto
out_release_region
;
...
...
@@ -389,7 +392,7 @@ static void __devexit amd8111_remove(struct pci_dev *dev)
}
static
struct
pci_driver
amd8111_driver
=
{
.
name
=
"amd8111 smbus
2.0
"
,
.
name
=
"amd8111 smbus"
,
.
id_table
=
amd8111_ids
,
.
probe
=
amd8111_probe
,
.
remove
=
__devexit_p
(
amd8111_remove
),
...
...
drivers/i2c/busses/i2c-i801.c
0 → 100644
View file @
2b3163d4
/*
i801.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl>,
Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker
<mdsxyz123@yahoo.com>
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; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
SUPPORTED DEVICES PCI ID
82801AA 2413
82801AB 2423
82801BA 2443
82801CA/CAM 2483
82801DB 24C3 (HW PEC supported, 32 byte buffer not supported)
This driver supports several versions of Intel's I/O Controller Hubs (ICH).
For SMBus support, they are similar to the PIIX4 and are part
of Intel's '810' and other chipsets.
See the doc/busses/i2c-i801 file for details.
I2C Block Read and Process Call are not supported.
*/
/* Note: we assume there can only be one I801, with one SMBus interface */
/* #define DEBUG 1 */
#include <linux/module.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/i2c.h>
#include <asm/io.h>
MODULE_LICENSE
(
"GPL"
);
#ifdef I2C_FUNC_SMBUS_BLOCK_DATA_PEC
#define HAVE_PEC
#endif
#ifndef PCI_DEVICE_ID_INTEL_82801CA_SMBUS
#define PCI_DEVICE_ID_INTEL_82801CA_SMBUS 0x2483
#endif
#ifndef PCI_DEVICE_ID_INTEL_82801DB_SMBUS
#define PCI_DEVICE_ID_INTEL_82801DB_SMBUS 0x24C3
#endif
static
int
supported
[]
=
{
PCI_DEVICE_ID_INTEL_82801AA_3
,
PCI_DEVICE_ID_INTEL_82801AB_3
,
PCI_DEVICE_ID_INTEL_82801BA_2
,
PCI_DEVICE_ID_INTEL_82801CA_SMBUS
,
PCI_DEVICE_ID_INTEL_82801DB_SMBUS
,
0
};
/* I801 SMBus address offsets */
#define SMBHSTSTS (0 + i801_smba)
#define SMBHSTCNT (2 + i801_smba)
#define SMBHSTCMD (3 + i801_smba)
#define SMBHSTADD (4 + i801_smba)
#define SMBHSTDAT0 (5 + i801_smba)
#define SMBHSTDAT1 (6 + i801_smba)
#define SMBBLKDAT (7 + i801_smba)
#define SMBPEC (8 + i801_smba)
/* ICH4 only */
#define SMBAUXSTS (12 + i801_smba)
/* ICH4 only */
#define SMBAUXCTL (13 + i801_smba)
/* ICH4 only */
/* PCI Address Constants */
#define SMBBA 0x020
#define SMBHSTCFG 0x040
#define SMBREV 0x008
/* Host configuration bits for SMBHSTCFG */
#define SMBHSTCFG_HST_EN 1
#define SMBHSTCFG_SMB_SMI_EN 2
#define SMBHSTCFG_I2C_EN 4
/* Other settings */
#define MAX_TIMEOUT 100
#define ENABLE_INT9 0
/* set to 0x01 to enable - untested */
/* I801 command constants */
#define I801_QUICK 0x00
#define I801_BYTE 0x04
#define I801_BYTE_DATA 0x08
#define I801_WORD_DATA 0x0C
#define I801_PROC_CALL 0x10
/* later chips only, unimplemented */
#define I801_BLOCK_DATA 0x14
#define I801_I2C_BLOCK_DATA 0x18
/* unimplemented */
#define I801_BLOCK_LAST 0x34
#define I801_I2C_BLOCK_LAST 0x38
/* unimplemented */
#define I801_START 0x40
#define I801_PEC_EN 0x80
/* ICH4 only */
/* insmod parameters */
/* If force_addr is set to anything different from 0, we forcibly enable
the I801 at the given address. VERY DANGEROUS! */
static
int
force_addr
=
0
;
MODULE_PARM
(
force_addr
,
"i"
);
MODULE_PARM_DESC
(
force_addr
,
"Forcibly enable the I801 at the given address. "
"EXTREMELY DANGEROUS!"
);
static
void
i801_do_pause
(
unsigned
int
amount
);
static
int
i801_transaction
(
void
);
static
int
i801_block_transaction
(
union
i2c_smbus_data
*
data
,
char
read_write
,
int
command
);
static
unsigned
short
i801_smba
;
static
struct
pci_dev
*
I801_dev
;
static
int
isich4
;
static
int
i801_setup
(
struct
pci_dev
*
dev
)
{
int
error_return
=
0
;
int
*
num
=
supported
;
unsigned
char
temp
;
/* Note: we keep on searching until we have found 'function 3' */
if
(
PCI_FUNC
(
dev
->
devfn
)
!=
3
)
return
-
ENODEV
;
I801_dev
=
dev
;
isich4
=
*
num
==
PCI_DEVICE_ID_INTEL_82801DB_SMBUS
;
/* Determine the address of the SMBus areas */
if
(
force_addr
)
{
i801_smba
=
force_addr
&
0xfff0
;
}
else
{
pci_read_config_word
(
I801_dev
,
SMBBA
,
&
i801_smba
);
i801_smba
&=
0xfff0
;
if
(
i801_smba
==
0
)
{
printk
(
KERN_ERR
"i2c-i801.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr
\n
"
);
return
-
ENODEV
;
}
}
if
(
check_region
(
i801_smba
,
(
isich4
?
16
:
8
)))
{
printk
(
KERN_ERR
"i2c-i801.o: I801_smb region 0x%x already in use!
\n
"
,
i801_smba
);
error_return
=
-
ENODEV
;
goto
END
;
}
pci_read_config_byte
(
I801_dev
,
SMBHSTCFG
,
&
temp
);
temp
&=
~
SMBHSTCFG_I2C_EN
;
/* SMBus timing */
pci_write_config_byte
(
I801_dev
,
SMBHSTCFG
,
temp
);
/* If force_addr is set, we program the new address here. Just to make
sure, we disable the device first. */
if
(
force_addr
)
{
pci_write_config_byte
(
I801_dev
,
SMBHSTCFG
,
temp
&
0xfe
);
pci_write_config_word
(
I801_dev
,
SMBBA
,
i801_smba
);
pci_write_config_byte
(
I801_dev
,
SMBHSTCFG
,
temp
|
0x01
);
printk
(
KERN_WARNING
"i2c-i801.o: WARNING: I801 SMBus interface set to new "
"address %04x!
\n
"
,
i801_smba
);
}
else
if
((
temp
&
1
)
==
0
)
{
pci_write_config_byte
(
I801_dev
,
SMBHSTCFG
,
temp
|
1
);
printk
(
KERN_WARNING
"i2c-i801.o: enabling SMBus device
\n
"
);
}
request_region
(
i801_smba
,
(
isich4
?
16
:
8
),
"i801-smbus"
);
#ifdef DEBUG
if
(
temp
&
0x02
)
printk
(
KERN_DEBUG
"i2c-i801.o: I801 using Interrupt SMI# for SMBus.
\n
"
);
else
printk
(
KERN_DEBUG
"i2c-i801.o: I801 using PCI Interrupt for SMBus.
\n
"
);
pci_read_config_byte
(
I801_dev
,
SMBREV
,
&
temp
);
printk
(
KERN_DEBUG
"i2c-i801.o: SMBREV = 0x%X
\n
"
,
temp
);
printk
(
KERN_DEBUG
"i2c-i801.o: I801_smba = 0x%X
\n
"
,
i801_smba
);
#endif
/* DEBUG */
END:
return
error_return
;
}
void
i801_do_pause
(
unsigned
int
amount
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
amount
);
}
int
i801_transaction
(
void
)
{
int
temp
;
int
result
=
0
;
int
timeout
=
0
;
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
"DAT1=%02x
\n
"
,
inb_p
(
SMBHSTCNT
),
inb_p
(
SMBHSTCMD
),
inb_p
(
SMBHSTADD
),
inb_p
(
SMBHSTDAT0
),
inb_p
(
SMBHSTDAT1
));
#endif
/* Make sure the SMBus host is ready to start transmitting */
/* 0x1f = Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
if
((
temp
=
(
0x1f
&
inb_p
(
SMBHSTSTS
)))
!=
0x00
)
{
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: SMBus busy (%02x). Resetting...
\n
"
,
temp
);
#endif
outb_p
(
temp
,
SMBHSTSTS
);
if
((
temp
=
(
0x1f
&
inb_p
(
SMBHSTSTS
)))
!=
0x00
)
{
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: Failed! (%02x)
\n
"
,
temp
);
#endif
return
-
1
;
}
else
{
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: Successfull!
\n
"
);
#endif
}
}
outb_p
(
inb
(
SMBHSTCNT
)
|
I801_START
,
SMBHSTCNT
);
/* We will always wait for a fraction of a second! */
do
{
i801_do_pause
(
1
);
temp
=
inb_p
(
SMBHSTSTS
);
}
while
((
temp
&
0x01
)
&&
(
timeout
++
<
MAX_TIMEOUT
));
/* If the SMBus is still busy, we give up */
if
(
timeout
>=
MAX_TIMEOUT
)
{
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: SMBus Timeout!
\n
"
);
result
=
-
1
;
#endif
}
if
(
temp
&
0x10
)
{
result
=
-
1
;
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: Error: Failed bus transaction
\n
"
);
#endif
}
if
(
temp
&
0x08
)
{
result
=
-
1
;
printk
(
KERN_ERR
"i2c-i801.o: Bus collision! SMBus may be locked until next hard
\n
"
"reset. (sorry!)
\n
"
);
/* Clock stops and slave is stuck in mid-transmission */
}
if
(
temp
&
0x04
)
{
result
=
-
1
;
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: Error: no response!
\n
"
);
#endif
}
if
((
inb_p
(
SMBHSTSTS
)
&
0x1f
)
!=
0x00
)
outb_p
(
inb
(
SMBHSTSTS
),
SMBHSTSTS
);
if
((
temp
=
(
0x1f
&
inb_p
(
SMBHSTSTS
)))
!=
0x00
)
{
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: Failed reset at end of transaction (%02x)
\n
"
,
temp
);
#endif
}
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
"DAT0=%02x, DAT1=%02x
\n
"
,
inb_p
(
SMBHSTCNT
),
inb_p
(
SMBHSTCMD
),
inb_p
(
SMBHSTADD
),
inb_p
(
SMBHSTDAT0
),
inb_p
(
SMBHSTDAT1
));
#endif
return
result
;
}
/* All-inclusive block transaction function */
int
i801_block_transaction
(
union
i2c_smbus_data
*
data
,
char
read_write
,
int
command
)
{
int
i
,
len
;
int
smbcmd
;
int
temp
;
int
result
=
0
;
int
timeout
;
unsigned
char
hostc
,
errmask
;
if
(
command
==
I2C_SMBUS_I2C_BLOCK_DATA
)
{
if
(
read_write
==
I2C_SMBUS_WRITE
)
{
/* set I2C_EN bit in configuration register */
pci_read_config_byte
(
I801_dev
,
SMBHSTCFG
,
&
hostc
);
pci_write_config_byte
(
I801_dev
,
SMBHSTCFG
,
hostc
|
SMBHSTCFG_I2C_EN
);
}
else
{
printk
(
"i2c-i801.o: "
"I2C_SMBUS_I2C_BLOCK_READ not supported!
\n
"
);
return
-
1
;
}
}
if
(
read_write
==
I2C_SMBUS_WRITE
)
{
len
=
data
->
block
[
0
];
if
(
len
<
1
)
len
=
1
;
if
(
len
>
32
)
len
=
32
;
outb_p
(
len
,
SMBHSTDAT0
);
outb_p
(
data
->
block
[
1
],
SMBBLKDAT
);
}
else
{
len
=
32
;
/* max for reads */
}
if
(
isich4
&&
command
!=
I2C_SMBUS_I2C_BLOCK_DATA
)
{
/* set 32 byte buffer */
}
for
(
i
=
1
;
i
<=
len
;
i
++
)
{
if
(
i
==
len
&&
read_write
==
I2C_SMBUS_READ
)
smbcmd
=
I801_BLOCK_LAST
;
else
smbcmd
=
I801_BLOCK_DATA
;
#if 0 /* now using HW PEC */
if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC)
smbcmd |= I801_PEC_EN;
#endif
outb_p
(
smbcmd
|
ENABLE_INT9
,
SMBHSTCNT
);
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: Block (pre %d): CNT=%02x, CMD=%02x, ADD=%02x, "
"DAT0=%02x, BLKDAT=%02x
\n
"
,
i
,
inb_p
(
SMBHSTCNT
),
inb_p
(
SMBHSTCMD
),
inb_p
(
SMBHSTADD
),
inb_p
(
SMBHSTDAT0
),
inb_p
(
SMBBLKDAT
));
#endif
/* Make sure the SMBus host is ready to start transmitting */
temp
=
inb_p
(
SMBHSTSTS
);
if
(
i
==
1
)
{
/* Erronenous conditions before transaction:
* Byte_Done, Failed, Bus_Err, Dev_Err, Intr, Host_Busy */
errmask
=
0x9f
;
}
else
{
/* Erronenous conditions during transaction:
* Failed, Bus_Err, Dev_Err, Intr */
errmask
=
0x1e
;
}
if
(
temp
&
errmask
)
{
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: SMBus busy (%02x). Resetting...
\n
"
,
temp
);
#endif
outb_p
(
temp
,
SMBHSTSTS
);
if
(((
temp
=
inb_p
(
SMBHSTSTS
))
&
errmask
)
!=
0x00
)
{
printk
(
KERN_ERR
"i2c-i801.o: Reset failed! (%02x)
\n
"
,
temp
);
result
=
-
1
;
goto
END
;
}
if
(
i
!=
1
)
{
result
=
-
1
;
/* if die in middle of block transaction, fail */
goto
END
;
}
}
if
(
i
==
1
)
{
#if 0 /* #ifdef HAVE_PEC (now using HW PEC) */
if(isich4 && command == I2C_SMBUS_BLOCK_DATA_PEC) {
if(read_write == I2C_SMBUS_WRITE)
outb_p(data->block[len + 1], SMBPEC);
}
#endif
outb_p
(
inb
(
SMBHSTCNT
)
|
I801_START
,
SMBHSTCNT
);
}
/* We will always wait for a fraction of a second! */
timeout
=
0
;
do
{
temp
=
inb_p
(
SMBHSTSTS
);
i801_do_pause
(
1
);
}
while
((
!
(
temp
&
0x80
))
&&
(
timeout
++
<
MAX_TIMEOUT
));
/* If the SMBus is still busy, we give up */
if
(
timeout
>=
MAX_TIMEOUT
)
{
result
=
-
1
;
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: SMBus Timeout!
\n
"
);
#endif
}
if
(
temp
&
0x10
)
{
result
=
-
1
;
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: Error: Failed bus transaction
\n
"
);
#endif
}
else
if
(
temp
&
0x08
)
{
result
=
-
1
;
printk
(
KERN_ERR
"i2c-i801.o: Bus collision!
\n
"
);
}
else
if
(
temp
&
0x04
)
{
result
=
-
1
;
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-i801.o: Error: no response!
\n
"
);
#endif
}
if
(
i
==
1
&&
read_write
==
I2C_SMBUS_READ
)
{
len
=
inb_p
(
SMBHSTDAT0
);
if
(
len
<
1
)
len
=
1
;
if
(
len
>
32
)
len
=
32
;
data
->
block
[
0
]
=
len
;
}
/* Retrieve/store value in SMBBLKDAT */
if
(
read_write
==
I2C_SMBUS_READ
)
data
->
block
[
i
]
=
inb_p
(
SMBBLKDAT
);
if
(
read_write
==
I2C_SMBUS_WRITE
&&
i
+
1
<=
len
)
outb_p
(
data
->
block
[
i
+
1
],
SMBBLKDAT
);
if
((
temp
&
0x9e
)
!=
0x00
)
outb_p
(
temp
,
SMBHSTSTS
);
/* signals SMBBLKDAT ready */
#ifdef DEBUG
if
((
temp
=
(
0x1e
&
inb_p
(
SMBHSTSTS
)))
!=
0x00
)
{
printk
(
KERN_DEBUG
"i2c-i801.o: Bad status (%02x) at end of transaction
\n
"
,
temp
);
}
printk
(
KERN_DEBUG
"i2c-i801.o: Block (post %d): CNT=%02x, CMD=%02x, ADD=%02x, "
"DAT0=%02x, BLKDAT=%02x
\n
"
,
i
,
inb_p
(
SMBHSTCNT
),
inb_p
(
SMBHSTCMD
),
inb_p
(
SMBHSTADD
),
inb_p
(
SMBHSTDAT0
),
inb_p
(
SMBBLKDAT
));
#endif
if
(
result
<
0
)
goto
END
;
}
#ifdef HAVE_PEC
if
(
isich4
&&
command
==
I2C_SMBUS_BLOCK_DATA_PEC
)
{
/* wait for INTR bit as advised by Intel */
timeout
=
0
;
do
{
temp
=
inb_p
(
SMBHSTSTS
);
i801_do_pause
(
1
);
}
while
((
!
(
temp
&
0x02
))
&&
(
timeout
++
<
MAX_TIMEOUT
));
if
(
timeout
>=
MAX_TIMEOUT
)
{
printk
(
KERN_DEBUG
"i2c-i801.o: PEC Timeout!
\n
"
);
}
#if 0 /* now using HW PEC */
if(read_write == I2C_SMBUS_READ) {
data->block[len + 1] = inb_p(SMBPEC);
}
#endif
outb_p
(
temp
,
SMBHSTSTS
);
}
#endif
result
=
0
;
END:
if
(
command
==
I2C_SMBUS_I2C_BLOCK_DATA
)
{
/* restore saved configuration register value */
pci_write_config_byte
(
I801_dev
,
SMBHSTCFG
,
hostc
);
}
return
result
;
}
/* Return -1 on error. */
s32
i801_access
(
struct
i2c_adapter
*
adap
,
u16
addr
,
unsigned
short
flags
,
char
read_write
,
u8
command
,
int
size
,
union
i2c_smbus_data
*
data
)
{
int
hwpec
=
0
;
int
block
=
0
;
int
ret
,
xact
=
0
;
#ifdef HAVE_PEC
if
(
isich4
)
hwpec
=
(
flags
&
I2C_CLIENT_PEC
)
!=
0
;
#endif
switch
(
size
)
{
case
I2C_SMBUS_QUICK
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
xact
=
I801_QUICK
;
break
;
case
I2C_SMBUS_BYTE
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
outb_p
(
command
,
SMBHSTCMD
);
xact
=
I801_BYTE
;
break
;
case
I2C_SMBUS_BYTE_DATA
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
outb_p
(
command
,
SMBHSTCMD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
outb_p
(
data
->
byte
,
SMBHSTDAT0
);
xact
=
I801_BYTE_DATA
;
break
;
case
I2C_SMBUS_WORD_DATA
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
outb_p
(
command
,
SMBHSTCMD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
{
outb_p
(
data
->
word
&
0xff
,
SMBHSTDAT0
);
outb_p
((
data
->
word
&
0xff00
)
>>
8
,
SMBHSTDAT1
);
}
xact
=
I801_WORD_DATA
;
break
;
case
I2C_SMBUS_BLOCK_DATA
:
case
I2C_SMBUS_I2C_BLOCK_DATA
:
#ifdef HAVE_PEC
case
I2C_SMBUS_BLOCK_DATA_PEC
:
if
(
hwpec
&&
size
==
I2C_SMBUS_BLOCK_DATA
)
size
=
I2C_SMBUS_BLOCK_DATA_PEC
;
#endif
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
outb_p
(
command
,
SMBHSTCMD
);
block
=
1
;
break
;
case
I2C_SMBUS_PROC_CALL
:
default:
printk
(
KERN_ERR
"i2c-i801.o: Unsupported transaction %d
\n
"
,
size
);
return
-
1
;
}
#ifdef HAVE_PEC
if
(
isich4
&&
hwpec
)
{
if
(
size
!=
I2C_SMBUS_QUICK
&&
size
!=
I2C_SMBUS_I2C_BLOCK_DATA
)
outb_p
(
1
,
SMBAUXCTL
);
/* enable HW PEC */
}
#endif
if
(
block
)
ret
=
i801_block_transaction
(
data
,
read_write
,
size
);
else
{
outb_p
(
xact
|
ENABLE_INT9
,
SMBHSTCNT
);
ret
=
i801_transaction
();
}
#ifdef HAVE_PEC
if
(
isich4
&&
hwpec
)
{
if
(
size
!=
I2C_SMBUS_QUICK
&&
size
!=
I2C_SMBUS_I2C_BLOCK_DATA
)
outb_p
(
0
,
SMBAUXCTL
);
}
#endif
if
(
block
)
return
ret
;
if
(
ret
)
return
-
1
;
if
((
read_write
==
I2C_SMBUS_WRITE
)
||
(
xact
==
I801_QUICK
))
return
0
;
switch
(
xact
&
0x7f
)
{
case
I801_BYTE
:
/* Result put in SMBHSTDAT0 */
case
I801_BYTE_DATA
:
data
->
byte
=
inb_p
(
SMBHSTDAT0
);
break
;
case
I801_WORD_DATA
:
data
->
word
=
inb_p
(
SMBHSTDAT0
)
+
(
inb_p
(
SMBHSTDAT1
)
<<
8
);
break
;
}
return
0
;
}
u32
i801_func
(
struct
i2c_adapter
*
adapter
)
{
return
I2C_FUNC_SMBUS_QUICK
|
I2C_FUNC_SMBUS_BYTE
|
I2C_FUNC_SMBUS_BYTE_DATA
|
I2C_FUNC_SMBUS_WORD_DATA
|
I2C_FUNC_SMBUS_BLOCK_DATA
|
I2C_FUNC_SMBUS_WRITE_I2C_BLOCK
#ifdef HAVE_PEC
|
(
isich4
?
I2C_FUNC_SMBUS_BLOCK_DATA_PEC
|
I2C_FUNC_SMBUS_HWPEC_CALC
:
0
)
#endif
;
}
static
struct
i2c_algorithm
smbus_algorithm
=
{
.
name
=
"Non-I2C SMBus adapter"
,
.
id
=
I2C_ALGO_SMBUS
,
.
smbus_xfer
=
i801_access
,
.
functionality
=
i801_func
,
};
static
struct
i2c_adapter
i801_adapter
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"unset"
,
.
id
=
I2C_ALGO_SMBUS
|
I2C_HW_SMBUS_I801
,
.
algo
=
&
smbus_algorithm
,
};
static
struct
pci_device_id
i801_ids
[]
__devinitdata
=
{
{
.
vendor
=
PCI_VENDOR_ID_INTEL
,
.
device
=
PCI_DEVICE_ID_INTEL_82801AA_3
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
},
{
.
vendor
=
PCI_VENDOR_ID_INTEL
,
.
device
=
PCI_DEVICE_ID_INTEL_82801AB_3
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
},
{
.
vendor
=
PCI_VENDOR_ID_INTEL
,
.
device
=
PCI_DEVICE_ID_INTEL_82801BA_2
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
},
{
.
vendor
=
PCI_VENDOR_ID_INTEL
,
.
device
=
PCI_DEVICE_ID_INTEL_82801CA_SMBUS
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
},
{
.
vendor
=
PCI_VENDOR_ID_INTEL
,
.
device
=
PCI_DEVICE_ID_INTEL_82801DB_SMBUS
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
},
{
0
,
}
};
static
int
__devinit
i801_probe
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
id
)
{
if
(
i801_setup
(
dev
))
{
printk
(
KERN_WARNING
"i2c-i801.o: I801 not detected, module not inserted.
\n
"
);
return
-
ENODEV
;
}
/* set up the driverfs linkage to our parent device */
i801_adapter
.
dev
.
parent
=
&
dev
->
dev
;
sprintf
(
i801_adapter
.
name
,
"SMBus I801 adapter at %04x"
,
i801_smba
);
return
i2c_add_adapter
(
&
i801_adapter
);
}
static
void
__devexit
i801_remove
(
struct
pci_dev
*
dev
)
{
i2c_del_adapter
(
&
i801_adapter
);
}
static
struct
pci_driver
i801_driver
=
{
.
name
=
"i801 smbus"
,
.
id_table
=
i801_ids
,
.
probe
=
i801_probe
,
.
remove
=
__devexit_p
(
i801_remove
),
};
static
int
__init
i2c_i801_init
(
void
)
{
printk
(
KERN_INFO
"i2c-i801.o version %s (%s)
\n
"
,
I2C_VERSION
,
I2C_DATE
);
return
pci_module_init
(
&
i801_driver
);
}
static
void
__exit
i2c_i801_exit
(
void
)
{
pci_unregister_driver
(
&
i801_driver
);
release_region
(
i801_smba
,
(
isich4
?
16
:
8
));
}
MODULE_AUTHOR
(
"Frodo Looijaard <frodol@dds.nl>, Philip Edelbrock <phil@netroedge.com>, and Mark D. Studebaker <mdsxyz123@yahoo.com>"
);
MODULE_DESCRIPTION
(
"I801 SMBus driver"
);
module_init
(
i2c_i801_init
);
module_exit
(
i2c_i801_exit
);
drivers/i2c/busses/i2c-piix4.c
0 → 100644
View file @
2b3163d4
/*
piix4.c - Part of lm_sensors, Linux kernel modules for hardware
monitoring
Copyright (c) 1998 - 2002 Frodo Looijaard <frodol@dds.nl> and
Philip Edelbrock <phil@netroedge.com>
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; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
/*
Supports:
Intel PIIX4, 440MX
Serverworks OSB4, CSB5
SMSC Victory66
Note: we assume there can only be one device, with one SMBus interface.
*/
#include <linux/module.h>
#include <linux/config.h>
#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/stddef.h>
#include <linux/sched.h>
#include <linux/ioport.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/apm_bios.h>
#include <asm/io.h>
struct
sd
{
const
unsigned
short
mfr
;
const
unsigned
short
dev
;
const
unsigned
char
fn
;
const
char
*
name
;
};
/* PIIX4 SMBus address offsets */
#define SMBHSTSTS (0 + piix4_smba)
#define SMBHSLVSTS (1 + piix4_smba)
#define SMBHSTCNT (2 + piix4_smba)
#define SMBHSTCMD (3 + piix4_smba)
#define SMBHSTADD (4 + piix4_smba)
#define SMBHSTDAT0 (5 + piix4_smba)
#define SMBHSTDAT1 (6 + piix4_smba)
#define SMBBLKDAT (7 + piix4_smba)
#define SMBSLVCNT (8 + piix4_smba)
#define SMBSHDWCMD (9 + piix4_smba)
#define SMBSLVEVT (0xA + piix4_smba)
#define SMBSLVDAT (0xC + piix4_smba)
/* PCI Address Constants */
#define SMBBA 0x090
#define SMBHSTCFG 0x0D2
#define SMBSLVC 0x0D3
#define SMBSHDW1 0x0D4
#define SMBSHDW2 0x0D5
#define SMBREV 0x0D6
/* Other settings */
#define MAX_TIMEOUT 500
#define ENABLE_INT9 0
/* PIIX4 constants */
#define PIIX4_QUICK 0x00
#define PIIX4_BYTE 0x04
#define PIIX4_BYTE_DATA 0x08
#define PIIX4_WORD_DATA 0x0C
#define PIIX4_BLOCK_DATA 0x14
/* insmod parameters */
/* If force is set to anything different from 0, we forcibly enable the
PIIX4. DANGEROUS! */
static
int
force
=
0
;
MODULE_PARM
(
force
,
"i"
);
MODULE_PARM_DESC
(
force
,
"Forcibly enable the PIIX4. DANGEROUS!"
);
/* If force_addr is set to anything different from 0, we forcibly enable
the PIIX4 at the given address. VERY DANGEROUS! */
static
int
force_addr
=
0
;
MODULE_PARM
(
force_addr
,
"i"
);
MODULE_PARM_DESC
(
force_addr
,
"Forcibly enable the PIIX4 at the given address. "
"EXTREMELY DANGEROUS!"
);
static
void
piix4_do_pause
(
unsigned
int
amount
);
static
int
piix4_transaction
(
void
);
static
unsigned
short
piix4_smba
=
0
;
/*
* Get DMI information.
*/
static
int
ibm_dmi_probe
(
void
)
{
#ifdef CONFIG_X86
extern
int
is_unsafe_smbus
;
return
is_unsafe_smbus
;
#else
return
0
;
#endif
}
static
int
piix4_setup
(
struct
pci_dev
*
PIIX4_dev
,
const
struct
pci_device_id
*
id
)
{
int
error_return
=
0
;
unsigned
char
temp
;
/* match up the function */
if
(
PCI_FUNC
(
PIIX4_dev
->
devfn
)
!=
id
->
driver_data
)
return
-
ENODEV
;
printk
(
KERN_INFO
"i2c-piix4.o: Found %s device
\n
"
,
PIIX4_dev
->
dev
.
name
);
if
(
ibm_dmi_probe
())
{
printk
(
KERN_ERR
"i2c-piix4.o: IBM Laptop detected; this module may corrupt
\n
"
);
printk
(
KERN_ERR
" your serial eeprom! Refusing to load module!
\n
"
);
error_return
=
-
EPERM
;
goto
END
;
}
/* Determine the address of the SMBus areas */
if
(
force_addr
)
{
piix4_smba
=
force_addr
&
0xfff0
;
force
=
0
;
}
else
{
pci_read_config_word
(
PIIX4_dev
,
SMBBA
,
&
piix4_smba
);
piix4_smba
&=
0xfff0
;
if
(
piix4_smba
==
0
)
{
printk
(
KERN_ERR
"i2c-piix4.o: SMB base address uninitialized - upgrade BIOS or use force_addr=0xaddr
\n
"
);
return
-
ENODEV
;
}
}
if
(
check_region
(
piix4_smba
,
8
))
{
printk
(
KERN_ERR
"i2c-piix4.o: SMB region 0x%x already in use!
\n
"
,
piix4_smba
);
error_return
=
-
ENODEV
;
goto
END
;
}
pci_read_config_byte
(
PIIX4_dev
,
SMBHSTCFG
,
&
temp
);
/* If force_addr is set, we program the new address here. Just to make
sure, we disable the PIIX4 first. */
if
(
force_addr
)
{
pci_write_config_byte
(
PIIX4_dev
,
SMBHSTCFG
,
temp
&
0xfe
);
pci_write_config_word
(
PIIX4_dev
,
SMBBA
,
piix4_smba
);
pci_write_config_byte
(
PIIX4_dev
,
SMBHSTCFG
,
temp
|
0x01
);
printk
(
KERN_INFO
"i2c-piix4.o: WARNING: SMBus interface set to new "
"address %04x!
\n
"
,
piix4_smba
);
}
else
if
((
temp
&
1
)
==
0
)
{
if
(
force
)
{
/* This should never need to be done, but has been noted that
many Dell machines have the SMBus interface on the PIIX4
disabled!? NOTE: This assumes I/O space and other allocations WERE
done by the Bios! Don't complain if your hardware does weird
things after enabling this. :') Check for Bios updates before
resorting to this. */
pci_write_config_byte
(
PIIX4_dev
,
SMBHSTCFG
,
temp
|
1
);
printk
(
KERN_NOTICE
"i2c-piix4.o: WARNING: SMBus interface has been FORCEFULLY "
"ENABLED!
\n
"
);
}
else
{
printk
(
KERN_ERR
"i2c-piix4.o: Host SMBus controller not enabled!
\n
"
);
error_return
=
-
ENODEV
;
goto
END
;
}
}
/* Everything is happy, let's grab the memory and set things up. */
request_region
(
piix4_smba
,
8
,
"piix4-smbus"
);
#ifdef DEBUG
if
((
temp
&
0x0E
)
==
8
)
printk
(
KERN_DEBUG
"i2c-piix4.o: Using Interrupt 9 for SMBus.
\n
"
);
else
if
((
temp
&
0x0E
)
==
0
)
printk
(
KERN_DEBUG
"i2c-piix4.o: Using Interrupt SMI# for SMBus.
\n
"
);
else
printk
(
KERN_ERR
"i2c-piix4.o: Illegal Interrupt configuration (or code out "
"of date)!
\n
"
);
pci_read_config_byte
(
PIIX4_dev
,
SMBREV
,
&
temp
);
printk
(
KERN_DEBUG
"i2c-piix4.o: SMBREV = 0x%X
\n
"
,
temp
);
printk
(
KERN_DEBUG
"i2c-piix4.o: SMBA = 0x%X
\n
"
,
piix4_smba
);
#endif
/* DEBUG */
END:
return
error_return
;
}
/* Internally used pause function */
static
void
piix4_do_pause
(
unsigned
int
amount
)
{
current
->
state
=
TASK_INTERRUPTIBLE
;
schedule_timeout
(
amount
);
}
/* Another internally used function */
static
int
piix4_transaction
(
void
)
{
int
temp
;
int
result
=
0
;
int
timeout
=
0
;
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-piix4.o: Transaction (pre): CNT=%02x, CMD=%02x, ADD=%02x, DAT0=%02x, "
"DAT1=%02x
\n
"
,
inb_p
(
SMBHSTCNT
),
inb_p
(
SMBHSTCMD
),
inb_p
(
SMBHSTADD
),
inb_p
(
SMBHSTDAT0
),
inb_p
(
SMBHSTDAT1
));
#endif
/* Make sure the SMBus host is ready to start transmitting */
if
((
temp
=
inb_p
(
SMBHSTSTS
))
!=
0x00
)
{
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-piix4.o: SMBus busy (%02x). Resetting...
\n
"
,
temp
);
#endif
outb_p
(
temp
,
SMBHSTSTS
);
if
((
temp
=
inb_p
(
SMBHSTSTS
))
!=
0x00
)
{
#ifdef DEBUG
printk
(
KERN_ERR
"i2c-piix4.o: Failed! (%02x)
\n
"
,
temp
);
#endif
return
-
1
;
}
else
{
#ifdef DEBUG
printk
(
KERN_DEBUG
"i2c-piix4.o: Successfull!
\n
"
);
#endif
}
}
/* start the transaction by setting bit 6 */
outb_p
(
inb
(
SMBHSTCNT
)
|
0x040
,
SMBHSTCNT
);
/* We will always wait for a fraction of a second! (See PIIX4 docs errata) */
do
{
piix4_do_pause
(
1
);
temp
=
inb_p
(
SMBHSTSTS
);
}
while
((
temp
&
0x01
)
&&
(
timeout
++
<
MAX_TIMEOUT
));
#ifdef DEBUG
/* If the SMBus is still busy, we give up */
if
(
timeout
>=
MAX_TIMEOUT
)
{
printk
(
KERN_ERR
"i2c-piix4.o: SMBus Timeout!
\n
"
);
result
=
-
1
;
}
#endif
if
(
temp
&
0x10
)
{
result
=
-
1
;
#ifdef DEBUG
printk
(
KERN_ERR
"i2c-piix4.o: Error: Failed bus transaction
\n
"
);
#endif
}
if
(
temp
&
0x08
)
{
result
=
-
1
;
printk
(
KERN_ERR
"i2c-piix4.o: Bus collision! SMBus may be locked until next hard
\n
"
"reset. (sorry!)
\n
"
);
/* Clock stops and slave is stuck in mid-transmission */
}
if
(
temp
&
0x04
)
{
result
=
-
1
;
#ifdef DEBUG
printk
(
KERN_ERR
"i2c-piix4.o: Error: no response!
\n
"
);
#endif
}
if
(
inb_p
(
SMBHSTSTS
)
!=
0x00
)
outb_p
(
inb
(
SMBHSTSTS
),
SMBHSTSTS
);
#ifdef DEBUG
if
((
temp
=
inb_p
(
SMBHSTSTS
))
!=
0x00
)
{
printk
(
KERN_ERR
"i2c-piix4.o: Failed reset at end of transaction (%02x)
\n
"
,
temp
);
}
printk
(
KERN_DEBUG
"i2c-piix4.o: Transaction (post): CNT=%02x, CMD=%02x, ADD=%02x, "
"DAT0=%02x, DAT1=%02x
\n
"
,
inb_p
(
SMBHSTCNT
),
inb_p
(
SMBHSTCMD
),
inb_p
(
SMBHSTADD
),
inb_p
(
SMBHSTDAT0
),
inb_p
(
SMBHSTDAT1
));
#endif
return
result
;
}
/* Return -1 on error. */
static
s32
piix4_access
(
struct
i2c_adapter
*
adap
,
u16
addr
,
unsigned
short
flags
,
char
read_write
,
u8
command
,
int
size
,
union
i2c_smbus_data
*
data
)
{
int
i
,
len
;
switch
(
size
)
{
case
I2C_SMBUS_PROC_CALL
:
printk
(
KERN_ERR
"i2c-piix4.o: I2C_SMBUS_PROC_CALL not supported!
\n
"
);
return
-
1
;
case
I2C_SMBUS_QUICK
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
size
=
PIIX4_QUICK
;
break
;
case
I2C_SMBUS_BYTE
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
outb_p
(
command
,
SMBHSTCMD
);
size
=
PIIX4_BYTE
;
break
;
case
I2C_SMBUS_BYTE_DATA
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
outb_p
(
command
,
SMBHSTCMD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
outb_p
(
data
->
byte
,
SMBHSTDAT0
);
size
=
PIIX4_BYTE_DATA
;
break
;
case
I2C_SMBUS_WORD_DATA
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
outb_p
(
command
,
SMBHSTCMD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
{
outb_p
(
data
->
word
&
0xff
,
SMBHSTDAT0
);
outb_p
((
data
->
word
&
0xff00
)
>>
8
,
SMBHSTDAT1
);
}
size
=
PIIX4_WORD_DATA
;
break
;
case
I2C_SMBUS_BLOCK_DATA
:
outb_p
(((
addr
&
0x7f
)
<<
1
)
|
(
read_write
&
0x01
),
SMBHSTADD
);
outb_p
(
command
,
SMBHSTCMD
);
if
(
read_write
==
I2C_SMBUS_WRITE
)
{
len
=
data
->
block
[
0
];
if
(
len
<
0
)
len
=
0
;
if
(
len
>
32
)
len
=
32
;
outb_p
(
len
,
SMBHSTDAT0
);
i
=
inb_p
(
SMBHSTCNT
);
/* Reset SMBBLKDAT */
for
(
i
=
1
;
i
<=
len
;
i
++
)
outb_p
(
data
->
block
[
i
],
SMBBLKDAT
);
}
size
=
PIIX4_BLOCK_DATA
;
break
;
}
outb_p
((
size
&
0x1C
)
+
(
ENABLE_INT9
&
1
),
SMBHSTCNT
);
if
(
piix4_transaction
())
/* Error in transaction */
return
-
1
;
if
((
read_write
==
I2C_SMBUS_WRITE
)
||
(
size
==
PIIX4_QUICK
))
return
0
;
switch
(
size
)
{
case
PIIX4_BYTE
:
/* Where is the result put? I assume here it is in
SMBHSTDAT0 but it might just as well be in the
SMBHSTCMD. No clue in the docs */
data
->
byte
=
inb_p
(
SMBHSTDAT0
);
break
;
case
PIIX4_BYTE_DATA
:
data
->
byte
=
inb_p
(
SMBHSTDAT0
);
break
;
case
PIIX4_WORD_DATA
:
data
->
word
=
inb_p
(
SMBHSTDAT0
)
+
(
inb_p
(
SMBHSTDAT1
)
<<
8
);
break
;
case
PIIX4_BLOCK_DATA
:
data
->
block
[
0
]
=
inb_p
(
SMBHSTDAT0
);
i
=
inb_p
(
SMBHSTCNT
);
/* Reset SMBBLKDAT */
for
(
i
=
1
;
i
<=
data
->
block
[
0
];
i
++
)
data
->
block
[
i
]
=
inb_p
(
SMBBLKDAT
);
break
;
}
return
0
;
}
static
u32
piix4_func
(
struct
i2c_adapter
*
adapter
)
{
return
I2C_FUNC_SMBUS_QUICK
|
I2C_FUNC_SMBUS_BYTE
|
I2C_FUNC_SMBUS_BYTE_DATA
|
I2C_FUNC_SMBUS_WORD_DATA
|
I2C_FUNC_SMBUS_BLOCK_DATA
;
}
static
struct
i2c_algorithm
smbus_algorithm
=
{
.
name
=
"Non-I2C SMBus adapter"
,
.
id
=
I2C_ALGO_SMBUS
,
.
smbus_xfer
=
piix4_access
,
.
functionality
=
piix4_func
,
};
static
struct
i2c_adapter
piix4_adapter
=
{
.
owner
=
THIS_MODULE
,
.
name
=
"unset"
,
.
id
=
I2C_ALGO_SMBUS
|
I2C_HW_SMBUS_PIIX4
,
.
algo
=
&
smbus_algorithm
,
};
static
struct
pci_device_id
piix4_ids
[]
__devinitdata
=
{
{
.
vendor
=
PCI_VENDOR_ID_INTEL
,
.
device
=
PCI_DEVICE_ID_INTEL_82371AB_3
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
driver_data
=
3
},
{
.
vendor
=
PCI_VENDOR_ID_SERVERWORKS
,
.
device
=
PCI_DEVICE_ID_SERVERWORKS_OSB4
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
driver_data
=
0
,
},
{
.
vendor
=
PCI_VENDOR_ID_SERVERWORKS
,
.
device
=
PCI_DEVICE_ID_SERVERWORKS_CSB5
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
driver_data
=
0
,
},
{
.
vendor
=
PCI_VENDOR_ID_INTEL
,
.
device
=
PCI_DEVICE_ID_INTEL_82443MX_3
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
driver_data
=
3
,
},
{
.
vendor
=
PCI_VENDOR_ID_EFAR
,
.
device
=
PCI_DEVICE_ID_EFAR_SLC90E66_3
,
.
subvendor
=
PCI_ANY_ID
,
.
subdevice
=
PCI_ANY_ID
,
.
driver_data
=
0
,
},
{
0
,
}
};
static
int
__devinit
piix4_probe
(
struct
pci_dev
*
dev
,
const
struct
pci_device_id
*
id
)
{
int
retval
;
retval
=
piix4_setup
(
dev
,
id
);
if
(
retval
)
return
retval
;
/* set up the driverfs linkage to our parent device */
piix4_adapter
.
dev
.
parent
=
&
dev
->
dev
;
sprintf
(
piix4_adapter
.
name
,
"SMBus PIIX4 adapter at %04x"
,
piix4_smba
);
retval
=
i2c_add_adapter
(
&
piix4_adapter
);
return
retval
;
}
static
void
__devexit
piix4_remove
(
struct
pci_dev
*
dev
)
{
i2c_del_adapter
(
&
piix4_adapter
);
}
static
struct
pci_driver
piix4_driver
=
{
.
name
=
"piix4 smbus"
,
.
id_table
=
piix4_ids
,
.
probe
=
piix4_probe
,
.
remove
=
__devexit_p
(
piix4_remove
),
};
static
int
__init
i2c_piix4_init
(
void
)
{
printk
(
"i2c-piix4.o version %s (%s)
\n
"
,
I2C_VERSION
,
I2C_DATE
);
return
pci_module_init
(
&
piix4_driver
);
}
static
void
__exit
i2c_piix4_exit
(
void
)
{
pci_unregister_driver
(
&
piix4_driver
);
release_region
(
piix4_smba
,
8
);
}
MODULE_AUTHOR
(
"Frodo Looijaard <frodol@dds.nl> and Philip Edelbrock <phil@netroedge.com>"
);
MODULE_DESCRIPTION
(
"PIIX4 SMBus driver"
);
MODULE_LICENSE
(
"GPL"
);
module_init
(
i2c_piix4_init
);
module_exit
(
i2c_piix4_exit
);
drivers/i2c/i2c-core.c
View file @
2b3163d4
...
...
@@ -30,6 +30,7 @@
#include <linux/proc_fs.h>
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/seq_file.h>
#include <asm/uaccess.h>
...
...
@@ -87,6 +88,16 @@ int i2c_add_adapter(struct i2c_adapter *adap)
init_MUTEX
(
&
adap
->
bus
);
init_MUTEX
(
&
adap
->
list
);
/* Add the adapter to the driver core.
* If the parent pointer is not set up,
* we add this adapter to the legacy bus.
*/
if
(
adap
->
dev
.
parent
==
NULL
)
adap
->
dev
.
parent
=
&
legacy_bus
;
sprintf
(
adap
->
dev
.
bus_id
,
"i2c-%d"
,
i
);
strcpy
(
adap
->
dev
.
name
,
"i2c controller"
);
device_register
(
&
adap
->
dev
);
/* inform drivers of new adapters */
for
(
j
=
0
;
j
<
I2C_DRIVER_MAX
;
j
++
)
if
(
drivers
[
j
]
!=
NULL
&&
...
...
@@ -154,6 +165,9 @@ int i2c_del_adapter(struct i2c_adapter *adap)
i2cproc_remove
(
i
);
/* clean up the sysfs representation */
device_unregister
(
&
adap
->
dev
);
adapters
[
i
]
=
NULL
;
DEB
(
printk
(
KERN_DEBUG
"i2c-core.o: adapter unregistered: %s
\n
"
,
adap
->
name
));
...
...
@@ -313,42 +327,45 @@ int i2c_check_addr(struct i2c_adapter *adapter, int addr)
int
i2c_attach_client
(
struct
i2c_client
*
client
)
{
struct
i2c_adapter
*
adapter
=
client
->
adapter
;
int
res
=
-
EBUSY
,
i
;
int
i
;
down
(
&
adapter
->
list
);
if
(
__i2c_check_addr
(
client
->
adapter
,
client
->
addr
))
if
(
__i2c_check_addr
(
client
->
adapter
,
client
->
addr
))
goto
out_unlock_list
;
for
(
i
=
0
;
i
<
I2C_CLIENT_MAX
;
i
++
)
if
(
NULL
==
adapter
->
clients
[
i
])
break
;
if
(
I2C_CLIENT_MAX
==
i
)
{
printk
(
KERN_WARNING
" i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.
\n
"
,
client
->
name
);
res
=
-
ENOMEM
;
goto
out_unlock_list
;
for
(
i
=
0
;
i
<
I2C_CLIENT_MAX
;
i
++
)
{
if
(
!
adapter
->
clients
[
i
])
goto
free_slot
;
}
printk
(
KERN_WARNING
" i2c-core.o: attach_client(%s) - enlarge I2C_CLIENT_MAX.
\n
"
,
client
->
name
);
out_unlock_list:
up
(
&
adapter
->
list
);
return
-
EBUSY
;
free_slot:
adapter
->
clients
[
i
]
=
client
;
up
(
&
adapter
->
list
);
if
(
adapter
->
client_register
)
if
(
adapter
->
client_register
(
client
))
printk
(
KERN_DEBUG
"i2c-core.o: warning: client_register seems "
if
(
adapter
->
client_register
)
{
if
(
adapter
->
client_register
(
client
))
{
printk
(
KERN_DEBUG
"i2c-core.o: warning: client_register seems "
"to have failed for client %02x at adapter %s
\n
"
,
client
->
addr
,
adapter
->
name
);
DEB
(
printk
(
KERN_DEBUG
"i2c-core.o: client [%s] registered to adapter [%s](pos. %d).
\n
"
,
client
->
name
,
adapter
->
name
,
i
));
client
->
addr
,
adapter
->
name
);
}
}
DEB
(
printk
(
KERN_DEBUG
"i2c-core.o: client [%s] registered to adapter [%s] "
"(pos. %d).
\n
"
,
client
->
name
,
adapter
->
name
,
i
));
if
(
client
->
flags
&
I2C_CLIENT_ALLOW_USE
)
if
(
client
->
flags
&
I2C_CLIENT_ALLOW_USE
)
client
->
usage_count
=
0
;
return
0
;
out_unlock_list:
up
(
&
adapter
->
list
);
return
res
;
}
...
...
@@ -363,28 +380,30 @@ int i2c_detach_client(struct i2c_client *client)
if
(
adapter
->
client_unregister
)
{
res
=
adapter
->
client_unregister
(
client
);
if
(
res
)
{
printk
(
KERN_ERR
"i2c-core.o: client_unregister [%s] failed, "
"client not detached"
,
client
->
name
);
return
res
;
printk
(
KERN_ERR
"i2c-core.o: client_unregister [%s] failed, "
"client not detached"
,
client
->
name
);
goto
out
;
}
}
down
(
&
adapter
->
list
);
for
(
i
=
0
;
i
<
I2C_CLIENT_MAX
;
i
++
)
{
if
(
client
==
adapter
->
clients
[
i
])
break
;
if
(
client
==
adapter
->
clients
[
i
])
{
adapter
->
clients
[
i
]
=
NULL
;
goto
out_unlock
;
}
}
if
(
I2C_CLIENT_MAX
==
i
)
{
printk
(
KERN_WARNING
" i2c-core.o: unregister_client "
"[%s] not found
\n
"
,
client
->
name
);
return
-
ENODEV
;
}
else
adapter
->
clients
[
i
]
=
NULL
;
up
(
&
adapter
->
list
);
printk
(
KERN_WARNING
" i2c-core.o: unregister_client [%s] not found
\n
"
,
client
->
name
);
res
=
-
ENODEV
;
return
0
;
out_unlock:
up
(
&
adapter
->
list
);
out:
return
res
;
}
static
int
i2c_inc_use_client
(
struct
i2c_client
*
client
)
...
...
@@ -443,45 +462,7 @@ int i2c_release_client(struct i2c_client *client)
return
0
;
}
/* ----------------------------------------------------
* The /proc functions
* ----------------------------------------------------
*/
#ifdef CONFIG_PROC_FS
/* This function generates the output for /proc/bus/i2c */
static
int
read_bus_i2c
(
char
*
buf
,
char
**
start
,
off_t
offset
,
int
len
,
int
*
eof
,
void
*
private
)
{
int
i
;
int
nr
=
0
;
/* Note that it is safe to write a `little' beyond len. Yes, really. */
/* Fuck you. Will convert this to seq_file later. --hch */
down
(
&
core_lists
);
for
(
i
=
0
;
(
i
<
I2C_ADAP_MAX
)
&&
(
nr
<
len
);
i
++
)
{
if
(
adapters
[
i
])
{
nr
+=
sprintf
(
buf
+
nr
,
"i2c-%d
\t
"
,
i
);
if
(
adapters
[
i
]
->
algo
->
smbus_xfer
)
{
if
(
adapters
[
i
]
->
algo
->
master_xfer
)
nr
+=
sprintf
(
buf
+
nr
,
"smbus/i2c"
);
else
nr
+=
sprintf
(
buf
+
nr
,
"smbus "
);
}
else
if
(
adapters
[
i
]
->
algo
->
master_xfer
)
nr
+=
sprintf
(
buf
+
nr
,
"i2c "
);
else
nr
+=
sprintf
(
buf
+
nr
,
"dummy "
);
nr
+=
sprintf
(
buf
+
nr
,
"
\t
%-32s
\t
%-32s
\n
"
,
adapters
[
i
]
->
name
,
adapters
[
i
]
->
algo
->
name
);
}
}
up
(
&
core_lists
);
return
nr
;
}
/* This function generates the output for /proc/bus/i2c-? */
static
ssize_t
i2cproc_bus_read
(
struct
file
*
file
,
char
*
buf
,
size_t
count
,
loff_t
*
ppos
)
...
...
@@ -551,6 +532,50 @@ static struct file_operations i2cproc_operations = {
.
read
=
i2cproc_bus_read
,
};
/* This function generates the output for /proc/bus/i2c */
static
int
bus_i2c_show
(
struct
seq_file
*
s
,
void
*
p
)
{
int
i
;
down
(
&
core_lists
);
for
(
i
=
0
;
i
<
I2C_ADAP_MAX
;
i
++
)
{
struct
i2c_adapter
*
adapter
=
adapters
[
i
];
if
(
!
adapter
)
continue
;
seq_printf
(
s
,
"i2c-%d
\t
"
,
i
);
if
(
adapter
->
algo
->
smbus_xfer
)
{
if
(
adapter
->
algo
->
master_xfer
)
seq_printf
(
s
,
"smbus/i2c"
);
else
seq_printf
(
s
,
"smbus "
);
}
else
if
(
adapter
->
algo
->
master_xfer
)
seq_printf
(
s
,
"i2c "
);
else
seq_printf
(
s
,
"dummy "
);
seq_printf
(
s
,
"
\t
%-32s
\t
%-32s
\n
"
,
adapter
->
name
,
adapter
->
algo
->
name
);
}
up
(
&
core_lists
);
return
0
;
}
static
int
bus_i2c_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
return
single_open
(
file
,
bus_i2c_show
,
NULL
);
}
static
struct
file_operations
bus_i2c_fops
=
{
.
open
=
bus_i2c_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
single_release
,
};
static
int
i2cproc_register
(
struct
i2c_adapter
*
adap
,
int
bus
)
{
struct
proc_dir_entry
*
proc_entry
;
...
...
@@ -563,7 +588,7 @@ static int i2cproc_register(struct i2c_adapter *adap, int bus)
goto
fail
;
proc_entry
->
proc_fops
=
&
i2cproc_operations
;
proc_entry
->
owner
=
THIS_MODULE
;
proc_entry
->
owner
=
adap
->
owner
;
adap
->
inode
=
proc_entry
->
low_ino
;
return
0
;
fail:
...
...
@@ -583,25 +608,53 @@ static int __init i2cproc_init(void)
{
struct
proc_dir_entry
*
proc_bus_i2c
;
proc_bus_i2c
=
create_proc_entry
(
"i2c"
,
0
,
proc_bus
);
if
(
!
proc_bus_i2c
)
{
printk
(
KERN_ERR
"i2c-core.o: Could not create /proc/bus/i2c"
);
return
-
ENOENT
;
}
proc_bus_i2c
=
create_proc_entry
(
"i2c"
,
0
,
proc_bus
);
if
(
!
proc_bus_i2c
)
goto
fail
;
proc_bus_i2c
->
proc_fops
=
&
bus_i2c_fops
;
proc_bus_i2c
->
owner
=
THIS_MODULE
;
return
0
;
proc_bus_i2c
->
read_proc
=
&
read_bus_i2c
;
pr
oc_bus_i2c
->
owner
=
THIS_MODULE
;
return
0
;
fail:
pr
intk
(
KERN_ERR
"i2c-core.o: Could not create /proc/bus/i2c"
)
;
return
-
ENOENT
;
}
static
void
__exit
i2cproc_cleanup
(
void
)
{
remove_proc_entry
(
"i2c"
,
proc_bus
);
}
#else
static
int
__init
i2cproc_init
(
void
)
{
return
0
;
}
static
void
__exit
i2cproc_cleanup
(
void
)
{
}
#endif
/* CONFIG_PROC_FS */
/* match always succeeds, as we want the probe() to tell if we really accept this match */
static
int
i2c_device_match
(
struct
device
*
dev
,
struct
device_driver
*
drv
)
{
return
1
;
}
struct
bus_type
i2c_bus_type
=
{
.
name
=
"i2c"
,
.
match
=
i2c_device_match
,
};
static
int
__init
i2c_init
(
void
)
{
bus_register
(
&
i2c_bus_type
);
return
i2cproc_init
();
}
static
void
__exit
i2c_exit
(
void
)
{
i2cproc_cleanup
();
bus_unregister
(
&
i2c_bus_type
);
}
module_init
(
i2cproc_init
);
module_exit
(
i2cproc_cleanup
);
#endif
/* def CONFIG_PROC_FS */
module_init
(
i2c_init
);
module_exit
(
i2c_exit
);
/* ----------------------------------------------------
* the functional interface to the i2c busses.
...
...
drivers/i2c/i2c-proc.c
View file @
2b3163d4
...
...
@@ -35,8 +35,6 @@
#include <linux/i2c-proc.h>
#include <asm/uaccess.h>
static
int
i2c_create_name
(
char
**
name
,
const
char
*
prefix
,
struct
i2c_adapter
*
adapter
,
int
addr
);
static
int
i2c_parse_reals
(
int
*
nrels
,
void
*
buffer
,
int
bufsize
,
long
*
results
,
int
magnitude
);
static
int
i2c_write_reals
(
int
nrels
,
void
*
buffer
,
size_t
*
bufsize
,
...
...
@@ -54,15 +52,6 @@ static struct ctl_table_header *i2c_entries[SENSORS_ENTRY_MAX];
static
struct
i2c_client
*
i2c_clients
[
SENSORS_ENTRY_MAX
];
static
ctl_table
sysctl_table
[]
=
{
{
CTL_DEV
,
"dev"
,
NULL
,
0
,
0555
},
{
0
},
{
DEV_SENSORS
,
"sensors"
,
NULL
,
0
,
0555
},
{
0
},
{
0
,
NULL
,
NULL
,
0
,
0555
},
{
0
}
};
static
ctl_table
i2c_proc_dev_sensors
[]
=
{
{
SENSORS_CHIPS
,
"chips"
,
NULL
,
0
,
0644
,
NULL
,
&
i2c_proc_chips
,
&
i2c_sysctl_chips
},
...
...
@@ -87,36 +76,40 @@ static struct ctl_table_header *i2c_proc_header;
(for a LM78 chip on the ISA bus at port 0x310), or lm75-i2c-3-4e (for
a LM75 chip on the third i2c bus at address 0x4e).
name is allocated first. */
static
int
i2c_create_name
(
char
**
name
,
const
char
*
prefix
,
struct
i2c_adapter
*
adapter
,
int
addr
)
static
char
*
generate_name
(
struct
i2c_client
*
client
,
const
char
*
prefix
)
{
char
name_buffer
[
50
];
int
id
,
i
,
end
;
if
(
i2c_is_isa_adapter
(
adapter
))
struct
i2c_adapter
*
adapter
=
client
->
adapter
;
int
addr
=
client
->
addr
;
char
name_buffer
[
50
],
*
name
;
if
(
i2c_is_isa_adapter
(
adapter
))
{
sprintf
(
name_buffer
,
"%s-isa-%04x"
,
prefix
,
addr
);
else
if
(
!
adapter
->
algo
->
smbus_xfer
&&
!
adapter
->
algo
->
master_xfer
)
{
/* dummy adapter, generate prefix */
}
else
if
(
adapter
->
algo
->
smbus_xfer
||
adapter
->
algo
->
master_xfer
)
{
int
id
=
i2c_adapter_id
(
adapter
);
if
(
id
<
0
)
return
ERR_PTR
(
-
ENOENT
);
sprintf
(
name_buffer
,
"%s-i2c-%d-%02x"
,
prefix
,
id
,
addr
);
}
else
{
/* dummy adapter, generate prefix */
int
end
,
i
;
sprintf
(
name_buffer
,
"%s-"
,
prefix
);
end
=
strlen
(
name_buffer
);
for
(
i
=
0
;
i
<
32
;
i
++
)
{
if
(
adapter
->
algo
->
name
[
i
]
==
' '
)
for
(
i
=
0
;
i
<
32
;
i
++
)
{
if
(
adapter
->
algo
->
name
[
i
]
==
' '
)
break
;
name_buffer
[
end
++
]
=
tolower
(
adapter
->
algo
->
name
[
i
]);
}
name_buffer
[
end
]
=
0
;
sprintf
(
name_buffer
+
end
,
"-%04x"
,
addr
);
}
else
{
if
((
id
=
i2c_adapter_id
(
adapter
))
<
0
)
return
-
ENOENT
;
sprintf
(
name_buffer
,
"%s-i2c-%d-%02x"
,
prefix
,
id
,
addr
);
}
*
name
=
kmalloc
(
strlen
(
name_buffer
)
+
1
,
GFP_KERNEL
);
if
(
!*
name
)
{
printk
(
KERN_WARNING
"i2c_create_name: not enough memory
\n
"
);
return
-
ENOMEM
;
}
strcpy
(
*
name
,
name_buffer
);
return
0
;
name
=
kmalloc
(
strlen
(
name_buffer
)
+
1
,
GFP_KERNEL
);
if
(
unlikely
(
!
name
))
return
ERR_PTR
(
-
ENOMEM
);
strcpy
(
name
,
name_buffer
);
return
name
;
}
/* This rather complex function must be called when you want to add an entry
...
...
@@ -127,93 +120,80 @@ static int i2c_create_name(char **name, const char *prefix,
If any driver wants subdirectories within the newly created directory,
this function must be updated! */
int
i2c_register_entry
(
struct
i2c_client
*
client
,
const
char
*
prefix
,
ctl_table
*
ctl_template
)
struct
ctl_table
*
leaf
)
{
int
i
,
res
,
len
,
id
;
ctl_table
*
new_table
,
*
client_tbl
,
*
tbl
;
char
*
name
;
struct
ctl_table_header
*
new_header
;
struct
{
struct
ctl_table
root
[
2
],
dev
[
2
],
sensors
[
2
];
}
*
tbl
;
struct
ctl_table_header
*
hdr
;
struct
ctl_table
*
tmp
;
const
char
*
name
;
int
id
;
name
=
generate_name
(
client
,
prefix
);
if
(
IS_ERR
(
name
))
return
PTR_ERR
(
name
);
for
(
id
=
0
;
id
<
SENSORS_ENTRY_MAX
;
id
++
)
{
if
(
!
i2c_entries
[
id
])
goto
free_slot
;
}
if
((
res
=
i2c_create_name
(
&
name
,
prefix
,
client
->
adapter
,
client
->
addr
)))
return
res
;
goto
out_free_name
;
for
(
id
=
0
;
id
<
SENSORS_ENTRY_MAX
;
id
++
)
if
(
!
i2c_entries
[
id
])
{
break
;
}
if
(
id
==
SENSORS_ENTRY_MAX
)
{
kfree
(
name
);
return
-
ENOMEM
;
}
free_slot:
tbl
=
kmalloc
(
sizeof
(
*
tbl
),
GFP_KERNEL
);
if
(
unlikely
(
!
tbl
))
goto
out_free_name
;
memset
(
tbl
,
0
,
sizeof
(
*
tbl
));
id
+=
256
;
len
=
0
;
while
(
ctl_template
[
len
].
procname
)
len
++
;
if
(
!
(
new_table
=
kmalloc
(
sizeof
(
sysctl_table
)
+
sizeof
(
ctl_table
)
*
(
len
+
1
),
GFP_KERNEL
)))
{
kfree
(
name
);
return
-
ENOMEM
;
}
for
(
tmp
=
leaf
;
tmp
->
ctl_name
;
tmp
++
)
tmp
->
extra2
=
client
;
memcpy
(
new_table
,
sysctl_table
,
sizeof
(
sysctl_table
));
tbl
=
new_table
;
/* sys/ */
tbl
=
tbl
->
child
=
tbl
+
2
;
/* dev/ */
tbl
=
tbl
->
child
=
tbl
+
2
;
/* sensors/ */
client_tbl
=
tbl
->
child
=
tbl
+
2
;
/* XX-chip-YY-ZZ/ */
tbl
->
sensors
->
ctl_name
=
id
+
256
;
tbl
->
sensors
->
procname
=
name
;
tbl
->
sensors
->
mode
=
0555
;
tbl
->
sensors
->
child
=
leaf
;
client_tbl
->
procname
=
name
;
client_tbl
->
ctl_name
=
id
;
client_tbl
->
child
=
client_tbl
+
2
;
tbl
->
dev
->
ctl_name
=
DEV_SENSORS
;
tbl
->
dev
->
procname
=
"sensors"
;
tbl
->
dev
->
mode
=
0555
;
tbl
->
dev
->
child
=
tbl
->
sensors
;
/* Next the client sysctls. --km */
tbl
=
client_tbl
->
child
;
memcpy
(
tbl
,
ctl_template
,
sizeof
(
ctl_table
)
*
(
len
+
1
));
for
(
i
=
0
;
i
<
len
;
i
++
)
tbl
[
i
].
extra2
=
client
;
tbl
->
root
->
ctl_name
=
CTL_DEV
;
tbl
->
root
->
procname
=
"dev"
;
tbl
->
root
->
mode
=
0555
;
tbl
->
root
->
child
=
tbl
->
dev
;
if
(
!
(
new_header
=
register_sysctl_table
(
new_table
,
0
)))
{
printk
(
KERN_ERR
"i2c-proc.o: error: sysctl interface not supported by kernel!
\n
"
);
kfree
(
new_table
);
kfree
(
name
);
return
-
EPERM
;
}
hdr
=
register_sysctl_table
(
tbl
->
root
,
0
);
if
(
unlikely
(
!
hdr
))
goto
out_free_tbl
;
i2c_entries
[
id
-
256
]
=
new_header
;
i2c_entries
[
id
]
=
hdr
;
i2c_clients
[
id
]
=
client
;
i2c_clients
[
id
-
256
]
=
client
;
return
(
id
+
256
);
/* XXX(hch) why?? */
#ifdef DEBUG
if
(
!
new_header
||
!
new_header
->
ctl_table
||
!
new_header
->
ctl_table
->
child
||
!
new_header
->
ctl_table
->
child
->
child
||
!
new_header
->
ctl_table
->
child
->
child
->
de
)
{
printk
(
KERN_ERR
"i2c-proc.o: NULL pointer when trying to install fill_inode fix!
\n
"
);
return
id
;
}
#endif
/* DEBUG */
client_tbl
->
de
->
owner
=
client
->
driver
->
owner
;
return
id
;
out_free_tbl:
kfree
(
tbl
);
out_free_name:
kfree
(
name
);
return
-
ENOMEM
;
}
void
i2c_deregister_entry
(
int
id
)
{
ctl_table
*
table
;
char
*
temp
;
id
-=
256
;
id
-=
256
;
if
(
i2c_entries
[
id
])
{
table
=
i2c_entries
[
id
]
->
ctl_table
;
unregister_sysctl_table
(
i2c_entries
[
id
]);
/* 2-step kfree needed to keep gcc happy about const points */
(
const
char
*
)
temp
=
table
[
4
].
procname
;
kfree
(
temp
);
kfree
(
table
);
i2c_entries
[
id
]
=
NULL
;
i2c_clients
[
id
]
=
NULL
;
struct
ctl_table_header
*
hdr
=
i2c_entries
[
id
];
struct
ctl_table
*
tbl
=
hdr
->
ctl_table
;
unregister_sysctl_table
(
hdr
);
kfree
(
tbl
->
child
->
child
->
procname
);
kfree
(
tbl
);
/* actually the whole anonymous struct */
}
i2c_entries
[
id
]
=
NULL
;
i2c_clients
[
id
]
=
NULL
;
}
static
int
i2c_proc_chips
(
ctl_table
*
ctl
,
int
write
,
struct
file
*
filp
,
...
...
drivers/md/linear.c
View file @
2b3163d4
...
...
@@ -203,36 +203,34 @@ static int linear_make_request (request_queue_t *q, struct bio *bio)
return
0
;
}
bio
->
bi_bdev
=
tmp_dev
->
rdev
->
bdev
;
bio
->
bi_sector
=
bio
->
bi_sector
-
(
tmp_dev
->
offset
<<
1
);
bio
->
bi_sector
=
bio
->
bi_sector
-
(
tmp_dev
->
offset
<<
1
)
+
tmp_dev
->
rdev
->
data_offset
;
return
1
;
}
static
int
linear_status
(
char
*
page
,
mddev_t
*
mddev
)
static
void
linear_status
(
struct
seq_file
*
seq
,
mddev_t
*
mddev
)
{
int
sz
=
0
;
#undef MD_DEBUG
#ifdef MD_DEBUG
int
j
;
linear_conf_t
*
conf
=
mddev_to_conf
(
mddev
);
s
z
+=
sprintf
(
page
+
sz
,
" "
);
s
eq_printf
(
seq
,
" "
);
for
(
j
=
0
;
j
<
conf
->
nr_zones
;
j
++
)
{
s
z
+=
sprintf
(
page
+
sz
,
"[%s"
,
s
eq_printf
(
seq
,
"[%s"
,
bdev_partition_name
(
conf
->
hash_table
[
j
].
dev0
->
rdev
->
bdev
));
if
(
conf
->
hash_table
[
j
].
dev1
)
s
z
+=
sprintf
(
page
+
sz
,
"/%s] "
,
s
eq_printf
(
seq
,
"/%s] "
,
bdev_partition_name
(
conf
->
hash_table
[
j
].
dev1
->
rdev
->
bdev
));
else
s
z
+=
sprintf
(
page
+
sz
,
"] "
);
s
eq_printf
(
seq
,
"] "
);
}
s
z
+=
sprintf
(
page
+
sz
,
"
\n
"
);
s
eq_printf
(
seq
,
"
\n
"
);
#endif
sz
+=
sprintf
(
page
+
sz
,
" %dk rounding"
,
mddev
->
chunk_size
/
1024
);
return
sz
;
seq_printf
(
seq
,
" %dk rounding"
,
mddev
->
chunk_size
/
1024
);
}
...
...
drivers/md/md.c
View file @
2b3163d4
...
...
@@ -124,9 +124,6 @@ static ctl_table raid_root_table[] = {
{
.
ctl_name
=
0
}
};
static
void
md_recover_arrays
(
void
);
static
mdk_thread_t
*
md_recovery_thread
;
sector_t
md_size
[
MAX_MD_DEVS
];
static
struct
block_device_operations
md_fops
;
...
...
@@ -222,6 +219,7 @@ static mddev_t * mddev_find(int unit)
init_MUTEX
(
&
new
->
reconfig_sem
);
INIT_LIST_HEAD
(
&
new
->
disks
);
INIT_LIST_HEAD
(
&
new
->
all_mddevs
);
init_timer
(
&
new
->
safemode_timer
);
atomic_set
(
&
new
->
active
,
1
);
blk_queue_make_request
(
&
new
->
queue
,
md_fail_request
);
...
...
@@ -272,40 +270,35 @@ static mdk_rdev_t * find_rdev(mddev_t * mddev, dev_t dev)
return
NULL
;
}
static
sector_t
calc_dev_sboffset
(
struct
block_device
*
bdev
)
inline
static
sector_t
calc_dev_sboffset
(
struct
block_device
*
bdev
)
{
sector_t
size
=
bdev
->
bd_inode
->
i_size
>>
BLOCK_SIZE_BITS
;
return
MD_NEW_SIZE_BLOCKS
(
size
);
}
static
sector_t
calc_dev_size
(
struct
block_device
*
bdev
,
mddev_t
*
mddev
)
static
sector_t
calc_dev_size
(
mdk_rdev_t
*
rdev
,
unsigned
chunk_size
)
{
sector_t
size
;
if
(
mddev
->
persistent
)
size
=
calc_dev_sboffset
(
bdev
);
else
size
=
bdev
->
bd_inode
->
i_size
>>
BLOCK_SIZE_BITS
;
if
(
mddev
->
chunk_size
)
size
&=
~
((
sector_t
)
mddev
->
chunk_size
/
1024
-
1
);
size
=
rdev
->
sb_offset
;
if
(
chunk_size
)
size
&=
~
((
sector_t
)
chunk_size
/
1024
-
1
);
return
size
;
}
static
sector_t
zoned_raid_size
(
mddev_t
*
mddev
)
{
sector_t
mask
;
mdk_rdev_t
*
rdev
;
struct
list_head
*
tmp
;
/*
* do size and offset calculations.
*/
mask
=
~
((
sector_t
)
mddev
->
chunk_size
/
1024
-
1
);
ITERATE_RDEV
(
mddev
,
rdev
,
tmp
)
{
rdev
->
size
&=
mask
;
ITERATE_RDEV
(
mddev
,
rdev
,
tmp
)
md_size
[
mdidx
(
mddev
)]
+=
rdev
->
size
;
}
return
0
;
}
...
...
@@ -389,7 +382,6 @@ static int sync_page_io(struct block_device *bdev, sector_t sector, int size,
static
int
read_disk_sb
(
mdk_rdev_t
*
rdev
)
{
sector_t
sb_offset
;
if
(
!
rdev
->
sb_page
)
{
MD_BUG
();
...
...
@@ -398,16 +390,8 @@ static int read_disk_sb(mdk_rdev_t * rdev)
if
(
rdev
->
sb_loaded
)
return
0
;
/*
* Calculate the position of the superblock,
* it's at the end of the disk.
*
* It also happens to be a multiple of 4Kb.
*/
sb_offset
=
calc_dev_sboffset
(
rdev
->
bdev
);
rdev
->
sb_offset
=
sb_offset
;
if
(
!
sync_page_io
(
rdev
->
bdev
,
sb_offset
<<
1
,
MD_SB_BYTES
,
rdev
->
sb_page
,
READ
))
if
(
!
sync_page_io
(
rdev
->
bdev
,
rdev
->
sb_offset
<<
1
,
MD_SB_BYTES
,
rdev
->
sb_page
,
READ
))
goto
fail
;
rdev
->
sb_loaded
=
1
;
return
0
;
...
...
@@ -486,7 +470,7 @@ static unsigned int calc_sb_csum(mdp_super_t * sb)
* We rely on user-space to write the initial superblock, and support
* reading and updating of superblocks.
* Interface methods are:
* int load_super(mdk_rdev_t *dev, mdk_rdev_t *refdev)
* int load_super(mdk_rdev_t *dev, mdk_rdev_t *refdev
, int minor_version
)
* loads and validates a superblock on dev.
* if refdev != NULL, compare superblocks on both devices
* Return:
...
...
@@ -511,7 +495,7 @@ static unsigned int calc_sb_csum(mdp_super_t * sb)
struct
super_type
{
char
*
name
;
struct
module
*
owner
;
int
(
*
load_super
)(
mdk_rdev_t
*
rdev
,
mdk_rdev_t
*
refdev
);
int
(
*
load_super
)(
mdk_rdev_t
*
rdev
,
mdk_rdev_t
*
refdev
,
int
minor_version
);
int
(
*
validate_super
)(
mddev_t
*
mddev
,
mdk_rdev_t
*
rdev
);
void
(
*
sync_super
)(
mddev_t
*
mddev
,
mdk_rdev_t
*
rdev
);
};
...
...
@@ -519,10 +503,20 @@ struct super_type {
/*
* load_super for 0.90.0
*/
static
int
super_90_load
(
mdk_rdev_t
*
rdev
,
mdk_rdev_t
*
refdev
)
static
int
super_90_load
(
mdk_rdev_t
*
rdev
,
mdk_rdev_t
*
refdev
,
int
minor_version
)
{
mdp_super_t
*
sb
;
int
ret
;
sector_t
sb_offset
;
/*
* Calculate the position of the superblock,
* it's at the end of the disk.
*
* It also happens to be a multiple of 4Kb.
*/
sb_offset
=
calc_dev_sboffset
(
rdev
->
bdev
);
rdev
->
sb_offset
=
sb_offset
;
ret
=
read_disk_sb
(
rdev
);
if
(
ret
)
return
ret
;
...
...
@@ -557,6 +551,12 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev)
}
rdev
->
preferred_minor
=
sb
->
md_minor
;
rdev
->
data_offset
=
0
;
if
(
sb
->
level
==
MULTIPATH
)
rdev
->
desc_nr
=
-
1
;
else
rdev
->
desc_nr
=
sb
->
this_disk
.
number
;
if
(
refdev
==
0
)
ret
=
1
;
...
...
@@ -582,7 +582,7 @@ static int super_90_load(mdk_rdev_t *rdev, mdk_rdev_t *refdev)
else
ret
=
0
;
}
rdev
->
size
=
calc_dev_size
(
rdev
,
sb
->
chunk_size
);
abort:
return
ret
;
...
...
@@ -597,7 +597,7 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
mdp_super_t
*
sb
=
(
mdp_super_t
*
)
page_address
(
rdev
->
sb_page
);
if
(
mddev
->
raid_disks
==
0
)
{
mddev
->
major_version
=
sb
->
major_version
;
mddev
->
major_version
=
0
;
mddev
->
minor_version
=
sb
->
minor_version
;
mddev
->
patch_version
=
sb
->
patch_version
;
mddev
->
persistent
=
!
sb
->
not_persistent
;
...
...
@@ -634,7 +634,6 @@ static int super_90_validate(mddev_t *mddev, mdk_rdev_t *rdev)
return
-
EINVAL
;
}
if
(
mddev
->
level
!=
LEVEL_MULTIPATH
)
{
rdev
->
desc_nr
=
sb
->
this_disk
.
number
;
rdev
->
raid_disk
=
-
1
;
rdev
->
in_sync
=
rdev
->
faulty
=
0
;
desc
=
sb
->
disks
+
rdev
->
desc_nr
;
...
...
@@ -704,10 +703,8 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb
->
recovery_cp
=
mddev
->
recovery_cp
;
sb
->
cp_events_hi
=
(
mddev
->
events
>>
32
);
sb
->
cp_events_lo
=
(
u32
)
mddev
->
events
;
if
(
mddev
->
recovery_cp
==
MaxSector
)
{
printk
(
KERN_INFO
"md: marking sb clean...
\n
"
);
if
(
mddev
->
recovery_cp
==
MaxSector
)
sb
->
state
=
(
1
<<
MD_SB_CLEAN
);
}
}
else
sb
->
recovery_cp
=
0
;
...
...
@@ -717,7 +714,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb
->
disks
[
0
].
state
=
(
1
<<
MD_DISK_REMOVED
);
ITERATE_RDEV
(
mddev
,
rdev2
,
tmp
)
{
mdp_disk_t
*
d
;
if
(
rdev2
->
raid_disk
>=
0
)
if
(
rdev2
->
raid_disk
>=
0
&&
rdev2
->
in_sync
&&
!
rdev2
->
faulty
)
rdev2
->
desc_nr
=
rdev2
->
raid_disk
;
else
rdev2
->
desc_nr
=
next_spare
++
;
...
...
@@ -726,7 +723,7 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
d
->
number
=
rdev2
->
desc_nr
;
d
->
major
=
MAJOR
(
rdev2
->
bdev
->
bd_dev
);
d
->
minor
=
MINOR
(
rdev2
->
bdev
->
bd_dev
);
if
(
rdev2
->
raid_disk
>=
0
)
if
(
rdev2
->
raid_disk
>=
0
&&
rdev
->
in_sync
&&
!
rdev2
->
faulty
)
d
->
raid_disk
=
rdev2
->
raid_disk
;
else
d
->
raid_disk
=
rdev2
->
desc_nr
;
/* compatibility */
...
...
@@ -766,6 +763,210 @@ static void super_90_sync(mddev_t *mddev, mdk_rdev_t *rdev)
sb
->
sb_csum
=
calc_sb_csum
(
sb
);
}
/*
* version 1 superblock
*/
static
unsigned
int
calc_sb_1_csum
(
struct
mdp_superblock_1
*
sb
)
{
unsigned
int
disk_csum
,
csum
;
int
size
=
256
+
sb
->
max_dev
*
2
;
disk_csum
=
sb
->
sb_csum
;
sb
->
sb_csum
=
0
;
csum
=
csum_partial
((
void
*
)
sb
,
size
,
0
);
sb
->
sb_csum
=
disk_csum
;
return
csum
;
}
static
int
super_1_load
(
mdk_rdev_t
*
rdev
,
mdk_rdev_t
*
refdev
,
int
minor_version
)
{
struct
mdp_superblock_1
*
sb
;
int
ret
;
sector_t
sb_offset
;
/*
* Calculate the position of the superblock.
* It is always aligned to a 4K boundary and
* depeding on minor_version, it can be:
* 0: At least 8K, but less than 12K, from end of device
* 1: At start of device
* 2: 4K from start of device.
*/
switch
(
minor_version
)
{
case
0
:
sb_offset
=
rdev
->
bdev
->
bd_inode
->
i_size
>>
9
;
sb_offset
-=
8
*
2
;
sb_offset
&=
~
(
4
*
2
);
/* convert from sectors to K */
sb_offset
/=
2
;
break
;
case
1
:
sb_offset
=
0
;
break
;
case
2
:
sb_offset
=
4
;
break
;
default:
return
-
EINVAL
;
}
rdev
->
sb_offset
=
sb_offset
;
ret
=
read_disk_sb
(
rdev
);
if
(
ret
)
return
ret
;
sb
=
(
struct
mdp_superblock_1
*
)
page_address
(
rdev
->
sb_page
);
if
(
sb
->
magic
!=
cpu_to_le32
(
MD_SB_MAGIC
)
||
sb
->
major_version
!=
cpu_to_le32
(
1
)
||
le32_to_cpu
(
sb
->
max_dev
)
>
(
4096
-
256
)
/
2
||
le64_to_cpu
(
sb
->
super_offset
)
!=
(
rdev
->
sb_offset
<<
1
)
||
sb
->
feature_map
!=
0
)
return
-
EINVAL
;
if
(
calc_sb_1_csum
(
sb
)
!=
sb
->
sb_csum
)
{
printk
(
BAD_CSUM
,
bdev_partition_name
(
rdev
->
bdev
));
return
-
EINVAL
;
}
rdev
->
preferred_minor
=
0xffff
;
rdev
->
data_offset
=
le64_to_cpu
(
sb
->
data_offset
);
if
(
refdev
==
0
)
return
1
;
else
{
__u64
ev1
,
ev2
;
struct
mdp_superblock_1
*
refsb
=
(
struct
mdp_superblock_1
*
)
page_address
(
refdev
->
sb_page
);
if
(
memcmp
(
sb
->
set_uuid
,
refsb
->
set_uuid
,
16
)
!=
0
||
sb
->
level
!=
refsb
->
level
||
sb
->
layout
!=
refsb
->
layout
||
sb
->
chunksize
!=
refsb
->
chunksize
)
{
printk
(
KERN_WARNING
"md: %s has strangely different superblock to %s
\n
"
,
bdev_partition_name
(
rdev
->
bdev
),
bdev_partition_name
(
refdev
->
bdev
));
return
-
EINVAL
;
}
ev1
=
le64_to_cpu
(
sb
->
events
);
ev2
=
le64_to_cpu
(
refsb
->
events
);
if
(
ev1
>
ev2
)
return
1
;
}
if
(
minor_version
)
rdev
->
size
=
((
rdev
->
bdev
->
bd_inode
->
i_size
>>
9
)
-
le64_to_cpu
(
sb
->
data_offset
))
/
2
;
else
rdev
->
size
=
rdev
->
sb_offset
;
if
(
rdev
->
size
<
le64_to_cpu
(
sb
->
data_size
)
/
2
)
return
-
EINVAL
;
rdev
->
size
=
le64_to_cpu
(
sb
->
data_size
)
/
2
;
if
(
le32_to_cpu
(
sb
->
chunksize
))
rdev
->
size
&=
~
((
sector_t
)
le32_to_cpu
(
sb
->
chunksize
)
/
2
-
1
);
return
0
;
}
static
int
super_1_validate
(
mddev_t
*
mddev
,
mdk_rdev_t
*
rdev
)
{
struct
mdp_superblock_1
*
sb
=
(
struct
mdp_superblock_1
*
)
page_address
(
rdev
->
sb_page
);
if
(
mddev
->
raid_disks
==
0
)
{
mddev
->
major_version
=
1
;
mddev
->
minor_version
=
0
;
mddev
->
patch_version
=
0
;
mddev
->
persistent
=
1
;
mddev
->
chunk_size
=
le32_to_cpu
(
sb
->
chunksize
)
<<
9
;
mddev
->
ctime
=
le64_to_cpu
(
sb
->
ctime
)
&
((
1ULL
<<
32
)
-
1
);
mddev
->
utime
=
le64_to_cpu
(
sb
->
utime
)
&
((
1ULL
<<
32
)
-
1
);
mddev
->
level
=
le32_to_cpu
(
sb
->
level
);
mddev
->
layout
=
le32_to_cpu
(
sb
->
layout
);
mddev
->
raid_disks
=
le32_to_cpu
(
sb
->
raid_disks
);
mddev
->
size
=
(
u32
)
le64_to_cpu
(
sb
->
size
);
mddev
->
events
=
le64_to_cpu
(
sb
->
events
);
mddev
->
recovery_cp
=
le64_to_cpu
(
sb
->
resync_offset
);
memcpy
(
mddev
->
uuid
,
sb
->
set_uuid
,
16
);
mddev
->
max_disks
=
(
4096
-
256
)
/
2
;
}
else
{
__u64
ev1
;
ev1
=
le64_to_cpu
(
sb
->
events
);
++
ev1
;
if
(
ev1
<
mddev
->
events
)
return
-
EINVAL
;
}
if
(
mddev
->
level
!=
LEVEL_MULTIPATH
)
{
int
role
;
rdev
->
desc_nr
=
le32_to_cpu
(
sb
->
dev_number
);
role
=
le16_to_cpu
(
sb
->
dev_roles
[
rdev
->
desc_nr
]);
switch
(
role
)
{
case
0xffff
:
/* spare */
rdev
->
in_sync
=
0
;
rdev
->
faulty
=
0
;
rdev
->
raid_disk
=
-
1
;
break
;
case
0xfffe
:
/* faulty */
rdev
->
in_sync
=
0
;
rdev
->
faulty
=
1
;
rdev
->
raid_disk
=
-
1
;
break
;
default:
rdev
->
in_sync
=
1
;
rdev
->
faulty
=
0
;
rdev
->
raid_disk
=
role
;
break
;
}
}
return
0
;
}
static
void
super_1_sync
(
mddev_t
*
mddev
,
mdk_rdev_t
*
rdev
)
{
struct
mdp_superblock_1
*
sb
;
struct
list_head
*
tmp
;
mdk_rdev_t
*
rdev2
;
int
max_dev
,
i
;
/* make rdev->sb match mddev and rdev data. */
sb
=
(
struct
mdp_superblock_1
*
)
page_address
(
rdev
->
sb_page
);
sb
->
feature_map
=
0
;
sb
->
pad0
=
0
;
memset
(
sb
->
pad1
,
0
,
sizeof
(
sb
->
pad1
));
memset
(
sb
->
pad2
,
0
,
sizeof
(
sb
->
pad2
));
memset
(
sb
->
pad3
,
0
,
sizeof
(
sb
->
pad3
));
sb
->
utime
=
cpu_to_le64
((
__u64
)
mddev
->
utime
);
sb
->
events
=
cpu_to_le64
(
mddev
->
events
);
if
(
mddev
->
in_sync
)
sb
->
resync_offset
=
cpu_to_le64
(
mddev
->
recovery_cp
);
else
sb
->
resync_offset
=
cpu_to_le64
(
0
);
max_dev
=
0
;
ITERATE_RDEV
(
mddev
,
rdev2
,
tmp
)
if
(
rdev2
->
desc_nr
>
max_dev
)
max_dev
=
rdev2
->
desc_nr
;
sb
->
max_dev
=
max_dev
;
for
(
i
=
0
;
i
<
max_dev
;
i
++
)
sb
->
dev_roles
[
max_dev
]
=
cpu_to_le16
(
0xfffe
);
ITERATE_RDEV
(
mddev
,
rdev2
,
tmp
)
{
i
=
rdev2
->
desc_nr
;
if
(
rdev2
->
faulty
)
sb
->
dev_roles
[
i
]
=
cpu_to_le16
(
0xfffe
);
else
if
(
rdev2
->
in_sync
)
sb
->
dev_roles
[
i
]
=
cpu_to_le16
(
rdev2
->
raid_disk
);
else
sb
->
dev_roles
[
i
]
=
cpu_to_le16
(
0xffff
);
}
sb
->
recovery_offset
=
cpu_to_le64
(
0
);
/* not supported yet */
}
struct
super_type
super_types
[]
=
{
[
0
]
=
{
.
name
=
"0.90.0"
,
...
...
@@ -774,9 +975,14 @@ struct super_type super_types[] = {
.
validate_super
=
super_90_validate
,
.
sync_super
=
super_90_sync
,
},
[
1
]
=
{
.
name
=
"md-1"
,
.
owner
=
THIS_MODULE
,
.
load_super
=
super_1_load
,
.
validate_super
=
super_1_validate
,
.
sync_super
=
super_1_sync
,
},
};
static
mdk_rdev_t
*
match_dev_unit
(
mddev_t
*
mddev
,
mdk_rdev_t
*
dev
)
{
...
...
@@ -804,13 +1010,13 @@ static int match_mddev_units(mddev_t *mddev1, mddev_t *mddev2)
static
LIST_HEAD
(
pending_raid_disks
);
static
void
bind_rdev_to_array
(
mdk_rdev_t
*
rdev
,
mddev_t
*
mddev
)
static
int
bind_rdev_to_array
(
mdk_rdev_t
*
rdev
,
mddev_t
*
mddev
)
{
mdk_rdev_t
*
same_pdev
;
if
(
rdev
->
mddev
)
{
MD_BUG
();
return
;
return
-
EINVAL
;
}
same_pdev
=
match_dev_unit
(
mddev
,
rdev
);
if
(
same_pdev
)
...
...
@@ -820,9 +1026,25 @@ static void bind_rdev_to_array(mdk_rdev_t * rdev, mddev_t * mddev)
mdidx
(
mddev
),
bdev_partition_name
(
rdev
->
bdev
),
bdev_partition_name
(
same_pdev
->
bdev
));
/* Verify rdev->desc_nr is unique.
* If it is -1, assign a free number, else
* check number is not in use
*/
if
(
rdev
->
desc_nr
<
0
)
{
int
choice
=
0
;
if
(
mddev
->
pers
)
choice
=
mddev
->
raid_disks
;
while
(
find_rdev_nr
(
mddev
,
choice
))
choice
++
;
rdev
->
desc_nr
=
choice
;
}
else
{
if
(
find_rdev_nr
(
mddev
,
rdev
->
desc_nr
))
return
-
EBUSY
;
}
list_add
(
&
rdev
->
same_set
,
&
mddev
->
disks
);
rdev
->
mddev
=
mddev
;
printk
(
KERN_INFO
"md: bind<%s>
\n
"
,
bdev_partition_name
(
rdev
->
bdev
));
return
0
;
}
static
void
unbind_rdev_from_array
(
mdk_rdev_t
*
rdev
)
...
...
@@ -910,6 +1132,7 @@ static void export_array(mddev_t *mddev)
if
(
!
list_empty
(
&
mddev
->
disks
))
MD_BUG
();
mddev
->
raid_disks
=
0
;
mddev
->
major_version
=
0
;
}
#undef BAD_CSUM
...
...
@@ -994,8 +1217,6 @@ void md_print_devices(void)
static
int
write_disk_sb
(
mdk_rdev_t
*
rdev
)
{
sector_t
sb_offset
;
sector_t
size
;
if
(
!
rdev
->
sb_loaded
)
{
MD_BUG
();
...
...
@@ -1006,35 +1227,12 @@ static int write_disk_sb(mdk_rdev_t * rdev)
return
1
;
}
sb_offset
=
calc_dev_sboffset
(
rdev
->
bdev
);
if
(
rdev
->
sb_offset
!=
sb_offset
)
{
printk
(
KERN_INFO
"%s's sb offset has changed from %llu to %llu, skipping
\n
"
,
bdev_partition_name
(
rdev
->
bdev
),
(
unsigned
long
long
)
rdev
->
sb_offset
,
(
unsigned
long
long
)
sb_offset
);
goto
skip
;
}
/*
* If the disk went offline meanwhile and it's just a spare, then
* its size has changed to zero silently, and the MD code does
* not yet know that it's faulty.
*/
size
=
calc_dev_size
(
rdev
->
bdev
,
rdev
->
mddev
);
if
(
size
!=
rdev
->
size
)
{
printk
(
KERN_INFO
"%s's size has changed from %llu to %llu since import, skipping
\n
"
,
bdev_partition_name
(
rdev
->
bdev
),
(
unsigned
long
long
)
rdev
->
size
,
(
unsigned
long
long
)
size
);
goto
skip
;
}
printk
(
KERN_INFO
"(write) %s's sb offset: %llu
\n
"
,
bdev_partition_name
(
rdev
->
bdev
),
(
unsigned
long
long
)
sb_offset
);
dprintk
(
KERN_INFO
"(write) %s's sb offset: %llu
\n
"
,
bdev_partition_name
(
rdev
->
bdev
),
(
unsigned
long
long
)
rdev
->
sb_offset
);
if
(
sync_page_io
(
rdev
->
bdev
,
rdev
->
sb_offset
<<
1
,
MD_SB_BYTES
,
rdev
->
sb_page
,
WRITE
))
return
0
;
if
(
!
sync_page_io
(
rdev
->
bdev
,
sb_offset
<<
1
,
MD_SB_BYTES
,
rdev
->
sb_page
,
WRITE
))
goto
fail
;
skip:
return
0
;
fail:
printk
(
"md: write_disk_sb failed for device %s
\n
"
,
bdev_partition_name
(
rdev
->
bdev
));
return
1
;
}
...
...
@@ -1045,7 +1243,8 @@ static void sync_sbs(mddev_t * mddev)
struct
list_head
*
tmp
;
ITERATE_RDEV
(
mddev
,
rdev
,
tmp
)
{
super_90_sync
(
mddev
,
rdev
);
super_types
[
mddev
->
major_version
].
sync_super
(
mddev
,
rdev
);
rdev
->
sb_loaded
=
1
;
}
}
...
...
@@ -1079,20 +1278,20 @@ static void md_update_sb(mddev_t * mddev)
if
(
!
mddev
->
persistent
)
return
;
printk
(
KERN_INFO
"md: updating md%d RAID superblock on device (in sync %d)
\n
"
,
d
printk
(
KERN_INFO
"md: updating md%d RAID superblock on device (in sync %d)
\n
"
,
mdidx
(
mddev
),
mddev
->
in_sync
);
err
=
0
;
ITERATE_RDEV
(
mddev
,
rdev
,
tmp
)
{
printk
(
KERN_INFO
"md: "
);
d
printk
(
KERN_INFO
"md: "
);
if
(
rdev
->
faulty
)
printk
(
"(skipping faulty "
);
d
printk
(
"(skipping faulty "
);
printk
(
"%s "
,
bdev_partition_name
(
rdev
->
bdev
));
d
printk
(
"%s "
,
bdev_partition_name
(
rdev
->
bdev
));
if
(
!
rdev
->
faulty
)
{
err
+=
write_disk_sb
(
rdev
);
}
else
printk
(
")
\n
"
);
d
printk
(
")
\n
"
);
if
(
!
err
&&
mddev
->
level
==
LEVEL_MULTIPATH
)
/* only need to write one superblock... */
break
;
...
...
@@ -1107,7 +1306,7 @@ static void md_update_sb(mddev_t * mddev)
}
/*
* Import a device. If '
on_disk'
, then sanity check the superblock
* Import a device. If '
super_format' >= 0
, then sanity check the superblock
*
* mark the device faulty if:
*
...
...
@@ -1116,7 +1315,7 @@ static void md_update_sb(mddev_t * mddev)
*
* a faulty rdev _never_ has rdev->sb set.
*/
static
mdk_rdev_t
*
md_import_device
(
dev_t
newdev
,
int
on_disk
)
static
mdk_rdev_t
*
md_import_device
(
dev_t
newdev
,
int
super_format
,
int
super_minor
)
{
int
err
;
mdk_rdev_t
*
rdev
;
...
...
@@ -1141,6 +1340,7 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int on_disk)
rdev
->
desc_nr
=
-
1
;
rdev
->
faulty
=
0
;
rdev
->
in_sync
=
0
;
rdev
->
data_offset
=
0
;
atomic_set
(
&
rdev
->
nr_pending
,
0
);
size
=
rdev
->
bdev
->
bd_inode
->
i_size
>>
BLOCK_SIZE_BITS
;
...
...
@@ -1152,8 +1352,9 @@ static mdk_rdev_t *md_import_device(dev_t newdev, int on_disk)
goto
abort_free
;
}
if
(
on_disk
)
{
err
=
super_90_load
(
rdev
,
NULL
);
if
(
super_format
>=
0
)
{
err
=
super_types
[
super_format
].
load_super
(
rdev
,
NULL
,
super_minor
);
if
(
err
==
-
EINVAL
)
{
printk
(
KERN_WARNING
"md: %s has invalid sb, not importing!
\n
"
,
bdev_partition_name
(
rdev
->
bdev
));
...
...
@@ -1206,7 +1407,8 @@ static int analyze_sbs(mddev_t * mddev)
freshest
=
NULL
;
ITERATE_RDEV
(
mddev
,
rdev
,
tmp
)
switch
(
super_90_load
(
rdev
,
freshest
))
{
switch
(
super_types
[
mddev
->
major_version
].
load_super
(
rdev
,
freshest
,
mddev
->
minor_version
))
{
case
1
:
freshest
=
rdev
;
break
;
...
...
@@ -1218,12 +1420,14 @@ static int analyze_sbs(mddev_t * mddev)
}
super_90_validate
(
mddev
,
freshest
);
super_types
[
mddev
->
major_version
].
validate_super
(
mddev
,
freshest
);
i
=
0
;
ITERATE_RDEV
(
mddev
,
rdev
,
tmp
)
{
if
(
rdev
!=
freshest
)
if
(
super_90_validate
(
mddev
,
rdev
))
{
if
(
super_types
[
mddev
->
major_version
].
validate_super
(
mddev
,
rdev
))
{
printk
(
KERN_WARNING
"md: kicking non-fresh %s from array!
\n
"
,
bdev_partition_name
(
rdev
->
bdev
));
kick_rdev_from_array
(
rdev
);
...
...
@@ -1278,11 +1482,6 @@ static int device_size_calculation(mddev_t * mddev)
ITERATE_RDEV
(
mddev
,
rdev
,
tmp
)
{
if
(
rdev
->
faulty
)
continue
;
if
(
rdev
->
size
)
{
MD_BUG
();
continue
;
}
rdev
->
size
=
calc_dev_size
(
rdev
->
bdev
,
mddev
);
if
(
rdev
->
size
<
mddev
->
chunk_size
/
1024
)
{
printk
(
KERN_WARNING
"md: Dev %s smaller than chunk_size: %lluk < %dk
\n
"
,
...
...
@@ -1380,6 +1579,16 @@ static struct gendisk *md_probe(dev_t dev, int *part, void *data)
return
NULL
;
}
void
md_wakeup_thread
(
mdk_thread_t
*
thread
);
static
void
md_safemode_timeout
(
unsigned
long
data
)
{
mddev_t
*
mddev
=
(
mddev_t
*
)
data
;
mddev
->
safemode
=
1
;
md_wakeup_thread
(
mddev
->
thread
);
}
#define TOO_BIG_CHUNKSIZE KERN_ERR \
"too big chunk_size: %d > %d\n"
...
...
@@ -1521,13 +1730,14 @@ static int do_md_run(mddev_t * mddev)
}
atomic_set
(
&
mddev
->
writes_pending
,
0
);
mddev
->
safemode
=
0
;
if
(
mddev
->
pers
->
sync_request
)
mddev
->
in_sync
=
0
;
else
mddev
->
in_sync
=
1
;
mddev
->
safemode_timer
.
function
=
md_safemode_timeout
;
mddev
->
safemode_timer
.
data
=
(
unsigned
long
)
mddev
;
mddev
->
safemode_delay
=
(
20
*
HZ
)
/
1000
+
1
;
/* 20 msec delay */
mddev
->
in_sync
=
1
;
md_update_sb
(
mddev
);
md_recover_arrays
();
set_bit
(
MD_RECOVERY_NEEDED
,
&
mddev
->
recovery
);
md_wakeup_thread
(
mddev
->
thread
);
set_capacity
(
disk
,
md_size
[
mdidx
(
mddev
)]
<<
1
);
return
(
0
);
}
...
...
@@ -1553,7 +1763,6 @@ static int restart_array(mddev_t *mddev)
goto
out
;
mddev
->
safemode
=
0
;
mddev
->
in_sync
=
0
;
md_update_sb
(
mddev
);
mddev
->
ro
=
0
;
set_disk_ro
(
disk
,
0
);
...
...
@@ -1563,7 +1772,8 @@ static int restart_array(mddev_t *mddev)
/*
* Kick recovery or resync if necessary
*/
md_recover_arrays
();
set_bit
(
MD_RECOVERY_NEEDED
,
&
mddev
->
recovery
);
md_wakeup_thread
(
mddev
->
thread
);
err
=
0
;
}
else
{
printk
(
KERN_ERR
"md: md%d has no personality assigned.
\n
"
,
...
...
@@ -1593,12 +1803,13 @@ static int do_md_stop(mddev_t * mddev, int ro)
if
(
mddev
->
pers
)
{
if
(
mddev
->
sync_thread
)
{
if
(
mddev
->
recovery_running
>
0
)
mddev
->
recovery_running
=
-
1
;
set_bit
(
MD_RECOVERY_INTR
,
&
mddev
->
recovery
);
md_unregister_thread
(
mddev
->
sync_thread
);
mddev
->
sync_thread
=
NULL
;
}
del_timer_sync
(
&
mddev
->
safemode_timer
);
invalidate_device
(
mk_kdev
(
disk
->
major
,
disk
->
first_minor
),
1
);
if
(
ro
)
{
...
...
@@ -1699,7 +1910,7 @@ static void autorun_devices(void)
printk
(
KERN_INFO
"md: considering %s ...
\n
"
,
bdev_partition_name
(
rdev0
->
bdev
));
INIT_LIST_HEAD
(
&
candidates
);
ITERATE_RDEV_PENDING
(
rdev
,
tmp
)
if
(
super_90_load
(
rdev
,
rdev0
)
>=
0
)
{
if
(
super_90_load
(
rdev
,
rdev0
,
0
)
>=
0
)
{
printk
(
KERN_INFO
"md: adding %s ...
\n
"
,
bdev_partition_name
(
rdev
->
bdev
));
list_move
(
&
rdev
->
same_set
,
&
candidates
);
}
...
...
@@ -1717,7 +1928,8 @@ static void autorun_devices(void)
if
(
mddev_lock
(
mddev
))
printk
(
KERN_WARNING
"md: md%d locked, cannot run
\n
"
,
mdidx
(
mddev
));
else
if
(
mddev
->
raid_disks
||
!
list_empty
(
&
mddev
->
disks
))
{
else
if
(
mddev
->
raid_disks
||
mddev
->
major_version
||
!
list_empty
(
&
mddev
->
disks
))
{
printk
(
KERN_WARNING
"md: md%d already running, cannot run %s
\n
"
,
mdidx
(
mddev
),
bdev_partition_name
(
rdev0
->
bdev
));
mddev_unlock
(
mddev
);
...
...
@@ -1725,7 +1937,8 @@ static void autorun_devices(void)
printk
(
KERN_INFO
"md: created md%d
\n
"
,
mdidx
(
mddev
));
ITERATE_RDEV_GENERIC
(
candidates
,
rdev
,
tmp
)
{
list_del_init
(
&
rdev
->
same_set
);
bind_rdev_to_array
(
rdev
,
mddev
);
if
(
bind_rdev_to_array
(
rdev
,
mddev
))
export_rdev
(
rdev
);
}
autorun_array
(
mddev
);
mddev_unlock
(
mddev
);
...
...
@@ -1778,7 +1991,7 @@ static int autostart_array(dev_t startdev)
mdp_super_t
*
sb
=
NULL
;
mdk_rdev_t
*
start_rdev
=
NULL
,
*
rdev
;
start_rdev
=
md_import_device
(
startdev
,
1
);
start_rdev
=
md_import_device
(
startdev
,
0
,
0
);
if
(
IS_ERR
(
start_rdev
))
{
printk
(
KERN_WARNING
"md: could not import %s!
\n
"
,
partition_name
(
startdev
));
return
err
;
...
...
@@ -1812,7 +2025,7 @@ static int autostart_array(dev_t startdev)
continue
;
if
(
dev
==
startdev
)
continue
;
rdev
=
md_import_device
(
dev
,
1
);
rdev
=
md_import_device
(
dev
,
0
,
0
);
if
(
IS_ERR
(
rdev
))
{
printk
(
KERN_WARNING
"md: could not import %s, trying to run array nevertheless.
\n
"
,
partition_name
(
dev
));
...
...
@@ -1874,10 +2087,9 @@ static int get_array_info(mddev_t * mddev, void * arg)
}
}
info
.
major_version
=
mddev
->
major_version
;
info
.
major_version
=
mddev
->
major_version
;
info
.
minor_version
=
mddev
->
minor_version
;
info
.
patch_version
=
mddev
->
patch_version
;
info
.
patch_version
=
1
;
info
.
ctime
=
mddev
->
ctime
;
info
.
level
=
mddev
->
level
;
info
.
size
=
mddev
->
size
;
...
...
@@ -1888,7 +2100,7 @@ static int get_array_info(mddev_t * mddev, void * arg)
info
.
utime
=
mddev
->
utime
;
info
.
state
=
0
;
if
(
mddev
->
recovery_cp
==
MaxSector
)
if
(
mddev
->
in_sync
)
info
.
state
=
(
1
<<
MD_SB_CLEAN
);
info
.
active_disks
=
active
;
info
.
working_disks
=
working
;
...
...
@@ -1943,13 +2155,13 @@ static int get_disk_info(mddev_t * mddev, void * arg)
static
int
add_new_disk
(
mddev_t
*
mddev
,
mdu_disk_info_t
*
info
)
{
sector_t
size
;
mdk_rdev_t
*
rdev
;
dev_t
dev
;
dev
=
MKDEV
(
info
->
major
,
info
->
minor
);
if
(
!
mddev
->
raid_disks
)
{
int
err
;
/* expecting a device which has a superblock */
rdev
=
md_import_device
(
dev
,
1
);
rdev
=
md_import_device
(
dev
,
mddev
->
major_version
,
mddev
->
minor_version
);
if
(
IS_ERR
(
rdev
))
{
printk
(
KERN_WARNING
"md: md_import_device returned %ld
\n
"
,
PTR_ERR
(
rdev
));
return
PTR_ERR
(
rdev
);
...
...
@@ -1957,7 +2169,8 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
if
(
!
list_empty
(
&
mddev
->
disks
))
{
mdk_rdev_t
*
rdev0
=
list_entry
(
mddev
->
disks
.
next
,
mdk_rdev_t
,
same_set
);
int
err
=
super_90_load
(
rdev
,
rdev0
);
int
err
=
super_types
[
mddev
->
major_version
]
.
load_super
(
rdev
,
rdev0
,
mddev
->
minor_version
);
if
(
err
<
0
)
{
printk
(
KERN_WARNING
"md: %s has different UUID to %s
\n
"
,
bdev_partition_name
(
rdev
->
bdev
),
bdev_partition_name
(
rdev0
->
bdev
));
...
...
@@ -1965,12 +2178,52 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
return
-
EINVAL
;
}
}
bind_rdev_to_array
(
rdev
,
mddev
);
return
0
;
err
=
bind_rdev_to_array
(
rdev
,
mddev
);
if
(
err
)
export_rdev
(
rdev
);
return
err
;
}
/*
* add_new_disk can be used once the array is assembled
* to add "hot spares". They must already have a superblock
* written
*/
if
(
mddev
->
pers
)
{
int
err
;
if
(
!
mddev
->
pers
->
hot_add_disk
)
{
printk
(
KERN_WARNING
"md%d: personality does not support diskops!
\n
"
,
mdidx
(
mddev
));
return
-
EINVAL
;
}
rdev
=
md_import_device
(
dev
,
mddev
->
major_version
,
mddev
->
minor_version
);
if
(
IS_ERR
(
rdev
))
{
printk
(
KERN_WARNING
"md: md_import_device returned %ld
\n
"
,
PTR_ERR
(
rdev
));
return
PTR_ERR
(
rdev
);
}
rdev
->
in_sync
=
0
;
/* just to be sure */
rdev
->
raid_disk
=
-
1
;
err
=
bind_rdev_to_array
(
rdev
,
mddev
);
if
(
err
)
export_rdev
(
rdev
);
if
(
mddev
->
thread
)
md_wakeup_thread
(
mddev
->
thread
);
return
err
;
}
/* otherwise, add_new_disk is only allowed
* for major_version==0 superblocks
*/
if
(
mddev
->
major_version
!=
0
)
{
printk
(
KERN_WARNING
"md%d: ADD_NEW_DISK not supported
\n
"
,
mdidx
(
mddev
));
return
-
EINVAL
;
}
if
(
!
(
info
->
state
&
(
1
<<
MD_DISK_FAULTY
)))
{
rdev
=
md_import_device
(
dev
,
0
);
int
err
;
rdev
=
md_import_device
(
dev
,
-
1
,
0
);
if
(
IS_ERR
(
rdev
))
{
printk
(
KERN_WARNING
"md: error, md_import_device() returned %ld
\n
"
,
PTR_ERR
(
rdev
));
return
PTR_ERR
(
rdev
);
...
...
@@ -1987,16 +2240,21 @@ static int add_new_disk(mddev_t * mddev, mdu_disk_info_t *info)
else
rdev
->
in_sync
=
0
;
bind_rdev_to_array
(
rdev
,
mddev
);
err
=
bind_rdev_to_array
(
rdev
,
mddev
);
if
(
err
)
{
export_rdev
(
rdev
);
return
err
;
}
if
(
!
mddev
->
persistent
)
if
(
!
mddev
->
persistent
)
{
printk
(
KERN_INFO
"md: nonpersistent superblock ...
\n
"
);
rdev
->
sb_offset
=
rdev
->
bdev
->
bd_inode
->
i_size
>>
BLOCK_SIZE_BITS
;
}
else
rdev
->
sb_offset
=
calc_dev_sboffset
(
rdev
->
bdev
);
rdev
->
size
=
calc_dev_size
(
rdev
,
mddev
->
chunk_size
);
size
=
calc_dev_size
(
rdev
->
bdev
,
mddev
);
rdev
->
sb_offset
=
calc_dev_sboffset
(
rdev
->
bdev
);
if
(
!
mddev
->
size
||
(
mddev
->
size
>
size
))
mddev
->
size
=
size
;
if
(
!
mddev
->
size
||
(
mddev
->
size
>
rdev
->
size
))
mddev
->
size
=
rdev
->
size
;
}
return
0
;
...
...
@@ -2066,7 +2324,7 @@ static int hot_remove_disk(mddev_t * mddev, dev_t dev)
static
int
hot_add_disk
(
mddev_t
*
mddev
,
dev_t
dev
)
{
int
i
,
err
;
int
err
;
unsigned
int
size
;
mdk_rdev_t
*
rdev
;
...
...
@@ -2076,19 +2334,26 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
printk
(
KERN_INFO
"md: trying to hot-add %s to md%d ...
\n
"
,
partition_name
(
dev
),
mdidx
(
mddev
));
if
(
mddev
->
major_version
!=
0
)
{
printk
(
KERN_WARNING
"md%d: HOT_ADD may only be used with version-0 superblocks.
\n
"
,
mdidx
(
mddev
));
return
-
EINVAL
;
}
if
(
!
mddev
->
pers
->
hot_add_disk
)
{
printk
(
KERN_WARNING
"md%d: personality does not support diskops!
\n
"
,
mdidx
(
mddev
));
return
-
EINVAL
;
}
rdev
=
md_import_device
(
dev
,
0
);
rdev
=
md_import_device
(
dev
,
-
1
,
0
);
if
(
IS_ERR
(
rdev
))
{
printk
(
KERN_WARNING
"md: error, md_import_device() returned %ld
\n
"
,
PTR_ERR
(
rdev
));
return
-
EINVAL
;
}
size
=
calc_dev_size
(
rdev
->
bdev
,
mddev
);
rdev
->
sb_offset
=
calc_dev_sboffset
(
rdev
->
bdev
);
size
=
calc_dev_size
(
rdev
,
mddev
->
chunk_size
);
rdev
->
size
=
size
;
if
(
size
<
mddev
->
size
)
{
printk
(
KERN_WARNING
"md%d: disk size %llu blocks < array size %llu
\n
"
,
...
...
@@ -2105,27 +2370,21 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
goto
abort_export
;
}
rdev
->
in_sync
=
0
;
rdev
->
desc_nr
=
-
1
;
bind_rdev_to_array
(
rdev
,
mddev
);
/*
* The rest should better be atomic, we can have disk failures
* noticed in interrupt contexts ...
*/
rdev
->
size
=
size
;
rdev
->
sb_offset
=
calc_dev_sboffset
(
rdev
->
bdev
);
for
(
i
=
mddev
->
raid_disks
;
i
<
mddev
->
max_disks
;
i
++
)
if
(
find_rdev_nr
(
mddev
,
i
)
==
NULL
)
break
;
if
(
i
==
mddev
->
max_disks
)
{
if
(
rdev
->
desc_nr
==
mddev
->
max_disks
)
{
printk
(
KERN_WARNING
"md%d: can not hot-add to full array!
\n
"
,
mdidx
(
mddev
));
err
=
-
EBUSY
;
goto
abort_unbind_export
;
}
rdev
->
desc_nr
=
i
;
rdev
->
raid_disk
=
-
1
;
md_update_sb
(
mddev
);
...
...
@@ -2134,7 +2393,8 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
* Kick recovery, maybe this spare has to be added to the
* array immediately.
*/
md_recover_arrays
();
set_bit
(
MD_RECOVERY_NEEDED
,
&
mddev
->
recovery
);
md_wakeup_thread
(
mddev
->
thread
);
return
0
;
...
...
@@ -2146,9 +2406,37 @@ static int hot_add_disk(mddev_t * mddev, dev_t dev)
return
err
;
}
/*
* set_array_info is used two different ways
* The original usage is when creating a new array.
* In this usage, raid_disks is > = and it together with
* level, size, not_persistent,layout,chunksize determine the
* shape of the array.
* This will always create an array with a type-0.90.0 superblock.
* The newer usage is when assembling an array.
* In this case raid_disks will be 0, and the major_version field is
* use to determine which style super-blocks are to be found on the devices.
* The minor and patch _version numbers are also kept incase the
* super_block handler wishes to interpret them.
*/
static
int
set_array_info
(
mddev_t
*
mddev
,
mdu_array_info_t
*
info
)
{
if
(
info
->
raid_disks
==
0
)
{
/* just setting version number for superblock loading */
if
(
info
->
major_version
<
0
||
info
->
major_version
>=
sizeof
(
super_types
)
/
sizeof
(
super_types
[
0
])
||
super_types
[
info
->
major_version
].
name
==
NULL
)
{
/* maybe try to auto-load a module? */
printk
(
KERN_INFO
"md: superblock version %d not known
\n
"
,
info
->
major_version
);
return
-
EINVAL
;
}
mddev
->
major_version
=
info
->
major_version
;
mddev
->
minor_version
=
info
->
minor_version
;
mddev
->
patch_version
=
info
->
patch_version
;
return
0
;
}
mddev
->
major_version
=
MD_MAJOR_VERSION
;
mddev
->
minor_version
=
MD_MINOR_VERSION
;
mddev
->
patch_version
=
MD_PATCHLEVEL_VERSION
;
...
...
@@ -2169,6 +2457,7 @@ static int set_array_info(mddev_t * mddev, mdu_array_info_t *info)
mddev
->
layout
=
info
->
layout
;
mddev
->
chunk_size
=
info
->
chunk_size
;
mddev
->
max_disks
=
MD_SB_DISKS
;
/*
...
...
@@ -2282,9 +2571,11 @@ static int md_ioctl(struct inode *inode, struct file *file,
err
=
-
EBUSY
;
goto
abort_unlock
;
}
if
(
arg
)
{
{
mdu_array_info_t
info
;
if
(
copy_from_user
(
&
info
,
(
void
*
)
arg
,
sizeof
(
info
)))
{
if
(
!
arg
)
memset
(
&
info
,
0
,
sizeof
(
info
));
else
if
(
copy_from_user
(
&
info
,
(
void
*
)
arg
,
sizeof
(
info
)))
{
err
=
-
EFAULT
;
goto
abort_unlock
;
}
...
...
@@ -2473,12 +2764,6 @@ static struct block_device_operations md_fops =
.
ioctl
=
md_ioctl
,
};
static
inline
void
flush_curr_signals
(
void
)
{
flush_signals
(
current
);
}
int
md_thread
(
void
*
arg
)
{
mdk_thread_t
*
thread
=
arg
;
...
...
@@ -2489,7 +2774,7 @@ int md_thread(void * arg)
* Detach thread
*/
daemonize
(
thread
->
name
);
daemonize
(
thread
->
name
,
mdidx
(
thread
->
mddev
)
);
current
->
exit_signal
=
SIGCHLD
;
allow_signal
(
SIGKILL
);
...
...
@@ -2510,7 +2795,7 @@ int md_thread(void * arg)
complete
(
thread
->
event
);
while
(
thread
->
run
)
{
void
(
*
run
)(
void
*
data
);
void
(
*
run
)(
mddev_t
*
);
wait_event_interruptible
(
thread
->
wqueue
,
test_bit
(
THREAD_WAKEUP
,
&
thread
->
flags
));
...
...
@@ -2521,11 +2806,11 @@ int md_thread(void * arg)
run
=
thread
->
run
;
if
(
run
)
{
run
(
thread
->
data
);
run
(
thread
->
mddev
);
blk_run_queues
();
}
if
(
signal_pending
(
current
))
flush_
curr_signals
(
);
flush_
signals
(
current
);
}
complete
(
thread
->
event
);
return
0
;
...
...
@@ -2538,8 +2823,8 @@ void md_wakeup_thread(mdk_thread_t *thread)
wake_up
(
&
thread
->
wqueue
);
}
mdk_thread_t
*
md_register_thread
(
void
(
*
run
)
(
void
*
)
,
void
*
data
,
const
char
*
name
)
mdk_thread_t
*
md_register_thread
(
void
(
*
run
)
(
mddev_t
*
),
mddev_t
*
mddev
,
const
char
*
name
)
{
mdk_thread_t
*
thread
;
int
ret
;
...
...
@@ -2556,7 +2841,7 @@ mdk_thread_t *md_register_thread(void (*run) (void *),
init_completion
(
&
event
);
thread
->
event
=
&
event
;
thread
->
run
=
run
;
thread
->
data
=
data
;
thread
->
mddev
=
mddev
;
thread
->
name
=
name
;
ret
=
kernel_thread
(
md_thread
,
thread
,
0
);
if
(
ret
<
0
)
{
...
...
@@ -2591,16 +2876,6 @@ void md_unregister_thread(mdk_thread_t *thread)
kfree
(
thread
);
}
static
void
md_recover_arrays
(
void
)
{
if
(
!
md_recovery_thread
)
{
MD_BUG
();
return
;
}
md_wakeup_thread
(
md_recovery_thread
);
}
void
md_error
(
mddev_t
*
mddev
,
mdk_rdev_t
*
rdev
)
{
dprintk
(
"md_error dev:(%d:%d), rdev:(%d:%d), (caller: %p,%p,%p,%p).
\n
"
,
...
...
@@ -2618,33 +2893,34 @@ void md_error(mddev_t *mddev, mdk_rdev_t *rdev)
if
(
!
mddev
->
pers
->
error_handler
)
return
;
mddev
->
pers
->
error_handler
(
mddev
,
rdev
);
md_recover_arrays
();
set_bit
(
MD_RECOVERY_NEEDED
,
&
mddev
->
recovery
);
md_wakeup_thread
(
mddev
->
thread
);
}
static
int
status_unused
(
char
*
page
)
/* seq_file implementation /proc/mdstat */
static
void
status_unused
(
struct
seq_file
*
seq
)
{
int
sz
=
0
,
i
=
0
;
int
i
=
0
;
mdk_rdev_t
*
rdev
;
struct
list_head
*
tmp
;
s
z
+=
sprintf
(
page
+
sz
,
"unused devices: "
);
s
eq_printf
(
seq
,
"unused devices: "
);
ITERATE_RDEV_PENDING
(
rdev
,
tmp
)
{
i
++
;
s
z
+=
sprintf
(
page
+
sz
,
"%s "
,
s
eq_printf
(
seq
,
"%s "
,
bdev_partition_name
(
rdev
->
bdev
));
}
if
(
!
i
)
s
z
+=
sprintf
(
page
+
sz
,
"<none>"
);
s
eq_printf
(
seq
,
"<none>"
);
sz
+=
sprintf
(
page
+
sz
,
"
\n
"
);
return
sz
;
seq_printf
(
seq
,
"
\n
"
);
}
static
int
status_resync
(
char
*
page
,
mddev_t
*
mddev
)
static
void
status_resync
(
struct
seq_file
*
seq
,
mddev_t
*
mddev
)
{
int
sz
=
0
;
unsigned
long
max_blocks
,
resync
,
res
,
dt
,
db
,
rt
;
resync
=
(
mddev
->
curr_resync
-
atomic_read
(
&
mddev
->
recovery_active
))
/
2
;
...
...
@@ -2655,21 +2931,22 @@ static int status_resync(char * page, mddev_t * mddev)
*/
if
(
!
max_blocks
)
{
MD_BUG
();
return
0
;
return
;
}
res
=
(
resync
/
1024
)
*
1000
/
(
max_blocks
/
1024
+
1
);
{
int
i
,
x
=
res
/
50
,
y
=
20
-
x
;
s
z
+=
sprintf
(
page
+
sz
,
"["
);
s
eq_printf
(
seq
,
"["
);
for
(
i
=
0
;
i
<
x
;
i
++
)
s
z
+=
sprintf
(
page
+
sz
,
"="
);
s
z
+=
sprintf
(
page
+
sz
,
">"
);
s
eq_printf
(
seq
,
"="
);
s
eq_printf
(
seq
,
">"
);
for
(
i
=
0
;
i
<
y
;
i
++
)
s
z
+=
sprintf
(
page
+
sz
,
"."
);
s
z
+=
sprintf
(
page
+
sz
,
"] "
);
s
eq_printf
(
seq
,
"."
);
s
eq_printf
(
seq
,
"] "
);
}
sz
+=
sprintf
(
page
+
sz
,
" %s =%3lu.%lu%% (%lu/%lu)"
,
(
mddev
->
spares
?
"recovery"
:
"resync"
),
seq_printf
(
seq
,
" %s =%3lu.%lu%% (%lu/%lu)"
,
(
test_bit
(
MD_RECOVERY_SYNC
,
&
mddev
->
recovery
)
?
"resync"
:
"recovery"
),
res
/
10
,
res
%
10
,
resync
,
max_blocks
);
/*
...
...
@@ -2686,44 +2963,110 @@ static int status_resync(char * page, mddev_t * mddev)
db
=
resync
-
(
mddev
->
resync_mark_cnt
/
2
);
rt
=
(
dt
*
((
max_blocks
-
resync
)
/
(
db
/
100
+
1
)))
/
100
;
s
z
+=
sprintf
(
page
+
sz
,
" finish=%lu.%lumin"
,
rt
/
60
,
(
rt
%
60
)
/
6
);
s
eq_printf
(
seq
,
" finish=%lu.%lumin"
,
rt
/
60
,
(
rt
%
60
)
/
6
);
sz
+=
sprintf
(
page
+
sz
,
" speed=%ldK/sec"
,
db
/
dt
);
seq_printf
(
seq
,
" speed=%ldK/sec"
,
db
/
dt
);
}
return
sz
;
static
void
*
md_seq_start
(
struct
seq_file
*
seq
,
loff_t
*
pos
)
{
struct
list_head
*
tmp
;
loff_t
l
=
*
pos
;
mddev_t
*
mddev
;
if
(
l
>
0x10000
)
return
NULL
;
if
(
!
l
--
)
/* header */
return
(
void
*
)
1
;
spin_lock
(
&
all_mddevs_lock
);
list_for_each
(
tmp
,
&
all_mddevs
)
if
(
!
l
--
)
{
mddev
=
list_entry
(
tmp
,
mddev_t
,
all_mddevs
);
mddev_get
(
mddev
);
spin_unlock
(
&
all_mddevs_lock
);
return
mddev
;
}
spin_unlock
(
&
all_mddevs_lock
);
return
(
void
*
)
2
;
/* tail */
}
static
void
*
md_seq_next
(
struct
seq_file
*
seq
,
void
*
v
,
loff_t
*
pos
)
{
struct
list_head
*
tmp
;
mddev_t
*
next_mddev
,
*
mddev
=
v
;
++*
pos
;
if
(
v
==
(
void
*
)
2
)
return
NULL
;
spin_lock
(
&
all_mddevs_lock
);
if
(
v
==
(
void
*
)
1
)
tmp
=
all_mddevs
.
next
;
else
tmp
=
mddev
->
all_mddevs
.
next
;
if
(
tmp
!=
&
all_mddevs
)
next_mddev
=
mddev_get
(
list_entry
(
tmp
,
mddev_t
,
all_mddevs
));
else
{
next_mddev
=
(
void
*
)
2
;
*
pos
=
0x10000
;
}
spin_unlock
(
&
all_mddevs_lock
);
if
(
v
!=
(
void
*
)
1
)
mddev_put
(
mddev
);
return
next_mddev
;
}
static
void
md_seq_stop
(
struct
seq_file
*
seq
,
void
*
v
)
{
mddev_t
*
mddev
=
v
;
if
(
mddev
&&
v
!=
(
void
*
)
1
&&
v
!=
(
void
*
)
2
)
mddev_put
(
mddev
);
}
static
int
md_status_read_proc
(
char
*
page
,
char
**
start
,
off_t
off
,
int
count
,
int
*
eof
,
void
*
data
)
static
int
md_seq_show
(
struct
seq_file
*
seq
,
void
*
v
)
{
int
sz
=
0
,
j
;
mddev_t
*
mddev
=
v
;
sector_t
size
;
struct
list_head
*
tmp
,
*
tmp
2
;
struct
list_head
*
tmp2
;
mdk_rdev_t
*
rdev
;
mddev_t
*
mddev
;
int
i
;
sz
+=
sprintf
(
page
+
sz
,
"Personalities : "
);
for
(
j
=
0
;
j
<
MAX_PERSONALITY
;
j
++
)
if
(
pers
[
j
])
sz
+=
sprintf
(
page
+
sz
,
"[%s] "
,
pers
[
j
]
->
name
);
if
(
v
==
(
void
*
)
1
)
{
seq_printf
(
seq
,
"Personalities : "
);
for
(
i
=
0
;
i
<
MAX_PERSONALITY
;
i
++
)
if
(
pers
[
i
])
seq_printf
(
seq
,
"[%s] "
,
pers
[
i
]
->
name
);
sz
+=
sprintf
(
page
+
sz
,
"
\n
"
);
seq_printf
(
seq
,
"
\n
"
);
return
0
;
}
if
(
v
==
(
void
*
)
2
)
{
status_unused
(
seq
);
return
0
;
}
ITERATE_MDDEV
(
mddev
,
tmp
)
if
(
mddev_lock
(
mddev
)
==
0
)
{
sz
+=
sprintf
(
page
+
sz
,
"md%d : %sactive"
,
mdidx
(
mddev
),
if
(
mddev_lock
(
mddev
)
!=
0
)
return
-
EINTR
;
if
(
mddev
->
pers
||
mddev
->
raid_disks
||
!
list_empty
(
&
mddev
->
disks
))
{
seq_printf
(
seq
,
"md%d : %sactive"
,
mdidx
(
mddev
),
mddev
->
pers
?
""
:
"in"
);
if
(
mddev
->
pers
)
{
if
(
mddev
->
ro
)
s
z
+=
sprintf
(
page
+
sz
,
" (read-only)"
);
s
z
+=
sprintf
(
page
+
sz
,
" %s"
,
mddev
->
pers
->
name
);
s
eq_printf
(
seq
,
" (read-only)"
);
s
eq_printf
(
seq
,
" %s"
,
mddev
->
pers
->
name
);
}
size
=
0
;
ITERATE_RDEV
(
mddev
,
rdev
,
tmp2
)
{
s
z
+=
sprintf
(
page
+
sz
,
" %s[%d]"
,
s
eq_printf
(
seq
,
" %s[%d]"
,
bdev_partition_name
(
rdev
->
bdev
),
rdev
->
desc_nr
);
if
(
rdev
->
faulty
)
{
s
z
+=
sprintf
(
page
+
sz
,
"(F)"
);
s
eq_printf
(
seq
,
"(F)"
);
continue
;
}
size
+=
rdev
->
size
;
...
...
@@ -2731,34 +3074,50 @@ static int md_status_read_proc(char *page, char **start, off_t off,
if
(
!
list_empty
(
&
mddev
->
disks
))
{
if
(
mddev
->
pers
)
s
z
+=
sprintf
(
page
+
sz
,
"
\n
%llu blocks"
,
s
eq_printf
(
seq
,
"
\n
%llu blocks"
,
(
unsigned
long
long
)
md_size
[
mdidx
(
mddev
)]);
else
s
z
+=
sprintf
(
page
+
sz
,
"
\n
%llu blocks"
,
(
unsigned
long
long
)
size
);
s
eq_printf
(
seq
,
"
\n
%llu blocks"
,
(
unsigned
long
long
)
size
);
}
if
(
!
mddev
->
pers
)
{
sz
+=
sprintf
(
page
+
sz
,
"
\n
"
);
mddev_unlock
(
mddev
);
continue
;
if
(
mddev
->
pers
)
{
mddev
->
pers
->
status
(
seq
,
mddev
);
seq_printf
(
seq
,
"
\n
"
);
if
(
mddev
->
curr_resync
>
2
)
status_resync
(
seq
,
mddev
);
else
if
(
mddev
->
curr_resync
==
1
||
mddev
->
curr_resync
==
2
)
seq_printf
(
seq
,
" resync=DELAYED"
);
}
sz
+=
mddev
->
pers
->
status
(
page
+
sz
,
mddev
);
seq_printf
(
seq
,
"
\n
"
);
}
mddev_unlock
(
mddev
);
return
0
;
}
sz
+=
sprintf
(
page
+
sz
,
"
\n
"
);
if
(
mddev
->
curr_resync
>
2
)
sz
+=
status_resync
(
page
+
sz
,
mddev
);
else
if
(
mddev
->
curr_resync
==
1
||
mddev
->
curr_resync
==
2
)
sz
+=
sprintf
(
page
+
sz
,
" resync=DELAYED"
);
static
struct
seq_operations
md_seq_ops
=
{
.
start
=
md_seq_start
,
.
next
=
md_seq_next
,
.
stop
=
md_seq_stop
,
.
show
=
md_seq_show
,
};
sz
+=
sprintf
(
page
+
sz
,
"
\n
"
);
mddev_unlock
(
mddev
);
}
sz
+=
status_unused
(
page
+
sz
);
static
int
md_seq_open
(
struct
inode
*
inode
,
struct
file
*
file
)
{
int
error
;
return
sz
;
error
=
seq_open
(
file
,
&
md_seq_ops
);
return
error
;
}
static
struct
file_operations
md_seq_fops
=
{
.
open
=
md_seq_open
,
.
read
=
seq_read
,
.
llseek
=
seq_lseek
,
.
release
=
seq_release
,
};
int
register_md_personality
(
int
pnum
,
mdk_personality_t
*
p
)
{
if
(
pnum
>=
MAX_PERSONALITY
)
{
...
...
@@ -2820,9 +3179,8 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok)
atomic_sub
(
blocks
,
&
mddev
->
recovery_active
);
wake_up
(
&
mddev
->
recovery_wait
);
if
(
!
ok
)
{
mddev
->
recovery_error
=
-
EIO
;
mddev
->
recovery_running
=
-
1
;
md_recover_arrays
();
set_bit
(
MD_RECOVERY_ERR
,
&
mddev
->
recovery
);
md_wakeup_thread
(
mddev
->
thread
);
// stop recovery, signal do_sync ....
}
}
...
...
@@ -2830,40 +3188,49 @@ void md_done_sync(mddev_t *mddev, int blocks, int ok)
void
md_write_start
(
mddev_t
*
mddev
)
{
if
(
mddev
->
safemode
&&
!
atomic_read
(
&
mddev
->
writes_pending
))
{
if
(
!
atomic_read
(
&
mddev
->
writes_pending
))
{
mddev_lock_uninterruptible
(
mddev
);
atomic_inc
(
&
mddev
->
writes_pending
);
if
(
mddev
->
in_sync
)
{
mddev
->
in_sync
=
0
;
del_timer
(
&
mddev
->
safemode_timer
);
md_update_sb
(
mddev
);
}
atomic_inc
(
&
mddev
->
writes_pending
);
mddev_unlock
(
mddev
);
}
else
atomic_inc
(
&
mddev
->
writes_pending
);
}
void
md_write_end
(
mddev_t
*
mddev
,
mdk_thread_t
*
thread
)
void
md_write_end
(
mddev_t
*
mddev
)
{
if
(
atomic_dec_and_test
(
&
mddev
->
writes_pending
)
&&
mddev
->
safemode
)
md_wakeup_thread
(
thread
);
if
(
atomic_dec_and_test
(
&
mddev
->
writes_pending
))
{
if
(
mddev
->
safemode
==
2
)
md_wakeup_thread
(
mddev
->
thread
);
else
mod_timer
(
&
mddev
->
safemode_timer
,
jiffies
+
mddev
->
safemode_delay
);
}
}
static
inline
void
md_enter_safemode
(
mddev_t
*
mddev
)
{
mddev_lock_uninterruptible
(
mddev
);
if
(
mddev
->
safemode
&&
!
atomic_read
(
&
mddev
->
writes_pending
)
&&
!
mddev
->
in_sync
&&
!
mddev
->
recovery_running
)
{
if
(
mddev
->
safemode
&&
!
atomic_read
(
&
mddev
->
writes_pending
)
&&
!
mddev
->
in_sync
&&
mddev
->
recovery_cp
==
MaxSector
)
{
mddev
->
in_sync
=
1
;
md_update_sb
(
mddev
);
}
mddev_unlock
(
mddev
);
if
(
mddev
->
safemode
==
1
)
mddev
->
safemode
=
0
;
}
void
md_handle_safemode
(
mddev_t
*
mddev
)
{
if
(
signal_pending
(
current
))
{
printk
(
KERN_INFO
"md: md%d in safe mode
\n
"
,
mdidx
(
mddev
));
mddev
->
safemode
=
1
;
flush_
curr_signals
(
);
printk
(
KERN_INFO
"md: md%d in
immediate
safe mode
\n
"
,
mdidx
(
mddev
));
mddev
->
safemode
=
2
;
flush_
signals
(
current
);
}
if
(
mddev
->
safemode
)
md_enter_safemode
(
mddev
);
...
...
@@ -2874,9 +3241,8 @@ DECLARE_WAIT_QUEUE_HEAD(resync_wait);
#define SYNC_MARKS 10
#define SYNC_MARK_STEP (3*HZ)
static
void
md_do_sync
(
void
*
data
)
static
void
md_do_sync
(
mddev_t
*
mddev
)
{
mddev_t
*
mddev
=
data
;
mddev_t
*
mddev2
;
unsigned
int
max_sectors
,
currspeed
=
0
,
j
,
window
,
err
;
...
...
@@ -2887,7 +3253,7 @@ static void md_do_sync(void *data)
unsigned
long
last_check
;
/* just incase thread restarts... */
if
(
mddev
->
recovery_running
<=
0
)
if
(
test_bit
(
MD_RECOVERY_DONE
,
&
mddev
->
recovery
)
)
return
;
/* we overload curr_resync somewhat here.
...
...
@@ -2914,14 +3280,16 @@ static void md_do_sync(void *data)
}
if
(
wait_event_interruptible
(
resync_wait
,
mddev2
->
curr_resync
<
mddev
->
curr_resync
))
{
flush_
curr_signals
(
);
flush_
signals
(
current
);
err
=
-
EINTR
;
mddev_put
(
mddev2
);
goto
skip
;
}
}
if
(
mddev
->
curr_resync
==
1
)
if
(
mddev
->
curr_resync
==
1
)
{
mddev_put
(
mddev2
);
break
;
}
}
}
while
(
mddev
->
curr_resync
<
2
);
...
...
@@ -2934,9 +3302,13 @@ static void md_do_sync(void *data)
sysctl_speed_limit_max
);
is_mddev_idle
(
mddev
);
/* this also initializes IO event counters */
if
(
test_bit
(
MD_RECOVERY_SYNC
,
&
mddev
->
recovery
))
j
=
mddev
->
recovery_cp
;
else
j
=
0
;
for
(
m
=
0
;
m
<
SYNC_MARKS
;
m
++
)
{
mark
[
m
]
=
jiffies
;
mark_cnt
[
m
]
=
mddev
->
recovery_cp
;
mark_cnt
[
m
]
=
j
;
}
last_mark
=
0
;
mddev
->
resync_mark
=
mark
[
last_mark
];
...
...
@@ -2953,12 +3325,10 @@ static void md_do_sync(void *data)
init_waitqueue_head
(
&
mddev
->
recovery_wait
);
last_check
=
0
;
mddev
->
recovery_error
=
0
;
if
(
mddev
->
recovery_cp
)
if
(
j
)
printk
(
KERN_INFO
"md: resuming recovery of md%d from checkpoint.
\n
"
,
mdidx
(
mddev
));
for
(
j
=
mddev
->
recovery_cp
;
j
<
max_sectors
;
)
{
while
(
j
<
max_sectors
)
{
int
sectors
;
sectors
=
mddev
->
pers
->
sync_request
(
mddev
,
j
,
currspeed
<
sysctl_speed_limit_min
);
...
...
@@ -2975,6 +3345,10 @@ static void md_do_sync(void *data)
last_check
=
j
;
if
(
test_bit
(
MD_RECOVERY_INTR
,
&
mddev
->
recovery
)
||
test_bit
(
MD_RECOVERY_ERR
,
&
mddev
->
recovery
))
break
;
blk_run_queues
();
repeat:
...
...
@@ -2995,7 +3369,7 @@ static void md_do_sync(void *data)
* got a signal, exit.
*/
printk
(
KERN_INFO
"md: md_do_sync() got signal ... exiting
\n
"
);
flush_
curr_signals
(
);
flush_
signals
(
current
);
err
=
-
EINTR
;
goto
out
;
}
...
...
@@ -3029,39 +3403,42 @@ static void md_do_sync(void *data)
out:
wait_event
(
mddev
->
recovery_wait
,
!
atomic_read
(
&
mddev
->
recovery_active
));
if
(
mddev
->
recovery_running
<
0
&&
!
mddev
->
recovery_error
&&
mddev
->
curr_resync
>
2
)
{
/* interrupted but no write errors */
printk
(
KERN_INFO
"md: checkpointing recovery of md%d.
\n
"
,
mdidx
(
mddev
));
mddev
->
recovery_cp
=
mddev
->
curr_resync
;
}
/* tell personality that we are finished */
mddev
->
pers
->
sync_request
(
mddev
,
max_sectors
,
1
);
skip:
mddev
->
curr_resync
=
0
;
if
(
err
)
mddev
->
recovery_running
=
-
1
;
if
(
mddev
->
recovery_running
>
0
)
mddev
->
recovery_running
=
0
;
if
(
mddev
->
recovery_running
==
0
)
mddev
->
recovery_cp
=
MaxSector
;
set_bit
(
MD_RECOVERY_ERR
,
&
mddev
->
recovery
);
if
(
!
test_bit
(
MD_RECOVERY_ERR
,
&
mddev
->
recovery
)
&&
mddev
->
curr_resync
>
2
&&
mddev
->
curr_resync
>
mddev
->
recovery_cp
)
{
if
(
test_bit
(
MD_RECOVERY_INTR
,
&
mddev
->
recovery
))
{
printk
(
KERN_INFO
"md: checkpointing recovery of md%d.
\n
"
,
mdidx
(
mddev
));
mddev
->
recovery_cp
=
mddev
->
curr_resync
;
}
else
mddev
->
recovery_cp
=
MaxSector
;
}
if
(
mddev
->
safemode
)
md_enter_safemode
(
mddev
);
md_recover_arrays
();
skip:
mddev
->
curr_resync
=
0
;
set_bit
(
MD_RECOVERY_DONE
,
&
mddev
->
recovery
);
md_wakeup_thread
(
mddev
->
thread
);
}
/*
* This is the kernel thread that watches all md arrays for re-sync and other
* action that might be needed.
* This routine is regularly called by all per-raid-array threads to
* deal with generic issues like resync and super-block update.
* Raid personalities that don't have a thread (linear/raid0) do not
* need this as they never do any recovery or update the superblock.
*
* It does not do any resync itself, but rather "forks" off other threads
* to do that as needed.
* When it is determined that resync is needed, we set
"->recovery_running" and
* create a thread at ->sync_thread.
* When the thread finishes it
clears recovery_running (or sets an error
)
* and wakeup up this thread which will reap the thread and finish up.
* When it is determined that resync is needed, we set
MD_RECOVERY_RUNNING in
*
"->recovery" and
create a thread at ->sync_thread.
* When the thread finishes it
sets MD_RECOVERY_DONE (and might set MD_RECOVERY_ERR
)
* and wakeup
s
up this thread which will reap the thread and finish up.
* This thread also removes any faulty devices (with nr_pending == 0).
*
* The overall approach is:
...
...
@@ -3072,41 +3449,47 @@ static void md_do_sync(void *data)
* 5/ If array is degraded, try to add spares devices
* 6/ If array has spares or is not in-sync, start a resync thread.
*/
void
md_
do_recovery
(
void
*
data
)
void
md_
check_recovery
(
mddev_t
*
mddev
)
{
mddev_t
*
mddev
;
mdk_rdev_t
*
rdev
;
struct
list_head
*
tmp
,
*
rtmp
;
struct
list_head
*
rtmp
;
dprintk
(
KERN_INFO
"md: recovery thread got woken up ...
\n
"
);
ITERATE_MDDEV
(
mddev
,
tmp
)
if
(
mddev_lock
(
mddev
)
==
0
)
{
if
(
!
mddev
->
raid_disks
||
!
mddev
->
pers
||
mddev
->
ro
)
goto
unlock
;
if
(
mddev
->
ro
)
return
;
if
(
!
(
mddev
->
sb_dirty
||
test_bit
(
MD_RECOVERY_NEEDED
,
&
mddev
->
recovery
)
||
test_bit
(
MD_RECOVERY_DONE
,
&
mddev
->
recovery
)
))
return
;
if
(
mddev_trylock
(
mddev
)
==
0
)
{
int
spares
=
0
;
if
(
mddev
->
sb_dirty
)
md_update_sb
(
mddev
);
if
(
mddev
->
recovery_running
>
0
)
if
(
test_bit
(
MD_RECOVERY_RUNNING
,
&
mddev
->
recovery
)
&&
!
test_bit
(
MD_RECOVERY_DONE
,
&
mddev
->
recovery
))
/* resync/recovery still happening */
goto
unlock
;
if
(
mddev
->
sync_thread
)
{
/* resync has finished, collect result */
md_unregister_thread
(
mddev
->
sync_thread
);
mddev
->
sync_thread
=
NULL
;
if
(
mddev
->
recovery_running
==
0
)
{
if
(
!
test_bit
(
MD_RECOVERY_ERR
,
&
mddev
->
recovery
)
)
{
/* success...*/
/* activate any spares */
mddev
->
pers
->
spare_active
(
mddev
);
mddev
->
spares
=
0
;
}
md_update_sb
(
mddev
);
mddev
->
recovery
_running
=
0
;
mddev
->
recovery
=
0
;
wake_up
(
&
resync_wait
);
goto
unlock
;
}
if
(
mddev
->
recovery
_running
)
{
if
(
mddev
->
recovery
)
{
/* that's odd.. */
mddev
->
recovery
_running
=
0
;
mddev
->
recovery
=
0
;
wake_up
(
&
resync_wait
);
}
...
...
@@ -3114,7 +3497,6 @@ void md_do_recovery(void *data)
* remove any failed drives, then
* add spares if possible
*/
mddev
->
spares
=
0
;
ITERATE_RDEV
(
mddev
,
rdev
,
rtmp
)
{
if
(
rdev
->
raid_disk
>=
0
&&
rdev
->
faulty
&&
...
...
@@ -3123,43 +3505,41 @@ void md_do_recovery(void *data)
rdev
->
raid_disk
=
-
1
;
}
if
(
!
rdev
->
faulty
&&
rdev
->
raid_disk
>=
0
&&
!
rdev
->
in_sync
)
mddev
->
spares
++
;
spares
++
;
}
if
(
mddev
->
degraded
)
{
ITERATE_RDEV
(
mddev
,
rdev
,
rtmp
)
if
(
rdev
->
raid_disk
<
0
&&
!
rdev
->
faulty
)
{
if
(
mddev
->
pers
->
hot_add_disk
(
mddev
,
rdev
))
{
mddev
->
spares
++
;
mddev
->
recovery_cp
=
0
;
}
if
(
mddev
->
pers
->
hot_add_disk
(
mddev
,
rdev
))
spares
++
;
else
break
;
}
}
if
(
!
mddev
->
spares
&&
(
mddev
->
recovery_cp
==
MaxSector
))
{
if
(
!
spares
&&
(
mddev
->
recovery_cp
==
MaxSector
))
{
/* nothing we can do ... */
goto
unlock
;
}
if
(
mddev
->
pers
->
sync_request
)
{
set_bit
(
MD_RECOVERY_RUNNING
,
&
mddev
->
recovery
);
if
(
!
spares
)
set_bit
(
MD_RECOVERY_SYNC
,
&
mddev
->
recovery
);
mddev
->
sync_thread
=
md_register_thread
(
md_do_sync
,
mddev
,
"md_resync"
);
"md
%d
_resync"
);
if
(
!
mddev
->
sync_thread
)
{
printk
(
KERN_ERR
"md%d: could not start resync thread...
\n
"
,
mdidx
(
mddev
));
/* leave the spares where they are, it shouldn't hurt */
mddev
->
recovery
_running
=
0
;
mddev
->
recovery
=
0
;
}
else
{
mddev
->
recovery_running
=
1
;
md_wakeup_thread
(
mddev
->
sync_thread
);
}
}
unlock:
mddev_unlock
(
mddev
);
}
dprintk
(
KERN_INFO
"md: recovery thread finished ...
\n
"
);
}
int
md_notify_reboot
(
struct
notifier_block
*
this
,
...
...
@@ -3194,6 +3574,7 @@ struct notifier_block md_notifier = {
static
void
md_geninit
(
void
)
{
struct
proc_dir_entry
*
p
;
int
i
;
for
(
i
=
0
;
i
<
MAX_MD_DEVS
;
i
++
)
{
...
...
@@ -3203,13 +3584,14 @@ static void md_geninit(void)
dprintk
(
"md: sizeof(mdp_super_t) = %d
\n
"
,
(
int
)
sizeof
(
mdp_super_t
));
#ifdef CONFIG_PROC_FS
create_proc_read_entry
(
"mdstat"
,
0
,
NULL
,
md_status_read_proc
,
NULL
);
p
=
create_proc_entry
(
"mdstat"
,
S_IRUGO
,
NULL
);
if
(
p
)
p
->
proc_fops
=
&
md_seq_fops
;
#endif
}
int
__init
md_init
(
void
)
{
static
char
*
name
=
"mdrecoveryd"
;
int
minor
;
printk
(
KERN_INFO
"md: md driver %d.%d.%d MAX_MD_DEVS=%d, MD_SB_DISKS=%d
\n
"
,
...
...
@@ -3229,11 +3611,6 @@ int __init md_init(void)
S_IFBLK
|
S_IRUSR
|
S_IWUSR
,
&
md_fops
,
NULL
);
}
md_recovery_thread
=
md_register_thread
(
md_do_recovery
,
NULL
,
name
);
if
(
!
md_recovery_thread
)
printk
(
KERN_ALERT
"md: bug: couldn't allocate md_recovery_thread
\n
"
);
register_reboot_notifier
(
&
md_notifier
);
raid_table_header
=
register_sysctl_table
(
raid_root_table
,
1
);
...
...
@@ -3268,7 +3645,7 @@ static void autostart_arrays(void)
for
(
i
=
0
;
i
<
dev_cnt
;
i
++
)
{
dev_t
dev
=
detected_devices
[
i
];
rdev
=
md_import_device
(
dev
,
1
);
rdev
=
md_import_device
(
dev
,
0
,
0
);
if
(
IS_ERR
(
rdev
))
{
printk
(
KERN_ALERT
"md: could not import %s!
\n
"
,
partition_name
(
dev
));
...
...
@@ -3291,7 +3668,6 @@ static __exit void md_exit(void)
{
int
i
;
blk_unregister_region
(
MKDEV
(
MAJOR_NR
,
0
),
MAX_MD_DEVS
);
md_unregister_thread
(
md_recovery_thread
);
for
(
i
=
0
;
i
<
MAX_MD_DEVS
;
i
++
)
devfs_remove
(
"md/%d"
,
i
);
devfs_remove
(
"md"
);
...
...
@@ -3331,4 +3707,5 @@ EXPORT_SYMBOL(md_unregister_thread);
EXPORT_SYMBOL
(
md_wakeup_thread
);
EXPORT_SYMBOL
(
md_print_devices
);
EXPORT_SYMBOL
(
md_interrupt_thread
);
EXPORT_SYMBOL
(
md_check_recovery
);
MODULE_LICENSE
(
"GPL"
);
drivers/md/multipath.c
View file @
2b3163d4
...
...
@@ -86,7 +86,6 @@ static void multipath_reschedule_retry (struct multipath_bh *mp_bh)
{
unsigned
long
flags
;
mddev_t
*
mddev
=
mp_bh
->
mddev
;
multipath_conf_t
*
conf
=
mddev_to_conf
(
mddev
);
spin_lock_irqsave
(
&
retry_list_lock
,
flags
);
if
(
multipath_retry_list
==
NULL
)
...
...
@@ -95,7 +94,7 @@ static void multipath_reschedule_retry (struct multipath_bh *mp_bh)
multipath_retry_tail
=
&
mp_bh
->
next_mp
;
mp_bh
->
next_mp
=
NULL
;
spin_unlock_irqrestore
(
&
retry_list_lock
,
flags
);
md_wakeup_thread
(
conf
->
thread
);
md_wakeup_thread
(
mddev
->
thread
);
}
...
...
@@ -185,19 +184,18 @@ static int multipath_make_request (request_queue_t *q, struct bio * bio)
return
0
;
}
static
int
multipath_status
(
char
*
page
,
mddev_t
*
mddev
)
static
void
multipath_status
(
struct
seq_file
*
seq
,
mddev_t
*
mddev
)
{
multipath_conf_t
*
conf
=
mddev_to_conf
(
mddev
);
int
sz
=
0
,
i
;
int
i
;
s
z
+=
sprintf
(
page
+
sz
,
" [%d/%d] ["
,
conf
->
raid_disks
,
s
eq_printf
(
seq
,
" [%d/%d] ["
,
conf
->
raid_disks
,
conf
->
working_disks
);
for
(
i
=
0
;
i
<
conf
->
raid_disks
;
i
++
)
s
z
+=
sprintf
(
page
+
sz
,
"%s"
,
s
eq_printf
(
seq
,
"%s"
,
conf
->
multipaths
[
i
].
rdev
&&
conf
->
multipaths
[
i
].
rdev
->
in_sync
?
"U"
:
"_"
);
sz
+=
sprintf
(
page
+
sz
,
"]"
);
return
sz
;
seq_printf
(
seq
,
"]"
);
}
#define LAST_DISK KERN_ALERT \
...
...
@@ -334,14 +332,14 @@ static int multipath_remove_disk(mddev_t *mddev, int number)
* 3. Performs writes following reads for array syncronising.
*/
static
void
multipathd
(
void
*
data
)
static
void
multipathd
(
mddev_t
*
mddev
)
{
struct
multipath_bh
*
mp_bh
;
struct
bio
*
bio
;
unsigned
long
flags
;
mddev_t
*
mddev
;
mdk_rdev_t
*
rdev
;
md_check_recovery
(
mddev
);
for
(;;)
{
spin_lock_irqsave
(
&
retry_list_lock
,
flags
);
mp_bh
=
multipath_retry_list
;
...
...
@@ -471,10 +469,10 @@ static int multipath_run (mddev_t *mddev)
}
{
const
char
*
name
=
"m
ultipathd
"
;
const
char
*
name
=
"m
d%d_multipath
"
;
conf
->
thread
=
md_register_thread
(
multipathd
,
conf
,
name
);
if
(
!
conf
->
thread
)
{
mddev
->
thread
=
md_register_thread
(
multipathd
,
mddev
,
name
);
if
(
!
mddev
->
thread
)
{
printk
(
THREAD_ERROR
,
mdidx
(
mddev
));
goto
out_free_conf
;
}
...
...
@@ -513,7 +511,7 @@ static int multipath_stop (mddev_t *mddev)
{
multipath_conf_t
*
conf
=
mddev_to_conf
(
mddev
);
md_unregister_thread
(
conf
->
thread
);
md_unregister_thread
(
mddev
->
thread
);
mempool_destroy
(
conf
->
pool
);
kfree
(
conf
);
mddev
->
private
=
NULL
;
...
...
drivers/md/raid0.c
View file @
2b3163d4
...
...
@@ -349,7 +349,7 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio)
* is the only IO operation happening on this bh.
*/
bio
->
bi_bdev
=
tmp_dev
->
bdev
;
bio
->
bi_sector
=
rsect
;
bio
->
bi_sector
=
rsect
+
tmp_dev
->
data_offset
;
/*
* Let the main block layer submit the IO and resolve recursion:
...
...
@@ -372,41 +372,40 @@ static int raid0_make_request (request_queue_t *q, struct bio *bio)
return
0
;
}
static
int
raid0_status
(
char
*
page
,
mddev_t
*
mddev
)
static
void
raid0_status
(
struct
seq_file
*
seq
,
mddev_t
*
mddev
)
{
int
sz
=
0
;
#undef MD_DEBUG
#ifdef MD_DEBUG
int
j
,
k
;
raid0_conf_t
*
conf
=
mddev_to_conf
(
mddev
);
s
z
+=
sprintf
(
page
+
sz
,
" "
);
s
eq_printf
(
seq
,
" "
);
for
(
j
=
0
;
j
<
conf
->
nr_zones
;
j
++
)
{
s
z
+=
sprintf
(
page
+
sz
,
"[z%d"
,
s
eq_printf
(
seq
,
"[z%d"
,
conf
->
hash_table
[
j
].
zone0
-
conf
->
strip_zone
);
if
(
conf
->
hash_table
[
j
].
zone1
)
s
z
+=
sprintf
(
page
+
sz
,
"/z%d] "
,
s
eq_printf
(
seq
,
"/z%d] "
,
conf
->
hash_table
[
j
].
zone1
-
conf
->
strip_zone
);
else
s
z
+=
sprintf
(
page
+
sz
,
"] "
);
s
eq_printf
(
seq
,
"] "
);
}
s
z
+=
sprintf
(
page
+
sz
,
"
\n
"
);
s
eq_printf
(
seq
,
"
\n
"
);
for
(
j
=
0
;
j
<
conf
->
nr_strip_zones
;
j
++
)
{
s
z
+=
sprintf
(
page
+
sz
,
" z%d=["
,
j
);
s
eq_printf
(
seq
,
" z%d=["
,
j
);
for
(
k
=
0
;
k
<
conf
->
strip_zone
[
j
].
nb_dev
;
k
++
)
s
z
+=
sprintf
(
page
+
sz
,
"%s/"
,
bdev_partition_name
(
s
eq_printf
(
seq
,
"%s/"
,
bdev_partition_name
(
conf
->
strip_zone
[
j
].
dev
[
k
]
->
bdev
));
sz
--
;
s
z
+=
sprintf
(
page
+
sz
,
"] zo=%d do=%d s=%d
\n
"
,
s
eq_printf
(
seq
,
"] zo=%d do=%d s=%d
\n
"
,
conf
->
strip_zone
[
j
].
zone_offset
,
conf
->
strip_zone
[
j
].
dev_offset
,
conf
->
strip_zone
[
j
].
size
);
}
#endif
s
z
+=
sprintf
(
page
+
sz
,
" %dk chunks"
,
mddev
->
chunk_size
/
1024
);
return
sz
;
s
eq_printf
(
seq
,
" %dk chunks"
,
mddev
->
chunk_size
/
1024
);
return
;
}
static
mdk_personality_t
raid0_personality
=
...
...
drivers/md/raid1.c
View file @
2b3163d4
...
...
@@ -225,13 +225,12 @@ static void reschedule_retry(r1bio_t *r1_bio)
{
unsigned
long
flags
;
mddev_t
*
mddev
=
r1_bio
->
mddev
;
conf_t
*
conf
=
mddev_to_conf
(
mddev
);
spin_lock_irqsave
(
&
retry_list_lock
,
flags
);
list_add
(
&
r1_bio
->
retry_list
,
&
retry_list_head
);
spin_unlock_irqrestore
(
&
retry_list_lock
,
flags
);
md_wakeup_thread
(
conf
->
thread
);
md_wakeup_thread
(
mddev
->
thread
);
}
/*
...
...
@@ -320,7 +319,7 @@ static int end_request(struct bio *bio, unsigned int bytes_done, int error)
* already.
*/
if
(
atomic_dec_and_test
(
&
r1_bio
->
remaining
))
{
md_write_end
(
r1_bio
->
mddev
,
conf
->
thread
);
md_write_end
(
r1_bio
->
mddev
);
raid_end_bio_io
(
r1_bio
,
uptodate
);
}
}
...
...
@@ -494,7 +493,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
BUG
();
r1_bio
->
read_bio
=
read_bio
;
read_bio
->
bi_sector
=
r1_bio
->
sector
;
read_bio
->
bi_sector
=
r1_bio
->
sector
+
mirror
->
rdev
->
data_offset
;
read_bio
->
bi_bdev
=
mirror
->
rdev
->
bdev
;
read_bio
->
bi_end_io
=
end_request
;
read_bio
->
bi_rw
=
r1_bio
->
cmd
;
...
...
@@ -529,7 +528,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
mbio
=
bio_clone
(
bio
,
GFP_NOIO
);
r1_bio
->
write_bios
[
i
]
=
mbio
;
mbio
->
bi_sector
=
r1_bio
->
sector
;
mbio
->
bi_sector
=
r1_bio
->
sector
+
conf
->
mirrors
[
i
].
rdev
->
data_offset
;
mbio
->
bi_bdev
=
conf
->
mirrors
[
i
].
rdev
->
bdev
;
mbio
->
bi_end_io
=
end_request
;
mbio
->
bi_rw
=
r1_bio
->
cmd
;
...
...
@@ -542,7 +541,7 @@ static int make_request(request_queue_t *q, struct bio * bio)
* If all mirrors are non-operational
* then return an IO error:
*/
md_write_end
(
mddev
,
conf
->
thread
);
md_write_end
(
mddev
);
raid_end_bio_io
(
r1_bio
,
0
);
return
0
;
}
...
...
@@ -571,19 +570,18 @@ static int make_request(request_queue_t *q, struct bio * bio)
return
0
;
}
static
int
status
(
char
*
page
,
mddev_t
*
mddev
)
static
void
status
(
struct
seq_file
*
seq
,
mddev_t
*
mddev
)
{
conf_t
*
conf
=
mddev_to_conf
(
mddev
);
int
sz
=
0
,
i
;
int
i
;
s
z
+=
sprintf
(
page
+
sz
,
" [%d/%d] ["
,
conf
->
raid_disks
,
s
eq_printf
(
seq
,
" [%d/%d] ["
,
conf
->
raid_disks
,
conf
->
working_disks
);
for
(
i
=
0
;
i
<
conf
->
raid_disks
;
i
++
)
s
z
+=
sprintf
(
page
+
sz
,
"%s"
,
s
eq_printf
(
seq
,
"%s"
,
conf
->
mirrors
[
i
].
rdev
&&
conf
->
mirrors
[
i
].
rdev
->
in_sync
?
"U"
:
"_"
);
sz
+=
sprintf
(
page
+
sz
,
"]"
);
return
sz
;
seq_printf
(
seq
,
"]"
);
}
#define LAST_DISK KERN_ALERT \
...
...
@@ -624,10 +622,9 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
mddev
->
degraded
++
;
conf
->
working_disks
--
;
/*
* if recovery
was running, stop it now
.
* if recovery
is running, make sure it aborts
.
*/
if
(
mddev
->
recovery_running
)
mddev
->
recovery_running
=
-
EIO
;
set_bit
(
MD_RECOVERY_ERR
,
&
mddev
->
recovery
);
}
rdev
->
in_sync
=
0
;
rdev
->
faulty
=
1
;
...
...
@@ -859,7 +856,7 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
mbio
=
bio_clone
(
bio
,
GFP_NOIO
);
r1_bio
->
write_bios
[
i
]
=
mbio
;
mbio
->
bi_bdev
=
conf
->
mirrors
[
i
].
rdev
->
bdev
;
mbio
->
bi_sector
=
r1_bio
->
sector
;
mbio
->
bi_sector
=
r1_bio
->
sector
|
conf
->
mirrors
[
i
].
rdev
->
data_offset
;
mbio
->
bi_end_io
=
end_sync_write
;
mbio
->
bi_rw
=
WRITE
;
mbio
->
bi_private
=
r1_bio
;
...
...
@@ -900,17 +897,17 @@ static void sync_request_write(mddev_t *mddev, r1bio_t *r1_bio)
* 3. Performs writes following reads for array syncronising.
*/
static
void
raid1d
(
void
*
data
)
static
void
raid1d
(
mddev_t
*
mddev
)
{
struct
list_head
*
head
=
&
retry_list_head
;
r1bio_t
*
r1_bio
;
struct
bio
*
bio
;
unsigned
long
flags
;
mddev_t
*
mddev
;
conf_t
*
conf
=
data
;
conf_t
*
conf
=
mddev_to_conf
(
mddev
);
mdk_rdev_t
*
rdev
;
md_handle_safemode
(
conf
->
mddev
);
md_check_recovery
(
mddev
);
md_handle_safemode
(
mddev
);
for
(;;)
{
spin_lock_irqsave
(
&
retry_list_lock
,
flags
);
...
...
@@ -937,7 +934,7 @@ static void raid1d(void *data)
printk
(
REDIRECT_SECTOR
,
bdev_partition_name
(
rdev
->
bdev
),
(
unsigned
long
long
)
r1_bio
->
sector
);
bio
->
bi_bdev
=
rdev
->
bdev
;
bio
->
bi_sector
=
r1_bio
->
sector
;
bio
->
bi_sector
=
r1_bio
->
sector
+
rdev
->
data_offset
;
bio
->
bi_rw
=
r1_bio
->
cmd
;
generic_make_request
(
bio
);
...
...
@@ -1048,7 +1045,7 @@ static int sync_request(mddev_t *mddev, sector_t sector_nr, int go_faster)
read_bio
=
bio_clone
(
r1_bio
->
master_bio
,
GFP_NOIO
);
read_bio
->
bi_sector
=
sector_nr
;
read_bio
->
bi_sector
=
sector_nr
+
mirror
->
rdev
->
data_offset
;
read_bio
->
bi_bdev
=
mirror
->
rdev
->
bdev
;
read_bio
->
bi_end_io
=
end_sync_read
;
read_bio
->
bi_rw
=
READ
;
...
...
@@ -1190,10 +1187,8 @@ static int run(mddev_t *mddev)
{
snprintf
(
conf
->
thread_name
,
MD_THREAD_NAME_MAX
,
"raid1d_md%d"
,
mdidx
(
mddev
));
conf
->
thread
=
md_register_thread
(
raid1d
,
conf
,
conf
->
thread_name
);
if
(
!
conf
->
thread
)
{
mddev
->
thread
=
md_register_thread
(
raid1d
,
mddev
,
"md%d_raid1"
);
if
(
!
mddev
->
thread
)
{
printk
(
THREAD_ERROR
,
mdidx
(
mddev
));
goto
out_free_conf
;
}
...
...
@@ -1219,7 +1214,8 @@ static int stop(mddev_t *mddev)
{
conf_t
*
conf
=
mddev_to_conf
(
mddev
);
md_unregister_thread
(
conf
->
thread
);
md_unregister_thread
(
mddev
->
thread
);
mddev
->
thread
=
NULL
;
if
(
conf
->
r1bio_pool
)
mempool_destroy
(
conf
->
r1bio_pool
);
kfree
(
conf
);
...
...
drivers/md/raid5.c
View file @
2b3163d4
...
...
@@ -71,12 +71,12 @@ static inline void __release_stripe(raid5_conf_t *conf, struct stripe_head *sh)
list_add_tail
(
&
sh
->
lru
,
&
conf
->
delayed_list
);
else
list_add_tail
(
&
sh
->
lru
,
&
conf
->
handle_list
);
md_wakeup_thread
(
conf
->
thread
);
md_wakeup_thread
(
conf
->
mddev
->
thread
);
}
else
{
if
(
test_and_clear_bit
(
STRIPE_PREREAD_ACTIVE
,
&
sh
->
state
))
{
atomic_dec
(
&
conf
->
preread_active_stripes
);
if
(
atomic_read
(
&
conf
->
preread_active_stripes
)
<
IO_THRESHOLD
)
md_wakeup_thread
(
conf
->
thread
);
md_wakeup_thread
(
conf
->
mddev
->
thread
);
}
list_add_tail
(
&
sh
->
lru
,
&
conf
->
inactive_list
);
atomic_dec
(
&
conf
->
active_stripes
);
...
...
@@ -463,10 +463,9 @@ static void error(mddev_t *mddev, mdk_rdev_t *rdev)
conf
->
failed_disks
++
;
rdev
->
in_sync
=
0
;
/*
* if recovery was running,
stop it now
.
* if recovery was running,
make sure it aborts
.
*/
if
(
mddev
->
recovery_running
)
mddev
->
recovery_running
=
-
EIO
;
set_bit
(
MD_RECOVERY_ERR
,
&
mddev
->
recovery
);
}
rdev
->
faulty
=
1
;
printk
(
KERN_ALERT
...
...
@@ -913,7 +912,7 @@ static void handle_stripe(struct stripe_head *sh)
struct
bio
*
nextbi
=
bi
->
bi_next
;
clear_bit
(
BIO_UPTODATE
,
&
bi
->
bi_flags
);
if
(
--
bi
->
bi_phys_segments
==
0
)
{
md_write_end
(
conf
->
mddev
,
conf
->
thread
);
md_write_end
(
conf
->
mddev
);
bi
->
bi_next
=
return_bi
;
return_bi
=
bi
;
}
...
...
@@ -970,7 +969,7 @@ static void handle_stripe(struct stripe_head *sh)
while
(
wbi
&&
wbi
->
bi_sector
<
dev
->
sector
+
STRIPE_SECTORS
)
{
wbi2
=
wbi
->
bi_next
;
if
(
--
wbi
->
bi_phys_segments
==
0
)
{
md_write_end
(
conf
->
mddev
,
conf
->
thread
);
md_write_end
(
conf
->
mddev
);
wbi
->
bi_next
=
return_bi
;
return_bi
=
wbi
;
}
...
...
@@ -1113,7 +1112,7 @@ static void handle_stripe(struct stripe_head *sh)
if
(
test_and_clear_bit
(
STRIPE_PREREAD_ACTIVE
,
&
sh
->
state
))
{
atomic_dec
(
&
conf
->
preread_active_stripes
);
if
(
atomic_read
(
&
conf
->
preread_active_stripes
)
<
IO_THRESHOLD
)
md_wakeup_thread
(
conf
->
thread
);
md_wakeup_thread
(
conf
->
mddev
->
thread
);
}
}
}
...
...
@@ -1207,7 +1206,7 @@ static void handle_stripe(struct stripe_head *sh)
bi
->
bi_bdev
=
rdev
->
bdev
;
PRINTK
(
"for %llu schedule op %ld on disc %d
\n
"
,
(
unsigned
long
long
)
sh
->
sector
,
bi
->
bi_rw
,
i
);
atomic_inc
(
&
sh
->
count
);
bi
->
bi_sector
=
sh
->
sector
;
bi
->
bi_sector
=
sh
->
sector
+
rdev
->
data_offset
;
bi
->
bi_flags
=
1
<<
BIO_UPTODATE
;
bi
->
bi_vcnt
=
1
;
bi
->
bi_idx
=
0
;
...
...
@@ -1251,7 +1250,7 @@ static void raid5_unplug_device(void *data)
if
(
blk_remove_plug
(
q
))
raid5_activate_delayed
(
conf
);
md_wakeup_thread
(
conf
->
thread
);
md_wakeup_thread
(
mddev
->
thread
);
spin_unlock_irqrestore
(
&
conf
->
device_lock
,
flags
);
}
...
...
@@ -1304,7 +1303,7 @@ static int make_request (request_queue_t *q, struct bio * bi)
int
bytes
=
bi
->
bi_size
;
if
(
bio_data_dir
(
bi
)
==
WRITE
)
md_write_end
(
mddev
,
conf
->
thread
);
md_write_end
(
mddev
);
bi
->
bi_size
=
0
;
bi
->
bi_end_io
(
bi
,
bytes
,
0
);
}
...
...
@@ -1356,16 +1355,17 @@ static int sync_request (mddev_t *mddev, sector_t sector_nr, int go_faster)
* During the scan, completed stripes are saved for us by the interrupt
* handler, so that they will not have to wait for our next wakeup.
*/
static
void
raid5d
(
void
*
data
)
static
void
raid5d
(
mddev_t
*
mddev
)
{
struct
stripe_head
*
sh
;
raid5_conf_t
*
conf
=
data
;
mddev_t
*
mddev
=
conf
->
mddev
;
raid5_conf_t
*
conf
=
mddev_to_conf
(
mddev
);
int
handled
;
PRINTK
(
"+++ raid5d active
\n
"
);
md_check_recovery
(
mddev
);
md_handle_safemode
(
mddev
);
handled
=
0
;
spin_lock_irq
(
&
conf
->
device_lock
);
while
(
1
)
{
...
...
@@ -1486,10 +1486,8 @@ static int run (mddev_t *mddev)
}
{
snprintf
(
conf
->
thread_name
,
MD_THREAD_NAME_MAX
,
"raid5d_md%d"
,
mdidx
(
mddev
));
conf
->
thread
=
md_register_thread
(
raid5d
,
conf
,
conf
->
thread_name
);
if
(
!
conf
->
thread
)
{
mddev
->
thread
=
md_register_thread
(
raid5d
,
mddev
,
"md%d_raid5"
);
if
(
!
mddev
->
thread
)
{
printk
(
KERN_ERR
"raid5: couldn't allocate thread for md%d
\n
"
,
mdidx
(
mddev
));
goto
abort
;
}
...
...
@@ -1500,7 +1498,7 @@ static int run (mddev_t *mddev)
if
(
grow_stripes
(
conf
,
conf
->
max_nr_stripes
))
{
printk
(
KERN_ERR
"raid5: couldn't allocate %dkB for buffers
\n
"
,
memory
);
shrink_stripes
(
conf
);
md_unregister_thread
(
conf
->
thread
);
md_unregister_thread
(
mddev
->
thread
);
goto
abort
;
}
else
printk
(
KERN_INFO
"raid5: allocated %dkB for md%d
\n
"
,
memory
,
mdidx
(
mddev
));
...
...
@@ -1536,7 +1534,8 @@ static int stop (mddev_t *mddev)
{
raid5_conf_t
*
conf
=
(
raid5_conf_t
*
)
mddev
->
private
;
md_unregister_thread
(
conf
->
thread
);
md_unregister_thread
(
mddev
->
thread
);
mddev
->
thread
=
NULL
;
shrink_stripes
(
conf
);
free_pages
((
unsigned
long
)
conf
->
stripe_hashtbl
,
HASH_PAGES_ORDER
);
kfree
(
conf
);
...
...
@@ -1574,29 +1573,26 @@ static void printall (raid5_conf_t *conf)
}
}
spin_unlock_irq
(
&
conf
->
device_lock
);
PRINTK
(
"--- raid5d inactive
\n
"
);
}
#endif
static
int
status
(
char
*
page
,
mddev_t
*
mddev
)
static
void
status
(
struct
seq_file
*
seq
,
mddev_t
*
mddev
)
{
raid5_conf_t
*
conf
=
(
raid5_conf_t
*
)
mddev
->
private
;
int
sz
=
0
,
i
;
int
i
;
s
z
+=
sprintf
(
page
+
sz
,
" level %d, %dk chunk, algorithm %d"
,
mddev
->
level
,
mddev
->
chunk_size
>>
10
,
mddev
->
layout
);
s
z
+=
sprintf
(
page
+
sz
,
" [%d/%d] ["
,
conf
->
raid_disks
,
conf
->
working_disks
);
s
eq_printf
(
seq
,
" level %d, %dk chunk, algorithm %d"
,
mddev
->
level
,
mddev
->
chunk_size
>>
10
,
mddev
->
layout
);
s
eq_printf
(
seq
,
" [%d/%d] ["
,
conf
->
raid_disks
,
conf
->
working_disks
);
for
(
i
=
0
;
i
<
conf
->
raid_disks
;
i
++
)
s
z
+=
sprintf
(
page
+
sz
,
"%s"
,
s
eq_printf
(
seq
,
"%s"
,
conf
->
disks
[
i
].
rdev
&&
conf
->
disks
[
i
].
rdev
->
in_sync
?
"U"
:
"_"
);
s
z
+=
sprintf
(
page
+
sz
,
"]"
);
s
eq_printf
(
seq
,
"]"
);
#if RAID5_DEBUG
#define D(x) \
s
z += sprintf (page+sz
, "<"#x":%d>", atomic_read(&conf->x))
s
eq_printf (seq
, "<"#x":%d>", atomic_read(&conf->x))
printall
(
conf
);
#endif
return
sz
;
}
static
void
print_raid5_conf
(
raid5_conf_t
*
conf
)
...
...
fs/lockd/svclock.c
View file @
2b3163d4
...
...
@@ -305,8 +305,6 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
(
long
long
)
lock
->
fl
.
fl_end
,
wait
);
/* Lock file against concurrent access */
down
(
&
file
->
f_sema
);
/* Get existing block (in case client is busy-waiting) */
block
=
nlmsvc_lookup_block
(
file
,
lock
,
0
);
...
...
@@ -314,6 +312,9 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
lock
->
fl
.
fl_flags
|=
FL_LOCKD
;
again:
/* Lock file against concurrent access */
down
(
&
file
->
f_sema
);
if
(
!
(
conflock
=
posix_test_lock
(
&
file
->
f_file
,
&
lock
->
fl
)))
{
error
=
posix_lock_file
(
&
file
->
f_file
,
&
lock
->
fl
);
...
...
@@ -346,7 +347,10 @@ nlmsvc_lock(struct svc_rqst *rqstp, struct nlm_file *file,
/* If we don't have a block, create and initialize it. Then
* retry because we may have slept in kmalloc. */
/* We have to release f_sema as nlmsvc_create_block may try to
* to claim it while doing host garbage collection */
if
(
block
==
NULL
)
{
up
(
&
file
->
f_sema
);
dprintk
(
"lockd: blocking on this lock (allocating).
\n
"
);
if
(
!
(
block
=
nlmsvc_create_block
(
rqstp
,
file
,
lock
,
cookie
)))
return
nlm_lck_denied_nolocks
;
...
...
fs/nfsd/export.c
View file @
2b3163d4
...
...
@@ -294,7 +294,9 @@ int svc_export_parse(struct cache_detail *cd, char *mesg, int mlen)
/* client */
len
=
qword_get
(
&
mesg
,
buf
,
PAGE_SIZE
);
if
(
len
<=
0
)
return
-
EINVAL
;
err
=
-
EINVAL
;
if
(
len
<=
0
)
goto
out
;
err
=
-
ENOENT
;
dom
=
auth_domain_find
(
buf
);
if
(
!
dom
)
...
...
@@ -473,8 +475,14 @@ exp_get_by_name(svc_client *clp, struct vfsmount *mnt, struct dentry *dentry,
exp
=
svc_export_lookup
(
&
key
,
0
);
if
(
exp
!=
NULL
)
if
(
cache_check
(
&
svc_export_cache
,
&
exp
->
h
,
reqp
))
switch
(
cache_check
(
&
svc_export_cache
,
&
exp
->
h
,
reqp
))
{
case
0
:
break
;
case
-
EAGAIN
:
exp
=
ERR_PTR
(
-
EAGAIN
);
break
;
default:
exp
=
NULL
;
}
return
exp
;
}
...
...
@@ -915,7 +923,8 @@ struct flags {
{
NFSEXP_UIDMAP
,
{
"uidmap"
,
""
}},
{
NFSEXP_KERBEROS
,
{
"kerberos"
,
""
}},
{
NFSEXP_SUNSECURE
,
{
"sunsecure"
,
""
}},
{
NFSEXP_CROSSMNT
,
{
"nohide"
,
""
}},
{
NFSEXP_NOHIDE
,
{
"nohide"
,
""
}},
{
NFSEXP_CROSSMNT
,
{
"crossmnt"
,
""
}},
{
NFSEXP_NOSUBTREECHECK
,
{
"no_subtree_check"
,
""
}},
{
NFSEXP_NOAUTHNLM
,
{
"insecure_locks"
,
""
}},
#ifdef MSNFS
...
...
fs/nfsd/vfs.c
View file @
2b3163d4
...
...
@@ -79,7 +79,7 @@ static struct raparms * raparm_cache;
* N.B. After this call _both_ fhp and resfh need an fh_put
*
* If the lookup would cross a mountpoint, and the mounted filesystem
* is exported to the client with NFSEXP_
CROSSMNT
, then the lookup is
* is exported to the client with NFSEXP_
NOHIDE
, then the lookup is
* accepted as it stands and the mounted directory is
* returned. Otherwise the covered directory is returned.
* NOTE: this mountpoint crossing is not supported properly by all
...
...
@@ -115,7 +115,7 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
read_lock
(
&
dparent_lock
);
dentry
=
dget
(
dparent
->
d_parent
);
read_unlock
(
&
dparent_lock
);
}
else
if
(
!
EX_
CROSSMNT
(
exp
))
}
else
if
(
!
EX_
NOHIDE
(
exp
))
dentry
=
dget
(
dparent
);
/* .. == . just like at / */
else
{
/* checking mountpoint crossing is very different when stepping up */
...
...
@@ -133,6 +133,12 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
exp2
=
exp_parent
(
exp
->
ex_client
,
mnt
,
dentry
,
&
rqstp
->
rq_chandle
);
if
(
IS_ERR
(
exp2
))
{
err
=
PTR_ERR
(
exp2
);
dput
(
dentry
);
mntput
(
mnt
);
goto
out
;
}
if
(
!
exp2
)
{
dput
(
dentry
);
dentry
=
dget
(
dparent
);
...
...
@@ -157,9 +163,19 @@ nfsd_lookup(struct svc_rqst *rqstp, struct svc_fh *fhp, const char *name,
struct
dentry
*
mounts
=
dget
(
dentry
);
while
(
follow_down
(
&
mnt
,
&
mounts
)
&&
d_mountpoint
(
mounts
))
;
exp2
=
exp_get_by_name
(
exp
->
ex_client
,
mnt
,
mounts
,
&
rqstp
->
rq_chandle
);
if
(
exp2
&&
EX_CROSSMNT
(
exp2
))
{
if
(
IS_ERR
(
exp2
))
{
err
=
PTR_ERR
(
exp2
);
dput
(
mounts
);
dput
(
dentry
);
mntput
(
mnt
);
goto
out
;
}
if
(
exp2
&&
((
exp
->
ex_flags
&
NFSEXP_CROSSMNT
)
||
EX_NOHIDE
(
exp2
)))
{
/* successfully crossed mount point */
exp_put
(
exp
);
exp
=
exp2
;
...
...
fs/reiserfs/journal.c
View file @
2b3163d4
...
...
@@ -1310,6 +1310,10 @@ static void free_journal_ram(struct super_block *p_s_sb) {
if
(
SB_JOURNAL
(
p_s_sb
)
->
j_header_bh
)
{
brelse
(
SB_JOURNAL
(
p_s_sb
)
->
j_header_bh
)
;
}
/* j_header_bh is on the journal dev, make sure not to release the journal
* dev until we brelse j_header_bh
*/
release_journal_dev
(
p_s_sb
,
SB_JOURNAL
(
p_s_sb
));
vfree
(
SB_JOURNAL
(
p_s_sb
))
;
}
...
...
@@ -1341,7 +1345,6 @@ static int do_journal_release(struct reiserfs_transaction_handle *th, struct sup
commit_wq
=
NULL
;
}
release_journal_dev
(
p_s_sb
,
SB_JOURNAL
(
p_s_sb
)
);
free_journal_ram
(
p_s_sb
)
;
return
0
;
...
...
@@ -1867,24 +1870,18 @@ static int release_journal_dev( struct super_block *super,
int
result
;
result
=
0
;
if
(
journal
->
j_dev_file
!=
NULL
)
{
/*
* journal block device was taken via filp_open
*/
result
=
filp_close
(
journal
->
j_dev_file
,
NULL
);
journal
->
j_dev_file
=
NULL
;
journal
->
j_dev_bd
=
NULL
;
}
else
if
(
journal
->
j_dev_bd
!=
NULL
)
{
/*
* journal block device was taken via bdget and blkdev_get
*/
result
=
blkdev_put
(
journal
->
j_dev_bd
,
BDEV_FS
);
journal
->
j_dev_bd
=
NULL
;
}
if
(
result
!=
0
)
{
reiserfs_warning
(
"sh-457: release_journal_dev: Cannot release journal device: %i"
,
result
);
reiserfs_warning
(
"sh-457: release_journal_dev: Cannot release journal device: %i
\n
"
,
result
);
}
return
result
;
}
...
...
@@ -1895,6 +1892,7 @@ static int journal_init_dev( struct super_block *super,
{
int
result
;
dev_t
jdev
;
int
blkdev_mode
=
FMODE_READ
|
FMODE_WRITE
;
result
=
0
;
...
...
@@ -1902,12 +1900,16 @@ static int journal_init_dev( struct super_block *super,
journal
->
j_dev_file
=
NULL
;
jdev
=
SB_ONDISK_JOURNAL_DEVICE
(
super
)
?
SB_ONDISK_JOURNAL_DEVICE
(
super
)
:
super
->
s_dev
;
if
(
bdev_read_only
(
super
->
s_bdev
))
blkdev_mode
=
FMODE_READ
;
/* there is no "jdev" option and journal is on separate device */
if
(
(
!
jdev_name
||
!
jdev_name
[
0
]
)
)
{
journal
->
j_dev_bd
=
bdget
(
jdev
);
if
(
journal
->
j_dev_bd
)
result
=
blkdev_get
(
journal
->
j_dev_bd
,
FMODE_READ
|
FMODE_WRITE
,
0
,
blkdev_mode
,
0
,
BDEV_FS
);
else
result
=
-
ENOMEM
;
...
...
@@ -1928,10 +1930,10 @@ static int journal_init_dev( struct super_block *super,
jdev_inode
=
journal
->
j_dev_file
->
f_dentry
->
d_inode
;
journal
->
j_dev_bd
=
jdev_inode
->
i_bdev
;
if
(
!
S_ISBLK
(
jdev_inode
->
i_mode
)
)
{
printk
(
"journal_init_dev: '%s' is not a block device"
,
jdev_name
);
printk
(
"journal_init_dev: '%s' is not a block device
\n
"
,
jdev_name
);
result
=
-
ENOTBLK
;
}
else
if
(
jdev_inode
->
i_bdev
==
NULL
)
{
printk
(
"journal_init_dev: bdev uninitialized for '%s'"
,
jdev_name
);
printk
(
"journal_init_dev: bdev uninitialized for '%s'
\n
"
,
jdev_name
);
result
=
-
ENOMEM
;
}
else
{
/* ok */
...
...
@@ -1941,12 +1943,12 @@ static int journal_init_dev( struct super_block *super,
}
else
{
result
=
PTR_ERR
(
journal
->
j_dev_file
);
journal
->
j_dev_file
=
NULL
;
printk
(
"journal_init_dev: Cannot open '%s': %i"
,
jdev_name
,
result
);
printk
(
"journal_init_dev: Cannot open '%s': %i
\n
"
,
jdev_name
,
result
);
}
if
(
result
!=
0
)
{
release_journal_dev
(
super
,
journal
);
}
printk
(
"journal_init_dev: journal device: %s"
,
bdevname
(
journal
->
j_dev_bd
));
printk
(
"journal_init_dev: journal device: %s
\n
"
,
bdevname
(
journal
->
j_dev_bd
));
return
result
;
}
...
...
@@ -1960,20 +1962,24 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
struct
reiserfs_journal_header
*
jh
;
struct
reiserfs_journal
*
journal
;
if
(
sizeof
(
struct
reiserfs_journal_commit
)
!=
4096
||
sizeof
(
struct
reiserfs_journal_desc
)
!=
4096
)
{
printk
(
"journal-1249: commit or desc struct not 4096 %Zd %Zd
\n
"
,
sizeof
(
struct
reiserfs_journal_commit
),
if
(
sizeof
(
struct
reiserfs_journal_commit
)
!=
4096
||
sizeof
(
struct
reiserfs_journal_desc
)
!=
4096
)
{
printk
(
"journal-1249: commit or desc struct not 4096 %Zd %Zd
\n
"
,
sizeof
(
struct
reiserfs_journal_commit
),
sizeof
(
struct
reiserfs_journal_desc
))
;
return
1
;
}
return
1
;
}
journal
=
SB_JOURNAL
(
p_s_sb
)
=
vmalloc
(
sizeof
(
struct
reiserfs_journal
))
;
if
(
!
journal
)
{
printk
(
"journal-1256: unable to get memory for journal structure
\n
"
)
;
return
1
;
}
return
1
;
}
memset
(
journal
,
0
,
sizeof
(
struct
reiserfs_journal
))
;
INIT_LIST_HEAD
(
&
SB_JOURNAL
(
p_s_sb
)
->
j_bitmap_nodes
)
;
INIT_LIST_HEAD
(
&
SB_JOURNAL
(
p_s_sb
)
->
j_prealloc_list
);
reiserfs_allocate_list_bitmaps
(
p_s_sb
,
SB_JOURNAL
(
p_s_sb
)
->
j_list_bitmap
,
SB_BMAP_NR
(
p_s_sb
))
;
allocate_bitmap_nodes
(
p_s_sb
)
;
/* reserved for journal area support */
SB_JOURNAL_1st_RESERVED_BLOCK
(
p_s_sb
)
=
(
old_format
?
...
...
@@ -1983,7 +1989,7 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
if
(
journal_init_dev
(
p_s_sb
,
journal
,
j_dev_name
)
!=
0
)
{
printk
(
"sh-462: unable to initialize jornal device
\n
"
);
return
1
;
goto
free_and_return
;
}
rs
=
SB_DISK_SUPER_BLOCK
(
p_s_sb
);
...
...
@@ -1993,8 +1999,7 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
SB_ONDISK_JOURNAL_1st_BLOCK
(
p_s_sb
)
+
SB_ONDISK_JOURNAL_SIZE
(
p_s_sb
));
if
(
!
bhjh
)
{
printk
(
"sh-459: unable to read journal header
\n
"
)
;
release_journal_dev
(
p_s_sb
,
journal
);
return
1
;
goto
free_and_return
;
}
jh
=
(
struct
reiserfs_journal_header
*
)(
bhjh
->
b_data
);
...
...
@@ -2005,8 +2010,7 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
jh
->
jh_journal
.
jp_journal_magic
,
bdevname
(
SB_JOURNAL
(
p_s_sb
)
->
j_dev_bd
),
sb_jp_journal_magic
(
rs
),
reiserfs_bdevname
(
p_s_sb
));
brelse
(
bhjh
);
release_journal_dev
(
p_s_sb
,
journal
);
return
1
;
goto
free_and_return
;
}
SB_JOURNAL_TRANS_MAX
(
p_s_sb
)
=
le32_to_cpu
(
jh
->
jh_journal
.
jp_journal_trans_max
);
...
...
@@ -2064,7 +2068,6 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
brelse
(
bhjh
);
SB_JOURNAL
(
p_s_sb
)
->
j_list_bitmap_index
=
0
;
SB_JOURNAL_LIST_INDEX
(
p_s_sb
)
=
-
10000
;
/* make sure flush_old_commits does not try to flush a list while replay is on */
...
...
@@ -2075,12 +2078,8 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
memset
(
SB_JOURNAL
(
p_s_sb
)
->
j_list_hash_table
,
0
,
JOURNAL_HASH_SIZE
*
sizeof
(
struct
reiserfs_journal_cnode
*
))
;
memset
(
journal_writers
,
0
,
sizeof
(
char
*
)
*
512
)
;
/* debug code */
INIT_LIST_HEAD
(
&
SB_JOURNAL
(
p_s_sb
)
->
j_bitmap_nodes
)
;
INIT_LIST_HEAD
(
&
SB_JOURNAL
(
p_s_sb
)
->
j_dirty_buffers
)
;
spin_lock_init
(
&
SB_JOURNAL
(
p_s_sb
)
->
j_dirty_buffers_lock
)
;
reiserfs_allocate_list_bitmaps
(
p_s_sb
,
SB_JOURNAL
(
p_s_sb
)
->
j_list_bitmap
,
SB_BMAP_NR
(
p_s_sb
))
;
allocate_bitmap_nodes
(
p_s_sb
)
;
SB_JOURNAL
(
p_s_sb
)
->
j_start
=
0
;
SB_JOURNAL
(
p_s_sb
)
->
j_len
=
0
;
...
...
@@ -2107,20 +2106,15 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
SB_JOURNAL_LIST
(
p_s_sb
)[
0
].
j_list_bitmap
=
get_list_bitmap
(
p_s_sb
,
SB_JOURNAL_LIST
(
p_s_sb
))
;
if
(
!
(
SB_JOURNAL_LIST
(
p_s_sb
)[
0
].
j_list_bitmap
))
{
reiserfs_warning
(
"journal-2005, get_list_bitmap failed for journal list 0
\n
"
)
;
release_journal_dev
(
p_s_sb
,
journal
);
return
1
;
goto
free_and_return
;
}
if
(
journal_read
(
p_s_sb
)
<
0
)
{
reiserfs_warning
(
"Replay Failure, unable to mount
\n
"
)
;
free_journal_ram
(
p_s_sb
)
;
release_journal_dev
(
p_s_sb
,
journal
);
return
1
;
goto
free_and_return
;
}
SB_JOURNAL_LIST_INDEX
(
p_s_sb
)
=
0
;
/* once the read is done, we can set this
where it belongs */
INIT_LIST_HEAD
(
&
SB_JOURNAL
(
p_s_sb
)
->
j_prealloc_list
);
if
(
reiserfs_dont_log
(
p_s_sb
))
return
0
;
...
...
@@ -2129,7 +2123,9 @@ int journal_init(struct super_block *p_s_sb, const char * j_dev_name, int old_fo
commit_wq
=
create_workqueue
(
"reiserfs"
);
return
0
;
free_and_return:
free_journal_ram
(
p_s_sb
);
return
1
;
}
/*
...
...
include/asm-generic/xor.h
View file @
2b3163d4
...
...
@@ -678,35 +678,35 @@ xor_32regs_p_5(unsigned long bytes, unsigned long *p1, unsigned long *p2,
}
static
struct
xor_block_template
xor_block_8regs
=
{
name:
"8regs"
,
do_2:
xor_8regs_2
,
do_3:
xor_8regs_3
,
do_4:
xor_8regs_4
,
do_5:
xor_8regs_5
,
.
name
=
"8regs"
,
.
do_2
=
xor_8regs_2
,
.
do_3
=
xor_8regs_3
,
.
do_4
=
xor_8regs_4
,
.
do_5
=
xor_8regs_5
,
};
static
struct
xor_block_template
xor_block_32regs
=
{
name:
"32regs"
,
do_2:
xor_32regs_2
,
do_3:
xor_32regs_3
,
do_4:
xor_32regs_4
,
do_5:
xor_32regs_5
,
.
name
=
"32regs"
,
.
do_2
=
xor_32regs_2
,
.
do_3
=
xor_32regs_3
,
.
do_4
=
xor_32regs_4
,
.
do_5
=
xor_32regs_5
,
};
static
struct
xor_block_template
xor_block_8regs_p
=
{
name:
"8regs_prefetch"
,
do_2:
xor_8regs_p_2
,
do_3:
xor_8regs_p_3
,
do_4:
xor_8regs_p_4
,
do_5:
xor_8regs_p_5
,
.
name
=
"8regs_prefetch"
,
.
do_2
=
xor_8regs_p_2
,
.
do_3
=
xor_8regs_p_3
,
.
do_4
=
xor_8regs_p_4
,
.
do_5
=
xor_8regs_p_5
,
};
static
struct
xor_block_template
xor_block_32regs_p
=
{
name:
"32regs_prefetch"
,
do_2:
xor_32regs_p_2
,
do_3:
xor_32regs_p_3
,
do_4:
xor_32regs_p_4
,
do_5:
xor_32regs_p_5
,
.
name
=
"32regs_prefetch"
,
.
do_2
=
xor_32regs_p_2
,
.
do_3
=
xor_32regs_p_3
,
.
do_4
=
xor_32regs_p_4
,
.
do_5
=
xor_32regs_p_5
,
};
#define XOR_TRY_TEMPLATES \
...
...
include/asm-i386/cpufeature.h
View file @
2b3163d4
...
...
@@ -9,9 +9,9 @@
#include <linux/bitops.h>
#define NCAPINTS
4
/* Currently we have 4
32-bit words worth of info */
#define NCAPINTS
6
/* Currently we have 6
32-bit words worth of info */
/* Intel-defined CPU features, CPUID level 0x00000001, word 0 */
/* Intel-defined CPU features, CPUID level 0x00000001
(edx)
, word 0 */
#define X86_FEATURE_FPU (0*32+ 0)
/* Onboard FPU */
#define X86_FEATURE_VME (0*32+ 1)
/* Virtual Mode Extensions */
#define X86_FEATURE_DE (0*32+ 2)
/* Debugging Extensions */
...
...
@@ -64,6 +64,11 @@
#define X86_FEATURE_CYRIX_ARR (3*32+ 2)
/* Cyrix ARRs (= MTRRs) */
#define X86_FEATURE_CENTAUR_MCR (3*32+ 3)
/* Centaur MCRs (= MTRRs) */
/* Intel-defined CPU features, CPUID level 0x00000001 (ecx), word 4 */
/* VIA/Cyrix/Centaur-defined CPU features, CPUID level 0xC0000001, word 5 */
#define X86_FEATURE_XSTORE (5*32+ 2)
/* on-CPU RNG present (xstore insn) */
#define cpu_has(c, bit) test_bit(bit, (c)->x86_capability)
#define boot_cpu_has(bit) test_bit(bit, boot_cpu_data.x86_capability)
...
...
@@ -87,6 +92,7 @@
#define cpu_has_k6_mtrr boot_cpu_has(X86_FEATURE_K6_MTRR)
#define cpu_has_cyrix_arr boot_cpu_has(X86_FEATURE_CYRIX_ARR)
#define cpu_has_centaur_mcr boot_cpu_has(X86_FEATURE_CENTAUR_MCR)
#define cpu_has_xstore boot_cpu_has(X86_FEATURE_XSTORE)
#endif
/* __ASM_I386_CPUFEATURE_H */
...
...
include/asm-i386/msr.h
View file @
2b3163d4
...
...
@@ -218,6 +218,7 @@
/* VIA Cyrix defined MSRs*/
#define MSR_VIA_FCR 0x1107
#define MSR_VIA_LONGHAUL 0x110a
#define MSR_VIA_RNG 0x110b
#define MSR_VIA_BCR2 0x1147
/* Transmeta defined MSRs */
...
...
include/asm-i386/xor.h
View file @
2b3163d4
...
...
@@ -25,6 +25,7 @@
#define XO3(x,y) " pxor 8*("#x")(%4), %%mm"#y" ;\n"
#define XO4(x,y) " pxor 8*("#x")(%5), %%mm"#y" ;\n"
#include <asm/i387.h>
static
void
xor_pII_mmx_2
(
unsigned
long
bytes
,
unsigned
long
*
p1
,
unsigned
long
*
p2
)
...
...
include/linux/device.h
View file @
2b3163d4
...
...
@@ -366,6 +366,7 @@ extern int platform_device_register(struct platform_device *);
extern
void
platform_device_unregister
(
struct
platform_device
*
);
extern
struct
bus_type
platform_bus_type
;
extern
struct
device
legacy_bus
;
/* drivers/base/power.c */
extern
int
device_suspend
(
u32
state
,
u32
level
);
...
...
include/linux/i2c.h
View file @
2b3163d4
...
...
@@ -34,6 +34,7 @@
#include <linux/module.h>
#include <linux/types.h>
#include <linux/i2c-id.h>
#include <linux/device.h>
/* for struct device */
#include <asm/semaphore.h>
/* --- General options ------------------------------------------------ */
...
...
@@ -144,6 +145,8 @@ struct i2c_driver {
int
(
*
command
)(
struct
i2c_client
*
client
,
unsigned
int
cmd
,
void
*
arg
);
};
extern
struct
bus_type
i2c_bus_type
;
/*
* i2c_client identifies a single device (i.e. chip) that is connected to an
* i2c bus. The behaviour is defined by the routines of the driver. This
...
...
@@ -228,12 +231,14 @@ struct i2c_adapter {
int
timeout
;
int
retries
;
struct
device
dev
;
/* the adapter device */
#ifdef CONFIG_PROC_FS
/* No need to set this when you initialize the adapter */
int
inode
;
#endif
/* def CONFIG_PROC_FS */
};
#define to_i2c_adapter(d) container_of(d, struct i2c_adapter, dev)
/*flags for the driver struct: */
#define I2C_DF_NOTIFY 0x01
/* notify on bus (de/a)ttaches */
...
...
include/linux/nfsd/export.h
View file @
2b3163d4
...
...
@@ -35,12 +35,13 @@
#define NFSEXP_UIDMAP 0x0040
#define NFSEXP_KERBEROS 0x0080
/* not available */
#define NFSEXP_SUNSECURE 0x0100
#define NFSEXP_
CROSSMNT
0x0200
#define NFSEXP_
NOHIDE
0x0200
#define NFSEXP_NOSUBTREECHECK 0x0400
#define NFSEXP_NOAUTHNLM 0x0800
/* Don't authenticate NLM requests - just trust */
#define NFSEXP_MSNFS 0x1000
/* do silly things that MS clients expect */
#define NFSEXP_FSID 0x2000
#define NFSEXP_ALLFLAGS 0x3FFF
#define NFSEXP_CROSSMNT 0x4000
#define NFSEXP_ALLFLAGS 0x7FFF
#ifdef __KERNEL__
...
...
@@ -73,7 +74,7 @@ struct svc_expkey {
#define EX_SECURE(exp) (!((exp)->ex_flags & NFSEXP_INSECURE_PORT))
#define EX_ISSYNC(exp) (!((exp)->ex_flags & NFSEXP_ASYNC))
#define EX_RDONLY(exp) ((exp)->ex_flags & NFSEXP_READONLY)
#define EX_
CROSSMNT(exp) ((exp)->ex_flags & NFSEXP_CROSSMNT
)
#define EX_
NOHIDE(exp) ((exp)->ex_flags & NFSEXP_NOHIDE
)
#define EX_SUNSECURE(exp) ((exp)->ex_flags & NFSEXP_SUNSECURE)
#define EX_WGATHER(exp) ((exp)->ex_flags & NFSEXP_GATHERED_WRITES)
...
...
include/linux/raid/md.h
View file @
2b3163d4
...
...
@@ -27,6 +27,7 @@
#include <linux/module.h>
#include <linux/hdreg.h>
#include <linux/proc_fs.h>
#include <linux/seq_file.h>
#include <linux/smp_lock.h>
#include <linux/delay.h>
#include <net/checksum.h>
...
...
@@ -68,13 +69,14 @@ extern inline char * bdev_partition_name (struct block_device *bdev)
}
extern
int
register_md_personality
(
int
p_num
,
mdk_personality_t
*
p
);
extern
int
unregister_md_personality
(
int
p_num
);
extern
mdk_thread_t
*
md_register_thread
(
void
(
*
run
)
(
void
*
data
),
void
*
data
,
const
char
*
name
);
extern
mdk_thread_t
*
md_register_thread
(
void
(
*
run
)
(
mddev_t
*
mddev
),
mddev_t
*
mddev
,
const
char
*
name
);
extern
void
md_unregister_thread
(
mdk_thread_t
*
thread
);
extern
void
md_wakeup_thread
(
mdk_thread_t
*
thread
);
extern
void
md_check_recovery
(
mddev_t
*
mddev
);
extern
void
md_interrupt_thread
(
mdk_thread_t
*
thread
);
extern
void
md_write_start
(
mddev_t
*
mddev
);
extern
void
md_write_end
(
mddev_t
*
mddev
,
mdk_thread_t
*
thread
);
extern
void
md_write_end
(
mddev_t
*
mddev
);
extern
void
md_handle_safemode
(
mddev_t
*
mddev
);
extern
void
md_done_sync
(
mddev_t
*
mddev
,
int
blocks
,
int
ok
);
extern
void
md_sync_acct
(
mdk_rdev_t
*
rdev
,
unsigned
long
nr_sectors
);
...
...
include/linux/raid/md_k.h
View file @
2b3163d4
...
...
@@ -155,6 +155,7 @@ struct mdk_rdev_s
struct
page
*
sb_page
;
int
sb_loaded
;
sector_t
data_offset
;
/* start of data in array */
sector_t
sb_offset
;
int
preferred_minor
;
/* autorun support */
...
...
@@ -206,22 +207,31 @@ struct mddev_s
char
uuid
[
16
];
struct
mdk_thread_s
*
thread
;
/* management thread */
struct
mdk_thread_s
*
sync_thread
;
/* doing resync or reconstruct */
unsigned
long
curr_resync
;
/* blocks scheduled */
unsigned
long
resync_mark
;
/* a recent timestamp */
unsigned
long
resync_mark_cnt
;
/* blocks written at resync_mark */
/* recovery_running is 0 for no recovery/resync,
* 1 for active recovery
* 2 for active resync
* -error for an error (e.g. -EINTR)
* it can only be set > 0 under reconfig_sem
/* recovery/resync flags
* NEEDED: we might need to start a resync/recover
* RUNNING: a thread is running, or about to be started
* SYNC: actually doing a resync, not a recovery
* ERR: and IO error was detected - abort the resync/recovery
* INTR: someone requested a (clean) early abort.
* DONE: thread is done and is waiting to be reaped
*/
int
recovery_running
;
int
recovery_error
;
/* error from recovery write */
#define MD_RECOVERY_RUNNING 0
#define MD_RECOVERY_SYNC 1
#define MD_RECOVERY_ERR 2
#define MD_RECOVERY_INTR 3
#define MD_RECOVERY_DONE 4
#define MD_RECOVERY_NEEDED 5
unsigned
long
recovery
;
int
in_sync
;
/* know to not need resync */
struct
semaphore
reconfig_sem
;
atomic_t
active
;
int
spares
;
int
degraded
;
/* whether md should consider
* adding a spare
...
...
@@ -230,9 +240,11 @@ struct mddev_s
atomic_t
recovery_active
;
/* blocks scheduled, but not written */
wait_queue_head_t
recovery_wait
;
sector_t
recovery_cp
;
int
safemode
;
/* if set, update "clean" superblock
unsigned
int
safemode
;
/* if set, update "clean" superblock
* when no writes pending.
*/
unsigned
int
safemode_delay
;
struct
timer_list
safemode_timer
;
atomic_t
writes_pending
;
request_queue_t
queue
;
/* for plugging ... */
...
...
@@ -245,7 +257,7 @@ struct mdk_personality_s
int
(
*
make_request
)(
request_queue_t
*
q
,
struct
bio
*
bio
);
int
(
*
run
)(
mddev_t
*
mddev
);
int
(
*
stop
)(
mddev_t
*
mddev
);
int
(
*
status
)(
char
*
page
,
mddev_t
*
mddev
);
void
(
*
status
)(
struct
seq_file
*
seq
,
mddev_t
*
mddev
);
/* error_handler must set ->faulty and clear ->in_sync
* if appropriate, and should abort recovery if needed
*/
...
...
@@ -292,8 +304,8 @@ extern mdk_rdev_t * find_rdev_nr(mddev_t *mddev, int nr);
ITERATE_RDEV_GENERIC(pending_raid_disks,rdev,tmp)
typedef
struct
mdk_thread_s
{
void
(
*
run
)
(
void
*
data
);
void
*
data
;
void
(
*
run
)
(
mddev_t
*
mddev
);
mddev_t
*
mddev
;
wait_queue_head_t
wqueue
;
unsigned
long
flags
;
struct
completion
*
event
;
...
...
include/linux/raid/md_p.h
View file @
2b3163d4
...
...
@@ -173,5 +173,58 @@ static inline __u64 md_event(mdp_super_t *sb) {
return
(
ev
<<
32
)
|
sb
->
events_lo
;
}
/*
* The version-1 superblock :
* All numeric fields are little-endian.
*
* total size: 256 bytes plus 2 per device.
* 1K allows 384 devices.
*/
struct
mdp_superblock_1
{
/* constant array information - 128 bytes */
__u32
magic
;
/* MD_SB_MAGIC: 0xa92b4efc - little endian */
__u32
major_version
;
/* 1 */
__u32
feature_map
;
/* 0 for now */
__u32
pad0
;
/* always set to 0 when writing */
__u8
set_uuid
[
16
];
/* user-space generated. */
char
set_name
[
32
];
/* set and interpreted by user-space */
__u64
ctime
;
/* lo 40 bits are seconds, top 24 are microseconds or 0*/
__u32
level
;
/* -4 (multipath), -1 (linear), 0,1,4,5 */
__u32
layout
;
/* only for raid5 currently */
__u64
size
;
/* used size of component devices, in 512byte sectors */
__u32
chunksize
;
/* in 512byte sectors */
__u32
raid_disks
;
__u8
pad1
[
128
-
92
];
/* set to 0 when written */
/* constant this-device information - 64 bytes */
__u64
data_offset
;
/* sector start of data, often 0 */
__u64
data_size
;
/* sectors in this device that can be used for data */
__u64
super_offset
;
/* sector start of this superblock */
__u64
recovery_offset
;
/* sectors before this offset (from data_offset) have been recovered */
__u32
dev_number
;
/* permanent identifier of this device - not role in raid */
__u32
cnt_corrected_read
;
/* number of read errors that were corrected by re-writing */
__u8
device_uuid
[
16
];
/* user-space setable, ignored by kernel */
__u8
pad2
[
64
-
56
];
/* set to 0 when writing */
/* array state information - 64 bytes */
__u64
utime
;
/* 40 bits second, 24 btes microseconds */
__u64
events
;
/* incremented when superblock updated */
__u64
resync_offset
;
/* data before this offset (from data_offset) known to be in sync */
__u32
sb_csum
;
/* checksum upto devs[max_dev] */
__u32
max_dev
;
/* size of devs[] array to consider */
__u8
pad3
[
64
-
40
];
/* set to 0 when writing */
/* device state information. Indexed by dev_number.
* 2 bytes per device
* Note there are no per-device state flags. State information is rolled
* into the 'roles' value. If a device is spare or faulty, then it doesn't
* have a meaningful role.
*/
__u16
dev_roles
[
0
];
/* role in array, or 0xffff for a spare, or 0xfffe for faulty */
};
#endif
include/linux/raid/multipath.h
View file @
2b3163d4
...
...
@@ -13,7 +13,6 @@ struct multipath_private_data {
struct
multipath_info
multipaths
[
MD_SB_DISKS
];
int
raid_disks
;
int
working_disks
;
mdk_thread_t
*
thread
;
spinlock_t
device_lock
;
mempool_t
*
pool
;
...
...
include/linux/raid/raid1.h
View file @
2b3163d4
...
...
@@ -19,7 +19,6 @@ struct r1_private_data_s {
int
working_disks
;
int
last_used
;
sector_t
next_seq_sect
;
mdk_thread_t
*
thread
;
spinlock_t
device_lock
;
/* for use when syncing mirrors: */
...
...
@@ -34,7 +33,6 @@ struct r1_private_data_s {
mempool_t
*
r1bio_pool
;
mempool_t
*
r1buf_pool
;
char
thread_name
[
MD_THREAD_NAME_MAX
];
};
typedef
struct
r1_private_data_s
conf_t
;
...
...
include/linux/raid/raid5.h
View file @
2b3163d4
...
...
@@ -203,7 +203,6 @@ struct disk_info {
struct
raid5_private_data
{
struct
stripe_head
**
stripe_hashtbl
;
mddev_t
*
mddev
;
mdk_thread_t
*
thread
;
struct
disk_info
disks
[
MD_SB_DISKS
];
struct
disk_info
*
spare
;
int
chunk_size
,
level
,
algorithm
;
...
...
@@ -226,7 +225,6 @@ struct raid5_private_data {
* waiting for 25% to be free
*/
spinlock_t
device_lock
;
char
thread_name
[
MD_THREAD_NAME_MAX
];
};
typedef
struct
raid5_private_data
raid5_conf_t
;
...
...
include/linux/sunrpc/cache.h
View file @
2b3163d4
...
...
@@ -190,6 +190,7 @@ RTN *FNAME ARGS \
else read_unlock(&(DETAIL)->hash_lock); \
if (set) \
cache_fresh(DETAIL, &tmp->MEMBER, item->MEMBER.expiry_time); \
if (set==1 && new) cache_fresh(DETAIL, &new->MEMBER, 0); \
if (new) (DETAIL)->cache_put(&new->MEMBER, DETAIL); \
return tmp; \
} \
...
...
net/sunrpc/svcauth_unix.c
View file @
2b3163d4
...
...
@@ -441,9 +441,6 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp)
return
SVC_DENIED
;
}
/* Put NULL verifier */
svc_putu32
(
resv
,
RPC_AUTH_NULL
);
svc_putu32
(
resv
,
0
);
key
.
m_class
=
rqstp
->
rq_server
->
sv_program
->
pg_class
;
key
.
m_addr
=
rqstp
->
rq_addr
.
sin_addr
;
...
...
@@ -470,8 +467,13 @@ svcauth_unix_accept(struct svc_rqst *rqstp, u32 *authp)
}
else
rv
=
SVC_DROP
;
if
(
rqstp
->
rq_client
==
NULL
&&
rqstp
->
rq_proc
!=
0
)
if
(
r
v
==
SVC_OK
&&
r
qstp
->
rq_client
==
NULL
&&
rqstp
->
rq_proc
!=
0
)
goto
badcred
;
/* Put NULL verifier */
svc_putu32
(
resv
,
RPC_AUTH_NULL
);
svc_putu32
(
resv
,
0
);
return
rv
;
badcred:
...
...
net/sunrpc/svcsock.c
View file @
2b3163d4
...
...
@@ -577,12 +577,15 @@ svc_udp_recvfrom(struct svc_rqst *rqstp)
if
(
skb_is_nonlinear
(
skb
))
{
/* we have to copy */
local_bh_disable
();
if
(
csum_partial_copy_to_xdr
(
&
rqstp
->
rq_arg
,
skb
))
{
local_bh_enable
();
/* checksum error */
skb_free_datagram
(
svsk
->
sk_sk
,
skb
);
svc_sock_received
(
svsk
);
return
0
;
}
local_bh_enable
();
skb_free_datagram
(
svsk
->
sk_sk
,
skb
);
}
else
{
/* we can use it in-place */
...
...
@@ -1435,7 +1438,7 @@ static struct cache_deferred_req *
svc_defer
(
struct
cache_req
*
req
)
{
struct
svc_rqst
*
rqstp
=
container_of
(
req
,
struct
svc_rqst
,
rq_chandle
);
int
size
=
sizeof
(
struct
svc_deferred_req
)
+
(
rqstp
->
rq_arg
.
head
[
0
].
iov_
len
);
int
size
=
sizeof
(
struct
svc_deferred_req
)
+
(
rqstp
->
rq_arg
.
len
);
struct
svc_deferred_req
*
dr
;
if
(
rqstp
->
rq_arg
.
page_len
)
...
...
@@ -1444,6 +1447,7 @@ svc_defer(struct cache_req *req)
dr
=
rqstp
->
rq_deferred
;
rqstp
->
rq_deferred
=
NULL
;
}
else
{
int
skip
=
rqstp
->
rq_arg
.
len
-
rqstp
->
rq_arg
.
head
[
0
].
iov_len
;
/* FIXME maybe discard if size too large */
dr
=
kmalloc
(
size
,
GFP_KERNEL
);
if
(
dr
==
NULL
)
...
...
@@ -1452,8 +1456,8 @@ svc_defer(struct cache_req *req)
dr
->
serv
=
rqstp
->
rq_server
;
dr
->
prot
=
rqstp
->
rq_prot
;
dr
->
addr
=
rqstp
->
rq_addr
;
dr
->
argslen
=
rqstp
->
rq_arg
.
head
[
0
].
iov_
len
>>
2
;
memcpy
(
dr
->
args
,
rqstp
->
rq_arg
.
head
[
0
].
iov_base
,
dr
->
argslen
<<
2
);
dr
->
argslen
=
rqstp
->
rq_arg
.
len
>>
2
;
memcpy
(
dr
->
args
,
rqstp
->
rq_arg
.
head
[
0
].
iov_base
-
skip
,
dr
->
argslen
<<
2
);
}
spin_lock
(
&
rqstp
->
rq_server
->
sv_lock
);
rqstp
->
rq_sock
->
sk_inuse
++
;
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment