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

📄 sd.c

📁 linux 内核源代码
💻 C
📖 第 1 页 / 共 4 页
字号:
		   SCpnt->device->use_10_for_rw) {		if (this_count > 0xffff)			this_count = 0xffff;		SCpnt->cmnd[0] += READ_10 - READ_6;		SCpnt->cmnd[1] |= blk_fua_rq(rq) ? 0x8 : 0;		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 (unlikely(blk_fua_rq(rq))) {			/*			 * This happens only if this drive failed			 * 10byte rw command with ILLEGAL_REQUEST			 * during operation and thus turned off			 * use_10_for_rw.			 */			scmd_printk(KERN_ERR, SCpnt,				    "FUA write on READ/WRITE(6) drive\n");			goto out;		}		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 = 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;	SCpnt->allowed = SD_MAX_RETRIES;	SCpnt->timeout_per_command = timeout;	/*	 * This indicates that the command is ready from our end to be	 * queued.	 */	ret = BLKPREP_OK; out:	return scsi_prep_return(q, rq, ret);}/** *	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, sd_printk(KERN_INFO, sdkp, "sd_open\n"));	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, sd_printk(KERN_INFO, sdkp, "sd_release\n"));	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_getgeo(struct block_device *bdev, struct hd_geometry *geo){	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);	geo->heads = diskinfo[0];	geo->sectors = diskinfo[1];	geo->cylinders = diskinfo[2];	return 0;}/** *	sd_ioctl - process an ioctl *	@inode: only i_rdev/i_bdev members may be used *	@filp: only f_mode and f_flags may be used *	@cmd: ioctl command number *	@arg: this is third argument given to ioctl(2) system call. *	Often contains a pointer. * *	Returns 0 if successful (some ioctls return postive numbers on *	success as well). Returns a negated errno value in case of error. * *	Note: most ioctls are forward onto the block subsystem or further *	down in the scsi subsystem. **/static int sd_ioctl(struct inode * inode, struct file * filp, 		    unsigned int cmd, unsigned long arg){	struct block_device *bdev = inode->i_bdev;	struct gendisk *disk = bdev->bd_disk;	struct scsi_device *sdp = scsi_disk(disk)->device;	void __user *p = (void __user *)arg;	int error;    	SCSI_LOG_IOCTL(1, printk("sd_ioctl: disk=%s, cmd=0x%x\n",						disk->disk_name, cmd));	/*	 * 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.	 */	error = scsi_nonblockable_ioctl(sdp, cmd, p, filp);	if (!scsi_block_when_processing_errors(sdp) || !error)		return error;	/*	 * Send SCSI addressing ioctls directly to mid level, send other	 * ioctls to block level and then onto mid level if they can't be	 * resolved.	 */	switch (cmd) {		case SCSI_IOCTL_GET_IDLUN:		case SCSI_IOCTL_GET_BUS_NUMBER:			return scsi_ioctl(sdp, cmd, p);		default:			error = scsi_cmd_ioctl(filp, disk->queue, disk, cmd, p);			if (error != -ENOTTY)				return error;	}	return scsi_ioctl(sdp, cmd, p);}static void set_media_not_present(struct scsi_disk *sdkp){	sdkp->media_present = 0;	sdkp->capacity = 0;	sdkp->device->changed = 1;}/** *	sd_media_changed - check if our medium changed *	@disk: kernel device descriptor  * *	Returns 0 if not applicable or no change; 1 if change * *	Note: this function is invoked from the block subsystem. **/static int sd_media_changed(struct gendisk *disk){	struct scsi_disk *sdkp = scsi_disk(disk);	struct scsi_device *sdp = sdkp->device;	int retval;	SCSI_LOG_HLQUEUE(3, sd_printk(KERN_INFO, sdkp, "sd_media_changed\n"));	if (!sdp->removable)		return 0;	/*	 * If the device is offline, don't send any commands - just pretend as	 * if the command failed.  If the device ever comes back online, we	 * can deal with it then.  It is only because of unrecoverable errors	 * that we would ever take a device offline in the first place.	 */	if (!scsi_device_online(sdp))		goto not_present;	/*	 * Using TEST_UNIT_READY enables differentiation between drive with	 * no cartridge loaded - NOT READY, drive with changed cartridge -	 * UNIT ATTENTION, or with same cartridge - GOOD STATUS.	 *	 * Drives that auto spin down. eg iomega jaz 1G, will be started	 * by sd_spinup_disk() from sd_revalidate_disk(), which happens whenever	 * sd_revalidate() is called.	 */	retval = -ENODEV;	if (scsi_block_when_processing_errors(sdp))		retval = scsi_test_unit_ready(sdp, SD_TIMEOUT, SD_MAX_RETRIES);	/*	 * Unable to test, unit probably not ready.   This usually	 * means there is no disc in the drive.  Mark as changed,	 * and we will figure it out later once the drive is	 * available again.	 */	if (retval)		 goto not_present;	/*	 * For removable scsi disk we have to recognise the presence	 * of a disk in the drive. This is kept in the struct scsi_disk	 * struct and tested at open !  Daniel Roche (dan@lectra.fr)	 */	sdkp->media_present = 1;	retval = sdp->changed;	sdp->changed = 0;	return retval;not_present:	set_media_not_present(sdkp);	return 1;}static int sd_sync_cache(struct scsi_disk *sdkp){	int retries, res;	struct scsi_device *sdp = sdkp->device;	struct scsi_sense_hdr sshdr;	if (!scsi_device_online(sdp))		return -ENODEV;	for (retries = 3; retries > 0; --retries) {		unsigned char cmd[10] = { 0 };		cmd[0] = SYNCHRONIZE_CACHE;		/*		 * Leave the rest of the command zero to indicate		 * flush everything.		 */		res = scsi_execute_req(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,				       SD_TIMEOUT, SD_MAX_RETRIES);		if (res == 0)			break;	}	if (res) {		sd_print_result(sdkp, res);		if (driver_byte(res) & DRIVER_SENSE)			sd_print_sense_hdr(sdkp, &sshdr);	}	if (res)		return -EIO;	return 0;}static void sd_prepare_flush(struct request_queue *q, struct request *rq){	memset(rq->cmd, 0, sizeof(rq->cmd));	rq->cmd_type = REQ_TYPE_BLOCK_PC;	rq->timeout = SD_TIMEOUT;	rq->cmd[0] = SYNCHRONIZE_CACHE;	rq->cmd_len = 10;}static void sd_rescan(struct device *dev){	struct scsi_disk *sdkp = scsi_disk_get_from_dev(dev);	if (sdkp) {		sd_revalidate_disk(sdkp->disk);		scsi_disk_put(sdkp);	}}#ifdef CONFIG_COMPAT/*  * This gets directly called from VFS. When the ioctl  * is not recognized we go back to the other translation paths.  */static long sd_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg){	struct block_device *bdev = file->f_path.dentry->d_inode->i_bdev;	struct gendisk *disk = bdev->bd_disk;	struct scsi_device *sdev = scsi_disk(disk)->device;	/*	 * 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;	       	if (sdev->host->hostt->compat_ioctl) {		int ret;		ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);		return ret;	}	/* 	 * Let the static ioctl translation table take care of it.	 */	return -ENOIOCTLCMD; }#endifstatic struct block_device_operations sd_fops = {	.owner			= THIS_MODULE,	.open			= sd_open,	.release		= sd_release,	.ioctl			= sd_ioctl,	.getgeo			= sd_getgeo,#ifdef CONFIG_COMPAT	.compat_ioctl		= sd_compat_ioctl,#endif	.media_changed		= sd_media_changed,	.revalidate_disk	= sd_revalidate_disk,};/** *	sd_done - bottom half handler: called when the lower level *	driver has completed (successfully or otherwise) a scsi command. *	@SCpnt: mid-level's per command structure. * *	Note: potentially run from within an ISR. Must not block. **/static int sd_done(struct scsi_cmnd *SCpnt){	int result = SCpnt->result; 	unsigned int xfer_size = SCpnt->request_bufflen; 	unsigned int good_bytes = result ? 0 : xfer_size; 	u64 start_lba = SCpnt->request->sector; 	u64 bad_lba;	struct scsi_sense_hdr sshdr;	int sense_valid = 0;	int sense_deferred = 0;	int info_valid;	if (result) {		sense_valid = scsi_command_normalize_sense(SCpnt, &sshdr);		if (sense_valid)			sense_deferred = scsi_sense_is_deferred(&sshdr);	}#ifdef CONFIG_SCSI_LOGGING	SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt));	if (sense_valid) {		SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt,						   "sd_done: sb[respc,sk,asc,"						   "ascq]=%x,%x,%x,%x\n",						   sshdr.response_code,						   sshdr.sense_key, sshdr.asc,						   sshdr.ascq));	}#endif	if (driver_byte(result) != DRIVER_SENSE &&	    (!sense_valid || sense_deferred))		goto out;	switch (sshdr.sense_key) {	case HARDWARE_ERROR:	case MEDIUM_ERROR:		if (!blk_fs_request(SCpnt->request))			goto out;		info_valid = scsi_get_sense_info_fld(SCpnt->sense_buffer,						     SCSI_SENSE_BUFFERSIZE,						     &bad_lba);		if (!info_valid)			goto out;		if (xfer_size <= SCpnt->device->sector_size)			goto out;		switch (SCpnt->device->sector_size) {		case 256:			start_lba <<= 1;			break;		case 512:			break;		case 1024:			start_lba >>= 1;			break;		case 2048:			start_lba >>= 2;			break;		case 4096:

⌨️ 快捷键说明

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