Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 58687
b: refs/heads/master
c: 6746544
h: refs/heads/master
i:
  58685: e1dd397
  58683: 91125ac
  58679: 84b9ced
  58671: af4a528
  58655: 59f3641
  58623: 0637571
v: v3
  • Loading branch information
Tejun Heo authored and Jeff Garzik committed Jul 9, 2007
1 parent 9b42fb5 commit 94ad651
Show file tree
Hide file tree
Showing 6 changed files with 141 additions and 100 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 69b16a5f4c4f1dab70d4d555c487c318c6878b3e
refs/heads/master: 6746544c3b143ca7071d144f1882ccbe1f47b08d
204 changes: 125 additions & 79 deletions trunk/drivers/ata/libata-acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -272,92 +272,48 @@ static int taskfile_load_raw(struct ata_device *dev,
return 0;
}

/**
* ata_dev_set_taskfiles - write the drive taskfile settings from _GTF
* @dev: target ATA device
* @gtf: pointer to array of _GTF taskfiles to execute
* @gtf_count: number of taskfiles
*
* This applies to both PATA and SATA drives.
*
* Execute taskfiles in @gtf.
*
* LOCKING:
* EH context.
*
* RETURNS:
* 0 on success, -errno on failure.
*/
static int ata_dev_set_taskfiles(struct ata_device *dev,
struct ata_acpi_gtf *gtf, int gtf_count)
{
struct ata_port *ap = dev->ap;
int ix;

if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER: port#: %d\n",
__FUNCTION__, ap->port_no);

if (!(ap->flags & ATA_FLAG_ACPI_SATA))
return 0;

if (!ata_dev_enabled(dev) || (ap->flags & ATA_FLAG_DISABLED))
return -ENODEV;

/* send all TaskFile registers (0x1f1-0x1f7) *in*that*order* */
for (ix = 0; ix < gtf_count; ix++)
taskfile_load_raw(dev, gtf++);

return 0;
}

/**
* ata_acpi_exec_tfs - get then write drive taskfile settings
* @ap: the ata_port for the drive
* @dev: target ATA device
*
* This applies to both PATA and SATA drives.
* Evaluate _GTF and excute returned taskfiles.
*
* LOCKING:
* EH context.
*
* RETURNS:
* 0 on success, -errno on failure.
* Number of executed taskfiles on success, 0 if _GTF doesn't exist or
* doesn't contain valid data. -errno on other errors.
*/
int ata_acpi_exec_tfs(struct ata_port *ap)
static int ata_acpi_exec_tfs(struct ata_device *dev)
{
int ix, ret = 0;

/*
* TBD - implement PATA support. For now,
* we should not run GTF on PATA devices since some
* PATA require execution of GTM/STM before GTF.
*/
if (!(ap->flags & ATA_FLAG_ACPI_SATA))
return 0;

for (ix = 0; ix < ATA_MAX_DEVICES; ix++) {
struct ata_device *dev = &ap->device[ix];
struct ata_acpi_gtf *gtf = NULL;
int gtf_count;
void *ptr_to_free = NULL;

if (!ata_dev_enabled(dev))
continue;

ret = ata_dev_get_GTF(dev, &gtf, &ptr_to_free);
if (ret == 0)
continue;
if (ret < 0)
break;
gtf_count = ret;

ret = ata_dev_set_taskfiles(dev, gtf, gtf_count);
kfree(ptr_to_free);
if (ret < 0)
break;
struct ata_acpi_gtf *gtf = NULL;
void *ptr_to_free = NULL;
int gtf_count, i, rc;

/* get taskfiles */
rc = ata_dev_get_GTF(dev, &gtf, &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;
}

return ret;
kfree(ptr_to_free);

if (rc == 0)
return gtf_count;
return rc;
}

/**
Expand All @@ -376,7 +332,7 @@ int ata_acpi_exec_tfs(struct ata_port *ap)
* RETURNS:
* 0 on success, -errno on failure.
*/
int ata_acpi_push_id(struct ata_device *dev)
static int ata_acpi_push_id(struct ata_device *dev)
{
struct ata_port *ap = dev->ap;
int err;
Expand All @@ -396,7 +352,7 @@ int ata_acpi_push_id(struct ata_device *dev)
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG,
"%s: Not a SATA device\n", __FUNCTION__);
goto out;
return 0;
}

/* Give the drive Identify data to the drive via the _SDD method */
Expand All @@ -418,9 +374,99 @@ int ata_acpi_push_id(struct ata_device *dev)
ata_dev_printk(dev, KERN_WARNING,
"ACPI _SDD failed (AE 0x%x)\n", status);

/* always return success */
out:
return 0;
return err;
}

/**
* ata_acpi_on_resume - ATA ACPI hook called on resume
* @ap: target ATA port
*
* This function is called when @ap is resumed - right after port
* itself is resumed but before any EH action is taken.
*
* LOCKING:
* EH context.
*/
void ata_acpi_on_resume(struct ata_port *ap)
{
int i;

/* schedule _GTF */
for (i = 0; i < ATA_MAX_DEVICES; i++)
ap->device[i].flags |= ATA_DFLAG_ACPI_PENDING;
}

