dasd.c
来自「linux-2.4.29操作系统的源码」· C语言 代码 · 共 2,133 行 · 第 1/5 页
C
2,133 行
/* * File...........: linux/drivers/s390/block/dasd.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> * Horst Hummel <Horst.Hummel@de.ibm.com> * Carsten Otte <Cotte@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999-2001 * * $Revision: 1.298.2.11 $ * * History of changes (starts July 2000) * 11/09/00 complete redesign after code review * 02/01/01 added dynamic registration of ioctls * fixed bug in registration of new majors * fixed handling of request during dasd_end_request * fixed handling of plugged queues * fixed partition handling and HDIO_GETGEO * fixed traditional naming scheme for devices beyond 702 * fixed some race conditions related to modules * added devfs suupport * 03/06/01 refined dynamic attach/detach for leaving devices which are online. * 03/09/01 refined dynamic modifiaction of devices * 03/12/01 moved policy in dasd_format to dasdfmt (renamed BIODASDFORMAT) * 03/19/01 added BIODASDINFO-ioctl * removed 2.2 compatibility * 04/27/01 fixed PL030119COT (dasd_disciplines does not work) * 04/30/01 fixed PL030146HSM (module locking with dynamic ioctls) * fixed PL030130SBA (handling of invalid ranges) * 05/02/01 fixed PL030145SBA (killing dasdmt) * fixed PL030149SBA (status of 'accepted' devices) * fixed PL030146SBA (BUG in ibm.c after adding device) * added BIODASDPRRD ioctl interface * 05/11/01 fixed PL030164MVE (trap in probeonly mode) * 05/15/01 fixed devfs support for unformatted devices * 06/26/01 hopefully fixed PL030172SBA,PL030234SBA * 07/09/01 fixed PL030324MSH (wrong statistics output) * 07/16/01 merged in new fixes for handling low-mem situations * 01/22/01 fixed PL030579KBE (wrong statistics) * 08/07/03 fixed LTC BZ 3847 Erroneous message when formatting DASD */#include <linux/config.h>#include <linux/version.h>#include <linux/kmod.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/stddef.h>#include <linux/kernel.h>#include <linux/tqueue.h>#include <linux/timer.h>#include <linux/slab.h>#include <linux/genhd.h>#include <linux/hdreg.h>#include <linux/interrupt.h>#include <linux/ctype.h>#ifdef CONFIG_PROC_FS#include <linux/proc_fs.h>#endif /* CONFIG_PROC_FS */#include <linux/spinlock.h>#include <linux/devfs_fs_kernel.h>#include <linux/blkpg.h>#include <linux/wait.h>#include <asm/ccwcache.h>#include <asm/debug.h>#include <asm/atomic.h>#include <asm/delay.h>#include <asm/io.h>#include <asm/semaphore.h>#include <asm/ebcdic.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <asm/s390_ext.h>#include <asm/s390dyn.h>#include <asm/idals.h>#include "dasd_int.h"#ifdef CONFIG_DASD_ECKD#include "dasd_eckd.h"#endif /* CONFIG_DASD_ECKD */#ifdef CONFIG_DASD_FBA#include "dasd_fba.h"#endif /* CONFIG_DASD_FBA */#ifdef CONFIG_DASD_DIAG#include "dasd_diag.h"#endif /* CONFIG_DASD_DIAG *//******************************************************************************** * SECTION: exported variables of dasd.c ********************************************************************************/debug_info_t *dasd_debug_area;MODULE_AUTHOR ("Holger Smolinski <Holger.Smolinski@de.ibm.com>");MODULE_DESCRIPTION ("Linux on S/390 DASD device driver," " Copyright 2000 IBM Corporation");MODULE_SUPPORTED_DEVICE ("dasd");MODULE_PARM (dasd, "1-" __MODULE_STRING (256) "s");MODULE_PARM (dasd_disciplines, "1-" __MODULE_STRING (8) "s");#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2,4,12))MODULE_LICENSE ("GPL");#endifEXPORT_SYMBOL (dasd_chanq_enq_head);EXPORT_SYMBOL (dasd_debug_area);EXPORT_SYMBOL (dasd_chanq_enq);EXPORT_SYMBOL (dasd_chanq_deq);EXPORT_SYMBOL (dasd_discipline_add);EXPORT_SYMBOL (dasd_discipline_del);EXPORT_SYMBOL (dasd_start_IO);EXPORT_SYMBOL (dasd_term_IO);EXPORT_SYMBOL (dasd_schedule_bh);EXPORT_SYMBOL (dasd_schedule_bh_timed);EXPORT_SYMBOL (dasd_int_handler);EXPORT_SYMBOL (dasd_oper_handler);EXPORT_SYMBOL (dasd_alloc_request);EXPORT_SYMBOL (dasd_free_request);EXPORT_SYMBOL (dasd_ioctl_no_register);EXPORT_SYMBOL (dasd_ioctl_no_unregister);EXPORT_SYMBOL (dasd_default_erp_action);EXPORT_SYMBOL (dasd_default_erp_postaction);EXPORT_SYMBOL (dasd_sleep_on_req);EXPORT_SYMBOL (dasd_set_normalized_cda);EXPORT_SYMBOL (dasd_device_from_kdev);/******************************************************************************** * SECTION: Constant definitions to be used within this file ********************************************************************************/#define PRINTK_HEADER DASD_NAME":"#define DASD_PROFILE /* fill profile information - used for */ /* statistics and perfomance */#ifndef CONFIG_PROC_FS /* DASD_PROFILE doesn't make sense */#undef DASD_PROFILE /* without procfs */#endif /* not CONFIG_PROC_FS */#define DASD_CHANQ_MAX_SIZE 4/******************************************************************************** * SECTION: prototypes for static functions of dasd.c ********************************************************************************/static request_fn_proc do_dasd_request;static int dasd_set_device_level (unsigned int, dasd_discipline_t *, int);static request_queue_t *dasd_get_queue (kdev_t kdev);static void cleanup_dasd (void);static void dasd_plug_device (dasd_device_t * device);static int dasd_fillgeo (int kdev, struct hd_geometry *geo);static void dasd_enable_ranges (dasd_range_t *, dasd_discipline_t *, int); static void dasd_disable_ranges (dasd_range_t *, dasd_discipline_t *, int, int); static void dasd_enable_single_device ( unsigned long);static inline int dasd_state_init_to_ready(dasd_device_t*);static inline void dasd_setup_partitions ( dasd_device_t *);static inline void dasd_destroy_partitions ( dasd_device_t *);static inline int dasd_setup_blkdev(dasd_device_t*);static void dasd_deactivate_queue (dasd_device_t *);static inline int dasd_disable_blkdev(dasd_device_t*);static void dasd_flush_chanq ( dasd_device_t * device, int destroy ); static void dasd_flush_request_queues ( dasd_device_t * device, int destroy );static struct block_device_operations dasd_device_operations;static inline dasd_device_t ** dasd_device_from_devno (int);static void dasd_process_queues (dasd_device_t * device);static int dasd_sleep_on_immediate (ccw_req_t *cqr);static int dasd_devno_from_devindex (int devindex);static int dasd_devindex_from_devno (int devno);/******************************************************************************** * SECTION: static variables of dasd.c ********************************************************************************/static devfs_handle_t dasd_devfs_handle;static wait_queue_head_t dasd_init_waitq;static atomic_t dasd_init_pending = ATOMIC_INIT (0);#ifdef CONFIG_DASD_DYNAMIC/******************************************************************************** * SECTION: managing dynamic configuration of dasd_driver ********************************************************************************/static struct list_head dasd_devreg_head = LIST_HEAD_INIT (dasd_devreg_head);/* * function: dasd_create_devreg * creates a dasd_devreg_t related to a devno */static inline dasd_devreg_t *dasd_create_devreg (int devno){ dasd_devreg_t *r = kmalloc (sizeof (dasd_devreg_t), GFP_KERNEL); if (r != NULL) { memset (r, 0, sizeof (dasd_devreg_t)); r->devreg.ci.devno = devno; r->devreg.flag = DEVREG_TYPE_DEVNO; r->devreg.oper_func = dasd_oper_handler; } return r;}/* * function: dasd_destroy_devreg * destroys the dasd_devreg_t given as argument */static inline voiddasd_destroy_devreg (dasd_devreg_t * devreg){ kfree (devreg);}#endif /* CONFIG_DASD_DYNAMIC *//******************************************************************************** * SECTION: managing setup of dasd_driver ********************************************************************************//* default setting is probeonly, autodetect */static int dasd_probeonly = 0; /* is true, when probeonly mode is active */static int dasd_autodetect = 0; /* is true, when autodetection is active */static dasd_range_t dasd_range_head = { list:LIST_HEAD_INIT (dasd_range_head.list) };static spinlock_t range_lock = SPIN_LOCK_UNLOCKED;/* * function: dasd_create_range * creates a dasd_range_t according to the arguments * FIXME: no check is performed for reoccurrence of a devno */static inline dasd_range_t *dasd_create_range (int from, int to, int features){ dasd_range_t *range = NULL; range = (dasd_range_t *) kmalloc (sizeof (dasd_range_t), GFP_KERNEL); if (range == NULL) return NULL; memset (range, 0, sizeof (dasd_range_t)); range->from = from; range->to = to; range->features = features; return range;}/* * function dasd_destroy_range * destroy a range allocated wit dasd_crate_range * CAUTION: must not be callen in arunning sysztem, because it destroys * the mapping of DASDs */static inline voiddasd_destroy_range (dasd_range_t * range){ kfree (range);}/* * function: dasd_append_range * appends the range given as argument to the list anchored at dasd_range_head. */static inline voiddasd_append_range (dasd_range_t * range){ long flags; spin_lock_irqsave (&range_lock, flags); list_add_tail (&range->list, &dasd_range_head.list); spin_unlock_irqrestore (&range_lock, flags);}/* * function dasd_dechain_range * removes a range from the chain of ranges * CAUTION: must not be called in a running system because it destroys * the mapping of devices */static inline voiddasd_dechain_range (dasd_range_t * range){ unsigned long flags; spin_lock_irqsave (&range_lock, flags); list_del (&range->list); spin_unlock_irqrestore (&range_lock, flags);}/* * function: dasd_add_range * creates a dasd_range_t according to the arguments and * appends it to the list of ranges. * If a device in the range is already in an other range, we split the * range and add the subranges (no duplicate devices). * additionally a devreg_t is created and added to the list of devregs */static inline voiddasd_add_range (int from, int to, int features){ dasd_range_t *range; int start, end, index, i; if (from > to) { MESSAGE (KERN_DEBUG, "Adding device range %04x-%04x: " "range invalid, ignoring.", from, to); return; } /* loop over the given range, remove the already contained devices */ /* and add the remaining subranges */ for (start = index = from, end = -EINVAL; index <= to; index++) { if (dasd_devindex_from_devno(index) >= 0) { /* current device is already in range */ MESSAGE (KERN_DEBUG, "dasd_add_range %04x-%04x: " "device %04x is already in range", from, to, index); if (start == index) start++; /* first already in range */ else end = index -1; /* current already in range */ } else { if (index == to) end = to; /* end of original range reached */ } range = NULL; if (end != -EINVAL) { MESSAGE (KERN_DEBUG, "dasd_add_range %04x-%04x: " "add (sub)range %04x-%04x", from, to, start, end); range = dasd_create_range (start, end, features); end = -EINVAL; start = index + 1; } if (range) { dasd_append_range (range);#ifdef CONFIG_DASD_DYNAMIC /* allocate and chain devreg infos for the devnos... */ for (i = range->from; i <= range->to; i++) { dasd_devreg_t *reg = dasd_create_devreg (i); s390_device_register (®->devreg); list_add (®->list, &dasd_devreg_head); }#endif /* CONFIG_DASD_DYNAMIC */ } } return;}/* * function: dasd_remove_range * removes a range and the corresponding devregs from all of the chains * CAUTION: must not be called in a running system because it destroys * the mapping of devices! */static inline voiddasd_remove_range (dasd_range_t * range){#ifdef CONFIG_DASD_DYNAMIC /* deallocate and dechain devreg infos for the devnos... */ { int i; for (i = range->from; i <= range->to; i++) { struct list_head *l; dasd_devreg_t *reg = NULL; list_for_each (l, &dasd_devreg_head) { reg = list_entry (l, dasd_devreg_t, list); if (reg->devreg.flag == DEVREG_TYPE_DEVNO && reg->devreg.ci.devno == i && reg->devreg.oper_func == dasd_oper_handler) break; } if (l == &dasd_devreg_head) BUG (); list_del(®->list); s390_device_unregister (®->devreg); dasd_destroy_devreg (reg); } }#endif /* CONFIG_DASD_DYNAMIC */ dasd_dechain_range (range); dasd_destroy_range (range);}/* * function: dasd_devindex_from_devno * finds the logical number of the devno supplied as argument in the list * of dasd ranges and returns it or ENODEV when not found */static intdasd_devindex_from_devno (int devno){ dasd_range_t *temp; int devindex = 0; unsigned long flags; struct list_head *l; spin_lock_irqsave (&range_lock, flags); list_for_each (l, &dasd_range_head.list) { temp = list_entry (l, dasd_range_t, list); if (devno >= temp->from && devno <= temp->to) { spin_unlock_irqrestore (&range_lock, flags); return devindex + devno - temp->from; } devindex += temp->to - temp->from + 1; } spin_unlock_irqrestore (&range_lock, flags); return -ENODEV;}/* * function: dasd_devno_from_devindex */static intdasd_devno_from_devindex (int devindex){ dasd_range_t *temp; unsigned long flags; struct list_head *l;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?