* [RFC 0/5] ACPI methods for SATA
@ 2005-11-23 23:40 Randy Dunlap
2005-11-23 23:48 ` [RFC 1/5] ata_acpi: Makefile + Kconfig Randy Dunlap
` (4 more replies)
0 siblings, 5 replies; 8+ messages in thread
From: Randy Dunlap @ 2005-11-23 23:40 UTC (permalink / raw)
To: ide
This is my current work-in-progress for comments on
ACPI methods for SATA (and PATA later on, unless a patch
from Shaohua Li on the mailing list handles PATA).
Quick status:
Working:
- find devices in namespace
- evaluate _SDD
- evaluate _GTF
- simulate writing taskfile to device
TODO:
- write taskfile to device in a generic, non-controller-specific way
- add more usage events for _SDD and _GTF (SATA) per
ACPI 3.0 spec, section 9.9.3.3, page 288.
---
~Randy
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC 1/5] ata_acpi: Makefile + Kconfig
2005-11-23 23:40 [RFC 0/5] ACPI methods for SATA Randy Dunlap
@ 2005-11-23 23:48 ` Randy Dunlap
2005-11-23 23:51 ` [RFC 2/5] ata_acpi: libata.h fields Randy Dunlap
` (3 subsequent siblings)
4 siblings, 0 replies; 8+ messages in thread
From: Randy Dunlap @ 2005-11-23 23:48 UTC (permalink / raw)
To: jgarzik; +Cc: linux-ide
From: Randy Dunlap <randy_d_dunlap@linux.intel.com>
Add ata_acpi in Makefile and Kconfig.
Signed-off-by: Randy Dunlap <randy_d_dunlap@linux.intel.com>
drivers/scsi/Kconfig | 5 +++++
drivers/scsi/Makefile | 1 +
2 files changed, 6 insertions(+)
--- linux-2615-rc2c.orig/drivers/scsi/Makefile
+++ linux-2615-rc2c/drivers/scsi/Makefile
@@ -138,6 +138,7 @@ obj-$(CONFIG_SCSI_SATA_NV) += libata.o s
obj-$(CONFIG_SCSI_SATA_ULI) += libata.o sata_uli.o
obj-$(CONFIG_SCSI_SATA_MV) += libata.o sata_mv.o
obj-$(CONFIG_SCSI_PDC_ADMA) += libata.o pdc_adma.o
+obj-$(CONFIG_SCSI_SATA_ACPI) += libata.o ata_acpi.o
obj-$(CONFIG_ARM) += arm/
--- linux-2615-rc2c.orig/drivers/scsi/Kconfig
+++ linux-2615-rc2c/drivers/scsi/Kconfig
@@ -598,6 +598,11 @@ config SCSI_SATA_INTEL_COMBINED
depends on IDE=y && !BLK_DEV_IDE_SATA && (SCSI_SATA_AHCI || SCSI_ATA_PIIX)
default y
+config SCSI_SATA_ACPI
+ bool
+ depends on SCSI_SATA && ACPI
+ default y
+
config SCSI_BUSLOGIC
tristate "BusLogic SCSI support"
depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API
---
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC 2/5] ata_acpi: libata.h fields
2005-11-23 23:40 [RFC 0/5] ACPI methods for SATA Randy Dunlap
2005-11-23 23:48 ` [RFC 1/5] ata_acpi: Makefile + Kconfig Randy Dunlap
@ 2005-11-23 23:51 ` Randy Dunlap
2005-11-24 0:38 ` Edward Falk
2005-11-23 23:52 ` [RFC 3/5] ata_acpi: invoke ACPI support functions Randy Dunlap
` (2 subsequent siblings)
4 siblings, 1 reply; 8+ messages in thread
From: Randy Dunlap @ 2005-11-23 23:51 UTC (permalink / raw)
To: jgarzik; +Cc: linux-ide
From: Randy Dunlap <randy_d_dunlap@linux.intel.com>
Add ACPI data pointer/length holders.
Signed-off-by: Randy Dunlap <randy_d_dunlap@linux.intel.com>
include/linux/libata.h | 6 ++++++
1 files changed, 6 insertions(+)
--- linux-2615-rc2c.orig/include/linux/libata.h
+++ linux-2615-rc2c/include/linux/libata.h
@@ -33,6 +33,7 @@
#include <asm/io.h>
#include <linux/ata.h>
#include <linux/workqueue.h>
+#include <acpi/acpi.h>
/*
* compile-time options
@@ -310,6 +311,11 @@ struct ata_device {
u16 cylinders; /* Number of cylinders */
u16 heads; /* Number of heads */
u16 sectors; /* Number of sectors per track */
+
+ /* ACPI objects info */
+ acpi_handle obj_handle;
+ acpi_size gtf_length;
+ u8 *gtf_address;
};
struct ata_port {
---
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC 3/5] ata_acpi: invoke ACPI support functions
2005-11-23 23:40 [RFC 0/5] ACPI methods for SATA Randy Dunlap
2005-11-23 23:48 ` [RFC 1/5] ata_acpi: Makefile + Kconfig Randy Dunlap
2005-11-23 23:51 ` [RFC 2/5] ata_acpi: libata.h fields Randy Dunlap
@ 2005-11-23 23:52 ` Randy Dunlap
2005-11-23 23:53 ` [RFC 4/5] ata_acpi: kernel-doc Randy Dunlap
2005-11-23 23:54 ` [RFC 5/5] ata_acpi: add ACPI support functions Randy Dunlap
4 siblings, 0 replies; 8+ messages in thread
From: Randy Dunlap @ 2005-11-23 23:52 UTC (permalink / raw)
To: jgarzik; +Cc: linux-ide
From: Randy Dunlap <randy_d_dunlap@linux.intel.com>
Add calls to ACPI methods for SATA drives.
Signed-off-by: Randy Dunlap <randy_d_dunlap@linux.intel.com>
drivers/scsi/libata-core.c | 4 ++++
drivers/scsi/libata.h | 7 +++++++
2 files changed, 11 insertions(+)
--- linux-2615-rc2c.orig/drivers/scsi/libata-core.c
+++ linux-2615-rc2c/drivers/scsi/libata-core.c
@@ -1345,6 +1345,8 @@ void ata_dev_config(struct ata_port *ap,
if (ap->ops->dev_config)
ap->ops->dev_config(ap, &ap->device[i]);
+
+ do_drive_SDD(ap, i);
}
/**
@@ -1784,6 +1786,8 @@ static void ata_set_mode(struct ata_port
if (ap->flags & ATA_FLAG_PORT_DISABLED)
return;
+ do_drive_update_taskfiles(ap);
+
if (ap->ops->post_set_mode)
ap->ops->post_set_mode(ap);
--- linux-2615-rc2c.orig/drivers/scsi/libata.h
+++ linux-2615-rc2c/drivers/scsi/libata.h
@@ -53,6 +53,13 @@ extern int ata_task_ioctl(struct scsi_de
extern int ata_cmd_ioctl(struct scsi_device *scsidev, void __user *arg);
+/* ata_acpi.c */
+extern int do_drive_SDD(struct ata_port *ap, unsigned int ix);
+extern int do_drive_get_GTF(struct ata_port *ap, struct ata_device *atadev);
+extern int do_drive_set_taskfiles(struct ata_port *ap, struct ata_device *atadev);
+extern int do_drive_update_taskfiles(struct ata_port *ap);
+
+
/* libata-scsi.c */
extern void ata_scsi_scan_host(struct ata_port *ap);
extern int ata_scsi_error(struct Scsi_Host *host);
---
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC 4/5] ata_acpi: kernel-doc
2005-11-23 23:40 [RFC 0/5] ACPI methods for SATA Randy Dunlap
` (2 preceding siblings ...)
2005-11-23 23:52 ` [RFC 3/5] ata_acpi: invoke ACPI support functions Randy Dunlap
@ 2005-11-23 23:53 ` Randy Dunlap
2005-11-23 23:54 ` [RFC 5/5] ata_acpi: add ACPI support functions Randy Dunlap
4 siblings, 0 replies; 8+ messages in thread
From: Randy Dunlap @ 2005-11-23 23:53 UTC (permalink / raw)
To: jgarzik; +Cc: ide
From: Randy Dunlap <randy_d_dunlap@linux.intel.com>
Add ata_acpi.c to libata kernel-doc template file.
Signed-off-by: Randy Dunlap <randy_d_dunlap@linux.intel.com>
Documentation/DocBook/libata.tmpl | 6 ++++++
1 files changed, 6 insertions(+)
--- linux-2615-rc2c.orig/Documentation/DocBook/libata.tmpl
+++ linux-2615-rc2c/Documentation/DocBook/libata.tmpl
@@ -787,6 +787,12 @@ and other resources, etc.
!Idrivers/scsi/libata-scsi.c
</chapter>
+ <chapter id="libataAcpi">
+ <title>libata ACPI interfaces/methods</title>
+!Edrivers/scsi/ata_acpi.c
+!Idrivers/scsi/ata_acpi.c
+ </chapter>
+
<chapter id="ataExceptions">
<title>ATA errors & exceptions</title>
---
^ permalink raw reply [flat|nested] 8+ messages in thread
* [RFC 5/5] ata_acpi: add ACPI support functions
2005-11-23 23:40 [RFC 0/5] ACPI methods for SATA Randy Dunlap
` (3 preceding siblings ...)
2005-11-23 23:53 ` [RFC 4/5] ata_acpi: kernel-doc Randy Dunlap
@ 2005-11-23 23:54 ` Randy Dunlap
4 siblings, 0 replies; 8+ messages in thread
From: Randy Dunlap @ 2005-11-23 23:54 UTC (permalink / raw)
To: jgarzik; +Cc: linux-ide
From: Randy Dunlap <randy_d_dunlap@linux.intel.com>
Add support for ACPI methods to SATA suspend/resume.
Signed-off-by: Randy Dunlap <randy_d_dunlap@linux.intel.com>
drivers/scsi/ata_acpi.c | 499 ++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 499 insertions(+)
--- /dev/null
+++ linux-2615-rc2c/drivers/scsi/ata_acpi.c
@@ -0,0 +1,499 @@
+/*
+ * ata-acpi.c
+ * Provides ACPI support for PATA/SATA.
+ *
+ * Copyright (C) 2005 Intel Corp.
+ * Copyright (C) 2005 Randy Dunlap
+ */
+
+#include <linux/ata.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <acpi/acpi.h>
+#include "scsi.h"
+#include <linux/libata.h>
+#include <linux/pci.h>
+
+#include <acpi/acpi_bus.h>
+#include <acpi/acnames.h>
+#include <acpi/acnamesp.h>
+#include <acpi/acparser.h>
+#include <acpi/acexcep.h>
+#include <acpi/acmacros.h>
+#include <acpi/actypes.h>
+
+#define SATA_ROOT_PORT(x) (((x) >> 16) & 0xffff)
+#define SATA_PORT_NUMBER(x) ((x) & 0xffff) /* or NO_PORT_MULT */
+#define NO_PORT_MULT 0xffff
+#define SATA_ADR_RSVD 0xffffffff
+
+#define REGS_PER_GTF 7
+struct taskfile_array {
+ u8 tfa[REGS_PER_GTF]; /* regs. 0x1f1 - 0x1f7 */
+};
+
+#define DEBUGGING 1
+/* note: adds function name and KERN_DEBUG */
+#ifdef DEBUGGING
+#define DEBPRINT(fmt, args...) \
+ printk(KERN_DEBUG "%s: " fmt, __FUNCTION__, ## args)
+#else
+#define DEBPRINT(fmt, args...) do {} while (0)
+#endif /* DEBUGGING */
+
+static u8 *acpi_path_name(acpi_handle handle)
+{
+ acpi_status status;
+ static u8 path_name[ACPI_PATHNAME_MAX];
+ struct acpi_buffer ret_buf = { ACPI_PATHNAME_MAX, path_name };
+
+ memset(path_name, 0, sizeof (path_name));
+ status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &ret_buf);
+
+ if (ACPI_FAILURE(status))
+ return NULL;
+
+ return path_name;
+}
+
+/**
+ * pci_acpi_get_dev_handle - finds acpi_handle and pci device.function
+ * @dev: device to locate
+ * @handle: returned acpi_handle for @dev
+ * @pcidevfn: return PCI device.func for @dev
+ *
+ * Returns 0 on success, <0 on error.
+ */
+static int pci_acpi_get_dev_handle(struct device *dev, acpi_handle *handle,
+ acpi_integer *pcidevfn)
+{
+ struct pci_dev *pci_dev;
+ acpi_integer addr;
+
+ pci_dev = to_pci_dev(dev);
+ /* Please refer to the ACPI spec for the syntax of _ADR. */
+ addr = (PCI_SLOT(pci_dev->devfn) << 16) | PCI_FUNC(pci_dev->devfn);
+ *pcidevfn = addr;
+ *handle = acpi_get_child(DEVICE_ACPI_HANDLE(dev->parent), addr);
+ DEBPRINT("pcidevfn: 0x%llx\n",
+ (unsigned long long)*pcidevfn);
+ if (!*handle)
+ return -ENODEV;
+ return 0;
+}
+
+struct walk_info { /* can be trimmed some */
+ struct device *dev;
+ struct acpi_device *adev;
+ acpi_handle handle;
+ acpi_integer pcidevfn;
+ unsigned int drivenum;
+ acpi_handle obj_handle;
+ struct ata_port *ataport;
+ struct ata_device *atadev;
+ u32 sata_adr;
+ int status;
+ char basepath[ACPI_PATHNAME_MAX];
+ int basepath_len;
+};
+
+static acpi_status get_devices(acpi_handle handle,
+ u32 level, void *context, void **return_value)
+{
+ acpi_status status;
+ struct walk_info *winfo = context;
+ u8 *path_name = acpi_path_name(handle);
+ struct acpi_buffer buffer;
+ struct acpi_device_info *dinfo;
+
+ buffer.length = ACPI_ALLOCATE_LOCAL_BUFFER;
+ buffer.pointer = NULL;
+ status = acpi_get_object_info(handle, &buffer);
+
+ if (ACPI_SUCCESS(status)) {
+ dinfo = buffer.pointer;
+
+ /* find full device path name for pcidevfn */
+ if (dinfo && (dinfo->valid & ACPI_VALID_ADR) &&
+ dinfo->address == winfo->pcidevfn) {
+ DEBPRINT(":%s: matches pcidevfn (0x%llx)\n",
+ path_name, winfo->pcidevfn);
+ strlcpy(winfo->basepath, path_name,
+ sizeof(winfo->basepath));
+ winfo->basepath_len = strlen(path_name);
+ goto out;
+ }
+
+ /* if basepath is not yet known, ignore this object */
+ if (!winfo->basepath_len)
+ goto out;
+
+ /* if this object is in scope of basepath, maybe use it */
+ if (strncmp(path_name, winfo->basepath,
+ winfo->basepath_len) == 0) {
+ if (!(dinfo->valid & ACPI_VALID_ADR))
+ goto out;
+ DEBPRINT("GOT ONE: "
+ "(%s) root_port = 0x%llx, port_num = 0x%llx\n",
+ path_name,
+ SATA_ROOT_PORT(dinfo->address),
+ SATA_PORT_NUMBER(dinfo->address));
+ /* heuristics: */
+ if (SATA_PORT_NUMBER(dinfo->address) != NO_PORT_MULT)
+ DEBPRINT("warning: don't know how to handle SATA port multiplier\n");
+ if (SATA_ROOT_PORT(dinfo->address) ==
+ winfo->ataport->port_no &&
+ SATA_PORT_NUMBER(dinfo->address) == NO_PORT_MULT) {
+ DEBPRINT("THIS ^^^^^ is the requested SATA drive (handle = 0x%p)\n",
+ handle);
+ winfo->sata_adr = dinfo->address;
+ winfo->obj_handle = handle;
+ }
+ }
+out:
+ ACPI_MEM_FREE(dinfo);
+ }
+
+ return status;
+}
+
+/* Get the SATA drive _ADR object. */
+static int get_sata_adr(struct device *dev, acpi_handle handle,
+ acpi_integer pcidevfn, unsigned int drive,
+ struct ata_port *ap,
+ struct ata_device *atadev, u32 *dev_adr)
+{
+ acpi_status status;
+ struct walk_info *winfo;
+ int err = -ENOMEM;
+
+ winfo = kzalloc(sizeof(struct walk_info), GFP_KERNEL);
+ if (!winfo)
+ goto out;
+
+ winfo->dev = dev;
+ winfo->atadev = atadev;
+ winfo->ataport = ap;
+ if (acpi_bus_get_device(handle, &winfo->adev) < 0)
+ DEBPRINT("acpi_bus_get_device failed\n");
+ winfo->handle = handle;
+ winfo->pcidevfn = pcidevfn;
+ winfo->drivenum = drive;
+
+ status = acpi_get_devices(NULL, get_devices, winfo, NULL);
+ if (ACPI_FAILURE(status))
+ err = -ENODEV;
+ else {
+ *dev_adr = winfo->sata_adr;
+ atadev->obj_handle = winfo->obj_handle;
+ err = 0;
+ }
+ kfree(winfo);
+out:
+ return err;
+}
+
+/**
+ * do_drive_SDD - send Identify data to a drive
+ * @ap: the ata_port for the drive
+ * @ix: drive index
+ *
+ * Must be after Identify (Packet) Device -- uses its data.
+ */
+int do_drive_SDD(struct ata_port *ap, unsigned int ix)
+{
+// struct acpi_device_walk_info *info =
+// (struct acpi_device_walk_info *)context;
+// struct acpi_parameter_info pinfo;
+ acpi_handle handle;
+ acpi_integer pcidevfn;
+ int err = -ENODEV;
+ struct device *dev = ap->host_set->dev;
+ struct ata_device *atadev = &ap->device[ix];
+ u32 dev_adr;
+ acpi_status status;
+ struct acpi_object_list input;
+ union acpi_object in_params[1];
+
+ printk(KERN_DEBUG
+ "%s: ap->id: %d, ix = %d, port#: %d, hard_port#: %d\n",
+ __FUNCTION__, ap->id, ix, ap->port_no, ap->hard_port_no);
+
+ /* Don't continue if not a SATA device. */
+ if (!ata_id_is_sata(atadev->id))
+ goto out;
+
+ /* Don't continue if device has no _ADR method.
+ * _SDD is intended for known motherboard devices. */
+ err = pci_acpi_get_dev_handle(dev, &handle, &pcidevfn);
+ if (err < 0)
+ goto out;
+ /* Get this drive's _ADR info. */
+ dev_adr = SATA_ADR_RSVD;
+ err = get_sata_adr(dev, handle, pcidevfn, ix, ap, atadev, &dev_adr);
+ if (err < 0 || dev_adr == SATA_ADR_RSVD || atadev->obj_handle == NULL)
+ goto out;
+
+ /* Give the drive Identify data to the drive via the _SDD method */
+ /* _SDD: set up input parameters */
+ input.count = 1;
+ input.pointer = in_params;
+ in_params[0].type = ACPI_TYPE_BUFFER;
+ in_params[0].buffer.length = sizeof(atadev->id);
+ in_params[0].buffer.pointer = (u8 *)atadev->id;
+ /* Output buffer: _SDD has no output */
+
+ /* It's OK for _SDD to be missing too. */
+ status = acpi_evaluate_object(atadev->obj_handle, "_SDD", &input, NULL);
+ err = ACPI_FAILURE(status) ? -EIO : 0;
+ if (err < 0) {
+ printk(KERN_DEBUG
+ "ata%u(%u): %s _SDD error: status = 0x%x\n",
+ ap->id, ap->device->devno, __FUNCTION__, status);
+ }
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(do_drive_SDD);
+
+/**
+ * do_drive_get_GTF - get the drive bootup default taskfile settings
+ * @ap: the ata_port for the drive
+ * @atadev: target ata_device
+ *
+ * This applies to both PATA and SATA drives.
+ *
+ * The _GTF method has no input parameters.
+ * It returns a variable number of register set values (registers
+ * hex 1F1..1F7, taskfiles).
+ * The <variable number> is not known in advance, so have ACPI-CA
+ * allocate the buffer as needed and return it, then free it later.
+ *
+ */
+int do_drive_get_GTF(struct ata_port *ap, struct ata_device *atadev)
+{
+// struct acpi_device_walk_info *info =
+// (struct acpi_device_walk_info *)context;
+// struct acpi_parameter_info pinfo;
+ acpi_status status;
+ acpi_handle handle;
+ acpi_integer pcidevfn;
+ struct acpi_buffer output;
+ union acpi_object *out_obj;
+ struct device *dev = ap->host_set->dev;
+ int err = -ENODEV;
+
+ if (!ata_dev_present(atadev)) /* or port disabled ? */
+ goto out;
+
+ /* Don't continue if device has no _ADR method.
+ * _GTF is intended for known motherboard devices. */
+ err = pci_acpi_get_dev_handle(dev, &handle, &pcidevfn);
+ if (err < 0)
+ goto out;
+
+ /* Setting up output buffer */
+ output.length = ACPI_ALLOCATE_BUFFER;
+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */
+
+ /* _GTF has no input parameters */
+ err = -EIO;
+ status = acpi_evaluate_object(atadev->obj_handle, "_GTF",
+ NULL, &output);
+ if (ACPI_FAILURE(status)) {
+ ACPI_MEM_FREE(output.pointer);
+ printk(KERN_DEBUG
+ "%s: Run _GTF error: status = 0x%x\n",
+ __FUNCTION__, status);
+ goto out;
+ }
+
+ if (!output.length || !output.pointer) {
+ printk(KERN_DEBUG
+ "%s: Run _GTF: length or ptr is NULL (0x%llx, 0x%p)\n",
+ __FUNCTION__,
+ (unsigned long long)output.length, output.pointer);
+ ACPI_MEM_FREE(output.pointer);
+ goto out;
+ }
+
+ out_obj = output.pointer;
+ if (out_obj->type != ACPI_TYPE_BUFFER) {
+ ACPI_MEM_FREE(output.pointer);
+ printk(KERN_DEBUG "%s: Run _GTF: error: "
+ "expected object type of ACPI_TYPE_BUFFER, got 0x%x\n",
+ __FUNCTION__, out_obj->type);
+ err = -ENOENT;
+ goto out;
+ }
+
+ atadev->gtf_length = out_obj->buffer.length;
+ atadev->gtf_address = out_obj->buffer.pointer;
+ err = 0;
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(do_drive_get_GTF);
+
+/**
+ * taskfile_load_pio - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs ATA taskfile to standard ATA host controller.
+ *
+ * LOCKING: TBD:
+ * Inherited from caller.
+ */
+static void taskfile_load_pio(struct ata_port *ap,
+ const struct taskfile_array *gtf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ outb(gtf->tfa[0], ioaddr->feature_addr);
+ outb(gtf->tfa[1], ioaddr->nsect_addr);
+ outb(gtf->tfa[2], ioaddr->lbal_addr);
+ outb(gtf->tfa[3], ioaddr->lbam_addr);
+ outb(gtf->tfa[4], ioaddr->lbah_addr);
+ outb(gtf->tfa[5], ioaddr->device_addr);
+ outb(gtf->tfa[6], ioaddr->command_addr);
+
+ ata_wait_idle(ap);
+}
+
+/**
+ * taskfile_load_mmio - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs ATA taskfile to standard ATA host controller using MMIO.
+ *
+ * LOCKING: TBD:
+ * Inherited from caller.
+ */
+static void taskfile_load_mmio(struct ata_port *ap,
+ const struct taskfile_array *gtf)
+{
+ struct ata_ioports *ioaddr = &ap->ioaddr;
+
+ writeb(gtf->tfa[0], (void __iomem *) ioaddr->feature_addr);
+ writeb(gtf->tfa[1], (void __iomem *) ioaddr->nsect_addr);
+ writeb(gtf->tfa[2], (void __iomem *) ioaddr->lbal_addr);
+ writeb(gtf->tfa[3], (void __iomem *) ioaddr->lbam_addr);
+ writeb(gtf->tfa[4], (void __iomem *) ioaddr->lbah_addr);
+ writeb(gtf->tfa[5], (void __iomem *) ioaddr->device_addr);
+ writeb(gtf->tfa[6], (void __iomem *) ioaddr->command_addr);
+
+ ata_wait_idle(ap);
+}
+
+
+/**
+ * taskfile_load_raw - send taskfile registers to host controller
+ * @ap: Port to which output is sent
+ * @gtf: raw ATA taskfile register set (0x1f1 - 0x1f7)
+ *
+ * Outputs ATA taskfile to standard ATA host controller using MMIO
+ * or PIO as indicated by the ATA_FLAG_MMIO flag.
+ * Writes the control, feature, nsect, lbal, lbam, and lbah registers.
+ * Optionally (ATA_TFLAG_LBA48) writes hob_feature, hob_nsect,
+ * hob_lbal, hob_lbam, and hob_lbah.
+ *
+ * This function waits for idle (!BUSY and !DRQ) after writing
+ * registers. If the control register has a new value, this
+ * function also waits for idle after writing control and before
+ * writing the remaining registers.
+ *
+ * LOCKING: TBD:
+ * Inherited from caller.
+ */
+static void taskfile_load_raw(struct ata_port *ap,
+ const struct taskfile_array *gtf)
+{
+ DEBPRINT("(0x1f1-1f7): hex: %02x %02x %02x %02x %02x %02x %02x\n",
+ gtf->tfa[0], gtf->tfa[1], gtf->tfa[2],
+ gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]);
+
+
+#if 0
+ if (ap->flags & ATA_FLAG_MMIO)
+ taskfile_load_mmio(ap, gtf);
+ else
+ taskfile_load_pio(ap, gtf);
+#endif
+}
+
+/**
+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF
+ * @ap: the ata_port for the drive
+ * @atadev: target ata_device
+ *
+ * This applies to both PATA and SATA drives.
+ *
+ * Write {atadev->gtf_address, length atadev->gtf_length} in groups of
+ * REGS_PER_GTF bytes.
+ *
+ */
+int do_drive_set_taskfiles(struct ata_port *ap, struct ata_device *atadev)
+{
+// struct acpi_device_walk_info *info =
+// (struct acpi_device_walk_info *)context;
+// struct acpi_parameter_info pinfo;
+// struct device *dev = ap->host_set->dev;
+ int err = -ENODEV;
+ int gtf_count =
+ atadev->gtf_length / REGS_PER_GTF;
+ int ix;
+ struct taskfile_array *gtf;
+
+ if (!ata_dev_present(atadev)) /* or port disabled ? */
+ goto out;
+ if (!gtf_count) /* shouldn't be here */
+ goto out;
+
+ DEBPRINT("total GTF bytes = %lld (0x%llx), gtf_count = %d\n",
+ (unsigned long long)atadev->gtf_length,
+ (unsigned long long)atadev->gtf_length, gtf_count);
+ if (atadev->gtf_length % REGS_PER_GTF) {
+ printk(KERN_ERR "%s: unexpected GTF length (%zd)\n",
+ __FUNCTION__, atadev->gtf_length);
+ goto out;
+ }
+
+ for (ix = 0; ix < gtf_count; ix++) {
+ gtf = (struct taskfile_array *)
+ (atadev->gtf_address + ix * REGS_PER_GTF);
+
+ /* TBD: writing the taskfile array must have a more
+ * generic interface than this.... */
+ /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
+ taskfile_load_raw(ap, gtf);
+ }
+
+ err = 0;
+out:
+ return err;
+}
+EXPORT_SYMBOL_GPL(do_drive_set_taskfiles);
+
+/**
+ * do_drive_update_taskfiles - get then write drive taskfile settings
+ * @ap: the ata_port for the drive
+ *
+ * This applies to both PATA and SATA drives.
+ */
+int do_drive_update_taskfiles(struct ata_port *ap)
+{
+ int ix;
+ int ret;
+
+ for (ix = 0; ix < ATA_MAX_DEVICES; ix++) {
+ ret = do_drive_get_GTF(ap, &ap->device[ix]);
+ if (ret >= 0)
+ ret = do_drive_set_taskfiles(ap, &ap->device[ix]);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(do_drive_update_taskfiles);
---
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC 2/5] ata_acpi: libata.h fields
2005-11-23 23:51 ` [RFC 2/5] ata_acpi: libata.h fields Randy Dunlap
@ 2005-11-24 0:38 ` Edward Falk
2005-11-28 5:03 ` Randy.Dunlap
0 siblings, 1 reply; 8+ messages in thread
From: Edward Falk @ 2005-11-24 0:38 UTC (permalink / raw)
To: Randy Dunlap; +Cc: jgarzik, linux-ide
Why do this in the libata layer rather than the block or device layers?
^ permalink raw reply [flat|nested] 8+ messages in thread
* Re: [RFC 2/5] ata_acpi: libata.h fields
2005-11-24 0:38 ` Edward Falk
@ 2005-11-28 5:03 ` Randy.Dunlap
0 siblings, 0 replies; 8+ messages in thread
From: Randy.Dunlap @ 2005-11-28 5:03 UTC (permalink / raw)
To: Edward Falk; +Cc: randy_d_dunlap, jgarzik, linux-ide
On Wed, 23 Nov 2005 16:38:22 -0800 Edward Falk wrote:
> Why do this in the libata layer rather than the block or device layers?
> -
Hi,
Thanks for your question.
There is some device-to-ACPI table associations that are needed.
I don't see how the block layer would be appropriate for that.
Could it be?
Also, calls must be made to each SATA device driver to perform
a raw taskfile write.
What do you mean by the device layer? Maybe the ops function entries
in each SATA driver? If so, it looks like I may need to add the
raw taskfile write as an entry there, but I haven't really
studied that very much yet.
Do you have some other (different) suggestions for doing this?
---
~Randy
^ permalink raw reply [flat|nested] 8+ messages in thread
end of thread, other threads:[~2005-11-28 5:03 UTC | newest]
Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2005-11-23 23:40 [RFC 0/5] ACPI methods for SATA Randy Dunlap
2005-11-23 23:48 ` [RFC 1/5] ata_acpi: Makefile + Kconfig Randy Dunlap
2005-11-23 23:51 ` [RFC 2/5] ata_acpi: libata.h fields Randy Dunlap
2005-11-24 0:38 ` Edward Falk
2005-11-28 5:03 ` Randy.Dunlap
2005-11-23 23:52 ` [RFC 3/5] ata_acpi: invoke ACPI support functions Randy Dunlap
2005-11-23 23:53 ` [RFC 4/5] ata_acpi: kernel-doc Randy Dunlap
2005-11-23 23:54 ` [RFC 5/5] ata_acpi: add ACPI support functions Randy Dunlap
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).