aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/scsi/libata-core.c26
-rw-r--r--drivers/scsi/libata-eh.c103
-rw-r--r--include/linux/libata.h4
3 files changed, 131 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 */
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 086e14690954..6758b4d374a0 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -665,6 +665,10 @@ extern void ata_eng_timeout(struct ata_port *ap);
665 665
666extern void ata_port_schedule_eh(struct ata_port *ap); 666extern void ata_port_schedule_eh(struct ata_port *ap);
667extern int ata_port_abort(struct ata_port *ap); 667extern int ata_port_abort(struct ata_port *ap);
668extern int ata_port_freeze(struct ata_port *ap);
669
670extern void ata_eh_freeze_port(struct ata_port *ap);
671extern void ata_eh_thaw_port(struct ata_port *ap);
668 672
669extern void ata_eh_qc_complete(struct ata_queued_cmd *qc); 673extern void ata_eh_qc_complete(struct ata_queued_cmd *qc);
670extern void ata_eh_qc_retry(struct ata_queued_cmd *qc); 674extern void ata_eh_qc_retry(struct ata_queued_cmd *qc);