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

📄 sd.c

📁 Linux Kernel 2.6.9 for OMAP1710
💻 C
📖 第 1 页 / 共 3 页
字号:
	             (unsigned long __user *)&loc->start))		return -EFAULT;	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 subsytem. **/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.	 */	if (!scsi_block_when_processing_errors(sdp))		return -ENODEV;	if (cmd == HDIO_GETGEO) {		if (!arg)			return -EINVAL;		return sd_hdio_getgeo(bdev, p);	}	/*	 * 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, 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, printk("sd_media_changed: disk=%s\n",						disk->disk_name));	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_device *sdp){	struct scsi_request *sreq;	int retries, res;	if (!scsi_device_online(sdp))		return -ENODEV;	sreq = scsi_allocate_request(sdp, GFP_KERNEL);	if (!sreq) {		printk("FAILED\n  No memory for request\n");		return -ENOMEM;	}	sreq->sr_data_direction = DMA_NONE;	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.		 */		scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES);		if (sreq->sr_result == 0)			break;	}	res = sreq->sr_result;	if (res) {		printk(KERN_WARNING "FAILED\n  status = %x, message = %02x, "				    "host = %d, driver = %02x\n  ",				    status_byte(res), msg_byte(res),				    host_byte(res), driver_byte(res));			if (driver_byte(res) & DRIVER_SENSE)				scsi_print_req_sense("sd", sreq);	}	scsi_release_request(sreq);	return res;}static int sd_issue_flush(struct device *dev, sector_t *error_sector){	struct scsi_device *sdp = to_scsi_device(dev);	struct scsi_disk *sdkp = dev_get_drvdata(dev);	if (!sdkp)               return -ENODEV;	if (!sdkp->WCE)		return 0;	return sd_sync_cache(sdp);}static void sd_rescan(struct device *dev){	struct scsi_disk *sdkp = dev_get_drvdata(dev);	sd_revalidate_disk(sdkp->disk);}static struct block_device_operations sd_fops = {	.owner			= THIS_MODULE,	.open			= sd_open,	.release		= sd_release,	.ioctl			= sd_ioctl,	.media_changed		= sd_media_changed,	.revalidate_disk	= sd_revalidate_disk,};/** *	sd_rw_intr - 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 void sd_rw_intr(struct scsi_cmnd * SCpnt){	int result = SCpnt->result;	int this_count = SCpnt->bufflen;	int good_bytes = (result == 0 ? this_count : 0);	sector_t block_sectors = 1;	sector_t error_sector;#ifdef CONFIG_SCSI_LOGGING	SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: %s: res=0x%x\n", 				SCpnt->request->rq_disk->disk_name, result));	if (0 != result) {		SCSI_LOG_HLCOMPLETE(1, printk("sd_rw_intr: sb[0,2,asc,ascq]"				"=%x,%x,%x,%x\n", SCpnt->sense_buffer[0],			SCpnt->sense_buffer[2], SCpnt->sense_buffer[12],			SCpnt->sense_buffer[13]));	}#endif	/*	   Handle MEDIUM ERRORs that indicate partial success.  Since this is a	   relatively rare error condition, no care is taken to avoid	   unnecessary additional work such as memcpy's that could be avoided.	 */	/* An error occurred */	if (driver_byte(result) != 0 && 	/* An error occurred */	    (SCpnt->sense_buffer[0] & 0x7f) == 0x70) { /* Sense current */		switch (SCpnt->sense_buffer[2]) {		case MEDIUM_ERROR:			if (!(SCpnt->sense_buffer[0] & 0x80))				break;			if (!blk_fs_request(SCpnt->request))				break;			error_sector = (SCpnt->sense_buffer[3] << 24) |			(SCpnt->sense_buffer[4] << 16) |			(SCpnt->sense_buffer[5] << 8) |			SCpnt->sense_buffer[6];			if (SCpnt->request->bio != NULL)				block_sectors = bio_sectors(SCpnt->request->bio);			switch (SCpnt->device->sector_size) {			case 1024:				error_sector <<= 1;				if (block_sectors < 2)					block_sectors = 2;				break;			case 2048:				error_sector <<= 2;				if (block_sectors < 4)					block_sectors = 4;				break;			case 4096:				error_sector <<=3;				if (block_sectors < 8)					block_sectors = 8;				break;			case 256:				error_sector >>= 1;				break;			default:				break;			}			error_sector &= ~(block_sectors - 1);			good_bytes = (error_sector - SCpnt->request->sector) << 9;			if (good_bytes < 0 || good_bytes >= this_count)				good_bytes = 0;			break;		case RECOVERED_ERROR: /* an error occurred, but it recovered */		case NO_SENSE: /* LLDD got sense data */			/*			 * Inform the user, but make sure that it's not treated			 * as a hard error.			 */			scsi_print_sense("sd", SCpnt);			SCpnt->result = 0;			SCpnt->sense_buffer[0] = 0x0;			good_bytes = this_count;			break;		case ILLEGAL_REQUEST:			if (SCpnt->device->use_10_for_rw &&			    (SCpnt->cmnd[0] == READ_10 ||			     SCpnt->cmnd[0] == WRITE_10))				SCpnt->device->use_10_for_rw = 0;			if (SCpnt->device->use_10_for_ms &&			    (SCpnt->cmnd[0] == MODE_SENSE_10 ||			     SCpnt->cmnd[0] == MODE_SELECT_10))				SCpnt->device->use_10_for_ms = 0;			break;		default:			break;		}	}	/*	 * This calls the generic completion function, now that we know	 * how many actual sectors finished, and how many sectors we need	 * to say have failed.	 */	scsi_io_completion(SCpnt, good_bytes, block_sectors << 9);}static int media_not_present(struct scsi_disk *sdkp, struct scsi_request *srp){	if (!srp->sr_result)		return 0;	if (!(driver_byte(srp->sr_result) & DRIVER_SENSE))		return 0;	if (srp->sr_sense_buffer[2] != NOT_READY &&	    srp->sr_sense_buffer[2] != UNIT_ATTENTION)	    	return 0;	if (srp->sr_sense_buffer[12] != 0x3A) /* medium not present */		return 0;	set_media_not_present(sdkp);	return 1;}/* * spinup disk - called only in sd_revalidate_disk() */static voidsd_spinup_disk(struct scsi_disk *sdkp, char *diskname,	       struct scsi_request *SRpnt, unsigned char *buffer) {	unsigned char cmd[10];	unsigned long spintime_value = 0;	int retries, spintime;	unsigned int the_result;	spintime = 0;	/* Spin up drives, as required.  Only do this at boot time */	/* Spinup needs to be done for module loads too. */	do {		retries = 0;		do {			cmd[0] = TEST_UNIT_READY;			memset((void *) &cmd[1], 0, 9);			SRpnt->sr_cmd_len = 0;			SRpnt->sr_sense_buffer[0] = 0;			SRpnt->sr_sense_buffer[2] = 0;			SRpnt->sr_data_direction = DMA_NONE;			scsi_wait_req (SRpnt, (void *) cmd, (void *) buffer,				       0/*512*/, SD_TIMEOUT, SD_MAX_RETRIES);			the_result = SRpnt->sr_result;			retries++;		} while (retries < 3 && 			 (!scsi_status_is_good(the_result) ||			  ((driver_byte(the_result) & DRIVER_SENSE) &&			   SRpnt->sr_sense_buffer[2] == UNIT_ATTENTION)));		/*		 * If the drive has indicated to us that it doesn't have		 * any media in it, don't bother with any of the rest of		 * this crap.		 */		if (media_not_present(sdkp, SRpnt))			return;		if ((driver_byte(the_result) & DRIVER_SENSE) == 0) {			/* no sense, TUR either succeeded or failed			 * with a status error */			if(!spintime && !scsi_status_is_good(the_result))				printk(KERN_NOTICE "%s: Unit Not Ready, error = 0x%x\n", diskname, the_result);			break;		}							/*		 * The device does not want the automatic start to be issued.		 */		if (sdkp->device->no_start_on_add) {			break;		}		/*		 * If manual intervention is required, or this is an		 * absent USB storage device, a spinup is meaningless.		 */		if (SRpnt->sr_sense_buffer[2] == NOT_READY &&		    SRpnt->sr_sense_buffer[12] == 4 /* not ready */ &&		    SRpnt->sr_sense_buffer[13] == 3) {			break;		/* manual intervention required */		/*		 * Issue command to spin up drive when not ready		 */		} else if (SRpnt->sr_sense_buffer[2] == NOT_READY) {			unsigned long time1;			if (!spintime) {				printk(KERN_NOTICE "%s: Spinning up disk...",				       diskname);				cmd[0] = START_STOP;				cmd[1] = 1;	/* Return immediately */				memset((void *) &cmd[2], 0, 8);				cmd[4] = 1;	/* Start spin cycle */				SRpnt->sr_cmd_len = 0;				SRpnt->sr_sense_buffer[0] = 0;				SRpnt->sr_sense_buffer[2] = 0;				SRpnt->sr_data_direction = DMA_NONE;				scsi_wait_req(SRpnt, (void *)cmd, 					      (void *) buffer, 0/*512*/, 					      SD_TIMEOUT, SD_MAX_RETRIES);				spintime_value = jiffies;			}			spintime = 1;			time1 = HZ;			/* Wait 1 second for next try */			do {				current->state = TASK_UNINTERRUPTIBLE;				time1 = schedule_timeout(time1);			} while(time1);			printk(".");		} else {			/* we don't understand the sense code, so it's			 * probably pointless to loop */			if(!spintime) {				printk(KERN_NOTICE "%s: Unit Not Ready, sense:\n", diskname);				scsi_print_req_sense("", SRpnt);			}			break;		}					} while (spintime &&		 time_after(spintime_value + 100 * HZ, jiffies));	if (spintime) {		if (scsi_status_is_good(the_result))			printk("ready\n");		else			printk("not responding...\n");	}}/* * read disk capacity */static voidsd_read_capacity(struct scsi_disk *sdkp, char *diskname,		 struct scsi_request *SRpnt, unsigned char *buffer) {	unsigned char cmd[16];	struct scsi_device *sdp = sdkp->device;	int the_result, retries;	int sector_size = 0;	int longrc = 0;repeat:	retries = 3;	do {		if (longrc) {			memset((void *) cmd, 0, 16);			cmd[0] = SERVICE_ACTION_IN;			cmd[1] = SAI_READ_CAPACITY_16;			cmd[13] = 12;			memset((void *) buffer, 0, 12);		} else {			cmd[0] = READ_CAPACITY;			memset((void *) &cmd[1], 0, 9);			memset((void *) buffer, 0, 8);		}				SRpnt->sr_cmd_len = 0;		SRpnt->sr_sense_buffer[0] = 0;		SRpnt->sr_sense_buffer[2] = 0;		SRpnt->sr_data_direction = DMA_FROM_DEVICE;		scsi_wait_req(SRpnt, (void *) cmd, (void *) buffer,			      longrc ? 12 : 8, SD_TIMEOUT, SD_MAX_RETRIES);		if (media_not_present(sdkp, SRpnt))			return;		the_result = SRpnt->sr_result;		retries--;	} while (the_result && retries);	if (the_result && !longrc) {		printk(KERN_NOTICE "%s : READ CAPACITY failed.\n"		       "%s : status=%x, message=%02x, host=%d, driver=%02x \n",		       diskname, diskname,		       status_byte(the_result),		       msg_byte(the_result),		       host_byte(the_result),		       driver_byte(the_result));		if (driver_byte(the_result) & DRIVER_SENSE)			scsi_print_req_sense("sd", SRpnt);		else			printk("%s : sense not available. \n", diskname);		/* Set dirty bit for removable devices if not ready -		 * sometimes drives will not report this properly. */		if (sdp->removable &&		    SRpnt->sr_sense_buffer[2] == NOT_READY)			sdp->changed = 1;		/* Either no media are present but the drive didn't tell us,		   or they are present but the read capacity command fails */		/* sdkp->media_present = 0; -- not always correct */		sdkp->capacity = 0x200000; /* 1 GB - random */		return;	} else if (the_result && longrc) {		/* READ CAPACITY(16) has been failed */		printk(KERN_NOTICE "%s : READ CAPACITY(16) failed.\n"		       "%s : status=%x, message=%02x, host=%d, driver=%02x \n",		       diskname, diskname,		       status_byte(the_result),		       msg_byte(the_result),		       host_byte(the_result),		       driver_byte(the_result));		printk(KERN_NOTICE "%s : use 0xffffffff as device size\n",		       diskname);				sdkp->capacity = 1 + (sector_t) 0xffffffff;				goto got_data;	}	

⌨️ 快捷键说明

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