linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 3/4] libata: implement ata_dev_revalidate()
  2006-02-15 10:02 [PATCHSET] libata: implement and use ata_dev_revalidate() Tejun Heo
@ 2006-02-15 10:02 ` Tejun Heo
  0 siblings, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-02-15 10:02 UTC (permalink / raw)
  To: jgarzik, albertcc, linux-ide; +Cc: Tejun Heo

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: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |  115 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/libata.h     |    2 +
 2 files changed, 117 insertions(+), 0 deletions(-)

95213b21c681afd2eef1e5cbae21337208ac4c46
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 05dadf5..54ed8fd 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2341,6 +2341,120 @@ int ata_drive_probe_reset(struct ata_por
 	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_WARNING
+		       "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_WARNING
+		       "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_WARNING
+		       "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_WARNING
+		       "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 0;
+
+	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)
 {
@@ -4956,6 +5070,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);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index e8e02a0..81014be 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -485,6 +485,8 @@ extern int ata_std_softreset(struct ata_
 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
-- 
1.1.5



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 1/4] libata: re-initialize parameters before configuring
  2006-03-01  8:20 [PATCHSET] libata: implement and use ata_dev_revalidate(), take #2 Tejun Heo
@ 2006-03-01  8:20 ` Tejun Heo
  2006-03-01  8:20 ` [PATCH 3/4] libata: implement ata_dev_revalidate() Tejun Heo
  2006-03-01  8:20 ` [PATCH 4/4] libata: revalidate after transfer mode configuration Tejun Heo
  2 siblings, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-03-01  8:20 UTC (permalink / raw)
  To: jgarzik, linux-ide; +Cc: Tejun Heo

In ata_dev_configure(), reinitialize parameters before configuring.
This change is for revalidation and hotplug.  As ata_dev_configure()
can be entered multiple times, parameters need to be reinitialized.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |    9 +++++++++
 1 files changed, 9 insertions(+), 0 deletions(-)

ce0cef100691a38180b32a74ce6ab7ca90b390f0
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 63ba1aa..17d113b 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1082,6 +1082,15 @@ static int ata_dev_configure(struct ata_
 
 	DPRINTK("ENTER, host %u, dev %u\n", ap->id, dev->devno);
 
+	/* initialize to-be-configured parameters */
+	dev->flags = 0;
+	dev->max_sectors = 0;
+	dev->cdb_len = 0;
+	dev->n_sectors = 0;
+	dev->cylinders = 0;
+	dev->heads = 0;
+	dev->sectors = 0;
+
 	/*
 	 * common ATA, ATAPI feature tests
 	 */
-- 
1.2.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 3/4] libata: implement ata_dev_revalidate()
  2006-03-01  8:20 [PATCHSET] libata: implement and use ata_dev_revalidate(), take #2 Tejun Heo
  2006-03-01  8:20 ` [PATCH 1/4] libata: re-initialize parameters before configuring Tejun Heo
@ 2006-03-01  8:20 ` Tejun Heo
  2006-03-03 22:39   ` Jeff Garzik
  2006-03-01  8:20 ` [PATCH 4/4] libata: revalidate after transfer mode configuration Tejun Heo
  2 siblings, 1 reply; 8+ messages in thread
From: Tejun Heo @ 2006-03-01  8:20 UTC (permalink / raw)
  To: jgarzik, linux-ide; +Cc: Tejun Heo

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: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |  115 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/libata.h     |    2 +
 2 files changed, 117 insertions(+), 0 deletions(-)

5f157f520bce43bee189d18e0736065ce7997334
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 64e087b..d599e8f 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2341,6 +2341,120 @@ int ata_drive_probe_reset(struct ata_por
 	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_WARNING
+		       "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_WARNING
+		       "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_WARNING
+		       "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_WARNING
+		       "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 0;
+
+	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)
 {
@@ -4960,6 +5074,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);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 1aab218..1392d22 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -485,6 +485,8 @@ extern int ata_std_softreset(struct ata_
 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
-- 
1.2.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCH 4/4] libata: revalidate after transfer mode configuration
  2006-03-01  8:20 [PATCHSET] libata: implement and use ata_dev_revalidate(), take #2 Tejun Heo
  2006-03-01  8:20 ` [PATCH 1/4] libata: re-initialize parameters before configuring Tejun Heo
  2006-03-01  8:20 ` [PATCH 3/4] libata: implement ata_dev_revalidate() Tejun Heo
@ 2006-03-01  8:20 ` Tejun Heo
  2006-03-03 22:42   ` Jeff Garzik
  2 siblings, 1 reply; 8+ messages in thread
From: Tejun Heo @ 2006-03-01  8:20 UTC (permalink / raw)
  To: jgarzik, linux-ide; +Cc: Tejun Heo

Revalidate device after transfer mode configuration.  This also makes
dev->id up-to-date.

Signed-off-by: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |    6 ++++++
 1 files changed, 6 insertions(+), 0 deletions(-)

