aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTomas Henzl <thenzl@redhat.com>2014-07-30 09:12:22 -0400
committerChristoph Hellwig <hch@lst.de>2014-08-01 08:16:40 -0400
commit6f8f31c7a890283bea85c7aac45f089b5766472d (patch)
tree6b979d0b2ac3faa855d6ccab16df3f8982ca1614
parent5bd355ee3b0191c6846918b049b3940182bec1cb (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.c137
-rw-r--r--drivers/scsi/pm8001/pm8001_hwi.c4
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);
551out: 556out:
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}
629out: 633out:
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);
704out1:
705 kfree(cmd_ptr);
706out: 704out:
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
715static ssize_t pm8001_show_update_fw(struct device *cdev, 714static 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;