示例#1
0
/*
 * Called when an error was detected during the last packet command.
 * We queue a request sense packet command at the head of the request
 * queue.
 */
void ide_retry_pc(ide_drive_t *drive)
{
	struct request *failed_rq = drive->hwif->rq;
	struct request *sense_rq = &drive->sense_rq;
	struct ide_atapi_pc *pc = &drive->request_sense_pc;

	(void)ide_read_error(drive);

	/* init pc from sense_rq */
	ide_init_pc(pc);
	memcpy(pc->c, sense_rq->cmd, 12);

	if (drive->media == ide_tape)
		drive->atapi_flags |= IDE_AFLAG_IGNORE_DSC;

	/*
	 * Push back the failed request and put request sense on top
	 * of it.  The failed command will be retried after sense data
	 * is acquired.
	 */
	drive->hwif->rq = NULL;
	ide_requeue_and_plug(drive, failed_rq);
	if (ide_queue_sense_rq(drive, pc)) {
		blk_start_request(failed_rq);
		ide_complete_rq(drive, -EIO, blk_rq_bytes(failed_rq));
	}
}
示例#2
0
文件: ide-io.c 项目: 03199618/linux
irqreturn_t ide_intr (int irq, void *dev_id)
{
	ide_hwif_t *hwif = (ide_hwif_t *)dev_id;
	struct ide_host *host = hwif->host;
	ide_drive_t *uninitialized_var(drive);
	ide_handler_t *handler;
	unsigned long flags;
	ide_startstop_t startstop;
	irqreturn_t irq_ret = IRQ_NONE;
	int plug_device = 0;
	struct request *uninitialized_var(rq_in_flight);

	if (host->host_flags & IDE_HFLAG_SERIALIZE) {
		if (hwif != host->cur_port)
			goto out_early;
	}

	spin_lock_irqsave(&hwif->lock, flags);

	if (hwif->port_ops && hwif->port_ops->test_irq &&
	    hwif->port_ops->test_irq(hwif) == 0)
		goto out;

	handler = hwif->handler;

	if (handler == NULL || hwif->polling) {
		/*
		 * 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.
		 */
		if ((host->irq_flags & IRQF_SHARED) == 0) {
			/*
			 * Probably not a shared PCI interrupt,
			 * so we can safely try to do something about it:
			 */
			unexpected_intr(irq, hwif);
		} else {
			/*
			 * Whack the status register, just in case
			 * we have a leftover pending IRQ.
			 */
			(void)hwif->tp_ops->read_status(hwif);
		}
		goto out;
	}

	drive = hwif->cur_dev;

	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.
		 */
		goto out;

	hwif->handler = NULL;
	hwif->expiry = NULL;
	hwif->req_gen++;
	del_timer(&hwif->timer);
	spin_unlock(&hwif->lock);

	if (hwif->port_ops && hwif->port_ops->clear_irq)
		hwif->port_ops->clear_irq(drive);

	if (drive->dev_flags & IDE_DFLAG_UNMASK)
		local_irq_enable_in_hardirq();

	/* service this interrupt, may set handler for next interrupt */
	startstop = handler(drive);

	spin_lock_irq(&hwif->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.
	 */
	if (startstop == ide_stopped && hwif->polling == 0) {
		BUG_ON(hwif->handler);
		rq_in_flight = hwif->rq;
		hwif->rq = NULL;
		ide_unlock_port(hwif);
		plug_device = 1;
	}
	irq_ret = IRQ_HANDLED;
out:
	spin_unlock_irqrestore(&hwif->lock, flags);
out_early:
	if (plug_device) {
		ide_unlock_host(hwif->host);
		ide_requeue_and_plug(drive, rq_in_flight);
	}

	return irq_ret;
}
示例#3
0
文件: ide-io.c 项目: 03199618/linux
void ide_timer_expiry (unsigned long data)
{
	ide_hwif_t	*hwif = (ide_hwif_t *)data;
	ide_drive_t	*uninitialized_var(drive);
	ide_handler_t	*handler;
	unsigned long	flags;
	int		wait = -1;
	int		plug_device = 0;
	struct request	*uninitialized_var(rq_in_flight);

	spin_lock_irqsave(&hwif->lock, flags);

	handler = hwif->handler;

	if (handler == NULL || hwif->req_gen != hwif->req_gen_timer) {
		/*
		 * 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.
		 */
	} else {
		ide_expiry_t *expiry = hwif->expiry;
		ide_startstop_t startstop = ide_stopped;

		drive = hwif->cur_dev;

		if (expiry) {
			wait = expiry(drive);
			if (wait > 0) { /* continue */
				/* reset timer */
				hwif->timer.expires = jiffies + wait;
				hwif->req_gen_timer = hwif->req_gen;
				add_timer(&hwif->timer);
				spin_unlock_irqrestore(&hwif->lock, flags);
				return;
			}
		}
		hwif->handler = NULL;
		hwif->expiry = 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(&hwif->lock);
		/* disable_irq_nosync ?? */
		disable_irq(hwif->irq);
		/* local CPU only, as if we were handling an interrupt */
		local_irq_disable();
		if (hwif->polling) {
			startstop = handler(drive);
		} else if (drive_is_ready(drive)) {
			if (drive->waiting_for_dma)
				hwif->dma_ops->dma_lost_irq(drive);
			if (hwif->port_ops && hwif->port_ops->clear_irq)
				hwif->port_ops->clear_irq(drive);

			printk(KERN_WARNING "%s: lost interrupt\n",
				drive->name);
			startstop = handler(drive);
		} else {
			if (drive->waiting_for_dma)
				startstop = ide_dma_timeout_retry(drive, wait);
			else
				startstop = ide_error(drive, "irq timeout",
					hwif->tp_ops->read_status(hwif));
		}
		spin_lock_irq(&hwif->lock);
		enable_irq(hwif->irq);
		if (startstop == ide_stopped && hwif->polling == 0) {
			rq_in_flight = hwif->rq;
			hwif->rq = NULL;
			ide_unlock_port(hwif);
			plug_device = 1;
		}
	}
	spin_unlock_irqrestore(&hwif->lock, flags);

	if (plug_device) {
		ide_unlock_host(hwif->host);
		ide_requeue_and_plug(drive, rq_in_flight);
	}
}