📄 dasd.c
字号:
/* * 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 * * 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 */#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 <asm/dasd.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");EXPORT_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_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":"#undef DASD_PROFILE /* fill profile information - used for */ /* statistics and perfomance */#define DASD_MIN_SIZE_FOR_QUEUE 32#undef CONFIG_DYNAMIC_QUEUE_MIN_SIZE#define DASD_CHANQ_MAX_SIZE 6/* 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);/* 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 = 1; /* is true, when probeonly mode is active */static int dasd_autodetect = 1; /* 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; int i; if ( from > to ) { printk (KERN_WARNING PRINTK_HEADER "Adding device range %04x-%04x: range invalid, ignoring.\n", from, to); return NULL; } for (i=from;i<=to;i++) { if (dasd_device_from_devno(i)) { printk (KERN_WARNING PRINTK_HEADER "device range %04x-%04x: device %04x is already in a range.\n", from, to, i); } } 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 * additionally a devreg_t is created and added to the list of devregs */static inline dasd_range_t *dasd_add_range (int from, int to, int features){ dasd_range_t *range; range = dasd_create_range (from, to, features); if (!range) return NULL; dasd_append_range (range);#ifdef CONFIG_DASD_DYNAMIC /* allocate and chain devreg infos for the devnos... */ { int i; 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 range;}/* * 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; spin_lock_irqsave (&range_lock, flags); list_for_each (l, &dasd_range_head.list) { temp = list_entry (l, dasd_range_t, list); if ( devindex < temp->to - temp->from + 1) { spin_unlock_irqrestore (&range_lock, flags); return temp->from + devindex; } devindex -= temp->to - temp->from + 1; } spin_unlock_irqrestore (&range_lock, flags); return -ENODEV;}/* SECTION: parsing the dasd= parameter of the parmline/insmod cmdline *//* * char *dasd[] is intended to hold the ranges supplied by the dasd= statement * it is named 'dasd' to directly be filled by insmod with the comma separated * strings when running as a module. * a maximum of 256 ranges can be supplied, as the parmline is limited to * <1024 Byte anyway. */char *dasd[256];char *dasd_disciplines[8];#ifndef MODULE/* * function: dasd_split_parm_string * splits the parmline given to the kernel into comma separated strings * which are filled into the 'dasd[]' array, to be parsed later on */static voiddasd_split_parm_string (char *str){ char *tmp = str; int count = 0; while (tmp != NULL && *tmp != '\0') { char *end; int len; end = strchr (tmp, ','); if (end == NULL) { len = strlen (tmp) + 1; } else { len = (long) end - (long) tmp + 1; *end = '\0'; end++; } dasd[count] = kmalloc (len * sizeof (char), GFP_ATOMIC); if (dasd[count] == NULL) { printk (KERN_WARNING PRINTK_HEADER "can't store dasd= parameter no %d\n", count + 1); break; } memset (dasd[count], 0, len * sizeof (char)); memcpy (dasd[count], tmp, len * sizeof (char));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -