[PATCH] libata: implement new SCR handling and port on/offline functions

Implement ata_scr_{valid|read|write|write_flush}() and
ata_port_{online|offline}().  These functions replace
scr_{read|write}() and sata_dev_present().

Major difference between between the new SCR functions and the old
ones is that the new ones have a way to signal error to the caller.
This makes handling SCR-available and SCR-unavailable cases in the
same path easier.  Also, it eases later PM implementation where SCR
access can fail due to various reasons.

ata_port_{online|offline}() functions return 1 only when they are
affirmitive of the condition.  e.g.  if SCR is unaccessible or
presence cannot be determined for other reasons, these functions
return 0.  So, ata_port_online() != !ata_port_offline().  This
distinction is useful in many exception handling cases.

Signed-off-by: Tejun Heo <htejun@gmail.com>
This commit is contained in:
Tejun Heo 2006-05-15 20:57:46 +09:00
parent 838df6284c
commit 34bf21704c
2 changed files with 149 additions and 0 deletions

View File

@ -4365,6 +4365,143 @@ irqreturn_t ata_interrupt (int irq, void *dev_instance, struct pt_regs *regs)
return IRQ_RETVAL(handled);
}
/**
* sata_scr_valid - test whether SCRs are accessible
* @ap: ATA port to test SCR accessibility for
*
* Test whether SCRs are accessible for @ap.
*
* LOCKING:
* None.
*
* RETURNS:
* 1 if SCRs are accessible, 0 otherwise.
*/
int sata_scr_valid(struct ata_port *ap)
{
return ap->cbl == ATA_CBL_SATA && ap->ops->scr_read;
}
/**
* sata_scr_read - read SCR register of the specified port
* @ap: ATA port to read SCR for
* @reg: SCR to read
* @val: Place to store read value
*
* Read SCR register @reg of @ap into *@val. This function is
* guaranteed to succeed if the cable type of the port is SATA
* and the port implements ->scr_read.
*
* LOCKING:
* None.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
int sata_scr_read(struct ata_port *ap, int reg, u32 *val)
{
if (sata_scr_valid(ap)) {
*val = ap->ops->scr_read(ap, reg);
return 0;
}
return -EOPNOTSUPP;
}
/**
* sata_scr_write - write SCR register of the specified port
* @ap: ATA port to write SCR for
* @reg: SCR to write
* @val: value to write
*
* Write @val to SCR register @reg of @ap. This function is
* guaranteed to succeed if the cable type of the port is SATA
* and the port implements ->scr_read.
*
* LOCKING:
* None.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
int sata_scr_write(struct ata_port *ap, int reg, u32 val)
{
if (sata_scr_valid(ap)) {
ap->ops->scr_write(ap, reg, val);
return 0;
}
return -EOPNOTSUPP;
}
/**
* sata_scr_write_flush - write SCR register of the specified port and flush
* @ap: ATA port to write SCR for
* @reg: SCR to write
* @val: value to write
*
* This function is identical to sata_scr_write() except that this
* function performs flush after writing to the register.
*
* LOCKING:
* None.
*
* RETURNS:
* 0 on success, negative errno on failure.
*/
int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val)
{
if (sata_scr_valid(ap)) {
ap->ops->scr_write(ap, reg, val);
ap->ops->scr_read(ap, reg);
return 0;
}
return -EOPNOTSUPP;
}
/**
* ata_port_online - test whether the given port is online
* @ap: ATA port to test
*
* Test whether @ap is online. Note that this function returns 0
* if online status of @ap cannot be obtained, so
* ata_port_online(ap) != !ata_port_offline(ap).
*
* LOCKING:
* None.
*
* RETURNS:
* 1 if the port online status is available and online.
*/
int ata_port_online(struct ata_port *ap)
{
u32 sstatus;
if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) == 0x3)
return 1;
return 0;
}
/**
* ata_port_offline - test whether the given port is offline
* @ap: ATA port to test
*
* Test whether @ap is offline. Note that this function returns
* 0 if offline status of @ap cannot be obtained, so
* ata_port_online(ap) != !ata_port_offline(ap).
*
* LOCKING:
* None.
*
* RETURNS:
* 1 if the port offline status is available and offline.
*/
int ata_port_offline(struct ata_port *ap)
{
u32 sstatus;
if (!sata_scr_read(ap, SCR_STATUS, &sstatus) && (sstatus & 0xf) != 0x3)
return 1;
return 0;
}
/*
* Execute a 'simple' command, that only consists of the opcode 'cmd' itself,
@ -5133,6 +5270,12 @@ EXPORT_SYMBOL_GPL(ata_scsi_queuecmd);
EXPORT_SYMBOL_GPL(ata_scsi_slave_config);
EXPORT_SYMBOL_GPL(ata_scsi_release);
EXPORT_SYMBOL_GPL(ata_host_intr);
EXPORT_SYMBOL_GPL(sata_scr_valid);
EXPORT_SYMBOL_GPL(sata_scr_read);
EXPORT_SYMBOL_GPL(sata_scr_write);
EXPORT_SYMBOL_GPL(sata_scr_write_flush);
EXPORT_SYMBOL_GPL(ata_port_online);
EXPORT_SYMBOL_GPL(ata_port_offline);
EXPORT_SYMBOL_GPL(ata_id_string);
EXPORT_SYMBOL_GPL(ata_id_c_string);
EXPORT_SYMBOL_GPL(ata_scsi_simulate);

View File

@ -536,6 +536,12 @@ extern int ata_scsi_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
extern int ata_scsi_queuecmd(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *));
extern int ata_scsi_release(struct Scsi_Host *host);
extern unsigned int ata_host_intr(struct ata_port *ap, struct ata_queued_cmd *qc);
extern int sata_scr_valid(struct ata_port *ap);
extern int sata_scr_read(struct ata_port *ap, int reg, u32 *val);
extern int sata_scr_write(struct ata_port *ap, int reg, u32 val);
extern int sata_scr_write_flush(struct ata_port *ap, int reg, u32 val);
extern int ata_port_online(struct ata_port *ap);
extern int ata_port_offline(struct ata_port *ap);
extern int ata_scsi_device_resume(struct scsi_device *);
extern int ata_scsi_device_suspend(struct scsi_device *, pm_message_t state);
extern int ata_device_resume(struct ata_port *, struct ata_device *);