| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- #include "scsiHostPhy.h"
- #include "ZuluSCSI_platform.h"
- #include "ZuluSCSI_log.h"
- #include "ZuluSCSI_log_trace.h"
- #include <assert.h>
- #include <scsi2sd.h>
- extern "C" {
- #include <scsi.h>
- }
- volatile bool g_scsiHostPhyReset;
- // Release bus and pulse RST signal, initialize PHY to host mode.
- void scsiHostPhyReset(void)
- {
- SCSI_RELEASE_OUTPUTS();
- SCSI_ENABLE_INITIATOR();
- SCSI_OUT(RST, 1);
- delay(2);
- SCSI_OUT(RST, 0);
- delay(250);
- g_scsiHostPhyReset = false;
- }
- // Select a device, id 0-7.
- // Returns true if the target answers to selection request.
- bool scsiHostPhySelect(int target_id)
- {
- SCSI_RELEASE_OUTPUTS();
- // We can't write individual data bus bits, so use a bit modified
- // arbitration scheme. We always yield to any other initiator on
- // the bus.
- scsiLogInitiatorPhaseChange(BUS_BUSY);
- SCSI_OUT(BSY, 1);
- for (int wait = 0; wait < 10; wait++)
- {
- delayMicroseconds(1);
- if (SCSI_IN_DATA() != 0)
- {
- azdbg("scsiHostPhySelect: bus is busy");
- scsiLogInitiatorPhaseChange(BUS_FREE);
- SCSI_RELEASE_OUTPUTS();
- return false;
- }
- }
- // Selection phase
- scsiLogInitiatorPhaseChange(SELECTION);
- azdbg("------ SELECTING ", target_id);
- SCSI_OUT(SEL, 1);
- delayMicroseconds(5);
- SCSI_OUT_DATA(1 << target_id);
- delayMicroseconds(5);
- SCSI_OUT(BSY, 0);
- // Wait for target to respond
- for (int wait = 0; wait < 250; wait++)
- {
- delayMicroseconds(1000);
- if (SCSI_IN(BSY))
- {
- break;
- }
- }
- if (!SCSI_IN(BSY))
- {
- // No response
- SCSI_RELEASE_OUTPUTS();
- return false;
- }
- // We need to assert OUT_BSY to enable IO buffer U105 to read status signals.
- SCSI_OUT(BSY, 1);
- SCSI_OUT(SEL, 0);
- return true;
- }
- // Read the current communication phase as signaled by the target
- int scsiHostPhyGetPhase()
- {
- // Disable OUT_BSY for a short time to see if the target is still on line
- SCSI_OUT(BSY, 0);
- delay_100ns();
- if (!SCSI_IN(BSY))
- {
- scsiLogInitiatorPhaseChange(BUS_FREE);
- return BUS_FREE;
- }
- // Re-enable OUT_BSY to read signal states
- SCSI_OUT(BSY, 1);
- delay_100ns();
- int phase = 0;
- if (SCSI_IN(CD)) phase |= __scsiphase_cd;
- if (SCSI_IN(IO)) phase |= __scsiphase_io;
- if (SCSI_IN(MSG)) phase |= __scsiphase_msg;
- scsiLogInitiatorPhaseChange(phase);
- return phase;
- }
- bool scsiHostRequestWaiting()
- {
- return SCSI_IN(REQ);
- }
- // Blocking data transfer
- #define SCSIHOST_WAIT_ACTIVE(pin) \
- if (!SCSI_IN(pin)) { \
- if (!SCSI_IN(pin)) { \
- while(!SCSI_IN(pin) && !g_scsiHostPhyReset); \
- } \
- }
- #define SCSIHOST_WAIT_INACTIVE(pin) \
- if (SCSI_IN(pin)) { \
- if (SCSI_IN(pin)) { \
- while(SCSI_IN(pin) && !g_scsiHostPhyReset); \
- } \
- }
- // Write one byte to SCSI target using the handshake mechanism
- static inline void scsiHostWriteOneByte(uint8_t value)
- {
- SCSIHOST_WAIT_ACTIVE(REQ);
- SCSI_OUT_DATA(value);
- delay_100ns(); // DB setup time before ACK
- SCSI_OUT(ACK, 1);
- SCSIHOST_WAIT_INACTIVE(REQ);
- SCSI_RELEASE_DATA_REQ();
- SCSI_OUT(ACK, 0);
- }
- // Read one byte from SCSI target using the handshake mechanism.
- static inline uint8_t scsiHostReadOneByte(int* parityError)
- {
- SCSIHOST_WAIT_ACTIVE(REQ);
- uint16_t r = SCSI_IN_DATA();
- SCSI_OUT(ACK, 1);
- SCSIHOST_WAIT_INACTIVE(REQ);
- SCSI_OUT(ACK, 0);
- if (parityError && r != (g_scsi_parity_lookup[r & 0xFF] ^ SCSI_IO_DATA_MASK))
- {
- azlog("Parity error in scsiReadOneByte(): ", (uint32_t)r);
- *parityError = 1;
- }
- return (uint8_t)r;
- }
- bool scsiHostWrite(const uint8_t *data, uint32_t count)
- {
- scsiLogDataOut(data, count);
- for (uint32_t i = 0; i < count; i++)
- {
- if (g_scsiHostPhyReset) return false;
- scsiHostWriteOneByte(data[i]);
- }
- return true;
- }
- bool scsiHostRead(uint8_t *data, uint32_t count)
- {
- for (uint32_t i = 0; i < count; i++)
- {
- if (g_scsiHostPhyReset) return false;
- data[i] = scsiHostReadOneByte(NULL);
- }
- scsiLogDataIn(data, count);
- return true;
- }
- // Release all bus signals
- void scsiHostPhyRelease()
- {
- scsiLogInitiatorPhaseChange(BUS_FREE);
- SCSI_RELEASE_OUTPUTS();
- }
|