diff options
Diffstat (limited to 'drivers/scsi/pm8001/pm8001_ctl.c')
| -rw-r--r-- | drivers/scsi/pm8001/pm8001_ctl.c | 151 | 
1 files changed, 75 insertions, 76 deletions
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index a368d77b8d41..7abbf284da1a 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c @@ -397,7 +397,10 @@ static ssize_t pm8001_ctl_bios_version_show(struct device *cdev,  	payload.func_specific = kzalloc(4096, GFP_KERNEL);  	if (!payload.func_specific)  		return -ENOMEM; -	PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload); +	if (PM8001_CHIP_DISP->get_nvmd_req(pm8001_ha, &payload)) { +		kfree(payload.func_specific); +		return -ENOMEM; +	}  	wait_for_completion(&completion);  	virt_addr = pm8001_ha->memoryMap.region[NVMD].virt_ptr;  	for (bios_index = BIOSOFFSET; bios_index < BIOS_OFFSET_LIMIT; @@ -523,18 +526,19 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)  {  	struct pm8001_ioctl_payload	*payload;  	DECLARE_COMPLETION_ONSTACK(completion); -	u8		*ioctlbuffer = NULL; -	u32		length = 0; -	u32		ret = 0; +	u8		*ioctlbuffer; +	u32		ret; +	u32		length = 1024 * 5 + sizeof(*payload) - 1; + +	if (pm8001_ha->fw_image->size > 4096) { +		pm8001_ha->fw_status = FAIL_FILE_SIZE; +		return -EFAULT; +	} -	length = 1024 * 5 + sizeof(*payload) - 1;  	ioctlbuffer = kzalloc(length, GFP_KERNEL); -	if (!ioctlbuffer) +	if (!ioctlbuffer) { +		pm8001_ha->fw_status = FAIL_OUT_MEMORY;  		return -ENOMEM; -	if ((pm8001_ha->fw_image->size <= 0) || -	    (pm8001_ha->fw_image->size > 4096)) { -		ret = FAIL_FILE_SIZE; -		goto out;  	}  	payload = (struct pm8001_ioctl_payload *)ioctlbuffer;  	memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data, @@ -544,6 +548,10 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha)  	payload->minor_function = 0x1;  	pm8001_ha->nvmd_completion = &completion;  	ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload); +	if (ret) { +		pm8001_ha->fw_status = FAIL_OUT_MEMORY; +		goto out; +	}  	wait_for_completion(&completion);  out:  	kfree(ioctlbuffer); @@ -554,35 +562,31 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)  {  	struct pm8001_ioctl_payload	*payload;  	DECLARE_COMPLETION_ONSTACK(completion); -	u8		*ioctlbuffer = NULL; -	u32		length = 0; +	u8		*ioctlbuffer;  	struct fw_control_info	*fwControl; -	u32		loopNumber, loopcount = 0; -	u32		sizeRead = 0;  	u32		partitionSize, partitionSizeTmp; -	u32		ret = 0; -	u32		partitionNumber = 0; +	u32		loopNumber, loopcount;  	struct pm8001_fw_image_header *image_hdr; +	u32		sizeRead = 0; +	u32		ret = 0; +	u32		length = 1024 * 16 + sizeof(*payload) - 1; -	length = 1024 * 16 + sizeof(*payload) - 1; +	if (pm8001_ha->fw_image->size < 28) { +		pm8001_ha->fw_status = FAIL_FILE_SIZE; +		return -EFAULT; +	}  	ioctlbuffer = kzalloc(length, GFP_KERNEL); -	image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data; -	if (!ioctlbuffer) +	if (!ioctlbuffer) { +		pm8001_ha->fw_status = FAIL_OUT_MEMORY;  		return -ENOMEM; -	if (pm8001_ha->fw_image->size < 28) { -		ret = FAIL_FILE_SIZE; -		goto out;  	} - +	image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data;  	while (sizeRead < pm8001_ha->fw_image->size) {  		partitionSizeTmp =  			*(u32 *)((u8 *)&image_hdr->image_length + sizeRead);  		partitionSize = be32_to_cpu(partitionSizeTmp); -		loopcount = (partitionSize + HEADER_LEN)/IOCTL_BUF_SIZE; -		if (loopcount % IOCTL_BUF_SIZE) -			loopcount++; -		if (loopcount == 0) -			loopcount++; +		loopcount = DIV_ROUND_UP(partitionSize + HEADER_LEN, +					IOCTL_BUF_SIZE);  		for (loopNumber = 0; loopNumber < loopcount; loopNumber++) {  			payload = (struct pm8001_ioctl_payload *)ioctlbuffer;  			payload->length = 1024*16; @@ -614,18 +618,18 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha)  		pm8001_ha->nvmd_completion = &completion;  		ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload); +		if (ret) { +			pm8001_ha->fw_status = FAIL_OUT_MEMORY; +			goto out; +		}  		wait_for_completion(&completion); -		if (ret || (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS)) { -			ret = fwControl->retcode; -			kfree(ioctlbuffer); -			ioctlbuffer = NULL; -			break; +		if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) { +			pm8001_ha->fw_status = fwControl->retcode; +			ret = -EFAULT; +			goto out; +		}  		}  	} -	if (ret) -		break; -	partitionNumber++; -}  out:  	kfree(ioctlbuffer);  	return ret; @@ -640,22 +644,29 @@ static ssize_t pm8001_store_update_fw(struct device *cdev,  	char *cmd_ptr, *filename_ptr;  	int res, i;  	int flash_command = FLASH_CMD_NONE; -	int err = 0; +	int ret; +  	if (!capable(CAP_SYS_ADMIN))  		return -EACCES; -	cmd_ptr = kzalloc(count*2, GFP_KERNEL); +	/* this test protects us from running two flash processes at once, +	 * so we should start with this test */ +	if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) +		return -EINPROGRESS; +	pm8001_ha->fw_status = FLASH_IN_PROGRESS; +	cmd_ptr = kzalloc(count*2, GFP_KERNEL);  	if (!cmd_ptr) { -		err = FAIL_OUT_MEMORY; -		goto out; +		pm8001_ha->fw_status = FAIL_OUT_MEMORY; +		return -ENOMEM;  	}  	filename_ptr = cmd_ptr + count;  	res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr);  	if (res != 2) { -		err = FAIL_PARAMETERS; -		goto out1; +		pm8001_ha->fw_status = FAIL_PARAMETERS; +		ret = -EINVAL; +		goto out;  	}  	for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) { @@ -666,50 +677,38 @@ static ssize_t pm8001_store_update_fw(struct device *cdev,  		}  	}  	if (flash_command == FLASH_CMD_NONE) { -		err = FAIL_PARAMETERS; -		goto out1; +		pm8001_ha->fw_status = FAIL_PARAMETERS; +		ret = -EINVAL; +		goto out;  	} -	if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) { -		err = FLASH_IN_PROGRESS; -		goto out1; -	} -	err = request_firmware(&pm8001_ha->fw_image, +	ret = request_firmware(&pm8001_ha->fw_image,  			       filename_ptr,  			       pm8001_ha->dev); -	if (err) { +	if (ret) {  		PM8001_FAIL_DBG(pm8001_ha, -			pm8001_printk("Failed to load firmware image file %s," -			" error %d\n", filename_ptr, err)); -		err = FAIL_OPEN_BIOS_FILE; -		goto out1; +			pm8001_printk( +			"Failed to load firmware image file %s,	error %d\n", +			filename_ptr, ret)); +		pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE; +		goto out;  	} -	switch (flash_command) { -	case FLASH_CMD_UPDATE: -		pm8001_ha->fw_status = FLASH_IN_PROGRESS; -		err = pm8001_update_flash(pm8001_ha); -		break; -	case FLASH_CMD_SET_NVMD: -		pm8001_ha->fw_status = FLASH_IN_PROGRESS; -		err = pm8001_set_nvmd(pm8001_ha); -		break; -	default: -		pm8001_ha->fw_status = FAIL_PARAMETERS; -		err = FAIL_PARAMETERS; -		break; -	} +	if (FLASH_CMD_UPDATE == flash_command) +		ret = pm8001_update_flash(pm8001_ha); +	else +		ret = pm8001_set_nvmd(pm8001_ha); +  	release_firmware(pm8001_ha->fw_image); -out1: -	kfree(cmd_ptr);  out: -	pm8001_ha->fw_status = err; +	kfree(cmd_ptr); -	if (!err) -		return count; -	else -		return -err; +	if (ret) +		return ret; + +	pm8001_ha->fw_status = FLASH_OK; +	return count;  }  static ssize_t pm8001_show_update_fw(struct device *cdev,  |