aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2007-12-15 01:05:06 -0500
committerJeff Garzik <jeff@garzik.org>2007-12-17 20:33:15 -0500
commit3264a8d8f95348e05cc6ac1ce747a8339ed7ab08 (patch)
tree7d9045e726e7e63d6a7cad426b1c9f000298c886
parent0e8634bf8e48e50aa96c7e7becafcf9d98c1a28d (diff)
libata-acpi: implement _GTF command filtering
Implement _GTF command filtering which can be controlled by libata.acpi_filter kernel parameter. Currently SETXFER and LOCK commands are filtered. libata configures transfer mode by itself and _GTF SETXFER commands can potentially disrupt device configuration. _GTM/_STM mechanism can't handle hotplugging too well and when _GTF is executed, controller is in PIO0 rather than the mode _STM configured. Note that detecting SET MAX LOCK requires looking at the previous command. This adds a bit to code complexity. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
-rw-r--r--drivers/ata/libata-acpi.c159
1 files changed, 115 insertions, 44 deletions
diff --git a/drivers/ata/libata-acpi.c b/drivers/ata/libata-acpi.c
index d4cb557a727d..7bf4befd96bc 100644
--- a/drivers/ata/libata-acpi.c
+++ b/drivers/ata/libata-acpi.c
@@ -6,6 +6,7 @@
6 * Copyright (C) 2006 Randy Dunlap 6 * Copyright (C) 2006 Randy Dunlap
7 */ 7 */
8 8
9#include <linux/module.h>
9#include <linux/ata.h> 10#include <linux/ata.h>
10#include <linux/delay.h> 11#include <linux/delay.h>
11#include <linux/device.h> 12#include <linux/device.h>
@@ -25,6 +26,18 @@
25#include <acpi/acmacros.h> 26#include <acpi/acmacros.h>
26#include <acpi/actypes.h> 27#include <acpi/actypes.h>
27 28
29enum {
30 ATA_ACPI_FILTER_SETXFER = 1 << 0,
31 ATA_ACPI_FILTER_LOCK = 1 << 1,
32
33 ATA_ACPI_FILTER_DEFAULT = ATA_ACPI_FILTER_SETXFER |
34 ATA_ACPI_FILTER_LOCK,
35};
36
37static unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT;
38module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644);
39MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=set xfermode, 0x2=lock/freeze lock)");
40
28#define NO_PORT_MULT 0xffff 41#define NO_PORT_MULT 0xffff
29#define SATA_ADR(root, pmp) (((root) << 16) | (pmp)) 42#define SATA_ADR(root, pmp) (((root) << 16) | (pmp))
30 43
@@ -465,6 +478,60 @@ int ata_acpi_cbl_80wire(struct ata_port *ap)
465 478
466EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); 479EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire);
467 480
481static void ata_acpi_gtf_to_tf(struct ata_device *dev,
482 const struct ata_acpi_gtf *gtf,
483 struct ata_taskfile *tf)
484{
485 ata_tf_init(dev, tf);
486
487 tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE;
488 tf->protocol = ATA_PROT_NODATA;
489 tf->feature = gtf->tf[0]; /* 0x1f1 */
490 tf->nsect = gtf->tf[1]; /* 0x1f2 */
491 tf->lbal = gtf->tf[2]; /* 0x1f3 */
492 tf->lbam = gtf->tf[3]; /* 0x1f4 */
493 tf->lbah = gtf->tf[4]; /* 0x1f5 */
494 tf->device = gtf->tf[5]; /* 0x1f6 */
495 tf->command = gtf->tf[6]; /* 0x1f7 */
496}
497
498static int ata_acpi_filter_tf(const struct ata_taskfile *tf,
499 const struct ata_taskfile *ptf)
500{
501 if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_SETXFER) {
502 /* libata doesn't use ACPI to configure transfer mode.
503 * It will only confuse device configuration. Skip.
504 */
505 if (tf->command == ATA_CMD_SET_FEATURES &&
506 tf->feature == SETFEATURES_XFER)
507 return 1;
508 }
509
510 if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_LOCK) {
511 /* BIOS writers, sorry but we don't wanna lock
512 * features unless the user explicitly said so.
513 */
514
515 /* DEVICE CONFIGURATION FREEZE LOCK */
516 if (tf->command == ATA_CMD_CONF_OVERLAY &&
517 tf->feature == ATA_DCO_FREEZE_LOCK)
518 return 1;
519
520 /* SECURITY FREEZE LOCK */
521 if (tf->command == ATA_CMD_SEC_FREEZE_LOCK)
522 return 1;
523
524 /* SET MAX LOCK and SET MAX FREEZE LOCK */
525 if ((!ptf || ptf->command != ATA_CMD_READ_NATIVE_MAX) &&
526 tf->command == ATA_CMD_SET_MAX &&
527 (tf->feature == ATA_SET_MAX_LOCK ||
528 tf->feature == ATA_SET_MAX_FREEZE_LOCK))
529 return 1;
530 }
531
532 return 0;
533}
534
468/** 535/**
469 * ata_acpi_run_tf - send taskfile registers to host controller 536 * ata_acpi_run_tf - send taskfile registers to host controller
470 * @dev: target ATA device 537 * @dev: target ATA device
@@ -485,13 +552,15 @@ EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire);
485 * EH context. 552 * EH context.
486 * 553 *
487 * RETURNS: 554 * RETURNS:
488 * 1 if command is executed successfully. 0 if ignored or rejected, 555 * 1 if command is executed successfully. 0 if ignored, rejected or
489 * -errno on other errors. 556 * filtered out, -errno on other errors.
490 */ 557 */
491static int ata_acpi_run_tf(struct ata_device *dev, 558static int ata_acpi_run_tf(struct ata_device *dev,
492 const struct ata_acpi_gtf *gtf) 559 const struct ata_acpi_gtf *gtf,
560 const struct ata_acpi_gtf *prev_gtf)
493{ 561{
494 struct ata_taskfile tf, rtf; 562 struct ata_taskfile *pptf = NULL;
563 struct ata_taskfile tf, ptf, rtf;
495 unsigned int err_mask; 564 unsigned int err_mask;
496 const char *level; 565 const char *level;
497 char msg[60]; 566 char msg[60];
@@ -502,44 +571,44 @@ static int ata_acpi_run_tf(struct ata_device *dev,
502 && (gtf->tf[6] == 0)) 571 && (gtf->tf[6] == 0))
503 return 0; 572 return 0;
504 573
505 ata_tf_init(dev, &tf); 574 ata_acpi_gtf_to_tf(dev, gtf, &tf);
506 575 if (prev_gtf) {
507 /* convert gtf to tf */ 576 ata_acpi_gtf_to_tf(dev, prev_gtf, &ptf);
508 tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ 577 pptf = &ptf;
509 tf.protocol = ATA_PROT_NODATA; 578 }
510 tf.feature = gtf->tf[0]; /* 0x1f1 */ 579
511 tf.nsect = gtf->tf[1]; /* 0x1f2 */ 580 if (!ata_acpi_filter_tf(&tf, pptf)) {
512 tf.lbal = gtf->tf[2]; /* 0x1f3 */ 581 rtf = tf;
513 tf.lbam = gtf->tf[3]; /* 0x1f4 */ 582 err_mask = ata_exec_internal(dev, &rtf, NULL,
514 tf.lbah = gtf->tf[4]; /* 0x1f5 */ 583 DMA_NONE, NULL, 0, 0);
515 tf.device = gtf->tf[5]; /* 0x1f6 */ 584
516 tf.command = gtf->tf[6]; /* 0x1f7 */ 585 switch (err_mask) {
517 586 case 0:
518 rtf = tf; 587 level = KERN_DEBUG;
519 err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0); 588 snprintf(msg, sizeof(msg), "succeeded");
520 589 rc = 1;
521 switch (err_mask) { 590 break;
522 case 0: 591
523 level = KERN_DEBUG; 592 case AC_ERR_DEV:
524 snprintf(msg, sizeof(msg), "succeeded"); 593 level = KERN_INFO;
525 rc = 1; 594 snprintf(msg, sizeof(msg),
526 break; 595 "rejected by device (Stat=0x%02x Err=0x%02x)",
527 596 rtf.command, rtf.feature);
528 case AC_ERR_DEV: 597 rc = 0;
598 break;
599
600 default:
601 level = KERN_ERR;
602 snprintf(msg, sizeof(msg),
603 "failed (Emask=0x%x Stat=0x%02x Err=0x%02x)",
604 err_mask, rtf.command, rtf.feature);
605 rc = -EIO;
606 break;
607 }
608 } else {
529 level = KERN_INFO; 609 level = KERN_INFO;
530 snprintf(msg, sizeof(msg), 610 snprintf(msg, sizeof(msg), "filtered out");
531 "rejected by device (Stat=0x%02x Err=0x%02x)",
532 rtf.command, rtf.feature);
533 rc = 0; 611 rc = 0;
534 break;
535
536 default:
537 level = KERN_ERR;
538 snprintf(msg, sizeof(msg),
539 "failed (Emask=0x%x Stat=0x%02x Err=0x%02x)",
540 err_mask, rtf.command, rtf.feature);
541 rc = -EIO;
542 break;
543 } 612 }
544 613
545 ata_dev_printk(dev, level, 614 ata_dev_printk(dev, level,
@@ -566,7 +635,7 @@ static int ata_acpi_run_tf(struct ata_device *dev,
566 */ 635 */
567static int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed) 636static int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed)
568{ 637{
569 struct ata_acpi_gtf *gtf = NULL; 638 struct ata_acpi_gtf *gtf = NULL, *pgtf = NULL;
570 int gtf_count, i, rc; 639 int gtf_count, i, rc;
571 640
572 /* get taskfiles */ 641 /* get taskfiles */
@@ -576,12 +645,14 @@ static int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed)
576 gtf_count = rc; 645 gtf_count = rc;
577 646
578 /* execute them */ 647 /* execute them */
579 for (i = 0; i < gtf_count; i++) { 648 for (i = 0; i < gtf_count; i++, gtf++) {
580 rc = ata_acpi_run_tf(dev, gtf++); 649 rc = ata_acpi_run_tf(dev, gtf, pgtf);
581 if (rc < 0) 650 if (rc < 0)
582 break; 651 break;
583 if (rc) 652 if (rc) {
584 (*nr_executed)++; 653 (*nr_executed)++;
654 pgtf = gtf;
655 }
585 } 656 }
586 657
587 ata_acpi_clear_gtf(dev); 658 ata_acpi_clear_gtf(dev);