⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dasd.c

📁 Linux内核源代码 为压缩文件 是<<Linux内核>>一书中的源代码
💻 C
📖 第 1 页 / 共 3 页
字号:
/*  * File...........: linux/drivers/s390/block/dasd.c * Author(s)......: Holger Smolinski <Holger.Smolinski@de.ibm.com> *                : Utz Bacher <utz.bacher@de.ibm.com> * Bugreports.to..: <Linux390@de.ibm.com> * (C) IBM Corporation, IBM Deutschland Entwicklung GmbH, 1999,2000 */#include <linux/config.h>#include <linux/init.h>#include <linux/stddef.h>#include <linux/kernel.h>#ifdef MODULE#include <linux/module.h>#endif				/* MODULE */#include <linux/tqueue.h>#include <linux/timer.h>#include <linux/malloc.h>#include <linux/genhd.h>#include <linux/devfs_fs_kernel.h>#include <linux/hdreg.h>#include <linux/interrupt.h>#include <linux/ctype.h>#include <asm/io.h>#include <asm/semaphore.h>#include <asm/ebcdic.h>#include <asm/uaccess.h>#include <asm/irq.h>#include <linux/dasd.h>#include <linux/blk.h>#include "dasd_erp.h"#include "dasd_types.h"#include "dasd_ccwstuff.h"#define PRINTK_HEADER DASD_NAME":"#define CCW_READ_DEVICE_CHARACTERISTICS  0x64#define DASD_SSCH_RETRIES 2/* This macro is a little tricky, but makes the code more easy to read... */#define MATCH(info,ct,cm,dt,dm) ( \(( info -> sid_data.cu_type  ct ) && ( info -> sid_data.cu_model cm )) && \(( info -> sid_data.dev_type dt ) && ( info -> sid_data.dev_model dm )) )/* Prototypes for the functions called from external */static int dasd_ioctl (struct inode *, struct file *, unsigned int, unsigned long);static int dasd_open (struct inode *, struct file *);static int dasd_release (struct inode *, struct file *);void dasd_debug (unsigned long tag);void dasd_profile_add (cqr_t *cqr);void dasd_proc_init (void);static int dasd_format( int, format_data_t * );static struct block_device_operations dasd_device_operations;spinlock_t dasd_lock;		/* general purpose lock for the dasd driver *//* All asynchronous I/O should waint on this wait_queue */wait_queue_head_t dasd_waitq;static int dasd_autodetect = 1;static int dasd_devno[DASD_MAX_DEVICES] ={0,};static int dasd_count = 0;extern dasd_chanq_t *cq_head;static intdasd_get_hexdigit (char c){	if ((c >= '0') && (c <= '9'))		return c - '0';	if ((c >= 'a') && (c <= 'f'))		return c + 10 - 'a';	if ((c >= 'A') && (c <= 'F'))		return c + 10 - 'A';	return -1;}/* sets the string pointer after the next comma */static voiddasd_scan_for_next_comma (char **strptr){	while (((**strptr) != ',') && ((**strptr)++))		(*strptr)++;	/* set the position AFTER the comma */	if (**strptr == ',')		(*strptr)++;}/*sets the string pointer after the next comma, if a parse error occured */static intdasd_get_next_int (char **strptr){	int j, i = -1;		/* for cosmetic reasons first -1, then 0 */	if (isxdigit (**strptr)) {		for (i = 0; isxdigit (**strptr);) {			i <<= 4;			j = dasd_get_hexdigit (**strptr);			if (j == -1) {				PRINT_ERR ("no integer: skipping range.\n");				dasd_scan_for_next_comma (strptr);				i = -1;				break;			}			i += j;			(*strptr)++;			if (i > 0xffff) {				PRINT_ERR (" value too big, skipping range.\n");				dasd_scan_for_next_comma (strptr);				i = -1;				break;			}		}	}	return i;}static inline intdevindex_from_devno (int devno){	int i;	for (i = 0; i < dasd_count; i++) {		if (dasd_devno[i] == devno)			return i;	}	if (dasd_autodetect) {		if (dasd_count < DASD_MAX_DEVICES) {			dasd_devno[dasd_count] = devno;			return dasd_count++;		}		return -EOVERFLOW;	}	return -ENODEV;}/* returns 1, if dasd_no is in the specified ranges, otherwise 0 */static inline intdasd_is_accessible (int devno){	return (devindex_from_devno (devno) >= 0);}/* dasd_insert_range skips ranges, if the start or the end is -1 */static voiddasd_insert_range (int start, int end){	int curr;	FUNCTION_ENTRY ("dasd_insert_range");	if (dasd_count >= DASD_MAX_DEVICES) {		PRINT_ERR (" too many devices specified, ignoring some.\n");		FUNCTION_EXIT ("dasd_insert_range");		return;	}	if ((start == -1) || (end == -1)) {		PRINT_ERR ("invalid format of parameter, skipping range\n");		FUNCTION_EXIT ("dasd_insert_range");		return;	}	if (end < start) {		PRINT_ERR (" ignoring range from %x to %x - start value " \			   "must be less than end value.\n", start, end);		FUNCTION_EXIT ("dasd_insert_range");		return;	}/* concurrent execution would be critical, but will not occur here */	for (curr = start; curr <= end; curr++) {		if (dasd_is_accessible (curr)) {			PRINT_WARN (" %x is already in list as device %d\n",				    curr, devindex_from_devno (curr));		}		dasd_devno[dasd_count] = curr;		dasd_count++;		if (dasd_count >= DASD_MAX_DEVICES) {			PRINT_ERR (" too many devices specified, ignoring some.\n");			break;		}	}	PRINT_INFO (" added dasd range from %x to %x.\n",		    start, dasd_devno[dasd_count - 1]);	FUNCTION_EXIT ("dasd_insert_range");}static int __initdasd_setup (char *str){	int devno, devno2;	FUNCTION_ENTRY ("dasd_setup");	dasd_autodetect = 0;	while (*str && *str != 1) {		if (!isxdigit (*str)) {			str++;	/* to avoid looping on two commas */			PRINT_ERR (" kernel parameter in invalid format.\n");			continue;		}		devno = dasd_get_next_int (&str);		/* range was skipped? -> scan for comma has been done */		if (devno == -1)			continue;		if (*str == ',') {			str++;			dasd_insert_range (devno, devno);			continue;		}		if (*str == '-') {			str++;			devno2 = dasd_get_next_int (&str);			if (devno2 == -1) {				PRINT_ERR (" invalid character in " \					   "kernel parameters.");			} else {				dasd_insert_range (devno, devno2);			}			dasd_scan_for_next_comma (&str);			continue;		}		if (*str == 0) {			dasd_insert_range (devno, devno);			break;		}		PRINT_ERR (" unexpected character in kernel parameter, " \			   "skipping range.\n");	}	FUNCTION_EXIT ("dasd_setup");        return 1;}__setup("dasd=", dasd_setup);dasd_information_t *dasd_info[DASD_MAX_DEVICES] = {NULL,};static struct hd_struct dd_hdstruct[DASD_MAX_DEVICES << PARTN_BITS];static int dasd_blks[256] = {0,};static int dasd_secsize[256] = {0,};static int dasd_blksize[256] = {0,};static int dasd_maxsecs[256] = {0,};struct gendisk dd_gendisk ={	MAJOR_NR,		/* Major number */	"dasd",			/* Major name */	PARTN_BITS,		/* Bits to shift to get real from partn */	1 << PARTN_BITS,	/* Number of partitions per real */	dd_hdstruct,		/* hd struct */	dasd_blks,		/* sizes in blocks */	DASD_MAX_DEVICES,	/* number */	NULL,			/* internal */	NULL			/* next */};static atomic_t bh_scheduled = ATOMIC_INIT (0);static inline voidschedule_bh (void (*func) (void)){	static struct tq_struct dasd_tq =	{0,};	/* Protect against rescheduling, when already running */	if (atomic_compare_and_swap (0, 1, &bh_scheduled))		return;	dasd_tq.routine = (void *) (void *) func;	queue_task (&dasd_tq, &tq_immediate);	mark_bh (IMMEDIATE_BH);	return;}voidsleep_done (struct semaphore *sem){	if (sem != NULL) {		up (sem);	}}voidsleep (int timeout){	struct semaphore sem;	struct timer_list timer;        init_MUTEX_LOCKED (&sem);	init_timer (&timer);	timer.data = (unsigned long) &sem;	timer.expires = jiffies + timeout;	timer.function = (void (*)(unsigned long)) sleep_done;	printk (KERN_DEBUG PRINTK_HEADER		"Sleeping for timer tics %d\n", timeout);	add_timer (&timer);	down (&sem);	del_timer (&timer);}#ifdef CONFIG_DASD_ECKDextern dasd_operations_t dasd_eckd_operations;#endif				/* CONFIG_DASD_ECKD */#ifdef CONFIG_DASD_MDSKextern dasd_operations_t dasd_mdsk_operations;#endif				/* CONFIG_DASD_MDSK */dasd_operations_t *dasd_disciplines[] ={#ifdef CONFIG_DASD_ECKD	&dasd_eckd_operations,#endif				/* CONFIG_DASD_ECKD */#ifdef CONFIG_DASD_MDSK	&dasd_mdsk_operations,#endif				/* CONFIG_DASD_MDSK */#ifdef CONFIG_DASD_CKD	&dasd_ckd_operations,#endif				/* CONFIG_DASD_CKD */        NULL};char *dasd_name[] ={#ifdef CONFIG_DASD_ECKD	"ECKD",#endif				/* CONFIG_DASD_ECKD */#ifdef CONFIG_DASD_MDSK	"MDSK",#endif				/* CONFIG_DASD_MDSK */#ifdef CONFIG_DASD_CKD        "CKD",#endif                          /* CONFIG_DASD_CKD */	"END"};static inline intdo_dasd_ioctl (struct inode *inp, unsigned int no, unsigned long data){	int rc;	int di;	dasd_information_t *dev;	di = DEVICE_NR (inp->i_rdev);	if (!dasd_info[di]) {		PRINT_WARN ("No device registered as %d\n", inp->i_rdev);		return -EINVAL;	}	if ((_IOC_DIR (no) != _IOC_NONE) && (data == 0)) {		PRINT_DEBUG ("empty data ptr");		return -EINVAL;	}	dev = dasd_info[di];	if (!dev) {		PRINT_WARN ("No device registered as %d\n", inp->i_rdev);		return -EINVAL;	}	PRINT_INFO ("ioctl 0x%08x %s'0x%x'%d(%d) on dev %d/%d (%d) with data %8lx\n", no,		    _IOC_DIR (no) == _IOC_NONE ? "0" :		    _IOC_DIR (no) == _IOC_READ ? "r" :		    _IOC_DIR (no) == _IOC_WRITE ? "w" :		    _IOC_DIR (no) == (_IOC_READ | _IOC_WRITE) ? "rw" : "u",		    _IOC_TYPE (no), _IOC_NR (no), _IOC_SIZE (no),		    MAJOR (inp->i_rdev), MINOR (inp->i_rdev), di, data);	switch (no) {	case BLKGETSIZE:{	/* Return device size */			unsigned long blocks;			if (inp->i_rdev & 0x01) {				blocks = (dev->sizes.blocks - 3) <<				    dev->sizes.s2b_shift;			} else {				blocks = dev->sizes.kbytes << dev->sizes.s2b_shift;			}			rc = copy_to_user ((long *) data, &blocks, sizeof (long));			break;		}	case BLKFLSBUF:{			rc = fsync_dev (inp->i_rdev);			break;		}	case BLKRAGET:{			rc = copy_to_user ((long *) data,					read_ahead + MAJOR_NR, sizeof (long));			break;		}	case BLKRASET:{			rc = copy_from_user (read_ahead + MAJOR_NR,					     (long *) data, sizeof (long));			break;		}	case BLKRRPART:{			INTERNAL_CHECK ("BLKRPART not implemented%s", "");			rc = -EINVAL;			break;		}	case HDIO_GETGEO:{			INTERNAL_CHECK ("HDIO_GETGEO not implemented%s", "");			rc = -EINVAL;			break;		}	case BIODASDRSID:{			rc = copy_to_user ((void *) data,					   &(dev->info.sid_data),					   sizeof (senseid_t));			break;		}	case BIODASDRWTB:{			int offset = 0;			int xlt;			rc = copy_from_user (&xlt, (void *) data,					     sizeof (int));                        PRINT_INFO("Xlating %d to",xlt);			if (rc)				break;			if (MINOR (inp->i_rdev) & 1)				offset = 3;			xlt += offset;                        printk(" %d \n",xlt);			rc = copy_to_user ((void *) data, &xlt,					   sizeof (int));			break;		}	case BIODASDFORMAT:{			/* fdata == NULL is a valid arg to dasd_format ! */			format_data_t *fdata = NULL;			if (data) {				fdata = kmalloc (sizeof (format_data_t),						 GFP_ATOMIC);				if (!fdata) {					rc = -ENOMEM;					break;				}				rc = copy_from_user (fdata, (void *) data,						     sizeof (format_data_t));				if (rc)					break;			}			rc = dasd_format (inp->i_rdev, fdata);			if (fdata) {				kfree (fdata);			}			break;		}	default:		rc = -EINVAL;		break;	}	return rc;}static voiddasd_end_request (struct request *req, int uptodate){	struct buffer_head *bh;	FUNCTION_ENTRY ("dasd_end_request");#if DASD_PARANOIA > 2	if (!req) {		INTERNAL_CHECK ("end_request called with zero arg%s\n", "");	}#endif				/* DASD_PARANOIA */	while ((bh = req->bh) != NULL) {		req->bh = bh->b_reqnext;		bh->b_reqnext = NULL;		bh->b_end_io (bh, uptodate);	}	if (!end_that_request_first (req, uptodate, DEVICE_NAME)) {#ifndef DEVICE_NO_RANDOM		add_blkdev_randomness (MAJOR (req->rq_dev));#endif		DEVICE_OFF (req->rq_dev);		end_that_request_last (req);	}	FUNCTION_EXIT ("dasd_end_request");	return;}voiddasd_wakeup (void){	wake_up (&dasd_waitq);}intdasd_unregister_dasd (int irq, dasd_type_t dt, dev_info_t * info){	int rc = 0;	FUNCTION_ENTRY ("dasd_unregister_dasd");	INTERNAL_CHECK ("dasd_unregister_dasd not implemented%s\n", "");	FUNCTION_EXIT ("dasd_unregister_dasd");	return rc;}/* Below you find the functions already cleaned up */static dasd_type_tcheck_type (dev_info_t * info){	dasd_type_t type = dasd_none;	FUNCTION_ENTRY ("check_type");#ifdef CONFIG_DASD_ECKD	if (MATCH (info, == 0x3990, ||1, == 0x3390, ||1) ||	    MATCH (info, == 0x9343, ||1, == 0x9345, ||1) ||	    MATCH (info, == 0x3990, ||1, == 0x3380, ||1)) {		type = dasd_eckd;	} else#endif				/* CONFIG_DASD_ECKD */#ifdef CONFIG_DASD_MDSK        if ( MACHINE_IS_VM ) {          type = dasd_mdsk;        } else #endif 		/* CONFIG_DASD_MDSK */        {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -