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 @@ -25,6 +26,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)) @@ -33,6 +44,21 @@ struct ata_acpi_gtf { u8 tf[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */ } __packed; +static void acpi_xxx(struct ata_port *ap) +{ + struct pci_dev *pdev = to_pci_dev(ap->host->dev); + u32 reg48, reg50; + + if (!(ap->flags & ATA_FLAG_XXX)) + return; + + pci_read_config_dword(pdev, 0x48, ®48); + pci_read_config_dword(pdev, 0x50, ®50); + + dev_printk(KERN_INFO, &pdev->dev, "XXX PCI 0x48=0x%08x 0x50=0x%08x\n", + reg48, reg50); +} + /* * Helper - belongs in the PCI layer somewhere eventually */ @@ -200,13 +226,26 @@ void ata_acpi_associate(struct ata_host * RETURNS: * 0 on success, -ENOENT if _GTM doesn't exist, -errno on failure. */ -int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *gtm) +int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *gtm) { + struct ata_device *dev; struct acpi_buffer output = { .length = ACPI_ALLOCATE_BUFFER }; union acpi_object *out_obj; acpi_status status; int rc = 0; + /* Don't do _GTM if no device is enabled on the channel. Some + * odd clown _GTM implementations fail miserably if there's no + * device on the channel. + */ + ata_link_for_each_dev(dev, &ap->link) + if (ata_dev_enabled(dev)) + break; + if (!dev) { + ata_port_printk(ap, KERN_INFO, "XXX skipping _GTM on empty channel\n"); + return -ENOENT; + } + status = acpi_evaluate_object(ap->acpi_handle, "_GTM", NULL, &output); rc = -ENOENT; @@ -259,7 +298,7 @@ EXPORT_SYMBOL_GPL(ata_acpi_gtm); * RETURNS: * 0 on success, -ENOENT if _STM doesn't exist, -errno on failure. */ -int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm) +int ata_acpi_stm(struct ata_port *ap, struct ata_acpi_gtm *stm) { acpi_status status; struct acpi_object_list input; @@ -311,8 +350,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) @@ -332,6 +371,8 @@ static int ata_dev_get_GTF(struct ata_de __FUNCTION__, ap->port_no); /* _GTF has no input parameters */ + ata_port_printk(ap, KERN_INFO, "XXX evaluating _GTF\n"); + acpi_xxx(ap); status = acpi_evaluate_object(dev->acpi_handle, "_GTF", NULL, &output); if (ACPI_FAILURE(status)) { @@ -339,6 +380,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 +392,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 +401,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 +409,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 +442,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 +466,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 +531,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 +609,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; } /** @@ -605,18 +718,26 @@ int ata_acpi_on_suspend(struct ata_port BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); /* store timing parameters */ + acpi_xxx(ap); rc = ata_acpi_gtm(ap, &ap->acpi_gtm); + acpi_xxx(ap); spin_lock_irqsave(ap->lock, flags); - if (rc == 0) + if (rc == 0) { + ata_port_printk(ap, KERN_INFO, "XXX _GTM saved on suspend\n"); ap->pflags |= ATA_PFLAG_GTM_VALID; - else + } else ap->pflags &= ~ATA_PFLAG_GTM_VALID; spin_unlock_irqrestore(ap->lock, flags); - if (rc == -ENOENT) - rc = 0; - return rc; + /* Don't fail suspend because of _GTM failure. This will skip + * _STM during resume and has the possibility of failing _GTF + * but that's better than failing suspend/resume. After all, + * libata doesn't depend on ACPI to configure devices. + */ + if (rc) + ata_port_printk(ap, KERN_INFO, "XXX ignoring _GTM failure %d\n", rc); + return 0; } /** @@ -637,7 +758,13 @@ void ata_acpi_on_resume(struct ata_port BUG_ON(ap->flags & ATA_FLAG_ACPI_SATA); /* restore timing parameters */ + acpi_xxx(ap); ata_acpi_stm(ap, &ap->acpi_gtm); + acpi_xxx(ap); + ata_port_printk(ap, KERN_INFO, "XXX _STM performed on resume %02x:%02x/%02x:%02x %x\n", + ap->acpi_gtm.drive[0].pio, ap->acpi_gtm.drive[0].dma, + ap->acpi_gtm.drive[1].pio, ap->acpi_gtm.drive[1].dma, + ap->acpi_gtm.flags); } /* schedule _GTF */ @@ -664,6 +791,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 +811,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 +830,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; } Index: work/include/linux/libata.h =================================================================== --- work.orig/include/linux/libata.h +++ work/include/linux/libata.h @@ -189,6 +189,7 @@ enum { ATA_FLAG_AN = (1 << 18), /* controller supports AN */ ATA_FLAG_PMP = (1 << 19), /* controller supports PMP */ ATA_FLAG_IPM = (1 << 20), /* driver can handle IPM */ + ATA_FLAG_XXX = (1 << 21), /* The following flag belongs to ap->pflags but is kept in * ap->flags because it's referenced in many LLDs and will be @@ -940,8 +941,8 @@ enum { /* libata-acpi.c */ #ifdef CONFIG_ATA_ACPI extern int ata_acpi_cbl_80wire(struct ata_port *ap); -int ata_acpi_stm(const struct ata_port *ap, struct ata_acpi_gtm *stm); -int ata_acpi_gtm(const struct ata_port *ap, struct ata_acpi_gtm *stm); +int ata_acpi_stm(struct ata_port *ap, struct ata_acpi_gtm *stm); +int ata_acpi_gtm(struct ata_port *ap, struct ata_acpi_gtm *stm); #else static inline int ata_acpi_cbl_80wire(struct ata_port *ap) { return 0; } #endif @@ -1013,18 +1014,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/pata_via.c =================================================================== --- work.orig/drivers/ata/pata_via.c +++ work/drivers/ata/pata_via.c @@ -463,7 +463,7 @@ static int via_init_one(struct pci_dev * /* Early VIA without UDMA support */ static const struct ata_port_info via_mwdma_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_XXX, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &via_port_ops @@ -471,7 +471,7 @@ static int via_init_one(struct pci_dev * /* Ditto with IRQ masking required */ static const struct ata_port_info via_mwdma_info_borked = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_XXX, .pio_mask = 0x1f, .mwdma_mask = 0x07, .port_ops = &via_port_ops_noirq, @@ -479,7 +479,7 @@ static int via_init_one(struct pci_dev * /* VIA UDMA 33 devices (and borked 66) */ static const struct ata_port_info via_udma33_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_XXX, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = ATA_UDMA2, @@ -488,7 +488,7 @@ static int via_init_one(struct pci_dev * /* VIA UDMA 66 devices */ static const struct ata_port_info via_udma66_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_XXX, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = ATA_UDMA4, @@ -497,7 +497,7 @@ static int via_init_one(struct pci_dev * /* VIA UDMA 100 devices */ static const struct ata_port_info via_udma100_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_XXX, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = ATA_UDMA5, @@ -506,7 +506,7 @@ static int via_init_one(struct pci_dev * /* UDMA133 with bad AST (All current 133) */ static const struct ata_port_info via_udma133_info = { .sht = &via_sht, - .flags = ATA_FLAG_SLAVE_POSS, + .flags = ATA_FLAG_SLAVE_POSS | ATA_FLAG_XXX, .pio_mask = 0x1f, .mwdma_mask = 0x07, .udma_mask = ATA_UDMA6, /* FIXME: should check north bridge */