4 * Copyright (C) 2004 FUJITSU LIMITED
5 * Written by Nobuhiro Tachino (ntachino@jp.fujitsu.com)
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2, or (at your option)
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include <linux/kernel.h>
26 #include <linux/delay.h>
27 #include <linux/nmi.h>
28 #include <linux/timer.h>
29 #include <linux/interrupt.h>
30 #include <linux/workqueue.h>
31 #include <linux/genhd.h>
32 #include <linux/diskdump.h>
33 #include <asm/diskdump.h>
35 static DECLARE_MUTEX(dump_ops_mutex);
36 struct disk_dump_ops* dump_ops = NULL;
38 int diskdump_mode = 0;
39 EXPORT_SYMBOL_GPL(diskdump_mode);
41 void (*diskdump_func) (struct pt_regs *regs) = NULL;
42 EXPORT_SYMBOL_GPL(diskdump_func);
44 static unsigned long long timestamp_base;
45 static unsigned long timestamp_hz;
49 * register/unregister diskdump operations
51 int diskdump_register_ops(struct disk_dump_ops* op)
53 down(&dump_ops_mutex);
64 EXPORT_SYMBOL_GPL(diskdump_register_ops);
66 void diskdump_unregister_ops(void)
68 down(&dump_ops_mutex);
73 EXPORT_SYMBOL_GPL(diskdump_unregister_ops);
79 static struct gendisk *device_to_gendisk(struct device *dev)
84 /* trace symlink to "block" */
86 qstr.len = strlen(qstr.name);
87 qstr.hash = full_name_hash(qstr.name, qstr.len);
88 d = d_lookup(dev->kobj.dentry, &qstr);
89 if (!d || !d->d_fsdata)
92 return container_of(d->d_fsdata, struct gendisk, kobj);
95 ssize_t diskdump_sysfs_store(struct device *dev, const char *buf, size_t count)
98 struct block_device *bdev;
101 if (!dump_ops || !dump_ops->add_dump || !dump_ops->remove_dump)
104 /* get partition number */
105 sscanf (buf, "%d\n", &part);
111 /* get block device */
112 if (!(disk = device_to_gendisk(dev)) ||
113 !(bdev = bdget_disk(disk, part)))
116 /* add/remove device */
117 down(&dump_ops_mutex);
119 dump_ops->add_dump(dev, bdev);
121 dump_ops->remove_dump(bdev);
127 EXPORT_SYMBOL_GPL(diskdump_sysfs_store);
129 ssize_t diskdump_sysfs_show(struct device *dev, char *buf)
131 struct gendisk *disk;
132 struct block_device *bdev;
133 int part, tmp, len = 0, maxlen = 1024;
135 char name[BDEVNAME_SIZE];
137 if (!dump_ops || !dump_ops->find_dump)
141 disk = device_to_gendisk(dev);
142 if (!disk || !disk->part)
146 down(&dump_ops_mutex);
147 for (part = 0; part < disk->minors - 1; part++) {
148 bdev = bdget_disk(disk, part);
149 if (dump_ops->find_dump(bdev)) {
150 tmp = sprintf(p, "%s\n", bdevname(bdev, name));
163 EXPORT_SYMBOL_GPL(diskdump_sysfs_show);
166 * run timer/tasklet/workqueue during dump
168 void diskdump_setup_timestamp(void)
170 unsigned long long t;
172 platform_timestamp(timestamp_base);
174 platform_timestamp(t);
175 timestamp_hz = (unsigned long)(t - timestamp_base);
179 EXPORT_SYMBOL_GPL(diskdump_setup_timestamp);
181 void diskdump_update(void)
183 unsigned long long t;
185 touch_nmi_watchdog();
188 platform_timestamp(t);
189 while (t > timestamp_base + timestamp_hz) {
190 timestamp_base += timestamp_hz;
192 platform_timestamp(t);
197 dump_run_workqueue();
200 EXPORT_SYMBOL_GPL(diskdump_update);
204 * register/unregister hook
206 int diskdump_register_hook(void (*dump_func) (struct pt_regs *))
211 diskdump_func = dump_func;
216 EXPORT_SYMBOL_GPL(diskdump_register_hook);
218 void diskdump_unregister_hook(void)
220 diskdump_func = NULL;
223 EXPORT_SYMBOL_GPL(diskdump_unregister_hook);
225 void (*netdump_func) (struct pt_regs *regs) = NULL;
226 int netdump_mode = 0;
227 EXPORT_SYMBOL_GPL(netdump_mode);
230 * Try crashdump. Diskdump is first, netdump is second.
231 * We clear diskdump_func before call of diskdump_func, so
232 * If double panic would occur in diskdump, netdump can handle
235 void try_crashdump(struct pt_regs *regs)
237 void (*func)(struct pt_regs *);
240 func = diskdump_func;
241 diskdump_func = NULL;