mirror of
https://github.com/torvalds/linux.git
synced 2024-11-15 16:41:58 +00:00
[PATCH] libata: implement ata_drive_probe_reset()
Most low level drivers share supported reset/classify actions and sequence. This patch implements ata_drive_probe_reset() which helps constructing ->probe_reset from three component operations - softreset, hardreset and postreset. This minimizes duplicate code and yet allows flexibility if needed. The three component operations can also be shared by EH later. Signed-off-by: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jgarzik@pobox.com>
This commit is contained in:
parent
c19ba8af4f
commit
a62c0fc526
@ -2233,6 +2233,94 @@ err_out:
|
||||
DPRINTK("EXIT\n");
|
||||
}
|
||||
|
||||
static int do_probe_reset(struct ata_port *ap, ata_reset_fn_t reset,
|
||||
ata_postreset_fn_t postreset,
|
||||
unsigned int *classes)
|
||||
{
|
||||
int i, rc;
|
||||
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++)
|
||||
classes[i] = ATA_DEV_UNKNOWN;
|
||||
|
||||
rc = reset(ap, 0, classes);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
/* If any class isn't ATA_DEV_UNKNOWN, consider classification
|
||||
* is complete and convert all ATA_DEV_UNKNOWN to
|
||||
* ATA_DEV_NONE.
|
||||
*/
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++)
|
||||
if (classes[i] != ATA_DEV_UNKNOWN)
|
||||
break;
|
||||
|
||||
if (i < ATA_MAX_DEVICES)
|
||||
for (i = 0; i < ATA_MAX_DEVICES; i++)
|
||||
if (classes[i] == ATA_DEV_UNKNOWN)
|
||||
classes[i] = ATA_DEV_NONE;
|
||||
|
||||
if (postreset)
|
||||
postreset(ap, classes);
|
||||
|
||||
return classes[0] != ATA_DEV_UNKNOWN ? 0 : -ENODEV;
|
||||
}
|
||||
|
||||
/**
|
||||
* ata_drive_probe_reset - Perform probe reset with given methods
|
||||
* @ap: port to reset
|
||||
* @softreset: softreset method (can be NULL)
|
||||
* @hardreset: hardreset method (can be NULL)
|
||||
* @postreset: postreset method (can be NULL)
|
||||
* @classes: resulting classes of attached devices
|
||||
*
|
||||
* Reset the specified port and classify attached devices using
|
||||
* given methods. This function prefers softreset but tries all
|
||||
* possible reset sequences to reset and classify devices. This
|
||||
* function is intended to be used for constructing ->probe_reset
|
||||
* callback by low level drivers.
|
||||
*
|
||||
* Reset methods should follow the following rules.
|
||||
*
|
||||
* - Return 0 on sucess, -errno on failure.
|
||||
* - If classification is supported, fill classes[] with
|
||||
* recognized class codes.
|
||||
* - If classification is not supported, leave classes[] alone.
|
||||
* - If verbose is non-zero, print error message on failure;
|
||||
* otherwise, shut up.
|
||||
*
|
||||
* LOCKING:
|
||||
* Kernel thread context (may sleep)
|
||||
*
|
||||
* RETURNS:
|
||||
* 0 on success, -EINVAL if no reset method is avaliable, -ENODEV
|
||||
* if classification fails, and any error code from reset
|
||||
* methods.
|
||||
*/
|
||||
int ata_drive_probe_reset(struct ata_port *ap,
|
||||
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
|
||||
ata_postreset_fn_t postreset, unsigned int *classes)
|
||||
{
|
||||
int rc = -EINVAL;
|
||||
|
||||
if (softreset) {
|
||||
rc = do_probe_reset(ap, softreset, postreset, classes);
|
||||
if (rc == 0)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!hardreset)
|
||||
return rc;
|
||||
|
||||
rc = do_probe_reset(ap, hardreset, postreset, classes);
|
||||
if (rc == 0 || rc != -ENODEV)
|
||||
return rc;
|
||||
|
||||
if (softreset)
|
||||
rc = do_probe_reset(ap, softreset, postreset, classes);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void ata_pr_blacklisted(const struct ata_port *ap,
|
||||
const struct ata_device *dev)
|
||||
{
|
||||
@ -5180,6 +5268,7 @@ EXPORT_SYMBOL_GPL(ata_port_probe);
|
||||
EXPORT_SYMBOL_GPL(sata_phy_reset);
|
||||
EXPORT_SYMBOL_GPL(__sata_phy_reset);
|
||||
EXPORT_SYMBOL_GPL(ata_bus_reset);
|
||||
EXPORT_SYMBOL_GPL(ata_drive_probe_reset);
|
||||
EXPORT_SYMBOL_GPL(ata_port_disable);
|
||||
EXPORT_SYMBOL_GPL(ata_ratelimit);
|
||||
EXPORT_SYMBOL_GPL(ata_busy_sleep);
|
||||
|
@ -241,6 +241,8 @@ struct ata_queued_cmd;
|
||||
|
||||
/* typedefs */
|
||||
typedef void (*ata_qc_cb_t) (struct ata_queued_cmd *qc);
|
||||
typedef int (*ata_reset_fn_t)(struct ata_port *, int, unsigned int *);
|
||||
typedef void (*ata_postreset_fn_t)(struct ata_port *ap, unsigned int *);
|
||||
|
||||
struct ata_ioports {
|
||||
unsigned long cmd_addr;
|
||||
@ -478,6 +480,9 @@ extern void ata_port_probe(struct ata_port *);
|
||||
extern void __sata_phy_reset(struct ata_port *ap);
|
||||
extern void sata_phy_reset(struct ata_port *ap);
|
||||
extern void ata_bus_reset(struct ata_port *ap);
|
||||
extern int ata_drive_probe_reset(struct ata_port *ap,
|
||||
ata_reset_fn_t softreset, ata_reset_fn_t hardreset,
|
||||
ata_postreset_fn_t postreset, unsigned int *classes);
|
||||
extern void ata_port_disable(struct ata_port *);
|
||||
extern void ata_std_ports(struct ata_ioports *ioaddr);
|
||||
#ifdef CONFIG_PCI
|
||||
|
Loading…
Reference in New Issue
Block a user