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

📄 ide-disk.c

📁 ep9315平台下硬盘驱动的源码
💻 C
📖 第 1 页 / 共 4 页
字号:
			return startstop;		}		if (!drive->unmask)			local_irq_disable();		if (drive->mult_count) {			ide_hwgroup_t *hwgroup = HWGROUP(drive);	/*	 * Ugh.. this part looks ugly because we MUST set up	 * the interrupt handler before outputting the first block	 * of data to be written.  If we hit an error (corrupted buffer list)	 * in ide_multwrite(), then we need to remove the handler/timer	 * before returning.  Fortunately, this NEVER happens (right?).	 *	 * Except when you get an error it seems...	 *	 * MAJOR DATA INTEGRITY BUG !!! only if we error 	 */			hwgroup->wrq = *rq; /* scratchpad */			ide_set_handler(drive, &multwrite_intr, WAIT_CMD, NULL);			if (ide_multwrite(drive, drive->mult_count)) {				unsigned long flags;				spin_lock_irqsave(&io_request_lock, flags);				hwgroup->handler = NULL;				del_timer(&hwgroup->timer);				spin_unlock_irqrestore(&io_request_lock, flags);				return ide_stopped;			}		} else {			unsigned long flags;			char *to = ide_map_buffer(rq, &flags);			ide_set_handler(drive, &write_intr, WAIT_CMD, NULL);			taskfile_output_data(drive, to, SECTOR_WORDS);			ide_unmap_buffer(to, &flags);		}		return ide_started;	}	printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);	idedisk_end_request(drive, 0);	return ide_stopped;}#else /* CONFIG_IDE_TASKFILE_IO */static ide_startstop_t chs_rw_disk(ide_drive_t *, struct request *, unsigned long);static ide_startstop_t lba_28_rw_disk(ide_drive_t *, struct request *, unsigned long);static ide_startstop_t lba_48_rw_disk(ide_drive_t *, struct request *, unsigned long long);/* * __ide_do_rw_disk() issues READ and WRITE commands to a disk, * using LBA if supported, or CHS otherwise, to address sectors. * It also takes care of issuing special DRIVE_CMDs. */ide_startstop_t __ide_do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block){	if (!blk_fs_request(rq)) {		printk(KERN_ERR "%s: bad command: %d\n", drive->name, rq->cmd);		idedisk_end_request(drive, 0);		return ide_stopped;	}	/*	 * 268435455  == 137439 MB or 28bit limit	 *	 * need to add split taskfile operations based on 28bit threshold.	 */	if (drive->addressing == 1)		/* 48-bit LBA */		return lba_48_rw_disk(drive, rq, (unsigned long long) block);	if (drive->select.b.lba)		/* 28-bit LBA */		return lba_28_rw_disk(drive, rq, (unsigned long) block);	/* 28-bit CHS : DIE DIE DIE piece of legacy crap!!! */	return chs_rw_disk(drive, rq, (unsigned long) block);}static task_ioreg_t get_command (ide_drive_t *drive, int cmd){	int lba48bit = (drive->id->cfs_enable_2 & 0x0400) ? 1 : 0;#if 1	lba48bit = (drive->addressing == 1) ? 1 : 0;#endif	if ((cmd == READ) && (drive->using_dma))		return (lba48bit) ? WIN_READDMA_EXT : WIN_READDMA;	else if ((cmd == READ) && (drive->mult_count))		return (lba48bit) ? WIN_MULTREAD_EXT : WIN_MULTREAD;	else if (cmd == READ)		return (lba48bit) ? WIN_READ_EXT : WIN_READ;	else if ((cmd == WRITE) && (drive->using_dma))		return (lba48bit) ? WIN_WRITEDMA_EXT : WIN_WRITEDMA;	else if ((cmd == WRITE) && (drive->mult_count))		return (lba48bit) ? WIN_MULTWRITE_EXT : WIN_MULTWRITE;	else if (cmd == WRITE)		return (lba48bit) ? WIN_WRITE_EXT : WIN_WRITE;	else		return WIN_NOP;}static ide_startstop_t chs_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block){	ide_task_t		args;	int			sectors;	ata_nsector_t		nsectors;	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));	unsigned int track	= (block / drive->sect);	unsigned int sect	= (block % drive->sect) + 1;	unsigned int head	= (track % drive->head);	unsigned int cyl	= (track / drive->head);	nsectors.all = (u16) rq->nr_sectors;#ifdef DEBUG	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");	printk("CHS=%d/%d/%d, ", cyl, head, sect);	printk("sectors=%ld, ", rq->nr_sectors);	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);#endif	memset(&args, 0, sizeof(ide_task_t));	sectors	= (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;	args.tfRegister[IDE_SECTOR_OFFSET]	= sect;	args.tfRegister[IDE_LCYL_OFFSET]	= cyl;	args.tfRegister[IDE_HCYL_OFFSET]	= (cyl>>8);	args.tfRegister[IDE_SELECT_OFFSET]	= head;	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;	args.tfRegister[IDE_COMMAND_OFFSET]	= command;	args.command_type			= ide_cmd_type_parser(&args);	args.rq					= (struct request *) rq;	rq->special				= (ide_task_t *)&args;	return do_rw_taskfile(drive, &args);}static ide_startstop_t lba_28_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block){	ide_task_t		args;	int			sectors;	ata_nsector_t		nsectors;	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));	nsectors.all = (u16) rq->nr_sectors;#ifdef DEBUG	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");	printk("LBAsect=%lld, ", block);	printk("sectors=%ld, ", rq->nr_sectors);	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);#endif	memset(&args, 0, sizeof(ide_task_t));	sectors = (rq->nr_sectors == 256) ? 0x00 : rq->nr_sectors;	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;	args.tfRegister[IDE_SECTOR_OFFSET]	= block;	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);	args.tfRegister[IDE_SELECT_OFFSET]	= ((block>>8)&0x0f);	args.tfRegister[IDE_SELECT_OFFSET]	|= drive->select.all;	args.tfRegister[IDE_COMMAND_OFFSET]	= command;	args.command_type			= ide_cmd_type_parser(&args);	args.rq					= (struct request *) rq;	rq->special				= (ide_task_t *)&args;	return do_rw_taskfile(drive, &args);}/* * 268435455  == 137439 MB or 28bit limit * 320173056  == 163929 MB or 48bit addressing * 1073741822 == 549756 MB or 48bit addressing fake drive */static ide_startstop_t lba_48_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long long block){	ide_task_t		args;	int			sectors;	ata_nsector_t		nsectors;	task_ioreg_t command	= get_command(drive, rq_data_dir(rq));	nsectors.all = (u16) rq->nr_sectors;#ifdef DEBUG	printk("%s: %sing: ", drive->name, (rq_data_dir(rq)==READ) ? "read" : "writ");	printk("LBAsect=%lld, ", block);	printk("sectors=%ld, ", rq->nr_sectors);	printk("buffer=0x%08lx\n", (unsigned long) rq->buffer);#endif	memset(&args, 0, sizeof(ide_task_t));	sectors = (rq->nr_sectors == 65536) ? 0 : rq->nr_sectors;	args.tfRegister[IDE_NSECTOR_OFFSET]	= sectors;	args.tfRegister[IDE_SECTOR_OFFSET]	= block;	/* low lba */	args.tfRegister[IDE_LCYL_OFFSET]	= (block>>=8);	/* mid lba */	args.tfRegister[IDE_HCYL_OFFSET]	= (block>>=8);	/* hi  lba */	args.tfRegister[IDE_SELECT_OFFSET]	= drive->select.all;	args.tfRegister[IDE_COMMAND_OFFSET]	= command;	args.hobRegister[IDE_NSECTOR_OFFSET_HOB]= sectors >> 8;	args.hobRegister[IDE_SECTOR_OFFSET_HOB]	= (block>>=8);	/* low lba */	args.hobRegister[IDE_LCYL_OFFSET_HOB]	= (block>>=8);	/* mid lba */	args.hobRegister[IDE_HCYL_OFFSET_HOB]	= (block>>=8);	/* hi  lba */	args.hobRegister[IDE_SELECT_OFFSET_HOB]	= drive->select.all;	args.hobRegister[IDE_CONTROL_OFFSET_HOB]= (drive->ctl|0x80);	args.command_type			= ide_cmd_type_parser(&args);	args.rq					= (struct request *) rq;	rq->special				= (ide_task_t *)&args;	return do_rw_taskfile(drive, &args);}#endif /* CONFIG_IDE_TASKFILE_IO */static ide_startstop_t ide_do_rw_disk (ide_drive_t *drive, struct request *rq, unsigned long block){	ide_hwif_t *hwif	= HWIF(drive);	if (hwif->rw_disk)		return hwif->rw_disk(drive, rq, block);	else 		return __ide_do_rw_disk(drive, rq, block);}EXPORT_SYMBOL_GPL(__ide_do_rw_disk);static int idedisk_open (struct inode *inode, struct file *filp, ide_drive_t *drive){	MOD_INC_USE_COUNT;	if (drive->removable && drive->usage == 1) {		ide_task_t args;		int cf;		memset(&args, 0, sizeof(ide_task_t));		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORLOCK;		args.command_type = ide_cmd_type_parser(&args);		check_disk_change(inode->i_rdev);		/*		 * 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;		drive->wcache = 0;		/* Cache enabled ? */		if (drive->id->csfo & 1)			drive->wcache = 1;		/* Cache command set available ? */		if (drive->id->cfs_enable_1 & (1<<5))			drive->wcache = 1;		/* ATA6 cache extended commands */		cf = drive->id->command_set_2 >> 24;		if((cf & 0xC0) == 0x40 && (cf & 0x30) != 0)			drive->wcache = 1;	}	return 0;}static int do_idedisk_flushcache(ide_drive_t *drive);static int ide_cacheflush_p(ide_drive_t *drive){	if(drive->wcache)	{		if (do_idedisk_flushcache(drive))		{			printk (KERN_INFO "%s: Write Cache FAILED Flushing!\n",				drive->name);			return -EIO;		}		return 1;	}	return 0;}static void idedisk_release (struct inode *inode, struct file *filp, ide_drive_t *drive){	if (drive->removable && !drive->usage) {		ide_task_t args;		memset(&args, 0, sizeof(ide_task_t));		args.tfRegister[IDE_COMMAND_OFFSET] = WIN_DOORUNLOCK;		args.command_type = ide_cmd_type_parser(&args);		invalidate_bdev(inode->i_bdev, 0);		if (drive->doorlocking && ide_raw_taskfile(drive, &args, NULL))			drive->doorlocking = 0;	}	ide_cacheflush_p(drive);	MOD_DEC_USE_COUNT;}static int idedisk_media_change (ide_drive_t *drive){	/* if removable, always assume it was changed */	return drive->removable;}static void idedisk_revalidate (ide_drive_t *drive){	grok_partitions(HWIF(drive)->gd, drive->select.b.unit,			1<<PARTN_BITS,			current_capacity(drive));}static int idedisk_end_request (ide_drive_t *drive, int uptodate){	struct request *rq;	unsigned long flags;	int ret = 1;	spin_lock_irqsave(&io_request_lock, flags);	rq = HWGROUP(drive)->rq;	/*	 * decide whether to reenable DMA -- 3 is a random magic for now,	 * if we DMA timeout more than 3 times, just stay in PIO	 */	if (drive->state == DMA_PIO_RETRY && drive->retry_pio <= 3) {		drive->state = 0;		HWGROUP(drive)->hwif->ide_dma_on(drive);	}	if (!end_that_request_first(rq, uptodate, drive->name)) {		add_blkdev_randomness(MAJOR(rq->rq_dev));		blkdev_dequeue_request(rq);		HWGROUP(drive)->rq = NULL;		end_that_request_last(rq);		ret = 0;	}	spin_unlock_irqrestore(&io_request_lock, flags);	return ret;}static u8 idedisk_dump_status (ide_drive_t *drive, const char *msg, u8 stat){	ide_hwif_t *hwif = HWIF(drive);	unsigned long flags;	u8 err = 0;	local_irq_set(flags);	printk("%s: %s: status=0x%02x", drive->name, msg, stat);#if FANCY_STATUS_DUMPS	printk(" { ");	if (stat & BUSY_STAT)		printk("Busy ");	else {		if (stat & READY_STAT)	printk("DriveReady ");		if (stat & WRERR_STAT)	printk("DeviceFault ");		if (stat & SEEK_STAT)	printk("SeekComplete ");		if (stat & DRQ_STAT)	printk("DataRequest ");		if (stat & ECC_STAT)	printk("CorrectedError ");		if (stat & INDEX_STAT)	printk("Index ");		if (stat & ERR_STAT)	printk("Error ");	}	printk("}");#endif	/* FANCY_STATUS_DUMPS */	printk("\n");	if ((stat & (BUSY_STAT|ERR_STAT)) == ERR_STAT) {		err = hwif->INB(IDE_ERROR_REG);		printk("%s: %s: error=0x%02x", drive->name, msg, err);#if FANCY_STATUS_DUMPS		printk(" { ");		if (err & ABRT_ERR)	printk("DriveStatusError ");		if (err & ICRC_ERR)			printk("Bad%s ", (err & ABRT_ERR) ? "CRC" : "Sector");		if (err & ECC_ERR)	printk("UncorrectableError ");		if (err & ID_ERR)	printk("SectorIdNotFound ");		if (err & TRK0_ERR)	printk("TrackZeroNotFound ");		if (err & MARK_ERR)	printk("AddrMarkNotFound ");		printk("}");		if ((err & (BBD_ERR | ABRT_ERR)) == BBD_ERR ||		    (err & (ECC_ERR|ID_ERR|MARK_ERR))) {			if (drive->addressing == 1) {				__u64 sectors = 0;				u32 low = 0, high = 0;				low = idedisk_read_24(drive);				hwif->OUTB(drive->ctl|0x80, IDE_CONTROL_REG);				high = idedisk_read_24(drive);				sectors = ((__u64)high << 24) | low;				printk(", LBAsect=%llu, high=%d, low=%d",				       (unsigned long long) sectors,				       high, low);			} else {				u8 cur = hwif->INB(IDE_SELECT_REG);				if (cur & 0x40) {	/* using LBA? */					printk(", LBAsect=%ld", (unsigned long)					 ((cur&0xf)<<24)					 |(hwif->INB(IDE_HCYL_REG)<<16)					 |(hwif->INB(IDE_LCYL_REG)<<8)					 | hwif->INB(IDE_SECTOR_REG));				} else {					printk(", CHS=%d/%d/%d",					 (hwif->INB(IDE_HCYL_REG)<<8) +					  hwif->INB(IDE_LCYL_REG),					  cur & 0xf,					  hwif->INB(IDE_SECTOR_REG));				}			}			if (HWGROUP(drive) && HWGROUP(drive)->rq)				printk(", sector=%ld",					HWGROUP(drive)->rq->sector);		}	}#endif	/* FANCY_STATUS_DUMPS */	printk("\n");	local_irq_restore(flags);	return err;}ide_startstop_t idedisk_error (ide_drive_t *drive, const char *msg, u8 stat){	ide_hwif_t *hwif;	struct request *rq;	u8 err;	int i = (drive->mult_count ? drive->mult_count : 1) * SECTOR_WORDS;	err = idedisk_dump_status(drive, msg, stat);	if (drive == NULL || (rq = HWGROUP(drive)->rq) == NULL)		return ide_stopped;	hwif = HWIF(drive);	/* retry only "normal" I/O: */	switch (rq->cmd) {		case IDE_DRIVE_CMD:		case IDE_DRIVE_TASK:		case IDE_DRIVE_TASKFILE:			rq->errors = 1;			ide_end_drive_cmd(drive, stat, err);			return ide_stopped;#if 0		case IDE_DRIVE_TASKFILE:			rq->errors = 1;			ide_end_taskfile(drive, stat, err);			return ide_stopped;#endif		default:			break;	}	if (stat & BUSY_STAT || ((stat & WRERR_STAT) && !drive->nowerr)) {		/* other bits are useless when BUSY */		rq->errors |= ERROR_RESET;	} else if (stat & ERR_STAT) {		/* err has different meaning on cdrom and tape */		if (err == ABRT_ERR) {			if (drive->select.b.lba &&			    /* some newer drives don't support WIN_SPECIFY */			    hwif->INB(IDE_COMMAND_REG) == WIN_SPECIFY)				return ide_stopped;		} else if ((err & BAD_CRC) == BAD_CRC) {			/* UDMA crc error, just retry the operation */			drive->crc_count++;		} else if (err & (BBD_ERR | ECC_ERR)) {			/* retries won't help these */			rq->errors = ERROR_MAX;		} else if (err & TRK0_ERR) {			/* help it find track zero */			rq->errors |= ERROR_RECAL;		}	}	if ((stat & DRQ_STAT) && rq_data_dir(rq) == READ) {		/*		 * try_to_flush_leftover_data() is invoked in response to		 * a drive unexpectedly having its DRQ_STAT bit set.  As		 * an alternative to resetting the drive, this routine		 * tries to clear the condition by read a sector's worth		 * of data from the drive.  Of course, this may not help		 * if the drive is *waiting* for data from *us*.		 */		while (i > 0) {			u32 buffer[16];			unsigned int wcount = (i > 16) ? 16 : i;			i -= wcount;			taskfile_input_data(drive, buffer, wcount);		}	}	if (hwif->INB(IDE_STATUS_REG) & (BUSY_STAT|DRQ_STAT)) {		/* force an abort */		hwif->OUTB(WIN_IDLEIMMEDIATE,IDE_COMMAND_REG);	}	if (rq->errors >= ERROR_MAX)		DRIVER(drive)->end_request(drive, 0);	else {		if ((rq->errors & ERROR_RESET) == ERROR_RESET) {			++rq->errors;			return ide_do_reset(drive);

⌨️ 快捷键说明

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