e49629655eeb4f316ae092c98f542953b09fd654
[SCSI2SD-V6.git] / src / firmware / scsiPhy.c
1 // Copyright (C) 2013 Michael McMaster <michael@codesrc.com>
2 //
3 // This file is part of SCSI2SD.
4 //
5 // SCSI2SD is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // SCSI2SD is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with SCSI2SD. If not, see <http://www.gnu.org/licenses/>.
17
18 #include "stm32f2xx.h"
19 #include "stm32f2xx_hal.h"
20 #include "stm32f2xx_hal_dma.h"
21
22 #include "scsi.h"
23 #include "scsiPhy.h"
24 #include "trace.h"
25 #include "time.h"
26 #include "fpga.h"
27 #include "led.h"
28
29 #include <string.h>
30
31 // 5MB/s sync and async.
32 // Assumes a 96MHz fpga clock.
33 // 2:0 Deskew count, 55ns
34 // 6:4 Hold count, 53ns
35 // 3:0 Assertion count, 80ns
36 #define SCSI_DEFAULT_DESKEW 0x6
37 #define SCSI_DEFAULT_TIMING ((0x5 << 4) | 0x8)
38
39 // 10MB/s
40 // 2:0 Deskew count, 25ns
41 // 6:4 Hold count, 33ns
42 // 3:0 Assertion count, 30ns
43 #define SCSI_FAST10_DESKEW 3
44 #define SCSI_FAST10_TIMING ((0x3 << 4) | 0x3)
45
46 // 20MB/s
47 // 2:0 Deskew count, 12ns
48 // 6:4 Hold count, 17ns
49 // 3:0 Assertion count, 15ns
50 #define SCSI_FAST20_DESKEW 2
51 #define SCSI_FAST20_TIMING ((0x2 << 4) | 0x2)
52
53 // Private DMA variables.
54 static int dmaInProgress = 0;
55
56 static DMA_HandleTypeDef memToFSMC;
57 static DMA_HandleTypeDef fsmcToMem;
58
59
60 volatile uint8_t scsiRxDMAComplete;
61 volatile uint8_t scsiTxDMAComplete;
62
63 #if 0
64 CY_ISR_PROTO(scsiRxCompleteISR);
65 CY_ISR(scsiRxCompleteISR)
66 {
67 traceIrq(trace_scsiRxCompleteISR);
68 scsiRxDMAComplete = 1;
69 }
70
71 CY_ISR_PROTO(scsiTxCompleteISR);
72 CY_ISR(scsiTxCompleteISR)
73 {
74 traceIrq(trace_scsiTxCompleteISR);
75 scsiTxDMAComplete = 1;
76 }
77 #endif
78
79 uint8_t scsiPhyFifoSel = 0; // global
80
81 // scsi IRQ handler is initialised by the STM32 HAL. Connected to
82 // PE4
83 // Note: naming is important to ensure this function is listed in the
84 // vector table.
85 void EXTI4_IRQHandler()
86 {
87 traceIrq(trace_scsiResetISR);
88
89 // Make sure that interrupt flag is set
90 if (__HAL_GPIO_EXTI_GET_IT(GPIO_PIN_4) != RESET) {
91
92 // Clear interrupt flag
93 __HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_4);
94
95 scsiDev.resetFlag = scsiDev.resetFlag || scsiStatusRST();
96 // TODO grab SEL status as well
97
98 }
99 }
100
101 static void assertFail()
102 {
103 while (1)
104 {
105 s2s_ledOn();
106 s2s_delay_ms(100);
107 s2s_ledOff();
108 s2s_delay_ms(100);
109 }
110 }
111
112 void
113 scsiSetDataCount(uint32_t count)
114 {
115 *SCSI_DATA_CNT_HI = count >> 8;
116 *SCSI_DATA_CNT_LO = count & 0xff;
117 *SCSI_DATA_CNT_SET = 1;
118 }
119
120 uint8_t
121 scsiReadByte(void)
122 {
123 #if FIFODEBUG
124 if (!scsiPhyFifoAltEmpty()) {
125 // Force a lock-up.
126 assertFail();
127 }
128 #endif
129 scsiSetDataCount(1);
130
131 trace(trace_spinPhyRxFifo);
132 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}
133 scsiPhyFifoFlip();
134 uint8_t val = scsiPhyRx();
135 // TODO scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();
136
137 #if FIFODEBUG
138 if (!scsiPhyFifoEmpty()) {
139 int j = 0;
140 uint8_t k __attribute((unused));
141 while (!scsiPhyFifoEmpty()) { k = scsiPhyRx(); ++j; }
142
143 // Force a lock-up.
144 assertFail();
145 }
146 #endif
147 return val;
148 }
149
150
151 static void
152 scsiReadPIO(uint8_t* data, uint32_t count)
153 {
154 uint16_t* fifoData = (uint16_t*)data;
155 for (int i = 0; i < (count + 1) / 2; ++i)
156 {
157 fifoData[i] = scsiPhyRx(); // TODO ASSUMES LITTLE ENDIAN
158 }
159 }
160
161 void
162 scsiReadDMA(uint8_t* data, uint32_t count)
163 {
164 // Prepare DMA transfer
165 dmaInProgress = 1;
166 trace(trace_doRxSingleDMA);
167
168 scsiTxDMAComplete = 1; // TODO not used much
169 scsiRxDMAComplete = 0; // TODO not used much
170
171 HAL_DMA_Start(
172 &fsmcToMem,
173 (uint32_t) SCSI_FIFO_DATA,
174 (uint32_t) data,
175 (count + 1) / 2);
176 }
177
178 int
179 scsiReadDMAPoll()
180 {
181 int complete = __HAL_DMA_GET_COUNTER(&fsmcToMem) == 0;
182 complete = complete && (HAL_DMA_PollForTransfer(&fsmcToMem, HAL_DMA_FULL_TRANSFER, 0xffffffff) == HAL_OK);
183 if (complete)
184 {
185 scsiTxDMAComplete = 1; // TODO MM FIX IRQ
186 scsiRxDMAComplete = 1;
187
188 dmaInProgress = 0;
189 #if 0
190 // TODO MM scsiDev.parityError = scsiDev.parityError || SCSI_Parity_Error_Read();
191 #endif
192 return 1;
193
194 }
195 else
196 {
197 return 0;
198 }
199 }
200
201 void
202 scsiRead(uint8_t* data, uint32_t count, int* parityError)
203 {
204 int i = 0;
205 *parityError = 0;
206
207
208 uint32_t chunk = ((count - i) > SCSI_FIFO_DEPTH)
209 ? SCSI_FIFO_DEPTH : (count - i);
210 #ifdef SCSI_FSMC_DMA
211 if (chunk >= 16)
212 {
213 // DMA is doing 32bit transfers.
214 chunk = chunk & 0xFFFFFFF8;
215 }
216 #endif
217 scsiSetDataCount(chunk);
218
219 while (i < count && likely(!scsiDev.resetFlag))
220 {
221 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}
222 *parityError |= scsiParityError();
223 scsiPhyFifoFlip();
224
225 uint32_t nextChunk = ((count - i - chunk) > SCSI_FIFO_DEPTH)
226 ? SCSI_FIFO_DEPTH : (count - i - chunk);
227 #ifdef SCSI_FSMC_DMA
228 if (nextChunk >= 16)
229 {
230 nextChunk = nextChunk & 0xFFFFFFF8;
231 }
232 #endif
233 if (nextChunk > 0)
234 {
235 scsiSetDataCount(nextChunk);
236 }
237
238 #ifdef SCSI_FSMC_DMA
239 if (chunk < 16)
240 #endif
241 {
242 scsiReadPIO(data + i, chunk);
243 }
244 #ifdef SCSI_FSMC_DMA
245 else
246 {
247 scsiReadDMA(data + i, chunk);
248
249 trace(trace_spinReadDMAPoll);
250
251 while (!scsiReadDMAPoll() && likely(!scsiDev.resetFlag))
252 {
253 };
254 }
255 #endif
256
257
258 i += chunk;
259 chunk = nextChunk;
260 }
261 #if FIFODEBUG
262 if (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty()) {
263 int j = 0;
264 while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++j; }
265 scsiPhyFifoFlip();
266 int k = 0;
267 while (!scsiPhyFifoEmpty()) { scsiPhyRx(); ++k; }
268 // Force a lock-up.
269 assertFail();
270 }
271 #endif
272 }
273
274 void
275 scsiWriteByte(uint8_t value)
276 {
277 #if FIFODEBUG
278 if (!scsiPhyFifoEmpty()) {
279 // Force a lock-up.
280 assertFail();
281 }
282 #endif
283 trace(trace_spinPhyTxFifo);
284 scsiPhyTx(value);
285 scsiPhyFifoFlip();
286
287 scsiSetDataCount(1);
288
289 trace(trace_spinTxComplete);
290 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag)) {}
291
292 #if FIFODEBUG
293 if (!scsiPhyFifoAltEmpty()) {
294 // Force a lock-up.
295 assertFail();
296 }
297 #endif
298 }
299
300 static void
301 scsiWritePIO(const uint8_t* data, uint32_t count)
302 {
303 uint16_t* fifoData = (uint16_t*)data;
304 for (int i = 0; i < (count + 1) / 2; ++i)
305 {
306 scsiPhyTx(fifoData[i]);
307 }
308 }
309
310 void
311 scsiWriteDMA(const uint8_t* data, uint32_t count)
312 {
313 // Prepare DMA transfer
314 dmaInProgress = 1;
315 trace(trace_doTxSingleDMA);
316
317 scsiTxDMAComplete = 0;
318 scsiRxDMAComplete = 1;
319
320 HAL_DMA_Start(
321 &memToFSMC,
322 (uint32_t) data,
323 (uint32_t) SCSI_FIFO_DATA,
324 count / 4);
325 }
326
327 int
328 scsiWriteDMAPoll()
329 {
330 int complete = __HAL_DMA_GET_COUNTER(&memToFSMC) == 0;
331 complete = complete && (HAL_DMA_PollForTransfer(&memToFSMC, HAL_DMA_FULL_TRANSFER, 0xffffffff) == HAL_OK);
332 if (complete)
333 {
334 scsiTxDMAComplete = 1; // TODO MM FIX IRQ
335 scsiRxDMAComplete = 1;
336
337 dmaInProgress = 0;
338 return 1;
339 }
340 else
341 {
342 return 0;
343 }
344 }
345
346 void
347 scsiWrite(const uint8_t* data, uint32_t count)
348 {
349 int i = 0;
350 while (i < count && likely(!scsiDev.resetFlag))
351 {
352 uint32_t chunk = ((count - i) > SCSI_FIFO_DEPTH)
353 ? SCSI_FIFO_DEPTH : (count - i);
354
355 #if FIFODEBUG
356 if (!scsiPhyFifoEmpty()) {
357 // Force a lock-up.
358 assertFail();
359 }
360 #endif
361
362 #ifdef SCSI_FSMC_DMA
363 if (chunk < 16)
364 #endif
365 {
366 scsiWritePIO(data + i, chunk);
367 }
368 #ifdef SCSI_FSMC_DMA
369 else
370 {
371 // DMA is doing 32bit transfers.
372 chunk = chunk & 0xFFFFFFF8;
373 scsiWriteDMA(data + i, chunk);
374
375 trace(trace_spinReadDMAPoll);
376
377 while (!scsiWriteDMAPoll() && likely(!scsiDev.resetFlag))
378 {
379 }
380 }
381 #endif
382
383 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
384 {
385 }
386
387 #if FIFODEBUG
388 if (!scsiPhyFifoAltEmpty()) {
389 // Force a lock-up.
390 assertFail();
391 }
392 #endif
393
394 scsiPhyFifoFlip();
395 scsiSetDataCount(chunk);
396 i += chunk;
397 }
398 while (!scsiPhyComplete() && likely(!scsiDev.resetFlag))
399 {
400 }
401
402 #if FIFODEBUG
403 if (!scsiPhyFifoAltEmpty()) {
404 // Force a lock-up.
405 assertFail();
406 }
407 #endif
408 }
409
410 static inline void busSettleDelay(void)
411 {
412 // Data Release time (switching IO) = 400ns
413 // + Bus Settle time (switching phase) = 400ns.
414 s2s_delay_us(1); // Close enough.
415 }
416
417 void scsiEnterBusFree()
418 {
419 *SCSI_CTRL_BSY = 0x00;
420 // We now have a Bus Clear Delay of 800ns to release remaining signals.
421 *SCSI_CTRL_PHASE = 0;
422 }
423
424 void scsiEnterPhase(int phase)
425 {
426 // ANSI INCITS 362-2002 SPI-3 10.7.1:
427 // Phase changes are not allowed while REQ or ACK is asserted.
428 while (likely(!scsiDev.resetFlag) && scsiStatusACK()) {}
429
430 int newPhase = phase > 0 ? phase : 0;
431 int oldPhase = *SCSI_CTRL_PHASE;
432
433 if (!scsiDev.resetFlag && (!scsiPhyFifoEmpty() || !scsiPhyFifoAltEmpty())) {
434 // Force a lock-up.
435 assertFail();
436 }
437 if (newPhase != oldPhase)
438 {
439 if ((newPhase == DATA_IN || newPhase == DATA_OUT) &&
440 scsiDev.target->syncOffset)
441 {
442 if (scsiDev.target->syncPeriod == 12)
443 {
444 // SCSI2 FAST-20 Timing. 20MB/s.
445 *SCSI_CTRL_DESKEW = SCSI_FAST20_DESKEW;
446 *SCSI_CTRL_TIMING = SCSI_FAST20_TIMING;
447 }
448 else if (scsiDev.target->syncPeriod == 25)
449 {
450 // SCSI2 FAST Timing. 10MB/s.
451 *SCSI_CTRL_DESKEW = SCSI_FAST10_DESKEW;
452 *SCSI_CTRL_TIMING = SCSI_FAST10_TIMING;
453 } else {
454 // 5MB/s Timing
455 *SCSI_CTRL_DESKEW = SCSI_DEFAULT_DESKEW;
456 *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
457 }
458
459 *SCSI_CTRL_SYNC_OFFSET = scsiDev.target->syncOffset;
460 } else {
461 *SCSI_CTRL_SYNC_OFFSET = 0;
462
463 // 5MB/s Timing
464 *SCSI_CTRL_DESKEW = SCSI_DEFAULT_DESKEW;
465 *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
466 }
467
468 *SCSI_CTRL_PHASE = newPhase;
469 busSettleDelay();
470
471 if (scsiDev.compatMode < COMPAT_SCSI2)
472 {
473 s2s_delay_us(100);
474 }
475
476 }
477 }
478
479 void scsiPhyReset()
480 {
481 trace(trace_scsiPhyReset);
482 if (dmaInProgress)
483 {
484 trace(trace_spinDMAReset);
485 HAL_DMA_Abort(&memToFSMC);
486 HAL_DMA_Abort(&fsmcToMem);
487
488 dmaInProgress = 0;
489 }
490
491 *SCSI_CTRL_PHASE = 0x00;
492 *SCSI_CTRL_BSY = 0x00;
493 s2s_fpgaReset(); // Clears fifos etc.
494
495 scsiPhyFifoSel = 0;
496 *SCSI_FIFO_SEL = 0;
497 *SCSI_CTRL_DBX = 0;
498
499 *SCSI_CTRL_SYNC_OFFSET = 0;
500 *SCSI_CTRL_DESKEW = SCSI_DEFAULT_DESKEW;
501 *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
502
503 // DMA Benchmark code
504 // Currently 11MB/s.
505 #ifdef DMA_BENCHMARK
506 while(1)
507 {
508 s2s_ledOn();
509 // 100MB
510 for (int i = 0; i < (100LL * 1024 * 1024 / SCSI_FIFO_DEPTH); ++i)
511 {
512 HAL_DMA_Start(
513 &memToFSMC,
514 (uint32_t) &scsiDev.data[0],
515 (uint32_t) SCSI_FIFO_DATA,
516 SCSI_FIFO_DEPTH / 4);
517
518 HAL_DMA_PollForTransfer(
519 &memToFSMC,
520 HAL_DMA_FULL_TRANSFER,
521 0xffffffff);
522
523 s2s_fpgaReset();
524 }
525 s2s_ledOff();
526
527 for(int i = 0; i < 10; ++i) s2s_delay_ms(1000);
528 }
529 #endif
530
531 // FPGA comms test code
532 #ifdef FPGA_TEST
533 while(1)
534 {
535 for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)
536 {
537 scsiDev.data[j] = j;
538 }
539
540 if (!scsiPhyFifoEmpty())
541 {
542 assertFail();
543 }
544
545 *SCSI_CTRL_PHASE = DATA_IN;
546 HAL_DMA_Start(
547 &memToFSMC,
548 (uint32_t) &scsiDev.data[0],
549 (uint32_t) SCSI_FIFO_DATA,
550 SCSI_FIFO_DEPTH / 4);
551
552 HAL_DMA_PollForTransfer(
553 &memToFSMC,
554 HAL_DMA_FULL_TRANSFER,
555 0xffffffff);
556
557 if (!scsiPhyFifoFull())
558 {
559 assertFail();
560 }
561
562 memset(&scsiDev.data[0], 0, SCSI_FIFO_DEPTH);
563
564 *SCSI_CTRL_PHASE = DATA_OUT;
565 HAL_DMA_Start(
566 &fsmcToMem,
567 (uint32_t) SCSI_FIFO_DATA,
568 (uint32_t) &scsiDev.data[0],
569 SCSI_FIFO_DEPTH / 2);
570
571 HAL_DMA_PollForTransfer(
572 &fsmcToMem,
573 HAL_DMA_FULL_TRANSFER,
574 0xffffffff);
575
576 if (!scsiPhyFifoEmpty())
577 {
578 assertFail();
579 }
580
581
582 for (int j = 0; j < SCSI_FIFO_DEPTH; ++j)
583 {
584 if (scsiDev.data[j] != (uint8_t) j)
585 {
586 assertFail();
587 }
588 }
589
590 s2s_fpgaReset();
591
592 }
593 #endif
594
595 #ifdef SCSI_FREQ_TEST
596 while(1)
597 {
598 *SCSI_CTRL_DBX = 0xAA;
599 *SCSI_CTRL_DBX = 0x55;
600 }
601 #endif
602
603 }
604
605 static void scsiPhyInitDMA()
606 {
607 // One-time init only.
608 static uint8_t init = 0;
609 if (init == 0)
610 {
611 init = 1;
612
613 // Memory to memory transfers can only be done using DMA2
614 __DMA2_CLK_ENABLE();
615
616 // Transmit SCSI data. The source data is treated as the
617 // peripheral (even though this is memory-to-memory)
618 memToFSMC.Instance = DMA2_Stream0;
619 memToFSMC.Init.Channel = DMA_CHANNEL_0;
620 memToFSMC.Init.Direction = DMA_MEMORY_TO_MEMORY;
621 memToFSMC.Init.PeriphInc = DMA_PINC_ENABLE;
622 memToFSMC.Init.MemInc = DMA_MINC_DISABLE;
623 memToFSMC.Init.PeriphDataAlignment = DMA_PDATAALIGN_WORD;
624 memToFSMC.Init.MemDataAlignment = DMA_MDATAALIGN_HALFWORD;
625 memToFSMC.Init.Mode = DMA_NORMAL;
626 memToFSMC.Init.Priority = DMA_PRIORITY_LOW;
627 // FIFO mode is needed to allow conversion from 32bit words to the
628 // 16bit FSMC interface.
629 memToFSMC.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
630
631 // We only use 1 word (4 bytes) in the fifo at a time. Normally it's
632 // better to let the DMA fifo fill up then do burst transfers, but
633 // bursting out the FSMC interface will be very slow and may starve
634 // other (faster) transfers. We don't want to risk the SDIO transfers
635 // from overrun/underrun conditions.
636 memToFSMC.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
637 memToFSMC.Init.MemBurst = DMA_MBURST_SINGLE;
638 memToFSMC.Init.PeriphBurst = DMA_PBURST_SINGLE;
639 HAL_DMA_Init(&memToFSMC);
640
641 // Receive SCSI data. The source data (fsmc) is treated as the
642 // peripheral (even though this is memory-to-memory)
643 fsmcToMem.Instance = DMA2_Stream1;
644 fsmcToMem.Init.Channel = DMA_CHANNEL_0;
645 fsmcToMem.Init.Direction = DMA_MEMORY_TO_MEMORY;
646 fsmcToMem.Init.PeriphInc = DMA_PINC_DISABLE;
647 fsmcToMem.Init.MemInc = DMA_MINC_ENABLE;
648 fsmcToMem.Init.PeriphDataAlignment = DMA_PDATAALIGN_HALFWORD;
649 fsmcToMem.Init.MemDataAlignment = DMA_MDATAALIGN_WORD;
650 fsmcToMem.Init.Mode = DMA_NORMAL;
651 fsmcToMem.Init.Priority = DMA_PRIORITY_LOW;
652 fsmcToMem.Init.FIFOMode = DMA_FIFOMODE_ENABLE;
653 fsmcToMem.Init.FIFOThreshold = DMA_FIFO_THRESHOLD_1QUARTERFULL;
654 fsmcToMem.Init.MemBurst = DMA_MBURST_SINGLE;
655 fsmcToMem.Init.PeriphBurst = DMA_PBURST_SINGLE;
656 HAL_DMA_Init(&fsmcToMem);
657
658 // TODO configure IRQs
659 }
660 }
661
662
663 void scsiPhyInit()
664 {
665 scsiPhyInitDMA();
666
667 *SCSI_CTRL_IDMASK = 0x00; // Reset in scsiPhyConfig
668 *SCSI_CTRL_PHASE = 0x00;
669 *SCSI_CTRL_BSY = 0x00;
670 scsiPhyFifoSel = 0;
671 *SCSI_FIFO_SEL = 0;
672 *SCSI_CTRL_DBX = 0;
673
674 *SCSI_CTRL_SYNC_OFFSET = 0;
675 *SCSI_CTRL_DESKEW = SCSI_DEFAULT_DESKEW;
676 *SCSI_CTRL_TIMING = SCSI_DEFAULT_TIMING;
677
678 }
679
680 void scsiPhyConfig()
681 {
682 if (scsiDev.boardCfg.flags6 & S2S_CFG_ENABLE_TERMINATOR)
683 {
684 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_RESET);
685 }
686 else
687 {
688 HAL_GPIO_WritePin(nTERM_EN_GPIO_Port, nTERM_EN_Pin, GPIO_PIN_SET);
689 }
690
691
692 uint8_t idMask = 0;
693 for (int i = 0; i < 8; ++i)
694 {
695 const S2S_TargetCfg* cfg = s2s_getConfigById(i);
696 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
697 {
698 idMask |= (1 << i);
699 }
700 }
701 *SCSI_CTRL_IDMASK = idMask;
702
703 *SCSI_CTRL_FLAGS =
704 ((scsiDev.boardCfg.flags & S2S_CFG_DISABLE_GLITCH) ?
705 SCSI_CTRL_FLAGS_DISABLE_GLITCH : 0) |
706 ((scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY) ?
707 SCSI_CTRL_FLAGS_ENABLE_PARITY : 0);
708
709 }
710
711
712 // 1 = DBx error
713 // 2 = Parity error
714 // 4 = MSG error
715 // 8 = CD error
716 // 16 = IO error
717 // 32 = other error
718 int scsiSelfTest()
719 {
720 if (scsiDev.phase != BUS_FREE)
721 {
722 return 32;
723 }
724
725 // Acquire the SCSI bus.
726 for (int i = 0; i < 100; ++i)
727 {
728 if (scsiStatusBSY())
729 {
730 s2s_delay_ms(1);
731 }
732 }
733 if (scsiStatusBSY())
734 {
735 // Error, couldn't acquire scsi bus
736 return 32;
737 }
738 *SCSI_CTRL_BSY = 1;
739 if (! scsiStatusBSY())
740 {
741 // Error, BSY doesn't work.
742 return 32;
743 }
744
745 // Should be safe to use the bus now.
746
747 int result = 0;
748
749 // TEST DBx
750 // TODO test DBp
751 int i;
752 for (i = 0; i < 256; ++i)
753 {
754 *SCSI_CTRL_DBX = i;
755 busSettleDelay();
756 if (*SCSI_STS_DBX != (i & 0xff))
757 {
758 result |= 1;
759 }
760 /*if (Lookup_OddParity[i & 0xff] != SCSI_ReadPin(SCSI_In_DBP))
761 {
762 result |= 2;
763 }*/
764 }
765 *SCSI_CTRL_DBX = 0;
766
767 // TEST MSG, CD, IO
768 /* TODO
769 for (i = 0; i < 8; ++i)
770 {
771 SCSI_CTL_PHASE_Write(i);
772 scsiDeskewDelay();
773
774 if (SCSI_ReadPin(SCSI_In_MSG) != !!(i & __scsiphase_msg))
775 {
776 result |= 4;
777 }
778 if (SCSI_ReadPin(SCSI_In_CD) != !!(i & __scsiphase_cd))
779 {
780 result |= 8;
781 }
782 if (SCSI_ReadPin(SCSI_In_IO) != !!(i & __scsiphase_io))
783 {
784 result |= 16;
785 }
786 }
787 SCSI_CTL_PHASE_Write(0);
788
789 uint32_t signalsOut[] = { SCSI_Out_ATN, SCSI_Out_BSY, SCSI_Out_RST, SCSI_Out_SEL };
790 uint32_t signalsIn[] = { SCSI_Filt_ATN, SCSI_Filt_BSY, SCSI_Filt_RST, SCSI_Filt_SEL };
791
792 for (i = 0; i < 4; ++i)
793 {
794 SCSI_SetPin(signalsOut[i]);
795 scsiDeskewDelay();
796
797 int j;
798 for (j = 0; j < 4; ++j)
799 {
800 if (i == j)
801 {
802 if (! SCSI_ReadFilt(signalsIn[j]))
803 {
804 result |= 32;
805 }
806 }
807 else
808 {
809 if (SCSI_ReadFilt(signalsIn[j]))
810 {
811 result |= 32;
812 }
813 }
814 }
815 SCSI_ClearPin(signalsOut[i]);
816 }
817 */
818
819 *SCSI_CTRL_BSY = 0;
820 return result;
821 }
822