ide-iops.c

来自「ep9315平台下硬盘驱动的源码」· C语言 代码 · 共 1,372 行 · 第 1/3 页

C
1,372 行
字号
#endif}EXPORT_SYMBOL(ide_driveid_update);/* * Similar to ide_wait_stat(), except it never calls ide_error internally. * This is a kludge to handle the new ide_config_drive_speed() function, * and should not otherwise be used anywhere.  Eventually, the tuneproc's * should be updated to return ide_startstop_t, in which case we can get * rid of this abomination again.  :)   -ml * * It is gone.......... * * const char *msg == consider adding for verbose errors. */int ide_config_drive_speed (ide_drive_t *drive, u8 speed){	ide_hwif_t *hwif	= HWIF(drive);	int	i, error	= 1;	u8 stat;//	while (HWGROUP(drive)->busy)//		ide_delay_50ms();#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)	hwif->ide_dma_host_off(drive);#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */	/*	 * Don't use ide_wait_cmd here - it will	 * attempt to set_geometry and recalibrate,	 * but for some reason these don't work at	 * this point (lost interrupt).	 */        /*         * Select the drive, and issue the SETFEATURES command         */	disable_irq_nosync(hwif->irq);	udelay(1);	SELECT_DRIVE(drive);	SELECT_MASK(drive, 0);	udelay(1);	if (IDE_CONTROL_REG)		hwif->OUTB(drive->ctl | 2, IDE_CONTROL_REG);	hwif->OUTB(speed, IDE_NSECTOR_REG);	hwif->OUTB(SETFEATURES_XFER, IDE_FEATURE_REG);	hwif->OUTB(WIN_SETFEATURES, IDE_COMMAND_REG);	if ((IDE_CONTROL_REG) && (drive->quirk_list == 2))		hwif->OUTB(drive->ctl, IDE_CONTROL_REG);	udelay(1);	/*	 * Wait for drive to become non-BUSY	 */	if ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {		unsigned long flags, timeout;		local_irq_set(flags);		timeout = jiffies + WAIT_CMD;		while ((stat = hwif->INB(IDE_STATUS_REG)) & BUSY_STAT) {			if (time_after(jiffies, timeout))				break;		}		local_irq_restore(flags);	}	/*	 * Allow status to settle, then read it again.	 * A few rare drives vastly violate the 400ns spec here,	 * so we'll wait up to 10usec for a "good" status	 * rather than expensively fail things immediately.	 * This fix courtesy of Matthew Faupel & Niccolo Rigacci.	 */	for (i = 0; i < 10; i++) {		udelay(1);		if (OK_STAT((stat = hwif->INB(IDE_STATUS_REG)), DRIVE_READY, BUSY_STAT|DRQ_STAT|ERR_STAT)) {			error = 0;			break;		}	}	SELECT_MASK(drive, 0);	enable_irq(hwif->irq);	if (error) {		(void) ide_dump_status(drive, "set_drive_speed_status", stat);		return error;	}	drive->id->dma_ultra &= ~0xFF00;	drive->id->dma_mword &= ~0x0F00;	drive->id->dma_1word &= ~0x0F00;#if defined(CONFIG_BLK_DEV_IDEDMA) && !defined(CONFIG_DMA_NONPCI)	if (speed >= XFER_SW_DMA_0)		hwif->ide_dma_host_on(drive);	else		hwif->ide_dma_off_quietly(drive);#endif /* (CONFIG_BLK_DEV_IDEDMA) && !(CONFIG_DMA_NONPCI) */	switch(speed) {		case XFER_UDMA_7:   drive->id->dma_ultra |= 0x8080; break;		case XFER_UDMA_6:   drive->id->dma_ultra |= 0x4040; break;		case XFER_UDMA_5:   drive->id->dma_ultra |= 0x2020; break;		case XFER_UDMA_4:   drive->id->dma_ultra |= 0x1010; break;		case XFER_UDMA_3:   drive->id->dma_ultra |= 0x0808; break;		case XFER_UDMA_2:   drive->id->dma_ultra |= 0x0404; break;		case XFER_UDMA_1:   drive->id->dma_ultra |= 0x0202; break;		case XFER_UDMA_0:   drive->id->dma_ultra |= 0x0101; break;		case XFER_MW_DMA_2: drive->id->dma_mword |= 0x0404; break;		case XFER_MW_DMA_1: drive->id->dma_mword |= 0x0202; break;		case XFER_MW_DMA_0: drive->id->dma_mword |= 0x0101; break;		case XFER_SW_DMA_2: drive->id->dma_1word |= 0x0404; break;		case XFER_SW_DMA_1: drive->id->dma_1word |= 0x0202; break;		case XFER_SW_DMA_0: drive->id->dma_1word |= 0x0101; break;		default: break;	}	if (!drive->init_speed)		drive->init_speed = speed;	drive->current_speed = speed;	return error;}EXPORT_SYMBOL(ide_config_drive_speed);/* * This should get invoked any time we exit the driver to * wait for an interrupt response from a drive.  handler() points * at the appropriate code to handle the next interrupt, and a * timer is started to prevent us from waiting forever in case * something goes wrong (see the ide_timer_expiry() handler later on). * * See also ide_execute_command */void __ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,		      unsigned int timeout, ide_expiry_t *expiry){	ide_hwgroup_t *hwgroup = HWGROUP(drive);	if (hwgroup->handler != NULL) {		printk(KERN_CRIT "%s: ide_set_handler: handler not null; "			"old=%p, new=%p\n",			drive->name, hwgroup->handler, handler);		BUG();	}	hwgroup->handler	= handler;	hwgroup->expiry		= expiry;	hwgroup->timer.expires	= jiffies + timeout;	add_timer(&hwgroup->timer);}EXPORT_SYMBOL(__ide_set_handler);void ide_set_handler (ide_drive_t *drive, ide_handler_t *handler,		      unsigned int timeout, ide_expiry_t *expiry){	unsigned long flags;	spin_lock_irqsave(&io_request_lock, flags);	__ide_set_handler(drive, handler, timeout, expiry);	spin_unlock_irqrestore(&io_request_lock, flags);}EXPORT_SYMBOL(ide_set_handler);/** *	ide_execute_command	-	execute an IDE command *	@drive: IDE drive to issue the command against *	@command: command byte to write *	@handler: handler for next phase *	@timeout: timeout for command *	@expiry:  handler to run on timeout * *	Helper function to issue an IDE command. This handles the *	atomicity requirements, command timing and ensures that the  *	handler and IRQ setup do not race. All IDE command kick off *	should go via this function or do equivalent locking. */ void ide_execute_command(ide_drive_t *drive, task_ioreg_t cmd, ide_handler_t *handler, unsigned timeout, ide_expiry_t *expiry){	unsigned long flags;	ide_hwgroup_t *hwgroup = HWGROUP(drive);	ide_hwif_t *hwif = HWIF(drive);		spin_lock_irqsave(&io_request_lock, flags);		if(hwgroup->handler)		BUG();	hwgroup->handler	= handler;	hwgroup->expiry		= expiry;	hwgroup->timer.expires	= jiffies + timeout;	add_timer(&hwgroup->timer);	hwif->OUTBSYNC(drive, cmd, IDE_COMMAND_REG);	/* Drive takes 400nS to respond, we must avoid the IRQ being	   serviced before that. 	   	   FIXME: we could skip this delay with care on non shared	   devices 	   	   For DMA transfers highpoint have a neat trick we could	   use. When they take an IRQ they check STS but also that	   the DMA count is not zero (see hpt's own driver)	*/	ndelay(400);	spin_unlock_irqrestore(&io_request_lock, flags);}EXPORT_SYMBOL(ide_execute_command);/* needed below */static ide_startstop_t do_reset1 (ide_drive_t *, int);/* * atapi_reset_pollfunc() gets invoked to poll the interface for completion every 50ms * during an atapi drive reset operation. If the drive has not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. */static ide_startstop_t atapi_reset_pollfunc (ide_drive_t *drive){	ide_hwgroup_t *hwgroup	= HWGROUP(drive);	ide_hwif_t *hwif	= HWIF(drive);	u8 stat;	SELECT_DRIVE(drive);	udelay (10);	if (OK_STAT(stat = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {		printk("%s: ATAPI reset complete\n", drive->name);	} else {		if (time_before(jiffies, hwgroup->poll_timeout)) {			if (HWGROUP(drive)->handler != NULL)				BUG();			ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);			/* continue polling */			return ide_started;		}		/* end of polling */		hwgroup->poll_timeout = 0;		printk("%s: ATAPI reset timed-out, status=0x%02x\n",				drive->name, stat);		/* do it the old fashioned way */		return do_reset1(drive, 1);	}	/* done polling */	hwgroup->poll_timeout = 0;	return ide_stopped;}/* * reset_pollfunc() gets invoked to poll the interface for completion every 50ms * during an ide reset operation. If the drives have not yet responded, * and we have not yet hit our maximum waiting time, then the timer is restarted * for another 50ms. */static ide_startstop_t reset_pollfunc (ide_drive_t *drive){	ide_hwgroup_t *hwgroup	= HWGROUP(drive);	ide_hwif_t *hwif	= HWIF(drive);	u8 tmp;	if (hwif->reset_poll != NULL) {		if (hwif->reset_poll(drive)) {			printk(KERN_ERR "%s: host reset_poll failure for %s.\n",				hwif->name, drive->name);			return ide_stopped;		}	}	if (!OK_STAT(tmp = hwif->INB(IDE_STATUS_REG), 0, BUSY_STAT)) {		if (time_before(jiffies, hwgroup->poll_timeout)) {			if (HWGROUP(drive)->handler != NULL)				BUG();			ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);			/* continue polling */			return ide_started;		}		printk("%s: reset timed-out, status=0x%02x\n", hwif->name, tmp);		drive->failures++;	} else  {		printk("%s: reset: ", hwif->name);		if ((tmp = hwif->INB(IDE_ERROR_REG)) == 1) {			printk("success\n");			drive->failures = 0;		} else {			drive->failures++;#if FANCY_STATUS_DUMPS			printk("master: ");			switch (tmp & 0x7f) {				case 1: printk("passed");					break;				case 2: printk("formatter device error");					break;				case 3: printk("sector buffer error");					break;				case 4: printk("ECC circuitry error");					break;				case 5: printk("controlling MPU error");					break;				default:printk("error (0x%02x?)", tmp);			}			if (tmp & 0x80)				printk("; slave: failed");			printk("\n");#else			printk("failed\n");#endif /* FANCY_STATUS_DUMPS */		}	}	hwgroup->poll_timeout = 0;	/* done polling */	return ide_stopped;}void check_dma_crc (ide_drive_t *drive){	if (drive->crc_count) {		(void) HWIF(drive)->ide_dma_off_quietly(drive);		ide_set_xfer_rate(drive, ide_auto_reduce_xfer(drive));		if (drive->current_speed >= XFER_SW_DMA_0)			(void) HWIF(drive)->ide_dma_on(drive);	} else {		(void) HWIF(drive)->ide_dma_off(drive);	}}void pre_reset (ide_drive_t *drive){	DRIVER(drive)->pre_reset(drive);	if (!drive->keep_settings) {		if (drive->using_dma) {			check_dma_crc(drive);		} else {			drive->unmask = 0;			drive->io_32bit = 0;		}		return;	}	if (drive->using_dma)		check_dma_crc(drive);	if (HWIF(drive)->pre_reset != NULL)		HWIF(drive)->pre_reset(drive);}/* * do_reset1() attempts to recover a confused drive by resetting it. * Unfortunately, resetting a disk drive actually resets all devices on * the same interface, so it can really be thought of as resetting the * interface rather than resetting the drive. * * ATAPI devices have their own reset mechanism which allows them to be * individually reset without clobbering other devices on the same interface. * * Unfortunately, the IDE interface does not generate an interrupt to let * us know when the reset operation has finished, so we must poll for this. * Equally poor, though, is the fact that this may a very long time to complete, * (up to 30 seconds worstcase).  So, instead of busy-waiting here for it, * we set a timer to poll at 50ms intervals. */static ide_startstop_t do_reset1 (ide_drive_t *drive, int do_not_try_atapi){	unsigned int unit;	unsigned long flags;	ide_hwif_t *hwif;	ide_hwgroup_t *hwgroup;		spin_lock_irqsave(&io_request_lock, flags);		hwgroup = HWGROUP(drive);	hwif = HWIF(drive);		/* We must not reset with running handlers */	if(hwgroup->handler != NULL)		BUG();	/* For an ATAPI device, first try an ATAPI SRST. */	if (drive->media != ide_disk && !do_not_try_atapi) {		pre_reset(drive);		SELECT_DRIVE(drive);		udelay (20);		hwif->OUTB(WIN_SRST, IDE_COMMAND_REG);		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;		__ide_set_handler(drive, &atapi_reset_pollfunc, HZ/20, NULL);		spin_unlock_irqrestore(&io_request_lock, flags);		return ide_started;	}	/*	 * First, reset any device state data we were maintaining	 * for any of the drives on this interface.	 */	for (unit = 0; unit < MAX_DRIVES; ++unit)		pre_reset(&hwif->drives[unit]);#if OK_TO_RESET_CONTROLLER	if (!IDE_CONTROL_REG) {		spin_unlock_irqrestore(&io_request_lock, flags);		return ide_stopped;	}	/*	 * Note that we also set nIEN while resetting the device,	 * to mask unwanted interrupts from the interface during the reset.	 * However, due to the design of PC hardware, this will cause an	 * immediate interrupt due to the edge transition it produces.	 * This single interrupt gives us a "fast poll" for drives that	 * recover from reset very quickly, saving us the first 50ms wait time.	 */	/* set SRST and nIEN */	hwif->OUTBSYNC(drive, drive->ctl|6,IDE_CONTROL_REG);	/* more than enough time */	udelay(10);	if (drive->quirk_list == 2) {		/* clear SRST and nIEN */		hwif->OUTBSYNC(drive, drive->ctl, IDE_CONTROL_REG);	} else {		/* clear SRST, leave nIEN */		hwif->OUTBSYNC(drive, drive->ctl|2, IDE_CONTROL_REG);	}	/* more than enough time */	udelay(10);		hwgroup->poll_timeout = jiffies + WAIT_WORSTCASE;	__ide_set_handler(drive, &reset_pollfunc, HZ/20, NULL);	/*	 * Some weird controller like resetting themselves to a strange	 * state when the disks are reset this way. At least, the Winbond	 * 553 documentation says that	 */	if (hwif->resetproc != NULL) {		hwif->resetproc(drive);	}#endif	/* OK_TO_RESET_CONTROLLER */	spin_unlock_irqrestore(&io_request_lock, flags);	return ide_started;}/* * ide_do_reset() is the entry point to the drive/interface reset code. * * Caller must not hold the io_request lock. */ ide_startstop_t ide_do_reset (ide_drive_t *drive){	return do_reset1(drive, 0);}EXPORT_SYMBOL(ide_do_reset);

⌨️ 快捷键说明

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