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

📄 sd.c

📁 linux和2410结合开发 用他可以生成2410所需的zImage文件
💻 C
📖 第 1 页 / 共 3 页
字号:
/* *      sd.c Copyright (C) 1992 Drew Eckhardt *           Copyright (C) 1993, 1994, 1995, 1999 Eric Youngdale * *      Linux scsi disk driver *              Initial versions: Drew Eckhardt *              Subsequent revisions: Eric Youngdale * *      <drew@colorado.edu> * *       Modified by Eric Youngdale ericy@andante.org to *       add scatter-gather, multiple outstanding request, and other *       enhancements. * *       Modified by Eric Youngdale eric@andante.org to support loadable *       low-level scsi drivers. * *       Modified by Jirka Hanika geo@ff.cuni.cz to support more *       scsi disks using eight major numbers. * *       Modified by Richard Gooch rgooch@atnf.csiro.au to support devfs. *	 *	 Modified by Torben Mathiasen tmm@image.dk *       Resource allocation fixes in sd_init and cleanups. *	 *	 Modified by Alex Davis <letmein@erols.com> *       Fix problem where partition info not being read in sd_open. *	 *	 Modified by Alex Davis <letmein@erols.com> *       Fix problem where removable media could be ejected after sd_open. */#include <linux/config.h>#include <linux/module.h>#include <linux/fs.h>#include <linux/kernel.h>#include <linux/sched.h>#include <linux/mm.h>#include <linux/string.h>#include <linux/hdreg.h>#include <linux/errno.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/smp.h>#include <asm/uaccess.h>#include <asm/system.h>#include <asm/io.h>#define MAJOR_NR SCSI_DISK0_MAJOR#include <linux/blk.h>#include <linux/blkpg.h>#include "scsi.h"#include "hosts.h"#include "sd.h"#include <scsi/scsi_ioctl.h>#include "constants.h"#include <scsi/scsicam.h>	/* must follow "hosts.h" */#include <linux/genhd.h>/* *  static const char RCSid[] = "$Header:"; */#define SD_MAJOR(i) (!(i) ? SCSI_DISK0_MAJOR : SCSI_DISK1_MAJOR-1+(i))#define SCSI_DISKS_PER_MAJOR	16#define SD_MAJOR_NUMBER(i)	SD_MAJOR((i) >> 8)#define SD_MINOR_NUMBER(i)	((i) & 255)#define MKDEV_SD_PARTITION(i)	MKDEV(SD_MAJOR_NUMBER(i), (i) & 255)#define MKDEV_SD(index)		MKDEV_SD_PARTITION((index) << 4)#define N_USED_SCSI_DISKS  (sd_template.dev_max + SCSI_DISKS_PER_MAJOR - 1)#define N_USED_SD_MAJORS   (N_USED_SCSI_DISKS / SCSI_DISKS_PER_MAJOR)#define MAX_RETRIES 5/* *  Time out in seconds for disks and Magneto-opticals (which are slower). */#define SD_TIMEOUT (30 * HZ)#define SD_MOD_TIMEOUT (75 * HZ)struct hd_struct *sd;static Scsi_Disk *rscsi_disks;static int *sd_sizes;static int *sd_blocksizes;static int *sd_hardsizes;	/* Hardware sector size */static int *sd_max_sectors;static int check_scsidisk_media_change(kdev_t);static int fop_revalidate_scsidisk(kdev_t);static int sd_init_onedisk(int);static int sd_init(void);static void sd_finish(void);static int sd_attach(Scsi_Device *);static int sd_detect(Scsi_Device *);static void sd_detach(Scsi_Device *);static int sd_init_command(Scsi_Cmnd *);static struct Scsi_Device_Template sd_template = {	name:"disk",	tag:"sd",	scsi_type:TYPE_DISK,	major:SCSI_DISK0_MAJOR,        /*         * Secondary range of majors that this driver handles.         */	min_major:SCSI_DISK1_MAJOR,	max_major:SCSI_DISK7_MAJOR,	blk:1,	detect:sd_detect,	init:sd_init,	finish:sd_finish,	attach:sd_attach,	detach:sd_detach,	init_command:sd_init_command,};static void rw_intr(Scsi_Cmnd * SCpnt);#if defined(CONFIG_PPC)/* * Moved from arch/ppc/pmac_setup.c.  This is where it really belongs. */kdev_t __initsd_find_target(void *host, int tgt){    Scsi_Disk *dp;    int i;    for (dp = rscsi_disks, i = 0; i < sd_template.dev_max; ++i, ++dp)        if (dp->device != NULL && dp->device->host == host            && dp->device->id == tgt)            return MKDEV_SD(i);    return 0;}#endifstatic int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg){	kdev_t dev = inode->i_rdev;	struct Scsi_Host * host;	Scsi_Device * SDev;	int diskinfo[4];    	SDev = rscsi_disks[DEVICE_NR(dev)].device;	if (!SDev)		return -ENODEV;	/*	 * If we are in the middle of error recovery, don't let anyone	 * else try and use this device.  Also, if error recovery fails, it	 * may try and take the device offline, in which case all further	 * access to the device is prohibited.	 */	if( !scsi_block_when_processing_errors(SDev) )	{		return -ENODEV;	}	switch (cmd) 	{		case HDIO_GETGEO:   /* Return BIOS disk parameters */		{			struct hd_geometry *loc = (struct hd_geometry *) arg;			if(!loc)				return -EINVAL;			host = rscsi_disks[DEVICE_NR(dev)].device->host;				/* default to most commonly used values */			        diskinfo[0] = 0x40;	        	diskinfo[1] = 0x20;	        	diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11;				/* override with calculated, extended default, or driver values */				if(host->hostt->bios_param != NULL)				host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)],					    dev,					    &diskinfo[0]);			else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)],					dev, &diskinfo[0]);			if (put_user(diskinfo[0], &loc->heads) ||				put_user(diskinfo[1], &loc->sectors) ||				put_user(diskinfo[2], &loc->cylinders) ||				put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start))				return -EFAULT;			return 0;		}		case HDIO_GETGEO_BIG:		{			struct hd_big_geometry *loc = (struct hd_big_geometry *) arg;			if(!loc)				return -EINVAL;			host = rscsi_disks[DEVICE_NR(dev)].device->host;			/* default to most commonly used values */			diskinfo[0] = 0x40;			diskinfo[1] = 0x20;			diskinfo[2] = rscsi_disks[DEVICE_NR(dev)].capacity >> 11;			/* override with calculated, extended default, or driver values */			if(host->hostt->bios_param != NULL)				host->hostt->bios_param(&rscsi_disks[DEVICE_NR(dev)],					    dev,					    &diskinfo[0]);			else scsicam_bios_param(&rscsi_disks[DEVICE_NR(dev)],					dev, &diskinfo[0]);			if (put_user(diskinfo[0], &loc->heads) ||				put_user(diskinfo[1], &loc->sectors) ||				put_user(diskinfo[2], (unsigned int *) &loc->cylinders) ||				put_user(sd[SD_PARTITION(inode->i_rdev)].start_sect, &loc->start))				return -EFAULT;			return 0;		}		case BLKGETSIZE:		case BLKGETSIZE64:		case BLKROSET:		case BLKROGET:		case BLKRASET:		case BLKRAGET:		case BLKFLSBUF:		case BLKSSZGET:		case BLKPG:		case BLKELVGET:		case BLKELVSET:		case BLKBSZGET:		case BLKBSZSET:			return blk_ioctl(inode->i_rdev, cmd, arg);		case BLKRRPART: /* Re-read partition tables */		        if (!capable(CAP_SYS_ADMIN))		                return -EACCES;			return revalidate_scsidisk(dev, 1);		default:			return scsi_ioctl(rscsi_disks[DEVICE_NR(dev)].device , cmd, (void *) arg);	}}static void sd_devname(unsigned int disknum, char *buffer){	if (disknum < 26)		sprintf(buffer, "sd%c", 'a' + disknum);	else {		unsigned int min1;		unsigned int min2;		/*		 * For larger numbers of disks, we need to go to a new		 * naming scheme.		 */		min1 = disknum / 26;		min2 = disknum % 26;		sprintf(buffer, "sd%c%c", 'a' + min1 - 1, 'a' + min2);	}}static request_queue_t *sd_find_queue(kdev_t dev){	Scsi_Disk *dpnt; 	int target; 	target = DEVICE_NR(dev);	dpnt = &rscsi_disks[target];	if (!dpnt)		return NULL;	/* No such device */	return &dpnt->device->request_queue;}static int sd_init_command(Scsi_Cmnd * SCpnt){	int dev, devm, block, this_count;	Scsi_Disk *dpnt;#if CONFIG_SCSI_LOGGING	char nbuff[6];#endif	devm = SD_PARTITION(SCpnt->request.rq_dev);	dev = DEVICE_NR(SCpnt->request.rq_dev);	block = SCpnt->request.sector;	this_count = SCpnt->request_bufflen >> 9;	SCSI_LOG_HLQUEUE(1, printk("Doing sd request, dev = %d, block = %d\n", devm, block));	dpnt = &rscsi_disks[dev];	if (devm >= (sd_template.dev_max << 4) ||	    !dpnt ||	    !dpnt->device->online || 	    block + SCpnt->request.nr_sectors > sd[devm].nr_sects) {		SCSI_LOG_HLQUEUE(2, printk("Finishing %ld sectors\n", SCpnt->request.nr_sectors));		SCSI_LOG_HLQUEUE(2, printk("Retry with 0x%p\n", SCpnt));		return 0;	}	block += sd[devm].start_sect;	if (dpnt->device->changed) {		/*		 * quietly refuse to do anything to a changed disc until the changed		 * bit has been reset		 */		/* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */		return 0;	}	SCSI_LOG_HLQUEUE(2, sd_devname(devm, nbuff));	SCSI_LOG_HLQUEUE(2, printk("%s : real dev = /dev/%d, block = %d\n",				   nbuff, dev, block));	/*	 * 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 (dpnt->device->sector_size == 1024) {		if ((block & 1) || (SCpnt->request.nr_sectors & 1)) {			printk("sd.c:Bad block number requested");			return 0;		} else {			block = block >> 1;			this_count = this_count >> 1;		}	}	if (dpnt->device->sector_size == 2048) {		if ((block & 3) || (SCpnt->request.nr_sectors & 3)) {			printk("sd.c:Bad block number requested");			return 0;		} else {			block = block >> 2;			this_count = this_count >> 2;		}	}	if (dpnt->device->sector_size == 4096) {		if ((block & 7) || (SCpnt->request.nr_sectors & 7)) {			printk("sd.c:Bad block number requested");			return 0;		} else {			block = block >> 3;			this_count = this_count >> 3;		}	}	switch (SCpnt->request.cmd) {	case WRITE:		if (!dpnt->device->writeable) {			return 0;		}		SCpnt->cmnd[0] = WRITE_6;		SCpnt->sc_data_direction = SCSI_DATA_WRITE;		break;	case READ:		SCpnt->cmnd[0] = READ_6;		SCpnt->sc_data_direction = SCSI_DATA_READ;		break;	default:		panic("Unknown sd command %d\n", SCpnt->request.cmd);	}	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n",				   nbuff,		   (SCpnt->request.cmd == WRITE) ? "writing" : "reading",				 this_count, SCpnt->request.nr_sectors));	SCpnt->cmnd[1] = (SCpnt->device->scsi_level <= SCSI_2) ?			 ((SCpnt->lun << 5) & 0xe0) : 0;	if (((this_count > 0xff) || (block > 0x1fffff)) || SCpnt->device->ten) {		if (this_count > 0xffff)			this_count = 0xffff;		SCpnt->cmnd[0] += READ_10 - READ_6;		SCpnt->cmnd[2] = (unsigned char) (block >> 24) & 0xff;		SCpnt->cmnd[3] = (unsigned char) (block >> 16) & 0xff;		SCpnt->cmnd[4] = (unsigned char) (block >> 8) & 0xff;		SCpnt->cmnd[5] = (unsigned char) block & 0xff;		SCpnt->cmnd[6] = SCpnt->cmnd[9] = 0;		SCpnt->cmnd[7] = (unsigned char) (this_count >> 8) & 0xff;		SCpnt->cmnd[8] = (unsigned char) this_count & 0xff;	} else {		if (this_count > 0xff)			this_count = 0xff;		SCpnt->cmnd[1] |= (unsigned char) ((block >> 16) & 0x1f);		SCpnt->cmnd[2] = (unsigned char) ((block >> 8) & 0xff);		SCpnt->cmnd[3] = (unsigned char) block & 0xff;		SCpnt->cmnd[4] = (unsigned char) this_count;		SCpnt->cmnd[5] = 0;	}	/*	 * We shouldn't disconnect in the middle of a sector, so with a dumb	 * host adapter, it's safe to assume that we can at least transfer	 * this many bytes between each connect / disconnect.	 */	SCpnt->transfersize = dpnt->device->sector_size;	SCpnt->underflow = this_count << 9;	SCpnt->allowed = MAX_RETRIES;	SCpnt->timeout_per_command = (SCpnt->device->type == TYPE_DISK ?				      SD_TIMEOUT : SD_MOD_TIMEOUT);	/*	 * This is the completion routine we use.  This is matched in terms	 * of capability to this function.	 */	SCpnt->done = rw_intr;	/*	 * This indicates that the command is ready from our end to be	 * queued.	 */	return 1;}static int sd_open(struct inode *inode, struct file *filp){	int target, retval = -ENXIO;	Scsi_Device * SDev;	target = DEVICE_NR(inode->i_rdev);	SCSI_LOG_HLQUEUE(1, printk("target=%d, max=%d\n", target, sd_template.dev_max));	if (target >= sd_template.dev_max || !rscsi_disks[target].device)		return -ENXIO;	/* No such device */	/*	 * If the device is in error recovery, wait until it is done.	 * If the device is offline, then disallow any access to it.	 */	if (!scsi_block_when_processing_errors(rscsi_disks[target].device)) {		return -ENXIO;	}	/*	 * Make sure that only one process can do a check_change_disk at one time.	 * This is also used to lock out further access when the partition table	 * is being re-read.	 */	while (rscsi_disks[target].device->busy) {		barrier();		cpu_relax();	}	/*	 * The following code can sleep.	 * Module unloading must be prevented	 */	SDev = rscsi_disks[target].device;	if (SDev->host->hostt->module)		__MOD_INC_USE_COUNT(SDev->host->hostt->module);	if (sd_template.module)		__MOD_INC_USE_COUNT(sd_template.module);	SDev->access_count++;	if (rscsi_disks[target].device->removable) {		SDev->allow_revalidate = 1;		check_disk_change(inode->i_rdev);		SDev->allow_revalidate = 0;

⌨️ 快捷键说明

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