diff options
-rw-r--r-- | utils/imxtools/scsitools/Makefile | 20 | ||||
-rw-r--r-- | utils/imxtools/scsitools/misc.c | 53 | ||||
-rw-r--r-- | utils/imxtools/scsitools/misc.h | 50 | ||||
-rw-r--r-- | utils/imxtools/scsitools/scsitool.c | 310 | ||||
-rw-r--r-- | utils/imxtools/scsitools/stmp_scsi.h | 42 |
5 files changed, 475 insertions, 0 deletions
diff --git a/utils/imxtools/scsitools/Makefile b/utils/imxtools/scsitools/Makefile new file mode 100644 index 0000000000..ed4bc88d0b --- /dev/null +++ b/utils/imxtools/scsitools/Makefile @@ -0,0 +1,20 @@ +DEFINES= +CC=gcc +LD=gcc +CFLAGS=-g -std=c99 -W -Wall $(DEFINES) +LDFLAGS=-lsgutils2 +BINS=scsitool + +all: $(BINS) + +%.o: %.c + $(CC) $(CFLAGS) -c -o $@ $< + +scsitool: scsitool.o misc.o + $(LD) -o $@ $^ $(LDFLAGS) + +clean: + rm -fr *.o + +veryclean: + rm -rf $(BINS) diff --git a/utils/imxtools/scsitools/misc.c b/utils/imxtools/scsitools/misc.c new file mode 100644 index 0000000000..108235e7fd --- /dev/null +++ b/utils/imxtools/scsitools/misc.c @@ -0,0 +1,53 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include <stdlib.h> +#include <stdio.h> +#include <time.h> +#include <ctype.h> +#include "misc.h" + +char OFF[] = { 0x1b, 0x5b, 0x31, 0x3b, '0', '0', 0x6d, '\0' }; + +char GREY[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '0', 0x6d, '\0' }; +char RED[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '1', 0x6d, '\0' }; +char GREEN[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '2', 0x6d, '\0' }; +char YELLOW[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '3', 0x6d, '\0' }; +char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' }; + +static bool g_color_enable = true; + +void *xmalloc(size_t s) +{ + void * r = malloc(s); + if(!r) bugp("malloc"); + return r; +} + +void enable_color(bool enable) +{ + g_color_enable = enable; +} + +void color(color_t c) +{ + if(g_color_enable) + printf("%s", (char *)c); +} diff --git a/utils/imxtools/scsitools/misc.h b/utils/imxtools/scsitools/misc.h new file mode 100644 index 0000000000..035b0ef8c1 --- /dev/null +++ b/utils/imxtools/scsitools/misc.h @@ -0,0 +1,50 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2010 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __MISC_H__ +#define __MISC_H__ + +#include <stdbool.h> +#include <stdio.h> + +#define _STR(a) #a +#define STR(a) _STR(a) + +#define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0) +#define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0) + +#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) + +typedef char color_t[]; + +extern color_t OFF, GREY, RED, GREEN, YELLOW, BLUE; +void *xmalloc(size_t s); +void color(color_t c); +void enable_color(bool enable); + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +#define cprintf(col, ...) do {color(col); printf(__VA_ARGS__); }while(0) + +#define cprintf_field(str1, ...) do{ cprintf(GREEN, str1); cprintf(YELLOW, __VA_ARGS__); }while(0) + +#endif /* __MISC_H__ */ diff --git a/utils/imxtools/scsitools/scsitool.c b/utils/imxtools/scsitools/scsitool.c new file mode 100644 index 0000000000..7fc68f8c37 --- /dev/null +++ b/utils/imxtools/scsitools/scsitool.c @@ -0,0 +1,310 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2012 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#include <stdio.h> +#include <stdint.h> +#include <stdbool.h> +#include <stdlib.h> +#include <stddef.h> +#include <string.h> +#include <getopt.h> +#include <stdarg.h> +#include <ctype.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <scsi/scsi.h> +#include <scsi/sg_lib.h> +#include <scsi/sg_pt.h> +#include "misc.h" +#include "stmp_scsi.h" + +bool g_debug = false; +bool g_force = false; +int g_dev_fd = 0; + +#define let_the_force_flow(x) do { if(!g_force) return x; } while(0) +#define continue_the_force(x) if(x) let_the_force_flow(x) + +#define check_field(v_exp, v_have, str_ok, str_bad) \ + if((v_exp) != (v_have)) \ + { cprintf(RED, str_bad); let_the_force_flow(__LINE__); } \ + else { cprintf(RED, str_ok); } + +#define errorf(...) do { cprintf(GREY, __VA_ARGS__); return __LINE__; } while(0) + +#if 0 +void *buffer_alloc(int sz) +{ +#ifdef SG_LIB_MINGW + unsigned psz = getpagesize(); +#else + unsigned psz = sysconf(_SC_PAGESIZE); /* was getpagesize() */ +#endif + void *buffer = malloc(sz + psz); + return (void *)(((ptrdiff_t)(buffer + psz - 1)) & ~(psz - 1)); +} +#else +void *buffer_alloc(int sz) +{ + return malloc(sz); +} +#endif + +static void print_hex(void *_buffer, int buffer_size) +{ + uint8_t *buffer = _buffer; + for(int i = 0; i < buffer_size; i += 16) + { + for(int j = 0; j < 16; j++) + { + if(i + j < buffer_size) + cprintf(YELLOW, " %02x", buffer[i + j]); + else + cprintf(YELLOW, " "); + } + printf(" "); + for(int j = 0; j < 16; j++) + { + if(i + j < buffer_size) + cprintf(RED, "%c", isprint(buffer[i + j]) ? buffer[i + j] : '.'); + else + cprintf(RED, " "); + } + printf("\n"); + } +} + +/* Do read */ +#define DO_READ (1 << 1) +/* Do write */ +#define DO_WRITE (1 << 2) + +/* returns <0 on error and status otherwise */ +int do_scsi(uint8_t *cdb, int cdb_size, unsigned flags, void *sense, int *sense_size, void *buffer, int *buf_size) +{ + char error[256]; + struct sg_pt_base *obj = construct_scsi_pt_obj(); + if(obj == NULL) + { + cprintf(GREY, "construct_scsi_pt_obj failed\n"); + return 1; + } + set_scsi_pt_cdb(obj, cdb, cdb_size); + if(sense) + set_scsi_pt_sense(obj, sense, *sense_size); + if(flags & DO_READ) + set_scsi_pt_data_in(obj, buffer, *buf_size); + if(flags & DO_WRITE) + set_scsi_pt_data_out(obj, buffer, *buf_size); + int ret = do_scsi_pt(obj, g_dev_fd, 1, 0); + switch(get_scsi_pt_result_category(obj)) + { + case SCSI_PT_RESULT_SENSE: + case SCSI_PT_RESULT_GOOD: + ret = get_scsi_pt_status_response(obj); + break; + case SCSI_PT_RESULT_STATUS: + cprintf(GREY, "Status error: %d (", get_scsi_pt_status_response(obj)); + sg_print_scsi_status(get_scsi_pt_status_response(obj)); + printf(")\n"); + break; + case SCSI_PT_RESULT_TRANSPORT_ERR: + cprintf(GREY, "Transport error: %s\n", get_scsi_pt_transport_err_str(obj, 256, error)); + ret = -2; + break; + case SCSI_PT_RESULT_OS_ERR: + cprintf(GREY, "OS error: %s\n", get_scsi_pt_os_err_str(obj, 256, error)); + ret = -3; + break; + default: + cprintf(GREY, "Unknown error\n"); + break; + } + + if(sense) + *sense_size = get_scsi_pt_sense_len(obj); + if(flags & (DO_WRITE | DO_READ)) + *buf_size -= get_scsi_pt_resid(obj); + + destruct_scsi_pt_obj(obj); + return ret; +} + +int do_sense_analysis(int status, uint8_t *sense, int sense_size) +{ + if(status != GOOD || g_debug) + { + cprintf_field("Status:", " "); fflush(stdout); + sg_print_scsi_status(status); + cprintf_field("\nSense:", " "); fflush(stdout); + sg_print_sense(NULL, sense, sense_size, 0); + } + if(status == GOOD) + return 0; + return status; +} + +int stmp_inquiry(uint8_t *dev_type, char vendor[9], char product[17]) +{ + unsigned char buffer[56]; + uint8_t cdb[10]; + memset(cdb, 0, sizeof(cdb)); + cdb[0] = 0x12; + cdb[4] = sizeof(buffer); + + uint8_t sense[32]; + int sense_size = sizeof(sense); + + int buf_sz = sizeof(buffer); + int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, buffer, &buf_sz); + if(ret < 0) + return ret; + ret = do_sense_analysis(ret, sense, sense_size); + if(ret) + return ret; + if(buf_sz != sizeof(buffer)) + return -1; + *dev_type = buffer[0]; + memcpy(vendor, buffer + 8, 8); + vendor[8] = 0; + memcpy(product, buffer + 16, 16); + product[16] = 0; + return 0; +} + +static int stmp_get_protocol_version(struct scsi_stmp_protocol_version_t *ver) +{ + uint8_t cdb[10]; + memset(cdb, 0, sizeof(cdb)); + cdb[0] = SCSI_STMP_READ; + cdb[1] = SCSI_STMP_CMD_GET_PROTOCOL_VERSION; + + uint8_t sense[32]; + int sense_size = sizeof(sense); + + int buf_sz = sizeof(struct scsi_stmp_protocol_version_t); + int ret = do_scsi(cdb, sizeof(cdb), DO_READ, sense, &sense_size, ver, &buf_sz); + if(ret < 0) + return ret; + ret = do_sense_analysis(ret, sense, sense_size); + if(ret) + return ret; + if(buf_sz != sizeof(struct scsi_stmp_protocol_version_t)) + return -1; + return 0; +} + +static int do_work(void) +{ + cprintf(BLUE, "Information\n"); + + uint8_t dev_type; + char vendor[9]; + char product[17]; + int ret = stmp_inquiry(&dev_type, vendor, product); + if(ret) + errorf("Cannot get inquiry data: %d\n", ret); + cprintf_field(" Vendor: ", "%s\n", vendor); + cprintf_field(" Product: ", "%s\n", product); + + struct scsi_stmp_protocol_version_t ver; + ret = stmp_get_protocol_version(&ver); + if(ret) + errorf("Cannot get protocol version: %d\n", ret); + + cprintf_field(" Protocol: ", "%x.%x\n", ver.major, ver.minor); + + return 0; +} + +static void usage(void) +{ + printf("Usage: scsitool [options] <dev>\n"); + printf("Options:\n"); + printf(" -f/--force\tForce to continue on errors\n"); + printf(" -?/--help\tDisplay this message\n"); + printf(" -d/--debug\tDisplay debug messages\n"); + printf(" -c/--no-color\tDisable color output\n"); + exit(1); +} + +int main(int argc, char **argv) +{ + while(1) + { + static struct option long_options[] = + { + {"help", no_argument, 0, '?'}, + {"debug", no_argument, 0, 'd'}, + {"no-color", no_argument, 0, 'c'}, + {"force", no_argument, 0, 'f'}, + {0, 0, 0, 0} + }; + + int c = getopt_long(argc, argv, "?dcf", long_options, NULL); + if(c == -1) + break; + switch(c) + { + case -1: + break; + case 'c': + enable_color(false); + break; + case 'd': + g_debug = true; + break; + case 'f': + g_force = true; + break; + case '?': + usage(); + break; + default: + abort(); + } + } + + if(argc - optind != 1) + { + usage(); + return 1; + } + + int ret = 0; + g_dev_fd = scsi_pt_open_device(argv[optind], false, true); + if(g_dev_fd < 0) + { + cprintf(GREY, "Cannot open device: %m\n"); + ret = 1; + goto Lend; + } + + do_work(); + + scsi_pt_close_device(g_dev_fd); +Lend: + color(OFF); + + return ret; +} + diff --git a/utils/imxtools/scsitools/stmp_scsi.h b/utils/imxtools/scsitools/stmp_scsi.h new file mode 100644 index 0000000000..14f651f6dd --- /dev/null +++ b/utils/imxtools/scsitools/stmp_scsi.h @@ -0,0 +1,42 @@ +/*************************************************************************** + * __________ __ ___. + * Open \______ \ ____ ____ | | _\_ |__ _______ ___ + * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / + * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < + * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ + * \/ \/ \/ \/ \/ + * $Id$ + * + * Copyright (C) 2012 Amaury Pouly + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ****************************************************************************/ +#ifndef __STMP_SCSI__ +#define __STMP_SCSI__ + +#include <stdint.h> + +#define SCSI_STMP_READ 0xc0 +#define SCSI_STMP_WRITE 0xc1 +/** STMP: Command */ +#define SCSI_STMP_CMD_GET_PROTOCOL_VERSION 0 +#define SCSI_STMP_CMD_GET_LOGICAL_MEDIA_INFO 2 +#define SCSI_STMP_CMD_GET_LOGICAL_TABLE 5 +#define SCSI_STMP_CMD_GET_LOGICAL_DRIVE_INFO 0x12 +#define SCSI_STMP_CMD_GET_CHIP_MAJOR_REV_ID 0x30 +#define SCSI_STMP_CMD_GET_ROM_REV_ID 0x37 + +struct scsi_stmp_protocol_version_t +{ + uint8_t major; + uint8_t minor; +} __attribute__((packed)); + +#endif /* __STMP_SCSI__ */ |