Improved scsi signal noise rejection, fixed write performance, fixed bug with multipl...
[SCSI2SD-V6.git] / src / firmware / scsi.c
1 // Copyright (C) 2014 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 "scsi.h"
19 #include "scsiPhy.h"
20 #include "config.h"
21 #include "diagnostic.h"
22 #include "disk.h"
23 #include "inquiry.h"
24 #include "led.h"
25 #include "mode.h"
26 #include "time.h"
27 #include "bsp.h"
28 #include "cdrom.h"
29 //#include "debug.h"
30 #include "tape.h"
31 #include "mo.h"
32 #include "vendor.h"
33
34 #include <string.h>
35
36 // Global SCSI device state.
37 ScsiDevice scsiDev S2S_DMA_ALIGN;
38
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);
47
48 static void doReserveRelease(void);
49
50 void enter_BusFree()
51 {
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)
55 {
56 s2s_delay_us(2);
57 }
58
59 #if 0
60 if (scsiDev.status != GOOD && isDebugEnabled())
61 {
62 // We want to capture debug information for failure cases.
63 s2s_delay_ms(64);
64 }
65 #endif
66
67
68 scsiEnterBusFree();
69
70 // Wait for the initiator to cease driving signals
71 // Bus settle delay + bus clear delay = 1200ns
72 s2s_delay_us(2);
73
74
75 s2s_ledOff();
76 scsiDev.phase = BUS_FREE;
77 scsiDev.selFlag = 0;
78 }
79
80 static void enter_MessageIn(uint8_t message)
81 {
82 scsiDev.msgIn = message;
83 scsiDev.phase = MESSAGE_IN;
84 }
85
86 int process_MessageIn(int releaseBusFree)
87 {
88 scsiEnterPhase(MESSAGE_IN);
89 scsiWriteByte(scsiDev.msgIn);
90
91 if (unlikely(scsiDev.atnFlag))
92 {
93 // If there was a parity error, we go
94 // back to MESSAGE_OUT first, get out parity error message, then come
95 // back here.
96 return 0;
97 }
98 else if ((scsiDev.msgIn == MSG_LINKED_COMMAND_COMPLETE) ||
99 (scsiDev.msgIn == MSG_LINKED_COMMAND_COMPLETE_WITH_FLAG))
100 {
101 // Go back to the command phase and start again.
102 scsiDev.phase = COMMAND;
103 scsiDev.dataPtr = 0;
104 scsiDev.savedDataPtr = 0;
105 scsiDev.dataLen = 0;
106 scsiDev.status = GOOD;
107 transfer.blocks = 0;
108 transfer.currentBlock = 0;
109 return 0;
110 }
111 else if (releaseBusFree) /*if (scsiDev.msgIn == MSG_COMMAND_COMPLETE)*/
112 {
113 enter_BusFree();
114 return 1;
115 }
116 else
117 {
118 return 1;
119 }
120 }
121
122 static void messageReject()
123 {
124 scsiEnterPhase(MESSAGE_IN);
125 scsiWriteByte(MSG_REJECT);
126 }
127
128 static void enter_Status(uint8_t status)
129 {
130 scsiDev.status = status;
131 scsiDev.phase = STATUS;
132
133 scsiDev.lastStatus = scsiDev.status;
134 scsiDev.lastSense = scsiDev.target->sense.code;
135 scsiDev.lastSenseASC = scsiDev.target->sense.asc;
136 }
137
138 void process_Status()
139 {
140 scsiEnterPhase(STATUS);
141
142 uint8_t message;
143
144 uint8_t control = scsiDev.cdb[scsiDev.cdbLen - 1];
145
146 if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI)
147 {
148 // OMTI non-standard LINK control
149 if (control & 0x01)
150 {
151 scsiDev.phase = COMMAND;
152 return;
153 }
154 }
155
156 if ((scsiDev.status == GOOD) && (control & 0x01))
157 {
158 // Linked command.
159 scsiDev.status = INTERMEDIATE;
160 if (control & 0x02)
161 {
162 message = MSG_LINKED_COMMAND_COMPLETE_WITH_FLAG;
163 }
164 else
165 {
166 message = MSG_LINKED_COMMAND_COMPLETE;
167 }
168 }
169 else
170 {
171 message = MSG_COMMAND_COMPLETE;
172 }
173
174 if (scsiDev.target->cfg->quirks == S2S_CFG_QUIRKS_OMTI)
175 {
176 scsiDev.status |= (scsiDev.target->targetId & 0x03) << 5;
177 }
178
179 scsiWriteByte(scsiDev.status);
180
181 scsiDev.lastStatus = scsiDev.status;
182 scsiDev.lastSense = scsiDev.target->sense.code;
183 scsiDev.lastSenseASC = scsiDev.target->sense.asc;
184
185 // Command Complete occurs AFTER a valid status has been
186 // sent. then we go bus-free.
187 enter_MessageIn(message);
188 }
189
190 static void enter_DataIn(int len)
191 {
192 scsiDev.dataLen = len;
193 scsiDev.phase = DATA_IN;
194 }
195
196 static void process_DataIn()
197 {
198 uint32_t len;
199
200 if (scsiDev.dataLen > sizeof(scsiDev.data))
201 {
202 scsiDev.dataLen = sizeof(scsiDev.data);
203 }
204
205 len = scsiDev.dataLen - scsiDev.dataPtr;
206 if (len > 0)
207 {
208 scsiEnterPhase(DATA_IN);
209 scsiWrite(scsiDev.data + scsiDev.dataPtr, len);
210 scsiDev.dataPtr += len;
211 }
212
213 if ((scsiDev.dataPtr >= scsiDev.dataLen) &&
214 (transfer.currentBlock == transfer.blocks))
215 {
216 enter_Status(GOOD);
217 }
218 }
219
220 static void process_DataOut()
221 {
222 uint32_t len;
223
224 if (scsiDev.dataLen > sizeof(scsiDev.data))
225 {
226 scsiDev.dataLen = sizeof(scsiDev.data);
227 }
228
229 len = scsiDev.dataLen - scsiDev.dataPtr;
230 if (len > 0)
231 {
232 scsiEnterPhase(DATA_OUT);
233
234 int parityError = 0;
235 scsiRead(scsiDev.data + scsiDev.dataPtr, len, &parityError);
236 scsiDev.dataPtr += len;
237
238 if (parityError &&
239 (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
240 {
241 scsiDev.target->sense.code = ABORTED_COMMAND;
242 scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
243 enter_Status(CHECK_CONDITION);
244 }
245 }
246
247 if ((scsiDev.dataPtr >= scsiDev.dataLen) &&
248 (transfer.currentBlock == transfer.blocks))
249 {
250 if (scsiDev.postDataOutHook != NULL)
251 {
252 scsiDev.postDataOutHook();
253 }
254 else
255 {
256 enter_Status(GOOD);
257 }
258 }
259 }
260
261 static const uint8_t CmdGroupBytes[8] = {6, 10, 10, 6, 6, 12, 6, 6};
262 static void process_Command()
263 {
264 int group;
265 uint8_t command;
266 uint8_t control;
267
268 scsiEnterPhase(COMMAND);
269
270 memset(scsiDev.cdb + 6, 0, sizeof(scsiDev.cdb) - 6);
271 int parityError = 0;
272 scsiRead(scsiDev.cdb, 6, &parityError);
273
274 group = scsiDev.cdb[0] >> 5;
275 scsiDev.cdbLen = CmdGroupBytes[group];
276 if (parityError &&
277 (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
278 {
279 // Don't try and read more bytes, as we cannot be sure what group
280 // the command should be.
281 }
282 else if (scsiDev.cdbLen - 6 > 0)
283 {
284 scsiRead(scsiDev.cdb + 6, scsiDev.cdbLen - 6, &parityError);
285 }
286
287 command = scsiDev.cdb[0];
288
289 // Prefer LUN's set by IDENTIFY messages for newer hosts.
290 if (scsiDev.lun < 0)
291 {
292 scsiDev.lun = scsiDev.cdb[1] >> 5;
293 }
294
295 control = scsiDev.cdb[scsiDev.cdbLen - 1];
296
297 scsiDev.cmdCount++;
298 const S2S_TargetCfg* cfg = scsiDev.target->cfg;
299
300 if (unlikely(scsiDev.resetFlag))
301 {
302 // Don't log bogus commands
303 scsiDev.cmdCount--;
304 memset(scsiDev.cdb, 0xff, sizeof(scsiDev.cdb));
305 return;
306 }
307 else if (parityError &&
308 (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
309 {
310 scsiDev.target->sense.code = ABORTED_COMMAND;
311 scsiDev.target->sense.asc = SCSI_PARITY_ERROR;
312 enter_Status(CHECK_CONDITION);
313 }
314 else if ((control & 0x02) && ((control & 0x01) == 0))
315 {
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);
320 }
321 else if (command == 0x12)
322 {
323 s2s_scsiInquiry();
324 }
325 else if (command == 0x03)
326 {
327 // REQUEST SENSE
328 uint32_t allocLength = scsiDev.cdb[4];
329
330 // As specified by the SASI and SCSI1 standard.
331 // Newer initiators won't be specifying 0 anyway.
332 if (allocLength == 0) allocLength = 4;
333
334 memset(scsiDev.data, 0, 256); // Max possible alloc length
335 scsiDev.data[0] = 0xF0;
336 scsiDev.data[2] = scsiDev.target->sense.code & 0x0F;
337
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;
342
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;
347
348 // Silently truncate results. SCSI-2 spec 8.2.14.
349 enter_DataIn(allocLength);
350
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;
354 }
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))
361 {
362 scsiDev.target->sense.code = UNIT_ATTENTION;
363 scsiDev.target->sense.asc = scsiDev.target->unitAttention;
364
365 // If initiator doesn't do REQUEST SENSE for the next command, then
366 // data is lost.
367 scsiDev.target->unitAttention = 0;
368
369 enter_Status(CHECK_CONDITION);
370 }
371 else if (scsiDev.lun)
372 {
373 scsiDev.target->sense.code = ILLEGAL_REQUEST;
374 scsiDev.target->sense.asc = LOGICAL_UNIT_NOT_SUPPORTED;
375 enter_Status(CHECK_CONDITION);
376 }
377 else if (command == 0x17 || command == 0x16)
378 {
379 doReserveRelease();
380 }
381 else if ((scsiDev.target->reservedId >= 0) &&
382 (scsiDev.target->reservedId != scsiDev.initiatorId))
383 {
384 enter_Status(CONFLICT);
385 }
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()))
391 {
392 // Already handled.
393 }
394 else if (scsiDiskCommand())
395 {
396 // Already handled.
397 // check for the performance-critical read/write
398 // commands ASAP.
399 }
400 else if (command == 0x1C)
401 {
402 scsiReceiveDiagnostic();
403 }
404 else if (command == 0x1D)
405 {
406 scsiSendDiagnostic();
407 }
408 else if (command == 0x3B)
409 {
410 scsiWriteBuffer();
411 }
412 else if (command == 0x3C)
413 {
414 scsiReadBuffer();
415 }
416 else if (!scsiModeCommand() && !scsiVendorCommand())
417 {
418 scsiDev.target->sense.code = ILLEGAL_REQUEST;
419 scsiDev.target->sense.asc = INVALID_COMMAND_OPERATION_CODE;
420 enter_Status(CHECK_CONDITION);
421 }
422
423 // Successful
424 if (scsiDev.phase == COMMAND) // No status set, and not in DATA_IN
425 {
426 enter_Status(GOOD);
427 }
428
429 }
430
431 static void doReserveRelease()
432 {
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];
437
438 int canRelease =
439 (!thirdPty && (scsiDev.initiatorId == scsiDev.target->reservedId)) ||
440 (thirdPty &&
441 (scsiDev.target->reserverId == scsiDev.initiatorId) &&
442 (scsiDev.target->reservedId == thirdPtyId)
443 );
444
445 if (extentReservation)
446 {
447 // Not supported.
448 scsiDev.target->sense.code = ILLEGAL_REQUEST;
449 scsiDev.target->sense.asc = INVALID_FIELD_IN_CDB;
450 enter_Status(CHECK_CONDITION);
451 }
452 else if (command == 0x17) // release
453 {
454 if ((scsiDev.target->reservedId < 0) || canRelease)
455 {
456 scsiDev.target->reservedId = -1;
457 scsiDev.target->reserverId = -1;
458 }
459 else
460 {
461 enter_Status(CONFLICT);
462 }
463 }
464 else // assume reserve.
465 {
466 if ((scsiDev.target->reservedId < 0) || canRelease)
467 {
468 scsiDev.target->reserverId = scsiDev.initiatorId;
469 if (thirdPty)
470 {
471 scsiDev.target->reservedId = thirdPtyId;
472 }
473 else
474 {
475 scsiDev.target->reservedId = scsiDev.initiatorId;
476 }
477 }
478 else
479 {
480 // Already reserved by someone else!
481 enter_Status(CONFLICT);
482 }
483 }
484 }
485
486 static uint32_t resetUntil = 0;
487
488 static void scsiReset()
489 {
490 scsiDev.rstCount++;
491 s2s_ledOff();
492
493 scsiPhyReset();
494
495 scsiDev.phase = BUS_FREE;
496 scsiDev.atnFlag = 0;
497 scsiDev.resetFlag = 0;
498 scsiDev.selFlag = 0;
499 scsiDev.lun = -1;
500 scsiDev.compatMode = COMPAT_UNKNOWN;
501
502 if (scsiDev.target)
503 {
504 if (scsiDev.target->unitAttention != POWER_ON_RESET)
505 {
506 scsiDev.target->unitAttention = SCSI_BUS_RESET;
507 }
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;
512 }
513 scsiDev.target = NULL;
514
515 for (int i = 0; i < S2S_MAX_TARGETS; ++i)
516 {
517 scsiDev.targets[i].syncOffset = 0;
518 scsiDev.targets[i].syncPeriod = 0;
519 }
520 scsiDev.minSyncPeriod = 0;
521
522 scsiDiskReset();
523
524 scsiDev.postDataOutHook = NULL;
525
526 scsiDev.sdUnderrunCount = 0;
527
528 // Sleep to allow the bus to settle down a bit.
529 // We must be ready again within the "Reset to selection time" of
530 // 250ms.
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
535 // USB comms
536 resetUntil = s2s_getTime_ms() + 2; // At least 1ms.
537 }
538
539 static void enter_SelectionPhase()
540 {
541 // Ignore stale versions of this flag, but ensure we know the
542 // current value if the flag is still set.
543 scsiDev.atnFlag = 0;
544 scsiDev.dataPtr = 0;
545 scsiDev.savedDataPtr = 0;
546 scsiDev.dataLen = 0;
547 scsiDev.status = GOOD;
548 scsiDev.phase = SELECTION;
549 scsiDev.lun = -1;
550 scsiDev.discPriv = 0;
551
552 scsiDev.initiatorId = -1;
553 scsiDev.target = NULL;
554
555 transfer.blocks = 0;
556 transfer.currentBlock = 0;
557
558 scsiDev.postDataOutHook = NULL;
559
560 scsiDev.needSyncNegotiationAck = 0;
561 }
562
563 static void process_SelectionPhase()
564 {
565 // Selection delays.
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
571 {
572 if (scsiDev.compatMode < COMPAT_SCSI2)
573 {
574 s2s_delay_ms(1);
575 }
576 }
577 else if (scsiDev.boardCfg.selectionDelay != 0)
578 {
579 s2s_delay_ms(scsiDev.boardCfg.selectionDelay);
580 }
581
582 uint8_t selStatus = *SCSI_STS_SELECTED;
583 if ((selStatus == 0) && (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_SEL_LATCH))
584 {
585 selStatus = scsiDev.selFlag;
586 }
587
588 int tgtIndex;
589 TargetState* target = NULL;
590 for (tgtIndex = 0; tgtIndex < S2S_MAX_TARGETS; ++tgtIndex)
591 {
592 if (scsiDev.targets[tgtIndex].targetId == (selStatus & 7))
593 {
594 target = &scsiDev.targets[tgtIndex];
595 break;
596 }
597 }
598 if ((target != NULL) && (selStatus & 0x40))
599 {
600 // We've been selected!
601 // Assert BSY - Selection success!
602 // must happen within 200us (Selection abort time) of seeing our
603 // ID + SEL.
604 // (Note: the initiator will be waiting the "Selection time-out delay"
605 // for our BSY response, which is actually a very generous 250ms)
606 *SCSI_CTRL_BSY = 1;
607 s2s_ledOn();
608
609 scsiDev.target = target;
610
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;
615
616
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)
622 {
623 target->unitAttention = 0;
624 scsiDev.compatMode = COMPAT_SCSI1;
625 }
626 else if (!(scsiDev.boardCfg.flags & S2S_CFG_ENABLE_SCSI2))
627 {
628 scsiDev.compatMode = COMPAT_SCSI2_DISABLED;
629 }
630 else
631 {
632 scsiDev.compatMode = COMPAT_SCSI2;
633 }
634
635 scsiDev.selCount++;
636
637
638 // Save our initiator now that we're no longer in a time-critical
639 // section.
640 // SCSI1/SASI initiators may not set their own ID.
641 scsiDev.initiatorId = (selStatus >> 3) & 0x7;
642
643 while (likely(!scsiDev.resetFlag) && scsiStatusSEL())
644 {
645 // Wait until the end of the selection phase.
646 }
647
648 scsiDev.phase = COMMAND;
649 }
650 else if (!selStatus)
651 {
652 scsiDev.phase = BUS_BUSY;
653 }
654 scsiDev.selFlag = 0;
655 }
656
657 static void process_MessageOut()
658 {
659 int wasNeedSyncNegotiationAck = scsiDev.needSyncNegotiationAck;
660 scsiDev.needSyncNegotiationAck = 0; // Successful on -most- messages.
661
662 scsiEnterPhase(MESSAGE_OUT);
663
664 scsiDev.atnFlag = 0;
665 scsiDev.msgOut = scsiReadByte();
666 scsiDev.msgCount++;
667
668 if (scsiParityError() &&
669 (scsiDev.boardCfg.flags & S2S_CFG_ENABLE_PARITY))
670 {
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)
675 {
676 scsiReadByte();
677 }
678
679 // Go-back and try the message again.
680 scsiDev.atnFlag = 1;
681 }
682 else if (scsiDev.msgOut == 0x00)
683 {
684 // COMMAND COMPLETE. but why would the target be receiving this ? nfi.
685 enter_BusFree();
686 }
687 else if (scsiDev.msgOut == 0x06)
688 {
689 // ABORT
690 scsiDiskReset();
691 enter_BusFree();
692 }
693 else if (scsiDev.msgOut == 0x0C)
694 {
695 // BUS DEVICE RESET
696
697 scsiDiskReset();
698
699 scsiDev.target->unitAttention = SCSI_BUS_RESET;
700
701 // ANY initiator can reset the reservation state via this message.
702 scsiDev.target->reservedId = -1;
703 scsiDev.target->reserverId = -1;
704
705 // Cancel any sync negotiation
706 scsiDev.target->syncOffset = 0;
707 scsiDev.target->syncPeriod = 0;
708
709 enter_BusFree();
710 }
711 else if (scsiDev.msgOut == 0x05)
712 {
713 // Initiate Detected Error
714 // Ignore for now
715 }
716 else if (scsiDev.msgOut == 0x0F)
717 {
718 // INITIATE RECOVERY
719 // Ignore for now
720 }
721 else if (scsiDev.msgOut == 0x10)
722 {
723 // RELEASE RECOVERY
724 // Ignore for now
725 enter_BusFree();
726 }
727 else if (scsiDev.msgOut == MSG_REJECT)
728 {
729 // Message Reject
730 // Oh well.
731
732 if (wasNeedSyncNegotiationAck)
733 {
734 scsiDev.target->syncOffset = 0;
735 scsiDev.target->syncPeriod = 0;
736 }
737 }
738 else if (scsiDev.msgOut == 0x08)
739 {
740 // NOP
741 }
742 else if (scsiDev.msgOut == 0x09)
743 {
744 // Message Parity Error
745 // Go back and re-send the last message.
746 scsiDev.phase = MESSAGE_IN;
747
748 if (wasNeedSyncNegotiationAck)
749 {
750 scsiDev.target->syncOffset = 0;
751 scsiDev.target->syncPeriod = 0;
752 }
753 }
754 else if (scsiDev.msgOut & 0x80) // 0x80 -> 0xFF
755 {
756 // IDENTIFY
757 if ((scsiDev.msgOut & 0x18) || // Reserved bits set.
758 (scsiDev.msgOut & 0x20)) // We don't have any target routines!
759 {
760 messageReject();
761 }
762
763 scsiDev.lun = scsiDev.msgOut & 0x7;
764 scsiDev.discPriv =
765 ((scsiDev.msgOut & 0x40) && (scsiDev.initiatorId >= 0))
766 ? 1 : 0;
767 }
768 else if (scsiDev.msgOut >= 0x20 && scsiDev.msgOut <= 0x2F)
769 {
770 // Two byte message. We don't support these. read and discard.
771 scsiReadByte();
772
773 if (scsiDev.msgOut == 0x23) {
774 // Ignore Wide Residue. We're only 8 bit anyway.
775 } else {
776 messageReject();
777 }
778 }
779 else if (scsiDev.msgOut == 0x01)
780 {
781 int i;
782
783 // Extended message.
784 int msgLen = scsiReadByte();
785 if (msgLen == 0) msgLen = 256;
786 uint8_t extmsg[256];
787 for (i = 0; i < msgLen && !scsiDev.resetFlag; ++i)
788 {
789 // Discard bytes.
790 extmsg[i] = scsiReadByte();
791 }
792
793 if (extmsg[0] == 3 && msgLen == 2) // Wide Data Request
794 {
795 // Negotiate down to 8bit
796 scsiEnterPhase(MESSAGE_IN);
797 static const uint8_t WDTR[] = {0x01, 0x02, 0x03, 0x00};
798 scsiWrite(WDTR, sizeof(WDTR));
799
800 // SDTR becomes invalidated.
801 scsiDev.target->syncOffset = 0;
802 scsiDev.target->syncPeriod = 0;
803 }
804 else if (extmsg[0] == 1 && msgLen == 3) // Synchronous data request
805 {
806 int oldPeriod = scsiDev.target->syncPeriod;
807 int oldOffset = scsiDev.target->syncOffset;
808
809 int transferPeriod = extmsg[1];
810 int offset = extmsg[2];
811
812 if ((
813 (transferPeriod > 0) &&
814 (transferPeriod < scsiDev.minSyncPeriod)) ||
815 (scsiDev.minSyncPeriod == 0))
816 {
817 scsiDev.minSyncPeriod = transferPeriod;
818 }
819
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
823 // register.
824 (transferPeriod == 0) ||
825 (offset == 0) ||
826 ((scsiDev.boardCfg.scsiSpeed != S2S_CFG_SPEED_NoLimit) &&
827 (scsiDev.boardCfg.scsiSpeed <= S2S_CFG_SPEED_ASYNC_50)))
828 {
829 scsiDev.target->syncOffset = 0;
830 scsiDev.target->syncPeriod = 0;
831 } else {
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))
839 {
840 scsiDev.target->syncPeriod = 16; // 15.6MB/s
841 }
842 else if (scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_TURBO)
843 {
844 scsiDev.target->syncPeriod = transferPeriod;
845 }
846 else if (transferPeriod <= 25 &&
847 ((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit) ||
848 (scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)))
849 {
850 scsiDev.target->syncPeriod = 25; // 100ns, 10MB/s
851
852 } else if (transferPeriod < 50 &&
853 ((scsiDev.boardCfg.scsiSpeed == S2S_CFG_SPEED_NoLimit) ||
854 (scsiDev.boardCfg.scsiSpeed >= S2S_CFG_SPEED_SYNC_10)))
855 {
856 scsiDev.target->syncPeriod = transferPeriod;
857 } else if (transferPeriod >= 50)
858 {
859 scsiDev.target->syncPeriod = transferPeriod;
860 } else {
861 scsiDev.target->syncPeriod = 50;
862 }
863 }
864
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.
870 {
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.
876 }
877 }
878 else
879 {
880 // Not supported
881 messageReject();
882 }
883 }
884 else
885 {
886 messageReject();
887 }
888
889 // Re-check the ATN flag in case it stays asserted.
890 scsiDev.atnFlag |= scsiStatusATN();
891
892 if (!scsiDev.atnFlag)
893 {
894 // Message wasn't rejected!
895 scsiDev.needSyncNegotiationAck = 0;
896 }
897 }
898
899 void scsiPoll(void)
900 {
901 if (resetUntil != 0 && resetUntil > s2s_getTime_ms())
902 {
903 return;
904 }
905 resetUntil = 0;
906
907 if (unlikely(scsiDev.resetFlag))
908 {
909 scsiReset();
910 // Still in reset phase for a few ms.
911 // Do not try and process any commands.
912 return;
913 }
914
915 switch (scsiDev.phase)
916 {
917 case BUS_FREE:
918 if (scsiStatusBSY())
919 {
920 scsiDev.phase = BUS_BUSY;
921 }
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)
927 {
928 enter_SelectionPhase();
929 }
930 break;
931
932 case BUS_BUSY:
933 // Someone is using the bus. Perhaps they are trying to
934 // select us.
935 if (scsiDev.selFlag || *SCSI_STS_SELECTED)
936 {
937 enter_SelectionPhase();
938 }
939 else if (!scsiStatusBSY())
940 {
941 scsiDev.phase = BUS_FREE;
942 }
943 break;
944
945 case ARBITRATION:
946 // TODO Support reselection.
947 break;
948
949 case SELECTION:
950 process_SelectionPhase();
951 break;
952
953 case RESELECTION:
954 // Not currently supported!
955 break;
956
957 case COMMAND:
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.
961 if (scsiDev.atnFlag)
962 {
963 process_MessageOut();
964 }
965 else
966 {
967 process_Command();
968 }
969 break;
970
971 case DATA_IN:
972 scsiDev.atnFlag |= scsiStatusATN();
973 if (scsiDev.atnFlag)
974 {
975 process_MessageOut();
976 }
977 else
978 {
979 process_DataIn();
980 }
981 break;
982
983 case DATA_OUT:
984 scsiDev.atnFlag |= scsiStatusATN();
985 if (scsiDev.atnFlag)
986 {
987 process_MessageOut();
988 }
989 else
990 {
991 process_DataOut();
992 }
993 break;
994
995 case STATUS:
996 scsiDev.atnFlag |= scsiStatusATN();
997 if (scsiDev.atnFlag)
998 {
999 process_MessageOut();
1000 }
1001 else
1002 {
1003 process_Status();
1004 }
1005 break;
1006
1007 case MESSAGE_IN:
1008 scsiDev.atnFlag |= scsiStatusATN();
1009 if (scsiDev.atnFlag)
1010 {
1011 process_MessageOut();
1012 }
1013 else
1014 {
1015 process_MessageIn(1);
1016 }
1017
1018 break;
1019
1020 case MESSAGE_OUT:
1021 process_MessageOut();
1022 break;
1023 }
1024 }
1025
1026 void scsiInit()
1027 {
1028 static int firstInit = 1;
1029
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;
1036
1037 int i;
1038 for (i = 0; i < S2S_MAX_TARGETS; ++i)
1039 {
1040 const S2S_TargetCfg* cfg = s2s_getConfigByIndex(i);
1041 if (cfg && (cfg->scsiId & S2S_CFG_TARGET_ENABLED))
1042 {
1043 scsiDev.targets[i].targetId = cfg->scsiId & S2S_CFG_TARGET_ID_BITS;
1044 scsiDev.targets[i].cfg = cfg;
1045
1046 scsiDev.targets[i].liveCfg.bytesPerSector = cfg->bytesPerSector;
1047 }
1048 else
1049 {
1050 scsiDev.targets[i].targetId = 0xff;
1051 scsiDev.targets[i].cfg = NULL;
1052 }
1053 scsiDev.targets[i].reservedId = -1;
1054 scsiDev.targets[i].reserverId = -1;
1055 if (firstInit)
1056 {
1057 scsiDev.targets[i].unitAttention = POWER_ON_RESET;
1058 }
1059 else
1060 {
1061 scsiDev.targets[i].unitAttention = PARAMETERS_CHANGED;
1062 }
1063 scsiDev.targets[i].sense.code = NO_SENSE;
1064 scsiDev.targets[i].sense.asc = NO_ADDITIONAL_SENSE_INFORMATION;
1065
1066 scsiDev.targets[i].syncOffset = 0;
1067 scsiDev.targets[i].syncPeriod = 0;
1068 }
1069 firstInit = 0;
1070 }
1071
1072 /* TODO REENABLE
1073 void scsiDisconnect()
1074 {
1075 scsiEnterPhase(MESSAGE_IN);
1076 scsiWriteByte(0x02); // save data pointer
1077 scsiWriteByte(0x04); // disconnect msg.
1078
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;
1084 enter_BusFree();
1085 scsiDev.phase = phase;
1086 }
1087 */
1088
1089 /* TODO REENABLE
1090 int scsiReconnect()
1091 {
1092 int reconnected = 0;
1093
1094 int sel = SCSI_ReadFilt(SCSI_Filt_SEL);
1095 int bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
1096 if (!sel && !bsy)
1097 {
1098 s2s_delay_us(1);
1099 sel = SCSI_ReadFilt(SCSI_Filt_SEL);
1100 bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
1101 }
1102
1103 if (!sel && !bsy)
1104 {
1105 // Arbitrate.
1106 s2s_ledOn();
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);
1111
1112 s2s_delay_us(3); // arbitrate delay. 2.4us.
1113
1114 uint8_t dbx = scsiReadDBxPins();
1115 sel = SCSI_ReadFilt(SCSI_Filt_SEL);
1116 if (sel || ((dbx ^ scsiIdMask) > scsiIdMask))
1117 {
1118 // Lost arbitration.
1119 SCSI_Out_Ctl_Write(0);
1120 SCSI_ClearPin(SCSI_Out_BSY);
1121 s2s_ledOff();
1122 }
1123 else
1124 {
1125 // Won arbitration
1126 SCSI_SetPin(SCSI_Out_SEL);
1127 s2s_delay_us(1); // Bus clear + Bus settle.
1128
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
1136
1137 uint32_t waitStart_ms = getTime_ms();
1138 bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
1139 // Wait for initiator.
1140 while (
1141 !bsy &&
1142 !scsiDev.resetFlag &&
1143 (elapsedTime_ms(waitStart_ms) < 250))
1144 {
1145 bsy = SCSI_ReadFilt(SCSI_Filt_BSY);
1146 }
1147
1148 if (bsy)
1149 {
1150 SCSI_SetPin(SCSI_Out_BSY);
1151 scsiDeskewDelay(); // 2 deskew delays
1152 scsiDeskewDelay(); // 2 deskew delays
1153 SCSI_ClearPin(SCSI_Out_SEL);
1154
1155 // Prepare for the initial IDENTIFY message.
1156 SCSI_Out_Ctl_Write(0);
1157 scsiEnterPhase(MESSAGE_IN);
1158
1159 // Send identify command
1160 scsiWriteByte(0x80);
1161
1162 scsiEnterPhase(scsiDev.phase);
1163 reconnected = 1;
1164 }
1165 else
1166 {
1167 // reselect timeout.
1168 SCSI_Out_Ctl_Write(0);
1169 SCSI_ClearPin(SCSI_Out_SEL);
1170 SCSI_CTL_PHASE_Write(0);
1171 s2s_ledOff();
1172 }
1173 }
1174 }
1175 return reconnected;
1176 }
1177 */
1178