diff options
Diffstat (limited to 'utils/imxtools/scsitools/stmp_scsi.c')
-rw-r--r-- | utils/imxtools/scsitools/stmp_scsi.c | 175 |
1 files changed, 174 insertions, 1 deletions
diff --git a/utils/imxtools/scsitools/stmp_scsi.c b/utils/imxtools/scsitools/stmp_scsi.c index dcda91e295..e1d0dc4c77 100644 --- a/utils/imxtools/scsitools/stmp_scsi.c +++ b/utils/imxtools/scsitools/stmp_scsi.c | |||
@@ -23,7 +23,6 @@ | |||
23 | #include <stdarg.h> | 23 | #include <stdarg.h> |
24 | #include <stdio.h> | 24 | #include <stdio.h> |
25 | #define _BSD_SOURCE | 25 | #define _BSD_SOURCE |
26 | #include <endian.h> | ||
27 | #include "stmp_scsi.h" | 26 | #include "stmp_scsi.h" |
28 | 27 | ||
29 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) | 28 | #define MIN(a, b) ((a) < (b) ? (a) : (b)) |
@@ -131,6 +130,7 @@ int stmp_sense_analysis(stmp_device_t dev, int status, uint8_t *sense, int sense | |||
131 | for(int i = 0; i < sense_size; i++) | 130 | for(int i = 0; i < sense_size; i++) |
132 | stmp_printf(dev, " %02x", sense[i]); | 131 | stmp_printf(dev, " %02x", sense[i]); |
133 | stmp_printf(dev, "\n"); | 132 | stmp_printf(dev, "\n"); |
133 | rb_scsi_decode_sense(dev->dev, sense, sense_size); | ||
134 | } | 134 | } |
135 | return status; | 135 | return status; |
136 | } | 136 | } |
@@ -614,3 +614,176 @@ int stmp_get_logical_drive_info(stmp_device_t dev, uint8_t drive, struct stmp_lo | |||
614 | } | 614 | } |
615 | return 0; | 615 | return 0; |
616 | } | 616 | } |
617 | |||
618 | int stmp_read_firmware(stmp_device_t dev, void *user, stmp_fw_rw_fn_t fn) | ||
619 | { | ||
620 | /* read logicial table */ | ||
621 | uint8_t *sector = NULL; | ||
622 | struct stmp_logical_media_table_t *table = NULL; | ||
623 | int ret = stmp_get_logical_media_table(dev, &table); | ||
624 | if(ret) | ||
625 | { | ||
626 | stmp_printf(dev, "Cannot get logical table: %d\n", ret); | ||
627 | return -1; | ||
628 | } | ||
629 | /* locate firmware partition */ | ||
630 | int entry = 0; | ||
631 | while(entry < table->header.count) | ||
632 | if(table->entry[entry].type == SCSI_STMP_DRIVE_TYPE_SYSTEM && | ||
633 | table->entry[entry].tag == SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT) | ||
634 | break; | ||
635 | else | ||
636 | entry++; | ||
637 | if(entry == table->header.count) | ||
638 | { | ||
639 | stmp_printf(dev, "Cannot find firmware partition\n"); | ||
640 | goto Lerr; | ||
641 | } | ||
642 | uint8_t drive_no = table->entry[entry].drive_no; | ||
643 | uint64_t drive_sz = table->entry[entry].size; | ||
644 | stmp_debugf(dev, "Firmware drive: %#x\n", drive_no); | ||
645 | stmp_debugf(dev, "Firmware max size: %#llx\n", (unsigned long long)drive_sz); | ||
646 | /* get drive info */ | ||
647 | struct stmp_logical_drive_info_t info; | ||
648 | ret = stmp_get_logical_drive_info(dev, drive_no, &info); | ||
649 | if(ret || !info.has.sector_size) | ||
650 | { | ||
651 | stmp_printf(dev, "Cannot get sector size\n"); | ||
652 | goto Lerr; | ||
653 | } | ||
654 | unsigned sector_size = info.sector_size; | ||
655 | stmp_debugf(dev, "Firmware sector size: %lu\n", (unsigned long)sector_size); | ||
656 | /* allocate a buffer for one sector */ | ||
657 | sector = malloc(sector_size); | ||
658 | /* read the first sector to check it is correct and get the total size */ | ||
659 | ret = stmp_read_logical_drive_sectors(dev, drive_no, 0, 1, sector, sector_size); | ||
660 | if(ret) | ||
661 | { | ||
662 | stmp_printf(dev, "Cannot read first sector: %d\n", ret); | ||
663 | goto Lerr; | ||
664 | } | ||
665 | uint32_t sig = *(uint32_t *)(sector + 0x14); | ||
666 | if(sig != 0x504d5453) | ||
667 | { | ||
668 | stmp_printf(dev, "There is something wrong: the first sector doesn't have the STMP signature.\n"); | ||
669 | goto Lerr; | ||
670 | } | ||
671 | uint32_t fw_size = *(uint32_t *)(sector + 0x1c) * 16; /* see SB file format */ | ||
672 | stmp_debugf(dev, "Firmware size: %#x\n", fw_size); | ||
673 | /* if fn is NULL, just return the size immediately */ | ||
674 | if(fn != NULL) | ||
675 | { | ||
676 | /* read all sectors one by one */ | ||
677 | for(int sec = 0; sec * sector_size < fw_size; sec++) | ||
678 | { | ||
679 | ret = stmp_read_logical_drive_sectors(dev, drive_no, sec, 1, sector, sector_size); | ||
680 | if(ret) | ||
681 | { | ||
682 | stmp_printf(dev, "Cannot read sector %d: %d\n", sec, ret); | ||
683 | goto Lerr; | ||
684 | } | ||
685 | int xfer_len = MIN(sector_size, fw_size - sec * sector_size); | ||
686 | ret = fn(user, sector, xfer_len); | ||
687 | if(ret != xfer_len) | ||
688 | { | ||
689 | stmp_printf(dev, "User write failed: %d\n", ret); | ||
690 | goto Lerr; | ||
691 | } | ||
692 | } | ||
693 | } | ||
694 | ret = fw_size; | ||
695 | Lend: | ||
696 | free(table); | ||
697 | if(sector) | ||
698 | free(sector); | ||
699 | return ret; | ||
700 | Lerr: | ||
701 | ret = -1; | ||
702 | goto Lend; | ||
703 | } | ||
704 | |||
705 | int stmp_write_firmware(stmp_device_t dev, void *user, stmp_fw_rw_fn_t fn) | ||
706 | { | ||
707 | /* read logicial table */ | ||
708 | struct stmp_logical_media_table_t *table = NULL; | ||
709 | int ret = stmp_get_logical_media_table(dev, &table); | ||
710 | if(ret) | ||
711 | { | ||
712 | stmp_printf(dev, "Cannot get logical table: %d\n", ret); | ||
713 | return -1; | ||
714 | } | ||
715 | /* locate firmware partition */ | ||
716 | int entry = 0; | ||
717 | while(entry < table->header.count) | ||
718 | if(table->entry[entry].type == SCSI_STMP_DRIVE_TYPE_SYSTEM && | ||
719 | table->entry[entry].tag == SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT) | ||
720 | break; | ||
721 | else | ||
722 | entry++; | ||
723 | if(entry == table->header.count) | ||
724 | { | ||
725 | stmp_printf(dev, "Cannot find firmware partition\n"); | ||
726 | goto Lerr; | ||
727 | } | ||
728 | uint8_t drive_no = table->entry[entry].drive_no; | ||
729 | uint64_t drive_sz = table->entry[entry].size; | ||
730 | stmp_debugf(dev, "Firmware drive: %#x\n", drive_no); | ||
731 | stmp_debugf(dev, "Firmware max size: %#llx\n", (unsigned long long)drive_sz); | ||
732 | /* get drive info */ | ||
733 | struct stmp_logical_drive_info_t info; | ||
734 | ret = stmp_get_logical_drive_info(dev, drive_no, &info); | ||
735 | if(ret || !info.has.sector_size) | ||
736 | { | ||
737 | stmp_printf(dev, "Cannot get sector size\n"); | ||
738 | goto Lerr; | ||
739 | } | ||
740 | unsigned sector_size = info.sector_size; | ||
741 | stmp_debugf(dev, "Firmware sector size: %lu\n", (unsigned long)sector_size); | ||
742 | /* allocate a buffer for one sector */ | ||
743 | uint8_t *sector = malloc(sector_size); | ||
744 | /* read the first sector to check it is correct and get the total size */ | ||
745 | ret = fn(user, sector, sector_size); | ||
746 | /* the whole file could be smaller than one sector, but it must be greater | ||
747 | * then the header size */ | ||
748 | if(ret < 0x20) | ||
749 | { | ||
750 | stmp_printf(dev, "User read failed: %d\n", ret); | ||
751 | goto Lerr; | ||
752 | } | ||
753 | uint32_t sig = *(uint32_t *)(sector + 0x14); | ||
754 | if(sig != 0x504d5453) | ||
755 | { | ||
756 | stmp_printf(dev, "There is something wrong: the first sector doesn't have the STMP signature.\n"); | ||
757 | goto Lerr; | ||
758 | } | ||
759 | uint32_t fw_size = *(uint32_t *)(sector + 0x1c) * 16; /* see SB file format */ | ||
760 | stmp_debugf(dev, "Firmware size: %#x\n", fw_size); | ||
761 | /* write all sectors one by one */ | ||
762 | for(int sec = 0; sec * sector_size < fw_size; sec++) | ||
763 | { | ||
764 | int xfer_len = MIN(sector_size, fw_size - sec * sector_size); | ||
765 | /* avoid rereading the first sector */ | ||
766 | if(sec != 0) | ||
767 | ret = fn(user, sector, xfer_len); | ||
768 | if(ret != xfer_len) | ||
769 | { | ||
770 | stmp_printf(dev, "User read failed: %d\n", ret); | ||
771 | goto Lerr; | ||
772 | } | ||
773 | if(ret < (int)sector_size) | ||
774 | memset(sector + ret, 0, sector_size - ret); | ||
775 | ret = stmp_write_logical_drive_sectors(dev, drive_no, sec, 1, sector, sector_size); | ||
776 | if(ret) | ||
777 | { | ||
778 | stmp_printf(dev, "Cannot write sector %d: %d\n", sec, ret); | ||
779 | goto Lerr; | ||
780 | } | ||
781 | } | ||
782 | ret = fw_size; | ||
783 | Lend: | ||
784 | free(table); | ||
785 | return ret; | ||
786 | Lerr: | ||
787 | ret = -1; | ||
788 | goto Lend; | ||
789 | } | ||