aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/scsi/libata-core.c26
-rw-r--r--drivers/scsi/libata-eh.c103
2 files changed, 127 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);
diff --git a/drivers/scsi/libata-eh.c b/drivers/scsi/libata-eh.c
index 037a561809f5..cb4e2b8d32d9 100644
--- a/drivers/scsi/libata-eh.c
+++ b/drivers/scsi/libata-eh.c
@@ -291,6 +291,109 @@ int ata_port_abort(struct ata_port *ap)
291 return nr_aborted; 291 return nr_aborted;
292} 292}
293 293
294/**
295 * __ata_port_freeze - freeze port
296 * @ap: ATA port to freeze
297 *
298 * This function is called when HSM violation or some other
299 * condition disrupts normal operation of the port. Frozen port
300 * is not allowed to perform any operation until the port is
301 * thawed, which usually follows a successful reset.
302 *
303 * ap->ops->freeze() callback can be used for freezing the port
304 * hardware-wise (e.g. mask interrupt and stop DMA engine). If a
305 * port cannot be frozen hardware-wise, the interrupt handler
306 * must ack and clear interrupts unconditionally while the port
307 * is frozen.
308 *
309 * LOCKING:
310 * spin_lock_irqsave(host_set lock)
311 */
312static void __ata_port_freeze(struct ata_port *ap)
313{
314 WARN_ON(!ap->ops->error_handler);
315
316 if (ap->ops->freeze)
317 ap->ops->freeze(ap);
318
319 ap->flags |= ATA_FLAG_FROZEN;
320
321 DPRINTK("ata%u port frozen\n", ap->id);
322}
323
324/**
325 * ata_port_freeze - abort & freeze port
326 * @ap: ATA port to freeze
327 *
328 * Abort and freeze @ap.
329 *
330 * LOCKING:
331 * spin_lock_irqsave(host_set lock)
332 *
333 * RETURNS:
334 * Number of aborted commands.
335 */
336int ata_port_freeze(struct ata_port *ap)
337{
338 int nr_aborted;
339
340 WARN_ON(!ap->ops->error_handler);
341
342 nr_aborted = ata_port_abort(ap);
343 __ata_port_freeze(ap);
344
345 return nr_aborted;
346}
347
348/**
349 * ata_eh_freeze_port - EH helper to freeze port
350 * @ap: ATA port to freeze
351 *
352 * Freeze @ap.
353 *
354 * LOCKING:
355 * None.
356 */
357void ata_eh_freeze_port(struct ata_port *ap)
358{
359 unsigned long flags;
360
361 if (!ap->ops->error_handler)
362 return;
363
364 spin_lock_irqsave(&ap->host_set->lock, flags);
365 __ata_port_freeze(ap);
366 spin_unlock_irqrestore(&ap->host_set->lock, flags);
367}
368
369/**
370 * ata_port_thaw_port - EH helper to thaw port
371 * @ap: ATA port to thaw
372 *
373 * Thaw frozen port @ap.
374 *
375 * LOCKING:
376 * None.
377 */
378void ata_eh_thaw_port(struct ata_port *ap)
379{
380 unsigned long flags;
381
382 if (!ap->ops->error_handler)
383 return;
384
385 spin_lock_irqsave(&ap->host_set->lock, flags);
386
387 ap->flags &= ~ATA_FLAG_FROZEN;
388
389 if (ap->ops->thaw)
390 ap->ops->thaw(ap);
391
392 spin_unlock_irqrestore(&ap->host_set->lock, flags);
393
394 DPRINTK("ata%u port thawed\n", ap->id);
395}
396
294static void ata_eh_scsidone(struct scsi_cmnd *scmd) 397static void ata_eh_scsidone(struct scsi_cmnd *scmd)
295{ 398{
296 /* nada */ 399 /* nada */