diff options
| -rw-r--r-- | drivers/scsi/libata-core.c | 115 | ||||
| -rw-r--r-- | include/linux/libata.h | 2 |
2 files changed, 117 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); |
diff --git a/include/linux/libata.h b/include/linux/libata.h index 86a504f0ef06..66dce58f1941 100644 --- a/include/linux/libata.h +++ b/include/linux/libata.h | |||
| @@ -485,6 +485,8 @@ extern int ata_std_softreset(struct ata_port *ap, int verbose, | |||
| 485 | extern int sata_std_hardreset(struct ata_port *ap, int verbose, | 485 | extern int sata_std_hardreset(struct ata_port *ap, int verbose, |
| 486 | unsigned int *class); | 486 | unsigned int *class); |
| 487 | extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); | 487 | extern void ata_std_postreset(struct ata_port *ap, unsigned int *classes); |
| 488 | extern int ata_dev_revalidate(struct ata_port *ap, struct ata_device *dev, | ||
| 489 | int post_reset); | ||
| 488 | extern void ata_port_disable(struct ata_port *); | 490 | extern void ata_port_disable(struct ata_port *); |
| 489 | extern void ata_std_ports(struct ata_ioports *ioaddr); | 491 | extern void ata_std_ports(struct ata_ioports *ioaddr); |
| 490 | #ifdef CONFIG_PCI | 492 | #ifdef CONFIG_PCI |
