BlueSCSI_log_trace.cpp 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315
  1. // SCSI trace logging
  2. //
  3. // Copyright (c) 2022 Rabbit Hole Computing™
  4. // Copyright (c) 2023 Eric Helgeson
  5. #include "BlueSCSI_log_trace.h"
  6. #include "BlueSCSI_log.h"
  7. #include <scsi2sd.h>
  8. #include "BlueSCSI_Toolbox.h"
  9. extern "C" {
  10. #include <scsi.h>
  11. #include <scsiPhy.h>
  12. }
  13. static bool g_LogData = false;
  14. static bool g_LogInitiatorCommand = false;
  15. static int g_InByteCount = 0;
  16. static int g_OutByteCount = 0;
  17. static uint16_t g_DataChecksum = 0;
  18. static const char *getCommandName(uint8_t cmd)
  19. {
  20. switch (cmd)
  21. {
  22. case 0x00: return "TestUnitReady";
  23. case 0x01: return "RezeroUnit/Rewind";
  24. case 0x03: return "RequestSense";
  25. case 0x04: return "FormatUnit";
  26. case 0x05: return "ReadBlockLimits";
  27. case 0x06: return "IomegaVendorCommand";
  28. case 0x08: return "Read6";
  29. case 0x0A: return "Write6";
  30. case 0x0B: return "Seek6";
  31. case 0x0C: return "Xebec InitializeDriveCharacteristics";
  32. case 0x0F: return "Xebec WriteSectorBuffer";
  33. case 0x10: return "WriteFilemarks";
  34. case 0x11: return "Space";
  35. case 0x12: return "Inquiry";
  36. case 0x13: return "Verify";
  37. case 0x15: return "ModeSelect6";
  38. case 0x16: return "Reserve";
  39. case 0x17: return "Release";
  40. case 0x19: return "Erase";
  41. case 0x1A: return "ModeSense";
  42. case 0x1B: return "StartStopUnit";
  43. case 0x1C: return "ReceiveDiagnostic";
  44. case 0x1D: return "SendDiagnostic";
  45. case 0x1E: return "PreventAllowMediumRemoval";
  46. case 0x25: return "ReadCapacity";
  47. case 0x28: return "Read10";
  48. case 0x2A: return "Write10";
  49. case 0x2B: return "Seek10";
  50. case 0x2C: return "Erase10";
  51. case 0x2E: return "WriteVerify";
  52. case 0x2F: return "Verify";
  53. case 0x34: return "PreFetch/ReadPosition";
  54. case 0x35: return "SynchronizeCache";
  55. case 0x36: return "LockUnlockCache";
  56. case 0x37: return "ReadDefectData";
  57. case 0x3B: return "WriteBuffer";
  58. case 0x3C: return "ReadBuffer";
  59. case 0x42: return "CDROM Read SubChannel";
  60. case 0x43: return "CDROM Read TOC";
  61. case 0x44: return "CDROM Read Header";
  62. case 0x46: return "CDROM GetConfiguration";
  63. case 0x4A: return "GetEventStatusNotification";
  64. case 0x4B: return "CDROM PauseResume";
  65. case 0x4E: return "CDROM StopPlayScan";
  66. case 0x51: return "CDROM ReadDiscInformation";
  67. case 0x45: return "CDROM PlayAudio10";
  68. case 0xA5: return "CDROM PlayAudio12";
  69. case 0x47: return "CDROM PlayAudioMSF";
  70. case 0x48: return "CDROM PauseResume";
  71. case 0x52: return "CDROM ReadTrackInformation";
  72. case 0xBB: return "CDROM SetCDSpeed";
  73. case 0xBD: return "CDROM MechanismStatus";
  74. case 0xBE: return "ReadCD";
  75. case 0xB9: return "ReadCDMSF";
  76. case 0x55: return "ModeSelect10";
  77. case 0x5A: return "ModeSense10";
  78. case 0xAC: return "Erase12";
  79. case 0xA8: return "Read12";
  80. case 0xC0: return "OMTI-5204 DefineFlexibleDiskFormat";
  81. case 0xC2: return "OMTI-5204 AssignDiskParameters";
  82. case 0xE0: return "Xebec RAM Diagnostic";
  83. case 0xE4: return "Xebec Drive Diagnostic";
  84. case BLUESCSI_TOOLBOX_COUNT_FILES: return "BLUESCSI_TOOLBOX_COUNT_FILES";
  85. case BLUESCSI_TOOLBOX_LIST_FILES: return "BLUESCSI_TOOLBOX_LIST_FILES";
  86. case BLUESCSI_TOOLBOX_GET_FILE: return "BLUESCSI_TOOLBOX_GET_FILE";
  87. case BLUESCSI_TOOLBOX_SEND_FILE_PREP: return "BLUESCSI_TOOLBOX_SEND_FILE_PREP";
  88. case BLUESCSI_TOOLBOX_SEND_FILE_10: return "BLUESCSI_TOOLBOX_SEND_FILE_10";
  89. case BLUESCSI_TOOLBOX_SEND_FILE_END: return "BLUESCSI_TOOLBOX_SEND_FILE_END";
  90. case BLUESCSI_TOOLBOX_TOGGLE_DEBUG: return "BLUESCSI_TOOLBOX_TOGGLE_DEBUG";
  91. case BLUESCSI_TOOLBOX_LIST_CDS: return "BLUESCSI_TOOLBOX_LIST_CDS";
  92. case BLUESCSI_TOOLBOX_SET_NEXT_CD: return "BLUESCSI_TOOLBOX_SET_NEXT_CD";
  93. case BLUESCSI_TOOLBOX_LIST_DEVICES: return "BLUESCSI_TOOLBOX_LIST_DEVICES";
  94. case BLUESCSI_TOOLBOX_COUNT_CDS: return "BLUESCSI_TOOLBOX_COUNT_CDS";
  95. default: return "Unknown";
  96. }
  97. }
  98. static void printNewPhase(int phase, bool initiator = false)
  99. {
  100. g_LogData = false;
  101. g_LogInitiatorCommand = false;
  102. if (!g_log_debug)
  103. {
  104. return;
  105. }
  106. switch(phase)
  107. {
  108. case BUS_FREE:
  109. debuglog("-- BUS_FREE");
  110. break;
  111. case BUS_BUSY:
  112. debuglog("-- BUS_BUSY");
  113. break;
  114. case ARBITRATION:
  115. debuglog("---- ARBITRATION");
  116. break;
  117. case SELECTION:
  118. if (initiator)
  119. debuglog("---- SELECTION");
  120. else
  121. debuglog("---- SELECTION: ", (int)(*SCSI_STS_SELECTED & 7));
  122. break;
  123. case RESELECTION:
  124. debuglog("---- RESELECTION");
  125. break;
  126. case STATUS:
  127. if (initiator)
  128. {
  129. debuglog("---- STATUS");
  130. g_LogData = true;
  131. }
  132. else if (scsiDev.status == GOOD)
  133. {
  134. debuglog("---- STATUS: 0 GOOD");
  135. }
  136. else if (scsiDev.status == CHECK_CONDITION && scsiDev.target)
  137. {
  138. debuglog("---- STATUS: 2 CHECK_CONDITION, sense ", (uint32_t)scsiDev.target->sense.asc);
  139. }
  140. else
  141. {
  142. debuglog("---- STATUS: ", (int)scsiDev.status);
  143. }
  144. break;
  145. case COMMAND:
  146. g_LogInitiatorCommand = initiator;
  147. g_LogData = true;
  148. break;
  149. case DATA_IN:
  150. if (!initiator && scsiDev.target->syncOffset > 0)
  151. debuglog("---- DATA_IN, syncOffset ", (int)scsiDev.target->syncOffset,
  152. " syncPeriod ", (int)scsiDev.target->syncPeriod);
  153. else
  154. debuglog("---- DATA_IN");
  155. break;
  156. case DATA_OUT:
  157. if (!initiator && scsiDev.target->syncOffset > 0)
  158. debuglog("---- DATA_OUT, syncOffset ", (int)scsiDev.target->syncOffset,
  159. " syncPeriod ", (int)scsiDev.target->syncPeriod);
  160. // log Xebec vendor commands data
  161. else if (scsiDev.cdb[0] == 0x0C || scsiDev.cdb[0] == 0x0F)
  162. g_LogData = true;
  163. else
  164. debuglog("---- DATA_OUT");
  165. break;
  166. case MESSAGE_IN:
  167. debuglog("---- MESSAGE_IN");
  168. g_LogData = true;
  169. break;
  170. case MESSAGE_OUT:
  171. debuglog("---- MESSAGE_OUT");
  172. g_LogData = true;
  173. break;
  174. default:
  175. debuglog("---- PHASE: ", phase);
  176. break;
  177. }
  178. }
  179. void scsiLogPhaseChange(int new_phase)
  180. {
  181. static int old_scsi_id = 0;
  182. static int old_phase = BUS_FREE;
  183. static int old_sync_period = 0;
  184. if (new_phase != old_phase)
  185. {
  186. if (old_phase == DATA_IN || old_phase == DATA_OUT)
  187. {
  188. debuglog("---- Total IN: ", g_InByteCount, " OUT: ", g_OutByteCount, " CHECKSUM: ", (int)g_DataChecksum);
  189. }
  190. // log Xebec vendor command
  191. if (old_phase == DATA_OUT && scsiDev.cdb[0] == 0x0C && g_OutByteCount == 8)
  192. {
  193. int cylinders = ((uint16_t)scsiDev.data[0] << 8) + scsiDev.data[1];
  194. int heads = scsiDev.data[2];
  195. int reducedWrite = ((uint16_t)scsiDev.data[3] << 8) + scsiDev.data[4];
  196. int writePrecomp = ((uint16_t)scsiDev.data[5] << 8) + scsiDev.data[6];
  197. int eccBurst = scsiDev.data[7];
  198. debuglog("---- Xebec Initialize Drive Characteristics: cylinders=", cylinders, " heads=", heads,
  199. " reducedWrite=", reducedWrite, " writePrecomp=", writePrecomp, " eccBurst=", eccBurst);
  200. }
  201. g_InByteCount = g_OutByteCount = 0;
  202. g_DataChecksum = 0;
  203. if (old_phase >= 0 &&
  204. scsiDev.target != NULL &&
  205. old_scsi_id == scsiDev.target->targetId &&
  206. old_sync_period != scsiDev.target->syncPeriod)
  207. {
  208. // Add a log message when negotiated synchronous speed changes.
  209. int syncper = scsiDev.target->syncPeriod;
  210. int syncoff = scsiDev.target->syncOffset;
  211. if (syncper > 0)
  212. {
  213. int mbyte_per_s = (1000 + syncper * 2) / (syncper * 4);
  214. log("SCSI ID ", (int)scsiDev.target->targetId,
  215. " negotiated synchronous mode ", mbyte_per_s, " MB/s ",
  216. "(period 4x", syncper, " ns, offset ", syncoff, " bytes)");
  217. }
  218. else
  219. {
  220. log("SCSI ID ", (int)scsiDev.target->targetId,
  221. " negotiated asynchronous mode ",
  222. "(period 4x", syncper, " ns, offset ", syncoff, " bytes)");
  223. }
  224. }
  225. printNewPhase(new_phase);
  226. old_phase = new_phase;
  227. old_sync_period = scsiDev.target->syncPeriod;
  228. old_scsi_id = scsiDev.target->targetId;
  229. }
  230. }
  231. void scsiLogInitiatorPhaseChange(int new_phase)
  232. {
  233. static int old_phase = BUS_FREE;
  234. if (new_phase != old_phase)
  235. {
  236. if (old_phase == DATA_IN || old_phase == DATA_OUT)
  237. {
  238. debuglog("---- Total IN: ", g_InByteCount, " OUT: ", g_OutByteCount, " CHECKSUM: ", (int)g_DataChecksum);
  239. }
  240. g_InByteCount = g_OutByteCount = 0;
  241. g_DataChecksum = 0;
  242. printNewPhase(new_phase, true);
  243. old_phase = new_phase;
  244. }
  245. }
  246. void scsiLogDataIn(const uint8_t *buf, uint32_t length)
  247. {
  248. if (g_LogData)
  249. {
  250. debuglog("------ IN: ", bytearray(buf, length));
  251. }
  252. if (g_log_debug)
  253. {
  254. // BSD checksum algorithm
  255. for (uint32_t i = 0; i < length; i++)
  256. {
  257. g_DataChecksum = (g_DataChecksum >> 1) + ((g_DataChecksum & 1) << 15);
  258. g_DataChecksum += buf[i];
  259. }
  260. }
  261. g_InByteCount += length;
  262. }
  263. void scsiLogDataOut(const uint8_t *buf, uint32_t length)
  264. {
  265. if (buf == scsiDev.cdb || g_LogInitiatorCommand)
  266. {
  267. debuglog("---- COMMAND: ", getCommandName(buf[0]));
  268. }
  269. if (g_LogData)
  270. {
  271. debuglog("------ OUT: ", bytearray(buf, length));
  272. }
  273. if (g_log_debug)
  274. {
  275. // BSD checksum algorithm
  276. for (uint32_t i = 0; i < length; i++)
  277. {
  278. g_DataChecksum = (g_DataChecksum >> 1) + ((g_DataChecksum & 1) << 15);
  279. g_DataChecksum += buf[i];
  280. }
  281. }
  282. g_OutByteCount += length;
  283. }