aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libata-core.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-05-15 07:58:09 -0400
committerTejun Heo <htejun@gmail.com>2006-05-15 07:58:09 -0400
commite318049949b07152d851dbfebbd93e560af45ebe (patch)
treecbc322c94717c9ac5d7e2c48a9f690a2e0145b81 /drivers/scsi/libata-core.c
parent7b70fc039824bc7303e4007a5f758f832de56611 (diff)
[PATCH] libata-eh-fw: implement freeze/thaw
Freezing is performed atomic w.r.t. host_set->lock and once frozen LLDD is not allowed to access the port or any qc on it. Also, libata makes sure that no new qc gets issued to a frozen port. A frozen port is thawed after a reset operation completes successfully, so reset methods must do its job while the port is frozen. During initialization all ports get frozen before requesting IRQ, so reset methods are always invoked on a frozen port. Optional ->freeze and ->thaw operations notify LLDD that the port is being frozen and thawed, respectively. LLDD can disable/enable hardware interrupt in these callbacks if the controller's IRQ mask can be changed dynamically. If the controller doesn't allow such operation, LLDD can check for frozen state in the interrupt handler and ack/clear interrupts unconditionally while frozen. Signed-off-by: Tejun Heo <htejun@gmail.com>
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r--drivers/scsi/libata-core.c26
1 files changed, 24 insertions, 2 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 9c97783462d6..63857a90ac28 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -987,6 +987,12 @@ unsigned ata_exec_internal(struct ata_device *dev,
987 987
988 spin_lock_irqsave(&ap->host_set->lock, flags); 988 spin_lock_irqsave(&ap->host_set->lock, flags);
989 989
990 /* no internal command while frozen */
991 if (ap->flags & ATA_FLAG_FROZEN) {
992 spin_unlock_irqrestore(&ap->host_set->lock, flags);
993 return AC_ERR_SYSTEM;
994 }
995
990 /* initialize internal qc */ 996 /* initialize internal qc */
991 997
992 /* XXX: Tag 0 is used for drivers with legacy EH as some 998 /* XXX: Tag 0 is used for drivers with legacy EH as some
@@ -2565,8 +2571,11 @@ void ata_std_postreset(struct ata_port *ap, unsigned int *classes)
2565 sata_scr_write(ap, SCR_ERROR, serror); 2571 sata_scr_write(ap, SCR_ERROR, serror);
2566 2572
2567 /* re-enable interrupts */ 2573 /* re-enable interrupts */
2568 if (ap->ioaddr.ctl_addr) /* FIXME: hack. create a hook instead */ 2574 if (!ap->ops->error_handler) {
2569 ata_irq_on(ap); 2575 /* FIXME: hack. create a hook instead */
2576 if (ap->ioaddr.ctl_addr)
2577 ata_irq_on(ap);
2578 }
2570 2579
2571 /* is double-select really necessary? */ 2580 /* is double-select really necessary? */
2572 if (classes[0] != ATA_DEV_NONE) 2581 if (classes[0] != ATA_DEV_NONE)
@@ -2681,6 +2690,8 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
2681{ 2690{
2682 int rc = -EINVAL; 2691 int rc = -EINVAL;
2683 2692
2693 ata_eh_freeze_port(ap);
2694
2684 if (probeinit) 2695 if (probeinit)
2685 probeinit(ap); 2696 probeinit(ap);
2686 2697
@@ -2725,6 +2736,9 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
2725 if (rc == 0) { 2736 if (rc == 0) {
2726 if (postreset) 2737 if (postreset)
2727 postreset(ap, classes); 2738 postreset(ap, classes);
2739
2740 ata_eh_thaw_port(ap);
2741
2728 if (classes[0] == ATA_DEV_UNKNOWN) 2742 if (classes[0] == ATA_DEV_UNKNOWN)
2729 rc = -ENODEV; 2743 rc = -ENODEV;
2730 } 2744 }
@@ -4039,6 +4053,10 @@ static struct ata_queued_cmd *ata_qc_new(struct ata_port *ap)
4039 struct ata_queued_cmd *qc = NULL; 4053 struct ata_queued_cmd *qc = NULL;
4040 unsigned int i; 4054 unsigned int i;
4041 4055
4056 /* no command while frozen */
4057 if (unlikely(ap->flags & ATA_FLAG_FROZEN))
4058 return NULL;
4059
4042 /* the last tag is reserved for internal command. */ 4060 /* the last tag is reserved for internal command. */
4043 for (i = 0; i < ATA_MAX_QUEUE - 1; i++) 4061 for (i = 0; i < ATA_MAX_QUEUE - 1; i++)
4044 if (!test_and_set_bit(i, &ap->qactive)) { 4062 if (!test_and_set_bit(i, &ap->qactive)) {
@@ -4953,6 +4971,7 @@ int ata_device_add(const struct ata_probe_ent *ent)
4953 4971
4954 ata_chk_status(ap); 4972 ata_chk_status(ap);
4955 host_set->ops->irq_clear(ap); 4973 host_set->ops->irq_clear(ap);
4974 ata_eh_freeze_port(ap); /* freeze port before requesting IRQ */
4956 count++; 4975 count++;
4957 } 4976 }
4958 4977
@@ -5385,5 +5404,8 @@ EXPORT_SYMBOL_GPL(ata_scsi_device_resume);
5385EXPORT_SYMBOL_GPL(ata_eng_timeout); 5404EXPORT_SYMBOL_GPL(ata_eng_timeout);
5386EXPORT_SYMBOL_GPL(ata_port_schedule_eh); 5405EXPORT_SYMBOL_GPL(ata_port_schedule_eh);
5387EXPORT_SYMBOL_GPL(ata_port_abort); 5406EXPORT_SYMBOL_GPL(ata_port_abort);
5407EXPORT_SYMBOL_GPL(ata_port_freeze);
5408EXPORT_SYMBOL_GPL(ata_eh_freeze_port);
5409EXPORT_SYMBOL_GPL(ata_eh_thaw_port);
5388EXPORT_SYMBOL_GPL(ata_eh_qc_complete); 5410EXPORT_SYMBOL_GPL(ata_eh_qc_complete);
5389EXPORT_SYMBOL_GPL(ata_eh_qc_retry); 5411EXPORT_SYMBOL_GPL(ata_eh_qc_retry);