Messages in this thread Patch in this message | | | Date | Wed, 07 Jul 2004 17:31:17 +0900 | From | Takao Indoh <> | Subject | [PATCH 2/4][Diskdump]Update patches |
| |
This is a patch for scsi common layer.
diff -Nur linux-2.6.7.org/drivers/scsi/Kconfig linux-2.6.7/drivers/scsi/Kconfig --- linux-2.6.7.org/drivers/scsi/Kconfig 2004-06-22 10:27:49.000000000 +0900 +++ linux-2.6.7/drivers/scsi/Kconfig 2004-07-07 14:16:22.000000000 +0900 @@ -55,6 +55,12 @@ In this case, do not compile the driver for your SCSI host adapter (below) as a module either. +config SCSI_DUMP + tristate "SCSI dump support" + depends on DISKDUMP && SCSI + help + SCSI dump support + config CHR_DEV_ST tristate "SCSI tape support" depends on SCSI diff -Nur linux-2.6.7.org/drivers/scsi/Makefile linux-2.6.7/drivers/scsi/Makefile --- linux-2.6.7.org/drivers/scsi/Makefile 2004-06-22 10:27:51.000000000 +0900 +++ linux-2.6.7/drivers/scsi/Makefile 2004-07-07 14:16:22.000000000 +0900 @@ -136,6 +136,8 @@ obj-$(CONFIG_BLK_DEV_SR) += sr_mod.o obj-$(CONFIG_CHR_DEV_SG) += sg.o +obj-$(CONFIG_SCSI_DUMP) += scsi_dump.o + scsi_mod-y += scsi.o hosts.o scsi_ioctl.o constants.o \ scsicam.o scsi_error.o scsi_lib.o \ scsi_scan.o scsi_syms.o scsi_sysfs.o \ diff -Nur linux-2.6.7.org/drivers/scsi/scsi.c linux-2.6.7/drivers/scsi/scsi.c --- linux-2.6.7.org/drivers/scsi/scsi.c 2004-06-22 10:27:49.000000000 +0900 +++ linux-2.6.7/drivers/scsi/scsi.c 2004-07-07 14:16:22.000000000 +0900 @@ -691,6 +691,9 @@ { unsigned long flags; + if (crashdump_mode()) + return; + /* * We don't have to worry about this one timing out any more. * If we are unable to remove the timer, then the command diff -Nur linux-2.6.7.org/drivers/scsi/scsi_dump.c linux-2.6.7/drivers/scsi/scsi_dump.c --- linux-2.6.7.org/drivers/scsi/scsi_dump.c 1970-01-01 09:00:00.000000000 +0900 +++ linux-2.6.7/drivers/scsi/scsi_dump.c 2004-07-07 14:16:22.000000000 +0900 @@ -0,0 +1,623 @@ +/* + * linux/drivers/scsi/scsi_dump.c + * + * Copyright (C) 2004 FUJITSU LIMITED + * Written by Nobuhiro Tachino (ntachino@jp.fujitsu.com) + * + * Some codes are derived from drivers/scsi/sd.c + */ +/* + * 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, 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. + * + */ + +#include <linux/module.h> + +#include <linux/fs.h> +#include <linux/kernel.h> +#include <linux/sched.h> + +#include <linux/blkdev.h> +#include <linux/blkpg.h> + +#include <linux/genhd.h> +#include <linux/utsname.h> +#include <linux/crc32.h> +#include <linux/delay.h> +#include <linux/diskdump.h> + +#include <scsi/scsi.h> +#include <scsi/scsi_ioctl.h> +#include <scsi/scsi_host.h> +#include <scsi/scsi_cmnd.h> +#include <scsi/scsi_device.h> + +#include "scsi_priv.h" + +/* + * Fixme: Legacy dma direction interfaces. + */ +#define SCSI_DATA_UNKNOWN (DMA_BIDIRECTIONAL) +#define SCSI_DATA_WRITE (DMA_TO_DEVICE) +#define SCSI_DATA_READ (DMA_FROM_DEVICE) +#define SCSI_DATA_NONE (DMA_NONE) + +#define MAX_RETRIES 5 +#define SD_TIMEOUT (60 * HZ) + +#define Dbg(x, ...) pr_debug("scsi_dump: " x "\n", ## __VA_ARGS__) +#define Err(x, ...) pr_err ("scsi_dump: " x "\n", ## __VA_ARGS__) +#define Warn(x, ...) pr_warn ("scsi_dump: " x "\n", ## __VA_ARGS__) +#define Info(x, ...) pr_info ("scsi_dump: " x "\n", ## __VA_ARGS__) + +/* blocks to 512byte sectors */ +#define BLOCK_SECTOR(s) ((s) << (DUMP_BLOCK_SHIFT - 9)) + +static int quiesce_ok = 0; +static struct scsi_cmnd scsi_dump_cmnd; +static struct request scsi_dump_req; +static uint32_t module_crc; + +static void rw_intr(struct scsi_cmnd * scmd) +{ + scmd->done = NULL; +} + +/* + * Common code to make Scsi_Cmnd + */ +static void init_scsi_command(struct scsi_device *sdev, struct scsi_cmnd *scmd, + void *buf, int len, unsigned char direction, + int set_lun) +{ + scmd->request = &scsi_dump_req; + scmd->sc_magic = SCSI_CMND_MAGIC; + scmd->owner = SCSI_OWNER_MIDLEVEL; + scmd->device = sdev; + scmd->buffer = scmd->request_buffer = buf; + scmd->bufflen = scmd->request_bufflen = len; + + + scmd->sc_data_direction = direction; + + memcpy(scmd->data_cmnd, scmd->cmnd, sizeof(scmd->cmnd)); + scmd->cmd_len = COMMAND_SIZE(scmd->cmnd[0]); + scmd->old_cmd_len = scmd->cmd_len; + + + if (set_lun) + scmd->cmnd[1] |= (sdev->scsi_level <= SCSI_2) ? + ((sdev->lun << 5) & 0xe0) : 0; + + scmd->transfersize = sdev->sector_size; + if (direction == SCSI_DATA_WRITE) + scmd->underflow = len; + + scmd->allowed = MAX_RETRIES; + scmd->timeout_per_command = SD_TIMEOUT; + + /* + * This is the completion routine we use. This is matched in terms + * of capability to this function. + */ + scmd->done = rw_intr; +} + +/* MODE SENSE */ +static void init_mode_sense_command(struct scsi_device *sdev, + struct scsi_cmnd *scmd, void *buf) +{ + memset(scmd, 0, sizeof(*scmd)); + scmd->cmnd[0] = MODE_SENSE; + scmd->cmnd[1] = 0x00; /* DBD=0 */ + scmd->cmnd[2] = 0x08; /* PCF=0 Page 8(Cache) */ + scmd->cmnd[4] = 255; + + init_scsi_command(sdev, scmd, buf, 256, SCSI_DATA_READ, 1); +} + +/* MODE SELECT */ +static void init_mode_select_command(struct scsi_device *sdev, + struct scsi_cmnd *scmd, void *buf, int len) +{ + memset(scmd, 0, sizeof(*scmd)); + scmd->cmnd[0] = MODE_SELECT; + scmd->cmnd[1] = 0x10; /* PF=1 SP=0 */ + scmd->cmnd[4] = len; + + init_scsi_command(sdev, scmd, buf, len, SCSI_DATA_WRITE, 1); +} + +/* SYNCHRONIZE CACHE */ +static void init_sync_command(struct scsi_device *sdev, struct scsi_cmnd * scmd) +{ + memset(scmd, 0, sizeof(*scmd)); + scmd->cmnd[0] = SYNCHRONIZE_CACHE; + + init_scsi_command(sdev, scmd, NULL, 0, SCSI_DATA_NONE, 0); +} + +/* REQUEST SENSE */ +static void init_sense_command(struct scsi_device *sdev, struct scsi_cmnd *scmd, + void *buf) +{ + memset(scmd, 0, sizeof(*scmd)); + scmd->cmnd[0] = REQUEST_SENSE; + scmd->cmnd[4] = 255; + + init_scsi_command(sdev, scmd, buf, 256, SCSI_DATA_READ, 1); +} + +/* READ/WRITE */ +static int init_rw_command(struct disk_dump_partition *dump_part, + struct scsi_device *sdev, struct scsi_cmnd * scmd, + int rw, int block, void *buf, unsigned int len) +{ + int this_count = len >> 9; + + memset(scmd, 0, sizeof(*scmd)); + + if (block + this_count > dump_part->nr_sects) { + Err("block number %d is larger than %lu", + block + this_count, dump_part->nr_sects); + return -EFBIG; + } + + block += dump_part->start_sect; + + /* + * If we have a 1K hardware sectorsize, prevent access to single + * 512 byte sectors. In theory we could handle this - in fact + * the scsi cdrom driver must be able to handle this because + * we typically use 1K blocksizes, and cdroms typically have + * 2K hardware sectorsizes. Of course, things are simpler + * with the cdrom, since it is read-only. For performance + * reasons, the filesystems should be able to handle this + * and not force the scsi disk driver to use bounce buffers + * for this. + */ + if (sdev->sector_size == 1024) { + block = block >> 1; + this_count = this_count >> 1; + } + if (sdev->sector_size == 2048) { + block = block >> 2; + this_count = this_count >> 2; + } + if (sdev->sector_size == 4096) { + block = block >> 3; + this_count = this_count >> 3; + } + switch (rw) { + case WRITE: + if (!sdev->writeable) { + Err("writable media"); + return 0; + } + scmd->cmnd[0] = WRITE_10; + break; + case READ: + scmd->cmnd[0] = READ_10; + break; + default: + Err("Unknown command %d", rw); + return -EINVAL; + } + + if (this_count > 0xffff) + this_count = 0xffff; + + scmd->cmnd[2] = (unsigned char) (block >> 24) & 0xff; + scmd->cmnd[3] = (unsigned char) (block >> 16) & 0xff; + scmd->cmnd[4] = (unsigned char) (block >> 8) & 0xff; + scmd->cmnd[5] = (unsigned char) block & 0xff; + scmd->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff; + scmd->cmnd[8] = (unsigned char) this_count & 0xff; + + init_scsi_command(sdev, scmd, buf, len, + (rw == WRITE ? SCSI_DATA_WRITE : SCSI_DATA_READ), 1); + return 0; +} + +/* + * Check the status of scsi command and determine whether it is + * success, fail, or retriable. + * + * Return code + * > 0: should retry + * = 0: success + * < 0: fail + */ +static int cmd_result(struct scsi_cmnd *scmd) +{ + int status; + + status = status_byte(scmd->result); + + switch (scsi_decide_disposition(scmd)) { + case FAILED: + break; + case NEEDS_RETRY: + case ADD_TO_MLQUEUE: + return 1 /* retry */; + case SUCCESS: + if (host_byte(scmd->result) != DID_OK) + break; + + if (status == GOOD || status == INTERMEDIATE_GOOD + || status == INTERMEDIATE_C_GOOD) + return 0; + if (status == CHECK_CONDITION && + scmd->sense_buffer[2] == RECOVERED_ERROR) + return 0; + break; + default: + Err("bad disposition: %d", scmd->result); + return -EIO; + } + + Err("command %x failed with 0x%x", scmd->cmnd[0], scmd->result); + return -EIO; +} + +static int send_command(struct scsi_cmnd *scmd) +{ + struct Scsi_Host *host = scmd->device->host; + struct scsi_device *sdev = scmd->device; + int ret; + + do { + if (!scsi_device_online(sdev)) { + Err("Scsi disk is not online"); + return -EIO; + } + if (sdev->changed) { + Err("SCSI disk has been changed. Prohibiting further I/O"); + return -EIO; + } + + spin_lock(host->host_lock); + host->hostt->queuecommand(scmd, rw_intr); + spin_unlock(host->host_lock); + + while (scmd->done != NULL) { + host->hostt->dump_poll(scmd->device); + udelay(100); + diskdump_update(); + } + scmd->done = rw_intr; + } while ((ret = cmd_result(scmd)) > 0); + + return ret; +} + +/* + * If Write Cache Enable of disk device is not set, write I/O takes + * long long time. So enable WCE temporary and issue SYNCHRONIZE CACHE + * after all write I/Os are done, Following system reboot will reset + * WCE bit to original value. + */ +static void +enable_write_cache(struct scsi_device *sdev) +{ + char buf[256]; + int ret; + int data_len; + + Dbg("enable write cache"); + memset(buf, 0, 256); + + init_mode_sense_command(sdev, &scsi_dump_cmnd, buf); + if ((ret = send_command(&scsi_dump_cmnd)) < 0) { + Warn("MODE SENSE failed"); + return; + } + + if (buf[14] & 0x04) /* WCE is already set */ + return; + + data_len = buf[0] + 1; /* Data length in mode parameter header */ + buf[0] = 0; + buf[1] = 0; + buf[2] = 0; + buf[12] &= 0x7f; /* clear PS */ + buf[14] |= 0x04; /* set WCE */ + + init_mode_select_command(sdev, &scsi_dump_cmnd, buf, data_len); + if ((ret = send_command(&scsi_dump_cmnd)) < 0) { + Warn("MODE SELECT failed"); + + init_sense_command(sdev, &scsi_dump_cmnd, buf); + if ((ret = send_command(&scsi_dump_cmnd)) < 0) { + Err("sense failed"); + } + } +} + +/* + * Check whether the dump device is sane enough to handle I/O. + * + * Return value: + * 0: the device is ok + * < 0: the device is not ok + * > 0: Cannot determine + */ +static int +scsi_dump_sanity_check(struct disk_dump_device *dump_device) +{ + struct scsi_device *sdev = dump_device->device; + struct Scsi_Host *host = sdev->host; + int adapter_sanity = 0; + int sanity = 0; + + if (!check_crc_module()) { + Err("checksum error. scsi dump module may be compromised."); + return -EINVAL; + } + /* + * If host's spinlock is already taken, assume it's part + * of crash and skip it. + */ + if (!scsi_device_online(sdev)) { + Warn("device not online: host %d channel %d id %d lun %d", + host->host_no, sdev->channel, sdev->id, sdev->lun); + return -EIO; + } + if (sdev->changed) { + Err("SCSI disk has been changed. Prohibiting further I/O: host %d channel %d id %d lun %d", + host->host_no, sdev->channel, sdev->id, sdev->lun); + return -EIO; + } + + if (host->hostt->dump_sanity_check) { + adapter_sanity = host->hostt->dump_sanity_check(sdev); + if (adapter_sanity < 0) { + Warn("adapter status is not sane"); + return adapter_sanity; + } + } + + if (!spin_is_locked(host->host_lock)) { + sanity = 0; + } else { + Warn("host_lock is held: host %d channel %d id %d lun %d", + host->host_no, sdev->channel, sdev->id, sdev->lun); + return -EIO; + } + return sanity + adapter_sanity; +} + +/* + * Try to reset the host adapter. If the adapter does not have its host reset + * handler, try to use its bus device reset handler. + */ +static int scsi_dump_reset(struct scsi_device *sdev) +{ + struct Scsi_Host *host = sdev->host; + struct scsi_host_template *hostt = host->hostt; + char buf[256]; + int ret, i; + + init_sense_command(sdev, &scsi_dump_cmnd, buf); + + if (hostt->eh_host_reset_handler) { + spin_lock(host->host_lock); + ret = hostt->eh_host_reset_handler(&scsi_dump_cmnd); + } else if (hostt->eh_bus_reset_handler) { + spin_lock(host->host_lock); + ret = hostt->eh_bus_reset_handler(&scsi_dump_cmnd); + } else + return 0; + spin_unlock(host->host_lock); + + if (ret != SUCCESS) { + Err("adapter reset failed"); + return -EIO; + } + + /* bus reset settle time. 5sec for old disk devices */ + for (i = 0; i < 5000; i++) { + diskdump_update(); + mdelay(1); + } + + Dbg("request sense"); + if ((ret = send_command(&scsi_dump_cmnd)) < 0) { + Err("sense failed"); + return -EIO; + } + return 0; +} + +static int +scsi_dump_quiesce(struct disk_dump_device *dump_device) +{ + struct scsi_device *sdev = dump_device->device; + struct Scsi_Host *host = sdev->host; + int ret; + + if (host->hostt->dump_quiesce) { + ret = host->hostt->dump_quiesce(sdev); + if (ret < 0) + return ret; + } + + Dbg("do bus reset"); + if ((ret = scsi_dump_reset(sdev)) < 0) + return ret; + + if (sdev->scsi_level >= SCSI_2) + enable_write_cache(sdev); + + quiesce_ok = 1; + return 0; +} + +static int scsi_dump_rw_block(struct disk_dump_partition *dump_part, int rw, + unsigned long dump_block_nr, void *buf, int len) +{ + struct disk_dump_device *dump_device = dump_part->device; + struct scsi_device *sdev = dump_device->device; + int block_nr = BLOCK_SECTOR(dump_block_nr); + int ret; + + if (!quiesce_ok) { + Err("quiesce not called"); + return -EIO; + } + + ret = init_rw_command(dump_part, sdev, &scsi_dump_cmnd, rw, + block_nr, buf, DUMP_BLOCK_SIZE * len); + if (ret < 0) { + Err("init_rw_command failed"); + return ret; + } + return send_command(&scsi_dump_cmnd); +} + +static int +scsi_dump_shutdown(struct disk_dump_device *dump_device) +{ + struct scsi_device *sdev = dump_device->device; + struct Scsi_Host *host = sdev->host; + + if (sdev->scsi_level >= SCSI_2) { + init_sync_command(sdev, &scsi_dump_cmnd); + send_command(&scsi_dump_cmnd); + } + + if (host->hostt->dump_shutdown) + return host->hostt->dump_shutdown(sdev); + + return 0; +} + +struct disk_dump_device_ops scsi_dump_device_ops = { + .sanity_check = scsi_dump_sanity_check, + .rw_block = scsi_dump_rw_block, + .quiesce = scsi_dump_quiesce, + .shutdown = scsi_dump_shutdown, +}; + +static int scsi_dump_add(struct scsi_device *sdev, struct block_device *bdev) +{ + struct disk_dump_device *dump_device; + int error; + + if (!sdev->host->hostt->dump_poll) + return -ENOTSUPP; + + if (!(dump_device = kmalloc(sizeof(*dump_device), GFP_KERNEL))) + return -ENOMEM; + + memset(dump_device, 0, sizeof(*dump_device)); + INIT_LIST_HEAD(&dump_device->partitions); + dump_device->device = sdev; + + if ((error = scsi_device_get(sdev)) != 0) { + kfree(dump_device); + return error; + } + + memcpy(&dump_device->ops, &scsi_dump_device_ops, + sizeof(scsi_dump_device_ops)); + if (sdev->host->max_sectors) { + dump_device->max_blocks = + (sdev->sector_size * sdev->host->max_sectors) + >> DUMP_BLOCK_SHIFT; + } + + if (!try_module_get(THIS_MODULE)) { + kfree(dump_device); + scsi_device_put(sdev); + return -EINVAL; + } + + if (register_disk_dump_device(dump_device, bdev)) { + scsi_device_put(sdev); + module_put(THIS_MODULE); + } + + return 0; +} + +static int scsi_dump_remove(struct scsi_device *sdev, struct block_device *bdev) +{ + if (!unregister_disk_dump_device(bdev)) { + scsi_device_put(sdev); + module_put(THIS_MODULE); + } + return 0; +} + + +/* + * sysfs interface + */ +static ssize_t scsi_dump_store_handler(struct device *dev, const char *buf, + size_t count) +{ + struct scsi_device *sdev = to_scsi_device(dev); + struct gendisk *disk; + struct block_device *bdev; + int part, remove = 0; + + sscanf (buf, "%d\n", &part); + if (part < 0) { + part = -part; + remove = 1; + } + + disk = device_to_gendisk(dev); + if (!disk) + return count; + bdev = bdget_disk(disk, part); + + if (!(bdev = bdget_disk(disk, part))) + return count; + + /* register/unregister device */ + if (!remove) + scsi_dump_add(sdev, bdev); + else + scsi_dump_remove(sdev, bdev); + + return count; +} + +extern int sdev_dump_handler_register(struct device_attribute *); +extern void sdev_dump_handler_unregister(void); + +static int init_scsi_dump(void) +{ + struct device_attribute attr; + + set_crc_modules(); + attr.show = print_disk_dump_device; + attr.store = scsi_dump_store_handler; + sdev_dump_handler_register(&attr); + + return 0; +} + +static void cleanup_scsi_dump(void) +{ + sdev_dump_handler_unregister(); +} + +module_init(init_scsi_dump); +module_exit(cleanup_scsi_dump); + +MODULE_LICENSE("GPL"); diff -Nur linux-2.6.7.org/drivers/scsi/scsi_error.c linux-2.6.7/drivers/scsi/scsi_error.c --- linux-2.6.7.org/drivers/scsi/scsi_error.c 2004-06-22 10:27:50.000000000 +0900 +++ linux-2.6.7/drivers/scsi/scsi_error.c 2004-07-07 14:16:22.000000000 +0900 @@ -402,6 +402,9 @@ **/ static void scsi_eh_done(struct scsi_cmnd *scmd) { + if (crashdump_mode()) + return; + /* * if the timeout handler is already running, then just set the * flag which says we finished late, and return. we have no diff -Nur linux-2.6.7.org/drivers/scsi/scsi_syms.c linux-2.6.7/drivers/scsi/scsi_syms.c --- linux-2.6.7.org/drivers/scsi/scsi_syms.c 2004-06-22 10:27:50.000000000 +0900 +++ linux-2.6.7/drivers/scsi/scsi_syms.c 2004-07-07 14:16:22.000000000 +0900 @@ -25,6 +25,7 @@ #include "scsi.h" #include "scsi_logging.h" +#include "scsi_priv.h" /* @@ -107,3 +108,5 @@ */ EXPORT_SYMBOL(scsi_add_timer); EXPORT_SYMBOL(scsi_delete_timer); + +EXPORT_SYMBOL(scsi_decide_disposition); diff -Nur linux-2.6.7.org/drivers/scsi/scsi_sysfs.c linux-2.6.7/drivers/scsi/scsi_sysfs.c --- linux-2.6.7.org/drivers/scsi/scsi_sysfs.c 2004-06-22 10:27:50.000000000 +0900 +++ linux-2.6.7/drivers/scsi/scsi_sysfs.c 2004-07-07 17:01:26.146353152 +0900 @@ -375,6 +375,66 @@ DEVICE_ATTR(state, S_IRUGO | S_IWUSR, show_state_field, store_state_field); +static DECLARE_MUTEX(sdev_dump_mutex); + +static struct device_attribute sdev_dump_attr = { + .show = NULL, + .store = NULL, +}; + +int sdev_dump_handler_register(struct device_attribute* attr) +{ + if (sdev_dump_attr.show || sdev_dump_attr.store) + return -EEXIST; + + down(&sdev_dump_mutex); + sdev_dump_attr = *attr; + up(&sdev_dump_mutex); + + return 0; +} + +EXPORT_SYMBOL(sdev_dump_handler_register); + +void sdev_dump_handler_unregister(void) +{ + down(&sdev_dump_mutex); + sdev_dump_attr.show = NULL; + sdev_dump_attr.store = NULL; + up(&sdev_dump_mutex); +} + +EXPORT_SYMBOL(sdev_dump_handler_unregister); + +static ssize_t +sdev_store_dump(struct device *dev, const char *buf, size_t count) +{ + ssize_t ret = count; + + down(&sdev_dump_mutex); + if (sdev_dump_attr.store) + ret = sdev_dump_attr.store(dev, buf, count); + up(&sdev_dump_mutex); + + return ret; +} + +static ssize_t +sdev_show_dump(struct device *dev, char *buf) +{ + ssize_t ret; + + down(&sdev_dump_mutex); + if (sdev_dump_attr.show) + ret = sdev_dump_attr.show(dev, buf); + else + ret = snprintf(buf, 20, "handler not found\n"); + up(&sdev_dump_mutex); + + return ret; +} + +DEVICE_ATTR(dump, S_IRUGO | S_IWUSR, sdev_show_dump, sdev_store_dump); /* Default template for device attributes. May NOT be modified */ static struct device_attribute *scsi_sysfs_sdev_attrs[] = { @@ -389,6 +449,7 @@ &dev_attr_delete, &dev_attr_state, &dev_attr_timeout, + &dev_attr_dump, NULL }; diff -Nur linux-2.6.7.org/include/scsi/scsi_host.h linux-2.6.7/include/scsi/scsi_host.h --- linux-2.6.7.org/include/scsi/scsi_host.h 2004-06-22 10:27:28.000000000 +0900 +++ linux-2.6.7/include/scsi/scsi_host.h 2004-07-07 14:16:22.000000000 +0900 @@ -345,6 +345,47 @@ * module_init/module_exit. */ struct list_head legacy_hosts; + +#if defined(CONFIG_SCSI_DUMP) || defined(CONFIG_SCSI_DUMP_MODULE) + /* operations for dump */ + + /* + * dump_sanity_check() checks if the selected device works normally. + * A device which returns an error status will not be selected as + * the dump device. + * + * Status: OPTIONAL + */ + int (* dump_sanity_check)(struct scsi_device *); + + /* + * dump_quiesce() is called after the device is selected as the + * dump device. Usually, host reset is executed and Write Cache + * Enable bit of the disk device is temporarily set for the + * dump operation. + * + * Status: OPTIONAL + */ + int (* dump_quiesce)(struct scsi_device *); + + /* + * dump_shutdown() is called after dump is completed. Usually + * "SYNCHRONIZE CACHE" command is issued to the disk. + * + * Status: OPTIONAL + */ + int (* dump_shutdown)(struct scsi_device *); + + /* + * dump_poll() should call the interrupt handler. It is called + * repeatedly after queuecommand() is issued, and until the command + * is completed. If the low level device driver support crash dump, + * it must have this routine. + * + * Status: OPTIONAL + */ + void (* dump_poll)(struct scsi_device *); +#endif }; /* - To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
| |