summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorMark Lord <liml@rtr.ca>2009-03-19 20:32:21 +0300
committerJeff Garzik <jgarzik@redhat.com>2009-03-25 05:40:05 +0300
commite18086d69cb5bb864749a0637f6ac573aa89d5ea (patch)
tree2d3e541787eb30743693dd45c96ebabb9be0f0a6 /drivers
parent000b344f4ca7828ee43940255c8bbb32e2c7dbec (diff)
downloadlinux-e18086d69cb5bb864749a0637f6ac573aa89d5ea.tar.xz
[libata] More robust parsing for IDENTIFY DEVICE multi_count field
Make libata more robust when parsing the multi_count field from a drive's identify data. This prevents us from attempting to use dubious multi_count values ad infinitum. Reset dev->multi_count to zero and reprobe it each time through this routine, as it can change on device reset. Also ensure that the reported "maximum" value is valid and is a power of two, and that the reported "count" value is valid and also a power of two. And that the "count" value is not greater than the "maximum" value. Signed-off-by: Mark Lord <mlord@pobox.com> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/ata/libata-core.c13
1 files changed, 11 insertions, 2 deletions
diff --git a/drivers/ata/libata-core.c b/drivers/ata/libata-core.c
index d4a7b8a96ecd..e7ea77cf6069 100644
--- a/drivers/ata/libata-core.c
+++ b/drivers/ata/libata-core.c
@@ -57,6 +57,7 @@
#include <linux/scatterlist.h>
#include <linux/io.h>
#include <linux/async.h>
+#include <linux/log2.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_host.h>
@@ -2389,6 +2390,7 @@ int ata_dev_configure(struct ata_device *dev)
dev->cylinders = 0;
dev->heads = 0;
dev->sectors = 0;
+ dev->multi_count = 0;
/*
* common ATA, ATAPI feature tests
@@ -2426,8 +2428,15 @@ int ata_dev_configure(struct ata_device *dev)
dev->n_sectors = ata_id_n_sectors(id);
- if (dev->id[59] & 0x100)
- dev->multi_count = dev->id[59] & 0xff;
+ /* get current R/W Multiple count setting */
+ if ((dev->id[47] >> 8) == 0x80 && (dev->id[59] & 0x100)) {
+ unsigned int max = dev->id[47] & 0xff;
+ unsigned int cnt = dev->id[59] & 0xff;
+ /* only recognize/allow powers of two here */
+ if (is_power_of_2(max) && is_power_of_2(cnt))
+ if (cnt <= max)
+ dev->multi_count = cnt;
+ }
if (ata_id_has_lba(id)) {
const char *lba_desc;