summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Pouly <amaury.pouly@gmail.com>2013-12-24 01:09:33 +0100
committerAmaury Pouly <amaury.pouly@gmail.com>2013-12-24 12:39:58 +0100
commit84f1a0af3b62c3c10d838fe387035a8145c35ca3 (patch)
tree82a6db61bfab6ff25f26666f1956ab9dcd584884
parente0636afed2cfc64df77225607b21a0e6be12c48e (diff)
downloadrockbox-84f1a0af3b62c3c10d838fe387035a8145c35ca3.tar.gz
rockbox-84f1a0af3b62c3c10d838fe387035a8145c35ca3.zip
imxtools/scsitools: tool can now write a firmware using SCSI
Change-Id: Iac803d4b2d48319a1a32d1101f5041d20174c7a1
-rw-r--r--utils/imxtools/scsitools/scsitool.c163
1 files changed, 162 insertions, 1 deletions
diff --git a/utils/imxtools/scsitools/scsitool.c b/utils/imxtools/scsitools/scsitool.c
index d8d47f8b48..2c82d5b841 100644
--- a/utils/imxtools/scsitools/scsitool.c
+++ b/utils/imxtools/scsitools/scsitool.c
@@ -400,6 +400,28 @@ static int stmp_read_logical_drive_sectors(uint8_t drive, uint64_t address,
400 return do_sense_analysis(ret, sense, sense_size); 400 return do_sense_analysis(ret, sense, sense_size);
401} 401}
402 402
403static int stmp_write_logical_drive_sectors(uint8_t drive, uint64_t address,
404 uint32_t count, void *buffer, int *buffer_size)
405{
406 uint8_t cdb[16];
407 memset(cdb, 0, sizeof(cdb));
408 cdb[0] = SCSI_STMP_WRITE;
409 cdb[1] = SCSI_STMP_CMD_WRITE_LOGICAL_DRIVE_SECTOR;
410 cdb[2] = drive;
411 address = fix_endian64be(address);
412 memcpy(&cdb[3], &address, sizeof(address));
413 count = fix_endian32be(count);
414 memcpy(&cdb[11], &count, sizeof(count));
415
416 uint8_t sense[32];
417 int sense_size = sizeof(sense);
418
419 int ret = do_scsi(cdb, sizeof(cdb), DO_WRITE, sense, &sense_size, buffer, buffer_size);
420 if(ret < 0)
421 return ret;
422 return do_sense_analysis(ret, sense, sense_size);
423}
424
403static const char *stmp_get_logical_media_type_string(uint32_t type) 425static const char *stmp_get_logical_media_type_string(uint32_t type)
404{ 426{
405 switch(type) 427 switch(type)
@@ -912,6 +934,7 @@ void do_extract(const char *file)
912 if(ret || len != (int)sector_size) 934 if(ret || len != (int)sector_size)
913 { 935 {
914 cprintf(GREY, "Cannot read first sector\n"); 936 cprintf(GREY, "Cannot read first sector\n");
937 return;
915 } 938 }
916 uint32_t fw_size = *(uint32_t *)(sector + 0x1c) * 16; 939 uint32_t fw_size = *(uint32_t *)(sector + 0x1c) * 16;
917 if(g_debug) 940 if(g_debug)
@@ -947,6 +970,130 @@ Lend:
947 fclose(f); 970 fclose(f);
948} 971}
949 972
973void do_write(const char *file, int want_a_brick)
974{
975 if(!want_a_brick)
976 {
977 cprintf(GREY, "Writing a new firmware is a dangerous operation that should be attempted\n");
978 cprintf(GREY, "if you know what you are doing. If you do, please add the --yes-i-want-a-brick\n");
979 cprintf(GREY, "option on the command line and do not complain if you end up with a brick ;)\n");
980 return;
981 }
982 FILE *f = NULL;
983 cprintf(BLUE, "Writing firmware...\n");
984
985 struct
986 {
987 struct scsi_stmp_logical_table_t header;
988 struct scsi_stmp_logical_table_entry_t entry[20];
989 }__attribute__((packed)) table;
990
991 int ret = stmp_get_logical_table(&table.header, sizeof(table.entry) / sizeof(table.entry[0]));
992 if(ret)
993 {
994 cprintf(GREY, "Cannot get logical table: %d\n", ret);
995 goto Lend;
996 }
997 int entry = 0;
998 while(entry < table.header.count)
999 if(table.entry[entry].type == SCSI_STMP_DRIVE_TYPE_SYSTEM &&
1000 table.entry[entry].tag == SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT)
1001 break;
1002 else
1003 entry++;
1004 if(entry == table.header.count)
1005 {
1006 cprintf(GREY, "Cannot find firmware partition\n");
1007 goto Lend;
1008 }
1009 uint8_t drive_no = table.entry[entry].drive_no;
1010 uint64_t drive_sz = table.entry[entry].size;
1011 if(g_debug)
1012 {
1013 cprintf(RED, "* ");
1014 cprintf_field("Drive: ", "%#x\n", drive_no);
1015 cprintf(RED, "* ");
1016 cprintf_field("Size: ", "%#llx\n", (unsigned long long)drive_sz);
1017 }
1018 int len = 4;
1019 uint32_t sector_size;
1020 ret = stmp_get_logical_drive_info(drive_no, SCSI_STMP_DRIVE_INFO_SECTOR_SIZE, &sector_size, &len);
1021 if(ret || len != 4)
1022 {
1023 cprintf(GREY, "Cannot get sector size\n");
1024 goto Lend;
1025 }
1026 sector_size = fix_endian32be(sector_size);
1027 if(g_debug)
1028 {
1029 cprintf(RED, "* ");
1030 cprintf_field("Sector size: ", "%lu\n", (unsigned long)sector_size);
1031 }
1032 uint8_t *sector = malloc(sector_size);
1033
1034 /* sanity check by reading first sector */
1035 len = sector_size;
1036 ret = stmp_read_logical_drive_sectors(drive_no, 0, 1, sector, &len);
1037 if(ret || len != (int)sector_size)
1038 {
1039 cprintf(GREY, "Cannot read first sector\n");
1040 return;
1041 }
1042 uint32_t sig = *(uint32_t *)(sector + 0x14);
1043 if(sig != 0x504d5453)
1044 {
1045 cprintf(GREY, "There is something wrong: the first sector doesn't have the STMP signature. Bailing out...\n");
1046 return;
1047 }
1048
1049 f = fopen(file, "rb");
1050 if(f == NULL)
1051 {
1052 cprintf(GREY, "Cannot open '%s' for writing: %m\n", file);
1053 goto Lend;
1054 }
1055 fseek(f, 0, SEEK_END);
1056 int fw_size = ftell(f);
1057 fseek(f, 0, SEEK_SET);
1058 if(g_debug)
1059 {
1060 cprintf(RED, "* ");
1061 cprintf_field("Firmware size: ", "%#x\n", fw_size);
1062 }
1063 /* sanity check size */
1064 if((uint64_t)fw_size > drive_sz)
1065 {
1066 cprintf(GREY, "You cannot write a firmware greater than the partition size.\n");
1067 goto Lend;
1068 }
1069
1070 for(int off = 0; off < fw_size; off += sector_size)
1071 {
1072 int sec = off / sector_size;
1073 int xfer_len = MIN(fw_size - off, (int)sector_size);
1074 if(fread(sector, xfer_len, 1, f) != 1)
1075 {
1076 cprintf(GREY, "Read failed: %m\n");
1077 goto Lend;
1078 }
1079 /* NOTE transfer a whole sector even if incomplete, the device won't access
1080 * partial sectors */
1081 if(xfer_len < (int)sector_size)
1082 memset(sector + xfer_len, 0, sector_size - xfer_len);
1083 len = sector_size;
1084 ret = stmp_write_logical_drive_sectors(drive_no, sec, 1, sector, &len);
1085 if(ret || len != (int)sector_size)
1086 {
1087 cprintf(GREY, "Cannot write sector %d\n", sec);
1088 goto Lend;
1089 }
1090 }
1091 cprintf(BLUE, "Done\n");
1092Lend:
1093 if(f)
1094 fclose(f);
1095}
1096
950static void usage(void) 1097static void usage(void)
951{ 1098{
952 printf("Usage: scsitool [options] <dev>\n"); 1099 printf("Usage: scsitool [options] <dev>\n");
@@ -956,15 +1103,20 @@ static void usage(void)
956 printf(" -d/--debug Display debug messages\n"); 1103 printf(" -d/--debug Display debug messages\n");
957 printf(" -c/--no-color Disable color output\n"); 1104 printf(" -c/--no-color Disable color output\n");
958 printf(" -x/--extract-fw <file> Extract firmware to file\n"); 1105 printf(" -x/--extract-fw <file> Extract firmware to file\n");
1106 printf(" -w/--write-fw <file> Write firmware to device\n");
959 printf(" -i/--info Display device information\n"); 1107 printf(" -i/--info Display device information\n");
1108 printf(" --yes-i-want-a-brick Allow the tool to turn your device into a brick\n");
960 exit(1); 1109 exit(1);
961} 1110}
962 1111
1112static int g_yes_i_want_a_brick = 0;
1113
963int main(int argc, char **argv) 1114int main(int argc, char **argv)
964{ 1115{
965 if(argc == 1) 1116 if(argc == 1)
966 usage(); 1117 usage();
967 const char *extract_fw = NULL; 1118 const char *extract_fw = NULL;
1119 const char *write_fw = NULL;
968 bool info = false; 1120 bool info = false;
969 while(1) 1121 while(1)
970 { 1122 {
@@ -975,15 +1127,19 @@ int main(int argc, char **argv)
975 {"no-color", no_argument, 0, 'c'}, 1127 {"no-color", no_argument, 0, 'c'},
976 {"force", no_argument, 0, 'f'}, 1128 {"force", no_argument, 0, 'f'},
977 {"extract-fw", required_argument, 0, 'x'}, 1129 {"extract-fw", required_argument, 0, 'x'},
1130 {"write-fw", required_argument, 0, 'w'},
978 {"info", no_argument, 0, 'i'}, 1131 {"info", no_argument, 0, 'i'},
1132 {"yes-i-want-a-brick", no_argument, &g_yes_i_want_a_brick, 1},
979 {0, 0, 0, 0} 1133 {0, 0, 0, 0}
980 }; 1134 };
981 1135
982 int c = getopt_long(argc, argv, "?dcfx:i", long_options, NULL); 1136 int c = getopt_long(argc, argv, "?dcfx:iw:", long_options, NULL);
983 if(c == -1) 1137 if(c == -1)
984 break; 1138 break;
985 switch(c) 1139 switch(c)
986 { 1140 {
1141 case 0:
1142 continue;
987 case -1: 1143 case -1:
988 break; 1144 break;
989 case 'c': 1145 case 'c':
@@ -1001,6 +1157,9 @@ int main(int argc, char **argv)
1001 case 'x': 1157 case 'x':
1002 extract_fw = optarg; 1158 extract_fw = optarg;
1003 break; 1159 break;
1160 case 'w':
1161 write_fw = optarg;
1162 break;
1004 case 'i': 1163 case 'i':
1005 info = true; 1164 info = true;
1006 break; 1165 break;
@@ -1028,6 +1187,8 @@ int main(int argc, char **argv)
1028 do_extract(extract_fw); 1187 do_extract(extract_fw);
1029 if(info) 1188 if(info)
1030 do_info(); 1189 do_info();
1190 if(write_fw)
1191 do_write(write_fw, g_yes_i_want_a_brick);
1031 1192
1032 scsi_pt_close_device(g_dev_fd); 1193 scsi_pt_close_device(g_dev_fd);
1033Lend: 1194Lend: