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

📄 ide-io.c

📁 ep9315平台下硬盘驱动的源码
💻 C
📖 第 1 页 / 共 3 页
字号:
	/*	 * complain a little, later we might remove some of this verbosity	 */	if (error < 0) {		printk(KERN_ERR "%s: error waiting for DMA\n", drive->name);		(void)HWIF(drive)->ide_dma_end(drive);		ret = DRIVER(drive)->error(drive, "dma timeout retry",				hwif->INB(IDE_STATUS_REG));	} else {	printk(KERN_ERR "%s: timeout waiting for DMA\n", drive->name);	(void) hwif->ide_dma_timeout(drive);	}	/*	 * disable dma for now, but remember that we did so because of	 * a timeout -- we'll reenable after we finish this next request	 * (or rather the first chunk of it) in pio.	 */	drive->retry_pio++;	drive->state = DMA_PIO_RETRY;	(void) hwif->ide_dma_off_quietly(drive);	/*	 * un-busy drive etc (hwgroup->busy is cleared on return) and	 * make sure request is sane	 */	rq = HWGROUP(drive)->rq;	HWGROUP(drive)->rq = NULL;	rq->errors = 0;	rq->sector = rq->bh->b_rsector;	rq->current_nr_sectors = rq->bh->b_size >> 9;	rq->hard_cur_sectors = rq->current_nr_sectors;	rq->buffer = rq->bh->b_data;	return ret;}/** *	ide_timer_expiry	-	handle lack of an IDE interrupt *	@data: timer callback magic (hwgroup) * *	An IDE command has timed out before the expected drive return *	occurred. At this point we attempt to clean up the current *	mess. If the current handler includes an expiry handler then *	we invoke the expiry handler, and providing it is happy the *	work is done. If that fails we apply generic recovery rules *	invoking the handler and checking the drive DMA status. We *	have an excessively incestuous relationship with the DMA *	logic that wants cleaning up. */ void ide_timer_expiry (unsigned long data){	ide_hwgroup_t	*hwgroup = (ide_hwgroup_t *) data;	ide_handler_t	*handler;	ide_expiry_t	*expiry; 	unsigned long	flags;	unsigned long	wait = -1;	spin_lock_irqsave(&io_request_lock, flags);	if ((handler = hwgroup->handler) == NULL) {		/*		 * Either a marginal timeout occurred		 * (got the interrupt just as timer expired),		 * or we were "sleeping" to give other devices a chance.		 * Either way, we don't really want to complain about anything.		 */		if (hwgroup->sleeping) {			hwgroup->sleeping = 0;			hwgroup->busy = 0;		}	} else {		ide_drive_t *drive = hwgroup->drive;		if (!drive) {			printk(KERN_ERR "ide_timer_expiry: hwgroup->drive was NULL\n");			hwgroup->handler = NULL;		} else {			ide_hwif_t *hwif;			ide_startstop_t startstop = ide_stopped;			if (!hwgroup->busy) {				hwgroup->busy = 1;	/* paranoia */				printk(KERN_ERR "%s: ide_timer_expiry: hwgroup->busy was 0 ??\n", drive->name);			}			if ((expiry = hwgroup->expiry) != NULL) {				/* continue */				if ((wait = expiry(drive)) > 0) {					/* reset timer */					hwgroup->timer.expires  = jiffies + wait;					add_timer(&hwgroup->timer);					spin_unlock_irqrestore(&io_request_lock, flags);					return;				}			}			hwgroup->handler = NULL;			/*			 * We need to simulate a real interrupt when invoking			 * the handler() function, which means we need to			 * globally mask the specific IRQ:			 */			spin_unlock(&io_request_lock);			hwif  = HWIF(drive);#if DISABLE_IRQ_NOSYNC			disable_irq_nosync(hwif->irq);#else			/* disable_irq_nosync ?? */			disable_irq(hwif->irq);#endif /* DISABLE_IRQ_NOSYNC */			/* local CPU only,			 * as if we were handling an interrupt */			local_irq_disable();			if (hwgroup->poll_timeout != 0) {				startstop = handler(drive);			} else if (drive_is_ready(drive)) {				if (drive->waiting_for_dma)					(void) hwgroup->hwif->ide_dma_lostirq(drive);				(void)ide_ack_intr(hwif);				printk(KERN_ERR "%s: lost interrupt\n", drive->name);				startstop = handler(drive);			} else {				if (drive->waiting_for_dma) {					startstop = ide_dma_timeout_retry(drive, wait);				} else {					startstop = DRIVER(drive)->error(drive, "irq timeout", hwif->INB(IDE_STATUS_REG));				}			}			set_recovery_timer(hwif);			drive->service_time = jiffies - drive->service_start;			spin_lock_irq(&io_request_lock);			enable_irq(hwif->irq);			if (startstop == ide_stopped)				hwgroup->busy = 0;		}	}	ide_do_request(hwgroup, IDE_NO_IRQ);	spin_unlock_irqrestore(&io_request_lock, flags);}EXPORT_SYMBOL(ide_timer_expiry);/** *	unexpected_intr		-	handle an unexpected IDE interrupt *	@irq: interrupt line *	@hwgroup: hwgroup being processed * *	There's nothing really useful we can do with an unexpected interrupt, *	other than reading the status register (to clear it), and logging it. *	There should be no way that an irq can happen before we're ready for it, *	so we needn't worry much about losing an "important" interrupt here. * *	On laptops (and "green" PCs), an unexpected interrupt occurs whenever *	the drive enters "idle", "standby", or "sleep" mode, so if the status *	looks "good", we just ignore the interrupt completely. * *	This routine assumes __cli() is in effect when called. * *	If an unexpected interrupt happens on irq15 while we are handling irq14 *	and if the two interfaces are "serialized" (CMD640), then it looks like *	we could screw up by interfering with a new request being set up for  *	irq15. * *	In reality, this is a non-issue.  The new command is not sent unless  *	the drive is ready to accept one, in which case we know the drive is *	not trying to interrupt us.  And ide_set_handler() is always invoked *	before completing the issuance of any new drive command, so we will not *	be accidentally invoked as a result of any valid command completion *	interrupt. * *	Note that we must walk the entire hwgroup here. We know which hwif *	is doing the current command, but we don't know which hwif burped *	mysteriously. */ static void unexpected_intr (int irq, ide_hwgroup_t *hwgroup){	u8 stat;	ide_hwif_t *hwif = hwgroup->hwif;	/*	 * handle the unexpected interrupt	 */	do {		if (hwif->irq == irq) {			stat = hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);			if (!OK_STAT(stat, READY_STAT, BAD_STAT)) {				/* Try to not flood the console with msgs */				static unsigned long last_msgtime, count;				++count;				if (time_after(jiffies, last_msgtime + HZ)) {					last_msgtime = jiffies;					printk(KERN_ERR "%s%s: unexpected interrupt, "						"status=0x%02x, count=%ld\n",						hwif->name,						(hwif->next==hwgroup->hwif) ? "" : "(?)", stat, count);				}			}		}	} while ((hwif = hwif->next) != hwgroup->hwif);}/** *	ide_intr	-	default IDE interrupt handler *	@irq: interrupt number *	@dev_id: hwif group *	@regs: unused weirdness from the kernel irq layer * *	This is the default IRQ handler for the IDE layer. You should *	not need to override it. If you do be aware it is subtle in *	places * *	hwgroup->hwif is the interface in the group currently performing *	a command. hwgroup->drive is the drive and hwgroup->handler is *	the IRQ handler to call. As we issue a command the handlers *	step through multiple states, reassigning the handler to the *	next step in the process. Unlike a smart SCSI controller IDE *	expects the main processor to sequence the various transfer *	stages. We also manage a poll timer to catch up with most *	timeout situations. There are still a few where the handlers *	don't ever decide to give up. * *	The handler eventually returns ide_stopped to indicate the *	request completed. At this point we issue the next request *	on the hwgroup and the process begins again. */ void ide_intr (int irq, void *dev_id, struct pt_regs *regs){	unsigned long flags;	ide_hwgroup_t *hwgroup = (ide_hwgroup_t *)dev_id;	ide_hwif_t *hwif;	ide_drive_t *drive;	ide_handler_t *handler;	ide_startstop_t startstop;	spin_lock_irqsave(&io_request_lock, flags);	hwif = hwgroup->hwif;	if (!ide_ack_intr(hwif)) {		spin_unlock_irqrestore(&io_request_lock, flags);		return;	}	if ((handler = hwgroup->handler) == NULL ||	    hwgroup->poll_timeout != 0) {		/*		 * Not expecting an interrupt from this drive.		 * That means this could be:		 *	(1) an interrupt from another PCI device		 *	sharing the same PCI INT# as us.		 * or	(2) a drive just entered sleep or standby mode,		 *	and is interrupting to let us know.		 * or	(3) a spurious interrupt of unknown origin.		 *		 * For PCI, we cannot tell the difference,		 * so in that case we just ignore it and hope it goes away.		 */#ifdef CONFIG_BLK_DEV_IDEPCI		if (hwif->pci_dev && !hwif->pci_dev->vendor)#endif	/* CONFIG_BLK_DEV_IDEPCI */		{			/*			 * Probably not a shared PCI interrupt,			 * so we can safely try to do something about it:			 */			unexpected_intr(irq, hwgroup);#ifdef CONFIG_BLK_DEV_IDEPCI		} else {			/*			 * Whack the status register, just in case			 * we have a leftover pending IRQ.			 */			(void) hwif->INB(hwif->io_ports[IDE_STATUS_OFFSET]);#endif /* CONFIG_BLK_DEV_IDEPCI */		}		spin_unlock_irqrestore(&io_request_lock, flags);		return;	}	drive = hwgroup->drive;	if (!drive) {		/*		 * This should NEVER happen, and there isn't much		 * we could do about it here.		 */		spin_unlock_irqrestore(&io_request_lock, flags);		return;	}	if (!drive_is_ready(drive)) {		/*		 * This happens regularly when we share a PCI IRQ with		 * another device.  Unfortunately, it can also happen		 * with some buggy drives that trigger the IRQ before		 * their status register is up to date.  Hopefully we have		 * enough advance overhead that the latter isn't a problem.		 */		spin_unlock_irqrestore(&io_request_lock, flags);		return;	}	if (!hwgroup->busy) {		hwgroup->busy = 1;	/* paranoia */		printk(KERN_ERR "%s: ide_intr: hwgroup->busy was 0 ??\n", drive->name);	}	hwgroup->handler = NULL;	del_timer(&hwgroup->timer);	spin_unlock(&io_request_lock);	if (drive->unmask)		local_irq_enable();	/* service this interrupt, may set handler for next interrupt */	startstop = handler(drive);	spin_lock_irq(&io_request_lock);	/*	 * Note that handler() may have set things up for another	 * interrupt to occur soon, but it cannot happen until	 * we exit from this routine, because it will be the	 * same irq as is currently being serviced here, and Linux	 * won't allow another of the same (on any CPU) until we return.	 */	set_recovery_timer(HWIF(drive));	drive->service_time = jiffies - drive->service_start;	if (startstop == ide_stopped) {		if (hwgroup->handler == NULL) {	/* paranoia */			hwgroup->busy = 0;			ide_do_request(hwgroup, hwif->irq);		} else {			printk(KERN_ERR "%s: ide_intr: huh? expected NULL handler "				"on exit\n", drive->name);		}	}	spin_unlock_irqrestore(&io_request_lock, flags);}EXPORT_SYMBOL(ide_intr);/* * get_info_ptr() returns the (ide_drive_t *) for a given device number. * It returns NULL if the given device number does not match any present drives. */ide_drive_t *get_info_ptr (kdev_t i_rdev){	int		major = MAJOR(i_rdev);	unsigned int	h;	for (h = 0; h < MAX_HWIFS; ++h) {		ide_hwif_t  *hwif = &ide_hwifs[h];		if (hwif->present && major == hwif->major) {			unsigned unit = DEVICE_NR(i_rdev);			if (unit < MAX_DRIVES) {				ide_drive_t *drive = &hwif->drives[unit];				if (drive->present)					return drive;			}			break;		}	}	return NULL;}EXPORT_SYMBOL(get_info_ptr);/** *	ide_init_drive_cmd	-	initialize a drive command request *	@rq: request object * *	Initialize a request before we fill it in and send it down to *	ide_do_drive_cmd. Commands must be set up by this function. Right *	now it doesn't do a lot, but if that changes abusers will have a *	nasty suprise. */void ide_init_drive_cmd (struct request *rq){	memset(rq, 0, sizeof(*rq));	rq->cmd = IDE_DRIVE_CMD;}EXPORT_SYMBOL(ide_init_drive_cmd);/** *	ide_do_drive_cmd	-	issue IDE special command *	@drive: device to issue command *	@rq: request to issue *	@action: action for processing * *	This function issues a special IDE device request *	onto the request queue. * *	If action is ide_wait, then the rq is queued at the end of the *	request queue, and the function sleeps until it has been processed. *	This is for use when invoked from an ioctl handler. * *	If action is ide_preempt, then the rq is queued at the head of *	the request queue, displacing the currently-being-processed *	request and this function returns immediately without waiting *	for the new rq to be completed.  This is VERY DANGEROUS, and is *	intended for careful use by the ATAPI tape/cdrom driver code. * *	If action is ide_next, then the rq is queued immediately after *	the currently-being-processed-request (if any), and the function *	returns without waiting for the new rq to be completed.  As above, *	This is VERY DANGEROUS, and is intended for careful use by the *	ATAPI tape/cdrom driver code. * *	If action is ide_end, then the rq is queued at the end of the *	request queue, and the function returns immediately without waiting *	for the new rq to be completed. This is again intended for careful *	use by the ATAPI tape/cdrom driver code. */ int ide_do_drive_cmd (ide_drive_t *drive, struct request *rq, ide_action_t action){	unsigned long flags;	ide_hwgroup_t *hwgroup = HWGROUP(drive);	unsigned int major = HWIF(drive)->major;	request_queue_t *q = &drive->queue;	struct list_head *queue_head = &q->queue_head;	DECLARE_COMPLETION(wait);#ifdef CONFIG_BLK_DEV_PDC4030	if (HWIF(drive)->chipset == ide_pdc4030 && rq->buffer != NULL)		return -ENOSYS;  /* special drive cmds not supported */#endif	rq->errors = 0;	rq->rq_status = RQ_ACTIVE;	rq->rq_dev = MKDEV(major,(drive->select.b.unit)<<PARTN_BITS);	if (action == ide_wait)		rq->waiting = &wait;	spin_lock_irqsave(&io_request_lock, flags);	if (blk_queue_empty(q) || action == ide_preempt) {		if (action == ide_preempt)			hwgroup->rq = NULL;	} else {		if (action == ide_wait || action == ide_end) {			queue_head = queue_head->prev;		} else			queue_head = queue_head->next;	}	list_add(&rq->queue, queue_head);	ide_do_request(hwgroup, IDE_NO_IRQ);	spin_unlock_irqrestore(&io_request_lock, flags);	if (action == ide_wait) {		/* wait for it to be serviced */		wait_for_completion(&wait);		/* return -EIO if errors */		return rq->errors ? -EIO : 0;	}	return 0;}EXPORT_SYMBOL(ide_do_drive_cmd);

⌨️ 快捷键说明

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