ide-disk.c

来自「Linux Kernel 2.6.9 for OMAP1710」· C语言 代码 · 共 1,865 行 · 第 1/4 页

C
1,865
字号
}/* * Power Management state machine. This one is rather trivial for now, * we should probably add more, like switching back to PIO on suspend * to help some BIOSes, re-do the door locking on resume, etc... */enum {	idedisk_pm_flush_cache	= ide_pm_state_start_suspend,	idedisk_pm_standby,	idedisk_pm_idle		= ide_pm_state_start_resume,	idedisk_pm_restore_dma,};static void idedisk_complete_power_step (ide_drive_t *drive, struct request *rq, u8 stat, u8 error){	switch (rq->pm->pm_step) {	case idedisk_pm_flush_cache:	/* Suspend step 1 (flush cache) complete */		if (rq->pm->pm_state == 4)			rq->pm->pm_step = ide_pm_state_completed;		else			rq->pm->pm_step = idedisk_pm_standby;		break;	case idedisk_pm_standby:	/* Suspend step 2 (standby) complete */		rq->pm->pm_step = ide_pm_state_completed;		break;	case idedisk_pm_idle:		/* Resume step 1 (idle) complete */		rq->pm->pm_step = idedisk_pm_restore_dma;		break;	}}static ide_startstop_t idedisk_start_power_step (ide_drive_t *drive, struct request *rq){	ide_task_t *args = rq->special;	memset(args, 0, sizeof(*args));	switch (rq->pm->pm_step) {	case idedisk_pm_flush_cache:	/* Suspend step 1 (flush cache) */		/* Not supported? Switch to next step now. */		if (!drive->wcache || !ide_id_has_flush_cache(drive->id)) {			idedisk_complete_power_step(drive, rq, 0, 0);			return ide_stopped;		}		if (ide_id_has_flush_cache_ext(drive->id))			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE_EXT;		else			args->tfRegister[IDE_COMMAND_OFFSET] = WIN_FLUSH_CACHE;		args->command_type = IDE_DRIVE_TASK_NO_DATA;		args->handler	   = &task_no_data_intr;		return do_rw_taskfile(drive, args);	case idedisk_pm_standby:	/* Suspend step 2 (standby) */		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_STANDBYNOW1;		args->command_type = IDE_DRIVE_TASK_NO_DATA;		args->handler	   = &task_no_data_intr;		return do_rw_taskfile(drive, args);	case idedisk_pm_idle:		/* Resume step 1 (idle) */		args->tfRegister[IDE_COMMAND_OFFSET] = WIN_IDLEIMMEDIATE;		args->command_type = IDE_DRIVE_TASK_NO_DATA;		args->handler = task_no_data_intr;		return do_rw_taskfile(drive, args);	case idedisk_pm_restore_dma:	/* Resume step 2 (restore DMA) */		/*		 * Right now, all we do is call hwif->ide_dma_check(drive),		 * we could be smarter and check for current xfer_speed		 * in struct drive etc...		 * Also, this step could be implemented as a generic helper		 * as most subdrivers will use it		 */		if ((drive->id->capability & 1) == 0)			break;		if (HWIF(drive)->ide_dma_check == NULL)			break;		HWIF(drive)->ide_dma_check(drive);		break;	}	rq->pm->pm_step = ide_pm_state_completed;	return ide_stopped;}static void idedisk_setup (ide_drive_t *drive){	struct hd_driveid *id = drive->id;	unsigned long long capacity;	int barrier;	idedisk_add_settings(drive);	if (drive->id_read == 0)		return;	/*	 * CompactFlash cards and their brethern look just like hard drives	 * to us, but they are removable and don't have a doorlock mechanism.	 */	if (drive->removable && !(drive->is_flash)) {		/*		 * Removable disks (eg. SYQUEST); ignore 'WD' drives 		 */		if (id->model[0] != 'W' || id->model[1] != 'D') {			drive->doorlocking = 1;		}	}	(void)set_lba_addressing(drive, 1);	if (drive->addressing == 1) {		ide_hwif_t *hwif = HWIF(drive);		int max_s = 2048;		if (max_s > hwif->rqsize)			max_s = hwif->rqsize;		blk_queue_max_sectors(drive->queue, max_s);	}	printk(KERN_INFO "%s: max request size: %dKiB\n", drive->name, drive->queue->max_sectors / 2);	/* Extract geometry if we did not already have one for the drive */	if (!drive->cyl || !drive->head || !drive->sect) {		drive->cyl     = drive->bios_cyl  = id->cyls;		drive->head    = drive->bios_head = id->heads;		drive->sect    = drive->bios_sect = id->sectors;	}	/* Handle logical geometry translation by the drive */	if ((id->field_valid & 1) && id->cur_cyls &&	    id->cur_heads && (id->cur_heads <= 16) && id->cur_sectors) {		drive->cyl  = id->cur_cyls;		drive->head = id->cur_heads;		drive->sect = id->cur_sectors;	}	/* Use physical geometry if what we have still makes no sense */	if (drive->head > 16 && id->heads && id->heads <= 16) {		drive->cyl  = id->cyls;		drive->head = id->heads;		drive->sect = id->sectors;	}	/* calculate drive capacity, and select LBA if possible */	init_idedisk_capacity (drive);	/* limit drive capacity to 137GB if LBA48 cannot be used */	if (drive->addressing == 0 && drive->capacity64 > 1ULL << 28) {		printk(KERN_WARNING "%s: cannot use LBA48 - full capacity "		       "%llu sectors (%llu MB)\n",		       drive->name, (unsigned long long)drive->capacity64,		       sectors_to_MB(drive->capacity64));		drive->capacity64 = 1ULL << 28;	}	if (drive->hwif->no_lba48_dma && drive->addressing) {		if (drive->capacity64 > 1ULL << 28) {			printk(KERN_INFO "%s: cannot use LBA48 DMA - PIO mode will"					 " be used for accessing sectors > %u\n",					 drive->name, 1 << 28);		} else			drive->addressing = 0;	}	/*	 * if possible, give fdisk access to more of the drive,	 * by correcting bios_cyls:	 */	capacity = idedisk_capacity (drive);	if (!drive->forced_geom) {		if (idedisk_supports_lba48(drive->id)) {			/* compatibility */			drive->bios_sect = 63;			drive->bios_head = 255;		}		if (drive->bios_sect && drive->bios_head) {			unsigned int cap0 = capacity; /* truncate to 32 bits */			unsigned int cylsz, cyl;			if (cap0 != capacity)				drive->bios_cyl = 65535;			else {				cylsz = drive->bios_sect * drive->bios_head;				cyl = cap0 / cylsz;				if (cyl > 65535)					cyl = 65535;				if (cyl > drive->bios_cyl)					drive->bios_cyl = cyl;			}		}	}	printk(KERN_INFO "%s: %llu sectors (%llu MB)",			 drive->name, capacity, sectors_to_MB(capacity));	/* Only print cache size when it was specified */	if (id->buf_size)		printk (" w/%dKiB Cache", id->buf_size/2);	printk(", CHS=%d/%d/%d", 	       drive->bios_cyl, drive->bios_head, drive->bios_sect);	if (drive->using_dma)		(void) HWIF(drive)->ide_dma_verbose(drive);	printk("\n");	drive->mult_count = 0;	if (id->max_multsect) {#ifdef CONFIG_IDEDISK_MULTI_MODE		id->multsect = ((id->max_multsect/2) > 1) ? id->max_multsect : 0;		id->multsect_valid = id->multsect ? 1 : 0;		drive->mult_req = id->multsect_valid ? id->max_multsect : INITIAL_MULT_COUNT;		drive->special.b.set_multmode = drive->mult_req ? 1 : 0;#else	/* original, pre IDE-NFG, per request of AC */		drive->mult_req = INITIAL_MULT_COUNT;		if (drive->mult_req > id->max_multsect)			drive->mult_req = id->max_multsect;		if (drive->mult_req || ((id->multsect_valid & 1) && id->multsect))			drive->special.b.set_multmode = 1;#endif	/* CONFIG_IDEDISK_MULTI_MODE */	}	drive->no_io_32bit = id->dword_io ? 1 : 0;	/* write cache enabled? */	if ((id->csfo & 1) || (id->cfs_enable_1 & (1 << 5)))		drive->wcache = 1;	write_cache(drive, 1);	/*	 * We must avoid issuing commands a drive does not understand	 * or we may crash it. We check flush cache is supported. We also	 * check we have the LBA48 flush cache if the drive capacity is	 * too large. By this time we have trimmed the drive capacity if	 * LBA48 is not available so we don't need to recheck that.	 */	barrier = 0;	if (ide_id_has_flush_cache(id))		barrier = 1;	if (drive->addressing == 1) {		/* Can't issue the correct flush ? */		if (capacity > (1ULL << 28) && !ide_id_has_flush_cache_ext(id))			barrier = 0;	}	printk(KERN_DEBUG "%s: cache flushes %ssupported\n",		drive->name, barrier ? "" : "not ");	if (barrier) {		blk_queue_ordered(drive->queue, 1);		blk_queue_issue_flush_fn(drive->queue, idedisk_issue_flush);	}}static void ide_cacheflush_p(ide_drive_t *drive){	if (!drive->wcache || !ide_id_has_flush_cache(drive->id))		return;	if (do_idedisk_flushcache(drive))		printk(KERN_INFO "%s: wcache flush failed!\n", drive->name);}static int idedisk_cleanup (ide_drive_t *drive){	struct gendisk *g = drive->disk;	ide_cacheflush_p(drive);	if (ide_unregister_subdriver(drive))		return 1;	del_gendisk(g);	drive->devfs_name[0] = '\0';	g->fops = ide_fops;	return 0;}static int idedisk_attach(ide_drive_t *drive);static void ide_device_shutdown(struct device *dev){	ide_drive_t *drive = container_of(dev, ide_drive_t, gendev);#ifdef	CONFIG_ALPHA	/* On Alpha, halt(8) doesn't actually turn the machine off,	   it puts you into the sort of firmware monitor. Typically,	   it's used to boot another kernel image, so it's not much	   different from reboot(8). Therefore, we don't need to	   spin down the disk in this case, especially since Alpha	   firmware doesn't handle disks in standby mode properly.	   On the other hand, it's reasonably safe to turn the power	   off when the shutdown process reaches the firmware prompt,	   as the firmware initialization takes rather long time -	   at least 10 seconds, which should be sufficient for	   the disk to expire its write cache. */	if (system_state != SYSTEM_POWER_OFF) {#else	if (system_state == SYSTEM_RESTART) {#endif		ide_cacheflush_p(drive);		return;	}	printk("Shutdown: %s\n", drive->name);	dev->bus->suspend(dev, PM_SUSPEND_STANDBY);}/* *      IDE subdriver functions, registered with ide.c */static ide_driver_t idedisk_driver = {	.owner			= THIS_MODULE,	.gen_driver = {		.shutdown	= ide_device_shutdown,	},	.name			= "ide-disk",	.version		= IDEDISK_VERSION,	.media			= ide_disk,	.busy			= 0,	.supports_dsc_overlap	= 0,	.cleanup		= idedisk_cleanup,	.do_request		= ide_do_rw_disk,	.sense			= idedisk_dump_status,	.error			= idedisk_error,	.abort			= idedisk_abort,	.pre_reset		= idedisk_pre_reset,	.capacity		= idedisk_capacity,	.special		= idedisk_special,	.proc			= idedisk_proc,	.attach			= idedisk_attach,	.drives			= LIST_HEAD_INIT(idedisk_driver.drives),	.start_power_step	= idedisk_start_power_step,	.complete_power_step	= idedisk_complete_power_step,};static int idedisk_open(struct inode *inode, struct file *filp){	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;	drive->usage++;	if (drive->removable && drive->usage == 1) {		ide_task_t args;		memset(&args, 0, sizeof(ide_task_t));		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;		args.command_type = IDE_DRIVE_TASK_NO_DATA;		args.handler	  = &task_no_data_intr;		check_disk_change(inode->i_bdev);		/*		 * Ignore the return code from door_lock,		 * since the open() has already succeeded,		 * and the door_lock is irrelevant at this point.		 */		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))			drive->doorlocking = 0;	}	return 0;}static int idedisk_release(struct inode *inode, struct file *filp){	ide_drive_t *drive = inode->i_bdev->bd_disk->private_data;	if (drive->usage == 1)		ide_cacheflush_p(drive);	if (drive->removable && drive->usage == 1) {		ide_task_t args;		memset(&args, 0, sizeof(ide_task_t));		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;		args.command_type = IDE_DRIVE_TASK_NO_DATA;		args.handler	  = &task_no_data_intr;		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))			drive->doorlocking = 0;	}	drive->usage--;	return 0;}static int idedisk_ioctl(struct inode *inode, struct file *file,			unsigned int cmd, unsigned long arg){	struct block_device *bdev = inode->i_bdev;	return generic_ide_ioctl(file, bdev, cmd, arg);}static int idedisk_media_changed(struct gendisk *disk){	ide_drive_t *drive = disk->private_data;	/* do not scan partitions twice if this is a removable device */	if (drive->attach) {		drive->attach = 0;		return 0;	}	/* if removable, always assume it was changed */	return drive->removable;}static int idedisk_revalidate_disk(struct gendisk *disk){	ide_drive_t *drive = disk->private_data;	set_capacity(disk, current_capacity(drive));	return 0;}static struct block_device_operations idedisk_ops = {	.owner		= THIS_MODULE,	.open		= idedisk_open,	.release	= idedisk_release,	.ioctl		= idedisk_ioctl,	.media_changed	= idedisk_media_changed,	.revalidate_disk= idedisk_revalidate_disk};MODULE_DESCRIPTION("ATA DISK Driver");static int idedisk_attach(ide_drive_t *drive){	struct gendisk *g = drive->disk;	/* strstr("foo", "") is non-NULL */	if (!strstr("ide-disk", drive->driver_req))		goto failed;	if (!drive->present)		goto failed;	if (drive->media != ide_disk)		goto failed;	if (ide_register_subdriver(drive, &idedisk_driver)) {		printk (KERN_ERR "ide-disk: %s: Failed to register the driver with ide.c\n", drive->name);		goto failed;	}	DRIVER(drive)->busy++;	idedisk_setup(drive);	if ((!drive->head || drive->head > 16) && !drive->select.b.lba) {		printk(KERN_ERR "%s: INVALID GEOMETRY: %d PHYSICAL HEADS?\n",			drive->name, drive->head);		drive->attach = 0;	} else		drive->attach = 1;	DRIVER(drive)->busy--;	g->minors = 1 << PARTN_BITS;	strcpy(g->devfs_name, drive->devfs_name);	g->driverfs_dev = &drive->gendev;	g->flags = drive->removable ? GENHD_FL_REMOVABLE : 0;	set_capacity(g, current_capacity(drive));	g->fops = &idedisk_ops;	add_disk(g);	return 0;failed:	return 1;}static void __exit idedisk_exit (void){	ide_unregister_driver(&idedisk_driver);}static int idedisk_init (void){	return ide_register_driver(&idedisk_driver);}module_init(idedisk_init);module_exit(idedisk_exit);MODULE_LICENSE("GPL");

⌨️ 快捷键说明

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