Index: work/include/linux/libata.h =================================================================== --- work.orig/include/linux/libata.h +++ work/include/linux/libata.h @@ -1013,18 +1013,18 @@ extern void ata_do_eh(struct ata_port *a * printk helpers */ #define ata_port_printk(ap, lv, fmt, args...) \ - printk(lv"ata%u: "fmt, (ap)->print_id , ##args) + printk("%sata%u: "fmt, lv, (ap)->print_id , ##args) #define ata_link_printk(link, lv, fmt, args...) do { \ if ((link)->ap->nr_pmp_links) \ - printk(lv"ata%u.%02u: "fmt, (link)->ap->print_id, \ + printk("%sata%u.%02u: "fmt, lv, (link)->ap->print_id, \ (link)->pmp , ##args); \ else \ - printk(lv"ata%u: "fmt, (link)->ap->print_id , ##args); \ + printk("%sata%u: "fmt, lv, (link)->ap->print_id , ##args); \ } while(0) #define ata_dev_printk(dev, lv, fmt, args...) \ - printk(lv"ata%u.%02u: "fmt, (dev)->link->ap->print_id, \ + printk("%sata%u.%02u: "fmt, lv, (dev)->link->ap->print_id, \ (dev)->link->pmp + (dev)->devno , ##args) /* Index: work/include/linux/ata.h =================================================================== --- work.orig/include/linux/ata.h +++ work/include/linux/ata.h @@ -190,6 +190,8 @@ enum { ATA_CMD_READ_LOG_EXT = 0x2f, ATA_CMD_PMP_READ = 0xE4, ATA_CMD_PMP_WRITE = 0xE8, + ATA_CMD_CONF_OVERLAY = 0xB1, + ATA_CMD_SEC_FREEZE_LOCK = 0xF5, /* READ_LOG_EXT pages */ ATA_LOG_SATA_NCQ = 0x10, @@ -239,6 +241,19 @@ enum { SATA_AN = 0x05, /* Asynchronous Notification */ SATA_DIPM = 0x03, /* Device Initiated Power Management */ + /* feature values for SET_MAX */ + ATA_SET_MAX_ADDR = 0x00, + ATA_SET_MAX_PASSWD = 0x01, + ATA_SET_MAX_LOCK = 0x02, + ATA_SET_MAX_UNLOCK = 0x03, + ATA_SET_MAX_FREEZE_LOCK = 0x04, + + /* feature values for DEVICE CONFIGURATION OVERLAY */ + ATA_DCO_RESTORE = 0xC0, + ATA_DCO_FREEZE_LOCK = 0xC1, + ATA_DCO_IDENTIFY = 0xC2, + ATA_DCO_SET = 0xC3, + /* ATAPI stuff */ ATAPI_PKT_DMA = (1 << 0), ATAPI_DMADIR = (1 << 2), /* ATAPI data dir: Index: work/drivers/ata/libata-acpi.c =================================================================== --- work.orig/drivers/ata/libata-acpi.c +++ work/drivers/ata/libata-acpi.c @@ -6,6 +6,7 @@ * Copyright (C) 2006 Randy Dunlap */ +#include #include #include #include @@ -14,6 +15,7 @@ #include #include #include +#include #include #include "libata.h" @@ -25,6 +27,16 @@ #include #include +enum { + ATA_ACPI_FILTER_LOCK = 1 << 0, + + ATA_ACPI_FILTER_DEFAULT = ATA_ACPI_FILTER_LOCK, +}; + +static unsigned int ata_acpi_gtf_filter = ATA_ACPI_FILTER_DEFAULT; +module_param_named(acpi_gtf_filter, ata_acpi_gtf_filter, int, 0644); +MODULE_PARM_DESC(acpi_gtf_filter, "filter mask for ACPI _GTF commands, set to filter out (0x1=lock/freeze lock)"); + #define NO_PORT_MULT 0xffff #define SATA_ADR(root, pmp) (((root) << 16) | (pmp)) @@ -34,6 +46,56 @@ struct ata_acpi_gtf { } __packed; /* + * Blacklist implementation. Locking and global variables are to work + * around dmi_check_system() interface which is painful to extend. + */ +static spinlock_t ata_acpi_blist_lock = SPIN_LOCK_UNLOCKED; +static const char *ata_acpi_blist_busid; +static int ata_acpi_blist_matched = 0; + +static int ata_acpi_blist_match(const struct dmi_system_id *dmi_id) +{ + const char *match_bus_id = dmi_id->driver_data; + + if (match_bus_id && strcmp(match_bus_id, ata_acpi_blist_busid)) + return 0; + + ata_acpi_blist_matched = 1; + return 1; +} + +static const struct dmi_system_id ata_acpi_blist[] = { + { + .ident = "CN700-8237", + .matches = { + DMI_MATCH(DMI_BOARD_NAME, "CN700-8237"), + DMI_MATCH(DMI_BIOS_VENDOR, "Phoenix Technologies, LTD"), + DMI_MATCH(DMI_BIOS_VERSION, "6.00 PG"), + }, + .callback = ata_acpi_blist_match, + .driver_data = "0000:00:0f.1", + }, + + { } /* terminate list */ +}; + +static int ata_acpi_check_blist(struct device *dev) +{ + int rc; + + spin_lock(&ata_acpi_blist_lock); + + ata_acpi_blist_matched = 0; + ata_acpi_blist_busid = dev->bus_id; + dmi_check_system(ata_acpi_blist); + rc = ata_acpi_blist_matched; + + spin_unlock(&ata_acpi_blist_lock); + + return rc; +} + +/* * Helper - belongs in the PCI layer somewhere eventually */ static int is_pci_dev(struct device *dev) @@ -157,6 +219,12 @@ void ata_acpi_associate(struct ata_host if (!is_pci_dev(host->dev) || libata_noacpi) return; + if (ata_acpi_check_blist(host->dev)) { + dev_printk(KERN_INFO, host->dev, + "ATA ACPI blacklisted on this system, disabled\n"); + return; + } + host->acpi_handle = DEVICE_ACPI_HANDLE(host->dev); if (!host->acpi_handle) return; @@ -311,8 +379,8 @@ EXPORT_SYMBOL_GPL(ata_acpi_stm); * EH context. * * RETURNS: - * Number of taskfiles on success, 0 if _GTF doesn't exist or doesn't - * contain valid data. + * Number of taskfiles on success, 0 if _GTF doesn't exist. -EINVAL + * if _GTF is invalid. */ static int ata_dev_get_GTF(struct ata_device *dev, struct ata_acpi_gtf **gtf, void **ptr_to_free) @@ -339,6 +407,7 @@ static int ata_dev_get_GTF(struct ata_de ata_dev_printk(dev, KERN_WARNING, "_GTF evaluation failed (AE 0x%x)\n", status); + rc = -EINVAL; } goto out_free; } @@ -350,6 +419,7 @@ static int ata_dev_get_GTF(struct ata_de __FUNCTION__, (unsigned long long)output.length, output.pointer); + rc = -EINVAL; goto out_free; } @@ -358,6 +428,7 @@ static int ata_dev_get_GTF(struct ata_de ata_dev_printk(dev, KERN_WARNING, "_GTF unexpected object type 0x%x\n", out_obj->type); + rc = -EINVAL; goto out_free; } @@ -365,6 +436,7 @@ static int ata_dev_get_GTF(struct ata_de ata_dev_printk(dev, KERN_WARNING, "unexpected _GTF length (%d)\n", out_obj->buffer.length); + rc = -EINVAL; goto out_free; } @@ -397,7 +469,7 @@ int ata_acpi_cbl_80wire(struct ata_port int valid = 0; /* No _GTM data, no information */ - if (ata_acpi_gtm(ap, >m) < 0) + if (!ap->acpi_handle || ata_acpi_gtm(ap, >m) < 0) return 0; /* Split timing, DMA enabled */ @@ -421,8 +493,53 @@ int ata_acpi_cbl_80wire(struct ata_port EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); +static void ata_acpi_gtf_to_tf(struct ata_device *dev, + const struct ata_acpi_gtf *gtf, + struct ata_taskfile *tf) +{ + ata_tf_init(dev, tf); + + tf->flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; + tf->protocol = ATA_PROT_NODATA; + tf->feature = gtf->tf[0]; /* 0x1f1 */ + tf->nsect = gtf->tf[1]; /* 0x1f2 */ + tf->lbal = gtf->tf[2]; /* 0x1f3 */ + tf->lbam = gtf->tf[3]; /* 0x1f4 */ + tf->lbah = gtf->tf[4]; /* 0x1f5 */ + tf->device = gtf->tf[5]; /* 0x1f6 */ + tf->command = gtf->tf[6]; /* 0x1f7 */ +} + +static int ata_acpi_filter_tf(const struct ata_taskfile *tf, + const struct ata_taskfile *ptf) +{ + if (ata_acpi_gtf_filter & ATA_ACPI_FILTER_LOCK) { + /* BIOS writers, sorry but we don't wanna lock + * features unless the user explicitly said so. + */ + + /* DEVICE CONFIGURATION FREEZE LOCK */ + if (tf->command == ATA_CMD_CONF_OVERLAY && + tf->feature == ATA_DCO_FREEZE_LOCK) + return 1; + + /* SECURITY FREEZE LOCK */ + if (tf->command == ATA_CMD_SEC_FREEZE_LOCK) + return 1; + + /* SET MAX LOCK and SET MAX FREEZE LOCK */ + if ((!ptf || ptf->command != ATA_CMD_READ_NATIVE_MAX) && + tf->command == ATA_CMD_SET_MAX && + (tf->feature == ATA_SET_MAX_LOCK || + tf->feature == ATA_SET_MAX_FREEZE_LOCK)) + return 1; + } + + return 0; +} + /** - * taskfile_load_raw - send taskfile registers to host controller + * ata_acpi_run_tf - send taskfile registers to host controller * @dev: target ATA device * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7) * @@ -441,56 +558,77 @@ EXPORT_SYMBOL_GPL(ata_acpi_cbl_80wire); * EH context. * * RETURNS: - * 0 on success, -errno on failure. + * 1 if command is executed successfully. 0 if ignored, rejected or + * filtered out, -errno on other errors. */ -static int taskfile_load_raw(struct ata_device *dev, - const struct ata_acpi_gtf *gtf) +static int ata_acpi_run_tf(struct ata_device *dev, + const struct ata_acpi_gtf *gtf, + const struct ata_acpi_gtf *prev_gtf) { - struct ata_port *ap = dev->link->ap; - struct ata_taskfile tf, rtf; + struct ata_taskfile *pptf = NULL; + struct ata_taskfile tf, ptf, rtf; unsigned int err_mask; + const char *level; + char msg[60]; + int rc; if ((gtf->tf[0] == 0) && (gtf->tf[1] == 0) && (gtf->tf[2] == 0) && (gtf->tf[3] == 0) && (gtf->tf[4] == 0) && (gtf->tf[5] == 0) && (gtf->tf[6] == 0)) return 0; - ata_tf_init(dev, &tf); + ata_acpi_gtf_to_tf(dev, gtf, &tf); + if (prev_gtf) { + ata_acpi_gtf_to_tf(dev, prev_gtf, &ptf); + pptf = &ptf; + } - /* convert gtf to tf */ - tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ - tf.protocol = ATA_PROT_NODATA; - tf.feature = gtf->tf[0]; /* 0x1f1 */ - tf.nsect = gtf->tf[1]; /* 0x1f2 */ - tf.lbal = gtf->tf[2]; /* 0x1f3 */ - tf.lbam = gtf->tf[3]; /* 0x1f4 */ - tf.lbah = gtf->tf[4]; /* 0x1f5 */ - tf.device = gtf->tf[5]; /* 0x1f6 */ - tf.command = gtf->tf[6]; /* 0x1f7 */ + if (!ata_acpi_filter_tf(&tf, pptf)) { + rtf = tf; + err_mask = ata_exec_internal(dev, &rtf, NULL, + DMA_NONE, NULL, 0, 0); + + switch (err_mask) { + case 0: + level = KERN_DEBUG; + snprintf(msg, sizeof(msg), "succeeded"); + rc = 1; + break; - if (ata_msg_probe(ap)) - ata_dev_printk(dev, KERN_DEBUG, "executing ACPI cmd " - "%02x/%02x:%02x:%02x:%02x:%02x:%02x\n", - tf.command, tf.feature, tf.nsect, - tf.lbal, tf.lbam, tf.lbah, tf.device); - - rtf = tf; - err_mask = ata_exec_internal(dev, &rtf, NULL, DMA_NONE, NULL, 0, 0); - if (err_mask) { - ata_dev_printk(dev, KERN_ERR, - "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x failed " - "(Emask=0x%x Stat=0x%02x Err=0x%02x)\n", - tf.command, tf.feature, tf.nsect, tf.lbal, tf.lbam, - tf.lbah, tf.device, err_mask, rtf.command, rtf.feature); - return -EIO; + case AC_ERR_DEV: + level = KERN_INFO; + snprintf(msg, sizeof(msg), + "rejected by device (Stat=0x%02x Err=0x%02x)", + rtf.command, rtf.feature); + rc = 0; + break; + + default: + level = KERN_ERR; + snprintf(msg, sizeof(msg), + "failed (Emask=0x%x Stat=0x%02x Err=0x%02x)", + err_mask, rtf.command, rtf.feature); + rc = -EIO; + break; + } + } else { + level = KERN_INFO; + snprintf(msg, sizeof(msg), "filtered out"); + rc = 0; } - return 0; + ata_dev_printk(dev, level, + "ACPI cmd %02x/%02x:%02x:%02x:%02x:%02x:%02x %s\n", + tf.command, tf.feature, tf.nsect, tf.lbal, + tf.lbam, tf.lbah, tf.device, msg); + + return rc; } /** * ata_acpi_exec_tfs - get then write drive taskfile settings * @dev: target ATA device + * @nr_executed: out paramter for the number of executed commands * * Evaluate _GTF and excute returned taskfiles. * @@ -498,35 +636,37 @@ static int taskfile_load_raw(struct ata_ * EH context. * * RETURNS: - * Number of executed taskfiles on success, 0 if _GTF doesn't exist or - * doesn't contain valid data. -errno on other errors. + * Number of executed taskfiles on success, 0 if _GTF doesn't exist. + * -errno on other errors. */ -static int ata_acpi_exec_tfs(struct ata_device *dev) +static int ata_acpi_exec_tfs(struct ata_device *dev, int *nr_executed) { - struct ata_acpi_gtf *gtf = NULL; + struct ata_acpi_gtf *gtf = NULL, *pgtf = NULL; void *ptr_to_free = NULL; int gtf_count, i, rc; /* get taskfiles */ - gtf_count = ata_dev_get_GTF(dev, >f, &ptr_to_free); + rc = ata_dev_get_GTF(dev, >f, &ptr_to_free); + if (rc < 0) + return rc; + gtf_count = rc; /* execute them */ - for (i = 0, rc = 0; i < gtf_count; i++) { - int tmp; - - /* ACPI errors are eventually ignored. Run till the - * end even after errors. - */ - tmp = taskfile_load_raw(dev, gtf++); - if (!rc) - rc = tmp; + for (i = 0; i < gtf_count; i++, gtf++) { + rc = ata_acpi_run_tf(dev, gtf, pgtf); + if (rc < 0) + break; + if (rc) { + (*nr_executed)++; + pgtf = gtf; + } } kfree(ptr_to_free); - if (rc == 0) - return gtf_count; - return rc; + if (rc < 0) + return rc; + return 0; } /** @@ -664,6 +804,8 @@ int ata_acpi_on_devcfg(struct ata_device struct ata_port *ap = dev->link->ap; struct ata_eh_context *ehc = &ap->link.eh_context; int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA; + int nr_executed = 0; + const char *reason; int rc; if (!dev->acpi_handle) @@ -682,14 +824,14 @@ int ata_acpi_on_devcfg(struct ata_device } /* do _GTF */ - rc = ata_acpi_exec_tfs(dev); - if (rc < 0) + rc = ata_acpi_exec_tfs(dev, &nr_executed); + if (rc) goto acpi_err; dev->flags &= ~ATA_DFLAG_ACPI_PENDING; /* refresh IDENTIFY page if any _GTF command has been executed */ - if (rc > 0) { + if (nr_executed) { rc = ata_dev_reread_id(dev, 0); if (rc < 0) { ata_dev_printk(dev, KERN_ERR, "failed to IDENTIFY " @@ -701,17 +843,25 @@ int ata_acpi_on_devcfg(struct ata_device return 0; acpi_err: - /* let EH retry on the first failure, disable ACPI on the second */ - if (dev->flags & ATA_DFLAG_ACPI_FAILED) { - ata_dev_printk(dev, KERN_WARNING, "ACPI on devcfg failed the " - "second time, disabling (errno=%d)\n", rc); + /* fail and let EH retry once more for unknown IO errors */ + if (rc != -EINVAL && !(dev->flags & ATA_DFLAG_ACPI_FAILED)) { + dev->flags |= ATA_DFLAG_ACPI_FAILED; + return rc; + } - dev->acpi_handle = NULL; + if (rc == -EINVAL) + reason = "_GTF invalid"; + else + reason = "failed the second time"; + + ata_dev_printk(dev, KERN_WARNING, "ACPI: %s, disabled\n", reason); + dev->acpi_handle = NULL; + + /* We can safely continue if no _GTF command has been executed + * and port is not frozen. + */ + if (!nr_executed && !(ap->pflags & ATA_PFLAG_FROZEN)) + return 0; - /* if port is working, request IDENTIFY reload and continue */ - if (!(ap->pflags & ATA_PFLAG_FROZEN)) - rc = 1; - } - dev->flags |= ATA_DFLAG_ACPI_FAILED; return rc; }