/**
* ata_acpi_on_devcfg - ATA ACPI hook called on device donfiguration
* @dev: target ATA device
*
* This function is called when @dev is about to be configured.
* IDENTIFY data might have been modified after this hook is run.
*
* LOCKING:
* EH context.
*
* RETURNS:
* Positive number if IDENTIFY data needs to be refreshed, 0 if not,
* -errno on failure.
*/
int ata_acpi_on_devcfg(struct ata_device *dev)
{
struct ata_port *ap = dev->ap;
struct ata_eh_context *ehc = &ap->eh_context;
int acpi_sata = ap->flags & ATA_FLAG_ACPI_SATA;
int rc;

/* XXX: _STM isn't implemented yet, skip if IDE for now */
if (!acpi_sata)
return 0;

if (!dev->acpi_handle)
return 0;

/* do we need to do _GTF? */
if (!(dev->flags & ATA_DFLAG_ACPI_PENDING) &&
!(acpi_sata && (ehc->i.flags & ATA_EHI_DID_HARDRESET)))
return 0;

/* do _SDD if SATA */
if (acpi_sata) {
rc = ata_acpi_push_id(dev);
if (rc)
goto acpi_err;
}

/* do _GTF */
rc = ata_acpi_exec_tfs(dev);
if (rc < 0)
goto acpi_err;

dev->flags &= ~ATA_DFLAG_ACPI_PENDING;

/* refresh IDENTIFY page if any _GTF command has been executed */
if (rc > 0) {
rc = ata_dev_reread_id(dev, 0);
if (rc < 0) {
ata_dev_printk(dev, KERN_ERR, "failed to IDENTIFY "
"after ACPI commands\n");
return rc;
}
}

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);

dev->acpi_handle = NULL;

/* 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;
}
16 changes: 6 additions & 10 deletions trunk/drivers/ata/libata-core.c
Original file line number Diff line number Diff line change
Expand Up @@ -1845,7 +1845,8 @@ static void ata_dev_config_ncq(struct ata_device *dev,
int ata_dev_configure(struct ata_device *dev)
{
struct ata_port *ap = dev->ap;
int print_info = ap->eh_context.i.flags & ATA_EHI_PRINTINFO;
struct ata_eh_context *ehc = &ap->eh_context;
int print_info = ehc->i.flags & ATA_EHI_PRINTINFO;
const u16 *id = dev->id;
unsigned int xfer_mask;
char revbuf[7]; /* XYZ-99\0 */
Expand All @@ -1862,15 +1863,10 @@ int ata_dev_configure(struct ata_device *dev)
if (ata_msg_probe(ap))
ata_dev_printk(dev, KERN_DEBUG, "%s: ENTER\n", __FUNCTION__);

/* set _SDD */
rc = ata_acpi_push_id(dev);
if (rc) {
ata_dev_printk(dev, KERN_WARNING, "failed to set _SDD(%d)\n",
rc);
}

/* retrieve and execute the ATA task file of _GTF */
ata_acpi_exec_tfs(ap);
/* let ACPI work its magic */
rc = ata_acpi_on_devcfg(dev);
if (rc)
return rc;

/* print device capabilities */
if (ata_msg_probe(ap))
Expand Down
3 changes: 3 additions & 0 deletions trunk/drivers/ata/libata-eh.c
Original file line number Diff line number Diff line change
Expand Up @@ -2207,6 +2207,9 @@ static void ata_eh_handle_port_resume(struct ata_port *ap)
if (ap->ops->port_resume)
rc = ap->ops->port_resume(ap);

/* tell ACPI that we're resuming */
ata_acpi_on_resume(ap);

/* report result */
spin_lock_irqsave(ap->lock, flags);
ap->pflags &= ~(ATA_PFLAG_PM_PENDING | ATA_PFLAG_SUSPENDED);
Expand Down
14 changes: 4 additions & 10 deletions trunk/drivers/ata/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,18 +99,12 @@ extern struct ata_port *ata_port_alloc(struct ata_host *host);
/* libata-acpi.c */
#ifdef CONFIG_ATA_ACPI
extern void ata_acpi_associate(struct ata_host *host);
extern int ata_acpi_exec_tfs(struct ata_port *ap);
extern int ata_acpi_push_id(struct ata_device *dev);
extern void ata_acpi_on_resume(struct ata_port *ap);
extern int ata_acpi_on_devcfg(struct ata_device *adev);
#else
static inline void ata_acpi_associate(struct ata_host *host) { }
static inline int ata_acpi_exec_tfs(struct ata_port *ap)
{
return 0;
}
static inline int ata_acpi_push_id(struct ata_device *dev)
{
return 0;
}
static inline void ata_acpi_on_resume(struct ata_port *ap) { }
static inline int ata_acpi_on_devcfg(struct ata_device *adev) { return 0; }
#endif

/* libata-scsi.c */
Expand Down
2 changes: 2 additions & 0 deletions trunk/include/linux/libata.h
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,8 @@ enum {
ATA_DFLAG_CDB_INTR = (1 << 2), /* device asserts INTRQ when ready for CDB */
ATA_DFLAG_NCQ = (1 << 3), /* device supports NCQ */
ATA_DFLAG_FLUSH_EXT = (1 << 4), /* do FLUSH_EXT instead of FLUSH */
ATA_DFLAG_ACPI_PENDING = (1 << 5), /* ACPI resume action pending */
ATA_DFLAG_ACPI_FAILED = (1 << 6), /* ACPI on devcfg has failed */
ATA_DFLAG_CFG_MASK = (1 << 8) - 1,

ATA_DFLAG_PIO = (1 << 8), /* device limited to PIO mode */
Expand Down

0 comments on commit 94ad651

Please sign in to comment.