提交 623a3128 编写于 作者: T Tejun Heo 提交者: Jeff Garzik

[PATCH] libata: implement ata_dev_revalidate()

ata_dev_revalidate() re-reads IDENTIFY PAGE of the given device and
makes sure it's the same device as the configured one.  Once it's
verified that it's the same device, @dev is configured according to
newly read IDENTIFY PAGE.  Note that revalidation currently doesn't
invoke transfer mode reconfiguration.

Criteria for 'same device'

* same class (of course)
* same model string
* same serial string
* if ATA, same n_sectors (to catch geometry parameter changes)
Signed-off-by: NTejun Heo <htejun@gmail.com>
Signed-off-by: NJeff Garzik <jeff@garzik.org>
上级 4c2d721a
......@@ -2345,6 +2345,120 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
return rc;
}
/**
* ata_dev_same_device - Determine whether new ID matches configured device
* @ap: port on which the device to compare against resides
* @dev: device to compare against
* @new_class: class of the new device
* @new_id: IDENTIFY page of the new device
*
* Compare @new_class and @new_id against @dev and determine
* whether @dev is the device indicated by @new_class and
* @new_id.
*
* LOCKING:
* None.
*
* RETURNS:
* 1 if @dev matches @new_class and @new_id, 0 otherwise.
*/
static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev,
unsigned int new_class, const u16 *new_id)
{
const u16 *old_id = dev->id;
unsigned char model[2][41], serial[2][21];
u64 new_n_sectors;
if (dev->class != new_class) {
printk(KERN_INFO
"ata%u: dev %u class mismatch %d != %d\n",
ap->id, dev->devno, dev->class, new_class);
return 0;
}
ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
new_n_sectors = ata_id_n_sectors(new_id);
if (strcmp(model[0], model[1])) {
printk(KERN_INFO
"ata%u: dev %u model number mismatch '%s' != '%s'\n",
ap->id, dev->devno, model[0], model[1]);
return 0;
}
if (strcmp(serial[0], serial[1])) {
printk(KERN_INFO
"ata%u: dev %u serial number mismatch '%s' != '%s'\n",
ap->id, dev->devno, serial[0], serial[1]);
return 0;
}
if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) {
printk(KERN_INFO
"ata%u: dev %u n_sectors mismatch %llu != %llu\n",
ap->id, dev->devno, (unsigned long long)dev->n_sectors,
(unsigned long long)new_n_sectors);
return 0;
}
return 1;
}
/**
* ata_dev_revalidate - Revalidate ATA device
* @ap: port on which the device to revalidate resides
* @dev: device to revalidate
* @post_reset: is this revalidation after reset?
*
* Re-read IDENTIFY page and make sure @dev is still attached to
* the port.
*
* LOCKING:
* Kernel thread context (may sleep)
*
* RETURNS:
* 0 on success, negative errno otherwise
*/
int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
int post_reset)
{
unsigned int class;
u16 *id;
int rc;
if (!ata_dev_present(dev))
return -ENODEV;
class = dev->class;
id = NULL;
/* allocate & read ID data */
rc = ata_dev_read_id(ap, dev, &class, post_reset, &id);
if (rc)
goto fail;
/* is the device still there? */
if (!ata_dev_same_device(ap, dev, class, id)) {
rc = -ENODEV;
goto fail;
}
kfree(dev->id);
dev->id = id;
/* configure device according to the new ID */
return ata_dev_configure(ap, dev, 0);
fail:
printk(KERN_ERR "ata%u: dev %u revalidation failed (errno=%d)\n",
ap->id, dev->devno, rc);
kfree(id);
return rc;
}
static void ata_pr_blacklisted(const struct ata_port *ap,
const struct ata_device *dev)
{
......@@ -4964,6 +5078,7 @@ EXPORT_SYMBOL_GPL(sata_std_hardreset);
EXPORT_SYMBOL_GPL(ata_std_postreset);
EXPORT_SYMBOL_GPL(ata_std_probe_reset);
EXPORT_SYMBOL_GPL(ata_drive_probe_reset);
EXPORT_SYMBOL_GPL(ata_dev_revalidate);
EXPORT_SYMBOL_GPL(ata_port_disable);
EXPORT_SYMBOL_GPL(ata_ratelimit);
EXPORT_SYMBOL_GPL(ata_busy_sleep);
......
......@@ -485,6 +485,8 @@ extern int ata_std_softreset(struct ata_port *ap, int verbose,
extern int sata_std_hardreset(struct ata_port *ap, int verbose,
unsigned int *class);
extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes);
extern int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
int post_reset);
extern void ata_port_disable(struct ata_port *);
extern void ata_std_ports(struct ata_ioports *ioaddr);
#ifdef CONFIG_PCI
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册