Commit 691b4773 authored by Yinghai Lu's avatar Yinghai Lu Committed by James Bottomley

[SCSI] ses: fix data corruption

one system: initrd get courrupted:

RAMDISK: Compressed image found at block 0
RAMDISK: incomplete write (-28 != 2048) 134217728
crc error
VFS: Mounted root (ext2 filesystem).
Freeing unused kernel memory: 388k freed
init_special_inode: bogus i_mode (177777)
Warning: unable to open an initial console.
init_special_inode: bogus i_mode (177777)
init_special_inode: bogus i_mode (177777)
Kernel panic - not syncing: No init found.  Try passing init= option to kernel.

bisected to
commit 9927c688
Author: James Bottomley <James.Bottomley@HansenPartnership.com>
Date:   Sun Feb 3 15:48:56 2008 -0600

    [SCSI] ses: add new Enclosure ULD

changes:
1. change char to unsigned char to avoid type change later.
2. preserve len for page1
3. need to move desc_ptr even the entry is not enclosure_component_device/raid.
   so keep desc_ptr on right position
4. record page7 len, and double check if desc_ptr out of boundary before touch.
5. fix typo in subenclosure checking: should use hdr_buf instead.

[jejb: style fixes]
Signed-off-by: default avatarYinghai Lu <yinghai.lu@sun.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@HansenPartnership.com>
parent 1309d4e6
...@@ -33,9 +33,9 @@ ...@@ -33,9 +33,9 @@
#include <scsi/scsi_host.h> #include <scsi/scsi_host.h>
struct ses_device { struct ses_device {
char *page1; unsigned char *page1;
char *page2; unsigned char *page2;
char *page10; unsigned char *page10;
short page1_len; short page1_len;
short page2_len; short page2_len;
short page10_len; short page10_len;
...@@ -67,7 +67,7 @@ static int ses_probe(struct device *dev) ...@@ -67,7 +67,7 @@ static int ses_probe(struct device *dev)
static int ses_recv_diag(struct scsi_device *sdev, int page_code, static int ses_recv_diag(struct scsi_device *sdev, int page_code,
void *buf, int bufflen) void *buf, int bufflen)
{ {
char cmd[] = { unsigned char cmd[] = {
RECEIVE_DIAGNOSTIC, RECEIVE_DIAGNOSTIC,
1, /* Set PCV bit */ 1, /* Set PCV bit */
page_code, page_code,
...@@ -85,7 +85,7 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code, ...@@ -85,7 +85,7 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code,
{ {
u32 result; u32 result;
char cmd[] = { unsigned char cmd[] = {
SEND_DIAGNOSTIC, SEND_DIAGNOSTIC,
0x10, /* Set PF bit */ 0x10, /* Set PF bit */
0, 0,
...@@ -104,13 +104,13 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code, ...@@ -104,13 +104,13 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code,
static int ses_set_page2_descriptor(struct enclosure_device *edev, static int ses_set_page2_descriptor(struct enclosure_device *edev,
struct enclosure_component *ecomp, struct enclosure_component *ecomp,
char *desc) unsigned char *desc)
{ {
int i, j, count = 0, descriptor = ecomp->number; int i, j, count = 0, descriptor = ecomp->number;
struct scsi_device *sdev = to_scsi_device(edev->cdev.dev); struct scsi_device *sdev = to_scsi_device(edev->cdev.dev);
struct ses_device *ses_dev = edev->scratch; struct ses_device *ses_dev = edev->scratch;
char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
char *desc_ptr = ses_dev->page2 + 8; unsigned char *desc_ptr = ses_dev->page2 + 8;
/* Clear everything */ /* Clear everything */
memset(desc_ptr, 0, ses_dev->page2_len - 8); memset(desc_ptr, 0, ses_dev->page2_len - 8);
...@@ -133,14 +133,14 @@ static int ses_set_page2_descriptor(struct enclosure_device *edev, ...@@ -133,14 +133,14 @@ static int ses_set_page2_descriptor(struct enclosure_device *edev,
return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); return ses_send_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len);
} }
static char *ses_get_page2_descriptor(struct enclosure_device *edev, static unsigned char *ses_get_page2_descriptor(struct enclosure_device *edev,
struct enclosure_component *ecomp) struct enclosure_component *ecomp)
{ {
int i, j, count = 0, descriptor = ecomp->number; int i, j, count = 0, descriptor = ecomp->number;
struct scsi_device *sdev = to_scsi_device(edev->cdev.dev); struct scsi_device *sdev = to_scsi_device(edev->cdev.dev);
struct ses_device *ses_dev = edev->scratch; struct ses_device *ses_dev = edev->scratch;
char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
char *desc_ptr = ses_dev->page2 + 8; unsigned char *desc_ptr = ses_dev->page2 + 8;
ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len); ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len);
...@@ -160,17 +160,18 @@ static char *ses_get_page2_descriptor(struct enclosure_device *edev, ...@@ -160,17 +160,18 @@ static char *ses_get_page2_descriptor(struct enclosure_device *edev,
static void ses_get_fault(struct enclosure_device *edev, static void ses_get_fault(struct enclosure_device *edev,
struct enclosure_component *ecomp) struct enclosure_component *ecomp)
{ {
char *desc; unsigned char *desc;
desc = ses_get_page2_descriptor(edev, ecomp); desc = ses_get_page2_descriptor(edev, ecomp);
ecomp->fault = (desc[3] & 0x60) >> 4; if (desc)
ecomp->fault = (desc[3] & 0x60) >> 4;
} }
static int ses_set_fault(struct enclosure_device *edev, static int ses_set_fault(struct enclosure_device *edev,
struct enclosure_component *ecomp, struct enclosure_component *ecomp,
enum enclosure_component_setting val) enum enclosure_component_setting val)
{ {
char desc[4] = {0 }; unsigned char desc[4] = {0 };
switch (val) { switch (val) {
case ENCLOSURE_SETTING_DISABLED: case ENCLOSURE_SETTING_DISABLED:
...@@ -190,26 +191,28 @@ static int ses_set_fault(struct enclosure_device *edev, ...@@ -190,26 +191,28 @@ static int ses_set_fault(struct enclosure_device *edev,
static void ses_get_status(struct enclosure_device *edev, static void ses_get_status(struct enclosure_device *edev,
struct enclosure_component *ecomp) struct enclosure_component *ecomp)
{ {
char *desc; unsigned char *desc;
desc = ses_get_page2_descriptor(edev, ecomp); desc = ses_get_page2_descriptor(edev, ecomp);
ecomp->status = (desc[0] & 0x0f); if (desc)
ecomp->status = (desc[0] & 0x0f);
} }
static void ses_get_locate(struct enclosure_device *edev, static void ses_get_locate(struct enclosure_device *edev,
struct enclosure_component *ecomp) struct enclosure_component *ecomp)
{ {
char *desc; unsigned char *desc;
desc = ses_get_page2_descriptor(edev, ecomp); desc = ses_get_page2_descriptor(edev, ecomp);
ecomp->locate = (desc[2] & 0x02) ? 1 : 0; if (desc)
ecomp->locate = (desc[2] & 0x02) ? 1 : 0;
} }
static int ses_set_locate(struct enclosure_device *edev, static int ses_set_locate(struct enclosure_device *edev,
struct enclosure_component *ecomp, struct enclosure_component *ecomp,
enum enclosure_component_setting val) enum enclosure_component_setting val)
{ {
char desc[4] = {0 }; unsigned char desc[4] = {0 };
switch (val) { switch (val) {
case ENCLOSURE_SETTING_DISABLED: case ENCLOSURE_SETTING_DISABLED:
...@@ -229,7 +232,7 @@ static int ses_set_active(struct enclosure_device *edev, ...@@ -229,7 +232,7 @@ static int ses_set_active(struct enclosure_device *edev,
struct enclosure_component *ecomp, struct enclosure_component *ecomp,
enum enclosure_component_setting val) enum enclosure_component_setting val)
{ {
char desc[4] = {0 }; unsigned char desc[4] = {0 };
switch (val) { switch (val) {
case ENCLOSURE_SETTING_DISABLED: case ENCLOSURE_SETTING_DISABLED:
...@@ -409,11 +412,11 @@ static int ses_intf_add(struct class_device *cdev, ...@@ -409,11 +412,11 @@ static int ses_intf_add(struct class_device *cdev,
{ {
struct scsi_device *sdev = to_scsi_device(cdev->dev); struct scsi_device *sdev = to_scsi_device(cdev->dev);
struct scsi_device *tmp_sdev; struct scsi_device *tmp_sdev;
unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr, unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr = NULL,
*addl_desc_ptr; *addl_desc_ptr = NULL;
struct ses_device *ses_dev; struct ses_device *ses_dev;
u32 result; u32 result;
int i, j, types, len, components = 0; int i, j, types, len, page7_len = 0, components = 0;
int err = -ENOMEM; int err = -ENOMEM;
struct enclosure_device *edev; struct enclosure_device *edev;
struct ses_component *scomp = NULL; struct ses_component *scomp = NULL;
...@@ -447,7 +450,7 @@ static int ses_intf_add(struct class_device *cdev, ...@@ -447,7 +450,7 @@ static int ses_intf_add(struct class_device *cdev,
* traversal routines more complex */ * traversal routines more complex */
sdev_printk(KERN_ERR, sdev, sdev_printk(KERN_ERR, sdev,
"FIXME driver has no support for subenclosures (%d)\n", "FIXME driver has no support for subenclosures (%d)\n",
buf[1]); hdr_buf[1]);
goto err_free; goto err_free;
} }
...@@ -461,9 +464,8 @@ static int ses_intf_add(struct class_device *cdev, ...@@ -461,9 +464,8 @@ static int ses_intf_add(struct class_device *cdev,
goto recv_failed; goto recv_failed;
types = buf[10]; types = buf[10];
len = buf[11];
type_ptr = buf + 12 + len; type_ptr = buf + 12 + buf[11];
for (i = 0; i < types; i++, type_ptr += 4) { for (i = 0; i < types; i++, type_ptr += 4) {
if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE || if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
...@@ -494,22 +496,21 @@ static int ses_intf_add(struct class_device *cdev, ...@@ -494,22 +496,21 @@ static int ses_intf_add(struct class_device *cdev,
/* The additional information page --- allows us /* The additional information page --- allows us
* to match up the devices */ * to match up the devices */
result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE); result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE);
if (result) if (!result) {
goto no_page10;
len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; buf = kzalloc(len, GFP_KERNEL);
buf = kzalloc(len, GFP_KERNEL); if (!buf)
if (!buf) goto err_free;
goto err_free;
result = ses_recv_diag(sdev, 10, buf, len);
result = ses_recv_diag(sdev, 10, buf, len); if (result)
if (result) goto recv_failed;
goto recv_failed; ses_dev->page10 = buf;
ses_dev->page10 = buf; ses_dev->page10_len = len;
ses_dev->page10_len = len; buf = NULL;
buf = NULL; }
no_page10:
scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL); scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL);
if (!scomp) if (!scomp)
goto err_free; goto err_free;
...@@ -530,7 +531,7 @@ static int ses_intf_add(struct class_device *cdev, ...@@ -530,7 +531,7 @@ static int ses_intf_add(struct class_device *cdev,
if (result) if (result)
goto simple_populate; goto simple_populate;
len = (hdr_buf[2] << 8) + hdr_buf[3] + 4; page7_len = len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
/* add 1 for trailing '\0' we'll use */ /* add 1 for trailing '\0' we'll use */
buf = kzalloc(len + 1, GFP_KERNEL); buf = kzalloc(len + 1, GFP_KERNEL);
if (!buf) if (!buf)
...@@ -547,7 +548,8 @@ static int ses_intf_add(struct class_device *cdev, ...@@ -547,7 +548,8 @@ static int ses_intf_add(struct class_device *cdev,
len = (desc_ptr[2] << 8) + desc_ptr[3]; len = (desc_ptr[2] << 8) + desc_ptr[3];
/* skip past overall descriptor */ /* skip past overall descriptor */
desc_ptr += len + 4; desc_ptr += len + 4;
addl_desc_ptr = ses_dev->page10 + 8; if (ses_dev->page10)
addl_desc_ptr = ses_dev->page10 + 8;
} }
type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11]; type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
components = 0; components = 0;
...@@ -557,29 +559,35 @@ static int ses_intf_add(struct class_device *cdev, ...@@ -557,29 +559,35 @@ static int ses_intf_add(struct class_device *cdev,
struct enclosure_component *ecomp; struct enclosure_component *ecomp;
if (desc_ptr) { if (desc_ptr) {
len = (desc_ptr[2] << 8) + desc_ptr[3]; if (desc_ptr >= buf + page7_len) {
desc_ptr += 4; desc_ptr = NULL;
/* Add trailing zero - pushes into } else {
* reserved space */ len = (desc_ptr[2] << 8) + desc_ptr[3];
desc_ptr[len] = '\0'; desc_ptr += 4;
name = desc_ptr; /* Add trailing zero - pushes into
* reserved space */
desc_ptr[len] = '\0';
name = desc_ptr;
}
} }
if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE && if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE) type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) {
continue;
ecomp = enclosure_component_register(edev, ecomp = enclosure_component_register(edev,
components++, components++,
type_ptr[0], type_ptr[0],
name); name);
if (desc_ptr) {
desc_ptr += len; if (!IS_ERR(ecomp) && addl_desc_ptr)
if (!IS_ERR(ecomp))
ses_process_descriptor(ecomp, ses_process_descriptor(ecomp,
addl_desc_ptr); addl_desc_ptr);
if (addl_desc_ptr)
addl_desc_ptr += addl_desc_ptr[1] + 2;
} }
if (desc_ptr)
desc_ptr += len;
if (addl_desc_ptr)
addl_desc_ptr += addl_desc_ptr[1] + 2;
} }
} }
kfree(buf); kfree(buf);
......
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