diff options
author | Tomas Henzl <thenzl@redhat.com> | 2014-07-30 09:12:22 -0400 |
---|---|---|
committer | Christoph Hellwig <hch@lst.de> | 2014-08-01 08:16:40 -0400 |
commit | 6f8f31c7a890283bea85c7aac45f089b5766472d (patch) | |
tree | 6b979d0b2ac3faa855d6ccab16df3f8982ca1614 | |
parent | 5bd355ee3b0191c6846918b049b3940182bec1cb (diff) |
pm8001: fix pm8001_store_update_fw
The current implementation may mix the negative value returned from
pm8001_set_nvmd with count. -(-ENOMEM) could be interpreted as bytes
programmed, this patch fixes it.
Signed-off-by: Tomas Henzl <thenzl@redhat.com>
Signed-off-by: Suresh Thiagarajan <Suresh.Thiagarajan@pmcs.com>
Signed-off-by: Christoph Hellwig <hch@lst.de>
-rw-r--r-- | drivers/scsi/pm8001/pm8001_ctl.c | 137 | ||||
-rw-r--r-- | drivers/scsi/pm8001/pm8001_hwi.c | 4 |
2 files changed, 70 insertions, 71 deletions
diff --git a/drivers/scsi/pm8001/pm8001_ctl.c b/drivers/scsi/pm8001/pm8001_ctl.c index e9b0921e9450..7abbf284da1a 100644 --- a/drivers/scsi/pm8001/pm8001_ctl.c +++ b/drivers/scsi/pm8001/pm8001_ctl.c | |||
@@ -526,18 +526,19 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha) | |||
526 | { | 526 | { |
527 | struct pm8001_ioctl_payload *payload; | 527 | struct pm8001_ioctl_payload *payload; |
528 | DECLARE_COMPLETION_ONSTACK(completion); | 528 | DECLARE_COMPLETION_ONSTACK(completion); |
529 | u8 *ioctlbuffer = NULL; | 529 | u8 *ioctlbuffer; |
530 | u32 length = 0; | 530 | u32 ret; |
531 | u32 ret = 0; | 531 | u32 length = 1024 * 5 + sizeof(*payload) - 1; |
532 | |||
533 | if (pm8001_ha->fw_image->size > 4096) { | ||
534 | pm8001_ha->fw_status = FAIL_FILE_SIZE; | ||
535 | return -EFAULT; | ||
536 | } | ||
532 | 537 | ||
533 | length = 1024 * 5 + sizeof(*payload) - 1; | ||
534 | ioctlbuffer = kzalloc(length, GFP_KERNEL); | 538 | ioctlbuffer = kzalloc(length, GFP_KERNEL); |
535 | if (!ioctlbuffer) | 539 | if (!ioctlbuffer) { |
540 | pm8001_ha->fw_status = FAIL_OUT_MEMORY; | ||
536 | return -ENOMEM; | 541 | return -ENOMEM; |
537 | if ((pm8001_ha->fw_image->size <= 0) || | ||
538 | (pm8001_ha->fw_image->size > 4096)) { | ||
539 | ret = FAIL_FILE_SIZE; | ||
540 | goto out; | ||
541 | } | 542 | } |
542 | payload = (struct pm8001_ioctl_payload *)ioctlbuffer; | 543 | payload = (struct pm8001_ioctl_payload *)ioctlbuffer; |
543 | memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data, | 544 | memcpy((u8 *)&payload->func_specific, (u8 *)pm8001_ha->fw_image->data, |
@@ -547,6 +548,10 @@ static int pm8001_set_nvmd(struct pm8001_hba_info *pm8001_ha) | |||
547 | payload->minor_function = 0x1; | 548 | payload->minor_function = 0x1; |
548 | pm8001_ha->nvmd_completion = &completion; | 549 | pm8001_ha->nvmd_completion = &completion; |
549 | ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload); | 550 | ret = PM8001_CHIP_DISP->set_nvmd_req(pm8001_ha, payload); |
551 | if (ret) { | ||
552 | pm8001_ha->fw_status = FAIL_OUT_MEMORY; | ||
553 | goto out; | ||
554 | } | ||
550 | wait_for_completion(&completion); | 555 | wait_for_completion(&completion); |
551 | out: | 556 | out: |
552 | kfree(ioctlbuffer); | 557 | kfree(ioctlbuffer); |
@@ -557,26 +562,25 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha) | |||
557 | { | 562 | { |
558 | struct pm8001_ioctl_payload *payload; | 563 | struct pm8001_ioctl_payload *payload; |
559 | DECLARE_COMPLETION_ONSTACK(completion); | 564 | DECLARE_COMPLETION_ONSTACK(completion); |
560 | u8 *ioctlbuffer = NULL; | 565 | u8 *ioctlbuffer; |
561 | u32 length = 0; | ||
562 | struct fw_control_info *fwControl; | 566 | struct fw_control_info *fwControl; |
563 | u32 loopNumber, loopcount = 0; | ||
564 | u32 sizeRead = 0; | ||
565 | u32 partitionSize, partitionSizeTmp; | 567 | u32 partitionSize, partitionSizeTmp; |
566 | u32 ret = 0; | 568 | u32 loopNumber, loopcount; |
567 | u32 partitionNumber = 0; | ||
568 | struct pm8001_fw_image_header *image_hdr; | 569 | struct pm8001_fw_image_header *image_hdr; |
570 | u32 sizeRead = 0; | ||
571 | u32 ret = 0; | ||
572 | u32 length = 1024 * 16 + sizeof(*payload) - 1; | ||
569 | 573 | ||
570 | length = 1024 * 16 + sizeof(*payload) - 1; | 574 | if (pm8001_ha->fw_image->size < 28) { |
575 | pm8001_ha->fw_status = FAIL_FILE_SIZE; | ||
576 | return -EFAULT; | ||
577 | } | ||
571 | ioctlbuffer = kzalloc(length, GFP_KERNEL); | 578 | ioctlbuffer = kzalloc(length, GFP_KERNEL); |
572 | image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data; | 579 | if (!ioctlbuffer) { |
573 | if (!ioctlbuffer) | 580 | pm8001_ha->fw_status = FAIL_OUT_MEMORY; |
574 | return -ENOMEM; | 581 | return -ENOMEM; |
575 | if (pm8001_ha->fw_image->size < 28) { | ||
576 | ret = FAIL_FILE_SIZE; | ||
577 | goto out; | ||
578 | } | 582 | } |
579 | 583 | image_hdr = (struct pm8001_fw_image_header *)pm8001_ha->fw_image->data; | |
580 | while (sizeRead < pm8001_ha->fw_image->size) { | 584 | while (sizeRead < pm8001_ha->fw_image->size) { |
581 | partitionSizeTmp = | 585 | partitionSizeTmp = |
582 | *(u32 *)((u8 *)&image_hdr->image_length + sizeRead); | 586 | *(u32 *)((u8 *)&image_hdr->image_length + sizeRead); |
@@ -614,18 +618,18 @@ static int pm8001_update_flash(struct pm8001_hba_info *pm8001_ha) | |||
614 | 618 | ||
615 | pm8001_ha->nvmd_completion = &completion; | 619 | pm8001_ha->nvmd_completion = &completion; |
616 | ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload); | 620 | ret = PM8001_CHIP_DISP->fw_flash_update_req(pm8001_ha, payload); |
617 | if (ret) | 621 | if (ret) { |
618 | break; | 622 | pm8001_ha->fw_status = FAIL_OUT_MEMORY; |
623 | goto out; | ||
624 | } | ||
619 | wait_for_completion(&completion); | 625 | wait_for_completion(&completion); |
620 | if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) { | 626 | if (fwControl->retcode > FLASH_UPDATE_IN_PROGRESS) { |
621 | ret = fwControl->retcode; | 627 | pm8001_ha->fw_status = fwControl->retcode; |
622 | break; | 628 | ret = -EFAULT; |
629 | goto out; | ||
630 | } | ||
623 | } | 631 | } |
624 | } | 632 | } |
625 | if (ret) | ||
626 | break; | ||
627 | partitionNumber++; | ||
628 | } | ||
629 | out: | 633 | out: |
630 | kfree(ioctlbuffer); | 634 | kfree(ioctlbuffer); |
631 | return ret; | 635 | return ret; |
@@ -640,22 +644,29 @@ static ssize_t pm8001_store_update_fw(struct device *cdev, | |||
640 | char *cmd_ptr, *filename_ptr; | 644 | char *cmd_ptr, *filename_ptr; |
641 | int res, i; | 645 | int res, i; |
642 | int flash_command = FLASH_CMD_NONE; | 646 | int flash_command = FLASH_CMD_NONE; |
643 | int err = 0; | 647 | int ret; |
648 | |||
644 | if (!capable(CAP_SYS_ADMIN)) | 649 | if (!capable(CAP_SYS_ADMIN)) |
645 | return -EACCES; | 650 | return -EACCES; |
646 | 651 | ||
647 | cmd_ptr = kzalloc(count*2, GFP_KERNEL); | 652 | /* this test protects us from running two flash processes at once, |
653 | * so we should start with this test */ | ||
654 | if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) | ||
655 | return -EINPROGRESS; | ||
656 | pm8001_ha->fw_status = FLASH_IN_PROGRESS; | ||
648 | 657 | ||
658 | cmd_ptr = kzalloc(count*2, GFP_KERNEL); | ||
649 | if (!cmd_ptr) { | 659 | if (!cmd_ptr) { |
650 | err = FAIL_OUT_MEMORY; | 660 | pm8001_ha->fw_status = FAIL_OUT_MEMORY; |
651 | goto out; | 661 | return -ENOMEM; |
652 | } | 662 | } |
653 | 663 | ||
654 | filename_ptr = cmd_ptr + count; | 664 | filename_ptr = cmd_ptr + count; |
655 | res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr); | 665 | res = sscanf(buf, "%s %s", cmd_ptr, filename_ptr); |
656 | if (res != 2) { | 666 | if (res != 2) { |
657 | err = FAIL_PARAMETERS; | 667 | pm8001_ha->fw_status = FAIL_PARAMETERS; |
658 | goto out1; | 668 | ret = -EINVAL; |
669 | goto out; | ||
659 | } | 670 | } |
660 | 671 | ||
661 | for (i = 0; flash_command_table[i].code != FLASH_CMD_NONE; i++) { | 672 | 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, | |||
666 | } | 677 | } |
667 | } | 678 | } |
668 | if (flash_command == FLASH_CMD_NONE) { | 679 | if (flash_command == FLASH_CMD_NONE) { |
669 | err = FAIL_PARAMETERS; | 680 | pm8001_ha->fw_status = FAIL_PARAMETERS; |
670 | goto out1; | 681 | ret = -EINVAL; |
682 | goto out; | ||
671 | } | 683 | } |
672 | 684 | ||
673 | if (pm8001_ha->fw_status == FLASH_IN_PROGRESS) { | 685 | ret = request_firmware(&pm8001_ha->fw_image, |
674 | err = FLASH_IN_PROGRESS; | ||
675 | goto out1; | ||
676 | } | ||
677 | err = request_firmware(&pm8001_ha->fw_image, | ||
678 | filename_ptr, | 686 | filename_ptr, |
679 | pm8001_ha->dev); | 687 | pm8001_ha->dev); |
680 | 688 | ||
681 | if (err) { | 689 | if (ret) { |
682 | PM8001_FAIL_DBG(pm8001_ha, | 690 | PM8001_FAIL_DBG(pm8001_ha, |
683 | pm8001_printk("Failed to load firmware image file %s," | 691 | pm8001_printk( |
684 | " error %d\n", filename_ptr, err)); | 692 | "Failed to load firmware image file %s, error %d\n", |
685 | err = FAIL_OPEN_BIOS_FILE; | 693 | filename_ptr, ret)); |
686 | goto out1; | 694 | pm8001_ha->fw_status = FAIL_OPEN_BIOS_FILE; |
695 | goto out; | ||
687 | } | 696 | } |
688 | 697 | ||
689 | switch (flash_command) { | 698 | if (FLASH_CMD_UPDATE == flash_command) |
690 | case FLASH_CMD_UPDATE: | 699 | ret = pm8001_update_flash(pm8001_ha); |
691 | pm8001_ha->fw_status = FLASH_IN_PROGRESS; | 700 | else |
692 | err = pm8001_update_flash(pm8001_ha); | 701 | ret = pm8001_set_nvmd(pm8001_ha); |
693 | break; | 702 | |
694 | case FLASH_CMD_SET_NVMD: | ||
695 | pm8001_ha->fw_status = FLASH_IN_PROGRESS; | ||
696 | err = pm8001_set_nvmd(pm8001_ha); | ||
697 | break; | ||
698 | default: | ||
699 | pm8001_ha->fw_status = FAIL_PARAMETERS; | ||
700 | err = FAIL_PARAMETERS; | ||
701 | break; | ||
702 | } | ||
703 | release_firmware(pm8001_ha->fw_image); | 703 | release_firmware(pm8001_ha->fw_image); |
704 | out1: | ||
705 | kfree(cmd_ptr); | ||
706 | out: | 704 | out: |
707 | pm8001_ha->fw_status = err; | 705 | kfree(cmd_ptr); |
708 | 706 | ||
709 | if (!err) | 707 | if (ret) |
710 | return count; | 708 | return ret; |
711 | else | 709 | |
712 | return -err; | 710 | pm8001_ha->fw_status = FLASH_OK; |
711 | return count; | ||
713 | } | 712 | } |
714 | 713 | ||
715 | static ssize_t pm8001_show_update_fw(struct device *cdev, | 714 | static ssize_t pm8001_show_update_fw(struct device *cdev, |
diff --git a/drivers/scsi/pm8001/pm8001_hwi.c b/drivers/scsi/pm8001/pm8001_hwi.c index 173831016f5f..dd12c6fe57a6 100644 --- a/drivers/scsi/pm8001/pm8001_hwi.c +++ b/drivers/scsi/pm8001/pm8001_hwi.c | |||
@@ -4824,7 +4824,7 @@ int pm8001_chip_set_nvmd_req(struct pm8001_hba_info *pm8001_ha, | |||
4824 | rc = pm8001_tag_alloc(pm8001_ha, &tag); | 4824 | rc = pm8001_tag_alloc(pm8001_ha, &tag); |
4825 | if (rc) { | 4825 | if (rc) { |
4826 | kfree(fw_control_context); | 4826 | kfree(fw_control_context); |
4827 | return rc; | 4827 | return -EBUSY; |
4828 | } | 4828 | } |
4829 | ccb = &pm8001_ha->ccb_info[tag]; | 4829 | ccb = &pm8001_ha->ccb_info[tag]; |
4830 | ccb->fw_control_context = fw_control_context; | 4830 | ccb->fw_control_context = fw_control_context; |
@@ -4946,7 +4946,7 @@ pm8001_chip_fw_flash_update_req(struct pm8001_hba_info *pm8001_ha, | |||
4946 | rc = pm8001_tag_alloc(pm8001_ha, &tag); | 4946 | rc = pm8001_tag_alloc(pm8001_ha, &tag); |
4947 | if (rc) { | 4947 | if (rc) { |
4948 | kfree(fw_control_context); | 4948 | kfree(fw_control_context); |
4949 | return rc; | 4949 | return -EBUSY; |
4950 | } | 4950 | } |
4951 | ccb = &pm8001_ha->ccb_info[tag]; | 4951 | ccb = &pm8001_ha->ccb_info[tag]; |
4952 | ccb->fw_control_context = fw_control_context; | 4952 | ccb->fw_control_context = fw_control_context; |