scsiHostPhy.cpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  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 < 250; wait++)
  53. {
  54. delayMicroseconds(1000);
  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_OUT(BSY, 1);
  68. SCSI_OUT(SEL, 0);
  69. return true;
  70. }
  71. // Read the current communication phase as signaled by the target
  72. int scsiHostPhyGetPhase()
  73. {
  74. // Disable OUT_BSY for a short time to see if the target is still on line
  75. SCSI_OUT(BSY, 0);
  76. delay_100ns();
  77. if (!SCSI_IN(BSY))
  78. {
  79. scsiLogInitiatorPhaseChange(BUS_FREE);
  80. return BUS_FREE;
  81. }
  82. // Re-enable OUT_BSY to read signal states
  83. SCSI_OUT(BSY, 1);
  84. delay_100ns();
  85. int phase = 0;
  86. if (SCSI_IN(CD)) phase |= __scsiphase_cd;
  87. if (SCSI_IN(IO)) phase |= __scsiphase_io;
  88. if (SCSI_IN(MSG)) phase |= __scsiphase_msg;
  89. scsiLogInitiatorPhaseChange(phase);
  90. return phase;
  91. }
  92. bool scsiHostRequestWaiting()
  93. {
  94. return SCSI_IN(REQ);
  95. }
  96. // Blocking data transfer
  97. #define SCSIHOST_WAIT_ACTIVE(pin) \
  98. if (!SCSI_IN(pin)) { \
  99. if (!SCSI_IN(pin)) { \
  100. while(!SCSI_IN(pin) && !g_scsiHostPhyReset); \
  101. } \
  102. }
  103. #define SCSIHOST_WAIT_INACTIVE(pin) \
  104. if (SCSI_IN(pin)) { \
  105. if (SCSI_IN(pin)) { \
  106. while(SCSI_IN(pin) && !g_scsiHostPhyReset); \
  107. } \
  108. }
  109. // Write one byte to SCSI target using the handshake mechanism
  110. static inline void scsiHostWriteOneByte(uint8_t value)
  111. {
  112. SCSIHOST_WAIT_ACTIVE(REQ);
  113. SCSI_OUT_DATA(value);
  114. delay_100ns(); // DB setup time before ACK
  115. SCSI_OUT(ACK, 1);
  116. SCSIHOST_WAIT_INACTIVE(REQ);
  117. SCSI_RELEASE_DATA_REQ();
  118. SCSI_OUT(ACK, 0);
  119. }
  120. // Read one byte from SCSI target using the handshake mechanism.
  121. static inline uint8_t scsiHostReadOneByte(int* parityError)
  122. {
  123. SCSIHOST_WAIT_ACTIVE(REQ);
  124. uint16_t r = SCSI_IN_DATA();
  125. SCSI_OUT(ACK, 1);
  126. SCSIHOST_WAIT_INACTIVE(REQ);
  127. SCSI_OUT(ACK, 0);
  128. if (parityError && r != (g_scsi_parity_lookup[r & 0xFF] ^ SCSI_IO_DATA_MASK))
  129. {
  130. azlog("Parity error in scsiReadOneByte(): ", (uint32_t)r);
  131. *parityError = 1;
  132. }
  133. return (uint8_t)r;
  134. }
  135. bool scsiHostWrite(const uint8_t *data, uint32_t count)
  136. {
  137. scsiLogDataOut(data, count);
  138. for (uint32_t i = 0; i < count; i++)
  139. {
  140. if (g_scsiHostPhyReset) return false;
  141. scsiHostWriteOneByte(data[i]);
  142. }
  143. return true;
  144. }
  145. bool scsiHostRead(uint8_t *data, uint32_t count)
  146. {
  147. for (uint32_t i = 0; i < count; i++)
  148. {
  149. if (g_scsiHostPhyReset) return false;
  150. data[i] = scsiHostReadOneByte(NULL);
  151. }
  152. scsiLogDataIn(data, count);
  153. return true;
  154. }
  155. // Release all bus signals
  156. void scsiHostPhyRelease()
  157. {
  158. scsiLogInitiatorPhaseChange(BUS_FREE);
  159. SCSI_RELEASE_OUTPUTS();
  160. }