ZuluSCSI_log_trace.cpp 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. /**
  2. * ZuluSCSI™ - Copyright (c) 2022 Rabbit Hole Computing™
  3. *
  4. * ZuluSCSI™ firmware is licensed under the GPL version 3 or any later version. 
  5. *
  6. * https://www.gnu.org/licenses/gpl-3.0.html
  7. * ----
  8. * This program is free software: you can redistribute it and/or modify
  9. * it under the terms of the GNU General Public License as published by
  10. * the Free Software Foundation, either version 3 of the License, or
  11. * (at your option) any later version. 
  12. *
  13. * This program is distributed in the hope that it will be useful,
  14. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  16. * GNU General Public License for more details. 
  17. *
  18. * You should have received a copy of the GNU General Public License
  19. * along with this program.  If not, see <https://www.gnu.org/licenses/>.
  20. **/
  21. // SCSI trace logging
  22. #include "ZuluSCSI_log_trace.h"
  23. #include "ZuluSCSI_log.h"
  24. #include <scsi2sd.h>
  25. extern "C" {
  26. #include <scsi.h>
  27. #include <scsiPhy.h>
  28. }
  29. static bool g_LogData = false;
  30. static bool g_LogInitiatorCommand = false;
  31. static int g_InByteCount = 0;
  32. static int g_OutByteCount = 0;
  33. static uint16_t g_DataChecksum = 0;
  34. static const char *getCommandName(uint8_t cmd)
  35. {
  36. switch (cmd)
  37. {
  38. case 0x00: return "TestUnitReady";
  39. case 0x01: return "RezeroUnit/Rewind";
  40. case 0x03: return "RequestSense";
  41. case 0x04: return "FormatUnit";
  42. case 0x05: return "ReadBlockLimits";
  43. case 0x08: return "Read6";
  44. case 0x0A: return "Write6";
  45. case 0x0B: return "Seek6";
  46. case 0x0F: return "WriteSectorBuffer";
  47. case 0x10: return "WriteFilemarks";
  48. case 0x11: return "Space";
  49. case 0x12: return "Inquiry";
  50. case 0x13: return "Verify";
  51. case 0x15: return "ModeSelect6";
  52. case 0x16: return "Reserve";
  53. case 0x17: return "Release";
  54. case 0x19: return "Erase";
  55. case 0x1A: return "ModeSense";
  56. case 0x1B: return "StartStopUnit";
  57. case 0x1C: return "ReceiveDiagnostic";
  58. case 0x1D: return "SendDiagnostic";
  59. case 0x1E: return "PreventAllowMediumRemoval";
  60. case 0x25: return "ReadCapacity";
  61. case 0x28: return "Read10";
  62. case 0x2A: return "Write10";
  63. case 0x2B: return "Seek10";
  64. case 0x2C: return "Erase10";
  65. case 0x2E: return "WriteVerify";
  66. case 0x2F: return "Verify";
  67. case 0x34: return "PreFetch/ReadPosition";
  68. case 0x35: return "SynchronizeCache";
  69. case 0x36: return "LockUnlockCache";
  70. case 0x37: return "ReadDefectData";
  71. case 0x3B: return "WriteBuffer";
  72. case 0x3C: return "ReadBuffer";
  73. case 0x42: return "CDROM Read SubChannel";
  74. case 0x43: return "CDROM Read TOC";
  75. case 0x44: return "CDROM Read Header";
  76. case 0x46: return "CDROM GetConfiguration";
  77. case 0x4A: return "GetEventStatusNotification";
  78. case 0x4B: return "CDROM PauseResume";
  79. case 0x4E: return "CDROM StopPlayScan";
  80. case 0x51: return "CDROM ReadDiscInformation";
  81. case 0x45: return "CDROM PlayAudio10";
  82. case 0xA5: return "CDROM PlayAudio12";
  83. case 0x47: return "CDROM PlayAudioMSF";
  84. case 0x48: return "CDROM PauseResume";
  85. case 0x52: return "CDROM ReadTrackInformation";
  86. case 0xBB: return "CDROM SetCDSpeed";
  87. case 0xBD: return "CDROM MechanismStatus";
  88. case 0xBE: return "ReadCD";
  89. case 0xB9: return "ReadCDMSF";
  90. case 0x55: return "ModeSelect10";
  91. case 0x5A: return "ModeSense10";
  92. case 0xAC: return "Erase12";
  93. case 0xA8: return "Read12";
  94. case 0xC0: return "OMTI-5204 DefineFlexibleDiskFormat";
  95. case 0xC2: return "OMTI-5204 AssignDiskParameters";
  96. default: return "Unknown";
  97. }
  98. }
  99. static void printNewPhase(int phase, bool initiator = false)
  100. {
  101. g_LogData = false;
  102. g_LogInitiatorCommand = false;
  103. if (!g_log_debug)
  104. {
  105. return;
  106. }
  107. switch(phase)
  108. {
  109. case BUS_FREE:
  110. dbgmsg("-- BUS_FREE");
  111. break;
  112. case BUS_BUSY:
  113. dbgmsg("-- BUS_BUSY");
  114. break;
  115. case ARBITRATION:
  116. dbgmsg("---- ARBITRATION");
  117. break;
  118. case SELECTION:
  119. if (initiator)
  120. dbgmsg("---- SELECTION");
  121. else
  122. dbgmsg("---- SELECTION: ", (int)(*SCSI_STS_SELECTED & 7));
  123. break;
  124. case RESELECTION:
  125. dbgmsg("---- RESELECTION");
  126. break;
  127. case STATUS:
  128. if (initiator)
  129. {
  130. dbgmsg("---- STATUS");
  131. g_LogData = true;
  132. }
  133. else if (scsiDev.status == GOOD)
  134. {
  135. dbgmsg("---- STATUS: 0 GOOD");
  136. }
  137. else if (scsiDev.status == CHECK_CONDITION && scsiDev.target)
  138. {
  139. dbgmsg("---- STATUS: 2 CHECK_CONDITION, sense ", (uint32_t)scsiDev.target->sense.asc);
  140. }
  141. else
  142. {
  143. dbgmsg("---- STATUS: ", (int)scsiDev.status);
  144. }
  145. break;
  146. case COMMAND:
  147. g_LogInitiatorCommand = initiator;
  148. g_LogData = true;
  149. break;
  150. case DATA_IN:
  151. if (!initiator && scsiDev.target->syncOffset > 0)
  152. dbgmsg("---- DATA_IN, syncOffset ", (int)scsiDev.target->syncOffset,
  153. " syncPeriod ", (int)scsiDev.target->syncPeriod);
  154. else
  155. dbgmsg("---- DATA_IN");
  156. break;
  157. case DATA_OUT:
  158. if (!initiator && scsiDev.target->syncOffset > 0)
  159. dbgmsg("---- DATA_OUT, syncOffset ", (int)scsiDev.target->syncOffset,
  160. " syncPeriod ", (int)scsiDev.target->syncPeriod);
  161. else
  162. dbgmsg("---- DATA_OUT");
  163. break;
  164. case MESSAGE_IN:
  165. dbgmsg("---- MESSAGE_IN");
  166. g_LogData = true;
  167. break;
  168. case MESSAGE_OUT:
  169. dbgmsg("---- MESSAGE_OUT");
  170. g_LogData = true;
  171. break;
  172. default:
  173. dbgmsg("---- PHASE: ", phase);
  174. break;
  175. }
  176. }
  177. void scsiLogPhaseChange(int new_phase)
  178. {
  179. static int old_scsi_id = 0;
  180. static int old_phase = BUS_FREE;
  181. static int old_sync_period = 0;
  182. if (new_phase != old_phase)
  183. {
  184. if (old_phase == DATA_IN || old_phase == DATA_OUT)
  185. {
  186. dbgmsg("---- Total IN: ", g_InByteCount, " OUT: ", g_OutByteCount, " CHECKSUM: ", (int)g_DataChecksum);
  187. }
  188. g_InByteCount = g_OutByteCount = 0;
  189. g_DataChecksum = 0;
  190. if (old_phase >= 0 &&
  191. scsiDev.target != NULL &&
  192. old_scsi_id == scsiDev.target->targetId &&
  193. old_sync_period != scsiDev.target->syncPeriod)
  194. {
  195. // Add a log message when negotiated synchronous speed changes.
  196. int syncper = scsiDev.target->syncPeriod;
  197. int syncoff = scsiDev.target->syncOffset;
  198. if (syncper > 0)
  199. {
  200. int mbyte_per_s = (1000 + syncper * 2) / (syncper * 4);
  201. logmsg("SCSI ID ", (int)scsiDev.target->targetId,
  202. " negotiated synchronous mode ", mbyte_per_s, " MB/s ",
  203. "(period 4x", syncper, " ns, offset ", syncoff, " bytes)");
  204. }
  205. else
  206. {
  207. logmsg("SCSI ID ", (int)scsiDev.target->targetId,
  208. " negotiated asynchronous mode ",
  209. "(period 4x", syncper, " ns, offset ", syncoff, " bytes)");
  210. }
  211. }
  212. printNewPhase(new_phase);
  213. old_phase = new_phase;
  214. old_sync_period = scsiDev.target->syncPeriod;
  215. old_scsi_id = scsiDev.target->targetId;
  216. }
  217. }
  218. void scsiLogInitiatorPhaseChange(int new_phase)
  219. {
  220. static int old_phase = BUS_FREE;
  221. if (new_phase != old_phase)
  222. {
  223. if (old_phase == DATA_IN || old_phase == DATA_OUT)
  224. {
  225. dbgmsg("---- Total IN: ", g_InByteCount, " OUT: ", g_OutByteCount, " CHECKSUM: ", (int)g_DataChecksum);
  226. }
  227. g_InByteCount = g_OutByteCount = 0;
  228. g_DataChecksum = 0;
  229. printNewPhase(new_phase, true);
  230. old_phase = new_phase;
  231. }
  232. }
  233. void scsiLogDataIn(const uint8_t *buf, uint32_t length)
  234. {
  235. if (g_LogData)
  236. {
  237. dbgmsg("------ IN: ", bytearray(buf, length));
  238. }
  239. if (g_log_debug)
  240. {
  241. // BSD checksum algorithm
  242. for (uint32_t i = 0; i < length; i++)
  243. {
  244. g_DataChecksum = (g_DataChecksum >> 1) + ((g_DataChecksum & 1) << 15);
  245. g_DataChecksum += buf[i];
  246. }
  247. }
  248. g_InByteCount += length;
  249. }
  250. void scsiLogDataOut(const uint8_t *buf, uint32_t length)
  251. {
  252. if (buf == scsiDev.cdb || g_LogInitiatorCommand)
  253. {
  254. dbgmsg("---- COMMAND: ", getCommandName(buf[0]));
  255. }
  256. if (g_LogData)
  257. {
  258. dbgmsg("------ OUT: ", bytearray(buf, length));
  259. }
  260. if (g_log_debug)
  261. {
  262. // BSD checksum algorithm
  263. for (uint32_t i = 0; i < length; i++)
  264. {
  265. g_DataChecksum = (g_DataChecksum >> 1) + ((g_DataChecksum & 1) << 15);
  266. g_DataChecksum += buf[i];
  267. }
  268. }
  269. g_OutByteCount += length;
  270. }