diff options
Diffstat (limited to 'utils/imxtools/scsitools/scsitool.c')
-rw-r--r-- | utils/imxtools/scsitools/scsitool.c | 264 |
1 files changed, 77 insertions, 187 deletions
diff --git a/utils/imxtools/scsitools/scsitool.c b/utils/imxtools/scsitools/scsitool.c index a84b5919d7..8367af6939 100644 --- a/utils/imxtools/scsitools/scsitool.c +++ b/utils/imxtools/scsitools/scsitool.c | |||
@@ -31,6 +31,8 @@ | |||
31 | #include <sys/stat.h> | 31 | #include <sys/stat.h> |
32 | #include <fcntl.h> | 32 | #include <fcntl.h> |
33 | #include <unistd.h> | 33 | #include <unistd.h> |
34 | #include <inttypes.h> | ||
35 | #include <errno.h> | ||
34 | #include "rbscsi.h" | 36 | #include "rbscsi.h" |
35 | #include "misc.h" | 37 | #include "misc.h" |
36 | #include "stmp_scsi.h" | 38 | #include "stmp_scsi.h" |
@@ -147,7 +149,7 @@ static int do_info(void) | |||
147 | cprintf_field(" Number of drives:", " %u\n", info.nr_drives); | 149 | cprintf_field(" Number of drives:", " %u\n", info.nr_drives); |
148 | if(info.has.size) | 150 | if(info.has.size) |
149 | { | 151 | { |
150 | cprintf_field(" Media size:", " %llu ", (unsigned long long)info.size); | 152 | cprintf_field(" Media size:", " %" PRIu64 " ", info.size); |
151 | cprintf(RED, "(%.3f %s)\n", get_size_natural(info.size), get_size_suffix(info.size)); | 153 | cprintf(RED, "(%.3f %s)\n", get_size_natural(info.size), get_size_suffix(info.size)); |
152 | } | 154 | } |
153 | if(info.has.alloc_size) | 155 | if(info.has.alloc_size) |
@@ -226,17 +228,17 @@ static int do_info(void) | |||
226 | continue; | 228 | continue; |
227 | if(info.has.sector_size) | 229 | if(info.has.sector_size) |
228 | { | 230 | { |
229 | cprintf_field(" Sector size:", " %llu ", (unsigned long long)info.sector_size); | 231 | cprintf_field(" Sector size:", " %" PRIu32 " ", info.sector_size); |
230 | cprintf(RED, "(%.3f %s)\n", get_size_natural(info.sector_size), get_size_suffix(info.sector_size)); | 232 | cprintf(RED, "(%.3f %s)\n", get_size_natural(info.sector_size), get_size_suffix(info.sector_size)); |
231 | } | 233 | } |
232 | if(info.has.erase_size) | 234 | if(info.has.erase_size) |
233 | { | 235 | { |
234 | cprintf_field(" Erase size:", " %llu ", (unsigned long long)info.erase_size); | 236 | cprintf_field(" Erase size:", " %" PRIu32 " ", info.erase_size); |
235 | cprintf(RED, "(%.3f %s)\n", get_size_natural(info.erase_size), get_size_suffix(info.erase_size)); | 237 | cprintf(RED, "(%.3f %s)\n", get_size_natural(info.erase_size), get_size_suffix(info.erase_size)); |
236 | } | 238 | } |
237 | if(info.has.size) | 239 | if(info.has.size) |
238 | { | 240 | { |
239 | cprintf_field(" Drive size:", " %llu ", (unsigned long long)info.size); | 241 | cprintf_field(" Drive size:", " %" PRIu64 " ", info.size); |
240 | cprintf(RED, "(%.3f %s)\n", get_size_natural(info.size), get_size_suffix(info.size)); | 242 | cprintf(RED, "(%.3f %s)\n", get_size_natural(info.size), get_size_suffix(info.size)); |
241 | } | 243 | } |
242 | if(info.has.sector_count) | 244 | if(info.has.sector_count) |
@@ -282,92 +284,70 @@ static int do_info(void) | |||
282 | return 0; | 284 | return 0; |
283 | } | 285 | } |
284 | 286 | ||
285 | void do_extract(const char *file) | 287 | struct rw_fw_context_t |
286 | { | 288 | { |
287 | FILE *f = NULL; | 289 | int tot_size; |
288 | cprintf(BLUE, "Extracting firmware...\n"); | 290 | int cur_size; |
289 | 291 | int last_percent; | |
290 | struct stmp_logical_media_table_t *table = NULL; | 292 | FILE *f; |
291 | int ret = stmp_get_logical_media_table(g_dev_fd, &table); | 293 | bool read; |
292 | if(ret) | 294 | }; |
293 | { | 295 | |
294 | cprintf(GREY, "Cannot get logical table: %d\n", ret); | 296 | int rw_fw(void *user, void *buf, size_t size) |
295 | goto Lend; | 297 | { |
296 | } | 298 | struct rw_fw_context_t *ctx = user; |
297 | int entry = 0; | 299 | int this_percent = (ctx->cur_size * 100LLU) / ctx->tot_size; |
298 | while(entry < table->header.count) | 300 | if(this_percent != ctx->last_percent && (this_percent % 5) == 0) |
299 | if(table->entry[entry].type == SCSI_STMP_DRIVE_TYPE_SYSTEM && | ||
300 | table->entry[entry].tag == SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT) | ||
301 | break; | ||
302 | else | ||
303 | entry++; | ||
304 | if(entry == table->header.count) | ||
305 | { | ||
306 | cprintf(GREY, "Cannot find firmware partition\n"); | ||
307 | goto Lend; | ||
308 | } | ||
309 | uint8_t drive_no = table->entry[entry].drive_no; | ||
310 | uint64_t drive_sz = table->entry[entry].size; | ||
311 | if(g_debug) | ||
312 | { | ||
313 | cprintf(RED, "* "); | ||
314 | cprintf_field("Drive: ", "%#x\n", drive_no); | ||
315 | cprintf(RED, "* "); | ||
316 | cprintf_field("Size: ", "%#llx\n", (unsigned long long)drive_sz); | ||
317 | } | ||
318 | struct stmp_logical_drive_info_t info; | ||
319 | ret = stmp_get_logical_drive_info(g_dev_fd, drive_no, &info); | ||
320 | if(ret || !info.has.sector_size) | ||
321 | { | ||
322 | cprintf(GREY, "Cannot get sector size\n"); | ||
323 | goto Lend; | ||
324 | } | ||
325 | unsigned sector_size = info.sector_size; | ||
326 | if(g_debug) | ||
327 | { | ||
328 | cprintf(RED, "* "); | ||
329 | cprintf_field("Sector size: ", "%lu\n", (unsigned long)sector_size); | ||
330 | } | ||
331 | uint8_t *sector = malloc(sector_size); | ||
332 | ret = stmp_read_logical_drive_sectors(g_dev_fd, drive_no, 0, 1, sector, sector_size); | ||
333 | if(ret) | ||
334 | { | ||
335 | cprintf(GREY, "Cannot read first sector: %d\n", ret); | ||
336 | goto Lend; | ||
337 | } | ||
338 | uint32_t fw_size = *(uint32_t *)(sector + 0x1c) * 16; | ||
339 | if(g_debug) | ||
340 | { | 301 | { |
341 | cprintf(RED, "* "); | 302 | cprintf(RED, "%d%%", this_percent); |
342 | cprintf_field("Firmware size: ", "%#x\n", fw_size); | 303 | cprintf(YELLOW, "..."); |
304 | fflush(stdout); | ||
343 | } | 305 | } |
306 | ctx->last_percent = this_percent; | ||
307 | int ret = -1; | ||
308 | if(ctx->read) | ||
309 | ret = fread(buf, size, 1, ctx->f); | ||
310 | else | ||
311 | ret = fwrite(buf, size, 1, ctx->f); | ||
312 | ctx->cur_size += size; | ||
313 | if(ret != 1) | ||
314 | return -1; | ||
315 | else | ||
316 | return size; | ||
317 | } | ||
344 | 318 | ||
345 | f = fopen(file, "wb"); | 319 | void rw_finish(struct rw_fw_context_t *ctx) |
320 | { | ||
321 | if(ctx->last_percent == 100) | ||
322 | return; | ||
323 | cprintf(RED, "100%%\n"); | ||
324 | } | ||
325 | |||
326 | void do_extract(const char *file) | ||
327 | { | ||
328 | FILE *f = fopen(file, "wb"); | ||
346 | if(f == NULL) | 329 | if(f == NULL) |
347 | { | 330 | { |
348 | cprintf(GREY, "Cannot open '%s' for writing: %m\n", file); | 331 | cprintf(GREY, "Cannot open output file: %s\n", strerror(errno)); |
349 | goto Lend; | 332 | return; |
350 | } | 333 | } |
351 | 334 | int ret = stmp_read_firmware(g_dev_fd, NULL, NULL); | |
352 | for(int sec = 0; sec * sector_size < fw_size; sec++) | 335 | if(ret < 0) |
353 | { | 336 | { |
354 | ret = stmp_read_logical_drive_sectors(g_dev_fd, drive_no, sec, 1, sector, sector_size); | 337 | cprintf(GREY, "Cannot get firmware size: %d\n", ret); |
355 | if(ret) | 338 | return; |
356 | { | ||
357 | cprintf(GREY, "Cannot read sector %d: %d\n", sec, ret); | ||
358 | goto Lend; | ||
359 | } | ||
360 | if(fwrite(sector, sector_size, 1, f) != 1) | ||
361 | { | ||
362 | cprintf(GREY, "Write failed: %m\n"); | ||
363 | goto Lend; | ||
364 | } | ||
365 | } | 339 | } |
366 | cprintf(BLUE, "Done\n"); | 340 | struct rw_fw_context_t ctx; |
367 | Lend: | 341 | ctx.tot_size = ret; |
368 | free(table); | 342 | ctx.cur_size = 0; |
369 | if(f) | 343 | ctx.f = f; |
370 | fclose(f); | 344 | ctx.last_percent = -1; |
345 | ctx.read = false; | ||
346 | ret = stmp_read_firmware(g_dev_fd, &ctx, &rw_fw); | ||
347 | if(ret < 0) | ||
348 | cprintf(GREY, "Cannot read firmware: %d\n", ret); | ||
349 | rw_finish(&ctx); | ||
350 | fclose(f); | ||
371 | } | 351 | } |
372 | 352 | ||
373 | void do_write(const char *file, int want_a_brick) | 353 | void do_write(const char *file, int want_a_brick) |
@@ -379,115 +359,25 @@ void do_write(const char *file, int want_a_brick) | |||
379 | cprintf(GREY, "option on the command line and do not complain if you end up with a brick ;)\n"); | 359 | cprintf(GREY, "option on the command line and do not complain if you end up with a brick ;)\n"); |
380 | return; | 360 | return; |
381 | } | 361 | } |
382 | FILE *f = NULL; | 362 | FILE *f = fopen(file, "rb"); |
383 | cprintf(BLUE, "Writing firmware...\n"); | ||
384 | |||
385 | struct stmp_logical_media_table_t *table = NULL; | ||
386 | int ret = stmp_get_logical_media_table(g_dev_fd, &table); | ||
387 | if(ret) | ||
388 | { | ||
389 | cprintf(GREY, "Cannot get logical table: %d\n", ret); | ||
390 | goto Lend; | ||
391 | } | ||
392 | int entry = 0; | ||
393 | while(entry < table->header.count) | ||
394 | if(table->entry[entry].type == SCSI_STMP_DRIVE_TYPE_SYSTEM && | ||
395 | table->entry[entry].tag == SCSI_STMP_DRIVE_TAG_SYSTEM_BOOT) | ||
396 | break; | ||
397 | else | ||
398 | entry++; | ||
399 | if(entry == table->header.count) | ||
400 | { | ||
401 | cprintf(GREY, "Cannot find firmware partition\n"); | ||
402 | goto Lend; | ||
403 | } | ||
404 | uint8_t drive_no = table->entry[entry].drive_no; | ||
405 | uint64_t drive_sz = table->entry[entry].size; | ||
406 | if(g_debug) | ||
407 | { | ||
408 | cprintf(RED, "* "); | ||
409 | cprintf_field("Drive: ", "%#x\n", drive_no); | ||
410 | cprintf(RED, "* "); | ||
411 | cprintf_field("Size: ", "%#llx\n", (unsigned long long)drive_sz); | ||
412 | } | ||
413 | struct stmp_logical_drive_info_t info; | ||
414 | ret = stmp_get_logical_drive_info(g_dev_fd, drive_no, &info); | ||
415 | if(ret || !info.has.sector_size) | ||
416 | { | ||
417 | cprintf(GREY, "Cannot get sector size\n"); | ||
418 | goto Lend; | ||
419 | } | ||
420 | unsigned sector_size = info.sector_size; | ||
421 | uint8_t *sector = malloc(sector_size); | ||
422 | |||
423 | /* sanity check by reading first sector */ | ||
424 | ret = stmp_read_logical_drive_sectors(g_dev_fd, drive_no, 0, 1, sector, sector_size); | ||
425 | if(ret) | ||
426 | { | ||
427 | cprintf(GREY, "Cannot read first sector: %d\n", ret); | ||
428 | return; | ||
429 | } | ||
430 | uint32_t sig = *(uint32_t *)(sector + 0x14); | ||
431 | if(sig != 0x504d5453) | ||
432 | { | ||
433 | cprintf(GREY, "There is something wrong: the first sector doesn't have the STMP signature. Bailing out...\n"); | ||
434 | return; | ||
435 | } | ||
436 | |||
437 | f = fopen(file, "rb"); | ||
438 | if(f == NULL) | 363 | if(f == NULL) |
439 | { | 364 | { |
440 | cprintf(GREY, "Cannot open '%s' for writing: %m\n", file); | 365 | cprintf(GREY, "Cannot open output file: %s\n", strerror(errno)); |
441 | goto Lend; | 366 | return; |
442 | } | 367 | } |
368 | struct rw_fw_context_t ctx; | ||
443 | fseek(f, 0, SEEK_END); | 369 | fseek(f, 0, SEEK_END); |
444 | int fw_size = ftell(f); | 370 | ctx.tot_size = ftell(f); |
445 | fseek(f, 0, SEEK_SET); | 371 | fseek(f, 0, SEEK_SET); |
446 | if(g_debug) | 372 | ctx.cur_size = 0; |
447 | { | 373 | ctx.f = f; |
448 | cprintf(RED, "* "); | 374 | ctx.last_percent = -1; |
449 | cprintf_field("Firmware size: ", "%#x\n", fw_size); | 375 | ctx.read = true; |
450 | } | 376 | int ret = stmp_write_firmware(g_dev_fd, &ctx, &rw_fw); |
451 | /* sanity check size */ | 377 | if(ret < 0) |
452 | if((uint64_t)fw_size > drive_sz) | 378 | cprintf(GREY, "Cannot write firmware: %d\n", ret); |
453 | { | 379 | rw_finish(&ctx); |
454 | cprintf(GREY, "You cannot write a firmware greater than the partition size.\n"); | 380 | fclose(f); |
455 | goto Lend; | ||
456 | } | ||
457 | |||
458 | int percent = -1; | ||
459 | for(int off = 0; off < fw_size; off += sector_size) | ||
460 | { | ||
461 | int sec = off / sector_size; | ||
462 | int this_percent = (sec * 100) / (fw_size / sector_size); | ||
463 | if(this_percent != percent && (this_percent % 5) == 0) | ||
464 | { | ||
465 | cprintf(RED, "%d%%", this_percent); | ||
466 | cprintf(YELLOW, "..."); | ||
467 | fflush(stdout); | ||
468 | } | ||
469 | percent = this_percent; | ||
470 | int xfer_len = MIN(fw_size - off, (int)sector_size); | ||
471 | if(fread(sector, xfer_len, 1, f) != 1) | ||
472 | { | ||
473 | cprintf(GREY, "Read failed: %m\n"); | ||
474 | goto Lend; | ||
475 | } | ||
476 | /* NOTE transfer a whole sector even if incomplete, the device won't access | ||
477 | * partial sectors */ | ||
478 | if(xfer_len < (int)sector_size) | ||
479 | memset(sector + xfer_len, 0, sector_size - xfer_len); | ||
480 | ret = stmp_write_logical_drive_sectors(g_dev_fd, drive_no, sec, 1, sector, sector_size); | ||
481 | if(ret) | ||
482 | { | ||
483 | cprintf(GREY, "Cannot write sector %d: %d\n", sec, ret); | ||
484 | goto Lend; | ||
485 | } | ||
486 | } | ||
487 | cprintf(BLUE, "Done\n"); | ||
488 | Lend: | ||
489 | if(f) | ||
490 | fclose(f); | ||
491 | } | 381 | } |
492 | 382 | ||
493 | static void usage(void) | 383 | static void usage(void) |
@@ -586,14 +476,14 @@ int main(int argc, char **argv) | |||
586 | rb_scsi_device_t scsi_dev = rb_scsi_open(argv[optind], g_debug ? RB_SCSI_DEBUG : 0, NULL, scsi_printf); | 476 | rb_scsi_device_t scsi_dev = rb_scsi_open(argv[optind], g_debug ? RB_SCSI_DEBUG : 0, NULL, scsi_printf); |
587 | if(scsi_dev == 0) | 477 | if(scsi_dev == 0) |
588 | { | 478 | { |
589 | cprintf(GREY, "Cannot open device: %m\n"); | 479 | cprintf(GREY, "Cannot open device\n"); |
590 | ret = 1; | 480 | ret = 1; |
591 | goto Lend; | 481 | goto Lend; |
592 | } | 482 | } |
593 | g_dev_fd = stmp_open(scsi_dev, g_debug ? STMP_DEBUG : 0, NULL, scsi_printf); | 483 | g_dev_fd = stmp_open(scsi_dev, g_debug ? STMP_DEBUG : 0, NULL, scsi_printf); |
594 | if(g_dev_fd == 0) | 484 | if(g_dev_fd == 0) |
595 | { | 485 | { |
596 | cprintf(GREY, "Cannot open stmp device: %m\n"); | 486 | cprintf(GREY, "Cannot open stmp device\n"); |
597 | ret = 2; | 487 | ret = 2; |
598 | goto Lend; | 488 | goto Lend; |
599 | } | 489 | } |