Bugzilla – Attachment 70613 Details for
Bug 151517
FSC Lifebook does not resume
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Requests
|
IDP Log In
|
Forgot Password
[patch]
sata-acpi-suspend.patch
sata-acpi-suspend.patch (text/plain), 62.42 KB, created by
Hannes Reinecke
on 2006-02-28 12:01:53 UTC
(
hide
)
Description:
sata-acpi-suspend.patch
Filename:
MIME Type:
Creator:
Hannes Reinecke
Created:
2006-02-28 12:01:53 UTC
Size:
62.42 KB
patch
obsolete
>--- linux-2.6.13-SL100_BRANCH/drivers/scsi/Makefile.orig 2006-02-22 08:35:30.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/drivers/scsi/Makefile 2006-02-22 08:35:39.000000000 +0100 >@@ -162,7 +162,8 @@ zalon7xx-objs := zalon.o ncr53c8xx.o > NCR_Q720_mod-objs := NCR_Q720.o ncr53c8xx.o > cpqfc-objs := cpqfcTSinit.o cpqfcTScontrol.o cpqfcTSi2c.o \ > cpqfcTSworker.o cpqfcTStrigger.o >-libata-objs := libata-core.o libata-scsi.o >+libata-y := libata-core.o libata-scsi.o >+libata-$(CONFIG_SCSI_SATA_ACPI) += libata-acpi.o > > # Files generated that shall be removed upon make clean > clean-files := 53c7xx_d.h 53c700_d.h \ >--- linux-2.6.13-SL100_BRANCH/drivers/scsi/libata-acpi.c.orig 2006-02-22 08:35:30.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/drivers/scsi/libata-acpi.c 2006-02-24 13:16:14.000000000 +0100 >@@ -0,0 +1,995 @@ >+/* >+ * libata-acpi.c >+ * Provides ACPI support for PATA/SATA. >+ * >+ * Copyright (C) 2005 Intel Corp. >+ * Copyright (C) 2005 Randy Dunlap >+ */ >+ >+#include <linux/ata.h> >+#include <linux/delay.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 "libata.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 */ >+}; >+ >+struct GTM_buffer { >+ __u32 PIO_speed0; >+ __u32 DMA_speed0; >+ __u32 PIO_speed1; >+ __u32 DMA_speed1; >+ __u32 GTM_flags; >+}; >+ >+#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 */ >+ >+/** >+ * sata_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 >+ * >+ * This function is somewhat SATA-specific. Or at least the >+ * IDE and SCSI versions of this function are different, >+ * so it's not entirely generic code. >+ * >+ * Returns 0 on success, <0 on error. >+ */ >+static int sata_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); /* NOTE: PCI-specific */ >+ /* 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); >+ printk(KERN_DEBUG "%s: SATA dev addr=0x%llx, handle=0x%p\n", >+ __FUNCTION__, (unsigned long long)addr, *handle); >+ if (!*handle) >+ return -ENODEV; >+ return 0; >+} >+ >+/** >+ * pata_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 >+ * >+ * The PATA and SATA versions of this function are different. >+ * >+ * Returns 0 on success, <0 on error. >+ */ >+static int pata_get_dev_handle(struct device *dev, acpi_handle *handle, >+ acpi_integer *pcidevfn) >+{ >+ unsigned int domain, bus, devnum, func; >+ acpi_integer addr; >+ acpi_handle dev_handle, parent_handle; >+ int scanned; >+ struct acpi_buffer buffer = {.length = ACPI_ALLOCATE_BUFFER, >+ .pointer = NULL}; >+ acpi_status status; >+ struct acpi_device_info *dinfo = NULL; >+ int ret = -ENODEV; >+ >+ printk(KERN_DEBUG "%s: enter: dev->bus_id='%s'\n", >+ __FUNCTION__, dev->bus_id); >+ if ((scanned = sscanf(dev->bus_id, "%x:%x:%x.%x", >+ &domain, &bus, &devnum, &func)) != 4) { >+ printk(KERN_DEBUG "%s: sscanf ret. %d\n", >+ __FUNCTION__, scanned); >+ goto err; >+ } >+ >+ dev_handle = DEVICE_ACPI_HANDLE(dev); >+ parent_handle = DEVICE_ACPI_HANDLE(dev->parent); >+ >+ status = acpi_get_object_info(parent_handle, &buffer); >+ if (ACPI_FAILURE(status)) { >+ printk(KERN_DEBUG "%s: get_object_info for parent failed\n", >+ __FUNCTION__); >+ goto err; >+ } >+ dinfo = buffer.pointer; >+ if (dinfo && (dinfo->valid & ACPI_VALID_ADR) && >+ dinfo->address == bus) { >+ /* ACPI spec for _ADR for PCI bus: */ >+ addr = (acpi_integer)(devnum << 16 | func); >+ *pcidevfn = addr; >+ *handle = dev_handle; >+ } else { >+ printk(KERN_DEBUG "%s: get_object_info for parent has wrong " >+ " bus: %llu, should be %d\n", >+ __FUNCTION__, >+ dinfo ? (unsigned long long)dinfo->address : -1ULL, >+ bus); >+ goto err; >+ } >+ >+ printk(KERN_DEBUG "%s: dev_handle: 0x%p, parent_handle: 0x%p\n", >+ __FUNCTION__, dev_handle, parent_handle); >+ printk(KERN_DEBUG >+ "%s: for dev=0x%x.%x, addr=0x%llx, parent=0x%p, *handle=0x%p\n", >+ __FUNCTION__, devnum, func, (unsigned long long)addr, >+ dev->parent, *handle); >+ if (!*handle) >+ goto err; >+ ret = 0; >+err: >+ acpi_os_free(dinfo); >+ return ret; >+} >+ >+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; >+ struct acpi_buffer namebuf = {ACPI_ALLOCATE_BUFFER, NULL}; >+ char *pathname; >+ struct acpi_buffer buffer; >+ struct acpi_device_info *dinfo; >+ >+ status = acpi_get_name(handle, ACPI_FULL_PATHNAME, &namebuf); >+ if (status) >+ goto ret; >+ pathname = namebuf.pointer; >+ >+ buffer.length = ACPI_ALLOCATE_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) { >+ if (ata_msg_probe(winfo->ataport)) >+ printk(KERN_DEBUG >+ ":%s: matches pcidevfn (0x%llx)\n", >+ pathname, winfo->pcidevfn); >+ strlcpy(winfo->basepath, pathname, >+ sizeof(winfo->basepath)); >+ winfo->basepath_len = strlen(pathname); >+ 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(pathname, winfo->basepath, >+ winfo->basepath_len) == 0) { >+ if (!(dinfo->valid & ACPI_VALID_ADR)) >+ goto out; >+ if (ata_msg_probe(winfo->ataport)) >+ printk(KERN_DEBUG "GOT ONE: (%s) " >+ "root_port = 0x%llx, port_num = 0x%llx\n", >+ pathname, >+ SATA_ROOT_PORT(dinfo->address), >+ SATA_PORT_NUMBER(dinfo->address)); >+ /* heuristics: */ >+ if (SATA_PORT_NUMBER(dinfo->address) != NO_PORT_MULT) >+ if (ata_msg_probe(winfo->ataport)) >+ printk(KERN_DEBUG >+ "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) { >+ if (ata_msg_probe(winfo->ataport)) >+ printk(KERN_DEBUG >+ "THIS ^^^^^ is the requested SATA drive (handle = 0x%p)\n", >+ handle); >+ winfo->sata_adr = dinfo->address; >+ winfo->obj_handle = handle; >+ } >+ } >+out: >+ acpi_os_free(dinfo); >+ } >+ acpi_os_free(pathname); >+ >+ret: >+ 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 = kmalloc(sizeof(struct walk_info), GFP_KERNEL); >+ if (!winfo) >+ goto out; >+ >+ memset(winfo, 0, sizeof(struct walk_info)); >+ >+ winfo->dev = dev; >+ winfo->atadev = atadev; >+ winfo->ataport = ap; >+ if (acpi_bus_get_device(handle, &winfo->adev) < 0) >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "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)) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: acpi_get_devices failed\n", >+ __FUNCTION__); >+ err = -ENODEV; >+ } else { >+ *dev_adr = winfo->sata_adr; >+ atadev->obj_handle = winfo->obj_handle; >+ err = 0; >+ } >+ kfree(winfo); >+out: >+ return err; >+} >+ >+/** >+ * ata_acpi_push_id - send Identify data to a drive >+ * @ap: the ata_port for the drive >+ * @ix: drive index >+ * >+ * _SDD ACPI object: for SATA mode only. >+ * Must be after Identify (Packet) Device -- uses its data. >+ */ >+int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) >+{ >+ 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]; >+ >+ if (ap->legacy_mode) { >+ printk(KERN_DEBUG "%s: should not be here for PATA mode\n", >+ __FUNCTION__); >+ return 0; >+ } >+ if (noacpi) >+ return 0; >+ >+ if (ata_msg_probe(ap)) >+ 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)) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: ata_id_is_sata is False\n", >+ __FUNCTION__); >+ goto out; >+ } >+ >+ /* Don't continue if device has no _ADR method. >+ * _SDD is intended for known motherboard devices. */ >+ err = sata_get_dev_handle(dev, &handle, &pcidevfn); >+ if (err < 0) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: sata_get_dev_handle failed (%d\n", >+ __FUNCTION__, err); >+ goto out; >+ } >+ >+ /* Get this drive's _ADR info. if not already known. */ >+ if (!atadev->obj_handle) { >+ 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) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: get_sata_adr failed: " >+ "err=%d, dev_adr=%u, obj_handle=0x%p\n", >+ __FUNCTION__, err, dev_adr, >+ atadev->obj_handle); >+ 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. */ >+ swap_buf_le16(atadev->id, ATA_ID_WORDS); >+ status = acpi_evaluate_object(atadev->obj_handle, "_SDD", &input, NULL); >+ swap_buf_le16(atadev->id, ATA_ID_WORDS); >+ >+ err = ACPI_FAILURE(status) ? -EIO : 0; >+ if (err < 0) { >+ if (ata_msg_probe(ap)) >+ 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(ata_acpi_push_id); >+ >+/** >+ * do_drive_get_GTF - get the drive bootup default taskfile settings >+ * @ap: the ata_port for the drive >+ * @atadev: target ata_device >+ * @gtf_length: number of bytes of _GTF data returned at @gtf_address >+ * @gtf_address: buffer containing _GTF taskfile arrays >+ * >+ * 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. >+ * >+ * The returned @gtf_length and @gtf_address are only valid if the >+ * function return value is 0. >+ */ >+int do_drive_get_GTF(struct ata_port *ap, struct ata_device *atadev, >+ unsigned int *gtf_length, unsigned long *gtf_address, >+ unsigned long *obj_loc) >+{ >+ acpi_status status; >+ acpi_handle handle; >+ acpi_integer pcidevfn; >+ u32 dev_adr; >+ struct acpi_buffer output; >+ union acpi_object *out_obj; >+ struct device *dev = ap->host_set->dev; >+ int err = -ENODEV; >+ >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: ENTER: ap->id: %d, port#: %d, hard_port#: %d\n", >+ __FUNCTION__, ap->id, >+ ap->port_no, ap->hard_port_no); >+ >+ *gtf_length = 0; >+ *gtf_address = 0UL; >+ *obj_loc = 0UL; >+ >+ if (noacpi) >+ return 0; >+ >+ if (!ata_dev_present(atadev) || >+ (ap->flags & ATA_FLAG_PORT_DISABLED)) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: ERR: " >+ "ata_dev_present: %d, PORT_DISABLED: %lu\n", >+ __FUNCTION__, ata_dev_present(atadev), >+ ap->flags & ATA_FLAG_PORT_DISABLED); >+ goto out; >+ } >+ >+ /* Don't continue if device has no _ADR method. >+ * _GTF is intended for known motherboard devices. */ >+ if (!ata_id_is_sata(atadev->id)) { >+ err = pata_get_dev_handle(dev, &handle, &pcidevfn); >+ if (err < 0) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: pata_get_dev_handle failed (%d)\n", >+ __FUNCTION__, err); >+ goto out; >+ } >+ } else { >+ err = sata_get_dev_handle(dev, &handle, &pcidevfn); >+ if (err < 0) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: sata_get_dev_handle failed (%d\n", >+ __FUNCTION__, err); >+ goto out; >+ } >+ } >+ >+ /* Get this drive's _ADR info. if not already known. */ >+ if (!atadev->obj_handle) { >+ dev_adr = SATA_ADR_RSVD; >+ err = get_sata_adr(dev, handle, pcidevfn, 0, ap, atadev, >+ &dev_adr); >+ if (!ata_id_is_sata(atadev->id)) { >+ printk(KERN_DEBUG "%s: early exit\n", __FUNCTION__); >+ err = -1; >+ goto out; >+ } >+ if (err < 0 || dev_adr == SATA_ADR_RSVD || >+ !atadev->obj_handle) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: get_sata_adr failed: " >+ "err=%d, dev_adr=%u, obj_handle=0x%p\n", >+ __FUNCTION__, err, dev_adr, >+ atadev->obj_handle); >+ 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)) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: Run _GTF error: status = 0x%x\n", >+ __FUNCTION__, status); >+ goto out; >+ } >+ >+ if (!output.length || !output.pointer) { >+ if (ata_msg_probe(ap)) >+ 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_os_free(output.pointer); >+ goto out; >+ } >+ >+ out_obj = output.pointer; >+ if (out_obj->type != ACPI_TYPE_BUFFER) { >+ acpi_os_free(output.pointer); >+ if (ata_msg_probe(ap)) >+ 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; >+ } >+ >+ if (!out_obj->buffer.length || !out_obj->buffer.pointer || >+ out_obj->buffer.length % REGS_PER_GTF) { >+ if (ata_msg_drv(ap)) >+ printk(KERN_ERR >+ "%s: unexpected GTF length (%d) or addr (0x%p)\n", >+ __FUNCTION__, out_obj->buffer.length, >+ out_obj->buffer.pointer); >+ err = -ENOENT; >+ goto out; >+ } >+ >+ *gtf_length = out_obj->buffer.length; >+ *gtf_address = (unsigned long)out_obj->buffer.pointer; >+ *obj_loc = (unsigned long)out_obj; >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: returning " >+ "gtf_length=%d, gtf_address=0x%lx, obj_loc=0x%lx\n", >+ __FUNCTION__, *gtf_length, *gtf_address, *obj_loc); >+ err = 0; >+out: >+ return err; >+} >+EXPORT_SYMBOL_GPL(do_drive_get_GTF); >+ >+static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat) >+{ >+ return 0; >+} >+ >+/** >+ * 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, >+ struct ata_device *atadev, >+ const struct taskfile_array *gtf) >+{ >+ unsigned long timeout = HZ * 5; >+ >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: (0x1f1-1f7): hex: " >+ "%02x %02x %02x %02x %02x %02x %02x\n", >+ __FUNCTION__, >+ gtf->tfa[0], gtf->tfa[1], gtf->tfa[2], >+ gtf->tfa[3], gtf->tfa[4], gtf->tfa[5], gtf->tfa[6]); >+ >+ if (ap->ops->qc_issue) { >+ DECLARE_COMPLETION(wait); >+ struct ata_queued_cmd *qc; >+ int rc; >+ unsigned long flags; >+ >+ qc = ata_qc_new_init(ap, atadev); >+ BUG_ON(qc == NULL); >+ >+ /* convert gtf to tf */ >+ qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; /* TBD */ >+ qc->tf.protocol = atadev->class == ATA_DEV_ATAPI ? >+ ATA_PROT_ATAPI_NODATA : ATA_PROT_NODATA; >+ qc->tf.feature = gtf->tfa[0]; /* 0x1f1 */ >+ qc->tf.nsect = gtf->tfa[1]; /* 0x1f2 */ >+ qc->tf.lbal = gtf->tfa[2]; /* 0x1f3 */ >+ qc->tf.lbam = gtf->tfa[3]; /* 0x1f4 */ >+ qc->tf.lbah = gtf->tfa[4]; /* 0x1f5 */ >+ qc->tf.device = gtf->tfa[5]; /* 0x1f6 */ >+ qc->tf.command = gtf->tfa[6]; /* 0x1f7 */ >+ >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "call ata_qc_issue:\n"); >+ >+ qc->waiting = &wait; >+ qc->complete_fn = ata_qc_complete_noop; >+ >+ spin_lock_irqsave(&ap->host_set->lock, flags); >+ rc = ata_qc_issue(qc); >+ spin_unlock_irqrestore(&ap->host_set->lock, flags); >+ if (rc) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_ERR "%s: ata_qc_issue failed: %u\n", >+ __FUNCTION__, rc); >+ } else { >+ if (!wait_for_completion_timeout(&wait, timeout)) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_ERR "%s: ata_qc_issue timeout\n", __FUNCTION__); >+ qc->flags &= ~ATA_QCFLAG_ACTIVE; >+ } >+ } >+ } else >+ if (ata_msg_warn(ap)) >+ printk(KERN_WARNING >+ "%s: SATA driver is missing qc_issue function entry points\n", >+ __FUNCTION__); >+} >+ >+/** >+ * do_drive_set_taskfiles - write the drive taskfile settings from _GTF >+ * @ap: the ata_port for the drive >+ * @atadev: target ata_device >+ * @gtf_length: total number of bytes of _GTF taskfiles >+ * @gtf_address: location of _GTF taskfile arrays >+ * >+ * This applies to both PATA and SATA drives. >+ * >+ * Write {gtf_address, length gtf_length} in groups of >+ * REGS_PER_GTF bytes. >+ */ >+int do_drive_set_taskfiles(struct ata_port *ap, struct ata_device *atadev, >+ unsigned int gtf_length, unsigned long gtf_address) >+{ >+ int err = -ENODEV; >+ int gtf_count = gtf_length / REGS_PER_GTF; >+ int ix; >+ struct taskfile_array *gtf; >+ >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: ENTER: ap->id: %d, port#: %d, hard_port#: %d\n", >+ __FUNCTION__, ap->id, >+ ap->port_no, ap->hard_port_no); >+ >+ if (noacpi) >+ return 0; >+ if (!ata_id_is_sata(atadev->id)) { >+ printk(KERN_DEBUG "%s: skipping non-SATA drive\n", >+ __FUNCTION__); >+ return 0; >+ } >+ >+ if (!ata_dev_present(atadev) || >+ (ap->flags & ATA_FLAG_PORT_DISABLED)) >+ goto out; >+ if (!gtf_count) /* shouldn't be here */ >+ goto out; >+ >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: total GTF bytes=%u (0x%x), gtf_count=%d, addr=0x%lx\n", >+ __FUNCTION__, gtf_length, gtf_length, gtf_count, >+ gtf_address); >+ if (gtf_length % REGS_PER_GTF) { >+ if (ata_msg_drv(ap)) >+ printk(KERN_ERR "%s: unexpected GTF length (%d)\n", >+ __FUNCTION__, gtf_length); >+ goto out; >+ } >+ >+ for (ix = 0; ix < gtf_count; ix++) { >+ gtf = (struct taskfile_array *) >+ (gtf_address + ix * REGS_PER_GTF); >+ >+ /* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */ >+ taskfile_load_raw(ap, atadev, gtf); >+ } >+ >+ err = 0; >+out: >+ return err; >+} >+EXPORT_SYMBOL_GPL(do_drive_set_taskfiles); >+ >+/** >+ * ata_acpi_exec_tfs - get then write drive taskfile settings >+ * @ap: the ata_port for the drive >+ * >+ * This applies to both PATA and SATA drives. >+ */ >+int ata_acpi_exec_tfs(struct ata_port *ap) >+{ >+ int ix; >+ int ret; >+ unsigned int gtf_length; >+ unsigned long gtf_address; >+ unsigned long obj_loc; >+ >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: ENTER:\n", __FUNCTION__); >+ >+ if (noacpi) >+ return 0; >+ >+ for (ix = 0; ix < ATA_MAX_DEVICES; ix++) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: call get_GTF, ix=%d\n", >+ __FUNCTION__, ix); >+ ret = do_drive_get_GTF(ap, &ap->device[ix], >+ >f_length, >f_address, &obj_loc); >+ if (ret < 0) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: get_GTF error (%d)\n", >+ __FUNCTION__, ret); >+ break; >+ } >+ >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: call set_taskfiles, ix=%d\n", >+ __FUNCTION__, ix); >+ ret = do_drive_set_taskfiles(ap, &ap->device[ix], >+ gtf_length, gtf_address); >+ acpi_os_free((void *)obj_loc); >+ if (ret < 0) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: set_taskfiles error (%d)\n", >+ __FUNCTION__, ret); >+ break; >+ } >+ } >+ >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: ret=%d\n", __FUNCTION__, ret); >+ >+ return ret; >+} >+EXPORT_SYMBOL_GPL(ata_acpi_exec_tfs); >+ >+/** >+ * ata_acpi_get_timing - get the channel (controller) timings >+ * @ap: target ata_port (channel) >+ * >+ * For PATA ACPI, this function executes the _GTM ACPI method for the >+ * target channel. >+ * >+ * _GTM only applies to ATA controllers in PATA (legacy) mode, not to SATA. >+ * In legacy mode, ap->hard_port_no is channel (controller) number. >+ */ >+void ata_acpi_get_timing(struct ata_port *ap) >+{ >+ struct device *dev = ap->dev; >+ int err; >+ acpi_handle dev_handle; >+ acpi_integer pcidevfn; >+ acpi_handle chan_handle; >+ acpi_status status; >+ struct acpi_buffer output; >+ union acpi_object *out_obj; >+ struct GTM_buffer *gtm; >+ >+ if (noacpi) >+ goto out; >+ >+ if (!ap->legacy_mode) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: channel/controller not in legacy mode (%s)\n", >+ __FUNCTION__, dev->bus_id); >+ goto out; >+ } >+ >+ err = pata_get_dev_handle(dev, &dev_handle, &pcidevfn); >+ if (err < 0) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: pata_get_dev_handle failed (%d)\n", >+ __FUNCTION__, err); >+ goto out; >+ } >+ >+ /* get child objects of dev_handle == channel objects, >+ * + _their_ children == drive objects */ >+ /* channel is ap->hard_port_no */ >+ chan_handle = acpi_get_child(dev_handle, ap->hard_port_no); >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: chan adr=%d: handle=0x%p\n", >+ __FUNCTION__, ap->hard_port_no, chan_handle); >+ if (!chan_handle) >+ goto out; >+ >+#if 0 >+ /* TBD: also check ACPI object VALID bits */ >+ drive_handle = acpi_get_child(chan_handle, 0); >+ printk(KERN_DEBUG "%s: drive w/ adr=0: %c: 0x%p\n", >+ __FUNCTION__, >+ ap->device[0].class == ATA_DEV_NONE ? 'n' : 'v', >+ drive_handle); >+ drive_handle = acpi_get_child(chan_handle, 1); >+ printk(KERN_DEBUG "%s: drive w/ adr=1: %c: 0x%p\n", >+ __FUNCTION__, >+ ap->device[0].class == ATA_DEV_NONE ? 'n' : 'v', >+ drive_handle); >+#endif >+ >+ /* Setting up output buffer for _GTM */ >+ output.length = ACPI_ALLOCATE_BUFFER; >+ output.pointer = NULL; /* ACPI-CA sets this; save/free it later */ >+ >+ /* _GTM has no input parameters */ >+ status = acpi_evaluate_object(chan_handle, "_GTM", >+ NULL, &output); >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: _GTM status: %d, outptr: 0x%p, outlen: 0x%llx\n", >+ __FUNCTION__, status, output.pointer, >+ (unsigned long long)output.length); >+ if (ACPI_FAILURE(status)) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: Run _GTM error: status = 0x%x\n", >+ __FUNCTION__, status); >+ goto out; >+ } >+ >+ if (!output.length || !output.pointer) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: Run _GTM: " >+ "length or ptr is NULL (0x%llx, 0x%p)\n", >+ __FUNCTION__, >+ (unsigned long long)output.length, >+ output.pointer); >+ acpi_os_free(output.pointer); >+ goto out; >+ } >+ >+ out_obj = output.pointer; >+ if (out_obj->type != ACPI_TYPE_BUFFER) { >+ acpi_os_free(output.pointer); >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: Run _GTM: error: " >+ "expected object type of ACPI_TYPE_BUFFER, " >+ "got 0x%x\n", >+ __FUNCTION__, out_obj->type); >+ goto out; >+ } >+ >+ if (!out_obj->buffer.length || !out_obj->buffer.pointer || >+ out_obj->buffer.length != sizeof(struct GTM_buffer)) { >+ acpi_os_free(output.pointer); >+ if (ata_msg_drv(ap)) >+ printk(KERN_ERR >+ "%s: unexpected _GTM length (0x%x)[should be 0x%x] or addr (0x%p)\n", >+ __FUNCTION__, out_obj->buffer.length, >+ sizeof(struct GTM_buffer), out_obj->buffer.pointer); >+ goto out; >+ } >+ >+ gtm = (struct GTM_buffer *)out_obj->buffer.pointer; >+ if (ata_msg_probe(ap)) { >+ printk(KERN_DEBUG "%s: _GTM info: ptr: 0x%p, len: 0x%x, exp.len: 0x%Zx\n", >+ __FUNCTION__, out_obj->buffer.pointer, >+ out_obj->buffer.length, sizeof(struct GTM_buffer)); >+ printk(KERN_DEBUG "%s: _GTM fields: 0x%x, 0x%x, 0x%x, 0x%x, 0x%x\n", >+ __FUNCTION__, gtm->PIO_speed0, gtm->DMA_speed0, >+ gtm->PIO_speed1, gtm->DMA_speed1, gtm->GTM_flags); >+ } >+ >+ /* TBD: when to free gtm */ >+ ap->gtm = gtm; >+ kfree(ap->gtm_object_area); /* free previous then store new one */ >+ ap->gtm_object_area = out_obj; >+out:; >+} >+EXPORT_SYMBOL_GPL(ata_acpi_get_timing); >+ >+/** >+ * platform_set_timing - set the channel (controller) timings >+ * @ap: target ata_port (channel) >+ * >+ * For PATA ACPI, this function executes the _STM ACPI method for the >+ * target channel. >+ * >+ * _STM only applies to ATA controllers in PATA (legacy) mode, not to SATA. >+ * In legacy mode, ap->hard_port_no is channel (controller) number. >+ * >+ * _STM requires Identify Drive data, which must already be present in >+ * ata_device->id[] (i.e., it's not fetched here). >+ */ >+void ata_acpi_push_timing(struct ata_port *ap) >+{ >+ struct device *dev = ap->dev; >+ int err; >+ acpi_handle dev_handle; >+ acpi_integer pcidevfn; >+ acpi_handle chan_handle; >+ acpi_status status; >+ struct acpi_object_list input; >+ union acpi_object in_params[1]; >+ >+ if (noacpi) >+ goto out; >+ >+ if (!ap->legacy_mode) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: channel/controller not in legacy mode (%s)\n", >+ __FUNCTION__, dev->bus_id); >+ goto out; >+ } >+ >+ if (ap->device[0].id[49] || ap->device[1].id[49]) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: drive(s) on channel %d: missing Identify data\n", >+ __FUNCTION__, ap->hard_port_no); >+ goto out; >+ } >+ >+ err = pata_get_dev_handle(dev, &dev_handle, &pcidevfn); >+ if (err < 0) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: pata_get_dev_handle failed (%d)\n", >+ __FUNCTION__, err); >+ goto out; >+ } >+ >+ /* get child objects of dev_handle == channel objects, >+ * + _their_ children == drive objects */ >+ /* channel is ap->hard_port_no */ >+ chan_handle = acpi_get_child(dev_handle, ap->hard_port_no); >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: chan adr=%d: handle=0x%p\n", >+ __FUNCTION__, ap->hard_port_no, chan_handle); >+ if (!chan_handle) >+ goto out; >+ >+#if 0 >+ /* TBD: also check ACPI object VALID bits */ >+ drive_handle = acpi_get_child(chan_handle, 0); >+ printk(KERN_DEBUG "%s: drive w/ adr=0: %c: 0x%p\n", >+ __FUNCTION__, >+ ap->device[0].class == ATA_DEV_NONE ? 'n' : 'v', >+ drive_handle); >+ drive_handle = acpi_get_child(chan_handle, 1); >+ printk(KERN_DEBUG "%s: drive w/ adr=1: %c: 0x%p\n", >+ __FUNCTION__, >+ ap->device[0].class == ATA_DEV_NONE ? 'n' : 'v', >+ drive_handle); >+#endif >+ >+ /* Give the GTM buffer + drive Identify data to the channel via the >+ * _STM method: */ >+ /* setup input parameters buffer for _STM */ >+ input.count = 3; >+ input.pointer = in_params; >+ in_params[0].type = ACPI_TYPE_BUFFER; >+ in_params[0].buffer.length = sizeof(struct GTM_buffer); >+ in_params[0].buffer.pointer = (u8 *)ap->gtm; >+ in_params[1].type = ACPI_TYPE_BUFFER; >+ in_params[1].buffer.length = sizeof(ap->device[0].id); >+ in_params[1].buffer.pointer = (u8 *)ap->device[0].id; >+ in_params[2].type = ACPI_TYPE_BUFFER; >+ in_params[2].buffer.length = sizeof(ap->device[1].id); >+ in_params[2].buffer.pointer = (u8 *)ap->device[1].id; >+ /* Output buffer: _STM has no output */ >+ >+ swap_buf_le16(ap->device[0].id, ATA_ID_WORDS); >+ swap_buf_le16(ap->device[1].id, ATA_ID_WORDS); >+ status = acpi_evaluate_object(chan_handle, "_STM", &input, NULL); >+ swap_buf_le16(ap->device[0].id, ATA_ID_WORDS); >+ swap_buf_le16(ap->device[1].id, ATA_ID_WORDS); >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG "%s: _STM status: %d\n", >+ __FUNCTION__, status); >+ if (ACPI_FAILURE(status)) { >+ if (ata_msg_probe(ap)) >+ printk(KERN_DEBUG >+ "%s: Run _STM error: status = 0x%x\n", >+ __FUNCTION__, status); >+ goto out; >+ } >+ >+out:; >+} >+EXPORT_SYMBOL_GPL(ata_acpi_push_timing); >--- linux-2.6.13-SL100_BRANCH/drivers/scsi/libata.h.orig 2006-02-22 08:35:30.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/drivers/scsi/libata.h 2006-02-22 08:35:39.000000000 +0100 >@@ -35,6 +35,8 @@ struct ata_scsi_args { > }; > > /* libata-core.c */ >+extern int noacpi; >+extern int libata_printk; > extern struct ata_queued_cmd *ata_qc_new_init(struct ata_port *ap, > struct ata_device *dev); > extern void ata_qc_free(struct ata_queued_cmd *qc); >@@ -44,6 +46,52 @@ extern void ata_dev_select(struct ata_po > unsigned int wait, unsigned int can_sleep); > extern void ata_tf_to_host_nolock(struct ata_port *ap, struct ata_taskfile *tf); > extern void swap_buf_le16(u16 *buf, unsigned int buf_words); >+extern unsigned int ata_exec_internal(struct ata_port *ap, >+ struct ata_device *dev, >+ struct ata_taskfile *tf, >+ int dma_dir, void *buf, unsigned int buflen); >+ >+ >+/* libata-acpi.c */ >+#ifdef CONFIG_SCSI_SATA_ACPI >+extern int ata_acpi_push_id(struct ata_port *ap, unsigned int ix); >+extern int do_drive_get_GTF(struct ata_port *ap, struct ata_device *atadev, >+ unsigned int *gtf_length, unsigned long *gtf_address, >+ unsigned long *obj_loc); >+extern int do_drive_set_taskfiles(struct ata_port *ap, struct ata_device *atadev, >+ unsigned int gtf_length, unsigned long gtf_address); >+extern int ata_acpi_exec_tfs(struct ata_port *ap); >+extern void ata_acpi_get_timing(struct ata_port *ap); >+extern void ata_acpi_push_timing(struct ata_port *ap); >+#else >+static inline int ata_acpi_push_id(struct ata_port *ap, unsigned int ix) >+{ >+ return 0; >+} >+static inline int do_drive_get_GTF(struct ata_port *ap, >+ struct ata_device *atadev, >+ unsigned int *gtf_length, unsigned long *gtf_address, >+ unsigned long *obj_loc) >+{ >+ return 0; >+} >+static inline int do_drive_set_taskfiles(struct ata_port *ap, >+ struct ata_device *atadev, >+ unsigned int gtf_length, unsigned long gtf_address) >+{ >+ return 0; >+} >+static inline int ata_acpi_exec_tfs(struct ata_port *ap) >+{ >+ return 0; >+} >+static void ata_acpi_get_timing(struct ata_port *ap) >+{ >+} >+static void ata_acpi_push_timing(struct ata_port *ap) >+{ >+} >+#endif > > > /* libata-scsi.c */ >--- linux-2.6.13-SL100_BRANCH/drivers/scsi/ahci.c.orig 2006-02-28 09:48:20.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/drivers/scsi/ahci.c 2006-02-28 12:57:12.000000000 +0100 >@@ -87,12 +87,12 @@ enum { > PORT_CMD = 0x18, /* port command */ > PORT_TFDATA = 0x20, /* taskfile data */ > PORT_SIG = 0x24, /* device TF signature */ >- PORT_CMD_ISSUE = 0x38, /* command issue */ > PORT_SCR = 0x28, /* SATA phy register block */ > PORT_SCR_STAT = 0x28, /* SATA phy register: SStatus */ > PORT_SCR_CTL = 0x2c, /* SATA phy register: SControl */ > PORT_SCR_ERR = 0x30, /* SATA phy register: SError */ > PORT_SCR_ACT = 0x34, /* SATA phy register: SActive */ >+ PORT_CMD_ISSUE = 0x38, /* command issue */ > > /* PORT_IRQ_{STAT,MASK} bits */ > PORT_IRQ_COLD_PRES = (1 << 31), /* cold presence detect */ >@@ -176,10 +176,15 @@ static void ahci_scr_write (struct ata_p > static int ahci_init_one (struct pci_dev *pdev, const struct pci_device_id *ent); > static int ahci_qc_issue(struct ata_queued_cmd *qc); > static irqreturn_t ahci_interrupt (int irq, void *dev_instance, struct pt_regs *regs); >+static void ahci_start_engine(struct ata_port *ap); >+static int ahci_stop_engine(struct ata_port *ap); > static void ahci_phy_reset(struct ata_port *ap); > static void ahci_irq_clear(struct ata_port *ap); > static void ahci_eng_timeout(struct ata_port *ap); >+static void ahci_restart_port(struct ata_port *ap, u32 irq_stat); > static int ahci_port_start(struct ata_port *ap); >+static void ahci_port_suspend(struct ata_port *ap); >+static void ahci_port_resume(struct ata_port *ap); > static void ahci_port_stop(struct ata_port *ap); > static void ahci_host_stop(struct ata_host_set *host_set); > static void ahci_tf_read(struct ata_port *ap, struct ata_taskfile *tf); >@@ -187,6 +192,8 @@ static void ahci_qc_prep(struct ata_queu > static u8 ahci_check_status(struct ata_port *ap); > static u8 ahci_check_err(struct ata_port *ap); > static inline int ahci_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc); >+static int ahci_scsi_device_suspend(struct scsi_device *sdev); >+static int ahci_scsi_device_resume(struct scsi_device *sdev); > static void ahci_remove_one (struct pci_dev *pdev); > > static Scsi_Host_Template ahci_sht = { >@@ -207,8 +214,8 @@ static Scsi_Host_Template ahci_sht = { > .slave_configure = ata_scsi_slave_config, > .bios_param = ata_std_bios_param, > .ordered_flush = 1, >- .resume = ata_scsi_device_resume, >- .suspend = ata_scsi_device_suspend, >+ .resume = ahci_scsi_device_resume, >+ .suspend = ahci_scsi_device_suspend, > }; > > static struct ata_port_operations ahci_ops = { >@@ -246,7 +253,7 @@ static struct ata_port_info ahci_port_in > .host_flags = ATA_FLAG_SATA | ATA_FLAG_NO_LEGACY | > ATA_FLAG_SATA_RESET | ATA_FLAG_MMIO | > ATA_FLAG_PIO_DMA, >- .pio_mask = 0x03, /* pio3-4 */ >+ .pio_mask = 0x1f, /* pio0-4 */ > .udma_mask = 0x7f, /* udma0-6 ; FIXME */ > .port_ops = &ahci_ops, > }, >@@ -295,6 +302,24 @@ static inline void *ahci_port_base (void > return (void *) ahci_port_base_ul((unsigned long)base, port); > } > >+static void ahci_dump_port_status(struct ata_port *ap, int irq_stat, >+ char *msg) >+{ >+ void *mmio = ap->host_set->mmio_base; >+ void *port_mmio = ahci_port_base(mmio, ap->port_no); >+ >+ VPRINTK("ata%u: %s, " >+ "p_is %x is %x pis %x cmd %x tf %x ss %x se %x\n", >+ ap->id, msg, >+ irq_stat, >+ readl(mmio + HOST_IRQ_STAT), >+ readl(port_mmio + PORT_IRQ_STAT), >+ readl(port_mmio + PORT_CMD), >+ readl(port_mmio + PORT_TFDATA), >+ readl(port_mmio + PORT_SCR_STAT), >+ readl(port_mmio + PORT_SCR_ERR)); >+} >+ > static void ahci_host_stop(struct ata_host_set *host_set) > { > struct ahci_host_priv *hpriv = host_set->private_data; >@@ -306,10 +331,8 @@ static void ahci_host_stop(struct ata_ho > static int ahci_port_start(struct ata_port *ap) > { > struct device *dev = ap->host_set->dev; >- struct ahci_host_priv *hpriv = ap->host_set->private_data; > struct ahci_port_priv *pp; >- void *mem, *mmio = ap->host_set->mmio_base; >- void *port_mmio = ahci_port_base(mmio, ap->port_no); >+ void *mem; > dma_addr_t mem_dma; > > pp = kmalloc(sizeof(*pp), GFP_KERNEL); >@@ -354,6 +377,23 @@ static int ahci_port_start(struct ata_po > > ap->private_data = pp; > >+ /* >+ * Internal structures are initialized, >+ * we can now do a simple resume() >+ */ >+ ahci_port_resume(ap); >+ >+ return 0; >+} >+ >+ >+static void ahci_port_resume(struct ata_port *ap) >+{ >+ void *mmio = ap->host_set->mmio_base; >+ void *port_mmio = ahci_port_base(mmio, ap->port_no); >+ struct ahci_host_priv *hpriv = ap->host_set->private_data; >+ struct ahci_port_priv *pp = ap->private_data; >+ > if (hpriv->cap & HOST_CAP_64) > writel((pp->cmd_slot_dma >> 16) >> 16, port_mmio + PORT_LST_ADDR_HI); > writel(pp->cmd_slot_dma & 0xffffffff, port_mmio + PORT_LST_ADDR); >@@ -365,31 +405,49 @@ static int ahci_port_start(struct ata_po > readl(port_mmio + PORT_FIS_ADDR); /* flush */ > > writel(PORT_CMD_ICC_ACTIVE | PORT_CMD_FIS_RX | >- PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP | >- PORT_CMD_START, port_mmio + PORT_CMD); >+ PORT_CMD_POWER_ON | PORT_CMD_SPIN_UP, >+ port_mmio + PORT_CMD); > readl(port_mmio + PORT_CMD); /* flush */ > >- return 0; >+ ahci_start_engine(ap); > } > >- >-static void ahci_port_stop(struct ata_port *ap) >+static void ahci_port_suspend(struct ata_port *ap) > { >- struct device *dev = ap->host_set->dev; >- struct ahci_port_priv *pp = ap->private_data; > void *mmio = ap->host_set->mmio_base; > void *port_mmio = ahci_port_base(mmio, ap->port_no); > u32 tmp; >+ int work; >+ >+ ahci_stop_engine(ap); > >+ /* >+ * Disable FIS reception >+ */ > tmp = readl(port_mmio + PORT_CMD); >- tmp &= ~(PORT_CMD_START | PORT_CMD_FIS_RX); >+ tmp &= ~(PORT_CMD_FIS_RX); > writel(tmp, port_mmio + PORT_CMD); > readl(port_mmio + PORT_CMD); /* flush */ > >- /* spec says 500 msecs for each PORT_CMD_{START,FIS_RX} bit, so >- * this is slightly incorrect. >+ /* >+ * Wait for HBA to acknowledge. >+ * This could be as long as 500 msec > */ >- msleep(500); >+ work = 1000; >+ while (work-- > 0) { >+ tmp = readl(port_mmio + PORT_CMD); >+ if ((tmp & PORT_CMD_FIS_ON) == 0) >+ break; >+ udelay(10); >+ } >+} >+ >+static void ahci_port_stop(struct ata_port *ap) >+{ >+ struct device *dev = ap->host_set->dev; >+ struct ahci_port_priv *pp = ap->private_data; >+ >+ ahci_port_suspend(ap); > > ap->private_data = NULL; > dma_free_coherent(dev, AHCI_PORT_PRIV_DMA_SZ, >@@ -438,8 +496,16 @@ static void ahci_phy_reset(struct ata_po > struct ata_device *dev = &ap->device[0]; > u32 tmp; > >+ ahci_stop_engine(ap); >+ > __sata_phy_reset(ap); > >+ /* clear SATA phy error, if any */ >+ tmp = readl(port_mmio + PORT_SCR_ERR); >+ writel(tmp, port_mmio + PORT_SCR_ERR); >+ >+ ahci_start_engine(ap); >+ > if (ap->flags & ATA_FLAG_PORT_DISABLED) > return; > >@@ -538,29 +604,77 @@ static void ahci_qc_prep(struct ata_queu > ahci_fill_sg(qc); > } > >-static void ahci_intr_error(struct ata_port *ap, u32 irq_stat) >+static void ahci_start_engine(struct ata_port *ap) > { >- void *mmio = ap->host_set->mmio_base; >- void *port_mmio = ahci_port_base(mmio, ap->port_no); >+ void __iomem *mmio = ap->host_set->mmio_base; >+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); > u32 tmp; > int work; > >- /* stop DMA */ >+ tmp = readl(port_mmio + PORT_CMD); >+ /* >+ * AHCI rev 1.1 section 10.3.1: >+ * Software shall not set PxCMD.ST to â1â until it verifies >+ * that PxCMD.CR is â0â and has set PxCMD.FRE to â1â. >+ */ >+ if ((tmp & PORT_CMD_FIS_RX) == 0) >+ printk(KERN_WARNING "ata%d: dma not running\n",ap->id); >+ /* >+ * wait for engine to become idle. >+ */ >+ work = 1000; >+ while (work-- > 0) { >+ tmp = readl(port_mmio + PORT_CMD); >+ if ((tmp & PORT_CMD_LIST_ON) == 0) >+ break; >+ udelay(10); >+ } >+ >+ /* >+ * Start DMA >+ */ >+ tmp |= PORT_CMD_START; >+ writel(tmp, port_mmio + PORT_CMD); >+ readl(port_mmio + PORT_CMD); /* flush */ >+} >+ >+static int ahci_stop_engine(struct ata_port *ap) >+{ >+ void __iomem *mmio = ap->host_set->mmio_base; >+ void __iomem *port_mmio = ahci_port_base(mmio, ap->port_no); >+ int work; >+ u32 tmp; >+ > tmp = readl(port_mmio + PORT_CMD); > tmp &= ~PORT_CMD_START; > writel(tmp, port_mmio + PORT_CMD); > >- /* wait for engine to stop. TODO: this could be >- * as long as 500 msec >+ /* >+ * wait for engine to become idle > */ > work = 1000; > while (work-- > 0) { > tmp = readl(port_mmio + PORT_CMD); > if ((tmp & PORT_CMD_LIST_ON) == 0) >- break; >+ return 0; > udelay(10); > } > >+ return -EIO; >+} >+ >+static void ahci_restart_port(struct ata_port *ap, u32 irq_stat) >+{ >+ void *mmio = ap->host_set->mmio_base; >+ void *port_mmio = ahci_port_base(mmio, ap->port_no); >+ u32 tmp; >+ >+ if ((ap->device[0].class != ATA_DEV_ATAPI) || >+ ((irq_stat & PORT_IRQ_TF_ERR) == 0)) >+ ahci_dump_port_status(ap, irq_stat, "port reset"); >+ >+ ahci_stop_engine(ap); >+ > /* clear SATA phy error, if any */ > tmp = readl(port_mmio + PORT_SCR_ERR); > writel(tmp, port_mmio + PORT_SCR_ERR); >@@ -577,13 +691,7 @@ static void ahci_intr_error(struct ata_p > readl(port_mmio + PORT_SCR_CTL); /* flush */ > } > >- /* re-start DMA */ >- tmp = readl(port_mmio + PORT_CMD); >- tmp |= PORT_CMD_START; >- writel(tmp, port_mmio + PORT_CMD); >- readl(port_mmio + PORT_CMD); /* flush */ >- >- printk(KERN_WARNING "ata%u: error occurred, port reset\n", ap->id); >+ ahci_start_engine(ap); > } > > static void ahci_eng_timeout(struct ata_port *ap) >@@ -594,17 +702,17 @@ static void ahci_eng_timeout(struct ata_ > struct ata_queued_cmd *qc; > unsigned long flags; > >- DPRINTK("ENTER\n"); >+ printk(KERN_WARNING "ata%u: handling error/timeout\n", ap->id); > > spin_lock_irqsave(&host_set->lock, flags); > >- ahci_intr_error(ap, readl(port_mmio + PORT_IRQ_STAT)); >- > qc = ata_qc_from_tag(ap, ap->active_tag); > if (!qc) { > printk(KERN_ERR "ata%u: BUG: timeout without command\n", > ap->id); > } else { >+ ahci_restart_port(ap, readl(port_mmio + PORT_IRQ_STAT)); >+ > /* hack alert! We cannot use the supplied completion > * function from inside the ->eh_strategy_handler() thread. > * libata is the only user of ->eh_strategy_handler() in >@@ -639,7 +747,9 @@ static inline int ahci_host_intr(struct > } > > if (status & PORT_IRQ_FATAL) { >- ahci_intr_error(ap, status); >+ /* command processing has stopped due to error; restart */ >+ ahci_restart_port(ap, status); >+ > if (qc) > ata_qc_complete(qc, ATA_ERR); > } >@@ -675,12 +785,12 @@ static irqreturn_t ahci_interrupt (int i > > for (i = 0; i < host_set->n_ports; i++) { > struct ata_port *ap; >- u32 tmp; > >- VPRINTK("port %u\n", i); >+ if (!(irq_stat & (1 << i))) >+ continue; >+ > ap = host_set->ports[i]; >- tmp = irq_stat & (1 << i); >- if (tmp && ap) { >+ if (ap) { > struct ata_queued_cmd *qc; > qc = ata_qc_from_tag(ap, ap->active_tag); > if (ahci_host_intr(ap, qc)) >@@ -724,6 +834,34 @@ static void ahci_setup_port(struct ata_i > VPRINTK("EXIT\n"); > } > >+int ahci_scsi_device_suspend(struct scsi_device *sdev) >+{ >+ struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0]; >+ struct ata_device *dev = &ap->device[sdev->id]; >+ int rc; >+ >+ rc = ata_device_suspend(ap, dev); >+ >+ if (!rc) { >+ ahci_dump_port_status(ap, 0, "port suspend"); >+ ahci_port_suspend(ap); >+ } >+ >+ return rc; >+} >+ >+int ahci_scsi_device_resume(struct scsi_device *sdev) >+{ >+ struct ata_port *ap = (struct ata_port *) &sdev->host->hostdata[0]; >+ struct ata_device *dev = &ap->device[sdev->id]; >+ >+ ahci_port_resume(ap); >+ >+ ahci_dump_port_status(ap, 0, "port resume"); >+ >+ return ata_device_resume(ap, dev); >+} >+ > static int ahci_host_init(struct ata_probe_ent *probe_ent) > { > struct ahci_host_priv *hpriv = probe_ent->private_data; >--- linux-2.6.13-SL100_BRANCH/drivers/scsi/libata-core.c.orig 2006-02-22 08:35:30.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/drivers/scsi/libata-core.c 2006-02-28 10:24:39.000000000 +0100 >@@ -50,8 +50,8 @@ > #include "libata.h" > > static unsigned int ata_busy_sleep (struct ata_port *ap, >- unsigned long tmout_pat, >- unsigned long tmout); >+ unsigned long timeout_pat, >+ unsigned long timeout); > static void ata_set_mode(struct ata_port *ap); > static void ata_dev_set_xfermode(struct ata_port *ap, struct ata_device *dev); > static unsigned int ata_get_mode_mask(struct ata_port *ap, int shift); >@@ -59,12 +59,21 @@ static int fgb(u32 bitmap); > static int ata_choose_xfer_mode(struct ata_port *ap, > u8 *xfer_mode_out, > unsigned int *xfer_shift_out); >+static u64 ata_hpa_max_address(struct ata_port *ap, struct ata_device *dev); > static int ata_qc_complete_noop(struct ata_queued_cmd *qc, u8 drv_stat); > static void __ata_qc_complete(struct ata_queued_cmd *qc); > > static unsigned int ata_unique_id = 1; > static struct workqueue_struct *ata_wq; > >+int noacpi = 0; >+module_param(noacpi, int, 0444); >+MODULE_PARM_DESC(noacpi, "Disables use of ACPI in suspend/resume when set"); >+ >+int libata_printk = ATA_MSG_DRV; >+module_param_named(printk, libata_printk, int, 0644); >+MODULE_PARM_DESC(printk, "Set libata printk flags"); /* in linux/libata.h */ >+ > MODULE_AUTHOR("Jeff Garzik"); > MODULE_DESCRIPTION("Library module for ATA devices"); > MODULE_LICENSE("GPL"); >@@ -1205,11 +1214,11 @@ retry: > > /* print device capabilities */ > printk(KERN_DEBUG "ata%u: dev %u cfg " >- "49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x\n", >- ap->id, device, dev->id[49], >+ "00:%04x 49:%04x 82:%04x 83:%04x 84:%04x 85:%04x 86:%04x 87:%04x 88:%04x 93:%04x\n", >+ ap->id, device, dev->id[0], dev->id[49], > dev->id[82], dev->id[83], dev->id[84], > dev->id[85], dev->id[86], dev->id[87], >- dev->id[88]); >+ dev->id[88], dev->id[93]); > > /* > * common ATA, ATAPI feature tests >@@ -1258,11 +1267,20 @@ retry: > ap->host->max_cmd_len = 16; > > /* print device info to dmesg */ >- printk(KERN_INFO "ata%u: dev %u ATA, max %s, %Lu sectors:%s\n", >- ap->id, device, >+ printk(KERN_INFO "ata%u: dev %u ATA-%d, max %s, %Lu sectors:%s\n", >+ ap->id, device, i, > ata_mode_string(xfer_modes), > (unsigned long long)dev->n_sectors, > dev->flags & ATA_DFLAG_LBA48 ? " lba48" : ""); >+ >+ if (ata_id_hpa_enabled(dev->id)) { >+ u64 max_address; >+ >+ max_address = ata_hpa_max_address(ap, dev); >+ printk(KERN_INFO "ata%u: native max address %Lu\n", >+ ap->id, max_address); >+ } >+ > } > > /* ATAPI-specific feature tests */ >@@ -1324,6 +1342,8 @@ void ata_dev_config(struct ata_port *ap, > > if (ap->ops->dev_config) > ap->ops->dev_config(ap, &ap->device[i]); >+ >+ ata_acpi_push_id(ap, i); > } > > /** >@@ -1364,6 +1384,8 @@ static int ata_bus_probe(struct ata_port > if (ap->flags & ATA_FLAG_PORT_DISABLED) > goto err_out_disable; > >+ ata_acpi_exec_tfs(ap); >+ > return 0; > > err_out_disable: >@@ -1436,6 +1458,8 @@ void __sata_phy_reset(struct ata_port *a > return; > > if (ata_busy_sleep(ap, ATA_TMOUT_BOOT_QUICK, ATA_TMOUT_BOOT)) { >+ printk(KERN_INFO "ata%d: device not ready, disabling\n", >+ ap->id); > ata_port_disable(ap); > return; > } >@@ -1639,12 +1663,11 @@ err_out: > * or a timeout occurs. > * > * LOCKING: None. >- * > */ > > static unsigned int ata_busy_sleep (struct ata_port *ap, > unsigned long tmout_pat, >- unsigned long tmout) >+ unsigned long tmout) > { > unsigned long timer_start, timeout; > u8 status; >@@ -2129,6 +2152,80 @@ static void ata_dev_set_xfermode(struct > DPRINTK("EXIT\n"); > } > >+/* >+ * Execute a 'READ NATIVE MAX ADDRESS' command. >+ */ >+static u64 ata_hpa_max_address(struct ata_port *ap, struct ata_device *dev) >+{ >+ DECLARE_COMPLETION(wait); >+ struct ata_queued_cmd *qc; >+ int rc; >+ u64 max_address = 0; >+ unsigned long flags; >+ >+ /* set up set-features taskfile */ >+ DPRINTK("read native max address\n"); >+ >+ qc = ata_qc_new_init(ap, dev); >+ BUG_ON(qc == NULL); >+ >+ if (dev->flags & ATA_DFLAG_LBA48) >+ qc->tf.command = ATA_CMD_READ_NATIVE_EXT; >+ else >+ qc->tf.command = ATA_CMD_READ_NATIVE; >+ >+ qc->tf.flags |= ATA_TFLAG_ISADDR | ATA_TFLAG_DEVICE; >+ qc->tf.protocol = ATA_PROT_NODATA; >+ if (dev->devno) >+ qc->tf.device = ATA_LBA | ATA_DEV1; >+ else >+ qc->tf.device = ATA_LBA; >+ >+ qc->waiting = &wait; >+ qc->complete_fn = ata_qc_complete_noop; >+ >+ spin_lock_irqsave(&ap->host_set->lock, flags); >+ rc = ata_qc_issue(qc); >+ spin_unlock_irqrestore(&ap->host_set->lock, flags); >+ >+ if (rc) >+ ata_port_disable(ap); >+ else { >+ u8 status; >+ >+ wait_for_completion(&wait); >+ >+ status = ata_chk_status(ap); >+ if (status & ATA_ERR) { >+ u8 err = ata_chk_err(ap); >+ if (err & ATA_ABORTED) { >+ DPRINTK("error, command aborted\n"); >+ } else { >+ DPRINTK("error, status %x\n", err); >+ } >+ return 0; >+ } >+ >+ ap->ops->tf_read(ap, &qc->tf); >+ >+ max_address = (qc->tf.lbah << 16) + >+ (qc->tf.lbam << 8) + qc->tf.lbal; >+ if (dev->flags & ATA_DFLAG_LBA48) { >+ max_address += ((u64)qc->tf.hob_lbal << 24) + >+ ((u64)qc->tf.hob_lbam << 32) + >+ ((u64)qc->tf.hob_lbah << 40); >+ } else { >+ max_address += ((qc->tf.device & 0x0f) << 24); >+ } >+ >+ /* Add 1 to be compatible with the IDENTIFY output */ >+ DPRINTK("max_address %Lu\n", max_address + 1); >+ } >+ DPRINTK("EXIT\n"); >+ >+ return max_address; >+} >+ > /** > * ata_sg_clean - Unmap DMA memory associated with command > * @qc: Command containing DMA memory to be released >@@ -3840,9 +3937,17 @@ static int ata_do_simple_cmd(struct ata_ > rc = ata_qc_issue(qc); > spin_unlock_irqrestore(&ap->host_set->lock, flags); > >- if (!rc) >+ if (!rc) { >+ u8 status; > wait_for_completion(&wait); > >+ status = ata_chk_status(ap); >+ if (status & ATA_ERR) { >+ u8 err = ata_chk_err(ap); >+ DPRINTK("cmd %x error %x\n", cmd, err); >+ rc = -1; >+ } >+ } > return rc; > } > >@@ -3871,6 +3976,11 @@ static int ata_start_drive(struct ata_po > return ata_do_simple_cmd(ap, dev, ATA_CMD_IDLEIMMEDIATE); > } > >+static int ata_suspend_drive(struct ata_port *ap, struct ata_device *dev) >+{ >+ return ata_do_simple_cmd(ap, dev, ATA_CMD_SLEEP); >+} >+ > /** > * ata_device_resume - wakeup a previously suspended devices > * >@@ -3881,16 +3991,23 @@ static int ata_start_drive(struct ata_po > */ > int ata_device_resume(struct ata_port *ap, struct ata_device *dev) > { >+ int rc; >+ >+ if (!ata_dev_present(dev)) >+ return 0; >+ >+ printk(KERN_WARNING "ata%d: resume device\n", ap->id); >+ >+ ata_bus_probe(ap); >+ > if (ap->flags & ATA_FLAG_SUSPENDED) { > ap->flags &= ~ATA_FLAG_SUSPENDED; > ata_set_mode(ap); > } >- if (!ata_dev_present(dev)) >- return 0; >- if (dev->class == ATA_DEV_ATA) >- ata_start_drive(ap, dev); > >- return 0; >+ rc = ata_start_drive(ap, dev); >+ >+ return rc; > } > > /** >@@ -3904,11 +4021,15 @@ int ata_device_suspend(struct ata_port * > { > if (!ata_dev_present(dev)) > return 0; >+ >+ printk(KERN_WARNING "ata%d: suspend device\n", ap->id); >+ > if (dev->class == ATA_DEV_ATA) > ata_flush_cache(ap, dev); > >- ata_standby_drive(ap, dev); >+ ata_suspend_drive(ap, dev); > ap->flags |= ATA_FLAG_SUSPENDED; >+ > return 0; > } > >@@ -4009,6 +4130,7 @@ static void ata_host_init(struct ata_por > ap->port_no = port_no; > ap->hard_port_no = > ent->legacy_mode ? ent->hard_port_no : port_no; >+ ap->legacy_mode = ent->legacy_mode; > ap->pio_mask = ent->pio_mask; > ap->mwdma_mask = ent->mwdma_mask; > ap->udma_mask = ent->udma_mask; >@@ -4017,6 +4139,7 @@ static void ata_host_init(struct ata_por > ap->cbl = ATA_CBL_NONE; > ap->active_tag = ATA_TAG_POISON; > ap->last_ctl = 0xFF; >+ ap->dev = ent->dev; > > INIT_WORK(&ap->packet_task, atapi_packet_task, ap); > INIT_WORK(&ap->pio_task, ata_pio_task, ap); >@@ -4132,10 +4255,13 @@ int ata_device_add(struct ata_probe_ent > (ap->mwdma_mask << ATA_SHIFT_MWDMA) | > (ap->pio_mask << ATA_SHIFT_PIO); > >+ ap->msg_enable = libata_printk; >+ > /* print per-port info to dmesg */ > printk(KERN_INFO "ata%u: %cATA max %s cmd 0x%lX ctl 0x%lX " > "bmdma 0x%lX irq %lu\n", > ap->id, >+ ap->flags & ATA_FLAG_PATA_MODE ? 'P' : > ap->flags & ATA_FLAG_SATA ? 'S' : 'P', > ata_mode_string(xfer_mode_mask), > ap->ioaddr.cmd_addr, >@@ -4199,6 +4325,12 @@ int ata_device_add(struct ata_probe_ent > scsi_scan_host(ap->host); > } > >+ for (i = 0; i < ent->n_ports; i++) { >+ struct ata_port *ap = host_set->ports[i]; >+ >+ ata_acpi_get_timing(ap); >+ } >+ > dev_set_drvdata(dev, host_set); > > VPRINTK("EXIT, returning %u\n", ent->n_ports); >@@ -4423,14 +4555,21 @@ int ata_pci_init_one (struct pci_dev *pd > else > port[1] = port[0]; > >+ printk(KERN_DEBUG "%s: pci_dev class+intf: 0x%x\n", >+ __FUNCTION__, pdev->class); > if ((port[0]->host_flags & ATA_FLAG_NO_LEGACY) == 0 > && (pdev->class >> 8) == PCI_CLASS_STORAGE_IDE) { >+ printk(KERN_DEBUG "%s: NO_LEGACY == 0\n", __FUNCTION__); >+ port[0]->host_flags |= ATA_FLAG_PATA_MODE; >+ port[0]->host_flags &= ~ATA_FLAG_SATA; > /* TODO: support transitioning to native mode? */ > pci_read_config_byte(pdev, PCI_CLASS_PROG, &tmp8); > mask = (1 << 2) | (1 << 0); > if ((tmp8 & mask) != mask) > legacy_mode = (1 << 3); > } >+ else >+ printk(KERN_DEBUG "%s: NO_LEGACY == 1\n", __FUNCTION__); > > /* FIXME... */ > if ((!legacy_mode) && (n_ports > 1)) { >--- linux-2.6.13-SL100_BRANCH/drivers/scsi/sd.c.orig 2006-02-22 08:35:30.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/drivers/scsi/sd.c 2006-02-28 08:54:15.000000000 +0100 >@@ -119,6 +119,8 @@ static void sd_rw_intr(struct scsi_cmnd > static int sd_probe(struct device *); > static int sd_remove(struct device *); > static void sd_shutdown(struct device *dev); >+static int sd_suspend(struct device *dev, pm_message_t state, u32 level); >+static int sd_resume(struct device *dev, u32 level); > static void sd_rescan(struct device *); > static int sd_init_command(struct scsi_cmnd *); > static int sd_issue_flush(struct device *, sector_t *); >@@ -134,6 +136,8 @@ static struct scsi_driver sd_template = > .probe = sd_probe, > .remove = sd_remove, > .shutdown = sd_shutdown, >+ .suspend = sd_suspend, >+ .resume = sd_resume, > }, > .rescan = sd_rescan, > .init_command = sd_init_command, >@@ -680,6 +684,51 @@ not_present: > return 1; > } > >+static int sd_start_stop_unit(struct scsi_device *sdp, int start) >+{ >+ struct scsi_request *sreq; >+ int retries, res; >+ >+ if (!scsi_device_online(sdp)) >+ return -ENODEV; >+ >+ sreq = scsi_allocate_request(sdp, GFP_KERNEL); >+ if (!sreq) { >+ printk("FAILED\n No memory for request\n"); >+ return -ENOMEM; >+ } >+ >+ sreq->sr_data_direction = DMA_NONE; >+ for (retries = 3; retries > 0; --retries) { >+ unsigned char cmd[10] = { 0 }; >+ >+ cmd[0] = START_STOP; >+ cmd[1] = 1; /* Return immediately */ >+ memset((void *) &cmd[2], 0, 8); >+ cmd[4] = start; >+ /* >+ * Leave the rest of the command zero to indicate >+ * flush everything. >+ */ >+ scsi_wait_req(sreq, cmd, NULL, 0, SD_TIMEOUT, SD_MAX_RETRIES); >+ if (sreq->sr_result == 0) >+ break; >+ } >+ >+ res = sreq->sr_result; >+ if (res) { >+ printk(KERN_WARNING "FAILED\n status = %x, message = %02x, " >+ "host = %d, driver = %02x\n ", >+ status_byte(res), msg_byte(res), >+ host_byte(res), driver_byte(res)); >+ if (driver_byte(res) & DRIVER_SENSE) >+ scsi_print_req_sense("sd", sreq); >+ } >+ >+ scsi_release_request(sreq); >+ return res; >+} >+ > static int sd_sync_cache(struct scsi_device *sdp) > { > struct scsi_request *sreq; >@@ -1701,14 +1750,63 @@ static void sd_shutdown(struct device *d > if (!sdkp) > return; /* this can happen */ > >+ SCSI_LOG_HLQUEUE(3, printk("sd_shutdown: disk=%s\n", >+ sdkp->disk->disk_name)); >+ > if (!sdkp->WCE) > return; > > printk(KERN_NOTICE "Synchronizing SCSI cache for disk %s: \n", >- sdkp->disk->disk_name); >+ sdkp->disk->disk_name); > sd_sync_cache(sdp); >+ > } > >+/* Just quietly quiesce the device and SYNCHRONIZE CACHE for suspend too */ >+static int sd_suspend(struct device *dev, pm_message_t state, u32 level) >+{ >+ struct scsi_device *sdp = to_scsi_device(dev); >+ struct scsi_disk *sdkp = dev_get_drvdata(dev); >+ >+ if (!sdkp) >+ return 0; /* this can happen */ >+ >+ printk(KERN_NOTICE "Suspending SCSI disk %s\n", >+ sdkp->disk->disk_name); >+ >+ if (!sdkp->WCE) >+ return 0; >+ >+ /* don't try to sync an offline device ... it will only error */ >+ if (!scsi_device_online(sdp)) >+ return 0; >+ >+ if (sd_sync_cache(sdp)) >+ return -EIO; >+ >+ if (sd_start_stop_unit(sdp, 0)) >+ return -EIO; >+ >+ return 0; >+} >+ >+static int sd_resume(struct device *dev, u32 level) >+{ >+ struct scsi_device *sdp = to_scsi_device(dev); >+ struct scsi_disk *sdkp = dev_get_drvdata(dev); >+ >+ if (!sdkp) >+ return 0; >+ >+ printk(KERN_NOTICE "Resuming SCSI disk %s\n", >+ sdkp->disk->disk_name); >+ >+ if (sd_start_stop_unit(sdp, 1)) >+ return -EIO; >+ >+ return 0; >+} >+ > /** > * init_sd - entry point for this driver (both when built in or when > * a module). >--- linux-2.6.13-SL100_BRANCH/drivers/scsi/Kconfig.orig 2006-02-22 08:35:30.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/drivers/scsi/Kconfig 2006-02-22 08:35:39.000000000 +0100 >@@ -572,6 +572,19 @@ config SCSI_SATA_VITESSE > > If unsure, say N. > >+config SCSI_SATA_ACPI >+ bool >+ depends on SCSI_SATA && ACPI && PCI >+ default y >+ help >+ This option adds support for SATA-related ACPI objects. >+ These ACPI objects add the ability to retrieve taskfiles >+ from the ACPI BIOS and write them to the disk controller. >+ These objects may be related to performance, security, >+ power management, or other areas. >+ You can disable this at kernel boot time by using the >+ option 'libata.noacpi'. >+ > config SCSI_BUSLOGIC > tristate "BusLogic SCSI support" > depends on (PCI || ISA || MCA) && SCSI && ISA_DMA_API >--- linux-2.6.13-SL100_BRANCH/Documentation/kernel-parameters.txt.orig 2006-02-22 08:35:30.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/Documentation/kernel-parameters.txt 2006-02-22 08:35:39.000000000 +0100 >@@ -41,6 +41,7 @@ restrictions referred to are that the re > ISAPNP ISA PnP code is enabled. > ISDN Appropriate ISDN support is enabled. > JOY Appropriate joystick support is enabled. >+ LIBATA libata driver is enabled. > LP Printer support is enabled. > LOOP Loopback device support is enabled. > M68k M68k architecture is enabled. >@@ -898,6 +899,10 @@ running once the system is up. > emulation library even if a 387 maths coprocessor > is present. > >+ noacpi= [LIBATA] Disables use of ACPI in libata suspend/resume >+ when set. >+ Format: <int> >+ > noalign [KNL,ARM] > > noapic [SMP,APIC] Tells the kernel to not make use of any >@@ -1138,6 +1143,11 @@ running once the system is up. > [ISAPNP] Exclude memory regions for the autoconfiguration > Ranges are in pairs (memory base and size). > >+ printk= [LIBATA] Set libata printk level (mask). >+ The values are defined in include/linux/libata.h. >+ The default value is 1 (ATA_MSG_DRV). >+ Format: <int> >+ > profile= [KNL] Enable kernel profiling via /proc/profile > { schedule | <number> } > (param: schedule - profile schedule points} >--- linux-2.6.13-SL100_BRANCH/include/linux/libata.h.orig 2006-02-22 08:35:30.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/include/linux/libata.h 2006-02-28 10:53:43.000000000 +0100 >@@ -29,9 +29,13 @@ > #include <asm/io.h> > #include <linux/ata.h> > #include <linux/workqueue.h> >+#ifdef CONFIG_ACPI >+#include <acpi/acpi.h> >+#endif > > /* >- * compile-time options >+ * compile-time options: to be removed as soon as all the drivers are >+ * converted to the new debugging mechanism > */ > #undef ATA_DEBUG /* debugging output */ > #undef ATA_VERBOSE_DEBUG /* yet more debugging output */ >@@ -66,6 +70,38 @@ > } > #endif > >+/* NEW: debug levels */ >+#define HAVE_LIBATA_MSG 1 >+ >+enum { >+ ATA_MSG_DRV = 0x0001, >+ ATA_MSG_INFO = 0x0002, >+ ATA_MSG_PROBE = 0x0004, >+ ATA_MSG_WARN = 0x0008, >+ ATA_MSG_MALLOC = 0x0010, >+ ATA_MSG_CTL = 0x0020, >+ ATA_MSG_INTR = 0x0040, >+ ATA_MSG_ERR = 0x0080, >+}; >+ >+#define ata_msg_drv(p) ((p)->msg_enable & ATA_MSG_DRV) >+#define ata_msg_info(p) ((p)->msg_enable & ATA_MSG_INFO) >+#define ata_msg_probe(p) ((p)->msg_enable & ATA_MSG_PROBE) >+#define ata_msg_warn(p) ((p)->msg_enable & ATA_MSG_WARN) >+#define ata_msg_malloc(p) ((p)->msg_enable & ATA_MSG_MALLOC) >+#define ata_msg_ctl(p) ((p)->msg_enable & ATA_MSG_CTL) >+#define ata_msg_intr(p) ((p)->msg_enable & ATA_MSG_INTR) >+#define ata_msg_err(p) ((p)->msg_enable & ATA_MSG_ERR) >+ >+static inline u32 ata_msg_init(int dval, int default_msg_enable_bits) >+{ >+ if (dval < 0 || dval >= (sizeof(u32) * 8)) >+ return default_msg_enable_bits; /* should be 0x1 - only driver info msgs */ >+ if (!dval) >+ return 0; >+ return (1 << dval) - 1; >+} >+ > /* defines only for the constants which don't work well as enums */ > #define ATA_TAG_POISON 0xfafbfcfdU > >@@ -116,6 +152,7 @@ enum { > ATA_FLAG_SUSPENDED = (1 << 9), /* port is suspended */ > ATA_FLAG_NOINTR = (1 << 10),/* FIXME: Remove this once > * proper HSM is in place. */ >+ ATA_FLAG_PATA_MODE = (1 << 15), /* port in PATA mode */ > > ATA_QCFLAG_ACTIVE = (1 << 1), /* cmd not yet ack'd to scsi lyer */ > ATA_QCFLAG_SG = (1 << 3), /* have s/g table? */ >@@ -171,6 +208,7 @@ struct scsi_device; > struct ata_port_operations; > struct ata_port; > struct ata_queued_cmd; >+struct GTM_buffer; > > /* typedefs */ > typedef int (*ata_qc_cb_t) (struct ata_queued_cmd *qc, u8 drv_stat); >@@ -281,6 +319,11 @@ struct ata_device { > u8 xfer_protocol; /* taskfile xfer protocol */ > u8 read_cmd; /* opcode to use on read */ > u8 write_cmd; /* opcode to use on write */ >+ >+#ifdef CONFIG_SCSI_SATA_ACPI >+ /* ACPI objects info */ >+ acpi_handle obj_handle; >+#endif > }; > > struct ata_port { >@@ -298,6 +341,7 @@ struct ata_port { > > u8 ctl; /* cache of ATA control register */ > u8 last_ctl; /* Cache last written value */ >+ u8 legacy_mode; > unsigned int bus_state; > unsigned int port_state; > unsigned int pio_mask; >@@ -320,6 +364,13 @@ struct ata_port { > struct work_struct pio_task; > unsigned int pio_task_state; > unsigned long pio_task_timeout; >+ struct device *dev; >+ >+ u32 msg_enable; >+#ifdef CONFIG_SCSI_SATA_ACPI >+ struct GTM_buffer *gtm; >+ void *gtm_object_area; >+#endif > > void *private_data; > }; >@@ -537,9 +588,9 @@ static inline u8 ata_wait_idle(struct at > > if (status & (ATA_BUSY | ATA_DRQ)) { > unsigned long l = ap->ioaddr.status_addr; >- printk(KERN_WARNING >- "ATA: abnormal status 0x%X on port 0x%lX\n", >- status, l); >+ if (ata_msg_warn(ap)) >+ printk(KERN_WARNING "ATA: abnormal status 0x%X on port 0x%lX\n", >+ status, l); > } > > return status; >@@ -619,7 +670,8 @@ static inline u8 ata_irq_ack(struct ata_ > > status = ata_busy_wait(ap, bits, 1000); > if (status & bits) >- DPRINTK("abnormal status 0x%X\n", status); >+ if (ata_msg_err(ap)) >+ printk(KERN_ERR "abnormal status 0x%X\n", status); > > /* get controller status; clear intr, err bits */ > if (ap->flags & ATA_FLAG_MMIO) { >@@ -637,8 +689,10 @@ static inline u8 ata_irq_ack(struct ata_ > post_stat = inb(ap->ioaddr.bmdma_addr + ATA_DMA_STATUS); > } > >- VPRINTK("irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n", >- host_stat, post_stat, status); >+ if (ata_msg_intr(ap)) >+ printk(KERN_INFO "%s: irq ack: host_stat 0x%X, new host_stat 0x%X, drv_stat 0x%X\n", >+ __FUNCTION__, >+ host_stat, post_stat, status); > > return status; > } >--- linux-2.6.13-SL100_BRANCH/include/linux/ata.h.orig 2006-02-22 08:33:27.000000000 +0100 >+++ linux-2.6.13-SL100_BRANCH/include/linux/ata.h 2006-02-27 15:47:32.000000000 +0100 >@@ -127,6 +127,9 @@ enum { > ATA_CMD_VERIFY_EXT = 0x42, > ATA_CMD_STANDBYNOW1 = 0xE0, > ATA_CMD_IDLEIMMEDIATE = 0xE1, >+ ATA_CMD_SLEEP = 0xE6, >+ ATA_CMD_READ_NATIVE = 0xF8, >+ ATA_CMD_READ_NATIVE_EXT = 0x27, > > /* SETFEATURES stuff */ > SETFEATURES_XFER = 0x03, >@@ -227,11 +230,14 @@ struct ata_taskfile { > > #define ata_id_is_ata(id) (((id)[0] & (1 << 15)) == 0) > #define ata_id_is_sata(id) ((id)[93] == 0) >+#define ata_id_set_max_locked(id) ((id)[86] & (1 << 8)) >+#define ata_id_hpa_enabled(id) ((id)[85] & (1 << 10)) > #define ata_id_rahead_enabled(id) ((id)[85] & (1 << 6)) > #define ata_id_wcache_enabled(id) ((id)[85] & (1 << 5)) > #define ata_id_has_flush(id) ((id)[83] & (1 << 12)) > #define ata_id_has_flush_ext(id) ((id)[83] & (1 << 13)) > #define ata_id_has_lba48(id) ((id)[83] & (1 << 10)) >+#define ata_id_has_hpa(id) ((id)[82] & (1 << 10)) > #define ata_id_has_wcache(id) ((id)[82] & (1 << 5)) > #define ata_id_has_pm(id) ((id)[82] & (1 << 3)) > #define ata_id_has_lba(id) ((id)[49] & (1 << 9))
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
Actions:
View
|
Diff
Attachments on
bug 151517
:
68857
|
69602
|
69656
| 70613 |
73634