05f0163669d505077e04f114027bea39083320bc
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index d599e8f..d73109e 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -1621,6 +1621,12 @@ static void ata_dev_set_mode(struct ata_
 	idx = ofs + dev->xfer_shift;
 	WARN_ON(idx >= ARRAY_SIZE(xfer_mode_str));
 
+	if (ata_dev_revalidate(ap, dev, 0)) {
+		printk(KERN_ERR "ata%u: failed to revalidate after set "
+		       "xfermode, disabled\n", ap->id);
+		ata_port_disable(ap);
+	}
+
 	DPRINTK("idx=%d xfer_shift=%u, xfer_mode=0x%x, base=0x%x, offset=%d\n",
 		idx, dev->xfer_shift, (int)dev->xfer_mode, (int)base, ofs);
 
-- 
1.2.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

* [PATCHSET] libata: implement and use ata_dev_revalidate(), take #2
@ 2006-03-01  8:20 Tejun Heo
  2006-03-01  8:20 ` [PATCH 1/4] libata: re-initialize parameters before configuring Tejun Heo
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Tejun Heo @ 2006-03-01  8:20 UTC (permalink / raw)
  To: jgarzik, linux-ide, htejun

Hello, Jeff.

This is the second take of implement-and-use-ata_dev_revalidate
patchset.  In the last take[1], out of four patches, %1 got ACK'ed, %2
had some minor issues, %3 got no comment and %4 had some issue but got
resolved.

Changes from the last take are...

* in #2, @verbose is renamed to @print_info as suggested
* in #2, lba_desc change is described in the patch description

This patchset is against
the current #upstream[2]
+ kill-illegal-kfree patch[3]
+ reorganize-ata_dev_identify patchset[4]

Thanks.

--
tejun

[1] http://article.gmane.org/gmane.linux.ide/8050
[2] cccc65a3b60edaf721cdee5a14f68ba009341822
[3] http://article.gmane.org/gmane.linux.ide/8324
[4] http://article.gmane.org/gmane.linux.ide/8412



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 3/4] libata: implement ata_dev_revalidate()
  2006-03-01  8:20 ` [PATCH 3/4] libata: implement ata_dev_revalidate() Tejun Heo
@ 2006-03-03 22:39   ` Jeff Garzik
  0 siblings, 0 replies; 8+ messages in thread
From: Jeff Garzik @ 2006-03-03 22:39 UTC (permalink / raw)
  To: Tejun Heo; +Cc: linux-ide

Tejun Heo wrote:
> 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: Tejun Heo <htejun@gmail.com>
> 
> ---
> 
>  drivers/scsi/libata-core.c |  115 ++++++++++++++++++++++++++++++++++++++++++++
>  include/linux/libata.h     |    2 +
>  2 files changed, 117 insertions(+), 0 deletions(-)
> 
> 5f157f520bce43bee189d18e0736065ce7997334
> diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
> index 64e087b..d599e8f 100644
> --- a/drivers/scsi/libata-core.c
> +++ b/drivers/scsi/libata-core.c
> @@ -2341,6 +2341,120 @@ int ata_drive_probe_reset(struct ata_por
>  	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_WARNING
> +		       "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_WARNING
> +		       "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_WARNING
> +		       "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_WARNING
> +		       "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;

For the hotplug case, its inaccurate to call these warnings.


> + *	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 0;

I would think the proper return value for this case is -ENODEV.

Otherwise OK.

	Jeff



^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH 4/4] libata: revalidate after transfer mode configuration
  2006-03-01  8:20 ` [PATCH 4/4] libata: revalidate after transfer mode configuration Tejun Heo
@ 2006-03-03 22:42   ` Jeff Garzik
  0 siblings, 0 replies; 8+ messages in thread
From: Jeff Garzik @ 2006-03-03 22:42 UTC (permalink / raw)
  To: Tejun Heo; +Cc: linux-ide

Tejun Heo wrote:
> Revalidate device after transfer mode configuration.  This also makes
> dev->id up-to-date.
> 
> Signed-off-by: Tejun Heo <htejun@gmail.com>

ACK 1, 2 and 4.



^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH 3/4] libata: implement ata_dev_revalidate()
  2006-03-05  8:55 [PATCHSET] libata: implement and use ata_dev_revalidate(), take #3 Tejun Heo
@ 2006-03-05  8:55 ` Tejun Heo
  0 siblings, 0 replies; 8+ messages in thread
From: Tejun Heo @ 2006-03-05  8:55 UTC (permalink / raw)
  To: jgarzik, linux-ide; +Cc: Tejun Heo

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: Tejun Heo <htejun@gmail.com>

---

 drivers/scsi/libata-core.c |  115 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/libata.h     |    2 +
 2 files changed, 117 insertions(+), 0 deletions(-)

291782c65f9b708317c75869df3cbe58c36cb2b2
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index d65aa86..5d0adfa 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2345,6 +2345,120 @@ int ata_drive_probe_reset(struct ata_por
 	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);
diff --git a/include/linux/libata.h b/include/linux/libata.h
index 86a504f..66dce58 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -485,6 +485,8 @@ extern int ata_std_softreset(struct ata_
 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
-- 
1.2.1



^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2006-03-05  8:56 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-03-01  8:20 [PATCHSET] libata: implement and use ata_dev_revalidate(), take #2 Tejun Heo
2006-03-01  8:20 ` [PATCH 1/4] libata: re-initialize parameters before configuring Tejun Heo
2006-03-01  8:20 ` [PATCH 3/4] libata: implement ata_dev_revalidate() Tejun Heo
2006-03-03 22:39   ` Jeff Garzik
2006-03-01  8:20 ` [PATCH 4/4] libata: revalidate after transfer mode configuration Tejun Heo
2006-03-03 22:42   ` Jeff Garzik
  -- strict thread matches above, loose matches on Subject: below --
2006-03-05  8:55 [PATCHSET] libata: implement and use ata_dev_revalidate(), take #3 Tejun Heo
2006-03-05  8:55 ` [PATCH 3/4] libata: implement ata_dev_revalidate() Tejun Heo
2006-02-15 10:02 [PATCHSET] libata: implement and use ata_dev_revalidate() Tejun Heo
2006-02-15 10:02 ` [PATCH 3/4] libata: implement ata_dev_revalidate() Tejun Heo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).