diff options
author | Tejun Heo <htejun@gmail.com> | 2006-03-05 03:55:58 -0500 |
---|---|---|
committer | Jeff Garzik <jeff@garzik.org> | 2006-03-05 11:09:42 -0500 |
commit | 623a3128aa2b86caa8e06e762e9e444177e4fa47 (patch) | |
tree | 3e861e10c2963a22d2f097e5545fdcd865667602 /drivers/scsi/libata-core.c | |
parent | 4c2d721ab6413ee4ff33617ed1413458261f36ea (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.c | 115 |
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 | */ | ||
2365 | static 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 | */ | ||
2425 | int 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 | |||
2348 | static void ata_pr_blacklisted(const struct ata_port *ap, | 2462 | static 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); | |||
4964 | EXPORT_SYMBOL_GPL(ata_std_postreset); | 5078 | EXPORT_SYMBOL_GPL(ata_std_postreset); |
4965 | EXPORT_SYMBOL_GPL(ata_std_probe_reset); | 5079 | EXPORT_SYMBOL_GPL(ata_std_probe_reset); |
4966 | EXPORT_SYMBOL_GPL(ata_drive_probe_reset); | 5080 | EXPORT_SYMBOL_GPL(ata_drive_probe_reset); |
5081 | EXPORT_SYMBOL_GPL(ata_dev_revalidate); | ||
4967 | EXPORT_SYMBOL_GPL(ata_port_disable); | 5082 | EXPORT_SYMBOL_GPL(ata_port_disable); |
4968 | EXPORT_SYMBOL_GPL(ata_ratelimit); | 5083 | EXPORT_SYMBOL_GPL(ata_ratelimit); |
4969 | EXPORT_SYMBOL_GPL(ata_busy_sleep); | 5084 | EXPORT_SYMBOL_GPL(ata_busy_sleep); |