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

📄 sd.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
/* *      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/module.h>#include <linux/fs.h>#include <linux/kernel.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/delay.h>#include <linux/mutex.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/scsicam.h>#include <scsi/sd.h>#include "scsi_logging.h"MODULE_AUTHOR("Eric Youngdale");MODULE_DESCRIPTION("SCSI disk (sd) driver");MODULE_LICENSE("GPL");MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK0_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK1_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK2_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK3_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK4_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK5_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK6_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK7_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK8_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK9_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK10_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK11_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK12_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK13_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK14_MAJOR);MODULE_ALIAS_BLOCKDEV_MAJOR(SCSI_DISK15_MAJOR);MODULE_ALIAS_SCSI_DEVICE(TYPE_DISK);MODULE_ALIAS_SCSI_DEVICE(TYPE_MOD);MODULE_ALIAS_SCSI_DEVICE(TYPE_RBC);static int  sd_revalidate_disk(struct gendisk *);static int  sd_probe(struct device *);static int  sd_remove(struct device *);static void sd_shutdown(struct device *);static int sd_suspend(struct device *, pm_message_t state);static int sd_resume(struct device *);static void sd_rescan(struct device *);static int sd_done(struct scsi_cmnd *);static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);static void scsi_disk_release(struct class_device *cdev);static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);static void sd_print_result(struct scsi_disk *, int);static DEFINE_IDR(sd_index_idr);static DEFINE_SPINLOCK(sd_index_lock);/* 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 DEFINE_MUTEX(sd_ref_mutex);static const char *sd_cache_types[] = {	"write through", "none", "write back",	"write back, no read (daft)"};static ssize_t sd_store_cache_type(struct class_device *cdev, const char *buf,				   size_t count){	int i, ct = -1, rcd, wce, sp;	struct scsi_disk *sdkp = to_scsi_disk(cdev);	struct scsi_device *sdp = sdkp->device;	char buffer[64];	char *buffer_data;	struct scsi_mode_data data;	struct scsi_sense_hdr sshdr;	int len;	if (sdp->type != TYPE_DISK)		/* no cache control on RBC devices; theoretically they		 * can do it, but there's probably so many exceptions		 * it's not worth the risk */		return -EINVAL;	for (i = 0; i < ARRAY_SIZE(sd_cache_types); i++) {		const int len = strlen(sd_cache_types[i]);		if (strncmp(sd_cache_types[i], buf, len) == 0 &&		    buf[len] == '\n') {			ct = i;			break;		}	}	if (ct < 0)		return -EINVAL;	rcd = ct & 0x01 ? 1 : 0;	wce = ct & 0x02 ? 1 : 0;	if (scsi_mode_sense(sdp, 0x08, 8, buffer, sizeof(buffer), SD_TIMEOUT,			    SD_MAX_RETRIES, &data, NULL))		return -EINVAL;	len = min_t(size_t, sizeof(buffer), data.length - data.header_length -		  data.block_descriptor_length);	buffer_data = buffer + data.header_length +		data.block_descriptor_length;	buffer_data[2] &= ~0x05;	buffer_data[2] |= wce << 2 | rcd;	sp = buffer_data[0] & 0x80 ? 1 : 0;	if (scsi_mode_select(sdp, 1, sp, 8, buffer_data, len, SD_TIMEOUT,			     SD_MAX_RETRIES, &data, &sshdr)) {		if (scsi_sense_valid(&sshdr))			sd_print_sense_hdr(sdkp, &sshdr);		return -EINVAL;	}	sd_revalidate_disk(sdkp->disk);	return count;}static ssize_t sd_store_manage_start_stop(struct class_device *cdev,					  const char *buf, size_t count){	struct scsi_disk *sdkp = to_scsi_disk(cdev);	struct scsi_device *sdp = sdkp->device;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	sdp->manage_start_stop = simple_strtoul(buf, NULL, 10);	return count;}static ssize_t sd_store_allow_restart(struct class_device *cdev, const char *buf,				      size_t count){	struct scsi_disk *sdkp = to_scsi_disk(cdev);	struct scsi_device *sdp = sdkp->device;	if (!capable(CAP_SYS_ADMIN))		return -EACCES;	if (sdp->type != TYPE_DISK)		return -EINVAL;	sdp->allow_restart = simple_strtoul(buf, NULL, 10);	return count;}static ssize_t sd_show_cache_type(struct class_device *cdev, char *buf){	struct scsi_disk *sdkp = to_scsi_disk(cdev);	int ct = sdkp->RCD + 2*sdkp->WCE;	return snprintf(buf, 40, "%s\n", sd_cache_types[ct]);}static ssize_t sd_show_fua(struct class_device *cdev, char *buf){	struct scsi_disk *sdkp = to_scsi_disk(cdev);	return snprintf(buf, 20, "%u\n", sdkp->DPOFUA);}static ssize_t sd_show_manage_start_stop(struct class_device *cdev, char *buf){	struct scsi_disk *sdkp = to_scsi_disk(cdev);	struct scsi_device *sdp = sdkp->device;	return snprintf(buf, 20, "%u\n", sdp->manage_start_stop);}static ssize_t sd_show_allow_restart(struct class_device *cdev, char *buf){	struct scsi_disk *sdkp = to_scsi_disk(cdev);	return snprintf(buf, 40, "%d\n", sdkp->device->allow_restart);}static struct class_device_attribute sd_disk_attrs[] = {	__ATTR(cache_type, S_IRUGO|S_IWUSR, sd_show_cache_type,	       sd_store_cache_type),	__ATTR(FUA, S_IRUGO, sd_show_fua, NULL),	__ATTR(allow_restart, S_IRUGO|S_IWUSR, sd_show_allow_restart,	       sd_store_allow_restart),	__ATTR(manage_start_stop, S_IRUGO|S_IWUSR, sd_show_manage_start_stop,	       sd_store_manage_start_stop),	__ATTR_NULL,};static struct class sd_disk_class = {	.name		= "scsi_disk",	.owner		= THIS_MODULE,	.release	= scsi_disk_release,	.class_dev_attrs = sd_disk_attrs,};static struct scsi_driver sd_template = {	.owner			= THIS_MODULE,	.gendrv = {		.name		= "sd",		.probe		= sd_probe,		.remove		= sd_remove,		.suspend	= sd_suspend,		.resume		= sd_resume,		.shutdown	= sd_shutdown,	},	.rescan			= sd_rescan,	.done			= sd_done,};/* * 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 */	}}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;	if (disk->private_data) {		sdkp = scsi_disk(disk);		if (scsi_device_get(sdkp->device) == 0)			class_device_get(&sdkp->cdev);		else			sdkp = NULL;	}	return sdkp;}static struct scsi_disk *scsi_disk_get(struct gendisk *disk){	struct scsi_disk *sdkp;	mutex_lock(&sd_ref_mutex);	sdkp = __scsi_disk_get(disk);	mutex_unlock(&sd_ref_mutex);	return sdkp;}static struct scsi_disk *scsi_disk_get_from_dev(struct device *dev){	struct scsi_disk *sdkp;	mutex_lock(&sd_ref_mutex);	sdkp = dev_get_drvdata(dev);	if (sdkp)		sdkp = __scsi_disk_get(sdkp->disk);	mutex_unlock(&sd_ref_mutex);	return sdkp;}static void scsi_disk_put(struct scsi_disk *sdkp){	struct scsi_device *sdev = sdkp->device;	mutex_lock(&sd_ref_mutex);	class_device_put(&sdkp->cdev);	scsi_device_put(sdev);	mutex_unlock(&sd_ref_mutex);}/** *	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_prep_fn(struct request_queue *q, struct request *rq){	struct scsi_cmnd *SCpnt;	struct scsi_device *sdp = q->queuedata;	struct gendisk *disk = rq->rq_disk;	sector_t block = rq->sector;	unsigned int this_count = rq->nr_sectors;	unsigned int timeout = sdp->timeout;	int ret;	if (rq->cmd_type == REQ_TYPE_BLOCK_PC) {		ret = scsi_setup_blk_pc_cmnd(sdp, rq);		goto out;	} else if (rq->cmd_type != REQ_TYPE_FS) {		ret = BLKPREP_KILL;		goto out;	}	ret = scsi_setup_fs_cmnd(sdp, rq);	if (ret != BLKPREP_OK)		goto out;	SCpnt = rq->special;	/* from here on until we're complete, any goto out	 * is used for a killable error condition */	ret = BLKPREP_KILL;	SCSI_LOG_HLQUEUE(1, scmd_printk(KERN_INFO, SCpnt,					"sd_init_command: block=%llu, "					"count=%d\n",					(unsigned long long)block,					this_count));	if (!sdp || !scsi_device_online(sdp) || 	    block + rq->nr_sectors > get_capacity(disk)) {		SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,						"Finishing %ld sectors\n",						rq->nr_sectors));		SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,						"Retry with 0x%p\n", SCpnt));		goto out;	}	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"); */		goto out;	}	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt, "block=%llu\n",					(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) || (rq->nr_sectors & 1)) {			scmd_printk(KERN_ERR, SCpnt,				    "Bad block number requested\n");			goto out;		} else {			block = block >> 1;			this_count = this_count >> 1;		}	}	if (sdp->sector_size == 2048) {		if ((block & 3) || (rq->nr_sectors & 3)) {			scmd_printk(KERN_ERR, SCpnt,				    "Bad block number requested\n");			goto out;		} else {			block = block >> 2;			this_count = this_count >> 2;		}	}	if (sdp->sector_size == 4096) {		if ((block & 7) || (rq->nr_sectors & 7)) {			scmd_printk(KERN_ERR, SCpnt,				    "Bad block number requested\n");			goto out;		} else {			block = block >> 3;			this_count = this_count >> 3;		}	}	if (rq_data_dir(rq) == WRITE) {		if (!sdp->writeable) {			goto out;		}		SCpnt->cmnd[0] = WRITE_6;		SCpnt->sc_data_direction = DMA_TO_DEVICE;	} else if (rq_data_dir(rq) == READ) {		SCpnt->cmnd[0] = READ_6;		SCpnt->sc_data_direction = DMA_FROM_DEVICE;	} else {		scmd_printk(KERN_ERR, SCpnt, "Unknown command %x\n", rq->cmd_flags);		goto out;	}	SCSI_LOG_HLQUEUE(2, scmd_printk(KERN_INFO, SCpnt,					"%s %d/%ld 512 byte blocks.\n",					(rq_data_dir(rq) == WRITE) ?					"writing" : "reading", this_count,					rq->nr_sectors));	SCpnt->cmnd[1] = 0;		if (block > 0xffffffff) {		SCpnt->cmnd[0] += READ_16 - READ_6;		SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0;		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) ||

⌨️ 快捷键说明

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