summaryrefslogtreecommitdiff
path: root/utils/imxtools/scsitools/stmp_scsi.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/imxtools/scsitools/stmp_scsi.c')
-rw-r--r--utils/imxtools/scsitools/stmp_scsi.c175
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
618int 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;
695Lend:
696 free(table);
697 if(sector)
698 free(sector);
699 return ret;
700Lerr:
701 ret = -1;
702 goto Lend;
703}
704
705int 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;
783Lend:
784 free(table);
785 return ret;
786Lerr:
787 ret = -1;
788 goto Lend;
789}