1 // Copyright (C) 2014 Michael McMaster <michael@codesrc.com>
3 // This file is part of SCSI2SD.
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.
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.
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/>.
21 #include "diagnostic.h"
36 // Global SCSI device state.
37 ScsiDevice scsiDev S2S_DMA_ALIGN
;
39 static void enter_SelectionPhase(void);
40 static void process_SelectionPhase(void);
41 static void enter_MessageIn(uint8_t message
);
42 static void enter_Status(uint8_t status
);
43 static void enter_DataIn(int len
);
44 static void process_DataIn(void);
45 static void process_DataOut(void);
46 static void process_Command(void);
48 static void doReserveRelease(void);
52 // This delay probably isn't needed for most SCSI hosts, but it won't
53 // hurt either. It's possible some of the samplers needed this delay.
54 if (scsiDev
.compatMode
< COMPAT_SCSI2
)
60 if (scsiDev
.status
!= GOOD
&& isDebugEnabled())
62 // We want to capture debug information for failure cases.
70 // Wait for the initiator to cease driving signals
71 // Bus settle delay + bus clear delay = 1200ns
76 scsiDev
.phase
= BUS_FREE
;
80 static void enter_MessageIn(uint8_t message
)
82 scsiDev
.msgIn
= message
;
83 scsiDev
.phase
= MESSAGE_IN
;
86 int process_MessageIn(int releaseBusFree
)
88 scsiEnterPhase(MESSAGE_IN
);
89 scsiWriteByte(scsiDev
.msgIn
);
91 if (unlikely(scsiDev
.atnFlag
))
93 // If there was a parity error, we go
94 // back to MESSAGE_OUT first, get out parity error message, then come
98 else if ((scsiDev
.msgIn
== MSG_LINKED_COMMAND_COMPLETE
) ||
99 (scsiDev
.msgIn
== MSG_LINKED_COMMAND_COMPLETE_WITH_FLAG
))
101 // Go back to the command phase and start again.
102 scsiDev
.phase
= COMMAND
;
104 scsiDev
.savedDataPtr
= 0;
106 scsiDev
.status
= GOOD
;
108 transfer
.currentBlock
= 0;
111 else if (releaseBusFree
) /*if (scsiDev.msgIn == MSG_COMMAND_COMPLETE)*/
122 static void messageReject()
124 scsiEnterPhase(MESSAGE_IN
);
125 scsiWriteByte(MSG_REJECT
);
128 static void enter_Status(uint8_t status
)
130 scsiDev
.status
= status
;
131 scsiDev
.phase
= STATUS
;
133 scsiDev
.lastStatus
= scsiDev
.status
;
134 scsiDev
.lastSense
= scsiDev
.target
->sense
.code
;
135 scsiDev
.lastSenseASC
= scsiDev
.target
->sense
.asc
;
138 void process_Status()
140 scsiEnterPhase(STATUS
);
144 uint8_t control
= scsiDev
.cdb
[scsiDev
.cdbLen
- 1];
146 if (scsiDev
.target
->cfg
->quirks
== S2S_CFG_QUIRKS_OMTI
)
148 // OMTI non-standard LINK control
151 scsiDev
.phase
= COMMAND
;
156 if ((scsiDev
.status
== GOOD
) && (control
& 0x01))
159 scsiDev
.status
= INTERMEDIATE
;
162 message
= MSG_LINKED_COMMAND_COMPLETE_WITH_FLAG
;
166 message
= MSG_LINKED_COMMAND_COMPLETE
;
171 message
= MSG_COMMAND_COMPLETE
;
174 if (scsiDev
.target
->cfg
->quirks
== S2S_CFG_QUIRKS_OMTI
)
176 scsiDev
.status
|= (scsiDev
.target
->targetId
& 0x03) << 5;
179 scsiWriteByte(scsiDev
.status
);
181 scsiDev
.lastStatus
= scsiDev
.status
;
182 scsiDev
.lastSense
= scsiDev
.target
->sense
.code
;
183 scsiDev
.lastSenseASC
= scsiDev
.target
->sense
.asc
;
185 // Command Complete occurs AFTER a valid status has been
186 // sent. then we go bus-free.
187 enter_MessageIn(message
);
190 static void enter_DataIn(int len
)
192 scsiDev
.dataLen
= len
;
193 scsiDev
.phase
= DATA_IN
;
196 static void process_DataIn()
200 if (scsiDev
.dataLen
> sizeof(scsiDev
.data
))
202 scsiDev
.dataLen
= sizeof(scsiDev
.data
);
205 len
= scsiDev
.dataLen
- scsiDev
.dataPtr
;
208 scsiEnterPhase(DATA_IN
);
209 scsiWrite(scsiDev
.data
+ scsiDev
.dataPtr
, len
);
210 scsiDev
.dataPtr
+= len
;
213 if ((scsiDev
.dataPtr
>= scsiDev
.dataLen
) &&
214 (transfer
.currentBlock
== transfer
.blocks
))
220 static void process_DataOut()
224 if (scsiDev
.dataLen
> sizeof(scsiDev
.data
))
226 scsiDev
.dataLen
= sizeof(scsiDev
.data
);
229 len
= scsiDev
.dataLen
- scsiDev
.dataPtr
;
232 scsiEnterPhase(DATA_OUT
);
235 scsiRead(scsiDev
.data
+ scsiDev
.dataPtr
, len
, &parityError
);
236 scsiDev
.dataPtr
+= len
;
239 (scsiDev
.boardCfg
.flags
& S2S_CFG_ENABLE_PARITY
))
241 scsiDev
.target
->sense
.code
= ABORTED_COMMAND
;
242 scsiDev
.target
->sense
.asc
= SCSI_PARITY_ERROR
;
243 enter_Status(CHECK_CONDITION
);
247 if ((scsiDev
.dataPtr
>= scsiDev
.dataLen
) &&
248 (transfer
.currentBlock
== transfer
.blocks
))
250 if (scsiDev
.postDataOutHook
!= NULL
)
252 scsiDev
.postDataOutHook();
261 static const uint8_t CmdGroupBytes
[8] = {6, 10, 10, 6, 6, 12, 6, 6};
262 static void process_Command()
268 scsiEnterPhase(COMMAND
);
270 memset(scsiDev
.cdb
+ 6, 0, sizeof(scsiDev
.cdb
) - 6);
272 scsiRead(scsiDev
.cdb
, 6, &parityError
);
274 group
= scsiDev
.cdb
[0] >> 5;
275 scsiDev
.cdbLen
= CmdGroupBytes
[group
];
277 (scsiDev
.boardCfg
.flags
& S2S_CFG_ENABLE_PARITY
))
279 // Don't try and read more bytes, as we cannot be sure what group
280 // the command should be.
282 else if (scsiDev
.cdbLen
- 6 > 0)
284 scsiRead(scsiDev
.cdb
+ 6, scsiDev
.cdbLen
- 6, &parityError
);
287 command
= scsiDev
.cdb
[0];
289 // Prefer LUN's set by IDENTIFY messages for newer hosts.
292 scsiDev
.lun
= scsiDev
.cdb
[1] >> 5;
295 control
= scsiDev
.cdb
[scsiDev
.cdbLen
- 1];
298 const S2S_TargetCfg
* cfg
= scsiDev
.target
->cfg
;
300 if (unlikely(scsiDev
.resetFlag
))
302 // Don't log bogus commands
304 memset(scsiDev
.cdb
, 0xff, sizeof(scsiDev
.cdb
));
307 else if (parityError
&&
308 (scsiDev
.boardCfg
.flags
& S2S_CFG_ENABLE_PARITY
))
310 scsiDev
.target
->sense
.code
= ABORTED_COMMAND
;
311 scsiDev
.target
->sense
.asc
= SCSI_PARITY_ERROR
;
312 enter_Status(CHECK_CONDITION
);
314 else if ((control
& 0x02) && ((control
& 0x01) == 0))
316 // FLAG set without LINK flag.
317 scsiDev
.target
->sense
.code
= ILLEGAL_REQUEST
;
318 scsiDev
.target
->sense
.asc
= INVALID_FIELD_IN_CDB
;
319 enter_Status(CHECK_CONDITION
);
321 else if (command
== 0x12)
325 else if (command
== 0x03)
328 uint32_t allocLength
= scsiDev
.cdb
[4];
330 // As specified by the SASI and SCSI1 standard.
331 // Newer initiators won't be specifying 0 anyway.
332 if (allocLength
== 0) allocLength
= 4;
334 memset(scsiDev
.data
, 0, 256); // Max possible alloc length
335 scsiDev
.data
[0] = 0xF0;
336 scsiDev
.data
[2] = scsiDev
.target
->sense
.code
& 0x0F;
338 scsiDev
.data
[3] = transfer
.lba
>> 24;
339 scsiDev
.data
[4] = transfer
.lba
>> 16;
340 scsiDev
.data
[5] = transfer
.lba
>> 8;
341 scsiDev
.data
[6] = transfer
.lba
;
343 // Additional bytes if there are errors to report
344 scsiDev
.data
[7] = 10; // additional length
345 scsiDev
.data
[12] = scsiDev
.target
->sense
.asc
>> 8;
346 scsiDev
.data
[13] = scsiDev
.target
->sense
.asc
;
348 // Silently truncate results. SCSI-2 spec 8.2.14.
349 enter_DataIn(allocLength
);
351 // This is a good time to clear out old sense information.
352 scsiDev
.target
->sense
.code
= NO_SENSE
;
353 scsiDev
.target
->sense
.asc
= NO_ADDITIONAL_SENSE_INFORMATION
;
355 // Some old SCSI drivers do NOT properly support
356 // unitAttention. eg. the Mac Plus would trigger a SCSI reset
357 // on receiving the unit attention response on boot, thus
358 // triggering another unit attention condition.
359 else if (scsiDev
.target
->unitAttention
&&
360 (scsiDev
.boardCfg
.flags
& S2S_CFG_ENABLE_UNIT_ATTENTION
))
362 scsiDev
.target
->sense
.code
= UNIT_ATTENTION
;
363 scsiDev
.target
->sense
.asc
= scsiDev
.target
->unitAttention
;
365 // If initiator doesn't do REQUEST SENSE for the next command, then
367 scsiDev
.target
->unitAttention
= 0;
369 enter_Status(CHECK_CONDITION
);
371 else if (scsiDev
.lun
)
373 scsiDev
.target
->sense
.code
= ILLEGAL_REQUEST
;
374 scsiDev
.target
->sense
.asc
= LOGICAL_UNIT_NOT_SUPPORTED
;
375 enter_Status(CHECK_CONDITION
);
377 else if (command
== 0x17 || command
== 0x16)
381 else if ((scsiDev
.target
->reservedId
>= 0) &&
382 (scsiDev
.target
->reservedId
!= scsiDev
.initiatorId
))
384 enter_Status(CONFLICT
);
386 // Handle odd device types first that may override basic read and
387 // write commands. Will fall-through to generic disk handling.
388 else if (((cfg
->deviceType
== S2S_CFG_OPTICAL
) && scsiCDRomCommand()) ||
389 ((cfg
->deviceType
== S2S_CFG_SEQUENTIAL
) && scsiTapeCommand()) ||
390 ((cfg
->deviceType
== S2S_CFG_MO
) && scsiMOCommand()))
394 else if (scsiDiskCommand())
397 // check for the performance-critical read/write
400 else if (command
== 0x1C)
402 scsiReceiveDiagnostic();
404 else if (command
== 0x1D)
406 scsiSendDiagnostic();
408 else if (command
== 0x3B)
412 else if (command
== 0x3C)
416 else if (!scsiModeCommand() && !scsiVendorCommand())
418 scsiDev
.target
->sense
.code
= ILLEGAL_REQUEST
;
419 scsiDev
.target
->sense
.asc
= INVALID_COMMAND_OPERATION_CODE
;
420 enter_Status(CHECK_CONDITION
);
424 if (scsiDev
.phase
== COMMAND
) // No status set, and not in DATA_IN
431 static void doReserveRelease()
433 int extentReservation
= scsiDev
.cdb
[1] & 1;
434 int thirdPty
= scsiDev
.cdb
[1] & 0x10;
435 int thirdPtyId
= (scsiDev
.cdb
[1] >> 1) & 0x7;
436 uint8_t command
= scsiDev
.cdb
[0];
439 (!thirdPty
&& (scsiDev
.initiatorId
== scsiDev
.target
->reservedId
)) ||
441 (scsiDev
.target
->reserverId
== scsiDev
.initiatorId
) &&
442 (scsiDev
.target
->reservedId
== thirdPtyId
)
445 if (extentReservation
)
448 scsiDev
.target
->sense
.code
= ILLEGAL_REQUEST
;
449 scsiDev
.target
->sense
.asc
= INVALID_FIELD_IN_CDB
;
450 enter_Status(CHECK_CONDITION
);
452 else if (command
== 0x17) // release
454 if ((scsiDev
.target
->reservedId
< 0) || canRelease
)
456 scsiDev
.target
->reservedId
= -1;
457 scsiDev
.target
->reserverId
= -1;
461 enter_Status(CONFLICT
);
464 else // assume reserve.
466 if ((scsiDev
.target
->reservedId
< 0) || canRelease
)
468 scsiDev
.target
->reserverId
= scsiDev
.initiatorId
;
471 scsiDev
.target
->reservedId
= thirdPtyId
;
475 scsiDev
.target
->reservedId
= scsiDev
.initiatorId
;
480 // Already reserved by someone else!
481 enter_Status(CONFLICT
);
486 static uint32_t resetUntil
= 0;
488 static void scsiReset()
495 scsiDev
.phase
= BUS_FREE
;
497 scsiDev
.resetFlag
= 0;
500 scsiDev
.compatMode
= COMPAT_UNKNOWN
;
504 if (scsiDev
.target
->unitAttention
!= POWER_ON_RESET
)
506 scsiDev
.target
->unitAttention
= SCSI_BUS_RESET
;
508 scsiDev
.target
->reservedId
= -1;
509 scsiDev
.target
->reserverId
= -1;
510 scsiDev
.target
->sense
.code
= NO_SENSE
;
511 scsiDev
.target
->sense
.asc
= NO_ADDITIONAL_SENSE_INFORMATION
;
513 scsiDev
.target
= NULL
;
515 for (int i
= 0; i
< S2S_MAX_TARGETS
; ++i
)
517 scsiDev
.targets
[i
].syncOffset
= 0;
518 scsiDev
.targets
[i
].syncPeriod
= 0;
520 scsiDev
.minSyncPeriod
= 0;
524 scsiDev
.postDataOutHook
= NULL
;
526 scsiDev
.sdUnderrunCount
= 0;
528 // Sleep to allow the bus to settle down a bit.
529 // We must be ready again within the "Reset to selection time" of
531 // There is no guarantee that the RST line will be negated by then.
532 // NOTE: We could be connected and powered by USB for configuration,
533 // in which case TERMPWR cannot be supplied, and reset will ALWAYS
534 // be true. Therefore, the sleep here must be slow to avoid slowing
536 resetUntil
= s2s_getTime_ms() + 2; // At least 1ms.
539 static void enter_SelectionPhase()
541 // Ignore stale versions of this flag, but ensure we know the
542 // current value if the flag is still set.
545 scsiDev
.savedDataPtr
= 0;
547 scsiDev
.status
= GOOD
;
548 scsiDev
.phase
= SELECTION
;
550 scsiDev
.discPriv
= 0;
552 scsiDev
.initiatorId
= -1;
553 scsiDev
.target
= NULL
;
556 transfer
.currentBlock
= 0;
558 scsiDev
.postDataOutHook
= NULL
;
560 scsiDev
.needSyncNegotiationAck
= 0;
563 static void process_SelectionPhase()
566 // Many SCSI1 samplers that use a 5380 chip need a delay of at least 1ms.
567 // The Mac Plus boot-time (ie. rom code) selection abort time
568 // is < 1ms and must have no delay (standard suggests 250ms abort time)
569 // Most newer SCSI2 hosts don't care either way.
570 if (scsiDev
.boardCfg
.selectionDelay
== 255) // auto
572 if (scsiDev
.compatMode
< COMPAT_SCSI2
)
577 else if (scsiDev
.boardCfg
.selectionDelay
!= 0)
579 s2s_delay_ms(scsiDev
.boardCfg
.selectionDelay
);
582 uint8_t selStatus
= *SCSI_STS_SELECTED
;
583 if ((selStatus
== 0) && (scsiDev
.boardCfg
.flags
& S2S_CFG_ENABLE_SEL_LATCH
))
585 selStatus
= scsiDev
.selFlag
;
589 TargetState
* target
= NULL
;
590 for (tgtIndex
= 0; tgtIndex
< S2S_MAX_TARGETS
; ++tgtIndex
)
592 if (scsiDev
.targets
[tgtIndex
].targetId
== (selStatus
& 7))
594 target
= &scsiDev
.targets
[tgtIndex
];
598 if ((target
!= NULL
) && (selStatus
& 0x40))
600 // We've been selected!
601 // Assert BSY - Selection success!
602 // must happen within 200us (Selection abort time) of seeing our
604 // (Note: the initiator will be waiting the "Selection time-out delay"
605 // for our BSY response, which is actually a very generous 250ms)
609 scsiDev
.target
= target
;
611 // Do we enter MESSAGE OUT immediately ? SCSI 1 and 2 standards says
612 // move to MESSAGE OUT if ATN is true before we assert BSY.
613 // The initiator should assert ATN with SEL.
614 scsiDev
.atnFlag
= selStatus
& 0x80;
617 // Unit attention breaks many older SCSI hosts. Disable it completely
618 // for SCSI-1 (and older) hosts, regardless of our configured setting.
619 // Enable the compatability mode also as many SASI and SCSI1
620 // controllers don't generate parity bits.
621 if (!scsiDev
.atnFlag
)
623 target
->unitAttention
= 0;
624 scsiDev
.compatMode
= COMPAT_SCSI1
;
626 else if (!(scsiDev
.boardCfg
.flags
& S2S_CFG_ENABLE_SCSI2
))
628 scsiDev
.compatMode
= COMPAT_SCSI2_DISABLED
;
632 scsiDev
.compatMode
= COMPAT_SCSI2
;
638 // Save our initiator now that we're no longer in a time-critical
640 // SCSI1/SASI initiators may not set their own ID.
641 scsiDev
.initiatorId
= (selStatus
>> 3) & 0x7;
643 while (likely(!scsiDev
.resetFlag
) && scsiStatusSEL())
645 // Wait until the end of the selection phase.
648 scsiDev
.phase
= COMMAND
;
652 scsiDev
.phase
= BUS_BUSY
;
657 static void process_MessageOut()
659 int wasNeedSyncNegotiationAck
= scsiDev
.needSyncNegotiationAck
;
660 scsiDev
.needSyncNegotiationAck
= 0; // Successful on -most- messages.
662 scsiEnterPhase(MESSAGE_OUT
);
665 scsiDev
.msgOut
= scsiReadByte();
668 if (scsiParityError() &&
669 (scsiDev
.boardCfg
.flags
& S2S_CFG_ENABLE_PARITY
))
671 // Skip the remaining message bytes, and then start the MESSAGE_OUT
672 // phase again from the start. The initiator will re-send the
673 // same set of messages.
674 while (scsiStatusATN() && !scsiDev
.resetFlag
)
679 // Go-back and try the message again.
682 else if (scsiDev
.msgOut
== 0x00)
684 // COMMAND COMPLETE. but why would the target be receiving this ? nfi.
687 else if (scsiDev
.msgOut
== 0x06)
693 else if (scsiDev
.msgOut
== 0x0C)
699 scsiDev
.target
->unitAttention
= SCSI_BUS_RESET
;
701 // ANY initiator can reset the reservation state via this message.
702 scsiDev
.target
->reservedId
= -1;
703 scsiDev
.target
->reserverId
= -1;
705 // Cancel any sync negotiation
706 scsiDev
.target
->syncOffset
= 0;
707 scsiDev
.target
->syncPeriod
= 0;
711 else if (scsiDev
.msgOut
== 0x05)
713 // Initiate Detected Error
716 else if (scsiDev
.msgOut
== 0x0F)
721 else if (scsiDev
.msgOut
== 0x10)
727 else if (scsiDev
.msgOut
== MSG_REJECT
)
732 if (wasNeedSyncNegotiationAck
)
734 scsiDev
.target
->syncOffset
= 0;
735 scsiDev
.target
->syncPeriod
= 0;
738 else if (scsiDev
.msgOut
== 0x08)
742 else if (scsiDev
.msgOut
== 0x09)
744 // Message Parity Error
745 // Go back and re-send the last message.
746 scsiDev
.phase
= MESSAGE_IN
;
748 if (wasNeedSyncNegotiationAck
)
750 scsiDev
.target
->syncOffset
= 0;
751 scsiDev
.target
->syncPeriod
= 0;
754 else if (scsiDev
.msgOut
& 0x80) // 0x80 -> 0xFF
757 if ((scsiDev
.msgOut
& 0x18) || // Reserved bits set.
758 (scsiDev
.msgOut
& 0x20)) // We don't have any target routines!
763 scsiDev
.lun
= scsiDev
.msgOut
& 0x7;
765 ((scsiDev
.msgOut
& 0x40) && (scsiDev
.initiatorId
>= 0))
768 else if (scsiDev
.msgOut
>= 0x20 && scsiDev
.msgOut
<= 0x2F)
770 // Two byte message. We don't support these. read and discard.
773 if (scsiDev
.msgOut
== 0x23) {
774 // Ignore Wide Residue. We're only 8 bit anyway.
779 else if (scsiDev
.msgOut
== 0x01)
784 int msgLen
= scsiReadByte();
785 if (msgLen
== 0) msgLen
= 256;
787 for (i
= 0; i
< msgLen
&& !scsiDev
.resetFlag
; ++i
)
790 extmsg
[i
] = scsiReadByte();
793 if (extmsg
[0] == 3 && msgLen
== 2) // Wide Data Request
795 // Negotiate down to 8bit
796 scsiEnterPhase(MESSAGE_IN
);
797 static const uint8_t WDTR
[] = {0x01, 0x02, 0x03, 0x00};
798 scsiWrite(WDTR
, sizeof(WDTR
));
800 // SDTR becomes invalidated.
801 scsiDev
.target
->syncOffset
= 0;
802 scsiDev
.target
->syncPeriod
= 0;
804 else if (extmsg
[0] == 1 && msgLen
== 3) // Synchronous data request
806 int oldPeriod
= scsiDev
.target
->syncPeriod
;
807 int oldOffset
= scsiDev
.target
->syncOffset
;
809 int transferPeriod
= extmsg
[1];
810 int offset
= extmsg
[2];
813 (transferPeriod
> 0) &&
814 (transferPeriod
< scsiDev
.minSyncPeriod
)) ||
815 (scsiDev
.minSyncPeriod
== 0))
817 scsiDev
.minSyncPeriod
= transferPeriod
;
820 if ((transferPeriod
> 80) || // 320ns, 3.125MB/s
821 // Amiga A590 (WD33C93 chip) only does 3.5MB/s sync
822 // After 80 we start to run out of bits in the fpga timing
824 (transferPeriod
== 0) ||
826 ((scsiDev
.boardCfg
.scsiSpeed
!= S2S_CFG_SPEED_NoLimit
) &&
827 (scsiDev
.boardCfg
.scsiSpeed
<= S2S_CFG_SPEED_ASYNC_50
)))
829 scsiDev
.target
->syncOffset
= 0;
830 scsiDev
.target
->syncPeriod
= 0;
832 scsiDev
.target
->syncOffset
= offset
<= 15 ? offset
: 15;
833 // FAST20 / 50ns / 20MHz is disabled for now due to
834 // data corruption while reading data. We can count the
835 // ACK's correctly, but can't save the data to a register
836 // before it changes. (ie. transferPeriod == 12)
837 if ((scsiDev
.boardCfg
.scsiSpeed
== S2S_CFG_SPEED_TURBO
) &&
838 (transferPeriod
<= 16))
840 scsiDev
.target
->syncPeriod
= 16; // 15.6MB/s
842 else if (scsiDev
.boardCfg
.scsiSpeed
== S2S_CFG_SPEED_TURBO
)
844 scsiDev
.target
->syncPeriod
= transferPeriod
;
846 else if (transferPeriod
<= 25 &&
847 ((scsiDev
.boardCfg
.scsiSpeed
== S2S_CFG_SPEED_NoLimit
) ||
848 (scsiDev
.boardCfg
.scsiSpeed
>= S2S_CFG_SPEED_SYNC_10
)))
850 scsiDev
.target
->syncPeriod
= 25; // 100ns, 10MB/s
852 } else if (transferPeriod
< 50 &&
853 ((scsiDev
.boardCfg
.scsiSpeed
== S2S_CFG_SPEED_NoLimit
) ||
854 (scsiDev
.boardCfg
.scsiSpeed
>= S2S_CFG_SPEED_SYNC_10
)))
856 scsiDev
.target
->syncPeriod
= transferPeriod
;
857 } else if (transferPeriod
>= 50)
859 scsiDev
.target
->syncPeriod
= transferPeriod
;
861 scsiDev
.target
->syncPeriod
= 50;
865 if (transferPeriod
!= oldPeriod
||
866 scsiDev
.target
->syncPeriod
!= oldPeriod
||
867 offset
!= oldOffset
||
868 scsiDev
.target
->syncOffset
!= oldOffset
||
869 !wasNeedSyncNegotiationAck
) // Don't get into infinite loops negotiating.
871 scsiEnterPhase(MESSAGE_IN
);
872 uint8_t SDTR
[] = {0x01, 0x03, 0x01, scsiDev
.target
->syncPeriod
, scsiDev
.target
->syncOffset
};
873 scsiWrite(SDTR
, sizeof(SDTR
));
874 scsiDev
.needSyncNegotiationAck
= 1; // Check if this message is rejected.
875 scsiDev
.sdUnderrunCount
= 0; // reset counter, may work now.
889 // Re-check the ATN flag in case it stays asserted.
890 scsiDev
.atnFlag
|= scsiStatusATN();
892 if (!scsiDev
.atnFlag
)
894 // Message wasn't rejected!
895 scsiDev
.needSyncNegotiationAck
= 0;
901 if (resetUntil
!= 0 && resetUntil
> s2s_getTime_ms())
907 if (unlikely(scsiDev
.resetFlag
))
910 // Still in reset phase for a few ms.
911 // Do not try and process any commands.
915 switch (scsiDev
.phase
)
920 scsiDev
.phase
= BUS_BUSY
;
922 // The Arbitration phase is optional for SCSI1/SASI hosts if there is only
923 // one initiator in the chain. Support this by moving
924 // straight to selection if SEL is asserted.
925 // ie. the initiator won't assert BSY and it's own ID before moving to selection.
926 else if (scsiDev
.selFlag
|| *SCSI_STS_SELECTED
)
928 enter_SelectionPhase();
933 // Someone is using the bus. Perhaps they are trying to
935 if (scsiDev
.selFlag
|| *SCSI_STS_SELECTED
)
937 enter_SelectionPhase();
939 else if (!scsiStatusBSY())
941 scsiDev
.phase
= BUS_FREE
;
946 // TODO Support reselection.
950 process_SelectionPhase();
954 // Not currently supported!
958 // Do not check ATN here. SCSI 1 & 2 initiators must set ATN
959 // and SEL together upon entering the selection phase if they
960 // want to send a message (IDENTIFY) immediately.
963 process_MessageOut();
972 scsiDev
.atnFlag
|= scsiStatusATN();
975 process_MessageOut();
984 scsiDev
.atnFlag
|= scsiStatusATN();
987 process_MessageOut();
996 scsiDev
.atnFlag
|= scsiStatusATN();
999 process_MessageOut();
1008 scsiDev
.atnFlag
|= scsiStatusATN();
1009 if (scsiDev
.atnFlag
)
1011 process_MessageOut();
1015 process_MessageIn(1);
1021 process_MessageOut();
1028 static int firstInit
= 1;
1030 scsiDev
.atnFlag
= 0;
1031 scsiDev
.resetFlag
= 1;
1032 scsiDev
.selFlag
= 0;
1033 scsiDev
.phase
= BUS_FREE
;
1034 scsiDev
.target
= NULL
;
1035 scsiDev
.compatMode
= COMPAT_UNKNOWN
;
1038 for (i
= 0; i
< S2S_MAX_TARGETS
; ++i
)
1040 const S2S_TargetCfg
* cfg
= s2s_getConfigByIndex(i
);
1041 if (cfg
&& (cfg
->scsiId
& S2S_CFG_TARGET_ENABLED
))
1043 scsiDev
.targets
[i
].targetId
= cfg
->scsiId
& S2S_CFG_TARGET_ID_BITS
;
1044 scsiDev
.targets
[i
].cfg
= cfg
;
1046 scsiDev
.targets
[i
].liveCfg
.bytesPerSector
= cfg
->bytesPerSector
;
1050 scsiDev
.targets
[i
].targetId
= 0xff;
1051 scsiDev
.targets
[i
].cfg
= NULL
;
1053 scsiDev
.targets
[i
].reservedId
= -1;
1054 scsiDev
.targets
[i
].reserverId
= -1;
1057 scsiDev
.targets
[i
].unitAttention
= POWER_ON_RESET
;
1061 scsiDev
.targets
[i
].unitAttention
= PARAMETERS_CHANGED
;
1063 scsiDev
.targets
[i
].sense
.code
= NO_SENSE
;
1064 scsiDev
.targets
[i
].sense
.asc
= NO_ADDITIONAL_SENSE_INFORMATION
;
1066 scsiDev
.targets
[i
].syncOffset
= 0;
1067 scsiDev
.targets
[i
].syncPeriod
= 0;
1073 void scsiDisconnect()
1075 scsiEnterPhase(MESSAGE_IN);
1076 scsiWriteByte(0x02); // save data pointer
1077 scsiWriteByte(0x04); // disconnect msg.
1079 // For now, the caller is responsible for tracking the disconnected
1080 // state, and calling scsiReconnect.
1081 // Ideally the client would exit their loop and we'd implement this
1082 // as part of scsiPoll
1083 int phase = scsiDev.phase;
1085 scsiDev.phase = phase;
1092 int reconnected = 0;
1094 int sel = SCSI_ReadFilt(SCSI_Filt_SEL);
1095 int bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
1099 sel = SCSI_ReadFilt(SCSI_Filt_SEL);
1100 bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
1107 uint8_t scsiIdMask = 1 << scsiDev.target->targetId;
1108 SCSI_Out_Bits_Write(scsiIdMask);
1109 SCSI_Out_Ctl_Write(1); // Write bits manually.
1110 SCSI_SetPin(SCSI_Out_BSY);
1112 s2s_delay_us(3); // arbitrate delay. 2.4us.
1114 uint8_t dbx = scsiReadDBxPins();
1115 sel = SCSI_ReadFilt(SCSI_Filt_SEL);
1116 if (sel || ((dbx ^ scsiIdMask) > scsiIdMask))
1118 // Lost arbitration.
1119 SCSI_Out_Ctl_Write(0);
1120 SCSI_ClearPin(SCSI_Out_BSY);
1126 SCSI_SetPin(SCSI_Out_SEL);
1127 s2s_delay_us(1); // Bus clear + Bus settle.
1129 // Reselection phase
1130 SCSI_CTL_PHASE_Write(__scsiphase_io);
1131 SCSI_Out_Bits_Write(scsiIdMask | (1 << scsiDev.initiatorId));
1132 scsiDeskewDelay(); // 2 deskew delays
1133 scsiDeskewDelay(); // 2 deskew delays
1134 SCSI_ClearPin(SCSI_Out_BSY);
1135 s2s_delay_us(1); // Bus Settle Delay
1137 uint32_t waitStart_ms = getTime_ms();
1138 bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
1139 // Wait for initiator.
1142 !scsiDev.resetFlag &&
1143 (elapsedTime_ms(waitStart_ms) < 250))
1145 bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
1150 SCSI_SetPin(SCSI_Out_BSY);
1151 scsiDeskewDelay(); // 2 deskew delays
1152 scsiDeskewDelay(); // 2 deskew delays
1153 SCSI_ClearPin(SCSI_Out_SEL);
1155 // Prepare for the initial IDENTIFY message.
1156 SCSI_Out_Ctl_Write(0);
1157 scsiEnterPhase(MESSAGE_IN);
1159 // Send identify command
1160 scsiWriteByte(0x80);
1162 scsiEnterPhase(scsiDev.phase);
1167 // reselect timeout.
1168 SCSI_Out_Ctl_Write(0);
1169 SCSI_ClearPin(SCSI_Out_SEL);
1170 SCSI_CTL_PHASE_Write(0);