aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/scsi/libata-core.c
diff options
context:
space:
mode:
authorTejun Heo <htejun@gmail.com>2006-03-05 03:55:58 -0500
committerJeff Garzik <jeff@garzik.org>2006-03-05 11:09:42 -0500
commit623a3128aa2b86caa8e06e762e9e444177e4fa47 (patch)
tree3e861e10c2963a22d2f097e5545fdcd865667602 /drivers/scsi/libata-core.c
parent4c2d721ab6413ee4ff33617ed1413458261f36ea (diff)
[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: Tejun Heo <htejun@gmail.com> Signed-off-by: Jeff Garzik <jeff@garzik.org>
Diffstat (limited to 'drivers/scsi/libata-core.c')
-rw-r--r--drivers/scsi/libata-core.c115
1 files changed, 115 insertions, 0 deletions
diff --git a/drivers/scsi/libata-core.c b/drivers/scsi/libata-core.c
index d65aa86ddbb2..5d0adfa4610a 100644
--- a/drivers/scsi/libata-core.c
+++ b/drivers/scsi/libata-core.c
@@ -2345,6 +2345,120 @@ int ata_drive_probe_reset(struct ata_port *ap, ata_probeinit_fn_t probeinit,
2345 return rc; 2345 return rc;
2346} 2346}
2347 2347
2348/**
2349 * ata_dev_same_device - Determine whether new ID matches configured device
2350 * @ap: port on which the device to compare against resides
2351 * @dev: device to compare against
2352 * @new_class: class of the new device
2353 * @new_id: IDENTIFY page of the new device
2354 *
2355 * Compare @new_class and @new_id against @dev and determine
2356 * whether @dev is the device indicated by @new_class and
2357 * @new_id.
2358 *
2359 * LOCKING:
2360 * None.
2361 *
2362 * RETURNS:
2363 * 1 if @dev matches @new_class and @new_id, 0 otherwise.
2364 */
2365static int ata_dev_same_device(struct ata_port *ap, struct ata_device *dev,
2366 unsigned int new_class, const u16 *new_id)
2367{
2368 const u16 *old_id = dev->id;
2369 unsigned char model[2][41], serial[2][21];
2370 u64 new_n_sectors;
2371
2372 if (dev->class != new_class) {
2373 printk(KERN_INFO
2374 "ata%u: dev %u class mismatch %d != %d\n",
2375 ap->id, dev->devno, dev->class, new_class);
2376 return 0;
2377 }
2378
2379 ata_id_c_string(old_id, model[0], ATA_ID_PROD_OFS, sizeof(model[0]));
2380 ata_id_c_string(new_id, model[1], ATA_ID_PROD_OFS, sizeof(model[1]));
2381 ata_id_c_string(old_id, serial[0], ATA_ID_SERNO_OFS, sizeof(serial[0]));
2382 ata_id_c_string(new_id, serial[1], ATA_ID_SERNO_OFS, sizeof(serial[1]));
2383 new_n_sectors = ata_id_n_sectors(new_id);
2384
2385 if (strcmp(model[0], model[1])) {
2386 printk(KERN_INFO
2387 "ata%u: dev %u model number mismatch '%s' != '%s'\n",
2388 ap->id, dev->devno, model[0], model[1]);
2389 return 0;
2390 }
2391
2392 if (strcmp(serial[0], serial[1])) {
2393 printk(KERN_INFO
2394 "ata%u: dev %u serial number mismatch '%s' != '%s'\n",
2395 ap->id, dev->devno, serial[0], serial[1]);
2396 return 0;
2397 }
2398
2399 if (dev->class == ATA_DEV_ATA && dev->n_sectors != new_n_sectors) {
2400 printk(KERN_INFO
2401 "ata%u: dev %u n_sectors mismatch %llu != %llu\n",
2402 ap->id, dev->devno, (unsigned long long)dev->n_sectors,
2403 (unsigned long long)new_n_sectors);
2404 return 0;
2405 }
2406
2407 return 1;
2408}
2409
2410/**
2411 * ata_dev_revalidate - Revalidate ATA device
2412 * @ap: port on which the device to revalidate resides
2413 * @dev: device to revalidate
2414 * @post_reset: is this revalidation after reset?
2415 *
2416 * Re-read IDENTIFY page and make sure @dev is still attached to
2417 * the port.
2418 *
2419 * LOCKING:
2420 * Kernel thread context (may sleep)
2421 *
2422 * RETURNS:
2423 * 0 on success, negative errno otherwise
2424 */
2425int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev,
2426 int post_reset)
2427{
2428 unsigned int class;
2429 u16 *id;
2430 int rc;
2431
2432 if (!ata_dev_present(dev))
2433 return -ENODEV;
2434
2435 class = dev->class;
2436 id = NULL;
2437
2438 /* allocate & read ID data */
2439 rc = ata_dev_read_id(ap, dev, &class, post_reset, &id);
2440 if (rc)
2441 goto fail;
2442
2443 /* is the device still there? */
2444 if (!ata_dev_same_device(ap, dev, class, id)) {
2445 rc = -ENODEV;
2446 goto fail;
2447 }
2448
2449 kfree(dev->id);
2450 dev->id = id;
2451
2452 /* configure device according to the new ID */
2453 return ata_dev_configure(ap, dev, 0);
2454
2455 fail:
2456 printk(KERN_ERR "ata%u: dev %u revalidation failed (errno=%d)\n",
2457 ap->id, dev->devno, rc);
2458 kfree(id);
2459 return rc;
2460}
2461
2348static void ata_pr_blacklisted(const struct ata_port *ap, 2462static void ata_pr_blacklisted(const struct ata_port *ap,
2349 const struct ata_device *dev) 2463 const struct ata_device *dev)
2350{ 2464{
@@ -4964,6 +5078,7 @@ EXPORT_SYMBOL_GPL(sata_std_hardreset);
4964EXPORT_SYMBOL_GPL(ata_std_postreset); 5078EXPORT_SYMBOL_GPL(ata_std_postreset);
4965EXPORT_SYMBOL_GPL(ata_std_probe_reset); 5079EXPORT_SYMBOL_GPL(ata_std_probe_reset);
4966EXPORT_SYMBOL_GPL(ata_drive_probe_reset); 5080EXPORT_SYMBOL_GPL(ata_drive_probe_reset);
5081EXPORT_SYMBOL_GPL(ata_dev_revalidate);
4967EXPORT_SYMBOL_GPL(ata_port_disable); 5082EXPORT_SYMBOL_GPL(ata_port_disable);
4968EXPORT_SYMBOL_GPL(ata_ratelimit); 5083EXPORT_SYMBOL_GPL(ata_ratelimit);
4969EXPORT_SYMBOL_GPL(ata_busy_sleep); 5084EXPORT_SYMBOL_GPL(ata_busy_sleep);