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

📄 sd.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 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 *	Modification history: *       - Drew Eckhardt <drew@colorado.edu> original *       - Eric Youngdale <eric@andante.org> add scatter-gather, multiple  *         outstanding request, and other enhancements. *         Support loadable low-level scsi drivers. *       - Jirka Hanika <geo@ff.cuni.cz> support more scsi disks using  *         eight major numbers. *       - Richard Gooch <rgooch@atnf.csiro.au> support devfs. *	 - Torben Mathiasen <tmm@image.dk> Resource allocation fixes in  *	   sd_init and cleanups. *	 - Alex Davis <letmein@erols.com> Fix problem where partition info *	   not being read in sd_open. Fix problem where removable media  *	   could be ejected after sd_open. *	 - Douglas Gilbert <dgilbert@interlog.com> cleanup for lk 2.5.x *	 - Badari Pulavarty <pbadari@us.ibm.com>, Matthew Wilcox  *	   <willy@debian.org>, Kurt Garloff <garloff@suse.de>:  *	   Support 32k/1M disks. * *	Logging policy (needs CONFIG_SCSI_LOGGING defined): *	 - setting up transfer: SCSI_LOG_HLQUEUE levels 1 and 2 *	 - end of transfer (bh + scsi_lib): SCSI_LOG_HLCOMPLETE level 1 *	 - entering sd_ioctl: SCSI_LOG_IOCTL level 1 *	 - entering other commands: SCSI_LOG_HLQUEUE level 3 *	Note: when the logging level is set by the user, it must be greater *	than the level indicated above to trigger output.	 */#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/bio.h>#include <linux/genhd.h>#include <linux/hdreg.h>#include <linux/errno.h>#include <linux/idr.h>#include <linux/interrupt.h>#include <linux/init.h>#include <linux/blkdev.h>#include <linux/blkpg.h>#include <linux/kref.h>#include <asm/uaccess.h>#include <scsi/scsi.h>#include <scsi/scsi_cmnd.h>#include <scsi/scsi_dbg.h>#include <scsi/scsi_device.h>#include <scsi/scsi_driver.h>#include <scsi/scsi_eh.h>#include <scsi/scsi_host.h>#include <scsi/scsi_ioctl.h>#include <scsi/scsi_request.h>#include <scsi/scsicam.h>#include "scsi_logging.h"/* * More than enough for everybody ;)  The huge number of majors * is a leftover from 16bit dev_t days, we don't really need that * much numberspace. */#define SD_MAJORS	16/* * This is limited by the naming scheme enforced in sd_probe, * add another character to it if you really need more disks. */#define SD_MAX_DISKS	(((26 * 26) + 26 + 1) * 26)/* * Time out in seconds for disks and Magneto-opticals (which are slower). */#define SD_TIMEOUT		(30 * HZ)#define SD_MOD_TIMEOUT		(75 * HZ)/* * Number of allowed retries */#define SD_MAX_RETRIES		5static void scsi_disk_release(struct kref *kref);struct scsi_disk {	struct scsi_driver *driver;	/* always &sd_template */	struct scsi_device *device;	struct kref	kref;	struct gendisk	*disk;	unsigned int	openers;	/* protected by BKL for now, yuck */	sector_t	capacity;	/* size in 512-byte sectors */	u32		index;	u8		media_present;	u8		write_prot;	unsigned	WCE : 1;	/* state of disk WCE bit */	unsigned	RCD : 1;	/* state of disk RCD bit, unused */};static DEFINE_IDR(sd_index_idr);static spinlock_t sd_index_lock = SPIN_LOCK_UNLOCKED;/* This semaphore is used to mediate the 0->1 reference get in the * face of object destruction (i.e. we can't allow a get on an * object after last put) */static DECLARE_MUTEX(sd_ref_sem);static int sd_revalidate_disk(struct gendisk *disk);static void sd_rw_intr(struct scsi_cmnd * SCpnt);static int sd_probe(struct device *);static int sd_remove(struct device *);static void sd_shutdown(struct device *dev);static void sd_rescan(struct device *);static int sd_init_command(struct scsi_cmnd *);static int sd_issue_flush(struct device *, sector_t *);static void sd_read_capacity(struct scsi_disk *sdkp, char *diskname,		 struct scsi_request *SRpnt, unsigned char *buffer);static struct scsi_driver sd_template = {	.owner			= THIS_MODULE,	.gendrv = {		.name		= "sd",		.probe		= sd_probe,		.remove		= sd_remove,		.shutdown	= sd_shutdown,	},	.rescan			= sd_rescan,	.init_command		= sd_init_command,	.issue_flush		= sd_issue_flush,};/* * Device no to disk mapping: *  *       major         disc2     disc  p1 *   |............|.............|....|....| <- dev_t *    31        20 19          8 7  4 3  0 *  * Inside a major, we have 16k disks, however mapped non- * contiguously. The first 16 disks are for major0, the next * ones with major1, ... Disk 256 is for major0 again, disk 272  * for major1, ...  * As we stay compatible with our numbering scheme, we can reuse  * the well-know SCSI majors 8, 65--71, 136--143. */static int sd_major(int major_idx){	switch (major_idx) {	case 0:		return SCSI_DISK0_MAJOR;	case 1 ... 7:		return SCSI_DISK1_MAJOR + major_idx - 1;	case 8 ... 15:		return SCSI_DISK8_MAJOR + major_idx - 8;	default:		BUG();		return 0;	/* shut up gcc */	}}#define to_scsi_disk(obj) container_of(obj,struct scsi_disk,kref)static inline struct scsi_disk *scsi_disk(struct gendisk *disk){	return container_of(disk->private_data, struct scsi_disk, driver);}static struct scsi_disk *scsi_disk_get(struct gendisk *disk){	struct scsi_disk *sdkp = NULL;	down(&sd_ref_sem);	if (disk->private_data == NULL)		goto out;	sdkp = scsi_disk(disk);	kref_get(&sdkp->kref);	if (scsi_device_get(sdkp->device))		goto out_put;	up(&sd_ref_sem);	return sdkp; out_put:	kref_put(&sdkp->kref, scsi_disk_release);	sdkp = NULL; out:	up(&sd_ref_sem);	return sdkp;}static void scsi_disk_put(struct scsi_disk *sdkp){	down(&sd_ref_sem);	scsi_device_put(sdkp->device);	kref_put(&sdkp->kref, scsi_disk_release);	up(&sd_ref_sem);}/** *	sd_init_command - build a scsi (read or write) command from *	information in the request structure. *	@SCpnt: pointer to mid-level's per scsi command structure that *	contains request and into which the scsi command is written * *	Returns 1 if successful and 0 if error (or cannot be done now). **/static int sd_init_command(struct scsi_cmnd * SCpnt){	unsigned int this_count, timeout;	struct gendisk *disk;	sector_t block;	struct scsi_device *sdp = SCpnt->device;	timeout = sdp->timeout;	/*	 * these are already setup, just copy cdb basically	 */	if (SCpnt->request->flags & REQ_BLOCK_PC) {		struct request *rq = SCpnt->request;		if (sizeof(rq->cmd) > sizeof(SCpnt->cmnd))			return 0;		memcpy(SCpnt->cmnd, rq->cmd, sizeof(SCpnt->cmnd));		if (rq_data_dir(rq) == WRITE)			SCpnt->sc_data_direction = DMA_TO_DEVICE;		else if (rq->data_len)			SCpnt->sc_data_direction = DMA_FROM_DEVICE;		else			SCpnt->sc_data_direction = DMA_NONE;		this_count = rq->data_len;		if (rq->timeout)			timeout = rq->timeout;		SCpnt->transfersize = rq->data_len;		goto queue;	}	/*	 * we only do REQ_CMD and REQ_BLOCK_PC	 */	if (!(SCpnt->request->flags & REQ_CMD))		return 0;	disk = SCpnt->request->rq_disk;	block = SCpnt->request->sector;	this_count = SCpnt->request_bufflen >> 9;	SCSI_LOG_HLQUEUE(1, printk("sd_init_command: disk=%s, block=%llu, "			    "count=%d\n", disk->disk_name, (unsigned long long)block, this_count));	if (!sdp || !scsi_device_online(sdp) || 	    block + SCpnt->request->nr_sectors > get_capacity(disk)) {		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;	}	if (sdp->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, printk("%s : block=%llu\n",				   disk->disk_name, (unsigned long long)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 (sdp->sector_size == 1024) {		if ((block & 1) || (SCpnt->request->nr_sectors & 1)) {			printk(KERN_ERR "sd: Bad block number requested");			return 0;		} else {			block = block >> 1;			this_count = this_count >> 1;		}	}	if (sdp->sector_size == 2048) {		if ((block & 3) || (SCpnt->request->nr_sectors & 3)) {			printk(KERN_ERR "sd: Bad block number requested");			return 0;		} else {			block = block >> 2;			this_count = this_count >> 2;		}	}	if (sdp->sector_size == 4096) {		if ((block & 7) || (SCpnt->request->nr_sectors & 7)) {			printk(KERN_ERR "sd: Bad block number requested");			return 0;		} else {			block = block >> 3;			this_count = this_count >> 3;		}	}	if (rq_data_dir(SCpnt->request) == WRITE) {		if (!sdp->writeable) {			return 0;		}		SCpnt->cmnd[0] = WRITE_6;		SCpnt->sc_data_direction = DMA_TO_DEVICE;	} else if (rq_data_dir(SCpnt->request) == READ) {		SCpnt->cmnd[0] = READ_6;		SCpnt->sc_data_direction = DMA_FROM_DEVICE;	} else {		printk(KERN_ERR "sd: Unknown command %lx\n", 		       SCpnt->request->flags);/* overkill 	panic("Unknown sd command %lx\n", SCpnt->request->flags); */		return 0;	}	SCSI_LOG_HLQUEUE(2, printk("%s : %s %d/%ld 512 byte blocks.\n", 		disk->disk_name, (rq_data_dir(SCpnt->request) == WRITE) ? 		"writing" : "reading", this_count, SCpnt->request->nr_sectors));	SCpnt->cmnd[1] = 0;		if (block > 0xffffffff) {		SCpnt->cmnd[0] += READ_16 - READ_6;		SCpnt->cmnd[2] = sizeof(block) > 4 ? (unsigned char) (block >> 56) & 0xff : 0;		SCpnt->cmnd[3] = sizeof(block) > 4 ? (unsigned char) (block >> 48) & 0xff : 0;		SCpnt->cmnd[4] = sizeof(block) > 4 ? (unsigned char) (block >> 40) & 0xff : 0;		SCpnt->cmnd[5] = sizeof(block) > 4 ? (unsigned char) (block >> 32) & 0xff : 0;		SCpnt->cmnd[6] = (unsigned char) (block >> 24) & 0xff;		SCpnt->cmnd[7] = (unsigned char) (block >> 16) & 0xff;		SCpnt->cmnd[8] = (unsigned char) (block >> 8) & 0xff;		SCpnt->cmnd[9] = (unsigned char) block & 0xff;		SCpnt->cmnd[10] = (unsigned char) (this_count >> 24) & 0xff;		SCpnt->cmnd[11] = (unsigned char) (this_count >> 16) & 0xff;		SCpnt->cmnd[12] = (unsigned char) (this_count >> 8) & 0xff;		SCpnt->cmnd[13] = (unsigned char) this_count & 0xff;		SCpnt->cmnd[14] = SCpnt->cmnd[15] = 0;	} else if ((this_count > 0xff) || (block > 0x1fffff) ||		   SCpnt->device->use_10_for_rw) {		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;	}	SCpnt->request_bufflen = SCpnt->bufflen =			this_count * sdp->sector_size;	/*	 * 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 = sdp->sector_size;	SCpnt->underflow = this_count << 9;queue:	SCpnt->allowed = SD_MAX_RETRIES;	SCpnt->timeout_per_command = timeout;	/*	 * This is the completion routine we use.  This is matched in terms	 * of capability to this function.	 */	SCpnt->done = sd_rw_intr;	/*	 * This indicates that the command is ready from our end to be	 * queued.	 */	return 1;}/** *	sd_open - open a scsi disk device *	@inode: only i_rdev member may be used *	@filp: only f_mode and f_flags may be used * *	Returns 0 if successful. Returns a negated errno value in case  *	of error. * *	Note: This can be called from a user context (e.g. fsck(1) ) *	or from within the kernel (e.g. as a result of a mount(1) ). *	In the latter case @inode and @filp carry an abridged amount *	of information as noted above. **/static int sd_open(struct inode *inode, struct file *filp){	struct gendisk *disk = inode->i_bdev->bd_disk;	struct scsi_disk *sdkp;	struct scsi_device *sdev;	int retval;	if (!(sdkp = scsi_disk_get(disk)))		return -ENXIO;	SCSI_LOG_HLQUEUE(3, printk("sd_open: disk=%s\n", disk->disk_name));	sdev = sdkp->device;	/*	 * If the device is in error recovery, wait until it is done.	 * If the device is offline, then disallow any access to it.	 */	retval = -ENXIO;	if (!scsi_block_when_processing_errors(sdev))		goto error_out;	if (sdev->removable || sdkp->write_prot)		check_disk_change(inode->i_bdev);	/*	 * If the drive is empty, just let the open fail.	 */	retval = -ENOMEDIUM;	if (sdev->removable && !sdkp->media_present &&	    !(filp->f_flags & O_NDELAY))		goto error_out;	/*	 * If the device has the write protect tab set, have the open fail	 * if the user expects to be able to write to the thing.	 */	retval = -EROFS;	if (sdkp->write_prot && (filp->f_mode & FMODE_WRITE))		goto error_out;	/*	 * It is possible that the disk changing stuff resulted in	 * the device being taken offline.  If this is the case,	 * report this to the user, and don't pretend that the	 * open actually succeeded.	 */	retval = -ENXIO;	if (!scsi_device_online(sdev))		goto error_out;	if (!sdkp->openers++ && sdev->removable) {		if (scsi_block_when_processing_errors(sdev))			scsi_set_medium_removal(sdev, SCSI_REMOVAL_PREVENT);	}	return 0;error_out:	scsi_disk_put(sdkp);	return retval;	}/** *	sd_release - invoked when the (last) close(2) is called on this *	scsi disk. *	@inode: only i_rdev member may be used *	@filp: only f_mode and f_flags may be used * *	Returns 0.  * *	Note: may block (uninterruptible) if error recovery is underway *	on this disk. **/static int sd_release(struct inode *inode, struct file *filp){	struct gendisk *disk = inode->i_bdev->bd_disk;	struct scsi_disk *sdkp = scsi_disk(disk);	struct scsi_device *sdev = sdkp->device;	SCSI_LOG_HLQUEUE(3, printk("sd_release: disk=%s\n", disk->disk_name));	if (!--sdkp->openers && sdev->removable) {		if (scsi_block_when_processing_errors(sdev))			scsi_set_medium_removal(sdev, SCSI_REMOVAL_ALLOW);	}	/*	 * XXX and what if there are packets in flight and this close()	 * XXX is followed by a "rmmod sd_mod"?	 */	scsi_disk_put(sdkp);	return 0;}static int sd_hdio_getgeo(struct block_device *bdev, struct hd_geometry __user *loc){	struct scsi_disk *sdkp = scsi_disk(bdev->bd_disk);	struct scsi_device *sdp = sdkp->device;	struct Scsi_Host *host = sdp->host;	int diskinfo[4];	/* default to most commonly used values */        diskinfo[0] = 0x40;	/* 1 << 6 */       	diskinfo[1] = 0x20;	/* 1 << 5 */       	diskinfo[2] = sdkp->capacity >> 11;		/* override with calculated, extended default, or driver values */	if (host->hostt->bios_param)		host->hostt->bios_param(sdp, bdev, sdkp->capacity, diskinfo);	else		scsicam_bios_param(bdev, sdkp->capacity, diskinfo);	if (put_user(diskinfo[0], &loc->heads))		return -EFAULT;	if (put_user(diskinfo[1], &loc->sectors))		return -EFAULT;	if (put_user(diskinfo[2], &loc->cylinders))		return -EFAULT;	if (put_user((unsigned)get_start_sect(bdev),

⌨️ 快捷键说明

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