Commit 97c06978 authored by Mike Miller (OS Dev)'s avatar Mike Miller (OS Dev) Committed by Linus Torvalds

[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: default avatarMike Miller <mike.miller@hp.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent d6ad6711
...@@ -1291,13 +1291,19 @@ static void cciss_update_drive_info(int ctlr, int drv_index) ...@@ -1291,13 +1291,19 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
if (inq_buff == NULL) if (inq_buff == NULL)
goto mem_msg; goto mem_msg;
/* testing to see if 16-byte CDBs are already being used */
if (h->cciss_read == CCISS_READ_16) {
cciss_read_capacity_16(h->ctlr, drv_index, 1,
&total_size, &block_size);
goto geo_inq;
}
cciss_read_capacity(ctlr, drv_index, 1, cciss_read_capacity(ctlr, drv_index, 1,
&total_size, &block_size); &total_size, &block_size);
/* total size = last LBA + 1 */ /* if read_capacity returns all F's this volume is >2TB in size */
/* FFFFFFFF + 1 = 0, cannot have a logical volume of size 0 */ /* so we switch to 16-byte CDB's for all read/write ops */
/* so we assume this volume this must be >2TB in size */ if (total_size == 0xFFFFFFFFULL) {
if (total_size == (__u32) 0) {
cciss_read_capacity_16(ctlr, drv_index, 1, cciss_read_capacity_16(ctlr, drv_index, 1,
&total_size, &block_size); &total_size, &block_size);
h->cciss_read = CCISS_READ_16; h->cciss_read = CCISS_READ_16;
...@@ -1306,6 +1312,7 @@ static void cciss_update_drive_info(int ctlr, int drv_index) ...@@ -1306,6 +1312,7 @@ static void cciss_update_drive_info(int ctlr, int drv_index)
h->cciss_read = CCISS_READ_10; h->cciss_read = CCISS_READ_10;
h->cciss_write = CCISS_WRITE_10; h->cciss_write = CCISS_WRITE_10;
} }
geo_inq:
cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size, cciss_geometry_inquiry(ctlr, drv_index, 1, total_size, block_size,
inq_buff, &h->drv[drv_index]); inq_buff, &h->drv[drv_index]);
...@@ -1917,13 +1924,14 @@ static void cciss_geometry_inquiry(int ctlr, int logvol, ...@@ -1917,13 +1924,14 @@ static void cciss_geometry_inquiry(int ctlr, int logvol,
drv->raid_level = inq_buff->data_byte[8]; drv->raid_level = inq_buff->data_byte[8];
} }
drv->block_size = block_size; drv->block_size = block_size;
drv->nr_blocks = total_size; drv->nr_blocks = total_size + 1;
t = drv->heads * drv->sectors; t = drv->heads * drv->sectors;
if (t > 1) { if (t > 1) {
unsigned rem = sector_div(total_size, t); sector_t real_size = total_size + 1;
unsigned long rem = sector_div(real_size, t);
if (rem) if (rem)
total_size++; real_size++;
drv->cylinders = total_size; drv->cylinders = real_size;
} }
} else { /* Get geometry failed */ } else { /* Get geometry failed */
printk(KERN_WARNING "cciss: reading geometry failed\n"); 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,16 +1961,16 @@ cciss_read_capacity(int ctlr, int logvol, int withirq, sector_t *total_size,
ctlr, buf, sizeof(ReadCapdata_struct), ctlr, buf, sizeof(ReadCapdata_struct),
1, logvol, 0, NULL, TYPE_CMD); 1, logvol, 0, NULL, TYPE_CMD);
if (return_code == IO_OK) { if (return_code == IO_OK) {
*total_size = be32_to_cpu(*(__u32 *) buf->total_size)+1; *total_size = be32_to_cpu(*(__u32 *) buf->total_size);
*block_size = be32_to_cpu(*(__u32 *) buf->block_size); *block_size = be32_to_cpu(*(__u32 *) buf->block_size);
} else { /* read capacity command failed */ } else { /* read capacity command failed */
printk(KERN_WARNING "cciss: read capacity failed\n"); printk(KERN_WARNING "cciss: read capacity failed\n");
*total_size = 0; *total_size = 0;
*block_size = BLOCK_SIZE; *block_size = BLOCK_SIZE;
} }
if (*total_size != (__u32) 0) if (*total_size != 0)
printk(KERN_INFO " blocks= %llu block_size= %d\n", printk(KERN_INFO " blocks= %llu block_size= %d\n",
(unsigned long long)*total_size, *block_size); (unsigned long long)*total_size+1, *block_size);
kfree(buf); kfree(buf);
return; return;
} }
...@@ -1989,7 +1997,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size, ...@@ -1989,7 +1997,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
1, logvol, 0, NULL, TYPE_CMD); 1, logvol, 0, NULL, TYPE_CMD);
} }
if (return_code == IO_OK) { if (return_code == IO_OK) {
*total_size = be64_to_cpu(*(__u64 *) buf->total_size)+1; *total_size = be64_to_cpu(*(__u64 *) buf->total_size);
*block_size = be32_to_cpu(*(__u32 *) buf->block_size); *block_size = be32_to_cpu(*(__u32 *) buf->block_size);
} else { /* read capacity command failed */ } else { /* read capacity command failed */
printk(KERN_WARNING "cciss: read capacity failed\n"); 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,7 +2005,7 @@ cciss_read_capacity_16(int ctlr, int logvol, int withirq, sector_t *total_size,
*block_size = BLOCK_SIZE; *block_size = BLOCK_SIZE;
} }
printk(KERN_INFO " blocks= %llu block_size= %d\n", printk(KERN_INFO " blocks= %llu block_size= %d\n",
(unsigned long long)*total_size, *block_size); (unsigned long long)*total_size+1, *block_size);
kfree(buf); kfree(buf);
return; return;
} }
...@@ -3119,8 +3127,9 @@ static void cciss_getgeometry(int cntl_num) ...@@ -3119,8 +3127,9 @@ static void cciss_getgeometry(int cntl_num)
} }
cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size); cciss_read_capacity(cntl_num, i, 0, &total_size, &block_size);
/* total_size = last LBA + 1 */ /* If read_capacity returns all F's the logical is >2TB */
if(total_size == (__u32) 0) { /* so we switch to 16-byte CDBs for all read/write ops */
if(total_size == 0xFFFFFFFFULL) {
cciss_read_capacity_16(cntl_num, i, 0, cciss_read_capacity_16(cntl_num, i, 0,
&total_size, &block_size); &total_size, &block_size);
hba[cntl_num]->cciss_read = CCISS_READ_16; hba[cntl_num]->cciss_read = CCISS_READ_16;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment