diff options
Diffstat (limited to 'utils')
-rw-r--r-- | utils/nwztools/scsitools/scsitool.c | 140 |
1 files changed, 138 insertions, 2 deletions
diff --git a/utils/nwztools/scsitools/scsitool.c b/utils/nwztools/scsitools/scsitool.c index c85eb75f9a..7c18a46daa 100644 --- a/utils/nwztools/scsitools/scsitool.c +++ b/utils/nwztools/scsitools/scsitool.c | |||
@@ -989,6 +989,7 @@ static void usage(void) | |||
989 | { | 989 | { |
990 | printf("Usage:\n"); | 990 | printf("Usage:\n"); |
991 | printf(" scsitool [options] list_devices\n"); | 991 | printf(" scsitool [options] list_devices\n"); |
992 | printf(" scsitool [options] decode_scsi <cdb>\n"); | ||
992 | printf(" scsitool [options] <dev> <command> [arguments]\n"); | 993 | printf(" scsitool [options] <dev> <command> [arguments]\n"); |
993 | printf("Options:\n"); | 994 | printf("Options:\n"); |
994 | printf(" -o <prefix> Set output prefix\n"); | 995 | printf(" -o <prefix> Set output prefix\n"); |
@@ -1067,6 +1068,139 @@ static int list_devices(bool list_all) | |||
1067 | return 0; | 1068 | return 0; |
1068 | } | 1069 | } |
1069 | 1070 | ||
1071 | inline uint8_t xdigit2val(char c) | ||
1072 | { | ||
1073 | if('0' <= c && c <= '9') | ||
1074 | return c - '0'; | ||
1075 | else if('a' <= c && c <= 'f') | ||
1076 | return c - 'a' + 10; | ||
1077 | else if('A' <= c && c <= 'F') | ||
1078 | return c - 'A' + 10; | ||
1079 | else | ||
1080 | return 255; | ||
1081 | } | ||
1082 | |||
1083 | static int decode_scsi_a3(uint8_t *cdb, int cdb_len) | ||
1084 | { | ||
1085 | cprintf_field("Opcode: ", "A3\n"); | ||
1086 | cprintf(RED, "Unimplemented\n"); | ||
1087 | return 0; | ||
1088 | } | ||
1089 | |||
1090 | static int decode_scsi_a4(uint8_t *cdb, int cdb_len) | ||
1091 | { | ||
1092 | cprintf_field("Opcode: ", "A3\n"); | ||
1093 | cprintf(RED, "Unimplemented\n"); | ||
1094 | return 0; | ||
1095 | } | ||
1096 | |||
1097 | static int decode_scsi_empr_dpcc(uint8_t *cdb, int cdb_len) | ||
1098 | { | ||
1099 | cprintf_field("Opcode: ", "%X (EMPR DPCC)\n", cdb[0]); | ||
1100 | cprintf(RED, "Unimplemented\n"); | ||
1101 | return 0; | ||
1102 | } | ||
1103 | |||
1104 | static int decode_scsi_dnk(uint8_t *cdb, int cdb_len) | ||
1105 | { | ||
1106 | cprintf_field("Opcode: ", "%X (DNK)\n", cdb[0]); | ||
1107 | cprintf(RED, "Unimplemented\n"); | ||
1108 | return 0; | ||
1109 | } | ||
1110 | |||
1111 | static int decode_scsi_dpcc(uint8_t *cdb, int cdb_len) | ||
1112 | { | ||
1113 | cprintf_field("Opcode: ", "%X (DPCC)\n", cdb[0]); | ||
1114 | cprintf(RED, "Unimplemented\n"); | ||
1115 | return 0; | ||
1116 | } | ||
1117 | |||
1118 | static int decode_scsi_fc(uint8_t *cdb, int cdb_len) | ||
1119 | { | ||
1120 | cprintf_field("Opcode: ", "FC\n"); | ||
1121 | if(cdb[3] == 'd' && cdb[4] == 'b' && cdb[5] == 'm' && cdb[6] == 'n') | ||
1122 | { | ||
1123 | uint8_t cmd = cdb[2]; | ||
1124 | uint8_t flags = cdb[8]; | ||
1125 | const char *cmd_name = "Unknown"; | ||
1126 | if(cmd == 0x04) | ||
1127 | cmd_name = "Firmware Upgrade"; | ||
1128 | if(cmd == 0x20) | ||
1129 | cmd_name = "Get Device Info"; | ||
1130 | |||
1131 | cprintf(BLUE, "Device request:\n"); | ||
1132 | cprintf_field(" Command: ", "%x (%s)\n", cmd, cmd_name); | ||
1133 | cprintf_field(" Flags(?): ", "%x (Unknown)\n", flags); | ||
1134 | |||
1135 | } | ||
1136 | return 0; | ||
1137 | } | ||
1138 | |||
1139 | static int decode_scsi(int argc, char **argv) | ||
1140 | { | ||
1141 | /* we need to parse the arguments, we support either as one big hexdump: | ||
1142 | * fc002064626d6e0080000000 | ||
1143 | * or as a sequence of hex bytes: | ||
1144 | * fc 00 20 64 62 6d 6e 00 80 00 00 00 | ||
1145 | */ | ||
1146 | if(argc == 0) | ||
1147 | { | ||
1148 | cprintf(GREY, "You need to specify the CDB to decode\n"); | ||
1149 | return 1; | ||
1150 | } | ||
1151 | #define MAX_CDB 16 | ||
1152 | uint8_t cdb[MAX_CDB]; | ||
1153 | int cdb_len; | ||
1154 | if(argc > MAX_CDB) | ||
1155 | { | ||
1156 | cprintf(GREY, "This does not look like a CDB (more than %d bytes)\n", MAX_CDB); | ||
1157 | return 1; | ||
1158 | } | ||
1159 | if(argc == 1) | ||
1160 | { | ||
1161 | /* allow the string to start with 0x */ | ||
1162 | char *str = argv[0]; | ||
1163 | if(str[0] == '0' && str[1] == 'x') | ||
1164 | str += 2; | ||
1165 | cdb_len = strlen(str); | ||
1166 | if(cdb_len % 2) | ||
1167 | { | ||
1168 | cprintf(GREY, "The CDB must contain an even number of hex digits!\n"); | ||
1169 | return 1; | ||
1170 | } | ||
1171 | cdb_len /= 2; | ||
1172 | for(int i = 0; i < cdb_len; i++) | ||
1173 | { | ||
1174 | if(!isxdigit(str[2 * i]) || !isxdigit(str[2 * i + 1])) | ||
1175 | { | ||
1176 | cprintf(GREY, "The CDB must contain hex digits!\n"); | ||
1177 | return 1; | ||
1178 | } | ||
1179 | cdb[i] = xdigit2val(str[2 * i]) << 4 | xdigit2val(str[2 * i + 1]); | ||
1180 | } | ||
1181 | } | ||
1182 | else | ||
1183 | { | ||
1184 | cprintf(GREY, "unimplemented\n"); | ||
1185 | return 1; | ||
1186 | } | ||
1187 | cprintf(GREEN, "CDB: "); | ||
1188 | print_hex(cdb, cdb_len); | ||
1189 | |||
1190 | if(cdb[0] == CMD_A3) return decode_scsi_a3(cdb, cdb_len); | ||
1191 | if(cdb[0] == CMD_A4) return decode_scsi_a4(cdb, cdb_len); | ||
1192 | if(cdb[0] == CMD_EMPR_DPCC) return decode_scsi_empr_dpcc(cdb, cdb_len); | ||
1193 | if(cdb[0] == CMD_DNK) return decode_scsi_dnk(cdb, cdb_len); | ||
1194 | if(cdb[0] == CMD_DPCC) return decode_scsi_dpcc(cdb, cdb_len); | ||
1195 | if(cdb[0] == 0xfc) return decode_scsi_fc(cdb, cdb_len); | ||
1196 | else | ||
1197 | { | ||
1198 | cprintf(RED, "I cannot decode this SCSI command\n"); | ||
1199 | } | ||
1200 | |||
1201 | return 0; | ||
1202 | } | ||
1203 | |||
1070 | int main(int argc, char **argv) | 1204 | int main(int argc, char **argv) |
1071 | { | 1205 | { |
1072 | bool list_all = false; | 1206 | bool list_all = false; |
@@ -1130,9 +1264,11 @@ int main(int argc, char **argv) | |||
1130 | return 0; | 1264 | return 0; |
1131 | } | 1265 | } |
1132 | 1266 | ||
1133 | /* special list_devices command */ | 1267 | /* special list_devices/decode_scsi command */ |
1134 | if(argc == optind + 1 && strcmp(argv[optind], "list_devices") == 0) | 1268 | if(argc >= optind + 1 && strcmp(argv[optind], "list_devices") == 0) |
1135 | return list_devices(list_all); | 1269 | return list_devices(list_all); |
1270 | if(argc >= optind + 1 && strcmp(argv[optind], "decode_scsi") == 0) | ||
1271 | return decode_scsi(argc - optind - 1, argv + optind + 1); | ||
1136 | 1272 | ||
1137 | if(argc - optind < 2) | 1273 | if(argc - optind < 2) |
1138 | { | 1274 | { |