[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:
Tejun Heo 2006-01-24 17:05:22 +09:00 committed by Jeff Garzik
parent c19ba8af4f
commit a62c0fc526
2 changed files with 94 additions and 0 deletions

View file

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

View file

@ -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