Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

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

[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
Loading
Loading
Loading
Loading
+67 −59
Original line number Diff line number Diff line
@@ -33,9 +33,9 @@
#include <scsi/scsi_host.h>

struct ses_device {
	char *page1;
	char *page2;
	char *page10;
	unsigned char *page1;
	unsigned char *page2;
	unsigned char *page10;
	short page1_len;
	short page2_len;
	short page10_len;
@@ -67,7 +67,7 @@ static int ses_probe(struct device *dev)
static int ses_recv_diag(struct scsi_device *sdev, int page_code,
			 void *buf, int bufflen)
{
	char cmd[] = {
	unsigned char cmd[] = {
		RECEIVE_DIAGNOSTIC,
		1,		/* Set PCV bit */
		page_code,
@@ -85,7 +85,7 @@ static int ses_send_diag(struct scsi_device *sdev, int page_code,
{
	u32 result;

	char cmd[] = {
	unsigned char cmd[] = {
		SEND_DIAGNOSTIC,
		0x10,		/* Set PF bit */
		0,
@@ -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,
				      struct enclosure_component *ecomp,
				      char *desc)
				      unsigned char *desc)
{
	int i, j, count = 0, descriptor = ecomp->number;
	struct scsi_device *sdev = to_scsi_device(edev->cdev.dev);
	struct ses_device *ses_dev = edev->scratch;
	char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
	char *desc_ptr = ses_dev->page2 + 8;
	unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
	unsigned char *desc_ptr = ses_dev->page2 + 8;

	/* Clear everything */
	memset(desc_ptr, 0, ses_dev->page2_len - 8);
@@ -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);
}

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)
{
	int i, j, count = 0, descriptor = ecomp->number;
	struct scsi_device *sdev = to_scsi_device(edev->cdev.dev);
	struct ses_device *ses_dev = edev->scratch;
	char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
	char *desc_ptr = ses_dev->page2 + 8;
	unsigned char *type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
	unsigned char *desc_ptr = ses_dev->page2 + 8;

	ses_recv_diag(sdev, 2, ses_dev->page2, ses_dev->page2_len);

@@ -160,9 +160,10 @@ static char *ses_get_page2_descriptor(struct enclosure_device *edev,
static void ses_get_fault(struct enclosure_device *edev,
			  struct enclosure_component *ecomp)
{
	char *desc;
	unsigned char *desc;

	desc = ses_get_page2_descriptor(edev, ecomp);
	if (desc)
		ecomp->fault = (desc[3] & 0x60) >> 4;
}

@@ -170,7 +171,7 @@ static int ses_set_fault(struct enclosure_device *edev,
			  struct enclosure_component *ecomp,
			 enum enclosure_component_setting val)
{
	char desc[4] = {0 };
	unsigned char desc[4] = {0 };

	switch (val) {
	case ENCLOSURE_SETTING_DISABLED:
@@ -190,18 +191,20 @@ static int ses_set_fault(struct enclosure_device *edev,
static void ses_get_status(struct enclosure_device *edev,
			   struct enclosure_component *ecomp)
{
	char *desc;
	unsigned char *desc;

	desc = ses_get_page2_descriptor(edev, ecomp);
	if (desc)
		ecomp->status = (desc[0] & 0x0f);
}

static void ses_get_locate(struct enclosure_device *edev,
			   struct enclosure_component *ecomp)
{
	char *desc;
	unsigned char *desc;

	desc = ses_get_page2_descriptor(edev, ecomp);
	if (desc)
		ecomp->locate = (desc[2] & 0x02) ? 1 : 0;
}

@@ -209,7 +212,7 @@ static int ses_set_locate(struct enclosure_device *edev,
			  struct enclosure_component *ecomp,
			  enum enclosure_component_setting val)
{
	char desc[4] = {0 };
	unsigned char desc[4] = {0 };

	switch (val) {
	case ENCLOSURE_SETTING_DISABLED:
@@ -229,7 +232,7 @@ static int ses_set_active(struct enclosure_device *edev,
			  struct enclosure_component *ecomp,
			  enum enclosure_component_setting val)
{
	char desc[4] = {0 };
	unsigned char desc[4] = {0 };

	switch (val) {
	case ENCLOSURE_SETTING_DISABLED:
@@ -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 *tmp_sdev;
	unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr,
		*addl_desc_ptr;
	unsigned char *buf = NULL, *hdr_buf, *type_ptr, *desc_ptr = NULL,
		*addl_desc_ptr = NULL;
	struct ses_device *ses_dev;
	u32 result;
	int i, j, types, len, components = 0;
	int i, j, types, len, page7_len = 0, components = 0;
	int err = -ENOMEM;
	struct enclosure_device *edev;
	struct ses_component *scomp = NULL;
@@ -447,7 +450,7 @@ static int ses_intf_add(struct class_device *cdev,
		 * traversal routines more complex */
		sdev_printk(KERN_ERR, sdev,
			"FIXME driver has no support for subenclosures (%d)\n",
			buf[1]);
			hdr_buf[1]);
		goto err_free;
	}

@@ -461,9 +464,8 @@ static int ses_intf_add(struct class_device *cdev,
		goto recv_failed;

	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) {
		if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
@@ -494,8 +496,7 @@ static int ses_intf_add(struct class_device *cdev,
	/* The additional information page --- allows us
	 * to match up the devices */
	result = ses_recv_diag(sdev, 10, hdr_buf, INIT_ALLOC_SIZE);
	if (result)
		goto no_page10;
	if (!result) {

		len = (hdr_buf[2] << 8) + hdr_buf[3] + 4;
		buf = kzalloc(len, GFP_KERNEL);
@@ -508,8 +509,8 @@ static int ses_intf_add(struct class_device *cdev,
		ses_dev->page10 = buf;
		ses_dev->page10_len = len;
		buf = NULL;
	}

 no_page10:
	scomp = kzalloc(sizeof(struct ses_component) * components, GFP_KERNEL);
	if (!scomp)
		goto err_free;
@@ -530,7 +531,7 @@ static int ses_intf_add(struct class_device *cdev,
	if (result)
		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 */
	buf = kzalloc(len + 1, GFP_KERNEL);
	if (!buf)
@@ -547,6 +548,7 @@ static int ses_intf_add(struct class_device *cdev,
		len = (desc_ptr[2] << 8) + desc_ptr[3];
		/* skip past overall descriptor */
		desc_ptr += len + 4;
		if (ses_dev->page10)
			addl_desc_ptr = ses_dev->page10 + 8;
	}
	type_ptr = ses_dev->page1 + 12 + ses_dev->page1[11];
@@ -557,6 +559,9 @@ static int ses_intf_add(struct class_device *cdev,
			struct enclosure_component *ecomp;

			if (desc_ptr) {
				if (desc_ptr >= buf + page7_len) {
					desc_ptr = NULL;
				} else {
					len = (desc_ptr[2] << 8) + desc_ptr[3];
					desc_ptr += 4;
					/* Add trailing zero - pushes into
@@ -564,22 +569,25 @@ static int ses_intf_add(struct class_device *cdev,
					desc_ptr[len] = '\0';
					name = desc_ptr;
				}
			if (type_ptr[0] != ENCLOSURE_COMPONENT_DEVICE &&
			    type_ptr[0] != ENCLOSURE_COMPONENT_ARRAY_DEVICE)
				continue;
			}
			if (type_ptr[0] == ENCLOSURE_COMPONENT_DEVICE ||
			    type_ptr[0] == ENCLOSURE_COMPONENT_ARRAY_DEVICE) {

				ecomp =	enclosure_component_register(edev,
							     components++,
							     type_ptr[0],
							     name);
			if (desc_ptr) {
				desc_ptr += len;
				if (!IS_ERR(ecomp))

				if (!IS_ERR(ecomp) && addl_desc_ptr)
					ses_process_descriptor(ecomp,
							       addl_desc_ptr);
			}
			if (desc_ptr)
				desc_ptr += len;

			if (addl_desc_ptr)
				addl_desc_ptr += addl_desc_ptr[1] + 2;
			}

		}
	}
	kfree(buf);