linux-ide.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Tejun Heo <htejun@gmail.com>
To: jgarzik@pobox.com, linux-ide@vger.kernel.org,
	albertcc@tw.ibm.com, alan@lxorguk.ukuu.org.uk
Cc: Tejun Heo <htejun@gmail.com>
Subject: [PATCH 15/16] libata: implement ata_dev_revalidate()
Date: Fri, 27 Jan 2006 00:39:12 +0900	[thread overview]
Message-ID: <11382899522604-git-send-email-htejun@gmail.com> (raw)
In-Reply-To: <1138289951261-git-send-email-htejun@gmail.com>

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 |  119 ++++++++++++++++++++++++++++++++++++++++++++
 include/linux/libata.h     |    2 +
 2 files changed, 121 insertions(+), 0 deletions(-)

f6a56c850e45513559d097c0f3523e4fe9d8fbeb
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index 4150335..68ee230 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2660,6 +2660,124 @@ 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_dev_id_c_string(old_id, model[0],
+			    ATA_ID_PROD_OFS, sizeof(model[0]));
+	ata_dev_id_c_string(new_id, model[1],
+			    ATA_ID_PROD_OFS, sizeof(model[1]));
+	ata_dev_id_c_string(old_id, serial[0],
+			    ATA_ID_SERNO_OFS, sizeof(serial[0]));
+	ata_dev_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)
 {
@@ -5560,6 +5678,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 2221013..4ccea16 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -491,6 +491,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.3



  parent reply	other threads:[~2006-01-26 15:39 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2006-01-26 15:39 [PATCHSET] libata: reorganize configuration and implement revalidation Tejun Heo
2006-01-26 15:39 ` [PATCH 07/16] libata: convert dev->id to pointer Tejun Heo
2006-01-26 15:39 ` [PATCH 02/16] libata: use ata_dev_id_c_string() Tejun Heo
2006-01-26 15:39 ` [PATCH 09/16] libata: kill ata_dev_reread_id() Tejun Heo
2006-01-26 15:39 ` [PATCH 11/16] libata: fold ata_dev_config() into ata_dev_configure() Tejun Heo
2006-01-26 15:39 ` [PATCH 04/16] libata: separate out ata_id_major_version() Tejun Heo
2006-01-26 15:39 ` [PATCH 12/16] libata: reorganize ata_bus_probe() Tejun Heo
2006-01-26 15:39 ` [PATCH 05/16] libata: make ata_dump_id() take @id instead of @dev Tejun Heo
2006-01-26 15:39 ` [PATCH 01/16] libata: implement ata_dev_id_c_string() Tejun Heo
2006-01-26 15:39 ` [PATCH 13/16] libata: re-initialize parameters before configuring Tejun Heo
2006-01-26 15:39 ` [PATCH 16/16] libata: revalidate after transfer mode configuration Tejun Heo
2006-01-26 15:39 ` Tejun Heo [this message]
2006-01-26 17:42 ` [PATCHSET] libata: reorganize configuration and implement revalidation Mark Lord

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=11382899522604-git-send-email-htejun@gmail.com \
    --to=htejun@gmail.com \
    --cc=alan@lxorguk.ukuu.org.uk \
    --cc=albertcc@tw.ibm.com \
    --cc=jgarzik@pobox.com \
    --cc=linux-ide@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).