diff options
author | Mike Miller (OS Dev) <mikem@beardog.cca.cpqcorp.net> | 2007-03-06 04:42:14 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-03-06 12:30:25 -0500 |
commit | 97c06978515ed6e071bfd4a5e858837dd2b0edcf (patch) | |
tree | 026ffd8a6ba185128d0e30842dd5a66468a3f82f /drivers | |
parent | d6ad67112a78623025632865d716b2f7645874c5 (diff) |
[PATCH] cciss: fix for 2TB support
This patch changes the way we determine if a logical volume is larger than
2TB.
The original test looked for a total_size of 0. Originally we added 1 to the
total_size. That would make our read_capacity return size 0 for >2TB lv's.
We assumed that we could not have a lv size of 0 so it seemed OK until we were
in a clustered system. The backup node would see a size of 0 due to the
reservation on the drive. That caused the driver to switch to 16-byte CDB's
which are not supported on older controllers. After that everything was
broken.
It may seem petty but I don't see the value in trying to determine if the LBA
is beyond the 2TB boundary. That's why when we switch we use 16-byte CDB's
for all read/write operations. Please consider this for inclusion.
Signed-off-by: Mike Miller <mike.miller@hp.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/block/cciss.c | 39 |
1 files changed, 24 insertions, 15 deletions
diff --git a/drivers/block/cciss.c b/drivers/block/cciss.c index 05dfe357527c..8791e43cad5d 100644 --- a/drivers/block/cciss.c +++ b/drivers/block/cciss.c | |||
@@ -1291,13 +1291,19 @@ static void cciss_update_drive_info(int ctlr, int drv_index) | |||
1291 | if (inq_buff == NULL) | 1291 | if (inq_buff == NULL) |
1292 | goto mem_msg; | 1292 | goto mem_msg; |
1293 | 1293 | ||
1294 | /* testing to see if 16-byte CDBs are already being used */ | ||
1295 | if (h->cciss_read == CCISS_READ_16) { | ||
1296 | cciss_read_capacity_16(h->ctlr, drv_index, 1, | ||
1297 | &total_size, &block_size); | ||
1298 | goto geo_inq; | ||
1299 | } | ||
1300 | |||
1294 | cciss_read_capacity(ctlr, drv_index, 1, | 1301 | cciss_read_capacity(ctlr, drv_index, 1, |
1295 | &total_size, &block_size); | 1302 | &total_size, &block_size); |
1296 | 1303 | ||
1297 | /* total size = last LBA + 1 */ | 1304 | /* if read_capacity returns all F's this volume is >2TB in size */ |
1298 | /* FFFFFFFF + 1 = 0, cannot have a logical volume of size 0 */ | 1305 | /* so we switch to 16-byte CDB's for all read/write ops */ |
1299 | /* so we assume this volume this must be >2TB in size */ | 1306 | if (total_size == 0xFFFFFFFFULL) { |
1300 | if (total_size == (__u32) 0) { | ||
1301 | cciss_read_capacity_16(ctlr, drv_index, 1, | 1307 | cciss_read_capacity_16(ctlr, drv_index, 1, |
1302 | &total_size, &block_size); | 1308 | &total_size, &block_size); |
1303 | h->cciss_read = CCISS_READ_16; | 1309 | h->cciss_read = CCISS_READ_16; |
@@ -1306,6 +1312,7 @@ static void cciss_update_drive_info(int ctlr, int drv_index) | |||
1306 | h->cciss_read = CCISS_READ_10; | 1312 | h->cciss_read = CCISS_READ_10; |
1307 | h->cciss_write = CCISS_WRITE_10; | 1313 | h->cciss_write = CCISS_WRITE_10; |
1308 | } | 1314 | } |
1315 | geo_inq: | ||
1309 | cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, | 1316 | cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, |
1310 | inq_buff, &h->drv[drv_index]); | 1317 | inq_buff, &h->drv[drv_index]); |
1311 | 1318 | ||
@@ -1917,13 +1924,14 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, | |||
1917 | drv->raid_level = inq_buff->data_byte[8]; | 1924 | drv->raid_level = inq_buff->data_byte[8]; |
1918 | } | 1925 | } |
1919 | drv->block_size = block_size; | 1926 | drv->block_size = block_size; |
1920 | drv->nr_blocks = total_size; | 1927 | drv->nr_blocks = total_size + 1; |
1921 | t = drv->heads * drv->sectors; | 1928 | t = drv->heads * drv->sectors; |
1922 | if (t > 1) { | 1929 | if (t > 1) { |
1923 | unsigned rem = sector_div(total_size, t); | 1930 | sector_t real_size = total_size + 1; |
1931 | unsigned long rem = sector_div(real_size, t); | ||
1924 | if (rem) | 1932 | if (rem) |
1925 | total_size++; | 1933 | real_size++; |
1926 | drv->cylinders = total_size; | 1934 | drv->cylinders = real_size; |
1927 | } | 1935 | } |
1928 | } else { /* Get geometry failed */ | 1936 | } else { /* Get geometry failed */ |
1929 | printk(KERN_WARNING "cciss: reading geometry failed\n"); | 1937 | printk(KERN_WARNING "cciss: reading geometry failed\n"); |
@@ -1953,16 +1961,16 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size, | |||
1953 | ctlr, buf, sizeof(ReadCapdata_struct), | 1961 | ctlr, buf, sizeof(ReadCapdata_struct), |
1954 | 1, logvol, 0, NULL, TYPE_CMD); | 1962 | 1, logvol, 0, NULL, TYPE_CMD); |
1955 | if (return_code == IO_OK) { | 1963 | if (return_code == IO_OK) { |
1956 | *total_size = be32_to_cpu(*(__u32 *) buf->total_size)+1; | 1964 | *total_size = be32_to_cpu(*(__u32 *) buf->total_size); |
1957 | *block_size = be32_to_cpu(*(__u32 *) buf->block_size); | 1965 | *block_size = be32_to_cpu(*(__u32 *) buf->block_size); |
1958 | } else { /* read capacity command failed */ | 1966 | } else { /* read capacity command failed */ |
1959 | printk(KERN_WARNING "cciss: read capacity failed\n"); | 1967 | printk(KERN_WARNING "cciss: read capacity failed\n"); |
1960 | *total_size = 0; | 1968 | *total_size = 0; |
1961 | *block_size = BLOCK_SIZE; | 1969 | *block_size = BLOCK_SIZE; |
1962 | } | 1970 | } |
1963 | if (*total_size != (__u32) 0) | 1971 | if (*total_size != 0) |
1964 | printk(KERN_INFO " blocks= %llu block_size= %d\n", | 1972 | printk(KERN_INFO " blocks= %llu block_size= %d\n", |
1965 | (unsigned long long)*total_size, *block_size); | 1973 | (unsigned long long)*total_size+1, *block_size); |
1966 | kfree(buf); | 1974 | kfree(buf); |
1967 | return; | 1975 | return; |
1968 | } | 1976 | } |
@@ -1989,7 +1997,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, | |||
1989 | 1, logvol, 0, NULL, TYPE_CMD); | 1997 | 1, logvol, 0, NULL, TYPE_CMD); |
1990 | } | 1998 | } |
1991 | if (return_code == IO_OK) { | 1999 | if (return_code == IO_OK) { |
1992 | *total_size = be64_to_cpu(*(__u64 *) buf->total_size)+1; | 2000 | *total_size = be64_to_cpu(*(__u64 *) buf->total_size); |
1993 | *block_size = be32_to_cpu(*(__u32 *) buf->block_size); | 2001 | *block_size = be32_to_cpu(*(__u32 *) buf->block_size); |
1994 | } else { /* read capacity command failed */ | 2002 | } else { /* read capacity command failed */ |
1995 | printk(KERN_WARNING "cciss: read capacity failed\n"); | 2003 | printk(KERN_WARNING "cciss: read capacity failed\n"); |
@@ -1997,7 +2005,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, | |||
1997 | *block_size = BLOCK_SIZE; | 2005 | *block_size = BLOCK_SIZE; |
1998 | } | 2006 | } |
1999 | printk(KERN_INFO " blocks= %llu block_size= %d\n", | 2007 | printk(KERN_INFO " blocks= %llu block_size= %d\n", |
2000 | (unsigned long long)*total_size, *block_size); | 2008 | (unsigned long long)*total_size+1, *block_size); |
2001 | kfree(buf); | 2009 | kfree(buf); |
2002 | return; | 2010 | return; |
2003 | } | 2011 | } |
@@ -3119,8 +3127,9 @@ static void cciss_getgeometry(int cntl_num) | |||
3119 | } | 3127 | } |
3120 | cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size); | 3128 | cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size); |
3121 | 3129 | ||
3122 | /* total_size = last LBA + 1 */ | 3130 | /* If read_capacity returns all F's the logical is >2TB */ |
3123 | if(total_size == (__u32) 0) { | 3131 | /* so we switch to 16-byte CDBs for all read/write ops */ |
3132 | if(total_size == 0xFFFFFFFFULL) { | ||
3124 | cciss_read_capacity_16(cntl_num, i, 0, | 3133 | cciss_read_capacity_16(cntl_num, i, 0, |
3125 | &total_size, &block_size); | 3134 | &total_size, &block_size); |
3126 | hba[cntl_num]->cciss_read = CCISS_READ_16; | 3135 | hba[cntl_num]->cciss_read = CCISS_READ_16; |