scsiHostPhy.cpp 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215
  1. #include "scsiHostPhy.h"
  2. #include "ZuluSCSI_platform.h"
  3. #include "ZuluSCSI_log.h"
  4. #include "ZuluSCSI_log_trace.h"
  5. #include <assert.h>
  6. #include <scsi2sd.h>
  7. extern "C" {
  8. #include <scsi.h>
  9. }
  10. volatile bool g_scsiHostPhyReset;
  11. // Release bus and pulse RST signal, initialize PHY to host mode.
  12. void scsiHostPhyReset(void)
  13. {
  14. SCSI_RELEASE_OUTPUTS();
  15. SCSI_ENABLE_INITIATOR();
  16. SCSI_OUT(RST, 1);
  17. delay(2);
  18. SCSI_OUT(RST, 0);
  19. delay(250);
  20. g_scsiHostPhyReset = false;
  21. }
  22. // Select a device, id 0-7.
  23. // Returns true if the target answers to selection request.
  24. bool scsiHostPhySelect(int target_id)
  25. {
  26. SCSI_RELEASE_OUTPUTS();
  27. // We can't write individual data bus bits, so use a bit modified
  28. // arbitration scheme. We always yield to any other initiator on
  29. // the bus.
  30. scsiLogInitiatorPhaseChange(BUS_BUSY);
  31. SCSI_OUT(BSY, 1);
  32. for (int wait = 0; wait < 10; wait++)
  33. {
  34. delayMicroseconds(1);
  35. if (SCSI_IN_DATA() != 0)
  36. {
  37. azdbg("scsiHostPhySelect: bus is busy");
  38. scsiLogInitiatorPhaseChange(BUS_FREE);
  39. SCSI_RELEASE_OUTPUTS();
  40. return false;
  41. }
  42. }
  43. // Selection phase
  44. scsiLogInitiatorPhaseChange(SELECTION);
  45. azdbg("------ SELECTING ", target_id);
  46. SCSI_OUT(SEL, 1);
  47. delayMicroseconds(5);
  48. SCSI_OUT_DATA(1 << target_id);
  49. delayMicroseconds(5);
  50. SCSI_OUT(BSY, 0);
  51. // Wait for target to respond
  52. for (int wait = 0; wait < 2500; wait++)
  53. {
  54. delayMicroseconds(100);
  55. if (SCSI_IN(BSY))
  56. {
  57. break;
  58. }
  59. }
  60. if (!SCSI_IN(BSY))
  61. {
  62. // No response
  63. SCSI_RELEASE_OUTPUTS();
  64. return false;
  65. }
  66. // We need to assert OUT_BSY to enable IO buffer U105 to read status signals.
  67. SCSI_RELEASE_DATA_REQ();
  68. SCSI_OUT(BSY, 1);
  69. SCSI_OUT(SEL, 0);
  70. return true;
  71. }
  72. // Read the current communication phase as signaled by the target
  73. int scsiHostPhyGetPhase()
  74. {
  75. static absolute_time_t last_online_time;
  76. if (g_scsiHostPhyReset)
  77. {
  78. // Reset request from watchdog timer
  79. scsiHostPhyRelease();
  80. return BUS_FREE;
  81. }
  82. int phase = 0;
  83. bool req_in = SCSI_IN(REQ);
  84. if (SCSI_IN(CD)) phase |= __scsiphase_cd;
  85. if (SCSI_IN(IO)) phase |= __scsiphase_io;
  86. if (SCSI_IN(MSG)) phase |= __scsiphase_msg;
  87. if (phase == 0 && absolute_time_diff_us(last_online_time, get_absolute_time()) > 100)
  88. {
  89. // Disable OUT_BSY for a short time to see if the target is still on line
  90. SCSI_OUT(BSY, 0);
  91. delay_100ns();
  92. if (!SCSI_IN(BSY))
  93. {
  94. scsiLogInitiatorPhaseChange(BUS_FREE);
  95. return BUS_FREE;
  96. }
  97. // Still online, re-enable OUT_BSY to enable IO buffers
  98. SCSI_OUT(BSY, 1);
  99. }
  100. last_online_time = get_absolute_time();
  101. if (!req_in)
  102. {
  103. // Don't act on phase changes until target asserts request signal.
  104. // This filters out any spurious changes on control signals.
  105. return BUS_BUSY;
  106. }
  107. else
  108. {
  109. scsiLogInitiatorPhaseChange(phase);
  110. return phase;
  111. }
  112. }
  113. bool scsiHostRequestWaiting()
  114. {
  115. return SCSI_IN(REQ);
  116. }
  117. // Blocking data transfer
  118. #define SCSIHOST_WAIT_ACTIVE(pin) \
  119. if (!SCSI_IN(pin)) { \
  120. if (!SCSI_IN(pin)) { \
  121. while(!SCSI_IN(pin) && !g_scsiHostPhyReset); \
  122. } \
  123. }
  124. #define SCSIHOST_WAIT_INACTIVE(pin) \
  125. if (SCSI_IN(pin)) { \
  126. if (SCSI_IN(pin)) { \
  127. while(SCSI_IN(pin) && !g_scsiHostPhyReset); \
  128. } \
  129. }
  130. // Write one byte to SCSI target using the handshake mechanism
  131. static inline void scsiHostWriteOneByte(uint8_t value)
  132. {
  133. SCSIHOST_WAIT_ACTIVE(REQ);
  134. SCSI_OUT_DATA(value);
  135. delay_100ns(); // DB setup time before ACK
  136. SCSI_OUT(ACK, 1);
  137. SCSIHOST_WAIT_INACTIVE(REQ);
  138. SCSI_RELEASE_DATA_REQ();
  139. SCSI_OUT(ACK, 0);
  140. }
  141. // Read one byte from SCSI target using the handshake mechanism.
  142. static inline uint8_t scsiHostReadOneByte(int* parityError)
  143. {
  144. SCSIHOST_WAIT_ACTIVE(REQ);
  145. uint16_t r = SCSI_IN_DATA();
  146. SCSI_OUT(ACK, 1);
  147. SCSIHOST_WAIT_INACTIVE(REQ);
  148. SCSI_OUT(ACK, 0);
  149. if (parityError && r != (g_scsi_parity_lookup[r & 0xFF] ^ SCSI_IO_DATA_MASK))
  150. {
  151. azlog("Parity error in scsiReadOneByte(): ", (uint32_t)r);
  152. *parityError = 1;
  153. }
  154. return (uint8_t)r;
  155. }
  156. bool scsiHostWrite(const uint8_t *data, uint32_t count)
  157. {
  158. scsiLogDataOut(data, count);
  159. for (uint32_t i = 0; i < count; i++)
  160. {
  161. if (g_scsiHostPhyReset) return false;
  162. scsiHostWriteOneByte(data[i]);
  163. }
  164. return true;
  165. }
  166. bool scsiHostRead(uint8_t *data, uint32_t count)
  167. {
  168. for (uint32_t i = 0; i < count; i++)
  169. {
  170. if (g_scsiHostPhyReset) return false;
  171. data[i] = scsiHostReadOneByte(NULL);
  172. }
  173. scsiLogDataIn(data, count);
  174. return true;
  175. }
  176. // Release all bus signals
  177. void scsiHostPhyRelease()
  178. {
  179. scsiLogInitiatorPhaseChange(BUS_FREE);
  180. SCSI_RELEASE_OUTPUTS();
  181. }